rust-embedded/rust-raspberrypi-OS-tutorials · error
No handler registered for IRQ {}
Error message
No handler registered for IRQ {} What it means
The BCM interrupt controller's local interrupt controller iterates all pending IRQs and looks each up in its handler table; a None entry panics with 'No handler registered for IRQ'. Like the GICv2 variant, this library treats an unclaimed pending interrupt as fatal because it cannot be acknowledged and would re-fire endlessly.
Source
Thrown at 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs:150
fn enable(&self, irq: &Self::IRQNumberType) {
self.wo_registers.lock(|regs| {
let enable_bit: u32 = 1 << (irq.get());
// Writing a 1 to a bit will set the corresponding IRQ enable bit. All other IRQ enable
// bits are unaffected. So we don't need read and OR'ing here.
regs.CORE0_TIMER_INTERRUPT_CONTROL.set(enable_bit);
});
}
fn handle_pending_irqs<'irq_context>(
&'irq_context self,
_ic: &exception::asynchronous::IRQContext<'irq_context>,
) {
self.handler_table.read(|table| {
for irq_number in self.pending_irqs() {
match table[irq_number] {
None => panic!("No handler registered for IRQ {}", irq_number),
Some(descriptor) => {
// Call the IRQ handler. Panics on failure.
descriptor.handler().handle().expect("Error handling IRQ");
}
}
}
})
}
fn print_handler(&self) {
use crate::info;
info!(" Local handler:");
self.handler_table.read(|table| {
for (i, opt) in table.iter().enumerate() {
if let Some(handler) = opt {
info!(" {: >3}. {}", i, handler.name());View on GitHub (pinned to 644474cc09)
Solutions
- Register a handler for the reported IRQ number on every core that can receive it (local IC handlers are per-core).
- Disable the unwanted local IRQ in the local interrupt controller's enable registers if it should never fire.
- Verify the pending IRQ number against the BCM2711/BCM2837 datasheet — BCM IRQ numbering differs from GIC numbering.
- Initialize and register handlers identically on each core during SMP bring-up.
Example fix
// before local_ic.irq_manager.enable(per_core_irq_number); // no handler registered on this core // after local_ic.irq_manager.register_handler(per_core_irq_number, &local_timer_handler); local_ic.irq_manager.enable(per_core_irq_number);
Defensive patterns
Strategy: validation
Validate before calling
// Register the handler on every core before enabling a local IRQ:
for core in 0..NUM_CORES {
local_ic(core).irq_manager.register_handler(irq, &handler);
local_ic(core).irq_manager.enable(irq);
} Type guard
fn irq_is_registered(irq: usize, table: &[Option<IrqDescriptor>]) -> bool {
table.get(irq).is_some() && table[irq].is_some()
} Prevention
- Use BCM-specific IRQ numbering; do not reuse GIC numbers.
- Initialize and register local-IC handlers identically on all cores during SMP bring-up.
- Mask IRQs you do not handle rather than leaving them enabled.
- Consult the BCM2711/BCM2837 datasheet when mapping pending IRQ numbers to devices.
When it happens
Trigger: pending_irqs() yields an IRQ number (from the local interrupt controller's pending registers) whose handler-table slot was never populated via register_handler() — e.g. a local/per-core interrupt (like a local timer or mailbox IRQ) enabled but not claimed.
Common situations: Enabling a local timer or aux IRQ in the local IC before registering its handler, different IRQ numbering per core causing a valid handler on core 0 to be missing on core 1, or copying GIC IRQ numbers into BCM table indices.
Related errors
- Error handling IRQ
- No handler registered for IRQ {}
- Error handling IRQ
- No handler registered for IRQ {}
- Error handling IRQ
AI-assisted analysis of rust-embedded/rust-raspberrypi-OS-tutorials@644474cc09 (2026-09-06).
Data as JSON: /api/errors/6c811ce7a885a1e6.
Report an issue: GitHub.