【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除
背景
上篇 blog
【OS】【Nuttx】【栈溢出】中断栈行为(Privileged Mode)
分析了 Cortex-M 中的 Privileged Level,并详细分析了 Privileged 和 Unprivileged 两种模式下的特征,下面继续
中断栈行为
OK,之前的 blog 介绍了 Processor Mode 和 Privilege Level,下面结合两个维度,看看它们对栈指针的综合影响,下面来模拟下模式的切换流程
- 芯片复位 :进入 Thread Mode ,CONTROL = 0b00,决定栈指针使用 MSP,并且为 Privileged 模式 ,而 MSP 将在启动文件中,由向量表进行初始化


- RTOS 启动任务:分配任务栈,比如执行
c
__set_PSP(0x20001000); // 设置 PSP
__set_CONTROL(0x3); // CONTROL[1]=1 (use PSP), CONTROL[0]=1 (unprivileged)
此时 PSP 被初始化为 0x20001000,并且栈指针被 RTOS 设置为指向 PSP(CONTROL[1]=1),Privilege Level 被设置成 unprivileged(CONTROL[0]=1),并将 CPU 的使用权交给任务(Thread Mode + PSP + unprivileged)
- 中断发生 :Processor Mode 自动切换到 Handler Mode,此时栈指针 SP 也自动切换为 MSP ,如果出现压栈动作的话,会压到主栈 MSP(独立中断栈),在中断服务程序 ISR 中软件执行都是特权级 Privileged


- 中断返回:MSP 自动弹栈,然后 Processor Mode 自动切回 Thread Mode,栈指针 SP 自动切回 PSP,任务继续运行
最后再总结一下
| 概念 | 说明 |
|---|---|
| 两种模式 | Thread(应用),Handler(异常) |
| 特权控制 | Handler 永远特权,Thread 可配置 |
| 双栈机制 | MSP(主栈),PSP(进程栈) |
| 栈选择 | Thread Mode 看 CONTROL[1],Handler Mode 强制使用 MSP |
| 栈隔离 | RTOS 利用 PSP/MSP 实现任务栈与中断栈分离 |
| 安全设计 | Unprivileged 模式下任务无法破坏系统寄存器 |
OK,再回到 Nuttx 这里的描述

可以看到,这里 rBS 不会在 ISR 中更新(原因之前 blog 提到过,会给性能带来极大影响),并且由于 RTOS (Nuttx)一般都会使用双栈模型(MSP/PSP),所以进入 ISR 之后,不可能使用 MSP 的栈底(SP 自动切换)来对比 PSP 的 rBS 栈底,也就不存在对中断栈溢出进行实时判断了,但可以用 Stack Monitor 结合染色模型去对中断栈做静态检查
不过,这里就引出了另一个点:当任务运行时,发生中断,CPU 自动切换到 Handler 模式,栈指针 SP 从 PSP 切换成 MSP,然后自动使用 ISR 独立的中断栈(MSP),此时 ISR 就不可能共享使用被中断任务的栈空间机会,这种推理大多数现代 RTOS 场景下是完全正确的,其关键在于,独立中断栈是否独立,取决于系统如何配置 CONTROL 寄存器和栈指针
Cortex-M 架构支持两种模式(双栈模型和单栈模型),而中断是否共享使用被中断任务的栈空间,是由软件决定的,在典型 RTOS 场景下使用双栈模型,任务用 PSP,到 ISR 时自动切换成 MSP,此时中断栈就是独立的,无法共享任务栈空间,这也是推荐,安全,主流的做法,是 RTOS 文档/代码中通常假设的情况
OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
【OS】【Nuttx】【栈溢出】中断栈行为(单栈模型)