Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rom_ext] Update the ROM_EXT ePMP configuration #20862

Merged
merged 1 commit into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions sw/device/silicon_creator/lib/epmp_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,36 @@ enum {
* W | 1
* X | 2
*
* Combinations not exposed by this enum should not be used. The 'unlocked'
* zero value should only be used for entries that are configured as OFF.
* NOTE: Because the chip is configured with MMWP=1 and MML=0, the ePMP bit
* patterns can sometimes have counterintuitive meanings.
*
* NOTE: After setting MML=1, the meanings of some of the bit patterns will
* change. See section 2.2 of the "PMP Enhancements for memory access and
* execution prevention on Machine mode (Smepmp)" document
* (https://github.com/riscv/riscv-tee/blob/main/Smepmp/Smepmp.pdf).
*/
typedef enum epmp_perm {
kEpmpPermUnlocked = 0,
/** M mode: no access. U mode: no access. */
kEpmpPermLockedNoAccess = EPMP_CFG_L,

/** M mode: read only. U mode: no access. */
kEpmpPermLockedReadOnly = EPMP_CFG_LR,

/** M mode: read/write. U mode: no access. */
kEpmpPermLockedReadWrite = EPMP_CFG_LRW,

/** M mode: read/execute. U mode: no access. */
kEpmpPermLockedReadExecute = EPMP_CFG_LRX,

/** M mode: read/execute. U mode: read/execute. */
kEpmpPermLockedReadWriteExecute = EPMP_CFG_LRWX,

/** M mode: read/write/execute. U mode: read only. */
kEpmpPermReadOnly = EPMP_CFG_R,

/** M mode: read/write/execute. U mode: read/execute. */
kEpmpPermReadExecute = EPMP_CFG_R | EPMP_CFG_X,
} epmp_perm_t;

/**
Expand Down
1 change: 1 addition & 0 deletions sw/device/silicon_creator/rom_ext/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ cc_library(
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/lib/base:bitfield",
"//sw/device/lib/base:csr",
"//sw/device/lib/base:hardened",
"//sw/device/silicon_creator/lib:epmp_state",
],
)
Expand Down
33 changes: 21 additions & 12 deletions sw/device/silicon_creator/rom_ext/doc/si_val.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,34 @@ The ePMP will allow access to the FLASH, to the MMIO region and to SRAM.
An example of how the SiVal `ROM_EXT` will configure the ePMP:

```console
0: 20010400 ----- ---- sz=00000000 ; OWNER code start.
1: 20013d24 TOR LX-R sz=00003924 ; OWNER code end.
2: 00008000 NAPOT L--R sz=00008000 ; OWNER data (if using remap window, else ROM data region)
3: 20000400 ----- ---- sz=00000000 ; ROM_EXT code start.
4: 20004fe8 TOR LX-R sz=00004be8 ; ROM_EXT code end.
5: 20000000 NAPOT L--R sz=00100000 ; FLASH data (1 MB).
6: 40130000 NAPOT L--- sz=00001000 ; OTP MMIO lockout.
7: 40480000 NAPOT L--- sz=00000400 ; AST MMIO lockout.
0: 40130000 NAPOT L--- sz=00001000 ; OTP MMIO lockout.
1: 40480000 NAPOT L--- sz=00000400 ; AST MMIO lockout.
2: 20010400 ----- ---- sz=00000000 ; OWNER code start.
3: 20013cac TOR -X-R sz=000038ac ; OWNER code end.
4: 00000000 ----- ---- sz=00000000 ; OWNER data (if using remap window, else unused).
5: 00000000 ----- ---- sz=00000000
6: 00000000 ----- ---- sz=00000000
7: 00000000 ----- ---- sz=00000000
8: 00000000 ----- ---- sz=00000000
9: 00000000 ----- ---- sz=00000000
10: 00000000 ----- ---- sz=00000000
11: 40000000 NAPOT L-WR sz=10000000 ; MMIO region.
12: 00000000 ----- ---- sz=00000000
10: 20000400 ----- ---- sz=00000000 ; ROM_EXT code start.
11: 20005bc8 TOR -X-R sz=000057c8 ; ROM_EXT code end.
12: 20000000 NAPOT L--R sz=00100000 ; FLASH data (1 MB).
13: 00010000 NAPOT LXWR sz=00001000 ; RvDM region (not PROD, RMA/DEV only).
14: 1001c000 NA4 L--- sz=00000004 ; Stack guard.
14: 40000000 NAPOT L-WR sz=10000000 ; MMIO region.
15: 10000000 NAPOT L-WR sz=00020000 ; RAM region.
mseccfg = 00000002 ; RLB=0, MMWP=1, MML=0.
```

In this configuration, the owner stage can re-arrange ePMP entries
2-11 as needed. Applications that require machine/user mode isolation can set
the MML bit after arranging the ePMP to the preferred configuration.

NOTE: if the ROM\_EXT stage is booted in the virtual slot, then ePMP entries
9/10/11 will be used to map the virtual window's code/data segments. Since
these entries are unlocked _and_ since the ROM\_EXT is no longer requred
after owner code boots, these entries can be reclaimed for owner use.

### OTP

- The OTP creator partition memory window is locked and is unreadable.
Expand Down
8 changes: 0 additions & 8 deletions sw/device/silicon_creator/rom_ext/e2e/lockdown/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,6 @@ opentitan_test(
opentitan_test(
name = "epmp_rlb_lockdown",
srcs = ["epmp_rlb_lockdown.c"],
cw310 = cw310_params(
exit_failure = "(PASS|FAIL|BFV|FAULT).*\r\n",
# Make sure the test program failed to modify the ePMP.
exit_success = (
"6: 40130000 NAPOT L--- sz=00001000\r\n" +
"7: 40480000 NAPOT L--- sz=00000400\r\n"
),
),
exec_env = {
"//hw/top_earlgrey:fpga_cw310_rom_ext": None,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "sw/device/lib/base/csr.h"
#include "sw/device/lib/base/status.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "sw/device/silicon_creator/lib/dbg_print.h"

Expand All @@ -13,13 +14,16 @@
OTTF_DEFINE_TEST_CONFIG();

bool test_main(void) {
// Try to overwrite ePMP entry 6 (ie: the otp lockout) by clearing its config
// Try to overwrite ePMP entry 0 (ie: the otp lockout) by clearing its config
// bits.
CSR_CLEAR_BITS(CSR_REG_PMPCFG1, 0xff << 16);
CSR_WRITE(CSR_REG_PMPADDR6, 0);
CSR_CLEAR_BITS(CSR_REG_PMPCFG0, 0xff);
CSR_WRITE(CSR_REG_PMPADDR0, 0);

// The test rule in the BUILD file will look for the expected configuration
// for ePMP entry 10.
dbg_print_epmp();
// Read back ePMP entry 0 and make sure it hasn't changed to zero.
uint32_t pmpcfg0, pmpaddr0;
CSR_READ(CSR_REG_PMPCFG0, &pmpcfg0);
CSR_READ(CSR_REG_PMPADDR0, &pmpaddr0);
CHECK((pmpcfg0 & 0xFF) != 0);
CHECK(pmpaddr0 != 0);
return true;
}
95 changes: 83 additions & 12 deletions sw/device/silicon_creator/rom_ext/rom_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,29 @@ extern const char _chip_info_start[];
// Life cycle state of the chip.
lifecycle_state_t lc_state = kLcStateProd;

// ePMP regions for important address spaces.
const epmp_region_t kMmioRegion = {
.start = TOP_EARLGREY_MMIO_BASE_ADDR,
.end = TOP_EARLGREY_MMIO_BASE_ADDR + TOP_EARLGREY_MMIO_SIZE_BYTES,
};

const epmp_region_t kFlashRegion = {
.start = TOP_EARLGREY_EFLASH_BASE_ADDR,
.end = TOP_EARLGREY_EFLASH_BASE_ADDR + TOP_EARLGREY_EFLASH_SIZE_BYTES,
};

const epmp_region_t kAstRegion = {
.start = TOP_EARLGREY_AST_BASE_ADDR,
.end = TOP_EARLGREY_AST_BASE_ADDR + TOP_EARLGREY_AST_SIZE_BYTES,
};

const epmp_region_t kOtpRegion = {
// We only want to lock out the register, not the memory mapped interface.
// The size of the register space is 0x1000 bytes.
.start = TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR,
.end = TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR + 0x1000,
};

OT_WARN_UNUSED_RESULT
static rom_error_t rom_ext_irq_error(void) {
uint32_t mcause;
Expand Down Expand Up @@ -286,25 +309,72 @@ static rom_error_t rom_ext_boot(const manifest_t *manifest) {
SEC_MMIO_WRITE_INCREMENT(kFlashCtrlSecMmioCreatorInfoPagesLockdown +
kOtpSecMmioCreatorSwCfgLockDown);

// Reconfigure the ePMP MMIO region to be a NAPOT region, thus freeing
// up a region for OTP DAI lockout.
rom_ext_epmp_mmio_adjust();
// ePMP region 15 gives access to RAM and is already configured correctly.

// Reconfigure the ePMP MMIO region to be NAPOT region 14, thus freeing
// up an ePMP entry for use elsewhere.
rom_ext_epmp_set_napot(14, kMmioRegion, kEpmpPermLockedReadWrite);

// ePMP region 13 allows RvDM access and is already configured correctly.

// ePMP region 12 gives read access to all of flash for both M and U modes.
// The flash access was in ePMP region 5. Clear it so it doesn't take
// priority over 12.
rom_ext_epmp_set_napot(12, kFlashRegion, kEpmpPermLockedReadOnly);
rom_ext_epmp_clear(5);

// Move the ROM_EXT TOR region from entries 3/4/6 to 9/10/11.
// If the ROM_EXT is located in the virtual window, the ROM will have
// configured ePMP entry 6 as the read-only region over the entire
// window.
//
// If not using the virtual window, we move the ROM_EXT TOR region to
// ePMP entries 10/11.
// If using the virtual window, we move the ROM_EXT read-only region to
// ePMP entry 11 and move the TOR region to 9/10.
uint32_t start, end, vwindow;
CSR_READ(CSR_REG_PMPADDR3, &start);
CSR_READ(CSR_REG_PMPADDR4, &end);
CSR_READ(CSR_REG_PMPADDR6, &vwindow);
uint8_t rxindex = 10;
if (vwindow) {
rxindex = 9;
uint32_t size = 1 << bitfield_count_trailing_zeroes32(~vwindow);
vwindow = (vwindow & ~(size - 1)) << 2;
size <<= 3;

rom_ext_epmp_set_napot(
11, (epmp_region_t){.start = vwindow, .end = vwindow + size},
kEpmpPermReadOnly);
}
rom_ext_epmp_set_tor(rxindex,
(epmp_region_t){.start = start << 2, .end = end << 2},
kEpmpPermReadExecute);
for (int8_t i = (int8_t)rxindex - 1; i >= 0; --i) {
rom_ext_epmp_clear((uint8_t)i);
}

// Use the ePMP to forbid access to the OTP DAI interface.
// TODO(cfrantz): This lockout is for silicon validation testing.
// We want to prevent accidental OTP programming by test programs before we
// commit to a finalized OTP configuration on test chips. Since the OTP
// controller doesn't have a per-boot register lockout, we'll use the ePMP to
// disable access to the programming interface.
rom_ext_epmp_otp_dai_lockout();
rom_ext_epmp_set_napot(0, kOtpRegion, kEpmpPermLockedNoAccess);

// TODO(cfrantz): This lockout is for silicon validation testing.
// We want to prevent access to the AST by test programs before we commit
// to a finalized AST configuration set in OTP.
rom_ext_epmp_ast_lockout();
rom_ext_epmp_set_napot(1, kAstRegion, kEpmpPermLockedNoAccess);
HARDENED_RETURN_IF_ERROR(epmp_state_check());

// Configure address translation, compute the epmp regions and the entry
// point for the virtual address in case the address translation is enabled.
// Otherwise, compute the epmp regions and the entry point for the load
// address.
//
// We'll map the owner code TOR region as ePMP entries 2/3. If using address
// translation, we'll configure ePMP entry 4 as the read-only region.
epmp_region_t text_region = manifest_code_region_get(manifest);
uintptr_t entry_point = manifest_entry_point_get(manifest);
switch (launder32(manifest->address_translation)) {
Expand All @@ -316,10 +386,12 @@ static rom_error_t rom_ext_boot(const manifest_t *manifest) {

// Unlock read-only for the whole rom_ext virtual memory.
HARDENED_RETURN_IF_ERROR(epmp_state_check());
rom_ext_epmp_unlock_owner_stage_r(
rom_ext_epmp_set_napot(
4,
(epmp_region_t){.start = (uintptr_t)_owner_virtual_start_address,
.end = (uintptr_t)_owner_virtual_start_address +
(uintptr_t)_owner_virtual_size});
(uintptr_t)_owner_virtual_size},
kEpmpPermReadOnly);
HARDENED_RETURN_IF_ERROR(epmp_state_check());

// Move the ROM_EXT execution section from the load address to the virtual
Expand All @@ -345,11 +417,10 @@ static rom_error_t rom_ext_boot(const manifest_t *manifest) {
// unlock the ROM_EXT code regions so the next stage can re-use those
// entries and clear RLB to prevent further changes to locked ePMP regions.
HARDENED_RETURN_IF_ERROR(epmp_state_check());
rom_ext_epmp_unlock_owner_stage_rx(text_region);
// We'd normally want to unlock the ROM_EXT regions so they can be re-used by
// OWNER code, however we need to prevent OWNER code from overriding the OTP
// lockout in entry 6.
// rom_ext_epmp_final_cleanup();
rom_ext_epmp_set_tor(2, text_region, kEpmpPermReadExecute);

// Now that we're done reconfiguring the ePMP, we'll clear the RLB bit to
// prevent any modification to locked entries.
rom_ext_epmp_clear_rlb();
HARDENED_RETURN_IF_ERROR(epmp_state_check());

Expand Down
Loading
Loading