@@ -23,9 +23,9 @@ use rv32i::pmp::{
23
23
const PMP_ENTRIES : usize = 16 ;
24
24
const PMP_ENTRIES_OVER_TWO : usize = 8 ;
25
25
const TOR_USER_REGIONS_DEBUG_ENABLE : usize = 4 ;
26
- const TOR_USER_REGIONS_DEBUG_DISABLE : usize = 5 ;
26
+ const TOR_USER_REGIONS_DEBUG_DISABLE : usize = 4 ;
27
27
const TOR_USER_ENTRIES_OFFSET_DEBUG_ENABLE : usize = 0 ;
28
- const TOR_USER_ENTRIES_OFFSET_DEBUG_DISABLE : usize = 2 ;
28
+ const TOR_USER_ENTRIES_OFFSET_DEBUG_DISABLE : usize = 4 ;
29
29
30
30
// ---------- EarlGrey ePMP memory region wrapper types ------------------------
31
31
//
@@ -221,8 +221,62 @@ pub enum EarlGreyEPMPError {
221
221
/// granting R/X on flash-memory where only R is required, because the
222
222
/// kernel-text is already marked as R/X in the high-priority regions above.
223
223
///
224
- /// The EarlGrey ePMP driver attempts to set up the following memory protection
225
- /// rules and layout when the debug-port is disabled:
224
+ /// Because the ROM_EXT and test ROM set up different ePMP configs, there are
225
+ /// separate initialization routines (`new` and `new_test_rom`) for those
226
+ /// environments.
227
+ ///
228
+ /// `new` (only available when the debug-port is disabled) attempts to set up
229
+ /// the following memory protection rules and layout:
230
+ ///
231
+ /// - `msseccfg` CSR:
232
+ ///
233
+ /// ```text
234
+ /// |-----+-----------------------------------------------------------+-------|
235
+ /// | BIT | LABEL | STATE |
236
+ /// |-----+-----------------------------------------------------------+-------|
237
+ /// | 0 | Machine-Mode Lockdown (MML) | 1 |
238
+ /// | 1 | Machine-Mode Whitelist Policy (MMWP) | 1 |
239
+ /// | 2 | Rule-Lock Bypass (RLB) | 0 |
240
+ /// |-----+-----------------------------------------------------------+-------|
241
+ /// ```
242
+ ///
243
+ /// - `pmpcfgX` / `pmpaddrX` CSRs:
244
+ ///
245
+ /// ```text
246
+ /// |-------+----------------------------------------+-----------+---+-------|
247
+ /// | ENTRY | REGION / ADDR | MODE | L | PERMS |
248
+ /// |-------+----------------------------------------+-----------+---+-------|
249
+ /// | 0 | Locked by the ROM_EXT or unused | NAPOT/OFF | X | |
250
+ /// | | | | | |
251
+ /// | 1 | Locked by the ROM_EXT or unused | NAPOT/OFF | X | |
252
+ /// | | | | | |
253
+ /// | 2 | -------------------------------------- | OFF | X | ----- |
254
+ /// | 3 | Kernel .text section | TOR | X | R/X |
255
+ /// | | | | | |
256
+ /// | 4 | / \ | OFF | | |
257
+ /// | 5 | \ Userspace TOR region #0 / | TOR | | ????? |
258
+ /// | | | | | |
259
+ /// | 6 | / \ | OFF | | |
260
+ /// | 7 | \ Userspace TOR region #1 / | TOR | | ????? |
261
+ /// | | | | | |
262
+ /// | 8 | / \ | OFF | | |
263
+ /// | 9 | \ Userspace TOR region #2 / | TOR | | ????? |
264
+ /// | | | | | |
265
+ /// | 10 | / \ | OFF | | |
266
+ /// | 11 | \ Userspace TOR region #3 / | TOR | | ????? |
267
+ /// | | | | | |
268
+ /// | 12 | FLASH (spanning kernel & apps) | NAPOT | X | R |
269
+ /// | | | | | |
270
+ /// | 13 | -------------------------------------- | OFF | X | ----- |
271
+ /// | | | | | |
272
+ /// | 14 | RAM (spanning kernel & apps) | NAPOT | X | R/W |
273
+ /// | | | | | |
274
+ /// | 15 | MMIO | NAPOT | X | R/W |
275
+ /// |-------+----------------------------------------+-----------+---+-------|
276
+ /// ```
277
+ ///
278
+ /// `new_test_rom` (only available when the debug-port is disabled) attempts to
279
+ /// set up the following memory protection rules and layout:
226
280
///
227
281
/// - `msseccfg` CSR:
228
282
///
@@ -245,20 +299,21 @@ pub enum EarlGreyEPMPError {
245
299
/// | 0 | ------------------------------------------- | OFF | X | ----- |
246
300
/// | 1 | Kernel .text section | TOR | X | R/X |
247
301
/// | | | | | |
248
- /// | 2 | / \ | OFF | | |
249
- /// | 3 | \ Userspace TOR region #0 / | TOR | | ????? |
302
+ /// | 2 | ------------------------------------------- | OFF | X | |
303
+ /// | | | | | |
304
+ /// | 3 | ------------------------------------------- | OFF | X | |
250
305
/// | | | | | |
251
306
/// | 4 | / \ | OFF | | |
252
- /// | 5 | \ Userspace TOR region #1 / | TOR | | ????? |
307
+ /// | 5 | \ Userspace TOR region #0 / | TOR | | ????? |
253
308
/// | | | | | |
254
309
/// | 6 | / \ | OFF | | |
255
- /// | 7 | \ Userspace TOR region #2 / | TOR | | ????? |
310
+ /// | 7 | \ Userspace TOR region #1 / | TOR | | ????? |
256
311
/// | | | | | |
257
312
/// | 8 | / \ | OFF | | |
258
- /// | 9 | \ Userspace TOR region #3 / | TOR | | ????? |
313
+ /// | 9 | \ Userspace TOR region #2 / | TOR | | ????? |
259
314
/// | | | | | |
260
315
/// | 10 | / \ | OFF | | |
261
- /// | 11 | \ Userspace TOR region #4 / | TOR | | ????? |
316
+ /// | 11 | \ Userspace TOR region #3 / | TOR | | ????? |
262
317
/// | | | | | |
263
318
/// | 12 | ------------------------------------------- | OFF | X | ----- |
264
319
/// | | | | | |
@@ -316,8 +371,8 @@ pub enum EarlGreyEPMPError {
316
371
/// These entires provide the kernel access to certain memory regions, as
317
372
/// required by the machine-mode whitelist policy (MMWP).
318
373
///
319
- /// The EarlGrey ePMP driver attempts to set up the following memory protection
320
- /// rules and layout when the debug-port is enabled :
374
+ /// `new_debug` (only available when the debug-port is enabled) attempts to set
375
+ /// up the following memory protection rules and layout :
321
376
///
322
377
/// - `msseccfg` CSR:
323
378
///
@@ -384,6 +439,109 @@ impl<const HANDOVER_CONFIG_CHECK: bool> EarlGreyEPMP<{ HANDOVER_CONFIG_CHECK },
384
439
) -> Result < Self , EarlGreyEPMPError > {
385
440
use kernel:: utilities:: registers:: interfaces:: { Readable , Writeable } ;
386
441
442
+ // --> We start with the "high-priority" ("lockdown") section of the
443
+ // ePMP configuration:
444
+
445
+ // Provide R/X access to the kernel .text as passed to us above.
446
+ // Allocate a TOR region in PMP entries 2 and 3:
447
+ csr:: CSR . pmpaddr2 . set ( ( kernel_text. 0 . start ( ) as usize ) >> 2 ) ;
448
+ csr:: CSR . pmpaddr3 . set ( ( kernel_text. 0 . end ( ) as usize ) >> 2 ) ;
449
+
450
+ // Set the appropriate `pmpcfg0` register value:
451
+ //
452
+ // 0x80 = 0b10000000, for start the address of the kernel .text TOR
453
+ // entry as well as entries 0 and 1.
454
+ // setting L(7) = 1, A(4-3) = OFF, X(2) = 0, W(1) = 0, R(0) = 0
455
+ //
456
+ // 0x8d = 0b10001101, for kernel .text TOR region
457
+ // setting L(7) = 1, A(4-3) = TOR, X(2) = 1, W(1) = 0, R(0) = 1
458
+ //
459
+ // Note that we try to lock entries 0 and 1 into OFF mode. If the
460
+ // ROM_EXT set these up and locked them, this will do nothing, otherwise
461
+ // it will permanently disable these entries (preventing them from being
462
+ // misused later).
463
+ csr:: CSR . pmpcfg0 . set ( 0x8d_80_80_80 ) ;
464
+
465
+ // --> Continue with the "low-priority" ("accessibility") section of the
466
+ // ePMP configuration:
467
+
468
+ // Configure a Read-Only NAPOT region for the entire flash (spanning
469
+ // kernel & apps, but overlayed by the R/X kernel text TOR section)
470
+ csr:: CSR . pmpaddr12 . set ( flash. 0 . napot_addr ( ) ) ;
471
+
472
+ // Configure a Read-Write NAPOT region for MMIO.
473
+ csr:: CSR . pmpaddr14 . set ( mmio. 0 . napot_addr ( ) ) ;
474
+
475
+ // Configure a Read-Write NAPOT region for the entire RAM (spanning
476
+ // kernel & apps)
477
+ csr:: CSR . pmpaddr15 . set ( ram. 0 . napot_addr ( ) ) ;
478
+
479
+ // With the FLASH, RAM and MMIO configured in separate regions, we can
480
+ // activate this new configuration, and further adjust the permissions
481
+ // of the (currently all-capable) last PMP entry `pmpaddr15` to be R/W,
482
+ // as required for MMIO:
483
+ //
484
+ // 0x99 = 0b10011001, for FLASH NAPOT region
485
+ // setting L(7) = 1, A(4-3) = NAPOT, X(2) = 0, W(1) = 0, R(0) = 1
486
+ //
487
+ // 0x80 = 0b10000000, for the unused region
488
+ // setting L(7) = 1, A(4-3) = OFF, X(2) = 0, W(1) = 0, R(0) = 0
489
+ //
490
+ // 0x9B = 0b10011011, for RAM & MMIO NAPOT regions
491
+ // setting L(7) = 1, A(4-3) = NAPOT, X(2) = 0, W(1) = 1, R(0) = 1
492
+ csr:: CSR . pmpcfg3 . set ( 0x9B_9B_80_99 ) ;
493
+
494
+ // Ensure that the other pmpcfgX CSRs are cleared:
495
+ csr:: CSR . pmpcfg1 . set ( 0x00000000 ) ;
496
+ csr:: CSR . pmpcfg2 . set ( 0x00000000 ) ;
497
+
498
+ // ---------- PMP machine CSRs configured, lock down the system
499
+
500
+ // Finally, enable machine-mode lockdown.
501
+ // Set RLB(2) = 0, MMWP(1) = 1, MML(0) = 1
502
+ csr:: CSR . mseccfg . set ( 0x00000003 ) ;
503
+
504
+ // ---------- System locked down, cross-check config
505
+
506
+ // Now, cross-check that the CSRs have the expected values. This acts as
507
+ // a sanity check, and can also help to protect against some set of
508
+ // fault-injection attacks. These checks can't be optimized out by the
509
+ // compiler, as they invoke assembly underneath which is not marked as
510
+ // ["pure"](https://doc.rust-lang.org/reference/inline-assembly.html).
511
+ //
512
+ // Note that different ROM_EXT versions configure entries 0 and 1
513
+ // differently, so we only confirm they are locked here.
514
+ if csr:: CSR . mseccfg . get ( ) != 0x00000003
515
+ || ( csr:: CSR . pmpcfg0 . get ( ) & 0xFFFF8080 ) != 0x8d808080
516
+ || csr:: CSR . pmpcfg1 . get ( ) != 0x00000000
517
+ || csr:: CSR . pmpcfg2 . get ( ) != 0x00000000
518
+ || csr:: CSR . pmpcfg3 . get ( ) != 0x9B9B8099
519
+ || csr:: CSR . pmpaddr2 . get ( ) != ( kernel_text. 0 . start ( ) as usize ) >> 2
520
+ || csr:: CSR . pmpaddr3 . get ( ) != ( kernel_text. 0 . end ( ) as usize ) >> 2
521
+ || csr:: CSR . pmpaddr12 . get ( ) != flash. 0 . napot_addr ( )
522
+ || csr:: CSR . pmpaddr14 . get ( ) != mmio. 0 . napot_addr ( )
523
+ || csr:: CSR . pmpaddr15 . get ( ) != ram. 0 . napot_addr ( )
524
+ {
525
+ return Err ( EarlGreyEPMPError :: SanityCheckFail ) ;
526
+ }
527
+
528
+ // The ePMP hardware was correctly configured, build the ePMP struct:
529
+ const DEFAULT_USER_PMPCFG_OCTET : Cell < TORUserPMPCFG > = Cell :: new ( TORUserPMPCFG :: OFF ) ;
530
+ Ok ( EarlGreyEPMP {
531
+ user_pmp_enabled : Cell :: new ( false ) ,
532
+ shadow_user_pmpcfgs : [ DEFAULT_USER_PMPCFG_OCTET ; TOR_USER_REGIONS_DEBUG_DISABLE ] ,
533
+ _pd : PhantomData ,
534
+ } )
535
+ }
536
+
537
+ pub unsafe fn new_test_rom (
538
+ flash : FlashRegion ,
539
+ ram : RAMRegion ,
540
+ mmio : MMIORegion ,
541
+ kernel_text : KernelTextRegion ,
542
+ ) -> Result < Self , EarlGreyEPMPError > {
543
+ use kernel:: utilities:: registers:: interfaces:: { Readable , Writeable } ;
544
+
387
545
if HANDOVER_CONFIG_CHECK {
388
546
Self :: check_initial_hardware_config ( ) ?;
389
547
} else {
@@ -429,11 +587,13 @@ impl<const HANDOVER_CONFIG_CHECK: bool> EarlGreyEPMP<{ HANDOVER_CONFIG_CHECK },
429
587
// Set the appropriate `pmpcfg0` register value:
430
588
//
431
589
// 0x80 = 0b10000000, for start address of the kernel .text TOR entry
590
+ // and to disable regions 2 & 3 (to be compatible with the
591
+ // non-test-rom constructor).
432
592
// setting L(7) = 1, A(4-3) = OFF, X(2) = 0, W(1) = 0, R(0) = 0
433
593
//
434
594
// 0x8d = 0b10001101, for kernel .text TOR region
435
595
// setting L(7) = 1, A(4-3) = TOR, X(2) = 1, W(1) = 0, R(0) = 1
436
- csr:: CSR . pmpcfg0 . set ( 0x00008d80 ) ;
596
+ csr:: CSR . pmpcfg0 . set ( 0x80808d80 ) ;
437
597
438
598
// --> Continue with the "low-priority" ("accessability") section of the
439
599
// ePMP configuration:
0 commit comments