CE6 OAL: What you need to know

Posted by: Sue Loh

This material is drawn from a talk that Travis Hobrla gave at MEDC 2006 (thanks Travis!) and contributed to by the whole Windows CE BSP team.

The driver changes that I have already written about the biggest CE6 differences that OEMs would care about.  Much less significant are the CE6 OAL changes.  The OAL, or OEM Adaptation Layer, is somewhat analogous to a HAL (Hardware Adaptation Layer).  The OAL plus a set of drivers comprise the BSP (Board Support Package), the software that makes the Windows CE OS run on the OEM’s hardware.

One big OAL detail that did not change: the production quality OAL initiative, or PQOAL.  PQOAL is a directory organization, a highly componentized set of libraries you can pick and choose from to compose your OAL.  The following illustration shows how all of the components come together to build a complete OAL which interfaces between the kernel and the hardware.

PQOAL was introduced in CE5, and is optional.  You can create CE5 and CE6 BSPs without using the PQOAL organization.  But it is easier to port a PQOAL BSP from CE5 to CE6.  If you have a non-PQOAL BSP that you want to port to CE6, you may choose whether to port to PQOAL while you are porting to CE6.  Our BSP team recommends adopting PQOAL; their expectation is that you will find the componentized organization easier to maintain and easier to port to new OS versions over time.  If you already have a BSP that uses the CE5 PQOAL organization, you’ll find the directory structure and available libraries to be quite similar in CE6.

So what did change?  In CE6 we split up three components that previously linked together to make the kernel executable, nk.exe.  CE5 the kernel, OAL and the Kernel Independent Transport Layer (KITL) all linked into nk.exe.  In CE6 these are broken into kernel.dll, oal.exe and kitl.dll.

The primary reason for this change was updateability.  In the past, if Microsoft released a kernel update, the OEM would have to take the updated kernel and link it again with their OAL to produce a new nk.exe.  Now the OEM only has to distribute Microsoft’s new kernel.dll.

Another benefit of this change is that it formalizes the interface between the kernel, OAL and KITL.  These components exchange tables of function pointers and variable values to communicate with each other, and cannot invoke functions other than those in the tables.  In CE5 and earlier OS versions, some OEMs found that since the OAL and kernel linked together into the same executable, they could call undocumented kernel APIs.  The problem with this is that Microsoft did not support the APIs being called this way.  Some of them had special cases or calling rules that OEMs would not know about.  Security holes and stability problems were possible.  Supportability was also a risk; kernel hotfixes between releases could potentially break OEM code.

An additional benefit of the kernel / OAL / KITL separation is that each module now has its own debug zones and can be debugged independently.  It is also a step on the way toward a dynamically loadable KITL – that’s not yet possible in CE6, but hopefully will be possible in the future.

So let’s dig further into the details of the separation of these binaries.

In Windows CE 5.0, the BSP directories built three different versions of the kernel exe.

  • OAL + Kernel = kern.exe

  • OAL + Kernel + KITL = kernkitl.exe

  • OAL + Kernel + KITL + Profiler = kernkitlprof.exe 

Maintaining these three different directories could be bothersome, and some OEMs chose only to maintain kern.exe.  This choice meant they could not use KITL for debugging or use the kernel profiler to measure performance bottlenecks.  I cannot emphasize enough how strongly we at Microsoft believe it is worth your time to set up KITL.  It is an up-front investment that will save you much debugging time as you work.

In Windows CE 6, we don’t build multiple versions of the OAL.  The separation of KITL into kitl.dll gets rid of the distinction between kern.exe and kernkitl.exe.  And we now recommend that OEMs always build profiling support into their OAL, getting rid of the need for separate kernkitl.exe and kernkitlprof.exe.  As a result, the platform directory only needs to build one executable: oal.exe.

A side note about profiling from an observer who is definitely not impartial.  🙂  Profiling support is not actually required, unless you want to use the kernel profiler.  But the required code to implement profiling is small, and won’t impact OS performance as long as the profiler is not actually running.  I believe the benefits of the profiler justify the small amount of work needed to set it up.  You could look at our sample BSPs to see how they implement profiling, or you could look at the previous blog post I wrote for an explanation of a simple profiling implementation.

We tried to simplify the CE6 OAL modularization as much as possible, to ease porting of CE5 OALs to CE6.  Each module builds a table of function pointers for use by the other modules.  The kernel exports NKGLOBAL (See the CE6 %_WINCEROOT%\public\common\oak\inc\nkglobal.h).  This table is too large to reproduce meaningfully here, but there are function pointers for things like debug output, interrupt hooking, synchronization objects, virtual memory operations, registry access, string operations, and other kernel interfaces.  There are also shared global variables passed via the NKGLOBAL table.

But OEMs don’t need to completely revise their OAL code to call kernel functions using these pointers.  We hid the existence of the kernel and KITL function pointer tables inside a library of wrapper functions that the OAL can use (nkstub.lib), so that exactly the same set of functions are available to the OAL as in the past.  For example, to use a critical section, the OAL doesn’t need to call the function table entry pNKGlobal->pfnEnterCS().  Instead, nkstub.lib has a wrapper function EnterCriticalSection() for the OAL to call as it did in the past:


