我希望我能坚持下去。
首先,参考http://www.cnblogs.com/we-hjb/archive/2008/10/29/1322509.html的帖子,把这个牛人的博客的帖子调通了,刚开始怎么调也调
不通,最后过了几天无意中又调试了一下,居然调通了。
接着,参考gooogleman的移植文档,按照他的思路进行了相应的修改。
中间也出过许多错误,下面我把我的错误贴出来和大家一起探讨一下:
首先,按照http://www.cnblogs.com/we-hjb/archive/2008/10/29/1322509.html这个帖子,大家进行OAL的快速调试,通过这个操作,我想大家
可以学到更多,最起码VS2005的一些功能我现在才知道。
其次,参照gooolman的帖子进行移植,在他的个人博客里面有说明。按着来就行了。
一、先编译后模拟器的精简版本,然后把模拟器的OAL相关的代码进行删除,换成5.0BSP的代码(把KITL相关的代码删除)并修改相应的sources
文件。COMMON目录下主要有smartmedia\dll和smartmedia\fmd两个source文件。OAL目录下主要有:OALEXE和OALLIB两个文件下的SOURCE文件。
把KITL在DIR目录里面屏蔽。
二、把C:\WINCE500\PLATFORM\SMDK2440A\Src\Common代替D:\WINCE600\PLATFORM\mini2440\SRC\Common
C:\WINCE500\PLATFORM\SMDK2440A\Src\Inc代替D:\WINCE600\PLATFORM\mini2440\SRC\Inc
三、编译OAL的时候会调用D:\WINCE600\PLATFORM\mini2440\SRC\Common下的很多代码生成的lib,所以我现在首先编译D:\WINCE600
\PLATFORM\mini2440\SRC\Common下面的所有代码,在VS2005 上点中Common然后右键选择“rebuild”,有错误了(有错误才是正常的,
(*^__^*) 嘻嘻……)
警告的内容:
BUILD: [Thrd:Sequence:Type ] Message
BUILD: [01:0000000039:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Intr\.\intr.c(379) : warning C4013: 'NKCallIntChain'
undefined; assuming extern returning int
BUILD: [01:0000000058:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Intr_dvs\.\intr.c(628) : warning C4013:
'NKCallIntChain' undefined; assuming extern returning int
BUILD: [01:0000000192:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\fmd\.\fmd.cpp(940) : warning C4018: '<' :
signed/unsigned mismatch
BUILD: [01:0000000193:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\fmd\.\fmd.cpp(941) : warning C4244: '=' :
conversion from 'unsigned long' to 'USHORT', possible loss of data
BUILD: [01:0000000194:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\fmd\.\fmd.cpp(945) : warning C4018: '<' :
signed/unsigned mismatch
BUILD: [01:0000000195:WARNN ] d:\wince600\platform\mini2440\src\common\smartmedia\fmd\fmd.cpp(956) : warning C4700:
uninitialized local variable 'pLockInfo' used
BUILD: [00:0000000445:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\Dll\: Missing source file: D:\WINCE600
\public\cesysgen\sdk\lib\ARMV4I\debug\coredll.lib.
BUILD: [00:0000000446:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\Dll\: Missing source file: D:\WINCE600
\public\cesysgen\oak\lib\ARMV4I\debug\fal.lib.
(这个VS2005 唯一不好的地方就是编译错误不是红色显示的)
出错地方
// First find if IRQ is claimed by chain
sysIntr = NKCallIntChain((UCHAR)irq);
晕,上面仅仅是警告,但是估计也有问题。跑到Common下打开build.err看看,有错误。
BUILD: [Thrd:Sequence:Type ] Message
BUILD: [01:0000000480:ERRORE] fal.lib(falmain.obj) : error LNK2019: unresolved external symbol FMDHOOK_UnhookInterface
referenced in function DSK_Deinit
BUILD: [01:0000000481:ERRORE] fal.lib(falmain.obj) : error LNK2019: unresolved external symbol FMDHOOK_HookInterface
referenced in function "void __cdecl GetFMDInterface(struct _DEVICE *)" (?GetFMDInterface@@YAXPAU_DEVICE@@@Z)
BUILD: [01:0000000482:ERRORE] smflash_lib.lib(fmd.obj) : error LNK2019: unresolved external symbol ReadPage512 referenced in
function "int __cdecl FMD_SB_ReadSector(unsigned long,unsigned char *,struct _SectorInfo *,unsigned long,int)" (?
FMD_SB_ReadSector@@YAHKPAEPAU_SectorInfo@@KH@Z)
BUILD: [01:0000000483:ERRORE] smflash_lib.lib(fmd.obj) : error LNK2019: unresolved external symbol WritePage512 referenced in
function "int __cdecl FMD_SB_WriteSector(unsigned long,unsigned char *,struct _SectorInfo *,unsigned long,int)" (?
FMD_SB_WriteSector@@YAHKPAEPAU_SectorInfo@@KH@Z)
BUILD: [01:0000000484:ERRORE] D:\WINCE600\platform\mini2440\target\ARMV4I\debug\smflash.dll : fatal error LNK1120: 4
unresolved externals
怎么回事呢?
接着参考http://bbs.driverdevelop.com/simple/index.php?t112006.htmlztg0021的帖子,发现他也遇见类似的错误,按照他的思路进行修改
:
Src\Common\Smartmedia\Dll中的sources文件修改
在SOURCELIBS语句段中原有的两个库的基础上增加下面的库
$(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\fmdhooklib.lib \
之后又有新的错误了。
BUILD: [Thrd:Sequence:Type ] Message
BUILD: [01:0000000432:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\Dll\sources(12) : U1033: syntax error :
'$(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\fmdhooklib.lib' unexpected
BUILD: [01:0000000434:ERRORE] NMAKE.EXE TargetLibFiles -i -c BUILDMSG=Stop. BUILDROOT=D:\WINCE600\PLATFORM\mini2440
CLEANBUILD=1 LINKONLY=1 NOPASS0=1 failed - rc = 2
警告:
BUILD: [Thrd:Sequence:Type ] Message
BUILD: [01:0000000039:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Intr\.\intr.c(379) : warning C4013: 'NKCallIntChain'
undefined; assuming extern returning int
BUILD: [01:0000000058:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Intr_dvs\.\intr.c(628) : warning C4013:
'NKCallIntChain' undefined; assuming extern returning int
BUILD: [01:0000000192:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\fmd\.\fmd.cpp(940) : warning C4018: '<' :
signed/unsigned mismatch
BUILD: [01:0000000193:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\fmd\.\fmd.cpp(941) : warning C4244: '=' :
conversion from 'unsigned long' to 'USHORT', possible loss of data
BUILD: [01:0000000194:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\fmd\.\fmd.cpp(945) : warning C4018: '<' :
signed/unsigned mismatch
BUILD: [01:0000000195:WARNN ] d:\wince600\platform\mini2440\src\common\smartmedia\fmd\fmd.cpp(956) : warning C4700:
uninitialized local variable 'pLockInfo' used
晕倒,把D:\WINCE600\PLATFORM\mini2440\SRC\Common目录下的Smartmedia换成ztg0021的那个就好了!
没有错误,编译成功!
警告:
BUILD: [Thrd:Sequence:Type ] Message
BUILD: [01:0000000039:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Intr\.\intr.c(380) : warning C4013: 'NKCallIntChain'
undefined; assuming extern returning int
BUILD: [01:0000000058:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Intr_dvs\.\intr.c(628) : warning C4013:
'NKCallIntChain' undefined; assuming extern returning int
BUILD: [00:0000000436:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\Dll\: Missing source file: D:\WINCE600
\public\cesysgen\sdk\lib\ARMV4I\debug\coredll.lib.
BUILD: [00:0000000437:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\Dll\: Missing source file: D:\WINCE600
\public\cesysgen\oak\lib\ARMV4I\debug\fal.lib.
BUILD: [00:0000000438:WARNN ] D:\WINCE600\PLATFORM\mini2440\src\common\Smartmedia\Dll\: Missing source file: D:\WINCE600
\public\cesysgen\oak\lib\ARMV4I\debug\fmdhooklib.lib.
继续编译OAL。在参考了gooogleman 的移植笔记,在OALlib的时候还是卡住了,始终是8个错误,我贴出来在此向大家求教下:
BUILD: [Thrd:Sequence:Type ] Message
BUILD: [01:0000000030:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\init.c(53) : error C2065: 'dwNKDrWatsonSize' :
undeclared identifier
BUILD: [01:0000000034:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\intr.c(71) : error C2065:
'BSP_BASE_REG_PA_DM9000_IOBASE' : undeclared identifier
BUILD: [01:0000000035:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\intr.c(71) : error C2051: case expression not
constant
BUILD: [01:0000000045:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(73) : error C2065: 'BSP_UART0_UFCON' :
undeclared identifier
BUILD: [01:0000000046:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(74) : error C2065: 'BSP_UART0_UMCON' :
undeclared identifier
BUILD: [01:0000000047:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(75) : error C2065: 'BSP_UART0_ULCON' :
undeclared identifier
BUILD: [01:0000000048:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(76) : error C2065: 'BSP_UART0_UCON' :
undeclared identifier
BUILD: [01:0000000049:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(77) : error C2065: 'BSP_UART0_UBRDIV' :
undeclared identifier
晕倒我的没有extern DWORD dwNKDrWatsonSize;会提示dwNKDrWatsonSize未定义错误,加上就好了,但是ztg0021的却要屏蔽
extern DWORD dwNKDrWatsonSize 才行的。希望等下不要出乱子。
这里我加上了这句外部声明,不知道最后的结果如何?先放在这里!但是编译COMMON时没有任何问题的。
在这里我要特别感谢一个人:wlc311
在CSDN的这些日子里,他就像一个老朋友帮了我很多,再次向他致谢!
wlc311搞定了6个错误:解决办法如下:
我提拱其中6个错误的解决方法:
BUILD: [01:0000000034:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\intr.c(71) : error C2065:
'BSP_BASE_REG_PA_DM9000_IOBASE' : undeclared identifier
在SRC->INC->bsp_base_reg_cfg中加上如这样:
#define BSP_BASE_REG_PA_DM9000_IOBASE 0x20000300
#define BSP_BASE_REG_PA_DM9000_MEMBASE 0x20000000
BUILD: [01:0000000045:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(73) : error C2065: 'BSP_UART0_UFCON' :
undeclared identifier
BUILD: [01:0000000046:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(74) : error C2065: 'BSP_UART0_UMCON' :
undeclared identifier
BUILD: [01:0000000047:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(75) : error C2065: 'BSP_UART0_ULCON' :
undeclared identifier
BUILD: [01:0000000048:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(76) : error C2065: 'BSP_UART0_UCON' :
undeclared identifier
BUILD: [01:0000000049:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\debug.c(77) : error C2065: 'BSP_UART0_UBRDIV' :
undeclared identifier
在SRC->INC->bsp_cfg中加上
#define BSP_UART0_ULCON 0x03 // 8 bits, 1 stop, no parity
#define BSP_UART0_UCON 0x0005 // pool mode, PCLK for UART
#define BSP_UART0_UFCON 0x00 // disable FIFO
#define BSP_UART0_UMCON 0x00 // disable auto flow control
#define BSP_UART0_UBRDIV (S3C2440A_PCLK/(115200*16) - 1)
其它两个原因,因为没遇到过这种情况,故不便乱说。
重新编译整个OAL
build.err变成
BUILD: [Thrd:Sequence:Type ] Message
BUILD: [01:0000000076:ERRORE] D:\WINCE600\PLATFORM\mini2440\src\oal\oallib\.\init.c(53) : error C2065: 'dwNKDrWatsonSize' :
undeclared identifier
关于:NKCallIntChain,我上网搜了一下,大概意思是:
要生成错误报告的dump文件,需要至少有128K的内存。OAL层初始化函数OEMInit中,变量dwNKDrWatsonSize就是记录这个内存的大小。内核会从
主内存区域的最后,保留出这一块内存。设置编译环境变量SYSGEN_WATSON_DMPGEN,让镜像包含有错误报告生成器的功能。
后面再论坛上求助,得到何宗健老师的指导:
何宗健老师:看来出错的代码在oal自己的代码中。其实我感觉,可以把dwNKDrWatsonSize注释掉,禁止dump这个功能,或者自己在任何一个头
文件里面定义一个就好了,看看5.0版本的bsp该变量定义在哪里的。据自己的经验,5.0移植6.0只要参考微软的官方移植文档,基本上工作量不
大。
zhengshijie:5.0里面直接外部引用的全局变量,在6.0里不能用了,而是通过
platform/common/src/inc/oal.h->public/common/oak/inc/oemglobal.h->public/common/oak/inc/bcoemglobal.h
#define dwNKDrWatsonSize g_pOemGlobal->cbErrReportSize
在6.0里把extern DWORD dwNKDrWatsonSize去掉就可以了,extern DWORD CEProcessorType;有这个定义的话也去掉。
接着又出现一个小问题:
大概错误是找不到KITL.DLL,所以无法生成OAL.EXE。
我不是屏蔽了嘛?
原来我在省城选项里还是选择了KITL=1,将其勾掉。
然后进行总体编译,生成OSDesign6,天啊,终于成功了!
NK.bin和NK.nb0生成了。
下面我要做的就是移植KITL,当然还要下载到板子里去试试!
忘记说了,Bootloader我直接从网上下了一个通用的,所以也就没有进行修改,后面我打算再研究下,最好再写一个NBOOT,再添加一个自己的LOGO,呵呵,先想想。
最后感谢:
wlc311,gooogleman,何宗健老师,WINCE.he前辈,QQ网名叫2008的朋友,谢谢你们给与我的帮助!
Clone一个BSP.
WinCE6.0安装armv4i架构后,里面提供了一个名字为DeviceEmulator的BSP. 这个BSP是s3c2410的BSP.我的是s3c2440a,就克隆这个吧.
[移植OAL]
WinCE5.0的OAL是编译成为一个静态库oal.lib,然后与内核nk.lib静态编译成kernel.exe,也就是nk.exe. 而WinCE6.0把OAL从kernel中剥离出来单独编译成为oal.exe,内核则编译成了Kernel.dll. 分离的代价是不能再直接使用相互的资源了,即相互间的全局变量和函数不能直接访问了. OEMGLOBAL和 NKGLOBAL这2个结构体充当了OAL和Kernel的接口桥梁. 分离的好处是更方便内核独立升级(嗯哼~ 这在将来会发生么?设备的架构可是千差万别的.我想替内核升级最有可能的还是OEMs,不是MS),不过另外一个好处是接口更清晰了,内核会需要哪些OEM函数显得更直观明了.
内核的启动和原来略有不同了,简单回顾WinCE5.0的内核启动过程:
下面是WinCE6.0的内核启动过程:
OAL不能调用内核的KernelStart()函数了, 所以自己要实现一个KernelStart() (nkldr.lib替我们完成了这个, 把nkldr.lib链接到OAL),调用nkldr.lib中的KernelStart().然后执行的ARMInit()函数有一个很重要的任务,它将位于OAL的OEMinitGlobals()函数指针赋值到Kdata中, 后面内核需要这个指针.接下来根据Kdata找到并跳转到内核kernel.dll的入口点NKStartup().
Kernel.dll开始执行NKStartUp(),首先要把和OAL的桥梁打通.也就是把内核的NKGlobal数据结构指针交给OAL,并且获得OAL的OEMGlobal的数据结构指针. 怎么实现的? 内核根据Kdata找到OAL中一个函数OEMInitGlobals() — 还记得吗,前面说到OAL的ARMInit()曾经郑重的把OEMInitGlobals函数指针赋值给了Kdata,就是为了这一天... 然后,把NKGlobal指针作为参数执行这个函数, 这个函数返回OAL的OEMGlobal的指针.(嗯哼~ OAL要实现OEMInitGlobals(), oemmain.lib替我们完成了这个,把oemmain.lib链接到OAL).
这个Kdata是个什么玩意? 它是内核数据结构, 简单理解成共享内存好了, oal 和 kernel都可访问到.再往后没啥好说了,内核可以访问OAL了,痛快的调用OEM函数,和以前WinCE5.0差不多. 最后调用KernelStart(),这回这个函数可是在内核里面了,WinCE6.0起来了……
这个流程和WinCE5.0有点点差别.都是因为OAL和kernel分离了.
[编译OAL]
空谈了这么久,来做实质性的工作吧,开始编译WinCE6.0的OAL. 微软希望它的设计使得移植OAL时候尽可能少工作量,所以oal.exe分2个步骤来实现.第一步:编译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.lib和oemmain.lib是干吗的?回溯前面的启动过程吧. nkldr.lib提供了KernelStart()的实现, oemmain.lib提供了OEMInitGlobals()的实现.当然还有更多的,不罗列了.
[定制OAL]
没有oal.lib咋办?做一个吧……前面提到OAL和Kernel分离,使得接口更加明显了,kernel到底需要OEMs提供哪些函数,可以参照着oemglobal.h文件里面OEMGLOBAL结构体来完成.并且在oemglobal.c里面对这个结构体初始化.这个文件位于oemmain.lib.发扬愚公移山的精神,我来抽丝拨茧一下,下面根据我的2440来分析最重要的必须的几个接口:
[Init相关接口]
要提供OEMInit(), OEMInitDebugSerial(),
OEMInit()函数,建立一个init.c,然后实现这个函数.
OEMInitDebugSerial()放到下面debug.c中实现.
[Debug相关接口]
OEMWriteDebugString
OEMInitDebugSerial
OEMWriteDebugByte
OEMReadDebugByte
OEMWriteDebugLED
PQOAL的oal_other.lib提供了OEMWriteDebugString(),
在OALLIB下创建debug.c ,然后实现OEMInitDebugSerial, OEMWriteDebugByte, OEMReadDebugByte, OEMWriteDebugLED这4个函数.
[Cache相关接口]
需要提供OEMCacheRangeFlush, 根据自己的架构去已有的PQOAL找吧,我的是oal_cache_arm920t.lib
[Time相关接口]
需要提供
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的一个区别.
[Scheduler相关接口]
OEMIdle, OEMNotifyThreadExit, OEMNotifyIntrOccurs, OEMUpdateReschedTime, 一个变量DefaultThreadQuantum.
[power相关接口]
OEMPowerOff, 这个还要说啥, 挂起时候会执行这个函数. PQOAL的oal_power_s3c2440a.lib已经帮忙实现了最基础的工作,会调用BSPPowerOff来完成平台相关的动作,建立一个文件power.c来实现这个BSPPowerOff.
[DRAM相关接口]
OEMGetExtensionDRAM, OEMEnumExtensionDRAM, CalcFSPages, 变量MainMemoryEndAddress
这组函数询问扩展RAM的情况,如果OEMEnumExtensionDRAM函数提供了, 就执行这个函数,否则执行OEMGetExtensionDRAM, CalcFSPages计算pages, 这个功能内核自己实现了,已经不要了,指向一个空函数即可.
[interrupt相关接口]
OEMInterruptEnable, OEMInterruptDisable, OEMInterruptDone,
OEMIniterruptMask,OEMInterruptHandler
基本工作PQOAL已经做好了,PQOAL下面几个接口完成平台相关工作,BSPIntrInit, BSPIntrRequestIrq, BSPINtrEnableIrq, BSPIntrDisableIrq, BSPIntrDoneIrq, BSPIntrActiveIrq.最后一个OEMInterruptHandler就是系统ISR, 将物理irq转换成逻辑中断SYSINTR_XXX.
[other ]
OEMIoControl .PQOAL里面已经实现了这个功能.如果OEMs要添加新的控制命令, 建立一个ioctl.c,定义一个全局数组g_oalIoCtlTable, 然后往数组里面填入命令字和对应命令执行的函数的名称.这个对应命令的执行函数当然要自己实现了. 驱动或者应用使用KernelIOControl这个api时候,相应命令的函数就会执行.
[总结]
1.WinCE6.0不只是将OAL和kernel分离.还将kitl也分离成为了kitl.dll. 所以,OAL也不能直接使用kitl的资源. 首先把kitl.c和kitl相关代码从OAL里面给放到kitl目录去.然后在OEMInit中不能调用OALKitlStart()了,用KITLIoctl(IOCTL_KITL_STARTUP, NULL, 0, NULL, 0, NULL);这一句来替代.
2.OAL需要使用的数据结构定义,和外部函数声明都在头文件nkexport.h中.可以在oal.h中include这个nkexport.h头文件.
3. PQOAL的oal_log库有了变化,如果使用了这个库的要注意,它不在使用g_oalLogMask这个全局变量了.
4. timer和timer_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就完成了.
WinCE6.0驱动移植( 驱动模型变化, 以及与WinCE5.0的比较)
引自:http://chenyq2008.spaces.live.com/blog/cns!F73164AC8D0D8D50!205.entry
陈永强
[设备管理器]
设备管理代码在private\winceos\coreos\device\目录.右边的WinCE6.0省略INC, IROM, NOPMIF, PMIF4个目录没有列出.这些目录是头文件, io资源管理, 电源管理接口.
看看设备管理器的入口点devmain.c. 在WinCE5.0时代, 设备管理器是作为一个进程来实现的:devece.exe. 所以里面就是一个入口函数WinMain()调用StartDeviceManager()函数. 再看WinCE6.0, devmain.c多出来了DevMainEntry(), DllEntry(), 啊哈~ 看来设备管理器也惨遭kernel的命运.变成了device.dll了.
[设备驱动加载过程]
oal.exe加载了kernel.dll, kernel.dll加载device.dll, device.dll加载devmgr.dll, 这个就是负责加载, 卸载, 管理流驱动的. 流程比较了半天,WinCE6.0的驱动加载和WinCE5.0的加载过程没有发现什么差别.也是分为静态加载和动态加载.静态加载就是启动时候加载.设备管理器找到HKLM\Drivers\BuiltIn下BusEnum.dll加载, 这是一个总线枚举驱动, 依照ORDER值指示的加载顺序,它来完成后续的加载工作, 也是使用ActiveDevice来加载. 至于动态加载,就是在系统起来后, 使用ActiveDevice加载一个驱动.加载后,也是在注册表的Active下面显示设备信息.
驱动在注册表需要提供的信息基本是一样的, 也是Prefix, Dll, Index, Order, Iclass这些基本的都一致,关键区别在Flags, UserProcGroup这2个键.
[FLAGS:驱动加载配置]
注册表里每个驱动可以包含一个键FLAGS, 这个配置决定了驱动的加载.下面是WinCE5.0的FLAGS的可选配置,(可以多项相与得到复合值)说明如下:
DEVFLAGS_NONE
注册表没有指定FLAGS
DEVFLAGS_UNLOAD
指示设备管理器执行完Init后卸掉驱动,并且返回成功.总线枚举驱动都这么干.
DEVFLAGS_LOADLIBRARY
通知设备管理器使用LoadLibrary代替LoadDriver.2者的区别:LoadLibrary加载的可以paged out.
DEVFLAGS_NOLOAD
指示设备管理器,驱动将不会被加载.
DEVFLAGS_NAKEDENTRIES
指示设备管理器前缀不要用.可以用前缀来active,但找函数入口点时候不要用前缀. 比如电池驱动指定这个标记后,设备管理器会用BAT这个前缀去实现驱动,但在调用接口时候不会默认的用BAT_Init,.BAT_***,而是自己去找入口点. 这样的目的是可以自由修改驱动接口函数名,可以不要和前缀相同了.
DEVFLAGS_BOOTPHASE_1
要求加载驱动时候,必须BootPhase大于1. BootPhase就是启动阶段的意思. 设备管理器启动是分阶段的.BootPhase1在找注册表.;BootPhase2 加载驱动;BootPhase3开始运行.(题外话,也可以只分2个阶段.)
DEVFLAGS_IRQ_EXCLUSIVE
在访问IRQ时候再加载.
WinCE6.0在此的基础上增加了几个
DEVFLAGS_LOAD_AS_USERPROC
这个是重头戏, 指示设备管理器,把驱动给加载到user mode. 设备管理器会创建一个Reflector.这个就是WinCE6.0主要的改进了.现在我也不懂, 后面再说说这个.
DEVFLAGS_NOUNLOAD
阻止驱动被卸载.
DEVFLAGS_TRUSTEDCALLRERONLY
指示设备管理器限制驱动只能被信任的应用程序open. 在WinCE5.0的文档里面也说有这个,但代码中没有发现,所以5.0应该是没有实现.(时空错乱?还是文档设计先行?还是ms藏私货了,反正我的版本没有.)
[驱动模型]
WinCE6.0的驱动模型难道没有变化?对比WinCE5.0,所有驱动都是被Device.exe或者GWES.exe加载. 在WinCE6.0, 这二者不存在了,变成了dll被nk.exe加载,自然的想法是, 所有驱动被加载到了nk.exe的进程空间? 仅此而已?
不管怎样,先启动模拟器观察证实一下, WinCE6.0的设备只有nk.exe, shell.exe, servicesd.exe, explorer.exe, 4个udevice.exe .嗯哼~, 不止device.exe没有了, 包括filesys.exe, gwes.exe……全体阵亡了,全变成nk.exe加载的dll. udevice.exe出现4个! 直觉这是驱动. 这些现象反映到驱动模型到底有什么变化?
前面的驱动加载时候提到注册表的Flags差异和新增UserProcGroup.Flags增加了一个DEVFLAGS_LOAD_AS_USERPROC,这个选项指示设备管理器将驱动加载成为user mode driver.再看看下面在devcore.c中StartDeviceManager()的伪代码:
StartDeviceManager()
{
初始化设备数据结构, 启动io资源管理,pnp设备管理,电源管理
DevloadInit();// 这儿加载设备驱动.
InitUserProMgr();//CE6新增,这儿初始化 user mode driver handling
While(1)
{
ProcessAutoDeregisterDevs();
ProcessDyingDevs();
ProcessDyingOpens();
}
}
嗯哼~ 看来还支持user mode 的驱动.既然叫user mode, 那肯定就不是加载在内核空间,不是在nk.exe空间了. 找到下面这张图, 简单明了.
设备管理器会依据DEVFLAGS_LOAD_AS_USERPROC的指示创建一个新的进程加载一个驱动, 这个进程就是udevice.exe了, 难怪模拟器里面有4个udevice.exe.在看左上边那个udevice.exe, 里面包含一组user-mode driver dll. 嗯哼~ 一个进程的确是可以加载多个dll的. 但哪些user mode驱动会被加载到一个udevice.exe? 呵呵, 一下就能猜到UserProcGroup这个键的作用了:给用户模式驱动分组啊, 相同组的加载到一个进程. 嗯, 顺便想起手册里面user mode driver host是什么了,用户模式驱动的寄主啊即udevice.exe.
具体怎么分组?UserProcGroup要等于什么值? 看看注册表:
[HKLM\Drivers\ProcGroup_0002]
ProcName=”servicesd.exe”
ProcVolPrefix=”$services”
ProcTimeout=20000
[HKLM\Driver\ProcGroup_0003]
ProcName=”udevice.exe”
ProcVolPrefix=”$udevice”
嗯哈~ 逻辑很简单, 在这建立一个组, 比如0003, 如果要加入这个组, 设置UserProcGroup等于这个3即可.0003只是表示代号,不是表示3个驱动哦.ProcName代表加载驱动的host进程名字. 原来udevice.exe和servicesd.exe进程是这么来的.
赶紧总结一下. 如果没有Flags指定DEVFLAGS_LOAD_AS_USERPROC, 那么驱动将被加载到nk.exe,即kernel mode driver;如果指定了,驱动将被加载到一个用户进程udevice.exe,成为user mode driver. 一个udevice.exe可以加载多个user mode driver或者只加载一个.
Buffer Tracked Events In RAM
选取这个, 将会在image中多出一个OSCapture.exe, 可以记录系统日志到文件
Enable Eboot Space In Memory
选这个,在os启动阶段, Eboot可以传输数据给os
Enable Event Tracking During Boot
选择这个, 系统日志跟踪启动早于内核和文件系统初始化前.
Enable Hardware-Assisted Debugging Support
新增选项.说是第三方硬件调试工具需要的(JTAG probes compiant with exdi2).管它去死.
Enable Kernel Debugger
需要kitl支持, 内核调试器. 可以step through code. 内核可以单步断点?不行吧,,,暂时还不想去调试内核.
Enable KITL
把kitl加入image.
Enable Profiling
在image增加profiler功能, 性能测试功能.
Enable Ship Build
以前看源码, 这个SHIP_BUILD宏, 会把所有的输出, RETAILMSG, DEBUGMSG都给mask掉了.
Flush Tracked Events To Release Directory
往image中加入CeLogFlush.exe, 自动把OSCapture.exe手机到的日子数据写入Celog.clg文件中.注意写入的是你的电脑release目录的文件哦?! 不知道怎么实现的.
Run-Time Image Can Be Larger Than 32MB
自己翻译
Use Xcopy Instead Of Links To Populate Release Directory
用xcopy命令替代copylink. 就是真的拷贝还是只是弄个link的区别.这个link和快捷方式应该不完全一样. 可能是linux的那样的, windows什么时候也支持link了?不知道…
Write Run-Time Image To Flash Memory
指示Eboot下载image到flash…这…到底要干吗?
对比WinCE5.0的, 少了
Enable CE Target control Support.
这个功能还是有用的啊, 没有kitl和activesync时候, 还是可以gi all一下.不过, 我在ce6上面试过了.这个功能并没有取消.可能是默认支持了.所以去掉这个
Enable Full Kernel Mode
嗯哼~. WinCE6.0的内核都重写了. 地址空间也发生天翻地覆的变化.这个肯定要去掉了.
Build过程如下: 1:假如cebuild.bat没有设定 -qbsp,cebuild.bat根据环境变量_DEPTREES包含的模块依次调用cebldtree.bat xxx,__QBLDPASS=preproc。 2:假如cebuild.bat没有设定 -q,cebldtree.bat调用cebuild1.bat public xxx,winceos会被换成了common。否则直接跳到步骤4。 3:cebuild1.bat进入xxx目录执行build。 4:cebldtree.bat发现假如是winceos则调用sysgen -b __QBLDPASS;否则调用sysgen -p xxx -b __QBLDPASS。 5:sysgen.bat调用%_PROJECTROOT%\oak\misc\cesysgen.bat,假如存在的话。 6:cesysgen.bat直接调用%_WINCEROOT%\public\cebase\oak\misc\cesysgen.bat。 7:后者cesysgen.bat把%_DEPTREES%的各个模块名加入到_REV_DEPTREES中。 8:cesysgen.bat调用PlatFile,也就是%_PLATFORMROOT%\%_TGTPLAT%\cebasecesysgen.bat preproc,假如存在的话。 9:BSP的cebasecesysgen.bat设置一些环境变量。 10:cesysgen.bat再依次调用ProjFile,也就是_REV_DEPTREES中各个模块的xxx.bat preproc。 首先寻找__CESYSGEN_PATH\xxx.bat,也就是D:\WCE_PROGS\WM5.0\PUBLIC\smartfon\oak\MISC\xxx.bat。 其次寻找%_PUBLICROOT%\cebase\oak\misc\xxx.bat, 最后寻找%_PUBLICROOT%\xxx\cebasecesysgen.bat 这些批处理文件设置一些环境变量。 11:重复步骤8~10,参数分别是pass1,pass2。 12:sysgen.bat接着步骤5往下,各个%_WINCEROOT%\public\common\oak\lib\%_TGTCPU%\%WINCEDEBUG%\langid目录下假如有coreres.res,就调用bldlist langid。 13:bldlist.bat把langid加进_LANGIDLIST。 14:sysgen.bat进入%_PUBLICROOT%\%___PUBLICPROJECT%\cesysgen,调用nmake __QBLDPASS。 15:重复步骤1~14,__QBLDPASS=postproc 16:cebuild.bat调用sysgenplatform.bat %_TARGETPLATROOT% preproc 17:sysgenplatform.bat调用%_PROJECTROOT%\oak\misc\cesysgen.bat,然后进入%_TARGETPLATROOT%\cesysge nnmake preproc 18:cebuild.bat调用cebuild1 platform %_PLATFORMROOT%\common 19:cebuild.bat调用sysgenplatform.bat %_TARGETPLATROOT% postproc 20:同17,变为postproc