第三章 ARM 处理器模式与寄存器
ARMv7-R 架构是一种模式架构。它包含六种特权模式和一种非特权用户模式。这里的特权指的是执行某些用户模式(非特权模式)无法完成的任务的能力。在用户模式下,某些影响整个系统配置的操作是受限的。例如,只有在特权模式下才能更改操作模式。模式与异常事件相关联,这些事件将在第十一章《异常与中断》中描述。
ARMv6Z 架构中引入的 TrustZone 安全扩展创建了两种独立于特权和处理器模式的安全状态(安全和非安全)。ARMv7-A 架构的虚拟化扩展还增加了一个超管模式 (Hyp),除了现有的特权模式外。虽然 ARMv7-R 架构配置文件没有实现安全扩展或虚拟化扩展,但它们在 ARMv7 架构中的存在导致特权(非特权或特权)操作模式根据特权级别进行了重新定义。
每次内存访问都有一个访问特权,可以是非特权或特权。
ARMv7-R 架构配置文件定义了以下特权级别:
PL0:应用软件的特权级别,在用户模式下执行。因此,在用户模式下执行的软件被称为非特权软件。此类软件无法访问系统的一些功能。特别是,它无法更改许多配置设置。PL0 级别的软件仅进行非特权的内存访问。
PL1:除用户模式以外的所有模式下的软件执行都在 PL1 级别。通常,操作系统软件在 PL1 级别执行。PL1 模式指的是除用户模式外的所有模式。
因此,我们可以根据特权级别重新定义处理器模式。
当前的处理器模式和执行状态包含在当前程序状态寄存器 (CPSR) 中。处理器状态和模式的更改可以由特权软件显式触发,或作为处理异常的结果发生。
3.1 寄存器
ARMv7-R 架构提供了十六个 32 位通用寄存器(R0-R15)供软件使用。其中十五个寄存器(R0-R14)可用于通用数据存储,而 R15 是程序计数器,其值在核心执行指令时会发生变化。软件显式写入 R15 会改变程序的执行流程。软件还可以访问 CPSR(当前程序状态寄存器),在特权模式下,还可以访问先前执行模式中保存的 CPSR 副本,称为保存程序状态寄存器(SPSR)。
尽管软件可以访问寄存器,但根据软件执行的模式和访问的寄存器,某个寄存器可能对应于不同的物理存储位置。这称为寄存器分组(banking),下图中的阴影寄存器就是分组的寄存器。它们使用物理上不同的存储,并且通常仅在进程以特定模式执行时才能访问。
在所有模式下,‘低寄存器’ 和 R15 共享相同的物理存储位置。上方的图显示了某些 ‘高寄存器’ 在特定模式下是分组的。例如,R8 到 R12 在 FIQ 模式下是分组的,即对它们的访问会指向不同的物理存储位置。在除了用户模式和系统模式之外的所有模式中,R13、R14 和 SPSR 也都是分组的。
注意
堆栈指针 R13 仅在 ARM 代码中可以作为通用寄存器使用,而在 Thumb 代码中不能。
在使用分组寄存器的情况下,软件通常不需要指定分组寄存器的实例。分组寄存器的实例由访问所处的模式隐含。例如,在用户模式下执行的程序指定 R13 时,访问的是 R13_usr。在 SVC 模式下执行的程序指定 R13 时,访问的是 R13_svc。
R14(链接寄存器)保存使用带链接分支(BL)指令进入的子程序的返回地址。当不支持从子程序返回时,R14 可以用作通用寄存器。R14_svc、R14_irq、R14_fiq、R14_abt 和 R14_und 类似地用于保存中断和异常发生时的返回地址,或在中断或异常例程中执行分支和链接指令时的返回地址。
R15 是程序计数器,保存当前程序地址(实际上,在 ARM 状态下,它总是指向当前指令前 8 字节的位置,在 Thumb 状态下,它总是指向当前指令前 4 字节的位置,这是原始 ARM1 处理器的三阶段流水线的遗留)。在 ARM 状态下,R15 的位 [1:0] 总是读作零。在 Thumb 状态下,R15 的位 [0] 总是读作零。
R0-R14 的复位值是不可预测的。堆栈指针 SP 必须在每种模式下由启动代码进行初始化,然后才能使用堆栈。AAPCS 或 AEABI 规范了软件在不同工具链或编程语言之间进行互操作时应如何使用通用寄存器。
3.1.1 程序状态寄存器
在任何时刻,你都可以访问16个寄存器(R0-R15)以及当前程序状态寄存器 (CPSR)。在用户模式下,会访问 CPSR 的受限形式,称为应用程序状态寄存器 (APSR)。
当前程序状态寄存器 (CPSR) 用于存储以下内容:
APSR 标志
当前处理器模式
中断禁用标志
当前处理器状态,即 ARM、Thumb、ThumbEE 或 Jazelle
字节序
IT 块的执行状态位
程序状态寄存器 (PSR) 形成了额外的一组银行寄存器。每个异常模式都有其自己的保存程序状态寄存器 (SPSR),当发生异常时,前异常 CPSR 的副本会自动存储在其中。这些寄存器在用户模式下不可访问。
应用程序开发人员必须使用 APSR 来访问可以在非特权模式下更改的 CPSR 部分。APSR 仅用于访问 N、Z、C、V、Q 和 GE[3:0] 位。这些位通常不直接访问,而是通过设置条件代码的指令来设置,并通过有条件执行的指令进行测试。
例如,指令 CMP R0, R1
比较 R0 和 R1 的值,如果它们相等,则设置零标志 (Z)。
CPSR 包含条件代码标志、当前模式位和其他信息,如下图所示。
各个位代表以下内容:
N:来自算术逻辑单元 (ALU) 的负结果。
Z:来自 ALU 的零结果。
C:ALU 操作的进位输出。
V:ALU 操作的溢出标志。
Q:累积饱和(也称为粘性位)。
J:指示处理器是否处于 Jazelle 状态。
GE[3:0]:由 SIMD 指令使用。
IT[7:0],bits[15:10, 26:25]:If-Then 条件执行 Thumb 指令组。
E:控制加载和存储操作的字节序。
A:值为 1 时禁用异步中止。
I:值为 1 时禁用 IRQ。
F:值为 1 时禁用 FIQ。
T:指示处理器是否处于 Thumb 状态。
M[4:0]:指定处理器模式。
处理器可以通过直接写入 CPSR 模式位的指令在模式之间切换。更常见的是,处理器由于异常事件的结果而自动切换模式。在用户模式下,无法操作控制处理器模式的位 [4:0] 或控制异常启用或禁用的 A、I 和 F 位。
3.1.2 Coprocessor 15
CP15,即系统控制协处理器,是处理器的一个核心部分,尽管它的名字里有“协处理器”一词。它提供了许多特性的控制。CP15可以包含最多16个主寄存器,每个寄存器的大小为32位。然而,CP15的访问受到特权控制,并且在用户(无特权)模式下并不是所有寄存器都可以访问。
CP15寄存器访问指令指定了所需的主寄存器,其它字段用于更精确地定义访问,并增加CP15中物理32位寄存器的数量。CP15中的16个主寄存器被命名为c0到c15,但通常用一系列字母来引用。
例如,CP15系统控制寄存器被命名为CP15.SCTLR。下表总结了一些在Cortex-R系列处理器中较为相关的寄存器的功能。在我们查看缓存和MPU的操作时,将会更详细地考虑其中一些寄存器。
所有的系统架构功能都是通过从协处理器15内的一组寄存器(CRn)读取或写入通用处理器寄存器(Rt)来控制的。指令中的 Op1、Op2 和 CRm 字段也可以用来选择寄存器或操作。其格式如下示例所示。
我们不会详细介绍每一个CP15寄存器,因为这会重复《ARM架构参考手册》或产品文档中可以轻松获得的参考信息。我们将查看两个示例:只读的主ID寄存器(MIDR),其格式如下图所示,以及位于3.1.3的系统控制寄存器(SCTLR)。
3.1.3 系统控制寄存器 (SCTLR)
系统控制寄存器 (SCTLR) 可以通过CP15访问。它具有以下功能:
控制标准内存。
控制系统设施。
提供核心实现功能的状态信息。
SCTLR只能在PL1(特权模式)下访问。
各个独立位表示以下含义:
IE 指令字节序(在Cortex-R7处理器上不可用):控制发给处理器的指令的字节序:
值为0:小端字节序(Little-endian)。
值为1:大端字节序(Big-endian)。
TE Thumb异常使能:控制异常是在ARM状态还是Thumb状态下处理:
值为0:ARM状态。
值为1:Thumb状态。
NMFI 不可屏蔽快速中断(Non-maskable FIQ,NMFI)支持。
EE 异常字节序:定义进入异常时CPSR.E位的值:
值为0:小端字节序(Little-endian)。
值为1:大端字节序(Big-endian)。
U(在Cortex-R7处理器上不可用):指示使用对齐模型。
FI 快速中断配置使能:
值为0:启用所有性能特性。
值为1:启用低中断延迟,禁用某些特性。
DZ 除零错误位:
值为0:除零操作返回零,不会触发异常。
值为1:除零操作触发未定义指令异常。
BR 背景区域位:
值为0:对未映射到MPU区域的地址的任何访问都会生成背景错误内存中止。
值为1:默认内存映射用作背景区域。
RR(在Cortex-R7处理器上不可用):缓存实现策略的循环置换位:
值为0:正常替换策略,例如随机替换。
值为1:可预测的策略,例如循环置换。
V 选择异常向量表的基地址:
值为0:低异常向量,基地址为0x00000000。
值为1:高异常向量,基地址为0xFFFF0000。
I 指令缓存使能位:
值为0:禁用指令缓存。
值为1:启用指令缓存。
Z 分支预测使能位:
值为0:禁用分支预测。
值为1:启用分支预测。
SW SWP/SWPB使能位:
值为0:禁用分支预测。
值为1:启用分支预测。
ARM建议ARMv7-R实现不支持这些指令。当支持使用此位时,复位时此位禁用SWP和SWPB。这意味着操作系统必须选择是否使用SWP和SWPB。
C 缓存使能位:
值为0:禁用数据和统一缓存。
值为1:启用数据和统一缓存。
A 对齐检查使能位:
值为0:禁用对齐故障检查。
值为1:启用对齐故障检查。
M 使能MPU:
值为0:禁用MPU。
值为1:启用MPU。
引导代码序列的一部分通常会设置CP15:SCTLR(系统控制寄存器)中的Z位,以启用分支预测。以下示例中展示了一个实现此操作的代码序列。
类似形式的代码可以在第15章的示例中找到。
数据的字节序由 CPSR.E 和 SCTLR.EE 位控制。CPSR.E 位可以通过 SETEND 指令进行更改。它还提供了用于转换寄存器中数据格式的指令,包括 REV 和 REV16 指令。