天天看點

WinCE6.0驅動移植( 驅動模型變化, 以及與WinCE5.0的比較)

WinCE6.0驅動移植( 驅動模型變化, 以及與WinCE5.0的比較)

陳永強

[裝置管理器]

裝置管理代碼在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了,變成了核心空間程式.

wince6.0當中,oal.exe(nk.exe),kernel.dll,(kitl.exe可選)都被加載到核心空間。

[裝置驅動加載過程]

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空間了. 找到下面這張圖, 簡單明了.

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, 那麼驅動将被kerneldevice.dll加載到核心空間,即kernel mode driver;如果指定了,驅動将被加載到一個使用者程序udevice.exe,成為user mode driver. 一個udevice.exe可以加載多個user mode driver或者隻加載一個.

繼續閱讀