ARMv8体系结构

基础知识

ARMv8新特性

① 4GB超大物理内存

② 64位虚拟地址空间

③ **31个64位宽的通用寄存器,**可以减少对栈的访问,从而提高了性能

④ 提供16KB和64KB的页面,有助于降低TLB的未命中率

⑤ 具有全新的异常处理模型,有助于降低操作系统和虚拟化的实现复杂度

⑥ 具有全新的加载-获取指令、存储-释放指令,专门为C++11、C11以及Java内存模型设计

专业术语

① 处理机(PE,Processing Element):把处理器处理事务的过程抽象为处理机,是 ARM 体系结构中对处理器核心的抽象描述。

② 执行状态(Execution State):处理器运行时的环境,包括寄存器的位宽、支持的指令集、异常模型、内存管理以及编程模型。ARMv8 有两个执行状态:

  • AArch64:64位的执行状态
    • 31个64位通用寄存器
    • 64位PC、SP以及异常链接寄存器ELR
    • 提供A64指令集
    • 定义ARMv8异常模型,支持4个异常等级,即EL0~EL3
    • 提供64位的内存模型
    • 定义一组处理器状态PSTATE用来保存PE状态
  • AArch32:32位的执行状态
    • 提供13个32位通用寄存器、PC、SP、LR
    • 支持A32和T32两套指令集
    • 支持ARMv7-A异常模型,基于PE模型并映射到ARMv8的异常模型中
    • 提供32位的虚拟内存访问机制
    • 定义一组PSTATE来保存PE状态

③ ARMv8指令集:ARMv8体系结构根据不同的执行状态提供不同指令集的支持。

  • A64指令集:AArch64下运行的64位指令集(指令还是32位,知识可以操作64位的寄存器)
  • A32指令集:AArch32下运行的32位指令集
  • T32指令集:AArch32下运行的16/32位指令集

④ 系统寄存器命名:在AArch64状态下,很多系统寄存器会根据不同的异常等级提供不同的变种寄存器,命名格式为<reg_name>_ELx,比如SP_EL0。

处理器执行状态

① ARM支持两种执行状态------AArch64和AArch32,分别对应64位执行状态和32位执行状态。处理器在复位后默认进入AArch64状态,并可通过异常返回(ERET)或异常陷入(Exception Entry)在不同执行状态之间切换。

② AArch64状态的异常等级确定了处理器当前运行的特权等级:

  • EL0:用户特权,普通用户程序运行
  • EL1:系统特权,用于操作系统内核,如果扩展了虚拟化扩展,运行虚拟机操作系统内核
  • EL2:运行虚拟化扩展的虚拟机监控器
  • EL3:运行安全世界中的安全监控器

③ 异常等级与安全状态的关系:ARMv8-A 将运行环境划分为安全世界(Secure World)和非安全世界(Non-secure World)。EL3 始终运行在安全世界,负责安全世界与非安全世界之间的切换;EL2 和 EL1 可分别运行在安全或非安全世界,而 EL0 的特权等级由所处的异常等级决定。

④ ARMv8-A 架构中,处理器通过异常级别和指令集状态实现了灵活的兼容性。在 AArch64 状态下,每个异常等级(如 EL1、EL0)可独立配置为运行 AArch64 或 AArch32 指令集。这种设计允许 64 位操作系统内核同时兼容 32 位和 64 位应用程序。

  • 当 64 位操作系统(运行于 EL1)调度一个 AArch32 应用程序时,操作系统在任务切换过程中通过 SVC 异常陷入 EL1,保存当前 AArch64 上下文后将 EL0 切换为 AArch32 状态,并通过 ERET 返回到 AArch32 的 EL0 执行该应用。
  • 相反,由于 32 位操作系统运行于 AArch32 的 EL1,无法提供 64 位寄存器环境,因此不能直接运行 AArch64 应用。
  • 执行状态切换的代价:AArch64 与 AArch32 之间的切换需要保存和恢复完整的寄存器上下文,并涉及 PSTATE 的更新,因此频繁切换会带来一定的性能开销。操作系统通常只在任务调度或异常处理时进行状态切换,以降低开销。

ARMv8支持的数据宽度

ARMv8 架构支持多种数据宽度,从最小的字节到最大的四字,每种数据宽度都有明确的位宽定义,适用于不同的应用场景:

  • 字节(Byte):8位,是 ARM 体系结构中最小的数据单位,常用于字符存储和位操作。
  • 半字(Half-word):16位,常用于存储 16 位整数或 Unicode 字符。
  • 字(Word):32位,是 AArch32 状态下的标准寄存器宽度,也是大多数指令操作的基本数据单位。
  • 双字(Double-word):64位,是 AArch64 状态下通用寄存器的标准宽度,支持 64 位整数运算和 64 位地址寻址。
  • 四字(Quad-word):128位,通常由两个 64 位寄存器组合使用,用于 SIMD 向量运算或 128 位数据操作。

