diff --git a/Cargo.toml b/Cargo.toml index 5917e3c..95098f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ exclude = [ [dependencies] tock-registers = { version = "0.9.0", default-features = false } # Use it as interface-only library. +paste = { version = "1.0" } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 1a43ef9..b442dc7 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,3 @@ [toolchain] -targets = ["aarch64-unknown-none-softfloat"] +channel = "nightly" +targets = ["aarch64-unknown-none"] diff --git a/src/asm.rs b/src/asm.rs index 8e0749d..bfa9ef8 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -8,8 +8,11 @@ //! Wrappers around ARMv8-A instructions. +pub mod at; pub mod barrier; +pub mod cache; pub mod random; +pub mod tlb; /// The classic no-op #[inline(always)] diff --git a/src/asm/at.rs b/src/asm/at.rs new file mode 100644 index 0000000..d6a6433 --- /dev/null +++ b/src/asm/at.rs @@ -0,0 +1,48 @@ +use crate::registers::*; + +mod sealed { + pub trait At { + fn at(&self, va: u64); + } +} + +macro_rules! at { + ($A:ident, $T: ident) => { + pub struct $T; + pub const $A: $T = $T {}; + + impl sealed::At for $T { + #[inline(always)] + fn at(&self, va: u64) { + match () { + #[cfg(target_arch = "aarch64")] + () => unsafe { + core::arch::asm!(concat!("at ", stringify!($A), ", {0}"), in(reg) va, options(nomem, nostack)) + }, + + #[cfg(not(target_arch = "aarch64"))] + () => unimplemented!(), + } + } + } + }; +} + +at!(S1E1R, S1e1r); +at!(S1E2R, S1e2r); + +#[inline(always)] +pub fn at(_arg: impl sealed::At, va: u64) { + _arg.at(va); +} + +#[inline(always)] +pub fn translate(_arg: impl sealed::At, va: u64) -> Option { + _arg.at(va); + let par = PAR_EL1.get(); + if PAR_EL1::F.read(par) == PAR_EL1::F::TranslationAborted.value { + None + } else { + Some(PAR_EL1::PA.read(par) << 12) + } +} diff --git a/src/asm/barrier.rs b/src/asm/barrier.rs index c3e9373..9691677 100644 --- a/src/asm/barrier.rs +++ b/src/asm/barrier.rs @@ -9,27 +9,30 @@ mod sealed { pub trait Dmb { - fn __dmb(&self); + fn dmb(&self); } pub trait Dsb { - fn __dsb(&self); + fn dsb(&self); } pub trait Isb { - fn __isb(&self); + fn isb(&self); } } macro_rules! dmb_dsb { - ($A:ident) => { - impl sealed::Dmb for $A { + ($A:ident, $T: ident) => { + pub struct $T; + pub const $A: $T = $T {}; + + impl sealed::Dmb for $T { #[inline(always)] - fn __dmb(&self) { + fn dmb(&self) { match () { #[cfg(target_arch = "aarch64")] () => unsafe { - core::arch::asm!(concat!("DMB ", stringify!($A)), options(nostack)) + core::arch::asm!(concat!("dmb ", stringify!($A)), options(nostack)) }, #[cfg(not(target_arch = "aarch64"))] @@ -37,13 +40,13 @@ macro_rules! dmb_dsb { } } } - impl sealed::Dsb for $A { + impl sealed::Dsb for $T { #[inline(always)] - fn __dsb(&self) { + fn dsb(&self) { match () { #[cfg(target_arch = "aarch64")] () => unsafe { - core::arch::asm!(concat!("DSB ", stringify!($A)), options(nostack)) + core::arch::asm!(concat!("dsb ", stringify!($A)), options(nostack)) }, #[cfg(not(target_arch = "aarch64"))] @@ -54,38 +57,67 @@ macro_rules! dmb_dsb { }; } -pub struct SY; -pub struct ST; -pub struct LD; -pub struct ISH; -pub struct ISHST; -pub struct ISHLD; -pub struct NSH; -pub struct NSHST; -pub struct NSHLD; -pub struct OSH; -pub struct OSHST; -pub struct OSHLD; - -dmb_dsb!(SY); -dmb_dsb!(ST); -dmb_dsb!(LD); -dmb_dsb!(ISH); -dmb_dsb!(ISHST); -dmb_dsb!(ISHLD); -dmb_dsb!(NSH); -dmb_dsb!(NSHST); -dmb_dsb!(NSHLD); -dmb_dsb!(OSH); -dmb_dsb!(OSHST); -dmb_dsb!(OSHLD); - -impl sealed::Isb for SY { +dmb_dsb!(SY, Sy); +dmb_dsb!(ST, St); +dmb_dsb!(LD, Ld); +dmb_dsb!(ISH, Ish); +dmb_dsb!(ISHST, Ishst); +dmb_dsb!(ISHLD, Ishld); +dmb_dsb!(NSH, Nsh); +dmb_dsb!(NSHST, Nshst); +dmb_dsb!(NSHLD, Nshld); +dmb_dsb!(OSH, Osh); +dmb_dsb!(OSHST, Oshst); +dmb_dsb!(OSHLD, Oshld); + +impl sealed::Isb for Sy { + #[inline(always)] + fn isb(&self) { + match () { + #[cfg(target_arch = "aarch64")] + () => unsafe { core::arch::asm!("isb sy", options(nostack)) }, + + #[cfg(not(target_arch = "aarch64"))] + () => unimplemented!(), + } + } +} + +pub struct None; +pub const NONE: None = None {}; + +impl sealed::Dsb for None { + #[inline(always)] + fn dsb(&self) { + match () { + #[cfg(target_arch = "aarch64")] + () => unsafe { core::arch::asm!("dsb", options(nostack)) }, + + #[cfg(not(target_arch = "aarch64"))] + () => unimplemented!(), + } + } +} + +impl sealed::Dmb for None { + #[inline(always)] + fn dmb(&self) { + match () { + #[cfg(target_arch = "aarch64")] + () => unsafe { core::arch::asm!("dmb", options(nostack)) }, + + #[cfg(not(target_arch = "aarch64"))] + () => unimplemented!(), + } + } +} + +impl sealed::Isb for None { #[inline(always)] - fn __isb(&self) { + fn isb(&self) { match () { #[cfg(target_arch = "aarch64")] - () => unsafe { core::arch::asm!("ISB SY", options(nostack)) }, + () => unsafe { core::arch::asm!("isb", options(nostack)) }, #[cfg(not(target_arch = "aarch64"))] () => unimplemented!(), @@ -93,29 +125,17 @@ impl sealed::Isb for SY { } } -/// Data Memory Barrier. #[inline(always)] -pub fn dmb(arg: A) -where - A: sealed::Dmb, -{ - arg.__dmb() +pub fn isb(_arg: impl sealed::Isb) { + _arg.isb() } -/// Data Synchronization Barrier. #[inline(always)] -pub fn dsb(arg: A) -where - A: sealed::Dsb, -{ - arg.__dsb() +pub fn dmb(_arg: impl sealed::Dmb) { + _arg.dmb() } -/// Instruction Synchronization Barrier. #[inline(always)] -pub fn isb(arg: A) -where - A: sealed::Isb, -{ - arg.__isb() +pub fn dsb(_arg: impl sealed::Dsb) { + _arg.dsb() } diff --git a/src/asm/cache.rs b/src/asm/cache.rs new file mode 100644 index 0000000..698750f --- /dev/null +++ b/src/asm/cache.rs @@ -0,0 +1,71 @@ +mod sealed { + + pub trait Ic { + fn ic(&self); + } + + pub trait Dc { + fn dc(&self, addr: u64); + } +} + +macro_rules! ic { + ($A:ident, $T: ident) => { + pub struct $T; + pub const $A: $T = $T {}; + + impl sealed::Ic for $T { + #[inline(always)] + fn ic(&self) { + match () { + #[cfg(target_arch = "aarch64")] + () => unsafe { + core::arch::asm!(concat!("ic ", stringify!($A)), options(nostack)) + }, + + #[cfg(not(target_arch = "aarch64"))] + () => unimplemented!(), + } + } + } + }; +} + +macro_rules! dc { + ($A: ident, $T: ident) => { + pub struct $T; + pub const $A: $T = $T{}; + impl sealed::Dc for $T { + #[inline(always)] + fn dc(&self, addr:u64){ + match() { + #[cfg(target_arch = "aarch64")] + () => unsafe { + core::arch::asm!(concat!("dc ",stringify!($A), ",{}"), in(reg) addr, options(nostack)) + }, + #[cfg(not(target_arch = "aarch64"))] + () => unimplemented!(), + } + } + } + } +} + +ic!(IALLU, Iallu); +ic!(IALLUIS, Ialluis); +dc!(CVAC, Cvac); +dc!(IVAC, Ivac); +dc!(CIVAC, Civac); +dc!(CISW, Cisw); +dc!(ISW, Isw); +dc!(CSW, Csw); + +#[inline(always)] +pub fn ic(_arg: impl sealed::Ic) { + _arg.ic(); +} + +#[inline(always)] +pub fn dc(_arg: impl sealed::Dc, addr: u64) { + _arg.dc(addr); +} diff --git a/src/asm/tlb.rs b/src/asm/tlb.rs new file mode 100644 index 0000000..8e19cb0 --- /dev/null +++ b/src/asm/tlb.rs @@ -0,0 +1,34 @@ +mod sealed { + pub trait Tlbi { + fn invalidate(&self); + } +} + +macro_rules! tlbi { + ($A: ident) => { + pub struct $A; + impl sealed::Tlbi for $A { + #[inline(always)] + fn invalidate(&self) { + match () { + #[cfg(target_arch = "aarch64")] + () => unsafe { + core::arch::asm!(concat!("TLBI ", stringify!($A)), options(nostack)) + }, + + #[cfg(not(target_arch = "aarch64"))] + () => unimplemented!(), + } + } + } + }; +} + +tlbi!(VMALLE1IS); +tlbi!(ALLE2IS); +tlbi!(ALLE3IS); + +#[inline(always)] +pub fn tlb_inv(_arg: impl sealed::Tlbi) { + _arg.invalidate(); +} diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 index 0000000..8e91d8c --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,100 @@ +use super::asm::barrier::{dsb, isb, NSH, SY}; +use crate::{ + asm::cache::{dc, ic, CISW, CIVAC, CSW, CVAC, IALLU, ISW, IVAC}, + irq::IRQ, + mmu::{MMRegion, MMSegment}, + registers::{Readable, Writeable, CCSIDR_EL1, CLIDR_EL1, CSSELR_EL1}, +}; + +pub struct ICache {} +pub struct DCache {} + +pub const ICACHE: ICache = ICache {}; +pub const DCACHE: DCache = DCache {}; + +pub enum FlushMode { + INV, + CLEAN, + INVCLEAN, +} + +pub enum AddressMode { + WAYSET, + VIRTUAL, +} + +impl DCache { + fn get_flush_func(&self, flush_mode: FlushMode, address_mode: AddressMode) -> impl Fn(u64) { + match address_mode { + AddressMode::WAYSET => match flush_mode { + FlushMode::INV => move |addr: u64| dc(ISW, addr), + FlushMode::CLEAN => move |addr: u64| dc(CSW, addr), + FlushMode::INVCLEAN => move |addr: u64| dc(CISW, addr), + }, + AddressMode::VIRTUAL => match flush_mode { + FlushMode::INV => move |addr: u64| dc(IVAC, addr), + FlushMode::CLEAN => move |addr: u64| dc(CVAC, addr), + FlushMode::INVCLEAN => move |addr: u64| dc(CIVAC, addr), + }, + } + } + + #[inline(always)] + pub fn flush(&self, addr: u64, mode: FlushMode) { + self.get_flush_func(mode, AddressMode::VIRTUAL)(addr); + dsb(SY); + isb(SY); + } + + pub fn flush_region(&self, virt: MMSegment, mode: FlushMode) { + MMRegion::new(virt, CCSIDR_EL1.read(CCSIDR_EL1::LineSize) + 4) + .into_iter() + .for_each(self.get_flush_func(mode, AddressMode::VIRTUAL)); + dsb(SY); + isb(SY); + } + + #[inline(always)] + pub fn flush_all(&self, mode: FlushMode) { + dsb(SY); + let loc = CLIDR_EL1.read(CLIDR_EL1::LoC) * 2; + let clidr = CLIDR_EL1.get(); + let _flush = self.get_flush_func(mode, AddressMode::WAYSET); + let mut irq = IRQ::new(); + + if loc != 0 { + for level in (0..loc).step_by(2) { + if (clidr >> (level + level >> 1)) & 0b111 < 2 { + continue; + } + + irq.save_and_disable(); + CSSELR_EL1.set(level); + isb(SY); + let ls = CCSIDR_EL1.read(CCSIDR_EL1::LineSize) + 4; // Notice that linesize needs taken special care of since CCSIDR_EL1 + // only offers log2(Words of Cache) instead of granularity of bytes + let m = CCSIDR_EL1.read(CCSIDR_EL1::AssociativityWithoutCCIDX); + let n = CCSIDR_EL1.read(CCSIDR_EL1::NumSetsWithoutCCIDX); + let k = m.leading_zeros(); + + irq.restore_and_enable(); + + (0..m + 1) + .flat_map(move |i| (0..n + 1).map(move |j| (i << k) | level | (j << ls))) + .for_each(&_flush); + } + } + + CSSELR_EL1.set(0); + dsb(SY); + isb(SY); + } +} + +impl ICache { + pub fn flush_all(&self) { + ic(IALLU); + dsb(NSH); + isb(SY); + } +} diff --git a/src/exception.rs b/src/exception.rs new file mode 100644 index 0000000..5384e3e --- /dev/null +++ b/src/exception.rs @@ -0,0 +1,17 @@ +#[derive(Copy, Clone)] +pub enum ExceptionReason { + HVC64 = 0b010110, + DataAbortLowerEl = 0b100100, + DataAbortCurrentEl = 0b100101, + Unimplemented = 0xff, +} + +impl From for ExceptionReason { + fn from(value: u64) -> Self { + match value { + x if x == Self::DataAbortLowerEl as u64 => Self::DataAbortLowerEl, + x if x == Self::DataAbortCurrentEl as u64 => Self::DataAbortCurrentEl, + _ => Self::Unimplemented, + } + } +} diff --git a/src/gic.rs b/src/gic.rs new file mode 100644 index 0000000..f01cccf --- /dev/null +++ b/src/gic.rs @@ -0,0 +1,21 @@ +pub mod v2; +pub mod v3; + +pub enum IRQState { + Inactive, + Pending, + Active, + PendingActive, +} + +impl From for IRQState { + fn from(value: u64) -> Self { + match value { + 0 => IRQState::Inactive, + 1 => IRQState::Pending, + 2 => IRQState::Active, + 3 => IRQState::PendingActive, + _ => panic!("illegal irq state input"), + } + } +} diff --git a/src/gic/v2.rs b/src/gic/v2.rs new file mode 100644 index 0000000..35f6e9a --- /dev/null +++ b/src/gic/v2.rs @@ -0,0 +1,206 @@ +mod registers; +use paste::paste; +pub use registers::*; +use tock_registers::{ + interfaces::{ReadWriteable, Readable, Writeable}, + registers::*, + *, +}; + +pub const GICC_CTLR_EN_BIT: usize = 0x1; +pub const GICC_CTLR_EOIMODENS_BIT: usize = 1 << 9; +pub const GIC_SGIS_NUM: usize = 16; +pub const GIC_INTS_MAX: usize = 1024; +pub const GIC_PRIVINT_NUM: usize = GIC_SGIS_NUM + GIC_PPIS_NUM; +pub const GIC_SPI_MAX: usize = 1024 - GIC_PRIVINT_NUM; +pub const GIC_PRIO_BITS: usize = 8; +pub const GIC_TARGET_BITS: usize = 8; +pub const GIC_TARGETS_MAX: usize = GIC_TARGET_BITS; +pub const GIC_CONFIG_BITS: usize = 2; + +const GICD_CTLR_EN_BIT: usize = 0x1; +const GIC_PPIS_NUM: usize = 16; +const GICH_HCR_LRENPIE_BIT: usize = 1 << 2; +const GIC_INT_REGS_NUM: usize = GIC_INTS_MAX / 32; +const GIC_PRIO_REGS_NUM: usize = GIC_INTS_MAX * 8 / 32; +const GIC_TARGET_REGS_NUM: usize = GIC_INTS_MAX * 8 / 32; +const GIC_CONFIG_REGS_NUM: usize = GIC_INTS_MAX * 2 / 32; +const GIC_SEC_REGS_NUM: usize = GIC_INTS_MAX * 2 / 32; + +pub const GIC_SGI_REGS_NUM: usize = GIC_SGIS_NUM * 8 / 32; +pub const GIC_LIST_REGS_NUM: usize = 64; +pub const GICD_TYPER_CPUNUM_OFF: usize = 5; +pub const GICD_TYPER_CPUNUM_MSK: usize = 0b11111; + +register_structs! { + #[allow(non_snake_case)] + #[repr(C)] + pub GicDistributorInner { + (0x0000 => pub CTLR: ReadWrite), + (0x0004 => pub TYPER: ReadOnly), + (0x0008 => pub IIDR: ReadOnly), + (0x000c => reserve0), + (0x0080 => pub IGROUPR: [ReadWrite; GIC_INT_REGS_NUM]), + (0x0100 => pub ISENABLER: [ReadWrite; GIC_INT_REGS_NUM]), + (0x0180 => pub ICENABLER: [ReadWrite; GIC_INT_REGS_NUM]), + (0x0200 => pub ISPENDR: [ReadWrite; GIC_INT_REGS_NUM]), + (0x0280 => pub ICPENDR: [ReadWrite; GIC_INT_REGS_NUM]), + (0x0300 => pub ISACTIVER: [ReadWrite; GIC_INT_REGS_NUM]), + (0x0380 => pub ICACTIVER: [ReadWrite; GIC_INT_REGS_NUM]), + (0x0400 => pub IPRIORITYR: [ReadWrite; GIC_PRIO_REGS_NUM]), + (0x0800 => pub ITARGETSR: [ReadWrite; GIC_TARGET_REGS_NUM]), + (0x0c00 => pub ICFGR: [ReadWrite; GIC_CONFIG_REGS_NUM]), + (0x0d00 => reserve1), + (0x0e00 => pub NSACR: [ReadWrite; GIC_SEC_REGS_NUM]), + (0x0f00 => pub SGIR: WriteOnly), + (0x0f04 => reserve2), + (0x0f10 => pub CPENDSGIR: [ReadWrite; GIC_SGI_REGS_NUM]), + (0x0f20 => pub SPENDSGIR: [ReadWrite; GIC_SGI_REGS_NUM]), + (0x0f30 => _reserved_3), + (0x1000 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + #[repr(C)] + pub GicCpuInterfaceInner { + (0x0000 => CTLR: ReadWrite), // CPU Interface Control Register + (0x0004 => PMR: ReadWrite), // Interrupt Priority Mask Register + (0x0008 => BPR: ReadWrite), // Binary Point Register + (0x000c => IAR: ReadOnly), // Interrupt Acknowledge Register + (0x0010 => EOIR: WriteOnly), // End of Interrupt Register + (0x0014 => RPR: ReadOnly), // Running Priority Register + (0x0018 => HPPIR: ReadOnly), // Highest Priority Pending Interrupt Register + (0x001c => ABPR: ReadWrite), // Aliased Binary Point Register + (0x0020 => AIAR: ReadOnly), // Aliased Interrupt Acknowledge Register + (0x0024 => AEOIR: WriteOnly), // Aliased End of Interrupt Register + (0x0028 => AHPPIR: ReadOnly), // Aliased Highest Priority Pending Interrupt Register + (0x002c => reserved_0), + (0x00d0 => APR: [ReadWrite; 4]), // Active Priorities Register + (0x00e0 => NSAPR: [ReadWrite; 4]), // Non-secure Active Priorities Register + (0x00f0 => reserved_1), + (0x00fc => IIDR: ReadOnly), // CPU Interface Identification Register + (0x0100 => reserved_2), + (0x1000 => DIR: WriteOnly), // Deactivate Interrupt Register + (0x1004 => reserved_3), + (0x2000 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + #[repr(C)] + pub GicHypervisorInterfaceInner { + (0x0000 => HCR: ReadWrite), + (0x0004 => VTR: ReadOnly), + (0x0008 => VMCR: ReadWrite), + (0x000c => reserve0), + (0x0010 => MISR: ReadOnly), + (0x0014 => reserve1), + (0x0020 => EISR: [ReadOnly; GIC_LIST_REGS_NUM / 32]), + (0x0028 => reserve2), + (0x0030 => ELRSR: [ReadOnly; GIC_LIST_REGS_NUM / 32]), + (0x0038 => reserve3), + (0x00f0 => APR: ReadWrite), + (0x00f4 => reserve4), + (0x0100 => LR: [ReadWrite; GIC_LIST_REGS_NUM]), + (0x0200 => reserve5), + (0x1000 => @END), + } +} + +unsafe impl Sync for GicDistributorInner {} +unsafe impl Sync for GicCpuInterfaceInner {} +unsafe impl Sync for GicHypervisorInterfaceInner {} + +macro_rules! bit_imp { + ($method: ident, $field: ident, $width: expr) => { + pub fn $method(&mut self, id: u32, pos: u32) { + let field_num = 32 / $width; + let reg_id = id / field_num; + let field_id = id & (field_num - 1); + self.$field[reg_id as usize] + .set(self.$field[reg_id as usize].get() | (1 << pos) << (field_id * $width)); + } + paste! { + pub fn [<$method _val>](&mut self, id: u32, val: u32){ + let field_num = 32 / $width; + let reg_id = id / field_num; + let field_id = id & (field_num - 1); + self.$field[reg_id as usize] + .set(self.$field[reg_id as usize].get() | (val << (field_id * $width))); + } + } + paste! { + pub fn [](&mut self, gid: u32, value: u32){ + self.$field[gid as usize].set(value); + } + } + }; +} + +macro_rules! field_imp { + ($method: ident, $field: ident, $width: expr, $interface: ident) => { + pub fn $method( + &mut self, + id: u32, + field: tock_registers::fields::FieldValue, + ) { + let field_num = 32 / $width; + let reg_id = id / field_num; + let field_id = id & (field_num - 1); + let mask = (1 << $width) - 1; + self.$field[reg_id as usize].set( + (self.$field[reg_id as usize].get() & (!(mask << (field_id * $width)))) + | (field.value << (field_id * $width)), + ); + } + }; +} + +impl GicDistributorInner { + bit_imp!(set_pend, ISPENDR, 1); + bit_imp!(clear_pend, ICPENDR, 1); + bit_imp!(activate, ISACTIVER, 1); + bit_imp!(deactivate, ICACTIVER, 1); + bit_imp!(set_priority, IPRIORITYR, 8); + bit_imp!(enable_intr, ISENABLER, 1); + bit_imp!(disable_intr, ICENABLER, 1); + + field_imp!(set_nsacr, NSACR, 2, GICD_NSCAR); + field_imp!(set_icfgr, ICFGR, 2, GICD_ICFGR); + + pub fn forward(&mut self, id: u32, cpu: u32) { + let i = (id / 4) as usize; + let j = id % 4; + let value = 1 << cpu; + let mask = (1 << 8) - 1; + self.ITARGETSR[i].set((self.ITARGETSR[i].get() & !(mask << (j << 3))) | value << (j << 3)) + } + pub fn enable_gic(&mut self) { + self.CTLR + .set((GICD_CTLR::ENGrp0::Enable + GICD_CTLR::ENGrp1::Enable).into()) + } + + pub fn disable_gic(&mut self) { + self.CTLR + .set((GICD_CTLR::ENGrp0::Disable + GICD_CTLR::ENGrp1::Disable).into()) + } +} + +impl GicCpuInterfaceInner { + pub fn enable(&mut self) { + self.CTLR + .set((GICC_CTLR::EN::Enable + GICC_CTLR::EOI::EOIR_DIR).into()); + } + pub fn disable(&mut self) { + self.CTLR.set(GICC_CTLR::EN::Disable.into()) + } + pub fn set_priority_mask(&mut self, mask: u8) { + self.PMR.set(GICC_PMR::PRIORITY.val(mask as u32).into()) + } + pub fn set_bpr(&mut self, bpr: u8) { + self.BPR.set(GICC_BPR::BP.val(bpr as u32).into()) + } +} diff --git a/src/gic/v2/registers.rs b/src/gic/v2/registers.rs new file mode 100644 index 0000000..cc57088 --- /dev/null +++ b/src/gic/v2/registers.rs @@ -0,0 +1,83 @@ +use tock_registers::*; + +register_bitfields! {u32, + pub GICD_CTLR [ + ENGrp1 OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + ENGrp0 OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] + ], + pub GICD_TYPER [ + LSPI OFFSET(11) NUMBITS(5) [], + SecurityExtn OFFSET(10) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + CPUNumber OFFSET(5) NUMBITS(3) [], + ITLines OFFSET(0) NUMBITS(5) [] + ], + pub GICD_IIDR [ + Variant OFFSET(16) NUMBITS(4) [], + Revision OFFSET(12) NUMBITS(4) [], + Implementer OFFSET(0) NUMBITS(12) [] + ], + pub GICD_ICFGR [ + IntConfig OFFSET(1) NUMBITS(1) [ + + ], + Trigger OFFSET(0) NUMBITS(1)[ + LevelSensative = 0b0, + EdgeTriggered = 0b1 + ] + ], + pub GICD_NSCAR [ + ACCESS OFFSET(0) NUMBITS(2) [ + None = 0b00, + RO = 0b01, + WO = 0b10, + WR = 0b11 + ] + ], + pub GICC_CTLR [ + EOI OFFSET(9) NUMBITS(1) [ + EOIR_DIR = 1, + EOIR_ONLY = 0 + ], + FIQBYPDISGRP1 OFFSET(6) NUMBITS(1) [ + Signal = 1, + NoSignal = 0 + ], + IRQBYPDISGRP1 OFFSET(5) NUMBITS(1) [ + // Bypass FIQ signal whether or not still affects CPU + // execution even if the gic is turned off + Signal = 1, + NoSignal = 0, + ], + EN OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + ], + pub GICC_PMR [ + PRIORITY OFFSET(0) NUMBITS(7)[ + + ] + ], + pub GICC_BPR [ + BP OFFSET(0) NUMBITS(2) [ + + ] + ], + pub GICC_GENERIC [ + CPUID OFFSET(10) NUMBITS(2) [ + + ], + INTRID OFFSET(0) NUMBITS(10) [ + + ], + ], +} diff --git a/src/gic/v3.rs b/src/gic/v3.rs new file mode 100644 index 0000000..b7ba65d --- /dev/null +++ b/src/gic/v3.rs @@ -0,0 +1,212 @@ +mod registers; +use core::mem::size_of; +use paste::paste; +pub use registers::*; +use tock_registers::{ + interfaces::{Readable, Writeable}, + registers::*, + *, +}; + +use crate::{asm::barrier::*, registers::*}; + +pub const GIC_SGIS_NUM: usize = 16; +pub const GIC_INTS_MAX: usize = 1024; +pub const GIC_PRIVINT_NUM: usize = GIC_SGIS_NUM + GIC_PPIS_NUM; +pub const GIC_SPI_MAX: usize = GIC_INTS_MAX - GIC_PRIVINT_NUM; +pub const GIC_PRIO_BITS: usize = 8; +pub const GIC_TARGET_BITS: usize = 8; +pub const GIC_TARGETS_MAX: usize = GIC_TARGET_BITS; +pub const GIC_CONFIG_BITS: usize = 2; +pub const GIC_SGI_REGS_NUM: usize = GIC_SGIS_NUM * 8 / 32; +pub const GIC_LIST_REGS_NUM: usize = 64; + +const GIC_PPIS_NUM: usize = 16; +const GIC_INT_RT_NUM: usize = 1019 - 32 + 1; +const GIC_INT_REGS_NUM: usize = GIC_INTS_MAX / 32; +const GIC_PRIO_REGS_NUM: usize = GIC_INTS_MAX * 8 / 32; +const GIC_TARGET_REGS_NUM: usize = GIC_INTS_MAX * 8 / 32; +const GIC_CONFIG_REGS_NUM: usize = GIC_INTS_MAX * 2 / 32; +const GIC_SEC_REGS_NUM: usize = GIC_INTS_MAX * 2 / 32; + +macro_rules! bit_imp { + ($method: ident, $field: ident, $width: expr) => { + pub fn $method(&mut self, id: u32, pos: u32) { + let field_num = 32 / $width; + let reg_id = id / field_num; + let field_id = id & (field_num - 1); + self.$field[reg_id as usize] + .set(self.$field[reg_id as usize].get() | (1 << pos) << (field_id * $width)); + } + paste! { + pub fn [<$method _val>](&mut self, id: u32, val: u32){ + let field_num = 32 / $width; + let reg_id = id / field_num; + let field_id = id & (field_num - 1); + self.$field[reg_id as usize] + .set(self.$field[reg_id as usize].get() | (val << (field_id * $width))); + } + } + paste! { + pub fn [](&mut self, gid: u32, value: u32){ + self.$field[gid as usize].set(value); + } + } + }; +} + +register_structs! { + #[allow(non_snake_case)] + pub GicDistributorInner { + (0x0000 => pub CTLR: ReadWrite), //Distributor Control Register + (0x0004 => pub TYPER: ReadOnly), //Interrupt Controller Type Register + (0x0008 => pub IIDR: ReadOnly), //Distributor Implementer Identification Register + (0x000c => pub TYPER2: ReadOnly), //Interrupt controller Type Register 2 + (0x0010 => pub STATUSR: ReadWrite), //Error Reporting Status Register, optional + (0x0014 => reserved0), + (0x0040 => pub SETSPI_NSR: WriteOnly), //Set SPI Register + (0x0044 => reserved1), + (0x0048 => pub CLRSPI_NSR: WriteOnly), //Clear SPI Register + (0x004c => reserved2), + (0x0050 => pub SETSPI_SR: WriteOnly), //Set SPI, Secure Register + (0x0054 => reserved3), + (0x0058 => pub CLRSPI_SR: WriteOnly), //Clear SPI, Secure Register + (0x005c => reserved4), + (0x0080 => pub IGROUPR: [ReadWrite; GIC_INT_REGS_NUM]), //Interrupt Group Registers + (0x0100 => pub ISENABLER: [ReadWrite; GIC_INT_REGS_NUM]), //Interrupt Set-Enable Registers + (0x0180 => pub ICENABLER: [ReadWrite; GIC_INT_REGS_NUM]), //Interrupt Clear-Enable Registers + (0x0200 => pub ISPENDR: [ReadWrite; GIC_INT_REGS_NUM]), //Interrupt Set-Pending Registers + (0x0280 => pub ICPENDR: [ReadWrite; GIC_INT_REGS_NUM]), //Interrupt Clear-Pending Registers + (0x0300 => pub ISACTIVER: [ReadWrite; GIC_INT_REGS_NUM]), //Interrupt Set-Active Registers + (0x0380 => pub ICACTIVER: [ReadWrite; GIC_INT_REGS_NUM]), //Interrupt Clear-Active Registers + (0x0400 => pub IPRIORITYR: [ReadWrite; GIC_PRIO_REGS_NUM]), //Interrupt Priority Registers + (0x0800 => pub ITARGETSR: [ReadWrite; GIC_TARGET_REGS_NUM]), //Interrupt Processor Targets Registers + (0x0c00 => pub ICFGR: [ReadWrite; GIC_CONFIG_REGS_NUM]), //Interrupt Configuration Registers + (0x0d00 => pub IGRPMODR: [ReadWrite; GIC_CONFIG_REGS_NUM]), //Interrupt Group Modifier Registers + (0x0e00 => pub NSACR: [ReadWrite; GIC_SEC_REGS_NUM]), //Non-secure Access Control Registers + (0x0f00 => pub SGIR: WriteOnly), //Software Generated Interrupt Register + (0x0f04 => reserved6), + (0x0f10 => pub CPENDSGIR: [ReadWrite; GIC_SGI_REGS_NUM]), //SGI Clear-Pending Registers + (0x0f20 => pub SPENDSGIR: [ReadWrite; GIC_SGI_REGS_NUM]), //SGI Set-Pending Registers + (0x0f30 => reserved7), + (0x6000 => pub IROUTER: [ReadWrite; (0x8000 - 0x6000) / size_of::()]), //Interrupt Routing Registers for extended SPI range + (0x8000 => reserved21), + (0xffd0 => ID_res1: [ReadOnly; (0xffe8 - 0xffd0) / size_of::()]), //Reserved for IMPLEMENTATION registers + (0xffe8 => pub PIDR2: ReadOnly), //Distributor Peripheral ID2 Register + (0xffec => ID_res2: [ReadOnly; (0x10000 - 0xffec) / size_of::()]), //Reserved for IMPLEMENTATION registers + (0x10000 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + pub GicRedistributorInner { + (0x0000 => pub CTLR: ReadWrite), // Redistributor Control Register + (0x0004 => pub IIDR: ReadOnly), // Implementer Identification Register + (0x0008 => pub TYPER: ReadOnly), // Redistributor Type Register + (0x0010 => pub STATUSR: ReadWrite), // Error Reporting Status Register, optional + (0x0014 => pub WAKER: ReadWrite), // Redistributor Wake Register + (0x0018 => pub MPAMIDR: ReadOnly), // Report maximum PARTID and PMG Register + (0x001c => pub PARTIDR: ReadWrite), // Set PARTID and PMG Register + (0x0020 => reserved18), + (0x0040 => pub SETLPIR: WriteOnly), // Set LPI Pending Register + (0x0048 => pub CLRLPIR: WriteOnly), // Clear LPI Pending Register + (0x0050 => reserved17), + (0x0070 => pub PROPBASER: ReadWrite), //Redistributor Properties Base Address Register + (0x0078 => pub PEDNBASER: ReadWrite), //Redistributor LPI Pending Table Base Address Register + (0x0080 => reserved16), + (0x00a0 => pub INVLPIR: WriteOnly), // Redistributor Invalidate LPI Register + (0x00a8 => reserved15), + (0x00b0 => pub INVALLR: WriteOnly), // Redistributor Invalidate All Register + (0x00b8 => reserved14), + (0x00c0 => pub SYNCR: ReadOnly), // Redistributor Synchronize Register + (0x00c8 => reserved13), + (0xffd0 => ID_res1: [ReadOnly; (0xffe8 - 0xffd0) / size_of::()]), //Reserved for IMPLEMENTATION registers + (0xffe8 => pub PIDR2: ReadOnly), //Distributor Peripheral ID2 Register + (0xffec => ID_res2: [ReadOnly; (0x10000 - 0xffec) / size_of::()]), //Reserved for IMPLEMENTATION registers + (0x10000 => reserved12), + (0x10080 => pub IGROUPR0: ReadWrite), //SGI_base frame, all below + (0x10084 => reserved11), + (0x10100 => pub ISENABLER0: ReadWrite), + (0x10104 => reserved10), + (0x10180 => pub ICENABLER0: ReadWrite), + (0x10184 => reserved9), + (0x10200 => pub ISPENDR0: ReadWrite), + (0x10204 => reserved8), + (0x10280 => pub ICPENDR0: ReadWrite), + (0x10284 => reserved7), + (0x10300 => pub ISACTIVER0: ReadWrite), + (0x10304 => reserved6), + (0x10380 => pub ICACTIVER0: ReadWrite), + (0x10384 => reserved5), + (0x10400 => pub IPRIORITYR: [ReadWrite;8]), + (0x10420 => reserved4), + (0x10c00 => pub ICFGR0: ReadWrite), + (0x10c04 => pub ICFGR1: ReadWrite), + (0x10c08 => reserved3), + (0x10d00 => pub IGRPMODR0: ReadWrite), + (0x10d04 => reserved2), + (0x10e00 => pub NSACR: ReadWrite), + (0x10e04 => reserved1), + (0x20000 => @END), + } +} + +#[repr(C)] +pub struct GICCpuInterface; + +unsafe impl Sync for GicDistributorInner {} +unsafe impl Sync for GicRedistributorInner {} +unsafe impl Sync for GICCpuInterface {} + +impl GicDistributorInner { + bit_imp!(set_priority, IPRIORITYR, 8); + bit_imp!(deactivate, ICACTIVER, 1); + bit_imp!(enable_intr, ISENABLER, 1); + bit_imp!(disable_intr, ICENABLER, 1); + bit_imp!(clear_pend, ICPENDR, 1); + bit_imp!(set_group, IGROUPR, 1); + bit_imp!(set_group_mod, IGRPMODR, 1); + bit_imp!(configure_intr, ICFGR, 2); + + pub fn forward(&mut self, id: u32, cpu: u32) { + // remove this hardcode + let cpumask = (cpu & 0x1) + ((cpu >> 1) << 7); + self.IROUTER[id as usize].set(cpumask as u64); + } + pub fn enable_gic(&mut self) { + self.CTLR.set( + (GICD_CTLR::ENGrp1NS::Enable + GICD_CTLR::ARE_NS::Enable + GICD_CTLR::ENGrp0::Enable) + .into(), + ) + } + + pub fn disable_gic(&mut self) { + self.CTLR + .set((GICD_CTLR::ENGrp1NS::Disable + GICD_CTLR::ARE_NS::Disable).into()) + } + + pub fn get_nr_lines(&self) -> u32 { + 32 * (1 + GICD_TYPER::ITLines.read(self.TYPER.get())) + } +} + +impl GicRedistributorInner { + bit_imp!(set_priority, IPRIORITYR, 8); + + pub fn wake_up_redis(&mut self) { + self.WAKER + .set(GICR_WAKER::ProcessorSleep::NotinLowState.modify(self.WAKER.get())); + while GICR_WAKER::ChildrenAsleep.is_set(self.WAKER.get()) {} + } +} + +impl GICCpuInterface { + pub fn enable_sre_bit(&self) { + if !ICC_SRE_EL1.is_set(ICC_SRE_EL1::SRE) { + ICC_SRE_EL1.modify(ICC_SRE_EL1::SRE::SR); + isb(NONE); + assert!(ICC_SRE_EL1.is_set(ICC_SRE_EL1::SRE)); + } + } +} diff --git a/src/gic/v3/registers.rs b/src/gic/v3/registers.rs new file mode 100644 index 0000000..0a16c5a --- /dev/null +++ b/src/gic/v3/registers.rs @@ -0,0 +1,51 @@ +use tock_registers::*; + +register_bitfields! {u32, + pub GICD_CTLR [ + ARE_NS OFFSET(5) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + ARE_S OFFSET(4) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + ENGrp1S OFFSET(2) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + ENGrp1NS OFFSET(1) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + ENGrp0 OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] + ], + pub GICD_TYPER [ + LSPI OFFSET(17) NUMBITS(5) [], + SecurityExtn OFFSET(10) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + CPUNumber OFFSET(5) NUMBITS(3) [], + ITLines OFFSET(0) NUMBITS(5) [] + ], + pub GICR_WAKER [ + ChildrenAsleep OFFSET(2) NUMBITS(1) [], + ProcessorSleep OFFSET(1) NUMBITS(1) [ + NotinLowState = 0b0, + LowState = 0b1 + ], + IMPDEF OFFSET(0) NUMBITS(1) [], + ], +} +register_bitfields! {u64, + pub GICR_TYPER [ + Last OFFSET(4) NUMBITS(1) [ + NotLast = 0b0, + Last = 0b1, + ] + ] +} diff --git a/src/irq.rs b/src/irq.rs new file mode 100644 index 0000000..92d34f2 --- /dev/null +++ b/src/irq.rs @@ -0,0 +1,33 @@ +#[repr(transparent)] +pub struct IRQ(u64); + +impl IRQ { + pub fn new() -> Self { + IRQ(0) + } + #[inline(always)] + unsafe fn enable(&self) { + unsafe { core::arch::asm!("msr daifclr, #2", options(nostack)) } + } + + #[inline(always)] + unsafe fn disable(&self) { + unsafe { core::arch::asm!("msr daifclr, #2", options(nostack)) } + } + + #[inline(always)] + pub fn save_and_disable(&mut self) { + unsafe { + core::arch::asm!("mrs {}, daif", out(reg) self.0, options(nostack)); + self.disable(); + } + } + + #[inline(always)] + pub fn restore_and_enable(&self) { + unsafe { + core::arch::asm!("msr daif, {}", in(reg) self.0, options(nostack)); + self.enable(); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 52c7402..0f310af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,6 +54,10 @@ //! profile](https://static.docs.arm.com/ddi0487/ca/DDI0487C_a_armv8_arm.pdf?_ga=2.266626254.1122218691.1534883460-1326731866.1530967873). #![no_std] - pub mod asm; +pub mod cache; +pub mod exception; +pub mod gic; +pub mod irq; +pub mod mmu; pub mod registers; diff --git a/src/mmu.rs b/src/mmu.rs new file mode 100644 index 0000000..04d0d7f --- /dev/null +++ b/src/mmu.rs @@ -0,0 +1,3 @@ +mod address; +pub mod descriptor; +pub use address::*; diff --git a/src/mmu/address.rs b/src/mmu/address.rs new file mode 100644 index 0000000..bec5dec --- /dev/null +++ b/src/mmu/address.rs @@ -0,0 +1,275 @@ +use super::descriptor::BlockDescriptor; +use core::{iter::StepBy, ops::Range}; +use tock_registers::{fields::FieldValue, register_bitfields}; + +register_bitfields! {u64, + VADescriptor [ + L0 OFFSET(39) NUMBITS(9) [], + L1 OFFSET(30) NUMBITS(9) [], + L2 OFFSET(21) NUMBITS(9) [], + L3 OFFSET(12) NUMBITS(9) [], + OFFSET OFFSET(0) NUMBITS(12) [] + ] +} + +#[derive(Clone, Copy, Debug)] +pub enum PageMode { + HugePage, + LargePage, + SmallPage, +} + +impl PageMode { + pub fn levels(&self) -> u8 { + match self { + PageMode::SmallPage => 3, + PageMode::LargePage => 2, + PageMode::HugePage => 1, + } + } +} + +impl From for u64 { + fn from(value: PageMode) -> Self { + match value { + PageMode::SmallPage => 0x1000, + PageMode::LargePage => 0x200000, + PageMode::HugePage => 0x40000000, + } + } +} + +impl From for FieldValue { + fn from(value: PageMode) -> Self { + match value { + PageMode::SmallPage => BlockDescriptor::TYPE::PAGE, + _ => BlockDescriptor::TYPE::BLOCK, + } + } +} + +#[derive(Copy, Clone)] +pub enum MMProt { + NormalReadOnly, + NormalExecOnly, + NormalReadWriteAll, + NormalReadWriteNoExec, + PrivilegedExecOnly, + PrivilegedReadOnly, + PrivilegedReadWrite, + VirtNone, + VirtWriteOnly, + VirtReadOnly, + VirtReadOnlyNoExec, + VirtReadWrite, + VirtReadWriteNoExec, + SecureExecOnly, + SecureReadOnly, + SecureReadWrite, +} + +#[derive(Copy, Clone)] +pub enum MMType { + Device, + Normal, + NormalNoExec, + ReadOnly, + Instruction, + SystemReserved, + SystemReadOnly, + SystemInstruction, + SecureReadOnly, + SecureExecOnly, + SecureReadWrite, + VirtNone, + VirtWriteOnly, + VirtReadOnly, + VirtReadOnlyNoExec, + VirtReadWrite, + VirtReadWriteNoExec, +} + +pub struct VirtLayout { + pub indexes: [usize; 4], + pub offset: u64, +} + +pub type MMSegment = (u64, u64); + +#[derive(Clone, Copy, Debug)] +pub struct MMRegion { + pub mem: MMSegment, + pub granule: u64, +} + +impl MMRegion { + pub fn new(segment: MMSegment, granule: u64) -> Self { + MMRegion { + mem: ( + segment.0 & (!(granule - 1)), + (segment.1 + granule - 1) & (!(granule - 1)), + ), + granule, + } + } + pub fn size(&self) -> u64 { + self.mem.1 - self.mem.0 + } +} + +impl MMType { + pub fn default_prot(&self) -> MMProt { + match *self { + Self::Normal => MMProt::NormalReadWriteAll, + Self::NormalNoExec => MMProt::NormalReadWriteNoExec, + Self::ReadOnly => MMProt::NormalReadOnly, + Self::Instruction => MMProt::NormalExecOnly, + Self::Device => MMProt::PrivilegedReadWrite, + Self::SystemReserved => MMProt::PrivilegedReadWrite, + Self::SystemInstruction => MMProt::PrivilegedExecOnly, + Self::SystemReadOnly => MMProt::PrivilegedReadOnly, + Self::VirtReadWrite => MMProt::VirtReadWrite, + _ => unimplemented!(), + } + } +} + +impl From for FieldValue { + fn from(value: MMProt) -> Self { + match value { + MMProt::NormalReadWriteAll => { + BlockDescriptor::UXN_XN::FALSE + + BlockDescriptor::PXN::FALSE + + BlockDescriptor::AP::RW_ELx_RW_EL0 + + BlockDescriptor::NS::TRUE + } + MMProt::NormalReadWriteNoExec => { + BlockDescriptor::UXN_XN::TRUE + + BlockDescriptor::PXN::TRUE + + BlockDescriptor::AP::RW_ELx_RW_EL0 + + BlockDescriptor::NS::TRUE + } + MMProt::NormalExecOnly => { + BlockDescriptor::UXN_XN::FALSE + + BlockDescriptor::PXN::FALSE + + BlockDescriptor::AP::RO_ELx_RO_EL0 + + BlockDescriptor::NS::TRUE + } + MMProt::NormalReadOnly => { + BlockDescriptor::UXN_XN::TRUE + + BlockDescriptor::PXN::TRUE + + BlockDescriptor::AP::RO_ELx_RO_EL0 + + BlockDescriptor::NS::TRUE + } + MMProt::PrivilegedReadOnly => { + BlockDescriptor::UXN_XN::TRUE + + BlockDescriptor::PXN::TRUE + + BlockDescriptor::AP::RO_ELx_None_EL0 + + BlockDescriptor::NS::TRUE + } + MMProt::PrivilegedExecOnly => { + BlockDescriptor::UXN_XN::TRUE + + BlockDescriptor::PXN::FALSE + + BlockDescriptor::AP::RO_ELx_None_EL0 + + BlockDescriptor::NS::TRUE + } + MMProt::PrivilegedReadWrite => { + BlockDescriptor::UXN_XN::TRUE + + BlockDescriptor::PXN::TRUE + + BlockDescriptor::AP::RW_ELx_None_EL0 + + BlockDescriptor::NS::TRUE + } + MMProt::VirtReadWrite => { + BlockDescriptor::UXN_XN::FALSE + + BlockDescriptor::PXN::FALSE + + BlockDescriptor::S2AP::WR + + BlockDescriptor::NS::TRUE + } + _ => unimplemented!(), + } + } +} + +impl From for FieldValue { + fn from(value: MMType) -> Self { + let prot_fields: FieldValue = value.default_prot().into(); + + let type_fields = match value { + MMType::Device => BlockDescriptor::SH::CLEAR, + MMType::VirtReadWrite => BlockDescriptor::SH::OS, + _ => BlockDescriptor::SH::IS + BlockDescriptor::NSE_NG::TRUE, + }; + + prot_fields + type_fields + BlockDescriptor::VALID::TRUE + BlockDescriptor::AF::TRUE + } +} + +#[derive(Copy, Clone)] +pub enum MMAttrIdx { + Attr0 = 0, + Attr1 = 1, + Attr2 = 2, + Attr3 = 3, + Attr4 = 4, + Attr5 = 5, + Attr6 = 6, + Attr7 = 7, +} + +impl From for FieldValue { + fn from(value: MMAttrIdx) -> Self { + BlockDescriptor::ATTR.val(value as u64) + } +} + +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum S2MemAttrNoFWB { + Device_nGnRnE = 0b0000, + Device_nGnRE = 0b0001, + Device_nGRE = 0b0010, + Device_GRE = 0b0011, + // this is only for platform supported MTE_PERM, + // if not, setting this will cause UNDEFINED BEHAVIOR. + Normal_NTA_Outer_WBC_Inner_WBC_FEAT_MTE_PERM = 0b0100, + + Normal_Outer_NC_Inner_NC = 0b0101, + Normal_Outer_NC_Inner_WTC = 0b0110, + Normal_Outer_NC_Inner_WBC = 0b0111, + + Normal_Outer_WTC_Inner_NC = 0b1001, + Normal_Outer_WTC_Inner_WTC = 0b1010, + Normal_Outer_WTC_Inner_WBC = 0b1011, + + Normal_Outer_WBC_Inner_NC = 0b1101, + Normal_Outer_WBC_Inner_WTC = 0b1110, + Normal_Outer_WBC_Inner_WBC = 0b1111, +} + +impl From for FieldValue { + fn from(value: S2MemAttrNoFWB) -> Self { + BlockDescriptor::S2ATTR.val(value as u64) + } +} + +impl IntoIterator for MMRegion { + type Item = u64; + type IntoIter = StepBy>; + fn into_iter(self) -> Self::IntoIter { + (self.mem.0..self.mem.1).step_by(self.granule as usize) + } +} + +impl From for VirtLayout { + fn from(value: u64) -> Self { + Self { + indexes: [ + VADescriptor::L0.read(value) as usize, + VADescriptor::L1.read(value) as usize, + VADescriptor::L2.read(value) as usize, + VADescriptor::L3.read(value) as usize, + ], + offset: VADescriptor::OFFSET.read(value), + } + } +} diff --git a/src/mmu/descriptor.rs b/src/mmu/descriptor.rs new file mode 100644 index 0000000..1115e59 --- /dev/null +++ b/src/mmu/descriptor.rs @@ -0,0 +1,165 @@ +use super::{address::PageMode, MMAttrIdx, MMType, S2MemAttrNoFWB}; +use tock_registers::{ + fields::{Field, FieldValue}, + register_bitfields, RegisterLongName, +}; + +register_bitfields! {u64, + pub BlockDescriptor [ + UXN_XN OFFSET(54) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ], + PXN OFFSET(53) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ], + CONTIGUOUS OFFSET(52) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ], + OUTPUT OFFSET(0) NUMBITS(48) [], + LOWER_ATTRS OFFSET(0) NUMBITS(12) [], + NSE_NG OFFSET(11) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ], + AF OFFSET(10) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ], + SH OFFSET(8) NUMBITS(2) [ + NS = 0b00, + RESERVED = 0b01, + OS = 0b10, + IS = 0b11 + ], + AP OFFSET(6) NUMBITS(2) [ + RW_ELx_None_EL0 = 0b00, + RW_ELx_RW_EL0 = 0b01, + RO_ELx_None_EL0 = 0b10, + RO_ELx_RO_EL0 = 0b11 + ], + S2AP OFFSET(6) NUMBITS(2) [ + NONE = 0b00, + RO = 0b01, + WO = 0b10, + WR = 0b11, + ], + NS OFFSET(5) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ], + ATTR OFFSET(2) NUMBITS(3) [ + + ], + + S2ATTR OFFSET(2) NUMBITS(4) [ + + ], + TYPE OFFSET(1) NUMBITS(1) [ + BLOCK = 0b0, + PAGE = 0b1 + ], + VALID OFFSET(0) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ] + ] +} + +register_bitfields! {u64, + pub TableDescriptor [ + NS OFFSET(63) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ], + AP OFFSET(61) NUMBITS(2) [ + NO_EFFECT = 0b00, + UNPRIV_RESTRICTED = 0b01, + WR_RESTRICTED = 0b10, + WR_UNPRIV_RD_RESTRICTED = 0b11 + ], + UXN_XN OFFSET(60) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ], + PXN OFFSET(59) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ], + OUTPUT OFFSET(0) NUMBITS(48) [], + LOWER_ATTRS OFFSET(0) NUMBITS(2) [], + TYPE OFFSET(1) NUMBITS(1) [ + TABLE = 0b1, + BLOCK = 0b0 + ], + VALID OFFSET(0) NUMBITS(1) [ + TRUE = 0b1, + FALSE = 0b0 + ] + ] +} + +pub trait Descriptor {} + +impl Descriptor for BlockDescriptor::Register {} +impl Descriptor for TableDescriptor::Register {} + +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct VADescriptor(pub u64); + +impl VADescriptor { + pub fn read(&self) -> u64 { + self.0 + } + + pub fn read_field(&self, field: Field) -> u64 + where + T: RegisterLongName, + { + field.read(self.0) + } + + pub fn write(&mut self, val: u64) { + self.0 = val; + } + + pub fn write_field(&mut self, field_value: FieldValue) + where + T: RegisterLongName, + { + self.0 = field_value.modify(self.0); + } + + pub fn output(&self) -> u64 { + TableDescriptor::OUTPUT.read(self.0) & !TableDescriptor::LOWER_ATTRS.mask + } + + pub fn table(output: u64) -> u64 { + (TableDescriptor::OUTPUT.val(output) + + TableDescriptor::TYPE::TABLE + + TableDescriptor::VALID::TRUE) + .value + } + + pub fn s1_block(output: u64, typ: MMType, mode: PageMode, idx: MMAttrIdx) -> u64 { + (BlockDescriptor::OUTPUT.val(output) + typ.into() + mode.into() + idx.into()).value + } + pub fn s2_block(output: u64, typ: MMType, mode: PageMode, idx: S2MemAttrNoFWB) -> u64 { + (BlockDescriptor::OUTPUT.val(output) + typ.into() + mode.into() + idx.into()).value + } +} + +impl From for VADescriptor { + fn from(value: u64) -> Self { + Self(value) + } +} + +impl From for u64 { + fn from(value: VADescriptor) -> Self { + value.0 + } +} diff --git a/src/registers.rs b/src/registers.rs index c4cf57f..89682be 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -23,6 +23,8 @@ mod clidr_el1; mod cntfrq_el0; mod cnthctl_el2; mod cnthp_ctl_el2; +mod cnthp_cval_el2; +mod cnthp_tval_el2; mod cntkctl_el1; mod cntp_ctl_el0; mod cntp_cval_el0; @@ -130,9 +132,65 @@ mod ttbr1_el1; mod vbar_el1; mod vbar_el2; mod vbar_el3; +mod vmpidr_el2; mod vtcr_el2; mod vttbr_el2; +mod icc_ap0r_el1; +mod icc_ap1r_el1; +mod icc_asgi1r_el1; +mod icc_bpr0_el1; +mod icc_bpr1_el1; +mod icc_ctlr_el1; +mod icc_ctlr_el3; +mod icc_dir_el1; +mod icc_eoir0_el1; +mod icc_eoir1_el1; +mod icc_hppir0_el1; +mod icc_hppir1_el1; +mod icc_iar0_el1; +mod icc_iar1_el1; +mod icc_igpren0_el1; +mod icc_igpren1_el1; +mod icc_igpren1_el3; +mod icc_nmiar1_el1; +mod icc_pmr_el1; +mod icc_rpr_el1; +mod icc_sgi0r_el1; +mod icc_sgi1r_el1; +mod icc_sre_el1; +mod icc_sre_el2; +mod icc_sre_el3; + +mod ich_eisr_el2; +mod ich_elrsr_el2; +mod ich_hcr_el2; +mod ich_lr_el2; +mod ich_misr_el2; +mod ich_vmcr_el2; +mod ich_vtr_el2; + +mod icv_ap0r_el1; +mod icv_ap1r_el1; +mod icv_asgi1r_el1; +mod icv_bpr0_el1; +mod icv_bpr1_el1; +mod icv_ctlr_el1; +mod icv_ctlr_el3; +mod icv_dir_el1; +mod icv_eoir0_el1; +mod icv_eoir1_el1; +mod icv_hppir0_el1; +mod icv_hppir1_el1; +mod icv_iar0_el1; +mod icv_iar1_el1; +mod icv_igpren0_el1; +mod icv_igpren1_el1; +mod icv_igpren1_el3; +mod icv_nmiar1_el1; +mod icv_pmr_el1; +mod icv_rpr_el1; + pub use actlr_el1::ACTLR_EL1; pub use actlr_el2::ACTLR_EL2; pub use actlr_el3::ACTLR_EL3; @@ -151,6 +209,8 @@ pub use clidr_el1::CLIDR_EL1; pub use cntfrq_el0::CNTFRQ_EL0; pub use cnthctl_el2::CNTHCTL_EL2; pub use cnthp_ctl_el2::CNTHP_CTL_EL2; +pub use cnthp_cval_el2::CNTHP_CVAL_EL2; +pub use cnthp_tval_el2::CNTHP_TVAL_EL2; pub use cntkctl_el1::CNTKCTL_EL1; pub use cntp_ctl_el0::CNTP_CTL_EL0; pub use cntp_cval_el0::CNTP_CVAL_EL0; @@ -258,8 +318,69 @@ pub use ttbr1_el1::TTBR1_EL1; pub use vbar_el1::VBAR_EL1; pub use vbar_el2::VBAR_EL2; pub use vbar_el3::VBAR_EL3; +pub use vmpidr_el2::VMPIDR_EL2; pub use vtcr_el2::VTCR_EL2; pub use vttbr_el2::VTTBR_EL2; +pub use icc_ap0r_el1::*; +pub use icc_ap1r_el1::*; +pub use icc_asgi1r_el1::ICC_ASGI1R_EL1; +pub use icc_bpr0_el1::ICC_BPR0_EL1; +pub use icc_bpr1_el1::ICC_BPR1_EL1; +pub use icc_ctlr_el1::ICC_CTLR_EL1; +pub use icc_ctlr_el3::ICC_CTLR_EL3; +pub use icc_eoir0_el1::ICC_EOIR0_EL1; +pub use icc_eoir1_el1::ICC_EOIR1_EL1; +pub use icc_hppir0_el1::ICC_HPPIR0_EL1; +pub use icc_hppir1_el1::ICC_HPPIR1_EL1; +pub use icc_iar0_el1::ICC_IAR0_EL1; +pub use icc_iar1_el1::ICC_IAR1_EL1; +pub use icc_igpren0_el1::ICC_IGPREN0_EL1; +pub use icc_igpren1_el1::ICC_IGPREN1_EL1; +pub use icc_igpren1_el3::ICC_IGPREN1_EL3; +pub use icc_nmiar1_el1::ICC_NMIAR1_EL1; +pub use icc_pmr_el1::ICC_PMR_EL1; +pub use icc_rpr_el1::ICC_RPR_EL1; +pub use icc_sgi0r_el1::ICC_SGI0R_EL1; +pub use icc_sgi1r_el1::ICC_SGI1R_EL1; +pub use icc_sre_el1::ICC_SRE_EL1; +pub use icc_sre_el2::ICC_SRE_EL2; +pub use icc_sre_el3::ICC_SRE_EL3; + +pub use ich_eisr_el2::ICH_EISR_EL2; +pub use ich_elrsr_el2::ICH_ELRSR_EL2; +pub use ich_hcr_el2::ICH_HCR_EL2; +pub use ich_lr_el2::*; +pub use ich_misr_el2::ICH_MISR_EL2; +pub use ich_vmcr_el2::ICH_VMCR_EL2; +pub use ich_vtr_el2::ICH_VTR_EL2; + +pub use icv_ap0r_el1::*; +pub use icv_ap1r_el1::*; +pub use icv_asgi1r_el1::ICV_ASGI1R_EL1; +pub use icv_bpr0_el1::ICV_BPR0_EL1; +pub use icv_bpr1_el1::ICV_BPR1_EL1; +pub use icv_ctlr_el1::ICV_CTLR_EL1; +pub use icv_ctlr_el3::ICV_CTLR_EL3; +pub use icv_eoir0_el1::ICV_EOIR0_EL1; +pub use icv_eoir1_el1::ICV_EOIR1_EL1; +pub use icv_hppir0_el1::ICV_HPPIR0_EL1; +pub use icv_hppir1_el1::ICV_HPPIR1_EL1; +pub use icv_iar0_el1::ICV_IAR0_EL1; +pub use icv_iar1_el1::ICV_IAR1_EL1; +pub use icv_igpren0_el1::ICV_IGPREN0_EL1; +pub use icv_igpren1_el1::ICV_IGPREN1_EL1; +pub use icv_igpren1_el3::ICV_IGPREN1_EL3; +pub use icv_nmiar1_el1::ICV_NMIAR1_EL1; +pub use icv_pmr_el1::ICV_PMR_EL1; +pub use icv_rpr_el1::ICV_RPR_EL1; + +pub trait TTBR {} + +impl TTBR for vttbr_el2::Reg {} +impl TTBR for ttbr0_el1::Reg {} +impl TTBR for ttbr1_el1::Reg {} +impl TTBR for ttbr0_el2::Reg {} + #[doc(inline)] pub use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; diff --git a/src/registers/cnthp_ctl_el2.rs b/src/registers/cnthp_ctl_el2.rs index be658f4..c953e47 100644 --- a/src/registers/cnthp_ctl_el2.rs +++ b/src/registers/cnthp_ctl_el2.rs @@ -4,6 +4,7 @@ // // Author(s): // - tsemo4917 +// - Yiyang Wu //! Counter-timer Hypervisor Physical Timer Control Register - EL2 //! @@ -34,13 +35,19 @@ register_bitfields! {u64, /// /// 0 Timer interrupt is not masked by the IMASK bit. /// 1 Timer interrupt is masked by the IMASK bit. - IMASK OFFSET(1) NUMBITS(1) [], + IMASK OFFSET(1) NUMBITS(1) [ + Masked = 1, + Unmasked = 0, + ], /// Enables the timer. Permitted values are: /// /// 0 Timer disabled. /// 1 Timer enabled. - ENABLE OFFSET(0) NUMBITS(1) [] + ENABLE OFFSET(0) NUMBITS(1) [ + Enabled = 1, + Disabled = 0 + ] ] } diff --git a/src/registers/cnthp_cval_el2.rs b/src/registers/cnthp_cval_el2.rs new file mode 100644 index 0000000..80cea87 --- /dev/null +++ b/src/registers/cnthp_cval_el2.rs @@ -0,0 +1,19 @@ +use tock_registers::interfaces::{Readable, Writeable}; + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = (); + + sys_coproc_read_raw!(u64, "CNTHP_CVAL_EL2", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = (); + + sys_coproc_write_raw!(u64, "CNTHP_CVAL_EL2", "x"); +} + +pub const CNTHP_CVAL_EL2: Reg = Reg {}; diff --git a/src/registers/cnthp_tval_el2.rs b/src/registers/cnthp_tval_el2.rs new file mode 100644 index 0000000..57e3e07 --- /dev/null +++ b/src/registers/cnthp_tval_el2.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Copyright (c) 2018-2023 by the author(s) +// +// Author(s): +// - Andre Richter + +//! Counter-timer Physical Timer TimerValue register - EL0 +//! +//! Holds the timer value for the EL1 physical timer. + +use tock_registers::interfaces::{Readable, Writeable}; + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = (); + + sys_coproc_read_raw!(u64, "CNTHP_TVAL_EL2", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = (); + + sys_coproc_write_raw!(u64, "CNTHP_TVAL_EL2", "x"); +} + +pub const CNTHP_TVAL_EL2: Reg = Reg {}; diff --git a/src/registers/esr_el2.rs b/src/registers/esr_el2.rs index 917b2ad..ca64ddd 100644 --- a/src/registers/esr_el2.rs +++ b/src/registers/esr_el2.rs @@ -81,7 +81,158 @@ register_bitfields! {u64, /// Instruction Specific Syndrome. Architecturally, this field can be defined independently /// for each defined Exception class. However, in practice, some ISS encodings are used for /// more than one Exception class. - ISS OFFSET(0) NUMBITS(25) [] + ISS OFFSET(0) NUMBITS(25) [], + + // Data Abort Syndrome Register fields + // These fields are only valid if EC.DataAbort is set. + + // Is the syndrome valid? + ISV OFFSET(24) NUMBITS(1) [ + /// 0b0: The syndrome information is not valid. + NotValid = 0, + /// 0b1: The syndrome information is valid. + Valid = 1 + ], + + // Syndrome Access Size + SAS OFFSET(22) NUMBITS(2) [ + /// 0b00: Byte + Byte = 0b00, + /// 0b01: Half-word + HalfWord = 0b01, + /// 0b10: Word + Word = 0b10, + /// 0b11: Double-word + DoubleWord = 0b11 + ], + + // Syndrome Sign-Extend + SSE OFFSET(21) NUMBITS(1) [ + /// 0b0: Zero-extend + ZeroExtend = 0, + /// 0b1: Sign-extend + SignExtend = 1 + ], + + // Syndrome Register + SRT OFFSET(16) NUMBITS(5) [], + + // Syndrome Register Width + SF OFFSET(15) NUMBITS(1) [ + /// 0b0: 32-bit + Bit32 = 0, + /// 0b1: 64-bit + Bit64 = 1 + ], + + // Acquire-Release + AR OFFSET(14) NUMBITS(1) [ + /// 0b0: Normal memory access + Normal = 0, + /// 0b1: Acquire or release access + AcquireRelease = 1 + ], + + // Virtual Nested Abort + VNCR OFFSET(13) NUMBITS(1) [ + /// 0b0: Not a virtual nested abort + NotVirtualNested = 0, + /// 0b1: Virtual nested abort + VirtualNested = 1 + ], + + // Load-Store Type + LST OFFSET(11) NUMBITS(2) [ + /// 0b01: ST64BV + ST64BV = 0b01, + /// 0b10: LD64B or ST64B + LD64BorST64B = 0b10, + /// 0b11: ST64BV0 + ST64BV0 = 0b11 + ], + + // Is FAR not valid? + FnV OFFSET(10) NUMBITS(1) [ + /// 0b0: FAR is valid + Valid = 0, + /// 0b1: FAR is not valid + NotValid = 1 + ], + + // External Abort Type + EA OFFSET(9) NUMBITS(1) [ + /// 0b0 Not an external abort + NotExternal = 0, + /// 0b1: External + External = 1 + ], + + // Cache maintenance operation + CM OFFSET(8) NUMBITS(1) [ + /// 0b0: Not a cache maintenance operation + NotCacheMaintenance = 0, + /// 0b1: Cache maintenance operation + CacheMaintenance = 1 + ], + + // Which stage caused the stage 2 abort? + S1PTW OFFSET(7) NUMBITS(1) [ + /// 0b0: Stage 1 + Stage1 = 0, + /// 0b1: Stage 2 + Stage2 = 1 + ], + + // Write not Read + WnR OFFSET(6) NUMBITS(1) [ + /// 0b0: Read access + Read = 0, + /// 0b1: Write access + Write = 1 + ], + + // Data Fault Status Code + DFSC OFFSET(0) NUMBITS(6) [ + /// 0b000000: Address size fault, level 0 + AddressSizeFaultLevel0 = 0b000000, + /// 0b000001: Address size fault, level 1 + AddressSizeFaultLevel1 = 0b000001, + /// 0b000010: Address size fault, level 2 + AddressSizeFaultLevel2 = 0b000010, + /// 0b000011: Address size fault, level 3 + AddressSizeFaultLevel3 = 0b000011, + + /// 0b000100: Translation fault, level 0 + TranslationFaultLevel0 = 0b000100, + /// 0b000101: Translation fault, level 1 + TranslationFaultLevel1 = 0b000101, + /// 0b000110: Translation fault, level 2 + TranslationFaultLevel2 = 0b000110, + /// 0b000111: Translation fault, level 3 + TranslationFaultLevel3 = 0b000111, + + /// 0b001000: Access flag fault, level 0 + AccessFlagFaultLevel0 = 0b001000, + /// 0b001001: Access flag fault, level 1 + AccessFlagFaultLevel1 = 0b001001, + /// 0b001010: Access flag fault, level 2 + AccessFlagFaultLevel2 = 0b001010, + /// 0b001011: Access flag fault, level 3 + AccessFlagFaultLevel3 = 0b001011, + + /// 0b001101: Permission fault, level 1 + PermissionFaultLevel1 = 0b001101, + /// 0b001110: Permission fault, level 2 + PermissionFaultLevel2 = 0b001110, + /// 0b001111: Permission fault, level 3 + PermissionFaultLevel3 = 0b001111, + + /// 0b010000: Synchronous external abort, not on translation table walk or + /// hardware update of translation table + SynchronousExternalAbortNotOnTranslationTableWalk = 0b010000 + + // ... and many more + ] ] } diff --git a/src/registers/hcr_el2.rs b/src/registers/hcr_el2.rs index 61a14bf..c6c6c13 100644 --- a/src/registers/hcr_el2.rs +++ b/src/registers/hcr_el2.rs @@ -143,6 +143,12 @@ register_bitfields! {u64, EnableTrapGeneralExceptionsToEl2 = 1, ], + /// Trap Virtual Memory controls, from EL0. + TVM OFFSET(26) NUMBITS(1) [ + DisableTrapVMCtrlRegistersToEl2 = 0, + EnableTrapVMCtrlRegistersToEl2 = 1, + ], + /// Trap data or unified cache maintenance instructions that operate by Set/Way. /// Traps execution of those cache maintenance instructions at EL1 to EL2, when /// EL2 is enabled in the current Security state. @@ -216,6 +222,11 @@ register_bitfields! {u64, EnableTrapEl1SmcToEl2 = 1, ], + TWE OFFSET(15) NUMBITS(1) [ + DisableTrapEl1WfetoEl2 = 0, + EnableTrapEl1WfetoEl2 = 1 + ], + /// Default Cacheability. /// /// 0 This control has no effect on the Non-secure EL1&0 translation regime. @@ -268,7 +279,10 @@ register_bitfields! {u64, /// Security state: /// - Physical SError interrupts are taken to EL2, unless they are routed to EL3. /// - When the value of HCR_EL2.TGE is 0, then virtual SError interrupts are enabled. - AMO OFFSET(5) NUMBITS(1) [], + AMO OFFSET(5) NUMBITS(1) [ + EnableSError = 1, + DisableSError= 0, + ], /// Physical IRQ Routing. /// @@ -329,6 +343,11 @@ register_bitfields! {u64, EnableVirtualFIQ = 1, ], + PTW OFFSET(2) NUMBITS(1) [ + DisablePTW = 0, + EnablePTW = 1 + ], + /// Set/Way Invalidation Override. Causes Non-secure EL1 execution of the data cache /// invalidate by set/way instructions to perform a data cache clean and invalidate by /// set/way: @@ -353,7 +372,10 @@ register_bitfields! {u64, /// /// When HCR_EL2.TGE is 1, the PE ignores the value of this field for all purposes other /// than a direct read of this field. - SWIO OFFSET(1) NUMBITS(1) [], + SWIO OFFSET(1) NUMBITS(1) [ + Disable = 0, + Enable = 1 + ], /// Virtualization enable. Enables stage 2 address translation for the EL1&0 translation regime, /// when EL2 is enabled in the current Security state. The possible values are: diff --git a/src/registers/hpfar_el2.rs b/src/registers/hpfar_el2.rs index beb9903..d75e9db 100644 --- a/src/registers/hpfar_el2.rs +++ b/src/registers/hpfar_el2.rs @@ -9,14 +9,21 @@ //! //! Holds the faulting IPA for some aborts on a stage 2 translation taken to EL2. -use tock_registers::{interfaces::Readable, register_bitfields}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, +}; register_bitfields! {u64, pub HPFAR_EL2 [ - /// Faulting IPA address space. - NS OFFSET(63) NUMBITS(1) [], - - /// Faulting Intermediate Physical Address. + /// Faulting IPA address space + NS OFFSET(63) NUMBITS(1) [ + Secure = 0, + NonSecure = 1 + ], + /// Faulting Intermediate Physical Address + /// 40 bits, 40 = 52 - 12. 12 is the size of the page. + /// For implementations with fewer than 52 physical address bits, the corresponding upper bits in this field are RES0. FIPA OFFSET(4) NUMBITS(48) [] ] } @@ -30,4 +37,11 @@ impl Readable for Reg { sys_coproc_read_raw!(u64, "HPFAR_EL2", "x"); } +impl Writeable for Reg { + type T = u64; + type R = HPFAR_EL2::Register; + + sys_coproc_write_raw!(u64, "HPFAR_EL2", "x"); +} + pub const HPFAR_EL2: Reg = Reg {}; diff --git a/src/registers/icc_ap0r_el1.rs b/src/registers/icc_ap0r_el1.rs new file mode 100644 index 0000000..f6b92ca --- /dev/null +++ b/src/registers/icc_ap0r_el1.rs @@ -0,0 +1,34 @@ +use tock_registers::register_bitfields; + +register_bitfields! {u64, + pub ICC_AP0R_EL1 [ + FIELDS OFFSET(0) NUMBITS(32) [] + ] +} + +macro_rules! ap { + ($reg: ident, $name: tt) => { + #[allow(non_snake_case)] + mod $reg { + use super::*; + use tock_registers::interfaces::*; + pub struct Reg; + impl Writeable for Reg { + type T = u64; + type R = ICC_AP0R_EL1::Register; + sys_coproc_write_raw!(u64, $name, "x"); + } + impl Readable for Reg { + type T = u64; + type R = ICC_AP0R_EL1::Register; + sys_coproc_read_raw!(u64, $name, "x"); + } + } + pub const $reg: $reg::Reg = $reg::Reg {}; + }; +} + +ap!(ICC_AP0R0_EL1, "S3_0_C12_C9_4"); +ap!(ICC_AP0R1_EL1, "S3_0_C12_C9_5"); +ap!(ICC_AP0R2_EL1, "S3_0_C12_C9_6"); +ap!(ICC_AP0R3_EL1, "S3_0_C12_C9_7"); diff --git a/src/registers/icc_ap1r_el1.rs b/src/registers/icc_ap1r_el1.rs new file mode 100644 index 0000000..c708d02 --- /dev/null +++ b/src/registers/icc_ap1r_el1.rs @@ -0,0 +1,34 @@ +use tock_registers::register_bitfields; + +register_bitfields! {u64, + pub ICC_AP1R_EL1 [ + FIELDS OFFSET(0) NUMBITS(32) [] + ] +} + +macro_rules! ap { + ($reg: ident, $asm_name: tt) => { + #[allow(non_snake_case)] + mod $reg { + use super::*; + use tock_registers::interfaces::*; + pub struct Reg; + impl Writeable for Reg { + type T = u64; + type R = ICC_AP1R_EL1::Register; + sys_coproc_write_raw!(u64, $asm_name, "x"); + } + impl Readable for Reg { + type T = u64; + type R = ICC_AP1R_EL1::Register; + sys_coproc_read_raw!(u64, $asm_name, "x"); + } + } + pub const $reg: $reg::Reg = $reg::Reg {}; + }; +} + +ap!(ICC_AP1R0_EL1, "S3_0_C12_C9_0"); +ap!(ICC_AP1R1_EL1, "S3_0_C12_C9_1"); +ap!(ICC_AP1R2_EL1, "S3_0_C12_C9_2"); +ap!(ICC_AP1R3_EL1, "S3_0_C12_C9_3"); diff --git a/src/registers/icc_asgi1r_el1.rs b/src/registers/icc_asgi1r_el1.rs new file mode 100644 index 0000000..0e01b9c --- /dev/null +++ b/src/registers/icc_asgi1r_el1.rs @@ -0,0 +1,39 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_ASGI1R_EL1 [ + Aff3 OFFSET(48) NUMBITS(8) [], + RS OFFSET(44) NUMBITS(4) [], + IRM OFFSET(40) NUMBITS(1) [], + Aff2 OFFSET(32) NUMBITS(8) [ + + ], + INTID OFFSET(24) NUMBITS(4) [ + + ], + Aff1 OFFSET(16) NUMBITS(24) [ + + ], + TARGET OFFSET(0) NUMBITS(16) [ + + ] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_ASGI1R_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_ASGI1R_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICC_ASGI1R_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_ASGI1R_EL1", "x"); +} + +pub const ICC_ASGI1R_EL1: Reg = Reg {}; diff --git a/src/registers/icc_bpr0_el1.rs b/src/registers/icc_bpr0_el1.rs new file mode 100644 index 0000000..1715abb --- /dev/null +++ b/src/registers/icc_bpr0_el1.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_BPR0_EL1 [ + BP OFFSET(0) NUMBITS(3) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_BPR0_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_BPR0_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICC_BPR0_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_BPR0_EL1", "x"); +} + +pub const ICC_BPR0_EL1: Reg = Reg {}; diff --git a/src/registers/icc_bpr1_el1.rs b/src/registers/icc_bpr1_el1.rs new file mode 100644 index 0000000..153efb2 --- /dev/null +++ b/src/registers/icc_bpr1_el1.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_BPR1_EL1 [ + BP OFFSET(0) NUMBITS(3) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_BPR1_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_BPR1_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICC_BPR1_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_BPR1_EL1", "x"); +} + +pub const ICC_BPR1_EL1: Reg = Reg {}; diff --git a/src/registers/icc_ctlr_el1.rs b/src/registers/icc_ctlr_el1.rs index 79bf22f..2e524ed 100644 --- a/src/registers/icc_ctlr_el1.rs +++ b/src/registers/icc_ctlr_el1.rs @@ -15,7 +15,39 @@ use tock_registers::{interfaces::Readable, register_bitfields}; register_bitfields! {u64, pub ICC_CTLR_EL1 [ /// Extended INTID range (read-only). - ExtRange OFFSET(19) NUMBITS(1) [], + ExtRange OFFSET(19) NUMBITS(1) [ + WideUnsupported = 0b0, // support int_id 1024 ... 8191 + WideSupported = 0b1, + ], + RSS OFFSET(18) NUMBITS(1) [ + Low = 0b0, + High = 0b1 + ], + A3V OFFSET(15) NUMBITS(1) [ + Disable = 0b0, + Enable = 0b1, + ], + SEIS OFFSET(14) NUMBITS(1) [ + Disable = 0b0, + Enable = 0b1 + ], + ID OFFSET(11) NUMBITS(3) [ + BIT_16 = 0b000, + BIT_24 = 0b001 + ], + PRI OFFSET(8) NUMBITS(3) [], + PMHE OFFSET(6) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0, + ], + EOI OFFSET(1) NUMBITS(1) [ + EOIR_DropAndDeactivate = 0b0, + EOIR_Drop_Dir_Deactivate = 0b1 + ], + CBPR OFFSET(0) NUMBITS(1) [ + Private = 0b0, + Shared = 0b1, + ] ] } @@ -28,4 +60,11 @@ impl Readable for Reg { sys_coproc_read_raw!(u64, "ICC_CTLR_EL1", "x"); } +impl Writeable for Reg { + type T = u64; + type R = ICC_CTLR_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_CTLR_EL1", "x"); +} + pub const ICC_CTLR_EL1: Reg = Reg {}; diff --git a/src/registers/icc_ctlr_el3.rs b/src/registers/icc_ctlr_el3.rs new file mode 100644 index 0000000..45790c3 --- /dev/null +++ b/src/registers/icc_ctlr_el3.rs @@ -0,0 +1,73 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_CTLR_EL3 [ + Ext OFFSET(19) NUMBITS(1) [ + WideUnsupported = 0b0, // support int_id 1024 ... 8191 + WideSupported = 0b1, + ], + RSS OFFSET(18) NUMBITS(1) [ + Low = 0b0, + High = 0b1 + ], + A3V OFFSET(15) NUMBITS(1) [ + Disable = 0b0, + Enable = 0b1, + ], + SEIS OFFSET(14) NUMBITS(1) [ + Disable = 0b0, + Enable = 0b1 + ], + ID OFFSET(11) NUMBITS(3) [ + BIT_16 = 0b000, + BIT_24 = 0b001 + ], + PRI OFFSET(8) NUMBITS(3) [], + PMHE OFFSET(6) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0, + ], + RM OFFSET(5) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + EOI_EL1S OFFSET(4) NUMBITS(1) [ + EOIR_DropAndDeactivate = 0b0, + EOIR_Drop_Dir_Deactivate = 0b1 + ], + EOI_EL1NS OFFSET(3) NUMBITS(1) [ + EOIR_DropAndDeactivate = 0b0, + EOIR_Drop_Dir_Deactivate = 0b1 + ], + EOI_EL3 OFFSET(2) NUMBITS(1) [ + EOIR_DropAndDeactivate = 0b0, + EOIR_Drop_Dir_Deactivate = 0b1 + ], + CBPR_EL1NS OFFSET(1) NUMBITS(1) [ + Private = 0b0, + Shared = 0b1, + ], + CBPR_EL1S OFFSET(0) NUMBITS(1) [ + Private = 0b0, + Shared = 0b1, + ] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_CTLR_EL3::Register; + + sys_coproc_read_raw!(u64, "ICC_CTLR_EL3", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICC_CTLR_EL3::Register; + + sys_coproc_write_raw!(u64, "ICC_CTLR_EL3", "x"); +} + +pub const ICC_CTLR_EL3: Reg = Reg {}; diff --git a/src/registers/icc_dir_el1.rs b/src/registers/icc_dir_el1.rs new file mode 100644 index 0000000..08fa5fc --- /dev/null +++ b/src/registers/icc_dir_el1.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_DIR_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_DIR_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_DIR_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICC_DIR_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_DIR_EL1", "x"); +} + +pub const ICC_DIR_EL1: Reg = Reg {}; diff --git a/src/registers/icc_eoir0_el1.rs b/src/registers/icc_eoir0_el1.rs new file mode 100644 index 0000000..5bd0fcc --- /dev/null +++ b/src/registers/icc_eoir0_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_EOIR0_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_EOIR0_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_EOIR0_EL1", "x"); +} + +pub const ICC_EOIR0_EL1: Reg = Reg {}; diff --git a/src/registers/icc_eoir1_el1.rs b/src/registers/icc_eoir1_el1.rs new file mode 100644 index 0000000..df9ab87 --- /dev/null +++ b/src/registers/icc_eoir1_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_EOIR1_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_EOIR1_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_EOIR1_EL1", "x"); +} + +pub const ICC_EOIR1_EL1: Reg = Reg {}; diff --git a/src/registers/icc_hppir0_el1.rs b/src/registers/icc_hppir0_el1.rs new file mode 100644 index 0000000..cf88344 --- /dev/null +++ b/src/registers/icc_hppir0_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_HPPIR0_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_HPPIR0_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_HPPIR0_EL1", "x"); +} + +pub const ICC_HPPIR0_EL1: Reg = Reg {}; diff --git a/src/registers/icc_hppir1_el1.rs b/src/registers/icc_hppir1_el1.rs new file mode 100644 index 0000000..9ae6402 --- /dev/null +++ b/src/registers/icc_hppir1_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_HPPIR1_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_HPPIR1_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_HPPIR1_EL1", "x"); +} + +pub const ICC_HPPIR1_EL1: Reg = Reg {}; diff --git a/src/registers/icc_iar0_el1.rs b/src/registers/icc_iar0_el1.rs new file mode 100644 index 0000000..a2b78d4 --- /dev/null +++ b/src/registers/icc_iar0_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_IAR0_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_IAR0_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_IAR0_EL1", "x"); +} + +pub const ICC_IAR0_EL1: Reg = Reg {}; diff --git a/src/registers/icc_iar1_el1.rs b/src/registers/icc_iar1_el1.rs new file mode 100644 index 0000000..867393f --- /dev/null +++ b/src/registers/icc_iar1_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_IAR1_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_IAR1_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_IAR1_EL1", "x"); +} + +pub const ICC_IAR1_EL1: Reg = Reg {}; diff --git a/src/registers/icc_igpren0_el1.rs b/src/registers/icc_igpren0_el1.rs new file mode 100644 index 0000000..11a2a72 --- /dev/null +++ b/src/registers/icc_igpren0_el1.rs @@ -0,0 +1,21 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_IGPREN0_EL1 [ + EN OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_IGPREN0_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_IGPREN0_EL1", "x"); +} + +pub const ICC_IGPREN0_EL1: Reg = Reg {}; diff --git a/src/registers/icc_igpren1_el1.rs b/src/registers/icc_igpren1_el1.rs new file mode 100644 index 0000000..09d04dc --- /dev/null +++ b/src/registers/icc_igpren1_el1.rs @@ -0,0 +1,28 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_IGPREN1_EL1 [ + EN OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_IGPREN1_EL1::Register; + + sys_coproc_read_raw!(u64, "S3_0_C12_C12_7", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICC_IGPREN1_EL1::Register; + + sys_coproc_write_raw!(u64, "S3_0_C12_C12_7", "x"); +} + +pub const ICC_IGPREN1_EL1: Reg = Reg {}; diff --git a/src/registers/icc_igpren1_el3.rs b/src/registers/icc_igpren1_el3.rs new file mode 100644 index 0000000..569227b --- /dev/null +++ b/src/registers/icc_igpren1_el3.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_IGPREN1_EL3 [ + ENGRP1S OFFSET(1) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + ENGRP1NS OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_IGPREN1_EL3::Register; + + sys_coproc_read_raw!(u64, "ICC_IGPREN1_EL3", "x"); +} + +pub const ICC_IGPREN1_EL3: Reg = Reg {}; diff --git a/src/registers/icc_nmiar1_el1.rs b/src/registers/icc_nmiar1_el1.rs new file mode 100644 index 0000000..6f14466 --- /dev/null +++ b/src/registers/icc_nmiar1_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_NMIAR1_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_NMIAR1_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_NMIAR1_EL1", "x"); +} + +pub const ICC_NMIAR1_EL1: Reg = Reg {}; diff --git a/src/registers/icc_pmr_el1.rs b/src/registers/icc_pmr_el1.rs new file mode 100644 index 0000000..53a9109 --- /dev/null +++ b/src/registers/icc_pmr_el1.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_PMR_EL1 [ + PRIORITY OFFSET(0) NUMBITS(8) [] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_PMR_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_PMR_EL1", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICC_PMR_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_PMR_EL1", "x"); +} + +pub const ICC_PMR_EL1: Reg = Reg {}; diff --git a/src/registers/icc_rpr_el1.rs b/src/registers/icc_rpr_el1.rs new file mode 100644 index 0000000..7a29f99 --- /dev/null +++ b/src/registers/icc_rpr_el1.rs @@ -0,0 +1,27 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_RPR_EL1 [ + NMI OFFSET(63) NUMBITS(1) [], + NMI_NS OFFSET(62) NUMBITS(1) [], + PRIORITY OFFSET(0) NUMBITS(8) [] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_RPR_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_RPR_EL1", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICC_RPR_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_RPR_EL1", "x"); +} + +pub const ICC_RPR_EL1: Reg = Reg {}; diff --git a/src/registers/icc_sgi0r_el1.rs b/src/registers/icc_sgi0r_el1.rs new file mode 100644 index 0000000..5bc3045 --- /dev/null +++ b/src/registers/icc_sgi0r_el1.rs @@ -0,0 +1,31 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_SGI0R_EL1 [ + Aff3 OFFSET(48) NUMBITS(8) [], + RS OFFSET(44) NUMBITS(4) [], + IRM OFFSET(40) NUMBITS(1) [], + Aff2 OFFSET(32) NUMBITS(8) [], + INTID OFFSET(24) NUMBITS(4) [], + Aff1 OFFSET(16) NUMBITS(24) [], + TARGET OFFSET(0) NUMBITS(16) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_SGI0R_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_SGI0R_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICC_SGI0R_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_SGI0R_EL1", "x"); +} + +pub const ICC_SGI0R_EL1: Reg = Reg {}; diff --git a/src/registers/icc_sgi1r_el1.rs b/src/registers/icc_sgi1r_el1.rs new file mode 100644 index 0000000..06be2da --- /dev/null +++ b/src/registers/icc_sgi1r_el1.rs @@ -0,0 +1,39 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICC_SGI1R_EL1 [ + Aff3 OFFSET(48) NUMBITS(8) [], + RS OFFSET(44) NUMBITS(4) [], + IRM OFFSET(40) NUMBITS(1) [], + Aff2 OFFSET(32) NUMBITS(8) [ + + ], + INTID OFFSET(24) NUMBITS(4) [ + + ], + Aff1 OFFSET(16) NUMBITS(24) [ + + ], + TARGET OFFSET(0) NUMBITS(16) [ + + ] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICC_SGI1R_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_SGI1R_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICC_SGI1R_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_SGI1R_EL1", "x"); +} + +pub const ICC_SGI1R_EL1: Reg = Reg {}; diff --git a/src/registers/icc_sre_el1.rs b/src/registers/icc_sre_el1.rs new file mode 100644 index 0000000..c090432 --- /dev/null +++ b/src/registers/icc_sre_el1.rs @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Copyright (c) 2018-2023 by the author(s) +// +// Author(s): +// - Yiyang Wu + +//! Interrupt Mask Bits +//! +//! Allows access to the interrupt mask bits. + +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, +}; + +register_bitfields! { u64, + pub ICC_SRE_EL1 [ + EN OFFSET(3) NUMBITS(1) [ + ENABLED = 1, + DISABLED = 0, + ], + DIB OFFSET(2) NUMBITS(1) [ + ENABLED = 1, + DISABLED = 0, + ], + DFB OFFSET(1) NUMBITS(1)[ + ENABLED = 1, + DISABLED = 0 + ], + SRE OFFSET(1) NUMBITS(1) [ + MEMORY = 0, + SR = 1 + ] + ], +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_SRE_EL1::Register; + + sys_coproc_read_raw!(u64, "ICC_SRE_EL1", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICC_SRE_EL1::Register; + + sys_coproc_write_raw!(u64, "ICC_SRE_EL1", "x"); +} + +pub const ICC_SRE_EL1: Reg = Reg {}; diff --git a/src/registers/icc_sre_el2.rs b/src/registers/icc_sre_el2.rs index 2db4ed4..fcecc8a 100644 --- a/src/registers/icc_sre_el2.rs +++ b/src/registers/icc_sre_el2.rs @@ -1,9 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT // -// Copyright (c) 2024 by the author(s) +// Copyright (c) 2018-2024 by the author(s) // // Author(s): // - Sangwan Kwon +// - Yiyang Wu //! Interrupt Controller System Register Enable Register - EL2 //! @@ -23,21 +24,30 @@ register_bitfields! {u64, /// EL1 accesses to ICC_SRE_EL1 trap to EL2. /// /// 1 EL1 accesses to ICC_SRE_EL1 do not trap to EL2. - ENABLE OFFSET(3) NUMBITS(1) [], + ENABLE OFFSET(3) NUMBITS(1) [ + Enabled = 1, + Disabled = 0, + ], /// Disable IRQ bypass. /// /// 0 IRQ bypass enabled. /// /// 1 IRQ bypass disabled. - DIB OFFSET(2) NUMBITS(1) [], + DIB OFFSET(2) NUMBITS(1) [ + Enabled = 1, + Disabled = 0, + ], /// Disable FIQ bypass. /// /// 0 FIQ bypass enabled. /// /// 1 FIQ bypass disabled. - DFB OFFSET(1) NUMBITS(1) [], + DFB OFFSET(1) NUMBITS(1) [ + Enabled = 1, + Disabled = 0, + ], /// System Register Enable. /// @@ -46,7 +56,10 @@ register_bitfields! {u64, /// /// 1 The System register interface to the ICH_* registers and the EL1 and EL2 /// ICC_* registers is enabled for EL2. - SRE OFFSET(0) NUMBITS(1) [], + SRE OFFSET(0) NUMBITS(1) [ + SR = 1, + Memory = 0, + ] ] } diff --git a/src/registers/icc_sre_el3.rs b/src/registers/icc_sre_el3.rs new file mode 100644 index 0000000..72970be --- /dev/null +++ b/src/registers/icc_sre_el3.rs @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Copyright (c) 2018-2023 by the author(s) +// +// Author(s): +// - Yiyang Wu + +//! Interrupt Mask Bits +//! +//! Allows access to the interrupt mask bits. + +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, +}; + +register_bitfields! { u64, + pub ICC_SRE_EL3 [ + EN OFFSET(3) NUMBITS(1) [ + ENABLED = 1, + DISABLED = 0, + ], + DIB OFFSET(2) NUMBITS(1) [ + ENABLED = 1, + DISABLED = 0, + ], + DFB OFFSET(1) NUMBITS(1)[ + ENABLED = 1, + DISABLED = 0 + ], + SRE OFFSET(1) NUMBITS(1) [ + MEMORY = 0, + SR = 1 + ] + ], +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICC_SRE_EL3::Register; + + sys_coproc_read_raw!(u64, "ICC_SRE_EL3", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICC_SRE_EL3::Register; + + sys_coproc_write_raw!(u64, "ICC_SRE_EL3", "x"); +} + +pub const ICC_SRE_EL3: Reg = Reg {}; diff --git a/src/registers/ich_eisr_el2.rs b/src/registers/ich_eisr_el2.rs new file mode 100644 index 0000000..77b3d92 --- /dev/null +++ b/src/registers/ich_eisr_el2.rs @@ -0,0 +1,40 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICH_EISR_EL2 [ + STATUS15 OFFSET(15) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS14 OFFSET(14) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS13 OFFSET(13) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS12 OFFSET(12) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS11 OFFSET(11) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS10 OFFSET(10) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS9 OFFSET(9) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS8 OFFSET(8) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS7 OFFSET(7) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS6 OFFSET(6) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS5 OFFSET(5) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS4 OFFSET(4) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS3 OFFSET(3) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS2 OFFSET(2) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS1 OFFSET(1) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS0 OFFSET(0) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICH_EISR_EL2::Register; + + sys_coproc_read_raw!(u64, "ICH_EISR_EL2", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICH_EISR_EL2::Register; + + sys_coproc_write_raw!(u64, "ICH_EISR_EL2", "x"); +} + +pub const ICH_EISR_EL2: Reg = Reg {}; diff --git a/src/registers/ich_elrsr_el2.rs b/src/registers/ich_elrsr_el2.rs new file mode 100644 index 0000000..c11aac3 --- /dev/null +++ b/src/registers/ich_elrsr_el2.rs @@ -0,0 +1,40 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICH_ELRSR_EL2 [ + STATUS15 OFFSET(15) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS14 OFFSET(14) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS13 OFFSET(13) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS12 OFFSET(12) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS11 OFFSET(11) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS10 OFFSET(10) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS9 OFFSET(9) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS8 OFFSET(8) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS7 OFFSET(7) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS6 OFFSET(6) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS5 OFFSET(5) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS4 OFFSET(4) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS3 OFFSET(3) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS2 OFFSET(2) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS1 OFFSET(1) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + STATUS0 OFFSET(0) NUMBITS(1) [Enable = 0b1, Disable = 0b0], + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICH_ELRSR_EL2::Register; + + sys_coproc_read_raw!(u64, "ICH_ELRSR_EL2", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICH_ELRSR_EL2::Register; + + sys_coproc_write_raw!(u64, "ICH_ELRSR_EL2", "x"); +} + +pub const ICH_ELRSR_EL2: Reg = Reg {}; diff --git a/src/registers/ich_hcr_el2.rs b/src/registers/ich_hcr_el2.rs index 451b686..0e1863e 100644 --- a/src/registers/ich_hcr_el2.rs +++ b/src/registers/ich_hcr_el2.rs @@ -22,51 +22,101 @@ register_bitfields! {u64, /// When ICH_VTR_EL2.DVIM == 1: /// Directly-injected Virtual Interrupt Mask. - DVIM OFFSET(15) NUMBITS(1) [], + DVIM OFFSET(15) NUMBITS(1) [ + Masked = 0b1, + Unmasked = 0b0 + ], /// When FEAT_GICv3_TDIR is implemented: /// Trap EL1 writes to ICC_DIR_EL1 and ICV_DIR_EL1. - TDIR OFFSET(14) NUMBITS(1) [], + TDIR OFFSET(14) NUMBITS(1) [ + Trapped = 0b1, + UnTrapped = 0b0 + ], + + TSEI OFFSET(13) NUMBITS(1) [ + Trapped = 0b1, + UnTrapped = 0b0 + ], + TALL1 OFFSET(12) NUMBITS(1) [ + Trapped = 0b1, + UnTrapped = 0b0 + ], + TALL0 OFFSET(11) NUMBITS(1) [ + Trapped = 0b1, + UnTrapped = 0b0 + ], + TC OFFSET(10) NUMBITS(1) [ + Trapped = 0b1, + UnTrapped = 0b0 + ], /// When FEAT_GICv4p1 is implemented: /// Controls whether deactivation of virtual SGIs can increment ICH_HCR_EL2.EOIcount. - vSGIEOICount OFFSET(8) NUMBITS(1) [], + vSGIEOICount OFFSET(8) NUMBITS(1) [ + Discard = 0b1, + Keep = 0b0 + ], /// VM Group 1 Disabled Interrupt Enable. Enables the signaling of a maintenance interrupt /// while signaling of Group 1 interrupts from the virtual CPU interface to the connected /// vPE is disabled. - VGrp1DIE OFFSET(7) NUMBITS(1) [], + VGrp1DIE OFFSET(7) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], /// VM Group 1 Enabled Interrupt Enable. Enables the signaling of a maintenance interrupt /// while signaling of Group 1 interrupts from the virtual CPU interface to the connected /// vPE is enabled - VGrp1EIE OFFSET(6) NUMBITS(1) [], + VGrp1EIE OFFSET(6) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], /// VM Group 0 Disabled Interrupt Enable. Enables the signaling of a maintenance interrupt /// while signaling of Group 0 interrupts from the virtual CPU interface to the connected /// vPE is disabled. - VGrp0DIE OFFSET(5) NUMBITS(1) [], + VGrp0DIE OFFSET(5) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], /// VM Group 0 Enabled Interrupt Enable. Enables the signaling of a maintenance interrupt /// while signaling of Group 0 interrupts from the virtual CPU interface to the connected /// vPE is enabled - VGrp0EIE OFFSET(4) NUMBITS(1) [], + VGrp0EIE OFFSET(4) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], /// No Pending Interrupt Enable. Enables the signaling of a maintenance interrupt when /// there are no List registers with the State field set to 0b01 (pending). - NPIE OFFSET(3) NUMBITS(1) [], + NPIE OFFSET(3) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], /// List Register Entry Not Present Interrupt Enable. Enables the signaling of a maintenance /// interrupt while the virtual CPU interface does not have a corresponding valid List /// register entry for an EOI request. - LRENPIE OFFSET(2) NUMBITS(1) [], + LRENPIE OFFSET(2) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], /// Underflow Interrupt Enable. Enables the signaling of a maintenance interrupt when the /// List registers are empty, or hold only one valid entry. - UIE OFFSET(1) NUMBITS(1) [], + UIE OFFSET(1) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0, + ], /// Enable. Global enable bit for the virtual CPU interface. - En OFFSET(0) NUMBITS(1) [], + En OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] ] } diff --git a/src/registers/ich_lr_el2.rs b/src/registers/ich_lr_el2.rs new file mode 100644 index 0000000..e586243 --- /dev/null +++ b/src/registers/ich_lr_el2.rs @@ -0,0 +1,52 @@ +use tock_registers::register_bitfields; + +register_bitfields! {u64, + pub ICH_LR_EL2 [ + State OFFSET(62) NUMBITS(2) [], + HW OFFSET(61) NUMBITS(1) [], + Group OFFSET(60) NUMBITS(1) [], + NMI OFFSET(59) NUMBITS(1) [], + Priority OFFSET(48) NUMBITS(8) [], + PINTID OFFSET(32) NUMBITS(13) [], + VINTID OFFSET(0) NUMBITS(32) [] + ] +} + +macro_rules! lr { + ($reg: ident, $name: tt) => { + #[allow(non_snake_case)] + mod $reg { + use super::*; + use tock_registers::interfaces::*; + pub struct Reg; + impl Writeable for Reg { + type T = u64; + type R = ICH_LR_EL2::Register; + sys_coproc_write_raw!(u64, $name, "x"); + } + impl Readable for Reg { + type T = u64; + type R = ICH_LR_EL2::Register; + sys_coproc_read_raw!(u64, $name, "x"); + } + } + pub const $reg: $reg::Reg = $reg::Reg {}; + }; +} + +lr!(ICH_LR0_EL2, "ICH_LR1_EL2"); +lr!(ICH_LR1_EL2, "ICH_LR1_EL2"); +lr!(ICH_LR2_EL2, "ICH_LR2_EL2"); +lr!(ICH_LR3_EL2, "ICH_LR3_EL2"); +lr!(ICH_LR4_EL2, "ICH_LR4_EL2"); +lr!(ICH_LR5_EL2, "ICH_LR5_EL2"); +lr!(ICH_LR6_EL2, "ICH_LR6_EL2"); +lr!(ICH_LR7_EL2, "ICH_LR7_EL2"); +lr!(ICH_LR8_EL2, "ICH_LR8_EL2"); +lr!(ICH_LR9_EL2, "ICH_LR9_EL2"); +lr!(ICH_LR10_EL2, "ICH_LR10_EL2"); +lr!(ICH_LR11_EL2, "ICH_LR11_EL2"); +lr!(ICH_LR12_EL2, "ICH_LR12_EL2"); +lr!(ICH_LR13_EL2, "ICH_LR13_EL2"); +lr!(ICH_LR14_EL2, "ICH_LR14_EL2"); +lr!(ICH_LR15_EL2, "ICH_LR15_EL2"); diff --git a/src/registers/ich_misr_el2.rs b/src/registers/ich_misr_el2.rs index 99ba785..772d837 100644 --- a/src/registers/ich_misr_el2.rs +++ b/src/registers/ich_misr_el2.rs @@ -11,18 +11,31 @@ use tock_registers::interfaces::{Readable, Writeable}; +register_bitfields! {u64, + pub ICH_MISR_EL2 [ + VGrp1D OFFSET(7) NUMBITS(1) [Asserted = 0b1, None = 0b0], + VGrp1E OFFSET(6) NUMBITS(1) [Asserted = 0b1, None = 0b0], + VGrp0D OFFSET(5) NUMBITS(1) [Asserted = 0b1, None = 0b0], + VGrp0E OFFSET(4) NUMBITS(1) [Asserted = 0b1, None = 0b0], + NP OFFSET(3) NUMBITS(1) [Asserted = 0b1, None = 0b0], + LRENP OFFSET(2) NUMBITS(1) [Asserted = 0b1, None = 0b0], + U OFFSET(1) NUMBITS(1) [Asserted = 0b1, None = 0b0], + EOI OFFSET(0) NUMBITS(1) [Asserted = 0b1, None = 0b0], + ] +} + pub struct Reg; impl Readable for Reg { type T = u64; - type R = (); + type R = ICH_MISR_EL2::Register; sys_coproc_read_raw!(u64, "ICH_MISR_EL2", "x"); } impl Writeable for Reg { type T = u64; - type R = (); + type R = ICH_MISR_EL2::Register; sys_coproc_write_raw!(u64, "ICH_MISR_EL2", "x"); } diff --git a/src/registers/ich_vmcr_el2.rs b/src/registers/ich_vmcr_el2.rs index a7c848e..2d15f41 100644 --- a/src/registers/ich_vmcr_el2.rs +++ b/src/registers/ich_vmcr_el2.rs @@ -9,20 +9,54 @@ //! //! Enables the hypervisor to save and restore the virtual machine view of the GIC state. -use tock_registers::interfaces::{Readable, Writeable}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, +}; + +register_bitfields! {u64, + pub ICH_VMCR_EL2 [ + VMPR OFFSET(24) NUMBITS(8) [], + VBPR0 OFFSET(21) NUMBITS(3) [], + VBPR1 OFFSET(18) NUMBITS(3) [], + VEOIM OFFSET(9) NUMBITS(1) [ + + ], + VCBPR OFFSET(4) NUMBITS(1) [ + Shared = 0b1, + Private = 0b0 + ], + VFIQEn OFFSET(3) NUMBITS(1) [ + IRQ = 0b0, + FIQ = 0b1 + ], + VAckCtl OFFSET(2) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + VENG1 OFFSET(1) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + VENG0 OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] + ] +} pub struct Reg; impl Readable for Reg { type T = u64; - type R = (); + type R = ICH_VMCR_EL2::Register; sys_coproc_read_raw!(u64, "ICH_VMCR_EL2", "x"); } impl Writeable for Reg { type T = u64; - type R = (); + type R = ICH_VMCR_EL2::Register; sys_coproc_write_raw!(u64, "ICH_VMCR_EL2", "x"); } diff --git a/src/registers/ich_vtr_el2.rs b/src/registers/ich_vtr_el2.rs index 1f3a3a7..0a0b84a 100644 --- a/src/registers/ich_vtr_el2.rs +++ b/src/registers/ich_vtr_el2.rs @@ -20,7 +20,31 @@ register_bitfields! {u64, PREbits OFFSET(26) NUMBITS(3) [], /// The number of virtual interrupt identifier bits supported. - IDbits OFFSET(23) NUMBITS(3) [], + IDbits OFFSET(23) NUMBITS(3) [ + BITS_16 = 0b000, + BITS_24 = 0b001 + ], + + SEIS OFFSET(22) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + A3V OFFSET(21) NUMBITS(1) [ + Zero = 0b0, + NonZero = 0b1 + ], + NV4 OFFSET(20) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + TDS OFFSET(19) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0, + ], + DVIM OFFSET(18) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0, + ], /// List Registers. Indicates the number of List registers implemented, minus one. ListRegs OFFSET(0) NUMBITS(5) [], diff --git a/src/registers/icv_ap0r_el1.rs b/src/registers/icv_ap0r_el1.rs new file mode 100644 index 0000000..4f99803 --- /dev/null +++ b/src/registers/icv_ap0r_el1.rs @@ -0,0 +1,34 @@ +use tock_registers::register_bitfields; + +register_bitfields! {u64, + pub ICV_AP0R_EL1 [ + FIELDS OFFSET(0) NUMBITS(32) [] + ] +} + +macro_rules! ap { + ($reg: ident, $name: tt) => { + #[allow(non_snake_case)] + mod $reg { + use super::*; + use tock_registers::interfaces::*; + pub struct Reg; + impl Writeable for Reg { + type T = u64; + type R = ICV_AP0R_EL1::Register; + sys_coproc_write_raw!(u64, $name, "x"); + } + impl Readable for Reg { + type T = u64; + type R = ICV_AP0R_EL1::Register; + sys_coproc_read_raw!(u64, $name, "x"); + } + } + pub const $reg: $reg::Reg = $reg::Reg {}; + }; +} + +ap!(ICV_AP0R0_EL1, "ICV_AP0R0_EL1"); +ap!(ICV_AP0R1_EL1, "ICV_AP0R1_EL1"); +ap!(ICV_AP0R2_EL1, "ICV_AP0R2_EL1"); +ap!(ICV_AP0R3_EL1, "ICV_AP0R3_EL1"); diff --git a/src/registers/icv_ap1r_el1.rs b/src/registers/icv_ap1r_el1.rs new file mode 100644 index 0000000..d6e5270 --- /dev/null +++ b/src/registers/icv_ap1r_el1.rs @@ -0,0 +1,34 @@ +use tock_registers::register_bitfields; + +register_bitfields! {u64, + pub ICV_AP1R_EL1 [ + FIELDS OFFSET(0) NUMBITS(32) [] + ] +} + +macro_rules! ap { + ($reg: ident, $name: tt) => { + #[allow(non_snake_case)] + mod $reg { + use super::*; + use tock_registers::interfaces::*; + pub struct Reg; + impl Writeable for Reg { + type T = u64; + type R = ICV_AP1R_EL1::Register; + sys_coproc_write_raw!(u64, $name, "x"); + } + impl Readable for Reg { + type T = u64; + type R = ICV_AP1R_EL1::Register; + sys_coproc_read_raw!(u64, $name, "x"); + } + } + pub const $reg: $reg::Reg = $reg::Reg {}; + }; +} + +ap!(ICV_AP1R0_EL1, "ICV_AP0R0_EL1"); +ap!(ICV_AP1R1_EL1, "ICV_AP0R1_EL1"); +ap!(ICV_AP1R2_EL1, "ICV_AP0R2_EL1"); +ap!(ICV_AP1R3_EL1, "ICV_AP0R3_EL1"); diff --git a/src/registers/icv_asgi1r_el1.rs b/src/registers/icv_asgi1r_el1.rs new file mode 100644 index 0000000..155850a --- /dev/null +++ b/src/registers/icv_asgi1r_el1.rs @@ -0,0 +1,39 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_ASGI1R_EL1 [ + Aff3 OFFSET(48) NUMBITS(8) [], + RS OFFSET(44) NUMBITS(4) [], + IRM OFFSET(40) NUMBITS(1) [], + Aff2 OFFSET(32) NUMBITS(8) [ + + ], + INTID OFFSET(24) NUMBITS(4) [ + + ], + Aff1 OFFSET(16) NUMBITS(24) [ + + ], + TARGET OFFSET(0) NUMBITS(16) [ + + ] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICV_ASGI1R_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_ASGI1R_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICV_ASGI1R_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_ASGI1R_EL1", "x"); +} + +pub const ICV_ASGI1R_EL1: Reg = Reg {}; diff --git a/src/registers/icv_bpr0_el1.rs b/src/registers/icv_bpr0_el1.rs new file mode 100644 index 0000000..fcda017 --- /dev/null +++ b/src/registers/icv_bpr0_el1.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_BPR0_EL1 [ + BP OFFSET(0) NUMBITS(3) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICV_BPR0_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_BPR0_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICV_BPR0_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_BPR0_EL1", "x"); +} + +pub const ICV_BPR0_EL1: Reg = Reg {}; diff --git a/src/registers/icv_bpr1_el1.rs b/src/registers/icv_bpr1_el1.rs new file mode 100644 index 0000000..d605de1 --- /dev/null +++ b/src/registers/icv_bpr1_el1.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_BPR1_EL1 [ + BP OFFSET(0) NUMBITS(3) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICV_BPR1_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_BPR1_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICV_BPR1_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_BPR1_EL1", "x"); +} + +pub const ICV_BPR1_EL1: Reg = Reg {}; diff --git a/src/registers/icv_ctlr_el1.rs b/src/registers/icv_ctlr_el1.rs new file mode 100644 index 0000000..e8baa0c --- /dev/null +++ b/src/registers/icv_ctlr_el1.rs @@ -0,0 +1,57 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_CTLR_EL1 [ + Ext OFFSET(19) NUMBITS(1) [ + WideUnsupported = 0b0, // support int_id 1024 ... 8191 + WideSupported = 0b1, + ], + RSS OFFSET(18) NUMBITS(1) [ + Low = 0b0, + High = 0b1 + ], + A3V OFFSET(15) NUMBITS(1) [ + Disable = 0b0, + Enable = 0b1, + ], + SEIS OFFSET(14) NUMBITS(1) [ + Disable = 0b0, + Enable = 0b1 + ], + ID OFFSET(11) NUMBITS(3) [ + BIT_16 = 0b000, + BIT_24 = 0b001 + ], + PRI OFFSET(8) NUMBITS(3) [], + PMHE OFFSET(6) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0, + ], + EOI OFFSET(1) NUMBITS(1) [ + EOIR_DropAndDeactivate = 0b0, + EOIR_Drop_Dir_Deactivate = 0b1 + ], + CBPR OFFSET(0) NUMBITS(1) [ + Private = 0b0, + Shared = 0b1, + ] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICV_CTLR_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_CTLR_EL1", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICV_CTLR_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_CTLR_EL1", "x"); +} + +pub const ICV_CTLR_EL1: Reg = Reg {}; diff --git a/src/registers/icv_ctlr_el3.rs b/src/registers/icv_ctlr_el3.rs new file mode 100644 index 0000000..06688f1 --- /dev/null +++ b/src/registers/icv_ctlr_el3.rs @@ -0,0 +1,73 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_CTLR_EL3 [ + Ext OFFSET(19) NUMBITS(1) [ + WideUnsupported = 0b0, // support int_id 1024 ... 8191 + WideSupported = 0b1, + ], + RSS OFFSET(18) NUMBITS(1) [ + Low = 0b0, + High = 0b1 + ], + A3V OFFSET(15) NUMBITS(1) [ + Disable = 0b0, + Enable = 0b1, + ], + SEIS OFFSET(14) NUMBITS(1) [ + Disable = 0b0, + Enable = 0b1 + ], + ID OFFSET(11) NUMBITS(3) [ + BIT_16 = 0b000, + BIT_24 = 0b001 + ], + PRI OFFSET(8) NUMBITS(3) [], + PMHE OFFSET(6) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0, + ], + RM OFFSET(5) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + EOI_EL1S OFFSET(4) NUMBITS(1) [ + EOIR_DropAndDeactivate = 0b0, + EOIR_Drop_Dir_Deactivate = 0b1 + ], + EOI_EL1NS OFFSET(3) NUMBITS(1) [ + EOIR_DropAndDeactivate = 0b0, + EOIR_Drop_Dir_Deactivate = 0b1 + ], + EOI_EL3 OFFSET(2) NUMBITS(1) [ + EOIR_DropAndDeactivate = 0b0, + EOIR_Drop_Dir_Deactivate = 0b1 + ], + CBPR_EL1NS OFFSET(1) NUMBITS(1) [ + Private = 0b0, + Shared = 0b1, + ], + CBPR_EL1S OFFSET(0) NUMBITS(1) [ + Private = 0b0, + Shared = 0b1, + ] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICV_CTLR_EL3::Register; + + sys_coproc_read_raw!(u64, "ICV_CTLR_EL3", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICV_CTLR_EL3::Register; + + sys_coproc_write_raw!(u64, "ICV_CTLR_EL3", "x"); +} + +pub const ICV_CTLR_EL3: Reg = Reg {}; diff --git a/src/registers/icv_dir_el1.rs b/src/registers/icv_dir_el1.rs new file mode 100644 index 0000000..2f837ca --- /dev/null +++ b/src/registers/icv_dir_el1.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_DIR_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICV_DIR_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_DIR_EL1", "x"); +} + +impl Readable for Reg { + type T = u64; + type R = ICV_DIR_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_DIR_EL1", "x"); +} + +pub const ICV_DIR_EL1: Reg = Reg {}; diff --git a/src/registers/icv_eoir0_el1.rs b/src/registers/icv_eoir0_el1.rs new file mode 100644 index 0000000..b411055 --- /dev/null +++ b/src/registers/icv_eoir0_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_EOIR0_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICV_EOIR0_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_EOIR0_EL1", "x"); +} + +pub const ICV_EOIR0_EL1: Reg = Reg {}; diff --git a/src/registers/icv_eoir1_el1.rs b/src/registers/icv_eoir1_el1.rs new file mode 100644 index 0000000..f0ea1f9 --- /dev/null +++ b/src/registers/icv_eoir1_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_EOIR1_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICV_EOIR1_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_EOIR1_EL1", "x"); +} + +pub const ICV_EOIR1_EL1: Reg = Reg {}; diff --git a/src/registers/icv_hppir0_el1.rs b/src/registers/icv_hppir0_el1.rs new file mode 100644 index 0000000..86dcbc3 --- /dev/null +++ b/src/registers/icv_hppir0_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_HPPIR0_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICV_HPPIR0_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_HPPIR0_EL1", "x"); +} + +pub const ICV_HPPIR0_EL1: Reg = Reg {}; diff --git a/src/registers/icv_hppir1_el1.rs b/src/registers/icv_hppir1_el1.rs new file mode 100644 index 0000000..e6d9b35 --- /dev/null +++ b/src/registers/icv_hppir1_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_HPPIR1_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICV_HPPIR1_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_HPPIR1_EL1", "x"); +} + +pub const ICV_HPPIR1_EL1: Reg = Reg {}; diff --git a/src/registers/icv_iar0_el1.rs b/src/registers/icv_iar0_el1.rs new file mode 100644 index 0000000..ffe8098 --- /dev/null +++ b/src/registers/icv_iar0_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_IAR0_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICV_IAR0_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_IAR0_EL1", "x"); +} + +pub const ICV_IAR0_EL1: Reg = Reg {}; diff --git a/src/registers/icv_iar1_el1.rs b/src/registers/icv_iar1_el1.rs new file mode 100644 index 0000000..51801a7 --- /dev/null +++ b/src/registers/icv_iar1_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_IAR1_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICV_IAR1_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_IAR1_EL1", "x"); +} + +pub const ICV_IAR1_EL1: Reg = Reg {}; diff --git a/src/registers/icv_igpren0_el1.rs b/src/registers/icv_igpren0_el1.rs new file mode 100644 index 0000000..8a6aa3a --- /dev/null +++ b/src/registers/icv_igpren0_el1.rs @@ -0,0 +1,21 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_IGPREN0_EL1 [ + EN OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICV_IGPREN0_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_IGPREN0_EL1", "x"); +} + +pub const ICV_IGPREN0_EL1: Reg = Reg {}; diff --git a/src/registers/icv_igpren1_el1.rs b/src/registers/icv_igpren1_el1.rs new file mode 100644 index 0000000..61e48fb --- /dev/null +++ b/src/registers/icv_igpren1_el1.rs @@ -0,0 +1,21 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_IGPREN1_EL1 [ + EN OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICV_IGPREN1_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_IGPREN1_EL1", "x"); +} + +pub const ICV_IGPREN1_EL1: Reg = Reg {}; diff --git a/src/registers/icv_igpren1_el3.rs b/src/registers/icv_igpren1_el3.rs new file mode 100644 index 0000000..a6d1779 --- /dev/null +++ b/src/registers/icv_igpren1_el3.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_IGPREN1_EL3 [ + ENGRP1S OFFSET(1) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ], + ENGRP1NS OFFSET(0) NUMBITS(1) [ + Enable = 0b1, + Disable = 0b0 + ] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICV_IGPREN1_EL3::Register; + + sys_coproc_read_raw!(u64, "ICV_IGPREN1_EL3", "x"); +} + +pub const ICV_IGPREN1_EL3: Reg = Reg {}; diff --git a/src/registers/icv_nmiar1_el1.rs b/src/registers/icv_nmiar1_el1.rs new file mode 100644 index 0000000..3efc248 --- /dev/null +++ b/src/registers/icv_nmiar1_el1.rs @@ -0,0 +1,18 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_NMIAR1_EL1 [ + INTID OFFSET(0) NUMBITS(24) [] + ] +} + +pub struct Reg; + +impl Writeable for Reg { + type T = u64; + type R = ICV_NMIAR1_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_NMIAR1_EL1", "x"); +} + +pub const ICV_NMIAR1_EL1: Reg = Reg {}; diff --git a/src/registers/icv_pmr_el1.rs b/src/registers/icv_pmr_el1.rs new file mode 100644 index 0000000..d9b4df7 --- /dev/null +++ b/src/registers/icv_pmr_el1.rs @@ -0,0 +1,25 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_PMR_EL1 [ + PRIORITY OFFSET(0) NUMBITS(8) [] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICV_PMR_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_PMR_EL1", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICV_PMR_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_PMR_EL1", "x"); +} + +pub const ICV_PMR_EL1: Reg = Reg {}; diff --git a/src/registers/icv_rpr_el1.rs b/src/registers/icv_rpr_el1.rs new file mode 100644 index 0000000..65c675b --- /dev/null +++ b/src/registers/icv_rpr_el1.rs @@ -0,0 +1,27 @@ +use tock_registers::{interfaces::*, register_bitfields}; + +register_bitfields! {u64, + pub ICV_RPR_EL1 [ + NMI OFFSET(63) NUMBITS(1) [], + NMI_NS OFFSET(62) NUMBITS(1) [], + PRIORITY OFFSET(0) NUMBITS(8) [] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = ICV_RPR_EL1::Register; + + sys_coproc_read_raw!(u64, "ICV_RPR_EL1", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = ICV_RPR_EL1::Register; + + sys_coproc_write_raw!(u64, "ICV_RPR_EL1", "x"); +} + +pub const ICV_RPR_EL1: Reg = Reg {}; diff --git a/src/registers/sctlr_el2.rs b/src/registers/sctlr_el2.rs index 64ab713..a7b6434 100644 --- a/src/registers/sctlr_el2.rs +++ b/src/registers/sctlr_el2.rs @@ -83,6 +83,24 @@ register_bitfields! {u64, IsSynch = 1 ], + /// Non-aligned access. This bit controls generation of Alignment faults under certain + /// conditions at EL2, and, when EL2 is enabled in the current Security state and + /// HCR_EL2.{E2H, TGE} == {1, 1}, EL0. + NAA OFFSET(6) NUMBITS(1) [ + Allowed = 1, + NotAllowed = 0 + ], + + /// SP Alignment check enable for EL0. + /// + /// When set to 1, if a load or store instruction executed at EL0 uses the SP + /// as the base address and the SP is not aligned to a 16-byte boundary, + /// then a SP alignment fault exception is generated. + SA0 OFFSET(4) NUMBITS(1) [ + Disable = 0, + Enable = 1 + ], + /// SP Alignment check enable. /// /// When set to 1, if a load or store instruction executed at EL2 uses the SP diff --git a/src/registers/tcr_el2.rs b/src/registers/tcr_el2.rs index d32dcea..92da8db 100644 --- a/src/registers/tcr_el2.rs +++ b/src/registers/tcr_el2.rs @@ -18,6 +18,10 @@ use tock_registers::{ register_bitfields! {u64, pub TCR_EL2 [ + AS OFFSET(36) NUMBITS(1) [ + Disable = 0, + Enable = 1, + ], /// When FEAT_HAFDBS is implemented hardware can update the dirty flags in the stage1 /// descriptors HD OFFSET(22) NUMBITS(1) [ diff --git a/src/registers/ttbr0_el2.rs b/src/registers/ttbr0_el2.rs index 66e73e7..749f963 100644 --- a/src/registers/ttbr0_el2.rs +++ b/src/registers/ttbr0_el2.rs @@ -22,7 +22,7 @@ register_bitfields! {u64, RES0 OFFSET(48) NUMBITS(16) [], /// Translation table base address - BADDR OFFSET(1) NUMBITS(48) [], + BADDR OFFSET(0) NUMBITS(48) [], /// Common not Private CnP OFFSET(0) NUMBITS(1) [] diff --git a/src/registers/ttbr1_el2.rs b/src/registers/ttbr1_el2.rs new file mode 100644 index 0000000..55e897d --- /dev/null +++ b/src/registers/ttbr1_el2.rs @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Copyright (c) 2018-2023 by the author(s) +// +// Author(s): +// - Yiyang Wu + +//! Translation Table Base Register 1 - EL2 +//! +//! Holds the base address of the translation table for the initial lookup for stage 1 of the +//! translation of an address from the higher VA range in the EL2&0 translation regime, and other +//! information for this translation regime. + +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, +}; + +register_bitfields! {u64, + pub TTBR1_EL2 [ + /// An ASID for the translation table base address. The TCR_EL2.A1 field selects either + /// TTBR0_EL2.ASID or TTBR1_EL1.ASID. + /// + /// If the implementation has only 8 bits of ASID, then the upper 8 bits of this field are + /// RES 0. + ASID OFFSET(48) NUMBITS(16) [], + + /// Translation table base address + BADDR OFFSET(1) NUMBITS(47) [], + + /// Common not Private + CnP OFFSET(0) NUMBITS(1) [] + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = TTBR1_EL2::Register; + + sys_coproc_read_raw!(u64, "TTBR1_EL2", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = TTBR1_EL2::Register; + + sys_coproc_write_raw!(u64, "TTBR1_EL2", "x"); +} + +impl Reg { + #[inline(always)] + pub fn get_baddr(&self) -> u64 { + self.read(TTBR1_EL2::BADDR) << 1 + } + + #[inline(always)] + pub fn set_baddr(&self, addr: u64) { + self.write(TTBR1_EL2::BADDR.val(addr >> 1)); + } +} + +pub const TTBR1_EL2: Reg = Reg {}; diff --git a/src/registers/vmpidr_el2.rs b/src/registers/vmpidr_el2.rs new file mode 100644 index 0000000..3adede3 --- /dev/null +++ b/src/registers/vmpidr_el2.rs @@ -0,0 +1,33 @@ +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, +}; + +register_bitfields! {u64, + pub VMPIDR_EL2 [ + U OFFSET(32) NUMBITS(8), + AFF3 OFFSET(25) NUMBITS(5), + MT OFFSET(24) NUMBITS(1), + AFF2 OFFSET(18) NUMBITS(5), + AFF1 OFFSET(8) NUMBITS(9), + AFF0 OFFSET(0) NUMBITS(8) + ] +} + +pub struct Reg; + +impl Readable for Reg { + type T = u64; + type R = VMPIDR_EL2::Register; + + sys_coproc_read_raw!(u64, "VMPIDR_EL2", "x"); +} + +impl Writeable for Reg { + type T = u64; + type R = VMPIDR_EL2::Register; + + sys_coproc_write_raw!(u64, "VMPIDR_EL2", "x"); +} + +pub const VMPIDR_EL2: Reg = Reg {};