標籤:驅動開發
1.
裝置對象一共有三種讀寫方式:緩衝區方式讀寫(Buffered方式);直接方式讀寫(Direct方式);Neither方式。這三種方式的Flags分別對應DO_BUFFERED_IO,DO_DIRECT_IO,0
在buffered方式中,I/O管理器先建立一個與使用者模式資料緩衝區大小相等的系統緩衝區。而你的驅動程式將使用這個系統緩衝區工作。I/O管理器負責在系統緩衝區和使用者模式緩衝區之間複製資料。
在direct方式中,I/O管理器鎖定了包含使用者模式緩衝區的實體記憶體頁,並建立一個稱為MDL(記憶體描述符表)的輔助資料結構來描述鎖定頁。因此你的驅動程式將使用MDL工作。
在neither方式中,I/O管理器僅簡單地把使用者模式的虛擬位址傳遞給你。而使用使用者模式地址的驅動程式應十分小心。
2.
下面介紹緩衝區方式讀寫。其優點是比較簡單的解決了將使用者地址傳入驅動的問題,缺點是需要使用者模式和核心模式之間資料複製,可想而知,運行效率會受到影響。適合少量記憶體操作時使用的一種方法。
現在以readfile為例,首先應用程式中需要提供一段緩衝區並把緩衝區大小作為參數傳入,例如
UCHAR OutputBuffer[10];
DWORD RetLen = 0;
readfile(hDevice,OutputBuffer,sizeof(OutputBuffer),&RetLen,NULL);
OutputBuffer是提供的輸出緩衝區,是使用者模式的記憶體位址,作業系統將此緩衝區的資料複製到核心模式下的地址中,sizeof(OutputBuffer)是緩衝區的大小,而RetLen是真正的輸出的位元組數。
那麼核心模式怎麼得到此核心模式地址呢?怎麼得到writefile或readfile的位元組數呢?答案在下面。
此核心模式下的地址可以通過此readfile建立的IRP的AssociatedIrp.SystemBuffer得到。
假如請求的IRP為PIRP pIrp(一般是派遣函數的參數),那麼UCHAR* OutputBuffer= (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
而readfile請求的位元組數為IO_STACK_LOCATION中的Parameters.Read.Length,writefilew為IO_STACK_LOCATION中的Parameters.Write.Length
//得到當前堆棧
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
//得到readfile緩衝區大小
ULONG cbread = stack->Parameters..Read.Length;
//得到writefile緩衝區大小
ULONG cbwrite = stack->Parameters.Write.Length;
得到了核心模式下的緩衝區地址了就可以對此緩衝區操作了。比如:
UCHAR* OutputBuffer= (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
ULONG cbread = stack->Parameters..Read.Length;
memcpy(OutputBuffer,0xBB,cbread);
這樣使用者模式下的緩衝區內得到的資料是0xBB。
另外還要設定實際操作的位元組數,pIrp->IoStatus.Information = cbread;(實際操作的位元組數不一定要設定為緩衝區的大小,但也不應該大於緩衝區的大小)
那麼使用者模式下readfile的RetLen被設定為cbread。
3.
附加說明:如果使用者模式調用DeviceIoControl的話,緩衝區的資訊獲得方式如下:
//得到當前堆棧
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
//得到輸入緩衝區大小
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
//得到輸出緩衝區大小
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
//輸入緩衝區資料
UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
//操作輸出緩衝區
UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
pIrp->IoStatus.Information = 實際操作位元組數。
驅動開發之 裝置讀寫方式:緩衝區方式