IOMMUFD

作者:

Jason Gunthorpe

作者:

Kevin Tian

概述

IOMMUFD 是使用者 API,用於控制 IOMMU 子系統,因為它涉及使用檔案描述符從使用者空間管理 IO 頁表。 它旨在通用並可被任何想要向用戶空間公開 DMA 的驅動程式使用。 預計這些驅動程式最終將棄用它們可能已經/歷史上實現的任何內部 IOMMU 邏輯(例如,vfio_iommu_type1.c)。

IOMMUFD 至少提供對所有 IOMMU 的 I/O 地址空間和 I/O 頁表的通用管理支援,並在設計中留有空間以新增非通用功能以滿足特定硬體功能。

在這種上下文中,大寫字母 (IOMMUFD) 指的是子系統,而小寫字母 (iommufd) 指的是透過 /dev/iommu 建立的供使用者空間使用的檔案描述符。

關鍵概念

使用者可見物件

以下 IOMMUFD 物件暴露給使用者空間

  • IOMMUFD_OBJ_IOAS,表示 I/O 地址空間 (IOAS),允許將使用者空間記憶體對映/取消對映到 I/O 虛擬地址 (IOVA) 範圍中。

    IOAS 是 VFIO 容器的功能替代品,與 VFIO 容器一樣,它將 IOVA 映射覆制到其中包含的 iommu_domains 列表中。

  • IOMMUFD_OBJ_DEVICE,表示由外部驅動程式繫結到 iommufd 的裝置。

  • IOMMUFD_OBJ_HWPT_PAGING,表示由 iommu 驅動程式管理的實際硬體 I/O 頁表(即,單個 struct iommu_domain)。“PAGING”主要指示此型別的 HWPT 應連結到 IOAS。它還表明它由具有 __IOMMU_DOMAIN_PAGING 特性標誌的 iommu_domain 支援。這可以是執行在使用者空間中的裝置的 UNMANAGED 階段 1 域,也可以是從客戶機級別物理地址到主機級別物理地址的對映的巢狀父級階段 2 域。

    IOAS 具有共享相同 IOVA 對映的 HWPT_PAGING 列表,它將使其對映與每個成員 HWPT_PAGING 同步。

  • IOMMUFD_OBJ_HWPT_NESTED,表示由使用者空間(例如,客戶機作業系統)管理的實際硬體 I/O 頁表(即,單個 struct iommu_domain)。“NESTED”表示此型別的 HWPT 應連結到 HWPT_PAGING。它還表明它由型別為 IOMMU_DOMAIN_NESTED 的 iommu_domain 支援。這必須是執行在使用者空間中的裝置的階段 1 域(例如,在啟用 IOMMU 巢狀轉換特性的客戶機 VM 中。)因此,必須使用給定的巢狀父級階段 2 域來建立它才能關聯。此由使用者空間管理的巢狀階段 1 頁表通常具有從客戶機級別 I/O 虛擬地址到客戶機級別物理地址的對映。

  • IOMMUFD_FAULT,表示一個軟體佇列,用於 HWPT 使用 IOMMU HW 的 PRI(頁面請求介面)報告 IO 頁面錯誤。此佇列物件為使用者空間提供一個 FD 來輪詢頁面錯誤事件並響應這些事件。必須首先建立一個 FAULT 物件以獲得一個 fault_id,然後可以透過在 IOMMU_HWPT_ALLOC 命令中設定其 flags 欄位中的 IOMMU_HWPT_FAULT_ID_VALID 位來分配一個啟用錯誤的 HWPT。

  • IOMMUFD_OBJ_VIOMMU,表示物理 IOMMU 例項的一個切片,傳遞給 VM 或與 VM 共享。它可能是某些 HW 加速的虛擬化特性和 VM 使用的一些 SW 資源。例如

    • 客戶機擁有的 ID 的安全名稱空間,例如,客戶機控制的快取標記

    • 非裝置相關的事件報告,例如,無效佇列錯誤

    • 跨物理 IOMMU 訪問可共享的巢狀父級頁表

    • 各種平臺 ID 的虛擬化,例如,RID 和其他 ID

    • 提供準虛擬化無效

    • 直接分配的無效佇列

    • 直接分配的中斷

    這樣的 vIOMMU 物件通常可以訪問巢狀父級頁表以支援某些 HW 加速的虛擬化特性。因此,必須給定一個巢狀父級 HWPT_PAGING 物件來建立 vIOMMU 物件,然後它將封裝該 HWPT_PAGING 物件。因此,可以使用 vIOMMU 物件來分配封裝的 HWPT_PAGING 物件,而不是分配 HWPT_NESTED 物件。

    注意

    名稱“vIOMMU”不一定與 VM 中的虛擬化 IOMMU 相同。VM 可以在具有多個物理 IOMMU 的機器上執行一個巨大的虛擬化 IOMMU,在這種情況下,VMM 會將來自此單個虛擬化 IOMMU 例項的請求或配置分派給為不同物理 IOMMU 的各個切片建立的多個 vIOMMU 物件。換句話說,vIOMMU 物件始終是一個物理 IOMMU 的表示,不一定是虛擬化 IOMMU 的表示。對於想要來自物理 IOMMU 的完整虛擬化特性的 VMM,建議構建與物理 IOMMU 數量相同的虛擬化 IOMMU,以便傳遞的裝置連線到由相應 vIOMMU 物件支援的它們自己的虛擬化 IOMMU,在這種情況下,客戶機作業系統會自然地進行“分派”,而不是 VMM 陷阱。

  • IOMMUFD_OBJ_VDEVICE,表示針對 IOMMUFD_OBJ_VIOMMU 的 IOMMUFD_OBJ_DEVICE 的虛擬裝置。此虛擬裝置儲存裝置的虛擬資訊或屬性(與 vIOMMU 相關)在 VM 中。一個直接的 vDATA 示例可以是裝置在 vIOMMU 上的虛擬 ID,這是一個 VMM 分配給裝置的唯一 ID,用於 vIOMMU 的轉換通道/埠,例如 ARM SMMUv3 的 vSID、AMD IOMMU 的 vDeviceID 和 Intel VT-d 的 vRID 到上下文表。一些高階安全資訊的潛在用例也可以透過此物件轉發,例如,機密計算架構中的安全級別或領域資訊。當 VMM 將裝置連線到 vIOMMU 時,它應該建立一個 vDEVICE 物件以轉發 VM 中的所有裝置資訊,這是與將同一裝置附加到 vIOMMU 保持的 HWPT_PAGING 分開的 ioctl 呼叫。

  • IOMMUFD_OBJ_VEVENTQ,表示 vIOMMU 用於報告其事件(例如,發生到巢狀階段 1 的轉換錯誤(不包括應透過 IOMMUFD_OBJ_FAULT 發生的 I/O 頁面錯誤)和特定於 HW 的事件)的軟體佇列。此佇列物件為使用者空間提供一個 FD 來輪詢/讀取 vIOMMU 事件。必須首先建立一個 vIOMMU 物件以獲得其 viommu_id,然後可以使用該 viommu_id 來分配 vEVENTQ。每個 vIOMMU 可以支援多種型別的 vEVENT,但每個 vEVENTQ 型別限制為一個 vEVENTQ。

所有使用者可見的物件都透過 IOMMU_DESTROY uAPI 銷燬。

下圖顯示了使用者可見物件和核心資料結構(iommufd 外部)之間的關係,數字是指建立物件和連結的操作

 _______________________________________________________________________
|                      iommufd (HWPT_PAGING only)                       |
|                                                                       |
|        [1]                  [3]                                [2]    |
|  ________________      _____________                        ________  |
| |                |    |             |                      |        | |
| |      IOAS      |<---| HWPT_PAGING |<---------------------| DEVICE | |
| |________________|    |_____________|                      |________| |
|         |                    |                                  |     |
|_________|____________________|__________________________________|_____|
          |                    |                                  |
          |              ______v_____                          ___v__
          | PFN storage |  (paging)  |                        |struct|
          |------------>|iommu_domain|<-----------------------|device|
                        |____________|                        |______|

 _______________________________________________________________________
|                      iommufd (with HWPT_NESTED)                       |
|                                                                       |
|        [1]                  [3]                [4]             [2]    |
|  ________________      _____________      _____________     ________  |
| |                |    |             |    |             |   |        | |
| |      IOAS      |<---| HWPT_PAGING |<---| HWPT_NESTED |<--| DEVICE | |
| |________________|    |_____________|    |_____________|   |________| |
|         |                    |                  |               |     |
|_________|____________________|__________________|_______________|_____|
          |                    |                  |               |
          |              ______v_____       ______v_____       ___v__
          | PFN storage |  (paging)  |     |  (nested)  |     |struct|
          |------------>|iommu_domain|<----|iommu_domain|<----|device|
                        |____________|     |____________|     |______|

 _______________________________________________________________________
