@@ -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 ( ) ,
@@ -67,7 +69,7 @@ impl El1Mpu {
67
69
///
68
70
/// ## Arguments
69
71
///
70
- /// - `region`: The [Region ] object containing the configuration for the MPU region.
72
+ /// - `region`: The [El1Region ] object containing the configuration for the MPU region.
71
73
/// - `idx`: The index of the region to be configured.
72
74
///
73
75
/// ## Errors
@@ -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 {
@@ -114,11 +116,11 @@ impl El1Mpu {
114
116
/// ## Arguments
115
117
///
116
118
/// - `regions_starting_idx`: The starting index for the regions to be reconfigured.
117
- /// - `regions`: A slice of [Region ] objects that will overwrite the previous regions starting from `regions_starting_idx`.
119
+ /// - `regions`: A slice of [El1Region ] objects that will overwrite the previous regions starting from `regions_starting_idx`.
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
{
@@ -161,8 +163,9 @@ impl El1Mpu {
161
163
162
164
/// Configure the EL1 MPU
163
165
///
164
- /// Write regions, attributes and enable/disable the background region with a single [Config] struct.
165
- pub fn configure ( & mut self , config : & Config ) -> Result < ( ) , Error > {
166
+ /// Write regions, attributes and enable/disable the background region
167
+ /// with a single [El1Config] struct.
168
+ pub fn configure ( & mut self , config : & El1Config ) -> Result < ( ) , Error > {
166
169
self . set_regions ( 0 , config. regions ) ?;
167
170
168
171
self . set_attributes ( config. memory_attributes ) ;
@@ -187,17 +190,180 @@ impl El1Mpu {
187
190
}
188
191
}
189
192
190
- /// Configuration for the PMSAv8-32 MPU
193
+ /// Represents our PMSAv8-32 EL2 MPU
194
+ pub struct El2Mpu ( ) ;
195
+
196
+ impl El2Mpu {
197
+ /// Create an EL2 MPU handle
198
+ ///
199
+ /// # Safety
200
+ ///
201
+ /// Only create one of these at any given time, as they access shared
202
+ /// mutable state within the processor and do read-modify-writes on that state.
203
+ pub unsafe fn new ( ) -> El2Mpu {
204
+ El2Mpu ( )
205
+ }
206
+
207
+ /// How many EL2 MPU regions are there?
208
+ pub fn num_regions ( & self ) -> u8 {
209
+ register:: Hmpuir :: read ( ) . region ( )
210
+ }
211
+
212
+ /// Access the current state of a region
213
+ pub fn get_region ( & mut self , idx : u8 ) -> Option < El2Region > {
214
+ if idx >= self . num_regions ( ) {
215
+ return None ;
216
+ }
217
+ register:: Hprselr :: write ( register:: Hprselr ( idx as u32 ) ) ;
218
+ let hprbar = register:: Hprbar :: read ( ) ;
219
+ let hprlar = register:: Hprlar :: read ( ) ;
220
+ let start_addr = ( hprbar. base ( ) . value ( ) << 6 ) as * mut u8 ;
221
+ let end_addr = ( ( hprlar. limit ( ) . value ( ) << 6 ) | 0x3F ) as * mut u8 ;
222
+ Some ( El2Region {
223
+ range : start_addr..=end_addr,
224
+ shareability : hprbar. shareability ( ) ,
225
+ access : hprbar. access_perms ( ) ,
226
+ no_exec : hprbar. nx ( ) ,
227
+ mair : hprlar. mair ( ) . value ( ) ,
228
+ enable : hprlar. enabled ( ) ,
229
+ } )
230
+ }
231
+
232
+ /// Write a single region to the EL2 MPU
233
+ ///
234
+ /// ## Arguments
235
+ ///
236
+ /// - `region`: The [El2Region] object containing the configuration for the MPU region.
237
+ /// - `idx`: The index of the region to be configured.
238
+ ///
239
+ /// ## Errors
240
+ ///
241
+ /// Returns:
242
+ /// - [Error::UnalignedRegion] if the region's start address is not 64-byte aligned.
243
+ /// - [Error::UnalignedRegion] if the region's end address is not 63-byte aligned.
244
+ /// - [Error::InvalidMair] if the region's MAIR index is invalid (greater than 7).
245
+ pub fn set_region ( & mut self , idx : u8 , region : & El2Region ) -> Result < ( ) , Error > {
246
+ let start = * ( region. range . start ( ) ) as usize as u32 ;
247
+ // Check for 64-byte alignment (0x3F is six bits)
248
+ if start & 0x3F != 0 {
249
+ return Err ( Error :: UnalignedRegion ( region. range . clone ( ) ) ) ;
250
+ }
251
+ let end = * ( region. range . end ( ) ) as usize as u32 ;
252
+ if end & 0x3F != 0x3F {
253
+ return Err ( Error :: UnalignedRegion ( region. range . clone ( ) ) ) ;
254
+ }
255
+ if region. mair > 7 {
256
+ return Err ( Error :: InvalidMair ( region. mair ) ) ;
257
+ }
258
+ register:: Hprselr :: write ( register:: Hprselr ( idx as u32 ) ) ;
259
+ register:: Hprbar :: write ( {
260
+ let mut bar = register:: Hprbar :: new_with_raw_value ( 0 ) ;
261
+ bar. set_base ( u26:: from_u32 ( start >> 6 ) ) ;
262
+ bar. set_access_perms ( region. access ) ;
263
+ bar. set_nx ( region. no_exec ) ;
264
+ bar. set_shareability ( region. shareability ) ;
265
+ bar
266
+ } ) ;
267
+ register:: Hprlar :: write ( {
268
+ let mut lar = register:: Hprlar :: new_with_raw_value ( 0 ) ;
269
+ lar. set_limit ( u26:: from_u32 ( end >> 6 ) ) ;
270
+ lar. set_enabled ( region. enable ) ;
271
+ lar. set_mair ( u3:: from_u8 ( region. mair ) ) ;
272
+ lar
273
+ } ) ;
274
+
275
+ Ok ( ( ) )
276
+ }
277
+
278
+ /// Writes a subset of EL2 MPU regions starting from a specified index.
279
+ ///
280
+ /// ## Arguments
281
+ ///
282
+ /// - `regions_starting_idx`: The starting index for the regions to be reconfigured.
283
+ /// - `regions`: A slice of [El2Region] objects that will overwrite the previous regions starting from `regions_starting_idx`.
284
+ pub fn set_regions (
285
+ & mut self ,
286
+ regions_starting_idx : u8 ,
287
+ regions : & [ El2Region ] ,
288
+ ) -> Result < ( ) , Error > {
289
+ if regions. len ( ) . saturating_add ( regions_starting_idx as usize ) > self . num_regions ( ) as usize
290
+ {
291
+ return Err ( Error :: TooManyRegions ) ;
292
+ }
293
+
294
+ for ( idx, region) in regions. iter ( ) . enumerate ( ) {
295
+ self . set_region ( idx as u8 + regions_starting_idx, region) ?;
296
+ }
297
+
298
+ Ok ( ( ) )
299
+ }
300
+
301
+ /// Set the memory attributes to HMAIR0 and HMAIR1
302
+ pub fn set_attributes ( & mut self , memattrs : & [ MemAttr ] ) {
303
+ let mem_attr0 = memattrs. get ( 0 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
304
+ let mem_attr1 = memattrs. get ( 1 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
305
+ let mem_attr2 = memattrs. get ( 2 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
306
+ let mem_attr3 = memattrs. get ( 3 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
307
+ let hmair0 = mem_attr3 << 24 | mem_attr2 << 16 | mem_attr1 << 8 | mem_attr0;
308
+ unsafe {
309
+ register:: Hmair0 :: write ( register:: Hmair0 ( hmair0) ) ;
310
+ }
311
+ let mem_attr0 = memattrs. get ( 4 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
312
+ let mem_attr1 = memattrs. get ( 5 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
313
+ let mem_attr2 = memattrs. get ( 6 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
314
+ let mem_attr3 = memattrs. get ( 7 ) . map ( |m| m. to_bits ( ) ) . unwrap_or ( 0 ) as u32 ;
315
+ let hmair1 = mem_attr3 << 24 | mem_attr2 << 16 | mem_attr1 << 8 | mem_attr0;
316
+ unsafe {
317
+ register:: Hmair1 :: write ( register:: Hmair1 ( hmair1) ) ;
318
+ }
319
+ }
320
+
321
+ /// Enable or disable the background region
322
+ pub fn background_region_enable ( & mut self , enable : bool ) {
323
+ register:: Hsctlr :: modify ( |r| {
324
+ r. set_br ( enable) ;
325
+ } ) ;
326
+ }
327
+
328
+ /// Configure the EL2 MPU
329
+ ///
330
+ /// Write regions, attributes and enable/disable the background region with a single [El2Config] struct.
331
+ pub fn configure ( & mut self , config : & El2Config ) -> Result < ( ) , Error > {
332
+ self . set_regions ( 0 , config. regions ) ?;
333
+
334
+ self . set_attributes ( config. memory_attributes ) ;
335
+
336
+ self . background_region_enable ( config. background_config ) ;
337
+
338
+ Ok ( ( ) )
339
+ }
340
+
341
+ /// Enable the EL2 MPU
342
+ pub fn enable ( & mut self ) {
343
+ register:: Hsctlr :: modify ( |r| {
344
+ r. set_m ( true ) ;
345
+ } ) ;
346
+ }
347
+
348
+ /// Disable the EL2 MPU
349
+ pub fn disable ( & mut self ) {
350
+ register:: Hsctlr :: modify ( |r| {
351
+ r. set_m ( false ) ;
352
+ } ) ;
353
+ }
354
+ }
355
+
356
+ /// Configuration for the PMSAv8-32 EL1 MPU
191
357
#[ derive( Clone , Debug , PartialEq , Eq ) ]
192
- pub struct Config < ' a > {
358
+ pub struct El1Config < ' a > {
193
359
/// Background Config Enable
194
360
///
195
361
/// If true, use the default MMU config if no other region matches an address
196
362
pub background_config : bool ,
197
363
/// Information about each Region.
198
364
///
199
365
/// If you pass more regions than the MPU supports, you get an error.
200
- pub regions : & ' a [ Region ] ,
366
+ pub regions : & ' a [ El1Region ] ,
201
367
/// Information about each Memory Attribute
202
368
///
203
369
/// If you pass more MemAttrs than the MPU supports (8), you get an error.
@@ -206,16 +372,16 @@ pub struct Config<'a> {
206
372
207
373
/// Configuration for the PMSAv8-32 MPU
208
374
#[ derive( Clone , Debug , PartialEq , Eq ) ]
209
- pub struct Region {
375
+ pub struct El1Region {
210
376
/// The range of the region
211
377
///
212
378
/// * The first address must be a multiple of 32.
213
379
/// * The length must be a multiple of 32.
214
380
pub range : core:: ops:: RangeInclusive < * mut u8 > ,
215
381
/// Shareability of the region
216
- pub shareability : Shareability ,
382
+ pub shareability : El1Shareability ,
217
383
/// Access for the region
218
- pub access : AccessPerms ,
384
+ pub access : El1AccessPerms ,
219
385
/// Is region no-exec?
220
386
pub no_exec : bool ,
221
387
/// Which Memory Attribute applies here?
@@ -230,7 +396,52 @@ pub struct Region {
230
396
231
397
// Creating a static Region is fine - the pointers within it
232
398
// only go to the MPU and aren't accessed via Rust code
233
- unsafe impl Sync for Region { }
399
+ unsafe impl Sync for El1Region { }
400
+
401
+ /// Configuration for the PMSAv8-32 EL2 MPU
402
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
403
+ pub struct El2Config < ' a > {
404
+ /// Background Config Enable
405
+ ///
406
+ /// If true, use the default MMU config if no other region matches an address
407
+ pub background_config : bool ,
408
+ /// Information about each Region.
409
+ ///
410
+ /// If you pass more regions than the MPU supports, you get an error.
411
+ pub regions : & ' a [ El2Region ] ,
412
+ /// Information about each Memory Attribute
413
+ ///
414
+ /// If you pass more MemAttrs than the MPU supports (8), you get an error.
415
+ pub memory_attributes : & ' a [ MemAttr ] ,
416
+ }
417
+
418
+ /// Configuration for the PMSAv8-32 EL2 MPU
419
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
420
+ pub struct El2Region {
421
+ /// The range of the region
422
+ ///
423
+ /// * The first address must be a multiple of 32.
424
+ /// * The length must be a multiple of 32.
425
+ pub range : core:: ops:: RangeInclusive < * mut u8 > ,
426
+ /// Shareability of the region
427
+ pub shareability : El2Shareability ,
428
+ /// Access for the region
429
+ pub access : El2AccessPerms ,
430
+ /// Is region no-exec?
431
+ pub no_exec : bool ,
432
+ /// Which Memory Attribute applies here?
433
+ ///
434
+ /// Selects from the eight attributes in {HMAIR0, HMAIR1}.
435
+ ///
436
+ /// Only values 0..=7 are valid here.
437
+ pub mair : u8 ,
438
+ /// Is this region enabled?
439
+ pub enable : bool ,
440
+ }
441
+
442
+ // Creating a static El2Region is fine - the pointers within it
443
+ // only go to the MPU and aren't accessed via Rust code
444
+ unsafe impl Sync for El2Region { }
234
445
235
446
/// Describes the memory ordering and cacheability of a region
236
447
#[ derive( Debug , Clone , PartialEq , Eq ) ]
0 commit comments