AArch64 Linux 的可擴充套件矩陣擴充套件支援

本文件簡要概述了 Linux 提供給使用者空間的介面,以支援 ARM 可擴充套件矩陣擴充套件 (SME) 的使用。

這只是最重要功能和問題的概述,並非旨在詳盡無遺。應與 AArch64 Linux 的可擴充套件向量擴充套件支援 中的 SVE 文件結合閱讀,該文件提供了 SME 中包含的流式 SVE 模式的詳細資訊。

本文件不旨在描述 SME 架構或程式設計師模型。為了幫助理解,附錄 A 中包含了 SME 相關程式設計師模型功能的最低限度描述。

1. 概述

  • PSTATE.SM、PSTATE.ZA、流式模式向量長度、ZA 和(如果存在)ZTn 暫存器狀態以及 TPIDR2_EL0 是按執行緒跟蹤的。

  • SME 的存在透過 aux vector AT_HWCAP2 條目中的 HWCAP2_SME 報告給使用者空間。此標誌的存在意味著 SME 指令和暫存器的存在,以及本文件中描述的特定於 Linux 的系統介面。SME 在 /proc/cpuinfo 中報告為“sme”。

  • SME2 的存在透過 aux vector AT_HWCAP2 條目中的 HWCAP2_SME2 報告給使用者空間。此標誌的存在意味著 SME2 指令和 ZT0 的存在,以及本文件中描述的特定於 Linux 的系統介面。SME2 在 /proc/cpuinfo 中報告為“sme2”。

  • 還可以透過使用 MRS 指令讀取 CPU ID 暫存器 ID_AA64PFR1_EL1 並檢查 SME 欄位的值是否非零來檢測使用者空間中 SME 指令的執行支援。[3]

    它不保證存在以下各節中描述的系統介面:需要驗證這些介面是否存在的軟體必須檢查 HWCAP2_SME。

  • 有許多可選的 SME 功能,這些功能的存在透過 AT_HWCAP2 報告:

    HWCAP2_SME_I16I64 HWCAP2_SME_F64F64 HWCAP2_SME_I8I32 HWCAP2_SME_F16F32 HWCAP2_SME_B16F32 HWCAP2_SME_F32F32 HWCAP2_SME_FA64 HWCAP2_SME2

    隨著 SME 架構的發展,此列表可能會隨著時間的推移而擴充套件。

    這些擴充套件也透過 CPU ID 暫存器 ID_AA64SMFR0_EL1 報告,使用者空間可以使用 MRS 指令讀取該暫存器。有關詳細資訊,請參閱 ARM64 ELF hwcapsARM64 CPU 功能暫存器

  • 偵錯程式應將自身限制為透過 NT_ARM_SVE、NT_ARM_SSVE、NT_ARM_ZA 和 NT_ARM_ZT regset 與目標進行互動。檢測對這些 regset 的支援的推薦方法是首先連線到目標程序,然後嘗試

    ptrace(PTRACE_GETREGSET, pid, NT_ARM_<regset>, &iov).

  • 每當 ZA 暫存器值在使用者空間和核心之間在記憶體中交換時,暫存器值在記憶體中編碼為一系列從 0 到 VL/8-1 的水平向量,儲存在與 SVE 向量相同的位元組序不變格式中。

  • 線上程建立時,PSTATE.ZA 和 TPIDR2_EL0 會被保留,除非指定了 CLONE_VM,在這種情況下,PSTATE.ZA 設定為 0,TPIDR2_EL0 設定為 0。

2. 向量長度

SME 定義了第二個向量長度,類似於 SVE 向量長度,它控制流式模式 SVE 向量和 ZA 矩陣陣列的大小。ZA 矩陣是正方形的,每條邊都具有與流式模式 SVE 向量一樣多的位元組。

3. 流式和非流式模式 SVE 狀態的共享

由實現定義 SVE 狀態的哪些部分(如果有)在流式和非流式模式之間共享。當透過軟體介面(如 ptrace)在模式之間切換時,如果未提供任何暫存器內容作為切換的一部分,則不會假定共享任何狀態,並且所有內容都將被清零。

4. 系統呼叫行為

  • 在 syscall 上,PSTATE.ZA 被保留,如果 PSTATE.ZA==1,則 ZA 矩陣和 ZTn(如果存在)的內容會被保留。

  • 在 syscall 上,PSTATE.SM 將被清除,SVE 暫存器將按照標準 SVE ABI 處理。

  • SVE 暫存器、ZA 或 ZTn 均不用於將引數傳遞給任何 syscall 或從任何 syscall 接收結果。

  • 在程序建立時(例如,clone()),新建立的程序的 PSTATE.SM 將被清除。

  • 執行緒的所有其他 SME 狀態,包括當前配置的向量長度、PR_SME_VL_INHERIT 標誌的狀態以及延遲向量長度(如果有),都會在所有 syscall 中保留,但第 6 節中描述的 execve() 的特定例外情況除外。

