libcortex_a9: add interrupt exit support for interrupt_handler macro #107

Merged
sb10q merged 4 commits from morgan/zynq-rs:interrupt into master 2023-11-20 12:30:29 +08:00
2 changed files with 40 additions and 17 deletions

View File

@ -56,19 +56,29 @@ extern "C" {
static CORE1_RESTART: AtomicBool = AtomicBool::new(false); static CORE1_RESTART: AtomicBool = AtomicBool::new(false);
interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, { interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
if MPIDR.read().cpu_id() == 1{ let mpcore = mpcore::RegisterBlock::mpcore();
let mpcore = mpcore::RegisterBlock::mpcore(); let mut gic = gic::InterruptController::gic(mpcore);
let mut gic = gic::InterruptController::gic(mpcore); let id = gic.get_interrupt_id();
let id = gic.get_interrupt_id(); match MPIDR.read().cpu_id(){
if id.0 == 0 { 0 => {
gic.end_interrupt(id); if id.0 == 0 {
asm::exit_irq(); println!("Interrupting core0...");
SP.write(&mut __stack1_start as *mut _ as u32); gic.end_interrupt(id);
asm::enable_irq(); return;
CORE1_RESTART.store(false, Ordering::Relaxed); }
notify_spin_lock(); },
main_core1(); 1 => {
} if id.0 == 0 {
gic.end_interrupt(id);
asm::exit_irq();
SP.write(&mut __stack1_start as *mut _ as u32);
asm::enable_irq();
CORE1_RESTART.store(false, Ordering::Relaxed);
notify_spin_lock();
main_core1();
}
},
_ => {}
} }
stdio::drop_uart(); stdio::drop_uart();
println!("IRQ"); println!("IRQ");
@ -134,6 +144,10 @@ pub fn main_core0() {
ddr.memtest(); ddr.memtest();
ram::init_alloc_ddr(&mut ddr); ram::init_alloc_ddr(&mut ddr);
info!("Send software interrupt to core0");
interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core0.into());
info!("Core0 returned from interrupt");
boot::Core1::start(false); boot::Core1::start(false);
let core1_req = unsafe { &mut CORE1_REQ.0 }; let core1_req = unsafe { &mut CORE1_REQ.0 };

View File

@ -36,7 +36,9 @@ pub fn notify_spin_lock() {
} }
#[macro_export] #[macro_export]
/// Interrupt handler, which setup the stack and jump to actual interrupt handler. /// Interrupt handler, which setup the stack and preserve registers before jumping to actual interrupt handler.
/// Registers r0-r12, PC, SP and CPSR are restored after the actual handler.
///
/// - `name` is the name of the interrupt, should be the same as the one defined in vector table. /// - `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. /// - `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. /// - `stack0` is the stack for the interrupt handler when called from core0.
@ -44,8 +46,7 @@ pub fn notify_spin_lock() {
/// - `body` is the body of the actual interrupt handler, should be a normal unsafe rust function /// - `body` is the body of the actual interrupt handler, should be a normal unsafe rust function
/// body. /// body.
/// ///
/// Note that the interrupt handler would use the same stack as normal programs by default, so /// Note that the interrupt handler would use the same stack as normal programs by default.
/// interrupt handlers should not return to normal program or it may corrupt the stack.
macro_rules! interrupt_handler { macro_rules! interrupt_handler {
($name:ident, $name2:ident, $stack0:ident, $stack1:ident, $body:block) => { ($name:ident, $name2:ident, $stack0:ident, $stack1:ident, $body:block) => {
#[link_section = ".text.boot"] #[link_section = ".text.boot"]
@ -54,19 +55,27 @@ macro_rules! interrupt_handler {
pub unsafe extern "C" fn $name() -> ! { pub unsafe extern "C" fn $name() -> ! {
asm!( asm!(
// setup SP, depending on CPU 0 or 1 // setup SP, depending on CPU 0 or 1
// and preserve registers
"sub lr, lr, #4",
"stmfd sp!, {{r0-r12, lr}}",
morgan marked this conversation as resolved Outdated
Outdated
Review

Nitpicking but the other instructions are lower-case.

Nitpicking but the other instructions are lower-case.
"mrc p15, #0, r0, c0, c0, #5", "mrc p15, #0, r0, c0, c0, #5",
concat!("movw r1, :lower16:", stringify!($stack0)), concat!("movw r1, :lower16:", stringify!($stack0)),
concat!("movt r1, :upper16:", stringify!($stack0)), concat!("movt r1, :upper16:", stringify!($stack0)),
"tst r0, #3", "tst r0, #3",
concat!("movwne r1, :lower16:", stringify!($stack1)), concat!("movwne r1, :lower16:", stringify!($stack1)),
concat!("movtne r1, :upper16:", stringify!($stack1)), concat!("movtne r1, :upper16:", stringify!($stack1)),
"mov r0, sp",
"mov sp, r1", "mov sp, r1",
"push {{r0, r1}}", // 2 registers are pushed to maintain 8 byte stack alignment
Outdated
Review

Unclear what this "stack alignment" does exactly and why it is needed.

Unclear what this "stack alignment" does exactly and why it is needed.

The arm doc state the stack need to be 8 byte align and the easiest way to do it is to push/pop in multiple of 2 registers.

When push {{r0}} is used with a timer interrupt, the wrpll satellite will result in the following error.
Which I suspect the compiler assume the stack pointer is 8 byte alignment and mess up the dellocation.

...
[     0.000067s]  INFO(satman): ARTIQ satellite manager starting...
[     0.006019s]  INFO(satman): gateware ident satellite
[     0.016080s]  INFO(libboard_zynq::i2c): PCA9548 detected
[     0.458796s]  INFO(libboard_artiq::wrpll): Main Si549 started
[     0.564532s]  INFO(satman): Switching SYS clocks...
[     0.619395s]  INFO(satman): SYS CLK switched successfully
[     0.921209s]  INFO(libboard_artiq::wrpll): Helper Si549 started
[     0.927196s]  INFO(satman): uplink is up, switching to recovered clock
[     0.933935s]  INFO(libboard_artiq::wrpll): WRPLL started
[     0.939230s]  INFO(libboard_artiq::wrpll): warming up si549...
[    20.945048s]  INFO(libboard_artiq::wrpll): tracking gtx frequency...
[    21.101694s]  INFO(libboard_artiq::wrpll): starting helper PLL...
[    21.468593s]  INFO(libboard_artiq::wrpll): ...locked
[    21.473541s]  INFO(libboard_artiq::wrpll): starting main PLL interrupt...
[    21.715075s]  INFO(satman): TSC loaded from uplink
[    21.724998s]  INFO(satman): rank: 1
[    21.728472s]  INFO(satman): routing table: RoutingTable { 0: 0; 1: 1 0; 2: 2 0; 3: 3 0; 4: 4 0; }
[    24.900000s]  INFO(ksupport::irq): current count = 50000001 <---- interrupt prints
[    29.880000s]  INFO(ksupport::irq): current count = 60000001
[    34.860000s]  INFO(ksupport::irq): current count = 70000001
[    36.263504s]  INFO(satman): uplink is down, switching to local oscillator clock
[    36.272139s] ERROR@�): received packet of an unknown type
[    37.454274s]  INFO@�): uplink is up, switching to recovered clock
[    37.461085s]  INFO(libboard_artiq::wrpll): WRPLL started
[    37.466302s]  INFO(libboard_artiq::wrpll): warming up si549...
[    57.472198s]  INFO(libboard_artiq::wrpll): tracking gtx frequency...
[    57.628844s]  INFO(libboard_artiq::wrpll): starting helper PLL...
[    57.995403s]  INFO(libboard_artiq::wrpll): ...locked
[    58.000352s]  INFO(libboard_artiq::wrpll): starting main PLL interrupt...
[    58.296202s]  INFO@�): TSC loaded from uplink
[    58.306209s]  INFO@�): rank: 1
[    58.309682s]  INFO@�): routing table: RoutingTable { 0: 0; 1: 1 0; 2: 2 0; 3: 3 0; 4: 4 0; }
[    59.760001s]  INFO(ksupport::irq): current count = 120000001
[    64.740001s]  INFO(ksupport::irq): current count = 130000001
[    66.578307s]  INFO@�): uplink is down, switching to local oscillator clock
Core 0 panic at /build/cargo-vendor-dir/linked_list_allocator-0.8.11/src/hole.rs:293:9: invalid deallocation (probably a double free)


The [arm doc](https://developer.arm.com/documentation/ddi0419/c/System-Level-Architecture/System-Level-Programmers--Model/ARMv6-M-exception-model/Stack-alignment-on-exception-entry?lang=en) state the stack need to be 8 byte align and the easiest way to do it is to push/pop in multiple of 2 registers. When `push {{r0}}` is used with a timer interrupt, the wrpll satellite will result in the following error. Which I suspect the compiler assume the stack pointer is 8 byte alignment and mess up the dellocation. ```bash ... [ 0.000067s] INFO(satman): ARTIQ satellite manager starting... [ 0.006019s] INFO(satman): gateware ident satellite [ 0.016080s] INFO(libboard_zynq::i2c): PCA9548 detected [ 0.458796s] INFO(libboard_artiq::wrpll): Main Si549 started [ 0.564532s] INFO(satman): Switching SYS clocks... [ 0.619395s] INFO(satman): SYS CLK switched successfully [ 0.921209s] INFO(libboard_artiq::wrpll): Helper Si549 started [ 0.927196s] INFO(satman): uplink is up, switching to recovered clock [ 0.933935s] INFO(libboard_artiq::wrpll): WRPLL started [ 0.939230s] INFO(libboard_artiq::wrpll): warming up si549... [ 20.945048s] INFO(libboard_artiq::wrpll): tracking gtx frequency... [ 21.101694s] INFO(libboard_artiq::wrpll): starting helper PLL... [ 21.468593s] INFO(libboard_artiq::wrpll): ...locked [ 21.473541s] INFO(libboard_artiq::wrpll): starting main PLL interrupt... [ 21.715075s] INFO(satman): TSC loaded from uplink [ 21.724998s] INFO(satman): rank: 1 [ 21.728472s] INFO(satman): routing table: RoutingTable { 0: 0; 1: 1 0; 2: 2 0; 3: 3 0; 4: 4 0; } [ 24.900000s] INFO(ksupport::irq): current count = 50000001 <---- interrupt prints [ 29.880000s] INFO(ksupport::irq): current count = 60000001 [ 34.860000s] INFO(ksupport::irq): current count = 70000001 [ 36.263504s] INFO(satman): uplink is down, switching to local oscillator clock [ 36.272139s] ERROR@�): received packet of an unknown type [ 37.454274s] INFO@�): uplink is up, switching to recovered clock [ 37.461085s] INFO(libboard_artiq::wrpll): WRPLL started [ 37.466302s] INFO(libboard_artiq::wrpll): warming up si549... [ 57.472198s] INFO(libboard_artiq::wrpll): tracking gtx frequency... [ 57.628844s] INFO(libboard_artiq::wrpll): starting helper PLL... [ 57.995403s] INFO(libboard_artiq::wrpll): ...locked [ 58.000352s] INFO(libboard_artiq::wrpll): starting main PLL interrupt... [ 58.296202s] INFO@�): TSC loaded from uplink [ 58.306209s] INFO@�): rank: 1 [ 58.309682s] INFO@�): routing table: RoutingTable { 0: 0; 1: 1 0; 2: 2 0; 3: 3 0; 4: 4 0; } [ 59.760001s] INFO(ksupport::irq): current count = 120000001 [ 64.740001s] INFO(ksupport::irq): current count = 130000001 [ 66.578307s] INFO@�): uplink is down, switching to local oscillator clock Core 0 panic at /build/cargo-vendor-dir/linked_list_allocator-0.8.11/src/hole.rs:293:9: invalid deallocation (probably a double free) ```
Outdated
Review

Code comment needs to be expanded.

Code comment needs to be expanded.
concat!("bl ", stringify!($name2)), concat!("bl ", stringify!($name2)),
"pop {{r0, r1}}",
"mov sp, r0",
"ldmfd sp!, {{r0-r12, pc}}^", // caret ^ : copy SPSR to the CPSR
options(noreturn) options(noreturn)
); );
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn $name2() -> ! $body pub unsafe extern "C" fn $name2() $body
}; };
} }