Steward
分享是一種喜悅、更是一種幸福
驅動程式 - Kernel Mode Driver Framework (KMDF) - 教學說明 - 5. File Buffer的使用策略
在AddDevice()中,會初始化相關旗標,其中有一個設定是關於I/O Manager的Buffer使用方式
1 2 3 4 5 6 | NTSTATUS AddDevice ( WDFDRIVER myDriver, PWDFDEVICE_INIT pMyDeviceInit) { ... WdfDeviceInitSetIoType (pMyDeviceInit, WdfDeviceIoBuffered ); ... } |
該參數主要用於什麼地方呢?
當User Application透過檔案系統跟驅動程式溝通時,User Application會將Buffer Pointer傳給Win32 API
1 2 3 4 5 6 7 | int __cdecl main ( int argc, char **argv) { ... ReadFile (hFile, szBuffer, sizeof (szBuffer), &dwRet, NULL ); WriteFile (hFile, szBuffer, sizeof (szBuffer), &dwRet, NULL ); ... } |
P.S. szBuffer是User Buffer Pointer
當User Application呼叫ReadFile()、WriteFile()後,I/O Manager會呼叫驅動程式的EvtIoRead、EvtIoWrite Callback副程式,那在驅動程式的Callback副程式要如何拿到User Application的Buffer資料呢?User Space的資料位址跟Kernel Space的資料位址是位於不同的地址空間,意思就是驅動程式不能直接存取這個User Buffer Pointer,所以I/O Manager要如何將這塊Buffer交給驅動程式,其使用的方式,就是所謂I/O Manager的Buffer使用策略,在Windows驅動程式中,I/O Manager有三種Buffer使用方式
使用方式 | 行為描述 |
---|---|
WdfDeviceIoBuffered | I/O Manager會新增一塊跟User Buffer一樣大小的記憶體,讀寫都需要由I/O Manager負責同步更新(進行複製的動作) |
WdfDeviceIoDirect | I/O Manager會Mapping User Buffer到一個MDL(Memory Description List),驅動程式使用這個MDL進行操作,相較於WdfDeviceIoBuffered,因為資料不須由I/O Manager做複製的動作,因此,效率會比較好 |
WdfDeviceIoNeither | Neither I/O的意思是Neither Buffered Nor Direct I/O,使用這種方式時,I/O Manager會將Use Buffer Pointer,透過特殊操作後,再傳遞給驅動程式使用,因為,驅動程式可以直接存取User Buffer的資料,因此,效率是這三種方式裡面最好的一個 |
驅動程式必須依據Buffer的設定去存取不同欄位的Pointer,這樣才可以正確存取到User Buffer
使用方式 | Callback | Buffer Pointer | Buffer Length |
---|---|---|---|
WdfDeviceIoBuffered | EvtIoRead() | WdfRequestRetrieveOutputMemory() | 第三個參數(Length) |
EvtIoWrite() | WdfRequestRetrieveInputMemory() | 第三個參數(Length) | |
WdfDeviceIoDirect(PIO) | EvtIoRead() | WdfRequestRetrieveOutputWdmMdl() | 第三個參數(Length) |
EvtIoWrite() | WdfRequestRetrieveInputWdmMdl() | 第三個參數(Length) | |
WdfDeviceIoDirect(DMA) | EvtIoRead() | WdfRequestRetrieveOutputWdmMdl() | 第三個參數(Length) |
EvtIoWrite() | WdfRequestRetrieveInputWdmMdl() | 第三個參數(Length) | |
WdfDeviceIoNeither | EvtIoRead() | WdfRequestRetrieveUnsafeUserOutputBuffer() | 第三個參數(Length) |
EvtIoWrite() | WdfRequestRetrieveUnsafeUserInputBuffer() | 第三個參數(Length) |