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;
}