1

Can someone explain me, how exactly system mode works when we have nested interrupt ?

As per ARM site

ARMv4 and later architectures include a privileged mode called System mode, to overcome this problem. System mode shares the same registers as User mode, it can run tasks that require privileged access, and exceptions no longer overwrite the link register.

So how system mode make use of registers of User mode ?

And upto what hierarchy level nested interrupts can be handled?

Rahul
  • 1,607
  • 3
  • 23
  • 41
  • This seems to be [the referred page](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0203j/Cihhfgah.html). Note, it is talking about **exceptions** and not interrupts. An *interrupt* is an **execption**, however, **FIQ**, **data aborts**, **program aborts**, **undefined exceptions**, etc. are all separate modes. You may save the state of these modes, specifically `lr` and `spsr`, to the system stack and then enter system mode. At this point, all code for all exceptions use the same stack. This is valuable as the `sp` can serve as more than a *stack*; Ie, process context. – artless noise Mar 19 '14 at 14:21

2 Answers2

3

Trying to handle nested interrupts in IRQ mode:

  • (USER) You are in user mode, your PC register tells where you are.

  • (USER) You get an interrupt.

  • (IRQ) Core switches to interrupt mode, disables interrupts (mask via cpsr.i) saves PC from user mode to LR in IRQ mode.

  • (IRQ) At this moment you can't get more interrupts because interrupts are disabled.

  • (IRQ) You are in IRQ mode and you do enable interrupts.

  • (IRQ) You call a function to handle related interrupt. After function call LR contains, return address into top level IRQ handler.

  • (IRQ) Another interrupt happens, LR gets overwritten with function handling interrupt. At this moment you can't have a stable state, simply because you can't use LR for your own purposes in IRQ mode and have interrupts enabled to support nested interrupts. You think you may save LR to stack, but that would be open to a race condition which would lead to inifinitive loops.

Handling nested interrupts via System mode:

  • (USER) You are in user mode, your PC register tells where you are.

  • (USER) You get an interrupt.

  • (IRQ) Core switches to interrupt mode, disables interrupts (mask via cpsr.i) saves PC from user mode to LR in IRQ mode.

  • (IRQ) At this moment you can't get more interrupts because interrupts are disabled.

  • (IRQ) You switch to system mode, enable IRQs.

  • (SYSTEM) Another interrupt happens but things work just because you don't race with hardware to keep your LR sane.

Look below to see which registers gets banked in which states.

enter image description here

Community
  • 1
  • 1
auselen
  • 27,577
  • 7
  • 73
  • 114
  • Why couldn't the IRQ code save the current context onto the interrupt stack then enable interrupts? I think that a variable may be needed to keep track of IRQ nesting, so when the nested level returns back to zero, a check for dispatch needed (another variable used for this, set if an IRQ handler calls a kernel signal function that unblocks a pending task) to do a context switch to a different user task if needed. – rcgldr Mar 20 '14 at 07:41
  • 1
    @rcgldr You can't reliably use BL{X} in IRQ mode with interrupts enabled, that's what I mean - any other funky solution yeah sure. – auselen Mar 20 '14 at 07:52
  • @auselen can you explain this line a little bit more `You think you may save LR to stack, but that would be open to a race condition which would lead to inifinitive loops.` I need to know what race condition will happen ? – Rahul Mar 20 '14 at 08:47
  • @auselen - Yes, the work around I recall was implemented in assembly, using R12 as a psuedo LR, knowing that R12 wouldn't get corrupted by a nested interrupt. I also recall a couple of mini-os where "user" code ran in supervisor mode, and one other that did the same, using system mode for nested IRQ's as you mentioned. – rcgldr Mar 20 '14 at 08:57
  • 1
    @Rahul You're in IRQ mode with interrupts enabled, your PC lets say is 0xA4, you do BL 0xB4 to do a call, PC becomes 0xB4, LR becomes 0xA4. If you want to return, you know you can use LR. However just at the time another interrupt happens then LR becomes 0xB4, and you loose where were you (you can't save LR in time). – auselen Mar 20 '14 at 08:58
  • @auselen got it... so with using the system mode only two interrupts can be handled ? one in system mode and other in irq mode.And which one will be handled first(I mean finish first0, irq which came first or the second one ? – Rahul Mar 20 '14 at 09:13
  • @Rahul - Once in system mode, the code would save the current context onto the stack (system / user stack pointer), so there's no limit to the level of nesting other than the size of the stack. Each instance of a nested IRQ would switch to system mode, push current context onto stack, then enable IRQ. – rcgldr Mar 20 '14 at 09:21
0

If you want to handle IRQ nestly, you have to deal with the very low level asm, which is one part of the heart of the OS.

Back to the code. I assume you have some idea of the ARM core registers. The most important thing in nesting IRQ is saving the states the ISR would return to. When IRQ happens, CPU will save the old CPSR to SPSR_irq and old PC to LR_irq and IRQ will be disabled. So, before jumping into the real ISR, you have to push {R0-R12}, LR_irq and SPSR_irq into the stack. Note, the IRQ is disabled right now and nothing would disturb you(unless the FIQ, but FIQ use other set of registers which does not interfere with IRQ registers). After that, you are safe to jump to the real ISR and enable IRQ.

When return from ISR, disable IRQ, and retrieve the SPSR from the stack, then do a LDM {R0-R12,PC}^ will get you back from where the interrupt happened.

P.S. If you only target AAPCS, you can only save {R0-R3, R12} in the entry, as the C function will not clobber {R4-R11}.

Grissiom
  • 11,355
  • 3
  • 18
  • 23