ARM64 CPU 特性暫存器

作者: Suzuki K Poulose <suzuki.poulose@arm.com>

此檔案描述了將 AArch64 CPU ID/特性暫存器匯出到使用者空間的 ABI。 此 ABI 的可用性透過 HWCAP 中的 HWCAP_CPUID 公佈。

1. 動機

ARM 架構定義了一組特性暫存器,用於描述 CPU/系統的能力。 訪問這些系統暫存器受到 EL0 的限制,並且應用程式沒有可靠的方法來提取此資訊以便在執行時做出更好的決策。 透過 HWCAP 嚮應用程式提供的可用資訊有限,但是它們的使用存在一些問題。

  1. 對 HWCAP 的任何更改都需要更新使用者空間(例如 libc)以檢測新的更改,這可能需要很長時間才能在發行版中出現。 公開暫存器允許應用程式獲取資訊,而無需更新工具鏈。

  2. 對 HWCAP 的訪問有時受到限制(例如,在 libc 之前,或在啟動時初始化 ld 時)。

  3. HWCAP 無法有效地表示非布林資訊。 該架構定義了一種規範格式,用於在 ID 暫存器中表示特性; 這是明確定義的,並且能夠表示所有有效的架構變體。

2. 要求

  1. 安全

    應用程式應該能夠使用基礎設施提供的資訊在系統上安全地執行。 這對具有異構 CPU 的系統具有更大的意義。 該基礎設施匯出一個值,該值在系統上所有可用的 CPU 上都是安全的。

    例如,如果至少一個 CPU 沒有實現 CRC32 指令,而其他 CPU 實現了,我們應該報告 CRC32 未實現。 否則,當應用程式排程到不支援 CRC32 的 CPU 上時可能會崩潰。

  2. 安全

    應用程式應該只能接收與使用者空間中的正常操作相關的資訊。 因此,一些欄位被遮蔽(即,變得不可見),並且它們的值設定為指示該特性“不受支援”。 有關可見特性的列表,請參見第 4 節。 此外,核心可能會根據它支援的內容來操作這些欄位。 例如,如果核心不支援 FP,則這些值可能表明 FP 不可用(即使 CPU 提供它)。

  3. 實現定義的特性

    根據 ARMv8-A 架構,該基礎設施不會公開任何“實現定義”的暫存器。

  4. CPU 識別

    MIDR_EL1 用於幫助識別處理器。 在異構系統上,這可能存在競爭(就像 getcpu() 一樣)。 在使用暫存器值時,該程序可能會遷移到另一個 CPU,除非設定了 CPU 親和性。 因此,無法保證該值反映了它當前正在執行的處理器。 REVIDR 和 AIDR 不會被公開,因為這些暫存器只有與 MIDR 結合使用才有意義。 或者,MIDR_EL1、REVIDR_EL1 和 AIDR_EL1 透過 sysfs 在

    /sys/devices/system/cpu/cpu$ID/regs/identification/
                                                  \- midr_el1
                                                  \- revidr_el1
                                                  \- aidr_el1
    

3. 實現

該基礎設施建立在“MRS”指令的模擬之上。 從應用程式訪問受限的系統暫存器會生成異常,並最終將 SIGILL 傳遞給該程序。 如果源屬於受支援的系統暫存器空間,則該基礎設施會掛鉤到異常處理程式並模擬該操作。

該基礎設施僅模擬以下系統暫存器空間

Op0=3, Op1=0, CRn=0, CRm=0,2,3,4,5,6,7

(有關暫存器列表,請參見 ARMv8 ARM DDI 0487A.h 中的表 C5-6 “非除錯系統暫存器訪問的系統指令編碼”)。

以下規則適用於基礎設施返回的值

  1. “實現定義”欄位的值設定為 0。

  2. 保留欄位的值將填充架構定義的保留值。

  3. “可見”欄位的值儲存特定特性的系統範圍安全值(MIDR_EL1 除外,請參見第 4 節)。

  4. 所有其他欄位(即,不可見欄位)設定為指示該特性缺失(由架構定義)。

4. 具有可見特性的暫存器列表

  1. ID_AA64ISAR0_EL1 - 指令集屬性暫存器 0

    名稱

    可見

    RNDR

    [63-60]

    y

    TS

    [55-52]

    y

    FHM

    [51-48]

    y

    DP

    [47-44]

    y

    SM4

    [43-40]

    y

    SM3

    [39-36]

    y

    SHA3

    [35-32]

    y

    RDM

    [31-28]

    y

    ATOMICS

    [23-20]

    y

    CRC32

    [19-16]

    y

    SHA2

    [15-12]

    y

    SHA1

    [11-8]

    y

    AES

    [7-4]

    y

  2. ID_AA64PFR0_EL1 - 處理器特性暫存器 0

    名稱

    可見

    DIT

    [51-48]

    y

    MPAM

    [43-40]

    n

    SVE

    [35-32]

    y

    GIC

    [27-24]

    n

    AdvSIMD

    [23-20]

    y

    FP

    [19-16]

    y

    EL3

    [15-12]

    n

    EL2

    [11-8]

    n

    EL1

    [7-4]

    n

    EL0

    [3-0]

    n

  3. ID_AA64PFR1_EL1 - 處理器特性暫存器 1

    名稱

    可見

    SME

    [27-24]

    y

    MTE

    [11-8]

    y

    SSBS

    [7-4]

    y

    BT

    [3-0]

    y

  4. MIDR_EL1 - 主 ID 暫存器

    名稱

    可見

    實現者

    [31-24]

    y

    變體

    [23-20]

    y

    架構

    [19-16]

    y

    部件號

    [15-4]

    y

    修訂版

    [3-0]

    y