|                      iommufd (with vIOMMU/vDEVICE)                    |
|                                                                       |
|                             [5]                [6]                    |
|                        _____________      _____________               |
|                       |             |    |             |              |
|      |----------------|    vIOMMU   |<---|   vDEVICE   |<----|        |
|      |                |             |    |_____________|     |        |
|      |                |             |                        |        |
|      |      [1]       |             |          [4]           | [2]    |
|      |     ______     |             |     _____________     _|______  |
|      |    |      |    |     [3]     |    |             |   |        | |
|      |    | IOAS |<---|(HWPT_PAGING)|<---| HWPT_NESTED |<--| DEVICE | |
|      |    |______|    |_____________|    |_____________|   |________| |
|      |        |              |                  |               |     |
|______|________|______________|__________________|_______________|_____|
       |        |              |                  |               |
 ______v_____   |        ______v_____       ______v_____       ___v__
|   struct   |  |  PFN  |  (paging)  |     |  (nested)  |     |struct|
|iommu_device|  |------>|iommu_domain|<----|iommu_domain|<----|device|
|____________|   storage|____________|     |____________|     |______|
  1. IOMMUFD_OBJ_IOAS 是透過 IOMMU_IOAS_ALLOC uAPI 建立的。一個 iommufd 可以儲存多個 IOAS 物件。IOAS 是最通用的物件,並且不公開特定於單個 IOMMU 驅動程式的介面。對 IOAS 的所有操作都必須在其中的每個 iommu_domain 上平等地操作。

  2. 當外部驅動程式呼叫 IOMMUFD kAPI 以將裝置繫結到 iommufd 時,會建立 IOMMUFD_OBJ_DEVICE。預期該驅動程式實現一組 ioctl 以允許使用者空間啟動繫結操作。成功完成此操作將建立對裝置的所需 DMA 所有權。驅動程式還必須設定 driver_managed_dma 標誌,並且在此操作成功之前不得觸控該裝置。

  3. IOMMUFD_OBJ_HWPT_PAGING 可以透過兩種方式建立

    • 當外部驅動程式呼叫 IOMMUFD kAPI 以將繫結的裝置附加到 IOAS 時,會自動建立 IOMMUFD_OBJ_HWPT_PAGING。同樣,外部驅動程式 uAPI 允許使用者空間啟動附加操作。如果 IOAS 的 HWPT_PAGING 列表中存在相容的成員 HWPT_PAGING 物件,則將重複使用它。否則,將建立一個表示使用者空間的 iommu_domain 的新 HWPT_PAGING,然後將其新增到列表中。成功完成此操作將設定 IOAS、裝置和 iommu_domain 之間的連結。一旦完成,裝置就可以進行 DMA。

    • 可以透過 IOMMU_HWPT_ALLOC uAPI 手動建立 IOMMUFD_OBJ_HWPT_PAGING,前提是提供透過 @pt_id 的 ioas_id 以將新的 HWPT_PAGING 關聯到相應的 IOAS 物件。此手動分配的好處是允許分配標誌(在 enum iommufd_hwpt_alloc_flags 中定義),例如,如果設定了 IOMMU_HWPT_ALLOC_NEST_PARENT 標誌,則它會分配一個巢狀父級 HWPT_PAGING。

  4. 只能透過 IOMMU_HWPT_ALLOC uAPI 手動建立 IOMMUFD_OBJ_HWPT_NESTED,前提是提供透過 @pt_id 的 HWPT_PAGING 或封裝巢狀父級 HWPT_PAGING 的 vIOMMU 物件的 hwpt_id 或 viommu_id 以將新的 HWPT_NESTED 物件關聯到相應的 HWPT_PAGING 物件。關聯的 HWPT_PAGING 物件必須是先前透過同一 uAPI 使用 IOMMU_HWPT_ALLOC_NEST_PARENT 標誌手動分配的巢狀父級,否則分配將失敗。IOMMU 驅動程式將進一步驗證該分配以確保巢狀父級域和要分配的巢狀域是相容的。成功完成此操作將設定 IOAS、裝置和 iommu_domains 之間的連結。一旦完成,裝置就可以透過兩階段轉換(也稱為巢狀轉換)進行 DMA。請注意,可以透過(然後關聯到)同一巢狀父級分配多個 HWPT_NESTED 物件。

    注意

    手動 IOMMUFD_OBJ_HWPT_PAGING 或 IOMMUFD_OBJ_HWPT_NESTED 都是透過同一 IOMMU_HWPT_ALLOC uAPI 建立的。區別在於透過 iommufd_hwpt_alloc 結構的 @pt_id 欄位傳遞的物件型別。

  5. 只能透過 IOMMU_VIOMMU_ALLOC uAPI 手動建立 IOMMUFD_OBJ_VIOMMU,前提是提供 dev_id(用於支援 vIOMMU 的裝置的物理 IOMMU)和 hwpt_id(用於將 vIOMMU 關聯到巢狀父級 HWPT_PAGING)。iommufd 核心會將 vIOMMU 物件連結到 struct device 後面的 struct iommu_device。並且 IOMMU 驅動程式可以實現一個 viommu_alloc 操作以分配其自己的 vIOMMU 資料結構,該資料結構嵌入了核心級結構 iommufd_viommu 和一些驅動程式特定的資料。如有必要,該驅動程式還可以為該 vIOMMU(以及因此為 VM)配置其 HW 虛擬化特性。成功完成此操作將設定 vIOMMU 物件和 HWPT_PAGING 之間的連結,然後可以使用此 vIOMMU 物件作為巢狀父級物件來分配上面描述的 HWPT_NESTED 物件。

  6. 只能透過 IOMMU_VDEVICE_ALLOC uAPI 手動建立 IOMMUFD_OBJ_VDEVICE,前提是提供 iommufd_viommu 物件的 viommu_id 和 iommufd_device 物件的 dev_id。vDEVICE 物件將是這兩個父物件之間的繫結。另一個 @virt_id 也將透過 uAPI 設定,從而為 iommufd 核心提供一個索引,用於將 vDEVICE 物件儲存到每個 vIOMMU 的 vDEVICE 陣列中。如有必要,IOMMU 驅動程式可以選擇實現一個 vdevce_alloc 操作以初始化其 HW 以實現與 vDEVICE 相關的虛擬化特性。成功完成此操作將設定 vIOMMU 和裝置之間的連結。

由於 DMA 所有權宣告,裝置只能繫結到 iommufd,並且最多隻能附加到一個 IOAS 物件(尚不支援 PASID)。

核心資料結構

使用者可見的物件由以下資料結構支援

  • IOMMUFD_OBJ_IOAS 的 iommufd_ioas。

  • IOMMUFD_OBJ_DEVICE 的 iommufd_device。

  • IOMMUFD_OBJ_HWPT_PAGING 的 iommufd_hwpt_paging。

  • IOMMUFD_OBJ_HWPT_NESTED 的 iommufd_hwpt_nested。

  • IOMMUFD_OBJ_FAULT 的 iommufd_fault。

  • IOMMUFD_OBJ_VIOMMU 的 iommufd_viommu。

  • IOMMUFD_OBJ_VDEVICE 的 iommufd_vdevice。

  • IOMMUFD_OBJ_VEVENTQ 的 iommufd_veventq。

檢視這些資料結構時,有幾個術語

  • 自動域 - 指將裝置附加到 IOAS 物件時自動建立的 iommu 域。這與 VFIO type1 的語義相容。

  • 手動域 - 指使用者指定為要由裝置附加的目標頁表的 iommu 域。雖然當前沒有直接建立此類域的 uAPI,但資料結構和演算法已準備好處理該用例。

  • 核心使用者 - 指像 VFIO mdev 這樣的東西,它使用 IOMMUFD 訪問介面來訪問 IOAS。這首先建立一個 iommufd_access 物件,該物件類似於繫結物理裝置的域。然後,訪問物件將允許將 IOVA 範圍轉換為 struct page * 列表,或對 IOVA 進行直接讀/寫。

iommufd_ioas 用作元資料資料結構來管理 IOVA 範圍如何對映到記憶體頁面,由以下組成

  • 儲存 IOVA 對映的 struct io_pagetable

  • 表示已填充 IOVA 部分的 struct iopt_area

  • 表示 PFN 儲存的 struct iopt_pages

  • 表示 IOMMU 中的 IO 頁表的 struct iommu_domain

  • 表示 PFN 的核心使用者的 struct iopt_pages_access

  • struct xarray pinned_pfns,儲存由核心使用者固定的頁面列表

