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
Owner

Summary

  • add interrupt exit support for interrupt_handler macro

    • interrupt_handler macro now perserve registers r0-r12, LR before entering the rust $name2 function
    • after exiting the $name2 function, registers r0-r12, PC, SP and CPSR will be restored and return to the status before interrupt
    • allow rust $name2 function to return
  • add interrupt return test to experiment for core0

    • tested on kasli_soc
  • Compilation check

    • nix build <variant> for szl, coraz7-experiments, zc706-experiments and kasli_soc-experiments. All compiled without warning

New experiment log

Zynq experiments
[     8.054689s]  INFO(experiments): Boot mode: SdCard
[     8.059468s]  INFO(experiments): Setup clock sources...
[     8.064675s] DEBUG(libboard_zynq::clocks::source): Set ARM_PLL to 1600000000 Hz
[     2.186158s] DEBUG(libboard_zynq::clocks::source): Set IO_PLL to 1000000000 Hz
[     2.195873s]  INFO(experiments): PLLs set up
[     2.200180s]  INFO(experiments): CPU Clocks: 799999992/399999996/266666664/133333332
[     0.000000s] DEBUG(libboard_zynq::clocks::source): Set DDR_PLL to 1066666666 Hz
[     0.007309s] DEBUG(libboard_zynq::ddr): DDR 3x/2x clocks: 533333328/355555552
[     0.014491s] DEBUG(libboard_zynq::ddr): DDR DCI clock: 10062892 Hz (divisors=2*53)
[     0.024395s]  INFO(libboard_zynq::ddr): memtest phase 0 (status: Normal)
511 MB Ok
[     1.207101s]  INFO(libboard_zynq::ddr): memtest phase 1 (status: Normal)
511 MB Ok
[     2.757427s]  INFO(libboard_zynq::ddr): memtest phase 2 (status: Normal)
511 MB Ok
[     4.308291s]  INFO(libboard_zynq::ddr): memtest phase 3 (status: Normal)
511 MB Ok
[     5.859095s]  INFO(experiments): Send software interrupt to core0
Interrupting core0...
[     5.867080s]  INFO(experiments): Core0 returned from interrupt
Hello from core1!
Hello from core1!
0 -> 0
Hello from core1!
1 -> 1
Hello from core1!
2 -> 4
Hello from core1!
3 -> 9
Hello from core1!
4 -> 16
Hello from core1!
5 -> 25
Hello from core1!
6 -> 36
Hello from core1!
7 -> 49
Hello from core1!
8 -> 64
Hello from core1!
9 -> 81
[     5.896819s] DEBUG(libboard_zynq::eth): Eth TX clock for 125000000: 999999990 / 1 / 8 = 124999998
Eth on
[     6.943991s]  INFO(experiments): time:      6.943989s, rx: 0k/s, tx: 0k/s
[     7.950983s]  INFO(experiments): time:      7.950982s, rx: 0k/s, tx: 0k/s
[     8.957981s]  INFO(experiments): time:      8.957979s, rx: 0k/s, tx: 0k/s
[     9.942073s]  INFO(libboard_zynq::eth): eth: got Link { speed: S1000, duplex: Full }
[     9.949866s] DEBUG(libboard_zynq::eth): Eth TX clock for 125000000: 999999990 / 1 / 8 = 124999998
[     9.964979s]  INFO(experiments): time:      9.964977s, rx: 0k/s, tx: 0k/s
[    10.971978s]  INFO(experiments): time:     10.971977s, rx: 0k/s, tx: 0k/s
[    11.978975s]  INFO(experiments): time:     11.978974s, rx: 0k/s, tx: 0k/s
...
## Summary - add interrupt exit support for interrupt_handler macro - interrupt_handler macro now perserve registers r0-r12, LR before entering the rust `$name2` function - after exiting the `$name2` function, registers r0-r12, PC, SP and CPSR will be restored and return to the status before interrupt - allow rust `$name2` function to return - add interrupt return test to experiment for core0 - tested on kasli_soc - Compilation check - `nix build <variant>` for szl, coraz7-experiments, zc706-experiments and kasli_soc-experiments. All compiled without warning ## New experiment log ```bash Zynq experiments [ 8.054689s] INFO(experiments): Boot mode: SdCard [ 8.059468s] INFO(experiments): Setup clock sources... [ 8.064675s] DEBUG(libboard_zynq::clocks::source): Set ARM_PLL to 1600000000 Hz [ 2.186158s] DEBUG(libboard_zynq::clocks::source): Set IO_PLL to 1000000000 Hz [ 2.195873s] INFO(experiments): PLLs set up [ 2.200180s] INFO(experiments): CPU Clocks: 799999992/399999996/266666664/133333332 [ 0.000000s] DEBUG(libboard_zynq::clocks::source): Set DDR_PLL to 1066666666 Hz [ 0.007309s] DEBUG(libboard_zynq::ddr): DDR 3x/2x clocks: 533333328/355555552 [ 0.014491s] DEBUG(libboard_zynq::ddr): DDR DCI clock: 10062892 Hz (divisors=2*53) [ 0.024395s] INFO(libboard_zynq::ddr): memtest phase 0 (status: Normal) 511 MB Ok [ 1.207101s] INFO(libboard_zynq::ddr): memtest phase 1 (status: Normal) 511 MB Ok [ 2.757427s] INFO(libboard_zynq::ddr): memtest phase 2 (status: Normal) 511 MB Ok [ 4.308291s] INFO(libboard_zynq::ddr): memtest phase 3 (status: Normal) 511 MB Ok [ 5.859095s] INFO(experiments): Send software interrupt to core0 Interrupting core0... [ 5.867080s] INFO(experiments): Core0 returned from interrupt Hello from core1! Hello from core1! 0 -> 0 Hello from core1! 1 -> 1 Hello from core1! 2 -> 4 Hello from core1! 3 -> 9 Hello from core1! 4 -> 16 Hello from core1! 5 -> 25 Hello from core1! 6 -> 36 Hello from core1! 7 -> 49 Hello from core1! 8 -> 64 Hello from core1! 9 -> 81 [ 5.896819s] DEBUG(libboard_zynq::eth): Eth TX clock for 125000000: 999999990 / 1 / 8 = 124999998 Eth on [ 6.943991s] INFO(experiments): time: 6.943989s, rx: 0k/s, tx: 0k/s [ 7.950983s] INFO(experiments): time: 7.950982s, rx: 0k/s, tx: 0k/s [ 8.957981s] INFO(experiments): time: 8.957979s, rx: 0k/s, tx: 0k/s [ 9.942073s] INFO(libboard_zynq::eth): eth: got Link { speed: S1000, duplex: Full } [ 9.949866s] DEBUG(libboard_zynq::eth): Eth TX clock for 125000000: 999999990 / 1 / 8 = 124999998 [ 9.964979s] INFO(experiments): time: 9.964977s, rx: 0k/s, tx: 0k/s [ 10.971978s] INFO(experiments): time: 10.971977s, rx: 0k/s, tx: 0k/s [ 11.978975s] INFO(experiments): time: 11.978974s, rx: 0k/s, tx: 0k/s ... ```
morgan added 2 commits 2023-11-14 15:02:46 +08:00
interrupt_handler: preserve registers and load them after $name2 fn
interrupt_handler: allow $name2 fn to return
sb10q reviewed 2023-11-19 11:27:25 +08:00
@ -56,1 +57,4 @@
// setup SP, depending on CPU 0 or 1
// and preserve registers
"SUB lr, lr, #4",
"STMFD sp!, {{r0-r12, lr}}",
Owner

