rust-embedded/rust-raspberrypi-OS-tutorials · error

Error handling IRQ

Error message

Error handling IRQ

What it means

In the BCM local interrupt controller, a registered handler's handle() returning Err triggers .expect("Error handling IRQ"), panicking. The library surfaces handler failures as fatal because the local IRQ cannot be considered serviced and the system state is undefined.

Source

Thrown at 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs:153

            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

  1. Read the specific Err from the failing handler's handle() and fix the underlying peripheral interaction (clear/ack the correct register).
  2. Ensure per-core device initialization completes before enabling the core's local IRQs.
  3. Make the handler robust to spurious firings (acknowledge and return Ok instead of Err).
  4. Check for races: disable the IRQ while reconfiguring the device it belongs to.

Example fix

// before
fn handle(&self) -> Result<(), &'static str> {
    Err("no pending source") // -> expect("Error handling IRQ") panic
}
// after
fn handle(&self) -> Result<(), &'static str> {
    if self.pending() { self.clear_pending(); }
    Ok(())
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure per-core device init completed before enabling its local IRQ:
if !local_timer_initialized_on(core_id) { panic!("init local timer before enabling its IRQ"); }

Prevention

When it happens

Trigger: The handler registered for a pending local IRQ (e.g. local timer) returns Err from handle() — internal state checks fail, the peripheral's pending bit cannot be cleared, or the handler's expected device state is absent when the IRQ arrives.

Common situations: Local timer handler running before the timer was initialized on that core, status-register bit layouts differing between BCM2837 and BCM2711, shared IRQs where the handler finds no source to service, and re-entrant IRQ handling corrupting handler state.

Related errors


AI-assisted analysis of rust-embedded/rust-raspberrypi-OS-tutorials@644474cc09 (2026-09-06). Data as JSON: /api/errors/078cfc91881550bc. Report an issue: GitHub.