每個 iopt_pages 表示一個完整的 PFN 的邏輯線性陣列。PFN 最終透過 mm_struct 從使用者空間 VA 派生。一旦固定,PFN 將儲存在 iommu_domain 的 IOPTE 中,或者如果它們已透過 iommufd_access 固定,則儲存在 pinned_pfns xarray 中。

PFN 必須在所有儲存位置的組合之間複製,具體取決於存在哪些域以及存在哪些型別的核心“軟體訪問”使用者。該機制確保一個頁面僅固定一次。

io_pagetable 由指向 iopt_pages 的 iopt_areas 組成,以及映象 IOVA 到 PFN 對映的 iommu_domains 列表。

多個 io_pagetable-s 可以透過它們的 iopt_area-s 共享一個 iopt_pages,這避免了多重固定和頁面消耗的雙重計算。

iommufd_ioas 可在子系統(例如,VFIO 和 VDPA)之間共享,只要由不同子系統管理的裝置繫結到同一個 iommufd。

IOMMUFD 使用者 API

通用 ioctl 格式

ioctl 介面遵循通用格式以允許擴充套件。每個 ioctl 都將一個結構指標作為引數傳遞,該引數在第一個 u32 中提供結構的大小。核心檢查它不理解的任何結構空間是否為 0。這允許使用者空間使用向後相容的部分,同時始終使用更新、更大的結構。

ioctls 對常見錯誤使用標準含義

  • ENOTTY:根本不支援 IOCTL 編號本身

  • E2BIG:支援 IOCTL 編號,但提供的結構在核心不理解的部分中具有非零值。

  • EOPNOTSUPP:支援 IOCTL 編號,並且理解該結構,但是已知欄位具有核心不理解或不支援的值。

  • EINVAL:理解了關於 IOCTL 的所有內容,但欄位不正確。

  • ENOENT:提供的 ID 或 IOVA 不存在。

  • ENOMEM:記憶體不足。

  • EOVERFLOW:數學溢位。

以及特定 ioctl 中的其他錯誤。

struct iommu_destroy

ioctl(IOMMU_DESTROY)

定義:

struct iommu_destroy {
    __u32 size;
    __u32 id;
};

成員

size

sizeof(struct iommu_destroy)

id

要銷燬的 iommufd 物件 ID。可以是任何可銷燬的物件型別。

描述

銷燬 iommufd 中儲存的任何物件。

struct iommu_ioas_alloc

ioctl(IOMMU_IOAS_ALLOC)

定義:

struct iommu_ioas_alloc {
    __u32 size;
    __u32 flags;
    __u32 out_ioas_id;
};

成員

size

sizeof(struct iommu_ioas_alloc)

flags

必須為 0

out_ioas_id

分配的物件的輸出 IOAS ID

描述

分配一個 IO 地址空間 (IOAS),該空間儲存一個 IO 虛擬地址 (IOVA) 到記憶體的對映。

struct iommu_iova_range

ioctl(IOMMU_IOVA_RANGE)

定義:

struct iommu_iova_range {
    __aligned_u64 start;
    __aligned_u64 last;
};

成員

start

第一個 IOVA

last

包含性的最後一個 IOVA

描述

IOVA 空間中的一個間隔。

struct iommu_ioas_iova_ranges

ioctl(IOMMU_IOAS_IOVA_RANGES)

定義:

struct iommu_ioas_iova_ranges {
    __u32 size;
    __u32 ioas_id;
    __u32 num_iovas;
    __u32 __reserved;
    __aligned_u64 allowed_iovas;
    __aligned_u64 out_iova_alignment;
};

成員

size

sizeof(struct iommu_ioas_iova_ranges)

ioas_id

要從中讀取範圍的 IOAS ID

num_iovas

輸入/輸出 IOAS 中範圍的總數

__reserved

必須為 0

allowed_iovas

指向 struct iommu_iova_range 的輸出陣列的指標

out_iova_alignment

對映 IOVA 所需的最小對齊

描述

查詢 IOAS 中允許的 IOVA 範圍。不允許在這些範圍之外對映 IOVA。num_iovas 將設定為 iova 的總數,並且 allowed_iovas[] 將在空間允許的情況下填充。

允許的範圍取決於 DMA 操作採用的 HW 路徑,並且可以在 IOAS 的生命週期內更改。一個新的空 IOAS 將具有一個完整範圍,並且每個附加的裝置將根據該裝置的 HW 限制縮小範圍。分離裝置可以擴大範圍。使用者空間應在每次附加/分離後查詢範圍,以瞭解哪些 IOVA 可用於對映。

在輸入時,num_iovas 是 allowed_iovas 陣列的長度。在輸出時,它是填充的 iova 的總數。如果 num_iovas 太小,則 ioctl 將返回 -EMSGSIZE 並將 num_iovas 設定為所需的值。在這種情況下,呼叫者應分配一個更大的輸出陣列並重新發出 ioctl。

out_iova_alignment 返回可以提供給 IOMMU_IOAS_MAP/COPY 的最小 IOVA 對齊方式。IOVA 必須滿足

starting_iova % out_iova_alignment == 0
(starting_iova + length) % out_iova_alignment == 0

out_iova_alignment 可以為 1,指示允許任何 IOVA。它不能高於系統 PAGE_SIZE。

struct iommu_ioas_allow_iovas

ioctl(IOMMU_IOAS_ALLOW_IOVAS)

定義:

struct iommu_ioas_allow_iovas {
    __u32 size;
    __u32 ioas_id;
    __u32 num_iovas;
    __u32 __reserved;
    __aligned_u64 allowed_iovas;
};

成員

size

sizeof(struct iommu_ioas_allow_iovas)

ioas_id

要從中允許 IOVA 的 IOAS ID

num_iovas

輸入/輸出 IOAS 中範圍的總數

__reserved

必須為 0

allowed_iovas

指向 struct iommu_iova_range 陣列的指標

描述

確保始終可以分配一系列 IOVA。如果此呼叫成功,則 IOMMU_IOAS_IOVA_RANGES 將永遠不會返回比此處提供的範圍更窄的 IOVA 範圍列表。如果 IOMMU_IOAS_IOVA_RANGES 當前比給定的範圍更窄,則此呼叫將失敗。

首次建立 IOAS 時,IOVA_RANGES 將最大程度地調整大小,並且隨著裝置的附加,IOVA 將根據裝置限制縮小。指定允許的範圍後,將拒絕任何縮小,即,如果裝置需要在允許的範圍內進行限制,則裝置附加可能會失敗。

自動 IOVA 分配也會受到此呼叫的影響。如果存在允許的 IOVA,則 MAP 將僅在允許的 IOVA 中分配。

此呼叫將整個允許列表替換為給定的列表。

enum iommufd_ioas_map_flags

對映和複製的標誌

常量

IOMMU_IOAS_MAP_FIXED_IOVA

如果清除,核心將計算一個適當的 IOVA 來放置對映

IOMMU_IOAS_MAP_WRITEABLE

允許 DMA 寫入此對映

IOMMU_IOAS_MAP_READABLE

允許 DMA 從此對映讀取

struct iommu_ioas_map

ioctl(IOMMU_IOAS_MAP)

定義:

struct iommu_ioas_map {
    __u32 size;
    __u32 flags;
    __u32 ioas_id;
    __u32 __reserved;
    __aligned_u64 user_va;
    __aligned_u64 length;
    __aligned_u64 iova;
};

成員

size

sizeof(struct iommu_ioas_map)

flags

enum iommufd_ioas_map_flags 的組合

ioas_id

IOAS ID 用於更改對映

__reserved

必須為 0

user_va

使用者空間指標,用於從開始對映

length

要對映的位元組數

iova

對映放置的 IOVA。如果設定了 IOMMU_IOAS_MAP_FIXED_IOVA,則必須將其作為輸入提供。

描述

從使用者指標設定 IOVA 對映。如果指定了 FIXED_IOVA,則對映將在 iova 處建立;否則,將自動選擇一個基於保留列表和允許列表的合適位置,並在 iova 中返回。

如果指定了 IOMMU_IOAS_MAP_FIXED_IOVA,則 iova 範圍當前必須未使用,不能替換現有的 IOVA。

struct iommu_ioas_map_file

ioctl(IOMMU_IOAS_MAP_FILE)

定義:

struct iommu_ioas_map_file {
    __u32 size;
    __u32 flags;
    __u32 ioas_id;
    __s32 fd;
    __aligned_u64 start;
    __aligned_u64 length;
    __aligned_u64 iova;
};

成員

size

sizeof(struct iommu_ioas_map_file)

flags

與 iommu_ioas_map 相同

ioas_id

與 iommu_ioas_map 相同

fd

要對映的 memfd

start

從檔案開頭開始對映的位元組偏移量

length

與 iommu_ioas_map 相同

iova

與 iommu_ioas_map 相同

描述

