49、Windows驅動程式模型設計筆記(七),IRP

來源:互聯網
上載者:User

一、IRP

MdlAddress(PMDL)域指向一個記憶體描述符表(MDL),該表描述了一個與該請求關聯的使用者模式緩衝區。如果頂級裝置對象的Flags域為DO_DIRECT_IO,則I/O管理器為IRP_MJ_READ或IRP_MJ_WRITE請求建立這個MDL。如果一個IRP_MJ_DEVICE_CONTROL請求的控制碼指定METHOD_IN_DIRECT或METHOD_OUT_DIRECT操作方式,則I/O管理器為該請求使用的輸出緩衝區建立一個MDL。MDL本身用於描述使用者模式虛擬緩衝區,但它同時也含有該緩衝區鎖定記憶體頁的物理地址。

    AssociatedIrp(union)域是一個三指標聯合。其中,與WDM驅動程式相關的指標是AssociatedIrp.SystemBuffer。 SystemBuffer指標指向一個資料緩衝區,該緩衝區位於核心模式的非分頁式記憶體中。對於IRP_MJ_READ和IRP_MJ_WRITE操作,如果頂級裝置指定DO_BUFFERED_IO標誌,則I/O管理器就建立這個資料緩衝區。對於IRP_MJ_DEVICE_CONTROL操作,如果I/O控制功能代碼指出需要緩衝區,則I/O管理器就建立這個資料緩衝區。I/O管理器把使用者模式程式發送給驅動程式的資料複製到這個緩衝區,這也是建立IRP過程的一部分。這些資料可以是與WriteFile調用有關的資料,或者是DeviceIoControl調用中所謂的輸入資料。對於讀請求,裝置驅動程式把讀出的資料填到這個緩衝區,然後I/O管理器再把緩衝區的內容複寫到使用者模式緩衝區。對於指定了METHOD_BUFFERED的I/O控制操作,驅動程式把所謂的輸出資料放到這個緩衝區,然後I/O管理器再把資料複製到使用者模式的輸出緩衝區。

    IoStatus(IO_STATUS_BLOCK)是一個僅包含兩個域的結構,驅動程式在最終完成請求時設定這個結構。IoStatus.Status域將收到一個NTSTATUS代碼,而IoStatus.Information的類型為ULONG_PTR,它將收到一個資訊值,該資訊值的確切含義要取決於具體的IRP類型和請求完成的狀態。Information域的一個公認用法是用於儲存資料轉送操作,如IRP_MJ_READ,的流量總計。某些PnP請求把這個域作為指向另外一個結構的指標,這個結構通常包含查詢請求的結果。

    UserBuffer(PVOID) 對於METHOD_NEITHER方式的IRP_MJ_DEVICE_CONTROL請求,該域包含輸出緩衝區的使用者模式虛擬位址。該域還用於儲存讀寫請求緩衝區的使用者模式虛擬位址,但指定了DO_BUFFERED_IO或DO_DIRECT_IO標誌的驅動程式,其讀寫常式通常不需要訪問這個域。當處理一個METHOD_NEITHER控制操作時,驅動程式能用這個地址建立自己的MDL。

    Tail.Overlay是Tail聯合中的一種結構,它含有幾個對WDM驅動程式有潛在用途的成員。圖示是Tail聯合的組成圖。在這個圖中,以水平方向從左至右是這個聯合的三個可選成員,在垂直方向是每個結構的成員描述。Tail.Overlay.DeviceQueueEntry(KDEVICE_QUEUE_ENTRY)和Tail.Overlay.DriverContext(PVOID[4])是Tail.Overlayare內一個未命名聯合的兩個可選成員(只能出現一個)。I/O管理器把DeviceQueueEntry作為裝置標準請求隊列中的串連域。當IRP還沒有進入某個隊列時,如果你擁有這個IRP你可以使用這個域,你可以任意使用DriverContext中的四個指標。Tail.Overlay.ListEntry(LIST_ENTRY)僅能作為你自己實現的私人隊列的串連域。

二、IO堆棧

    任何核心模式程式在建立一個IRP時,同時還建立了一個與之關聯的IO_STACK_LOCATION結構數組:數組中的每個堆棧單元都對應一個將處理該IRP的驅動程式,另外還有一個堆棧單元供IRP的建立者使用。堆棧單元中包含該IRP的類型代碼和參數資訊以及完成函數的地址。

