Exception Handling and Stack Pointer Transition in Cortex-M3
The Cortex-M3 processor, as part of the ARMv7-M architecture, employs a sophisticated exception handling mechanism that relies on two stack pointers: the Main Stack Pointer (MSP) and the Process Stack Pointer (PSP). The MSP is typically used in Handler Mode (privileged mode during exception handling), while the PSP is used in Thread Mode (unprivileged or user mode). The transition between these modes is governed by the EXC_RETURN value loaded into the Link Register (LR) at the end of an exception handler. This value determines the stack pointer to be used upon return and whether the processor should return to Thread Mode or remain in Handler Mode.
In the context of developing a simple RTOS on the STM32F103C8T6 microcontroller, a common issue arises when attempting to switch from Handler Mode to Thread Mode using the PSP. The EXC_RETURN value 0xFFFFFFFD
is used to indicate a return to Thread Mode with the PSP. However, this often results in a Usage Fault with the INVPC (Invalid PC Load) bit set in the Usage Fault Status Register (UFSR). This fault indicates that the processor encountered an invalid EXC_RETURN value or an improperly configured stack frame during the exception return sequence.
The core of the problem lies in the sequence of operations during the exception return. When the processor executes the BX LR
instruction with LR = 0xFFFFFFFD
, it attempts to switch to Thread Mode and use the PSP for stack operations. However, if the PSP is not correctly configured or the stack frame is improperly aligned, the processor cannot complete the exception return successfully, leading to a Usage Fault.
Misconfigured PSP and Stack Frame Alignment
The primary cause of the Usage Fault when using LR = 0xFFFFFFFD
is a misconfigured PSP or an improperly aligned stack frame. The Cortex-M3 requires that the PSP point to a valid stack frame that adheres to the ARMv7-M exception stack frame format. This stack frame must include the following registers in the specified order: xPSR, Return Address (PC), LR, R12, R3, R2, R1, and R0. If the PSP does not point to a valid stack frame or if the stack frame is misaligned, the processor cannot perform the exception return correctly.
Another potential cause is the timing of the PSP configuration relative to the exception return. The Cortex-M3 expects the PSP to be configured before the exception return sequence begins. If the PSP is modified after the processor has already started the exception return sequence, the processor may attempt to use an invalid or outdated PSP value, leading to a Usage Fault.
Additionally, the INVPC bit in the UFSR indicates that the processor encountered an invalid EXC_RETURN value. This can occur if the EXC_RETURN value is corrupted or if the processor is unable to interpret it correctly. In the case of LR = 0xFFFFFFFD
, the processor expects to switch to Thread Mode and use the PSP. If the PSP is not properly configured or the stack frame is invalid, the processor cannot complete the transition, resulting in a Usage Fault.
Correct PSP Configuration and Exception Return Sequence
To resolve the Usage Fault when switching to Thread Mode with the PSP, the PSP must be correctly configured, and the stack frame must be properly aligned before the exception return sequence begins. The following steps outline the correct approach to ensure a successful exception return:
-
Configure the PSP Before Exception Return: The PSP must be configured to point to a valid stack frame before the exception return sequence begins. This can be done using the
MSR PSP, R1
instruction, whereR1
contains the address of the stack frame. The stack frame must adhere to the ARMv7-M exception stack frame format, including the xPSR, Return Address (PC), LR, R12, R3, R2, R1, and R0 registers. -
Ensure Proper Stack Frame Alignment: The stack frame must be aligned to an 8-byte boundary, as required by the ARMv7-M architecture. Misalignment of the stack frame can cause the processor to misinterpret the stack frame contents, leading to a Usage Fault. Use the
ALIGN
directive in assembly code to ensure proper alignment of the stack frame. -
Use Correct EXC_RETURN Value: The EXC_RETURN value
0xFFFFFFFD
must be loaded into the LR before executing theBX LR
instruction. This value indicates that the processor should return to Thread Mode and use the PSP for stack operations. Ensure that the LR is not modified or corrupted before the exception return sequence. -
Avoid Modifying PSP During Exception Return: The PSP should not be modified during the exception return sequence. Any modifications to the PSP after the processor has started the exception return sequence can cause the processor to use an invalid or outdated PSP value, leading to a Usage Fault.
-
Verify Exception Stack Frame Contents: Before executing the exception return sequence, verify that the stack frame contains the correct values for the xPSR, Return Address (PC), LR, R12, R3, R2, R1, and R0 registers. Any discrepancies in the stack frame contents can cause the processor to misinterpret the stack frame, leading to a Usage Fault.
The following updated assembly code demonstrates the correct approach to configure the PSP and perform the exception return sequence:
.thumb
.syntax unified
.global __Sys_UserMode, __Sys_KernelMode, __Int_SVC
__Sys_UserMode:
SVC 0
BX LR
__Int_SVC:
@ Save kernel registers
LDR R1, =kernelSave
STMIA R1!, {R4-R11}
@ Set PSP to task stack bottom
LDR R1, [R0, 8 * 4]
MSR PSP, R1
@ Restore task registers
LDMIA R0!, {R4-R11}
@ Return to Thread Mode, using PSP
MOV LR, 0xFFFFFFFD
BX LR
__Sys_KernelMode:
@ Save task registers
STMIA R0!, {R4-R11}
@ Save PSP
MRS R1, PSP
STR R1, [R0]
@ Restore kernel registers
LDR R1, =kernelSave
LDMIA R1!, {R4-R11}
@ Return to Thread Mode, using MSP
MOV LR, 0xFFFFFFF9
BX LR
.section .bss
kernelSave:
.rept 8
.int 0x00000000
.endr
In this code, the PSP is configured before the exception return sequence begins, and the stack frame is properly aligned and populated with the correct values. The MOV LR, 0xFFFFFFFD
instruction sets the EXC_RETURN value to indicate a return to Thread Mode with the PSP, and the BX LR
instruction initiates the exception return sequence.
By following these steps and ensuring proper configuration of the PSP and stack frame, the Usage Fault can be avoided, and the processor can successfully transition from Handler Mode to Thread Mode using the PSP.