From 3fc207351af40e7b6138ef4fd1af182a12478f18 Mon Sep 17 00:00:00 2001 From: Yi-Hsuan Deng Date: Thu, 21 Nov 2024 14:39:23 +0000 Subject: [PATCH] [imm_rom_ext] Add immutable ROM_EXT ePMP reconfiguration Reconfigure ePMP in immutable ROM_EXT to remove executable permission on the immutable data segment. Now, ePMP will be reconfigured to the following layout before jumping to the mutable ROM_EXT: ``` * 6: MU_EXT ----- ---- * 7: MU_EXT TOR LX-R * 8: IM_EXT ----- ---- * 9: IM_EXT TOR LX-R * 10: VIRTUAL NAPOT L--R * 11: STACK NA4 L--- ``` MU_EXT stands for mutable part of rom_ext, and IM_EXT is the immutable part. Slot 10 will be empty if address translation is not enabled, and stack guard is added back to slot 11. Before jumping to Owner SW, all lock bits will be cleared, so all entries can be recycled by Owner SW. Owner SW will be placed at the same entries as before (2, 3, 4). Change-Id: Id9b6cd68cc24a5816d3e3dc8374b5533a7c6eb75 Signed-off-by: Yi-Hsuan Deng --- sw/device/silicon_creator/imm_rom_ext/BUILD | 16 +++ .../silicon_creator/imm_rom_ext/imm_rom_ext.c | 7 ++ .../imm_rom_ext/imm_rom_ext_epmp.c | 101 ++++++++++++++++++ .../imm_rom_ext/imm_rom_ext_epmp.h | 62 +++++++++++ sw/device/silicon_creator/lib/drivers/BUILD | 10 ++ sw/device/silicon_creator/lib/drivers/epmp.c | 35 +++++- sw/device/silicon_creator/lib/drivers/epmp.h | 25 +++++ .../lib/drivers/epmp_unittest.cc | 64 +++++++++++ sw/device/silicon_creator/rom_ext/rom_ext.c | 62 ++--------- 9 files changed, 321 insertions(+), 61 deletions(-) create mode 100644 sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.c create mode 100644 sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.h create mode 100644 sw/device/silicon_creator/lib/drivers/epmp_unittest.cc diff --git a/sw/device/silicon_creator/imm_rom_ext/BUILD b/sw/device/silicon_creator/imm_rom_ext/BUILD index 88707aa6ad16a9..777d07f0829bab 100644 --- a/sw/device/silicon_creator/imm_rom_ext/BUILD +++ b/sw/device/silicon_creator/imm_rom_ext/BUILD @@ -9,6 +9,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", @@ -27,3 +28,18 @@ cc_library( "//sw/device/silicon_creator/rom_ext:rom_ext_manifest", ], ) + +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", + ], +) diff --git a/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext.c b/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext.c index af5837253df441..fdfb88082bf16c 100644 --- a/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext.c +++ b/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext.c @@ -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" @@ -30,11 +31,14 @@ 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); dbg_printf("IMM_ROM_EXT v0.1\r\n"); + dbg_print_epmp(); // Establish our identity. const manifest_t *rom_ext = rom_ext_manifest(); @@ -47,6 +51,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; } diff --git a/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.c b/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.c new file mode 100644 index 00000000000000..ea2da8338e8f6e --- /dev/null +++ b/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.c @@ -0,0 +1,101 @@ +// 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/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 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) { + // 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 13 allows RvDM access. + // Leave it unchanged. + + // ePMP region 12 gives read access to all of flash for both M and U modes. + // This flash region was in ePMP region 5. + epmp_set_napot(12, kFlashRegion, kEpmpPermLockedReadOnly); + + // ePMP region 11 protects the stack from overflow. + // This stack guard was in ePMP region 14. + epmp_set_napot(11, kStackGuard, kEpmpPermLockedNoAccess); + + // 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; +} diff --git a/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.h b/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.h new file mode 100644 index 00000000000000..356e795817a68c --- /dev/null +++ b/sw/device/silicon_creator/imm_rom_ext/imm_rom_ext_epmp.h @@ -0,0 +1,62 @@ +// 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: FLASH NAPOT L--R + * 13: RvDM NAPOT LXWR + * 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. + */ +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_ diff --git a/sw/device/silicon_creator/lib/drivers/BUILD b/sw/device/silicon_creator/lib/drivers/BUILD index 6cd68df58c0678..38438c417c891a 100644 --- a/sw/device/silicon_creator/lib/drivers/BUILD +++ b/sw/device/silicon_creator/lib/drivers/BUILD @@ -914,3 +914,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", + ], +) diff --git a/sw/device/silicon_creator/lib/drivers/epmp.c b/sw/device/silicon_creator/lib/drivers/epmp.c index a11f9fb1bb6c13..306df514ad608b 100644 --- a/sw/device/silicon_creator/lib/drivers/epmp.c +++ b/sw/device/silicon_creator/lib/drivers/epmp.c @@ -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; @@ -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); } diff --git a/sw/device/silicon_creator/lib/drivers/epmp.h b/sw/device/silicon_creator/lib/drivers/epmp.h index bdabb32ac85d10..25cc3a35eca65b 100644 --- a/sw/device/silicon_creator/lib/drivers/epmp.h +++ b/sw/device/silicon_creator/lib/drivers/epmp.h @@ -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. * diff --git a/sw/device/silicon_creator/lib/drivers/epmp_unittest.cc b/sw/device/silicon_creator/lib/drivers/epmp_unittest.cc new file mode 100644 index 00000000000000..9f6989c8ae04da --- /dev/null +++ b/sw/device/silicon_creator/lib/drivers/epmp_unittest.cc @@ -0,0 +1,64 @@ +// 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/lib/drivers/epmp.h" + +#include "gtest/gtest.h" +#include "sw/device/silicon_creator/testing/rom_test.h" + +namespace epmp_unittest { +namespace { + +struct NapotCase { + /** + * Start / end of the NAPOT region. + */ + uint32_t start; + uint32_t end; + /** + * Encoded NAPOT address. + */ + uint32_t encoded; +}; + +class NapotTest : public rom_test::RomTest, + public testing::WithParamInterface {}; + +TEST_P(NapotTest, Codec) { + epmp_region_t region = { + .start = (uintptr_t)GetParam().start, + .end = (uintptr_t)GetParam().end, + }; + EXPECT_EQ(epmp_encode_napot(region), GetParam().encoded); + + epmp_region_t decoded = epmp_decode_napot(GetParam().encoded); + EXPECT_EQ(decoded.start, GetParam().start); + EXPECT_EQ(decoded.end, GetParam().end); +} + +INSTANTIATE_TEST_SUITE_P(AllCases, NapotTest, + testing::Values( + NapotCase{ + .start = 0b1000010100100100101010100000, + .end = 0b1000010100100100101011000000, + .encoded = 0b10000101001001001010101011, + }, + NapotCase{ + .start = 0b101000001101000011100000000000, + .end = 0b101000001101000011100100000000, + .encoded = 0b1010000011010000111000011111, + }, + NapotCase{ + .start = 0b10111111111111111111111111111000, + .end = 0b11000000000000000000000000000000, + .encoded = 0b101111111111111111111111111110, + }, + NapotCase{ + .start = 0b00000000000000000000000000000000, + .end = 0b10000000000000000000000000000000, + .encoded = 0b001111111111111111111111111111, + })); + +} // namespace +} // namespace epmp_unittest diff --git a/sw/device/silicon_creator/rom_ext/rom_ext.c b/sw/device/silicon_creator/rom_ext/rom_ext.c index b50ba4ff08b88b..34dfa5f68adc30 100644 --- a/sw/device/silicon_creator/rom_ext/rom_ext.c +++ b/sw/device/silicon_creator/rom_ext/rom_ext.c @@ -68,26 +68,11 @@ owner_config_t owner_config; owner_application_keyring_t keyring; // ePMP regions for important address spaces. -const epmp_region_t kRamRegion = { - .start = TOP_EARLGREY_RAM_MAIN_BASE_ADDR, - .end = TOP_EARLGREY_RAM_MAIN_BASE_ADDR + TOP_EARLGREY_RAM_MAIN_SIZE_BYTES, -}; - -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 kRvDmRegion = { .start = TOP_EARLGREY_RV_DM_MEM_BASE_ADDR, .end = TOP_EARLGREY_RV_DM_MEM_BASE_ADDR + TOP_EARLGREY_RV_DM_MEM_SIZE_BYTES, }; -const epmp_region_t kFlashRegion = { - .start = TOP_EARLGREY_EFLASH_BASE_ADDR, - .end = TOP_EARLGREY_EFLASH_BASE_ADDR + TOP_EARLGREY_EFLASH_SIZE_BYTES, -}; - OT_WARN_UNUSED_RESULT static rom_error_t rom_ext_irq_error(void) { uint32_t mcause; @@ -158,7 +143,11 @@ static rom_error_t rom_ext_init(boot_data_t *boot_data) { // Configure UART0 as stdout. uart_init(kUartNCOValue); - // TODO: Verify ePMP expectations from ROM. + // Reclaim entries 0 ~ 7 from ROM and IMM_ROM_EXT. + for (int8_t i = 7; i >= 0; --i) { + epmp_clear((uint8_t)i); + } + HARDENED_RETURN_IF_ERROR(epmp_state_check()); // Conditionally patch AST and check that it is in the expected state. HARDENED_RETURN_IF_ERROR(ast_patch(lc_state)); @@ -292,12 +281,7 @@ static rom_error_t rom_ext_boot(const manifest_t *manifest) { SEC_MMIO_WRITE_INCREMENT(kFlashCtrlSecMmioCreatorInfoPagesLockdown + kOtpSecMmioCreatorSwCfgLockDown); - // ePMP region 15 gives read/write access to RAM. - epmp_set_napot(15, kRamRegion, kEpmpPermReadWrite); - - // Reconfigure the ePMP MMIO region to be NAPOT region 14, thus freeing - // up an ePMP entry for use elsewhere. - epmp_set_napot(14, kMmioRegion, kEpmpPermReadWrite); + epmp_clear_lock_bits(); // ePMP region 13 allows RvDM access. if (lc_state == kLcStateProd || lc_state == kLcStateProdEnd) { @@ -307,40 +291,6 @@ static rom_error_t rom_ext_boot(const manifest_t *manifest) { epmp_set_napot(13, kRvDmRegion, kEpmpPermReadWriteExecute); } - // 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. - epmp_set_napot(12, kFlashRegion, kEpmpPermReadOnly); - 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; - - epmp_set_napot(11, (epmp_region_t){.start = vwindow, .end = vwindow + size}, - kEpmpPermReadOnly); - } - 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) { - epmp_clear((uint8_t)i); - } HARDENED_RETURN_IF_ERROR(epmp_state_check()); // Configure address translation, compute the epmp regions and the entry