diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index a3baaf070..6b649badf 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -150,6 +150,7 @@ SOURCE_TREZORHAL = [ 'embed/trezorhal/unix/fault_handlers.c', 'embed/trezorhal/unix/flash.c', 'embed/trezorhal/unix/flash_otp.c', + 'embed/trezorhal/unix/mpu.c', 'embed/trezorhal/unix/monoctr.c', 'embed/trezorhal/unix/random_delays.c', 'embed/trezorhal/unix/rng.c', diff --git a/core/SConscript.unix b/core/SConscript.unix index ca3c7fe75..bcb48e37b 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -423,6 +423,7 @@ SOURCE_UNIX = [ 'embed/trezorhal/unix/flash_otp.c', 'embed/trezorhal/unix/flash.c', 'embed/trezorhal/unix/fwutils.c', + 'embed/trezorhal/unix/mpu.c', 'embed/trezorhal/unix/random_delays.c', 'embed/trezorhal/unix/rng.c', 'embed/trezorhal/unix/systick.c', diff --git a/core/embed/boardloader/main.c b/core/embed/boardloader/main.c index 7aa83445c..d5b583191 100644 --- a/core/embed/boardloader/main.c +++ b/core/embed/boardloader/main.c @@ -262,8 +262,6 @@ int main(void) { clear_otg_hs_memory(); #endif - mpu_config_boardloader(); - fault_handlers_init(); #ifdef USE_SDRAM @@ -335,7 +333,7 @@ int main(void) { ensure_compatible_settings(); #endif - mpu_config_off(); + mpu_reconfig(MPU_MODE_DISABLED); // g_boot_command is preserved on STM32U5 jump_to(IMAGE_CODE_ALIGN(BOOTLOADER_START + IMAGE_HEADER_SIZE)); diff --git a/core/embed/bootloader/emulator.c b/core/embed/bootloader/emulator.c index f1c8481ff..99d2dd861 100644 --- a/core/embed/bootloader/emulator.c +++ b/core/embed/bootloader/emulator.c @@ -170,10 +170,6 @@ __attribute__((noreturn)) int main(int argc, char **argv) { jump_to(0); } -void mpu_config_bootloader(void) {} - -void mpu_config_off(void) {} - void jump_to(uint32_t address) { bool storage_is_erased = storage_empty(&STORAGE_AREAS[0]) && storage_empty(&STORAGE_AREAS[1]); diff --git a/core/embed/bootloader/emulator.h b/core/embed/bootloader/emulator.h index 9cf747075..7cd1adb01 100644 --- a/core/embed/bootloader/emulator.h +++ b/core/embed/bootloader/emulator.h @@ -13,8 +13,6 @@ extern uint8_t *FIRMWARE_START; void emulator_poll_events(void); void set_core_clock(int); -void mpu_config_bootloader(void); -void mpu_config_off(void); __attribute__((noreturn)) void jump_to(uint32_t address); #endif diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index 5099001e3..c65e0c063 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -251,6 +251,7 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, } static secbool check_vendor_header_lock(const vendor_header *const vhdr) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); uint8_t lock[FLASH_OTP_BLOCK_SIZE]; ensure(flash_otp_read(FLASH_OTP_BLOCK_VENDOR_HEADER_LOCK, 0, lock, FLASH_OTP_BLOCK_SIZE), @@ -260,10 +261,12 @@ static secbool check_vendor_header_lock(const vendor_header *const vhdr) { "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", FLASH_OTP_BLOCK_SIZE)) { + mpu_restore(mpu_mode); return sectrue; } uint8_t hash[32]; vendor_header_hash(vhdr, hash); + mpu_restore(mpu_mode); return sectrue * (0 == memcmp(lock, hash, 32)); } @@ -338,7 +341,8 @@ void real_jump_to_firmware(void) { ensure_compatible_settings(); #endif - mpu_config_off(); + mpu_reconfig(MPU_MODE_DISABLED); + jump_to(IMAGE_CODE_ALIGN(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE)); } @@ -398,8 +402,6 @@ int bootloader_main(void) { ui_screen_boot_stage_1(false); - mpu_config_bootloader(); - fault_handlers_init(); #ifdef TREZOR_EMULATOR diff --git a/core/embed/bootloader_ci/main.c b/core/embed/bootloader_ci/main.c index e58906273..931e97827 100644 --- a/core/embed/bootloader_ci/main.c +++ b/core/embed/bootloader_ci/main.c @@ -215,8 +215,6 @@ int main(void) { hash_processor_init(); #endif - mpu_config_bootloader(); - #if PRODUCTION check_bootloader_version(); #endif @@ -296,7 +294,8 @@ int main(void) { // do not check any trust flags on header, proceed - mpu_config_off(); + mpu_reconfig(MPU_MODE_DISABLED); + jump_to(IMAGE_CODE_ALIGN(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE)); return 0; diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index 933835f30..3b8d09455 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -176,15 +176,12 @@ int main(void) { secbool secret_ok = secret_optiga_get(secret); #endif - mpu_config_firmware_initial(); - entropy_init(); #if PRODUCTION || BOOTLOADER_QA check_and_replace_bootloader(); #endif - // Enable MPU - mpu_config_firmware(); + #endif // Init peripherals diff --git a/core/embed/lib/translations.c b/core/embed/lib/translations.c index d00fa0d48..191bcd989 100644 --- a/core/embed/lib/translations.c +++ b/core/embed/lib/translations.c @@ -5,6 +5,7 @@ #include "common.h" #include "flash.h" #include "model.h" +#include "mpu.h" bool translations_write(const uint8_t* data, uint32_t offset, uint32_t len) { uint32_t size = translations_area_bytesize(); @@ -12,12 +13,17 @@ bool translations_write(const uint8_t* data, uint32_t offset, uint32_t len) { return false; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_ASSETS); + ensure(flash_unlock_write(), "translations_write unlock"); // todo consider alignment ensure(flash_area_write_data_padded(&TRANSLATIONS_AREA, offset, data, len, 0xFF, FLASH_ALIGN(len)), "translations_write write"); ensure(flash_lock_write(), "translations_write lock"); + + mpu_restore(mpu_mode); + return true; } @@ -30,7 +36,9 @@ const uint8_t* translations_read(uint32_t* len, uint32_t offset) { } void translations_erase(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_ASSETS); ensure(flash_area_erase(&TRANSLATIONS_AREA, NULL), "translations erase"); + mpu_restore(mpu_mode); } uint32_t translations_area_bytesize(void) { diff --git a/core/embed/lib/unit_variant.c b/core/embed/lib/unit_variant.c index e062284de..4f5b7acaf 100644 --- a/core/embed/lib/unit_variant.c +++ b/core/embed/lib/unit_variant.c @@ -2,6 +2,7 @@ #include "flash_otp.h" #include "model.h" +#include "mpu.h" #include "unit_variant.h" #include TREZOR_BOARD @@ -51,6 +52,8 @@ static int16_t unit_variant_get_build_year(void) { } void unit_variant_init(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + uint8_t data[FLASH_OTP_BLOCK_SIZE]; secbool result = flash_otp_read(FLASH_OTP_BLOCK_DEVICE_VARIANT, 0, data, @@ -67,6 +70,8 @@ void unit_variant_init(void) { break; } } + + mpu_restore(mpu_mode); } uint8_t unit_variant_get_color(void) { return unit_variant_color; } diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index 05f0c931d..e69e5b6aa 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -813,15 +813,12 @@ int main(void) { uint32_t bootloader_version = read_bootloader_version(); const boardloader_version_t *boardloader_version = read_boardloader_version(); - mpu_config_prodtest_initial(); - #ifdef USE_OPTIGA optiga_init(); optiga_open_application(); pair_optiga(); #endif - mpu_config_prodtest(); fault_handlers_init(); display_clear(); diff --git a/core/embed/trezorhal/mpu.h b/core/embed/trezorhal/mpu.h index a4aa03728..cb9df5779 100644 --- a/core/embed/trezorhal/mpu.h +++ b/core/embed/trezorhal/mpu.h @@ -17,15 +17,48 @@ * along with this program. If not, see . */ -#ifndef __MPU_H__ -#define __MPU_H__ +#ifndef TREZORHAL_MPU_H +#define TREZORHAL_MPU_H -void mpu_config_off(void); -void mpu_config_boardloader(void); -void mpu_config_bootloader(void); -void mpu_config_firmware_initial(void); -void mpu_config_firmware(void); -void mpu_config_prodtest_initial(void); -void mpu_config_prodtest(void); +// The MPU driver can be set to on of the following modes. +// +// In each mode, the MPU is configured to allow access to specific +// memory regions. +// +// The `MPU_MODE_DEFAULT` mode is the most restrictive and serves as +// a base for other modes. +typedef enum { + MPU_MODE_DISABLED, // MPU is disabled + MPU_MODE_DEFAULT, // Default + MPU_MODE_BOARDCAPS, // + boardloader capabilities (privileged RO) + MPU_MODE_BOOTUPDATE, // + bootloader area (privileged RW) + MPU_MODE_OTP, // + OTP (privileged RW) + MPU_MODE_FSMC_REGS, // + FSMC control registers (privileged RW) + MPU_MODE_FLASHOB, // + Option bytes mapping (privileged RW) + MPU_MODE_SECRET, // + secret area (priviledeg RW) + MPU_MODE_STORAGE, // + both storage areas (privilehed RW) + MPU_MODE_ASSETS, // + assets (privileged RW) + MPU_MODE_APP, // + unprivileged DMA2D (RW) & Assets (RO) +} mpu_mode_t; -#endif +// Initializes the MPU and sets it to MPU_MODE_DISABLED. +// +// This function should be called before any other MPU function. +void mpu_init(void); + +// Returns the current MPU mode. +// +// If the MPU is not initialized, returns MPU_MODE_DISABLED. +mpu_mode_t mpu_get_mode(void); + +// Reconfigures the MPU to the given mode and returns the previous mode. +// +// If the MPU is not initialized, does nothing and returns MPU_MODE_DISABLED. +mpu_mode_t mpu_reconfig(mpu_mode_t mode); + +// Restores the MPU to the given mode. +// +// Same as `mpu_reconfig()`, but with a more descriptive name. +void mpu_restore(mpu_mode_t mode); + +#endif // TREZORHAL_MPU_H diff --git a/core/embed/trezorhal/stm32f4/board_capabilities.c b/core/embed/trezorhal/stm32f4/board_capabilities.c index c867c87cd..461fbaa15 100644 --- a/core/embed/trezorhal/stm32f4/board_capabilities.c +++ b/core/embed/trezorhal/stm32f4/board_capabilities.c @@ -17,10 +17,12 @@ * along with this program. If not, see . */ -#include "board_capabilities.h" #include + +#include "board_capabilities.h" #include "common.h" #include "model.h" +#include "mpu.h" static uint32_t board_name = 0; @@ -33,11 +35,14 @@ const boardloader_version_t *get_boardloader_version() { } void parse_boardloader_capabilities() { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_BOARDCAPS); + const uint8_t *pos = (const uint8_t *)BOARD_CAPABILITIES_ADDR; const uint8_t *end = (const uint8_t *)(BOARD_CAPABILITIES_ADDR + BOARD_CAPABILITIES_SIZE); if (memcmp(pos, CAPABILITIES_HEADER, 4) != 0) { + mpu_restore(mpu_mode); return; } @@ -70,6 +75,7 @@ void parse_boardloader_capabilities() { memcpy(&boardloader_version, pos, length); break; case TAG_TERMINATOR: + mpu_restore(mpu_mode); return; default: break; @@ -77,4 +83,6 @@ void parse_boardloader_capabilities() { pos += length; } + + mpu_restore(mpu_mode); } diff --git a/core/embed/trezorhal/stm32f4/bootutils.c b/core/embed/trezorhal/stm32f4/bootutils.c index ee01d3906..2fdd3f9af 100644 --- a/core/embed/trezorhal/stm32f4/bootutils.c +++ b/core/embed/trezorhal/stm32f4/bootutils.c @@ -91,7 +91,9 @@ reboot_with_args(boot_command_t command, const void* args, size_t args_size) { #ifdef ENSURE_COMPATIBLE_SETTINGS ensure_compatible_settings(); #endif - mpu_config_bootloader(); + + mpu_reconfig(MPU_MODE_DISABLED); + jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE, g_boot_command); for (;;) ; diff --git a/core/embed/trezorhal/stm32f4/entropy.c b/core/embed/trezorhal/stm32f4/entropy.c index 0c655c2ec..fd26328c8 100644 --- a/core/embed/trezorhal/stm32f4/entropy.c +++ b/core/embed/trezorhal/stm32f4/entropy.c @@ -22,6 +22,7 @@ #include "entropy.h" #include "flash_otp.h" #include "model.h" +#include "mpu.h" #include "rand.h" #include "stm32f4xx_ll_utils.h" @@ -29,6 +30,8 @@ static uint8_t g_hw_entropy[HW_ENTROPY_LEN]; void entropy_init(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + // collect entropy from UUID uint32_t w = LL_GetUID_Word0(); memcpy(g_hw_entropy, &w, 4); @@ -50,6 +53,8 @@ void entropy_init(void) { ensure(flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, g_hw_entropy + 12, FLASH_OTP_BLOCK_SIZE), NULL); + + mpu_restore(mpu_mode); } void entropy_get(uint8_t *buf) { memcpy(buf, g_hw_entropy, HW_ENTROPY_LEN); } diff --git a/core/embed/trezorhal/stm32f4/lowlevel.c b/core/embed/trezorhal/stm32f4/lowlevel.c index 5107522ed..188142f21 100644 --- a/core/embed/trezorhal/stm32f4/lowlevel.c +++ b/core/embed/trezorhal/stm32f4/lowlevel.c @@ -20,6 +20,9 @@ #include STM32_HAL_H #include "lowlevel.h" + +#include + #include "flash_otp.h" #pragma GCC optimize( \ @@ -80,19 +83,27 @@ secbool flash_check_option_bytes(void) { if (FLASH->OPTCR1 != FLASH_OPTCR1_nWRP) { return secfalse; } + + mpu_mode_t mode = mpu_reconfig(MPU_MODE_FLASHOB); // check values stored in flash memory if ((OPTION_BYTES_RDP_USER & ~3) != OPTION_BYTES_RDP_USER_VALUE) { // bits 0 and 1 are unused + mpu_reconfig(mode); return secfalse; } if ((OPTION_BYTES_BANK1_WRP & 0xCFFFU) != OPTION_BYTES_BANK1_WRP_VALUE) { // bits 12 and 13 are unused + mpu_reconfig(mode); return secfalse; } if ((OPTION_BYTES_BANK2_WRP & 0xFFFU) != OPTION_BYTES_BANK2_WRP_VALUE) { // bits 12, 13, 14, and 15 are unused + mpu_reconfig(mode); return secfalse; } + + mpu_reconfig(mode); + return sectrue; } diff --git a/core/embed/trezorhal/stm32f4/monoctr.c b/core/embed/trezorhal/stm32f4/monoctr.c index 70b58faa9..89551b308 100644 --- a/core/embed/trezorhal/stm32f4/monoctr.c +++ b/core/embed/trezorhal/stm32f4/monoctr.c @@ -20,6 +20,7 @@ #include "monoctr.h" #include "flash_otp.h" #include "model.h" +#include "mpu.h" #include "string.h" #if PRODUCTION @@ -70,7 +71,9 @@ secbool monoctr_write(monoctr_type_t type, uint8_t value) { } } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); ensure(flash_otp_write(block, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL); + mpu_restore(mpu_mode); #endif return sectrue; @@ -86,7 +89,9 @@ secbool monoctr_read(monoctr_type_t type, uint8_t* value) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); ensure(flash_otp_read(block, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL); + mpu_restore(mpu_mode); int result = 0; diff --git a/core/embed/trezorhal/stm32f4/mpu.c b/core/embed/trezorhal/stm32f4/mpu.c index af40d3814..92632a75f 100644 --- a/core/embed/trezorhal/stm32f4/mpu.c +++ b/core/embed/trezorhal/stm32f4/mpu.c @@ -19,20 +19,44 @@ #include STM32_HAL_H #include TREZOR_BOARD + +#include +#include + +#include "irq.h" +#include "model.h" +#include "mpu.h" + #include "stm32f4xx_ll_cortex.h" // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html -#define MPU_RASR_ATTR_FLASH (MPU_RASR_C_Msk) -#define MPU_RASR_ATTR_SRAM (MPU_RASR_C_Msk | MPU_RASR_S_Msk) -#define MPU_RASR_ATTR_PERIPH (MPU_RASR_B_Msk | MPU_RASR_S_Msk) +#define MPU_RASR_ATTR_FLASH_CODE (MPU_RASR_C_Msk) +#define MPU_RASR_ATTR_FLASH_DATA (MPU_RASR_C_Msk | MPU_RASR_XN_Msk) +#define MPU_RASR_ATTR_SRAM (MPU_RASR_C_Msk | MPU_RASR_S_Msk | MPU_RASR_XN_Msk) +#define MPU_RASR_ATTR_PERIPH (MPU_RASR_B_Msk | MPU_RASR_S_Msk | MPU_RASR_XN_Msk) +#define SET_REGION(region, start, size, mask, attr, access) \ + do { \ + uint32_t _enable = MPU_RASR_ENABLE_Msk; \ + uint32_t _size = LL_MPU_REGION_##size; \ + uint32_t _mask = (mask) << MPU_RASR_SRD_Pos; \ + uint32_t _attr = MPU_RASR_ATTR_##attr; \ + uint32_t _access = LL_MPU_REGION_##access; \ + MPU->RNR = region; \ + MPU->RBAR = (start) & ~0x1F; \ + MPU->RASR = _enable | _size | _mask | _attr | _access; \ + } while (0) + +#define DIS_REGION(region) \ + do { \ + MPU->RNR = region; \ + MPU->RBAR = 0; \ + MPU->RASR = 0; \ + } while (0) + +/* #define MPU_SUBREGION_DISABLE(X) ((X) << MPU_RASR_SRD_Pos) -void mpu_config_off(void) { - // Disable MPU - HAL_MPU_Disable(); -} - void mpu_config_boardloader(void) { // nothing to be done } @@ -103,7 +127,8 @@ void mpu_config_bootloader(void) { // Enable MPU HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); } - +*/ +/* void mpu_config_firmware_initial(void) {} void mpu_config_firmware(void) { @@ -111,14 +136,14 @@ void mpu_config_firmware(void) { HAL_MPU_Disable(); // Note: later entries overwrite previous ones - - /* - // Boardloader (0x08000000 - 0x0800FFFF, 64 KiB, read-only, execute never) - MPU->RBAR = FLASH_BASE | MPU_REGION_NUMBER0; - MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO | MPU_RASR_XN_Msk; - */ - +*/ +/* + // Boardloader (0x08000000 - 0x0800FFFF, 64 KiB, read-only, execute never) + MPU->RBAR = FLASH_BASE | MPU_REGION_NUMBER0; + MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | + LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO | MPU_RASR_XN_Msk; +*/ +/* // Bootloader (0x08020000 - 0x0803FFFF, 128 KiB, read-only) MPU->RNR = MPU_REGION_NUMBER0; MPU->RBAR = FLASH_BASE + 0x20000; @@ -308,3 +333,264 @@ void mpu_config_prodtest(void) { __asm__ volatile("dsb"); __asm__ volatile("isb"); } +*/ + +typedef struct { + // Set if the driver is initialized + bool initialized; + // Current mode + mpu_mode_t mode; + +} mpu_driver_t; + +mpu_driver_t g_mpu_driver = { + .initialized = false, + .mode = MPU_MODE_DISABLED, +}; + +static void mpu_init_fixed_regions(void) { + // Regions #0 to #4 are fixed for all targets + +#ifdef BOARDLOADER + // clang-format off + // Code in the Flash Bank #1 (Unprivileged, Read-Only, Executable) + // Subregion: 48KB = 64KB except 2/8 at end + SET_REGION( 0, BOARDLOADER_START, SIZE_2MB, 0xC0, FLASH_CODE, PRIV_RO_URO ); + DIS_REGION( 1 ); + // All CCMRAM (Unprivileged, Read-Write, Non-Executable) + SET_REGION( 2, CCMDATARAM_BASE, SIZE_64KB, 0x00, SRAM, FULL_ACCESS ); + // All SRAM (Unprivileged, Read-Write, Non-Executable) + // Subregion: 192KB = 256KB except 2/8 at end + SET_REGION( 3, SRAM_BASE, SIZE_256KB, 0xC0, SRAM, FULL_ACCESS ); + // Kernel RAM (Privileged, Read-Write, Non-Executable) + // SET_REGION( 4, ..., SIZE_xxx, 0xXX, ATTR_SRAM, PRIV_RW ); + DIS_REGION( 4 ); + // clang-format on +#endif +#ifdef BOOTLOADER + // clang-format off + // Code in the Flash Bank #1 (Unprivileged, Read-Only, Executable) + // Subregion: 128KB = 1024KB except 2/8 at start + SET_REGION( 0, BOARDLOADER_START, SIZE_2MB, 0x00, FLASH_CODE, PRIV_RO_URO ); + DIS_REGION( 1 ); + // All CCMRAM (Unprivileged, Read-Write, Non-Executable) + SET_REGION( 2, CCMDATARAM_BASE, SIZE_64KB, 0x00, SRAM, FULL_ACCESS ); + // All SRAM (Unprivileged, Read-Write, Non-Executable) + // Subregion: 192KB = 256KB except 2/8 at end + SET_REGION( 3, SRAM_BASE, SIZE_256KB, 0xC0, SRAM, FULL_ACCESS ); + // Kernel RAM (Privileged, Read-Write, Non-Executable) + // SET_REGION( 4, ..., SIZE_xxx, 0xXX, ATTR_SRAM, PRIV_RW ); + DIS_REGION( 4 ); + // clang-format on +#endif +#ifdef KERNEL + // clang-format off + // Code in the Flash Bank #1 (Unprivileged, Read-Only, Executable) + // Subregion: 768KB = 1024KB except 2/8 at start + SET_REGION( 0, FLASH_BASE, SIZE_1MB, 0x03, FLASH_CODE, PRIV_RO_URO ); + // Code in the Flash Bank #2 (Unprivileged, Read-Only, Executable) + // Subregion: 896KB = 1024KB except 1/8 at start + SET_REGION( 1, FLASH_BASE + 0x100000, SIZE_1MB, 0x01, FLASH_CODE, PRIV_RO_URO ); + // All CCMRAM (Unprivileged, Read-Write, Non-Executable) + SET_REGION( 2, CCMDATARAM_BASE, SIZE_64KB, 0x00, SRAM, FULL_ACCESS ); + // All SRAM (Unprivileged, Read-Write, Non-Executable) + // Subregion: 192KB = 256KB except 2/8 at end + SET_REGION( 3, SRAM_BASE, SIZE_256KB, 0xC0, SRAM, FULL_ACCESS ); + // Kernel RAM (Privileged, Read-Write, Non-Executable) + // SET_REGION( 4, ..., SIZE_xxx, 0xXX, ATTR_SRAM, PRIV_RW ); + DIS_REGION( 4 ); + // clang-format on +#endif +#ifdef FIRMWARE + // TODO +#endif +#ifdef PRODTEST + // TODO +#endif + + // Regions #5 to #7 are banked + DIS_REGION(5); + DIS_REGION(6); + DIS_REGION(7); +} + +void mpu_init(void) { + mpu_driver_t* drv = &g_mpu_driver; + + if (drv->initialized) { + return; + } + + irq_key_t irq_key = irq_lock(); + + HAL_MPU_Disable(); + + mpu_init_fixed_regions(); + + drv->mode = MPU_MODE_DISABLED; + drv->initialized = true; + + irq_unlock(irq_key); +} + +mpu_mode_t mpu_get_mode(void) { + mpu_driver_t* drv = &g_mpu_driver; + + if (!drv->initialized) { + return MPU_MODE_DISABLED; + } + + return drv->mode; +} + +// STM32F4xx memory map +// +// 0x08000000 2MB FLASH +// 0x10000000 64KB CCMRAM +// 0x1FFF7800 528B OTP +// 0x20000000 192KB SRAM +// 0x40000000 512MB PERIPH + +// STM32F4xx flash layout +// +// 0x08000000 4x 16KB (BANK #1) +// 0x08010000 1x 64KB (BANK #1) +// 0x08020000 7x 128KB (BANK #1) +// 0x08100000 4x 16KB (BANK #2) +// 0x08110000 1x 64KB (BANK #3) +// 0x08120000 7x 128KB (BANK #4) + +mpu_mode_t mpu_reconfig(mpu_mode_t mode) { + mpu_driver_t* drv = &g_mpu_driver; + + if (!drv->initialized) { + // Solves the issue when some IRQ handler tries to reconfigure + // MPU before it is initialized + return MPU_MODE_DISABLED; + } + + irq_key_t irq_key = irq_lock(); + + HAL_MPU_Disable(); + + // Region #5 and #6 are banked + + // clang-format off + switch (mode) { + case MPU_MODE_BOARDCAPS: + DIS_REGION( 5 ); + // Boardloader (Privileged, Read-Only, Non-Executable) + // Subregion: 48KB = 64KB except 2/8 at end + SET_REGION( 6, FLASH_BASE, SIZE_64KB, 0xC0, FLASH_DATA, PRIV_RO ); + break; + + case MPU_MODE_BOOTUPDATE: + DIS_REGION( 5 ); + // Bootloader (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_BASE + 0x20000, SIZE_128KB, 0x00, FLASH_DATA, PRIV_RW ); + break; + + case MPU_MODE_OTP: + DIS_REGION( 5 ); + // OTP (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_OTP_BASE, SIZE_1KB, 0x00, FLASH_DATA, FULL_ACCESS ); + break; + + case MPU_MODE_FSMC_REGS: + DIS_REGION( 5 ); + // FSMC Control Registers (Privileged, Read-Write, Non-Executable) + // 0xA0000000 = FMSC_R_BASE (not defined in used headers) + SET_REGION( 6, 0xA0000000, SIZE_4KB, 0x00, FLASH_DATA, FULL_ACCESS ); + break; + + case MPU_MODE_FLASHOB: + SET_REGION( 5, 0x1FFFC000, SIZE_1KB, 0x00, FLASH_DATA, PRIV_RO ); + SET_REGION( 6, 0x1FFEC000, SIZE_1KB, 0x00, FLASH_DATA, PRIV_RO ); + break; + +#ifdef USE_OPTIGA + // with optiga, we use the secret sector, and assets area is smaller + case MPU_MODE_SECRET: + DIS_REGION( 5 ); + // Secret sector in Bank #2 (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_BASE + 0x100000, SIZE_16KB, 0x00, FLASH_DATA, PRIV_RW ); + break; + + case MPU_MODE_ASSETS: + DIS_REGION( 5 ); + // Assets (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_BASE + 0x108000, SIZE_32KB, 0x00, FLASH_DATA, PRIV_RW ); + break; + + case MPU_MODE_APP: + // Unused (maybe privileged kernel code in the future) + DIS_REGION( 5 ); + // Assets (Unprivileged, Read-Only, Non-Executable) + SET_REGION( 6, FLASH_BASE + 0x108000, SIZE_32KB, 0x00, FLASH_DATA, PRIV_RO_URO ); + break; + +#else + // without optiga, we use additional sector for assets area + case MPU_MODE_ASSETS: + DIS_REGION( 5 ); + // Assets (Privileged, Read-Write, Non-Executable) + // Subregion: 48KB = 64KB except 2/8 at end + SET_REGION( 6, FLASH_BASE + 0x100000, SIZE_64KB, 0xC0, FLASH_DATA, PRIV_RW ); + break; + + case MPU_MODE_APP: + // Unused (maybe privileged kernel code in the future) + DIS_REGION( 5 ); + // Assets (Unprivileged, Read-Only, Non-Executable) + // Subregion: 48KB = 64KB except 2/8 at end + SET_REGION( 6, FLASH_BASE + 0x100000, SIZE_64KB, 0xC0, FLASH_DATA, PRIV_RO_URO ); + break; + +#endif + + case MPU_MODE_STORAGE: + // Storage in the Flash Bank #1 (Privileged, Read-Write, Non-Executable) + SET_REGION( 5, FLASH_BASE + 0x10000, SIZE_64KB, 0x00, FLASH_DATA, PRIV_RW ); + // Storage in the Flash Bank #2 (Privileged, Read-Write, Non-Executable) + SET_REGION( 6, FLASH_BASE + 0x110000, SIZE_64KB, 0x00, FLASH_DATA, PRIV_RW ); + break; + + + + case MPU_MODE_DEFAULT: + default: + DIS_REGION( 5 ); + DIS_REGION( 6 ); + break; + } + // clang-format on + + // Region #7 is banked + + // clang-format off + switch (mode) { + case MPU_MODE_APP: + // Dma2D (Unprivileged, Read-Write, Non-Executable) + // 3KB = 4KB except 1/4 at end + SET_REGION( 7, 0x4002B000, SIZE_4KB, 0xC0, PERIPH, FULL_ACCESS ); + break; + default: + // All Peripherals (Privileged, Read-Write, Non-Executable) + SET_REGION( 7, PERIPH_BASE, SIZE_1GB, 0x00, PERIPH, PRIV_RW ); + break; + } + // clang-format on + + if (mode != MPU_MODE_DISABLED) { + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + } + + mpu_mode_t prev_mode = drv->mode; + drv->mode = mode; + + irq_unlock(irq_key); + + return prev_mode; +} + +void mpu_restore(mpu_mode_t mode) { mpu_reconfig(mode); } diff --git a/core/embed/trezorhal/stm32f4/secret.c b/core/embed/trezorhal/stm32f4/secret.c index 72a3aefc0..a02df2636 100644 --- a/core/embed/trezorhal/stm32f4/secret.c +++ b/core/embed/trezorhal/stm32f4/secret.c @@ -4,6 +4,7 @@ #include "display_draw.h" #include "flash.h" #include "model.h" +#include "mpu.h" #ifdef FANCY_FATAL_ERROR #include "rust_ui.h" @@ -20,10 +21,15 @@ secbool secret_verify_header(void) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + bootloader_locked = memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0 ? sectrue : secfalse; + + mpu_restore(mpu_mode); + bootloader_locked_set = sectrue; return bootloader_locked; } @@ -44,12 +50,14 @@ void secret_write_header(void) { } void secret_write(const uint8_t* data, uint32_t offset, uint32_t len) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); ensure(flash_unlock_write(), "secret write"); for (int i = 0; i < len; i++) { ensure(flash_area_write_byte(&SECRET_AREA, offset + i, data[i]), "secret write"); } ensure(flash_lock_write(), "secret write"); + mpu_restore(mpu_mode); } secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len) { @@ -63,28 +71,40 @@ secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); memcpy(data, addr, len); + mpu_restore(mpu_mode); return sectrue; } secbool secret_wiped(void) { uint32_t size = flash_area_get_size(&SECRET_AREA); + secbool wiped = sectrue; + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); for (int i = 0; i < size; i += 4) { uint32_t* addr = (uint32_t*)flash_area_get_address(&SECRET_AREA, i, 4); if (addr == NULL) { - return secfalse; + wiped = secfalse; + break; } if (*addr != 0xFFFFFFFF) { - return secfalse; + wiped = secfalse; + break; } } - return sectrue; + + mpu_restore(mpu_mode); + + return wiped; } void secret_erase(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); + mpu_restore(mpu_mode); } secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) { diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c index 1f52fdfb2..fec5bf3c3 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c @@ -22,6 +22,7 @@ #include "display_io.h" #include "irq.h" +#include "mpu.h" __IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS = (__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE); @@ -127,7 +128,9 @@ void display_io_init_fmc(void) { normal_mode_timing.DataLatency = 2; // don't care normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A; + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_FSMC_REGS); HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL); + mpu_restore(mpu_mode); } #ifdef DISPLAY_TE_INTERRUPT_HANDLER diff --git a/core/embed/trezorhal/stm32u5/entropy.c b/core/embed/trezorhal/stm32u5/entropy.c index c1af6ded3..2b32cdfca 100644 --- a/core/embed/trezorhal/stm32u5/entropy.c +++ b/core/embed/trezorhal/stm32u5/entropy.c @@ -22,6 +22,7 @@ #include "entropy.h" #include "flash_otp.h" #include "model.h" +#include "mpu.h" #include "rand.h" #include "stm32u5xx_ll_utils.h" @@ -29,6 +30,8 @@ static uint8_t g_hw_entropy[HW_ENTROPY_LEN]; void entropy_init(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP); + // collect entropy from UUID uint32_t w = LL_GetUID_Word0(); memcpy(g_hw_entropy, &w, 4); @@ -50,6 +53,8 @@ void entropy_init(void) { ensure(flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, g_hw_entropy + 12, FLASH_OTP_BLOCK_SIZE), NULL); + + mpu_restore(mpu_mode); } void entropy_get(uint8_t *buf) { memcpy(buf, g_hw_entropy, HW_ENTROPY_LEN); } diff --git a/core/embed/trezorhal/stm32u5/monoctr.c b/core/embed/trezorhal/stm32u5/monoctr.c index 6504371fa..24171eab8 100644 --- a/core/embed/trezorhal/stm32u5/monoctr.c +++ b/core/embed/trezorhal/stm32u5/monoctr.c @@ -20,6 +20,7 @@ #include "monoctr.h" #include "flash_area.h" #include "model.h" +#include "mpu.h" #include "secret.h" static int32_t get_offset(monoctr_type_t type) { @@ -80,6 +81,8 @@ secbool monoctr_read(monoctr_type_t type, uint8_t *value) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + int counter = 0; int i = 0; @@ -111,10 +114,13 @@ secbool monoctr_read(monoctr_type_t type, uint8_t *value) { if (not_cleared != sectrue) { // monotonic counter is not valid + mpu_restore(mpu_mode); return secfalse; } } + mpu_restore(mpu_mode); + if (value != NULL) { *value = counter; } else { diff --git a/core/embed/trezorhal/stm32u5/mpu.c b/core/embed/trezorhal/stm32u5/mpu.c index 25c04d5e1..d6c752e44 100644 --- a/core/embed/trezorhal/stm32u5/mpu.c +++ b/core/embed/trezorhal/stm32u5/mpu.c @@ -19,8 +19,11 @@ #include STM32_HAL_H #include + #include "common.h" #include "model.h" +#include "mpu.h" + #include "stm32u5xx_ll_cortex.h" // region type @@ -152,106 +155,192 @@ static void mpu_set_attributes(void) { #define OTP_AND_ID_SIZE 0x800 -void mpu_config_boardloader(void) { - HAL_MPU_Disable(); - mpu_set_attributes(); +// clang-format on + +#define KERNEL_RAM_START (SRAM2_BASE - SIZE_16K) +#define KERNEL_RAM_SIZE (SIZE_24K) + +#define COREAPP_RAM1_START SRAM1_BASE +#define COREAPP_RAM1_SIZE (SIZE_192K - SIZE_16K) + +#define COREAPP_RAM2_START (SRAM2_BASE + SIZE_8K) +#define COREAPP_RAM2_SIZE (SRAM_SIZE - (SIZE_192K + SIZE_8K)) + +typedef struct { + // Set if the driver is initialized + bool initialized; + // Current mode + mpu_mode_t mode; + +} mpu_driver_t; + +mpu_driver_t g_mpu_driver = { + .initialized = false, + .mode = MPU_MODE_DISABLED, +}; + +static void mpu_init_fixed_regions(void) { + // Regions #0 to #5 are fixed for all targets + // clang-format off +#if defined(BOARDLOADER) // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, SECRET_START, SECRET_SIZE, FLASH_DATA, YES, NO ); // Secret - SET_REGION( 1, BOARDLOADER_START, BOARDLOADER_SIZE, FLASH_CODE, NO, NO ); // Boardloader code - SET_REGION( 2, BOOTLOADER_START, L1_REST_SIZE, FLASH_DATA, YES, NO ); // Bootloader + Storage + Firmware - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, NO ); // Peripherals + SET_REGION( 0, BOARDLOADER_START, BOARDLOADER_SIZE, FLASH_CODE, NO, NO ); + SET_REGION( 1, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); + DIS_REGION( 2 ); + DIS_REGION( 3 ); + DIS_REGION( 4 ); + SET_REGION( 5, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); +#endif +#if defined(BOOTLOADER) + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, BOOTLOADER_START, BOOTLOADER_SIZE, FLASH_CODE, NO, NO ); + SET_REGION( 1, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); + DIS_REGION( 2 ); + DIS_REGION( 3 ); + DIS_REGION( 4 ); + SET_REGION( 5, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); +#endif +#if defined(KERNEL) + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, KERNEL_START, KERNEL_SIZE, FLASH_CODE, NO, NO ); + SET_REGION( 1, KERNEL_RAM_START, KERNEL_RAM_SIZE, SRAM, YES, NO ); + SET_REGION( 2, COREAPP_START, COREAPP_SIZE, FLASH_CODE, NO, YES ); + SET_REGION( 3, COREAPP_RAM1_START, COREAPP_RAM1_SIZE, SRAM, YES, YES ); + SET_REGION( 4, COREAPP_RAM2_START, COREAPP_RAM2_SIZE, SRAM, YES, YES ); + SET_REGION( 5, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); +#endif +#if defined(FIRMWARE) + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, NO ); + SET_REGION( 1, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); + DIS_REGION( 2 ); + DIS_REGION( 3 ); + DIS_REGION( 4 ); + SET_REGION( 5, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); +#endif +#if defined(PRODTEST) + SET_REGION( 0, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, NO ); + SET_REGION( 1, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); + DIS_REGION( 2 ); + DIS_REGION( 3 ); + DIS_REGION( 4 ); + SET_REGION( 5, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); +#endif + + // Regions #6 and #7 are banked + DIS_REGION( 6 ); - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, NO ); // SRAM4 + DIS_REGION( 7 ); // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); } -void mpu_config_bootloader(void) { +void mpu_init(void) { + mpu_driver_t* drv = &g_mpu_driver; + + if (drv->initialized) { + return; + } + + irq_key_t irq_key = irq_lock(); + HAL_MPU_Disable(); + mpu_set_attributes(); - // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, SECRET_START, L2_PREV_SIZE, FLASH_DATA, YES, NO ); // Secret + Boardloader - SET_REGION( 1, BOOTLOADER_START, BOOTLOADER_SIZE, FLASH_CODE, NO, NO ); // Bootloader code - SET_REGION( 2, STORAGE_START, L2_REST_SIZE, FLASH_DATA, YES, NO ); // Storage + Firmware - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, NO ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, NO ); // OTP - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, NO ); // SRAM4 - // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + + mpu_init_fixed_regions(); + + drv->mode = MPU_MODE_DISABLED; + drv->initialized = true; + + irq_unlock(irq_key); } -void mpu_config_firmware_initial(void) { +mpu_mode_t mpu_get_mode(void) { + mpu_driver_t* drv = &g_mpu_driver; + + if (!drv->initialized) { + return MPU_MODE_DISABLED; + } + + return drv->mode; +} + +mpu_mode_t mpu_reconfig(mpu_mode_t mode) { + mpu_driver_t* drv = &g_mpu_driver; + + if (!drv->initialized) { + // Solves the issue when some IRQ handler tries to reconfigure + // MPU before it is initialized + return MPU_MODE_DISABLED; + } + + irq_key_t irq_key = irq_lock(); + HAL_MPU_Disable(); - mpu_set_attributes(); + + // Region #6 is banked + // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, BOOTLOADER_START, L3_PREV_SIZE_BLD, FLASH_DATA, YES, YES ); // Bootloader + Storage - SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware - SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, SIZE_2K, FLASH_DATA, YES, YES ); // OTP - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 + switch (mode) { + case MPU_MODE_DISABLED: + break; + case MPU_MODE_BOARDCAPS: + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 6, BOARDLOADER_START, BOARDLOADER_SIZE, FLASH_DATA, NO, NO ); + break; + case MPU_MODE_BOOTUPDATE: + SET_REGION( 6, BOOTLOADER_START, BOOTLOADER_SIZE, FLASH_DATA, YES, NO ); + break; + case MPU_MODE_OTP: + SET_REGION( 6, FLASH_OTP_BASE, OTP_AND_ID_SIZE, FLASH_DATA, NO, NO ); + break; + case MPU_MODE_SECRET: + SET_REGION( 6, SECRET_START, SECRET_SIZE, FLASH_DATA, YES, NO ); + break; + case MPU_MODE_STORAGE: + SET_REGION( 6, STORAGE_START, STORAGE_SIZE, FLASH_DATA, YES, NO ); + break; + case MPU_MODE_ASSETS: + SET_REGION( 6, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, NO ); + break; + case MPU_MODE_APP: + SET_REGION( 6, ASSETS_START, ASSETS_SIZE, FLASH_DATA, NO, YES ); + break; + case MPU_MODE_DEFAULT: + case MPU_MODE_FSMC_REGS: + default: + DIS_REGION( 6 ); + break; + } // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + + // Region #7 is banked + + // clang-format off + switch (mode) { + case MPU_MODE_APP: + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + // DMA2D peripherals (Uprivileged, Read-Write, Non-Executable) + SET_REGION( 7, 0x5002B000, SIZE_3K, PERIPHERAL, YES, YES ); + break; + default: + // All peripherals (Pivileged, Read-Write, Non-Executable) + SET_REGION( 7, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, NO ); + break; + } + // clang-format on + + if (mode != MPU_MODE_DISABLED) { + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + } + + mpu_mode_t prev_mode = drv->mode; + drv->mode = mode; + + irq_unlock(irq_key); + + return prev_mode; } -void mpu_config_firmware(void) { - HAL_MPU_Disable(); - mpu_set_attributes(); - // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, STORAGE_START, STORAGE_SIZE, FLASH_DATA, YES, YES ); // Storage - SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware - SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, YES ); // OTP - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 - // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); -} - -void mpu_config_prodtest_initial(void) { - HAL_MPU_Disable(); - mpu_set_attributes(); - // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, FLASH_BASE, L3_PREV_SIZE, FLASH_DATA, YES, YES ); // Secret, Bld, Storage - SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware - SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, YES ); // OTP - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 - // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); -} - -void mpu_config_prodtest(void) { - HAL_MPU_Disable(); - mpu_set_attributes(); - // clang-format off - // REGION ADDRESS SIZE TYPE WRITE UNPRIV - SET_REGION( 0, STORAGE_START, STORAGE_SIZE, FLASH_DATA, YES, YES ); // Storage - SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, YES, YES ); // Firmware - SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets - SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 - SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface - SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SET_REGION( 6, FLASH_OTP_BASE, OTP_AND_ID_SIZE, FLASH_DATA, YES, YES ); // OTP + device ID - SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 - // clang-format on - HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); -} - -void mpu_config_off(void) { HAL_MPU_Disable(); } +void mpu_restore(mpu_mode_t mode) { mpu_reconfig(mode); } diff --git a/core/embed/trezorhal/stm32u5/secret.c b/core/embed/trezorhal/stm32u5/secret.c index 104fdb5dd..33a08bbbe 100644 --- a/core/embed/trezorhal/stm32u5/secret.c +++ b/core/embed/trezorhal/stm32u5/secret.c @@ -6,6 +6,7 @@ #include "flash.h" #include "memzero.h" #include "model.h" +#include "mpu.h" #include "rng.h" #include "secure_aes.h" @@ -19,17 +20,25 @@ secbool secret_verify_header(void) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + bootloader_locked = memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0 ? sectrue : secfalse; + + mpu_restore(mpu_mode); + return bootloader_locked; } secbool secret_ensure_initialized(void) { if (sectrue != secret_verify_header()) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_STORAGE); ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), "erase storage failed"); + mpu_restore(mpu_mode); + secret_erase(); secret_write_header(); return secfalse; @@ -58,6 +67,7 @@ void secret_write_header(void) { } void secret_write(const uint8_t *data, uint32_t offset, uint32_t len) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); ensure(flash_unlock_write(), "secret write"); for (int i = 0; i < len / 16; i++) { ensure(flash_area_write_quadword(&SECRET_AREA, offset + (i * 16), @@ -65,6 +75,7 @@ void secret_write(const uint8_t *data, uint32_t offset, uint32_t len) { "secret write"); } ensure(flash_lock_write(), "secret write"); + mpu_restore(mpu_mode); } secbool secret_read(uint8_t *data, uint32_t offset, uint32_t len) { @@ -76,7 +87,10 @@ secbool secret_read(uint8_t *data, uint32_t offset, uint32_t len) { if (addr == NULL) { return secfalse; } + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); memcpy(data, addr, len); + mpu_restore(mpu_mode); return sectrue; } @@ -106,6 +120,8 @@ static secbool secret_present(uint32_t offset, uint32_t len) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + int secret_empty_bytes = 0; for (int i = 0; i < len; i++) { @@ -115,6 +131,9 @@ static secbool secret_present(uint32_t offset, uint32_t len) { secret_empty_bytes++; } } + + mpu_restore(mpu_mode); + return sectrue * (secret_empty_bytes != len); } @@ -152,6 +171,8 @@ static void secret_bhk_load(void) { } void secret_bhk_regenerate(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + ensure(flash_area_erase(&BHK_AREA, NULL), "Failed regenerating BHK"); ensure(flash_unlock_write(), "Failed regenerating BHK"); for (int i = 0; i < 2; i++) { @@ -164,6 +185,9 @@ void secret_bhk_regenerate(void) { memzero(val, sizeof(val)); ensure(res, "Failed regenerating BHK"); } + + mpu_restore(mpu_mode); + ensure(flash_lock_write(), "Failed regenerating BHK"); } @@ -187,6 +211,8 @@ secbool secret_optiga_writable(void) { return secfalse; } + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + int secret_empty_bytes = 0; for (int i = 0; i < len; i++) { @@ -196,6 +222,9 @@ secbool secret_optiga_writable(void) { secret_empty_bytes++; } } + + mpu_restore(mpu_mode); + return sectrue * (secret_empty_bytes == len); } @@ -272,7 +301,9 @@ void secret_optiga_erase(void) { } void secret_erase(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); + mpu_restore(mpu_mode); } void secret_prepare_fw(secbool allow_run_with_secret, secbool trust_all) { diff --git a/core/embed/trezorhal/unix/mpu.c b/core/embed/trezorhal/unix/mpu.c new file mode 100644 index 000000000..e91a8fa72 --- /dev/null +++ b/core/embed/trezorhal/unix/mpu.c @@ -0,0 +1,30 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mpu.h" + +void mpu_init(void) { + // MPU functions are not fully implemented in Emulator +} + +mpu_mode_t mpu_get_mode(void) { return MPU_MODE_DISABLED; } + +mpu_mode_t mpu_reconfig(mpu_mode_t mode) { return MPU_MODE_DISABLED; } + +void mpu_restore(mpu_mode_t mode) {}