一、ARM64体系结构概览:AArch64执行状态、寄存器组与异常等级

各位同学,咱们今天正式进入ARM64的世界。说实话,我第一次接触ARM64的时候,脑子里全是x86的那套东西,结果踩了不少坑。后来才明白,ARM64的设计哲学跟x86完全不一样——它更简洁、更规整,但也更讲究规矩。

这一章,咱们把地基打牢。我会从三个核心维度带你过一遍:AArch64执行状态、寄存器组、以及异常等级与安全模型。这些东西你搞懂了,后面写汇编、调性能、做系统移植,心里才有底。

1.1 AArch64执行状态:64位的真正起点

ARMv8-A架构引入了两种执行状态:AArch64和AArch32。咱们这门课只关注AArch64,也就是纯64位模式。

为什么叫“纯64位”?因为AArch64不是AArch32的简单扩展,而是重新设计的指令集。它使用64位虚拟地址、31个64位通用寄存器,并且抛弃了ARMv7时代那些历史包袱——比如PC可以直接读写、CPSR那种复杂的状态寄存器。

核心特征:

  • 地址宽度:64位虚拟地址,但当前实现通常只用48位或52位
  • 指令长度:固定32位,不再有Thumb/Thumb-2混合指令
  • 寄存器:31个通用寄存器(X0-X30),每个64位宽
  • 异常模型:4个异常等级(EL0-EL3),清晰分层

我个人习惯把AArch64比作一张白纸。ARM公司把过去20年的经验教训全倒进去,重新画了一张干净的图纸。你想想看,一个指令集能固定32位长度,这对流水线和分支预测有多友好?我在做性能调优时,经常因为指令对齐问题在x86上折腾半天,但在ARM64上几乎不用操心。

1.2 寄存器组:你的31个“工作台”

寄存器是CPU最宝贵的资源。AArch64提供了三类寄存器:通用寄存器、SIMD&FP寄存器、以及特殊寄存器。咱们一个一个说。

1.2.1 通用寄存器(X0-X30)

一共31个64位通用寄存器,编号X0到X30。每个寄存器都可以当作64位(X形式)或32位(W形式)使用。比如X0是64位,W0就是它的低32位。

寄存器 别名/用途 调用约定
X0-X7 参数寄存器 传递参数,X0也用于返回值
X8 间接结果寄存器 返回大结构体时使用
X9-X15 临时寄存器 调用者保存(caller-saved)
X16-X17 IP0/IP1 过程内调用临时寄存器
X18 平台寄存器 平台保留,通常不用
X19-X28 被调用者保存 callee-saved,函数内必须恢复
X29 帧指针(FP) 指向当前栈帧基址
X30 链接寄存器(LR) 保存函数返回地址

这里有个坑,我当年就栽过。X18在Windows和Linux上的用法不一样——Windows把它当作TEB(线程环境块)指针,Linux则保留给平台使用。如果你写跨平台代码,千万别碰X18。

避坑指南:我曾经在移植一个RTOS时,顺手把X18当通用寄存器用了,结果在某个硬件平台上直接崩溃。查了两天才发现,那个平台的固件把X18映射到了特殊功能寄存器。所以,除非你100%确定,否则别碰X18。

1.2.2 SIMD&FP寄存器(V0-V31)

ARM64的SIMD(单指令多数据)和浮点运算共用一组寄存器:V0到V31,每个128位宽。它们可以当作多种视图使用:

  • B/H/S/D/Q:8位/16位/32位/64位/128位标量
  • V.8B/V.16B:8个或16个字节
  • V.4H/V.8H:4个或8个半字
  • V.2S/V.4S:2个或4个单精度浮点
  • V.2D:2个双精度浮点

说白了,这32个寄存器就是你的“向量工作台”。做图像处理、音频编解码、或者矩阵运算时,它们能同时处理多个数据,效率极高。我记得有一次优化一个视频解码器,把关键循环改成NEON指令后,性能直接翻了3倍。

1.2.3 特殊寄存器

特殊寄存器不直接参与数据运算,但控制着CPU的行为。常用的有:

  • SP(栈指针):每个异常等级有自己的SP,EL0和EL1可以共享
  • PC(程序计数器):AArch64中不能直接写PC,只能通过分支指令修改
  • PSTATE:处理器状态,包含NZCV标志位、异常掩码等
  • TPIDR_EL0/TPIDR_EL1:线程/进程ID寄存器,常用于存储线程局部存储指针

嗯,这里要注意:PSTATE不是寄存器,而是一组状态位的抽象。你没法直接读写它,只能通过MSR/MRS指令操作它的别名寄存器,比如NZCV、DAIF等。

1.3 异常等级(EL0-EL3)与安全模型

ARM64的异常模型是它最优雅的设计之一。4个异常等级,从低到高:

  • EL0:用户态,运行应用程序
  • EL1:操作系统内核
  • EL2:虚拟机监视器(Hypervisor)
  • EL3:安全监视器(Secure Monitor)

每个等级都有独立的虚拟内存配置、异常向量表、以及系统寄存器。等级越高,权限越大。EL3可以访问所有资源,EL0只能碰自己的用户空间。

重要:异常等级不是简单的“优先级”,而是隔离域。EL0的崩溃不会影响EL1,EL1的崩溃不会影响EL2。这种分层设计让系统更健壮,也更容易做虚拟化和安全隔离。

1.3.1 安全模型:TrustZone

ARM64还有一个“安全世界”和“非安全世界”的概念,这就是TrustZone。它把物理硬件分成两个隔离的环境:

  • 非安全世界(Normal World):运行普通操作系统和应用程序
  • 安全世界(Secure World):运行安全操作系统,处理密钥、指纹、支付等敏感操作

切换两个世界需要通过EL3的安全监视器调用(SMC)。我在做手机安全方案时,经常需要写SMC处理程序——那玩意儿调试起来特别痛苦,因为安全世界里的断点会触发安全异常,普通调试器根本抓不到。

1.4 知识体系总览

下面这张图,把咱们这一章的核心内容串起来了。你可以把它当作ARM64体系结构的“地图”。

ARM64体系结构概览 ARM64体系结构核心要素 AArch64执行状态 寄存器组 异常等级与安全 64位虚拟地址 固定32位指令 31个通用寄存器 通用寄存器 X0-X30 SIMD&FP V0-V31 特殊寄存器 SP/PC/PSTATE EL0 用户态 EL1 内核态 EL2 Hypervisor EL3 Secure Monitor 关键设计理念 • 异常等级越高,权限越大,隔离性越强 • 寄存器命名规整:X/W/V/B/H/S/D/Q 视图清晰 • TrustZone 在 EL3 之上增加安全/非安全世界隔离

1.5 小结

这一章咱们把ARM64的骨架搭起来了。你记住三件事:

  1. AArch64是纯64位世界,跟32位模式完全割裂,别混着用
  2. 寄存器是性能的命根子,31个通用寄存器+32个SIMD寄存器,怎么分配、怎么保存,直接影响函数调用开销
  3. 异常等级是安全的基础,EL0到EL3层层隔离,写驱动、做虚拟化、搞安全方案,都得跟它们打交道