Building a CEPC Reference Board
June 4, 2002
So, you've been reading the Microsoft® Windows® CE .NET Get Embedded column every month (by a strange coincidence we have also been writing one every month), and by now you are just itching to try out some code, create several custom operating system images, and simply produce something to show to your colleagues in the office and say, "Cool, eh?" (Spookily, the first letters of "Cool" and "Eh" spell "CE.") But how to get started?
You could, of course, make use of the Windows CE .NET emulator. This is a great way to get started with the Windows CE .NET tools, and begin developing for Windows "Cool Eh" .NET. Better still, the Windows CE .NET Emulation Edition is a FREE Web download. Perhaps, though, you want to play with some real hardware... You're in luck: Windows CE .NET ships with support for a number of reference boards (see the list below), and supports additional reference boards through third-party board support packages (BSPs).
Here's the list of supported BSPs for Windows CE .NET
- x86: National Geode™ SP4SC30 Development Platform, Lanner EM-350/EM-351, Advantech PCM-5822/PCM-5823, CEPC, Emulator.
- ARM: SA-1110/SA-1111 (Assabet) Development Kit, Intel® XScale Microarchitecture Handheld Development Platform, ARM Integrator AP SDB.
- SHx: Hitachi SH7750 HARP SDB, Hitachi SH7729 HARP SDB.
- MIPS: NEC DDB-Vrc5476 (Boston), SDB NEC DDB-Vr4122 (Eagle) SDB.
Having a supported reference design gives you the ability to build an operating system image using Platform Builder (a tool that ships with the Windows CE .NET product), and download directly to your board, without needing to write the bootloader (more on this later), drivers, and so on. All of the on-board hardware and drivers are supported by the BSP. You can just select the BSP from the Platform Wizard, and choose your components from the catalog—build, download, debug, and deploy.
Perhaps the quickest way to build your very own custom reference platform is to use the CEPC reference design. The Windows CE .NET Help states that the CEPC reference platform is available from "any desktop computer vendor." All this is saying is that we can use a regular PC as a basis for the CEPC reference board. The CEPC reference platform has some specific hardware requirements, though, as follows:
- Processor: P5, PII, PIII, Pentium 4, Celeron, K6x, K7, Athlon, Duron.
- Memory: 32 MB PC100/133 3.3v; 64 MB recommended.
- Video Card: 3D Labs Oxygen VX1, TVIA CyberPro 5050, and any VESA 2.0 compatible card. More on this in a minute (or perhaps two minutes if you're a slow reader).
- Networking (optional): Linksys LNEPCI2T, Model LNE 2000, RealTek 8139, DEC 21140, DP83815-based cards, Netgear FA-312, and any PCI/ISA-based, NE2000-compatible network adapter.
- Other: Serial port, 3.5-inch 1.44-MB floppy disk, heat sink, and fan. A power supply may also be helpful.
More on Video: When building a CEPC reference board, there are a number of video cards that can be used. Windows CE .NET supports any VESA 2.0-compatible video card. A large number of boards fall into this group, and a number have been tested for Windows CE .NET. These include:
- ATI Rage Fury.
- ATI Expert2000.
- ATI RagePro.
- ATI Expert98.
- ATI XL series.
- Diamond Stealth S540.
- Number Nine SR9.
- Creative Labs TNT2 and TNT2 Ultra.
- Diamond Viper V770 and V770 Ultra.
- Voodoo3 2000 and 3000 series.
- Matrox G400 and G200 series.
- 3D Labs Oxygen VX1.
- Latest versions of the S3 Virge GX, GX/2, VX cards.
If you have a video card that you suspect may be VESA 2.0 compatible, and you want to use this with your CEPC device, then you can test out the supported VESA graphics modes of the card by running a utility called Vesatest, which ships with Windows CE .NET. More on this when we discuss booting a Windows CE .NET image on your CEPC.
The CEPC platform can be very flexible, providing the ability to add additional hardware into any free PCI/ISA slot, such as a PCMCIA card, or a IEEE-1394 card to host a peripheral, such as camera, or other device. Windows CE .NET ships with a BSP that supports the CEPC platform. This includes the drivers for the hardware we discussed above, and a boot loader that is capable of loading an operating system image (NK.BIN) from a serial or Ethernet connection with your development PC—or directly from boot media such as a floppy disk, flash media, or IDE hard drive.
So, you've dug out your old PC that's lurking under your desk that's been used as a footrest for more years than you can remember, brushed off the cobwebs, ticked off the CEPC hardware compatibility list, and you're all set. So how do we boot the initial operating system image? That's a great question, and very timely, since I was just moving on to talk about booting a CEPC.
Windows CE .NET ships with a sample boot floppy in WebImage format, which can be used to load a Windows CE operating system image. This can be loaded (as noted above), either locally from the boot media, or remotely using a serial or Ethernet connection. The WebImage floppy image files can be found in C:\Program Files\Windows CE Platform Builder\4.00\cepb\utilities (assuming you've used the default install options for Windows CE .NET product installation).
There are two files in this folder: WebSetup.exe, and cepcboot.144. The .144 file is a floppy disk image file; the WebSetup utility is used to transfer (and optionally format) a .144 image to a floppy disk. Chances are that the .144 extension is not registered on your development PC. Run the WebSetup utility once; this will register the .144 extension against the WebSetup utility. To create your boot floppy, simply double click on the cepbboot.144 file. This will load the WebSetup program. Select the appropriate drive to image, and go. (Note that the image below doesn't show any active drives. This is because this article is being written at 38,000 feet on my laptop, which doesn't have a built-in floppy drive).
Figure 1. The WebImage Utility, used to create a boot floppy
The boot floppy that has been generated by the cepcboot.144 file contains an image of MS-DOS, and some additional files, including an operating system loader program, loadcepc, and the Vesatest program. Loadcepc is a 16-bit, MS-DOS application that is provided in source, C:\WINCE400\PUBLIC\COMMON\OAK\CSP\I486\DOS\LOADCEPC. Note that you will need a copy of Microsoft® Visual C++® 1.52 to rebuild the loadcepc source.
At this point you may be asking yourself, "So, does that mean that I need to load MS-DOS before loading a Windows CE image?" Great question, and there are two answers:
- Yes. Using the cepcboot.144 file and the resulting MS-DOS boot floppy is a quick and easy way to get started with loading an operating system image—and the boot floppy contains utilities such as Vesatest. Also, using the boot floppy can be useful when diagnosing boot issues.
- No. There are some third-party DOS-less boot loaders available for Windows CE, from companies such as Venturcom and VIA. A DOS-less boot loader is also available through the Microsoft Solution Center in Munich, Germany. Also note that you won't be loading DOS on non-x86 devices.
If you already have MS-DOS bootable media and simply want to add the loadcepc program and vesatest utilities, you can take the files in flat-file format from the following folder. It's also a good opportunity to examine the config.sys and autoexec.bat, which are used to control the boot options for the loadcepc program. The flat files can be found in C:\WINCE400\PUBLIC\COMMON\OAK\CSP\I486\DOS\BOOTDISK.
So, let's take a look at how the boot floppy loads the Windows CE image. There are two files to look at, config.sys, and autoexec.bat.
Config.sys is used to load himem.sys (Himem.sys is a device driver required by DOS to use extended memory—all installed RAM in excess of 1 MB), and to display the boot menu to the user. The menu is listed below. This shows that the default option is CEPC_800. Use Ethernet to load an image at 800x600x16. How this interfaces with loadcepc is detailed in the autoexec.bat file.
[menu] menuitem=CEPC_LOCAL, Boot CE/PC (local nk.bin) menuitem=CEPC_D640, Boot CE/PC (ether via eboot.bin with /D:2 (640x480x8)) menuitem=CEPC_1024, Boot CE/PC (ether via eboot.bin with /L:1024x768x8) menuitem=CEPC_800, Boot CE/PC (ether via eboot.bin with /L:800x600x16) menuitem=CEPC_640, Boot CE/PC (ether via eboot.bin with /L:640x480x32) menuitem=CEPC_SERIAL, Boot CE/PC (serial via sboot.bin) menuitem=CEPC_PARALLEL, Boot CE/PC (parallel direct) menuitem=VESATEST, Run VesaTest program and list valid display modes menuitem=CLEAN, Clean Boot (no commands) menudefault=CEPC_800,5 menucolor=7,1
Autoexec.bat is used to run the loadcepc or vesatest programs. Below is an extract showing the default boot option of CEPC_800. The loadcepc program is run using a number of command-line options, some of which are set by the menu choice from config.sys (such as the resolution and color depth). Others, such as the IO Base and IRQ used by the network card, are configured globally at the top of the autoexec.bat file. Autoexec assumes that you will be booting using DHCP. This can be altered by setting the NET_IP variable as shown below (set NET_IP=192.168.0.10, or some other fixed ip value). You can, of course, step out to the command prompt (option 9 on the boot menu) and run loadcepc by hand.
set NET_IRQ=0 set NET_IOBASE=0 set NET_IP= :CEPC_800 REM ################################################################# REM Set RES=/L:800x600x16 for use with FLAT display driver. REM REM Format REM /L:DXxDYxBPP[:PXxPY] in DECIMAL!!!! REM set RES=/L:800x600x16 goto WITHRES :WITHRES REM ################################################################# REM Here we actually Launch LOADCEPC using the RES, NET_IOBASE, REM and NET_IRQ env vars we just set above based on menu REM selections. loadcepc /v /e:%NET_IOBASE%:%NET_IRQ%:%NET_IP% %RES% eboot.bin loadcepc has a number of command line options, as follows : Usage:LOADCEPC.EXE [/D:display] [/P] [/H] [/V] [(/E|/K):IO:IRQ[:<dotted IP>]] [/L:VXxVYxBPP[xPXxPY]] [/N:name] [<file name>] /D Display Resolution - 0 = 320x200x256 (default), 1 = 480x240x256, 2 = 640x480x256, 3 = 800x600x256, 4 = 1024x768x256 5 = 240x320x256, 6 = 208x240x256 /P Parallel port boot download. /H Help - displays this message /V Verbose - displays extra status information during boot /L:DXxDYxBPP[xPXxPY] (Use VESA VBE Linear/Flat Framebuffer video mode) DX, DY - Display X and Y Sizes BPP - Bits Per Pixel Color Depth (8, 16, 24, or 32) PX, PY - Optional Physical Screen X and Y Sizes Default <file name> is NK.BIN except for /P option which uses default on host unless <file name> specified.
Note the /L: is used for video display modes using the VESA BIOS extensions mentioned previously. Loadcepc will process this option and use the BIOS to set up and initialize the display card to the specified mode. One of the important things this does is to place the card into a flat memory mode, instead of the default banked mode needed for DOS applications. Using this approach, the display driver in the operating system image doesn't need to know anything about initializing the display at all. It only needs to know the location of the frame buffer and the pixel format (bits per pixel). So how does the driver know that? Does it call the BIOS to find out? Excellent questions!
The operating system does not call the BIOS, as Windows CE is designed for many platforms, as well as for CPUs that won't have one. Loadcepc reserves a section of memory in the first 2 MB of RAM for a set of boot arguments. This structure is aptly called the BOOTARGS. Loadcepc stores the display information in BOOTARGS, along with the serial port selection and the Ethernet boot information. This information is then used by Drivers, the OAL, and the bootloader.
What happens with the boot process going from power on to the Ethernet BOOT loader is illustrated in Figure 2.
Figure 2. CEPC Boot Sequence (Click on the thumbnail to see full image.)
Okay, now that you know what's going on with the BIOS, DOS, and Loadcepc, the next stage to grasp is the Ethernet boot loader, EBOOT.BIN. This is an actual Windows CE image (though it doesn't contain any part of the operating system). It is a small, 32-bit image that will communicate with the Platform Builder IDE to download a new operating system image and then jump to it. The boot loader is comprised of CPU and platform-specific functionality along with a large set of CPU/Platform independent code. Microsoft provides the BLCOMMON library to implement all of the platform-independent code. This leaves you with the platform-specific code. The code that you need to provide breaks down to 2 main groups:
- KITL communications "drivers"
- Platform initialization.
There are some other miscellaneous things a boot loader can do, but these are the ones of interest for this article. The platform-specific initialization and support is normally in an EBOOT folder in the BSP. The common portions of the boot loader source code are contained in C:\WINCE400\PUBLIC\COMMON\OAK\DRIVERS\ETHDBG\BLCOMMON. KITL communications drivers for the various NIC cards are contained in the various folders of the ETHDBG folder, or in the BSP itself, if not provided by Microsoft.
KITL communications drivers provide the means by which the boot loader displays progress and error information and also provides support for a method of downloading the operating system image (serial, parallel, Ethernet ...). The Ethernet boot loaders from Microsoft in the BSPs that ship with Platform Builder contain support for a variety of Ethernet NIC adapters. Microsoft provides support for NE2000-compatible NICs, Realtek 8139, DB83815 (MacPhyter) and USB Remote NDIS in EBOOT for the CEPC. Other BSPs include support for other controllers in their respective BSPs and boot loaders.
The Ethernet boot loader starts with a single function called Startup(). This function is often implemented in assembly language, as it may be loaded into flash as the reset vector for the CPU. In this way, the boot loader is the first piece of code executed. In the case of the CEPC and the PC architecture in general, as we have seen, this isn't the case. Nevertheless, on most of the other processors, some form of boot loader is placed in ROM/FLASH in early development to allow for easy download/updates of the operating system as you build up your system, drivers, and applications. Either way, the Startup() function serves as the entry point to the boot loader. It is responsible for initializing the CPU and RAM controllers at a minimum to support execution of the rest of the boot process. It will then initialize the communications device drivers for the platform. Usually this is at least a serial port and an Ethernet port. The serial port is really very important, and should not be overlooked, as problems with the Ethernet port are reported to the serial port.
The boot loader for CEPC supports a variety of options, many of which are provided from the LoadCEPC command line through the BOOTARGS memory location. These include the static IP address (if any), the port number and baud rate for serial-port debug information, and status. The BOOTARGS also includes information regarding the I/O Address or IRQ of the Ethernet NIC adapter. The boot loader in Main.c will check the BOOTARGS for information regarding the NIC, and attempt to find a PCI-bus NIC card matching the I/O address or IRQ (in case there is more then one card). If there is no IRQ or address specified, then it will scan the PCI bus to find a NIC card. If no PCI bus exists, or no NIC card is found matching the address or IRQ specified, the boot loader assumes an ISA NE2000-based Ethernet adapter.
It is important to note that to keep it relatively simple and CPU-independent whenever possible, the Ethernet download support in the boot loader does not use interrupts. The interrupts are enabled in the OAL later, after the image is loaded. The interrupt MUST NOT be shared, since the interrupt is handled internally at a low level in the operating system. Any other interrupts on the same IRQ will cause a failure when switching from polled to interrupt mode.
This is where the serial port output is very useful. As you will see, the debug output and the serial port output indicate what's happening and where the system got stuck. (This is one of the top problems encountered by new developers working with the CEPC.) To prevent the sharing, you will need to adjust the BIOS settings of your system. The "official" CEPC specs from Microsoft list the details of the settings for the system board. Other PC systems will vary depending on the BIOS version.
Once the boot loader has initialized the Ethernet port and any DMA required for it, it will create a unique name for the device for use with the Platform Builder IDE. The name is generated from a platform name (just a #define in the code) and the Ethernet MAC address. This name is sent in a UDP broadcast of a BOOTME packet. The BOOTME indicates to the IDE the device is requesting a download and indicates the name of the device. The name allows for multiple development devices and multiple developers to work from the same subnet. (It is generally a good idea to keep your development devices on an isolated subnet from your corporate network. Your company's IT staff will likely be much happier.)
After downloading a new copy of the operating system, the boot loader will then jump to the start address of the operating system image. Like the boot loader, the entry point for the operating system image is called Startup(). This code is mostly a duplicate of what is in the boot loader. The reason it's often duplicated is to allow the operating system image to load from a boot loader during development and later on move to flash as you get closer to a release. The Startup code executes before the MMU is enabled, so all addresses it uses are real physical addresses. This is in contrast to the rest of the system, which operates on virtual addresses.
After initializing the system, Startup calls KernelStart() (KernelInitialize() on the x86). This function initializes the kernel, sets up the virtual memory mapping defined in OEMAddressTable (ARM and x86—MIPS and SHx have a fixed mapping), and enables virtual memory. It then calls the OEMInitDebugSerial() function to initialize the debug serial port. After initializing the serial port, the kernel will print the Microsoft copyright banner through the debug port before calling OEMInit().
OEMInit() is where the major initialization of the platform as a whole should take place. Any special hardware setup and initialization should be done in device drivers. Sometimes, however, certain on-chip hardware that might have multiple functions must be placed in a required mode before the driver loads, in order for it to work correctly. You set up the interrupts handler(s) and system clocks in OEMInit() as well. One last item to initialize in OEMInit() is KITL and the transports for debug information.
For KITL transports, the CEPC BSP from Microsoft supports the NE2000, SMC9000, and USB Remote NDIS-based devices. You will note that this list does not match that of the Ethernet boot loader (EBOOT). In particular, the RTL8139 NIC is missing. This has caused a good deal of confusion and frustration for users, as it's possible to download the operating system through an RTL8139, but not use it for the kernel debugger and KITL, as the BSP is shipped from Microsoft. The good news is that you can grab the code from the boot loader and place it into the OAL to supply the missing functionality. This requires some modifications to:
- SOURCES files for the KITL builds of the kernel to hook in the RTL8139 code from the Microsoft-provided common libraries.
- The CONFIG.BIB for the platform to add the DMA buffer and adjust the image start addresses to match it.
- HALETHER.C for the OAL NIC support.
We won't go into all the details of the changes, as they are mostly just cut and paste, but we've included the modified files as part of the source code for this article.
Figure 3. EBOOT process (Click on the thumbnail to see full image.)
During the boot process, many messages are displayed through the debug serial port. Many boot problems are easily identified by checking this output. Even if you are using Ethernet for debug messages, the serial port is useful during the initial boot. It is used when problems arise in EBOOT, since the Ethernet connection is not yet established to Platform builder to send messages to. Once EBOOT has loaded the operating system and jumped to it, the operating system will use the established Ethernet connection to send its messages to the IDE.
Some of the messages from the operating system are displayed as errors or failures but are really just informational messages about the progress of the boot. It would be nice if the developers at Microsoft had a consistent set of rules on the format and content of these messages. (Sort of a style guideline for RETAIL and DEBUG messages.) Unfortunately, that doesn't exist, and we are left with a lot of messages that at first appear to be errors.
This is rather frustrating for developers new to Windows CE .NET when their systems don't boot completely. These messages could lead you off on a tangent for a while. The most common errors in bringing up a system are Memory configuration, NIC type selection, or unsupported NIC. (Interrupt conflicts with a NIC card for debugging.) So let's look at the output of a normal debug build and see some of those normal and harmless, but rather alarming to the uninitiated, messages.
0x81fff030: Did not find emulation code for x86... using floating point hardware.
This occurs on the x86, as there are some versions of the i486 architecture that do not include the floating-point co-processor. The system will check for the presence of the FPEMUL library. (You can specify that your BSP uses one of these CPUs by setting BSP_FPEMUL=1.) All code on an x86 is written assuming the presence of the co-processor. In a case where there isn't one, the instructions cause a trap in the kernel, which then calls the emulation library to implement the floating-point calculations. This message simply informs you that the kernel did not find the emulation library and therefore is using the hardware co-processor. If your CPU doesn't have the co-processor, this would be an important message to look for if your fonts are not showing up in the Microsoft® Internet Explorer shell (or other applications).
0x81ff3800: >>> Loading module filesys.exe at address 0x04010000- 0x0406B000 0x81ff3800: FileSystem Starting - starting with clean file system 0x81ff3800: Initobj : Error, continuing (1)... 0x81ff3800: Initobj : Error, continuing (1)...
Despite the "Error" in the message, this is perfectly normal and benign. The error condition is handled internally in FileSys.exe. It is really just a developer message that could benefit from a standard for writing messages, since it's not an error in the system as a whole, but at a method-call level message. Ideally, the FileSys would indicate it was dealing with the error and how it is doing so. Either way, you can safely ignore this. (Unless you get large quantities of them. In Windows CE versions prior to Windows CE .NET [V4.00] you would see a lot of these in a normal cold boot, but you shouldn't in the current version.)
0x81ff3800: FSREG: Logging in default user. 0x81ff3800: SetCurrentUser: Logging out (nobody), logging in default 0x81ff3800: FS: Using default path "\profiles\" 0x81ff3800: SetCurrentUser: Hives not supported -- using same registry for all users
This isn't an error, and indicates that the HIVE registry support is not included in the build, so that all users of the system will share the same registry settings. With the HIVE based registry, it is possible to log on different users to get different registry settings for each one.
0x81ff3800: FS: Using default path "Windows\" 0x81ff3800: FS: Using default path "Windows\" 0x81ff3800: FS: HKLM\System\Kernel "SystemPatchModule" != 1, not starting SystemPatchModule.exe.
This is a normal message. Microsoft provides a generic patching utility that you can place in the file system and set the registry DWORD value, "SystemPatchModule," to 1 under the HKEY_LOCAL_MACHINE\System\Kernel key. This will tell the file system to load the program SystemPatch.exe and then reboot when it exits. SystemPatch.exe is primarily a way to patch the registry of a system at boot time and then generate a reboot. However, since it is easy enough to just alter the registry and generate a reboot as part of any application, this particular "hook" is rarely used.
Okay, you understand the messages and the process of the boot better now. So just to make your head spin, we'll add a little twist. Boot loaders aren't required in Windows CE at all! They do make development a whole lot easier, but the operating system does not require one. (Unlike Windows 9x, which needs DOS as the boot loader, and even Windows XP, which still relies on the BIOS to manage Init and boot.)
This is an important feature for devices that want the fastest boot time and also desire a fully custom look, right from the boot. For instance, you can add code to OEMInit() to set up the display for your device, and copy a bitmap splash screen to the display while booting. Most of the retail Windows CE devices do that. You need to place your operating system image in FLASH or ROM configured to start from the reset vector to do that. Also note, Ethernet is NOT the only option. One of the sample BSPs provides a means for loading the operating system from an IDE drive with a FAT file system on it. Another option is to copy the FLASH/ROM to RAM and execute from RAM, instead of from FLASH or ROM, for better performance. It's really up to your device needs and your imagination...
You appear to have reached the end of the article at about the same time as we have. In later articles, we will take a look at building something using our shiny new CEPC reference platform, and dig into the details of working with real hardware.
Steve Maillet is the Founder and Senior Consultant for Entelechy Consulting. Steve has provided training and has developed Windows CE solutions for clients since 1997, when CE was first introduced. Steve is a frequent contributor to the Microsoft Windows CE development newsgroups. When he's not at his computer burning up the keys, Steve can be found jumping out of airplanes at the nearest drop zone.