Boot Loader Models for Microsoft Windows CE Platform Builder 3.0

Windows CE 3.0

Brett Muzzey
Microsoft Corporation

January 2001

Summary: This paper describes CEPC boot loader models, such as Loadcepc.exe and alternative loaders, and contains code for a sample boot loader for use with Microsoft Windows CE Platform Builder 3.0. (19 printed pages).


Disk Resident
BIOS Extension
ROM Boot Loader
Sample Boot Loader
Alternate graphics configurations
Define a temporary stack
Define general structures
Begin 16-bit code segment
Enable DRAM
Create a memory map and configure chip selects
Initialize CSC registers
Configure ISA bus and external system configurations
Set up I/O devices
Define a flash-based GDT
Begin 16-bit executable code
Begin startup
Initialize the graphics adapter
Configure clocks
Initialize graphics
Load the GDTR
Configure drivers
Set up data selectors and stack pointer
Load CEPC parameters
Jump to entry point in the Windows CE kernel
For More Information


A boot loader resides on the target device and manages the boot process. You can also use the boot loader to download code, such as a Microsoft® Windows® CE operating system (OS) image, from the development workstation to the target device. Once the OS is loaded, you can use the boot loader to monitor and debug the target device. Because the boot loader is used only for development, you do not need to include it with your Windows CE platform.

A CEPC enables you to develop Windows CE–based applications and device drivers on, providing a readily available platform to test and evaluate the features of the Windows CE OS. Microsoft Windows CE Platform Builder 3.0 includes a fully operational board support package (BSP) for a CEPC so that you can build test platforms for a CEPC without having to develop an OEM adaptation layer (OAL) or BSP from scratch.

Because CEPC is a generic hardware specification, not a particular hardware platform, there is no way to write a single boot loader that can bring up every possible CEPC. An ISA Ethernet or a PCMCIA Ethernet card would each require changes to the boot loader.

Platform Builder 3.0 includes Loadcepc.exe, an MS–DOS–based boot loader that allows you to install a generic Windows CE–based image on any desktop computer. Loadcepc.exe allows for easy image bring-up, but it relies on an MS-DOS boot floppy and basic input/output system (BIOS). Loadcepc.exe is only one boot loader method; Loadcepc.exe is not the only boot loader model, and a boot loader need not be tied to MS-DOS.

You can use any of the following boot loader models to develop a boot loader for a CEPC.

Boot loader Description
Loadcepc.exe Relies on system BIOS and MS-DOS
Disk Resident Eboot.bin is physically stored on disk
BIOS Extension Boot loader is placed as a BIOS extension into a network PROM socket
Flashable ROM Boot loader is placed directly in ROM, replacing system BIOS

Also included is sample code for a boot loader written for an AMD ElanSC400 board.


Use the Loadcepc.exe model to create a boot loader that is targeted at supporting the broadest range of computer platforms. It is typically used in a development environment, as it is flexible and easily accepts parameters for display resolution, Ethernet and serial port debugging, and so on. The Loadcepc.exe loader that includes Eboot.bin, used to perform Ethernet downloads, is dependent upon an MS–DOS boot disk floppy and two BIOS features: system BIOS and Video Electronics Standard Association (VESA) BIOS. Loadcepc.exe relies on the system BIOS to handle chip set configuration and bus enumeration and configuration. In cases where native video driver support is not available—Windows CE supports many different native drivers—it uses the VESA BIOS to set the video mode.

Loadcepc.exe only uses the CEPC to load an image; Windows CE is in no way dependent upon MS–DOS.

See the Getting Started Guide or Building a CEPC in Platform Builder help for specifics and step-by-step instructions on using the Loadcepc.exe model.

Disk Resident

One alternative to using the Loadcepc.exe model with an MS–DOS boot floppy is to store the boot loader image on disk as a system file and allowing the existing BIOS to load it. This lets you quickly boot an image, but loses the command-line configuration available in Loadcepc.exe; however, you could introduce a configuration file, stored on the media, and read by the loader at boot time. This model also requires a large disk volume if you want to store the CE–based image on disk.

BIOS Extension

