diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 76219ca..e44ccb1 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -1,6 +1,8 @@ #![no_std] #![no_main] #![feature(const_in_array_repeat_expressions)] +#![feature(naked_functions)] +#![feature(asm)] extern crate alloc; @@ -33,7 +35,7 @@ use libcortex_a9::{ sync_channel, regs::{MPIDR, SP}, spin_lock_yield, notify_spin_lock, - asm + asm, interrupt_handler }; use libregister::{RegisterR, RegisterW}; use libsupport_zynq::{ @@ -53,9 +55,7 @@ extern "C" { static CORE1_RESTART: AtomicBool = AtomicBool::new(false); -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn IRQ() { +interrupt_handler!(IRQ, irq, __stack0_start, __stack1_start, { if MPIDR.read().cpu_id() == 1{ let mpcore = mpcore::RegisterBlock::mpcore(); let mut gic = gic::InterruptController::gic(mpcore); @@ -73,7 +73,7 @@ pub unsafe extern "C" fn IRQ() { stdio::drop_uart(); println!("IRQ"); loop {} -} +}); pub fn restart_core1() { let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore()); diff --git a/libcortex_a9/src/lib.rs b/libcortex_a9/src/lib.rs index ad9b81d..aa847a3 100644 --- a/libcortex_a9/src/lib.rs +++ b/libcortex_a9/src/lib.rs @@ -6,17 +6,17 @@ extern crate alloc; pub mod asm; -pub mod regs; pub mod cache; +mod fpu; +pub mod l2c; pub mod mmu; pub mod mutex; -pub mod sync_channel; +pub mod regs; pub mod semaphore; -pub mod l2c; +pub mod sync_channel; mod uncached; -mod fpu; -pub use uncached::UncachedSlice; pub use fpu::enable_fpu; +pub use uncached::UncachedSlice; global_asm!(include_str!("exceptions.s")); @@ -35,3 +35,38 @@ pub fn notify_spin_lock() { } } +#[macro_export] +/// Interrupt handler, which setup the stack and jump to actual interrupt handler. +/// - `name` is the name of the interrupt, should be the same as the one defined in vector table. +/// - `name2` is the name for the actual handler, should be different from name. +/// - `stack0` is the stack for the interrupt handler when called from core0. +/// - `stack1` is the stack for the interrupt handler when called from core1. +/// - `body` is the body of the actual interrupt handler, should be a normal unsafe rust function +/// body. +/// +/// Note that the interrupt handler would use the same stack as normal programs by default, so +/// interrupt handlers should not return to normal program or it may corrupt the stack. +macro_rules! interrupt_handler { + ($name:ident, $name2:ident, $stack0:ident, $stack1:ident, $body:block) => { + #[link_section = ".text.boot"] + #[no_mangle] + #[naked] + pub unsafe extern "C" fn $name() -> ! { + asm!( + // setup SP, depending on CPU 0 or 1 + "mrc p15, #0, r0, c0, c0, #5", + concat!("movw r1, :lower16:", stringify!($stack0)), + concat!("movt r1, :upper16:", stringify!($stack0)), + "tst r0, #3", + concat!("movwne r1, :lower16:", stringify!($stack1)), + concat!("movtne r1, :upper16:", stringify!($stack1)), + "mov sp, r1", + concat!("bl ", stringify!($name2)), + options(noreturn) + ); + } + + #[no_mangle] + pub unsafe extern "C" fn $name2() -> ! $body + }; +} diff --git a/libsupport_zynq/src/abort.rs b/libsupport_zynq/src/abort.rs index 57d63d5..7fd996c 100644 --- a/libsupport_zynq/src/abort.rs +++ b/libsupport_zynq/src/abort.rs @@ -1,63 +1,49 @@ use libregister::RegisterR; -use libcortex_a9::regs::{DFSR, MPIDR}; +use libcortex_a9::{regs::{DFSR, MPIDR}, interrupt_handler}; use libboard_zynq::{println, stdio}; -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn UndefinedInstruction() { +interrupt_handler!(UndefinedInstruction, undefined_instruction, __stack0_start, __stack1_start, { stdio::drop_uart(); println!("UndefinedInstruction"); loop {} -} +}); -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn SoftwareInterrupt() { +interrupt_handler!(SoftwareInterrupt, software_interrupt, __stack0_start, __stack1_start, { stdio::drop_uart(); println!("SoftwareInterrupt"); loop {} -} +}); -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn PrefetchAbort() { +interrupt_handler!(PrefetchAbort, prefetch_abort, __stack0_start, __stack1_start, { stdio::drop_uart(); println!("PrefetchAbort"); loop {} -} +}); -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn DataAbort() { +interrupt_handler!(DataAbort, data_abort, __stack0_start, __stack1_start, { stdio::drop_uart(); println!("DataAbort on core {}", MPIDR.read().cpu_id()); println!("DFSR: {:03X}", DFSR.read()); loop {} -} +}); -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn ReservedException() { +interrupt_handler!(ReservedException, reserved_exception, __stack0_start, __stack1_start, { stdio::drop_uart(); println!("ReservedException"); loop {} -} +}); -#[link_section = ".text.boot"] -#[no_mangle] #[cfg(feature = "dummy_irq_handler")] -pub unsafe extern "C" fn IRQ() { +interrupt_handler!(IRQ, irq, __stack0_start, __stack1_start, { stdio::drop_uart(); println!("IRQ"); loop {} -} +}); -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn FIQ() { +interrupt_handler!(FIQ, fiq, __stack0_start, __stack1_start, { stdio::drop_uart(); println!("FIQ"); loop {} -} +}); diff --git a/libsupport_zynq/src/boot.rs b/libsupport_zynq/src/boot.rs index 57371aa..1cc5eef 100644 --- a/libsupport_zynq/src/boot.rs +++ b/libsupport_zynq/src/boot.rs @@ -4,7 +4,7 @@ use libregister::{ VolatileCell, RegisterR, RegisterW, RegisterRW, }; -use libcortex_a9::{asm, l2c, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock, enable_fpu}; +use libcortex_a9::{asm, l2c, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock, enable_fpu, interrupt_handler}; use libboard_zynq::{slcr, mpcore}; extern "C" { @@ -18,9 +18,7 @@ extern "C" { static mut CORE1_ENABLED: VolatileCell = VolatileCell::new(false); -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn Reset() -> ! { +interrupt_handler!(Reset, reset_irq, __stack0_start, __stack1_start, { match MPIDR.read().cpu_id() { 0 => { SP.write(&mut __stack0_start as *mut _ as u32); @@ -35,7 +33,7 @@ pub unsafe extern "C" fn Reset() -> ! { } _ => unreachable!(), } -} +}); #[inline(never)] unsafe extern "C" fn boot_core0() -> ! { diff --git a/libsupport_zynq/src/lib.rs b/libsupport_zynq/src/lib.rs index 6b360d6..b84e7d7 100644 --- a/libsupport_zynq/src/lib.rs +++ b/libsupport_zynq/src/lib.rs @@ -2,6 +2,8 @@ #![feature(alloc_error_handler)] #![feature(panic_info_message)] +#![feature(naked_functions)] +#![feature(asm)] pub extern crate alloc; pub extern crate compiler_builtins; @@ -11,3 +13,4 @@ mod abort; #[cfg(feature = "panic_handler")] mod panic; pub mod ram; +