共用方式為


IOMMU DMA 重新對應

本頁說明 Windows 11 22H2 (WDDM 3.0) 中引進的 IOMMU DMA 重新對應功能 (IOMMUv2) 。 如需 WDDM 3.0 之前 IOMMU GPU 隔離的相關資訊,請參閱 IOMMU 型 GPU 隔離

概觀

直到 WDDM 3.0 為止, Dxgkrnl 僅支援透過 1:1 實體重新對應來隔離 IOMMU,這表示 GPU 所存取的邏輯頁面會轉譯為相同的實體頁碼。 IOMMU DMA 重新映射允許 GPU 通過不再 1:1 映射的邏輯地址訪問內存。 相反地, Dxgkrnl 能夠提供邏輯上連續的位址範圍。

Dxgkrnl 對 GPU 施加了限制:GPU 必須能夠存取所有實體記憶體,裝置才能啟動。 如果 GPU 的最高可見位址不超過系統上安裝的最高實體位址,則 Dxgkrnl 會失敗配接器的初始化。 即將推出的服務器和高端工作站可以配置超過 1 TB 的內存,這跨越了許多 GPU 常見的 40 位地址空間限制。 DMA 重新對應會用作允許 GPU 在此環境中運作的機制。

在啟動時, Dxgkrnl 會藉由將裝置的最高可存取實體位址與系統上安裝的記憶體進行比較,以判斷是否需要邏輯重新對應。 如有必要,DMA 重新對應可用來將 GPU 可見界限內的邏輯位址範圍對應至系統上的任何實體記憶體。 例如,如果 GPU 的限制為 1 TB,則 Dxgkrnl 會從 [0, 1 TB) 配置邏輯位址,然後可以透過 IOMMU 對應至系統上的任何實體記憶體。

邏輯配接卡與實體配接卡

Dxgkrnl 區分邏輯配接器和實體配接器的概念。 實體適配器代表可能與其他裝置連結在一起的獨立硬體裝置,形成一個LDA 鏈。 邏輯配接卡代表一或多個鏈結的實體配接卡。

每個邏輯配接卡都會建立單一 IOMMU DMA 網域,並連接至所有連接的實體配接卡。 因此,所有實體配接卡都會共用相同的網域和相同的實體記憶體檢視。

整合式 GPU 與獨立式 GPU 支援

由於 IOMMU DMA 重新對應對內建 GPU 幾乎沒有價值,因為從定義上來說,這些 GPU 應已經設計為能存取系統中的所有實體記憶體,因此在內建零件上實施支援是可選的,但建議使用。

要獲得 WDDM 3.0 認證,離散 GPU 必須支援 IOMMU DMA 重新對應。

DDI 變更

進行了下列 DDI 變更以支援 IOMMU DMA 重新映射。

驅動程式功能

需要兩組驅動程式上限才能支援線性重新對應:

Dxgkrnl 透過 DXGKDDI_START_DEVICE 啟動裝置之前,必須提供這兩個上限,以便在存取任何記憶體之前建立裝置並將其連結至 IOMMU 網域。 只有在裝置未參考任何現有實體記憶體時,才能執行線性重映射。

獨享存取

IOMMU 網域連結和卸離速度極快,但目前並非不可部分完成。 此狀況表示透過 PCIe 發出的交易在交換至具有不同對應的 IOMMU 網域時,不保證能夠正確轉譯。

若要處理這種情況,從 Windows 10 1803 版 (WDDM 2.4) 開始,KMD 必須實作下列 DDI 配對,讓 Dxgkrnl 呼叫:

每當裝置切換到新的 IOMMU 網域時,驅動程式必須確保其硬體為無訊息。 也就是說,驅動程式必須確保它不會在這兩個呼叫之間從裝置讀取或寫入系統記憶體。

在這兩個呼叫之間, Dxgkrnl 會做出下列保證:

  • 排程器已暫停。 所有作用中的工作負載都會被清除,且不會將新的工作負載傳送至硬體或在硬體上排程。
  • 不會進行其他 DDI 呼叫。

作為這些呼叫的一部分,驅動程式可以選擇在獨佔存取期間停用和隱藏中斷 (包括垂直同步中斷) ,即使沒有來自 OS 的明確通知。

地址描述子清單

