diff --git a/src/gicv3.rs b/src/gicv3.rs index eadc7a8..2da944b 100644 --- a/src/gicv3.rs +++ b/src/gicv3.rs @@ -9,7 +9,7 @@ pub mod registers; use self::registers::{Gicd, GicdCtlr, Gicr, GicrCtlr, Sgi, Waker}; use crate::sysreg::{ read_icc_iar1_el1, write_icc_ctlr_el1, write_icc_eoir1_el1, write_icc_igrpen0_el1, - write_icc_igrpen1_el1, write_icc_pmr_el1, write_icc_sgi1r_el1, write_icc_sre_el1, + write_icc_igrpen1_el1, write_icc_pmr_el1, write_icc_sgi1r_el1, write_icc_sre_el1, IccSre, }; use crate::{IntId, Trigger}; use core::{hint::spin_loop, ptr::NonNull}; @@ -106,7 +106,7 @@ impl GicV3<'_> { /// for group 0 and group 1 interrupts separately. pub fn init_cpu(&mut self, cpu: usize) { // Enable system register access. - write_icc_sre_el1(0x01); + write_icc_sre_el1(IccSre::SRE); // Ignore error in case core is already awake. let _ = self.redistributor_mark_core_awake(cpu); diff --git a/src/sysreg.rs b/src/sysreg.rs index 0ded40e..a74c28c 100644 --- a/src/sysreg.rs +++ b/src/sysreg.rs @@ -14,12 +14,33 @@ mod aarch64; #[macro_use] mod aarch32; +use bitflags::bitflags; + read_sysreg32!(icc_iar1_el1, 0, c12, c12, 0, read_icc_iar1_el1); write_sysreg32!(icc_ctlr_el1, 0, c12, c12, 4, write_icc_ctlr_el1); write_sysreg32!(icc_eoir1_el1, 0, c12, c12, 1, write_icc_eoir1_el1); write_sysreg32!(icc_igrpen0_el1, 0, c12, c12, 6, write_icc_igrpen0_el1); write_sysreg32!(icc_igrpen1_el1, 0, c12, c12, 7, write_icc_igrpen1_el1); +write_sysreg32!(icc_igrpen1_el3, 6, c12, c12, 7, write_icc_igrpen1_el3); write_sysreg32!(icc_pmr_el1, 0, c4, c6, 0, write_icc_pmr_el1); write_sysreg64!(icc_sgi1r_el1, 0, c12, write_icc_sgi1r_el1); -write_sysreg32!(icc_sre_el1, 0, c12, c12, 5, write_icc_sre_el1); +write_sysreg32!(icc_sre_el1, 0, c12, c12, 5, write_icc_sre_el1, IccSre); + +bitflags! { + /// Type for the `icc_sre_el2` and `icc_sre_el3` registers. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct IccSre: u32 { + /// System register enable. + /// + /// Enables access to the GIC CPU interface system registers. + const SRE = 1 << 0; + /// Disable FIQ bypass. + const DFB = 1 << 1; + /// Disable IRQ bypass. + const DIB = 1 << 2; + // TODO: Should this be on a different type? Not all registers have it. + /// Enables lower EL access to ICC_SRE_ELn. + const ENABLE = 1 << 3; + } +} diff --git a/src/sysreg/aarch32.rs b/src/sysreg/aarch32.rs index c1f32a3..b679089 100644 --- a/src/sysreg/aarch32.rs +++ b/src/sysreg/aarch32.rs @@ -6,7 +6,7 @@ /// /// This should only be used for system registers which are indeed safe to read. macro_rules! read_sysreg32 { - ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2: literal, $function_name:ident) => { + ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2:literal, $function_name:ident) => { #[inline] #[doc = "Autogenerated function to read the 32-bit "] #[doc = stringify!($sysreg)] @@ -38,7 +38,7 @@ macro_rules! read_sysreg32 { /// /// This should only be used for system registers which are indeed safe to write. macro_rules! write_sysreg32 { - ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2: literal, $function_name:ident) => { + ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2:literal, $function_name:ident) => { #[inline] #[doc = "Autogenerated function to write the 32-bit "] #[doc = stringify!($sysreg)] @@ -62,6 +62,30 @@ macro_rules! write_sysreg32 { } } }; + ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2:literal, $function_name:ident, $type:ty) => { + #[inline] + #[doc = "Autogenerated function to write the 32-bit "] + #[doc = stringify!($sysreg)] + #[doc = " system register"] + pub fn $function_name(value: $type) { + // SAFETY: The caller of the macro guarantees that this system register is safe to + // write. + unsafe { + core::arch::asm!( + concat!( + "mcr p15, ", + stringify!($opc1), ",", + "{value}, ", + stringify!($crm), ",", + stringify!($crn), ",", + stringify!($opc2) + ), + options(nostack), + value = in(reg) value.bits(), + ); + } + } + }; } /// Generates a safe public function named `$function_name` to write to the 64-bit system register diff --git a/src/sysreg/aarch64.rs b/src/sysreg/aarch64.rs index 6660747..d1eed47 100644 --- a/src/sysreg/aarch64.rs +++ b/src/sysreg/aarch64.rs @@ -6,7 +6,7 @@ /// /// This should only be used for system registers which are indeed safe to read. macro_rules! read_sysreg32 { - ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2: literal, $function_name:ident) => { + ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2:literal, $function_name:ident) => { #[inline] #[doc = "Autogenerated function to read the 32-bit "] #[doc = stringify!($sysreg)] @@ -31,7 +31,7 @@ macro_rules! read_sysreg32 { /// /// This should only be used for system registers which are indeed safe to write. macro_rules! write_sysreg32 { - ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2: literal, $function_name:ident) => { + ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2:literal, $function_name:ident) => { #[inline] #[doc = "Autogenerated function to write the 32-bit "] #[doc = stringify!($sysreg)] @@ -48,6 +48,23 @@ macro_rules! write_sysreg32 { } } }; + ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2:literal, $function_name:ident, $type:ty) => { + #[inline] + #[doc = "Autogenerated function to write the 32-bit "] + #[doc = stringify!($sysreg)] + #[doc = " system register"] + pub fn $function_name(value: $type) { + // SAFETY: The caller of the macro guarantees that this system register is safe to + // write. + unsafe { + core::arch::asm!( + concat!("msr ", stringify!($sysreg), ", {value}"), + options(nostack), + value = in(reg) value.bits() as u64, + ); + } + } + }; } /// Generates a safe public function named `$function_name` to write to the 64-bit system register diff --git a/src/sysreg/fake.rs b/src/sysreg/fake.rs index dc05fa2..ab62047 100644 --- a/src/sysreg/fake.rs +++ b/src/sysreg/fake.rs @@ -4,6 +4,7 @@ //! Fake implementations of system register getters and setters for unit tests. +use super::IccSre; use std::sync::Mutex; /// Values of fake system registers. @@ -19,7 +20,7 @@ pub struct SystemRegisters { pub icc_igrpen1_el1: u32, pub icc_pmr_el1: u32, pub icc_sgi1r_el1: u64, - pub icc_sre_el1: u32, + pub icc_sre_el1: IccSre, } impl SystemRegisters { @@ -32,7 +33,7 @@ impl SystemRegisters { icc_igrpen1_el1: 0, icc_pmr_el1: 0, icc_sgi1r_el1: 0, - icc_sre_el1: 0, + icc_sre_el1: IccSre::empty(), } } } @@ -54,6 +55,11 @@ macro_rules! write_sysreg32 { crate::sysreg::fake::SYSREGS.lock().unwrap().$sysreg = value; } }; + ($sysreg:ident, $opc1:literal, $crm:ident, $crn:ident, $opc2: literal, $function_name:ident, $type:ty) => { + pub fn $function_name(value: $type) { + crate::sysreg::fake::SYSREGS.lock().unwrap().$sysreg = value; + } + }; } /// Generates a public function named `$function_name` to write to the fake system register