diff --git a/cortex-ar/src/pmsav8.rs b/cortex-ar/src/pmsav8.rs index 3ce1fb3..9906a83 100644 --- a/cortex-ar/src/pmsav8.rs +++ b/cortex-ar/src/pmsav8.rs @@ -11,7 +11,9 @@ use arbitrary_int::{u26, u3}; use crate::register; #[doc(inline)] -pub use register::prbar::{AccessPerms, Shareability}; +pub use register::hprbar::{AccessPerms as El2AccessPerms, Shareability as El2Shareability}; +#[doc(inline)] +pub use register::prbar::{AccessPerms as El1AccessPerms, Shareability as El1Shareability}; /// Ways this API can fail #[derive(Debug, Clone, PartialEq, Eq)] @@ -44,7 +46,7 @@ impl El1Mpu { } /// Access the current state of a region - pub fn get_region(&mut self, idx: u8) -> Option { + pub fn get_region(&mut self, idx: u8) -> Option { if idx >= self.num_regions() { return None; } @@ -53,7 +55,7 @@ impl El1Mpu { let prlar = register::Prlar::read(); let start_addr = (prbar.base().value() << 6) as *mut u8; let end_addr = ((prlar.limit().value() << 6) | 0x3F) as *mut u8; - Some(Region { + Some(El1Region { range: start_addr..=end_addr, shareability: prbar.shareability(), access: prbar.access_perms(), @@ -67,7 +69,7 @@ impl El1Mpu { /// /// ## Arguments /// - /// - `region`: The [Region] object containing the configuration for the MPU region. + /// - `region`: The [El1Region] object containing the configuration for the MPU region. /// - `idx`: The index of the region to be configured. /// /// ## Errors @@ -76,7 +78,7 @@ impl El1Mpu { /// - [Error::UnalignedRegion] if the region's start address is not 64-byte aligned. /// - [Error::UnalignedRegion] if the region's end address is not 63-byte aligned. /// - [Error::InvalidMair] if the region's MAIR index is invalid (greater than 7). - pub fn set_region(&mut self, idx: u8, region: &Region) -> Result<(), Error> { + pub fn set_region(&mut self, idx: u8, region: &El1Region) -> Result<(), Error> { let start = *(region.range.start()) as usize as u32; // Check for 64-byte alignment (0x3F is six bits) if start & 0x3F != 0 { @@ -114,11 +116,11 @@ impl El1Mpu { /// ## Arguments /// /// - `regions_starting_idx`: The starting index for the regions to be reconfigured. - /// - `regions`: A slice of [Region] objects that will overwrite the previous regions starting from `regions_starting_idx`. + /// - `regions`: A slice of [El1Region] objects that will overwrite the previous regions starting from `regions_starting_idx`. pub fn set_regions( &mut self, regions_starting_idx: u8, - regions: &[Region], + regions: &[El1Region], ) -> Result<(), Error> { if regions.len().saturating_add(regions_starting_idx as usize) > self.num_regions() as usize { @@ -161,8 +163,9 @@ impl El1Mpu { /// Configure the EL1 MPU /// - /// Write regions, attributes and enable/disable the background region with a single [Config] struct. - pub fn configure(&mut self, config: &Config) -> Result<(), Error> { + /// Write regions, attributes and enable/disable the background region + /// with a single [El1Config] struct. + pub fn configure(&mut self, config: &El1Config) -> Result<(), Error> { self.set_regions(0, config.regions)?; self.set_attributes(config.memory_attributes); @@ -187,9 +190,172 @@ impl El1Mpu { } } -/// Configuration for the PMSAv8-32 MPU +/// Represents our PMSAv8-32 EL2 MPU +pub struct El2Mpu(); + +impl El2Mpu { + /// Create an EL2 MPU handle + /// + /// # Safety + /// + /// Only create one of these at any given time, as they access shared + /// mutable state within the processor and do read-modify-writes on that state. + pub unsafe fn new() -> El2Mpu { + El2Mpu() + } + + /// How many EL2 MPU regions are there? + pub fn num_regions(&self) -> u8 { + register::Hmpuir::read().region() + } + + /// Access the current state of a region + pub fn get_region(&mut self, idx: u8) -> Option { + if idx >= self.num_regions() { + return None; + } + register::Hprselr::write(register::Hprselr(idx as u32)); + let hprbar = register::Hprbar::read(); + let hprlar = register::Hprlar::read(); + let start_addr = (hprbar.base().value() << 6) as *mut u8; + let end_addr = ((hprlar.limit().value() << 6) | 0x3F) as *mut u8; + Some(El2Region { + range: start_addr..=end_addr, + shareability: hprbar.shareability(), + access: hprbar.access_perms(), + no_exec: hprbar.nx(), + mair: hprlar.mair().value(), + enable: hprlar.enabled(), + }) + } + + /// Write a single region to the EL2 MPU + /// + /// ## Arguments + /// + /// - `region`: The [El2Region] object containing the configuration for the MPU region. + /// - `idx`: The index of the region to be configured. + /// + /// ## Errors + /// + /// Returns: + /// - [Error::UnalignedRegion] if the region's start address is not 64-byte aligned. + /// - [Error::UnalignedRegion] if the region's end address is not 63-byte aligned. + /// - [Error::InvalidMair] if the region's MAIR index is invalid (greater than 7). + pub fn set_region(&mut self, idx: u8, region: &El2Region) -> Result<(), Error> { + let start = *(region.range.start()) as usize as u32; + // Check for 64-byte alignment (0x3F is six bits) + if start & 0x3F != 0 { + return Err(Error::UnalignedRegion(region.range.clone())); + } + let end = *(region.range.end()) as usize as u32; + if end & 0x3F != 0x3F { + return Err(Error::UnalignedRegion(region.range.clone())); + } + if region.mair > 7 { + return Err(Error::InvalidMair(region.mair)); + } + register::Hprselr::write(register::Hprselr(idx as u32)); + register::Hprbar::write({ + let mut bar = register::Hprbar::new_with_raw_value(0); + bar.set_base(u26::from_u32(start >> 6)); + bar.set_access_perms(region.access); + bar.set_nx(region.no_exec); + bar.set_shareability(region.shareability); + bar + }); + register::Hprlar::write({ + let mut lar = register::Hprlar::new_with_raw_value(0); + lar.set_limit(u26::from_u32(end >> 6)); + lar.set_enabled(region.enable); + lar.set_mair(u3::from_u8(region.mair)); + lar + }); + + Ok(()) + } + + /// Writes a subset of EL2 MPU regions starting from a specified index. + /// + /// ## Arguments + /// + /// - `regions_starting_idx`: The starting index for the regions to be reconfigured. + /// - `regions`: A slice of [El2Region] objects that will overwrite the previous regions starting from `regions_starting_idx`. + pub fn set_regions( + &mut self, + regions_starting_idx: u8, + regions: &[El2Region], + ) -> Result<(), Error> { + if regions.len().saturating_add(regions_starting_idx as usize) > self.num_regions() as usize + { + return Err(Error::TooManyRegions); + } + + for (idx, region) in regions.iter().enumerate() { + self.set_region(idx as u8 + regions_starting_idx, region)?; + } + + Ok(()) + } + + /// Set the memory attributes to HMAIR0 and HMAIR1 + pub fn set_attributes(&mut self, memattrs: &[MemAttr]) { + let mem_attr0 = memattrs.get(0).map(|m| m.to_bits()).unwrap_or(0) as u32; + let mem_attr1 = memattrs.get(1).map(|m| m.to_bits()).unwrap_or(0) as u32; + let mem_attr2 = memattrs.get(2).map(|m| m.to_bits()).unwrap_or(0) as u32; + let mem_attr3 = memattrs.get(3).map(|m| m.to_bits()).unwrap_or(0) as u32; + let hmair0 = mem_attr3 << 24 | mem_attr2 << 16 | mem_attr1 << 8 | mem_attr0; + unsafe { + register::Hmair0::write(register::Hmair0(hmair0)); + } + let mem_attr0 = memattrs.get(4).map(|m| m.to_bits()).unwrap_or(0) as u32; + let mem_attr1 = memattrs.get(5).map(|m| m.to_bits()).unwrap_or(0) as u32; + let mem_attr2 = memattrs.get(6).map(|m| m.to_bits()).unwrap_or(0) as u32; + let mem_attr3 = memattrs.get(7).map(|m| m.to_bits()).unwrap_or(0) as u32; + let hmair1 = mem_attr3 << 24 | mem_attr2 << 16 | mem_attr1 << 8 | mem_attr0; + unsafe { + register::Hmair1::write(register::Hmair1(hmair1)); + } + } + + /// Enable or disable the background region + pub fn background_region_enable(&mut self, enable: bool) { + register::Hsctlr::modify(|r| { + r.set_br(enable); + }); + } + + /// Configure the EL2 MPU + /// + /// Write regions, attributes and enable/disable the background region with a single [El2Config] struct. + pub fn configure(&mut self, config: &El2Config) -> Result<(), Error> { + self.set_regions(0, config.regions)?; + + self.set_attributes(config.memory_attributes); + + self.background_region_enable(config.background_config); + + Ok(()) + } + + /// Enable the EL2 MPU + pub fn enable(&mut self) { + register::Hsctlr::modify(|r| { + r.set_m(true); + }); + } + + /// Disable the EL2 MPU + pub fn disable(&mut self) { + register::Hsctlr::modify(|r| { + r.set_m(false); + }); + } +} + +/// Configuration for the PMSAv8-32 EL1 MPU #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Config<'a> { +pub struct El1Config<'a> { /// Background Config Enable /// /// If true, use the default MMU config if no other region matches an address @@ -197,7 +363,7 @@ pub struct Config<'a> { /// Information about each Region. /// /// If you pass more regions than the MPU supports, you get an error. - pub regions: &'a [Region], + pub regions: &'a [El1Region], /// Information about each Memory Attribute /// /// If you pass more MemAttrs than the MPU supports (8), you get an error. @@ -206,16 +372,16 @@ pub struct Config<'a> { /// Configuration for the PMSAv8-32 MPU #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Region { +pub struct El1Region { /// The range of the region /// /// * The first address must be a multiple of 32. /// * The length must be a multiple of 32. pub range: core::ops::RangeInclusive<*mut u8>, /// Shareability of the region - pub shareability: Shareability, + pub shareability: El1Shareability, /// Access for the region - pub access: AccessPerms, + pub access: El1AccessPerms, /// Is region no-exec? pub no_exec: bool, /// Which Memory Attribute applies here? @@ -230,7 +396,52 @@ pub struct Region { // Creating a static Region is fine - the pointers within it // only go to the MPU and aren't accessed via Rust code -unsafe impl Sync for Region {} +unsafe impl Sync for El1Region {} + +/// Configuration for the PMSAv8-32 EL2 MPU +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct El2Config<'a> { + /// Background Config Enable + /// + /// If true, use the default MMU config if no other region matches an address + pub background_config: bool, + /// Information about each Region. + /// + /// If you pass more regions than the MPU supports, you get an error. + pub regions: &'a [El2Region], + /// Information about each Memory Attribute + /// + /// If you pass more MemAttrs than the MPU supports (8), you get an error. + pub memory_attributes: &'a [MemAttr], +} + +/// Configuration for the PMSAv8-32 EL2 MPU +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct El2Region { + /// The range of the region + /// + /// * The first address must be a multiple of 32. + /// * The length must be a multiple of 32. + pub range: core::ops::RangeInclusive<*mut u8>, + /// Shareability of the region + pub shareability: El2Shareability, + /// Access for the region + pub access: El2AccessPerms, + /// Is region no-exec? + pub no_exec: bool, + /// Which Memory Attribute applies here? + /// + /// Selects from the eight attributes in {HMAIR0, HMAIR1}. + /// + /// Only values 0..=7 are valid here. + pub mair: u8, + /// Is this region enabled? + pub enable: bool, +} + +// Creating a static El2Region is fine - the pointers within it +// only go to the MPU and aren't accessed via Rust code +unsafe impl Sync for El2Region {} /// Describes the memory ordering and cacheability of a region #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/cortex-ar/src/register/armv8r/hmpuir.rs b/cortex-ar/src/register/armv8r/hmpuir.rs index f3c8d44..28abf96 100644 --- a/cortex-ar/src/register/armv8r/hmpuir.rs +++ b/cortex-ar/src/register/armv8r/hmpuir.rs @@ -3,7 +3,13 @@ use crate::register::{SysReg, SysRegRead}; /// HMPUIR (*Hyp MPU Type Register*) -pub struct Hmpuir(pub u32); +#[bitbybit::bitfield(u32)] +pub struct Hmpuir { + /// The number of EL2 MPU regions implemented + #[bits(0..=7, r)] + region: u8, +} + impl SysReg for Hmpuir { const CP: u32 = 15; const CRN: u32 = 0; @@ -16,6 +22,6 @@ impl Hmpuir { #[inline] /// Reads HMPUIR (*Hyp MPU Type Register*) pub fn read() -> Hmpuir { - unsafe { Self(::read_raw()) } + unsafe { Self::new_with_raw_value(::read_raw()) } } } diff --git a/cortex-ar/src/register/armv8r/hprbar.rs b/cortex-ar/src/register/armv8r/hprbar.rs index 356846a..4fd3b10 100644 --- a/cortex-ar/src/register/armv8r/hprbar.rs +++ b/cortex-ar/src/register/armv8r/hprbar.rs @@ -1,9 +1,54 @@ //! Code for managing HPRBAR (*Hyp Protection Region Base Address Register*) +use arbitrary_int::u26; + use crate::register::{SysReg, SysRegRead, SysRegWrite}; +/// Shareability for an MPU Region +#[derive(Debug, PartialEq, Eq)] +#[bitbybit::bitenum(u2, exhaustive = true)] +pub enum Shareability { + /// Non-shareable + NonShareable = 0b00, + /// Reserved + Reserved = 0b01, + /// Outer-Shareable + OuterShareable = 0b10, + /// Inner-Shareable + InnerShareable = 0b11, +} + +/// Access Permissions for an MPU Region +#[derive(Debug, PartialEq, Eq)] +#[bitbybit::bitenum(u2, exhaustive = true)] +pub enum AccessPerms { + /// Read-Write at EL2, No access at EL1/0 + ReadWriteNoEL10 = 0b00, + /// Read-Write at EL2, EL1, and EL0 + ReadWrite = 0b01, + /// Read-Only at EL2, No access at EL1/0 + ReadOnlyNoEL10 = 0b10, + /// Read-Only at EL2, EL1, and EL0 + ReadOnly = 0b11, +} + /// HPRBAR (*Hyp Protection Region Base Address Register*) -pub struct Hprbar(pub u32); +#[bitbybit::bitfield(u32)] +pub struct Hprbar { + /// Base Address + #[bits(6..=31, rw)] + base: u26, + /// Shareability + #[bits(3..=4, rw)] + shareability: Shareability, + /// Access Permissions + #[bits(1..=2, rw)] + access_perms: AccessPerms, + /// Execute Never + #[bits(0..=0, rw)] + nx: bool, +} + impl SysReg for Hprbar { const CP: u32 = 15; const CRN: u32 = 6; @@ -16,20 +61,16 @@ impl Hprbar { #[inline] /// Reads HPRBAR (*Hyp Protection Region Base Address Register*) pub fn read() -> Hprbar { - unsafe { Self(::read_raw()) } + unsafe { Self::new_with_raw_value(::read_raw()) } } } impl crate::register::SysRegWrite for Hprbar {} impl Hprbar { #[inline] /// Writes HPRBAR (*Hyp Protection Region Base Address Register*) - /// - /// # Safety - /// - /// Ensure that this value is appropriate for this register - pub unsafe fn write(value: Self) { + pub fn write(value: Self) { unsafe { - ::write_raw(value.0); + ::write_raw(value.raw_value()); } } } diff --git a/cortex-ar/src/register/armv8r/hprlar.rs b/cortex-ar/src/register/armv8r/hprlar.rs index cff7b02..adbbad7 100644 --- a/cortex-ar/src/register/armv8r/hprlar.rs +++ b/cortex-ar/src/register/armv8r/hprlar.rs @@ -1,9 +1,23 @@ //! Code for managing HPRLAR (*Hyp Protection Region Limit Address Register*) +use arbitrary_int::{u26, u3}; + use crate::register::{SysReg, SysRegRead, SysRegWrite}; /// HPRLAR (*Hyp Protection Region Limit Address Register*) -pub struct Hprlar(pub u32); +#[bitbybit::bitfield(u32)] +pub struct Hprlar { + /// Length of region + #[bits(6..=31, rw)] + limit: u26, + /// Which HMAIR attribute to use + #[bits(1..=3, rw)] + mair: u3, + /// Is region enabled? + #[bits(0..=0, rw)] + enabled: bool, +} + impl SysReg for Hprlar { const CP: u32 = 15; const CRN: u32 = 6; @@ -16,20 +30,16 @@ impl Hprlar { #[inline] /// Reads HPRLAR (*Hyp Protection Region Limit Address Register*) pub fn read() -> Hprlar { - unsafe { Self(::read_raw()) } + unsafe { Self::new_with_raw_value(::read_raw()) } } } impl crate::register::SysRegWrite for Hprlar {} impl Hprlar { #[inline] /// Writes HPRLAR (*Hyp Protection Region Limit Address Register*) - /// - /// # Safety - /// - /// Ensure that this value is appropriate for this register - pub unsafe fn write(value: Self) { + pub fn write(value: Self) { unsafe { - ::write_raw(value.0); + ::write_raw(value.raw_value()); } } } diff --git a/cortex-ar/src/register/armv8r/hprselr.rs b/cortex-ar/src/register/armv8r/hprselr.rs index d6e43c4..89618f4 100644 --- a/cortex-ar/src/register/armv8r/hprselr.rs +++ b/cortex-ar/src/register/armv8r/hprselr.rs @@ -24,10 +24,8 @@ impl Hprselr { #[inline] /// Writes HPRSELR (*Hyp Protection Region Selection Register*) /// - /// # Safety - /// - /// Ensure that this value is appropriate for this register - pub unsafe fn write(value: Self) { + /// Controls what appears in HPRLAR and HPRBAR + pub fn write(value: Self) { unsafe { ::write_raw(value.0); } diff --git a/cortex-ar/src/register/armv8r/hsctlr.rs b/cortex-ar/src/register/armv8r/hsctlr.rs index 547ca4e..9abf5c4 100644 --- a/cortex-ar/src/register/armv8r/hsctlr.rs +++ b/cortex-ar/src/register/armv8r/hsctlr.rs @@ -3,7 +3,46 @@ use crate::register::{SysReg, SysRegRead, SysRegWrite}; /// HSCTLR (*Hyp System Control Register*) -pub struct Hsctlr(pub u32); +#[bitbybit::bitfield(u32)] +pub struct Hsctlr { + /// T32 Exception Enable. Controls whether exceptions to EL2 are taken to A32 or T32 state + #[bits(30..=30, rw)] + te: bool, + /// Exception Endianness. The value of the PSTATE.E bit on entry to Hyp mode + #[bits(25..=25, rw)] + ee: bool, + /// Fast Interrupts enable + #[bits(21..=21, rw)] + fi: bool, + /// Write permission implies XN (Execute-never) + #[bits(19..=19, rw)] + wxn: bool, + /// Background Region enable for EL2 + #[bits(17..=17, rw)] + br: bool, + /// Instruction access Cacheability control, for accesses at EL2 + #[bits(12..=12, rw)] + i: bool, + /// SETEND instruction disable. Disables SETEND instructions at EL2 + #[bits(8..=8, rw)] + sed: bool, + /// IT Disable. Disables some uses of IT instructions at EL2 + #[bits(7..=7, rw)] + itd: bool, + /// System instruction memory barrier enable + #[bits(5..=5, rw)] + cp15ben: bool, + /// Cacheability control, for data accesses at EL2 + #[bits(2..=2, rw)] + c: bool, + /// Alignment check enable + #[bits(1..=1, rw)] + a: bool, + /// MPU enable for the EL2 MPU + #[bits(0..=0, rw)] + m: bool, +} + impl SysReg for Hsctlr { const CP: u32 = 15; const CRN: u32 = 1; @@ -16,20 +55,26 @@ impl Hsctlr { #[inline] /// Reads HSCTLR (*Hyp System Control Register*) pub fn read() -> Hsctlr { - unsafe { Self(::read_raw()) } + unsafe { Self::new_with_raw_value(::read_raw()) } } } impl crate::register::SysRegWrite for Hsctlr {} impl Hsctlr { #[inline] /// Writes HSCTLR (*Hyp System Control Register*) - /// - /// # Safety - /// - /// Ensure that this value is appropriate for this register - pub unsafe fn write(value: Self) { + pub fn write(value: Self) { unsafe { - ::write_raw(value.0); + ::write_raw(value.raw_value()); } } + /// Read-modify-write this register + #[inline] + pub fn modify(f: F) + where + F: FnOnce(&mut Self), + { + let mut val = Self::read(); + f(&mut val); + Self::write(val); + } } diff --git a/examples/mps3-an536/reference/el2_hello-armv8r-none-eabihf.out b/examples/mps3-an536/reference/el2_hello-armv8r-none-eabihf.out new file mode 100644 index 0000000..a934b84 --- /dev/null +++ b/examples/mps3-an536/reference/el2_hello-armv8r-none-eabihf.out @@ -0,0 +1,27 @@ +Hello, this is semihosting! x = 1.000, y = 2.000 +Region 0: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 1: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 2: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 3: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 4: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 5: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 6: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 7: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 8: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 9: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 10: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 11: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 12: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 13: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 14: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +Region 15: El2Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL10, no_exec: false, mair: 0, enable: false } +PANIC: PanicInfo { + message: I am an example panic, + location: Location { + file: "src/bin/el2_hello.rs", + line: 31, + column: 5, + }, + can_unwind: true, + force_no_backtrace: false, +} diff --git a/examples/mps3-an536/reference/registers-armv8r-none-eabihf.out b/examples/mps3-an536/reference/registers-armv8r-none-eabihf.out index 2b4411f..39c2c55 100644 --- a/examples/mps3-an536/reference/registers-armv8r-none-eabihf.out +++ b/examples/mps3-an536/reference/registers-armv8r-none-eabihf.out @@ -3,37 +3,37 @@ CPSR { N=0 Z=1 C=1 V=0 Q=0 J=0 E=0 A=0 I=1 F=1 T=0 MODE=Ok(Sys) } IMP_CBAR { 0xf0000000 } VBAR { 0x08000000 } PMSA-v8 MPUIR: Mpuir { iregions: 0, dregions: 16, non_unified: false } -Region 0: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 1: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 2: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 3: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 4: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 5: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 6: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 7: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 8: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 9: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 10: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 11: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 12: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 13: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 14: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 15: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 0: Region { range: 0x0..=0x3fffffff, shareability: OuterShareable, access: ReadWrite, no_exec: true, mair: 0, enable: true } -Region 1: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 2: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 3: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 4: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 5: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 6: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 7: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 8: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 9: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 10: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 11: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 12: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 13: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 14: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } -Region 15: Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 0: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 1: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 2: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 3: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 4: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 5: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 6: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 7: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 8: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 9: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 10: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 11: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 12: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 13: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 14: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 15: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 0: El1Region { range: 0x0..=0x3fffffff, shareability: OuterShareable, access: ReadWrite, no_exec: true, mair: 0, enable: true } +Region 1: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 2: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 3: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 4: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 5: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 6: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 7: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 8: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 9: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 10: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 11: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 12: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 13: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 14: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } +Region 15: El1Region { range: 0x0..=0x3f, shareability: NonShareable, access: ReadWriteNoEL0, no_exec: false, mair: 0, enable: false } SCTLR { IE=0 TE=0 NMFI=0 EE=0 U=1 FI=0 DZ=1 BR=1 RR=0 V=0 I=0 Z=1 SW=0 C=0 A=0 M=0 } before setting C, I and Z SCTLR { IE=0 TE=0 NMFI=0 EE=0 U=1 FI=0 DZ=1 BR=1 RR=0 V=0 I=1 Z=1 SW=0 C=1 A=0 M=0 } after diff --git a/examples/mps3-an536/src/bin/el2_hello.rs b/examples/mps3-an536/src/bin/el2_hello.rs new file mode 100644 index 0000000..377b3e8 --- /dev/null +++ b/examples/mps3-an536/src/bin/el2_hello.rs @@ -0,0 +1,104 @@ +//! Semihosting hello-world for Arm Cortex-R52 running in EL2 (Hyp Mode) + +#![no_std] +#![no_main] + +// pull in our start-up code +use cortex_r_rt::entry; + +// pull in our library +use mps3_an536 as _; + +use cortex_ar::register::Hactlr; +use semihosting::println; + +/// The entry-point to the Rust application. +/// +/// It is called by the start-up code at the bottom of this file. +#[entry] +fn main() -> ! { + let x = 1.0f64; + let y = x * 2.0; + println!("Hello, this is semihosting! x = {:0.3}, y = {:0.3}", x, y); + + let mut mpu = unsafe { cortex_ar::pmsav8::El2Mpu::new() }; + for idx in 0..mpu.num_regions() { + if let Some(region) = mpu.get_region(idx) { + println!("Region {}: {:?}", idx, region); + } + } + + panic!("I am an example panic"); +} + +// Provide a custom `_start` function that sets us up in EL2 mode, with a +// stack. +// +// Unlike the default routine, it does not initialise any other stacks, or +// switch to EL1 mode. +core::arch::global_asm!( + r#" + // Work around https://github.com/rust-lang/rust/issues/127269 + .fpu vfp3-d16 + + .section .text.start + + .global _start + .type _start, %function + _start: + // Set stack pointer + ldr r0, =_stack_top + mov sp, r0 + ldr r1, =_hyp_stack_size + sub r0, r0, r1 + // Set the HVBAR (for EL2) to _vector_table + ldr r1, =_vector_table + mcr p15, 4, r1, c12, c0, 0 + // Configure HACTLR to let us enter EL1 + mrc p15, 4, r1, c1, c0, 1 + mov r2, {hactlr_bits} + orr r1, r1, r2 + mcr p15, 4, r1, c1, c0, 1 + // Init .data and .bss + bl _init_segments + // Allow VFP coprocessor access + mrc p15, 0, r0, c1, c0, 2 + orr r0, r0, #0xF00000 + mcr p15, 0, r0, c1, c0, 2 + // Enable VFP + mov r0, #0x40000000 + vmsr fpexc, r0 + // Zero all registers before calling kmain + mov r0, 0 + mov r1, 0 + mov r2, 0 + mov r3, 0 + mov r4, 0 + mov r5, 0 + mov r6, 0 + mov r7, 0 + mov r8, 0 + mov r9, 0 + mov r10, 0 + mov r11, 0 + mov r12, 0 + // Jump to application + bl kmain + // In case the application returns, loop forever + b . + .size _start, . - _start + "#, + hactlr_bits = const { + Hactlr::new_with_raw_value(0) + .with_cpuactlr(true) + .with_cdbgdci(true) + .with_flashifregionr(true) + .with_periphpregionr(true) + .with_qosr(true) + .with_bustimeoutr(true) + .with_intmonr(true) + .with_err(true) + .with_testr1(true) + .raw_value() + }, +); diff --git a/examples/mps3-an536/src/bin/registers.rs b/examples/mps3-an536/src/bin/registers.rs index f22453d..402aeb8 100644 --- a/examples/mps3-an536/src/bin/registers.rs +++ b/examples/mps3-an536/src/bin/registers.rs @@ -94,7 +94,8 @@ fn mpu_pmsa_v7() { fn mpu_pmsa_v8() { use cortex_ar::{ pmsav8::{ - AccessPerms, Cacheable, Config, El1Mpu, MemAttr, Region, RwAllocPolicy, Shareability, + Cacheable, El1AccessPerms, El1Config, El1Mpu, El1Region, El1Shareability, MemAttr, + RwAllocPolicy, }, register::Mpuir, }; @@ -114,12 +115,12 @@ fn mpu_pmsa_v8() { } // Load a config (but don't enable it) - mpu.configure(&Config { + mpu.configure(&El1Config { background_config: true, - regions: &[Region { + regions: &[El1Region { range: 0x0000_0000 as *mut u8..=0x3FFF_FFFF as *mut u8, - shareability: Shareability::OuterShareable, - access: AccessPerms::ReadWrite, + shareability: El1Shareability::OuterShareable, + access: El1AccessPerms::ReadWrite, no_exec: true, mair: 0, enable: true,