圖示. 驅動程式和I/O堆棧之間的平行關係

圖示. I/O堆棧單中繼資料結構

    MajorFunction(UCHAR)是該IRP的主功能碼。這個代碼應該為類似IRP_MJ_READ一樣的值,並與驅動程式對象中MajorFunction表的某個派遣函數指標相對應。

    MinorFunction(UCHAR)是該IRP的副功能碼。

    Parameters(union)是幾個子結構的聯合,每個請求類型都有自己專用的參數,而每個子結構就是一種參數。這些子結構包括Create(IRP_MJ_CREATE請求)、Read(IRP_MJ_READ請求)、StartDevice(IRP_MJ_PNP的IRP_MN_START_DEVICE子類型),等等。

    DeviceObject(PDEVICE_OBJECT)是與該堆棧單元對應的裝置對象的地址。該域由IoCallDriver函數負責填寫。

    FileObject(PFILE_OBJECT)是核心檔案對象的地址,IRP的目標就是這個檔案對象。驅動程式通常在處理清除請求(IRP_MJ_CLEANUP)時使用FileObject指標,以區分隊列中與該檔案對象無關的IRP。

    CompletionRoutine(PIO_COMPLETION_ROUTINE)是一個I/O完成常式的地址,該地址是由與這個堆棧單元對應的驅動程式的更上一層驅動程式設定的。你絕對不要直接設定這個域,應該調用IoSetCompletionRoutine函數,該函數知道如何參考下一層驅動程式的堆棧單元。裝置堆疊的最低一級驅動程式並不需要完成常式,因為它們必須直接完成請求。然而,請求的發起者有時確實需要一個完成常式,但通常沒有自己的堆棧單元。這就是為什麼每一級驅動程式都使用下一級驅動程式的堆棧單元儲存自己完成常式指標的原因。

    Context(PVOID)是一個任意的與上下文相關的值,將作為參數傳遞給完成常式。你絕對不要直接設定該域;它由IoSetCompletionRoutine函數自動化佈建,其值來自該函數的某個參數。

圖示. IRP處理的“標準模型”

1、建立

可以使用下面任何一種函數建立IRP:

•IoBuildAsynchronousFsdRequest 建立非同步IRP(不需要等待其完成)。該函數和下一個函數僅適用於建立某些類型的IRP。

•IoBuildSynchronousFsdRequest 建立同步IRP(需要等待其完成)。

•IoBuildDeviceIoControlRequest 建立一個同步IRP_MJ_DEVICE_CONTROL或IRP_MJ_INTERNAL_DEVICE_CONTROL請求。

•IoAllocateIrp 建立上面三個函數不支援的其它種類的IRP。

2、發往派遣常式

建立完IRP後,你可以調用IoGetNextIrpStackLocation函數獲得該IRP第一個堆棧單元的指標。然後初始化這個堆棧單元。在初始化過程的最後,你需要填充MajorFunction代碼。堆棧單元初始化完成後,就可以調用IoCallDriver函數把IRP發送到裝置驅動程式:

PDEVICE_OBJECT DeviceObject; //something gives you this

PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);

stack->MajorFunction = IRP_MJ_Xxx;

<other initialization of "stack">

NTSTATUS status = IoCallDriver(DeviceObject, Irp);

IoCallDriver函數的第一個參數是你在某處獲得的裝置對象的地址

    IRP中的第一個堆棧單元指標被初始化成指向該堆棧單元之前的堆棧單元,因為I/O堆棧實際上是IO_STACK_LOCATION結構數組,你可以認為這個指標被初始化為指向一個不存在的“-1”元素,因此當我們要初始化第一個堆棧單元時我們實際需要的是“下一個”堆棧單元。IoCallDriver將沿著這個堆棧指標找到第0個表項,並提取我們放在那裡的主功能代碼,在上例中為IRP_MJ_Xxx。然後IoCallDriver函數將利用DriverObject指標找到裝置對象中的MajorFunction表。IoCallDriver將使用主功能代碼索引這個表,最後調用找到的地址(派遣函數)。

NTSTATUS IoCallDriver(PDEVICE_OBJECT device, PIRP Irp)

{

IoSetNextIrpStackLocation(Irp);

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

stack->DeviceObject = device;

ULONG fcn = stack->MajorFunction;

PDRIVER_OBJECT driver = device->DriverObject;

return (*driver->MajorFunction[fcn])(device, Irp);

}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.