How Linux Kernel Handles Hardware Interrupts

This article provides an overview of how the Linux operating system kernel processes hardware interrupts. When external hardware components need the processor's attention, they issue an Interrupt Request (IRQ). Linux manages these asynchronous events through a structured two-half architecture designed to maintain system responsiveness, prevent data loss, and efficiently transition execution context between user space and kernel space.

1. The Hardware Trigger and Signal Routing

The interrupt process begins at the physical hardware layer:

  1. Hardware Assertion: A device (such as a network card, keyboard, or disk controller) asserts an electrical signal on an Interrupt Request (IRQ) line.
  2. Interrupt Controller: The signal reaches an interrupt controller—such as an Advanced Programmable Interrupt Controller (APIC) on x86 or a Generic Interrupt Controller (GIC) on ARM. The controller prioritizes the interrupt and translates the physical pin or message into an interrupt vector number.
  3. Signaling the CPU: The controller sends the vector number to the CPU core and raises an interrupt line on the processor.

2. CPU Context Switch and Vector Lookup

Upon detecting the interrupt line signal, the CPU interrupts its current execution flow:

  1. State Preservation: The CPU pauses the currently executing thread, pushes essential state information (such as the instruction pointer, flags, and general-purpose registers) onto the stack, and switches from user mode to kernel mode if necessary.
  2. Vector Table Lookup: The CPU uses the interrupt vector to index into the Interrupt Descriptor Table (IDT) or architecture-specific exception vector table.
  3. Dispatching the Handler: The vector entry points to low-level assembly code in the kernel, which saves the remaining register state and invokes do_IRQ(), the Linux kernel’s primary interrupt handling dispatcher.

3. The Two-Half Interrupt Model

Because hardware interrupts pause normal system execution and frequently disable further interrupts on the executing CPU, Linux splits interrupt handling into two stages: the Top Half and the Bottom Half.

The Top Half (Hard IRQ)

The top half is the Interrupt Service Routine (ISR) registered by the device driver using functions like request_irq().

The Bottom Half (Deferred Execution)

The bottom half handles the time-consuming and computationally intensive processing associated with the event, such as protocol decoding for network packets or filesystem parsing for storage blocks. Linux provides multiple mechanisms for bottom-half processing:

4. Returning from the Interrupt

Once the top-half handler finishes and bottom-half work is scheduled:

  1. The kernel checks whether any high-priority bottom halves (such as softirqs) need immediate execution before leaving the interrupt context. If the system is under heavy interrupt load, the kernel defers remaining softirq processing to the ksoftirqd kernel thread to prevent starving user-space processes.
  2. The kernel checks if the interrupted process needs to be rescheduled (e.g., if the interrupt woke up a higher-priority process).
  3. The CPU state (registers, stack pointer, program counter) is restored.
  4. An architecture-specific instruction (such as iret on x86) executes, returning the processor to the exact state and privilege level it occupied before the interrupt occurred.