注意:MIDR_EL1 的“可見”欄位將包含在獲取它的 CPU 上可用的值,而不是系統範圍的安全值。

  1. ID_AA64ISAR1_EL1 - 指令集屬性暫存器 1

    名稱

    可見

    I8MM

    [55-52]

    y

    DGH

    [51-48]

    y

    BF16

    [47-44]

    y

    SB

    [39-36]

    y

    FRINTTS

    [35-32]

    y

    GPI

    [31-28]

    y

    GPA

    [27-24]

    y

    LRCPC

    [23-20]

    y

    FCMA

    [19-16]

    y

    JSCVT

    [15-12]

    y

    API

    [11-8]

    y

    APA

    [7-4]

    y

    DPB

    [3-0]

    y

  2. ID_AA64MMFR0_EL1 - 記憶體模型特性暫存器 0

    名稱

    可見

    ECV

    [63-60]

    y

  3. ID_AA64MMFR2_EL1 - 記憶體模型特性暫存器 2

    名稱

    可見

    AT

    [35-32]

    y

  4. ID_AA64ZFR0_EL1 - SVE 特性 ID 暫存器 0

    名稱

    可見

    F64MM

    [59-56]

    y

    F32MM

    [55-52]

    y

    I8MM

    [47-44]

    y

    SM4

    [43-40]

    y

    SHA3

    [35-32]

    y

    B16B16

    [27-24]

    y

    BF16

    [23-20]

    y

    BitPerm

    [19-16]

    y

    AES

    [7-4]

    y

    SVEVer

    [3-0]

    y

  1. ID_AA64MMFR1_EL1 - 記憶體模型特性暫存器 1

    名稱

    可見

    AFP

    [47-44]

    y

  2. ID_AA64ISAR2_EL1 - 指令集屬性暫存器 2

    名稱

    可見

    CSSC

    [55-52]

    y

    RPRFM

    [51-48]

    y

    BC

    [23-20]

    y

    MOPS

    [19-16]

    y

    APA3

    [15-12]

    y

    GPA3

    [11-8]

    y

    RPRES

    [7-4]

    y

    WFXT

    [3-0]

    y

  3. MVFR0_EL1 - AArch32 媒體和 VFP 特性暫存器 0

名稱

可見

FPDP

[11-8]

y

  1. MVFR1_EL1 - AArch32 媒體和 VFP 特性暫存器 1

名稱

可見

SIMDFMAC

[31-28]

y

SIMDSP

[19-16]

y

SIMDInt

[15-12]

y

SIMDLS

[11-8]

y

  1. ID_ISAR5_EL1 - AArch32 指令集屬性暫存器 5

名稱

可見

CRC32

[19-16]

y

SHA2

[15-12]

y

SHA1

[11-8]

y

AES

[7-4]

y

附錄 I:示例

/*
 * Sample program to demonstrate the MRS emulation ABI.
 *
 * Copyright (C) 2015-2016, ARM Ltd
 *
 * Author: Suzuki K Poulose <suzuki.poulose@arm.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <asm/hwcap.h>
#include <stdio.h>
#include <sys/auxv.h>

#define get_cpu_ftr(id) ({                                    \
              unsigned long __val;                            \
              asm("mrs %0, "#id : "=r" (__val));              \
              printf("%-20s: 0x%016lx\n", #id, __val);        \
      })

int main(void)
{

      if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {
              fputs("CPUID registers unavailable\n", stderr);
              return 1;
      }

      get_cpu_ftr(ID_AA64ISAR0_EL1);
      get_cpu_ftr(ID_AA64ISAR1_EL1);
      get_cpu_ftr(ID_AA64MMFR0_EL1);
      get_cpu_ftr(ID_AA64MMFR1_EL1);
      get_cpu_ftr(ID_AA64PFR0_EL1);
      get_cpu_ftr(ID_AA64PFR1_EL1);
      get_cpu_ftr(ID_AA64DFR0_EL1);
      get_cpu_ftr(ID_AA64DFR1_EL1);

      get_cpu_ftr(MIDR_EL1);
      get_cpu_ftr(MPIDR_EL1);
      get_cpu_ftr(REVIDR_EL1);

#if 0
      /* Unexposed register access causes SIGILL */
      get_cpu_ftr(ID_MMFR0_EL1);
#endif

      return 0;
}