Another boot loader model is a BIOS extension, which can be used if you want to avoid running MS–DOS but are willing to rely on the BIOS for chip-set configuration. You place your boot loader in a BIOS extension that plugs into a network boot programmable ROM (PROM) socket or is available in some other fashion to being decoded or detected in the BIOS extension address range. No hard or floppy disk is required, but you may need to have a PROM programmer to create this boot ROM. With this mode, there are no Loadcepc.exe parameters available at boot time.

This model would typically be used in a setting where the Windows CE–based devices are clients on a host network and could rely on a server for boot image at all times. It is simpler than the Flashable ROM model since the computer BIOS has done much of the chip-set configuration prior to invoking the BIOS extension.

ROM Boot Loader

An additional boot loader model is a ROM boot loader where you place a boot loader directly in ROM and replace the standard computer BIOS. This is a chip set-specific model and is also the most complex alternate model to Loadcepc.exe. The loader must initialize low level RAM, northbridge, southbridge, PCI bus enumeration, VESA video BIOS configuration, and so on.

This model has a similar implementation to the BIOS extension model, but would only be used in a homogeneous environment since each new board or chip set would require a different boot loader. This is the primary loader model used by non-x86 platforms.

Sample Boot Loader

This sample boot loader for Windows CE has been written for an AMD ElanSC400 evaluation board. It loads Windows CE without requiring MS–DOS or the Loadcepc.exe utility. This section presents sections of a sample loader implementation, organized into logical steps that are described in brief detail.

Since this sample boot loader seeks to replace MS–DOS and Loadcepc.exe, it must emulate the required aspects of these components. Some of the drivers in the CEPC environment take parameters from Loadcepc.exe. These parameters are normally passed to Loadcepc.exe through the MS–DOS command line, and are then made available to the drivers by a pointer to a reserved global memory area. See the LOADRBUF reserved area in %_WINCEROOT%\PLATFORM\CEPC\FILES\CONFIG.BIB.

This sample boot loader defines the parameters and sets a pointer to the parameter buffer before transferring control to Windows CE.

Alternate graphics configurations

This boot loader is set up to use either an ISA-based graphics adapter or a custom VESA local bus graphics adapter. The boot loader automatically detects which graphics adapter is installed and configures the hardware accordingly.

The ISA graphics adapter uses the video BIOS to set up the mode before passing control to Windows CE. No video BIOS is present or required for some VESA bus devices, for example, the IGS 2010 card, since the IGS video driver handles the device configuration.

The sample boot loader defines memory based on the physical devices available, configures the ISA bus and I/O devices, initializes the graphics mode, delivers run parameters to the CEPC, and passes control to the Windows CE kernel.

The following steps are required.

  1. Define a temporary stack
  2. Define general structures
  3. Begin 16-bit code segment
  4. Enable DRAM
  5. Create a memory map and configure chip selects
  6. Initialize CSC registers
  7. Configure ISA bus and external system configurations
  8. Set up I/O devices
  9. Define a flash-based GDT
  10. Begin 16-bit executable code
  11. Begin startup
  12. Initialize the graphics adapter
  13. Configure clocks
  14. Initialize graphics
  15. Load the GDTR
  16. Configure drivers
  17. Set up data selectors and stack pointer
  18. Load CEPC parameters
  19. Jump to entry point in the Windows CE kernel

Define a temporary stack

Define the temp stack, as it needs to be in place when it receives control. Windows CE will set up its own stack when it gets control, but not immediately.

 =00FFFFFC TopOfStack = 00FFFFFCh ; ESP goes at top of 16 MB DRAM
 =001FFFFC ParamBlockPtr = 001FFFFCh ; Must match LOADRBUF in Config.bib

The AbsCall macro forces a far call to a particular fixed segment or offset.

AbsCall MACRO SegValue,OfsValue
        db  09Ah  ; Far call
        dw  OfsValue,SegValue

The OpSizePrefix macro makes it easier to add 66h prefixes to instructions.

OpSizePrefix MACRO
             db    66h

Define general structures

