Skip to content

Commit

Permalink
Panic if the user has bound an incompatible interrupt handler
Browse files Browse the repository at this point in the history
  • Loading branch information
bugadani committed Sep 16, 2024
1 parent 8b4c369 commit 5133906
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 6 deletions.
17 changes: 16 additions & 1 deletion esp-hal/src/gpio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ use crate::{
private::{self, Sealed},
Cpu,
InterruptConfigurable,
DEFAULT_INTERRUPT_HANDLER,
};

pub mod interconnect;
Expand Down Expand Up @@ -982,6 +983,7 @@ fn raise_gpio_interrupt_priority(core: Cpu, priority: Priority) {
#[allow(clippy::declare_interior_mutable_const)]
const NO_PRIO: AtomicUsize = AtomicUsize::new(Priority::None as usize);
static MAX_PRIO: [AtomicUsize; Cpu::COUNT] = [NO_PRIO; Cpu::COUNT];
static INTERNAL_HANDLER: extern "C" fn() = gpio_interrupt_handler;

#[cold]
fn do_raise_priority_level(max: &AtomicUsize, mut current_prio: usize, priority: Priority) {
Expand All @@ -994,12 +996,25 @@ fn raise_gpio_interrupt_priority(core: Cpu, priority: Priority) {
Ordering::Relaxed,
) {
Ok(_) => {
let current_handler =
crate::interrupt::bound_handler(crate::peripherals::Interrupt::GPIO);

if let Some(handler) = current_handler {
if handler != DEFAULT_INTERRUPT_HANDLER.handler() {
assert!(
handler == INTERNAL_HANDLER,
"The GPIO interrupt handler is already bound."
);
}
}

unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::GPIO,
gpio_interrupt_handler,
INTERNAL_HANDLER,
);
}

crate::interrupt::enable(crate::peripherals::Interrupt::GPIO, priority)
.unwrap();
}
Expand Down
16 changes: 14 additions & 2 deletions esp-hal/src/interrupt/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,12 +427,24 @@ mod vectored {
/// # Safety
///
/// This will replace any previously bound interrupt handler
pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn() -> ()) {
pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn()) {
let ptr = &peripherals::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler as *const _
as *mut unsafe extern "C" fn() -> ();
as *mut unsafe extern "C" fn();
ptr.write_volatile(handler);
}

/// Returns the currently bound interrupt handler.
pub fn bound_handler(interrupt: Interrupt) -> Option<unsafe extern "C" fn()> {
unsafe {
let addr = peripherals::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler;
if addr as usize == 0 {
return None;
}

Some(addr)
}
}

#[no_mangle]
#[ram]
unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) {
Expand Down
16 changes: 14 additions & 2 deletions esp-hal/src/interrupt/xtensa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,12 +419,24 @@ mod vectored {
/// # Safety
///
/// This will replace any previously bound interrupt handler
pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn() -> ()) {
pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn()) {
let ptr = &peripherals::__INTERRUPTS[interrupt as usize]._handler as *const _
as *mut unsafe extern "C" fn() -> ();
as *mut unsafe extern "C" fn();
ptr.write_volatile(handler);
}

/// Returns the currently bound interrupt handler.
pub fn bound_handler(interrupt: Interrupt) -> Option<unsafe extern "C" fn()> {
unsafe {
let addr = peripherals::__INTERRUPTS[interrupt as usize]._handler;
if addr as usize == 0 {
return None;
}

Some(addr)
}
}

fn interrupt_level_to_cpu_interrupt(
level: Priority,
is_edge: bool,
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ mod peripheral_macros {
$(
paste::paste!{
/// Binds an interrupt handler to the corresponding interrupt for this peripheral.
pub fn [<bind_ $interrupt:lower _interrupt >](&mut self, handler: unsafe extern "C" fn() -> ()) {
pub fn [<bind_ $interrupt:lower _interrupt >](&mut self, handler: unsafe extern "C" fn()) {
unsafe { $crate::interrupt::bind_interrupt($crate::peripherals::Interrupt::$interrupt, handler); }
}
}
Expand Down

0 comments on commit 5133906

Please sign in to comment.