伪造好的任务现场
2025/8/22大约 2 分钟
伪造好的任务现场
就是:
RTOS 在创建任务时,提前在任务栈里“假装”压入了一次中断现场,让 CPU 以后能像“从中断返回一样”直接开始执行这个任务,这样开始就不必要再多设置一次专门的任务转换了
===================== FreeRTOS 启动全过程 =====================
(1) 还在裸机环境(main函数内)
--------------------------------------------------------------
main()
│
├─ xTaskCreate() → 创建任务结构体TCB,伪造任务栈(任务栈内假装中断现场)
│
├─ vTaskStartScheduler()
│ │
│ ├─ 创建空闲任务、定时器任务
│ └─ 调用 xPortStartScheduler()
│ │
│ └─ prvStartFirstTask() ← 汇编启动
│ │
│ ├─ 从向量表取出栈顶地址,设置 MSP
│ ├─ 开中断 (CPSIE i, f)
│ └─ 触发 SVC 软中断 (svc 0)
│
▼
--------------------------------------------------------------
(2) CPU 进入 SVC 异常
--------------------------------------------------------------
CPU 自动做的事:
- 切换到 MSP
- 把 LR、xPSR、PC、R0~R3 等压栈(保存 main() 的上下文)
- 跳转到 vPortSVCHandler()
--------------------------------------------------------------
(3) vPortSVCHandler() 执行
--------------------------------------------------------------
ldr r3, =pxCurrentTCB ; 当前任务TCB
ldr r1, [r3]
ldr r0, [r1] ; 取出任务栈顶(伪造现场)
ldmia r0!, {r4-r11} ; 恢复部分寄存器
msr psp, r0 ; 设置 PSP = 任务栈
mov r0, #0
msr basepri, r0 ; 开中断
orr r14, #0xd
bx r14 ; 异常返回,CPU自动用PSP恢复剩余寄存器
--------------------------------------------------------------
(4) CPU 从异常返回 → 切换完成
--------------------------------------------------------------
此时:
MSP → 用于中断
PSP → 指向当前任务栈顶
PC → 任务函数地址
xPSR → 设置为线程模式
CPU 正式开始执行:
Task1_Function();
--------------------------------------------------------------
(5) 后续如果发生任务切换(PendSV)
--------------------------------------------------------------
保存当前任务的寄存器 → 切换 pxCurrentTCB → 恢复新任务寄存器
整个流程跟上面 SVC 的切换类似
--------------------------------------------------------------ldmia r0!, {r4-r11} 是从 PSP 指向的任务栈中恢复寄存器!*
关键点在于:在执行这条指令之前,r0 已经被设置为指向任务栈顶,而这个栈顶值是从任务的 TCB 中获取的
总结:SVC中断实现的是操作的堆栈从MSP到PSP转化,也就是从裸机到操作系统

