Interrupts and Exceptions

Modern computing is far from a simple, linear execution of instructions. While a CPU is designed to process code sequentially, it must remain highly responsive to the unpredictable nature of the outside world and the inherent errors that occur during execution. This responsiveness is achieved through two fundamental mechanisms: Interrupts and Exceptions. These serve as the primary communication channels between hardware and software, forming the bedrock of operating system kernels, device drivers, and low-level system debugging.
To understand how a system manages complex tasks, one must first distinguish between the two types of events that can divert the CPU from its current path.

  • Interrupts are asynchronous signals triggered by external hardware devices. Because they originate from outside the CPU, they are not tied to the execution of any specific instruction. Common examples include a timer expiring, a disk drive signaling that an I/O operation is complete, or a network interface card (NIC) receiving a new data packet.
  • Exceptions are synchronous events triggered by the CPU itself as a direct result of the instruction currently being executed. Because they are tied to the instruction stream, they are predictable and reproducible. Examples include a "divide-by-zero" error, a page fault, or a deliberate system call.

Despite their different origins, both mechanisms share a common goal: they pause the current execution flow, redirect the CPU to a specialized piece of code known as an Interrupt/Exception Handler, and—once the event is resolved—restore the original state to resume normal operation.

The Taxonomy of Interrupts

Interrupts are generally categorized based on how the CPU can respond to them:

  1. Maskable Interrupts: These are signals that the CPU can choose to ignore or delay. By manipulating specific bits in the CPU's status register (such as the IF flag in x86 architectures), the operating system can temporarily disable these interrupts to protect critical sections of code from being preempted. These are typically managed and routed by an interrupt controller, such as the APIC (Advanced Programmable Interrupt Controller).
  2. Non-Maskable Interrupts (NMI): These are high-priority signals that cannot be ignored by the CPU. NMIs are reserved for catastrophic hardware events that require immediate attention, such as memory parity errors or imminent power failure. When an NMI occurs, the CPU must stop everything to handle the emergency.

The Taxonomy of Exceptions

Following the standard architectural definitions (such as those found in Intel manuals), exceptions are classified by how they affect the instruction pointer and the ability to recover:

  • Faults: A fault is detected before the instruction is allowed to complete. The CPU saves the address of the offending instruction so that, once the issue is resolved, the instruction can be re-executed. A classic example is a Page Fault; the OS handles the missing memory page, and the CPU then retries the exact same instruction.
  • Traps: A trap is reported after the instruction has finished executing. The saved return address points to the next instruction in the sequence. The most common use for traps is the System Call (e.g., via the syscall or int 0x80 instructions), which allows a user-space application to intentionally "trap" into the kernel to request services.
  • Aborts: These represent severe, unrecoverable internal errors, such as hardware malfunctions or "double faults." In these cases, the system cannot reliably determine a recovery point, and the process (or the entire system) is typically terminated.

The Lifecycle of Event Handling

When an interrupt or exception occurs, the system undergoes a highly orchestrated transition:

  1. Context Saving: The CPU automatically pushes critical state information—such as the instruction pointer (EIP/RIP), code segment (CS), and flags (EFLAGS)—onto the stack. The software handler must then save any general-purpose registers to ensure the interrupted program's state is preserved perfectly.
  2. Vector Lookup: The CPU identifies the specific type of event using an Interrupt Vector Number. It then consults a predefined lookup table, such as the Interrupt Descriptor Table (IDT) in x86 or the Exception Vector Table in ARM, to find the memory address of the appropriate handler.
  3. Privilege Escalation: If the event triggers a transition from user mode to kernel mode, the CPU must switch to a secure kernel stack and elevate its privilege level to allow the handler to perform sensitive operations.
  4. Handler Execution: The kernel executes the specific service routine. For a clock interrupt, this might involve updating the system tick; for a page fault, it might involve allocating a physical memory frame.
  5. Context Restoration: Once the handler completes, a special instruction (such as iret) is executed. This pops the saved state from the stack, restores the privilege level, and returns the CPU to the exact point where it was interrupted.

Case Study: Handling a Page Fault in Linux

To see these concepts in action, consider a Page Fault in a Linux environment. When a program attempts to access a virtual address that is not currently mapped to physical RAM, the Memory Management Unit (MMU) triggers an exception (Vector 14 on x86).

/* Simplified conceptual logic for a page fault handler */
void page_fault_handler(struct pt_regs *regs, unsigned long error_code) {
    // Read the faulting virtual address from the CR2 register
    unsigned long addr = read_cr2(); 

    if (is_address_within_valid_vma(addr)) {
        // The address is valid but not in RAM (a "Fault")
        // 1. Allocate a physical page frame
        // 2. Update the page tables
        // 3. Return to the instruction to retry access
        handle_valid_page_fault(addr);
    } else {
        // The address is truly invalid (e.g., a null pointer dereference)
        // Send a SIGSEGV (Segmentation Fault) to terminate the process
        send_signal(SIGSEGV, current_task);
    }
}

In this scenario, the "Fault" mechanism allows the OS to transparently fix the issue and let the program continue as if nothing happened. However, if the address is illegal, the exception leads to a process termination.

Summary Comparison

Feature Interrupt Exception
Trigger Source External hardware devices The current CPU instruction
Synchronicity Asynchronous (can happen anytime) Synchronous (reproducible)
Maskability Usually maskable (except NMI) Generally non-maskable
Typical Examples Timer, Keyboard, Network Card Page Fault, Divide-by-Zero, Syscall

Conclusion

Interrupts and exceptions constitute the "event-driven" architecture that allows a CPU to interact with the physical world and manage software errors. Mastering these mechanisms is essential for anyone venturing into kernel development or driver engineering. As you progress, you will encounter even more nuanced topics, such as interrupt nesting, interrupt priorities, and the Linux "Top Half / Bottom Half" model (utilizing softirqs, tasklets, and workqueues) designed to keep the system responsive even under heavy I/O loads.