ARMv8寄存器

通用寄存器

① 64位执行状态支持31个通用寄存器,分别是X0~X30寄存器,而32位支持16个32位通用寄存器。AArch64 执行状态下,通用寄存器(X0~X30)均为 64 位宽,同时支持通过 W0~W30 访问其低 32 位,从而实现 32 位与 64 位数据操作的灵活切换。除了数据运算和存储之外,通用寄存器还可以在函数调用中起到特殊作用,ARM64体系结构的函数调用标准和规范对此有所约定。下表按照寄存器在函数调用中的不同用途,对31个通用寄存器进行分类说明:

REG 低32位 用途分类 说明
X0 W0 传递参数和结果 用于传递函数第1个参数,同时用于返回函数结果。
X1 W1 传递参数和结果 用于传递函数第2个参数,同时用于返回函数结果。
X2 W2 传递参数和结果 用于传递函数第3个参数。
X3 W3 传递参数和结果 用于传递函数第4个参数。
X4 W4 传递参数和结果 用于传递函数第5个参数。
X5 W5 传递参数和结果 用于传递函数第6个参数。
X6 W6 传递参数和结果 用于传递函数第7个参数。
X7 W7 传递参数和结果 用于传递函数第8个参数,也可用于返回间接结果。
X8 W8 间接结果寄存器 用于传递函数返回的间接结果地址,返回结构体或较大数据时使用
X9 W9 调用函数需要保存 调用者保存寄存器,由调用方负责保存,可自由使用。
X10 W10 调用函数需要保存 调用者保存寄存器,可自由使用。
X11 W11 调用函数需要保存 调用者保存寄存器,可自由使用。
X12 W12 调用函数需要保存 调用者保存寄存器,可自由使用。
X13 W13 调用函数需要保存 调用者保存寄存器,可自由使用。
X14 W14 调用函数需要保存 调用者保存寄存器,可自由使用。
X15 W15 调用函数需要保存 调用者保存寄存器,可自由使用。
X16 W16 平台寄存器 IP0,过程内调用临时寄存器,用于PLT跳转等场景。
X17 W17 平台寄存器 IP1,过程内调用临时寄存器,用于PLT跳转等场景。
X18 W18 平台寄存器 平台寄存器,保留给平台ABI使用,应用层代码一般不使用。
X19 W19 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X20 W20 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X21 W21 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X22 W22 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X23 W23 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X24 W24 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X25 W25 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X26 W26 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X27 W27 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X28 W28 被调用函数需要保存 被调用者保存寄存器,由被调用函数负责保存和恢复。
X29 W29 栈帧寄存器 帧指针(FP),用于指向当前函数的栈帧基址,维护栈回溯链。
X30 W30 链接寄存器 链接寄存器(LR),保存函数调用返回地址,BL指令执行时自动写入。

② 在上述31个通用寄存器中,X0~X7 用于传递函数参数和返回结果,X8 用于返回间接结果,X9~X15 为调用者保存寄存器,X16~X18 为平台相关寄存器,X19~X28 为被调用者保存寄存器,X29 作为栈帧指针,X30 作为链接寄存器。这种分工既保证了函数调用的高效性,也明确了各寄存器的保存责任,是 ARM64 函数调用规范(AAPCS64)的核心约定。

处理器状态

PSTATE(Processor State)是 ARMv8 架构中用于保存处理器当前状态的一组标志位,它反映了处理器的运行状态和控制信息。PSTATE 中的标志位主要分为四类:条件标志符号、执行状态控制、异常掩码标志位和访问权限,下面分别进行说明。

① 条件标志符号(Condition Flags)

  • N(Negative):负数标志位,当最近一次运算结果为负数时置 1,否则清 0。
  • Z(Zero):零标志位,当最近一次运算结果为零时置 1,否则清 0。
  • C(Carry):进位标志位,当运算产生进位(无符号溢出)时置 1,否则清 0。
  • V(Overflow):溢出标志位,当有符号运算发生溢出时置 1,否则清 0。

这四个条件标志位共同决定了条件分支指令(如 B.EQ、B.NE、B.GT 等)的执行结果,是程序流程控制的重要依据。

