From 2c265581c5cd34bf2a5fac0c93e7b683554d551c Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 9 Oct 2025 21:38:36 +0200 Subject: [PATCH] Add priority ceiling example --- examples/mps3-an536/Cargo.toml | 4 + ...ic-priority-ceiling-armv8r-none-eabihf.out | 23 +++ .../src/bin/gic-priority-ceiling.rs | 168 ++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 examples/mps3-an536/reference/gic-priority-ceiling-armv8r-none-eabihf.out create mode 100644 examples/mps3-an536/src/bin/gic-priority-ceiling.rs diff --git a/examples/mps3-an536/Cargo.toml b/examples/mps3-an536/Cargo.toml index a4ddf5e..9332121 100644 --- a/examples/mps3-an536/Cargo.toml +++ b/examples/mps3-an536/Cargo.toml @@ -45,3 +45,7 @@ required-features = ["gic"] [[bin]] name = "generic_timer_irq" required-features = ["gic"] + +[[bin]] +name = "gic-priority-ceiling" +required-features = ["gic"] diff --git a/examples/mps3-an536/reference/gic-priority-ceiling-armv8r-none-eabihf.out b/examples/mps3-an536/reference/gic-priority-ceiling-armv8r-none-eabihf.out new file mode 100644 index 0000000..bd00a91 --- /dev/null +++ b/examples/mps3-an536/reference/gic-priority-ceiling-armv8r-none-eabihf.out @@ -0,0 +1,23 @@ +Found PERIPHBASE 0xf0000000 +Creating GIC driver @ 0xf0000000 / 0xf0100000 +Calling git.setup(0) +Configure low-prio SGI... +Configure high-prio SGI... +gic.enable_interrupt() +Enabling interrupts... +CPSR: CPSR { N=0 Z=1 C=1 V=0 Q=0 J=0 E=0 A=0 I=1 F=1 T=0 MODE=Ok(Sys) } +CPSR: CPSR { N=0 Z=1 C=1 V=0 Q=0 J=0 E=0 A=0 I=0 F=1 T=0 MODE=Ok(Sys) } +Send lo-prio SGI +> IRQ +- IRQ Handling SGI 3 + - Low prio! + - Pre lock exit + - HIGH PRIO SHOULD RUN AFTER THIS +> IRQ +- IRQ Handling SGI 4 + - High prio! +< IRQ + - HIGH PRIO SHOULD RUN BEFORE THIS + - Post lock exit +< IRQ +IRQ test completed OK diff --git a/examples/mps3-an536/src/bin/gic-priority-ceiling.rs b/examples/mps3-an536/src/bin/gic-priority-ceiling.rs new file mode 100644 index 0000000..9ae0ed6 --- /dev/null +++ b/examples/mps3-an536/src/bin/gic-priority-ceiling.rs @@ -0,0 +1,168 @@ +//! GIC example to implement Priority Ceilings for Arm Cortex-R52 on an MPS2-AN336 + +#![no_std] +#![no_main] + +use core::ptr::NonNull; + +// pull in our start-up code +use cortex_r_rt::{entry, irq}; + +// pull in our library +use mps3_an536 as _; + +use arm_gic::{ + gicv3::{GicCpuInterface, GicV3, Group, InterruptGroup, SgiTarget, SgiTargetGroup}, + IntId, UniqueMmioPointer, +}; +use semihosting::println; + +/// Offset from PERIPHBASE for GIC Distributor +const GICD_BASE_OFFSET: usize = 0x0000_0000usize; + +/// Offset from PERIPHBASE for the first GIC Redistributor +const GICR_BASE_OFFSET: usize = 0x0010_0000usize; + +const SGI_INTID_LO: IntId = IntId::sgi(3); +const SGI_INTID_HI: IntId = IntId::sgi(4); + +// Priority for `SGI_INTID_LO` +const LOW_PRIORITY: u8 = 0x31; +// Priority for `SGI_INTID_HI` +const HIGH_PRIORITY: u8 = 0x10; + +/// The entry-point to the Rust application. +/// +/// It is called by the start-up code in `cortex-r-rt`. +#[entry] +fn main() -> ! { + // Get the GIC address by reading CBAR + let periphbase = cortex_ar::register::ImpCbar::read().periphbase(); + println!("Found PERIPHBASE {:010p}", periphbase); + let gicd_base = periphbase.wrapping_byte_add(GICD_BASE_OFFSET); + let gicr_base = periphbase.wrapping_byte_add(GICR_BASE_OFFSET); + + // Initialise the GIC. + println!( + "Creating GIC driver @ {:010p} / {:010p}", + gicd_base, gicr_base + ); + let gicd = unsafe { UniqueMmioPointer::new(NonNull::new(gicd_base.cast()).unwrap()) }; + let gicr = NonNull::new(gicr_base.cast()).unwrap(); + let mut gic = unsafe { GicV3::new(gicd, gicr, 1, false) }; + + println!("Calling git.setup(0)"); + gic.setup(0); + GicCpuInterface::set_priority_mask(0x80); + + // Configure a Software Generated Interrupt for Core 0 + println!("Configure low-prio SGI..."); + gic.set_interrupt_priority(SGI_INTID_LO, Some(0), LOW_PRIORITY) + .unwrap(); + gic.set_group(SGI_INTID_LO, Some(0), Group::Group1NS) + .unwrap(); + + println!("Configure high-prio SGI..."); + gic.set_interrupt_priority(SGI_INTID_HI, Some(0), HIGH_PRIORITY) + .unwrap(); + gic.set_group(SGI_INTID_HI, Some(0), Group::Group1NS) + .unwrap(); + + println!("gic.enable_interrupt()"); + gic.enable_interrupt(SGI_INTID_LO, Some(0), true).unwrap(); + gic.enable_interrupt(SGI_INTID_HI, Some(0), true).unwrap(); + + println!("Enabling interrupts..."); + dump_cpsr(); + unsafe { + cortex_ar::interrupt::enable(); + } + dump_cpsr(); + + // Send it + println!("Send lo-prio SGI"); + GicCpuInterface::send_sgi( + SGI_INTID_LO, + SgiTarget::List { + affinity3: 0, + affinity2: 0, + affinity1: 0, + target_list: 0b1, + }, + SgiTargetGroup::CurrentGroup1, + ) + .unwrap(); + + for _ in 0..1_000_000 { + cortex_ar::asm::nop(); + } + + println!("IRQ test completed OK"); + + semihosting::process::exit(0); +} + +fn dump_cpsr() { + let cpsr = cortex_ar::register::Cpsr::read(); + println!("CPSR: {:?}", cpsr); +} + +#[irq] +fn irq_handler() { + println!("> IRQ"); + while let Some(int_id) = GicCpuInterface::get_and_acknowledge_interrupt(InterruptGroup::Group1) + { + // let's go re-entrant + unsafe { + cortex_ar::interrupt::enable(); + } + println!("- IRQ Handling {:?}", int_id); + match int_id { + SGI_INTID_HI => high_prio(), + SGI_INTID_LO => low_prio(), + _ => unreachable!("We handle all enabled IRQs"), + } + // turn interrupts off again + cortex_ar::interrupt::disable(); + GicCpuInterface::end_interrupt(int_id, InterruptGroup::Group1); + } + println!("< IRQ"); +} + +/// High prio IRQ +fn high_prio() { + println!(" - High prio!"); +} + +/// Low prio IRQ +fn low_prio() { + println!(" - Low prio!"); + + priority_ceiling_lock(|| { + GicCpuInterface::send_sgi( + SGI_INTID_HI, + SgiTarget::List { + affinity3: 0, + affinity2: 0, + affinity1: 0, + target_list: 0b1, + }, + SgiTargetGroup::CurrentGroup1, + ) + .unwrap(); + println!(" - Pre lock exit"); + println!(" - HIGH PRIO SHOULD RUN AFTER THIS"); + }); + println!(" - HIGH PRIO SHOULD RUN BEFORE THIS"); + println!(" - Post lock exit"); +} + +fn priority_ceiling_lock(mut f: F) { + let prio = GicCpuInterface::get_priority_mask(); + // Block everything up to, and including, `HIGH_PRIORITY` + GicCpuInterface::set_priority_mask(HIGH_PRIORITY); + + f(); + + GicCpuInterface::set_priority_mask(prio); +}