Create a user-defined data type for an interrupt descriptor. In a similar fashion, the Global Descriptor Table (GDT) would be defined, see Define a flash-based GDT for more information.

 00000000 idesc STRUC
 00000000 01*(0000) off_15_0 DW 0
 00000002 01*(0000) sel DW 0
 00000004 01*(00) DB 0
 00000005 01*(86) dpl DB 10000110b
 00000006 01*(0000) off_31_16 DW 0
 00000008  idesc ENDS

Begin 16-bit code segment

At reset, the x86 processor will be executing in real mode, for example 16-bit segmented mode. The initial boot loader code will need to be assembled for this environment. An alternative is to use a 32-bit compiler/assembler and use operand and address prefixes to hand code the initial loader instructions.

  assume cs:CODE

Enable DRAM

Enable two banks of 32-bit dynamic RAM (DRAM).

This is the standard memory configuration shipped with the SC400 evaluation board starts at 0 and goes as high as 16 MB. The loader could choose to dynamically size DRAM or could assume a size at build time. The SDRAM controller for the platform then gets programmed with the memory limit, bank size, and page size information.

  0000 SC400RegInit:
  0000 AB00 dw 0AB00h
  0002 AB01 dw 0AB01h
  0004 0004 dw 0004h ; Max out DRAM timings. May change if using slower DRAM.
  0006 4005 dw 4005h ; Enable refresh, use 32 kHz osc for refresh

Create a memory map and configure chip selects

Create the memory map so that the ROMCS0 will point to the boot loader in the 128 KB dip socket. ROMCS1 and 2 are used to hold the CE–based image. Since the memory map will have 32 MB of DRAM, and 8 MB of flash memory, not counting the 128 KB just below 1 MB, the memory map will be set up as follows:

; FFFF0000 - FFFFFFFF  ; used only by far jump to boot loader below 1 MB
; 00280000 - FFFEFFFF  ; unused by anything
; 00240000 - 027FFFFF  ; 4 MB accessed via MMSF which generates ROMCS2
; 00200000 - 023FFFFF  ; 4 MB accessed via MMSE which generates ROMCS1
; 01000000 - 01FFFFFF  ; Space for 16 MB more of system DRAM
; 00100000 - 00FFFFFF  ; 15 MB system DRAM for Windows CE
; 000F0000 - 000FFFFF  ; boot loader code and data (ROMCS0)
; 000D0000 - 000EFFFF  ; unused by anything
; 000C0000 - 000CFFFF  ; reserved for graphics adapter ROM
; 000B0000 - 000BFFFF  ; unused by anything
; 000A0000 - 000AFFFF  ; graphics buffer
; 00000000 - 0009FFFF  ; System RAM used only by boot loader
  0008 9031 dw 9031h ; Point MMSE->ROMCS1, and MMSF>ROMCS2
  000A 0FB1 dw 0FB1h ; Force routing of CS2 to GPIO_CS0
  000C 02A6 dw 02A6h ; GPIO_CS0 low to support ROMCS2, CS1 = high
  000E 05A0 dw 05A0h ; GPIO_CS0, GPIO_CS1=outputs 

The following code documents the number of wait states for the physical flash device. You should configure the number of wait states required by your specific flash memory device.

  0010 0226 dw 0226h ; 2 wait states for ROMCS1 accesses--supports 90 ns flash memory
  0012 0228 dw 0228h ; 2 wait states for ROMCS2 accesses --supports 90 ns flash memory
  0014 1425 dw 1425h ; Configure romcs1 for fast speed, 16-bit application ROM interface
  0016 1427 dw 1427h ; Configure romcs2 for fast speec, 16-bit application ROM interface
  0018 C030 dw 0C030h ; Enable caching for MMSE and MMS F
  001A 00F1 dw 00F1h ; Force standard PCMCIA mode so MMS C-F are available
  001C 02D0 dw 02D0h ; Enable PCMCIA controller--required for 3e0/3e1 access for mms

Initialize CSC registers

Set the processor to 100 megahertz (MHz).

  001E 0580 dw 0580h ; CPU clk:hyper = 100 MHz, high = 33 MHz, low = 8 MHz
  0020 4140 dw 4140h ; Enable hyper speed mode