從 memfd 檔案設定 IOVA 對映。所有其他引數和語義都與 IOMMU_IOAS_MAP 的引數和語義匹配。

struct iommu_ioas_copy

ioctl(IOMMU_IOAS_COPY)

定義:

struct iommu_ioas_copy {
    __u32 size;
    __u32 flags;
    __u32 dst_ioas_id;
    __u32 src_ioas_id;
    __aligned_u64 length;
    __aligned_u64 dst_iova;
    __aligned_u64 src_iova;
};

成員

size

sizeof(struct iommu_ioas_copy)

flags

enum iommufd_ioas_map_flags 的組合

dst_ioas_id

IOAS ID 用於更改對映

src_ioas_id

要從中複製的 IOAS ID

length

要複製和對映的位元組數

dst_iova

對映放置的 IOVA。如果設定了 IOMMU_IOAS_MAP_FIXED_IOVA,則必須將其作為輸入提供。

src_iova

啟動複製的 IOVA

描述

從 src_ioas_id 複製一個已存在的對映,並在 dst_ioas_id 中建立它。src iova/length 必須與 IOMMU_IOAS_MAP 使用的範圍完全匹配。

這可以用於有效地將 IOAS 的一個子集克隆到另一個 IOAS,或者作為一種“快取”來加速對映。與建立等效的新對映相比,複製具有效率優勢,因為內部資源是共享的,並且核心只會固定使用者記憶體一次。

struct iommu_ioas_unmap

ioctl(IOMMU_IOAS_UNMAP)

定義:

struct iommu_ioas_unmap {
    __u32 size;
    __u32 ioas_id;
    __aligned_u64 iova;
    __aligned_u64 length;
};

成員

size

sizeof(struct iommu_ioas_unmap)

ioas_id

IOAS ID 用於更改對映

iova

開始取消對映的 IOVA

length

要取消對映的位元組數,並返回已取消對映的位元組

描述

取消對映一個 IOVA 範圍。iova/length 必須是先前使用 IOMMU_IOAS_MAP 或 IOMMU_IOAS_COPY 對映的範圍的超集。不允許拆分或截斷範圍。值 0 到 U64_MAX 將取消對映所有內容。

enum iommufd_option

ioctl(IOMMU_OPTION_RLIMIT_MODE) 和 ioctl(IOMMU_OPTION_HUGE_PAGES)

常量

IOMMU_OPTION_RLIMIT_MODE

更改 RLIMIT_MEMLOCK 記帳的工作方式。呼叫者必須具有呼叫此函式的許可權。值 0(預設)是基於使用者的記帳,1 使用基於程序的記帳。全域性選項,object_id 必須為 0

IOMMU_OPTION_HUGE_PAGES

值 1(預設)允許在生成 iommu 對映時組合連續的頁面。值 0 停用組合,所有內容都對映到 PAGE_SIZE。這對於基準測試很有用。這是一個按 IOAS 選項,object_id 必須是 IOAS ID。

enum iommufd_option_ops

ioctl(IOMMU_OPTION_OP_SET) 和 ioctl(IOMMU_OPTION_OP_GET)

常量

IOMMU_OPTION_OP_SET

設定選項的值

IOMMU_OPTION_OP_GET

獲取選項的值

struct iommu_option

iommu 選項複用器

定義:

struct iommu_option {
    __u32 size;
    __u32 option_id;
    __u16 op;
    __u16 __reserved;
    __u32 object_id;
    __aligned_u64 val64;
};

成員

size

sizeof(struct iommu_option)

option_id

enum iommufd_option 之一

op

enum iommufd_option_ops 之一

__reserved

必須為 0

object_id

如果需要,物件的 ID

val64

要設定的選項值或在 get 上返回的值

描述

更改一個簡單的選項值。此多路複用器允許控制物件的選項。IOMMU_OPTION_OP_SET 將載入一個選項,IOMMU_OPTION_OP_GET 將返回當前值。

enum iommufd_vfio_ioas_op

IOMMU_VFIO_IOAS_* ioctl

常量

IOMMU_VFIO_IOAS_GET

獲取當前的相容性 IOAS

IOMMU_VFIO_IOAS_SET

更改當前的相容性 IOAS

IOMMU_VFIO_IOAS_CLEAR

停用 VFIO 相容性

struct iommu_vfio_ioas

ioctl(IOMMU_VFIO_IOAS)

定義:

struct iommu_vfio_ioas {
    __u32 size;
    __u32 ioas_id;
    __u16 op;
    __u16 __reserved;
};

成員

size

sizeof(struct iommu_vfio_ioas)

ioas_id

對於 IOMMU_VFIO_IOAS_SET,輸入要設定的 IOAS ID。對於 IOMMU_VFIO_IOAS_GET,將輸出 IOAS ID

op

enum iommufd_vfio_ioas_op 之一

__reserved

必須為 0

描述

VFIO 相容性支援使用單個 ioas,因為 VFIO API 不支援 ID 欄位。設定或獲取 VFIO 相容性將使用的 IOAS。當在 iommufd 上使用 VFIO_GROUP_SET_CONTAINER 時,它將獲取相容性 ioas,無論是透過獲取已設定的內容還是自動建立一個。從那時起,VFIO 將繼續使用該 ioas,並且不受此 ioctl 的影響。SET 或 CLEAR 不會銷燬任何自動建立的 IOAS。

enum iommufd_hwpt_alloc_flags

HWPT 分配的標誌

常量

IOMMU_HWPT_ALLOC_NEST_PARENT

如果設定,則分配一個 HWPT,該 HWPT 可以在巢狀配置中用作父 HWPT。

IOMMU_HWPT_ALLOC_DIRTY_TRACKING

在裝置連線時強制執行裝置 IOMMU 的髒跟蹤支援

IOMMU_HWPT_FAULT_ID_VALID

hwpt 分配資料的 fault_id 欄位有效。

IOMMU_HWPT_ALLOC_PASID

請求一個可以與 PASID 一起使用的域。該域可以連線到裝置上的任何 PASID。連線到裝置的非 PASID 部分的任何域也必須標記,否則連線 PASID 將被阻止。對於想要連線 PASID 的使用者,不建議為裝置的非 PASID 部分和 PASID 部分使用 ioas。如果 IOMMU 不支援 PASID,它將返回錯誤 (-EOPNOTSUPP)。

enum iommu_hwpt_vtd_s1_flags

Intel VT-d stage-1 頁表條目屬性

常量

IOMMU_VTD_S1_SRE

Supervisor 請求

IOMMU_VTD_S1_EAFE

擴充套件訪問啟用

IOMMU_VTD_S1_WPE

防寫啟用

struct iommu_hwpt_vtd_s1

Intel VT-d stage-1 頁表資訊 (IOMMU_HWPT_DATA_VTD_S1)

定義:

struct iommu_hwpt_vtd_s1 {
    __aligned_u64 flags;
    __aligned_u64 pgtbl_addr;
    __u32 addr_width;
    __u32 __reserved;
};

成員

flags

enum iommu_hwpt_vtd_s1_flags 的組合

pgtbl_addr

stage-1 頁表的基地址。

addr_width

stage-1 頁表的地址寬度

__reserved

必須為 0

struct iommu_hwpt_arm_smmuv3

ARM SMMUv3 巢狀 STE (IOMMU_HWPT_DATA_ARM_SMMUV3)

定義:

struct iommu_hwpt_arm_smmuv3 {
    __aligned_le64 ste[2];
};

成員

ste

用於轉換的使用者空間 Stream Table Entry 的前兩個雙字。必須是小端序。允許的欄位:(請參閱 SMMUv3 HW Spec 中的“5.2 Stream Table Entry”) - word-0: V, Cfg, S1Fmt, S1ContextPtr, S1CDMax - word-1: EATS, S1DSS, S1CIR, S1COR, S1CSH, S1STALLD

描述

如果 ste 不合法或包含任何不允許的欄位,將返回 -EIO。Cfg 可用於選擇 S1、Bypass 或 Abort 配置。Bypass 巢狀域將與巢狀父域以相同的方式進行轉換。S1 將安裝一個指向使用者空間記憶體的 Context Descriptor Table,該記憶體由巢狀父域進行轉換。

enum iommu_hwpt_data_type

IOMMU HWPT 資料型別

常量

IOMMU_HWPT_DATA_NONE

無資料

IOMMU_HWPT_DATA_VTD_S1

Intel VT-d stage-1 頁表

IOMMU_HWPT_DATA_ARM_SMMUV3

ARM SMMUv3 Context Descriptor Table

struct iommu_hwpt_alloc

ioctl(IOMMU_HWPT_ALLOC)

定義:

struct iommu_hwpt_alloc {
    __u32 size;
    __u32 flags;
    __u32 dev_id;
    __u32 pt_id;
    __u32 out_hwpt_id;
    __u32 __reserved;
    __u32 data_type;
    __u32 data_len;
    __aligned_u64 data_uptr;
    __u32 fault_id;
    __u32 __reserved2;
};

成員

size

sizeof(struct iommu_hwpt_alloc)

flags

enum iommufd_hwpt_alloc_flags 的組合

dev_id

要為其分配此 HWPT 的裝置

pt_id

要將此 HWPT 連線到的 IOAS 或 HWPT 或 vIOMMU

out_hwpt_id

新 HWPT 的 ID

__reserved

必須為 0

data_type

enum iommu_hwpt_data_type 之一

data_len

型別特定資料的長度

data_uptr

指向型別特定資料的使用者指標

fault_id

IOMMUFD_FAULT 物件的 ID。僅當設定了 IOMMU_HWPT_FAULT_ID_VALID 的標誌欄位時有效。

__reserved2

填充到 64 位對齊。必須為 0。

描述

顯式分配一個硬體頁表物件。這與 iommufd_device_attach() 返回的物件型別相同,並且表示底層 iommu 驅動程式的 iommu_domain 核心物件。

將建立一個核心管理的 HWPT,其中包含來自給定 IOAS 的對映,透過 pt_id。此分配的 data_type 必須設定為 IOMMU_HWPT_DATA_NONE。透過 flags 傳遞 IOMMU_HWPT_ALLOC_NEST_PARENT,可以將 HWPT 分配為巢狀配置的父 HWPT。

將透過給定的 vIOMMU(包裝父 HWPT)或父 HWPT(透過 pt_id)建立一個使用者管理的巢狀 HWPT,其中父 HWPT 必須先前透過相同的 ioctl 從給定的 IOAS (pt_id) 分配。在這種情況下,data_type 必須設定為與底層 IOMMU 硬體支援的 I/O 頁表型別相對應的預定義型別。透過 dev_id 的裝置和透過 pt_id 的 vIOMMU 必須與同一個 IOMMU 例項關聯。

如果 data_type 設定為 IOMMU_HWPT_DATA_NONE,則 data_lendata_uptr 應為零。否則,必須同時給出 data_lendata_uptr

enum iommu_hw_info_vtd_flags

VT-d hw_info 的標誌

常量

IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17

如果設定,則不允許在 nested_parent 域上進行只讀對映。https://www.intel.com/content/www/us/en/content-details/772415/content-details.html

struct iommu_hw_info_vtd

Intel VT-d 硬體資訊

定義:

struct iommu_hw_info_vtd {
    __u32 flags;
    __u32 __reserved;
    __aligned_u64 cap_reg;
    __aligned_u64 ecap_reg;
};

成員

flags

enum iommu_hw_info_vtd_flags 的組合

__reserved

必須為 0

cap_reg

在 VT-d 規範第 11.4.2 節 Capability Register 中定義的 Intel VT-d capability 暫存器的值。

ecap_reg

在 VT-d 規範第 11.4.3 節 Extended Capability Register 中定義的 Intel VT-d capability 暫存器的值。

描述

使用者需要了解 Intel VT-d 規範來解碼暫存器值。

struct iommu_hw_info_arm_smmuv3

ARM SMMUv3 硬體資訊 (IOMMU_HW_INFO_TYPE_ARM_SMMUV3)

定義:

struct iommu_hw_info_arm_smmuv3 {
    __u32 flags;
    __u32 __reserved;
    __u32 idr[6];
    __u32 iidr;
    __u32 aidr;
};

成員

flags

必須設定為 0

__reserved

必須為 0

idr

ARM SMMU 非安全程式設計介面的已實現功能

iidr

有關 ARM SMMU 的實現和實現者以及支援的架構版本的資訊

aidr

ARM SMMU 架構版本

描述

有關 idriidraidr 的詳細資訊,請參閱 SMMUv3 Spec 中的 6.3.1 到 6.3.6 章。

這報告了原始的 HW 功能,並非所有位對於 userspace 來說都是有意義的。只應使用以下欄位

idr[0]: ST_LEVEL, TERM_MODEL, STALL_MODEL, TTENDIAN , CD2L, ASID16, TTF idr[1]: SIDSIZE, SSIDSIZE idr[3]: BBML, RIL idr[5]: VAX, GRAN64K, GRAN16K, GRAN4K

  • 如果可以建立 NESTED HWPT,則應假定 S1P 為 true

  • VFIO/iommufd 僅支援具有 COHACC 的平臺,應假定為 true。

  • ATS 是一個按裝置屬性。如果 VMM 在 ACPI/DT 中將任何裝置描述為具有 ATS 功能,則應設定相應的 idr。

此列表可能會在將來擴充套件(例如 E0PD、AIE、PBHA、D128、DS 等)。重要的是,VMM 不要讀取列表之外的位,以允許與未來核心相容。SMMUv3 架構中的幾個功能當前核心不支援巢狀:HTTU、BTM、MPAM 等。

enum iommu_hw_info_type

IOMMU 硬體資訊型別

常量

IOMMU_HW_INFO_TYPE_NONE

由不報告硬體資訊的驅動程式使用

IOMMU_HW_INFO_TYPE_INTEL_VTD

Intel VT-d iommu 資訊型別

IOMMU_HW_INFO_TYPE_ARM_SMMUV3

ARM SMMUv3 iommu 資訊型別

enum iommufd_hw_capabilities

常量

IOMMU_HW_CAP_DIRTY_TRACKING

IOMMU 硬體支援髒跟蹤。如果可用,則表示支援以下 API

IOMMU_HWPT_GET_DIRTY_BITMAP IOMMU_HWPT_SET_DIRTY_TRACKING

IOMMU_HW_CAP_PCI_PASID_EXEC

支援執行許可權,當 struct iommu_hw_info::out_max_pasid_log2 為零時,使用者忽略它。

IOMMU_HW_CAP_PCI_PASID_PRIV

支援特權模式,當 struct iommu_hw_info::out_max_pasid_log2 為零時,使用者忽略它。

struct iommu_hw_info

ioctl(IOMMU_GET_HW_INFO)

定義:

struct iommu_hw_info {
    __u32 size;
    __u32 flags;
    __u32 dev_id;
    __u32 data_len;
    __aligned_u64 data_uptr;
    __u32 out_data_type;
    __u8 out_max_pasid_log2;
    __u8 __reserved[3];
    __aligned_u64 out_capabilities;
};

成員

size

sizeof(struct iommu_hw_info)

flags

必須為 0

dev_id

繫結到 iommufd 的裝置

data_len

輸入使用者緩衝區長度(以位元組為單位)。輸出核心支援的資料長度

data_uptr

指向使用者空間緩衝區的使用者指標,核心使用該緩衝區填充 iommu 型別特定的硬體資訊資料

out_data_type

輸出 iommu 硬體資訊型別,如 enum iommu_hw_info_type 中所定義。

out_max_pasid_log2

輸出 PASID 的寬度。0 表示不支援 PASID。PCI 裝置轉向 out_capabilities 以檢查是否支援特定功能。

__reserved

必須為 0

out_capabilities

輸出通用 iommu 功能資訊型別,如 enum iommu_hw_capabilities 中所定義。

描述

從繫結到 iommufd 的給定裝置後面的 iommu 查詢 iommu 型別特定的硬體資訊資料。此硬體資訊資料將用於同步虛擬 iommu 和物理 iommu 之間的功能,例如,巢狀轉換設定需要檢查硬體資訊,以便訪客 stage-1 頁表可以與物理 iommu 相容。

要捕獲 iommu 型別特定的硬體資訊資料,必須提供 data_uptr 及其長度 data_len。如果使用者緩衝區大於核心擁有的資料,則尾隨位元組將被置零。否則,核心只使用 data_len 中給定的長度填充緩衝區。如果 ioctl 成功,data_len 將更新為核心實際支援的長度,out_data_type 將被填充以解碼 data_uptr 指向的緩衝區中填充的資料。允許輸入 data_len == 零。

struct iommu_hwpt_set_dirty_tracking

ioctl(IOMMU_HWPT_SET_DIRTY_TRACKING)

定義:

struct iommu_hwpt_set_dirty_tracking {
    __u32 size;
    __u32 flags;
    __u32 hwpt_id;
    __u32 __reserved;
};

成員

size

sizeof(struct iommu_hwpt_set_dirty_tracking)

flags

enum iommufd_hwpt_set_dirty_tracking_flags 的組合

hwpt_id

表示 IOMMU 域的 HW 頁表 ID

__reserved

必須為 0

描述

切換 HW 頁表上的髒頁追蹤。

enum iommufd_hwpt_get_dirty_bitmap_flags

獲取髒位的標誌

常量

IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR

僅讀取 PTE,而不清除任何髒位元資料。可以在期望下一次操作是對相同 IOVA 範圍進行取消對映的情況下傳遞此標誌。

