You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
3.7 KiB
73 lines
3.7 KiB
; 文件名: context_switch.s
|
|
; 目标平台: ARM Cortex-M3/M4 (STM32)
|
|
; 工具链: ARM Compiler 6 (Keil MDK/ARMCLANG)
|
|
; 描述: 通过 PendSV 异常实现 RTOS 上下文切换
|
|
|
|
PRESERVE8 ; 强制栈按 8 字节对齐 (Cortex-M 硬件要求)
|
|
THUMB ; 使用 Thumb-2 指令集
|
|
|
|
AREA |.text|, CODE, READONLY ; 定义代码段
|
|
EXPORT PendSV_Handler ; 导出 PendSV_Handler 符号
|
|
IMPORT current_task ; 从 C 代码导入 current_task 指针
|
|
IMPORT next_task ; 从 C 代码导入 next_task 指针
|
|
IMPORT switch_to_next_task ; 从 C 代码导入 switch_to_next_task 函数
|
|
PendSV_Handler PROC
|
|
;--------------------------------------------------
|
|
; 1. 关闭中断(确保上下文切换原子性)
|
|
;--------------------------------------------------
|
|
CPSID I ; 禁用中断 (PRIMASK=1)
|
|
CPSID F ; 禁用快速中断 (FAULTMASK=1)
|
|
|
|
;--------------------------------------------------
|
|
; 2. 更新当前任务的栈指针到 TCB
|
|
;--------------------------------------------------
|
|
LDR R1, = current_task ; 加载 current_task 的地址到 R1
|
|
LDR R1, [R1] ; 获取 current_task 指针的值(TCB地址)
|
|
CBZ R1, switch_nosave ; 如果是系统的第一个运行任务,不需要保存
|
|
;--------------------------------------------------
|
|
; 3. 保存当前任务上下文(R4-R11 手动保存)
|
|
; 硬件自动保存: R0-R3, R12, LR, PC, PSR (通过 PSP)
|
|
;--------------------------------------------------
|
|
MRS R0, PSP ; 获取当前任务的栈指针 PSP
|
|
STMFD R0!, {R4-R11} ; 将 R4-R11 压入任务栈(地址递增)
|
|
STR R0, [R1]
|
|
switch_nosave
|
|
;--------------------------------------------------
|
|
; 4. 切换当前任务和下一个任务(调用 C 函数)
|
|
;--------------------------------------------------
|
|
BL switch_to_next_task ; 调用 C 函数切换 current_task 和 next_task
|
|
|
|
;--------------------------------------------------
|
|
; 5. 加载下一个任务的上下文
|
|
;--------------------------------------------------
|
|
LDR R1, = current_task ; 重新加载 current_task(此时已切换为新任务)
|
|
LDR R2, [R1] ; 获取新任务的 TCB 地址
|
|
LDR R0, [R2] ; 从 TCB 中获取新任务的栈指针 PSP
|
|
|
|
;--------------------------------------------------
|
|
; 6. 恢复新任务的 R4-R11 寄存器
|
|
;--------------------------------------------------
|
|
LDMFD R0!, {R4-R11} ; 从栈中弹出 R4-R11(地址递减)
|
|
|
|
;--------------------------------------------------
|
|
; 7. 更新 PSP 为新任务的栈指针
|
|
;--------------------------------------------------
|
|
MSR PSP, R0 ; 设置新任务的栈指针 PSP
|
|
|
|
;--------------------------------------------------
|
|
; 8. 恢复中断并退出异常
|
|
;--------------------------------------------------
|
|
CPSIE F ; 启用快速中断 (FAULTMASK=0)
|
|
CPSIE I ; 启用中断 (PRIMASK=0)
|
|
|
|
;--------------------------------------------------
|
|
; 9. 异常返回(硬件自动恢复 R0-R3, R12, LR, PC, PSR)
|
|
; LR 需包含 EXC_RETURN 值(例如 0xFFFFFFFD 表示使用 PSP)
|
|
;--------------------------------------------------
|
|
MOV LR, #0xFFFFFFFD ; EXC_RETURN 标志:返回线程模式并使用 PSP
|
|
BX LR ; 退出异常,开始执行新任务
|
|
|
|
ENDP
|
|
|
|
ALIGN ; 确保代码对齐
|
|
END
|