Search code examples
armcortex-mstack-pointer

Which Stack Is Used Coming Out of Reset In ARM Cortex-M, MSP or PSP?


I've been reading various sections in the ARM Information Center to try and find my answer, however I came to a point where the documentation confused me so I'm hoping someone here can help.

I understand that there are two stacks in Cortex-M processors:

  • MSP (main stack pointer)
  • PSP (process stack pointer)

I'm trying to figure out how each one is used by the ARM core.

The documentation in the ARM Information Center when discussing the Cortex-M3 states the following:

The main stack is used at reset, and is always used in Handler mode (when entering an exception handler). The process stack pointer is only available as the current stack pointer when in Thread mode.

Okay, this tells me that the MSP is used at reset. However, the documentation also states the following:

Thread mode

Used to execute application software. The processor enters Thread mode when it comes out of reset.

Handler mode

Used to handle exceptions. The processor returns to Thread mode when it has finished all exception processing.

Okay, so this is what confuses me. If the MSP is used at reset and is always used in Handler mode, and the PSP is used in Thread mode, then how can the MSP be used at reset if the processor is in Thread mode at reset?


Solution

  • Simple answer: your final paragraph is incorrect. Thread mode uses the MSP by default.

    You don't say what processor you're using, so let's assume a Cortex-M3. Check out the description of the CONTROL register at the bottom of this page: the SPSEL bit controls which stack is in use, defaults to MSP for both Thread and Handler mode, and is only writable in Thread mode.

    Additionally, though it wasn't part of your question, Thread mode is privileged by default too. Setting the nPRIV bit in the same register makes Thread mode unprivileged.

    In summary: Handler mode is always privileged and always uses the MSP. By default, the same is true for Thread mode, but the CONTROL register allows this to be changed.

    A bit more context...

    If you were writing a small operating system, for example, it would be typical to want Thread mode code to be unprivileged. It also makes task switching much easier if Thread mode code uses the PSP because then your task switch code, which will inevitably be running in Handler mode (typically in the PendSV handler on a Cortex-M), can make use of its own stack without affecting the stacks of the tasks it's trying to switch.

    To do this, the operating system's initialisation code would typically have to (in this order):

    • Reserve some space for the idle task's stack, and use an MSR instruction to make the PSP point to the top of this region (this requires privilege but also must be done from Thread mode because SPSEL ignores writes in Handler mode)
    • Use another MSR instruction to set the SPSEL bit in the CONTROL register, switching the running code to using the PSP and the newly-prepared stack space
    • Issue an ISB instruction to ensure that all following instructions use the PSP as required
    • Use MSR once more to set the nPRIV bit in the CONTROL register, immediately removing privilege from Thread mode

    The running Thread mode code then becomes the idle task.