Understanding CEPC Boot Sequence in Windows Embedded Compact 7

Microsoft

bloggers

discussions

Understanding CEPC Boot Sequence in Windows Embedded Compact 7

  • Comments 0

Posted By David Campbell
Program Manager

He’s back!  Doug Boling has once again supplied us with a great write-up for those who missed his July webcast.   The topic will be a two-part post.  In the first part, Doug details an overview of the three CEPC boot loaders as well as the boot sequence on a PC - which is key to understanding the Windows Embedded Compact process:

It may come as a surprise that the most popular hardware platform for Windows Embedded Compact 7 (WEC) is the standard PC chassis.  This is also the hardware platform for Windows Embedded Standard (WES), but Compact 7 brings its own unique features.  A properly tuned Compact system can boot faster than WES. Writing drivers is significantly simpler on WEC than on Standard.  And of course, there is the dramatically lower licensing cost.  This isn’t to say that Windows Embedded Standard isn’t a great operating system, it is.  The point is that Compact has a different feature set than Standard and many embedded systems choose Compact over Standard on their embedded PCs.

The generic board support package for a PC is CEPC, short for CE on a PC.  The CEPC Board Support Package (BSP) has been around since Windows CE 3 back in the late 1990’s.  As such it has quite a history and the requisite backward compatibility code.  One of the more interesting components is the CEPC boot loaders. There are multiple CEPC boot loaders provided in WEC 7.  Each has its features and issues and unfortunately it’s easy to confuse the three boot loaders.  In this post, I hope to clear up any confusion and show the features of each loader.

CEPC Boot loaders

The CEPC board support package contains three separate boot loaders that can be used to boot Windows Embedded Compact.  The LoadCEPC boot loader is actually a Microsoft DOS application that loads either a classic Ethernet boot loader or directly loads a WEC image.  The BIOSLoader doesn’t need DOS.  Instead, it uses the Basic Input Output System (BIOS) firmware that is delivered with almost all PCs to access the hardware necessary to boot the operating system.  Finally the WCELDR boot loader, new to Windows Embedded Compact 7, is an improved BIOS loader that has a different feature set than BIOSLoader and a much simplified build method.

The source and binaries for three loaders are each in their own set of directories in the CEPC BSP.  LoadCEPC is located in \WINCE700\platform\CEPC\src\bootloader\dos. This directory contains the source code as well as various other binaries useful for LoadCEPC.

The BIOSLoader is located in \WINCE700\platform\CEPC\src\bootloader\biosloader.  Under this directory you will find source and binary for the various boot sectors as well as for the loader itself.

The WCELDR is located in C:\WINCE700\platform\CEPC\src\boot.  Here you will find the source and binary for this new loader as well as a new tool for installing this loader.

There is also the source code for the classic EBOOT and SBOOT boot loaders.  However, since these boot loaders need to be initially loaded from one of the other three, they are less interesting and I won’t be discussing them in this post.  The key is to realize that each of these boot loaders is different and incompatible at a binary level with the others.  Don’t mix these loaders (especially the BIOSLoader and WCELDR) as they are incompatible. Now, let’s look at each of these loaders.

LoadCEPC

LoadCEPC was the first boot loader provided by Microsoft for booting (then) Windows CE on PC hardware.  It is a DOS based application and therefore, the PC must first boot DOS and then launch LoadCEPC before Windows Embedded Compact can start. Thanks to its simplicity and surprising configurability strategy, LoadCEPC has remained popular for over 15 years.  The configurability is actually derived from configuring the DOS boot sequence to launch LoadCEPC with different command line parameters that configure various features such as image filename, Ethernet configuration and screen resolutions.

LoadCEPC suffers from a few issues though.  To use it, DOS must first be installed on the target system. Microsoft provides a binary image of a boot diskette that can be used with the tool MakeImageDisk.exe located in the directory 7.00\cepb\utilities under your Platform Builder (PB) install directory. On my machine the full path is:

C:\Program Files (x86)\Microsoft Platform Builder\7.00\cepb\utilities.

It’s actually a good idea to keep a bootable DOS diskette or CD-ROM available.  I’ve used mine in the past when I need to explore an older PC.

A consequence of using a DOS based application is that the solution is limited to what DOS supports. For example the version of DOS provided by PB only understands FAT12 and FAT16 formatted disks.  Given the storage today, even a small flash disk can tax a FAT16 formatted volume. 

