RFC-0224:使用者空間 J-Extension 指標遮蓋

RFC-0224:使用者空間 J 擴充功能指標遮蓋
狀態已接受
區域
  • Kernel
說明

為配合 RISC-V 指標遮罩擴充功能而進行的必要變更。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2023-03-09
審查日期 (年-月-日)2023-09-05

摘要

本文提出支援 Fuchsia 使用者空間中 RISC-V J 擴充功能指標遮罩功能所需的變更。

提振精神

RISC-V J 擴充功能的目標是讓 RISC-V 成為傳統上經過解譯或 JIT 編譯的語言,或是需要大型執行階段程式庫或語言層級虛擬機器的語言,都適用的目標。包括但不限於 C#、Go、Haskell、Java、JavaScript、OCaml、PHP、Python、R、Ruby、Scala、Smalltalk 或 WebAssembly。J 擴充功能的一項顯著功能是指標遮罩 (PM)。這項硬體功能啟用後,MMU 就能在記憶體存取時忽略有效位址的前 N 位元。這與 ARMv8.0 CPU 的 Top-Byte-Ignore (TBI) 功能非常相似。PM 的其中一項立即用途,是在使用者空間中啟用硬體輔助的 AddressSanitizer (HWASan),其中標記會儲存在頂端位元組中,用於追蹤記憶體。

術語

本文件使用的許多術語都可從 RFC-0143:使用者空間頂端位元忽略延伸而來。

位址 - 位址是 64 位元的整數,代表使用者位址空間界限內的某個位置。地址絕不會加上標記。

指標 - 可取消參照的記憶體位置,可能含有標記。這等同於 RISC-V Base ISA 中定義的有效位址。

標記:指標的上層位元,通常用於中繼資料。RISC-V 指標遮罩支援不同大小的標記。

Zjpm - 這是 J 擴充功能中指標遮罩功能的正式 ID。

設計

符合標記指標 ABI

Zjpm 可啟用已加上標記的使用者空間指標。核心處理這些指標時,須遵守 RFC-0143 中規定的相同規則。也就是:

  1. 核心會忽略從系統呼叫接收的使用者指標上的標記。

  2. 在接受位址的系統呼叫中傳遞已標記的指標是錯誤行為。

  3. 當核心接受已加上標記的指標時 (無論是透過系統呼叫或錯誤), 都會盡量保留標記,讓使用者程式碼稍後可以觀察到標記。

  4. 核心本身絕不會產生標記指標。

  5. 比較使用者空間指標時,核心會忽略可能存在的任何標記。

此外,Zjpm 會由核心啟動選項控制。與 ARM TBI 類似,啟用 Zjpm 後,所有使用者空間程序都會開啟這項功能。

RISC-V 不會為寫入偵錯暫存器的值提供語意意義,因此偵錯工具可以自由地將標記值寫入偵錯暫存器。對於監看點等功能,指標比較作業是透過 mcontext6 暫存器的 match 欄位控制,可控制為比對完全相符的標記值,或忽略標記 (就像指標遮罩一樣)。

將標記設為 8 位元 (適用於 Sv39 和 Sv48)

Zjpm 最直接的用途是在 RISC-V 上啟用記憶體錯誤偵測工具 (例如 HWASan),這類工具會將中繼資料儲存到指標的最高位元。ARM TBI 僅支援 8 位元的標記大小。不過,Zjpm 的彈性高出許多,可忽略記憶體存取的前幾位。在不同模式下,可透過 CSR 暫存器控制位元數。

最簡單的方法就是遵守現行規定。ARM TBI 和 HWASan 已使用 8 位元標記,但目前或可預見的未來,都不會需要大於 (或小於) 8 位元的標記。

Sv39 和 Sv48 僅支援 8 位元的標記大小。這是因為 Sv57 只支援遮蓋前 7 個位元。如果日後支援 Sv57,則必須重新檢視標記大小。

實作

實作方式與 ARM TBI 的實作方式非常相似。在 U 模式中,於 upm CSR 中設定 uenable 位元,即可啟用 Zjpm。您可以在 upm 中透過 ubits 位元欄位設定標記大小。