② 执行状态控制(Execution State Control)

  • EL(Exception Level):当前异常等级,表示处理器运行在 EL0~EL3 中的哪一个特权等级。
  • SP(Stack Pointer Select):栈指针选择位,用于选择当前使用的是 SP_EL0 还是当前异常等级对应的栈指针。
  • SS(Software Step):软件单步执行标志位,用于调试场景下的单步执行控制。
  • IL(Instruction Length):指令长度标志位,指示当前执行的指令是 A64(32 位)还是 T32(16 位)指令。

这些控制位决定了处理器当前的执行环境和指令集状态,是处理器状态切换的核心控制信息。

③ 异常掩码标志位(Exception Mask Bits)

  • D(Debug Mask):调试异常掩码位,置 1 时屏蔽调试异常。
  • A(SError Mask):异步异常掩码位,置 1 时屏蔽 SError 异步异常。
  • I(IRQ Mask):IRQ 中断掩码位,置 1 时屏蔽 IRQ 中断请求。
  • F(FIQ Mask):FIQ 中断掩码位,置 1 时屏蔽 FIQ 快速中断请求。

这四个掩码位分别控制不同类型异常的使能状态,操作系统在进入临界区或关键代码段时,通常会设置相应的掩码位来屏蔽中断,以保证操作的原子性。

④ 访问权限(Access Permissions)

  • PAN(Privileged Access Never):特权访问禁止位,置 1 时禁止特权模式访问用户空间内存,用于增强系统安全性。
  • UAO(User Access Override):用户访问覆盖位,置 1 时允许在特权模式下使用用户空间的访问权限,常用于系统调用中的用户数据拷贝。
  • DIT(Data Independent Timing):数据无关时序位,置 1 时指示某些指令的执行时间与数据无关,用于防止时序侧信道攻击。

访问权限相关的标志位主要用于控制特权模式对内存的访问行为,是 ARMv8 安全机制的重要组成部分。

特殊寄存器

在 AArch64 执行状态下,除了通用寄存器之外,还有一组特殊寄存器用于控制处理器状态、管理异常处理和系统配置。下面介绍几个常用的特殊寄存器。

① 零寄存器(Zero Register,XZR/WZR)

零寄存器是一个只读寄存器,读取时始终返回 0,写入时数据被丢弃。在 AArch64 状态下,XZR 表示 64 位零寄存器,WZR 表示 32 位零寄存器。它常用于初始化寄存器、比较操作或作为占位操作数,例如 MOV X0, XZR 可将 X0 清零。

② 程序计数器(PC,Program Counter)

PC 寄存器保存当前正在执行指令的地址。在 AArch64 状态下,PC 为 64 位宽,且不能像通用寄存器那样直接读写,只能通过分支指令(如 B、BL、BR)或异常返回指令(ERET)间接修改。PC 是程序执行流程控制的核心。

③ 栈指针(SP,Stack Pointer)

SP 寄存器指向当前栈顶地址,用于函数调用时的压栈和出栈操作。AArch64 为每个异常等级提供了独立的栈指针:SP_EL0 用于 EL0,SP_EL1、SP_EL2、SP_EL3 分别对应各特权等级。当前使用哪个 SP 由 PSTATE 中的 SPSel 位决定,这样设计可以避免不同特权等级之间栈的相互干扰。

④ 备份程序状态寄存器(SPSR,Saved Program Status Register)

SPSR 用于在异常发生时保存被中断程序的 PSTATE 状态。当处理器进入异常处理时,当前 PSTATE 会被自动保存到对应异常等级的 SPSR_ELx 中;当异常返回(ERET)时,SPSR 中的值会被恢复回 PSTATE,从而恢复被中断程序的执行状态。每个异常等级都有独立的 SPSR_ELx。

⑤ 异常链接寄存器(ELR,Exception Link Register)

ELR 用于保存异常发生时被中断指令的返回地址。当异常陷入时,处理器将当前 PC 值保存到对应异常等级的 ELR_ELx 中;异常返回时,ERET 指令将 ELR 中的地址写回 PC,使程序从被中断的位置继续执行。ELR 与 SPSR 配合,共同完成异常的保存与恢复。

⑥ 当前异常等级寄存器(CurrentEL)

CurrentEL 寄存器用于读取当前处理器所处的异常等级(EL0~EL3)。它是一个只读寄存器,操作系统可以读取 CurrentEL 来判断当前运行的特权级别,从而执行相应的权限检查或分支逻辑。可以通过MRS指令来读取。

⑦ 中断屏蔽寄存器(DAIF)