Also, to configure LoadCEPC, the CONFIG.SYS and AUTOEXEC.BAT files must be edited to allow the multiple launches of LoadCEPC with the different command lines.  For old hands, this may not be a big deal, but frankly the knowledge of how to properly configure the multiboot feature of DOS is somewhat of a lost art.

Finally, while Microsoft does provide the source for LoadCEPC, you will need to use Microsoft Visual C++ 1.52 to compile the application.  Fortunately, Microsoft continues to make this old version of Visual C available to MSDN subscribers.  However coding a DOS application is almost an exercise in technical archeology. You’ll need to dust off those old books by the likes of Ray Duncan to relearn what you need.

So, while LoadCEPC is a handy solution it really isn’t useful in a shipping embedded system.

BIOSLoader

LoadCEPC is useful but from its first introduction embedded developers have not wanted it used on shipping systems. There have been various boot loaders that were written to avoid booting DOS.  Looking back in my old Platform Builder trees, I can find in Windows CE 4, the ROMBoot loader that went directly to the hardware to read a hard disk and load the Windows CE image onto the system.  This loader didn’t even need a BIOS installed on the system.  The tradeoff was that it needed to initialize everything on the motherboard including the “Northbridge” memory controller.  This was a complex loader and needed to be customized for every motherboard due to its “code to the metal” design.

Starting with Windows CE 5, Microsoft introduced the BIOSLoader, a boot loader that used the BIOS interface to make it much more hardware independent.  The BIOSLoader in CE 5 was tucked away in an obscure directory, \wince500\public\common\csp\x86\biosloader. (So obscure, in fact, that when I was prepping for my webcast that is the basis of this blog post I missed it and incorrectly talked about the biosloader being introduced in Windows Embedded CE 6!)  What is interesting is that aside from some reorganizing into a more logical directory structure and some critical bug fixes, the BIOSLoader from CE 5 is pretty much the same code in the Windows Embedded Compact 7 tree located at \wince700\platform\cepc\src\bootloader\biosloader.

The BIOSLoader boots rather quickly since it doesn’t have to wait on DOS starting.  It supports all fat (or File Allocation Table) formats FAT12, FAT16, FAT32 and even ExFAT.  It also can be extensively configured through a text file BOOT.INI located in the root directory of the boot disk.  Below is an edited clip of a BOOT.INI file showing some of the keywords that can be used.

#
# BIOS loader configuation file
#

# Display settings
Video=on
DisplayWidth=640
DisplayHeight=480
# Possible values: 8, 15, 16, 24, 32
DisplayDepth=16

#
# Debug settings
#

# EthIO=0x3f0
# EthIRQ=5
# DbgIP=10.0.0.1

# Primary BIN file name
BinFile=nk.bin

# Alternative image.
# While booting hit the key corresponding to the suffix char (e.g. "1" for
# BinFile1) to boot the alternative image
BinFile1=nkl1.bin

# Secondary BIN file name. Used when BinFile fails.
BakBinFile=eboot.bin

# Boot delay (in seconds) in which to select the alternative image
Delay=0

# Device name root string
DeviceNameRoot=CEPC

# COM Port to pass in BootArgs
#   0 – Suppress, 1 - COM 1, 2 - COM 2, 3 - COM 3, 4 - COM 4
COMPort=1

The BIOSLoader is a popular boot loader on CEPC and even though it has been superseded by the WCELDR in Compact 7, it deserves a bit of discussion on how it works.  But before I can discuss the BIOSLoader flow, it requires a bit of a history lesson on how PCs have always booted from the first IBM PC back in 1981 to today.

PC Boot Basics

All BIOS-based PCs have a similar boot sequence that was first used on the IBM PC three decades ago.  On reset, the x86 processor jumps to its firmware. The firmware configures and optionally tests the basic hardware on the motherboard then attempts to load an operating system from one of the storage devices attached to the PC.  Older PCs had a rigid boot sequence that first looked for a disk in the floppy drive and, if one wasn’t found, looked for a hard disk. These days, the user can configure the drives to be examined and the sequence of the search.  In any case, the BIOS loads the first sector of the storage device. If it is a ‘removable disk’ such as a floppy disk, the first sector contains the “boot sector,” a combination of a structure that shows the structure of the device as well as some code to search for the operating system.  If the disk is larger, or considered a “non-removable disk,” it will contain what is termed the “master boot record.”  In either case, the BIOS loads the sector at the real mode address 0:7c00.  If the last two bytes in the sector are 0xAAFF, the BIOS jumps to the first byte in the boot sector.