現有的系統呼叫基礎架構應已設定完畢,可接受具有固定標記大小的標記使用者空間指標。

ZX_FEATURE_KIND_ADDRESS_TAGGING 功能會多出一個旗標 (類似 ZX_RISCV64_FEATURE_ADDRESS_TAGGING_ZJPM_8BIT),表示已啟用 Zjpm 和標記大小。ZX_RISCV64_FEATURE_ADDRESS_TAGGING_ZJPM_8BIT 表示前 8 位元一定會遮蓋,但日後我們可能會新增其他標記,表示要遮蓋更多上位元。舉例來說,我們可以新增類似 ZX_RISCV64_FEATURE_ADDRESS_TAGGING_ZJPM_16BIT 的內容,指出頂端 16 位元已遮蓋,但 ZX_FEATURE_KIND_ADDRESS_TAGGING 也會設定 8 位元等效旗標,確保檢查 8 位元旗標的相容程式碼適用於未來的系統。

Zjpm 也必須啟用 Zicsr 擴充功能,才能提供修改 CSR 暫存器的指令。

效能

對效能的影響應該微乎其微,現有的微基準將用於驗證。

測試

用於測試 ARM TBI 的同一套測試也應套用至 Zjpm。這些測試應大致不受啟用的地址標記模式影響。

缺點、替代方案和未知事項

Zjpm 比 ARM TBI 更有彈性,因此我們能支援更多遮蓋選項。

目前似乎沒有任何硬體支援最新版 Zjpm,因此核心如何探索硬體支援的項目,仍未明確指定。在我們瞭解硬體實際限制之前,如果支援任何功能,保守的單一功能永遠開啟模式將是最佳選擇。QEMU 應支援指標遮罩,並可透過「x-j」CPU 屬性啟用。

將標記一律設為其他靜態值

標記 ABI 允許支援不同大小的標記 (也就是說,我們不受限於 8 位元)。實際上,我們不太會使用虛擬位址的頂端位元。在 x86 上,我們實際上只會使用底部 48 位元,但這只是我們目前目標的假設,未來可能會有所變更。目前,表示標記大小的位元欄位長度為 5 位元,也就是說,指標最多只能忽略前 31 個位元。這個欄位以上的其餘位元是 WPRI,因此這個欄位日後可能會擴充,以容納較大的值。

對於 HWASan 等工具,記憶體標記演算法不一定會依附於 8 位元的標記大小。將標記大小增加到 16 位元等值,可以大幅降低標記比較中發生誤判的可能性,但這表示需要將較大的標記儲存到陰影記憶體中,這並非理想做法。目前 8 位元的偽陽性機率也很小。

將標記公開為使用者空間的可修改值

這個選項表示要向使用者公開指標遮罩功能。 也就是說,使用者可以 (1) 在執行階段啟用/停用指標遮蓋,以及 (2) 變更標記大小。由於沒有立即執行的必要,且需要新增更多系統呼叫來切換這些值,因此這可能不是理想做法。不過,標記 ABI 預留了空間,未來可支援這項功能。

指令擷取時的指標遮蔽

Zjpm 的一項強大功能,是在指令擷取時啟用 PM,包括因直線執行而導致 PC 單調遞增、控制項轉移 (例如分支和直接/間接跳轉,以及 uret/sret/mret) 所產生的指令擷取。這項提案僅列出資料指標的指標遮罩規則,但保留了日後探索這項選項的空間。

與其他理想硬體功能的互動

Zjpm 只會導入指標遮罩功能。其他實用功能 (例如標記檢查或沙箱強制執行) 可能會實作在軟體或未來需要 Zjpm 的硬體擴充功能中。類似的例子是 ARM MTE,這項功能依附於 TBI。

草稿變更

Zjpm 目前仍為提案草案,但我們希望在 RVA23 中批准這項提案,讓 HWASan 正式支援這項提案。如果規格有重大變更,我們會更新這份文件。