diff --git a/core/SConscript.boardloader b/core/SConscript.boardloader index 223a6d67f..493b865b3 100644 --- a/core/SConscript.boardloader +++ b/core/SConscript.boardloader @@ -78,6 +78,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', ] if NEW_RENDERING: diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 7db27641a..9cedfb1f4 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -117,6 +117,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_rgba8888.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/unit_variant.c', 'vendor/micropython/lib/uzlib/adler32.c', diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index 059d0276c..75e9e5f81 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -112,6 +112,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_rgba8888.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/unit_variant.c', 'vendor/micropython/lib/uzlib/adler32.c', @@ -148,7 +149,6 @@ SOURCE_BOOTLOADER = [ SOURCE_TREZORHAL = [ 'embed/trezorhal/unix/bootutils.c', 'embed/trezorhal/unix/common.c', - 'embed/trezorhal/unix/fault_handlers.c', 'embed/trezorhal/unix/flash.c', 'embed/trezorhal/unix/flash_otp.c', 'embed/trezorhal/unix/mpu.c', @@ -156,6 +156,7 @@ SOURCE_TREZORHAL = [ 'embed/trezorhal/unix/random_delays.c', 'embed/trezorhal/unix/rng.c', 'embed/trezorhal/unix/secret.c', + 'embed/trezorhal/unix/system.c', 'embed/trezorhal/unix/systick.c', 'embed/trezorhal/unix/systimer.c', 'embed/trezorhal/unix/usb.c', diff --git a/core/SConscript.coreapp b/core/SConscript.coreapp index 2550ef94e..a65908aac 100644 --- a/core/SConscript.coreapp +++ b/core/SConscript.coreapp @@ -235,6 +235,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/translations.c', 'embed/lib/unit_variant.c', diff --git a/core/SConscript.firmware b/core/SConscript.firmware index b80de0e4e..cd7001ecc 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -237,6 +237,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/translations.c', 'embed/lib/unit_variant.c', diff --git a/core/SConscript.kernel b/core/SConscript.kernel index 2be27fc7f..3b15bac4d 100644 --- a/core/SConscript.kernel +++ b/core/SConscript.kernel @@ -222,6 +222,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/translations.c', 'embed/lib/unit_variant.c', @@ -246,7 +247,7 @@ CPPDEFINES_MOD += [ if TREZOR_MODEL not in ('1', ): CPPDEFINES_MOD += [ - # 'FANCY_FATAL_ERROR', + 'FANCY_FATAL_ERROR', ] CPPDEFINES_MOD += ['USE_SVC_SHUTDOWN'] @@ -367,7 +368,7 @@ env.Replace( LINKFLAGS='-T embed/kernel/memory_${TREZOR_MODEL}%s.ld -Wl,--gc-sections -Wl,--print-memory-usage -Wl,-Map=build/kernel/kernel.map -Wl,--warn-common' % LD_VARIANT, CPPPATH=ALLPATHS, CPPDEFINES=[ - 'FIRMWARE', + 'KERNEL', 'TREZOR_MODEL_'+TREZOR_MODEL, 'USE_HAL_DRIVER', 'ARM_USER_MODE', diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index 3ae2a8c82..2302c2658 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -115,6 +115,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/qr-code-generator/qrcodegen.c', 'embed/lib/terminal.c', 'vendor/micropython/lib/uzlib/adler32.c', diff --git a/core/SConscript.reflash b/core/SConscript.reflash index b30f07fe0..20d5ddfb9 100644 --- a/core/SConscript.reflash +++ b/core/SConscript.reflash @@ -83,6 +83,7 @@ SOURCE_MOD += [ 'embed/lib/fonts/fonts.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', diff --git a/core/SConscript.unix b/core/SConscript.unix index 72afb5e2d..4f30ec765 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -243,6 +243,7 @@ SOURCE_MOD += [ 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', + 'embed/lib/rsod.c', 'embed/lib/terminal.c', 'embed/lib/translations.c', 'embed/lib/unit_variant.c', @@ -428,6 +429,7 @@ SOURCE_UNIX = [ 'embed/trezorhal/unix/mpu.c', 'embed/trezorhal/unix/random_delays.c', 'embed/trezorhal/unix/rng.c', + 'embed/trezorhal/unix/system.c', 'embed/trezorhal/unix/systick.c', 'embed/trezorhal/unix/systimer.c', 'embed/trezorhal/unix/time_estimate.c', diff --git a/core/embed/boardloader/main.c b/core/embed/boardloader/main.c index d5b583191..f79c31d98 100644 --- a/core/embed/boardloader/main.c +++ b/core/embed/boardloader/main.c @@ -21,18 +21,19 @@ #include TREZOR_BOARD #include "board_capabilities.h" +#include "bootutils.h" #include "buffers.h" #include "common.h" #include "compiler_traits.h" #include "display.h" #include "display_draw.h" -#include "fault_handlers.h" #include "flash.h" #include "image.h" #include "model.h" #include "mpu.h" #include "rng.h" -#include "systimer.h" +#include "rsod.h" +#include "system.h" #include "terminal.h" #ifdef USE_SD_CARD @@ -232,9 +233,34 @@ static secbool copy_sdcard(void) { } #endif +// Initializes system in emergency mode and shows RSOD +static void enter_emergency_mode(const systask_postmortem_t *pminfo) { + // Initialize the system's core services + // (If the kernel crashes in emergency mode, we are out of options + // and show the RSOD without attempting to re-enter emergency mode) + system_init(&rsod_terminal); + + // Initialize necessary drivers + display_init(DISPLAY_RESET_CONTENT); + + // Show RSOD using the terminal + rsod_terminal(pminfo); + + // Wait for the user to manually power off the device + secure_shutdown(); +} + +// Kernel panic handler +// (may be called from interrupt context) +static void kernel_panic(const systask_postmortem_t *pminfo) { + // Since the system state is unreliable, enter emergency mode + // and show the RSOD. + system_emergency_rescue(&enter_emergency_mode, pminfo); + // The previous function call never returns +} + int main(void) { - systick_init(); - systimer_init(); + system_init(&kernel_panic); reset_flags_reset(); @@ -262,8 +288,6 @@ int main(void) { clear_otg_hs_memory(); #endif - fault_handlers_init(); - #ifdef USE_SDRAM sdram_init(); #endif diff --git a/core/embed/boardloader/memory_stm32u58.ld b/core/embed/boardloader/memory_stm32u58.ld index b92fcf303..51aa0845c 100644 --- a/core/embed/boardloader/memory_stm32u58.ld +++ b/core/embed/boardloader/memory_stm32u58.ld @@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5); sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); sram6_start = ORIGIN(SRAM6); sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index c65e0c063..9c2e2d045 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -25,15 +25,16 @@ #include "common.h" #include "display.h" #include "display_utils.h" -#include "fault_handlers.h" #include "flash.h" #include "flash_otp.h" #include "image.h" #include "lowlevel.h" #include "messages.pb.h" #include "random_delays.h" +#include "rsod.h" #include "secbool.h" #include "secret.h" +#include "system.h" #include "systimer.h" #ifdef USE_DMA2D @@ -354,6 +355,35 @@ __attribute__((noreturn)) void jump_to_fw_through_reset(void) { } #endif +// Initializes system in emergency mode and shows RSOD +static void enter_emergency_mode(const systask_postmortem_t *pminfo) { + // Initialize the system's core services + // (If the kernel crashes in emergency mode, we are out of options + // and show the RSOD without attempting to re-enter emergency mode) + system_init(&rsod_terminal); + + // Initialize necessary drivers + display_init(DISPLAY_RESET_CONTENT); + +#ifdef FANCY_FATAL_ERROR + rsod_gui(pminfo); +#else + rsod_terminal(pminfo); +#endif + + // Wait for the user to manually power off the device + secure_shutdown(); +} + +// Kernel panic handler +// (may be called from interrupt context) +static void kernel_panic(const systask_postmortem_t *pminfo) { + // Since the system state is unreliable, enter emergency mode + // and show the RSOD. + system_emergency_rescue(&enter_emergency_mode, pminfo); + // The previous function call never returns +} + #ifndef TREZOR_EMULATOR int main(void) { #else @@ -361,8 +391,7 @@ int bootloader_main(void) { #endif secbool stay_in_bootloader = secfalse; - systick_init(); - systimer_init(); + system_init(&kernel_panic); rdi_init(); @@ -402,8 +431,6 @@ int bootloader_main(void) { ui_screen_boot_stage_1(false); - fault_handlers_init(); - #ifdef TREZOR_EMULATOR // wait a bit so that the empty lock icon is visible // (on a real device, we are waiting for touch init which takes longer) diff --git a/core/embed/bootloader/memory_stm32u58.ld b/core/embed/bootloader/memory_stm32u58.ld index 0812d1925..6711c5c4b 100644 --- a/core/embed/bootloader/memory_stm32u58.ld +++ b/core/embed/bootloader/memory_stm32u58.ld @@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5); sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); sram6_start = ORIGIN(SRAM6); sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); diff --git a/core/embed/bootloader_ci/main.c b/core/embed/bootloader_ci/main.c index 931e97827..b91426c1c 100644 --- a/core/embed/bootloader_ci/main.c +++ b/core/embed/bootloader_ci/main.c @@ -31,6 +31,7 @@ #include "random_delays.h" #include "rng.h" #include "secbool.h" +#include "system.h" #ifdef USE_TOUCH #include "touch.h" #endif @@ -202,9 +203,36 @@ static void check_bootloader_version(void) { #endif +static void error_handler(systask_t *task) { rsod_terminal(&task->pminfo); } + +// Initializes system in emergency mode and shows RSOD +static void enter_emergency_mode(const systask_postmortem_t *pminfo) { + // Initialize the system's core services + // (If the kernel crashes in emergency mode, we are out of options + // and show the RSOD without attempting to re-enter emergency mode) + system_init(&rsod_terminal); + + // Initialize necessary drivers + display_init(DISPLAY_RESET_CONTENT); + + // Show RSOD using the terminal + rsod_terminal(pminfo); + + // Wait for the user to manually power off the device + secure_shutdown(); +} + +// Kernel panic handler +// (may be called from interrupt context) +static void kernel_panic(const systask_postmortem_t *pminfo) { + // Since the system state is unreliable, enter emergency mode + // and show the RSOD. + system_emergency_rescue(&enter_emergency_mode, pminfo); + // The previous function call never returns +} + int main(void) { - systick_init(); - systimer_init(); + system_init(&kernel_panic); rdi_init(); #ifdef USE_TOUCH diff --git a/core/embed/bootloader_ci/memory_stm32u58.ld b/core/embed/bootloader_ci/memory_stm32u58.ld index 876807cb8..69f257018 100644 --- a/core/embed/bootloader_ci/memory_stm32u58.ld +++ b/core/embed/bootloader_ci/memory_stm32u58.ld @@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5); sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); sram6_start = ORIGIN(SRAM6); sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); diff --git a/core/embed/coreapp/main.c b/core/embed/coreapp/main.c index 8ea6f269b..6a5161172 100644 --- a/core/embed/coreapp/main.c +++ b/core/embed/coreapp/main.c @@ -37,16 +37,28 @@ #include "ports/stm32/pendsv.h" #include "error_handling.h" +#include "rsod.h" #include "rust_ui_common.h" #include "secbool.h" +#include "systask.h" +#include "system.h" #ifdef USE_SECP256K1_ZKP #include "zkp_context.h" #endif -int main(void) { +int main(uint32_t cmd, void *arg) { + if (cmd == 1) { + systask_postmortem_t *info = (systask_postmortem_t *)arg; + rsod_gui(info); + system_exit(0); + } + screen_boot_stage_2(); + // uint32_t *p = 0; + // *p = 0; + #ifdef USE_SECP256K1_ZKP ensure(sectrue * (zkp_context_init() == 0), NULL); #endif diff --git a/core/embed/coreapp/memory_T3T1.ld b/core/embed/coreapp/memory_T3T1.ld index 3fc9d3fae..810877697 100644 --- a/core/embed/coreapp/memory_T3T1.ld +++ b/core/embed/coreapp/memory_T3T1.ld @@ -16,15 +16,13 @@ MEMORY { main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ _sstack = ORIGIN(SRAM2); _estack = main_stack_base; +_stack_size = SIZEOF(.stack); /* used by the startup code to populate variables used by the C code */ data_lma = LOADADDR(.data); data_vma = ADDR(.data); data_size = SIZEOF(.data); -bss_start = ADDR(.bss); -bss_end = ADDR(.bss) + SIZEOF(.bss); - /* used by the startup code to populate variables used by the C code */ confidential_lma = LOADADDR(.confidential); confidential_vma = ADDR(.confidential); @@ -43,6 +41,8 @@ sram5_start = ORIGIN(SRAM5); sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); sram6_start = ORIGIN(SRAM6); sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); diff --git a/core/embed/coreapp/startup_stm32f4.S b/core/embed/coreapp/startup_stm32f4.S index f1a8a6784..d1a921abb 100644 --- a/core/embed/coreapp/startup_stm32f4.S +++ b/core/embed/coreapp/startup_stm32f4.S @@ -6,21 +6,17 @@ .type reset_handler, STT_FUNC reset_handler: - // setup environment for subsequent stage of code - ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM - ldr r2, =0 // r2 - the word-sized value to be written - bl memset_reg - - ldr r0, =boot_args_start // r0 - point to beginning of BOOT_ARGS - ldr r1, =boot_args_end // r1 - point to byte after the end of BOOT_ARGS - ldr r2, =0 // r2 - the word-sized value to be written - bl memset_reg - - ldr r0, =sram_start // r0 - point to beginning of SRAM - ldr r1, =sram_end // r1 - point to byte after the end of SRAM - ldr r2, =0 // r2 - the word-sized value to be written - bl memset_reg + push {r0, r1} + + // setup the stack protector with provided random value + ldr r0, = __stack_chk_guard + str r2, [r0] + + ldr r0, =bss_start + ldr r1, =0 + ldr r2, =bss_end + sub r2, r2, r0 + bl memset // copy data in from flash ldr r0, =data_vma // dst addr @@ -28,15 +24,14 @@ reset_handler: ldr r2, =data_size // size in bytes 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] + pop {r0, r1} // enter the application code + // returns exit code in r0 bl main - b secure_shutdown - + // terminate the application + // pass exit code in r0 + b system_exit .end diff --git a/core/embed/coreapp/startup_stm32u5.S b/core/embed/coreapp/startup_stm32u5.S index 6d94c656d..cc26b7470 100644 --- a/core/embed/coreapp/startup_stm32u5.S +++ b/core/embed/coreapp/startup_stm32u5.S @@ -6,53 +6,38 @@ .type reset_handler, STT_FUNC reset_handler: - // set the stack protection - ldr r0, =_sstack - add r0, r0, #128 // safety margin for the exception frame - msr PSPLIM, r0 + push {r0, r1} + + // setup the stack protector with provided random value + ldr r0, = __stack_chk_guard + str r2, [r0] ldr r0, =bss_start - ldr r1, =bss_end - ldr r2, =0 - bl memset_reg + ldr r1, =0 + ldr r2, =bss_end + sub r2, r2, r0 + bl memset // copy data in from flash - ldr r0, =data_vma // dst addr - ldr r1, =data_lma // src addr - ldr r2, =data_size // size in bytes + ldr r0, =data_vma + ldr r1, =data_lma + ldr r2, =data_size bl memcpy // copy confidential data in from flash - ldr r0, =confidential_vma // dst addr - ldr r1, =confidential_lma // src addr - ldr r2, =confidential_size // size in bytes + ldr r0, =confidential_vma + ldr r1, =confidential_lma + ldr r2, =confidential_size 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] + pop {r0, r1} // enter the application code + // returns exit code in r0 bl main - b secure_shutdown - - -memset_reg: - // call with the following (note that the arguments are not validated prior to use): - // r0 - address of first word to write (inclusive) - // r1 - address of first word following the address in r0 to NOT write (exclusive) - // r2 - word value to be written - // both addresses in r0 and r1 needs to be divisible by 4! - cmp r0, r1 - beq .L_loop_end - .L_loop_begin: - str r2, [r0], 4 // store the word in r2 to the address in r0, post-indexed - cmp r0, r1 - bne .L_loop_begin - .L_loop_end: - bx lr - + // terminate the application + // pass exit code in r0 + b system_exit .end diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index 3b8d09455..daad32c09 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -42,15 +42,16 @@ #include "compiler_traits.h" #include "display.h" #include "entropy.h" -#include "fault_handlers.h" #include "flash.h" #include "image.h" #include "memzero.h" #include "model.h" #include "mpu.h" #include "random_delays.h" +#include "rsod.h" #include "rust_ui.h" #include "secure_aes.h" +#include "system.h" #include "systimer.h" #include TREZOR_BOARD @@ -128,8 +129,7 @@ static void optiga_log_hex(const char *prefix, const uint8_t *data, #endif int main(void) { - systick_init(); - systimer_init(); + system_init(&rsod_gui); rdi_init(); @@ -186,8 +186,6 @@ int main(void) { // Init peripherals - fault_handlers_init(); - #if defined TREZOR_MODEL_T set_core_clock(CLOCK_180_MHZ); #endif diff --git a/core/embed/firmware/memory_T3T1.ld b/core/embed/firmware/memory_T3T1.ld index 4e3a2a88c..9bbf39047 100644 --- a/core/embed/firmware/memory_T3T1.ld +++ b/core/embed/firmware/memory_T3T1.ld @@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5); sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); sram6_start = ORIGIN(SRAM6); sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); diff --git a/core/embed/kernel/main.c b/core/embed/kernel/main.c index d945fe164..c09891639 100644 --- a/core/embed/kernel/main.c +++ b/core/embed/kernel/main.c @@ -19,27 +19,29 @@ #include STM32_HAL_H -#include "image.h" -#include "irq.h" -#include "syscall.h" +#include +#include "applet.h" #include "board_capabilities.h" +#include "bootutils.h" #include "display.h" #include "dma2d.h" #include "entropy.h" -#include "fault_handlers.h" #include "haptic.h" #include "i2c.h" +#include "image.h" +#include "irq.h" #include "memzero.h" #include "mpu.h" #include "optiga_commands.h" #include "optiga_transport.h" #include "random_delays.h" +#include "rsod.h" #include "sdcard.h" #include "secret.h" #include "secure_aes.h" +#include "system.h" #include "systick.h" -#include "systimer.h" #include "tamper.h" #include "touch.h" #include "unit_variant.h" @@ -65,15 +67,6 @@ static void optiga_log_hex(const char *prefix, const uint8_t *data, #endif void drivers_init() { - syscall_init(); - - systick_init(); - systimer_init(); - - fault_handlers_init(); - - systick_delay_ms(10); - #if defined TREZOR_MODEL_T set_core_clock(CLOCK_180_MHZ); #endif @@ -178,14 +171,88 @@ void drivers_init() { #endif } +// Initializes coreapp applet +static void coreapp_init(applet_t *applet) { + applet_header_t *coreapp_header = + (applet_header_t *)(COREAPP_START + IMAGE_HEADER_SIZE + 0x0400); + + applet_layout_t coreapp_layout = { + 0 + /* .data1_start = COREAPP_RAM1_START, + .data1_size = COREAPP_RAM1_SIZE, + .data2_start = COREAPP_RAM2_START, + .data2_size = COREAPP_RAM2_SIZE,*/ + }; + + applet_init(applet, coreapp_header, &coreapp_layout); +} + +// Shows RSOD (Red Screen of Death) +static void show_rsod(const systask_postmortem_t *pminfo) { +#ifdef FANCY_FATAL_ERROR + applet_t coreapp; + coreapp_init(&coreapp); + + // Reset and run the coreapp in RSOD mode + applet_reset(&coreapp, 1, pminfo, sizeof(systask_postmortem_t)); + systask_yield_to(&coreapp.task); + + if (coreapp.task.pminfo.reason == TASK_TERM_REASON_EXIT) { + // If the RSOD was shown successfully, proceed to shutdown + secure_shutdown(); + } +#endif + + // If coreapp crashed, fallback to showing the error using a terminal + rsod_terminal(pminfo); +} + +// Initializes system in emergency mode and shows RSOD +static void enter_emergency_mode(const systask_postmortem_t *pminfo) { + // Initialize the system's core services + // (If the kernel crashes in emergency mode, we are out of options + // and show the RSOD without attempting to re-enter emergency mode) + system_init(&rsod_terminal); + + // Initialize necessary drivers + display_init(DISPLAY_RESET_CONTENT); + + // Show RSOD + show_rsod(pminfo); + + // Wait for the user to manually power off the device + secure_shutdown(); +} + +// Kernel panic handler +// (may be called from interrupt context) +static void kernel_panic(const systask_postmortem_t *pminfo) { + // Since the system state is unreliable, enter emergency mode + // and show the RSOD. + system_emergency_rescue(&enter_emergency_mode, pminfo); + // The previous function call never returns +} + int main(void) { - mpu_init(); + // Initialize system's core services + system_init(&kernel_panic); // Initialize hardware drivers drivers_init(); - // Start unprivileged application - start_unprivileged_app(); + // Initialize coreapp task + applet_t coreapp; + coreapp_init(&coreapp); + + // Reset and run the coreapp + applet_reset(&coreapp, 0, NULL, 0); + systask_yield_to(&coreapp.task); + + // Coreapp crashed, show RSOD + show_rsod(&coreapp.task.pminfo); + + // Wait for the user to manually power off the device + secure_shutdown(); return 0; } diff --git a/core/embed/kernel/memory_T3T1.ld b/core/embed/kernel/memory_T3T1.ld index f799bf492..07a90ccc5 100644 --- a/core/embed/kernel/memory_T3T1.ld +++ b/core/embed/kernel/memory_T3T1.ld @@ -21,6 +21,9 @@ _estack = main_stack_base; data_lma = LOADADDR(.data); data_vma = ADDR(.data); data_size = SIZEOF(.data); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); + /* used by the startup code to populate variables used by the C code */ confidential_lma = LOADADDR(.confidential); diff --git a/core/embed/lib/error_handling.c b/core/embed/lib/error_handling.c index 1f2231760..2399ef0c0 100644 --- a/core/embed/lib/error_handling.c +++ b/core/embed/lib/error_handling.c @@ -18,25 +18,10 @@ */ #include -#ifdef TREZOR_EMULATOR -#include -#endif +#include -#include "bootutils.h" -#include "display.h" #include "error_handling.h" -#include "mini_printf.h" -#ifdef FANCY_FATAL_ERROR -#include "rust_ui.h" -#else -#include "terminal.h" -#endif - -#ifdef RGB16 -#define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00) -#else -#define COLOR_FATAL_ERROR COLOR_BLACK -#endif +#include "system.h" uint32_t __stack_chk_guard = 0; @@ -48,26 +33,16 @@ void __attribute__((noreturn, used)) __stack_chk_fail(void) { void __attribute__((noreturn)) error_shutdown_ex(const char *title, const char *message, const char *footer) { - if (title == NULL) { + if (title == NULL) { // !@# remove title = "INTERNAL ERROR"; } - if (footer == NULL) { + if (footer == NULL) { // !@# remove footer = "PLEASE VISIT\nTREZOR.IO/RSOD"; } -#ifdef FANCY_FATAL_ERROR - error_shutdown_rust(title, message, footer); -#else - display_orientation(0); - term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); - term_printf("%s\n", title); - if (message) { - term_printf("%s\n", message); - } - term_printf("\n%s\n", footer); - display_backlight(255); - secure_shutdown(); -#endif + system_exit_error(title, message, footer); + while (1) + ; } void __attribute__((noreturn)) error_shutdown(const char *message) { @@ -76,39 +51,9 @@ void __attribute__((noreturn)) error_shutdown(const char *message) { void __attribute__((noreturn)) __fatal_error(const char *msg, const char *file, int line) { -#ifdef TREZOR_EMULATOR - fprintf(stderr, "FATAL ERROR: %s\n", msg); - if (file) { - fprintf(stderr, "file: %s:%d\n", file, line); - } - fflush(stderr); -#endif -#ifdef FANCY_FATAL_ERROR - if (msg == NULL) { - char buf[128] = {0}; - mini_snprintf(buf, sizeof(buf), "%s:%d", file, line); - msg = buf; - } - error_shutdown(msg); -#else - display_orientation(0); - term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); - term_printf("\nINTERNAL ERROR:\n"); - if (msg) { - term_printf("msg : %s\n", msg); - } - if (file) { - term_printf("file: %s:%d\n", file, line); - } -#ifdef SCM_REVISION - const uint8_t *rev = (const uint8_t *)SCM_REVISION; - term_printf("rev : %02x%02x%02x%02x%02x\n", rev[0], rev[1], rev[2], rev[3], - rev[4]); -#endif - term_printf("\nPlease contact Trezor support.\n"); - display_backlight(255); - secure_shutdown(); -#endif + system_exit_fatal(msg, file, line); + while (1) + ; } void __attribute__((noreturn)) show_wipe_code_screen(void) { diff --git a/core/embed/lib/rsod.c b/core/embed/lib/rsod.c new file mode 100644 index 000000000..b1a189f3a --- /dev/null +++ b/core/embed/lib/rsod.c @@ -0,0 +1,141 @@ +/* + * 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 "rsod.h" +#include "display.h" +#include "mini_printf.h" +#include "system.h" +#include "terminal.h" + +#define RSOD_DEFAULT_TITLE "INTERNAL ERROR"; +#define RSOD_DEFAULT_MESSAGE "UNSPECIFIED"; +#define RSOD_DEFAULT_FOOTER "PLEASE VISIT TREZOR.IO/RSOD"; +#define RSOD_EXIT_MESSAGE "EXIT %d" + +#ifdef KERNEL_MODE + +#define RSOD_FG_COLOR COLOR_WHITE + +#ifdef USE_RGB_COLORS +#define RSOD_BG_COLOR RGB16(0x7F, 0x00, 0x00) +#else +#define RSOD_BG_COLOR COLOR_BLACK +#endif + +void rsod_terminal(const systask_postmortem_t* info) { + display_orientation(0); + term_set_color(RSOD_FG_COLOR, RSOD_BG_COLOR); + + const char* title = RSOD_DEFAULT_TITLE; + const char* message = RSOD_DEFAULT_MESSAGE; + const char* footer = RSOD_DEFAULT_FOOTER; + const char* file = NULL; + char message_buf[32] = {0}; + int line = 0; + + switch (info->reason) { + case TASK_TERM_REASON_EXIT: + mini_snprintf(message_buf, sizeof(message_buf), RSOD_EXIT_MESSAGE, + info->exit.code); + message = message_buf; + break; + case TASK_TERM_REASON_ERROR: + title = info->error.title; + message = info->error.message; + footer = info->error.footer; + break; + case TASK_TERM_REASON_FATAL: + message = info->fatal.expr; + file = info->fatal.file; + line = info->fatal.line; + break; + case TASK_TERM_REASON_FAULT: + message = system_fault_message(&info->fault); + break; + } + + if (title != NULL) { + term_printf("%s\n", title); + } + + if (message != NULL) { + term_printf("msg : %s\n", message); + } + + if (file) { + term_printf("file: %s:%d\n", file, line); + } + +#ifdef SCM_REVISION + const uint8_t* rev = (const uint8_t*)SCM_REVISION; + term_printf("rev : %02x%02x%02x%02x%02x\n", rev[0], rev[1], rev[2], rev[3], + rev[4]); +#endif + + if (footer != NULL) { + term_printf("\n%s\n", footer); + } + + display_backlight(255); +} + +#endif // KERNEL_MODE + +#if defined(FIRMWARE) || defined(BOOTLOADER) + +#include "rust_ui.h" + +void rsod_gui(const systask_postmortem_t* info) { + const char* title = RSOD_DEFAULT_TITLE; + const char* message = RSOD_DEFAULT_MESSAGE; + const char* footer = RSOD_DEFAULT_FOOTER; + char message_buf[128] = {0}; + + switch (info->reason) { + case TASK_TERM_REASON_EXIT: + mini_snprintf(message_buf, sizeof(message_buf), RSOD_EXIT_MESSAGE, + info->exit.code); + message = message_buf; + break; + + case TASK_TERM_REASON_ERROR: + title = info->error.title; + message = info->error.message; + footer = info->error.footer; + break; + + case TASK_TERM_REASON_FATAL: + message = info->fatal.expr; + if (message[0] == '\0') { + mini_snprintf(message_buf, sizeof(message_buf), "%s:%u", + info->fatal.file, (unsigned int)info->fatal.line); + message = message_buf; + } + break; + + case TASK_TERM_REASON_FAULT: + message = system_fault_message(&info->fault); + break; + } + + // Render the RSOD in Rust + display_rsod_rust(title, message, footer); +} + +#endif diff --git a/core/embed/trezorhal/unix/fault_handlers.c b/core/embed/lib/rsod.h similarity index 80% rename from core/embed/trezorhal/unix/fault_handlers.c rename to core/embed/lib/rsod.h index 1e7754849..8b7f3a73a 100644 --- a/core/embed/trezorhal/unix/fault_handlers.c +++ b/core/embed/lib/rsod.h @@ -17,6 +17,13 @@ * along with this program. If not, see . */ -#include +#ifndef LIB_RSOD_H +#define LIB_RSOD_H -void fault_handlers_init(void) {} +#include "systask.h" + +void rsod_terminal(const systask_postmortem_t* info); + +void rsod_gui(const systask_postmortem_t* info); + +#endif // LIB_RSOD_H diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index e69e5b6aa..e7019e436 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -31,7 +31,6 @@ #include "display.h" #include "display_draw.h" #include "display_utils.h" -#include "fault_handlers.h" #include "flash.h" #include "flash_otp.h" #include "fwutils.h" @@ -41,9 +40,11 @@ #include "mpu.h" #include "prodtest_common.h" #include "random_delays.h" +#include "rsod.h" #include "sbu.h" #include "sdcard.h" #include "secbool.h" +#include "system.h" #include "systimer.h" #include "touch.h" #include "usb.h" @@ -778,10 +779,35 @@ void cpuid_read(void) { #define BACKLIGHT_NORMAL 150 +// Initializes system in emergency mode and shows RSOD +static void enter_emergency_mode(const systask_postmortem_t *pminfo) { + // Initialize the system's core services + // (If the kernel crashes in emergency mode, we are out of options + // and show the RSOD without attempting to re-enter emergency mode) + system_init(&rsod_terminal); + + // Initialize necessary drivers + display_init(DISPLAY_RESET_CONTENT); + + // Show RSOD + rsod_terminal(pminfo); + + // Wait for the user to manually power off the device + secure_shutdown(); +} + +// Kernel panic handler +// (may be called from interrupt context) +static void kernel_panic(const systask_postmortem_t *pminfo) { + // Since the system state is unreliable, enter emergency mode + // and show the RSOD. + system_emergency_rescue(&enter_emergency_mode, pminfo); + // The previous function call never returns +} + int main(void) { - systick_init(); - systimer_init(); - rdi_init(); + system_init(&kernel_panic); + display_init(DISPLAY_RETAIN_CONTENT); #ifdef STM32U5 @@ -819,8 +845,6 @@ int main(void) { pair_optiga(); #endif - fault_handlers_init(); - display_clear(); draw_welcome_screen(); diff --git a/core/embed/prodtest/memory_stm32u58.ld b/core/embed/prodtest/memory_stm32u58.ld index eaa108f73..53c521686 100644 --- a/core/embed/prodtest/memory_stm32u58.ld +++ b/core/embed/prodtest/memory_stm32u58.ld @@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5); sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); sram6_start = ORIGIN(SRAM6); sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); diff --git a/core/embed/reflash/main.c b/core/embed/reflash/main.c index 114870872..d6c040278 100644 --- a/core/embed/reflash/main.c +++ b/core/embed/reflash/main.c @@ -23,6 +23,7 @@ #include STM32_HAL_H +#include "bootutils.h" #include "common.h" #include "display.h" #include "display_draw.h" @@ -30,9 +31,11 @@ #include "image.h" #include "model.h" #include "rng.h" +#include "rsod.h" #include "sbu.h" #include "sdcard.h" #include "secbool.h" +#include "system.h" #include "systimer.h" #include "terminal.h" #include "touch.h" @@ -43,7 +46,7 @@ static void progress_callback(int pos, int len) { term_printf("."); } -static void flash_from_sdcard(const flash_area_t* area, uint32_t source, +static void flash_from_sdcard(const flash_area_t *area, uint32_t source, uint32_t length) { static uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)]; @@ -68,9 +71,34 @@ static void flash_from_sdcard(const flash_area_t* area, uint32_t source, } } +// Initializes system in emergency mode and shows RSOD +static void enter_emergency_mode(const systask_postmortem_t *pminfo) { + // Initialize the system's core services + // (If the kernel crashes in emergency mode, we are out of options + // and show the RSOD without attempting to re-enter emergency mode) + system_init(&rsod_terminal); + + // Initialize necessary drivers + display_init(DISPLAY_RESET_CONTENT); + + // Show RSOD using the terminal + rsod_terminal(pminfo); + + // Wait for the user to manually power off the device + secure_shutdown(); +} + +// Kernel panic handler +// (may be called from interrupt context) +static void kernel_panic(const systask_postmortem_t *pminfo) { + // Since the system state is unreliable, enter emergency mode + // and show the RSOD. + system_emergency_rescue(&enter_emergency_mode, pminfo); + // The previous function call never returns +} + int main(void) { - systick_init(); - systimer_init(); + system_init(&kernel_panic); sdcard_init(); touch_init(); diff --git a/core/embed/reflash/memory_stm32u58.ld b/core/embed/reflash/memory_stm32u58.ld index e00c0df10..586970355 100644 --- a/core/embed/reflash/memory_stm32u58.ld +++ b/core/embed/reflash/memory_stm32u58.ld @@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5); sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); sram6_start = ORIGIN(SRAM6); sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); +bss_start = ADDR(.bss); +bss_end = ADDR(.bss) + SIZEOF(.bss); /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); diff --git a/core/embed/rust/rust_ui_common.h b/core/embed/rust/rust_ui_common.h index 11f03965a..6c8a8b7de 100644 --- a/core/embed/rust/rust_ui_common.h +++ b/core/embed/rust/rust_ui_common.h @@ -1,8 +1,7 @@ #include "common.h" -__attribute__((noreturn)) void error_shutdown_rust(const char* title, - const char* msg, - const char* footer); +void display_rsod_rust(const char* title, const char* message, + const char* footer); void screen_boot_stage_2(void); diff --git a/core/embed/rust/src/trezorhal/fatal_error.rs b/core/embed/rust/src/trezorhal/fatal_error.rs index 132c41eb1..1942690c6 100644 --- a/core/embed/rust/src/trezorhal/fatal_error.rs +++ b/core/embed/rust/src/trezorhal/fatal_error.rs @@ -1,31 +1,24 @@ mod ffi { extern "C" { - // trezorhal/bootuils.c - pub fn secure_shutdown() -> !; + // bootutils.h + pub fn error_shutdown(msg: *const cty::c_char) -> !; } } -use crate::ui::{ - shape, - ui_features::{ModelUI, UIFeaturesCommon}, -}; +pub fn error_shutdown(msg: &str) -> ! { + const MAX_LEN: usize = 63; + let mut buffer: [u8; MAX_LEN + 1] = [0; MAX_LEN + 1]; -fn shutdown() -> ! { - unsafe { ffi::secure_shutdown() } -} - -/// Shows an error message and shuts down the device. -pub fn error_shutdown(title: &str, msg: &str, footer: &str) -> ! { - // SAFETY: - // This is the only situation we are allowed use this function - // to allow nested calls to `run_with_bumps`/`render_on_display`, - // because after the error message is displayed, the application will - // shut down. - unsafe { shape::unlock_bumps_on_failure() }; + // Copy the message to the buffer + let msg_bytes = msg.as_bytes(); + let len = if msg_bytes.len() < MAX_LEN { msg_bytes.len() } else { MAX_LEN }; + buffer[..len].copy_from_slice(&msg_bytes[..len]); - ModelUI::screen_fatal_error(title, msg, footer); - ModelUI::backlight_on(); - shutdown() + unsafe { + // SAFETY: `buffer` is a valid null-terminated string + // and the function never returns. + ffi::error_shutdown(buffer.as_ptr() as *const cty::c_char); + } } /// Shows an error message on the screen and shuts down the device. @@ -46,7 +39,7 @@ pub fn __fatal_error(msg: &str, _file: &str, _line: u32) -> ! { dbg_println!("==="); } - error_shutdown("INTERNAL_ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + error_shutdown(msg); } pub trait UnwrapOrFatalError { diff --git a/core/embed/rust/src/ui/api/common_c.rs b/core/embed/rust/src/ui/api/common_c.rs index ccbed0d3a..2b560ea40 100644 --- a/core/embed/rust/src/ui/api/common_c.rs +++ b/core/embed/rust/src/ui/api/common_c.rs @@ -10,19 +10,32 @@ use crate::ui::{ geometry::{Alignment2D, Point}, }; -use crate::{trezorhal::fatal_error, ui::util::from_c_str}; +#[cfg(feature = "new_rendering")] +use crate::ui::shape; + + +use crate::{ui::util::from_c_str}; #[no_mangle] -extern "C" fn error_shutdown_rust( +extern "C" fn display_rsod_rust( title: *const cty::c_char, msg: *const cty::c_char, footer: *const cty::c_char, -) -> ! { +) { let title = unsafe { from_c_str(title) }.unwrap_or(""); let msg = unsafe { from_c_str(msg) }.unwrap_or(""); let footer = unsafe { from_c_str(footer) }.unwrap_or(""); - fatal_error::error_shutdown(title, msg, footer) + // SAFETY: + // This is the only situation we are allowed use this function + // to allow nested calls to `run_with_bumps`/`render_on_display`, + // because after the error message is displayed, the application will + // shut down. + #[cfg(feature = "new_rendering")] + unsafe { shape::unlock_bumps_on_failure() }; + + ModelUI::screen_fatal_error(title, msg, footer); + ModelUI::backlight_on(); } #[no_mangle] diff --git a/core/embed/trezorhal/applet.h b/core/embed/trezorhal/applet.h new file mode 100644 index 000000000..7fd68c1d0 --- /dev/null +++ b/core/embed/trezorhal/applet.h @@ -0,0 +1,79 @@ +/* + * 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 . + */ + +#ifndef TREZORHAL_APPLET_H +#define TREZORHAL_APPLET_H + +#include +#include + +#ifdef SYSCALL_DISPATCH + +#include "systask.h" + +// Applet entry point +typedef void (*applet_startup_t)(const char* args, uint32_t random); + +// Applet header found at the beginning of the applet binary +typedef struct { + // Stack area + uint32_t stack_start; + uint32_t stack_size; + // Applet entry point + applet_startup_t startup; +} applet_header_t; + +// Applet memory layout +typedef struct { + // Data area 1 + uint32_t data1_start; + uint32_t data1_size; + // Data area 2 + uint32_t data2_start; + uint32_t data2_size; + +} applet_layout_t; + +typedef struct { + // Points to the applet header found at the beginning of the applet binary + applet_header_t* header; + // Applet memory layout describing the memory areas + // the applet is allowed to use + applet_layout_t layout; + // Applet task + systask_t task; + + // + privileges + +} applet_t; + +// Initializes the applet structure +void applet_init(applet_t* applet, applet_header_t* header, + applet_layout_t* layout); + +// Resets the applet and prepares it for execution from its entry point. +// +// Applet does not start immediately, it needs to be scheduled by +// `systask_yield_to(&applet->task)` after calling this function. +void applet_reset(applet_t* applet, uint32_t cmd, const void* arg, + size_t arg_size); + +#endif // SYSCALL_DISPATCH + +#endif // TREZORHAL_APPLET_H \ No newline at end of file diff --git a/core/embed/trezorhal/fault_handlers.h b/core/embed/trezorhal/fault_handlers.h deleted file mode 100644 index 8372135f3..000000000 --- a/core/embed/trezorhal/fault_handlers.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef TREZORHAL_FAULT_HANDLERS_H -#define TREZORHAL_FAULT_HANDLERS_H - -// Initializes and enables fault handlers -void fault_handlers_init(void); - -#endif // TREZORHAL_FAULT_HANDLERS_H diff --git a/core/embed/trezorhal/stm32f4/applet.c b/core/embed/trezorhal/stm32f4/applet.c new file mode 100644 index 000000000..601cc48e3 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/applet.c @@ -0,0 +1,71 @@ +/* + * 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 "applet.h" +#include "mpu.h" +#include "rng.h" +#include "systask.h" + +#ifdef SYSCALL_DISPATCH + +void applet_init(applet_t* applet, applet_header_t* header, + applet_layout_t* layout) { + memset(applet, 0, sizeof(applet_t)); + + applet->header = header; + applet->layout = *layout; + + // !@# check if header refs are valid and inside the layout memory +} + +static void applet_clear_memory(applet_t* applet) { + if (applet->layout.data1_size > 0) { + memset((void*)applet->layout.data1_start, 0, applet->layout.data1_size); + } + if (applet->layout.data2_size > 0) { + memset((void*)applet->layout.data2_start, 0, applet->layout.data2_size); + } +} + +void applet_reset(applet_t* applet, uint32_t cmd, const void* arg, + size_t arg_size) { + // Clear all memory the applet is allowed to use + applet_clear_memory(applet); + + // Reset the applet task (stack pointer, etc.) + systask_init(&applet->task, applet->header->stack_start, + applet->header->stack_size); + + // Copy the arguments onto the applet stack + void* arg_copy = NULL; + if (arg != NULL && arg_size > 0) { + arg_copy = systask_push_data(&applet->task, arg, arg_size); + } + + // Schedule the applet task run + uint32_t arg1 = cmd; + uint32_t arg2 = (uint32_t)arg_copy; + uint32_t arg3 = rng_get(); + + systask_push_call(&applet->task, applet->header->startup, arg1, arg2, arg3); +} + +#endif // SYSCALL_DISPATCH diff --git a/core/embed/trezorhal/stm32f4/fault_handlers.c b/core/embed/trezorhal/stm32f4/fault_handlers.c deleted file mode 100644 index 35fc0ed03..000000000 --- a/core/embed/trezorhal/stm32f4/fault_handlers.c +++ /dev/null @@ -1,58 +0,0 @@ -#include TREZOR_BOARD - -#include "common.h" -#include "mpu.h" - -#ifdef KERNEL_MODE - -void fault_handlers_init(void) { - // Enable BUS fault and USAGE fault handlers - SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk); -} - -void HardFault_Handler(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(HF)"); -} - -void MemManage_Handler_MM(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(MM)"); -} - -void MemManage_Handler_SO(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(SO)"); -} - -void BusFault_Handler(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(BF)"); -} - -void UsageFault_Handler(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(UF)"); -} - -void NMI_Handler(void) { - mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); - // Clock Security System triggered NMI - if ((RCC->CIR & RCC_CIR_CSSF) != 0) { - error_shutdown("(CS)"); - } - mpu_restore(mpu_mode); -} - -// from util.s -extern void shutdown_privileged(void); - -void PVD_IRQHandler(void) { - mpu_reconfig(MPU_MODE_DEFAULT); -#ifdef BACKLIGHT_PWM_TIM - BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = 0; // turn off display backlight -#endif - shutdown_privileged(); -} - -#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/monoctr.c b/core/embed/trezorhal/stm32f4/monoctr.c index 863e80b76..031b311f4 100644 --- a/core/embed/trezorhal/stm32f4/monoctr.c +++ b/core/embed/trezorhal/stm32f4/monoctr.c @@ -76,7 +76,6 @@ 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; } @@ -131,9 +130,7 @@ secbool monoctr_read(monoctr_type_t type, uint8_t* value) { return secfalse; } #else - - *value = 0; - + *value = dummy_version; #endif return sectrue; diff --git a/core/embed/trezorhal/stm32f4/syscall.c b/core/embed/trezorhal/stm32f4/syscall.c index 1dc5791bf..c58a8f2c3 100644 --- a/core/embed/trezorhal/stm32f4/syscall.c +++ b/core/embed/trezorhal/stm32f4/syscall.c @@ -17,23 +17,13 @@ * along with this program. If not, see . */ -#include STM32_HAL_H - #include "syscall.h" -#include "image.h" -#include "irq.h" #include "mpu.h" #ifdef SYSCALL_DISPATCH -void syscall_init(void) { - // SVCall priority should be the lowest since it is - // generally a blocking operation - NVIC_SetPriority(SVCall_IRQn, IRQ_PRI_LOWEST); -} - __attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback( - uint32_t args1, uint32_t arg2, uint32_t arg3, void *callback) { + uint32_t args1, uint32_t arg2, uint32_t arg3, void* callback) { __asm__ volatile( "push {r1-r12, lr} \n" @@ -43,14 +33,24 @@ __attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback( "sub r12, r12, #32 \n" "msr PSP, r12 \n" - "str r0, [r12, #0] \n" // r0 - "str r1, [r12, #4] \n" // r1" - "str r2, [r12, #8] \n" // r2" + "str r0, [r12, #0] \n" // pass r0 + "str r1, [r12, #4] \n" // pass r1 + "str r2, [r12, #8] \n" // pass r2 "mov r1, #0 \n" - "str r1, [r12, #12] \n" // r3" - "str r1, [r12, #16] \n" // r12" - "str r1, [r12, #20] \n" // lr" + + "mov r4, r1 \n" // Clear registers r4-r11 + "mov r5, r1 \n" + "mov r6, r1 \n" + "mov r7, r1 \n" + "mov r8, r1 \n" + "mov r9, r1 \n" + "mov r10, r1 \n" + "mov r11, r1 \n" + + "str r1, [r12, #12] \n" // clear r3 + "str r1, [r12, #16] \n" // clear r12 + "str r1, [r12, #20] \n" // clear lr "bic r3, r3, #1 \n" "str r3, [r12, #24] \n" // return address @@ -73,133 +73,21 @@ __attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback( } uint32_t invoke_app_callback(uint32_t args1, uint32_t arg2, uint32_t arg3, - void *callback) { + void* callback) { mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_APP); uint32_t retval = _invoke_app_callback(args1, arg2, arg3, callback); mpu_reconfig(mpu_mode); return retval; } -// Jumps to reset vector of unprivileged application code -// -// Can be called only from an exception handler -__attribute__((naked, no_stack_protector)) static void start_app( - uint32_t app_start) { - __asm__ volatile( - "ldr r12, [r0, #0] \n" // stack pointer - "sub r12, r12, #32 \n" - "msr PSP, r12 \n" - - "mov r1, #0 \n" - "str r1, [r12, #0] \n" // r0 - "str r1, [r12, #4] \n" // r1" - "str r1, [r12, #8] \n" // r2" - "str r1, [r12, #12] \n" // r3" - "str r1, [r12, #16] \n" // r12" - "str r1, [r12, #20] \n" // lr" - - "ldr r1, [r0, #4] \n" // reset vector - "bic r1, r1, #1 \n" - "str r1, [r12, #24] \n" // return address - - "ldr r1, = 0x01000000 \n" - "str r1, [r12, #28] \n" // xPSR - - "ldr r1, = 0xE000EF34 \n" // FPU->FPPCCR - "ldr r0, [r1] \n" - "bic r0, r0, #1 \n" // Clear LSPACT to suppress lazy stacking to - "str r0, [r1] \n" // avoid potential PSP stack overwrite. - - "mrs r1, CONTROL \n" - "bic r1, r1, #4 \n" // Clear FPCA to suppress lazy stacking to - "msr CONTROL, r1 \n" // avoid potential PSP stack overwrite. - - "mrs r1, CONTROL \n" // Switch thread mode to unprivileged - "orr r1, r1, #1 \n" // by setting nPRIV bit in CONTROL register. - "msr CONTROL, r1 \n" // This applies after return from this - // handler. - - // return to Secure Thread mode (use Secure PSP) - "ldr lr, = 0xFFFFFFFD \n" - "bx lr \n"); -} - -void SVC_C_Handler(uint32_t *stack, uint32_t r4, uint32_t r5, uint32_t r6) { - uint8_t svc_number = ((uint8_t *)stack[6])[-2]; - uint32_t args[6] = {stack[0], stack[1], stack[2], stack[3], r4, r5}; - - mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); - - switch (svc_number) { -#ifdef SYSTEM_VIEW - case SVC_GET_DWT_CYCCNT: - cyccnt_cycles = *DWT_CYCCNT_ADDR; - break; -#endif - case SVC_START_APP: - mpu_reconfig(MPU_MODE_APP); - start_app(args[0]); - break; - case SVC_SYSCALL: - syscall_handler(args, r6); - stack[0] = args[0]; - stack[1] = args[1]; - break; - default: - stack[0] = 0xffffffff; - stack[1] = 0xffffffff; - break; - } - - mpu_restore(mpu_mode); -} - -__attribute__((naked, no_stack_protector)) void SVC_Handler(void) { +__attribute__((naked, no_stack_protector)) void return_from_app_callback( + uint32_t retval, uint32_t* msp) { __asm__ volatile( - " tst lr, #4 \n" // Bit #3 tells which stack pointer should we - // use - " ite eq \n" // Next 2 instructions are if-then-else - " mrseq r0, msp \n" // Make R0 point to main stack pointer - " mrsne r0, psp \n" // Make R0 point to process stack pointer - - " ldr r1, [r0, #24] \n" // Load the PC of the SVC handler - " ldrb r1, [r1, #-2] \n" // Load the instruction at the PC - " cmp r1, #2 \n" // SVC_CALLBACK_RETURN - " beq svc_callback_return \n" - - " mov r1, r4 \n" // pass R4 (arg5), R5 (arg6) and - " mov r2, r5 \n" // R6 (sycall_number) as arguments - " mov r3, r6 \n" // to SCV_C_Handler - " b SVC_C_Handler \n" // - - "svc_callback_return: \n" - - " ldr r0, [r0] \n" - " pop {r1} \n" - " msr PSP, r1 \n" - " pop {r1-r12, lr} \n" - " bx lr \n"); -} - -void __attribute__((no_stack_protector, noreturn)) -start_unprivileged_app(void) { - //!@# TODO calculate better - static const uint32_t app_start = COREAPP_START + IMAGE_HEADER_SIZE + 0x0400; - - mpu_reconfig(MPU_MODE_APP); - - register uint32_t ret __asm__("r0") = app_start; - - // SVC_START_APP is the only SVC that is allowed to be invoked from kernel - // itself and it is used to start the unprivileged application code - __asm__ volatile("svc %[svid]\n" - : "=r"(ret) - : [svid] "i"(SVC_START_APP), "r"(ret) - : "memory"); - - // We never get here, just to supress compiler warning - while (1) { - } + "MSR MSP, R1 \n" + "POP {R1} \n" + "MSR PSP, R1 \n" + "POP {R1-R12, LR} \n" + "BX LR \n"); } #endif // SYSCALL_DISPATCH diff --git a/core/embed/trezorhal/stm32f4/syscall.h b/core/embed/trezorhal/stm32f4/syscall.h index 32da335d9..a0cefd53a 100644 --- a/core/embed/trezorhal/stm32f4/syscall.h +++ b/core/embed/trezorhal/stm32f4/syscall.h @@ -22,18 +22,16 @@ #include +#include "applet.h" #include "syscall_numbers.h" // Reserved SVC numbers #define SVC_SYSCALL 0 -#define SVC_START_APP 1 +#define SVC_SYSTASK_YIELD 1 #define SVC_CALLBACK_RETURN 2 #ifdef KERNEL_MODE -// Initializes the SVC/Syscall handlers -void syscall_init(void); - // Handles all syscall requests. // // `args` points to an array of six 32-bit arguments. @@ -44,14 +42,13 @@ void syscall_init(void); // // Return values must be copied to `args[0]` and // `args[1]` (if returning a 64-bit value). -void syscall_handler(uint32_t *args, uint32_t syscall); +void syscall_handler(uint32_t* args, uint32_t syscall); // Invokes application callback from the syscall handler uint32_t invoke_app_callback(uint32_t args1, uint32_t arg2, uint32_t arg3, - void *callback); + void* callback); -// Jumps to reset vector in the unprivileged application -void __attribute__((noreturn)) start_unprivileged_app(void); +void return_from_app_callback(uint32_t retval, uint32_t* msp); #else // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/syscall_dispatch.c b/core/embed/trezorhal/stm32f4/syscall_dispatch.c index 12a40a8fb..729f45a93 100644 --- a/core/embed/trezorhal/stm32f4/syscall_dispatch.c +++ b/core/embed/trezorhal/stm32f4/syscall_dispatch.c @@ -34,6 +34,8 @@ #include "rng.h" #include "sdcard.h" #include "secret.h" +#include "systask.h" +#include "system.h" #include "systick.h" #include "touch.h" #include "translations.h" @@ -63,6 +65,17 @@ static void firmware_hash_callback_wrapper(void *context, uint32_t progress, void syscall_handler(uint32_t *args, uint32_t syscall) { switch (syscall) { + case SYSCALL_SYSTEM_EXIT: { + system_exit((int)args[0]); + } break; + case SYSCALL_SYSTEM_EXIT_ERROR: { + system_exit_error((const char *)args[0], (const char *)args[1], + (const char *)args[2]); + } break; + case SYSCALL_SYSTEM_EXIT_FATAL: { + system_exit_fatal((const char *)args[0], (const char *)args[1], + (int)args[2]); + } break; case SYSCALL_SYSTICK_CYCLES: { uint64_t cycles = systick_cycles(); args[0] = cycles & 0xFFFFFFFF; diff --git a/core/embed/trezorhal/stm32f4/syscall_numbers.h b/core/embed/trezorhal/stm32f4/syscall_numbers.h index 749e0510f..694f33924 100644 --- a/core/embed/trezorhal/stm32f4/syscall_numbers.h +++ b/core/embed/trezorhal/stm32f4/syscall_numbers.h @@ -20,10 +20,14 @@ #ifndef SYSCALL_NUMBERS_H #define SYSCALL_NUMBERS_H +// Syscall identifiers typedef enum { - // Syscalls numbers - SYSCALL_SYSTICK_CYCLES = 1, + SYSCALL_SYSTEM_EXIT = 1, + SYSCALL_SYSTEM_EXIT_ERROR, + SYSCALL_SYSTEM_EXIT_FATAL, + + SYSCALL_SYSTICK_CYCLES, SYSCALL_SYSTICK_MS, SYSCALL_SYSTICK_US, SYSCALL_SYSTICK_US_TO_CYCLES, diff --git a/core/embed/trezorhal/stm32f4/syscall_stubs.c b/core/embed/trezorhal/stm32f4/syscall_stubs.c index e85c6a627..12571705c 100644 --- a/core/embed/trezorhal/stm32f4/syscall_stubs.c +++ b/core/embed/trezorhal/stm32f4/syscall_stubs.c @@ -21,6 +21,33 @@ #ifndef KERNEL_MODE +// ============================================================================= +// system.h +// ============================================================================= + +#include "system.h" + +void system_exit(int exit_code) { + syscall_invoke1(exit_code, SYSCALL_SYSTEM_EXIT); + while (1) + ; +} + +void system_exit_error(const char *title, const char *message, + const char *footer) { + syscall_invoke3((uint32_t)title, (uint32_t)message, (uint32_t)footer, + SYSCALL_SYSTEM_EXIT_ERROR); + while (1) + ; +} + +void system_exit_fatal(const char *message, const char *file, int line) { + syscall_invoke3((uint32_t)message, (uint32_t)file, line, + SYSCALL_SYSTEM_EXIT_FATAL); + while (1) + ; +} + // ============================================================================= // systick.h // ============================================================================= diff --git a/core/embed/trezorhal/stm32f4/systask.c b/core/embed/trezorhal/stm32f4/systask.c new file mode 100644 index 000000000..10a04e0a6 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/systask.c @@ -0,0 +1,470 @@ +/* + * 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 STM32_HAL_H + +#include +#include + +#include "bootutils.h" +#include "irq.h" +#include "mpu.h" +#include "syscall.h" +#include "systask.h" +#include "system.h" + +#ifdef KERNEL_MODE + +#define STK_FRAME_R0 0 +#define STK_FRAME_R1 1 +#define STK_FRAME_R2 2 +#define STK_FRAME_R3 3 +#define STK_FRAME_R12 4 +#define STK_FRAME_LR 5 +#define STK_FRAME_RET_ADDR 6 +#define STK_FRAME_XPSR 7 + +// Task manager state +typedef struct { + // Error handler called when a kernel task terminates + systask_error_handler_t error_handler; + // Background kernel task + systask_t kernel_task; + // Currently running task + systask_t* active_task; + // Task to be scheduled next + systask_t* waiting_task; +} systask_scheduler_t; + +// Global task manager state +systask_scheduler_t g_systask_scheduler = {0}; + +void systask_scheduler_init(systask_error_handler_t error_handler) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + memset(scheduler, 0, sizeof(systask_scheduler_t)); + + scheduler->error_handler = error_handler; + scheduler->active_task = &scheduler->kernel_task; + scheduler->waiting_task = scheduler->active_task; + + // SVCall priority should be the lowest since it is + // generally a blocking operation + NVIC_SetPriority(SVCall_IRQn, IRQ_PRI_LOWEST); + NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_LOWEST); + + // Enable BusFault and UsageFault handlers + SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk); +} + +systask_t* systask_active(void) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + return scheduler->active_task; +} + +void systask_yield_to(systask_t* task) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0; + + if (handler_mode) { + scheduler->waiting_task = task; + SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; + __DSB(); + } else { + register uint32_t r0 __asm__("r0") = (uint32_t)task; + + // SVC_SYSTASK_YIELD is the only SVC that is allowed to be invoked from + // kernel itself, and it is used to start the unprivileged application code. + __asm__ volatile("svc %[svid]\n" + : "=r"(r0) + : [svid] "i"(SVC_SYSTASK_YIELD), "r"(r0) + : "memory"); + } +} + +void systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size) { + task->sp = stack_ptr + stack_size; + task->sp_lim = stack_ptr + 256; + task->exc_return = 0xFFFFFFED; // Thread mode, use PSP, pop FP context + task->mpu_mode = MPU_MODE_APP; +} + +uint32_t* systask_push_data(systask_t* task, const void* data, size_t size) { + uint32_t stack_remaining = task->sp - task->sp_lim; + if (stack_remaining < size) { + return NULL; + } + task->sp -= size; + + if (data != NULL) { + memcpy((void*)task->sp, data, size); + } else { + memset((void*)task->sp, 0, size); + } + + return (void*)task->sp; +} + +void systask_pop_data(systask_t* task, size_t size) { task->sp += size; } + +void systask_push_call(systask_t* task, void* entrypoint, uint32_t arg1, + uint32_t arg2, uint32_t arg3) { + // FP extension context + systask_push_data(task, NULL, 0x48); + // Standard exception frame + uint32_t* stk_frame = systask_push_data(task, NULL, 0x20); + // Registers r4-r11 + systask_push_data(task, NULL, 0x20); + // Registers s16-s31 + systask_push_data(task, NULL, 0x40); + + // Return to thread mode, use PSP, pop FP context + task->exc_return = 0xFFFFFFED; + + stk_frame[STK_FRAME_R0] = arg1; + stk_frame[STK_FRAME_R1] = arg2; + stk_frame[STK_FRAME_R2] = arg3; + stk_frame[STK_FRAME_RET_ADDR] = (uint32_t)entrypoint & ~1; + stk_frame[STK_FRAME_XPSR] = 0x01000000; // T (Thumb state) bit set +} + +// C part of PendSV handler that switches tasks +// +// `sp` is the stack pointer of the current task +// `sp_lim` is the stack pointer limit of the current task +// `exc_return` is the execution state of the current task +// +// Returns the context struct of the next task +__attribute((no_stack_protector, used)) static uint32_t scheduler_pendsv( + uint32_t sp, uint32_t sp_lim, uint32_t exc_return) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + // Save the current task context + systask_t* prev_task = scheduler->active_task; + prev_task->sp = sp; + prev_task->sp_lim = sp_lim; + prev_task->exc_return = exc_return; + prev_task->mpu_mode = mpu_get_mode(); + + // Switch to the next task + scheduler->active_task = scheduler->waiting_task; + + // Load the scheduled task context + systask_t* next_task = scheduler->active_task; + + // Set task privilege level + uint32_t control = __get_CONTROL(); + if (next_task == &scheduler->kernel_task) { + control &= ~CONTROL_nPRIV_Msk; + } else { + control |= CONTROL_nPRIV_Msk; + } + __set_CONTROL(control); + + // Setup the MPU for the new task + mpu_reconfig(next_task->mpu_mode); + + return (uint32_t)next_task; +} + +static void systask_kill(systask_t* task) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + + if (task == &scheduler->kernel_task) { + if (scheduler->error_handler != NULL) { + scheduler->error_handler(&task->pminfo); + } + secure_shutdown(); + } else if (task == scheduler->active_task) { + systask_yield_to(&scheduler->kernel_task); + } else { + // Inactive task + // !@# what to do?? mark it somehow?? + } +} + +void systask_exit(systask_t* task, int exit_code) { + systask_postmortem_t* pminfo = &task->pminfo; + + pminfo->reason = TASK_TERM_REASON_EXIT; + pminfo->exit.code = exit_code; + + systask_kill(task); +} + +void systask_exit_error(systask_t* task, const char* title, const char* message, + const char* footer) { + systask_postmortem_t* pminfo = &task->pminfo; + + pminfo->reason = TASK_TERM_REASON_ERROR; + + strncpy(pminfo->error.title, title, sizeof(pminfo->error.title) - 1); + pminfo->error.title[sizeof(pminfo->error.title) - 1] = '\0'; + + strncpy(pminfo->error.message, message, sizeof(pminfo->error.message) - 1); + pminfo->error.message[sizeof(pminfo->error.message) - 1] = '\0'; + + strncpy(pminfo->error.footer, footer, sizeof(pminfo->error.footer) - 1); + pminfo->error.footer[sizeof(pminfo->error.footer) - 1] = '\0'; + + systask_kill(task); +} + +void systask_exit_fatal(systask_t* task, const char* message, const char* file, + int line) { + systask_postmortem_t* pminfo = &task->pminfo; + + pminfo->reason = TASK_TERM_REASON_FATAL; + + strncpy(pminfo->fatal.file, file, sizeof(pminfo->fatal.file) - 1); + pminfo->fatal.file[sizeof(pminfo->fatal.file) - 1] = '\0'; + + strncpy(pminfo->fatal.expr, message, sizeof(pminfo->fatal.expr) - 1); + pminfo->fatal.expr[sizeof(pminfo->fatal.expr) - 1] = '\0'; + + pminfo->fatal.line = line; + + systask_kill(task); +} + +// Terminate active task from fault/exception handler +static void systask_exit_fault(void) { + systask_scheduler_t* scheduler = &g_systask_scheduler; + systask_t* task = scheduler->active_task; + systask_postmortem_t* pminfo = &task->pminfo; + + pminfo->reason = TASK_TERM_REASON_FAULT; + pminfo->fault.irqn = (__get_IPSR() & IPSR_ISR_Msk) - 16; + pminfo->fault.cfsr = SCB->CFSR; + pminfo->fault.mmfar = SCB->MMFAR; + pminfo->fault.bfar = SCB->BFAR; + pminfo->fault.hfsr = SCB->HFSR; + + systask_kill(task); +} + +__attribute__((naked, no_stack_protector)) void PendSV_Handler(void) { + __asm__ volatile( + "TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP) + +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "ITTEE EQ \n" + "MRSEQ R0, MSP \n" // Get current SP + "MRSEQ R1, MSPLIM \n" // Get current SP Limit + "MRSNE R0, PSP \n" + "MRSNE R1, PSPLIM \n" +#else + "ITE EQ \n" + "MRSEQ R0, MSP \n" // Get current SP + "MRSNE R0, PSP \n" + "MOV R1, #0 \n" // (fake SPLIM) +#endif + + "MOV R2, LR \n" // Get current EXC_RETURN + + "STMDB R0!, {R4-R11} \n" // Save R4-R11 to SP Frame Stack + "TST LR, #0x10 \n" // Check EXC_RETURN.Ftype bit to see if + // the current thread has a FP context + "IT EQ \n" + "VSTMDBEQ R0!, {S16-S31} \n" // If so, save S16-S31 FP addition + // context, that will also trigger lazy + // fp context preservation of S0-S15 + + "BL scheduler_pendsv \n" // Save SP value of current task + "LDR LR, [R0, #8] \n" // Get the EXC_RETURN value + "LDR R1, [R0, #4] \n" // Get the SP_LIM value + "LDR R0, [R0, #0] \n" // Get the SP value + + "TST LR, #0x10 \n" // Check EXC_RETURN.Ftype bit to see if + // the next thread has a FP context + "IT EQ \n" + "VLDMIAEQ R0!, {S16-S31} \n" // If so, restore S16-S31 + "LDMIA R0!, {R4-R11} \n" // Restore R4-R11 + + "TST LR, #0x4 \n" // Check EXC_RETURN to determine which + // SP the next thread is using +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "ITT NE \n" + "MSRNE PSPLIM, R1 \n" // Update the SP Limit and SP since MSP + // won't be changed + "MSRNE PSP, R0 \n" +#else + "IT NE \n" + "MSRNE PSP, R0 \n" // Update the SP Limit and SP since MSP + // won't be changed +#endif + "BX LR \n"); +} + +__attribute__((no_stack_protector, used)) static uint32_t svc_handler( + uint32_t* stack, uint32_t* msp, uint32_t exc_return, uint32_t r4, + uint32_t r5, uint32_t r6) { + uint8_t svc_number = ((uint8_t*)stack[6])[-2]; + uint32_t args[6] = {stack[0], stack[1], stack[2], stack[3], r4, r5}; + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + + switch (svc_number) { +#ifdef SYSTEM_VIEW + case SVC_GET_DWT_CYCCNT: + cyccnt_cycles = *DWT_CYCCNT_ADDR; + break; +#endif + case SVC_SYSTASK_YIELD: + systask_yield_to((systask_t*)args[0]); + break; +#ifdef SYSCALL_DISPATCH + case SVC_SYSCALL: + syscall_handler(args, r6); + stack[0] = args[0]; + stack[1] = args[1]; + break; + case SVC_CALLBACK_RETURN: + // g_return_value = args[0] + // exc_return = return_from_callback; + + mpu_restore(mpu_mode); + return_from_app_callback(args[0], msp); + break; +#endif + default: + break; + } + + mpu_restore(mpu_mode); + return exc_return; +} + +__attribute((naked, no_stack_protector)) void SVC_Handler(void) { + __asm__ volatile( + "TST LR, #0x4 \n" // Called from Process stack pointer? + "ITE EQ \n" + "MRSEQ R0, MSP \n" + "MRSNE R0, PSP \n" + "TST LR, #0x20 \n" + "IT EQ \n" + "ADDEQ R0, R0, #0x40 \n" + "MRS R1, MSP \n" + "MOV R2, LR \n" + "MOV R3, R4 \n" + "PUSH {R5, R6} \n" + "BL svc_handler \n" + "POP {R5, R6} \n" + "BX R0 \n" // Branch to the returned value + ); +} + +void HardFault_Handler(void) { + // A HardFault may also be caused by exception escalation. + // To ensure we have enough space to handle the exception, + // we set the stack pointer to the end of the stack. + extern uint8_t _estack; // linker script symbol + // Fix stack pointer + __set_MSP((uint32_t)&_estack); + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + systask_exit_fault(); + mpu_restore(mpu_mode); +} + +/* + .global MemManage_Handler + .type MemManage_Handler, STT_FUNC +MemManage_Handler: + ldr r2, =_sstack + mrs r1, msp + ldr r0, =_estack + msr msp, r0 + cmp r1, r2 + IT lt + bllt MemManage_Handler_SO + bl MemManage_Handler_MM +*/ + +void MemManage_Handler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + systask_exit_fault(); + mpu_restore(mpu_mode); +} + +void BusFault_Handler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + systask_exit_fault(); + mpu_restore(mpu_mode); +} + +void UsageFault_Handler(void) { +#ifdef STM32U5 + if (SCB->CFSR & SCB_CFSR_STKOF_Msk) { + // Stack overflow + extern uint8_t _estack; // linker script symbol + // Fix stack pointer + __set_MSP((uint32_t)&_estack); + } +#endif + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + systask_exit_fault(); + mpu_restore(mpu_mode); +} + +#ifdef STM32U5 +void SecureFault_Handler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + systask_exit_fault(); + mpu_restore(mpu_mode); +} +#endif + +#ifdef STM32U5 +void GTZC_IRQHandler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + systask_exit_fault(); + mpu_restore(mpu_mode); +} +#endif + +void NMI_Handler(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); +#ifdef STM32U5 + if ((RCC->CIFR & RCC_CIFR_CSSF) != 0) { +#else + if ((RCC->CIR & RCC_CIR_CSSF) != 0) { +#endif + // Clock Security System triggered NMI + systask_exit_fault(); + } + mpu_restore(mpu_mode); +} + +// from util.s +extern void shutdown_privileged(void); + +void PVD_PVM_IRQHandler(void) { + mpu_reconfig(MPU_MODE_DEFAULT); +#ifdef BACKLIGHT_PWM_TIM + // Turn off display backlight + BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = 0; +#endif + shutdown_privileged(); +} + +#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32f4/system.c b/core/embed/trezorhal/stm32f4/system.c new file mode 100644 index 000000000..0bd7e20b1 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/system.c @@ -0,0 +1,254 @@ +/* + * 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 STM32_HAL_H + +#include "system.h" +#include "bootutils.h" +#include "mpu.h" +#include "systask.h" +#include "systick.h" +#include "systimer.h" + +#ifdef KERNEL_MODE + +void system_init(systask_error_handler_t error_handler) { + mpu_init(); + mpu_reconfig(MPU_MODE_DEFAULT); + systask_scheduler_init(error_handler); + systick_init(); + systimer_init(); +} + +void system_exit(int exitcode) { systask_exit(systask_active(), exitcode); } + +void system_exit_error(const char* title, const char* message, + const char* footer) { + systask_exit_error(systask_active(), title, message, footer); +} + +void system_exit_fatal(const char* message, const char* file, int line) { + systask_exit_fatal(systask_active(), message, file, line); +} + +#endif // KERNEL_MODE + +#ifndef HardFault_IRQn +#define HardFault_IRQn (-13) // not defined in stm32lib/cmsis/stm32429xx.h +#endif + +const char* system_fault_message(const system_fault_t* fault) { + switch (fault->irqn) { + case HardFault_IRQn: + return "(HF)"; + case MemoryManagement_IRQn: + return "(MM)"; + case BusFault_IRQn: + return "(BF)"; + case UsageFault_IRQn: +#ifdef STM32U5 + if (fault->cfsr & SCB_CFSR_STKOF_Msk) { + return "(SO)"; + } else { + return "(UF)"; + } +#else + return "(UF)"; +#endif +#ifdef STM32U5 + case SecureFault_IRQn: + return "(SF)"; + case GTZC_IRQn: + return "(IA)"; +#endif + case NonMaskableInt_IRQn: + return "(CS)"; + } + return "(FAULT)"; +} + +// Disable all NVIC interrupts and clear pending flags +// so later the global interrupt can be re-enabled +__attribute__((used)) static void reset_nvic(void) { + // TODO: reset peripherals (at least DMA, DMA2D) + + for (int irqn = 0; irqn < 255; irqn++) { + NVIC_DisableIRQ(irqn); + NVIC_ClearPendingIRQ(irqn); + } + + __enable_irq(); +} + +__attribute((naked, no_stack_protector)) void system_emergency_rescue( + systask_error_handler_t error_handler, const systask_postmortem_t* pminfo) { + extern uint32_t __stack_chk_guard; + + __asm__ volatile( + "MOV R5, R1 \n" // R5 = pminfo + "MOV R6, R0 \n" // R6 = error_handler + + "CPSID I \n" // Disable interrupts + + // -------------------------------------------------------------- + // Disable MPU + // -------------------------------------------------------------- + + "DMB 0xF \n" // Data memory barrier + "LDR R0, =0xE000ED94 \n" // MPU->CTRL + "MOV R1, #0 \n" + "STR R1, [R0] \n" // Disable MPU + + // -------------------------------------------------------------- + // Disable SysTick + // -------------------------------------------------------------- + + "LDR R0, =0xE000E010 \n" // SysTick->CTRL + "MOV R1, #0 \n" + "STR R1, [R0] \n" // Disable SysTick + + // -------------------------------------------------------------- + // Setup new stack + // -------------------------------------------------------------- + + "LDR R0, =_estack \n" // Setup new stack + "MSR MSP, R0 \n" // Set MSP +#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) + "LDR R0, =_sstack \n" + "ADD R0, R0, #256 \n" // Add safety margin + "MSR MSPLIM, R0 \n" // Set MSPLIM +#endif + + // -------------------------------------------------------------- + // Copy pminfo to new stack + // -------------------------------------------------------------- + + "LDR R2, =%[PMINFO_SIZE] \n" // Copy pminfo to new stack + "SUB SP, R2 \n" // Allocate space for pminfo + "MOV R0, SP \n" // Destination + "MOV R1, R5 \n" + "MOV R5, R0 \n" // R5 = pminfo on new stack + "BL memcpy \n" + + // -------------------------------------------------------------- + // Save stack protector guard + // -------------------------------------------------------------- + + "LDR R0, =%[STK_GUARD] \n" // Save stack protector guard + "LDR R7, [R0] \n" // R7 = __stack_chk_guard + + // -------------------------------------------------------------- + // Clear .bss, initialize .data, ... + // -------------------------------------------------------------- + + "LDR R0, =bss_start \n" // Clear .bss + "MOV R1, #0 \n" + "LDR R2, =bss_end \n" + "SUB R2, R2, R0 \n" + "BL memset \n" + + "LDR R0, =data_vma \n" // Initialize .data + "LDR R1, =data_lma \n" + "LDR R2, =data_size \n" + "BL memcpy \n" + +#ifdef STM32U5 + "LDR R0, =confidential_vma \n" // Initialize .confidental + "LDR R1, =confidential_lma \n" + "LDR R2, =confidential_size \n" + "BL memcpy \n" +#endif + + // -------------------------------------------------------------- + // Restore stack protector guard + // -------------------------------------------------------------- + + "LDR R0, =%[STK_GUARD] \n" // Restore stack protector guard + "STR R7, [R0] \n" + + // -------------------------------------------------------------- + // Disable NVIC interrupts and clear pending flags + // -------------------------------------------------------------- + + "BL reset_nvic \n" // Disable all NVIC interrupts + "CPSIE I \n" // Re-enable interrupts + + // -------------------------------------------------------------- + // Check if we are in thread mode and if yes, jump to error_handler + // -------------------------------------------------------------- + + "LDR R1, =0x1FF \n" // Get lower 9 bits of IPSR + "MRS R0, IPSR \n" + "ANDS R0, R0, R1 \n" + "CMP R0, #0 \n" // == 0 if in thread mode + "ITTT EQ \n" + "MOVEQ R0, R5 \n" // R0 = pminfo + "LDREQ LR, =reboot \n" + "BXEQ R6 \n" // jump to error_handler directly + + // -------------------------------------------------------------- + // Return from exception to thread mode + // -------------------------------------------------------------- + + "SUB SP, SP, #32 \n" // Allocate space for exception frame + + "MOV R0, #0 \n" + "STR R5, [SP, #0] \n" // future R0 = pminfo + "STR R0, [SP, #4] \n" // future R1 = 0 + "STR R0, [SP, #8] \n" // future R2 = 0 + "STR R0, [SP, #12] \n" // future R3 = 0 + "STR R0, [SP, #16] \n" // future R12 = 0 + "LDR R1, =reboot \n" + "STR R0, [SP, #20] \n" // future LR = reboot() + "BIC R6, R6, #1 \n" + "STR R6, [SP, #24] \n" // return address = error_handler() + "LDR R1, = 0x01000000 \n" // THUMB bit set + "STR R1, [SP, #28] \n" // future xPSR + + "MOV R4, R0 \n" // Clear registers R4-R11 + "MOV R5, R0 \n" + "MOV R6, R0 \n" + "MOV R7, R0 \n" + "MOV R8, R0 \n" + "MOV R9, R0 \n" + "MOV R10, R0 \n" + "MOV R11, R0 \n" + + "MRS R0, CONTROL \n" + "BIC R0, R0, #4 \n" // Clear FPCA to suppress lazy stacking + // to avoid potential stack overwrite. + "BIC R0, R0, #2 \n" // Clear SPSEL to use MSP for thread + // mode + "BIC R0, R0, #1 \n" // Clear nPRIV to run in privileged mode + "MSR CONTROL, R1 \n" + + "LDR R1, = 0xE000EF34 \n" // FPU->FPPCCR + "LDR R0, [R1] \n" + "BIC R0, R0, #1 \n" // Clear LSPACT to suppress lazy + // stacking to + "STR R0, [R1] \n" // avoid potential stack overwrite. + + "LDR LR, = 0xFFFFFFF9 \n" // Return to Secure Thread mode, use MSP + "BX LR \n" + : // no output + : [PMINFO_SIZE] "i"(sizeof(systask_postmortem_t)), + [STK_GUARD] "i"(&__stack_chk_guard) + : // no clobber + ); +} diff --git a/core/embed/trezorhal/stm32f4/util.S b/core/embed/trezorhal/stm32f4/util.S index defc3c70f..94eae168a 100644 --- a/core/embed/trezorhal/stm32f4/util.S +++ b/core/embed/trezorhal/stm32f4/util.S @@ -112,16 +112,4 @@ shutdown_privileged: ldr r0, =0 b . // loop forever - .global MemManage_Handler - .type MemManage_Handler, STT_FUNC -MemManage_Handler: - ldr r2, =_sstack - mrs r1, msp - ldr r0, =_estack - msr msp, r0 - cmp r1, r2 - IT lt - bllt MemManage_Handler_SO - bl MemManage_Handler_MM - .end diff --git a/core/embed/trezorhal/stm32f4/vectortable.S b/core/embed/trezorhal/stm32f4/vectortable.S index 1cfec8c26..2f07d34fd 100644 --- a/core/embed/trezorhal/stm32f4/vectortable.S +++ b/core/embed/trezorhal/stm32f4/vectortable.S @@ -132,7 +132,8 @@ vector_table: .section .vector_table, "a" vector_table: - .word main_stack_base // defined in linker script + .word _sstack + .word _stack_size .word reset_handler diff --git a/core/embed/trezorhal/stm32u5/applet.c b/core/embed/trezorhal/stm32u5/applet.c new file mode 120000 index 000000000..0cdabf36a --- /dev/null +++ b/core/embed/trezorhal/stm32u5/applet.c @@ -0,0 +1 @@ +../stm32f4/applet.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/fault_handlers.c b/core/embed/trezorhal/stm32u5/fault_handlers.c deleted file mode 100644 index 2e4bbc78f..000000000 --- a/core/embed/trezorhal/stm32u5/fault_handlers.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "common.h" -#include "mpu.h" - -#ifdef KERNEL_MODE - -void fault_handlers_init(void) { - // Enable BUS fault and USAGE fault handlers - SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk); -} - -void HardFault_Handler(void) { - // A HardFault may also be caused by exception escalation. - // To ensure we have enough space to handle the exception, - // we set the stack pointer to the end of the stack. - extern uint8_t _estack; // linker script symbol - // Fix stack pointer - __set_MSP((uint32_t)&_estack); - - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(HF)"); -} - -void MemManage_Handler(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(MM)"); -} - -void BusFault_Handler(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(BF)"); -} - -void UsageFault_Handler(void) { - if (SCB->CFSR & SCB_CFSR_STKOF_Msk) { - // Stack overflow - extern uint8_t _estack; // linker script symbol - // Fix stack pointer - __set_MSP((uint32_t)&_estack); - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(SO)"); - } else { - // Other error - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(UF)"); - } -} - -void SecureFault_Handler(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(SF)"); -} - -void GTZC_IRQHandler(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - error_shutdown("(IA)"); -} - -void NMI_Handler(void) { - mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); - // Clock Security System triggered NMI - if ((RCC->CIFR & RCC_CIFR_CSSF) != 0) { - error_shutdown("(CS)"); - } - mpu_restore(mpu_mode); -} - -// from util.s -extern void shutdown_privileged(void); - -void PVD_PVM_IRQHandler(void) { - mpu_reconfig(MPU_MODE_DEFAULT); - TIM1->CCR1 = 0; // turn off display backlight - shutdown_privileged(); -} - -#endif // KERNEL_MODE diff --git a/core/embed/trezorhal/stm32u5/systask.c b/core/embed/trezorhal/stm32u5/systask.c new file mode 120000 index 000000000..7b6c139ae --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systask.c @@ -0,0 +1 @@ +../stm32f4/systask.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/system.c b/core/embed/trezorhal/stm32u5/system.c new file mode 120000 index 000000000..36a84d685 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/system.c @@ -0,0 +1 @@ +../stm32f4/system.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/vectortable.S b/core/embed/trezorhal/stm32u5/vectortable.S index 472414cae..d4f79d195 100644 --- a/core/embed/trezorhal/stm32u5/vectortable.S +++ b/core/embed/trezorhal/stm32u5/vectortable.S @@ -180,7 +180,8 @@ vector_table: .section .vector_table, "a" vector_table: - .word main_stack_base // defined in linker script + .word _sstack + .word _stack_size .word reset_handler #endif diff --git a/core/embed/trezorhal/systask.h b/core/embed/trezorhal/systask.h new file mode 100644 index 000000000..1c609a975 --- /dev/null +++ b/core/embed/trezorhal/systask.h @@ -0,0 +1,163 @@ +/* + * 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 . + */ + +#ifndef TREZORHAL_SYSTASK_H +#define TREZORHAL_SYSTASK_H + +#include +#include + +#include "mpu.h" + +// Termination reason for the task +typedef enum { + TASK_TERM_REASON_EXIT, + TASK_TERM_REASON_ERROR, + TASK_TERM_REASON_FATAL, + TASK_TERM_REASON_FAULT, + +} systask_term_reason_t; + +typedef struct { + // Fault/exception number (-15..-1) + int irqn; + // Configurable Fault Status Register + // (combined UFSR/BFSR/MMFSR) + uint32_t cfsr; + // Hard Fault Status Register + uint32_t hfsr; + // Address associated with MemManage fault + uint32_t mmfar; + // Address associated with the BusFault + uint32_t bfar; + +} system_fault_t; + +// Task post-mortem information +typedef struct { + systask_term_reason_t reason; + + union { + // Argument passed to `systask_exit()` + struct { + int code; + } exit; + + // Fault information catched in `systask_exit_fault()` + system_fault_t fault; + + // Arguments passed to `systask_exit_fatal()` + struct { + uint32_t line; + char file[64]; + char expr[64]; + } fatal; + + // Arguments passed to `systask_exit_error()` + struct { + char title[64]; + char message[64]; + char footer[64]; + } error; + }; + +} systask_postmortem_t; + +// Error handler callback invoke when kernel task terminates. +// +// The purpose of this callbacks display RSOD (Red Screen of Death). +// +// The callback may be called from any context, including interrupt context. +typedef void (*systask_error_handler_t)(const systask_postmortem_t* pminfo); + +#ifdef KERNEL_MODE + +// Task context used by the kernel to save the state of each task +// when switching between them +typedef struct { + // sp, sp_lim, exc_return should at the beginning + // and in this order to be compatible with the PendSV_Handler + // Stack pointer value + uint32_t sp; + // Stack pointer limit (ARMv8-M only) + uint32_t sp_lim; + // Exception return value + uint32_t exc_return; + // MPU mode the task is running in + mpu_mode_t mpu_mode; + // Task post-mortem information + systask_postmortem_t pminfo; + +} systask_t; + +// Initializes the scheduler for tasks +// +// No other task functions should be called before this function +void systask_scheduler_init(systask_error_handler_t error_handler); + +// Returns the currently running task +systask_t* systask_active(void); + +// Makes the given task the currently running task +void systask_yield_to(systask_t* task); + +// Initializes a task with the given stack pointer, stack size +// +// The task must be not be running when the function is called +void systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size); + +// Pushes data onto the stack of the task +// +// The task must be not be running when the function is called +uint32_t* systask_push_data(systask_t* task, const void* data, size_t size); + +// Pops data from the stack of the task +// +// The task must be not be running when the function is called +void systask_pop_data(systask_t* task, size_t size); + +// Runs the task with the given entrypoint and arguments +// +// The task must be not be running when the function is called +void systask_push_call(systask_t* task, void* fn, uint32_t arg1, uint32_t arg2, + uint32_t arg3); + +// Terminates the current task with the given exit code +// +// If the terminated task is the currently running task, the kernel task +// will be scheduled next +void systask_exit(systask_t* task, int exit_code); + +// Terminates the current task with an error message +// +// If the terminated task is the currently running task, the kernel task +// will be scheduled next +void systask_exit_error(systask_t* task, const char* title, const char* message, + const char* footer); + +// Terminates the current task with a fatal error message +// +// If the terminated task is the currently running task, the kernel task +// will be scheduled next +void systask_exit_fatal(systask_t* task, const char* message, const char* file, + int line); + +#endif // KERNEL_MODE + +#endif // TREZORHAL_SYSTASK_H diff --git a/core/embed/trezorhal/system.h b/core/embed/trezorhal/system.h new file mode 100644 index 000000000..1da4cc8ea --- /dev/null +++ b/core/embed/trezorhal/system.h @@ -0,0 +1,60 @@ +/* + * 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 . + */ + +#ifndef TREZORHAL_SYSTEM_H +#define TREZORHAL_SYSTEM_H + +#include + +// Initializes the fundamental system services +// (mpu, systick, systimer and task scheduler) +// +// `error_handler` is a callback that is called when a kernel task terminates +// with an error +void system_init(systask_error_handler_t error_handler); + +// Terminates the current app normally with the given exit code +void system_exit(int exitcode); + +// Terminates the current app with an error message +void system_exit_error(const char* title, const char* message, + const char* footer); + +// Terminates the current app with a fatal error message +void system_exit_fatal(const char* message, const char* file, int line); + +// Returns string representation of the system fault +const char* system_fault_message(const system_fault_t* fault); + +// Calls the error handler in the emergency mode +// +// This function is called when the system encounters a critical error +// and needs to perform a useful action (such as displaying an error message) +// before it is reset or shut down. +// +// The function may be called from any context, including interrupt context. +// It completely resets stack pointers, clears the .bss segment, reinitializes +// the .data segment, and calls the `error_handler` callback. +// +// The system will be in a state similar to a reset when `main()` is called +// (but with some hardware peripherals still initialized and running). +__attribute__((noreturn)) void system_emergency_rescue( + systask_error_handler_t error_handler, const systask_postmortem_t* pminfo); + +#endif // TREZORHAL_SYSTEM_H diff --git a/core/embed/trezorhal/unix/system.c b/core/embed/trezorhal/unix/system.c new file mode 100644 index 000000000..66cd19394 --- /dev/null +++ b/core/embed/trezorhal/unix/system.c @@ -0,0 +1,112 @@ +/* + * 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 +#include + +#include "bootutils.h" +#include "system.h" +#include "systick.h" +#include "systimer.h" + +systask_error_handler_t g_error_handler = NULL; + +void system_init(systask_error_handler_t error_handler) { + g_error_handler = error_handler; + systick_init(); + systimer_init(); +} + +void system_exit(int exitcode) { + if (g_error_handler != NULL) { + systask_postmortem_t pminfo = {0}; + + pminfo.reason = TASK_TERM_REASON_EXIT; + pminfo.exit.code = exitcode; + + g_error_handler(&pminfo); + } + + secure_shutdown(); +} + +void system_exit_error(const char* title, const char* message, + const char* footer) { + fprintf(stderr, "ERROR: %s\n", message); + fflush(stderr); + + if (g_error_handler != NULL) { + systask_postmortem_t pminfo = {0}; + + pminfo.reason = TASK_TERM_REASON_ERROR; + + strncpy(pminfo.error.title, title, sizeof(pminfo.error.title) - 1); + pminfo.error.title[sizeof(pminfo.error.title) - 1] = '\0'; + + strncpy(pminfo.error.message, message, sizeof(pminfo.error.message) - 1); + pminfo.error.message[sizeof(pminfo.error.message) - 1] = '\0'; + + strncpy(pminfo.error.footer, footer, sizeof(pminfo.error.footer) - 1); + pminfo.error.footer[sizeof(pminfo.error.footer) - 1] = '\0'; + + g_error_handler(&pminfo); + } + + secure_shutdown(); +} + +void system_exit_fatal(const char* message, const char* file, int line) { + fprintf(stderr, "ERROR: %s\n", message); + if (file) { + fprintf(stderr, "FILE: %s:%d\n", file, line); + } + fflush(stderr); + + if (g_error_handler != NULL) { + systask_postmortem_t pminfo = {0}; + + pminfo.reason = TASK_TERM_REASON_FATAL; + + strncpy(pminfo.fatal.file, file, sizeof(pminfo.fatal.file) - 1); + pminfo.fatal.file[sizeof(pminfo.fatal.file) - 1] = '\0'; + + strncpy(pminfo.fatal.expr, message, sizeof(pminfo.fatal.expr) - 1); + pminfo.fatal.expr[sizeof(pminfo.fatal.expr) - 1] = '\0'; + + pminfo.fatal.line = line; + + g_error_handler(&pminfo); + } + + secure_shutdown(); +} + +const char* system_fault_message(const system_fault_t* fault) { + // Not used in simulator + return "(FAULT)"; +} + +void system_emergency_rescue(systask_error_handler_t error_handler, + const systask_postmortem_t* pminfo) { + error_handler(pminfo); + + // We should never reach this point + exit(0); +} diff --git a/core/site_scons/models/stm32f4_common.py b/core/site_scons/models/stm32f4_common.py index c38b12e01..715b3fea2 100644 --- a/core/site_scons/models/stm32f4_common.py +++ b/core/site_scons/models/stm32f4_common.py @@ -40,11 +40,11 @@ def stm32f4_common_files(env, defines, sources, paths): ] sources += [ + "embed/trezorhal/stm32f4/applet.c", "embed/trezorhal/stm32f4/board_capabilities.c", "embed/trezorhal/stm32f4/bootutils.c", "embed/trezorhal/stm32f4/common.c", "embed/trezorhal/stm32f4/entropy.c", - "embed/trezorhal/stm32f4/fault_handlers.c", "embed/trezorhal/stm32f4/flash.c", "embed/trezorhal/stm32f4/flash_otp.c", "embed/trezorhal/stm32f4/fwutils.c", @@ -56,11 +56,14 @@ def stm32f4_common_files(env, defines, sources, paths): "embed/trezorhal/stm32f4/syscall.c", "embed/trezorhal/stm32f4/syscall_dispatch.c", "embed/trezorhal/stm32f4/syscall_stubs.c", + "embed/trezorhal/stm32f4/system.c", + "embed/trezorhal/stm32f4/systask.c", "embed/trezorhal/stm32f4/systick.c", "embed/trezorhal/stm32f4/systimer.c", "embed/trezorhal/stm32f4/time_estimate.c", "embed/trezorhal/stm32f4/random_delays.c", "embed/trezorhal/stm32f4/rng.c", + "embed/trezorhal/stm32f4/vectortable.S", ] diff --git a/core/site_scons/models/stm32u5_common.py b/core/site_scons/models/stm32u5_common.py index 0eea378cf..c62c066fe 100644 --- a/core/site_scons/models/stm32u5_common.py +++ b/core/site_scons/models/stm32u5_common.py @@ -49,11 +49,11 @@ def stm32u5_common_files(env, defines, sources, paths): ] sources += [ + "embed/trezorhal/stm32u5/applet.c", "embed/trezorhal/stm32u5/board_capabilities.c", "embed/trezorhal/stm32u5/bootutils.c", "embed/trezorhal/stm32u5/common.c", "embed/trezorhal/stm32u5/entropy.c", - "embed/trezorhal/stm32u5/fault_handlers.c", "embed/trezorhal/stm32u5/flash.c", "embed/trezorhal/stm32u5/flash_otp.c", "embed/trezorhal/stm32u5/fwutils.c", @@ -67,6 +67,8 @@ def stm32u5_common_files(env, defines, sources, paths): "embed/trezorhal/stm32u5/syscall.c", "embed/trezorhal/stm32u5/syscall_dispatch.c", "embed/trezorhal/stm32u5/syscall_stubs.c", + "embed/trezorhal/stm32u5/system.c", + "embed/trezorhal/stm32u5/systask.c", "embed/trezorhal/stm32u5/systick.c", "embed/trezorhal/stm32u5/systimer.c", "embed/trezorhal/stm32u5/random_delays.c", diff --git a/vendor/fido2-tests b/vendor/fido2-tests index b9deb14b9..9cfd22ef2 160000 --- a/vendor/fido2-tests +++ b/vendor/fido2-tests @@ -1 +1 @@ -Subproject commit b9deb14b9e38cffa31b6d9a880c5e0d6855ef6ce +Subproject commit 9cfd22ef20fec2c34d0f0e5c16a5d5152da30861