5. 訊號處理

  • 訊號處理程式以 PSTATE.SM=0、PSTATE.ZA=0 和 TPIDR2_EL0=0 呼叫。

  • 添加了一個新的訊號幀記錄 TPIDR2_MAGIC,格式化為 struct tpidr2_context,允許從訊號處理程式訪問 TPIDR2_EL0。

  • 一個新的訊號幀記錄 za_context 在訊號傳遞時編碼 ZA 暫存器內容。[1]

  • ZA 的訊號幀記錄始終包含基本元資料,特別是執行緒的向量長度(在 za_context.vl 中)。

  • ZA 矩陣可能包含在記錄中,也可能不包含,具體取決於 PSTATE.ZA 的值。當且僅當以下情況時,暫存器才存在:za_context.head.size >= ZA_SIG_CONTEXT_SIZE(sve_vq_from_vl(za_context.vl)),在這種情況下,PSTATE.ZA == 1。

  • 如果矩陣資料存在,則記錄的其餘部分具有 vl 相關的大小和佈局。定義了宏 ZA_SIG_* [1] 以方便訪問它們。

  • 矩陣儲存為一系列水平向量,格式與 SVE 向量使用的格式相同。

  • 如果 ZA 上下文太大而無法放入 sigcontext.__reserved[] 中,則會在堆疊上分配額外的空間,並在 __reserved[] 中寫入一個 extra_context 記錄,引用此空間。然後將 za_context 寫入額外空間。有關此機制的更多詳細資訊,請參閱 [1]。

  • 如果支援 ZTn 且 PSTATE.ZA==1,則將為 ZTn 生成訊號幀記錄。

  • ZTn 的訊號記錄具有 magic ZT_MAGIC (0x5a544e01),由標準訊號幀標頭組成,後跟一個 struct zt_context,指定系統支援的 ZTn 暫存器的數量,然後是 zt_context.nregs 個數據塊,每個暫存器 64 位元組。

5. 訊號返回

從訊號處理程式返回時

  • 如果訊號幀中沒有 za_context 記錄,或者如果記錄存在但不包含上一節中描述的任何暫存器資料,則 ZA 被停用。

  • 如果 za_context 存在於訊號幀中並且包含矩陣資料,則 PSTATE.ZA 設定為 1,ZA 用指定的資料填充。

  • 無法透過訊號返回更改向量長度。如果訊號幀中的 za_context.vl 與當前向量長度不匹配,則訊號返回嘗試被視為非法,導致強制 SIGSEGV。

  • 如果不支援 ZTn 或 PSTATE.ZA==0,則具有 ZTn 的訊號幀記錄是非法的,導致強制 SIGSEGV。

6. prctl 擴充套件

添加了一些新的 prctl() 呼叫,以允許程式管理 SME 向量長度

prctl(PR_SME_SET_VL, unsigned long arg)

設定呼叫執行緒的向量長度和相關標誌,其中 arg == vl | flags。呼叫程序的其他執行緒不受影響。

vl 是所需的向量長度,其中 sve_vl_valid(vl) 必須為真。

標誌

PR_SME_VL_INHERIT

在 execve() 期間繼承當前向量長度。否則,向量長度會在 execve() 處重置為系統預設值。(請參閱第 9 節。)

PR_SME_SET_VL_ONEXEC

將請求的向量長度更改延遲到此執行緒執行的下一個 execve()。

效果等效於線上程執行的下一個 execve()(如果有)之後立即隱式執行以下呼叫

prctl(PR_SME_SET_VL, arg & ~PR_SME_SET_VL_ONEXEC)

這允許啟動具有不同向量長度的新程式,同時避免呼叫者中的執行時副作用。

如果沒有 PR_SME_SET_VL_ONEXEC,則請求的更改會立即生效。

返回值:成功時為非負值,錯誤時為負值
EINVAL:不支援 SME,請求的向量長度無效,或者

標誌無效。

