Kernel/Interrupts/ and provides a unified interface for interrupt management.
Core Architecture
GenericInterruptHandler
The base class for all interrupt handlers (Kernel/Interrupts/GenericInterruptHandler.h):
- 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):
IRQHandler and implement handle_irq():
Return Value Semantics
Thehandle_interrupt() return value indicates whether the handler processed the interrupt:
true: Interrupt was handled by this handlerfalse: Interrupt was not from this device (important for shared IRQs)
Enabling and Disabling IRQs
InterruptDisabler:
Shared Interrupts
SharedIRQHandler
Multiple devices can share an interrupt line usingSharedIRQHandler (Kernel/Interrupts/SharedIRQHandler.h):
- Each registered handler is invoked
- Each handler checks if its device triggered the interrupt
- Handler returns true only if it processed the interrupt
- 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
Kernel/Arch/x86_64/Interrupts/APIC.h)
- Modern interrupt controller
- Supports multiple CPUs
- Local APIC per CPU
- I/O APIC for peripheral interrupts
Kernel/Arch/x86_64/Interrupts/IOAPIC.h)
- Routes interrupts to CPU Local APICs
- Supports interrupt remapping
- Programmable interrupt distribution
APIC vs PIC
APIC vs PIC
PIC Limitations:
- Maximum 15 IRQs
- No SMP support
- Fixed priority scheme
- Edge and level-triggered modes
- 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
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
- Hardware Event: Device asserts interrupt line
- Controller: Interrupt controller receives signal
- CPU: Controller signals CPU interrupt
- Handler Entry: CPU vectors to interrupt handler
- Handler Dispatch: Kernel identifies handler for IRQ number
- Device Handler: Device-specific handler processes interrupt
- EOI: Handler sends End-of-Interrupt to controller
- Return: Resume interrupted execution
End of Interrupt (EOI)
After processing an interrupt, the handler must signal completion:Interrupt Statistics
The kernel tracks interrupt statistics per CPU:- Total interrupt count per IRQ
- Per-CPU interrupt counts
- Handler invocation counts
/sys/kernel/interrupts in the filesystem.
Registration and Lifecycle
Registering an IRQ Handler
Handler Lifecycle
- Construction: Create handler with IRQ number
- Registration: Call
register_interrupt_handler() - Enable: Call
enable_irq()to start receiving interrupts - Active: Handle interrupts via
handle_irq() - Disable: Call
disable_irq()before cleanup - Unregister: Call
unregister_interrupt_handler() - Destruction: Destroy handler object
Architecture-Specific Handling
While theGenericInterruptHandler 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
- Exception vector table
- Four exception levels (EL0-EL3)
- IRQ and FIQ interrupt types
- Trap vector table
- Machine and Supervisor mode interrupts
- Interrupt delegation to S-mode
Best Practices
Handler Implementation
- Minimize Work: Do minimal work in interrupt context
- Defer Processing: Use work queues for heavy processing
- Return Quickly: Long handlers increase interrupt latency
- Check Source: Verify interrupt is from your device (for shared IRQs)
- 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:Related Files
Kernel/Interrupts/GenericInterruptHandler.{h,cpp}- Base handler classKernel/Interrupts/IRQHandler.{h,cpp}- Standard IRQ handlerKernel/Interrupts/SharedIRQHandler.{h,cpp}- Shared interrupt supportKernel/Interrupts/InterruptDisabler.h- Interrupt disabling utilityKernel/Arch/*/Interrupts/- Architecture-specific controllers
