STM32F103C8T6的Cortex-M3内核异常返回问题求助
Cortex-M3内核模式切换至用户模式(PSP)触发Usage Fault问题排查
问题场景
基于STM32开发简易RTOS,通过SVC中断实现内核到用户模式的上下文切换,中断处理函数__int_SVC汇编代码如下:
__int_SVC: @ __user_mode: @ save kernel context ldr r2, =kernel_save stmia r2!, {r4-r11} mov r1, pc str r1, [r2], 4 mov r1, lr str r1, [r2], 4 @ set up return frame for task mov r1, 8 loop1: ldr r2, [r0], 4 str r2, [sp], 4 add r1, -1 cmp r1, 0 bgt loop1 add sp, -4 * 8 @ restore other regs ldmia r0!, {r4-r11} ldr r1, [r0] msr psp, r1 @ enable interrupt tim2 @ ldr r0, nvic_base @ ldr r1, [r0] @ orr r1, r1, 0x10000000 @ str r1, [r0] @ go thread mode, using psp mov lr, 0xfffffffd bx lr .align 2 nvic_base: .word 0xE000E100 .section .bss .align 2 kernel_save: .rept 10 .word 0x00000000 .endr
执行bx lr时,若lr设为0xFFFFFFFD(返回线程模式并使用PSP作为栈指针),会触发Usage Fault,且Usage Fault状态寄存器的INVPC位置位,提示「尝试使用无效EXC_RETURN值执行异常操作」;但将lr设为0xFFFFFFF9(返回线程模式并使用MSP)时,能正常切换到用户代码,仅栈指针不符合预期。
已执行的调试操作
- 确认异常返回的返回栈配置正确
- 尝试通过POP、LDR等方式将EXC_RETURN值加载至PC,均无效
- 验证后续用户代码使用的PSP值有效
- 触发SVC时无其他活跃中断,无需设置Configuration Control Register的NONBASETHRDENA位
- 确认未修改xPSR中的异常编号
官方文档关键规则(翻译自Cortex-M3异常返回文档)
- EXC_RETURN值编码规则:
- 最低三位用于指定返回模式与栈指针:
- 位0:必须为1(标识这是异常返回,而非普通分支跳转)
- 位1:0=返回后使用MSP,1=返回后使用PSP
- 位2:0=返回线程模式,1=返回处理模式
- 合法的EXC_RETURN值包括:
0xFFFFFFF9:线程模式 + MSP0xFFFFFFFD:线程模式 + PSP0xFFFFFFF1:处理模式 + MSP0xFFFFFFF5:处理模式 + PSP
- 最低三位用于指定返回模式与栈指针:
- 异常返回失败触发条件:
若EXC_RETURN值不符合编码规则、栈指针未对齐、栈帧不完整或内存权限不足,会触发Usage Fault,其中INVPC位置位表示EXC_RETURN值无效。
排查方向
- 检查PSP对齐性:Cortex-M3要求栈指针必须8字节对齐,若
msr psp, r1设置的PSP值未满足双字对齐,使用0xFFFFFFFD返回时会触发错误 - 验证任务栈帧完整性:使用PSP返回时,栈帧必须包含完整的8个寄存器值(xPSR、PC、LR、R12、R0-R3),且顺序与异常入栈的顺序一致
- 检查CONTROL寄存器配置:返回用户模式时,CONTROL寄存器的位0(nPRIV)需为1;同时确认栈帧中xPSR的T位是否为1(Cortex-M3仅支持Thumb模式)
- 栈内存权限检查:用户模式下访问的PSP栈内存区域,需配置为用户可访问的权限,不能是内核专属的内存块
- 实时调试PSP值:在执行
msr psp, r1后,查看PSP的实际值是否指向合法的栈空间起始位置,是否超出内存范围
内容的提问来源于stack exchange,提问作者AO7
相关产品推荐
相关产品推荐

