diff --git a/sw/device/silicon_creator/lib/epmp_state.h b/sw/device/silicon_creator/lib/epmp_state.h index beb198ad4e2a3..046e20dab3002 100644 --- a/sw/device/silicon_creator/lib/epmp_state.h +++ b/sw/device/silicon_creator/lib/epmp_state.h @@ -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; /** diff --git a/sw/device/silicon_creator/rom_ext/BUILD b/sw/device/silicon_creator/rom_ext/BUILD index 0e5930744f4f2..94148d89b6ff9 100644 --- a/sw/device/silicon_creator/rom_ext/BUILD +++ b/sw/device/silicon_creator/rom_ext/BUILD @@ -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", ], ) diff --git a/sw/device/silicon_creator/rom_ext/doc/si_val.md b/sw/device/silicon_creator/rom_ext/doc/si_val.md index c0a20ac0d6831..baaf4f2517daf 100644 --- a/sw/device/silicon_creator/rom_ext/doc/si_val.md +++ b/sw/device/silicon_creator/rom_ext/doc/si_val.md @@ -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. diff --git a/sw/device/silicon_creator/rom_ext/e2e/lockdown/BUILD b/sw/device/silicon_creator/rom_ext/e2e/lockdown/BUILD index ce88d27f6ef18..82ec1cf857123 100644 --- a/sw/device/silicon_creator/rom_ext/e2e/lockdown/BUILD +++ b/sw/device/silicon_creator/rom_ext/e2e/lockdown/BUILD @@ -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, }, diff --git a/sw/device/silicon_creator/rom_ext/e2e/lockdown/epmp_rlb_lockdown.c b/sw/device/silicon_creator/rom_ext/e2e/lockdown/epmp_rlb_lockdown.c index 9335460da1950..bd51b6b3bd379 100644 --- a/sw/device/silicon_creator/rom_ext/e2e/lockdown/epmp_rlb_lockdown.c +++ b/sw/device/silicon_creator/rom_ext/e2e/lockdown/epmp_rlb_lockdown.c @@ -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" @@ -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; } diff --git a/sw/device/silicon_creator/rom_ext/rom_ext.c b/sw/device/silicon_creator/rom_ext/rom_ext.c index 82e2f1e6504b3..0413b0ce62ab5 100644 --- a/sw/device/silicon_creator/rom_ext/rom_ext.c +++ b/sw/device/silicon_creator/rom_ext/rom_ext.c @@ -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; @@ -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)) { @@ -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 @@ -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()); diff --git a/sw/device/silicon_creator/rom_ext/rom_ext_epmp.c b/sw/device/silicon_creator/rom_ext/rom_ext_epmp.c index a21d443ca76ee..30fecf438ce7c 100644 --- a/sw/device/silicon_creator/rom_ext/rom_ext_epmp.c +++ b/sw/device/silicon_creator/rom_ext/rom_ext_epmp.c @@ -6,173 +6,73 @@ #include "sw/device/lib/base/bitfield.h" #include "sw/device/lib/base/csr.h" +#include "sw/device/lib/base/hardened.h" +#include "sw/device/silicon_creator/lib/epmp_state.h" #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" -void rom_ext_epmp_unlock_owner_stage_rx(epmp_region_t region) { - const int kEntry = 1; - epmp_state_configure_tor(kEntry, region, kEpmpPermLockedReadExecute); - - // Update the hardware configuration (CSRs). - // - // Entry is hardcoded as 1. Make sure to modify hardcoded values if changing - // kEntry. - // - // The `pmp1cfg` configuration is the second field in `pmpcfg0`. - // - // 32 24 16 8 0 - // +-----------+-----------+-----------+-----------+ - // `pmpcfg0` = | `pmp3cfg | `pmp2cfg`| `pmp1cfg` | `pmp0cfg` | - // +-----------+-----------+-----------+-----------+ - - CSR_WRITE(CSR_REG_PMPADDR0, ((uint32_t)region.start) >> 2); - CSR_WRITE(CSR_REG_PMPADDR1, ((uint32_t)region.end) >> 2); - CSR_CLEAR_BITS(CSR_REG_PMPCFG0, 0xff << 8); - CSR_SET_BITS(CSR_REG_PMPCFG0, (kEpmpModeTor | kEpmpPermLockedReadExecute) - << 8); +#define EPMP_SET(cfg_reg, addr_reg, mask, cfg, addr) \ + CSR_CLEAR_BITS(CSR_REG_PMPCFG##cfg_reg, mask); \ + CSR_WRITE(CSR_REG_PMPADDR##addr_reg, pmpaddr); \ + CSR_SET_BITS(CSR_REG_PMPCFG##cfg_reg, cfg); + +static void rom_ext_epmp_set(uint8_t entry, uint32_t pmpcfg, uint32_t pmpaddr) { + uint32_t shift = 8 * (entry % 4); + uint32_t mask = 0xFFu << shift; + uint32_t cfg = (pmpcfg & 0xFFu) << shift; + HARDENED_CHECK_LT(entry, 16); + switch (entry) { + // clang-format off + case 0: EPMP_SET(0, 0, mask, cfg, pmpaddr); break; + case 1: EPMP_SET(0, 1, mask, cfg, pmpaddr); break; + case 2: EPMP_SET(0, 2, mask, cfg, pmpaddr); break; + case 3: EPMP_SET(0, 3, mask, cfg, pmpaddr); break; + case 4: EPMP_SET(1, 4, mask, cfg, pmpaddr); break; + case 5: EPMP_SET(1, 5, mask, cfg, pmpaddr); break; + case 6: EPMP_SET(1, 6, mask, cfg, pmpaddr); break; + case 7: EPMP_SET(1, 7, mask, cfg, pmpaddr); break; + case 8: EPMP_SET(2, 8, mask, cfg, pmpaddr); break; + case 9: EPMP_SET(2, 9, mask, cfg, pmpaddr); break; + case 10: EPMP_SET(2, 10, mask, cfg, pmpaddr); break; + case 11: EPMP_SET(2, 11, mask, cfg, pmpaddr); break; + case 12: EPMP_SET(3, 12, mask, cfg, pmpaddr); break; + case 13: EPMP_SET(3, 13, mask, cfg, pmpaddr); break; + case 14: EPMP_SET(3, 14, mask, cfg, pmpaddr); break; + case 15: EPMP_SET(3, 15, mask, cfg, pmpaddr); break; + // clang-format on + default: + // should be impossible to get here because of HARDENED_CHECK_LT above. + HARDENED_TRAP(); + } + uint32_t cfgent = entry / 4; + epmp_state.pmpcfg[cfgent] = (epmp_state.pmpcfg[cfgent] & ~mask) | cfg; + epmp_state.pmpaddr[entry] = pmpaddr; } -void rom_ext_epmp_unlock_owner_stage_r(epmp_region_t region) { - const int kEntry = 2; - epmp_state_configure_napot(kEntry, region, kEpmpPermLockedReadOnly); - - // Update the hardware configuration (CSRs). - // - // Entry is hardcoded as 2. Make sure to modify hardcoded values if changing - // kEntry. - // - // The `pmp2cfg` configuration is the third field in `pmpcfg0`. - // - // 32 24 16 8 0 - // +-----------+-----------+-----------+-----------+ - // `pmpcfg0` = | `pmp3cfg | `pmp2cfg`| `pmp1cfg` | `pmp0cfg` | - // +-----------+-----------+-----------+-----------+ - CSR_WRITE(CSR_REG_PMPADDR2, - (uint32_t)region.start >> 2 | - ((uint32_t)region.end - (uint32_t)region.start - 1) >> 3); - CSR_CLEAR_BITS(CSR_REG_PMPCFG0, 0xff << 16); - CSR_SET_BITS(CSR_REG_PMPCFG0, - ((kEpmpModeNapot | kEpmpPermLockedReadOnly) << 16)); +void rom_ext_epmp_clear(uint8_t entry) { + rom_ext_epmp_set(entry, kEpmpModeOff, 0); } -void rom_ext_epmp_mmio_adjust(void) { - const int kEntry = 11; - epmp_region_t region = { - .start = 0x40000000, - .end = 0x50000000, - }; - epmp_state_configure_napot(kEntry, region, kEpmpPermLockedReadWrite); - - // Update the hardware configuration (CSRs). - // - // Entry is hardcoded as 2. Make sure to modify hardcoded values if changing - // kEntry. - // - // The `pmp11cfg` configuration is the fourth field in `pmpcfg2`. - // - // 32 24 16 8 0 - // +-----------+-----------+-----------+-----------+ - // `pmpcfg2` = | `pmp11cfg | `pmp10cfg`| `pmp9cfg` | `pmp8cfg` | - // +-----------+-----------+-----------+-----------+ - CSR_WRITE(CSR_REG_PMPADDR11, - (uint32_t)region.start >> 2 | - ((uint32_t)region.end - (uint32_t)region.start - 1) >> 3); - CSR_CLEAR_BITS(CSR_REG_PMPCFG2, 0xff << 24); - CSR_SET_BITS(CSR_REG_PMPCFG2, - ((kEpmpModeNapot | kEpmpPermLockedReadWrite) << 24)); -} - -void rom_ext_epmp_otp_dai_lockout(void) { - const int kEntry = 6; - epmp_region_t region = { - .start = TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR, - .end = TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR + 0x1000, - }; - epmp_state_configure_napot(kEntry, region, kEpmpPermLockedNoAccess); - - // Update the hardware configuration (CSRs). - // - // Entry is hardcoded as 6. Make sure to modify hardcoded values if changing - // kEntry. - // - // The `pmp6cfg` configuration is the third field in `pmpcfg1`. - // - // 32 24 16 8 0 - // +-----------+-----------+-----------+-----------+ - // `pmpcfg1` = | `pmp7cfg | `pmp6cfg`| `pmp5cfg` | `pmp4cfg` | - // +-----------+-----------+-----------+-----------+ - CSR_WRITE(CSR_REG_PMPADDR6, - (uint32_t)region.start >> 2 | - ((uint32_t)region.end - (uint32_t)region.start - 1) >> 3); - CSR_CLEAR_BITS(CSR_REG_PMPCFG1, 0xff << 16); - CSR_SET_BITS(CSR_REG_PMPCFG1, - ((kEpmpModeNapot | kEpmpPermLockedNoAccess) << 16)); -} - -void rom_ext_epmp_ast_lockout(void) { - const int kEntry = 7; - epmp_region_t region = { - .start = TOP_EARLGREY_AST_BASE_ADDR, - .end = TOP_EARLGREY_AST_BASE_ADDR + TOP_EARLGREY_AST_SIZE_BYTES, - }; - epmp_state_configure_napot(kEntry, region, kEpmpPermLockedNoAccess); - - // Update the hardware configuration (CSRs). - // - // Entry is hardcoded as 7. Make sure to modify hardcoded values if changing - // kEntry. - // - // The `pmp7cfg` configuration is the fourth field in `pmpcfg1`. - // - // 32 24 16 8 0 - // +-----------+-----------+-----------+-----------+ - // `pmpcfg1` = | `pmp7cfg | `pmp6cfg`| `pmp5cfg` | `pmp4cfg` | - // +-----------+-----------+-----------+-----------+ - CSR_WRITE(CSR_REG_PMPADDR7, - (uint32_t)region.start >> 2 | - ((uint32_t)region.end - (uint32_t)region.start - 1) >> 3); - CSR_CLEAR_BITS(CSR_REG_PMPCFG1, 0xff << 24); - CSR_SET_BITS(CSR_REG_PMPCFG1, - ((kEpmpModeNapot | kEpmpPermLockedNoAccess) << 24)); -} - -void rom_ext_epmp_clear_rom_region(void) { - const int kEntry = 2; - const uint32_t kMask = (0xFF << 16); - epmp_state.pmpaddr[kEntry] = 0; - epmp_state.pmpcfg[0] &= ~kMask; - - // Update the hardware configuration (CSRs). - // - // Entry is hardcoded as 2. Make sure to modify hardcoded values if changing - // kEntry. - // - // The `pmp2cfg` configuration is the third field in `pmpcfg0`. - // - // 32 24 16 8 0 - // +-----------+-----------+-----------+-----------+ - // `pmpcfg0` = | `pmp3cfg | `pmp2cfg`| `pmp1cfg` | `pmp0cfg` | - // +-----------+-----------+-----------+-----------+ - CSR_WRITE(CSR_REG_PMPADDR2, 0); - CSR_CLEAR_BITS(CSR_REG_PMPCFG0, kMask); +void rom_ext_epmp_set_napot(uint8_t entry, epmp_region_t region, + epmp_perm_t perm) { + uint32_t length = region.end - region.start; + // The length must be 4 or more. + HARDENED_CHECK_GE(length, 4); + // The length must be a power of 2. + HARDENED_CHECK_EQ(bitfield_popcount32(length), 1); + // The start address must be naturally aligned with length. + HARDENED_CHECK_EQ(region.start & (length - 1), 0); + epmp_mode_t mode = length == 4 ? kEpmpModeNa4 : kEpmpModeNapot; + uint32_t addr = (region.start >> 2) | ((length - 1) >> 3); + rom_ext_epmp_set(entry, (uint32_t)mode | (uint32_t)perm, addr); } -void rom_ext_epmp_final_cleanup(void) { - // We want to clear the L bit from pmp3cfg and pmp4cfg to unlock the - // ROM_EXT region for the next stage. - // - // 32 24 16 8 0 - // +-----------+-----------+-----------+-----------+ - // `pmpcfg0` = | `pmp3cfg | `pmp2cfg`| `pmp1cfg` | `pmp0cfg` | - // +-----------+-----------+-----------+-----------+ - // `pmpcfg1` = | `pmp7cfg | `pmp6cfg`| `pmp5cfg` | `pmp4cfg` | - // +-----------+-----------+-----------+-----------+ - const uint32_t kMask0 = (uint32_t)(EPMP_CFG_L << 24); - const uint32_t kMask1 = (uint32_t)(EPMP_CFG_L << 0); - epmp_state.pmpcfg[0] &= ~kMask0; - epmp_state.pmpcfg[1] &= ~kMask1; - CSR_CLEAR_BITS(CSR_REG_PMPCFG0, kMask0); - CSR_CLEAR_BITS(CSR_REG_PMPCFG1, kMask1); +void rom_ext_epmp_set_tor(uint8_t entry, epmp_region_t region, + epmp_perm_t perm) { + uint32_t start = region.start >> 2; + uint32_t end = ((region.end + 3u) & ~3u) >> 2; + rom_ext_epmp_set(entry, kEpmpModeOff, start); + rom_ext_epmp_set(entry + 1, (uint32_t)kEpmpModeTor | (uint32_t)perm, end); } void rom_ext_epmp_clear_rlb(void) { diff --git a/sw/device/silicon_creator/rom_ext/rom_ext_epmp.h b/sw/device/silicon_creator/rom_ext/rom_ext_epmp.h index 6f68208f9952a..4a33bb4451739 100644 --- a/sw/device/silicon_creator/rom_ext/rom_ext_epmp.h +++ b/sw/device/silicon_creator/rom_ext/rom_ext_epmp.h @@ -37,70 +37,44 @@ extern "C" { // stage. /** - * Unlocks the provided first Silicon Owner stage region with read-execute - * permissions. + * Clear an ePMP entry. * - * The provided ePMP state is also updated to reflect the changes made to the - * hardware configuration. + * Sets the PMPADDR and PMPCFG entries to zero. * - * @param state The ePMP state to update. - * @param image Region for executable sections in the silicon Owner image. + * @param entry The ePMP entry to clear. */ -void rom_ext_epmp_unlock_owner_stage_rx(epmp_region_t image); +void rom_ext_epmp_clear(uint8_t entry); /** - * Unlocks the provided first silicon owner region with read-only permissions. + * Configures an ePMP entry for a NAPOT or NA4 region. * - * The provided ePMP state is also updated to reflect the changes made to the - * hardware configuration. - * The image size must be a power of 2 as this function uses NAPOT - * (Naturally-Aligned-Power-Of-Two) addressing mode. + * The region start must have an alignment consistend with the region size. The + * region size must be a power of two. If either of these conditions is not + * met, this function will fault. * - * @param state The ePMP state to update. - * @param region Region in the silicon Owner image to receive read-only - * permission. - */ -void rom_ext_epmp_unlock_owner_stage_r(epmp_region_t region); - -/** - * Adjusts the ePMP MMIO region from a TOR region to a NAPOT region. - * - * The earlgrey MMIO region is 0x4000_0000 to 0x5000_0000. We adjust - * this to a NAPOT region to free up an ePMP entry for other use. - */ -void rom_ext_epmp_mmio_adjust(void); - -/** - * Lock out access to the OTP DAI interface. + * From a configuration perspective, an NA4 region is just a special case of a + * NAPOT region. * - * The OTP controller doesn't have a per-boot software lock-out capability. - * In order to forbid accidental OTP programming during the bring-up process, - * we use the ePMP to forbid access to the OTP register space. + * @param entry The ePMP entry to configure. + * @param region The address region to configure. + * @param perm The ePMP permissions for the region. */ -void rom_ext_epmp_otp_dai_lockout(void); +void rom_ext_epmp_set_napot(uint8_t entry, epmp_region_t region, + epmp_perm_t perm); /** - * Lock out access to the AST registers. + * Configures an ePMP entry for a TOR region. * - * The AST peripheral contains all of the low-level analog configuration - * registers (sensors, clock trimming, etc). After ROM_EXT completes, - * the ePMP will forbid access to the AST register space. - */ -void rom_ext_epmp_ast_lockout(void); - -/** - * Clear the ROM mapping from the ePMP. - * - * The ROM memory mapping is no longer needed once the ROM_EXT starts. - */ -void rom_ext_epmp_clear_rom_region(void); - -/** - * Perform final cleanups to the ePMP configuration before owner handoff. + * The region start and end may be abitrary addresses. The start will be + * rounded down to a 4-byte address. The end will be rounded up to a 4-byte + * address. * - * Unlock the ROM_EXT code segments so they can be ovewritten by the next stage. + * @param entry The ePMP entry to configure. + * @param region The address region to configure. + * @param perm The ePMP permissions for the region. */ -void rom_ext_epmp_final_cleanup(void); +void rom_ext_epmp_set_tor(uint8_t entry, epmp_region_t region, + epmp_perm_t perm); /** * Clear the rule-locking-bypass (RLB) bit.