1. Interrupt Generation

  • A hardware device (e.g., NIC, keyboard) raises an interrupt via the Programmable Interrupt Controller (PIC/APIC).
  • The PIC converts the IRQ line into a vector number and signals the CPU via the INTR/NMI pin.

2. CPU State Save & Context Switch

  • The CPU finishes the current instruction, saves the process context (registers, PC, flags) to the stack, and disables local interrupts
  • Switches to the interrupt context (no associated process, interrupts disabled).

3. IDT Lookup

  • The CPU uses the Interrupt Descriptor Table (IDT) to find the handler address for the interrupt vector.
  • On ARM, the vector table (similar to x86 IDT) is preconfigured with handlers like handle_level_irq or handle_edge_irq.

4. Top Half Execution

  • Immediate Actions:
  • Acknowledge the interrupt at the hardware level (irq_data.chip->irq_ack())
  • Read device status registers to confirm the interrupt source
  • Minimal Processing:
  • Copy critical data (e.g., network packets) to kernel buffers.
  • Schedule deferred processing via bottom halves (tasklets, softirqs)
  • APIs: request_irq(), free_irq() for driver-level registration.

5. Bottom Half Execution

  • Deferred Work:
    • Process data in safe contexts (e.g., tasklet_schedule() or workqueues).
    • Runs with interrupts enabled (softirq context) or in process context (workqueues).
  • Mechanisms:
    • SoftIRQs: Statically allocated, high-priority (e.g., network RX)
    • Tasklets: Dynamically allocated, atomic (e.g., USB transfers).
    • Workqueues: Sleepable, process context (e.g., filesystem I/O) .

6. Interrupt Completion

  • Send End-of-Interrupt (EOI) to the PIC (e.g., irq_data.chip->irq_eoi())
  • The result is stored in eax/r0, and the kernel uses iret (x86) or exception return (ARM) to resume user execution.

7. Examples

Network Driver (Hardware Interrupt)

  • Top Half:
irqreturn_t nic_isr(int irq, void *dev_id) {
    // Read packet from hardware buffer
    tasklet_schedule(&nic_tasklet); // Schedule bottom half
    return IRQ_HANDLED;
}
  • Bottom Half:
void nic_tasklet_fn(unsigned long data) {
    // Process packets, update kernel networking stack
}