Microsoft Windows CE 3.0 Technical Articles  

Boot Loader Models for Microsoft Windows CE Platform Builder 3.0

This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

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 Guideor Building a CEPCin 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.

    .486p =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 ENDM

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

    OpSizePrefix MACRO db 66h ENDM

    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 GDTfor 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.


    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,

    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

    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 SC400MMSInit:

    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

    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

    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 + 19:16 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, 3:0=exe,e,w,a 007F CF db
    11001111b ; Bits 7:6 = G,DB, bits 5:4 = n/a, bits 3:0=Segment limit
    + 19:16 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

    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

    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

    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

    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.

    OpSizePrefix 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 00000000 CODE32 SEGMENT PARA PUBLIC USE32
    'CODE32' 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

    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.