PSTATE寄存器中的DAIF字段

⑧ 栈指针选择寄存器(SPSel)

PSTATE的SP字段

⑨ 特权访问禁止寄存器(PAN)

PSTATE的PAN字段

⑩ 用户访问覆盖寄存器(UAO)

PSTATE的UAO字段

⑪ 条件标志寄存器(NZCV)

PSTATE的NZCV字段

附带AI生成问题

基础概念

1. ARMv8 相比 ARMv7 有哪些主要新特性?

主要新特性包括:支持 4GB 超大物理内存;提供 64 位虚拟地址空间;拥有 31 个 64 位宽的通用寄存器,减少对栈的访问从而提升性能;提供 16KB 和 64KB 大页面,降低 TLB 未命中率;引入全新的异常处理模型,降低操作系统和虚拟化的实现复杂度;新增加载-获取、存储-释放指令,专门为 C++11、C11 以及 Java 内存模型设计。

2. 什么是 AArch64 和 AArch32?两者有哪些区别?

AArch64 是 64 位执行状态,提供 31 个 64 位通用寄存器、64 位 PC/SP/ELR,支持 A64 指令集,定义 ARMv8 异常模型(EL0~EL3);AArch32 是 32 位执行状态,提供 13 个 32 位通用寄存器、PC、SP、LR,支持 A32 和 T32 两套指令集,采用 ARMv7-A 异常模型并映射到 ARMv8 异常模型中。

3. A64、A32、T32 指令集分别对应什么执行状态?A64 的指令编码本身是多少位?

A64 指令集在 AArch64 下运行,A32 和 T32 指令集在 AArch32 下运行。A64 的指令编码本身仍是 32 位,只是可以操作 64 位寄存器,这是一个常见易错点。

4. 字节、半字、字、双字、四字分别是多少位?Word 在 AArch64 下是多少位?

字节为 8 位,半字为 16 位,字为 32 位,双字为 64 位,四字为 128 位。即使处于 AArch64 状态,Word 仍然是 32 位,而不是 64 位。

异常等级与执行状态

5. EL0~EL3 分别运行什么?

EL0 为用户特权,运行普通用户程序;EL1 为系统特权,运行操作系统内核,若启用虚拟化扩展则运行虚拟机操作系统内核;EL2 运行虚拟化扩展的虚拟机监控器;EL3 运行安全世界中的安全监控器。

6. EL3 的特殊性是什么?什么是安全世界和非安全世界?

EL3 始终运行在安全世界,负责安全世界与非安全世界之间的切换。安全世界用于运行可信固件和安全监控器,非安全世界运行普通操作系统和应用程序;EL2 和 EL1 可分别运行在安全或非安全世界,EL0 的特权等级由所处异常等级决定。

7. AArch64 和 AArch32 之间如何切换?什么指令/机制触发?

处理器复位后默认进入 AArch64 状态,可通过异常返回(ERET)或异常陷入(Exception Entry)在不同执行状态之间切换。例如 64 位操作系统调度 AArch32 应用时,通过 SVC 异常陷入 EL1,保存 AArch64 上下文后将 EL0 切换为 AArch32 状态,再通过 ERET 返回执行。

8. 复位后处理器默认进入什么执行状态?

复位后处理器默认进入 AArch64 执行状态。

通用寄存器与函数调用约定

9. ARM64 有多少个通用寄存器?说出 X0~X30 的用途分类。

ARM64 有 31 个通用寄存器(X0~X30)。X0~X7 用于传递函数参数和返回结果,X8 用于返回间接结果,X9~X15 为调用者保存寄存器,X16~X18 为平台相关寄存器,X19~X28 为被调用者保存寄存器,X29 作为栈帧指针,X30 作为链接寄存器。

10. X 寄存器和 W 寄存器是什么关系?W0 和 X0 是两个独立寄存器吗?

W0~W30 是 X0~X30 的低 32 位视图,W0 和 X0 不是两个独立寄存器,而是同一个寄存器的不同访问宽度。写入 W0 只会更新 X0 的低 32 位,并将高 32 位清零。

11. 哪些是调用者保存寄存器?哪些是被调用者保存寄存器?各由谁负责保存?

X9~X15 为调用者保存寄存器,由调用方负责保存;X19~X28 为被调用者保存寄存器,由被调用函数负责保存和恢复。这是 AAPCS64 函数调用规范的核心约定。

12. X29 和 X30 分别是什么?各自的作用?

X29 是帧指针(FP),用于指向当前函数的栈帧基址,维护栈回溯链;X30 是链接寄存器(LR),保存函数调用返回地址,BL 指令执行时自动写入。

