diff --git a/core/SConscript.boardloader b/core/SConscript.boardloader index 02ff325811..c067a83db8 100644 --- a/core/SConscript.boardloader +++ b/core/SConscript.boardloader @@ -79,10 +79,7 @@ env = Environment(ENV=os.environ, FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) -FILE_SUFFIX= env.get('ENV')['SUFFIX'] - SOURCE_BOARDLOADER = [ - f"embed/sys/startup/{FILE_SUFFIX}/startup_stage_0.s", 'embed/projects/boardloader/main.c', ] diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 2d7b133856..95c9cffec5 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -101,10 +101,7 @@ env = Environment( FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) -FILE_SUFFIX= env.get('ENV')['SUFFIX'] - SOURCE_BOOTLOADER = [ - f'embed/sys/startup/{FILE_SUFFIX}/startup_stage_1.s', 'embed/projects/bootloader/header.S', 'embed/projects/bootloader/bootui.c', 'embed/projects/bootloader/main.c', diff --git a/core/SConscript.bootloader_ci b/core/SConscript.bootloader_ci index 7df885fdfb..2c8bb2f661 100644 --- a/core/SConscript.bootloader_ci +++ b/core/SConscript.bootloader_ci @@ -95,10 +95,7 @@ env = Environment( FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) -FILE_SUFFIX= env.get('ENV')['SUFFIX'] - SOURCE_BOOTLOADER = [ - f'embed/sys/startup/{FILE_SUFFIX}/startup_stage_1.s', 'embed/projects/bootloader_ci/header.S', 'embed/projects/bootloader_ci/bootui.c', 'embed/projects/bootloader_ci/main.c', diff --git a/core/SConscript.firmware b/core/SConscript.firmware index c2d36dea19..e5dcc6a411 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -397,14 +397,11 @@ env = Environment( FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) -FILE_SUFFIX= env.get('ENV')['SUFFIX'] - SOURCE_FIRMWARE = [ 'embed/projects/firmware/header.S', 'embed/projects/firmware/main.c', 'embed/projects/firmware/mphalport.c', 'embed/projects/firmware/nlrthumb.c', - f'embed/sys/startup/{FILE_SUFFIX}/startup_stage_4.s', ] if 'sd_card' in FEATURES_AVAILABLE: diff --git a/core/SConscript.kernel b/core/SConscript.kernel index 6cdf868ec9..626904922e 100644 --- a/core/SConscript.kernel +++ b/core/SConscript.kernel @@ -258,11 +258,8 @@ env = Environment( FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) -FILE_SUFFIX= env.get('ENV')['SUFFIX'] - SOURCE_FIRMWARE = [ 'embed/projects/kernel/main.c', - f'embed/sys/startup/{FILE_SUFFIX}/startup_stage_2.s', ] if 'sd_card' in FEATURES_AVAILABLE: diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index ddce05f152..558062bd42 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -95,11 +95,7 @@ env = Environment( FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) -FILE_SUFFIX= env.get('ENV')['SUFFIX'] - - SOURCE_PRODTEST = [ - f'embed/sys/startup/{FILE_SUFFIX}/startup_stage_2.s', 'embed/projects/prodtest/header.S', 'embed/projects/prodtest/main.c', 'embed/projects/prodtest/prodtest_common.c', diff --git a/core/SConscript.reflash b/core/SConscript.reflash index 464bf18650..b72201a74f 100644 --- a/core/SConscript.reflash +++ b/core/SConscript.reflash @@ -81,10 +81,7 @@ env = Environment( FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) -FILE_SUFFIX= env.get('ENV')['SUFFIX'] - SOURCE_REFLASH = [ - f'embed/sys/startup/{FILE_SUFFIX}/startup_stage_2.s', 'embed/projects/reflash/header.S', 'embed/projects/reflash/main.c', ] diff --git a/core/embed/projects/firmware/main.c b/core/embed/projects/firmware/main.c index 6561ad66fb..5995091056 100644 --- a/core/embed/projects/firmware/main.c +++ b/core/embed/projects/firmware/main.c @@ -32,6 +32,7 @@ #include "ports/stm32/gccollect.h" #include "ports/stm32/pendsv.h" +#include #include #include #include @@ -111,3 +112,22 @@ mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) { return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +// `reset_handler` is the application entry point (first routine called +// from kernel) +__attribute((no_stack_protector)) void reset_handler(uint32_t cmd, void *arg, + uint32_t random_value) { + // Initialize linker script defined sections (.bss, .data, ...) + init_linker_sections(); + + // Initialize stack protector + extern uint32_t __stack_chk_guard; + __stack_chk_guard = random_value; + + // Now everything is perfectly initialized and we can do anything + // in C code + + int main_result = main(cmd, arg); + + system_exit(main_result); +} diff --git a/core/embed/sys/linker/inc/sys/linker_utils.h b/core/embed/sys/linker/inc/sys/linker_utils.h new file mode 100644 index 0000000000..e8307d38be --- /dev/null +++ b/core/embed/sys/linker/inc/sys/linker_utils.h @@ -0,0 +1,95 @@ + +/* + * 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 . + */ + +#pragma once + +// Initialize linker script-defined sections (.bss, .data, etc.) +// +// This function must be called only during the startup sequence, +// before executing any other code. In special cases, it can be used +// to reinitialize these sections if necessary. +void init_linker_sections(void); + +// Clears the unused portion of the stack. +// +// This includes memory between the start of the stack +// and the current stack pointer (SP). +// +// It's safe to call this function at any time, but it's +// recommended to call it only during the startup sequence. +void clear_unused_stack(void); + +// Maximum number of memory blocks in a memory region +#define MEMREGION_MAX_BLOCKS 8 + +typedef struct { + // block start address (inclusive) + void* start; + // block end address (exclusive) + void* end; +} memregion_block_t; + +typedef struct { + // non-overlapping memory blocks ordered by start address + memregion_block_t block[MEMREGION_MAX_BLOCKS]; +} memregion_t; + +#define MEMREGION_ALL_ACCESSIBLE_RAM \ + ({ \ + extern uint8_t _accessible_ram_0_start; \ + extern uint8_t _accessible_ram_0_end; \ + extern uint8_t _accessible_ram_1_start; \ + extern uint8_t _accessible_ram_1_end; \ + (memregion_t){.block = { \ + {&_accessible_ram_0_start, &_accessible_ram_0_end}, \ + {&_accessible_ram_1_start, &_accessible_ram_1_end}, \ + }}; \ + }) + +// Adds a new address range to the memory region. +// +// The start and end pointers must be aligned to 4-byte boundaries. +// +// The current implementation does not merge overlapping or adjacent blocks. +// This behavior is not required for the current use case and, in the +// worst case, will result in a few additional blocks in the region. +void memregion_add_range(memregion_t* region, void* start, void* end); + +// Deletes an address range from the memory region +// +// The range start and end pointers must be aligned to the 4 bytes. +void memregion_del_range(memregion_t* region, void* start, void* end); + +// Fill memory region with a value 32-bit value +void memregion_fill(memregion_t* region, uint32_t value); + +#define MEMREGION_ADD_SECTION(region, section_name) \ + { \ + extern uint8_t section_name##_start; \ + extern uint8_t section_name##_end; \ + memregion_add_range(region, §ion_name##_start, §ion_name##_end); \ + } + +#define MEMREGION_DEL_SECTION(region, section_name) \ + { \ + extern uint8_t section_name##_start; \ + extern uint8_t section_name##_end; \ + memregion_del_range(region, §ion_name##_start, §ion_name##_end); \ + } diff --git a/core/embed/sys/linker/linker_utils.c b/core/embed/sys/linker/linker_utils.c new file mode 100644 index 0000000000..47bf18b7ca --- /dev/null +++ b/core/embed/sys/linker/linker_utils.c @@ -0,0 +1,195 @@ +/* + * 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 + +#include + +void init_linker_sections(void) { + extern uint32_t _bss_section_start; + extern uint32_t _bss_section_end; + extern uint32_t _data_section_start; + extern uint32_t _data_section_end; + extern uint32_t _data_section_loadaddr; + extern uint32_t _confidential_section_start; + extern uint32_t _confidential_section_end; + extern uint32_t _confidential_section_loadaddr; + + // Pointer are intentionally volatile to prevent optimization + // (otherwise the compiler may optimize loops to memset/memcpy) + volatile uint32_t* dst; + volatile uint32_t* src; + + dst = &_bss_section_start; + while (dst < &_bss_section_end) { + *dst++ = 0; + } + + dst = &_data_section_start; + src = &_data_section_loadaddr; + while (dst < &_data_section_end) { + *dst++ = *src++; + } + + dst = &_confidential_section_start; + src = &_confidential_section_loadaddr; + while (dst < &_confidential_section_end) { + *dst++ = *src++; + } +} + +__attribute((naked, no_stack_protector)) void clear_unused_stack(void) { + extern uint32_t _stack_section_start; + + __asm__ volatile( + " MOV R0, #0 \n" + " LDR R1, =%[sstack] \n" + "1: \n" + " STR R0, [R1], #4 \n" + " CMP R1, SP \n" + " BNE 1b \n" + " BX LR \n" + : // no output + : [sstack] "i"((uint32_t)&_stack_section_start) + : // no clobber + ); +} + +static void memregion_remove_block(memregion_t* region, int idx) { + if (idx < 0 || idx >= MEMREGION_MAX_BLOCKS) { + return; + } + + for (int i = idx; i < MEMREGION_MAX_BLOCKS - 1; i++) { + region->block[i] = region->block[i + 1]; + } + + memregion_block_t* last = ®ion->block[MEMREGION_MAX_BLOCKS - 1]; + last->start = NULL; + last->end = NULL; +} + +static void memregion_insert_block(memregion_t* region, int idx, void* start, + void* end) { + if (idx < 0 || idx >= MEMREGION_MAX_BLOCKS) { + return; + } + + for (int i = MEMREGION_MAX_BLOCKS - 1; i > idx; i--) { + region->block[i] = region->block[i - 1]; + } + + region->block[idx].start = start; + region->block[idx].end = end; +} + +void memregion_add_range(memregion_t* region, void* start, void* end) { + int idx = 0; + + while ((start < end) && (idx < MEMREGION_MAX_BLOCKS)) { + memregion_block_t* b = ®ion->block[idx]; + if (b->start >= b->end) { + // The added range is completely after the last block + // in the region. Just add it as a block at the end. + b->start = start; + b->end = end; + break; + } else if (end < b->start) { + // The added range is completely before `b`. + // Shift all blocks after the inserted block + // Insert the new block + memregion_insert_block(region, idx, start, end); + break; + } else if (start < b->end) { + // The inserted range overlaps with `b`. + // Extend the block 'b'. + b->start = MIN(start, b->start); + // Shorten the added range + start = MAX(start, b->end); + } else { + // The added range is behind 'b' + // Move to the next block + idx += 1; + } + } +} + +void memregion_del_range(memregion_t* region, void* start, void* end) { + int idx = 0; + + while ((start < end) && (idx < MEMREGION_MAX_BLOCKS)) { + memregion_block_t* b = ®ion->block[idx]; + if (b->start >= b->end) { + // Deleted range is completely after the last block + break; + } else if (end < b->start) { + // Deleted range is completely before `b`. + break; + } else if (start < b->end) { + // Deleted range overlaps with `b`. + + if (start <= b->start) { + // Deleted range overlaps beginning of 'b'. + // Cut the beginning of the block 'b'. + b->start = MIN(end, b->end); + start = b->start; + + // If the block is empty, remove it + if (b->start >= b->end) { + memregion_remove_block(region, idx); + } + } else if (end >= b->end) { + // Deleted range overlaps end of 'b'. + // Cut the end of the block 'b' + b->end = start; + } else { + // Deleted range is inside 'b'. + // Split the block 'b' into two blocks. + void* new_start = end; + void* new_end = b->end; + + // Cut the end of the block 'b' + b->end = start; + + // Insert a new block, if there is a free space + memregion_insert_block(region, idx + 1, new_start, new_end); + break; + } + } else { + // The deleted range is behind 'b' + // Move to the next block + idx += 1; + } + } +} + +__attribute((no_stack_protector)) void memregion_fill(memregion_t* region, + uint32_t value) { + for (int i = 0; i < MEMREGION_MAX_BLOCKS; i++) { + memregion_block_t* block = ®ion->block[i]; + if (block->start < block->end) { + // Pointer is intentionally volatile to prevent optimization + // (otherwise the compiler may optimize loop to memset) + volatile uint32_t* ptr = block->start; + while ((void*)ptr < block->end) { + *ptr++ = value; + } + } + } +} diff --git a/core/embed/sys/startup/inc/sys/bootargs.h b/core/embed/sys/startup/inc/sys/bootargs.h index 92fc79d2bc..f566c5cbca 100644 --- a/core/embed/sys/startup/inc/sys/bootargs.h +++ b/core/embed/sys/startup/inc/sys/bootargs.h @@ -43,6 +43,12 @@ typedef union { } boot_args_t; +// Initialize bootargs module after bootloader startup +// +// r11_register is the value of the r11 register at bootloader entry. +// This value is used only on STM32F4 platform. On STM32U5, it is ignored. +void bootargs_init(uint32_t r11_register); + // Configures the boot command and associated arguments for the next reboot. // The arguments must adhere to the boot_args_t structure layout. void bootargs_set(boot_command_t command, const void* args, size_t args_size); diff --git a/core/embed/sys/startup/stm32/bootutils.c b/core/embed/sys/startup/stm32/bootutils.c index 1b69858749..a0c4858e37 100644 --- a/core/embed/sys/startup/stm32/bootutils.c +++ b/core/embed/sys/startup/stm32/bootutils.c @@ -81,6 +81,15 @@ void bootargs_get_args(boot_args_t* dest) { mpu_restore(mode); } + +void bootargs_init(uint32_t r11_register) { +#ifdef STM32U5 + g_boot_command_saved = g_boot_command; + g_boot_command = BOOT_COMMAND_NONE; +#else + g_boot_command_saved = r11_register; +#endif +} #endif // Deletes all secrets and SRAM2 where stack is located diff --git a/core/embed/sys/startup/stm32f4/startup_init.c b/core/embed/sys/startup/stm32f4/startup_init.c index f934632149..f6f535c710 100644 --- a/core/embed/sys/startup/stm32f4/startup_init.c +++ b/core/embed/sys/startup/stm32f4/startup_init.c @@ -21,7 +21,10 @@ #include #include +#include #include +#include +#include #include #include "startup_init.h" @@ -250,4 +253,65 @@ __attribute((used)) void clear_otg_hs_memory(void) { // the peripheral is not needed right now } +__attribute((no_stack_protector)) void reset_handler(void) { +#ifdef BOOTLOADER + uint32_t r11_value; + // Copy the value of R11 to the local variable r11_value + __asm__ volatile("MOV %0, R11" : "=r"(r11_value)); +#endif + + // Now .bss, .data are not initialized yet - we need to be + // careful with global variables. They are not initialized, + // contain random values and will be rewritten in the succesive + // code + + // Initialize system clocks + SystemInit(); + + // Clear unused part of stack + clear_unused_stack(); + + // Initialize random number generator + rng_init(); + + // Clear all memory except stack. + // Keep also bootargs in bootloader and boardloader. + memregion_t region = MEMREGION_ALL_ACCESSIBLE_RAM; + + MEMREGION_DEL_SECTION(®ion, _stack_section); +#ifdef BOOTLOADER + MEMREGION_DEL_SECTION(®ion, _bootargs_ram); +#endif + +#ifdef BOARDLOADER + memregion_fill(®ion, rng_get()); +#endif + memregion_fill(®ion, 0); + + // Initialize .bss, .data, ... + init_linker_sections(); + + // Initialize stack protector guard value + extern uint32_t __stack_chk_guard; + __stack_chk_guard = rng_get(); + + // Now everything is perfectly initialized and we can do anything + // in C code + + clear_otg_hs_memory(); + +#ifdef BOOTLOADER + bootargs_init(r11_value); +#endif + + // Enable interrupts and fault handlers + __enable_fault_irq(); + + // Run application + extern int main(void); + int main_result = main(); + + system_exit(main_result); +} + #endif // KERNEL_MODE diff --git a/core/embed/sys/startup/stm32f4/startup_stage_0.s b/core/embed/sys/startup/stm32f4/startup_stage_0.s deleted file mode 100644 index 0f244b9c5c..0000000000 --- a/core/embed/sys/startup/stm32f4/startup_stage_0.s +++ /dev/null @@ -1,62 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - bl SystemInit - - // read the first rng data and save it - ldr r0, =0 // r0 - previous value - ldr r1, =0 // r1 - whether to compare the previous value - bl rng_read - - // read the next rng data and make sure it is different than previous - // r0 - value returned from previous call - ldr r1, =1 // r1 - whether to compare the previous value - bl rng_read - mov r4, r0 // save TRNG output in r4 - - // wipe memory to remove any possible vestiges of sensitive data - // use unpredictable value as a defense against side-channels - mov r2, r4 // r2 - the word-sized value to be written - ldr r0, =_startup_clear_ram_0_start - ldr r1, =_startup_clear_ram_0_end - bl memset_reg - ldr r0, =_startup_clear_ram_1_start - ldr r1, =_startup_clear_ram_1_end - bl memset_reg - - // setup environment for subsequent stage of code - ldr r2, =0 // r2 - the word-sized value to be written - ldr r0, =_startup_clear_ram_0_start - ldr r1, =_startup_clear_ram_0_end - bl memset_reg - ldr r0, =_startup_clear_ram_1_start - ldr r1, =_startup_clear_ram_1_end - bl memset_reg - - // copy data in from flash - ldr r0, =_data_section_start // dst addr - ldr r1, =_data_section_loadaddr // src addr - ldr r2, =_data_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // setup the stack protector (see build script "-fstack-protector-all") - // with an unpredictable value - bl rng_get - ldr r1, = __stack_chk_guard - str r0, [r1] - - // Clear the USB FIFO memory to prevent data leakage of sensitive information. - // This peripheral memory is not cleared by a device reset. - bl clear_otg_hs_memory - - // enter the application code - bl main - - b system_exit - - .end diff --git a/core/embed/sys/startup/stm32f4/startup_stage_1.s b/core/embed/sys/startup/stm32f4/startup_stage_1.s deleted file mode 100644 index adc977605a..0000000000 --- a/core/embed/sys/startup/stm32f4/startup_stage_1.s +++ /dev/null @@ -1,46 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // setup environment for subsequent stage of code - ldr r2, =0 // r2 - the word-sized value to be written - ldr r0, =_startup_clear_ram_0_start - ldr r1, =_startup_clear_ram_0_end - bl memset_reg - ldr r0, =_startup_clear_ram_1_start - ldr r1, =_startup_clear_ram_1_end - bl memset_reg - - // copy data in from flash - ldr r0, =_data_section_start // dst addr - ldr r1, =_data_section_loadaddr // src addr - ldr r2, =_data_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value - bl rng_get - ldr r1, = __stack_chk_guard - str r0, [r1] - - // re-enable exceptions - // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: - // "If it is not necessary to ensure that a pended interrupt is recognized immediately before - // subsequent operations, it is not necessary to insert a memory barrier instruction." - cpsie f - - // r11 contains the command passed to bootargs_set() - // function called when the firmware rebooted to the bootloader - ldr r0, =g_boot_command_saved - str r11, [r0] - - // enter the application code - bl main - - b system_exit - - .end - diff --git a/core/embed/sys/startup/stm32f4/startup_stage_2.s b/core/embed/sys/startup/stm32f4/startup_stage_2.s deleted file mode 100644 index 8805d4f0d2..0000000000 --- a/core/embed/sys/startup/stm32f4/startup_stage_2.s +++ /dev/null @@ -1,40 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // setup environment for subsequent stage of code - ldr r2, =0 // r2 - the word-sized value to be written - ldr r0, =_startup_clear_ram_0_start - ldr r1, =_startup_clear_ram_0_end - bl memset_reg - ldr r0, =_startup_clear_ram_1_start - ldr r1, =_startup_clear_ram_1_end - bl memset_reg - - // copy data in from flash - ldr r0, =_data_section_start // dst addr - ldr r1, =_data_section_loadaddr // src addr - ldr r2, =_data_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value - bl rng_get - ldr r1, = __stack_chk_guard - str r0, [r1] - - // re-enable exceptions - // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: - // "If it is not necessary to ensure that a pended interrupt is recognized immediately before - // subsequent operations, it is not necessary to insert a memory barrier instruction." - cpsie f - - // enter the application code - bl main - - b system_exit - - .end diff --git a/core/embed/sys/startup/stm32f4/startup_stage_4.s b/core/embed/sys/startup/stm32f4/startup_stage_4.s deleted file mode 100644 index 683cf3a3f7..0000000000 --- a/core/embed/sys/startup/stm32f4/startup_stage_4.s +++ /dev/null @@ -1,38 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - - push {r0, r1} - - // setup the stack protector with provided random value - ldr r0, = __stack_chk_guard - str r2, [r0] - - ldr r0, =_bss_section_start - ldr r1, =0 - ldr r2, =_bss_section_end - sub r2, r2, r0 - bl memset - - // copy data in from flash - ldr r0, =_data_section_start // dst addr - ldr r1, =_data_section_loadaddr // src addr - ldr r2, =_data_section_end - sub r2, r2, r0 // size in bytes - bl memcpy - - pop {r0, r1} - - // enter the application code - // returns exit code in r0 - bl main - - // terminate the application - // pass exit code in r0 - b system_exit - - .end diff --git a/core/embed/sys/startup/stm32u5/startup_init.c b/core/embed/sys/startup/stm32u5/startup_init.c index dd4d6818b6..ca4f4af923 100644 --- a/core/embed/sys/startup/stm32u5/startup_init.c +++ b/core/embed/sys/startup/stm32u5/startup_init.c @@ -21,6 +21,9 @@ #include #include +#include +#include +#include #ifdef KERNEL_MODE @@ -186,9 +189,6 @@ void SystemInit(void) { // TODO turn off MSI? - // init the TRNG peripheral - rng_init(); - // set CP10 and CP11 to enable full access to the fpu coprocessor; SCB->CPACR |= ((3UL << 20U) | (3UL << 22U)); /* set CP10 and CP11 Full Access */ @@ -220,4 +220,61 @@ void SystemInit(void) { __HAL_RCC_GPIOD_CLK_ENABLE(); } +__attribute((no_stack_protector)) void reset_handler(void) { + // Set stack pointer limit for checking stack overflow + extern uint8_t _stack_section_start; + __set_MSPLIM((uintptr_t)&_stack_section_start + 128); + + // Now .bss, .data are not initialized yet - we need to be + // careful with global variables. They are not initialized, + // contain random values and will be rewritten in the succesive + // code + + // Initialize system clocks + SystemInit(); + + // Clear unused part of stack + clear_unused_stack(); + + // Initialize random number generator + rng_init(); + + // Clear all memory except stack. + // Keep also bootargs in bootloader and boardloader. + memregion_t region = MEMREGION_ALL_ACCESSIBLE_RAM; + + MEMREGION_DEL_SECTION(®ion, _stack_section); +#if defined BOARDLOADER || defined BOOTLOADER + MEMREGION_DEL_SECTION(®ion, _bootargs_ram); +#endif + +#ifdef BOARDLOADER + memregion_fill(®ion, rng_get()); +#endif + memregion_fill(®ion, 0); + + // Initialize .bss, .data, ... + init_linker_sections(); + + // Initialize stack protector guard value + extern uint32_t __stack_chk_guard; + __stack_chk_guard = rng_get(); + + // Now everything is perfectly initialized and we can do anything + // in C code + +#ifdef BOOTLOADER + bootargs_init(0); +#endif + + // Enable interrupts and fault handlers + __enable_fault_irq(); + + // Run application + extern int main(void); + int main_result = main(); + + system_exit(main_result); +} + #endif // #ifdef KERNEL_MODE diff --git a/core/embed/sys/startup/stm32u5/startup_stage_0.s b/core/embed/sys/startup/stm32u5/startup_stage_0.s deleted file mode 100644 index baa68ccbfe..0000000000 --- a/core/embed/sys/startup/stm32u5/startup_stage_0.s +++ /dev/null @@ -1,81 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // set the stack protection - ldr r0, =_stack_section_start - add r0, r0, #128 // safety margin for the exception frame - msr MSPLIM, r0 - - bl SystemInit - - // read the first rng data and save it - ldr r0, =0 // r0 - previous value - ldr r1, =0 // r1 - whether to compare the previous value - bl rng_read - - // read the next rng data and make sure it is different than previous - // r0 - value returned from previous call - ldr r1, =1 // r1 - whether to compare the previous value - bl rng_read - mov r4, r0 // save TRNG output in r4 - - // wipe memory to remove any possible vestiges of confidential data - - -fill_ram: - - mov r2, r4 // r2 - the word-sized value to be written - ldr r0, =_startup_clear_ram_0_start - ldr r1, =_startup_clear_ram_0_end - bl memset_reg - ldr r0, =_startup_clear_ram_1_start - ldr r1, =_startup_clear_ram_1_end - bl memset_reg - ldr r0, =_startup_clear_ram_2_start - ldr r1, =_startup_clear_ram_2_end - bl memset_reg - - // setup environment for subsequent stage of code - - -clear_ram: - ldr r2, =0 // r2 - the word-sized value to be written - ldr r0, =_startup_clear_ram_0_start - ldr r1, =_startup_clear_ram_0_end - bl memset_reg - ldr r0, =_startup_clear_ram_1_start - ldr r1, =_startup_clear_ram_1_end - bl memset_reg - ldr r0, =_startup_clear_ram_2_start - ldr r1, =_startup_clear_ram_2_end - bl memset_reg - - // copy data in from flash - ldr r0, =_data_section_start // dst addr - ldr r1, =_data_section_loadaddr // src addr - ldr r2, =_data_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // copy confidential data in from flash - ldr r0, =_confidential_section_start // dst addr - ldr r1, =_confidential_section_loadaddr // src addr - ldr r2, =_confidential_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value - bl rng_get - ldr r1, = __stack_chk_guard - str r0, [r1] - - // enter the application code - bl main - - b system_exit - - .end diff --git a/core/embed/sys/startup/stm32u5/startup_stage_1.s b/core/embed/sys/startup/stm32u5/startup_stage_1.s deleted file mode 100644 index 72c3eef2d5..0000000000 --- a/core/embed/sys/startup/stm32u5/startup_stage_1.s +++ /dev/null @@ -1,64 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // set the stack protection - ldr r0, =_stack_section_start - add r0, r0, #128 // safety margin for the exception frame - msr MSPLIM, r0 - - // setup environment for subsequent stage of code - ldr r2, =0 // r2 - the word-sized value to be written - ldr r0, =_startup_clear_ram_0_start - ldr r1, =_startup_clear_ram_0_end - bl memset_reg - ldr r0, =_startup_clear_ram_1_start - ldr r1, =_startup_clear_ram_1_end - bl memset_reg - ldr r0, =_startup_clear_ram_2_start - ldr r1, =_startup_clear_ram_2_end - bl memset_reg - - // copy data in from flash - ldr r0, =_data_section_start // dst addr - ldr r1, =_data_section_loadaddr // src addr - ldr r2, =_data_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // copy confidential data in from flash - ldr r0, =_confidential_section_start // dst addr - ldr r1, =_confidential_section_loadaddr // src addr - ldr r2, =_confidential_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value - bl rng_get - ldr r1, = __stack_chk_guard - str r0, [r1] - - // copy & clear g_boot_command - ldr r0, =g_boot_command - ldr r1, [r0] - ldr r0, =g_boot_command_saved - str r1, [r0] - ldr r0, =g_boot_command - mov r1, #0 - str r1, [r0] - - // re-enable exceptions - // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: - // "If it is not necessary to ensure that a pended interrupt is recognized immediately before - // subsequent operations, it is not necessary to insert a memory barrier instruction." - cpsie f - - // enter the application code - bl main - - b system_exit - - .end diff --git a/core/embed/sys/startup/stm32u5/startup_stage_2.s b/core/embed/sys/startup/stm32u5/startup_stage_2.s deleted file mode 100644 index c3acb8ab7d..0000000000 --- a/core/embed/sys/startup/stm32u5/startup_stage_2.s +++ /dev/null @@ -1,55 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - // set the stack protection - ldr r0, =_stack_section_start - add r0, r0, #128 // safety margin for the exception frame - msr MSPLIM, r0 - - // setup environment for subsequent stage of code - ldr r2, =0 // r2 - the word-sized value to be written - ldr r0, =_startup_clear_ram_0_start - ldr r1, =_startup_clear_ram_0_end - bl memset_reg - ldr r0, =_startup_clear_ram_1_start - ldr r1, =_startup_clear_ram_1_end - bl memset_reg - ldr r0, =_startup_clear_ram_2_start - ldr r1, =_startup_clear_ram_2_end - bl memset_reg - - // copy data in from flash - ldr r0, =_data_section_start // dst addr - ldr r1, =_data_section_loadaddr // src addr - ldr r2, =_data_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // copy confidential data in from flash - ldr r0, =_confidential_section_start // dst addr - ldr r1, =_confidential_section_loadaddr // src addr - ldr r2, =_confidential_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value - bl rng_get - ldr r1, = __stack_chk_guard - str r0, [r1] - - // re-enable exceptions - // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: - // "If it is not necessary to ensure that a pended interrupt is recognized immediately before - // subsequent operations, it is not necessary to insert a memory barrier instruction." - cpsie f - - // enter the application code - bl main - - b system_exit - - .end diff --git a/core/embed/sys/startup/stm32u5/startup_stage_4.s b/core/embed/sys/startup/stm32u5/startup_stage_4.s deleted file mode 100644 index 04c8819366..0000000000 --- a/core/embed/sys/startup/stm32u5/startup_stage_4.s +++ /dev/null @@ -1,45 +0,0 @@ - .syntax unified - - .text - - .global reset_handler - .type reset_handler, STT_FUNC -reset_handler: - - push {r0, r1} - - // setup the stack protector with provided random value - ldr r0, = __stack_chk_guard - str r2, [r0] - - ldr r0, =_bss_section_start - ldr r1, =0 - ldr r2, =_bss_section_end - sub r2, r2, r0 - bl memset - - // copy data in from flash - ldr r0, =_data_section_start // dst addr - ldr r1, =_data_section_loadaddr // src addr - ldr r2, =_data_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - // copy confidential data in from flash - ldr r0, =_confidential_section_start // dst addr - ldr r1, =_confidential_section_loadaddr // src addr - ldr r2, =_confidential_section_end // size in bytes - sub r2, r2, r0 - bl memcpy - - pop {r0, r1} - - // enter the application code - // returns exit code in r0 - bl main - - // terminate the application - // pass exit code in r0 - b system_exit - - .end diff --git a/core/site_scons/models/stm32f4_common.py b/core/site_scons/models/stm32f4_common.py index ba37025165..4843bacb35 100644 --- a/core/site_scons/models/stm32f4_common.py +++ b/core/site_scons/models/stm32f4_common.py @@ -18,6 +18,7 @@ def stm32f4_common_files(env, defines, sources, paths): "embed/sec/time_estimate/inc", "embed/sys/bsp/stm32f4", "embed/sys/irq/inc", + "embed/sys/linker/inc", "embed/sys/mpu/inc", "embed/sys/pvd/inc", "embed/sec/secret/inc", @@ -66,6 +67,7 @@ def stm32f4_common_files(env, defines, sources, paths): "embed/sec/rng/stm32/rng.c", "embed/sec/secret/stm32f4/secret.c", "embed/sec/time_estimate/stm32/time_estimate.c", + "embed/sys/linker/linker_utils.c", "embed/sys/mpu/stm32f4/mpu.c", "embed/sys/pvd/stm32/pvd.c", "embed/sys/startup/stm32/bootutils.c", diff --git a/core/site_scons/models/stm32u5_common.py b/core/site_scons/models/stm32u5_common.py index 736d062696..f3ff9e6ac3 100644 --- a/core/site_scons/models/stm32u5_common.py +++ b/core/site_scons/models/stm32u5_common.py @@ -20,6 +20,7 @@ def stm32u5_common_files(env, defines, sources, paths): "embed/sec/time_estimate/inc", "embed/sys/irq/inc", "embed/sys/bsp/stm32u5", + "embed/sys/linker/inc", "embed/sys/mpu/inc", "embed/sys/pvd/inc", "embed/sys/startup/inc", @@ -84,6 +85,7 @@ def stm32u5_common_files(env, defines, sources, paths): "embed/sec/secret/stm32u5/secret.c", "embed/sec/secure_aes/stm32u5/secure_aes.c", "embed/sec/time_estimate/stm32/time_estimate.c", + "embed/sys/linker/linker_utils.c", "embed/sys/mpu/stm32u5/mpu.c", "embed/sys/pvd/stm32/pvd.c", "embed/sys/startup/stm32/bootutils.c",