Configure ISA bus and external system configurations

Set up the bus and external systems.

  0022 5F38 dw 5F38h ; Select ISA IOCS16,iochrdy,PIRQ1,PIRQ0&AEN signals Vs. GPIOs
  0024 1439 dw 1439h ; select ISA signals vs. kbd rows, enable LBL2
  0026 08C1 dw 08C1h ; Enable external keyboard I/F
  0028 01D1 dw 01D1h ; Enable SC400 internal UART at 3f8
  002A 40D8 dw 40D8h ; Make SC400 internal UART use IRQ4
  002C 1ED4 dw 1ED4h ; Route pirq0->IRQ14 (IDE support) and pirq1->IRQ1 (keyboard support)
  002E 0CD5 dw 0CD5h ; Route pirq2->IRQ12--required for PS/2 mouse support
  0030 03D6 dw 03D6h ; Route pirq4->IRQ3 (PCNET ISA network card support)
  0032 01E5 dw 01E5h ; Enable proper termination for all configurations above

Set up MMSE (PCMCIA slot B window 3) to start at 32 MB for 4 MB

  0034 0068 dw  0068h
  0036 2069 dw  2069h
  0038 FF6A dw 0FF6Ah
  003A 236B dw  236Bh
  003C 006C dw  006Ch
  003E 206D dw  206Dh

Set up MMSF to start at 36 MB for 4 MB

  0040 0070 dw  0070h
  0042 2471 dw  2471h
  0044 FF72 dw 0FF72h
  0046 2773 dw  2773h
  0048 0074 dw  0074h
  004A 1C75 dw  1C75h

Enable MMS windows E, and F only.

  004C 1846 dw  1846h
  =000D  SC400MMSTableLen = ($ - SC400MMSInit) / 2

Set up I/O devices

Set up the ElanSC400 evaluation board I/O device initialization constants.

  004E  SuperIO_Reg_Initial_Values:
  004E 00 FF 4A  db 000h, 11111111b, 01001010b ; Enable UART, FDC, IDE
  0051 01 CC 0C  db 001h, 11001100b, 00001100b ; Set UART 1 to base 2E8
  0054 05 FF 05  db 005h, 11111111b, 00000101b ; Enable keyboard, disable RTC
  0057 0A FF 80  db 00Ah, 11111111b, 80h ; CS 0 address low
  005A 10 FF 06  db 010h, 11111111b, 06h ; CS 0 address high
  005D 0B B8 90  db 00Bh, 10111000b, 90h ; CS 0 enable
  0060 0C FF 80  db 00Ch, 11111111b, 80h ; CS 1 address low
  0063 11 FF 00  db 011h, 11111111b, 00h ; CS 1 address high
  0066 0D 38 90  db 00Dh, 00111000b, 90h ; CS 1 enable
  =0009  Num_SuperIO_Initial_Values = ($ - SuperIO_Reg_Initial_Values) / 3

Define a flash-based GDT

Define a flash-based GDT as this is a ROM–based GDT containing three descriptors. The first is the same for all GDTs and is called the null descriptor. It is there to allow the OS to invalidate a selector without causing a general protection (GP) fault. If anyone tries to use a selector that is loaded with the null descriptor, a GP fault will occur.

