Skip to main content
The SerenityOS kernel implements a flexible interrupt handling system that manages hardware and software interrupts across multiple architectures. The interrupt subsystem is located in Kernel/Interrupts/ and provides a unified interface for interrupt management.

Core Architecture

GenericInterruptHandler

The base class for all interrupt handlers (Kernel/Interrupts/GenericInterruptHandler.h):
Key features:
  • Abstract interface for all interrupt handlers
  • Per-CPU interrupt call counters
  • Registration and unregistration management
  • Support for shared interrupt lines

Handler Types

The kernel supports multiple handler types:
Using the appropriate handler type ensures correct interrupt routing and statistics tracking.

IRQ Handlers

IRQHandler

Standard interrupt handler for hardware devices (Kernel/Interrupts/IRQHandler.h):
Device drivers derive from IRQHandler and implement handle_irq():

Return Value Semantics

The handle_interrupt() return value indicates whether the handler processed the interrupt:
  • true: Interrupt was handled by this handler
  • false: Interrupt was not from this device (important for shared IRQs)

Enabling and Disabling IRQs

IRQs can also be temporarily disabled using InterruptDisabler:
Prolonged interrupt disabling can cause system latency and missed interrupts. Keep critical sections short.

Shared Interrupts

SharedIRQHandler

Multiple devices can share an interrupt line using SharedIRQHandler (Kernel/Interrupts/SharedIRQHandler.h):
When an interrupt occurs on a shared line:
  1. Each registered handler is invoked
  2. Each handler checks if its device triggered the interrupt
  3. Handler returns true only if it processed the interrupt
  4. The shared handler returns true if any handler processed it

PCI IRQ Handlers

PCIIRQHandler (Kernel/Interrupts/PCIIRQHandler.h) extends IRQHandler for PCI devices, handling:
  • MSI (Message Signaled Interrupts)
  • MSI-X (Extended MSI)
  • Legacy INTx interrupts

Special Interrupt Handlers

UnhandledInterruptHandler

Catches interrupts with no registered handler:

SpuriousInterruptHandler

Detects and handles spurious interrupts:

Interrupt Controllers

SerenityOS supports multiple interrupt controller architectures:

x86_64 Controllers

PIC (Programmable Interrupt Controller) (Kernel/Arch/x86_64/Interrupts/PIC.h)
  • Legacy 8259 PIC support
  • Two cascaded controllers (master/slave)
  • 15 IRQ lines total
  • Used on older systems or as fallback
APIC (Advanced Programmable Interrupt Controller) (Kernel/Arch/x86_64/Interrupts/APIC.h)
  • Modern interrupt controller
  • Supports multiple CPUs
  • Local APIC per CPU
  • I/O APIC for peripheral interrupts
IOAPIC (Kernel/Arch/x86_64/Interrupts/IOAPIC.h)
  • Routes interrupts to CPU Local APICs
  • Supports interrupt remapping
  • Programmable interrupt distribution
PIC Limitations:
  • Maximum 15 IRQs
  • No SMP support
  • Fixed priority scheme
  • Edge and level-triggered modes
APIC Advantages:
  • Up to 256 interrupt vectors
  • Per-CPU interrupt delivery
  • Advanced priority and routing
  • Better performance on SMP systems
  • Message-signaled interrupts (MSI)

ARM64 Controllers

GICv2 (Generic Interrupt Controller v2) (Kernel/Arch/aarch64/Interrupts/GICv2.h)
  • Standard ARM interrupt controller
  • Supports up to 8 CPUs
  • 1020 interrupt sources
GICv3 (Kernel/Arch/aarch64/Interrupts/GICv3.h)
  • Modern ARM interrupt controller
  • Improved scalability (supports more CPUs)
  • Interrupt routing to specific CPUs
  • LPI (Locality-specific Peripheral Interrupts)

RISC-V Controllers

PLIC (Platform-Level Interrupt Controller) (Kernel/Arch/riscv64/Interrupts/PLIC.h)
  • Standard RISC-V interrupt controller
  • Programmable priorities
  • Per-hart (hardware thread) interrupt delivery

Interrupt Flow

Interrupt Processing Sequence

  1. Hardware Event: Device asserts interrupt line
  2. Controller: Interrupt controller receives signal
  3. CPU: Controller signals CPU interrupt
  4. Handler Entry: CPU vectors to interrupt handler
  5. Handler Dispatch: Kernel identifies handler for IRQ number
  6. Device Handler: Device-specific handler processes interrupt
  7. EOI: Handler sends End-of-Interrupt to controller
  8. Return: Resume interrupted execution

End of Interrupt (EOI)

After processing an interrupt, the handler must signal completion:
Failure to send EOI prevents further interrupts from that source.

Interrupt Statistics

The kernel tracks interrupt statistics per CPU:
Statistics include:
  • Total interrupt count per IRQ
  • Per-CPU interrupt counts
  • Handler invocation counts
Access via /sys/kernel/interrupts in the filesystem.

Registration and Lifecycle

Registering an IRQ Handler

Handler Lifecycle

  1. Construction: Create handler with IRQ number
  2. Registration: Call register_interrupt_handler()
  3. Enable: Call enable_irq() to start receiving interrupts
  4. Active: Handle interrupts via handle_irq()
  5. Disable: Call disable_irq() before cleanup
  6. Unregister: Call unregister_interrupt_handler()
  7. Destruction: Destroy handler object
Always disable and unregister handlers before destruction to prevent use-after-free bugs.

Architecture-Specific Handling

While the GenericInterruptHandler interface is architecture-independent, the underlying implementation varies: x86_64:
  • Uses IDT (Interrupt Descriptor Table)
  • 256 interrupt vectors
  • Vectors 0-31: CPU exceptions
  • Vectors 32-255: Hardware interrupts
AArch64:
  • Exception vector table
  • Four exception levels (EL0-EL3)
  • IRQ and FIQ interrupt types
RISC-V:
  • Trap vector table
  • Machine and Supervisor mode interrupts
  • Interrupt delegation to S-mode

Best Practices

Handler Implementation

  1. Minimize Work: Do minimal work in interrupt context
  2. Defer Processing: Use work queues for heavy processing
  3. Return Quickly: Long handlers increase interrupt latency
  4. Check Source: Verify interrupt is from your device (for shared IRQs)
  5. Clear Source: Acknowledge interrupt at device level

Synchronization

Use spinlocks, not mutexes, for synchronization between interrupt handlers and regular code. Mutexes may sleep, which is forbidden in interrupt context.

Debugging Interrupts

Useful debugging techniques:
  • Kernel/Interrupts/GenericInterruptHandler.{h,cpp} - Base handler class
  • Kernel/Interrupts/IRQHandler.{h,cpp} - Standard IRQ handler
  • Kernel/Interrupts/SharedIRQHandler.{h,cpp} - Shared interrupt support
  • Kernel/Interrupts/InterruptDisabler.h - Interrupt disabling utility
  • Kernel/Arch/*/Interrupts/ - Architecture-specific controllers