struct iommu_hwpt_get_dirty_bitmap

ioctl(IOMMU_HWPT_GET_DIRTY_BITMAP)

定義:

struct iommu_hwpt_get_dirty_bitmap {
    __u32 size;
    __u32 hwpt_id;
    __u32 flags;
    __u32 __reserved;
    __aligned_u64 iova;
    __aligned_u64 length;
    __aligned_u64 page_size;
    __aligned_u64 data;
};

成員

size

sizeof(struct iommu_hwpt_get_dirty_bitmap)

hwpt_id

表示 IOMMU 域的 HW 頁表 ID

flags

enum iommufd_hwpt_get_dirty_bitmap_flags 的組合

__reserved

必須為 0

iova

點陣圖第一位的基本 IOVA

length

IOVA 範圍大小

page_size

點陣圖中每個位的頁面大小粒度

data

用於設定髒位的點陣圖。點陣圖中的每個位代表一個 page_size,它與任意 iova 偏差。

描述

檢查給定的 IOVA 是否為髒頁

data[(iova / page_size) / 64] & (1ULL << ((iova / page_size) % 64))

遍歷給定 IOVA 範圍的 IOMMU 頁表,以返回包含髒 IOVA 的點陣圖。這樣做的同時,預設情況下還會清除 IOPTE 中設定的所有髒位元資料。

enum iommu_hwpt_invalidate_data_type

IOMMU HWPT 快取無效化資料型別

常量

IOMMU_HWPT_INVALIDATE_DATA_VTD_S1

VTD_S1 的無效化資料

IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3

ARM SMMUv3 的無效化資料

enum iommu_hwpt_vtd_s1_invalidate_flags

Intel VT-d 階段 1 快取無效化的標誌

常量

IOMMU_VTD_INV_FLAGS_LEAF

指示無效化是應用於所有級別的頁面結構快取,還是僅應用於葉 PTE 快取。

struct iommu_hwpt_vtd_s1_invalidate

Intel VT-d 快取無效化 (IOMMU_HWPT_INVALIDATE_DATA_VTD_S1)

定義:

struct iommu_hwpt_vtd_s1_invalidate {
    __aligned_u64 addr;
    __aligned_u64 npages;
    __u32 flags;
    __u32 __reserved;
};

成員

addr

要無效化的範圍的起始地址。 它需要 4KB 對齊。

npages

要無效化的連續 4K 頁面的數量。

flags

enum iommu_hwpt_vtd_s1_invalidate_flags 的組合

__reserved

必須為 0

描述

用於巢狀轉換中使用者管理的階段 1 快取無效化的 Intel VT-d 特定無效化資料。 使用者空間使用此結構在修改階段 1 頁表後告訴受影響的快取範圍。

透過將 addr 設定為 0 並將 npages 設定為 U64_MAX 來使所有與頁表相關的快取無效。

如果啟用了 ATS,則裝置 TLB 將自動無效。

struct iommu_viommu_arm_smmuv3_invalidate

ARM SMMUv3 快取無效化 (IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3)

定義:

struct iommu_viommu_arm_smmuv3_invalidate {
    __aligned_le64 cmd[2];
};

成員

cmd

在 SMMU CMDQ 中執行的 128 位快取無效化命令。 必須是小端位元組序。

描述

僅在透過 hwpt_id 傳入 vIOMMU 時支援的命令列表

CMDQ_OP_TLBI_NSNH_ALL CMDQ_OP_TLBI_NH_VA CMDQ_OP_TLBI_NH_VAA CMDQ_OP_TLBI_NH_ALL CMDQ_OP_TLBI_NH_ASID CMDQ_OP_ATC_INV CMDQ_OP_CFGI_CD CMDQ_OP_CFGI_CD_ALL

如果不支援該命令,將返回 -EIO。

struct iommu_hwpt_invalidate

ioctl(IOMMU_HWPT_INVALIDATE)

定義:

struct iommu_hwpt_invalidate {
    __u32 size;
    __u32 hwpt_id;
    __aligned_u64 data_uptr;
    __u32 data_type;
    __u32 entry_len;
    __u32 entry_num;
    __u32 __reserved;
};

成員

size

sizeof(struct iommu_hwpt_invalidate)

hwpt_id

用於快取無效化的巢狀 HWPT 或 vIOMMU 的 ID

data_uptr

指向驅動程式特定快取無效化資料陣列的使用者指標。

data_type

enum iommu_hwpt_invalidate_data_type 之一,定義無效化請求陣列中所有條目的資料型別。 它應該是 hwpt_id 指向的 hwpt 支援的型別。

entry_len

請求陣列中請求條目的長度(以位元組為單位)

entry_num

輸入陣列中快取無效化請求的數量。 輸出核心成功處理的請求數量。

__reserved

必須為 0。

描述

使 iommu 快取對使用者管理的頁表或 vIOMMU 無效。 如果透過 hwpt_id 傳入 HWPT,則在修改使用者管理的頁表後,應執行此操作。 如果透過 hwpt_id 欄位傳入 vIOMMU,則可以重新整理其他快取,例如裝置快取或描述符快取。

每個 ioctl 可以支援陣列中的一個或多個快取無效化請求,陣列的總大小為 entry_len * entry_num

允許透過設定 entry_num**==0 來使用空的無效化請求陣列,在這種情況下,將忽略 **entry_lendata_uptr。 這可用於檢查核心是否支援給定的 data_type

enum iommu_hwpt_pgfault_flags

struct iommu_hwpt_pgfault 的標誌

常量

IOMMU_PGFAULT_FLAGS_PASID_VALID

故障資料的 pasid 欄位有效。

IOMMU_PGFAULT_FLAGS_LAST_PAGE

它是故障組的最後一個故障。

enum iommu_hwpt_pgfault_perm

struct iommu_hwpt_pgfault 的許可權位

常量

IOMMU_PGFAULT_PERM_READ

請求讀取許可權

IOMMU_PGFAULT_PERM_WRITE

請求寫入許可權

IOMMU_PGFAULT_PERM_EXEC

(PCIE 10.4.1) 使用 PASID TLP 字首中設定了 Execute Requested 位的 PASID 發出的請求。

IOMMU_PGFAULT_PERM_PRIV

(PCIE 10.4.1) 使用 PASID TLP 字首中設定了 Privileged Mode Requested 位的 PASID 發出的請求。

struct iommu_hwpt_pgfault

iommu 頁錯誤資料

定義:

struct iommu_hwpt_pgfault {
    __u32 flags;
    __u32 dev_id;
    __u32 pasid;
    __u32 grpid;
    __u32 perm;
    __u32 __reserved;
    __aligned_u64 addr;
    __u32 length;
    __u32 cookie;
};

成員

flags

enum iommu_hwpt_pgfault_flags 的組合

dev_id

發起裝置的 ID

pasid

程序地址空間 ID

grpid

頁面請求組索引

perm

enum iommu_hwpt_pgfault_perm 的組合

__reserved

必須為 0。

addr

錯誤地址

length

請求者希望提取多少資料的提示。 例如,如果 PRI 發起者知道它將進行 10MB 的傳輸,則它可以填寫 10MB,並且 OS 可以預先錯誤地讀取 10MB 的 IOVA。 如果沒有這樣的提示,則預設為 0。

cookie

核心管理的 cookie,用於標識一組故障訊息。 應在響應訊息中回顯該組的最後一個頁面錯誤中編碼的 cookie 編號。

enum iommufd_page_response_code

故障處理程式的返回狀態

常量

IOMMUFD_PAGE_RESP_SUCCESS

已處理故障並填充了頁表,請重試訪問。 這是 PCI 10.4.2.1 中定義的“成功”。

IOMMUFD_PAGE_RESP_INVALID

無法處理此故障,請勿重試訪問。 這是 PCI 10.4.2.1 中的“無效請求”。

struct iommu_hwpt_page_response

IOMMU 頁錯誤響應

定義:

struct iommu_hwpt_page_response {
    __u32 cookie;
    __u32 code;
};

成員

cookie

在故障訊息中報告的核心管理的 cookie。

code

enum iommufd_page_response_code 中的響應程式碼之一。

struct iommu_fault_alloc

ioctl(IOMMU_FAULT_QUEUE_ALLOC)

定義:

struct iommu_fault_alloc {
    __u32 size;
    __u32 flags;
    __u32 out_fault_id;
    __u32 out_fault_fd;
};

成員

size

sizeof(struct iommu_fault_alloc)

flags

必須為 0

out_fault_id

新 FAULT 的 ID

out_fault_fd

新 FAULT 的 fd

描述

顯式分配故障處理物件。

enum iommu_viommu_type

虛擬 IOMMU 型別

常量

