Start off in entry.S: in
assembly language.
Capture IRQ# by using different entry points for
each irq pointed to from the IDT. These are all
generated by a macro.
At this point IF=0 because of CPU interrupt cycle.
There may be spinlocks held by this thread; this may be a recursive
interrupt; there may be a softirq in execution on
this CPU: all this information is held in the current preempt_count
value, in separate parts.
Call do_IRQ, in C,
discussed in Love, pg. 86
Find irq# from argument struct that
was set up in entry.S
Add HARDIRQ_OFFSET to preempt_count for this thread, making this execution non-preemptible. This step is not covered in Love. This
elevated preempt_count is also how the system detects
recursive interrupts.
Do call to “ack”: Send EOI to PIC and mask off this IRQ in the PIC
using mask_and_ack_8259A
Call handle_IRQ_event:
IF=0 still at this
point. Normally, unless SA_INTERRUPT (now IRQF_DISABLED) is on for the
interrupt handler for this irq, enable interrupts on
the local CPU now.
Loop through the
registered interrupt handlers for this irq#, calling
each with its registered “dev_id”, which is a pointer
to data the driver needs. These handlers may use spinlocks (with IF=0, pg. 138),
and release them.
Disable interrupts on
local CPU: IF=0
Back to do_IRQ (and its helpers)
Reenable
this irq in PIC (call to “end”)
Subtract HARDIRQ_OFFSET
from preempt_count, undoing the previous addition.
If this interrupt is not recursive there are no softirq’s in execution on this CPU, and there are pending softirqs,
cal
do_softirq()
Return to entry.S
Back in entry.S, again
running with IF=0, this irq re-enabled in PIC, and
original preempt_count:
Find out if returning to user code or kernel code
(look at old CS register value masked by 3, i.e., low 2 bits: if 0, was kernel)
·
If returning to user and need_resched flag is on, call schedule (user
preemption)
·
If returning to kernel and need_resched is on, and preempt_count
== 0, call schedule (kernel preemption). Preempt_count == 0 means no spinlocks are held by this
thread, this is not a recursive interrupt, and there are no softirq’s
in execution on this CPU.
Restore registers, and iret
back to interrupted code
From this, we see that the individual interrupt
handlers registered by request_irq only need to do
the device-specific actions, not the EOI-sending or masking the irq in the PIC. Also they normally run with IF=1 on
the local processor, so they can be interrupted by other interrupts (of other
IRQ#s), but not preempted by these recursive interrupts.