Assembly 为什么ARM监控模式有自己的堆栈?

Assembly 为什么ARM监控模式有自己的堆栈?,assembly,arm,interrupt,Assembly,Arm,Interrupt,我正在玩一个Atmel AT91SAM7S微控制器,看起来IRQ处理程序应该在监控模式下执行,而主循环代码在系统模式下执行。另外,我应该保留RAM的某一部分,以供主管模式代码用作堆栈。我从演示程序获得的启动汇编代码默认保留128字节 为什么我必须为主管模式保留单独的堆栈空间;为什么它不能使用与系统模式(main)相同的堆栈?中断处理代码与主循环代码具有完全不同的堆栈有什么好处?我看到当前用于IRQ处理的汇编代码在跳转到中断处理程序之前从IRQ模式切换到管理器模式。在用户模式下执行中断处理程序是否

我正在玩一个Atmel AT91SAM7S微控制器,看起来IRQ处理程序应该在监控模式下执行,而主循环代码在系统模式下执行。另外,我应该保留RAM的某一部分,以供主管模式代码用作堆栈。我从演示程序获得的启动汇编代码默认保留128字节

为什么我必须为主管模式保留单独的堆栈空间;为什么它不能使用与系统模式(main)相同的堆栈?中断处理代码与主循环代码具有完全不同的堆栈有什么好处?我看到当前用于IRQ处理的汇编代码在跳转到中断处理程序之前从IRQ模式切换到管理器模式。在用户模式下执行中断处理程序是否合适?如果是的话,有什么我需要注意的吗

我这样问是因为如果中断有自己的堆栈,我需要估计在最坏的情况下中断将使用多少堆栈空间的上限。如果中断使用与main相同的堆栈,那么就没有必要这样做,只要有足够的可用RAM(最肯定的是,我不会使用那么多)

我能想到的唯一一件事是,如果您正在实现一个具有某种内存保护的操作系统,那么拥有一个单独的堆栈将非常有用;但既然我不这么做,那有关系吗

另外,我熟悉AVR及其中断处理

澄清

当CPU跳转到地址0x18时,中断处理开始,地址0x18包含到下面的AT91F_Irq_处理程序的分支指令。据我所知,处理器自动进入中断模式;根据触发的中断线,该组件在分支到(C)功能之前切换到监控模式。它从高级中断控制器(AIC)获取分支地址


您不必将supervisor r13用作堆栈。您可以将其用作通用寄存器来保存某些内容,然后转换到系统模式,并在该模式下运行ISR的其余部分。它是灵活的,你可以有一个不同的堆栈,如果你愿意;你不会像其他建筑一样被铐上手铐。您可以使用一些存储区域指针或通常是指向当前执行任务的指针(或双指针)填充监管器r13。您需要保存
lr
spsr
,以及任何其他寄存器,如果您希望ISR返回,这些寄存器将被关闭。我认为,一开始,正常的ARM将处于中断模式;也许你有其他的处理程序已经转换到主管模式了?通常,系统模式有一个内核堆栈/任务控制块,它在多任务系统中切换。主管模式是异常处理的常见模式

如果您只有一个任务,并且希望使用它的堆栈,那么可以使用以下方法。在supervisor中保存上下文后,转换到系统模式并执行ISR的其余部分。只需恢复寄存器,包括
lr
cpsr
,即可返回到正确的模式、程序计数器和条件代码


当然,您可以使用选项将supervisor r13用作异常堆栈,许多人可能会喜欢有限制的行为和更快的IRQ延迟,因为堆栈已预设并准备好供主要ISR主体使用。

堆栈溢出是一个非常严重的错误,这是该网站命名的原因。如果主管使用相同的堆栈,则在用户模式下无法从SO恢复。或者处理由IRQ或异常生成的SO。@HansPassant任何地方都不应该有堆栈溢出;如果你能确保这一点,你就不必首先关心恢复。但是(例如)只有128字节的中断堆栈,很容易意外地发生溢出(因为中断堆栈将溢出到用户堆栈中,至少在我的情况下是这样)。如果中断只在用户堆栈结束的堆栈上继续,就不会有问题;这是关于
cpsr
的问题,人们可能会对这个问题感兴趣。最重要的是,在返回中断的用户代码之前,请确保通过
pop
ing更正堆栈。您的用户代码可能需要一些选项。例如,有时“C”使用空格。它仅在函数调用时进行调整。如果你只是使用内存,你可能会踩到被中断的代码局部变量。是的,我理解这种危险,尽管AVR中使用了相同的堆栈方法,并且假设覆盖用户数据没有问题,因为它是在堆栈指针递增之前写入的。你认为ARM编译器(gcc)在这方面不够谨慎吗?我想,
gcc
有一些选项可以让它工作,另一个选项会破坏它。它甚至可能取决于gcc的版本;您需要查看手册,可能还需要查看生成的代码。我认为
fp
引用了局部变量,这可能是安全的,但我会(并且必须)分配另一个堆栈;中断处理程序通常没有那么复杂。只需更改128字节以满足您的ISR要求;你需要ISR堆栈要求高,系统内存要求低,这样才没有意义。我在gcc手册页中没有找到任何这样的选项。。。但是请注意,如果您允许中断嵌套,那么为中断使用单独的堆栈在这方面并没有帮助。
AT91F_Irq_Handler:
/* Manage Exception Entry               */
/* Adjust and save LR_irq in IRQ stack  */
                sub         lr, lr, #4
                stmfd       sp!, {lr}
/* Save r0 and SPSR (need to be saved for nested interrupt)  */
                mrs         r14, SPSR
                stmfd       sp!, {r0,r14}
/* Write in the IVR to support Protect Mode                 */
/* No effect in Normal Mode                             */
/* De-assert the NIRQ and clear the source in Protect Mode  */
                ldr         r14, =AT91C_BASE_AIC
                ldr         r0 , [r14, #AIC_IVR]
                str         r14, [r14, #AIC_IVR]

/* Enable Interrupt and Switch in Supervisor Mode  */
                msr         CPSR_c, #ARM_MODE_SVC

/* Save scratch/used registers and LR in User Stack  */
                stmfd       sp!, { r1-r3, r12, r14}

/* Branch to the routine pointed by the AIC_IVR  */
                mov         r14, pc
                bx          r0
/* Manage Exception Exit                                  */
/* Restore scratch/used registers and LR from User Stack  */
                ldmia       sp!, { r1-r3, r12, r14}

/* Disable Interrupt and switch back in IRQ mode  */
                msr         CPSR_c, #I_BIT | ARM_MODE_IRQ
/* Mark the End of Interrupt on the AIC  */
                ldr         r14, =AT91C_BASE_AIC
                str         r14, [r14, #AIC_EOICR]
/* Restore SPSR_irq and r0 from IRQ stack  */
                ldmia       sp!, {r0,r14}
                msr         SPSR_cxsf, r14
/* Restore adjusted  LR_irq from IRQ stack directly in the PC  */
                ldmia       sp!, {pc}^