Chinaunix首页 | 论坛 | 博客
  • 博客访问: 635468
  • 博文数量: 121
  • 博客积分: 8469
  • 博客等级: 中将
  • 技术积分: 1065
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-03 10:32
文章分类

全部博文(121)

文章存档

2013年(1)

2012年(15)

2010年(2)

2009年(8)

2008年(95)

我的朋友

分类: 嵌入式

2009-02-26 11:08:20

克隆BSP]

Clone一个BSP.

WinCE6.0安装armv4i架构后,里面提供了一个名字为DeviceEmulatorBSP. 这个BSPs3c2410BSP.我的是s3c2440a,就克隆这个吧.

 


移植OAL]

WinCE5.0OAL是编译成为一个静态库oal.lib,然后与内核nk.lib静态编译成kernel.exe,也就是nk.exe. WinCE6.0OALkernel中剥离出来单独编译成为oal.exe,内核则编译成了Kernel.dll. 分离的代价是不能再直接使用相互的资源了,即相互间的全局变量和函数不能直接访问了. OEMGLOBAL NKGLOBAL2个结构体充当了OALKernel的接口桥梁. 分离的好处是更方便内核独立升级(嗯哼~ 这在将来会发生么?设备的架构可是千差万别的.我想替内核升级最有可能的还是OEMs,不是MS),不过另外一个好处是接口更清晰了,内核会需要哪些OEM函数显得更直观明了.

内核的启动和原来略有不同了,简单回顾WinCE5.0的内核启动过程:

[NK.exe=Kern.exe]

StartUp()                      [ OAL入口点]

     KernelStart()                  [ kernel入口点]

              ArmInit()

                         OEMInitDebugSerial()

                 OEMInit()

           KernelInit()

               HeapInit()

               InitMemoryPool()

               ProcInit()

               SchedInit()

             FirstSchedule()                             

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 


下面是WinCE6.0的内核启动过程:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


OAL不能调用内核的KernelStart()函数了, 所以自己要实现一个KernelStart() (nkldr.lib替我们完成了这个, nkldr.lib链接到OAL),调用nkldr.lib中的KernelStart().然后执行的ARMInit()函数有一个很重要的任务,它将位于OALOEMinitGlobals()函数指针赋值到Kdata, 后面内核需要这个指针.接下来根据Kdata找到并跳转到内核kernel.dll的入口点NKStartup().

Kernel.dll开始执行NKStartUp(),首先要把和OAL的桥梁打通.也就是把内核的NKGlobal数据结构指针交给OAL,并且获得OALOEMGlobal的数据结构指针. 怎么实现的? 内核根据Kdata找到OAL中一个函数OEMInitGlobals()  还记得吗,前面说到OALARMInit()曾经郑重的把OEMInitGlobals函数指针赋值给了Kdata,就是为了这一天... 然后,NKGlobal指针作为参数执行这个函数, 这个函数返回OALOEMGlobal的指针.(嗯哼~ OAL要实现OEMInitGlobals(), oemmain.lib替我们完成了这个,oemmain.lib链接到OAL).

这个Kdata是个什么玩意? 它是内核数据结构, 简单理解成共享内存好了, oal kernel都可访问到.再往后没啥好说了,内核可以访问OAL,痛快的调用OEM函数,和以前WinCE5.0差不多. 最后调用KernelStart(),这回这个函数可是在内核里面了,WinCE6.0起来了……

这个流程和WinCE5.0有点点差别.都是因为OALkernel分离了.

编译OAL]

空谈了这么久,来做实质性的工作吧,开始编译WinCE6.0OAL. 微软希望它的设计使得移植OAL时候尽可能少工作量,所以oal.exe2个步骤来实现.第一步:编译oal.lib.第二步:编译oal.exe. 第一步的oal.lib可以就是原来版本的,你拷贝原来的oal目录代码到OALLIB目录编译一个oal.lib.关键是第二步,原来在WinCE5.0时候,oal.lib+nk.lib编译成了kern.exe,然后改名成nk.exe.现在,要把oal+nkstub.lib,编译成oal.exe.nk.lib也不是说不要就可以直接不要的.在编译oal.lib时候可是大量使用了nk.lib的东东. 你不会想全文重新改变函数和变量的调用形式吧? ok,nkstub.lib链接上.这么一来, OALEXE目录下的SOURCES文件里面,4个库被添加进来.

  TARGETLIBS= oal.lib oemmain.lib nkldr.lib nkstub.lib ……(路径省略)

Nkldr.liboemmain.lib是干吗的?回溯前面的启动过程吧. nkldr.lib提供了KernelStart()的实现, oemmain.lib提供了OEMInitGlobals()的实现.当然还有更多的,不罗列了.

定制OAL]

没有oal.lib咋办?做一个吧……前面提到OALKernel分离,使得接口更加明显了,kernel到底需要OEMs提供哪些函数,可以参照着oemglobal.h文件里面OEMGLOBAL结构体来完成.并且在oemglobal.c里面对这个结构体初始化.这个文件位于oemmain.lib.发扬愚公移山的精神,我来抽丝拨茧一下,下面根据我的2440来分析最重要的必须的几个接口:

相关接口]

