ISR(中断服务程序)是否有单独的堆栈?

Gin*_*cob 5 stack interrupt task isr freertos

使用RTOS(例如FreeRTOS)时,每个线程都有单独的堆栈空间。那么,ISR(中断服务程序)呢,它们在内存中是否有单独的堆栈?还是可以配置的?

如果它们没有用于存储在ISR中声明的局部变量的堆栈?

sat*_*ine 6

我有完全相同的问题,大量搜索使我得出这个结论:答案取决于您的芯片以及您使用的操作系统如何配置该芯片。

因此,看看我最喜欢的 ARM Cortex-M3 芯片之一(中断是一种异常形式),各个位置的文档如下:

操作模式

Cortex-M3 支持特权和用户(非特权)执行。以特权身份运行的代码具有完全访问权限,而以用户身份执行的代码具有有限的访问权限。这些限制包括对指令使用的限制,例如 MSR 字段、基于系统设计的对存储器和外设的访问,以及 MPU 配置施加的限制。

处理器支持两种操作模式,线程模式和处理程序模式。线程模式在重置时进入,通常在从异常返回时进入。在线程模式下,代码可以作为特权或非特权执行。

作为异常的结果,将进入处理程序模式。Handler 模式下的代码总是以 Privileged 的​​方式执行,因此内核会在发生异常时自动切换到 Privileged 模式。通过修改链接寄存器 (R14) 中的 EXC_RETURN 值,您可以在从异常返回时在特权线程模式和用户线程模式之间切换。您还可以通过使用 MSR 指令清除 CONTROL[0] 来从特权线程模式更改为用户线程模式。但是,您不能在不经过异常(例如 SVC)的情况下直接从非特权模式更改为特权模式。

主栈和进程栈

Cortex-M3 支持两种不同的堆栈,一个主堆栈和一个进程堆栈。为了支持这一点,Cortex-M3 有两个堆栈指针 (R13)。根据使用的堆栈,其中之一被银行出。这意味着一次只有一个堆栈指针作为 R13 可见。但是,可以使用 MRS 和 MSR 指令访问这两个堆栈指针。主堆栈在复位时使用,并且始终在处理程序模式下使用(进入异常处理程序时)。进程堆栈指针仅在线程模式下可用作当前堆栈指针。您可以通过以下两种方式之一选择在线程模式下使用哪个堆栈指针(主或进程):从处理程序模式退出时使用 EXC_RETURN 值,或在线程模式下使用 MSR 指令写入 CONTROL[1]。

和...

当处理器发生异常时,除非异常是尾链异常或迟到异常,否则处理器会将信息压入当前堆栈。此操作称为堆栈,八个数据字的结构称为堆栈帧。...

刚入栈后,栈指针指示栈帧中的最低地址

来自“ARM Cortex-M3权威指南”一书:

MSP 在 ARM 文档中也称为 SP_main,是上电后的默认 SP;它由内核代码和异常处理程序使用。PSP 或 ARM 文档中的 SP_process 通常由运行嵌入式操作系统的系统中的线程进程使用。

因为异常处理程序总是使用主堆栈指针,主堆栈内存应该包含足够的空间来容纳最大数量的嵌套中断。

发生异常时,寄存器 R0–R3、R12、LR、PC 和程序状态 (PSR) 被压入堆栈。如果正在运行的代码使用进程堆栈指针 (PSP),则将使用进程堆栈;如果正在运行的代码使用主堆栈指针 (MSP),则将使用主堆栈。之后,在处理程序期间将始终使用主堆栈,因此所有嵌套中断都将使用主堆栈。

更新 6/2017:

我之前的答案是不正确的,我分析了皮质处理器的 FreeRTOS 并将我的答案改写为:

Cortex-M3 的标准 FreeRTOS 版本实际上配置和使用 MSP 和 PSP。当第一个任务运行时,它修改 MSP 以指向向量表中指定的第一个地址(0x00000000),这往往是 SRAM 中的最后一个字,然后触发系统调用,在它设置的系统调用异常处理程序中PSP 到下一个任务堆栈位置,然后它修改异常 LR 值,以便“返回线程模式并在返回时使用进程堆栈”。

这意味着中断服务程序(AKA 异常处理程序)堆栈从向量表中指定的地址开始向下增长。

您可以配置您的链接器和启动代码以在您喜欢的任何位置定位异常处理程序堆栈,确保您的堆或其他内存区域不与异常处理程序区域重叠并确保该区域足够大。

其他芯片和操作系统的答案可能完全不同!