WinCE6.0驱动移植( 驱动模型变化, 以及与WinCE5.0的比较)

时间:2021-01-24 03:59:07

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资源管理, 电源管理接口.

WinCE6.0驱动移植( 驱动模型变化, 以及与WinCE5.0的比较)

看看设备管理器的入口点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, 4udevice.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空间了. 找到下面这张图, 简单明了.

WinCE6.0驱动移植( 驱动模型变化, 以及与WinCE5.0的比较)

设备管理器会依据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或者只加载一个.