要提供OEMInit(), OEMInitDebugSerial(),

OEMInit()函数,建立一个init.c,然后实现这个函数.

OEMInitDebugSerial()放到下面debug.c中实现.

相关接口]

OEMWriteDebugString

OEMInitDebugSerial

OEMWriteDebugByte

OEMReadDebugByte

OEMWriteDebugLED

PQOALoal_other.lib提供了OEMWriteDebugString(),

OALLIB下创建debug.c ,然后实现OEMInitDebugSerial, OEMWriteDebugByte, OEMReadDebugByte, OEMWriteDebugLED4个函数.

相关接口]

需要提供OEMCacheRangeFlush, 根据自己的架构去已有的PQOAL找吧,我的是oal_cache_arm920t.lib

相关接口]

需要提供

InitClock

OEMGetRealTime

OEMSetRealTime

OEMSetAlarmTime

OEMQueryPerfCounter

OEMQueryPerfFreq

OEMGetTickCount

 

InitClock,这个功能已经废除了, 相关功能被移到OEMPowerOff.所以可以实现一个空函数,在初始化OemGlobal时候,把这个指针赋值RetuanFalse()函数也是一样的效果.OEMGetRealTime ,OEMSetRealTime是设置读取rtc的日期功能.OEMSetAlarmTime是设置rtc的报警时刻,找到oal_rtc_s3c2440a.lib

OEMQueryPerfCounter,OEMQueryPerfFreq是提供更高精度时间的查询,

OEMGetTickCount返回当前CurMSec,系统运行了多少毫秒.oal_time.lib中已经有实现.特别强调的是,这个函数在WinCE5.0里面是SC_GetTickCount.需要把名字改了.这个是OAL的一个区别.

相关接口]

       OEMIdle, OEMNotifyThreadExit, OEMNotifyIntrOccurs, OEMUpdateReschedTime, 一个变量DefaultThreadQuantum.

相关接口]

OEMPowerOff, 这个还要说啥, 挂起时候会执行这个函数. PQOALoal_power_s3c2440a.lib已经帮忙实现了最基础的工作,会调用BSPPowerOff来完成平台相关的动作,建立一个文件power.c来实现这个BSPPowerOff.

                           

相关接口]

       OEMGetExtensionDRAM, OEMEnumExtensionDRAM, CalcFSPages, 变量MainMemoryEndAddress

这组函数询问扩展RAM的情况,如果OEMEnumExtensionDRAM函数提供了, 就执行这个函数,否则执行OEMGetExtensionDRAM, CalcFSPages计算pages, 这个功能内核自己实现了,已经不要了,指向一个空函数即可.

相关接口]

OEMInterruptEnable, OEMInterruptDisable, OEMInterruptDone,

OEMIniterruptMask,OEMInterruptHandler

       基本工作PQOAL已经做好了,PQOAL下面几个接口完成平台相关工作,BSPIntrInit, BSPIntrRequestIrq, BSPINtrEnableIrq, BSPIntrDisableIrq, BSPIntrDoneIrq, BSPIntrActiveIrq.最后一个OEMInterruptHandler就是系统ISR, 将物理irq转换成逻辑中断SYSINTR_XXX.

       OEMIoControl .PQOAL里面已经实现了这个功能.如果OEMs要添加新的控制命令, 建立一个ioctl.c,定义一个全局数组g_oalIoCtlTable, 然后往数组里面填入命令字和对应命令执行的函数的名称.这个对应命令的执行函数当然要自己实现了. 驱动或者应用使用KernelIOControl这个api时候,相应命令的函数就会执行.

总结]

1.WinCE6.0不只是将OALkernel分离.还将kitl也分离成为了kitl.dll. 所以,OAL也不能直接使用kitl的资源. 首先把kitl.ckitl相关代码从OAL里面给放到kitl目录去.然后在OEMInit中不能调用OALKitlStart(),KITLIoctl(IOCTL_KITL_STARTUP, NULL, 0, NULL, 0, NULL);这一句来替代.

2.OAL需要使用的数据结构定义,和外部函数声明都在头文件nkexport.h.可以在oal.hinclude这个nkexport.h头文件.

       3. PQOALoal_log库有了变化,如果使用了这个库的要注意,它不在使用g_oalLogMask这个全局变量了.

4. timertimer_dvs目录下的watchdog.c文件和nkexport.h中重复定义了pfnOEMRefreshWatchDog,dwOemWatchDogPeriod.一个解决办法是去掉watchdog.c.反正也可以不使用这个接口.默认传过去的是空接口ReturnFalse()

5. 编译smflash.dll出错,需要fal.lib一起编译成为smflash.dll. fal的源代码位于private\winceos\driver\msflash\src.这个fal.lib.好像和以前的不一样.从错误信息中观察,好像多出来2个接口.fmd.cpp里面增加这2个接口:

LPVOID FMDHOOK_HookInterface(PFMDInterface pInterface)

{ return (LPVOID) pInterface;}

Void FMDHOOK_UnhookInterface(LPVOID pContext, FMDInterface *pInterface){}

至此, 在给oal加上一个启动代码startup.s. 一个oal.lib就完成了.
阅读(1800) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~