AArch64 Linux 可伸縮向量擴充套件支援

作者: Dave Martin <Dave.Martin@arm.com>

日期: 2017 年 8 月 4 日

本文件簡要概述了 Linux 提供給使用者空間的介面,以便支援使用 ARM 可伸縮向量擴充套件 (SVE),包括與可伸縮矩陣擴充套件 (SME) 新增的流式 SVE 模式的互動。

這只是對最重要特性和問題的概述,並非旨在詳盡無遺。

本文件不旨在描述 SVE 架構或程式設計師模型。為了幫助理解,附錄 A 包含對 SVE 相關程式設計師模型特性的最簡描述。

1. 概述

  • SVE 暫存器 Z0..Z31、P0..P15 和 FFR 以及當前向量長度 VL,按執行緒跟蹤。

  • 在流式模式下,FFR 不可訪問,除非系統中存在 HWCAP2_SME_FA64,當不支援時,使用這些介面訪問流式模式 FFR 將讀取和寫入為零。

  • SVE 的存在透過輔助向量 AT_HWCAP 條目中的 HWCAP_SVE 報告給使用者空間。此標誌的存在意味著存在 SVE 指令和暫存器,以及本文件中描述的 Linux 特定系統介面。SVE 在 /proc/cpuinfo 中報告為“sve”。

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

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

  • 在支援 SVE2 擴充套件的硬體上,AT_HWCAP2 輔助向量條目中也會報告 HWCAP2_SVE2。 除此之外,可以透過以下方式報告 SVE2 的可選擴充套件:

    HWCAP2_SVE2 HWCAP2_SVEAES HWCAP2_SVEPMULL HWCAP2_SVEBITPERM HWCAP2_SVESHA3 HWCAP2_SVESM4 HWCAP2_SVE2P1

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

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

  • 在支援 SME 擴充套件的硬體上,AT_HWCAP2 輔助向量條目中也會報告 HWCAP2_SME。 其中,SME 添加了流式模式,該模式使用單獨的 SME 向量長度和相同的 Z/V 暫存器提供 SVE 功能集的子集。 有關更多詳細資訊,請參閱 AArch64 Linux 的可伸縮矩陣擴充套件支援

  • 偵錯程式應將自己限制為透過 NT_ARM_SVE regset 與目標互動。 檢測對此 regset 支援的推薦方法是首先連線到目標程序,然後嘗試 ptrace(PTRACE_GETREGSET, pid, NT_ARM_SVE, &iov)。 請注意,當存在 SME 且正在使用流式 SVE 模式時,暫存器的 FPSIMD 子集將透過 NT_ARM_SVE 讀取,並且 NT_ARM_SVE 寫入將退出目標中的流式模式。

  • 每當 SVE 可伸縮暫存器值 (Zn, Pn, FFR) 在使用者空間和核心之間以記憶體形式交換時,暫存器值都以位元組序不變的佈局在記憶體中編碼,位 [(8 * i + 7) : (8 * i)] 在記憶體表示的起始位置偏移 i 個位元組處編碼。 這會影響例如訊號幀 (struct sve_context) 和 ptrace 介面 (struct user_sve_header) 以及關聯的資料。

    請注意,在大端系統上,這會導致與 FPSIMD V 暫存器不同的位元組順序,FPSIMD V 暫存器儲存為單個主機位元組序 128 位值,暫存器的位 [(127 - 8 * i) : (120 - 8 * i)] 在偏移 i 個位元組處編碼。(struct fpsimd_context,struct user_fpsimd_state)。

2. 向量長度術語

SVE 向量 (Z) 暫存器的大小稱為“向量長度”。

為了避免對用於表示向量長度的單位產生混淆,核心採用以下約定:

  • 向量長度 (VL) = Z 暫存器的大小(以位元組為單位)

  • 向量四字 (VQ) = Z 暫存器的大小(以 128 位為單位)

(因此,VL = 16 * VQ。)

VQ 約定用於基礎粒度很重要的地方,例如在資料結構定義中。 在大多數其他情況下,使用 VL 約定。 這與 SVE 指令集架構中“VL”偽暫存器的含義一致。