為了支援實體和邏輯存取模式,並在運行時間無縫切換兩種模式, Dxgkrnl 提供描述位址描述元清單 (ADL) 的 DXGK_ADL 結構。 此資料結構類似於 MDL,但描述可以是實體或邏輯頁面的陣列。 因為這些頁面可以是邏輯頁面,所以 ADL 所描述的位址無法對應至虛擬位址,以進行直接 CPU 存取。

DxgkddiBuildpagingbuffer 的 DXGK_OPERATION_MAP_APERTURE_SEGMENT2 作業

VidMm 提供 DXGK_OPERATION_MAP_APERTURE_SEGMENT2 的分頁緩衝模式,用來將記憶體映射到孔徑區段,因為先前版本使用的 MDL 與邏輯位址不相容。 支援邏輯位址重新對應的 WDDM 3.0 驅動程式的 DxgkddiBuildpagingbuffer 回呼會接收 DXGK_OPERATION_MAP_APERTURE_SEGMENT2 模式的呼叫,而且不再接收原始 DXGK_OPERATION_MAP_APERTURE_SEGMENT 模式的呼叫。

需要此作業才能支援邏輯 DMA 重新對應。 其行為與原始作業類似,但提供 DXGK_ADL 而不是 MDL

typedef enum _DXGK_BUILDPAGINGBUFFER_OPERATION
{
#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM2_9)
    DXGK_OPERATION_MAP_APERTURE_SEGMENT2 = 17,
#endif //  DXGKDDI_INTERFACE_VERSION
};

// struct _DXGKARG_BUILDPAGINGBUFFER:
struct
{
    HANDLE  hDevice;
    HANDLE  hAllocation;
    UINT    SegmentId;
    SIZE_T  OffsetInPages;
    SIZE_T  NumberOfPages;
    DXGK_ADL Adl;
    DXGK_MAPAPERTUREFLAGS Flags;
    ULONG   AdlOffset;
    PVOID   CpuVisibleAddress;
} MapApertureSegment2;

若要選擇加入DXGK_OPERATION_MAP_APERTURE_SEGMENT2作業,驅動程式必須指出記憶體管理上限MapApertureSegment2 呼叫的支援:

