这篇复习笔记整理了我们从一段简单的 startup.s 汇编代码出发,深入探讨到 ARM Cortex-M 架构底层运行机制、双堆栈设计、特权等级划分以及安全域隔离的完整逻辑。
深度解构 ARM Cortex-M:从启动汇编到内核权力游戏
一、 启动文件的“第一桶金”:向量表与堆栈
在 startup.s 中,最核心的代码段定义了芯片上电后的初始状态。
SECTION CSTACK:DATA:NOROOT(3) ; 预留堆栈空间
SECTION .intvec:CODE:NOROOT(2) ; 定义向量表段
__vector_table
DCD sfe(CSTACK) ; Entry 0: 栈顶地址 (Initial SP)
DCD Reset_Handler ; Entry 1: 复位跳转地址- sfe(CSTACK):即 Section Far End。由于 ARM 堆栈是**满递减(Full Descending)**的,数据从高地址向低地址生长,因此初始 SP 必须指向栈区的末尾。
- 硬件逻辑:上电瞬间,CPU 硬件自动从向量表的第 0 个字读取数值加载到 SP (MSP),从第 1 个字读取地址加载到 PC。这是硬件强行规定的“契约”。
二、 双堆栈机制:MSP 与 PSP
ARM Cortex-M 设计了两个物理隔离的堆栈指针,这是实现操作系统隔离的基础。
- MSP (Main Stack Pointer):
- 角色:官家 / 管理者。
- 使用场景:芯片复位后默认使用,所有中断处理程序(ISR)强制使用。
- PSP (Process Stack Pointer):
- 角色:平民 / 用户任务。
- 使用场景:通常由 RTOS 切换给用户任务(Thread)使用。
设计意图:实现堆栈隔离。即使某个用户任务发生栈溢出,也不会破坏中断系统的运行空间(MSP),确保系统内核在紧急情况下依然稳定。
三、 权力的边界:特权级与处理器模式
CPU 通过“身份标签”来决定当前代码能否操作核心寄存器或外设。
| 维度 | 状态 A | 状态 B | 切换触发 |
|---|---|---|---|
| 处理器模式 | Thread Mode (跑普通程序) | Handler Mode (跑中断) | 异常/中断发生 |
| 特权等级 | Privileged (特权级) | Unprivileged (非特权级) | 修改 CONTROL 寄存器或 SVC 指令 |
- 硬件强制规则:只要进入 Handler Mode(中断),CPU 强制变为特权级,并强制使用 MSP。
- 软件降权:内核在跳转到用户 App 前,通过设置
CONTROL寄存器的nPRIV位,手动将权限降为非特权级。
四、 平行世界:TrustZone 安全域 (ARMv8-M)
在支持 TrustZone 的芯片上,权力又增加了一个“物理维度”:
- Secure (安全态):拥有最高权限,可访问所有资源(密钥、安全存储)。
- Non-Secure (非安全态):只能访问被标记为“非安全”的资源。
- 判定方式:CPU 内部的 SAU (安全属性单元) 像地图一样划分了地址空间。PC 指针落在哪个区域,CPU 就自动进入哪个状态。
五、 硬件如何识别“我是谁”?(核心原理)
CPU 并不是靠“思考”来区分权限,而是靠纯硬件电路逻辑:
- 寄存器位:内核中
CONTROL寄存器的nPRIV位直接连接到执行单元的门电路上。 - 物理信号线 (Sideband Signals):
- 当 CPU 访问内存或外设时,总线(AHB/AXI)上会并排跑着身份信号(如
HPROT特权信号、HNONSEC非安全信号)。 - 外设响应:如果一个标记为“安全”的外设接收到
HNONSEC=1(非安全)的信号,它的硬件逻辑会物理性地关闭数据通道,产生错误响应。
- 当 CPU 访问内存或外设时,总线(AHB/AXI)上会并排跑着身份信号(如
- 地址监控:SAU/MPU 硬件在指令周期内实时比对 PC 地址,一旦非法越界,硬件逻辑直接拉高 Fault 信号。
六、 开发者与编译器的权力边界
- 编译器 (Compiler):只负责“翻译”逻辑。它通过 CMSIS 宏(如
__set_PSP)提供工具,但不决定何时切换。 - 内核编写者 (Kernel Developer):
- 立宪:在
startup.s和初始化代码中配置 SAU 和 MPU(划定法律)。 - 放权:手动切换
CONTROL寄存器,由特权级进入非特权级。 - 仲裁:编写
SVC_Handler(处理系统调用)和各种Fault_Handler(处理违规行为)。
- 立宪:在
💡 复义总结
- 启动文件是权力的源头,在“保安(硬件检查机制)”上班前配置好一切。
- 硬件逻辑是法律的执行者,靠门电路瞬间拦截越权访问。
- 双堆栈和多等级共同构建了一个“保护圈”,让脆弱的用户应用无法动摇稳健的系统内核。