成功時

  • 呼叫執行緒的向量長度或將線上程的下一個 execve() 處應用的延遲向量長度(取決於 arg 中是否存在 PR_SME_SET_VL_ONEXEC),設定為系統支援的最大值,該值小於或等於 vl。如果 vl == SVE_VL_MAX,則設定的值將是系統支援的最大值。

  • 取消呼叫執行緒中任何先前未完成的延遲向量長度更改。

  • 返回的值描述了結果配置,編碼為 PR_SME_GET_VL。如果 arg 中不存在 PR_SME_SET_VL_ONEXEC,則此值中報告的向量長度是此執行緒的新當前向量長度;否則,報告的向量長度是將在此呼叫執行緒的下一個 execve() 處應用的延遲向量長度。

  • 更改向量長度會導致所有 ZA、ZTn、P0..P15、FFR 和 Z0..Z31 的所有位(除了 Z0 位 [127:0] .. Z31 位 [127:0])變得未指定,包括流式和非流式 SVE 狀態。使用等於執行緒當前向量長度的 vl 呼叫 PR_SME_SET_VL,或者使用 PR_SME_SET_VL_ONEXEC 標誌呼叫 PR_SME_SET_VL,並不構成此目的的向量長度更改。

  • 更改向量長度會導致 PSTATE.ZA 被清除。使用等於執行緒當前向量長度的 vl 呼叫 PR_SME_SET_VL,或者使用 PR_SME_SET_VL_ONEXEC 標誌呼叫 PR_SME_SET_VL,並不構成此目的的向量長度更改。

prctl(PR_SME_GET_VL)

獲取呼叫執行緒的向量長度。

以下標誌可以 OR 運算到結果中

PR_SME_VL_INHERIT

向量長度將在 execve() 中繼承。

無法確定是否存在未完成的延遲向量長度更改(這通常只會在 fork() 或 vfork() 與典型使用中相應的 execve() 之間發生)。

要從結果中提取向量長度,請將其與 PR_SME_VL_LEN_MASK 進行按位與運算。

返回值:成功時為非負值,錯誤時為負值

EINVAL:不支援 SME。

7. ptrace 擴充套件

  • 定義了一個新的 regset NT_ARM_SSVE,用於透過 PTRACE_GETREGSET 和 PTRACE_SETREGSET 訪問流式模式 SVE 狀態,這在 AArch64 Linux 的可擴充套件向量擴充套件支援 中有記錄。

  • 定義了一個新的 regset NT_ARM_ZA,用於透過 PTRACE_GETREGSET 和 PTRACE_SETREGSET 訪問 ZA 狀態。

    有關定義,請參閱 [2]。

regset 資料以 struct user_za_header 開頭,包含

size

完整 regset 的大小,以位元組為單位。這取決於 vl,並且可能取決於未來的其他因素。

如果對 PTRACE_GETREGSET 的呼叫請求的資料少於 size 的值,則呼叫者可以分配更大的緩衝區並重試以讀取完整的 regset。

max_size

regset 可以為目標執行緒增長到的最大大小(以位元組為單位)。即使目標執行緒更改其向量長度等,regset 也不會變得更大。

vl

目標執行緒的當前流式向量長度,以位元組為單位。

max_vl

目標執行緒的最大可能流式向量長度。

標誌

以下標誌中的零個或多個,其含義和行為與相應的 PR_SET_VL_* 標誌相同

SME_PT_VL_INHERIT

SME_PT_VL_ONEXEC(僅 SETREGSET)。

  • 更改向量長度和/或標誌的效果等效於 PR_SME_SET_VL 的文件中記錄的效果。

    如果呼叫者需要知道 SETREGSET 實際設定的 VL 是什麼,則必須進行進一步的 GETREGSET 呼叫,除非事先知道支援請求的 VL。

  • 有效負載的大小和佈局取決於標頭欄位。提供了 ZA_PT_ZA*() 宏以方便訪問資料。

  • 在任何一種情況下,對於 SETREGSET,允許省略有效負載,在這種情況下,向量長度和標誌會更改,並且 PSTATE.ZA 設定為 0(以及這些更改的任何後果)。如果提供了有效負載,則 PSTATE.ZA 將設定為 1。

  • 對於 SETREGSET,如果不支援請求的 VL,則效果將與省略有效負載的效果相同,除了報告 EIO 錯誤。不會嘗試將有效負載資料轉換為實際設定的向量長度的正確佈局。由呼叫者負責將有效負載佈局轉換為實際的 VL 並重試。

  • 寫入部分、不完整的有效負載的效果未指定。

  • 定義了一個新的 regset NT_ARM_ZT,用於透過 PTRACE_GETREGSET 和 PTRACE_SETREGSET 訪問 ZTn 狀態。

  • NT_ARM_ZT regset 由單個 512 位暫存器組成。

  • 當 PSTATE.ZA==0 時,讀取 NT_ARM_ZT 會將 ZTn 的所有位報告為 0。

  • 寫入 NT_ARM_ZT 將 PSTATE.ZA 設定為 1。

  • 如果提供了任何暫存器資料以及 SME_PT_VL_ONEXEC,則暫存器資料將以當前向量長度解釋,而不是配置為在 exec 上使用的向量長度。