IOMMU_VIOMMU_TYPE_DEFAULT

保留供將來使用

IOMMU_VIOMMU_TYPE_ARM_SMMUV3

ARM SMMUv3 驅動程式特定型別

struct iommu_viommu_alloc

ioctl(IOMMU_VIOMMU_ALLOC)

定義:

struct iommu_viommu_alloc {
    __u32 size;
    __u32 flags;
    __u32 type;
    __u32 dev_id;
    __u32 hwpt_id;
    __u32 out_viommu_id;
};

成員

size

sizeof(struct iommu_viommu_alloc)

flags

必須為 0

type

虛擬 IOMMU 的型別。 必須在 enum iommu_viommu_type 中定義

dev_id

裝置的物理 IOMMU 將用於支援虛擬 IOMMU

hwpt_id

要關聯的巢狀父 HWPT 的 ID

out_viommu_id

已分配物件的輸出虛擬 IOMMU ID

描述

分配一個虛擬 IOMMU 物件,表示底層物理 IOMMU 的虛擬化支援,該支援是真實 IOMMU HW 的安全隔離切片,對於特定的 VM 是唯一的。 全域性到 IOMMU 的操作連線到 vIOMMU,例如: - 訪客擁有的 ID 的安全名稱空間,例如訪客控制的快取標記 - 非裝置關聯的事件報告,例如無效化佇列錯誤 - 跨物理 IOMMU 訪問可共享的巢狀父頁表 - 各種平臺 ID 的虛擬化,例如 RID 等 - 提供準虛擬化無效 - 直接分配的無效化佇列 - 直接分配的中斷

struct iommu_vdevice_alloc

ioctl(IOMMU_VDEVICE_ALLOC)

定義:

struct iommu_vdevice_alloc {
    __u32 size;
    __u32 viommu_id;
    __u32 dev_id;
    __u32 out_vdevice_id;
    __aligned_u64 virt_id;
};

成員

size

sizeof(struct iommu_vdevice_alloc)

viommu_id

要與虛擬裝置關聯的 vIOMMU ID

dev_id

要在 vIOMMU 上分配虛擬例項的物理裝置

out_vdevice_id

vDevice 的物件控制代碼。 傳遞給 IOMMU_DESTORY

virt_id

每個 vIOMMU 的虛擬裝置 ID,例如 ARM SMMUv3 的 vSID、AMD IOMMU 的 vDeviceID 以及巢狀的 Intel VT-d 到上下文表的 vRID

描述

針對 vIOMMU 分配一個虛擬裝置例項(對於物理裝置)。 此例項在 VM 中儲存裝置的資訊(與其 vIOMMU 相關)。

struct iommu_ioas_change_process

ioctl(VFIO_IOAS_CHANGE_PROCESS)

定義:

struct iommu_ioas_change_process {
    __u32 size;
    __u32 __reserved;
};

成員

size

sizeof(struct iommu_ioas_change_process)

__reserved

必須為 0

描述

這將上下文中每個 IOAS 中每個記憶體對映的固定記憶體計數轉移到當前程序。 這僅支援使用 IOMMU_IOAS_MAP_FILE 建立的對映,如果存在其他對映,則返回 EINVAL。 如果 ioctl 返回失敗狀態,則不會進行任何更改。

此 API 對於將裝置的操作從一個程序轉移到另一個程序很有用,例如在使用者空間即時更新期間。

enum iommu_veventq_flag

struct iommufd_vevent_header 的標誌

常量

IOMMU_VEVENTQ_FLAG_LOST_EVENTS

vEVENTQ 已丟失 vEVENT

struct iommufd_vevent_header

vEVENTQ 狀態的虛擬事件標頭

定義:

struct iommufd_vevent_header {
    __u32 flags;
    __u32 sequence;
};

成員

flags

enum iommu_veventq_flag 的組合

sequence

vEVENTQ 中 vEVENT 的序列索引,範圍為 [0, INT_MAX],其中 INT_MAX 的下一個索引為 0

描述

每個 iommufd_vevent_header 報告以下 vEVENT 的序列索引

header0 {sequence=0}

data0

header1 {sequence=1}

data1

...

dataN

並且此序列索引預計對於前一個 vEVENT 的序列索引是單調的。 如果兩個相鄰的序列索引的增量大於 1,則表示已丟失增量 - 1 個 vEVENT,例如,丟失了兩個 vEVENT

...

header3 {sequence=3}

data3

header6 {sequence=6}

data6

...

如果 vEVENT 在 vEVENTQ 的尾部丟失,並且沒有後續 vEVENT 提供下一個序列索引,則會將 IOMMU_VEVENTQ_FLAG_LOST_EVENTS 標頭新增到尾部,並且此標頭後不會跟隨任何資料

header3 {sequence=3}

data3

header4 {flags=LOST_EVENTS, sequence=4}

enum iommu_veventq_type

虛擬事件佇列型別

常量

IOMMU_VEVENTQ_TYPE_DEFAULT

保留供將來使用

IOMMU_VEVENTQ_TYPE_ARM_SMMUV3

ARM SMMUv3 虛擬事件佇列

struct iommu_vevent_arm_smmuv3

ARM SMMUv3 虛擬事件 (IOMMU_VEVENTQ_TYPE_ARM_SMMUV3)

定義:

struct iommu_vevent_arm_smmuv3 {
    __aligned_le64 evt[4];
};

成員

evt

256 位 ARM SMMUv3 事件記錄,小端位元組序。 報告的事件記錄:(請參閱 SMMUv3 HW Spec 中的“7.3 Event records”) - 0x04 C_BAD_STE - 0x06 F_STREAM_DISABLED - 0x08 C_BAD_SUBSTREAMID - 0x0a C_BAD_CD - 0x10 F_TRANSLATION - 0x11 F_ADDR_SIZE - 0x12 F_ACCESS - 0x13 F_PERMISSION

描述

StreamID 欄位報告虛擬裝置 ID。 要接收裝置的虛擬事件,必須透過 IOMMU_VDEVICE_ALLOC 分配 vDEVICE。

struct iommu_veventq_alloc

ioctl(IOMMU_VEVENTQ_ALLOC)

定義:

struct iommu_veventq_alloc {
    __u32 size;
    __u32 flags;
    __u32 viommu_id;
    __u32 type;
    __u32 veventq_depth;
    __u32 out_veventq_id;
    __u32 out_veventq_fd;
    __u32 __reserved;
};

成員

size

sizeof(struct iommu_veventq_alloc)

flags

必須為 0

viommu_id

要與 vEVENTQ 關聯的虛擬 IOMMU ID

type

vEVENTQ 的型別。 必須在 enum iommu_veventq_type 中定義

veventq_depth

vEVENTQ 中的最大事件數

out_veventq_id

新 vEVENTQ 的 ID

out_veventq_fd

新 vEVENTQ 的 fd。 使用者空間在使用後必須關閉成功返回的 fd

__reserved

必須為 0

描述

顯式分配 vIOMMU 的虛擬事件佇列介面。 vIOMMU 可以具有不同型別的多個 FD,但每個 type 僅限於一個。 使用者空間應開啟 out_veventq_fd 以從 vEVENTQ 中讀取 vEVENT,如果存在可用的 vEVENT。 如果 vEVENT 的數量達到 veventq_depth,則 vEVENTQ 將因溢位而丟失事件。

在 vEVENTQ 中的每個 vEVENT 包含一個 struct iommufd_vevent_header,後跟一個特定型別的資料結構,在正常情況下

header0

data0

header1

data1

...

headerN

dataN

除非記錄了尾部的 IOMMU_VEVENTQ_FLAG_LOST_EVENTS 頭部 (參考 struct iommufd_vevent_header)。

IOMMUFD 核心 API

IOMMUFD kAPI 以裝置為中心,組相關技巧在幕後管理。這允許呼叫此 kAPI 的外部驅動程式實現一個簡單的以裝置為中心的 uAPI,用於將其裝置連線到 iommufd,而不是像 VFIO 那樣在其 uAPI 中顯式強制組語義。

struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx, struct device *dev, u32 *id)

將物理裝置繫結到 iommu fd

引數

struct iommufd_ctx *ictx

iommufd 檔案描述符

struct device *dev

指向物理裝置結構的指標

u32 *id

要返回給使用者空間的此裝置的輸出 ID 號

描述

成功的繫結會建立裝置的所有權並返回 struct iommufd_device 指標,否則返回錯誤指標。

使用此 API 的驅動程式必須設定 driver_managed_dma 並且在此例程成功並建立所有權之前不得觸碰裝置。

繫結 PCI 裝置會將整個 RID 置於 iommufd 控制之下。

呼叫者必須使用 iommufd_device_unbind() 來撤消此操作。

bool iommufd_ctx_has_group(struct iommufd_ctx *ictx, struct iommu_group *group)

