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) {}