assemblyarmembeddedcortex-mstack-pointer

Stack is not aligned to 8 bytes on exception entry


I'm writing a mini OS for my STM32F0 board, which has a Cortex-M0 CPU based on the ARMv6-M architecture. In particular, I'm doing the msp/psp switch after I've created the process queue for the scheduler. The alignment issue manifests if and only if I've already done the switch otherwise it seems to be absent.

The ARMv6-M architecture guarantees 8-byte stack alignment on exception entry even if the stack pointer wasn't previously aligned. In my trap handler, I've double checked that the sp automatically changes to msp on exception entry and it's not aligned anyways.

Here's the involved code:

extern "C" fn kmain() -> ! {
    // initialization code
    Process::spawner().new(task).new(shell).spawn();
    // infinite loop waiting for interruptions
}

#[inline(always)]
pub fn spawn(self) {
    unsafe {
        // Initialize the current process with the first one
        // when we're terminating the builder
        CURR_PROC.write(ptr::read(PROC_LIST.0));
    }

    Scheduler::init(self.idle_task_stack); // <--- THIS LINE
    SysTick::enable();
}

#[inline(always)]
pub fn init(psp: *mut u8) {
    unsafe {
        // Set PSP as default stack, flush the pipeline
        //  standard procedure. Using barriers.
        _switch_to_psp(psp); // <--- THIS LINE
    }
}
.global _switch_to_psp
.thumb
.thumb_func
_switch_to_psp:
    MSR psp, r0
    MOV r1, #2
    MSR CONTROL, r1
    ISB
    BX lr

Just by commenting the highlighted line, the msp correctly aligns to 8 bytes in the interrupt handler when the system timer interruption triggers, even if it previously wasn't. Note that I'm checking those registers both in the assembly wrapper and the rust handler to make sure that the handler prologue is not misaligning the stack and that is not the case. (I'm inlining each function because the stack pointer changes between the call and the return, hence the epilogue would break everything.)

Do you have any hint on why this happens?


Solution

  • I've come to the conclusion that the stack that gets aligned is not the current, but the one before the exception entry and so I shouldn't be concerned.

    There's an ambiguous paragraph which mentions:

    The CCR.STKALIGN bit indicates whether, as part of an exception entry, the processor aligns the SP to 4 bytes, or to 8 bytes

    That made me think of the SP as the current stack pointer. However, researching more carefully, I've found a better explanation:

    On an exception entry, the exception entry sequence ensures that the stack pointer in use before the exception entry has 8-byte alignment, by adjusting its alignment if necessary