The Partition Table (Master Boot Record)

Both FAT boot sectors and bootable Master Boot Records (MBR) contain executable code.  The difference is their function. The job of an MBR is to partition the disk into separate volumes. This is done with a table, called the Partition Table, at the end of the sector.  There are four entries in the partition table. Each entry looks like the following:

typedef struct _PARTENTRY {
        BYTE            Part_BootInd;           // If 80h means this is boot partition
        BYTE            Part_FirstHead;         // Partition starting head based 0
        BYTE            Part_FirstSector;       // Partition starting sector based 1
        BYTE            Part_FirstTrack;        // Partition starting track based 0
        BYTE            Part_FileSystem;        // Partition type signature field
        BYTE            Part_LastHead;          // Partition ending head based 0
        BYTE            Part_LastSector;        // Partition ending sector based 1
        BYTE            Part_LastTrack;         // Partition ending track based 0
        DWORD           Part_StartSector;       // Physical starting sector based 0
        DWORD           Part_TotalSectors;      // Total physical sectors in partition
} PARTENTRY;

The job of the code in the MBR is to first relocate itself at 0:7A00 and then to examine the partition table, find the “Active Partition” and load that partition’s boot sector at the recently vacated bytes at address 0:7c00. The Active Partition is the entry with a 0x80 in the Part_BootInd field of the partition table entry.  Only one partition can be marked active.

The MBR code doesn’t care about the format of the volume it is loading, only that there is a valid boot sector (marked by the 0xAA55) flag in that sector. The volume boot sector then executes as if there was no MBR.  Actually, the MBR does pass the location of the active partition table entry for boot sectors that are interested.

Desktop limitations on The Partition Table

The partition table can contain up to four entries, theoretically giving a maximum of four partitions on a disk.  However, since the early days of disk partitioning, DOS and later Windows, had the concept of a Primary Partition and an Extended Partition.  In fact Windows doesn’t recognize more than two partitions in the master boot record.  The Primary partition can contain an operating system image and the Extended Partition can be subdivided again into a second set of Primary and Extended partitions.  This sub-partitioning can continue for a practically infinite number of partitions with the primary partition in each extended partition recognized as data volumes.

Windows CE and Windows Embedded Compact can and do understand more than 2 partitions in an MBR and this can easily become a way to create an incompatible disk that can contain partitions recognized by Windows Embedded Compact but not seen by the desktop versions of Windows.  If you are creating a partitioned disk that must also be read by the desktop version of Windows, or Windows Embedded Standard, be sure to follow the Primary/Extended partition scheme required by those operating systems.

The Boot Sector

The boot sector for a bootable volume contains limited space (512 bytes) to do anything complex.  Because of this, boot sector code is pretty simple.  Each boot sector is written specifically for its file system format. Boot sectors for FAT12/16 volumes are different from FAT32 and ExFat volumes.  NTFS boot sectors again are specific to that format.  Regardless of the file system, the goal is the same: find sectors in the volume that contain the operating system boot code, load that code into memory and jump to it.  Since Windows Embedded Compact only understands FAT formatted volumes, I’ll limit my discussion to those boot sectors.

FAT boot sectors start with a structure called the BIOS Parameter Block.  The BPB describes the structure of the volume providing information such as the number of FAT tables, the number of sectors in each cluster and, given its basis in rotating magnetic storage, the number of cylinders, heads and sectors per track for the “disk.”  At the beginning of the BPB is a three byte field that contains x86 opcodes to jump past the BPB to the remainder of the boot sector code.  I’m not going to dive into the structure of the BPB as such a discussion could take pages.  The BPB is steeped in backward compatibility “gotchas” spanning dozens of Microsoft and non-Microsoft operating systems over 30 years.  This isn’t all that surprising given that the FAT file system has become the intergalactic standard for data storage. For those interested, Wikipedia has a fairly good discussion of the BPB

FAT File System

The FAT file system has a fairly well known structure than needs to be understood to appreciate how the boot sector finds the operating system.  The diagram below shows the organization of a storage volume formatted with FAT.