3. 系統呼叫行為

  • 在系統呼叫上,V0..V31 被保留(就像沒有 SVE 一樣)。 因此,Z0..Z31 的位 [127:0] 被保留。 Z0..Z31 的所有其他位,以及所有 P0..P15 和 FFR 在從系統呼叫返回時變為零。

  • SVE 暫存器不用作將引數傳遞到任何系統呼叫或從任何系統呼叫接收結果。

  • 執行緒的所有其他 SVE 狀態,包括當前配置的向量長度、PR_SVE_VL_INHERIT 標誌的狀態以及延遲向量長度(如果有),都將在所有系統呼叫中保留,但第 6 節中描述的 execve() 的特定異常除外。

    特別是,從 fork() 或 clone() 返回時,父程序和新的子程序或執行緒共享相同的 SVE 配置,與呼叫之前父程序的配置匹配。

4. 訊號處理

  • 一個新的訊號幀記錄 sve_context 在訊號傳遞時編碼 SVE 暫存器。[1]

  • 此記錄是 fpsimd_context 的補充。 FPSR 和 FPCR 暫存器僅存在於 fpsimd_context 中。 為方便起見,V0..V31 的內容在 sve_context 和 fpsimd_context 之間重複。

  • 該記錄包含一個標誌欄位,其中包括一個標誌 SVE_SIG_FLAG_SM,如果設定,則表示該執行緒處於流式模式,並且向量長度和暫存器資料(如果存在)描述流式 SVE 資料和向量長度。

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

  • SVE 暫存器可能包含在記錄中,也可能不包含在記錄中,具體取決於暫存器對於執行緒是否有效。 暫存器僅當以下情況時才存在:sve_context.head.size >= SVE_SIG_CONTEXT_SIZE(sve_vq_from_vl(sve_context.vl))。

  • 如果暫存器存在,則記錄的其餘部分具有 vl 相關的尺寸和佈局。 宏 SVE_SIG_* 定義為 [1],以方便訪問成員。

  • 每個可伸縮暫存器(Zn、Pn、FFR)都以位元組序不變的佈局儲存,位 [(8 * i + 7) : (8 * i)] 儲存在暫存器的記憶體表示形式的起始位置偏移 i 個位元組處。

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

5. 訊號返回

從訊號處理程式返回時

  • 如果訊號幀中沒有 sve_context 記錄,或者如果記錄存在但不包含上一節中描述的任何暫存器資料,則 SVE 暫存器/位將變為無效,並採用未指定的值。

  • 如果 sve_context 存在於訊號幀中幷包含完整的暫存器資料,則 SVE 暫存器將變為有效,並填充指定的資料。 但是,出於向後相容的原因,始終從 fpsimd_context.vregs[] 的相應成員恢復 Z0..Z31 的位 [127:0],而不是從 sve_context 恢復。 其餘位從 sve_context 恢復。

  • 無論 sve_context 是否存在,訊號幀中都必須包含 fpsimd_context。

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

  • 允許透過設定或清除 SVE_SIG_FLAG_SM 標誌來進入或退出流式模式,但應用程式應注意確保在執行此操作時,sve_context.vl 和任何暫存器資料都適合新模式下的向量長度。

6. prctl 擴充套件

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

prctl(PR_SVE_SET_VL, unsigned long arg)

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

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

flags

PR_SVE_VL_INHERIT

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

PR_SVE_SET_VL_ONEXEC

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

其效果等同於在此執行緒的下一個 execve()(如果有)之後立即隱式執行以下呼叫

prctl(PR_SVE_SET_VL, arg & ~PR_SVE_SET_VL_ONEXEC)

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

如果沒有 PR_SVE_SET_VL_ONEXEC,請求的更改將立即生效。

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

標誌無效。

成功後

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

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

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

  • 更改向量長度會導致除 Z0 位 [127:0] .. Z31 位 [127:0] 之外的所有 P0..P15、FFR 和 Z0..Z31 的所有位變為未指定。 呼叫 vl 等於執行緒當前向量長度的 PR_SVE_SET_VL,或呼叫帶有 PR_SVE_SET_VL_ONEXEC 標誌的 PR_SVE_SET_VL,並不構成此目的的向量長度的更改。

prctl(PR_SVE_GET_VL)

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

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

PR_SVE_VL_INHERIT

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

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

要從結果中提取向量長度,請使用 PR_SVE_VL_LEN_MASK 進行按位與運算。

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

EINVAL:不支援 SVE。

