在AddDevice()中,當Create Device後,必須初始化相關旗標,其中有一個設定是關於I/O Manager的Buffer使用方式
static NTSTATUS AddDevice(PDRIVER_OBJECT pMyDriver, PDEVICE_OBJECT pPhyDevice) { ... pMyDevice->Flags |= DO_BUFFERED_IO; ... }
該Flags主要用於什麼地方呢?
當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); ... }
szBuffer是User Buffer Pointer
當User Application呼叫ReadFile()、WriteFile()後,I/O Manager會呼叫驅動程式的IRP_MJ_READ、IRP_MJ_WRITE 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使用方式
使用方式 | 行為描述 |
---|---|
DO_BUFFERED_IO | I/O Manager會新增一塊跟User Buffer一樣大小的記憶體,讀寫都需要由I/O Manager負責同步更新(進行複製的動作) |
DO_DIRECT_IO | I/O Manager會Mapping User Buffer到一個MDL(Memory Description List),驅動程式使用這個MDL進行操作,相較於DO_BUFFERED_IO,因為資料不須由I/O Manager做複製的動作,因此,效率會比較好 |
DO_NEITHER_IO | Microsoft沒有定義DO_NEITHER_IO這個旗標,而Neither I/O的意思是Neither Buffered Nor Direct I/O,因此,當沒有設定DO_BUFFERED_IO或DO_DIRECT_IO時,就會使用Neither的方式,使用這種方式時,I/O Manager會將Use Buffer Pointer,透過特殊操作後,再傳遞給驅動程式使用,因為,驅動程式可以直接存取User Buffer的資料,因此,效率是這三種方式裡面最好的一個 |
驅動程式必須依據Buffer的設定去存取不同欄位的Pointer,這樣才可以正確存取到User Buffer
使用方式 | IRP | Buffer Pointer | Buffer Length |
---|---|---|---|
DO_BUFFERED_IO | IRP_MJ_READ | (IRP) AssociatedIrp.SystemBuffer | (IrpStack) Parameters.Read.Length |
IRP_MJ_WRITE | (IRP) AssociatedIrp.SystemBuffer | (IrpStack) Parameters.Write.Length | |
DO_DIRECT_IO(PIO) | IRP_MJ_READ | (MDL) MmGetSystemAddressForMdlSafe | (MDL) MmGetMdlByteCount |
IRP_MJ_WRITE | (MDL) MmGetSystemAddressForMdlSafe | (MDL) MmGetMdlByteCount | |
DO_DIRECT_IO(DMA) | IRP_MJ_READ | (MDL) MmGetMdlVirtualAddress | (MDL) MmGetMdlByteCount |
IRP_MJ_WRITE | (MDL) MmGetMdlVirtualAddress | (MDL) MmGetMdlByteCount | |
DO_NEITHER_IO | IRP_MJ_READ | (IRP) UserBuffer | (IrpStack) Parameters.Read.Length |
IRP_MJ_WRITE | (IRP) UserBuffer | (IrpStack) Parameters.Write.Length |
DO_BUFFERED_IO的流程(IRP_MJ_READ)
DO_DIRECT_IO(PIO)的流程(IRP_MJ_READ)
DO_DIRECT_IO(DMA)的流程(IRP_MJ_READ)