The boot sector is followed by a number of reserved/hidden sectors.  Beyond those sectors is a table called the FAT.  Typically there are two FATs to provide some redundancy for this critical information. The FAT is divided into 12, 16 or 32 bit entries which provides the naming basis for FAT12, FAT16, and FAT32. For FAT32 the top nibble (4 bits) of the FAT entry are ignored.

Each entry in the FAT table directly corresponds to a “cluster” of data in the data section of the volume. A cluster is some number of sectors of data.  If a FAT entry contains zero, its corresponding cluster is free and contains no valid data. If it contains a number greater than 1 and less than or equal to 0xfef/0xffef/0x?ffffef for FAT12/16/32, the cluster contains file data.  The number in the entry points to the next FAT table entry for that file.  The first entry is pointed to by the directory entry for that file. Thus the cluster number in directory entry is the first cluster for the file, the FAT table entry for that cluster either contains the number for the next FAT entry or if that is the last cluster, the FAT entry contains 0xfff/0xffff/0x0x?ffffffff for FAT12/FAT16/FAT32 respectively.  Bad clusters are marked with 0xff7/0xfff7/ox?ffffff7.

Files are located on a FAT disk by the directory structure.  There is always a root directory that lists the files in the root.  There is a slightly different algorithm for locating the root directory on FAT32 disks than FAT12/16 but it is generally it is located beyond the dual FATs.

The root directory is a table of 32 byte entries.  On FAT12 and FAT16, the size of the root directory is fixed when the disk is formatted.  FAT32 handles it a bit differently.  The following is the structure taken from the boot loader.  Note that the definitions for the fields are accurate for modern, Microsoft implementations of FAT not necessarily other older formats or non-Microsoft operating system implementations.  Here again, backward compatibility to cover 30 years of ‘progress’ is the issue. The firstClusterHi field is only valid on FAT32.

typedef struct DirEntry_t {
    char     fileName[8];                           // 00
    char     fileExt[3];                            // 08
    uint8_t  attrib;                                // 0B
    uint8_t  reserved1;                             // 0C
    uint8_t  createTimeFine;                        // 0D
    uint16_t createTime;                            // 0E
    uint16_t createDate;                            // 10
    uint16_t accessData;                            // 12
    uint16_t firstClusterHi;                        // 14
    uint16_t modifyTime;                            // 16
    uint16_t modifyDate;                            // 18
    uint16_t firstCluster;                          // 1A
    uint32_t fileSize;                              // 1C
} DirEntry_t;

The first 11 (non-zero terminated) characters in the structure are the file name and extension.  The size of these fields gives us the classic 8.3 naming limitation for DOS and classic FAT volumes.  I’m going into the details of how long file names are implemented with this structure as all the boot loaders in the CEPC BSP only need to know the 8.3 format.

That’s an overview of the PC boot requirements and sequence.  It’s great information to know even beyond booting a Windows Embedded Compact image.  At this point, my monitors at Microsoft have cut me off due to the length.  (It’s difficult to get an old PC hand to stop talking about this low level stuff, but the remainder of this blog post will have to wait until the next installment.)  Next time we’ll dive into the sequence of the BIOSLoader, discuss a new Windows Embedded Compact boot loader called the WCELDR and talk about how to customize the boot loader for your specific system.

Thanks again Doug for sharing your expertise with our audience.

Upcoming Webcast

Be sure to visit Doug’s website at www.bolingconsulting.com.  I would also point out that Doug has another webcast scheduled for August, here are the details: 

When: Tuesday Aug 21, 2012 - 9:00 AM Pacific Time

Title: Optimizing Windows Embedded Compact 7 on x86 Systems

Overview: The Windows Embedded Compact 7 Board Support Package for x86 systems appears to be disturbingly sparse in its code. In fact, there is a massive amount of code, it’s just hidden in the BSPCommon directory. This webcast will discuss the hidden features of the x86 BSP as well as other sources for BSP code for x86 systems.  Learn how to customize your x86 BSP in this code-filled webcast.

Registration link (includes link to previous recordings): http://www.microsoft.com/windowsembedded/en-us/develop/windows-embedded-compact-7-developer-classroom.aspx

I’m super grateful to Doug for these in-depth articles and both Doug and I would love to get feedback on the articles posted. Are they too long, are they the wrong topics, too much or too little info to support the topic?  Please do let Doug or I know. 

blog comments powered by Disqus