ARM64 CPU 特性寄存器

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

本文档描述了用于向用户空间导出 AArch64 CPU ID/特性寄存器的 ABI。该 ABI 的可用性通过 HWCAPs 中的 HWCAP_CPUID 进行通告。

1. 动机

ARM 架构定义了一组特性寄存器,用于描述 CPU/系统的功能。从 EL0 访问这些系统寄存器是受限的,且应用程序无法通过可靠的方式来提取这些信息以便在运行时做出更好的决策。通过 HWCAPs 可供应用程序获取的信息有限,然而它们的使用存在一些问题。

  1. 对 HWCAPs 的任何更改都需要更新用户空间(例如 libc)来检测新变化,这在发行版中可能需要很长时间才能实现。暴露这些寄存器允许应用程序获取信息,而无需更新工具链。

  2. 对 HWCAPs 的访问有时会受到限制(例如在 libc 之前,或者在启动时初始化 ld 时)。

  3. HWCAPs 无法有效地表示非布尔(non-boolean)信息。该架构为在 ID 寄存器中表示特性定义了一种规范格式;这经过了明确定义,并且能够表示所有有效的架构变体。

2. 要求

  1. 安全性

    应用程序应该能够使用该基础设施提供的信息在整个系统中安全地运行。这对于具有异构 CPU 的系统具有更大的影响。该基础设施导出一个在系统上所有可用 CPU 上都安全的值。

    例如,如果至少有一个 CPU 没有实现 CRC32 指令,而其他 CPU 实现了,我们应该报告未实现 CRC32。否则,当应用程序被调度到不支持 CRC32 的 CPU 上时可能会崩溃。

  2. 安全

    应用程序应该只能接收与用户空间中正常操作相关的信息。因此,某些字段被屏蔽(即变为不可见),并且它们的值被设置为指示该特性“不支持”。可见特性列表请参见第 4 节。此外,内核可能会根据其支持的功能来操作这些字段。例如,如果内核不支持 FP,这些值可能表明 FP 不可用(即使 CPU 提供了它)。

  3. 实现定义的特性

    该基础设施不会暴露根据 ARMv8-A 架构属于 IMPLEMENTATION DEFINED(实现定义)的任何寄存器。

  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 “System instruction encodings for non-Debug System register accesses”)。

以下规则适用于基础设施返回的值

  1. “IMPLEMENTATION DEFINED” 字段的值被设置为 0。

  2. 保留字段的值填充为架构定义的保留值。

  3. “可见”字段的值保存了该特定特性在整个系统范围内的安全值(MIDR_EL1 除外,见第 4 节)。

  4. 所有其他字段(即不可见字段)均被设置为指示该特性缺失(由架构定义)。

4. 具有可见特性的寄存器列表

  1. ID_AA64ISAR0_EL1 - 指令集属性寄存器 0

    名称

    bits

    visible

    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

    名称

    bits

    visible

    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

    名称

    bits

    visible

    SME

    [27-24]

    y

    MTE

    [11-8]

    y

    SSBS

    [7-4]

    y

    BT

    [3-0]

    y

  4. MIDR_EL1 - 主 ID 寄存器

    名称

    bits

    visible

    Implementer

    [31-24]

    y

    Variant

    [23-20]

    y

    架构

    [19-16]

    y

    PartNum

    [15-4]

    y

    Revision

    [3-0]

    y

注意:MIDR_EL1 的“可见”字段将包含在获取它的 CPU 上可用的值,而不是系统范围的安全值。

  1. ID_AA64ISAR1_EL1 - 指令集属性寄存器 1

    名称

    bits

    visible

    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

    名称

    bits

    visible

    ECV

    [63-60]

    y

  3. ID_AA64MMFR2_EL1 - 内存模型特性寄存器 2

    名称

    bits

    visible

    AT

    [35-32]

    y

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

    名称

    bits

    visible

    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

    名称

    bits

    visible

    AFP

    [47-44]

    y

  2. ID_AA64ISAR2_EL1 - 指令集属性寄存器 2

    名称

    bits

    visible

    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

名称

bits

visible

FPDP

[11-8]

y

  1. MVFR1_EL1 - AArch32 媒体和 VFP 特性寄存器 1

名称

bits

visible

SIMDFMAC

[31-28]

y

SIMDSP

[19-16]

y

SIMDInt

[15-12]

y

SIMDLS

[11-8]

y

  1. ID_ISAR5_EL1 - AArch32 指令集属性寄存器 5

名称

bits

visible

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