IRQ Stack location

Hi!

While debugging my project I've found out that my IRQ stack are mixed with application stack: both of them are allocated in the same RAM portion.

I managed to move the IRQ stack in its dedicated area but I would like to verify my code with some more expert people :-)

My "old" irq_handler was something like the following and my modifications are in red:

 

.equ SYS_MODE , 0x1F
.equ IRQ_MODE , 0x12
.equ INTC_ICCIAR_MASK , 0x1FFF
.equ INTC_ICCIAR_ADDR , 0xE820200C
.equ INTC_ICCEOIR_ADDR , 0xE8202010
.equ INTC_ICCHPIR_ADDR , 0xE8202018
.equ INTC_ICDIPR0_ADDR , 0xE8201400

    .func irq_handler
irq_handler:
    SUB lr, lr, #4
    SRSDB sp!, #SYS_MODE
    CPS #SYS_MODE #IRQ_MODE
    PUSH {r0-r3, r12}
read_intc_icciar_addr:
    /*; ++REE_SS Addressing ARM Errata 801120 */
    /*; Perform a dummy read to ensure ICCIAR is correct */
    LDR r1, =INTC_ICCHPIR_ADDR
    LDR r0, [r1]
    /*; --REE_SS Addressing ARM Errata 801120 */

    /*; ++REE_SS Addressing ARM Errata 733075 */
    /*; Check if ICCIAR is 0, 0x3FE or 0x3FF */
    /*; Load in to R3 - it will be used later as ICCIAR */
    LDR r1, =INTC_ICCIAR_ADDR
    LDR r3, [r1]

    CMP r3, #0
    BEQ read_intc_icciar_addr

    LDR r1, =1022
    CMP r3, r1
    BGE errata_733075_workaround
    B post_733075_workaround

errata_733075_workaround:
    /*; Perform a read from ulICDIPR0 and write value back */
    /*; It is sufficient to write the value that is already in the register. */
    /*; You can obtain the value to be written to the ICDIPR0 register by */
    /*; reading from it, or through other means" */
    LDR r1, =INTC_ICDIPR0_ADDR
    LDR r0, [r1]
    STR r0, [r1]

post_733075_workaround:
   /*; Get interrupt acknowledge register, from R3 to R0 */
   /*; ready to re-enter origional code */
   MOV r0, r3
   /*; --REE_SS Addressing ARM Errata 733075 */

   PUSH {r0}
   MOV r1, sp
   AND r1, r1, #4
   SUB sp, sp, r1
   PUSH {r1, lr}
   BL userdef_intc_handler_exe
   POP {r1, lr}
   ADD sp, sp, r1
   POP {r0}
   LDR r2, =INTC_ICCEOIR_ADDR
   STR r0, [r2]
   POP {r0-r3, r12}

   CPS #SYS_MODE
   RFEIA sp!
   .endfunc

 

Stack pointer for each mode are initialized in another file (reset_handler.S)

Are my modifications correct and complete?

It seems to work but I am really not an ASM expert.

 

Thank you very much!

Parents
  • Reading the arm wiki here www.heyrick.co.uk/.../Processor_modes

    It seems that as you have discovered IRQ_MODE uses shadow registers for the stack and link register and SYS_MODE uses the same registers as for user mode just with the privileges of SVC mode.

    Using IRQ_MODE allows for separate stacks but it seems you can't have nested interrupts of the same type if you make any sub-routine calls in the interrupt handler.

    Hope this helps

    Paul.
Reply
  • Reading the arm wiki here www.heyrick.co.uk/.../Processor_modes

    It seems that as you have discovered IRQ_MODE uses shadow registers for the stack and link register and SYS_MODE uses the same registers as for user mode just with the privileges of SVC mode.

    Using IRQ_MODE allows for separate stacks but it seems you can't have nested interrupts of the same type if you make any sub-routine calls in the interrupt handler.

    Hope this helps

    Paul.
Children
  • Hi Paul,
    starting from your hint I found some similar explanations:
    books.google.it/books

    infocenter.arm.com/.../index.jsp


    The main issue is the LR (R14) register that is overwritted by nested interrupts. Foolishly I could think to back it up somewhere but if noone never thought it I suppose that is an issue of my limited ARM knowledge, so I think I will give up. :-)
  • Yes, I was thinking how it could be backed up, you can't use the stack because that the problem you are trying to resolve. The only solution I could think of was to work out the maximum number of nested interrupts you could have and then have a counter in the interrupt handler incrementing on entry and decrementing on exit which saves R14 to an array based on the counter. This sounds as if it could be difficult to manage, but if you can guarantee a maximum number of interrupts then it should work.

    The fact that most articles I can see on it use the SYS_MODE then probably best to stick to that.

    Here is another article covering all types of interrupt handling.

    www.ece.umd.edu/.../ARM-Interrupts-1.pdf

    Paul