CS644: x86 Linux interrupt handling

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.