案例解脱Windows CE OAL的开发任务汇总.docx
《案例解脱Windows CE OAL的开发任务汇总.docx》由会员分享,可在线阅读,更多相关《案例解脱Windows CE OAL的开发任务汇总.docx(25页珍藏版)》请在冰点文库上搜索。
![案例解脱Windows CE OAL的开发任务汇总.docx](https://file1.bingdoc.com/fileroot1/2023-5/7/6a6c567c-aabd-4447-ac4b-780fb2748c08/6a6c567c-aabd-4447-ac4b-780fb2748c081.gif)
案例解脱WindowsCEOAL的开发任务汇总
第6章
案例解脱WindowsCEOAL
的开发任务汇总
6.1 OAL是什么
这里的OAL指的是WindowsCE的BSP的3个组成部分之一的用户OAL函数集合,而不是WindowsCE操作系统的OAL模块,请读者注意体会这两者之间的区别与联系。
OAL是OEMAdaptationLayer的缩写,它是介于目标设备硬件和WindowsCE操作系统内核之间的用户代码逻辑层。
称它为用户代码逻辑层包括两层意思,首先是OAL主要由OEM用户根据目标设备硬件设计的特点而编写的代码组成,不同的目标硬件设计就有不同的OAL;其次是OAL本身是由一系列用户开发实现的OEM函数组成,被WindowsCE的操作系统内核中间层代码调用以实现自身功能,在操作系统运行过程中不构成可执行模块实体。
常常将WindowsCE的BootLoader、OAL和设备驱动程序相提并论,这三者共同组成WindowsCE操作系统的板级支持包BSP(BoardSupportPackage)。
但是BootLoader有自身完整的程序执行流程,而OAL和设备驱动程序仅只是一些供操作系统在运行过程中调用的函数的集合,从这个意义上来说,OAL与设备驱动程序有更多的相似之处。
只不过WindowsCE的设备驱动程序一般只是用来驱动某一特定外设的,系统中缺少某一驱动程序只会造成与之对应的外设不能正常工作。
而OAL的主要工作是初始化和驱动供WindowsCE操作系统内核启动运行所需的核心硬件如MMU、cache、系统时钟、存储控制器、异常处理机制等,如果系统中缺少了OAL将造成操作系统根本无法启动运行。
所以可以把OAL理解成是WindowsCE操作系统所基于的硬件平台上的核心硬件的驱动程序、所有设备驱动程序中的最大者。
6.2 OEMGLOBAL结构体及其全局变量
前述kernel.dll模块的入口点函数NKStartup的所需完成的任务之一是找出用户OAL函数的入口点。
用户OAL函数,就是需要OEM用户负责开发实现的供OAL模块调用的功能函数。
这些函数的性质和在OAL模块中所起的作用与BootLoader的OEM函数是相似的,并且它们也是以OEM这3个字符作为函数名的前缀,称它们为OAL的OEM函数,在本篇书中也简称作OEM函数。
OAL的OEM函数不是一个而是一系列函数,用户OAL函数的入口点,意思是WindowsCE操作系统的启动程序可以通过调用这一个入口点函数而获取其余全部的OAL的OEM函数。
在WindowsCE操作系统中,这个入口点函数被命名为OEMInitGlobals。
虽然OEMInitGlobals函数也以OEM为函数名前缀,但是这并不是一个需要OEM用户开发实现的函数,它的实现源代码在源文件%_WINCEROOT%\PRIVATE\WINCEOS\COREOS\NK\OEMMAIN\oemglobal.c中。
这个目录下源文件被编译进了静态库oemmain.lib中,而这个静态库又是DeviceEmulator的OAL模块可执行文件oal.exe的组成部分。
以下是从DeviceEmulator的OAL模块的sources工程文件中截取的部分:
TARGETLIBS=\
$(_COMMONOAKROOT)\lib\$(_CPUDEPPATH)\oemmain.lib\
$(_COMMONOAKROOT)\lib\$(_CPUDEPPATH)\nkstub.lib\
$(_COMMONOAKROOT)\lib\$(_CPUDEPPATH)\nkldr.lib\
$(_TARGETPLATROOT)\lib\$(_CPUDEPPATH)\oal.lib\
…
对基于ARM架构的CPU的嵌入式目标系统来说,OEMInitGlobals函数的执行源代码可精简表示如下:
POEMGLOBALg_pOemGlobal=&OemGlobal;
……
POEMGLOBALOEMInitGlobals(PNKGLOBALpNKGlobal)
{
g_pNKGlobal=pNKGlobal;
g_pOemGlobal->dwARMCacheMode=OEMARMCacheMode();
returng_pOemGlobal;
}
这里真正起作用的是OEMGLOBAL结构体类型的静态全局变量OemGlobal,OEMInitGlobals函数的主要功能就是把它的地址指针返回给函数的调用者。
前文提过,OEMGLOBAL结构体是OAL模块的用户OEM函数的容器数据结构,它的成员多数都是函数指针类型,这些函数指针的类型定义实际上就是各OEM函数的函数接口定义。
但是WindowsCE操作系统内核并不是直接调用的记录在OemGlobal全局变量的各成员中的函数(指针)。
以负责向系统的调试端口输出用户提示字符串的OEMWriteDebugString函数为例,系统内核的源代码实际调用的是在源文件%_WINCEROOT%\PRIVATE\WINCEOS\COREOS\NK\OEMSTUB\oemstub.c中实现的OEMWriteDebugString函数,它的源代码如下:
voidOEMWriteDebugString(unsignedshort*str)
{
g_pOemGlobal->pfnWriteDebugString(str);
}
在oemstub.c源文件中定义并实现的这类函数还不止OEMWriteDebugString函数这一个,它们都被编译进了静态库文件oemstub.lib,而这个静态库是操作系统内核模块kernel.dll的组成部分。
WindowsCE操作系统的内核源代码通过调用oemstub.lib的库函数间接地使用记录在OemGlobal全局变量的各成员中的用户OAL函数的功能,这些库函数的功能实际上代表了被它调用的OEMGLOBAL结构体的各成员所记录的用户实现OEM函数的功能定义。
WindowsCEOAL的开发者想要将自己开发实现的OEM函数提交给操作系统,其途径就是在OemGlobal全局变量的定义位置或者随后的操作系统启动初始化代码中使用OEM函数的函数名(即函数指针)为相应功能的OemGlobal的函数指针成员赋值。
OEMGLOBAL结构体在头文件%_WINCEROOT%\PUBLIC\COMMON\OAK\INC\oemglobal.h中的完整定义如下:
typedefstruct_OEMGLOBAL{
DWORDdwVersion;
//initialization
PFN_InitDebugSerialpfnInitDebugSerial;
PFN_InitPlatformpfnInitPlatform;
//debugfunctions
PFN_WriteDebugBytepfnWriteDebugByte;
PFN_WriteDebugStringpfnWriteDebugString;
PFN_ReadDebugBytepfnReadDebugByte;
PFN_WriteDebugLEDpfnWriteDebugLED;
//cachefuctions
PFN_CacheRangeFlushpfnCacheRangeFlush;
//timerelatedfuncitons
PFN_InitClockpfnInitClock;
PFN_GetRealTimepfnGetRealTime;
PFN_SetRealTimepfnSetRealTime;
PFN_SetAlarmTimepfnSetAlarmTime;
PFN_QueryPerfCounterpfnQueryPerfCounter;
PFN_QueryPerfFreqpfnQueryPerfFreq;
PFN_GetTickCountpfnGetTickCount;
//schedulerrelatedfunctions
PFN_IdlepfnIdle;
PFN_NotifyThreadExitpfnNotifyThreadExit;
PFN_NotifyReschedulepfnNotifyReschedule;
PFN_NotifyIntrOccurspfnNotifyIntrOccurs;
PFN_UpdateReschedTimepfnUpdateReschedTime;
DWORDdwDefaultThreadQuantum;
//powerrelatedfunctions
PFN_PowerOffpfnPowerOff;
//DRAMdetectionfunctions
PFN_GetExtensionDRAMpfnGetExtensionDRAM;
PFN_EnumExtensionDRAMpfnEnumExtensionDRAM;
PFN_CalcFSPagespfnCalcFSPages;
DWORDdwMainMemoryEndAddress;
//interrupthandlingfunctions
PFN_InterruptEnablepfnInterruptEnable;
PFN_InterruptDisablepfnInterruptDisable;
PFN_InterruptDonepfnInterruptDone;
PFN_InterruptMaskpfnInterruptMask;
//co-procsupport
PFN_InitCoProcRegspfnInitCoProcRegs;
PFN_SaveCoProcRegspfnSaveCoProcRegs;
PFN_RestoreCoProcRegspfnRestoreCoProcRegs;
DWORDcbCoProcRegSize;
DWORDfSaveCoProcReg;
//persistentregistrysupport
PFN_ReadRegistrypfnReadRegistry;
PFN_WriteRegistrypfnWriteRegistry;
//watchdogsupport
PFN_RefreshWatchDogpfnRefreshWatchDog;
DWORDdwWatchDogPeriod;
DWORDdwWatchDogThreadPriority;
//profilersupport
PFN_ProfileTimerEnablepfnProfileTimerEnable;
PFN_ProfileTimerDisablepfnProfileTimerDisable;
//SimpleRAMbasedErrorReportingsupport
DWORDcbErrReportSize;//wascbNKDrWatsonSize
//others
PFN_IoctlpfnOEMIoctl;
PFN_KDIoctlpfnKDIoctl;
PFN_IsRompfnIsRom;
PFN_MapW32PrioritypfnMapW32Priority;
PFN_SetMemoryAttributespfnSetMemoryAttributes;
PFN_IsProcessorFeaturePresentpfnIsProcessorFeaturePresent;
PFN_HaltSystempfnHaltSystem;
PFN_NotifyForceCleanBootpfnNotifyForceCleanBoot;//filesysdetectedobject
storecorruptionandforce//systembootclean
PROMChain_tpROMChain;
//PlatformspecificinformationpassedfromOALtoKITL.
LPVOIDpKitlInfo;
PFNVOIDpfnKITLGlobalInit;//KITLentrypoint(settoKitldllmain
ifKITLispartofOEM)
DBGPARAM*pdpCurSettings;
//compiler/GSsecuritycookie
DWORD_PTR*p__security_cookie;
DWORD_PTR*p__security_cookie_complement;
//alarmresolution
DWORDdwAlarmResolution;//alarmresolutioninms
//rtcrolloversupport
DWORDdwYearsRTCRollover;//#ofyearsRTCrollover.
//reservesomeroomforfutureextention.
DWORD_rsvd_[8];//reserve8dwordforfuture
use
//CPU-dependentfieldsstarthere
#ifdefined(x86)
//CPUdependentfunctions
PFN_NMIHandlerpfnNMIHandler;//NMIHandler
#elifdefined(ARM)
PFN_InterruptHandlerpfnInterruptHandler;//interrupthandler
PFNVOIDpfnFIQHandler;//FIQhandler
DWORDdwARM1stLvlBits;//extrabitstobesetin1st
levelpagetable
DWORDdwARMCacheMode;//CandBbits
DWORDf_V6_VIVT_ICache;//v6specific-ifI-Cacheis
VIVTASID-tagged
//VFPfuncitons
PFN_SaveRestoreVFPCtrlRegspfnSaveVFPCtrlRegs;//saveVFPcontrolregisters
PFN_SaveRestoreVFPCtrlRegspfnRestoreVFPCtrlRegs;//restoreVFPcontrolregisters
PFN_HandleVFPExceptionpfnHandleVFPExcp;//handleVFPexception
#elifdefined(MIPS)
DWORDdwCoProcBits;//platformspecificco-proc
enablebits
DWORDdwOEMTLBLastIdx;//sizeofTLB-1
DWORDdwArchFlagOverride;//architectureflagoverride
constBYTE*pIntrPrio;//interruptprority(ptrto
64bytes)
constBYTE*pIntrMask;//interruptmask(ptrto8
bytes)
#elifdefined(SHx)
PFN_SHxNMIHandlerpfnNMIHandler;//NMIHandler
DWORDdwSHxIntEventCodeLength;//platformspecificinterrupt
codelength(inbits;12is
thedefault)
#else
#pragmaerror("NoCPUDefined")
#endif
}OEMGLOBAL,*POEMGLOBAL;
为了使读者对这一庞大的OEMGLOBAL结构体有一个宏观的印象,下面以ARM架构为主将它的各成员含义的简要描述列了一个表格,见有6-1,其中阴影的行是可选实现的OEM函数及数据成员。
表6-1 OEMGCOBAC结构体的成员
OEMGLOBAL结构体的成员
含义描述
以下成员是操作调试功能端口的OEM函数
pfnInitDebugSerial
这是负责初始化目标嵌入式系统的调试串口的OEM函数的指针,它所服务的oemstub.lib库函数是OEMInitDebugSerial。
WindowsCE操作系统的OAL模块与BootLoader共享完全相同的操作调试端口的OEM函数
pfnWriteDebugByte
这个函数指针所指向的OEM函数负责向嵌入式系统的调试端口输出一个字节数据,它所服务的oemstub.lib库函数是OEMWriteDebugByte
pfnWriteDebugString
这个函数指针所指向的OEM函数负责向嵌入式系统的调试端口输出一个字符串,它所服务的oemstub.lib库函数是OEMWriteDebugString
pfnReadDebugByte
这个函数指针所指向的OEM函数负责从嵌入式系统的调试端口读取一个字节数据,它所服务的oemstub.lib库函数是OEMReadDebugByte
pfnWriteDebugLED
这个函数指针所指向的OEM函数负责向嵌入式系统的用作调试功能的LED指示灯的端口输出一个4字节数据,这是一个可选实现的OEM函数,它所服务的oemstub.lib库函数是OEMWriteDebugLED
平台初始化功能函数
pfnInitPlatform
这是目标嵌入式系统的负责硬件平台初始化的OEM函数的指针,它所服务的oemstub.lib库函数是OEMInit
以下成员是实现系统时钟功能的OEM函数
pfnGetRealTime
这个函数指针所指向的OEM函数的功能是从实时时钟处获取当前的时间,它所服务的oemstub.lib库函数是OEMGetRealTime
pfnSetRealTime
这个函数指针所指向的OEM函数的功能是对实时时钟设置时间,它所服务的oemstub.lib库函数是OEMSetRealTime
pfnSetAlarmTime
这个函数指针所指向的OEM函数的功能是对实时时钟设置告警时间,它所服务的oemstub.lib库函数是OEMSetAlarmTime
续表
OEMGLOBAL结构体的成员
含义描述
pfnGetTickCount
这个函数指针所指向的OEM函数的功能是获取自从系统启动运行以来的时间毫秒数。
如果软件系统是Release配置,则这个时间毫秒数是系统实际运行时间减去系统挂起时间的毫秒数;如果是Debug配置,则它是系统运行时间减去180秒的时间毫秒数。
这个OEM函数指针所服务的oemstub.lib库函数是OEMGetTickCount
pfnInitClock
这个函数指针所指向的OEM函数负责初始化系统时钟,这是一个可选实现的OEM函数,它所服务的oemstub.lib库函数是OEMInitClock
pfnQueryPerfCounter
这个函数指针所指向的OEM函数的功能是获取高分辨率的性能计数器的当前计数值,这个高分辨率性能计数器实际上是向嵌入式系统提供比OEMGet-TickCount函数粒度更细的定时功能的定时器。
这是一个可选实现的OEM函数
pfnQueryPerfFreq
这个函数指针所指向的OEM函数的功能是获取高分辨率的性能计数器的频率值,这也是一个可选实现的OEM函数
dwAlarmResolution
这个数据成员记录目标系统的告警时钟的分辨率,也就是告警时钟的以毫秒为单位的使用粒度
dwYearsRTCRollover
这个数据成员记录目标系统的实时时钟的滚动周期年数。
滚动周期,指的是实时时钟计时发生溢出的时间周期
以下成员是实现线程调度管理及通知功能的OEM函数及数据
pfnNotifyThreadExit
这个函数指针所指向的OEM函数每当系统中有一个线程中止运行时它被操作系统内核调用。
这是一个可选实现的OEM函数
pfnNotifyReschedule
这个函数指针所指向的OEM函数每当系统中有一个线程进入可运行的就绪态时它被操作系统内核调用。
这也是一个可选实现的OEM函数
pfnNotifyIntrOccurs
这个函数指针所指向的OEM函数每当系统中有中断发生时它被操作系统内核调用。
这也是一个可选实现的OEM函数
pfnUpdateReschedTime
这个函数指针所指向的OEM函数可用来改变操作系统内核的线程调度的时间片的大小。
这也是一个可选实现的OEM函数
dwDefaultThreadQuantum
这个数据成员的默认取值是DEFAULT_THREAD_QUANTUM
以下成员是实现系统中断功能的OEM函数
pfnInterruptEnable
这个函数指针所指向的OEM函数的功能是启用特定外设的中断,它所服务的oemstub.lib库函数是OEMInterruptEnable
pfnInterruptDisable
这个函数指针所指向的OEM函数的功能是禁用特定外设的中断,它所服务的oemstub.lib库函数是OEMInterruptDisable
pfnInterruptDone
这个函数指针所指向的OEM函数在中断处理结束时刻被操作系统内核调用,它向OAL的开发者提供了在中断处理即将完成的时刻作出补充处理的机会,通常在设备驱动程序调用系统调用函数InterruptDone时操作系统内核调用这个OEM函数。
这个OEM函数所服务的oemstub.lib库函数是OEMInterruptDone
pfnInterruptMask
这个函数指针所指向的OEM函数的功能是根据中断的逻辑中断号屏蔽它对应的物理中断号,它所服务的oemstub.lib库函数是OEMInterruptMask
pfnInterruptHandler
这个函数指针所指向的OEM函数用作目标系统的IRQ中断处理函数,每当基于ARM架构CPU的嵌入式系统中有普通的IRQ中断发生时这个OEM函数被操作系统内核调用
pfnFIQHandler
这个函数指针所指向的OEM函数用作目标系统的FIQ中断处理函数。
FIQ是ARM架构CPU中的一类优先级最高的外设中断请求,它可以中断所有的IRQ中断而不能被IRQ打断
以下成员是实现利用协处理器功能的OEM函数与数据
pfnInitCoProcRegs
这个函数指针所指向的OEM函数被操作系统内核调用以初始化平台特定的调试功能寄存器。
这是一个可选实现的OEM函数
pfnSaveCoProcRegs
这个函数指针所指向的OEM函数在系统发生线程切