The other two selectors provide a flat 32 GB address space. This means that the segment will have a starting address of 0, and the 32-bit EIP, etc. will be the linear address. Although the selectors are being used by the hardware for address calculation, they are not relevant. One of the descriptors is set up to support the code segment, and must be loaded into CS. The other is set up for data segments, and may be loaded into DS-GS. X86 architecture requires separate descriptors for CS than for DS-GS because the protection mechanism does not allow writing to CS or executing code from DS-GS.

  0069  CE_GDT:  ; start of descriptor table
  =0000  GDT_NULL_SLCTR = ($-CE_GDT) ; null descriptor
  0069 0000 dw 0000h ; Segment limit 15:0
  006B 00 00 00  db 00h, 00h, 00h ; Segment base 23:0
  006E 00 db 00h ; Segment control bits - bits 3:0 = exe,e/c,w/r,a
  006F 00 db 00h ; Bits 7:6 = G,DB, bits 5:4 = n/a, bits 3:0=Segment limit +
  0070 00 db 00h ; Segment base 31:24
  =0008  GDT_CODE_SLCTR = ($-CE_GDT) ; Code segment descriptor; 
      Executable segment starts at 0 + and is 4 GB long.
  0071 FFFF dw 0FFFFh ; Segment limit 15:0
  0073 00 00 00  db 00h, 00h, 00h ; Segment base 23:0
  0076 9E db 10011110b ; Segment control bits: 7=P, 6:5=DPL, 4=DT, 3:0=exe,c,r,a
  0077 CF db 11001111b ; Bits 7:6 = G,DB, bits 5:4 = n/a, bits 3:0=Segment limit +
  =0010  GDT_DATA_SLCTR = ($-CE_GDT) ; Data segment descriptor; DS-ES 
      segments start at 0 and are 4 GB long.
  0079 FFFF dw 0FFFFh ; Segment limit 15:0
  007B 00 00 00  db 00h, 00h, 00h ; Segment base 23:0
  007E 92 db 10010010b ; Segment control bits: 7=P, 6:5=DPL, 4=DT, 
  007F CF db 11001111b ; Bits 7:6 = G,DB, bits 5:4 = n/a, bits 3:0=Segment limit +
  0080 00 db 00h ; Segment base 31:24

Begin 16-bit executable code

Set up the video BIOS extension to allow it to set up its own int 10h handler, you need a dummy extension in place. The video BIOS extension makes an int 10h call to disable the display-a standard computer BIOS would normally have a simple routine set up for int 10h by this time. Returning AX = 0 tells the video BIOS that the int 10h function is not supported by the system BIOS.

  PUBLIC InitialInt10hHandler
  0081  InitialInt10hHandler PROC
  0081 B8 0000  mov ax,0 ; Indicate non-handled function.
  0084 CF IRET
  0085  InitialInt10hHandler ENDP
The SC400 PMU only changes modes on edges of the 32 kHz clock.
  0085  Wait2Falling32KhzClkEdges PROC
  0085 B0 82 mov al,82h
  0087 E6 22 out 22h,al
  0089 WaitForFirstDrop:
  0089 E4 23 in al, 23h
  008B A8 08 test al, 8
  008D 75 FA jnz WaitForFirstDrop
  008F WaitForFirstRise:
  008F E4 23 in al, 23h
  0093 74 FA jz WaitForFirstRise
  0095 WaitFor2ndDrop:
  0095 E4 23 in al, 23h
  0097 A8 08 test al, 8
  0099 75 FA jnz WaitFor2ndDrop
  009B C3 ret
  009C  Wait2Falling32KhzClkEdges ENDP

Begin startup

Pass control directly through a FAR jump by the X86 reset vector hook in the boot loader. The sample code completes minimal chip initialization, transitions into protect mode, and then passes control to the CE OS which must be set up to reside at 3 MB (02000000h) by an entry in the Windows CE .bib file.

  009C  Start Up: 

Initialize the graphics adapter

Initialize the supported SC400, SuperIO, ISA or VESA graphics adapter. The sample code carries out basic SC400 initialization, and then enables the graphics adapter by leveraging its BIOS extension ROM. At this point, a temporary stack is needed.

  009C B8 9000   mov ax, 09000h
  009F 8E D0     mov ss, ax
  00A1 B8 FFFE   mov ax, 0FFFEh
  00A4 8B E0     mov sp, ax

Get addressability to the ROM–based constants.

  00A6 8C C8     mov ax, cs
  00A8 8E D8     mov ds, ax

The following code carries out basic initialization for the ElanSC400.

  00AA BE 0000r  mov si, offset SC400RegInit
  00AD B9 001A   mov cx, SC400RegTableLen
  00B0 BA 0022   mov dx, 22h ; The SC400 CSC index reg
  00B3 F3> 6F    rep outsw ; Blast out the inits