如果組中的任何裝置繫結到 ictx,則為 True

引數

struct iommufd_ctx *ictx

iommufd 檔案描述符

struct iommu_group *group

指向物理 iommu_group 結構的指標

描述

如果組中的任何裝置已繫結到此 ictx,例如透過 iommufd_device_bind(),則表示 ictx 擁有該組。

void iommufd_device_unbind(struct iommufd_device *idev)

撤消 iommufd_device_bind()

引數

struct iommufd_device *idev

iommufd_device_bind() 返回的裝置

描述

從 iommufd 控制中釋放裝置。DMA 所有權將返回到未擁有的狀態,DMA 由 DMA API 控制。這會使 iommufd_device 指標失效,不得併發呼叫使用它的其他 API。

int iommufd_device_attach(struct iommufd_device *idev, ioasid_t pasid, u32 *pt_id)

將裝置/pasid 連線到 iommu_domain

引數

struct iommufd_device *idev

要附加的裝置

ioasid_t pasid

要附加的 pasid

u32 *pt_id

輸入一個 IOMMUFD_OBJ_IOAS 或 IOMMUFD_OBJ_HWPT_PAGING 輸出 IOMMUFD_OBJ_HWPT_PAGING ID

描述

這會將裝置/pasid 連線到 iommu_domain,自動或手動選擇。 完成此操作後,裝置可以使用 **pasid** 執行 DMA。 如果此附件不用於 pasid,則 **pasid** 為 IOMMU_NO_PASID。

呼叫者應將結果 pt_id 返回給使用者空間。 此函式透過呼叫 iommufd_device_detach() 來撤消。

int iommufd_device_replace(struct iommufd_device *idev, ioasid_t pasid, u32 *pt_id)

更改裝置/pasid 的 iommu_domain

引數

struct iommufd_device *idev

要更改的裝置

ioasid_t pasid

要更改的 pasid

u32 *pt_id

輸入一個 IOMMUFD_OBJ_IOAS 或 IOMMUFD_OBJ_HWPT_PAGING 輸出 IOMMUFD_OBJ_HWPT_PAGING ID

描述

這和

iommufd_device_detach();
iommufd_device_attach();

如果失敗,則不會對附件進行任何更改。 iommu 驅動程式可以實現此功能,因此翻譯中沒有中斷。 只有在 iommufd_device_attach() 已經成功後才能呼叫此函式。 對於沒有 pasid 的情況,**pasid** 為 IOMMU_NO_PASID。

void iommufd_device_detach(struct iommufd_device *idev, ioasid_t pasid)

斷開裝置/裝置與 iommu_domain 的連線

引數

struct iommufd_device *idev

要分離的裝置

ioasid_t pasid

要分離的 pasid

描述

撤消 iommufd_device_attach()。 這會將 idev 從先前連線的 pt_id 斷開連線。 該裝置返回到阻止的 DMA 轉換。 對於沒有 pasid 的情況,**pasid** 為 IOMMU_NO_PASID。

struct iommufd_access *iommufd_access_create(struct iommufd_ctx *ictx, const struct iommufd_access_ops *ops, void *data, u32 *id)

建立一個 iommufd_access

引數

struct iommufd_ctx *ictx

iommufd 檔案描述符

const struct iommufd_access_ops *ops

驅動程式的 ops 與訪問相關聯

void *data

要傳遞到 ops 函式中的不透明資料

u32 *id

要返回給使用者空間的此訪問的輸出 ID 號

描述

iommufd_access 允許驅動程式在不使用 DMA 的情況下讀取/寫入 IOAS。 可以使用 iommufd_access_pin_pages()iommufd_access_rw() 函式訪問底層 CPU 記憶體。

提供的 ops 需要使用 iommufd_access_pin_pages()

void iommufd_access_destroy(struct iommufd_access *access)

銷燬 iommufd_access

引數

struct iommufd_access *access

要銷燬的訪問

描述

呼叫者必須先停止使用訪問,然後再銷燬它。

void iommufd_access_unpin_pages(struct iommufd_access *access, unsigned long iova, unsigned long length)

撤消 iommufd_access_pin_pages

引數

struct iommufd_access *access

要操作的 IOAS 訪問

unsigned long iova

起始 IOVA

unsigned long length

要訪問的位元組數

描述

返回 struct page。 呼叫者必須在呼叫此函式之前停止訪問它們。 iova/length 必須與提供給 access_pages 的完全匹配。

int iommufd_access_pin_pages(struct iommufd_access *access, unsigned long iova, unsigned long length, struct page **out_pages, unsigned int flags)

返回 iova 下的頁面列表

引數

struct iommufd_access *access

要操作的 IOAS 訪問

unsigned long iova

起始 IOVA

unsigned long length

要訪問的位元組數

struct page **out_pages

輸出頁面列表

unsigned int flags

IOPMMUFD_ACCESS_RW_* 標誌

描述

讀取從 iova 開始的 **length** 個位元組,並返回 struct page * 指標。 這些可以由呼叫者進行 kmap 以進行 CPU 訪問。

呼叫者必須在完成時執行 iommufd_access_unpin_pages() 以平衡此操作。

此 API 始終需要頁面對齊的 iova。 如果 ioas 對齊 >= PAGE_SIZE 並且 iova 是 PAGE_SIZE 對齊的,則會自然發生這種情況。 但是,較小的對齊方式存在一些極端情況,否則此 API 可能會在對齊的 iova 上失敗。

int iommufd_access_rw(struct iommufd_access *access, unsigned long iova, void *data, size_t length, unsigned int flags)

讀取或寫入 iova 下的資料

引數

struct iommufd_access *access

要操作的 IOAS 訪問

unsigned long iova

起始 IOVA

void *data

要複製到/從複製的核心緩衝區

size_t length

要訪問的位元組數

unsigned int flags

IOMMUFD_ACCESS_RW_* 標誌

描述

將核心資料複製到/從 IOVA/length 給定的範圍內。 如果標誌指示 IOMMUFD_ACCESS_RW_KTHREAD,則可以透過將其更改為 copy_to/from_user() 來最佳化大型副本。

void iommufd_ctx_get(struct iommufd_ctx *ictx)

獲取上下文引用

引數

struct iommufd_ctx *ictx

要獲取的上下文

描述

呼叫者必須已經擁有對 ictx 的有效引用。

struct iommufd_ctx *iommufd_ctx_from_file(struct file *file)

獲取 iommufd 上下文的引用

引數

struct file *file

從中獲取引用的檔案

描述

返回指向 iommufd_ctx 的指標,否則返回 ERR_PTR。 struct file 仍歸呼叫者所有,呼叫者仍必須執行 fput。 成功後,呼叫者有責任呼叫 iommufd_ctx_put()

struct iommufd_ctx *iommufd_ctx_from_fd(int fd)

獲取 iommufd 上下文的引用

引數

int fd

從中獲取引用的檔案描述符

描述

返回指向 iommufd_ctx 的指標,否則返回 ERR_PTR。 成功後,呼叫者有責任呼叫 iommufd_ctx_put()

void iommufd_ctx_put(struct iommufd_ctx *ictx)

放回引用

引數

struct iommufd_ctx *ictx

要放回的上下文

VFIO 和 IOMMUFD

可以透過兩種方式將 VFIO 裝置連線到 iommufd。

第一種是 VFIO 相容方式,透過直接實現 /dev/vfio/vfio 容器 IOCTL,將其對映到 io_pagetable 操作中。 這樣做允許透過將 /dev/vfio/vfio 符號連結到 /dev/iommufd 或擴充套件 VFIO 來使用 iommufd 在傳統的 VFIO 應用程式中,使用 iommufd 而不是容器 fd 來 SET_CONTAINER。

第二種方法直接擴充套件 VFIO 以支援一組新的基於裝置的使用者 API,這些 API 基於前面提到的 IOMMUFD 核心 API。 它需要使用者空間更改,但更好地匹配了 IOMMUFD API 語義,並且與第一種方法相比,更容易支援新的 iommufd 功能。

目前,這兩種方法仍在進行中。

正如 iommufd_vfio_check_extension() 中記錄的那樣,要趕上 VFIO type1,仍然有一些差距需要解決。

未來的待辦事項

目前,IOMMUFD 僅支援核心管理的 I/O 頁表,類似於 VFIO type1。 雷達上的新功能包括

  • 將 iommu_domain 繫結到 PASID/SSID

  • 使用者空間頁表,適用於 ARM、x86 和 S390

  • 繞過核心的使用者頁表失效

  • 在 IOMMU 中重用 KVM 頁表

  • 在 IOMMU 中跟蹤髒頁

  • 執行時增加/減少 IOPTE 大小

  • 在使用者空間解決錯誤的 PRI 支援