@@ -11,7 +11,9 @@ use arbitrary_int::{u26, u3};
11
11
use crate :: register;
12
12
13
13
#[ 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 } ;
15
17
16
18
/// Ways this API can fail
17
19
#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -44,7 +46,7 @@ impl El1Mpu {
44
46
}
45
47
46
48
/// 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 > {
48
50
if idx >= self . num_regions ( ) {
49
51
return None ;
50
52
}
@@ -53,7 +55,7 @@ impl El1Mpu {
53
55
let prlar = register:: Prlar :: read ( ) ;
54
56
let start_addr = ( prbar. base ( ) . value ( ) << 6 ) as * mut u8 ;
55
57
let end_addr = ( ( prlar. limit ( ) . value ( ) << 6 ) | 0x3F ) as * mut u8 ;
56
- Some ( Region {
58
+ Some ( El1Region {
57
59
range : start_addr..=end_addr,
58
60
shareability : prbar. shareability ( ) ,
59
61
access : prbar. access_perms ( ) ,
@@ -76,7 +78,7 @@ impl El1Mpu {
76
78
/// - [Error::UnalignedRegion] if the region's start address is not 64-byte aligned.
77
79
/// - [Error::UnalignedRegion] if the region's end address is not 63-byte aligned.
78
80
/// - [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 > {
80
82
let start = * ( region. range . start ( ) ) as usize as u32 ;
81
83
// Check for 64-byte alignment (0x3F is six bits)
82
84
if start & 0x3F != 0 {
@@ -118,7 +120,7 @@ impl El1Mpu {
118
120
pub fn set_regions (
119
121
& mut self ,
120
122
regions_starting_idx : u8 ,
121
- regions : & [ Region ] ,
123
+ regions : & [ El1Region ] ,
122
124
) -> Result < ( ) , Error > {
123
125
if regions. len ( ) . saturating_add ( regions_starting_idx as usize ) > self . num_regions ( ) as usize
124
126
{
@@ -162,7 +164,7 @@ impl El1Mpu {
162
164
/// Configure the EL1 MPU
163
165
///
164
166
/// 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 > {
166
168
self . set_regions ( 0 , config. regions ) ?;
167
169
168
170
self . set_attributes ( config. memory_attributes ) ;
@@ -187,17 +189,180 @@ impl El1Mpu {
187
189
}
188
190
}
189
191
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
191
356
#[ derive( Clone , Debug , PartialEq , Eq ) ]
192
- pub struct Config < ' a > {
357
+ pub struct El1Config < ' a > {
193
358
/// Background Config Enable
194
359
///
195
360
/// If true, use the default MMU config if no other region matches an address
196
361
pub background_config : bool ,
197
362
/// Information about each Region.
198
363
///
199
364
/// If you pass more regions than the MPU supports, you get an error.
200
- pub regions : & ' a [ Region ] ,
365
+ pub regions : & ' a [ El1Region ] ,
201
366
/// Information about each Memory Attribute
202
367
///
203
368
/// If you pass more MemAttrs than the MPU supports (8), you get an error.
@@ -206,16 +371,16 @@ pub struct Config<'a> {
206
371
207
372
/// Configuration for the PMSAv8-32 MPU
208
373
#[ derive( Clone , Debug , PartialEq , Eq ) ]
209
- pub struct Region {
374
+ pub struct El1Region {
210
375
/// The range of the region
211
376
///
212
377
/// * The first address must be a multiple of 32.
213
378
/// * The length must be a multiple of 32.
214
379
pub range : core:: ops:: RangeInclusive < * mut u8 > ,
215
380
/// Shareability of the region
216
- pub shareability : Shareability ,
381
+ pub shareability : El1Shareability ,
217
382
/// Access for the region
218
- pub access : AccessPerms ,
383
+ pub access : El1AccessPerms ,
219
384
/// Is region no-exec?
220
385
pub no_exec : bool ,
221
386
/// Which Memory Attribute applies here?
@@ -230,7 +395,52 @@ pub struct Region {
230
395
231
396
// Creating a static Region is fine - the pointers within it
232
397
// 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 { }
234
444
235
445
/// Describes the memory ordering and cacheability of a region
236
446
#[ derive( Debug , Clone , PartialEq , Eq ) ]
0 commit comments