At this point DRAM is enabled.

  00B5 BE 0034r  mov si, offset SC400MMSInit
  00B8 B9 000D   mov cx, SC400MMSTableLen
  00BB BA 03E0   mov dx, 3E0h ; The SC400 CSC index reg
  00BE F3> 6F    rep outsw ; Blast out the inits
  00C0 BA 0398   mov dx,398h  
   ;Superio index register on the ElanSC400 evaluation board

For the SC400, the first two reads of the index register after POR give the ID mechanism, 88H followed by 0H.

  00C3 EC        in al,dx
  00C4 EC        in al,dx
  00C5 BE 004Er  mov si, offset SuperIO_Reg_Initial_Values
  00C8 B9 0009   mov cx, Num_SuperIO_Initial_Values
  00CB Output_Super:
  00CB 2E: 8B 04 mov ax, cs:[si] ; get index into '306's indexed regs
                                  ; and mask to AH
  00CE EE        out dx,al  ; Output index
  00CF 42        inc dx
  00D0 EC        in  al,dx
  00D1 F6 D4     not ah  ; Get save mask
  00D3 22 C4 a   nd  al,ah
  00D5 F6 D4     not ah  ; Get replace mask
  00D7 2E: 22 64 02  and ah,cs:[si+2]
  00DB 83 C6 03  add si,3
  00DE 0A C4     or  al,ah
  00E0 EE        out dx,al  ; Must do twice for SuperIO
  00E1 EE        out dx,al
  00E2 4A        dec dx
  00E3 E2 E6     loop Output_Super

Configure clocks

Set up the real-time clock divide chain as soon as possible, as the real-time clock on the SC400 can take several seconds to stabilize.

  00E5 B0 8A mov al,0Ah + 80h
  00E7 E6 70 out 70h,al
  00E9 E4 71 in al,71h
  00EB 24 8F and al,10001111b ;mask off divider bits
  00ED 0C 20 or al,00100000b ;or in divider enable bit
  00EF E6 71 out 71h,al  ;enable the oscillator

Initialize graphics

There are two options for graphics with this demonstration: you can use an ISA–based graphics adapter which has its video BIOS on board, or you can put an IGS VESA local bus card on the SC400 evaluation board, and remove the ISA graphics adapter from the system. If you use the ISA–based graphics adapter, you will be limited to 320x240 resolution. The following code automatically detects if the VESA card is installed. If so, the VESA bus is enabled. This limits the use of certain SC400 options, so please refer to the SC400 user manual to understand the trade-offs you incur when using the VESA local bus.

Currently, the CE driver for IGS does not initialize the graphics chip. It can change the mode, but nothing else. Thus, leverage the IGS VGA BIOS which is provided free of charge by IGS. Since the IGS card has no option ROM like a normal ISA card would for storing the VGA BIOS, this software component must be blown into the RFA.

An ISA card would decode this at C0000h, so it should be put into the same location when booting from the RFA. However, by default, the C0000 segment is not part of the ROMCS0 decode. Cycles to that address range go to ISA so an ISA VGA card can decode them. Thus, if booting from RFA, be sure to enable the C000 segment for ROMCS0 linear decode.

The ElanSC400 evaluation board routes a few of the SuperIO's GPIOs back to the VESA slot. Normally, these signals are pulled high on the board. The GPIO port for these GPIO signals is located at 78h in the I/O map by default. To determine if the VESA video card is installed, read the GPIO port. If bits 6 and 7 are set, then no card is installed. This is the only way to know whether ISA or VL card is present.

  0106 B3 00 mov bl,  0 ; Will be set to 1 if VESA present
  0108 E4 78 in al, 78h ; Check for VESA bus option card
  010A 24 C0 and al, 0C0h
  010C 3C C0 cmp al, 0C0h
  010E 74 16 je UseISAVideo ; If both bits are set then no VESA

For an IGS card on the VESA bus, no initialization is required. The VESA bus must be enabled.

  0110 B0 14 mov al, 14h ; Enable VL Bus and hold it in reset
  0112 E6 22 out 22h, al
  0114 E4 23 in al, 23h
  0116 0C 18 or al, 18h
  0118 E6 23 out 23h, al
  011A B0 14 mov al,14h  ; Remove the reset from the VESA bus
  011C E6 22 out 22h,al
  011E E4 23 in al,23h
  0120 24 EF and al,0efh
  0122 E6 23 out 23h,al
  0124 EB 1F jmp PastISAGraphicsInit
  0126  UseISAVideo:

Hook int 10h (video) and point it to a dummy handler ready for when the VGA BIOS extension gets control.

  0126 B8 0000  mov ax, 0 ; Get IVT addressability
  0129 8E D8 mov ds, ax

Get 32 bit pointer to dummy interrupt 10h handler in EAX.

  012B B8 0000s  mov ax, seg InitialInt10hHandler
  012E 66| C1 E0 10  shl eax, 16
  0132 B8 0081r  mov ax, offset InitialInt10hHandler

Poke the pointer into the IVT.

  0135 BB 0040  mov bx,10h*4  ; 10h*40 gives int 10h IVT slot
  0138 66| 89 07  mov [bx], eax  ; DS:[40h]= pointer to IHR

Call VGA BIOS extension to install its own int 10h handler

                        AbsCall 0C000h,3  ; call far 0C000h:0003
1  593  013B 9A         db 09Ah  ; Far call
1  594  013C 0003 C000  dw 3,0C000h

For ISA VGA support, the sample code calls the graphics card int 10h handler to set 320x200 8 BPP graphics

  0140 B8 0013          mov ax, 0013h  ; ah=set_mode=0, al=mode=13h
  0143 CD 10            int 10h ; 320x200x8Bpp (mode 13h)
  0145  PastISAGraphicsInit:
  0145 B8 0000s         mov ax,data  ; Get addressability to data
  0148 8E D8            mov ds,ax
 Set up a linear pointer to the GDT. The GDT is in flash.
  014A 66| B8 00000000  mov eax, 0
  0150 B8 0000s         mov ax, code ; In flash, so it is relative to the CODE seg
  0153 66| C1 E0 04     shl eax,4
  0157 66| BB 00000000  mov ebx, 0
  015D BB 0069r         mov bx,offset CE_GDT; Must use bx with 16-bit offset
  0160 66| 03 C3        add eax, ebx ; and then do the seg:offset merge later
  0163 66| A3 0008r     mov PtrToGdt, eax
  0167 B8 0017          mov ax, (3*8) - 1 ; GDT has 3 entries
  016A A3 0006r         mov GDTLimit, ax

Load the GDTR

Initializes the DRAM-based GDTR structure, and also switches the CPU to protected mode.

First, generate a flat pointer to the protected code entry point.

  016D 66| B8 00000000 mov eax, 0
  0173 B8 0000s        mov ax, code32
  0176 66| C1 E0 04    shl eax, 4
  017A 66| 05 00000004r add eax, offset ProtectCodeEntryPoint
  0180 66| A3 0000r    mov PtrToProtModeEntry, eax

Next, poke the selector portion of the pointer with the code descriptor.

  0184 B8 0008         mov ax, 8
  0187 A3 0004r        mov ProtModeEntrySelector, ax

Load the pointer. Use the opsize prefix to get the full 48-bit pointer.

1  638  018A 66        db 66h
  018B 0F 01 16 0006r lgdt GDT_Pointer
  0190 0F 20 C0        mov eax, cr0 ; Get the current CR0
  0193 0C 01 or        al, 1  ; Set the PE bit to enable protected mode
  0195 0F 22 C0        mov cr0, eax ; Go to pmode, but STILL 16 bit ("D" bit=0)
  0198 EB 00           jmp FlushPipeline
  019A FlushPipeline:
  019A 66| FF 2E 0000r jmp fword ptr PtrToProtModeEntry
  019F  CODE ENDS ; End of 16-bit code segment
  assume cs:CODE32

Configure drivers

