Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5a65d68

Browse files
authored
Merge pull request #4034 from jrvanwhy/tock-new-rom_ext
opentitan: Add ROM_EXT-compatible ePMP setup.
2 parents 922afb0 + b5edf6f commit 5a65d68

File tree

1 file changed

+173
-13
lines changed

1 file changed

+173
-13
lines changed

chips/earlgrey/src/epmp.rs

Lines changed: 173 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ use rv32i::pmp::{
2323
const PMP_ENTRIES: usize = 16;
2424
const PMP_ENTRIES_OVER_TWO: usize = 8;
2525
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;
2727
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;
2929

3030
// ---------- EarlGrey ePMP memory region wrapper types ------------------------
3131
//
@@ -221,8 +221,62 @@ pub enum EarlGreyEPMPError {
221221
/// granting R/X on flash-memory where only R is required, because the
222222
/// kernel-text is already marked as R/X in the high-priority regions above.
223223
///
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:
226280
///
227281
/// - `msseccfg` CSR:
228282
///
@@ -245,20 +299,21 @@ pub enum EarlGreyEPMPError {
245299
/// | 0 | ------------------------------------------- | OFF | X | ----- |
246300
/// | 1 | Kernel .text section | TOR | X | R/X |
247301
/// | | | | | |
248-
/// | 2 | / \ | OFF | | |
249-
/// | 3 | \ Userspace TOR region #0 / | TOR | | ????? |
302+
/// | 2 | ------------------------------------------- | OFF | X | |
303+
/// | | | | | |
304+
/// | 3 | ------------------------------------------- | OFF | X | |
250305
/// | | | | | |
251306
/// | 4 | / \ | OFF | | |
252-
/// | 5 | \ Userspace TOR region #1 / | TOR | | ????? |
307+
/// | 5 | \ Userspace TOR region #0 / | TOR | | ????? |
253308
/// | | | | | |
254309
/// | 6 | / \ | OFF | | |
255-
/// | 7 | \ Userspace TOR region #2 / | TOR | | ????? |
310+
/// | 7 | \ Userspace TOR region #1 / | TOR | | ????? |
256311
/// | | | | | |
257312
/// | 8 | / \ | OFF | | |
258-
/// | 9 | \ Userspace TOR region #3 / | TOR | | ????? |
313+
/// | 9 | \ Userspace TOR region #2 / | TOR | | ????? |
259314
/// | | | | | |
260315
/// | 10 | / \ | OFF | | |
261-
/// | 11 | \ Userspace TOR region #4 / | TOR | | ????? |
316+
/// | 11 | \ Userspace TOR region #3 / | TOR | | ????? |
262317
/// | | | | | |
263318
/// | 12 | ------------------------------------------- | OFF | X | ----- |
264319
/// | | | | | |
@@ -316,8 +371,8 @@ pub enum EarlGreyEPMPError {
316371
/// These entires provide the kernel access to certain memory regions, as
317372
/// required by the machine-mode whitelist policy (MMWP).
318373
///
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:
321376
///
322377
/// - `msseccfg` CSR:
323378
///
@@ -384,6 +439,109 @@ impl<const HANDOVER_CONFIG_CHECK: bool> EarlGreyEPMP<{ HANDOVER_CONFIG_CHECK },
384439
) -> Result<Self, EarlGreyEPMPError> {
385440
use kernel::utilities::registers::interfaces::{Readable, Writeable};
386441

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+
387545
if HANDOVER_CONFIG_CHECK {
388546
Self::check_initial_hardware_config()?;
389547
} else {
@@ -429,11 +587,13 @@ impl<const HANDOVER_CONFIG_CHECK: bool> EarlGreyEPMP<{ HANDOVER_CONFIG_CHECK },
429587
// Set the appropriate `pmpcfg0` register value:
430588
//
431589
// 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).
432592
// setting L(7) = 1, A(4-3) = OFF, X(2) = 0, W(1) = 0, R(0) = 0
433593
//
434594
// 0x8d = 0b10001101, for kernel .text TOR region
435595
// 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);
437597

438598
// --> Continue with the "low-priority" ("accessability") section of the
439599
// ePMP configuration:

0 commit comments

Comments
 (0)