参考:
《Arm®v7-M Architecture Reference Manual》
ARMv7-M 系列其他文章:
深入理解 ARMv7-M | 异常/中断处理
1、Arm core registers
ARMv7-M 共有十三个通用的 32 位寄存器,即 R0 至 R12,此外还有三个具有特殊名称和使用模式的 32 位寄存器。
- SP:堆栈指针,用作指向当前活动堆栈的指针。复位时,此值被预设为主堆栈(Main statck)的顶部。
- LR:用于保存返回地址。当通过带链接分支指令(Branch with Link)调用子程序时,LR 中会保存返回地址,即调用点之后那条指令的地址。复位时,该寄存器的值为 0xFFFFFFFF。如果在子程序返回时直接使用这个复位值,会导致故障状态。此外,在进入异常时 LR 也会被更新,详见第 B1-531 页“异常进入行为”。LR 也可称为 R14。
- PC:程序计数器。有关 PC 的使用模型的详细说明。在复位时,PC 会被加载为复位处理程序的起始地址。PC 有时也被称为R15。
1.2 APSR
- N – 表示 ALU(算术逻辑单元)运算结果为负(Negative)。
- Z – 表示 ALU 运算结果为零(Zero)。
- C – 表示 ALU 运算产生了进位或借位(Carry out)。
- V – 表示 ALU 运算发生了溢出(oVerflow)。
- Q – 表示累积饱和标志(cumulative saturation),也被称为“粘性”标志(sticky)。
- GE[3:0] – 供部分 SIMD(单指令多数据)指令使用。
1.3 Execution state
Armv7-M 仅执行 Thumb 指令,因此始终以 Thumb 状态执行指令。
除正常程序执行外,处理器还可工作于调试(Debug)状态。关于 Debug 这一点我们以后再详解。
2、ARMv7-M 处理器模式
ARMv7-M 使用处理器模式(Processor mode)、软件执行的特权级(privilege levels)和栈指针(Stacks Pointer)描述程序运行时的基本状态。模式规定当前的执行上下文,特权级规定软件的访问权限,栈指针确定当前使用的栈。这些状态共同构成普通程序与异常处理程序之间的执行接口。
2.1 处理器模式
ARMv7-M 支持两种处理器模式:
| 模式 | 执行用途 |
|---|---|
| Thread mode(线程模式) | 执行应用程序和普通系统程序 |
| Handler mode(处理模式) | 执行异常处理程序 |
Thread mode 可以承载裸机程序的主循环,也可以承载操作系统调度的任务。架构中的 Thread mode 表示一种处理器执行模式;操作系统是否提供多线程,由软件设计决定。
复位完成后,处理器在 Thread mode 中执行。处理器响应中断、故障或监督调用等异常并进入相应处理程序时,进入 Handler mode。若一个异常处理程序被另一个异常抢占,处理器继续处于 Handler mode,执行新异常的处理程序。
异常返回必须在 Handler mode 中执行。返回目标可以是 Thread mode 中的程序,也可以是被抢占的 Handler mode 中的处理程序。模式转换由异常进入和异常返回机制管理,普通函数调用保持调用者所在的模式。
当前处理器模式可以通过中断程序状态寄存器IPSR中的异常编号判断:Thread mode 下该编号为 0;Handler mode 下记录当前正在处理的异常编号。
2.2 软件执行的特权级
ARMv7-M 支持特权执行(Privileged execution)和非特权执行(Unprivileged execution)。这种权限划分允许系统将关键控制功能交由特权软件管理,并限制应用程序对这些功能的直接访问。
特权软件可以使用架构提供的系统控制功能;非特权软件对部分指令、寄存器和存储区域的访问受到限制。代表性的权限差异包括:
| 资源或操作 | 特权执行 | 非特权执行 |
|---|---|---|
| NVIC 中断使能与优先级寄存器 | 可以按寄存器定义访问 | 不能直接访问 |
| SysTick 控制寄存器 | 可以按寄存器定义访问 | 不能直接访问 |
| 通过 MRS、MSR 访问特殊寄存器 | 按各寄存器的访问规则执行 | 部分访问受到限制 |
| 普通内存与外设访问 | 遵循适用的内存属性、MPU 和系统保护规则 | 遵循适用的内存属性、MPU 和系统保护规则,权限可以与特权访问不同 |
内存保护单元 MPU 可以为存储区域设置特权与非特权访问权限。例如,系统可以允许特权软件修改某个区域,同时仅允许非特权软件读取该区域。特权级与存储区域的保护属性共同决定一次访问是否被允许。
这类权限划分为操作系统内核、系统服务与应用程序之间的保护提供基础。具体权限限制见各指令、寄存器和内存保护机制的定义。Cortex-M7 通用用户指南 2.1.1
2.3 模式与特权级的关系
处理器模式描述程序的执行上下文,特权级描述软件的访问权限。ARMv7-M 对两者的组合规定如下:
| 处理器模式 | 特权级 | 典型用途 |
|---|---|---|
| Thread mode | 特权 | 系统初始化、裸机主程序或特权任务 |
| Thread mode | 非特权 | 受权限限制的应用程序或任务 |
| Handler mode | 特权 | 中断、故障和系统服务的异常处理程序 |
Handler mode 始终以特权执行;Thread mode 可以采用任一特权级。复位后的初始执行状态为特权Thread mode。
Thread mode 的特权级由CONTROL.nPRIV控制:
CONTROL.nPRIV | Thread mode 的特权级 |
|---|---|
| 0 | 特权 |
| 1 | 非特权 |
软件可以通过MRS指令读取CONTROL,通过MSR指令写入CONTROL。只有特权软件的写入能够改变其控制状态,非特权软件对CONTROL的写入被忽略。
特权 Thread mode 软件可以将nPRIV设置为 1,转入非特权执行。恢复特权执行需要特权软件介入。非特权应用通常通过 SVC 指令请求系统服务;处理器响应 SVCall 后,服务程序在特权 Handler mode 中执行。
Handler mode 中的特权软件可以修改CONTROL.nPRIV,确定随后返回 Thread mode 时使用的特权级。完成服务并异常返回后,线程按该位所规定的权限继续执行。
2.4 栈的选择
ARMv7-M 实现两个栈指针:
- MSP(Main Stack Pointer,主栈指针)。
- PSP(Process Stack Pointer,进程栈指针)。
寄存器 R13,也称 SP,使用当前选中的栈指针。Thread mode 的选择由CONTROL.SPSEL控制,Handler mode 始终使用 MSP。
| 处理器模式 | 选择条件 | 当前使用的栈指针 |
|---|---|---|
| Thread mode | CONTROL.SPSEL = 0 | MSP |
| Thread mode | CONTROL.SPSEL = 1 | PSP |
| Handler mode | 由架构固定 | MSP |
Handler mode 中,对CONTROL.SPSEL的显式写入被忽略,仅 Thread mode Privileged 可修改;异常返回时,硬件根据返回信息更新栈选择。
复位后,Thread mode 默认使用 MSP,其初始值由向量表的第 0 项提供。软件选择使用 PSP 前,应先为其设置有效的栈地址。操作系统通常让任务使用 PSP,让异常处理程序使用 MSP,以分别组织任务栈与异常处理程序栈。
通过MSR修改CONTROL后,软件必须执行ISB指令,确保更新在后续指令执行前生效。异常进入时的上下文保存、栈帧布局和异常返回时的栈恢复,将在 B1.5.6—B1.5.8 中介绍。