1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-05-25 19:56:09 +02:00

Add newtype for interrupt ID.

This commit is contained in:
Andrew Walbran 2023-04-12 15:10:41 +01:00
parent cddf766491
commit 8cdb93cc74
2 changed files with 77 additions and 26 deletions

View File

@ -53,14 +53,58 @@ macro_rules! write_sysreg {
/// The offset in bytes from `RD_base` to `SGI_base`. /// The offset in bytes from `RD_base` to `SGI_base`.
const SGI_OFFSET: usize = 0x10000; const SGI_OFFSET: usize = 0x10000;
/// The ID of the first Software Generated Interrupt. /// An interrupt ID.
pub const SGI_START: u32 = 0; #[derive(Copy, Clone, Debug, Eq, Ord, PartialOrd, PartialEq)]
pub struct IntId(u32);
/// The ID of the first Private Peripheral Interrupt. impl IntId {
pub const PPI_START: u32 = 16; /// The ID of the first Software Generated Interrupt.
const SGI_START: u32 = 0;
/// The ID of the first Shared Peripheral Interrupt. /// The ID of the first Private Peripheral Interrupt.
pub const SPI_START: u32 = 32; const PPI_START: u32 = 16;
/// The ID of the first Shared Peripheral Interrupt.
const SPI_START: u32 = 32;
/// The first special interrupt ID.
const SPECIAL_START: u32 = 1020;
/// Returns the interrupt ID for the given Software Generated Interrupt.
pub const fn sgi(sgi: u32) -> Self {
assert!(sgi < Self::PPI_START);
Self(Self::SGI_START + sgi)
}
/// Returns the interrupt ID for the given Private Peripheral Interrupt.
pub const fn ppi(ppi: u32) -> Self {
assert!(ppi < Self::SPI_START - Self::PPI_START);
Self(Self::PPI_START + ppi)
}
/// Returns the interrupt ID for the given Shared Peripheral Interrupt.
pub const fn spi(spi: u32) -> Self {
assert!(spi < Self::SPECIAL_START);
Self(Self::SPI_START + spi)
}
/// Returns whether this interrupt ID is for a Software Generated Interrupt.
fn is_sgi(self) -> bool {
self.0 < Self::PPI_START
}
/// Returns whether this interrupt ID is private to a core, i.e. it is an
/// SGI or PPI.
fn is_private(self) -> bool {
self.0 < Self::SPI_START
}
}
impl From<IntId> for u32 {
fn from(intid: IntId) -> Self {
intid.0
}
}
bitflags! { bitflags! {
#[repr(transparent)] #[repr(transparent)]
@ -408,9 +452,9 @@ impl GicV3 {
} }
/// Enables or disables the interrupt with the given ID. /// Enables or disables the interrupt with the given ID.
pub fn enable_interrupt(&mut self, intid: u32, enable: bool) { pub fn enable_interrupt(&mut self, intid: IntId, enable: bool) {
let index = (intid / 32) as usize; let index = (intid.0 / 32) as usize;
let bit = 1 << (intid % 32); let bit = 1 << (intid.0 % 32);
// Safe because we know that `self.gicd` is a valid and unique pointer // Safe because we know that `self.gicd` is a valid and unique pointer
// to the registers of a GIC distributor interface, and `self.sgi` to // to the registers of a GIC distributor interface, and `self.sgi` to
@ -418,12 +462,12 @@ impl GicV3 {
unsafe { unsafe {
if enable { if enable {
addr_of_mut!((*self.gicd).isenabler[index]).write_volatile(bit); addr_of_mut!((*self.gicd).isenabler[index]).write_volatile(bit);
if intid < SPI_START { if intid.is_private() {
addr_of_mut!((*self.sgi).isenabler0).write_volatile(bit); addr_of_mut!((*self.sgi).isenabler0).write_volatile(bit);
} }
} else { } else {
addr_of_mut!((*self.gicd).icenabler[index]).write_volatile(bit); addr_of_mut!((*self.gicd).icenabler[index]).write_volatile(bit);
if intid < SPI_START { if intid.is_private() {
addr_of_mut!((*self.sgi).icenabler0).write_volatile(bit); addr_of_mut!((*self.sgi).icenabler0).write_volatile(bit);
} }
} }
@ -470,33 +514,33 @@ impl GicV3 {
/// ///
/// Note that lower numbers correspond to higher priorities; i.e. 0 is the /// Note that lower numbers correspond to higher priorities; i.e. 0 is the
/// highest priority, and 255 is the lowest. /// highest priority, and 255 is the lowest.
pub fn set_interrupt_priority(&mut self, intid: u32, priority: u8) { pub fn set_interrupt_priority(&mut self, intid: IntId, priority: u8) {
// Safe because we know that `self.gicd` is a valid and unique pointer // Safe because we know that `self.gicd` is a valid and unique pointer
// to the registers of a GIC distributor interface, and `self.sgi` to // to the registers of a GIC distributor interface, and `self.sgi` to
// the SGI and PPI registers of a GIC redistributor interface. // the SGI and PPI registers of a GIC redistributor interface.
unsafe { unsafe {
// Affinity routing is enabled, so use the GICR for SGIs and PPIs. // Affinity routing is enabled, so use the GICR for SGIs and PPIs.
if intid < SPI_START { if intid.is_private() {
addr_of_mut!((*self.sgi).ipriorityr[intid as usize]) addr_of_mut!((*self.sgi).ipriorityr[intid.0 as usize])
.write_volatile(priority); .write_volatile(priority);
} else { } else {
addr_of_mut!((*self.gicd).ipriorityr[intid as usize]) addr_of_mut!((*self.gicd).ipriorityr[intid.0 as usize])
.write_volatile(priority); .write_volatile(priority);
} }
} }
} }
/// Configures the trigger type for the interrupt with the given ID. /// Configures the trigger type for the interrupt with the given ID.
pub fn set_trigger(&mut self, intid: u32, trigger: Trigger) { pub fn set_trigger(&mut self, intid: IntId, trigger: Trigger) {
let index = (intid / 16) as usize; let index = (intid.0 / 16) as usize;
let bit = 1 << (((intid % 16) * 2) + 1); let bit = 1 << (((intid.0 % 16) * 2) + 1);
// Safe because we know that `self.gicd` is a valid and unique pointer // Safe because we know that `self.gicd` is a valid and unique pointer
// to the registers of a GIC distributor interface, and `self.sgi` to // to the registers of a GIC distributor interface, and `self.sgi` to
// the SGI and PPI registers of a GIC redistributor interface. // the SGI and PPI registers of a GIC redistributor interface.
unsafe { unsafe {
// Affinity routing is enabled, so use the GICR for SGIs and PPIs. // Affinity routing is enabled, so use the GICR for SGIs and PPIs.
let register = if intid < SPI_START { let register = if intid.is_private() {
addr_of_mut!((*self.sgi).icfgr[index]) addr_of_mut!((*self.sgi).icfgr[index])
} else { } else {
addr_of_mut!((*self.gicd).icfgr[index]) addr_of_mut!((*self.gicd).icfgr[index])
@ -511,19 +555,26 @@ impl GicV3 {
/// Gets the ID of the highest priority signalled interrupt, and /// Gets the ID of the highest priority signalled interrupt, and
/// acknowledges it. /// acknowledges it.
pub fn get_and_acknowledge_interrupt() -> u32 { ///
/// Returns `None` if there is no pending interrupt of sufficient priority.
pub fn get_and_acknowledge_interrupt() -> Option<IntId> {
// Safe because reading this system register doesn't access memory in // Safe because reading this system register doesn't access memory in
// any way. // any way.
(unsafe { read_sysreg!(icc_iar1_el1) }) as u32 let intid = unsafe { read_sysreg!(icc_iar1_el1) } as u32;
if intid == IntId::SPECIAL_START {
None
} else {
Some(IntId(intid))
}
} }
/// Informs the interrupt controller that the CPU has completed processing /// Informs the interrupt controller that the CPU has completed processing
/// the given interrupt. This drops the interrupt priority and deactivates /// the given interrupt. This drops the interrupt priority and deactivates
/// the interrupt. /// the interrupt.
pub fn end_interrupt(intid: u32) { pub fn end_interrupt(intid: IntId) {
// Safe because writing to this system register doesn't access memory in // Safe because writing to this system register doesn't access memory in
// any way. // any way.
unsafe { write_sysreg!(icc_eoir1_el1, intid.into()) } unsafe { write_sysreg!(icc_eoir1_el1, intid.0.into()) }
} }
} }

View File

@ -23,7 +23,7 @@ mod pl011;
// ANCHOR_END: top // ANCHOR_END: top
mod pl031; mod pl031;
use crate::gicv3::{irq_enable, wfi, GicV3, Trigger, SPI_START}; use crate::gicv3::{irq_enable, wfi, GicV3, IntId, Trigger};
use crate::pl031::Rtc; use crate::pl031::Rtc;
use chrono::{TimeZone, Utc}; use chrono::{TimeZone, Utc};
use core::hint::spin_loop; use core::hint::spin_loop;
@ -43,8 +43,8 @@ const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
/// Base address of the PL031 RTC. /// Base address of the PL031 RTC.
const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _; const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;
/// The IRQ used by the PL031 RTC: SPI 2. /// The IRQ used by the PL031 RTC.
const PL031_IRQ: u32 = SPI_START + 2; const PL031_IRQ: IntId = IntId::spi(2);
// ANCHOR: main // ANCHOR: main
#[no_mangle] #[no_mangle]