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

[imm_rom_ext] Add immutable ROM_EXT ePMP reconfiguration #25310

Merged
merged 1 commit into from
Jan 9, 2025
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
17 changes: 17 additions & 0 deletions sw/device/silicon_creator/imm_rom_ext/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ cc_library(
srcs = ["imm_rom_ext.c"],
hdrs = ["imm_rom_ext.h"],
deps = [
":imm_rom_ext_epmp",
"//hw/top_earlgrey/ip_autogen/flash_ctrl:flash_ctrl_c_regs",
"//sw/device/lib/arch:device",
"//sw/device/lib/base:macros",
Expand All @@ -34,6 +35,22 @@ cc_library(
],
)

cc_library(
name = "imm_rom_ext_epmp",
srcs = ["imm_rom_ext_epmp.c"],
hdrs = ["imm_rom_ext_epmp.h"],
deps = [
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/lib/base:csr",
"//sw/device/lib/base:macros",
"//sw/device/silicon_creator/lib:epmp_state",
"//sw/device/silicon_creator/lib:error",
"//sw/device/silicon_creator/lib:manifest",
"//sw/device/silicon_creator/lib/drivers:epmp",
"//sw/device/silicon_creator/lib/drivers:lifecycle",
],
)

ld_library(
name = "ld_hello_world",
script = "hello_world.ld",
Expand Down
6 changes: 6 additions & 0 deletions sw/device/silicon_creator/imm_rom_ext/imm_rom_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "sw/device/lib/arch/device.h"
#include "sw/device/lib/base/macros.h"
#include "sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.h"
#include "sw/device/silicon_creator/lib/base/boot_measurements.h"
#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
#include "sw/device/silicon_creator/lib/cert/dice_chain.h"
Expand All @@ -31,6 +32,8 @@ static rom_error_t imm_rom_ext_start(void) {

// Initialize Immutable ROM EXT.
sec_mmio_next_stage_init();
HARDENED_RETURN_IF_ERROR(imm_rom_ext_epmp_reconfigure());

// Configure UART0 as stdout.
pinmux_init_uart0_tx();
uart_init(kUartNCOValue);
Expand All @@ -52,6 +55,9 @@ static rom_error_t imm_rom_ext_start(void) {
// Write the DICE certs to flash if they have been updated.
HARDENED_RETURN_IF_ERROR(dice_chain_flush_flash());

// Make mutable part executable.
HARDENED_RETURN_IF_ERROR(imm_rom_ext_epmp_mutable_rx(rom_ext));

return kErrorOk;
}

Expand Down
115 changes: 115 additions & 0 deletions sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.h"

#include "sw/device/lib/base/csr.h"
#include "sw/device/lib/base/macros.h"
#include "sw/device/silicon_creator/lib/drivers/epmp.h"
#include "sw/device/silicon_creator/lib/drivers/lifecycle.h"
#include "sw/device/silicon_creator/lib/epmp_state.h"
#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/lib/manifest.h"

#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.

// Address populated by the linker.
extern char _rom_ext_immutable_start[];
extern char _rom_ext_immutable_end[];
extern char _text_end[];
extern char _stack_start[]; // Lowest stack address.

static const epmp_region_t kMmioRegion = {
.start = TOP_EARLGREY_MMIO_BASE_ADDR,
.end = TOP_EARLGREY_MMIO_BASE_ADDR + TOP_EARLGREY_MMIO_SIZE_BYTES,
};

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

static const epmp_region_t kRvDmRegion = {
.start = TOP_EARLGREY_RV_DM_MEM_BASE_ADDR,
.end = TOP_EARLGREY_RV_DM_MEM_BASE_ADDR + TOP_EARLGREY_RV_DM_MEM_SIZE_BYTES,
};

static const epmp_region_t kStackGuard = {.start = (uintptr_t)_stack_start,
.end = (uintptr_t)_stack_start + 4};

static const epmp_region_t kImmTextRegion = {
.start = (uintptr_t)_rom_ext_immutable_start,
.end = (uintptr_t)_text_end,
};

rom_error_t imm_rom_ext_epmp_reconfigure(void) {
lifecycle_state_t lc_state = lifecycle_state_get();

// ePMP region 15 gives read/write access to RAM.
// Leave it unchanged.

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

// ePMP region 11 protects the stack from overflow.
// This stack guard was in ePMP region 14.
epmp_set_napot(11, kStackGuard, kEpmpPermLockedNoAccess);

// ePMP region 12 allows RvDM access.
// This RvDM region was in ePMP region 13.
if (lc_state == kLcStateProd || lc_state == kLcStateProdEnd) {
// No RvDM access in Prod states, so we can clear the entry.
epmp_clear(12);
} else {
epmp_set_napot(12, kRvDmRegion, kEpmpPermLockedReadWriteExecute);
}

// ePMP region 13 gives read access to all of flash for both M and U modes.
// This flash region was in ePMP region 5.
epmp_set_napot(13, kFlashRegion, kEpmpPermLockedReadOnly);

// Move the ROM_EXT virtual region from entry 6 to 10.
uint32_t virtual_napot;
CSR_READ(CSR_REG_PMPADDR6, &virtual_napot);
epmp_clear(10);
if (virtual_napot) {
epmp_set_napot(10, epmp_decode_napot(virtual_napot),
kEpmpPermLockedReadOnly);
}

// Clear mutable ROM_EXT entries (8 & 9).
epmp_clear(9);
epmp_clear(8);

// Immutable ROM_EXT TOR (6 & 7).
epmp_set_tor(6, kImmTextRegion, kEpmpPermLockedReadExecute);

// Clear entries from 5 ~ 3.
epmp_clear(5);
epmp_clear(4);
epmp_clear(3);

// 3 ~ 0 are ROM ePMP entries.
// Leave them unchanged.

HARDENED_RETURN_IF_ERROR(epmp_state_check());

return kErrorOk;
}

rom_error_t imm_rom_ext_epmp_mutable_rx(const manifest_t *manifest) {
// Immutable ROM_EXT TOR (8 & 9).
epmp_region_t mutable_code_region = manifest_code_region_get(manifest);

// Manifest code_region includes immutable data segment. Move the start
// address to exclude.
mutable_code_region.start = (uintptr_t)_rom_ext_immutable_end;

epmp_set_tor(8, mutable_code_region, kEpmpPermLockedReadExecute);

HARDENED_RETURN_IF_ERROR(epmp_state_check());

return kErrorOk;
}
66 changes: 66 additions & 0 deletions sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_IMM_ROM_EXT_IMM_ROM_EXT_EPMP_H_
#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_IMM_ROM_EXT_IMM_ROM_EXT_EPMP_H_

#ifdef __cplusplus
extern "C" {
#endif

#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/lib/manifest.h"

/**
* Reconfigure ePMP entries to lower priority.
*
* ePMP will be reconfigured to:
* 0: ROM ----- ----
* 1: ROM TOR LX-R
* 2: ROM NAPOT L--R
* 3: ------- ----- ----
* 4: ------- ----- ----
* 5: ------- ----- ----
* 6: IM_EXT ----- ----
* 7: IM_EXT TOR LX-R
* 8:[MU_EXT ----- ----]
* 9:[MU_EXT TOR LX-R]
* 10: VIRTUAL NAPOT L--R
* 11: STACK NA4 L---
* 12: RvDM NAPOT LXWR
* 13: FLASH NAPOT L--R
* 14: MMIO NAPOT L-WR
* 15: RAM NAPOT L-WR
*
* Mutable ROM_EXT segment (8 & 9) won't be configured by this function.
* `imm_rom_ext_epmp_mutable_rx` will configure them when we are ready to
* jump back to ROM.
*
* Entries 6~12 can be recycled in Owner SW stage.
*
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t imm_rom_ext_epmp_reconfigure(void);

/**
* Configure the Mutable ROM_EXT text segment with read-execute permissions.
*
* 8: MU_EXT ----- ----
* 9: MU_EXT TOR LX-R
*
* Note: When address translation is enabled, the manifest argument should
* point to the one in the virtual space.
*
* @param manifest Pointer to the rom_ext manifest.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t imm_rom_ext_epmp_mutable_rx(const manifest_t *manifest);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_IMM_ROM_EXT_IMM_ROM_EXT_EPMP_H_
10 changes: 10 additions & 0 deletions sw/device/silicon_creator/lib/drivers/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -893,3 +893,13 @@ cc_library(
"//sw/device/silicon_creator/lib:epmp_state",
],
)

cc_test(
name = "epmp_unittest",
srcs = ["epmp_unittest.cc"],
deps = [
":epmp",
"//sw/device/silicon_creator/testing:rom_test",
"@googletest//:gtest_main",
],
)
35 changes: 30 additions & 5 deletions sw/device/silicon_creator/lib/drivers/epmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
CSR_WRITE(CSR_REG_PMPADDR##addr_reg, pmpaddr); \
CSR_SET_BITS(CSR_REG_PMPCFG##cfg_reg, cfg);

static void epmp_set(uint8_t entry, uint32_t pmpcfg, uint32_t pmpaddr) {
void 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;
Expand Down Expand Up @@ -51,16 +51,41 @@ static void epmp_set(uint8_t entry, uint32_t pmpcfg, uint32_t pmpaddr) {

void epmp_clear(uint8_t entry) { epmp_set(entry, kEpmpModeOff, 0); }

void epmp_set_napot(uint8_t entry, epmp_region_t region, epmp_perm_t perm) {
uint32_t length = region.end - region.start;
void epmp_clear_lock_bits(void) {
const uint32_t mask =
((uint32_t)EPMP_CFG_L << 0 * 8) | ((uint32_t)EPMP_CFG_L << 1 * 8) |
((uint32_t)EPMP_CFG_L << 2 * 8) | ((uint32_t)EPMP_CFG_L << 3 * 8);
CSR_CLEAR_BITS(CSR_REG_PMPCFG0, mask);
CSR_CLEAR_BITS(CSR_REG_PMPCFG1, mask);
CSR_CLEAR_BITS(CSR_REG_PMPCFG2, mask);
CSR_CLEAR_BITS(CSR_REG_PMPCFG3, mask);
for (int cfgent = 0; cfgent < 4; ++cfgent) {
epmp_state.pmpcfg[cfgent] &= ~mask;
}
}

uint32_t epmp_encode_napot(epmp_region_t region) {
const 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);
return (region.start >> 2) | ((length - 1) >> 3);
}

epmp_region_t epmp_decode_napot(uint32_t pmpaddr) {
uint32_t size = 1 << bitfield_count_trailing_zeroes32(~pmpaddr);
pmpaddr = (pmpaddr & ~(size - 1)) << 2;
size <<= 3;
return (epmp_region_t){.start = pmpaddr, .end = pmpaddr + size};
}

void epmp_set_napot(uint8_t entry, epmp_region_t region, epmp_perm_t perm) {
uint32_t addr = epmp_encode_napot(region);
epmp_mode_t mode =
region.end - region.start == 4 ? kEpmpModeNa4 : kEpmpModeNapot;
epmp_set(entry, (uint32_t)mode | (uint32_t)perm, addr);
}

Expand Down
25 changes: 25 additions & 0 deletions sw/device/silicon_creator/lib/drivers/epmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,31 @@ extern "C" {
*/
void epmp_clear(uint8_t entry);

/**
* Clear the lock bit in all ePMP entries.
*/
void epmp_clear_lock_bits(void);

/**
* Encode a start/end address pair to NAPOT address.
*
* 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 region The address region to configure.
* @return The encoded NAPOT address.
*/
uint32_t epmp_encode_napot(epmp_region_t region);

/**
* Decode a NAPOT address back to start/end address pair.
*
* @param pmpaddr The encoded NAPOT address.
* @return region The decoded start/end address pair.
*/
epmp_region_t epmp_decode_napot(uint32_t pmpaddr);

/**
* Configures an ePMP entry for a NAPOT or NA4 region.
*
Expand Down
Loading
Loading