7. ptrace 擴充套件

  • 定義了新的 regsets NT_ARM_SVE 和 NT_ARM_SSVE,以用於 PTRACE_GETREGSET 和 PTRACE_SETREGSET。 NT_ARM_SSVE 描述了流式模式 SVE 暫存器,NT_ARM_SVE 描述了非流式模式 SVE 暫存器。

    在此描述中,當目標處於適當的流式或非流式模式並且正在使用超出與 FPSIMD Vn 暫存器共享的子集的資料時,暫存器集被稱為“有效”。

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

regset 資料以 struct user_sve_header 開頭,其中包含

size

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

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

max_size

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

vl

目標執行緒的當前向量長度(以位元組為單位)。

max_vl

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

flags

最多一個

SVE_PT_REGS_FPSIMD

SVE 暫存器無效 (GETREGSET) 或將變為無效 (SETREGSET)。

有效負載的型別為 struct user_fpsimd_state,其含義與 NT_PRFPREG 相同,從 user_sve_header 的 SVE_PT_FPSIMD_OFFSET 偏移量開始。

將來可能會附加額外的資料:有效負載的大小應使用 SVE_PT_FPSIMD_SIZE(vq, flags) 獲取。

vq 應使用 sve_vq_from_vl(vl) 獲取。

SVE_PT_REGS_SVE

SVE 暫存器有效 (GETREGSET) 或將變為有效 (SETREGSET)。

有效負載包含 SVE 暫存器資料,從 user_sve_header 的 SVE_PT_SVE_OFFSET 偏移量開始,大小為 SVE_PT_SVE_SIZE(vq, flags);

... 與零個或多個以下標誌進行 OR 運算,這些標誌具有與相應 PR_SET_VL_* 標誌相同的含義和行為

SVE_PT_VL_INHERIT

SVE_PT_VL_ONEXEC(僅 SETREGSET)。

如果未提供 FPSIMD 和 SVE 標誌,則沒有暫存器有效負載可用,這僅在實現 SME 時才有可能。

  • 更改向量長度和/或標誌的效果與 PR_SVE_SET_VL 的文件記錄的效果相同。

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

  • 在 SVE_PT_REGS_SVE 情況下,有效負載的大小和佈局取決於標頭欄位。 提供了 SVE_PT_SVE_*() 宏,以方便訪問成員。

  • 在任何一種情況下,對於 SETREGSET,都可以省略有效負載,在這種情況下,僅更改向量長度和標誌(以及這些更改的任何後果)。

  • 在支援 SME 的系統中,當處於流式模式時,NT_REG_SVE 的 GETREGSET 將僅返回沒有暫存器資料的 user_sve_header,類似地,當不處於流式模式時,NT_REG_SSVE 的 GETREGSET 將不返回任何暫存器資料。

  • NT_ARM_SSVE 的 GETREGSET 永遠不會返回 SVE_PT_REGS_FPSIMD。

  • 對於 SETREGSET,如果存在 SVE_PT_REGS_SVE 有效負載且不支援請求的 VL,則效果將與省略有效負載的效果相同,但會報告 EIO 錯誤。 不會嘗試將有效負載資料轉換為實際設定的向量長度的正確佈局。 執行緒的 FPSIMD 狀態被保留,但 SVE 暫存器的其餘位變為未指定。 由呼叫方轉換實際 VL 的有效負載佈局並重試。

  • 在實現 SME 的情況下,無論硬體在兩種模式之間共享資料的實現定義的行為如何,都不可能在處於流式模式時 GETREGSET 正常 SVE 的暫存器狀態,也不可能在處於正常模式時 GETREGSET 流式模式暫存器狀態。

  • 任何 NT_ARM_SVE 的 SETREGSET 都將退出流式模式(如果目標處於流式模式),並且任何 NT_ARM_SSVE 的 SETREGSET 都將進入流式模式(如果目標不處於流式模式)。

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

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

8. ELF 核心轉儲擴充套件

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

9. 系統執行時配置

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

/proc/sys/abi/sve_default_vector_length

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

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

在引導時,預設向量長度最初設定為 64 或最大支援的向量長度,以較小者為準。 這確定了 init 程序 (PID 1) 的初始向量長度。

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

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

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

    • 存在透過 PR_SVE_SET_VL_ONEXEC 標誌(或 SVE_PT_VL_ONEXEC)建立的掛起的延遲向量長度更改。

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