Configure the drivers at run time. This is part of the boot loader block information that gets passed in reserved memory from the boot loader to the Windows CE OS C declarations in Loadcepc.exe.

 UCHAR ucVideoMode; //
 Upper nibble:
 0xh = Unknown adapter type
 1xh = ATI based graphics adapter
 2xh = S3 Trio64 based graphics adapter
 3xh = Tseng labs based graphics adapter
 4x-fxh = Unknown adapter type
 Lower nibble:
 0  = 320x200 x 8BPP color
 1  = 480x240 color
 2  = 640x480 color
 3-FFh = undefined
 UCHAR ucComPort; //
 UCHAR ucBaudDivisor; //
 UCHAR ucPCIConfigType; //
 PUBLIC ParameterArray
 00000000  ParameterArray:
 00000000 00 db 0 ; parm[0] = video mode (0 = 320x200x8BPP)
 00000001 00 db 0 ; parm[1] = not used (changing the debug com port does not work)
 00000002 01 db 1 ; parm[2] = baud rate divisor (1=115200kbs, 2 = 57600, etc.)
 00000003 00 db 0 ; parm[3] = PCI config (0 = NO PCI, i.e. ISA)
 00000004  ProtectCodeEntryPoint:

Set up data selectors and stack pointer

Setup the minimum possible in terms of data selectors and stack pointers. It then jumps to the boot loader main() function.

All of the following are required.

 00000004 66| B8 0010  mov ax, GDT_DATA_SLCTR
 00000008 8E D8        mov ds, ax
 0000000A 8E C0        mov es, ax
 0000000C 8E D0        mov ss, ax
 0000000E BC 00FFFFFC  mov esp, TopOfStack 

The stack is at the top of DRAM.

Load CEPC parameters

The CEPC environment differs from environments such as the Hitachi D9000 hardware development platform (ODO) board. The Loadcepc.exe utility acts as a boot loader which leverages MS–DOS and BIOS. Since this assembly language boot loader seeks to replace BIOS, MS–DOS, and Loadcepc.exe, it must emulate the required aspects of these components. Some of the drivers in the CEPC environment take parameters from Loadcepc.exe. These parameters are normally passed to Loadcepc.exe by the MS–DOS command line, and are then available to the drivers using a pointer in a reserved global memory area (see the LOADRBUF reserved area in the \WINCE\PLATFORM\CEPC\FILES\CONFIG.BIB file). By default, the 32-bit pointer to the parameter array is at 001FFFFCh. The following code places a pointer to the parameter array that is defined locally in this boot loader.

Compute the segmentation to generate a linear pointer to the parameter block.
 00000013 B8 00000000s  mov eax, CODE32
 00000018 C1 E0 04      shl eax, 4
 0000001B 05 00000000r  add eax, offset ParameterArray
 00000020 A3 001FFFFC   mov [ds:ParamBlockPtr], eax  ; Create ptr to parms

Jump to entry point in the Windows CE kernel

Jump to the kernel entry point by jumping to the offset 0 in the image. There is a jump there to the actual entry point. The starting location of the CE-based image is configured using settings in the CONFIG.BIB file.

 00000025 BE 02000000  mov esi, 02000000h ; first address of ROM space at 32 MB
 0000002A FF E6        jmp esi
 0000002C  CODE32      ENDS ; End of 32-bit code segment
                       END StartUp

For More Information

For more information on Windows CE ROM image data formats, see the Platform Builder help.

The following two documents are of interest because the loader needs to know how to read these two file types and place the code, data, and so on, in the correct location:

  • Windows CE Binary Image Data Format (.bin)
  • Motorola 32-Bit Binary Data Format (.sre)

For general information on Microsoft file systems of interest when loading the OS image from local device storage like a hard disk drive or a Compact Flash/ATA Disk card, see this Microsoft Web Site.

For more information on boot sectors and how they interface with startup code, go to

For general information on creating a boot loader, see the following information:

  • Hardware docs
    • CPU manual
    • Chip set manuals, for example, northbridge or southbridge
    • Peripheral and controller manuals
    • Board-level design manuals
  • BIOS-vendor extension development information
  • IDE specification or BIOS int13h information for IDE storage access
  • FAT file system information, for example, MBR, boot sectors, and so on
  • CE BIN and SRE image format information

For Ethernet download code and supporting functions see the ETHDBG directory located at WINCE300\PUPLIB\COMMOM\OAK\DRIVERS\ETHDBG.