搭配 PIO 使用直接 I/O
使用程式設計 I/O (PIO) ,而不是 DMA 的驅動程式,必須將使用者空間緩衝區加倍地對應到系統空間位址範圍。 下圖說明 I/O 管理員如何為使用直接 I/O 的 PIO 傳輸作業設定 IRP_MJ_READ 要求。
此圖顯示使用 PIO 的裝置如何處理相同的工作。
某些使用者空間虛擬位址範圍代表目前線程的緩衝區,而且該緩衝區的內容實際上可能會儲存在部分實際不明確的頁面上。 如果緩衝區長度為非零,I/O 管理員會建立 MDL 來描述此緩衝區。
I/O 管理員會服務目前線程的讀取要求,其中線程會傳遞代表緩衝區的使用者空間虛擬位址範圍。
I/O 管理員或 FSD 會檢查使用者提供的緩衝區是否有協助工具。 如果 I/O 管理員已建立 MDL,它會使用 MDL 呼叫 MmProbeAndLockPages ,以指定使用者緩衝區的虛擬位址範圍。 MmProbeAndLockPages 也會填入 MDL 中對應的實體位址範圍。
I/O 管理員會在要求傳輸作業的 IRP 中,提供 MDL (MdlAddress) 指標。 在驅動程式完成 IRP 之後,I/O 管理員或檔案系統呼叫 MmUnlockPages 之前,MDL 中所述的實體頁面會保持鎖定狀態,並指派給緩衝區。 不過,這類 MDL 中的虛擬位址可能會變成不可見 (和不正確) ,即使在 IRP 傳送到設備磁碟機或可能分層到設備磁碟機上方的任何中繼驅動程式之前也一樣。
如果驅動程式需要系統 (虛擬) 位址,驅動程式會使用 IRP 的MdlAddress指標呼叫MmGetSystemAddressForMdlSafe,將 MDL中的使用者空間虛擬位址對應至系統空間位址範圍。 在上圖中,AliasBuff 代表描述雙對應位址的 MDL。
驅動程式會使用系統空間虛擬位址範圍,從兩次對應的 MDL (AliasBuff) 將資料讀入記憶體中。
當驅動程式呼叫 IoCompleteRequest來完成 IRP 時,如果驅動程式呼叫 MmGetSystemAddressForMdlSafe,I/O 管理員或檔案系統會釋放 MDL 的雙對應系統空間範圍。 I/O 管理員或檔案系統會解除鎖定 MDL 中所述的頁面,並代表驅動程式處置 MDL 和 IRP。 為了提升效能,驅動程式應該避免將 MDL 實體位址對應至系統空間,如步驟 3 所述,除非它們必須使用虛擬位址。 這麼做會不必要地使用系統頁面資料表專案,而且可以降低驅動程式效能和延展性。 此外,如果系統用完頁面資料表專案,系統可能會當機,因為大部分較舊的驅動程式無法處理這種情況。
目前使用者執行緒的緩衝區和執行緒本身保證只有在該執行緒為目前時,才會駐留在實體記憶體中。 針對上圖所示的執行緒,其使用者緩衝區的內容可以在另一個進程的執行緒執行時分頁到次要儲存體。 執行另一個進程的執行緒時,除非記憶體管理員已鎖定並保留包含原始執行緒緩衝區的對應實體頁面,否則可以覆寫要求執行緒緩衝區的系統實體記憶體。
不過,即使記憶體管理員保留緩衝區的實體頁面,原始執行緒的虛擬位址也不會在目前線程時保持可見。 因此,驅動程式無法使用 MmGetMdlVirtualAddress 傳回的虛擬位址來存取記憶體。 此常式的呼叫端必須將結果傳遞至 MapTransfer (以及 IRP 的 MdlAddress 指標) ,才能使用封包型系統或匯流排主機 DMA 傳輸資料。