10. Perf 擴充套件

  • arm64 特定 DWARF 標準 [5] 在索引 46 處添加了 VG(向量粒度)暫存器。 當可變長度 SVE 暫存器被推送到堆疊上時,此暫存器用於 DWARF 展開。

  • 其值等效於當前 SVE 向量長度 (VL)(以位為單位)除以 64。

  • 如果設定了 PERF_SAMPLE_REGS_USER 並且 sample_regs_user 掩碼的位 46 已設定,則該值將包含在 Perf 樣本的 regs[46] 欄位中。

  • 該值是獲取樣本時當前的值,並且會隨著時間的推移而變化。

  • 如果在使用這些設定呼叫 perf_event_open 時系統不支援 SVE,則事件將無法開啟。

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

本節提供 SVE 對 ARMv8-A 程式設計師模型的新增的最簡描述,這些新增與本文件相關。

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

A.1. 暫存器

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

  • 32 個 8VL 位向量暫存器 Z0..Z31 對於每個 Zn,Zn 位 [127:0] 是 ARMv8-A 向量暫存器 Vn 的別名。

    使用 Vn 暫存器名稱寫入暫存器會將相應 Zn 的所有位清零,但位 [127:0] 除外。

  • 16 個 VL 位謂詞暫存器 P0..P15

  • 1 個 VL 位專用謂詞暫存器 FFR(“首個故障暫存器”)

  • 一個 VL “偽暫存器”,用於確定每個向量暫存器的大小

    SVE 指令集架構不提供直接寫入 VL 的方法。 相反,它只能由 EL1 及以上版本透過寫入適當的系統暫存器來修改。

  • VL 的值可以由 EL1 及以上版本在執行時配置:16 <= VL <= VLmax,其中 VL 必須是 16 的倍數。

  • 最大向量長度由硬體確定:16 <= VLmax <= 256。

    (SVE 架構指定 256,但允許將來的架構修訂版提高此限制。)

  • FPSR 和 FPCR 從 ARMv8-A 保留,並且以類似於與 ARMv8 浮點運算互動的方式與 SVE 浮點運算互動

         8VL-1                       128               0  bit index
        +----          ////            -----------------+
     Z0 |                               :       V0      |
      :                                          :
     Z7 |                               :       V7      |
     Z8 |                               :     * V8      |
      :                                       :  :
    Z15 |                               :     *V15      |
    Z16 |                               :      V16      |
      :                                          :
    Z31 |                               :      V31      |
        +----          ////            -----------------+
                                                 31    0
         VL-1                  0                +-------+
        +----       ////      --+          FPSR |       |
     P0 |                       |               +-------+
      : |                       |         *FPCR |       |
    P15 |                       |               +-------+
        +----       ////      --+
    FFR |                       |               +-----+
        +----       ////      --+            VL |     |
                                                +-----+
    
(*)被呼叫者儲存

這僅適用於 Z-/V 暫存器的位 [63:0]。 FPCR 包含被呼叫者儲存和呼叫者儲存位。 有關詳細資訊,請參閱 [4]。

A.2. 過程呼叫標準

ARMv8-A 基本過程呼叫標準在附加的 SVE 暫存器狀態方面進行了如下擴充套件

  • 未與 FP/SIMD 共享的所有 SVE 暫存器位都是呼叫者儲存的。

  • Z8 位 [63:0] .. Z15 位 [63:0] 是被呼叫者儲存的。

    這是因為這些位以這種方式對映到 V8..V15,V8..V15 在基本過程呼叫標準中是呼叫者儲存的。

附錄 B. ARMv8-A FP/SIMD 程式設計師模型

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

有關更多資訊,請參閱 [4]。

ARMv8-A 定義了以下浮點/ SIMD 暫存器狀態

  • 32 個 128 位向量暫存器 V0..V31

  • 2 個 32 位狀態/控制暫存器 FPSR、FPCR

      127           0  bit index
     +---------------+
  V0 |               |
   : :               :
  V7 |               |
* V8 |               |
:  : :               :
*V15 |               |
 V16 |               |
   : :               :
 V31 |               |
     +---------------+

              31    0
             +-------+
        FPSR |       |
             +-------+
       *FPCR |       |
             +-------+
(*)被呼叫者儲存

這僅適用於 V 暫存器的 [63:0] 位。FPCR 包含被呼叫者儲存位和呼叫者儲存位的混合。

參考

[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 功能暫存器

[4] ARM IHI0055C

http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055c/IHI0055C_beta_aapcs64.pdf http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.html 用於 ARM 64 位架構(AArch64)的過程呼叫標準

[5] https://github.com/ARM-software/abi-aa/blob/main/aadwarf64/aadwarf64.rst