Does ISR (Interrupt Service Routine) have a separate stack?
Asked Answered
P

2

7

When using an RTOS (ex FreeRTOS), we have separate stack spaces for each thread. So what about ISR (Interrupt Service Routines), does they have a separate stack in the memory? Or is this configurable?

If they don't have a stack where the local variables declared in ISR get stored?

Pamphleteer answered 3/2, 2016 at 14:35 Comment(0)
P
9

I have the exact same question and a lot of searching leads me to this conclusion: the answer is dependent on your chip and how the OS you use configures that chip.

So looking at one of my favorite chips ARM Cortex-M3 (for which interrupts are a form of exception), the documentation at various spots reads:

Operating Modes

The Cortex-M3 supports Privileged and User (non-privileged) execution. Code run as Privileged has full access rights whereas code executed as User has limited access rights. The limitations include restrictions on instruction use such as MSR fields, access to memory and peripherals based on system design, and restrictions imposed by the MPU configuration.

The processor supports two operation modes, Thread mode and Handler mode. Thread mode is entered on reset and normally on return from an exception. When in Thread mode, code can be executed as either Privileged or Unprivileged.

Handler mode will be entered as a result of an exception. Code in Handler mode is always executed as Privileged, therefore the core will automatically switch to Privileged mode when exceptions occur. You can change between Privileged Thread mode and User Thread mode when returning from an exception by modifying the EXC_RETURN value in the link register (R14). You can also change from Privileged Thread to User Thread mode by clearing CONTROL[0] using an MSR instruction. However, you cannot directly change to privileged mode from unprivileged mode without going through an exception, for example an SVC.

Main and Process Stacks

The Cortex-M3 supports two different stacks, a main stack and a process stack. To support this the Cortex-M3 has two stack pointers (R13). One of these is banked out depending on the stack in use. This means that only one stack pointer at a time is visible as R13. However, both stack pointers can be accessed using the MRS and MSR instructions. 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. You can select which stack pointer (main or process) is used in Thread mode in one of two ways, either by using the EXC_RETURN value when exiting from Handler Mode or while in Thread Mode by writing to CONTROL[1] using an MSR instruction.

And...

When the processor takes an exception, unless the exception is a tail-chained or a late-arriving exception, the processor pushes information onto the current stack. This operation is referred to as stacking and the structure of eight data words is referred as the stack frame. ...

Immediately after stacking, the stack pointer indicates the lowest address in the stack frame

From the book "The Definitive Guide to the ARM Cortex-M3":

The MSP, also called SP_main in ARM documentation, is the default SP after power-up; it is used by kernel code and exception handlers. The PSP, or SP_process in ARM documentation, is typically used by thread processes in system with embedded OS running.

Because exception handlers always use the Main Stack Pointer, the main stack memory should contain enough space for the largest number of nesting interrupts.

When an exception takes place, the registers R0–R3, R12, LR, PC, and Program Status (PSR) are pushed to the stack. If the code that is running uses the Process Stack Pointer (PSP), the process stack will be used; if the code that is running uses the Main Stack Pointer (MSP), the main stack will be used. Afterward, the main stack will always be used during the handler, so all nested interrupts will use the main stack.

UPDATE 6/2017:

My previous answer was incorrect, I have analyzed FreeRTOS for cortex processors and rewritten my answer to:

The standard FreeRTOS version for the Cortex-M3 does in fact configure and use both the MSP and PSP. When the very first task runs it modifies MSP to point to the first address specified in the vector table (0x00000000), this tends to be the very last word in SRAM, then it triggers a system call, in the system call exception handler it sets the PSP to the next task stack location, then it modifies the exception LR value such that "return to thread mode and on return use the process stack".

This means that the interrupt service routine (AKA exception handler) stack is grows down from the address specified in the vector table.

You can configure your linker and startup code to locate the exception handler stack wherever you like, make sure your heap or other memory areas do not overlap the exception handler area and make sure the area is large enough.

The answer for other chips and operating systems could be completely different!

Plasterboard answered 1/12, 2016 at 7:10 Comment(4)
This is not correct (for Cortex-M). The MSP is used in interrupts (and before scheduling has started). The PSP is used by the the tasks. Thus is regardless of whether you are using the MPU variants or not. Privileged or Unprivileged mode is not related to the MSP and PSP. Interrupts always run using the MSP (but will stack the exception stack from on whatever stack is currently being used before the interrupt)Santiago
You are correct! I fixed my answer to correctly explain how FreeRTOS uses the PSP and MSP.Plasterboard
Stack grows down from the address specified in the vector table, right?Spatterdash
@DaveNadler Yes, apologies, in my brain things are upside-down since a linker script is written from low addresses to high addresses so I picture memory that way but that's not the convention. Conventionally low addresses are drawn below high addresses. I've corrected the answer to state that the stack grows down.Plasterboard
S
0

To help ensure your application has appropriate space on the ISR stack (MSP), here's some additional code to check actual ISR stack use. Use in addition to the checking you're already doing on FreeRTOS task stack use:

https://sourceforge.net/p/freertos/discussion/382005/thread/8418dd523e/

Update: I've posted my version of port.c that includes the ISR stack use check on github:

https://github.com/DRNadler/FreeRTOS_helpers

Spatterdash answered 21/8, 2019 at 17:29 Comment(1)
It looks like access to the SourceForge discussion is forbidden.Breebreech

© 2022 - 2024 — McMap. All rights reserved.