libcortex_a9: add interrupt exit support for interrupt_handler macro #107
@ -56,19 +56,29 @@ extern "C" {
|
||||
static CORE1_RESTART: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
||||
if MPIDR.read().cpu_id() == 1{
|
||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||
let mut gic = gic::InterruptController::gic(mpcore);
|
||||
let id = gic.get_interrupt_id();
|
||||
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();
|
||||
}
|
||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||
let mut gic = gic::InterruptController::gic(mpcore);
|
||||
let id = gic.get_interrupt_id();
|
||||
match MPIDR.read().cpu_id(){
|
||||
0 => {
|
||||
if id.0 == 0 {
|
||||
println!("Interrupting core0...");
|
||||
gic.end_interrupt(id);
|
||||
return;
|
||||
}
|
||||
},
|
||||
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();
|
||||
println!("IRQ");
|
||||
@ -134,6 +144,10 @@ pub fn main_core0() {
|
||||
ddr.memtest();
|
||||
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);
|
||||
|
||||
let core1_req = unsafe { &mut CORE1_REQ.0 };
|
||||
|
@ -36,7 +36,9 @@ pub fn notify_spin_lock() {
|
||||
}
|
||||
|
||||
#[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.
|
||||
/// - `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.
|
||||
@ -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.
|
||||
///
|
||||
/// 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.
|
||||
/// Note that the interrupt handler would use the same stack as normal programs by default.
|
||||
macro_rules! interrupt_handler {
|
||||
($name:ident, $name2:ident, $stack0:ident, $stack1:ident, $body:block) => {
|
||||
#[link_section = ".text.boot"]
|
||||
@ -54,19 +55,27 @@ macro_rules! interrupt_handler {
|
||||
pub unsafe extern "C" fn $name() -> ! {
|
||||
asm!(
|
||||
// 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
|
||||
"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 r0, sp",
|
||||
"mov sp, r1",
|
||||
"push {{r0, r1}}", // 2 registers are pushed to maintain 8 byte stack alignment
|
||||
sb10q
commented
Unclear what this "stack alignment" does exactly and why it is needed. Unclear what this "stack alignment" does exactly and why it is needed.
morgan
commented
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
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)
```
sb10q
commented
Code comment needs to be expanded. Code comment needs to be expanded.
|
||||
concat!("bl ", stringify!($name2)),
|
||||
"pop {{r0, r1}}",
|
||||
"mov sp, r0",
|
||||
"ldmfd sp!, {{r0-r12, pc}}^", // caret ^ : copy SPSR to the CPSR
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn $name2() -> ! $body
|
||||
pub unsafe extern "C" fn $name2() $body
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user
Nitpicking but the other instructions are lower-case.