|
|
@ -1,10 +1,6 @@ |
|
|
|
; 文件名: context_switch.s |
|
|
|
; 目标平台: ARM Cortex-M3/M4 (STM32) |
|
|
|
; 工具链: ARM Compiler 6 (Keil MDK/ARMCLANG) |
|
|
|
; 描述: 通过 PendSV 异常实现 RTOS 上下文切换 |
|
|
|
|
|
|
|
PRESERVE8 ; 强制栈按 8 字节对齐 (Cortex-M 硬件要求) |
|
|
|
THUMB ; 使用 Thumb-2 指令集 |
|
|
|
PRESERVE8 ; 8 字节对齐 |
|
|
|
THUMB ; 使用 Thumb 指令集 |
|
|
|
|
|
|
|
AREA |.text|, CODE, READONLY ; 定义代码段 |
|
|
|
EXPORT PendSV_Handler ; 导出 PendSV_Handler 符号 |
|
|
@ -12,8 +8,9 @@ |
|
|
|
IMPORT next_task ; 从 C 代码导入 next_task 指针 |
|
|
|
IMPORT switch_to_next_task ; 从 C 代码导入 switch_to_next_task 函数 |
|
|
|
PendSV_Handler PROC |
|
|
|
|
|
|
|
;-------------------------------------------------- |
|
|
|
; 1. 关闭中断(确保上下文切换原子性) |
|
|
|
; 1. 关闭中断(确保不会被更高优先级任务打断) |
|
|
|
;-------------------------------------------------- |
|
|
|
CPSID I ; 禁用中断 (PRIMASK=1) |
|
|
|
CPSID F ; 禁用快速中断 (FAULTMASK=1) |
|
|
@ -23,19 +20,21 @@ PendSV_Handler PROC |
|
|
|
;-------------------------------------------------- |
|
|
|
LDR R1, = current_task ; 加载 current_task 的地址到 R1 |
|
|
|
LDR R1, [R1] ; 获取 current_task 指针的值(TCB地址) |
|
|
|
CBZ R1, switch_nosave ; 如果是系统的第一个运行任务,不需要保存 |
|
|
|
CBZ R1, switch_nosave ; 如果获取到底SP为空就不需要保存,并且跳转到switch_nosave函数 |
|
|
|
|
|
|
|
;-------------------------------------------------- |
|
|
|
; 3. 保存当前任务上下文(R4-R11 手动保存) |
|
|
|
; 硬件自动保存: R0-R3, R12, LR, PC, PSR (通过 PSP) |
|
|
|
;-------------------------------------------------- |
|
|
|
MRS R0, PSP ; 获取当前任务的栈指针 PSP |
|
|
|
MRS R0, PSP ; 获取当前任务的栈指针 PSP |
|
|
|
STMFD R0!, {R4-R11} ; 将 R4-R11 压入任务栈(地址递增) |
|
|
|
STR R0, [R1] |
|
|
|
STR R0, [R1] ; 将PSP保存进TCB的SP |
|
|
|
|
|
|
|
switch_nosave |
|
|
|
;-------------------------------------------------- |
|
|
|
; 4. 切换当前任务和下一个任务(调用 C 函数) |
|
|
|
;-------------------------------------------------- |
|
|
|
BL switch_to_next_task ; 调用 C 函数切换 current_task 和 next_task |
|
|
|
BL switch_to_next_task ; 调用 C 函数witch_to_next_task 获取下一个TCB |
|
|
|
|
|
|
|
;-------------------------------------------------- |
|
|
|
; 5. 加载下一个任务的上下文 |
|
|
|