diff --git a/aarch32-cpu/src/pmsav8.rs b/aarch32-cpu/src/pmsav8.rs index 0f82f65..91be34e 100644 --- a/aarch32-cpu/src/pmsav8.rs +++ b/aarch32-cpu/src/pmsav8.rs @@ -23,7 +23,7 @@ pub enum Error { /// Found an invalid MAIR selector (only 0..=7 is valid) InvalidMair(u8), /// Found a region with invalid alignment - UnalignedRegion(core::ops::RangeInclusive<*mut u8>), + UnalignedRegion(core::ops::RangeInclusive<*const u8>), } /// Represents our PMSAv8-32 EL1 MPU @@ -224,8 +224,8 @@ impl El2Mpu { 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; + let start_addr = (hprbar.base().value() << 6) as *const u8; + let end_addr = ((hprlar.limit().value() << 6) | 0x3F) as *const u8; Some(El2Region { range: start_addr..=end_addr, shareability: hprbar.shareability(), @@ -385,7 +385,7 @@ pub struct El1Region { /// /// * The first address must be a multiple of 32. /// * The length must be a multiple of 32. - pub range: core::ops::RangeInclusive<*mut u8>, + pub range: core::ops::RangeInclusive<*const u8>, /// Shareability of the region pub shareability: El1Shareability, /// Access for the region @@ -430,7 +430,7 @@ pub struct El2Region { /// /// * The first address must be a multiple of 32. /// * The length must be a multiple of 32. - pub range: core::ops::RangeInclusive<*mut u8>, + pub range: core::ops::RangeInclusive<*const u8>, /// Shareability of the region pub shareability: El2Shareability, /// Access for the region diff --git a/aarch32-cpu/src/register/armv8r/prbar.rs b/aarch32-cpu/src/register/armv8r/prbar.rs index e67d741..4acabd1 100644 --- a/aarch32-cpu/src/register/armv8r/prbar.rs +++ b/aarch32-cpu/src/register/armv8r/prbar.rs @@ -83,7 +83,7 @@ impl Prbar { } /// Get the base address - pub fn base_address(self) -> *mut u8 { - (self.base().as_usize() << 6) as *mut u8 + pub fn base_address(self) -> *const u8 { + (self.base().as_usize() << 6) as *const u8 } } diff --git a/aarch32-cpu/src/register/armv8r/prlar.rs b/aarch32-cpu/src/register/armv8r/prlar.rs index f045ff8..6285fef 100644 --- a/aarch32-cpu/src/register/armv8r/prlar.rs +++ b/aarch32-cpu/src/register/armv8r/prlar.rs @@ -48,7 +48,7 @@ impl Prlar { } /// Gets the limit address - pub fn limit_address(self) -> *mut u8 { - ((self.limit().as_usize() << 6) | 0b111_111) as *mut u8 + pub fn limit_address(self) -> *const u8 { + ((self.limit().as_usize() << 6) | 0b111_111) as *const u8 } } diff --git a/aarch32-rt/link.x b/aarch32-rt/link.x index 09f77f0..309e3bc 100644 --- a/aarch32-rt/link.x +++ b/aarch32-rt/link.x @@ -56,18 +56,26 @@ SECTIONS { * May include FIQ handler code at the end. */ .vector_table ORIGIN(VECTORS) : { + __svector = .; + *(.vector_table) + + . = ALIGN(_region_alignment); + + __evector = .; } > VECTORS /* # Text * * Our executable code. */ - .text : { + .text : ALIGN(_region_alignment) { __stext = .; *(.text .text*) + . = ALIGN(_region_alignment); + __etext = .; } > CODE @@ -75,11 +83,13 @@ SECTIONS { * * Our constants. */ - .rodata : { + .rodata : ALIGN(_region_alignment) { __srodata = .; *(.rodata .rodata*) + . = ALIGN(_region_alignment); + __erodata = .; } > CODE @@ -87,13 +97,13 @@ SECTIONS { * * Our global variables that are not initialised to zero. */ - .data : ALIGN(4) { - . = ALIGN(4); + .data : ALIGN(_region_alignment) { + . = ALIGN(_region_alignment); __sdata = .; *(.data .data.*); - . = ALIGN(4); + . = ALIGN(_region_alignment); /* NB: __edata defined lower down */ } > DATA AT>CODE @@ -102,7 +112,7 @@ SECTIONS { * use the .data loading mechanism by pushing __edata. Note: do not change * output region or load region in those user sections! */ - . = ALIGN(4); + . = ALIGN(_region_alignment); __edata = .; /* LMA of .data */ @@ -112,13 +122,13 @@ SECTIONS { * * Our global variables that *are* initialised to zero. */ - .bss (NOLOAD) : ALIGN(4) { - . = ALIGN(4); + .bss (NOLOAD) : ALIGN(_region_alignment) { + . = ALIGN(_region_alignment); __sbss = .; *(.bss .bss* COMMON) - . = ALIGN(4); + . = ALIGN(_region_alignment); /* NB: __ebss defined lower down */ } > DATA @@ -133,18 +143,17 @@ SECTIONS { * * Our global variables that have no defined initial value. */ - .uninit (NOLOAD) : ALIGN(4) + .uninit (NOLOAD) : ALIGN(_region_alignment) { - . = ALIGN(4); + . = ALIGN(_region_alignment); __suninit = .; *(.uninit .uninit.*); - . = ALIGN(4); + . = ALIGN(_region_alignment); __euninit = .; } > DATA - /* # Stack Padding * * A padding region to push the stacks to the top of the STACKS region. @@ -164,9 +173,9 @@ SECTIONS { * * Space for all seven stacks. */ - .stacks (NOLOAD) : ALIGN(8) + .stacks (NOLOAD) : ALIGN(_stack_alignment) { - . = ALIGN(8); + . = ALIGN(_stack_alignment); /* Lowest address of allocated stack */ _stacks_low_end = .; @@ -176,31 +185,43 @@ SECTIONS { . += (_und_stack_size * _num_cores); _und_stack_high_end = .; + . += _inter_stack_padding; + /* Stack for SVC mode */ _svc_stack_low_end = .; . += (_svc_stack_size * _num_cores); _svc_stack_high_end = .; + . += _inter_stack_padding; + /* Stack for ABT mode */ _abt_stack_low_end = .; . += (_abt_stack_size * _num_cores); _abt_stack_high_end = .; + . += _inter_stack_padding; + /* Stack for HYP mode */ _hyp_stack_low_end = .; . += (_hyp_stack_size * _num_cores); _hyp_stack_high_end = .; + . += _inter_stack_padding; + /* Stack for IRQ mode */ _irq_stack_low_end = .; . += (_irq_stack_size * _num_cores); _irq_stack_high_end = .; + . += _inter_stack_padding; + /* Stack for FIQ mode */ _fiq_stack_low_end = .; . += (_fiq_stack_size * _num_cores); _fiq_stack_high_end = .; + . += _inter_stack_padding; + /* Stack for SYS mode */ _sys_stack_low_end = .; . += (_sys_stack_size * _num_cores); @@ -233,6 +254,16 @@ PROVIDE(_sys_stack_size = 16K); /* Default to one CPU core (i.e. one copy of each stack) */ PROVIDE(_num_cores = 1); +/* Default stack alignment. You can over-align if you want to set up MPU regions for the stacks */ +PROVIDE(_stack_alignment = 8); + +/* Default region alignment. You can over-align if you want to set up MPU regions for the stacks */ +PROVIDE(_region_alignment = 4); + +/* Default to no padding between stacks. You might want padding if you want turn on the MPU and */ +/* only have a single core (so the stacks are otherwise contiguous) */ +PROVIDE(_inter_stack_padding = 0); + /* Set this to 1 in memory.x to remove the filler section pushing the stacks to the end of STACKS. */ PROVIDE(_pack_stacks = 0); @@ -257,21 +288,31 @@ PROVIDE(_data_abort_handler = _default_handler); PROVIDE(_irq_handler = _default_handler); /* NB: There is no default C-language FIQ handler */ -/* Check the stack sizes are all a multiple of eight bytes */ -ASSERT(_und_stack_size % 8 == 0, " -ERROR(aarch32-rt): UND stack size (_und_stack_size) is not a multiple of 8 bytes"); -ASSERT(_svc_stack_size % 8 == 0, " -ERROR(aarch32-rt): SVC stack size (_svc_stack_size) is not a multiple of 8 bytes"); -ASSERT(_abt_stack_size % 8 == 0, " -ERROR(aarch32-rt): ABT stack size (_abt_stack_size) is not a multiple of 8 bytes"); -ASSERT(_hyp_stack_size % 8 == 0, " -ERROR(aarch32-rt): HYP stack size (_hyp_stack_size) is not a multiple of 8 bytes"); -ASSERT(_irq_stack_size % 8 == 0, " -ERROR(aarch32-rt): IRQ stack size (_irq_stack_size) is not a multiple of 8 bytes"); -ASSERT(_fiq_stack_size % 8 == 0, " -ERROR(aarch32-rt): FIQ stack size (_fiq_stack_size) is not a multiple of 8 bytes"); -ASSERT(_sys_stack_size % 8 == 0, " -ERROR(aarch32-rt): SYS stack size (_sys_stack_size) is not a multiple of 8 bytes"); +/* Check the values are all reasonable */ +ASSERT(_region_alignment % 4 == 0, " +ERROR(aarch32-rt): Region alignment (_region_alignment) is not a multiple of 4 bytes"); +ASSERT(_region_alignment >= 4, " +ERROR(aarch32-rt): Region alignment (_region_alignment) is not at least eight bytes"); +ASSERT(_stack_alignment % 8 == 0, " +ERROR(aarch32-rt): Stack alignment (_stack_alignment) is not a multiple of 8 bytes"); +ASSERT(_stack_alignment >= 8, " +ERROR(aarch32-rt): Stack alignment (_stack_alignment) is not at least eight bytes"); +ASSERT(_inter_stack_padding % _stack_alignment == 0, " +ERROR(aarch32-rt): Inter-Stack padding (_inter_stack_padding) is not a multiple of of the stack alignment"); +ASSERT(_und_stack_size % _stack_alignment == 0, " +ERROR(aarch32-rt): UND stack size (_und_stack_size) is not a multiple of the stack alignment"); +ASSERT(_svc_stack_size % _stack_alignment == 0, " +ERROR(aarch32-rt): SVC stack size (_svc_stack_size) is not a multiple of the stack alignment"); +ASSERT(_abt_stack_size % _stack_alignment == 0, " +ERROR(aarch32-rt): ABT stack size (_abt_stack_size) is not a multiple of the stack alignment"); +ASSERT(_hyp_stack_size % _stack_alignment == 0, " +ERROR(aarch32-rt): HYP stack size (_hyp_stack_size) is not a multiple of the stack alignment"); +ASSERT(_irq_stack_size % _stack_alignment == 0, " +ERROR(aarch32-rt): IRQ stack size (_irq_stack_size) is not a multiple of the stack alignment"); +ASSERT(_fiq_stack_size % _stack_alignment == 0, " +ERROR(aarch32-rt): FIQ stack size (_fiq_stack_size) is not a multiple of the stack alignment"); +ASSERT(_sys_stack_size % _stack_alignment == 0, " +ERROR(aarch32-rt): SYS stack size (_sys_stack_size) is not a multiple of the stack alignment"); ASSERT(_num_cores != 0, " ERROR(aarch32-rt): Number of cores cannot be zero"); diff --git a/aarch32-rt/src/lib.rs b/aarch32-rt/src/lib.rs index 03d4929..2ff0dca 100644 --- a/aarch32-rt/src/lib.rs +++ b/aarch32-rt/src/lib.rs @@ -558,6 +558,7 @@ mod arch_v7; ))] mod arch_v4; +pub mod sections; pub mod stacks; /// Our default exception handler. diff --git a/aarch32-rt/src/sections.rs b/aarch32-rt/src/sections.rs new file mode 100644 index 0000000..87eec9c --- /dev/null +++ b/aarch32-rt/src/sections.rs @@ -0,0 +1,158 @@ +//! Code to get the memory regions from the linker script +//! +//! This is useful if you want to set up the MPU + +/// Represents one of the memory regions in the linker script +#[derive(Debug, Copy, Clone)] +pub enum Section { + /// The .vector_table section + /// + /// Contains the reset and exception vectors + VectorTable, + /// The .text section + /// + /// Contains the executable code + Text, + /// The .rodata section + /// + /// Contains read-only static data + Rodata, + /// The .bss section + /// + /// Contains zero-initialised static data + Bss, + /// The .data section + /// + /// Contains non-zero-initialised static data + Data, + /// The .uninit section + /// + /// Contains non-initialised static data + Uninit, +} + +impl core::fmt::Display for Section { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.pad(match self { + Section::VectorTable => ".vector_table", + Section::Text => ".text", + Section::Rodata => ".rodata", + Section::Bss => ".bss", + Section::Data => ".data", + Section::Uninit => ".uninit", + }) + } +} + +impl Section { + /// Create an iterator over all the regions + pub fn iter() -> impl Iterator { + SectionIter::new() + } + + /// Get the highest address of this region + /// + /// Technically it gets *one past the end* of the region. + pub fn top(&self) -> *const u8 { + use core::ptr::addr_of; + unsafe extern "C" { + static __evector: u8; + static __etext: u8; + static __erodata: u8; + static __ebss: u8; + static __edata: u8; + static __euninit: u8; + } + match self { + Section::VectorTable => addr_of!(__evector), + Section::Text => addr_of!(__etext), + Section::Rodata => addr_of!(__erodata), + Section::Bss => addr_of!(__ebss), + Section::Data => addr_of!(__edata), + Section::Uninit => addr_of!(__euninit), + } + } + + /// Get the lowest address of this region + pub fn bottom(&self) -> *const u8 { + use core::ptr::addr_of; + unsafe extern "C" { + static __svector: u8; + static __stext: u8; + static __srodata: u8; + static __sbss: u8; + static __sdata: u8; + static __suninit: u8; + } + match self { + Section::VectorTable => addr_of!(__svector), + Section::Text => addr_of!(__stext), + Section::Rodata => addr_of!(__srodata), + Section::Bss => addr_of!(__sbss), + Section::Data => addr_of!(__sdata), + Section::Uninit => addr_of!(__suninit), + } + } + + /// Get the range of this region. + pub fn range(&self) -> Option> { + let bottom = self.bottom(); + let top = self.top(); + if bottom != top { + Some(bottom..top) + } else { + None + } + } + + /// Get the inclusive range of this region. + /// + /// This is the range you need to give to the PMSAv8 MPU code. + pub fn mpu_range(&self) -> Option> { + let bottom = self.bottom(); + let top = self.top(); + let top_under = unsafe { top.offset(-1) }; + if bottom != top { + Some(bottom..=top_under) + } else { + None + } + } +} + +/// Iterator over all the [`Region`] variants +pub struct SectionIter { + next: Option
, +} + +impl SectionIter { + /// Create a new [`RegionIter`] + pub fn new() -> Self { + Self { + next: Some(Section::VectorTable), + } + } +} + +impl Default for SectionIter { + fn default() -> Self { + SectionIter::new() + } +} + +impl Iterator for SectionIter { + type Item = Section; + + fn next(&mut self) -> Option { + let current = self.next; + self.next = match self.next { + Some(Section::VectorTable) => Some(Section::Text), + Some(Section::Text) => Some(Section::Rodata), + Some(Section::Rodata) => Some(Section::Bss), + Some(Section::Bss) => Some(Section::Data), + Some(Section::Data) => Some(Section::Uninit), + Some(Section::Uninit) | None => None, + }; + current + } +} diff --git a/aarch32-rt/src/stacks.rs b/aarch32-rt/src/stacks.rs index 6de2b2f..9a889ed 100644 --- a/aarch32-rt/src/stacks.rs +++ b/aarch32-rt/src/stacks.rs @@ -21,36 +21,22 @@ pub enum Stack { impl core::fmt::Display for Stack { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!( - f, - "{}", - match self { - Stack::Und => "UND", - Stack::Svc => "SVC", - Stack::Abt => "ABT", - Stack::Hyp => "HYP", - Stack::Irq => "IRQ", - Stack::Fiq => "FIQ", - Stack::Sys => "SYS", - } - ) + f.pad(match self { + Stack::Und => "UND", + Stack::Svc => "SVC", + Stack::Abt => "ABT", + Stack::Hyp => "HYP", + Stack::Irq => "IRQ", + Stack::Fiq => "FIQ", + Stack::Sys => "SYS", + }) } } impl Stack { /// Create an iterator over all the stacks pub fn iter() -> impl Iterator { - [ - Stack::Und, - Stack::Svc, - Stack::Abt, - Stack::Hyp, - Stack::Irq, - Stack::Fiq, - Stack::Sys, - ] - .iter() - .cloned() + StackIter::new() } /// Get the highest address of this stack, for the given core @@ -79,6 +65,20 @@ impl Stack { } } + /// Get the inclusive range of this stack, for the given core + /// + /// This is the range you need to give to the PMSAv8 MPU code. + pub fn mpu_range(&self, core: usize) -> Option> { + if let (Some(bottom), Some(top)) = (self.bottom(core), self.top(core)) { + let top = top as *const u8; + let bottom = bottom as *const u8; + let top_under = unsafe { top.offset(-1) }; + Some(bottom..=top_under) + } else { + None + } + } + /// Get number of cores in this system pub fn num_cores() -> usize { unsafe extern "C" { @@ -134,3 +134,41 @@ impl Stack { } } } + +/// Iterator over all the [`Stack`] variants +pub struct StackIter { + next: Option, +} + +impl StackIter { + /// Create a new [`StackIter`] + pub fn new() -> Self { + Self { + next: Some(Stack::Und), + } + } +} + +impl Default for StackIter { + fn default() -> Self { + StackIter::new() + } +} + +impl Iterator for StackIter { + type Item = Stack; + + fn next(&mut self) -> Option { + let current = self.next; + self.next = match self.next { + Some(Stack::Und) => Some(Stack::Svc), + Some(Stack::Svc) => Some(Stack::Abt), + Some(Stack::Abt) => Some(Stack::Hyp), + Some(Stack::Hyp) => Some(Stack::Irq), + Some(Stack::Irq) => Some(Stack::Fiq), + Some(Stack::Fiq) => Some(Stack::Sys), + Some(Stack::Sys) | None => None, + }; + current + } +} diff --git a/examples/mps3-an536/memory.x b/examples/mps3-an536/memory.x index 0015807..78257eb 100644 --- a/examples/mps3-an536/memory.x +++ b/examples/mps3-an536/memory.x @@ -32,8 +32,7 @@ SECTIONS { /* We put this in the header */ __irq_entries_end = .; } > CODE -} INSERT AFTER .text; - +} INSERT AFTER .rodata; PROVIDE(_hyp_stack_size = 16K); PROVIDE(_und_stack_size = 16K); @@ -42,3 +41,6 @@ PROVIDE(_abt_stack_size = 16K); PROVIDE(_irq_stack_size = 64); PROVIDE(_fiq_stack_size = 64); PROVIDE(_sys_stack_size = 16K); +PROVIDE(_stack_alignment = 64); +PROVIDE(_inter_stack_padding = 64); +PROVIDE(_region_alignment = 64K); diff --git a/examples/mps3-an536/reference/mpu_setup-armv8r-none-eabihf.out b/examples/mps3-an536/reference/mpu_setup-armv8r-none-eabihf.out new file mode 100644 index 0000000..7c873ea --- /dev/null +++ b/examples/mps3-an536/reference/mpu_setup-armv8r-none-eabihf.out @@ -0,0 +1,27 @@ + UND @ 0x1006be00..=0x1006fdff + SVC @ 0x1006fe40..=0x10073e3f + ABT @ 0x10073e80..=0x10077e7f + HYP @ 0x10077ec0..=0x1007bebf + IRQ @ 0x1007bf00..=0x1007bf3f + FIQ @ 0x1007bf80..=0x1007bfbf + SYS @ 0x1007c000..=0x1007ffff +.vector_table @ 0x08000000..=0x0800ffff + .text @ 0x08010000..=0x0801ffff + .rodata @ 0x08020000..=0x0802ffff + .data @ 0x10000000..=0x0fffffff + .bss @ 0x10000000..=0x1000ffff + .uninit @ 0x10010000..=0x1000ffff +Region 00: El1Region { range: 0x1006be00..=0x1006fdff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 01: El1Region { range: 0x1006fe40..=0x10073e3f, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 02: El1Region { range: 0x10073e80..=0x10077e7f, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 03: El1Region { range: 0x10077ec0..=0x1007bebf, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 04: El1Region { range: 0x1007bf00..=0x1007bf3f, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 05: El1Region { range: 0x1007bf80..=0x1007bfbf, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 06: El1Region { range: 0x1007c000..=0x1007ffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 07: El1Region { range: 0x08000000..=0x0800ffff, shareability: NonShareable, access: ReadOnly, no_exec: false , mair: 0000000000, enable: true } +Region 08: El1Region { range: 0x08010000..=0x0801ffff, shareability: NonShareable, access: ReadOnly, no_exec: false , mair: 0000000000, enable: true } +Region 09: El1Region { range: 0x08020000..=0x0802ffff, shareability: NonShareable, access: ReadOnly, no_exec: true , mair: 0000000000, enable: true } +Region 10: El1Region { range: 0x10000000..=0x0fffffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 11: El1Region { range: 0x10000000..=0x1000ffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 12: El1Region { range: 0x10010000..=0x1000ffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 13: El1Region { range: 0xe0000000..=0xffffffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000002, enable: true } diff --git a/examples/mps3-an536/reference/mpu_setup-thumbv8r-none-eabihf.out b/examples/mps3-an536/reference/mpu_setup-thumbv8r-none-eabihf.out new file mode 100644 index 0000000..7c873ea --- /dev/null +++ b/examples/mps3-an536/reference/mpu_setup-thumbv8r-none-eabihf.out @@ -0,0 +1,27 @@ + UND @ 0x1006be00..=0x1006fdff + SVC @ 0x1006fe40..=0x10073e3f + ABT @ 0x10073e80..=0x10077e7f + HYP @ 0x10077ec0..=0x1007bebf + IRQ @ 0x1007bf00..=0x1007bf3f + FIQ @ 0x1007bf80..=0x1007bfbf + SYS @ 0x1007c000..=0x1007ffff +.vector_table @ 0x08000000..=0x0800ffff + .text @ 0x08010000..=0x0801ffff + .rodata @ 0x08020000..=0x0802ffff + .data @ 0x10000000..=0x0fffffff + .bss @ 0x10000000..=0x1000ffff + .uninit @ 0x10010000..=0x1000ffff +Region 00: El1Region { range: 0x1006be00..=0x1006fdff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 01: El1Region { range: 0x1006fe40..=0x10073e3f, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 02: El1Region { range: 0x10073e80..=0x10077e7f, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 03: El1Region { range: 0x10077ec0..=0x1007bebf, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 04: El1Region { range: 0x1007bf00..=0x1007bf3f, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 05: El1Region { range: 0x1007bf80..=0x1007bfbf, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 06: El1Region { range: 0x1007c000..=0x1007ffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 07: El1Region { range: 0x08000000..=0x0800ffff, shareability: NonShareable, access: ReadOnly, no_exec: false , mair: 0000000000, enable: true } +Region 08: El1Region { range: 0x08010000..=0x0801ffff, shareability: NonShareable, access: ReadOnly, no_exec: false , mair: 0000000000, enable: true } +Region 09: El1Region { range: 0x08020000..=0x0802ffff, shareability: NonShareable, access: ReadOnly, no_exec: true , mair: 0000000000, enable: true } +Region 10: El1Region { range: 0x10000000..=0x0fffffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 11: El1Region { range: 0x10000000..=0x1000ffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 12: El1Region { range: 0x10010000..=0x1000ffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000001, enable: true } +Region 13: El1Region { range: 0xe0000000..=0xffffffff, shareability: NonShareable, access: ReadWrite, no_exec: true , mair: 0000000002, enable: true } diff --git a/examples/mps3-an536/src/bin/hvc-a32.rs b/examples/mps3-an536/src/bin/hvc-a32.rs index 2e48231..7dad76a 100644 --- a/examples/mps3-an536/src/bin/hvc-a32.rs +++ b/examples/mps3-an536/src/bin/hvc-a32.rs @@ -27,7 +27,7 @@ fn main() -> ! { fn hvc_handler(hsr: u32, frame: &aarch32_rt::Frame) -> u32 { let hsr = aarch32_cpu::register::Hsr::new_with_raw_value(hsr); println!("In hvc_handler, with {:08x?}, {:08x?}", hsr, frame); - return 0x12345678; + 0x12345678 } #[instruction_set(arm::a32)] diff --git a/examples/mps3-an536/src/bin/hvc-t32.rs b/examples/mps3-an536/src/bin/hvc-t32.rs index 4d0ce58..631bde1 100644 --- a/examples/mps3-an536/src/bin/hvc-t32.rs +++ b/examples/mps3-an536/src/bin/hvc-t32.rs @@ -27,7 +27,7 @@ fn main() -> ! { fn hvc_handler(hsr: u32, frame: &aarch32_rt::Frame) -> u32 { let hsr = aarch32_cpu::register::Hsr::new_with_raw_value(hsr); println!("In hvc_handler, with {:08x?}, {:08x?}", hsr, frame); - return 0x12345678; + 0x12345678 } #[instruction_set(arm::t32)] diff --git a/examples/mps3-an536/src/bin/mpu_setup.rs b/examples/mps3-an536/src/bin/mpu_setup.rs new file mode 100644 index 0000000..ae84cac --- /dev/null +++ b/examples/mps3-an536/src/bin/mpu_setup.rs @@ -0,0 +1,206 @@ +//! Stack-overflow check for Arm Cortex-R +//! +//! Uses the MPU to protect each stack + +#![no_std] +#![no_main] + +use aarch32_cpu::pmsav8::{ + Cacheable, El1AccessPerms, El1Mpu, El1Region, El1Shareability, MemAttr, RwAllocPolicy, +}; +use aarch32_rt::{entry, sections::Section, stacks::Stack}; +use semihosting::println; + +use mps3_an536 as _; + +unsafe extern "C" { + static __stext: u8; + static __etext: u8; + static __srodata: u8; + static __erodata: u8; + static __sdata: u8; + static __edata: u8; + static __sbss: u8; + static __ebss: u8; +} + +const MAIR_READ_ONLY: u8 = 0; +const MAIR_READ_WRITE: u8 = 1; +const MAIR_DEVICE: u8 = 2; + +static MEM_ATTRS: [MemAttr; 8] = [ + // Read-only Code RAM + MemAttr::NormalMemory { + outer: Cacheable::WriteThroughNonTransient(RwAllocPolicy::R), + inner: Cacheable::WriteThroughNonTransient(RwAllocPolicy::R), + }, + // Read-write RAM + MemAttr::NormalMemory { + outer: Cacheable::WriteBackNonTransient(RwAllocPolicy::W), + inner: Cacheable::WriteBackNonTransient(RwAllocPolicy::W), + }, + // Device Memory + MemAttr::DeviceMemory, + // Spare entries + MemAttr::DeviceMemory, + MemAttr::DeviceMemory, + MemAttr::DeviceMemory, + MemAttr::DeviceMemory, + MemAttr::DeviceMemory, +]; + +/// The entry-point to the Rust application. +/// +/// It is called by the start-up code in `aarch32-rt`. +#[entry] +fn main() -> ! { + let mut mpu = unsafe { El1Mpu::new() }; + + mpu.set_attributes(&MEM_ATTRS); + + let mut last = 0; + for (idx, stack) in Stack::iter().enumerate() { + let range = stack.mpu_range(0).unwrap(); + println!("{:>13} @ {:010x?}", stack, range); + + let region = El1Region { + range, + shareability: El1Shareability::NonShareable, + access: El1AccessPerms::ReadWrite, + no_exec: true, + mair: MAIR_READ_WRITE, + enable: true, + }; + mpu.set_region(idx as u8, ®ion).unwrap(); + last = idx as u8; + } + + let mut next = last + 1; + + if let Some(range) = Section::VectorTable.mpu_range() { + println!("{:>13} @ {:010x?}", Section::VectorTable, range); + mpu.set_region( + next, + &El1Region { + range, + shareability: El1Shareability::NonShareable, + access: El1AccessPerms::ReadOnly, + no_exec: false, + mair: MAIR_READ_ONLY, + enable: true, + }, + ) + .unwrap(); + next += 1; + } + + if let Some(range) = Section::Text.mpu_range() { + println!("{:>13} @ {:010x?}", Section::Text, range); + mpu.set_region( + next, + &El1Region { + range, + shareability: El1Shareability::NonShareable, + access: El1AccessPerms::ReadOnly, + no_exec: false, + mair: MAIR_READ_ONLY, + enable: true, + }, + ) + .unwrap(); + next += 1; + } + + if let Some(range) = Section::Rodata.mpu_range() { + println!("{:>13} @ {:010x?}", Section::Rodata, range); + mpu.set_region( + next, + &El1Region { + range, + shareability: El1Shareability::NonShareable, + access: El1AccessPerms::ReadOnly, + no_exec: true, + mair: MAIR_READ_ONLY, + enable: true, + }, + ) + .unwrap(); + next += 1; + } + + if let Some(range) = Section::Data.mpu_range() { + println!("{:>13} @ {:010x?}", Section::Data, range); + mpu.set_region( + next, + &El1Region { + range, + shareability: El1Shareability::NonShareable, + access: El1AccessPerms::ReadWrite, + no_exec: true, + mair: MAIR_READ_WRITE, + enable: true, + }, + ) + .unwrap(); + next += 1; + } + + if let Some(range) = Section::Bss.mpu_range() { + println!("{:>13} @ {:010x?}", Section::Bss, range); + mpu.set_region( + next, + &El1Region { + range, + shareability: El1Shareability::NonShareable, + access: El1AccessPerms::ReadWrite, + no_exec: true, + mair: MAIR_READ_WRITE, + enable: true, + }, + ) + .unwrap(); + next += 1; + } + + if let Some(range) = Section::Uninit.mpu_range() { + println!("{:>13} @ {:010x?}", Section::Uninit, range); + mpu.set_region( + next, + &El1Region { + range, + shareability: El1Shareability::NonShareable, + access: El1AccessPerms::ReadWrite, + no_exec: true, + mair: MAIR_READ_WRITE, + enable: true, + }, + ) + .unwrap(); + next += 1; + } + + mpu.set_region( + next, + &El1Region { + range: 0xE000_0000 as *const u8..=0xFFFF_FFFF as *const u8, + shareability: El1Shareability::NonShareable, + access: El1AccessPerms::ReadWrite, + no_exec: true, + mair: MAIR_DEVICE, + enable: true, + }, + ) + .unwrap(); + + mpu.enable(); + + for idx in 0..mpu.num_regions() { + if let Some(region) = mpu.get_region(idx) + && region.enable + { + println!("Region {:02}: {:010x?}", idx, region); + } + } + + mps3_an536::exit(0); +} diff --git a/examples/mps3-an536/src/bin/registers.rs b/examples/mps3-an536/src/bin/registers.rs index 2522b0b..46cb0b9 100644 --- a/examples/mps3-an536/src/bin/registers.rs +++ b/examples/mps3-an536/src/bin/registers.rs @@ -63,7 +63,7 @@ fn mpu_pmsa_v7() { mpu.configure(&Config { background_config: true, dregions: &[Region { - base: 0x2000_0000 as *mut u8, + base: 0x2000_0000 as *const u8, size: RegionSize::_16M, subregion_mask: 0x00, enabled: true, @@ -132,7 +132,7 @@ fn mpu_pmsa_v8() { background_config: true, regions: &[ El1Region { - range: 0x0000_0000 as *mut u8..=0x0FFF_FFFF as *mut u8, + range: 0x0000_0000 as *const u8..=0x0FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -140,7 +140,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0x1000_0000 as *mut u8..=0x1FFF_FFFF as *mut u8, + range: 0x1000_0000 as *const u8..=0x1FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -148,7 +148,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0x2000_0000 as *mut u8..=0x2FFF_FFFF as *mut u8, + range: 0x2000_0000 as *const u8..=0x2FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -156,7 +156,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0x3000_0000 as *mut u8..=0x3FFF_FFFF as *mut u8, + range: 0x3000_0000 as *const u8..=0x3FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -164,7 +164,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0x4000_0000 as *mut u8..=0x4FFF_FFFF as *mut u8, + range: 0x4000_0000 as *const u8..=0x4FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -172,7 +172,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0x5000_0000 as *mut u8..=0x5FFF_FFFF as *mut u8, + range: 0x5000_0000 as *const u8..=0x5FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -180,7 +180,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0x6000_0000 as *mut u8..=0x6FFF_FFFF as *mut u8, + range: 0x6000_0000 as *const u8..=0x6FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -188,7 +188,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0x7000_0000 as *mut u8..=0x7FFF_FFFF as *mut u8, + range: 0x7000_0000 as *const u8..=0x7FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -196,7 +196,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0x8000_0000 as *mut u8..=0x8FFF_FFFF as *mut u8, + range: 0x8000_0000 as *const u8..=0x8FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -204,7 +204,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0x9000_0000 as *mut u8..=0x9FFF_FFFF as *mut u8, + range: 0x9000_0000 as *const u8..=0x9FFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -212,7 +212,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0xA000_0000 as *mut u8..=0xAFFF_FFFF as *mut u8, + range: 0xA000_0000 as *const u8..=0xAFFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -220,7 +220,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0xB000_0000 as *mut u8..=0xBFFF_FFFF as *mut u8, + range: 0xB000_0000 as *const u8..=0xBFFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -228,7 +228,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0xC000_0000 as *mut u8..=0xCFFF_FFFF as *mut u8, + range: 0xC000_0000 as *const u8..=0xCFFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -236,7 +236,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0xD000_0000 as *mut u8..=0xDFFF_FFFF as *mut u8, + range: 0xD000_0000 as *const u8..=0xDFFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -244,7 +244,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0xE000_0000 as *mut u8..=0xEFFF_FFFF as *mut u8, + range: 0xE000_0000 as *const u8..=0xEFFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true, @@ -252,7 +252,7 @@ fn mpu_pmsa_v8() { enable: true, }, El1Region { - range: 0xF000_0000 as *mut u8..=0xFFFF_FFFF as *mut u8, + range: 0xF000_0000 as *const u8..=0xFFFF_FFFF as *const u8, shareability: El1Shareability::OuterShareable, access: El1AccessPerms::ReadWrite, no_exec: true,