13. BL 指令执行时,返回地址保存在哪里?

BL 指令执行时,返回地址自动保存到 X30(链接寄存器 LR)中。

PSTATE 与标志位

14. N、Z、C、V 标志位分别表示什么?C 和 V 的区别?

N 为负数标志位,运算结果为负时置 1;Z 为零标志位,结果为零时置 1;C 为进位标志位,无符号运算产生进位(无符号溢出)时置 1;V 为溢出标志位,有符号运算发生溢出时置 1。C 反映无符号溢出,V 反映有符号溢出,两者判断的溢出类型不同。

15. D、A、I、F 四个异常掩码位分别屏蔽什么?

D 屏蔽调试异常,A 屏蔽 SError 异步异常,I 屏蔽 IRQ 中断请求,F 屏蔽 FIQ 快速中断请求。操作系统进入临界区或关键代码段时,通常设置相应掩码位屏蔽中断以保证原子性。

特殊寄存器

16. XZR/WZR 是什么?读它和写它分别是什么效果?一般用在什么场景?

XZR/WZR 是零寄存器,读取时始终返回 0,写入时数据被丢弃。常用于初始化寄存器、比较操作或作为占位操作数,例如 MOV X0, XZR 可将 X0 清零。

17. AArch64 下 PC 能像通用寄存器那样直接读写吗?怎么修改 PC?

不能。PC 为 64 位宽,不能像通用寄存器那样直接读写,只能通过分支指令(如 B、BL、BR)或异常返回指令(ERET)间接修改。

18. SP 有几个?为什么每个异常等级要有独立的栈指针?由什么决定当前用哪个?

AArch64 为每个异常等级提供独立栈指针:SP_EL0 用于 EL0,SP_EL1、SP_EL2、SP_EL3 分别对应各特权等级。独立栈指针可避免不同特权等级之间栈的相互干扰。当前使用哪个 SP 由 PSTATE 中的 SPSel 位决定。

23. SPSR 保存什么?ELR 保存什么?两者如何配合完成异常的保存与恢复?

SPSR 保存被中断程序的 PSTATE 状态,ELR 保存被中断指令的返回地址。异常陷入时,处理器将当前 PSTATE 保存到 SPSR_ELx、将当前 PC 保存到 ELR_ELx;异常返回时,ERET 将 SPSR 恢复回 PSTATE、将 ELR 写回 PC,从而恢复被中断程序的执行。

24. ERET 指令执行时发生了什么?

ERET 执行时恢复 SPSR 到 PSTATE,并将 ELR 写回 PC,完成异常返回,使程序从被中断的位置继续执行。

25. CurrentEL 是什么?怎么读取?

CurrentEL 是当前异常等级寄存器,用于读取处理器当前所处的异常等级(EL0~EL3)。它是只读寄存器,操作系统可通过 MRS 指令读取,以判断当前特权级别并执行相应权限检查或分支逻辑。

26. 异常发生时,PSTATE 和返回地址分别被自动保存到哪里?

异常发生时,PSTATE 被自动保存到对应异常等级的 SPSR_ELx 中,返回地址(当前 PC 值)被自动保存到对应异常等级的 ELR_ELx 中。

相关推荐
一直C2 天前
嵌入式 Linux 驱动开发学习笔记(三)设备树、GPIO子系统、中断与外设驱动实战
驱动开发·单片机·嵌入式硬件·嵌入式·arm·imx6ull
zbyyd3 天前
Linux字符设备驱动:LED驱动实战开发
linux·单片机·arm·驱动
祖力554 天前
驱动工程搭建与字符设备驱动框架
linux·运维·服务器·内核·arm·imx6ull·驱动
susplus4 天前
【Linux驱动开发】字符设备介绍 | LED灯驱动基本实现(自动申请设备号+手动添加节点)
arm·led驱动·linux驱动开发
gscsded5 天前
MCUboot裸机移植实战
单片机·嵌入式硬件·arm
想喝奶茶啾啾5 天前
AMBA CHI架构以及规范中使用的术语 翻译笔记(1)
笔记·arm·chi
susplus6 天前
【IMX6ULL Linux系统移植】内核编译裁剪 + rootfs 构建 + 完整启动流程梳理
linux内核·arm·rootfs·linux启动
susplus8 天前
【IMX6ULL Linux系统移植】SD卡分区 | uboot详解
linux·arm·u-boot
剑指offer.12 天前
ARM裸机开发-SPI
arm开发·嵌入式硬件·嵌入式·arm