@@ -11,7 +11,9 @@ use arbitrary_int::{u26, u3};
1111use crate :: register;
1212
1313#[ doc( inline) ]
14- pub use register:: prbar:: { AccessPerms , Shareability } ;
14+ pub use register:: hprbar:: { AccessPerms as El2AccessPerms , Shareability as El2Shareability } ;
15+ #[ doc( inline) ]
16+ pub use register:: prbar:: { AccessPerms as El1AccessPerms , Shareability as El1Shareability } ;
1517
1618/// Ways this API can fail
1719#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -44,7 +46,7 @@ impl El1Mpu {
4446 }
4547
4648 /// Access the current state of a region
47- pub fn get_region ( & mut self , idx : u8 ) -> Option < Region > {
49+ pub fn get_region ( & mut self , idx : u8 ) -> Option < El1Region > {
4850 if idx >= self . num_regions ( ) {
4951 return None ;
5052 }
@@ -53,7 +55,7 @@ impl El1Mpu {
5355 let prlar = register:: Prlar :: read ( ) ;
5456 let start_addr = ( prbar. base ( ) . value ( ) << 6 ) as * mut u8 ;
5557 let end_addr = ( ( prlar. limit ( ) . value ( ) << 6 ) | 0x3F ) as * mut u8 ;
56- Some ( Region {
58+ Some ( El1Region {
5759 range : start_addr..=end_addr,
5860 shareability : prbar. shareability ( ) ,
5961 access : prbar. access_perms ( ) ,
@@ -76,7 +78,7 @@ impl El1Mpu {
7678 /// - [Error::UnalignedRegion] if the region's start address is not 64-byte aligned.
7779 /// - [Error::UnalignedRegion] if the region's end address is not 63-byte aligned.
7880 /// - [Error::InvalidMair] if the region's MAIR index is invalid (greater than 7).
79- pub fn set_region ( & mut self , idx : u8 , region : & Region ) -> Result < ( ) , Error > {
81+ pub fn set_region ( & mut self , idx : u8 , region : & El1Region ) -> Result < ( ) , Error > {
8082 let start = * ( region. range . start ( ) ) as usize as u32 ;
8183 // Check for 64-byte alignment (0x3F is six bits)
8284 if start & 0x3F != 0 {
@@ -118,7 +120,7 @@ impl El1Mpu {
118120 pub fn set_regions (
119121 & mut self ,
120122 regions_starting_idx : u8 ,
121- regions : & [ Region ] ,
123+ regions : & [ El1Region ] ,
122124 ) -> Result < ( ) , Error > {
123125 if regions. len ( ) . saturating_add ( regions_starting_idx as usize ) > self . num_regions ( ) as usize
124126 {
@@ -162,7 +164,7 @@ impl El1Mpu {
162164 /// Configure the EL1 MPU
163165 ///
164166 /// Write regions, attributes and enable/disable the background region with a single [Config] struct.
165- pub fn configure ( & mut self , config : & Config ) -> Result < ( ) , Error > {
167+ pub fn configure ( & mut self , config : & El1Config ) -> Result < ( ) , Error > {
166168 self . set_regions ( 0 , config. regions ) ?;
167169
168170 self . set_attributes ( config. memory_attributes ) ;
@@ -187,17 +189,180 @@ impl El1Mpu {
187189 }
188190}
189191
190- /// Configuration for the PMSAv8-32 MPU
192+ /// Represents our PMSAv8-32 EL2 MPU
193+ pub struct El2Mpu ( ) ;
194+
195+ impl El2Mpu {
196+ /// Create an EL2 MPU handle
197+ ///
198+ /// # Safety
199+ ///
200+ /// Only create one of these at any given time, as they access shared
201+ /// mutable state within the processor and do read-modify-writes on that state.
202+ pub unsafe fn new ( ) -> El2Mpu {
203+ El2Mpu ( )
204+ }
205+
206+ /// How many EL2 MPU regions are there?
207+ pub fn num_regions ( & self ) -> u8 {
208+ register:: Hmpuir :: read ( ) . region ( )
209+ }
210+
211+ /// Access the current state of a region
212+ pub fn get_region ( & mut self , idx : u8 ) -> Option < El2Region > {
213+ if idx >= self . num_regions ( ) {
214+ return None ;
215+ }
216+ register:: Hprselr :: write ( register:: Hprselr ( idx as u32 ) ) ;
217+ let hprbar = register:: Hprbar :: read ( ) ;
218+ let hprlar = register:: Hprlar :: read ( ) ;
219+ let start_addr = ( hprbar. base ( ) . value ( ) << 6 ) as * mut u8 ;
220+ let end_addr = ( ( hprlar. limit ( ) . value ( ) << 6 ) | 0x3F ) as * mut u8 ;
221+ Some ( El2Region {
222+ range : start_addr..=end_addr,
223+ shareability : hprbar. shareability ( ) ,
224+ access : hprbar. access_perms ( ) ,
225+ no_exec : hprbar. nx ( ) ,
226+ mair : hprlar. mair ( ) . value ( ) ,
227+ enable : hprlar. enabled ( ) ,
228+ } )
229+ }
230+
231+ /// Write a single region to the EL2 MPU
232+ ///
233+ /// ## Arguments
234+ ///
235+ /// - `region`: The [El2Region] object containing the configuration for the MPU region.
236+ /// - `idx`: The index of the region to be configured.
237+ ///
238+ /// ## Errors
239+ ///
240+ /// Returns:
241+ /// - [Error::UnalignedRegion] if the region's start address is not 64-byte aligned.
242+ /// - [Error::UnalignedRegion] if the region's end address is not 63-byte aligned.
243+ /// - [Error::InvalidMair] if the region's MAIR index is invalid (greater than 7).
244+ pub fn set_region ( & mut self , idx : u8 , region : & El2Region ) -> Result < ( ) , Error > {
245+ let start = * ( region. range . start ( ) ) as usize as u32 ;
246+ // Check for 64-byte alignment (0x3F is six bits)
247+ if start & 0x3F != 0 {
248+ return Err ( Error :: UnalignedRegion ( region. range . clone ( ) ) ) ;
249+ }
250+ let end = * ( region. range . end ( ) ) as usize as u32 ;
251+ if end & 0x3F != 0x3F {
252+ return Err ( Error :: UnalignedRegion ( region. range . clone ( ) ) ) ;
253+ }
254+ if region. mair > 7 {
255+ return Err ( Error :: InvalidMair ( region. mair ) ) ;
256+ }
257+ register:: Hprselr :: write ( register:: Hprselr ( idx as u32 ) ) ;
258+ register:: Hprbar :: write ( {
259+ let mut bar = register:: Hprbar :: new_with_raw_value ( 0 ) ;
260+ bar. set_base ( u26:: from_u32 ( start >> 6 ) ) ;
261+ bar. set_access_perms ( region. access ) ;
262+ bar. set_nx ( region. no_exec ) ;
263+ bar. set_shareability ( region. shareability ) ;
264+ bar
265+ } ) ;
266+ register:: Hprlar :: write ( {
267+ let mut lar = register:: Hprlar :: new_with_raw_value ( 0 ) ;
268+ lar. set_limit ( u26:: from_u32 ( end >> 6 ) ) ;
269+ lar. set_enabled ( region. enable ) ;
270+ lar. set_mair ( u3:: from_u8 ( region. mair ) ) ;
271+ lar
272+ } ) ;
273+
274+ Ok ( ( ) )
275+ }
276+
277+ /// Writes a subset of EL2 MPU regions starting from a specified index.
278+ ///
279+ /// ## Arguments
280+ ///
281+ /// - `regions_starting_idx`: The starting index for the regions to be reconfigured.
282+ /// - `regions`: A slice of [El2Region] objects that will overwrite the previous regions starting from `regions_starting_idx`.
283+ pub fn set_regions (
284+ & mut self ,
285+ regions_starting_idx : u8 ,
286+ regions : & [ El2Region ] ,
287+ ) -> Result < ( ) , Error > {
288+ if regions. len ( ) . saturating_add ( regions_starting_idx as usize ) > self . num_regions ( ) as usize
289+ {
290+ return Err ( Error :: TooManyRegions ) ;
291+ }
292+
293+ for ( idx, region) in regions. iter ( ) . enumerate ( ) {
294+ self . set_region ( idx as u8 + regions_starting_idx, region) ?;
295+ }
296+
297+ Ok ( ( ) )
298+ }
299+
300+ /// Set the memory attributes to HMAIR0 and HMAIR1
301+ pub fn set_attributes ( & mut self , memattrs : & [ MemAttr ] ) {
302+ let mem_attr0 = memattrs. get ( 0 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
303+ let mem_attr1 = memattrs. get ( 1 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
304+ let mem_attr2 = memattrs. get ( 2 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
305+ let mem_attr3 = memattrs. get ( 3 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
306+ let hmair0 = mem_attr3 << 24 | mem_attr2 << 16 | mem_attr1 << 8 | mem_attr0;
307+ unsafe {
308+ register:: Hmair0 :: write ( register:: Hmair0 ( hmair0) ) ;
309+ }
310+ let mem_attr0 = memattrs. get ( 4 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
311+ let mem_attr1 = memattrs. get ( 5 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
312+ let mem_attr2 = memattrs. get ( 6 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
313+ let mem_attr3 = memattrs. get ( 7 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
314+ let hmair1 = mem_attr3 << 24 | mem_attr2 << 16 | mem_attr1 << 8 | mem_attr0;
315+ unsafe {
316+ register:: Hmair1 :: write ( register:: Hmair1 ( hmair1) ) ;
317+ }
318+ }
319+
320+ /// Enable or disable the background region
321+ pub fn background_region_enable ( & mut self , enable : bool ) {
322+ register:: Hsctlr :: modify ( |r| {
323+ r. set_br ( enable) ;
324+ } ) ;
325+ }
326+
327+ /// Configure the EL2 MPU
328+ ///
329+ /// Write regions, attributes and enable/disable the background region with a single [El2Config] struct.
330+ pub fn configure ( & mut self , config : & El2Config ) -> Result < ( ) , Error > {
331+ self . set_regions ( 0 , config. regions ) ?;
332+
333+ self . set_attributes ( config. memory_attributes ) ;
334+
335+ self . background_region_enable ( config. background_config ) ;
336+
337+ Ok ( ( ) )
338+ }
339+
340+ /// Enable the EL2 MPU
341+ pub fn enable ( & mut self ) {
342+ register:: Hsctlr :: modify ( |r| {
343+ r. set_m ( true ) ;
344+ } ) ;
345+ }
346+
347+ /// Disable the EL2 MPU
348+ pub fn disable ( & mut self ) {
349+ register:: Hsctlr :: modify ( |r| {
350+ r. set_m ( false ) ;
351+ } ) ;
352+ }
353+ }
354+
355+ /// Configuration for the PMSAv8-32 EL1 MPU
191356#[ derive( Clone , Debug , PartialEq , Eq ) ]
192- pub struct Config < ' a > {
357+ pub struct El1Config < ' a > {
193358 /// Background Config Enable
194359 ///
195360 /// If true, use the default MMU config if no other region matches an address
196361 pub background_config : bool ,
197362 /// Information about each Region.
198363 ///
199364 /// If you pass more regions than the MPU supports, you get an error.
200- pub regions : & ' a [ Region ] ,
365+ pub regions : & ' a [ El1Region ] ,
201366 /// Information about each Memory Attribute
202367 ///
203368 /// If you pass more MemAttrs than the MPU supports (8), you get an error.
@@ -206,16 +371,16 @@ pub struct Config<'a> {
206371
207372/// Configuration for the PMSAv8-32 MPU
208373#[ derive( Clone , Debug , PartialEq , Eq ) ]
209- pub struct Region {
374+ pub struct El1Region {
210375 /// The range of the region
211376 ///
212377 /// * The first address must be a multiple of 32.
213378 /// * The length must be a multiple of 32.
214379 pub range : core:: ops:: RangeInclusive < * mut u8 > ,
215380 /// Shareability of the region
216- pub shareability : Shareability ,
381+ pub shareability : El1Shareability ,
217382 /// Access for the region
218- pub access : AccessPerms ,
383+ pub access : El1AccessPerms ,
219384 /// Is region no-exec?
220385 pub no_exec : bool ,
221386 /// Which Memory Attribute applies here?
@@ -230,7 +395,52 @@ pub struct Region {
230395
231396// Creating a static Region is fine - the pointers within it
232397// only go to the MPU and aren't accessed via Rust code
233- unsafe impl Sync for Region { }
398+ unsafe impl Sync for El1Region { }
399+
400+ /// Configuration for the PMSAv8-32 EL2 MPU
401+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
402+ pub struct El2Config < ' a > {
403+ /// Background Config Enable
404+ ///
405+ /// If true, use the default MMU config if no other region matches an address
406+ pub background_config : bool ,
407+ /// Information about each Region.
408+ ///
409+ /// If you pass more regions than the MPU supports, you get an error.
410+ pub regions : & ' a [ El2Region ] ,
411+ /// Information about each Memory Attribute
412+ ///
413+ /// If you pass more MemAttrs than the MPU supports (8), you get an error.
414+ pub memory_attributes : & ' a [ MemAttr ] ,
415+ }
416+
417+ /// Configuration for the PMSAv8-32 EL2 MPU
418+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
419+ pub struct El2Region {
420+ /// The range of the region
421+ ///
422+ /// * The first address must be a multiple of 32.
423+ /// * The length must be a multiple of 32.
424+ pub range : core:: ops:: RangeInclusive < * mut u8 > ,
425+ /// Shareability of the region
426+ pub shareability : El2Shareability ,
427+ /// Access for the region
428+ pub access : El2AccessPerms ,
429+ /// Is region no-exec?
430+ pub no_exec : bool ,
431+ /// Which Memory Attribute applies here?
432+ ///
433+ /// Selects from the eight attributes in {HMAIR0, HMAIR1}.
434+ ///
435+ /// Only values 0..=7 are valid here.
436+ pub mair : u8 ,
437+ /// Is this region enabled?
438+ pub enable : bool ,
439+ }
440+
441+ // Creating a static El2Region is fine - the pointers within it
442+ // only go to the MPU and aren't accessed via Rust code
443+ unsafe impl Sync for El2Region { }
234444
235445/// Describes the memory ordering and cacheability of a region
236446#[ derive( Debug , Clone , PartialEq , Eq ) ]
0 commit comments