8. ELF 核心轉儲擴充套件

  • NT_ARM_SSVE 註釋將新增到每個核心轉儲中,用於已轉儲程序的每個執行緒。這些內容將等效於如果為每個執行緒執行相應型別的 PTRACE_GETREGSET 時將讀取的資料(在生成核心轉儲時)。

  • NT_ARM_ZA 註釋將新增到每個核心轉儲中,用於已轉儲程序的每個執行緒。這些內容將等效於如果為每個執行緒執行 NT_ARM_ZA 的 PTRACE_GETREGSET 時將讀取的資料(在生成核心轉儲時)。

  • NT_ARM_ZT 註釋將新增到每個核心轉儲中,用於已轉儲程序的每個執行緒。這些內容將等效於如果為每個執行緒執行 NT_ARM_ZT 的 PTRACE_GETREGSET 時將讀取的資料(在生成核心轉儲時)。

  • NT_ARM_TLS 註釋將擴充套件到兩個暫存器,第二個暫存器將在支援 SME 的系統上包含 TPIDR2_EL0,否則將讀取為零,寫入將被忽略。

9. 系統執行時配置

  • 為了緩解擴充套件訊號幀對 ABI 的影響,提供了一種策略機制,供管理員、發行版維護者和開發人員設定使用者空間程序的預設向量長度

/proc/sys/abi/sme_default_vector_length

將整數的文字表示形式寫入此檔案會將系統預設向量長度設定為指定的值,該值使用與透過 PR_SME_SET_VL 設定向量長度相同的規則四捨五入為支援的值。

可以透過重新開啟該檔案並讀取其內容來確定結果。

在啟動時,預設向量長度最初設定為 32 或最大支援的向量長度,以較小且受支持者為準。這決定了 init 程序 (PID 1) 的初始向量長度。

讀取此檔案返回當前系統預設向量長度。

  • 在每次 execve() 呼叫時,新程序的新向量長度設定為系統預設向量長度,除非

    • 為呼叫執行緒設定了 PR_SME_VL_INHERIT(或等效的 SME_PT_VL_INHERIT),或者

    • 存在延遲向量長度更改,透過 PR_SME_SET_VL_ONEXEC 標誌(或 SME_PT_VL_ONEXEC)建立。

  • 修改系統預設向量長度不會影響任何現有程序或執行緒的向量長度,這些程序或執行緒不會進行 execve() 呼叫。

附錄 A. SME 程式設計師模型(資訊性)

本節提供 SME 對 ARMv8-A 程式設計師模型所做的新增的最低限度描述,這些新增與本文件相關。

注意:本節僅供參考,並非旨在完整或取代任何架構規範。

A.1. 暫存器

在 A64 狀態下,SME 添加了以下內容

  • 一種新模式,即流式模式,在該模式下,可以使用普通 FPSIMD 和 SVE 功能的子集。如果支援,EL0 軟體可以隨時進入和離開流式模式。

    為了獲得最佳系統性能,強烈建議軟體僅在主動使用時才啟用流式模式。

  • 一個新的向量長度,用於控制 ZA 和 Z 暫存器在流式模式下的大小,與 SVE 在非流式模式下使用的向量長度分開。不要求給定系統中兩種模式支援的當前選定向量長度或向量長度集之間存在任何關係。流式模式向量長度稱為 SVL。

  • 一個新的 ZA 矩陣暫存器。這是一個 SVLxSVL 位的正方形矩陣。ZA 上的大多數操作都需要啟用流式模式,但可以在沒有流式模式的情況下啟用 ZA,以便載入、儲存和保留資料。

    為了獲得最佳系統性能,強烈建議軟體僅在主動使用時才啟用 ZA。

  • 當 SME2 存在時,會引入一個新的 ZT0 暫存器。這是一個 512 位暫存器,當設定了 PSTATE.ZA 時可以訪問它,就像 ZA 本身一樣。

  • PSTATE 中的兩個新的 1 位欄位,可以透過 SMSTART 和 SMSTOP 指令或訪問 SVCR 系統暫存器來控制

    • PSTATE.ZA,如果為 1,則 ZA 矩陣是可訪問的並且具有有效資料,而如果為 0,則無法訪問 ZA。當 PSTATE.ZA 從 0 更改為 1 時,ZA 中的所有位都會被清除。

    • PSTATE.SM,如果為 1,則 PE 處於流式模式。當 PSTATE.SM 的值更改時,由實現定義在兩種模式下都有效的浮點暫存器位的子集是否可以保留。任何其他位將被清除。

參考文獻

[1] arch/arm64/include/uapi/asm/sigcontext.h

AArch64 Linux 訊號 ABI 定義

[2] arch/arm64/include/uapi/asm/ptrace.h

AArch64 Linux ptrace ABI 定義

[3] ARM64 CPU 功能暫存器