31. 使用 ENQCMD 的共享虛擬定址 (SVA)¶
31.1. 背景¶
共享虛擬定址 (SVA) 允許處理器和裝置使用相同的虛擬地址,從而避免了軟體將虛擬地址轉換為物理地址的需求。 SVA 是 PCIe 所謂的共享虛擬記憶體 (SVM)。
除了裝置使用應用程式虛擬地址的便利之外,它也不需要為 DMA 固定頁面。 PCIe 地址轉換服務 (ATS) 以及頁面請求介面 (PRI) 允許裝置的功能與 CPU 處理應用程式頁面錯誤的方式非常相似。 有關更多資訊,請參閱 PCIe 規範第 10 章:ATS 規範。
使用 SVA 需要平臺中的 IOMMU 支援。 IOMMU 還需要支援 PCIe 功能 ATS 和 PRI。 ATS 允許裝置快取虛擬地址的轉換。 IOMMU 驅動程式使用 mmu_notifier() 支援來保持裝置 TLB 快取和 CPU 快取同步。 當 ATS 查詢虛擬地址失敗時,裝置應使用 PRI 來請求將虛擬地址分頁到 CPU 頁表中。 裝置必須再次使用 ATS 才能在使用前獲取轉換。
31.2. 共享硬體工作佇列¶
與單根 I/O 虛擬化 (SR-IOV) 不同,可擴充套件 IOV (SIOV) 允許應用程式和虛擬機器 (VM) 使用共享工作佇列 (SWQ)。 與可能導致利用率不足的硬分割槽資源相比,這可以更好地利用硬體。 為了允許硬體區分硬體中透過 SWQ 介面執行工作的上下文,SIOV 使用程序地址空間 ID (PASID),這是一個由 PCIe SIG 定義的 20 位數字。
PASID 值編碼在來自裝置的所有事務中。 這允許 IOMMU 除了使用 PCIe 資源識別符號 (RID)(即匯流排/裝置/功能)之外,還可以按 PASID 粒度跟蹤 I/O。
31.3. ENQCMD¶
ENQCMD 是 Intel 平臺上的一個新指令,可原子地將工作描述符提交到裝置。 描述符包括要執行的操作、所有引數的虛擬地址、完成記錄的虛擬地址以及當前程序的 PASID(程序地址空間 ID)。
ENQCMD 使用非釋出語義,並且如果硬體接受了該命令,則會返回狀態。 這允許提交者知道是否需要重試提交,或者應提供其他特定於裝置的機制來實現公平性或確保向前進展。
ENQCMD 是確保應用程式可以直接將命令提交到硬體的粘合劑,並且還允許硬體瞭解應用程式上下文以透過使用 PASID 執行 I/O 操作。
31.4. 程序地址空間標記¶
一個新的執行緒範圍 MSR (IA32_PASID) 提供了使用者程序和其餘硬體之間的連線。 當應用程式首次訪問支援 SVA 的裝置時,此 MSR 將使用新分配的 PASID 進行初始化。 裝置的驅動程式呼叫特定於 IOMMU 的 API,該 API 設定 DMA 和頁面請求的路由。
例如,Intel 資料流加速器 (DSA) 使用 iommu_sva_bind_device(),它將執行以下操作
分配 PASID,並在 PASID 上下文條目中程式設計程序頁表(%cr3 暫存器)。
註冊 mmu_notifier() 以跟蹤任何頁表失效,以保持裝置 TLB 同步。 例如,當頁表條目失效時,IOMMU 會將失效傳播到裝置 TLB。 這將強制裝置將來對該虛擬地址的任何訪問參與 ATS。 如果 IOMMU 返回正確的響應,指示頁面不存在,則裝置將透過 PCIe PRI 協議請求將頁面分頁到記憶體中,然後再執行 I/O。
此 MSR 使用 XSAVE 功能集作為“管理程式狀態”進行管理,以確保在上下文切換期間更新 MSR。
31.5. PASID 管理¶
核心必須代表每個將使用 ENQCMD 的程序分配一個 PASID,並將其程式設計到新的 MSR 中,以將程序標識傳達給平臺硬體。 ENQCMD 使用儲存在此 MSR 中的 PASID 來標記來自此程序的請求。 當用戶使用 ENQCMD 指令將工作描述符提交到裝置時,描述符中的 PASID 欄位會自動填充 MSR_IA32_PASID 中的值。 來自裝置的 DMA 請求也使用相同的 PASID 進行標記。 平臺 IOMMU 使用事務中的 PASID 來執行地址轉換。 IOMMU API 使用 CPU 使用的程序地址(例如,x86 中的 %cr3 暫存器)在 IOMMU 中設定相應的 PASID 條目。
在任何應用程式執行緒可以與裝置互動之前,必須在每個邏輯 CPU 上配置 MSR。 屬於同一程序的執行緒共享相同的頁表,因此共享相同的 MSR 值。
31.6. PASID 生命週期管理¶
建立程序時,PASID 初始化為 IOMMU_PASID_INVALID (-1)。
只有訪問支援 SVA 的裝置的程序才需要分配 PASID。 當程序開啟/繫結支援 SVA 的裝置但未找到該程序的 PASID 時,才會發生此分配。 同一裝置或其他裝置的後續繫結將共享相同的 PASID。
儘管 PASID 是透過開啟裝置分配給程序的,但它在任何程序的執行緒中都不是活動的。 當執行緒嘗試使用 ENQCMD 將工作描述符提交到裝置時,它會懶惰地載入到 IA32_PASID MSR 中。
第一次訪問將觸發 #GP 錯誤,因為 IA32_PASID MSR 尚未初始化為分配給程序的 PASID 值(開啟裝置時)。 Linux #GP 處理程式注意到已為程序分配了一個 PASID,因此初始化 IA32_PASID MSR 並返回,以便重新執行 ENQCMD 指令。
在 fork(2) 或 exec(2) 上,PASID 從程序中刪除,因為它不再具有開啟裝置時的相同地址空間。
在 clone(2) 上,新任務共享相同的地址空間,因此將能夠使用分配給程序的 PASID。 IA32_PASID 不會搶先初始化,因為 PASID 值可能尚未分配,或者核心不知道該執行緒是否將訪問該裝置,並且清除的 IA32_PASID MSR 會透過 xstate 初始化最佳化來減少上下文切換開銷。 由於在將 PASID 分配給程序的 mm 之前建立的任何執行緒都必須處理 #GP 錯誤,因此新建立的執行緒也應該以一致的方式處理。
由於在取消繫結中釋放 PASID 和清除所有執行緒中的所有 IA32_PASID MSR 的複雜性,因此僅在 mm 退出時才懶惰地釋放 PASID。
如果程序對裝置檔案描述符執行 close(2) 並且對裝置 MMIO 門戶執行 munmap(2),則驅動程式將取消繫結裝置。 對於程序中訪問該裝置的任何執行緒,PASID 仍標記為 PASID_MSR 中的 VALID。 但這是無害的,因為如果沒有 MMIO 門戶,它們將無法向裝置提交新工作。
31.7. 關係¶
每個程序都有多個執行緒,但只有一個 PASID。
裝置具有有限數量(約 10 到 1000 個)的硬體工作佇列。 裝置驅動程式管理硬體工作佇列的分配。
單個 mmap() 將單個硬體工作佇列對映為“門戶”,並且每個門戶都對映到單個工作佇列。
對於程序與之互動的每個裝置,必須有一個或多個 mmap()’d 門戶。
程序中的多個執行緒可以共享單個門戶來訪問單個裝置。
多個程序可以分別 mmap() 同一個門戶,在這種情況下,它們仍然共享一個裝置硬體工作佇列。
所有執行緒都使用單個程序範圍的 PASID 與所有裝置互動。 例如,沒有每個執行緒或每個執行緒<->裝置對的 PASID。
31.8. 常見問題解答¶
什麼是 SVA/SVM?
共享虛擬定址 (SVA) 允許 I/O 硬體和處理器在同一地址空間中工作,即共享它。 有些人稱其為共享虛擬記憶體 (SVM),但 Linux 社群希望避免將其與 POSIX 共享記憶體和安全虛擬機器混淆,這些術語已經在流通。
什麼是 PASID?
程序地址空間 ID (PASID) 是 PCIe 定義的事務層資料包 (TLP) 字首。 PASID 是一個由 OS 分配和管理的 20 位數字。 PASID 包含在平臺和裝置之間的所有事務中。
共享工作佇列有何不同?
傳統上,為了使使用者空間應用程式與硬體互動,每個程序都需要一個單獨的硬體例項。 例如,將門鈴視為通知硬體有關要處理的工作的機制。 每個門鈴需要間隔 4k(或頁面大小),以實現程序隔離。 這需要硬體來配置該空間並在 MMIO 中保留它。 隨著執行緒數量變得非常大,這無法擴充套件。 硬體還管理共享工作佇列 (SWQ) 的佇列深度,並且使用者無需跟蹤佇列深度。 如果沒有空間接受命令,裝置將返回一個指示重試的錯誤。
使用者應檢查裝置上的可延期記憶體寫入 (DMWr) 功能,並且僅當裝置支援它時才提交 ENQCMD。 在新的 DMWr PCIe 術語中,裝置需要支援 DMWr 完成器功能。 此外,它需要所有交換機埠都支援 DMWr 路由,並且必須由 PCIe 子系統啟用,就像 PCIe 原子操作的託管方式一樣。
SWQ 允許硬體僅在裝置中配置單個地址。 當與 ENQCMD 一起提交工作時,裝置可以區分提交工作的程序,因為它將包含分配給該程序的 PASID。 這有助於裝置擴充套件到大量程序。
這與使用者空間裝置驅動程式相同嗎?
透過共享工作佇列與裝置通訊比完整的使用者空間驅動程式簡單得多。 核心驅動程式完成硬體的所有初始化。 使用者空間只需要擔心提交工作和處理完成。
這與 SR-IOV 相同嗎?
單根 I/O 虛擬化 (SR-IOV) 側重於為虛擬化硬體提供獨立的硬體介面。 因此,它需要成為一個幾乎完全功能的軟體介面,支援傳統的 BAR、透過 MSI-X 中斷的空間以及其自身的暫存器佈局。 虛擬功能 (VF) 由物理功能 (PF) 驅動程式協助。
可擴充套件 I/O 虛擬化建立在 PASID 概念的基礎上,為虛擬化建立裝置例項。 SIOV 需要主機軟體來協助建立虛擬裝置; 每個虛擬裝置由 PASID 以及裝置的匯流排/裝置/功能表示。 這允許裝置硬體最佳化裝置資源的建立,並且可以根據需要動態增長。 SR-IOV 的建立和管理本質上非常靜態。 有關更多詳細資訊,請參閱下面的參考。
為什麼不為每個應用程式建立一個虛擬功能?
建立 PCIe SR-IOV 型別虛擬功能 (VF) 的成本很高。 VF 需要複製硬體以用於 PCI 配置空間和中斷,例如 MSI-X。 在建立時,必須在 VF 之間對中斷等資源進行硬分割槽,並且無法根據需要動態擴充套件。 VF 並不完全獨立於物理功能 (PF)。 大多數 VF 都需要來自 PF 驅動程式的某種通訊和協助。 相比之下,SIOV 建立了一個軟體定義的裝置,其中所有配置和控制方面都透過慢速路徑進行調解。 工作提交和完成的發生沒有任何調解。
這是否支援虛擬化?
ENQCMD 可以從來賓 VM 中使用。 在這些情況下,VMM 有助於設定轉換表以從來賓 PASID 轉換為主機 PASID。 請參閱 ENQCMD 指令集參考以獲取更多詳細資訊。
是否需要固定記憶體?
當裝置支援 SVA 以及支援此類裝置的平臺硬體(例如 IOMMU)時,無需為 DMA 目的固定記憶體。 支援 SVA 的裝置也支援其他 PCIe 功能,這些功能消除了對記憶體的固定要求。
裝置 TLB 支援 - 裝置請求 IOMMU 在透過地址轉換服務 (ATS) 請求使用之前查詢地址。 如果對映存在但 OS 未分配頁面,則 IOMMU 硬體會返回不存在對映。
裝置請求透過頁面請求介面 (PRI) 對映虛擬地址。 OS 成功完成對映後,它會將響應返回給裝置。 裝置再次請求轉換並繼續。
IOMMU 與 OS 協作以管理裝置頁表的一致性。 刪除頁面時,它與裝置互動以刪除可能已快取的任何裝置 TLB 條目,然後再從 OS 中刪除對映。
31.9. 參考¶
SIOV: https://01.org/blogs/2019/assignable-interfaces-intel-scalable-i/o-virtualization-linux
ISE 中的 ENQCMD: https://software.intel.com/sites/default/files/managed/c5/15/architecture-instruction-set-extensions-programming-reference.pdf
DSA 規範: https://software.intel.com/sites/default/files/341204-intel-data-streaming-accelerator-spec.pdf