Nitpicking but the other instructions are lower-case.

Nitpicking but the other instructions are lower-case.
morgan marked this conversation as resolved
sb10q reviewed 2023-11-19 11:28:02 +08:00
@ -62,2 +66,4 @@
concat!("movtne r1, :upper16:", stringify!($stack1)),
"mov r0, sp",
"mov sp, r1",
"push {{r0, r1}}", // for stack alignment
Owner

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

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

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) ```
Owner

Code comment needs to be expanded.

Code comment needs to be expanded.
Owner

Generally looks good! Is this the recommended way to handle interrupts according to the ARM docs?

Generally looks good! Is this the recommended way to handle interrupts according to the ARM docs?
morgan added 1 commit 2023-11-20 12:16:18 +08:00
Author
Owner

Generally looks good! Is this the recommended way to handle interrupts according to the ARM docs?

Yes I followed this "Exit from an exception handler" from arm when making this patch

> Generally looks good! Is this the recommended way to handle interrupts according to the ARM docs? Yes I followed this "[Exit from an exception handler](https://developer.arm.com/documentation/den0013/d/Exception-Handling/Exception-handling/Exit-from-an-exception-handler)" from arm when making this patch
morgan added 1 commit 2023-11-20 12:29:37 +08:00
sb10q merged commit 24c804e6f0 into master 2023-11-20 12:30:29 +08:00
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: M-Labs/zynq-rs#107
No description provided.