Hooking ARM IRQs with FIQs
Written 2012-09-02
Tags:Latency FIQ IRQ hook Interrupt ARM
I stumbled on to an odd little trick recently. On the ARM architecture, there are two types of interrupts- Fast Interrupts(FIQ) and standard/slow interrupts(IRQ). I was writing an FIQ, but needed some way to test it. I figured I would re-use an existing external IRQ line, but I didn't really want to prevent the interrupt from reaching the OS. Luckily for me, it turns out it is possible to install an FIQ that is triggered by an existing IRQ, without breaking the behaviour of the existing IRQ.
On the processor I was using, there is a bit-vector that controls if an interrupt is actually an FIQ. If the interrupt is marked as an FIQ interrupt, the execution will jump FIQ vector. It is important to note that you can still keep an interrupt vector in place.
Most non-nested interrupts look something like this:
ACK interrupt
Do Something
SUBS PC, R14, #4 ;Return from interrupt/fiq and swap back the PSR(Program Status Register)
My FIQ looks something like this:
Do Something
Clear FIQ bit
SUBS PC, R14, #4
You'll note I didn't ACK the interrupt. That's because the slow interrupt will still run. When the external stimulus occurs, the CPU stops current processing(or may block a little while if interrupts are disabled), and executes the FIQ. The FIQ then marks the interrupts as not an FIQ. The FIQ keeps running until it returns. When it returns, the interrupt controller catches that there is still an outstanding interrupt, and then runs the standard interrupts handler. Because we cleared the FIQ bit in the FIQ, we should probably re-enable it after the IRQ completes.
I think there are several useful things you could do with this. You could measure interrupt delay between the event and the IRQ response by installing an FIQ that reads a timer, and reading it again in the OS after the IRQ completes. You could count the number of IRQ events in the system overall. You could test adding latency to existing IRQs.