在AddDevice()中,會初始化相關旗標,其中有一個設定是關於I/O Manager的Buffer使用方式
NTSTATUS AddDevice(WDFDRIVER myDriver, PWDFDEVICE_INIT pMyDeviceInit) { ... WdfDeviceInitSetIoType(pMyDeviceInit, WdfDeviceIoBuffered); ... }
該參數主要用於什麼地方呢?
當User Application透過檔案系統跟驅動程式溝通時,User Application會將Buffer Pointer傳給Win32 API
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) |