Domanda

I am new to ARM and learning about interrupt handling in ARM. I have read about how to set up IRQ handler in ARM but not sure how I write it in ARM assembly. Below is my understanding on setting up IRQ handler.

_IRQ_HANDER:

1) SUB lr, lr, #4 (Not sure what it do).

2) Would set up separate stack should be used in IRQ Mode. I know in x86 we set up stack like below:

push ebp
mov esp,ebp
sub esp,8

This will resrve 8 bytes of stack space.

But not sure how I do the same in ARM?

3) Store the non-banked register, we can do it this way:

  STMFD !sp {r13,r14}

4) Copy the CPSR to SPSR (how can I do it ARM assembly?)

5) Move to Processors IRQ mode (I am ok doing this in ARM assembly).

6) What is Next step?

Do we need to give the base address of PIC?

I am working with ARMV7 architecture.

È stato utile?

Soluzione

  1. The program counter on ARM points to the instruction being fetched, rather than the current instruction.

    For normal subroutine calls, this is perfect -- when the program counter is copied to the link register, it already points at the next instruction. In an interrupt handler, it points at the instruction after the interrupted instruction, so this needs to be corrected for.

    You can also apply this correction on the way out, e.g. by returning with SUBS pc, lr, #4. Note that if the interrupted code was running in Thumb mode, the lr is only two bytes ahead, so if you want to support user code in Thumb mode, you need to look at the spsr_IRQ to find out which offset to apply.

  2. On ARM, you already have a separate stack, because of register banking. When entering IQ mode, the registers r13 aka sp and r14 aka lr are switched over to r13_IRQ and r14_IRQ, which is why you do not need to restore lr for the interrupted application when exiting your interrupt handler.

    This stack needs to be set up before the first interrupt occurs. The kernel startup code at some point switches from the initial SVC mode to IRQ mode by changing the status register, at which point the r13_IRQ register becomes visible, writes the initial stack pointer there and switches back to SVC mode.

    Extending the stack frame works basically the same way as on x86, by subtracting from the stack pointer, e.g. using SUB sp,sp,#8.

    The x86 code you pasted does more than just extend stack space: it also builds a base pointer chain, which is useful if you want a debugger to display the call stack. For that to work, you need to fill out a full stack frame according to the ABI, with the saved return address in a specific slot etc, which I'd consider an advanced topic. If you expect to use a debugger inside C functions called from your interrupt handler, you can call the first C function with r12 set to zero, which will make the base pointer chain terminate at your handler function rather than confuse the debugger.

  3. You have it backwards -- these two registers are banked and do not need to be saved, unless you are reenabling interrupts while still in the handler. You need to save any registers your handler uses, and restore them prior to returning, the STore Multiple Full Descending (STMFD) instruction is correct for that.

  4. This is also backwards. You want to save the spsr_IRQ register rather than overwrite it. Again, this is a banked register, so you only need to do this if you are expecting more interrupts before your handler returns (i.e. you clear the "interrupt disable" bit in the PSR).

  5. You are already in IRQ mode. You leave IRQ mode either by setting a new mode in the status register, or by using an instruction with an S suffix (MOVS, SUBS, ADDS, ...) to set the pc from the lr (the "set status register" bit in this context means "copy the SPSR to the PSR").

  6. Afterwards, you handle the reason for the IRQ, typically by asking the interrupt controller (which is outside of the ARM core, so it is model dependent) what occured and then branching off into the appropriate code path. Depending on timing constraints, you can either handle the entire event, or just make a quick note to the idle loop that an interrupt occured and the appropriate function should be called the next time the system is idle.

Returning from an IRQ, you need to clean up the IRQ stack, restore any non-banked registers, and then use MOVS, SUBS or a similar instruction to set the pc and the cpsr at the same time.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top