typedef struct _DXGK_VIDMMCAPS {
  union {
    struct {
        ...
        UINT MapAperture2Supported : 1;
        ...
    }
    ...
} DXGK_VIDMMCAPS;

DXGK_VIDMMCAPS記憶體管理上限是DXGK_DRIVERCAPS資料結構的一部分。 驅動程式在未啟用此支援時,無法使用 DMA 重新對應(即邏輯位址重新對應)功能。

某些驅動程式可能需要 CPU 存取記憶體,以便在 MapApertureSegment2 呼叫期間使用。 這項功能可選擇性地透過另一個 MapApertureSegment2.CpuVisibleAddress 參數提供。 此位址是核心模式的虛擬位址,只要配置被映射到光圈區段,該位址仍然有效。 也就是說,該位址將在對應的 DXGK_OPERATION_UNMAP_APERTURE_SEGMENT 呼叫相同分配後立即被釋放。

不是所有分配都需要這個位址。 MapApertureCpuVisible 旗標已新增至配置旗標,以指出何時需要此位址。

如果未指定 MapApertureCpuVisible ,則 MapApertureSegment2.CpuVisibleAddress 對於 DXGK_OPERATION_MAP_APERTURE_SEGMENT2 作業會為 Null。

MapApertureCpuVisibleDxgkDdiBuildPagingBufferMapAperatureSegment2 功能的一部分,因此驅動程式必須設定 DXGK_VIDMMCAPS MapAperature2Supported 才能使用此字段。 如果未設定 MapAperature2Supported ,但驅動程式指定 MapApertureCpuVisible,則呼叫 DxgkDdiCreateAllocation 會失敗。

此外,若要接收 DXGK_OPERATION_MAP_APERTURE_SEGMENT2 作業,驅動程式必須設定 DXGK_ALLOCATIONINFOFLAGS_WDDM2_0 AccessedPhysical 旗標。 如果未設定 AccessedPhysically ,則在其支援的區段集中指定光圈區段的任何配置都會升級為隱含的系統記憶體區段,該區段不會接收MAP_APERTURE呼叫 (,因為沒有要對應的光圈範圍) 。

總而言之,若要正確接收系統記憶體配置的 CPU 位址,驅動程式必須設定下列旗標/上限:

  • DXGK_DRIVERCAPS::MemoryManagementCaps.MapAperture2Supported = 1
  • DXGK_ALLOCATIONINFOFLAGS_WDDM2_0::MapApertureCpuVisible = 1
  • DXGK_ALLOCATIONINFOFLAGS_WDDM2_0::AccessedPhysically = 1

針對 MapApertureSegment2 呼叫,啟用邏輯映射時,ADL 始終初始化並以連續方式傳遞。 驅動程式必須檢查 ADL 標誌,以判斷記憶體配置是否為連續性配置,並根據結果採取相應的行動。

記憶體管理服務

記憶體管理功能有三個基本需求:

  1. 管理實體記憶體的能力。 這項功能可能包括透過非分頁記憶體函式 (例如 MmAllocatePagesforMdlMmAllocateContiguousMemory) 配置記憶體,以及分頁記憶體函式 (例如 ZwCreateSectionZwAllocateVirtualMemory) 。 還需要表達 IO 空間範圍的能力。

  2. 從物理記憶體中映射出 GPU 可見的邏輯地址的能力。 這項功能會為呼叫端提供一個邏輯頁面的清單,就像 MDL 的 PFN 陣列一樣,GPU 可以被程式設計來存取。 呼叫這些函式可確保基礎實體頁面已鎖定且無法分頁。

  3. 能夠在使用者模式和核心模式中,使用指定的快取類型 (快取與寫入組合) 從實體記憶體對應 CPU 虛擬位址。

下表列出引進的 DDI(設備驅動介面)和相關的輸入結構,用來描述實體記憶體的分配及邏輯/虛擬視圖的映射。 這些 DDI 是更新版的,用來取代先前提供給驅動程式的回呼,作為管理 IOMMU 對應的工具(DxgkCbAllocatePagesforMdlDxgkCbAllocateContiguousMemoryDxgkCbMapMdlToIoMmu)。 針對支援邏輯重新對應的 WDDM 3.0 驅動程式,這些較舊的回呼函式已被取代,而且無法使用。 驅動程式應該改用下列記憶體管理回呼函式。

回呼函式必須在 IRQL <= APC_LEVEL 呼叫。 從 WDDM 3.2 開始,若驅動程式在呼叫任何這些函式時,IRQL 水準達到或超過 DISPATCH_LEVEL,將根據此需求進行驗證並啟動錯誤檢查。

回調 相關聯的回呼結構
DXGKCB_CREATEPHYSICALMEMORYOBJECT DXGKARGCB_CREATE_PHYSICAL_MEMORY_OBJECT
DXGKCB_DESTROYPHYSICALMEMORYOBJECT DXGKARGCB_DESTROY_PHYSICAL_MEMORY_OBJECT
DXGKCB_MAPPHYSICALMEMORY DXGKARGCB_MAP_PHYSICAL_MEMORY
DXGKCB_UNMAPPHYSICALMEMORY DXGKARGCB_UNMAP_PHYSICAL_MEMORY
DXGKCB_ALLOCATEADL DXGKARGCB_ALLOCATE_ADL
DXGKCB_FREEADL
DXGKCB_OPENPHYSICALMEMORYOBJECT DXGKARGCB_OPEN_PHYSICAL_MEMORY_OBJECT
DXGKCB_CLOSEPHYSICALMEMORYOBJECT DXGKARGCB_CLOSE_PHYSICAL_MEMORY_OBJECT

INF 變更

每個支援的裝置類型都必須將下列登錄機碼和值新增至 INF 的適當區段:

[DMAr.reg]
; Add REG_DWORD 'DmaRemappingCompatible' with value of 3 
HKR,Parameters,DmaRemappingCompatible,0x00010001,```3

此值告知 PnP 系統該裝置支援 DMA 重新對應。 然後,Dxgkrnl 和 HAL 會協調,以判斷應使用哪種類型的對應模式 (重新對應、傳遞等)。

雖然此登錄機碼存在於舊版 Windows 上,但值 '3' 從 Windows 10 版本 1803 (WDDM 2.4) 開始是唯一的,而且在不支援它的舊版本上會忽略。 此獨特的值可讓驅動程式在 INF 中設定此機碼,而不必擔心更低層級的相容性問題。