Exception return issues with Cortex-M3 on STM32F103C8T6

Hello community!
I am currently working on developing a simple RTOS on STM32 for learning purposes.

When I was testing a piece of code that switches from kernel mode to user mode, I encountered a strange issue.
I used SVC interrupt for context switching, and the handler name is __int_SVC.
This is what the code looks like:

__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


The problem is , when I set lr to 0xFFFFFFFD, which is the EXC_RETURN value for "go to thread mode and use PSP for stack pointer", after the "bx lr", it always triggers an Usage Fault, but instead when I set it to 0xFFFFFFF9, which is for "go to thread mode and use MSP for stack pointer", it works fine and successfully switches to user code, all register context switching is good except for SP because I want it set to PSP.

The Usage Fault Status Register has bit INVPC set indicating that "Attempts to do exception with bad value in EXC_RETURN number", I don't understand why 0xFFFFFFF9 works but 0xFFFFFFFD won't.

Things I tried for debugging:

  • I ensured that the return stack for exception return is set up properly.
  • I tried to load EXC_RETURN value into PC by different ways like POP, LDR, none work.
  • I made sure that PSP value set for subsequent user code is valid.
  • The SVC is the only active interrupt when it's triggered, so no need to set NONBASETHRDENA bit in Configuration Control Register
  • I made sure exception number in xPSR weren't modified.

I also found a document about exception return behavior but it's for ARMv7-M:https://developer.arm.com/documentation/ddi0403/d/System-Level-Architecture/System-Level-Programmers--Model/ARMv7-M-exception-model/Exception-return-behavior?lang=en

I tried to follow the pseudo-code's logic in the article, seems if you can make 0xFFFFFFF9 return successfully you should also have 0xFFFFFFFD work as well, but that's for v7-M, I'm not sure if things work the same in Cortex-M3.


Please let me know if you have any clues or if you want more information !

About exception return in CM3: https://developer.arm.com/documentation/dui0552/a/the-cortex-m3-processor/exception-model/exception-entry-and-return?lang=en

  • hello nancen, I had a similar problem last week and my scenario was: After calling svc instruction in an interrupt (for context switching), I expect svc_handler to return directly to the Thread site after execution, which means returning Thread mode + Using PSP, just like you, which also triggers UsageFault (INVPC). I changed from svc_handler to return to the upper layer interrupt first, and then return to the thread site when the outer layer interrupt returns, so there is no problem. For your question, I am also very confused. Could you please leave your email or contact information? I would like to discuss with you.