void WINAPI EnterCriticalSection (LPCRITICAL_SECTION lpcs)


    g_pNKGlobal->pfnEnterCS (lpcs);


This library of wrapper functions should make it easier to port OAL code to CE6.  All you have to do is link nkstub.lib into the OAL in order to call the kernel APIs.

Similarly, the OAL exports an OEMGLOBAL table (%_WINCEROOT%\public\common\oak\inc\oemglobal.h) with OAL functions and global variables.  Many of the functions in this table are required; the OS won’t work unless the OEM assigns the function pointers.  Others are optional; the OAL can pass NULL pointers and the OS would continue to work.  Required exports will be assigned to OEMGLOBAL by oemmain.lib (explained below), while you will need to assign optional exports inside your OEMInit routine.  For example, the OAL exports used to implement kernel profiling are optional.  So the Aspen7750R sample BSP assigns the profiling exports as follows.


void OEMInit()


    // other code removed

    g_pOemGlobal->pfnProfileTimerEnable  = OEMProfileTimerEnable;

    g_pOemGlobal->pfnProfileTimerDisable = OEMProfileTimerDisable;


To find out which OAL exports are optional and which are required, see the CE6 Platform Builder help for OEMGLOBAL.

As with NKGLOBAL, there is a wrapper library oemstub.lib that wraps the OAL exports.  Kitl.dll can use oemstub.lib to call OAL functions.




    return g_pOEMGlobal->pfnGetRealTime (pst);


Besides nkstub.lib and oemstub.lib, there are a few additional libraries in CE6 for OEM use:

  • Kitlcore.lib: This is a replacement for kitl.lib, implementing the KITL protocol and the initialization of the kitl.dll interface with the NKGLOBAL and OEMGLOBAL structures.  You should link this library into kitl.dll instead of kitl.lib.

  • Nkldr.lib: This library implements KernelInitialize / KernelStart, to link into oal.exe.

  • Oemmain.lib: This library implements the OEMInitGlobals function which exchanges function pointers with the kernel.  Link this into oal.exe.

The resulting work to port a CE5 BSP to CE6 would be to revise the platform directory structure slightly, and link with different libraries.  The old CE5 directory structure:

CE5 Directory










Now becomes:

CE6 Directory








Oal.lib is exactly the same as before, so the remaining porting steps between CE5 and CE6 boil down to building oal.exe and kitl.dll.

  1. The oalexe directory is the same as the old \kernel\kern\*, with nkldr.lib, oemmain.lib and nkstub.lib added to the sources file.

  2. The kitl directory comes from taking the KITL specific elements out of the old \kernel\kernkitl.  Convert it from an EXE to a DLL, remove the non KITL related binaries, and add nkstub.lib and oemstub.lib.  You will also need to add some global variables that used to be common with the OAL.

There are other small changes you’ll run into, related to differences in the sets of PQOAL libraries available between CE5 and CE6, but they’re relatively minor and not related to the OAL / kernel / KITL separation.

As a side note, the separation of OAL and KITL is actually optional, so your other choice could be:

CE6 Directory






As I mentioned previously:  Anecdotal experience from our beta partners said that BSP porting to CE6 took them mostly between one day and one month.  Travis Hobrla, a member of our BSP team, developed an awesome demo for MEDC 2006 (Mobile & Embedded DevCon) where he ported the CE5 CEPC OAL to CE6 in about 15 minutes.  If you are an OEM, your experiences may vary, but we don’t anticipate it being too painful.  It was our goal to make it an easy port.

Update!  Travis’s presentation and demo is also available in full on channel9: https://channel9.msdn.com/Showpost.aspx?postid=376154.

The main area where you may have to make big changes is if your CE5 OAL called kernel APIs that we did not intend to expose to the OAL.  In CE6 you would have to move that functionality out of the OAL, into a kernel-mode driver.  You might need to design the OAL to expose IOCTLs to work together with the kernel-mode driver to implement the old functionality.

One final detail you should be aware of is that for security reasons, the OS only exposes a few OAL IOCTLs to user-mode code.  By default, applications and user-mode drivers can’t call OAL IOCTLs that Microsoft didn’t specifically expose to user mode.  For more detail, see the “OAL IOCTL Codes” section of http://blogs.msdn.com/ce_base/archive/2006/11/14/application-compatibility-in-windows-ce-6-0.aspx.

Comments (4)

  1. Asang Dani says:


      Nice article. I had looked this up in a sample BSP. I think this "dll" thing is now extended all the way to kernel. I think overall CE 5/6 do an excellent job in avoiding "link time" symbolic dependency to a great extent in all areas.



  2. For those of you that enjoyed Sue’s excellent article CE6 OAL: What you need to know , the presentation

  3. For those of you that enjoyed Sue's excellent article CE6 OAL: What you need to know , the presentation

Skip to main content