diff --git a/core/embed/projects/bootloader/main.c b/core/embed/projects/bootloader/main.c index e2df8e6f11..a398799f92 100644 --- a/core/embed/projects/bootloader/main.c +++ b/core/embed/projects/bootloader/main.c @@ -390,6 +390,16 @@ int bootloader_main(void) { drivers_init(manufacturing_mode, &touch_initialized); +#ifdef USE_BOOTARGS_RSOD + if (bootargs_get_command() == BOOT_COMMAND_SHOW_RSOD) { + // post mortem info was left in bootargs + boot_args_t args; + bootargs_get_args(&args); + rsod_gui(&args.pminfo); + reboot_or_halt_after_rsod(); + } +#endif // USE_BOOTARGS_RSOD + ui_screen_boot_stage_1(false); #ifdef TREZOR_EMULATOR diff --git a/core/embed/projects/bootloader_ci/main.c b/core/embed/projects/bootloader_ci/main.c index 634ee0864a..6e27af826f 100644 --- a/core/embed/projects/bootloader_ci/main.c +++ b/core/embed/projects/bootloader_ci/main.c @@ -194,6 +194,16 @@ int main(void) { drivers_init(); +#ifdef USE_BOOTARGS_RSOD + if (bootargs_get_command() == BOOT_COMMAND_SHOW_RSOD) { + // post mortem info was left in bootargs + boot_args_t args; + bootargs_get_args(&args); + rsod_terminal(&args.pminfo); + reboot_or_halt_after_rsod(); + } +#endif // USE_BOOTARGS_RSOD + #if PRODUCTION && !defined STM32U5 // for STM32U5, this check is moved to boardloader ensure_bootloader_min_version(); diff --git a/core/embed/projects/kernel/main.c b/core/embed/projects/kernel/main.c index a83685092e..9da58f0637 100644 --- a/core/embed/projects/kernel/main.c +++ b/core/embed/projects/kernel/main.c @@ -238,6 +238,8 @@ static void coreapp_init(applet_t *applet) { applet_init(applet, coreapp_header, &coreapp_layout, &coreapp_privileges); } +#ifndef USE_BOOTARGS_RSOD + // Shows RSOD (Red Screen of Death) static void show_rsod(const systask_postmortem_t *pminfo) { #ifdef RSOD_IN_COREAPP @@ -281,13 +283,19 @@ static void init_and_show_rsod(const systask_postmortem_t *pminfo) { reboot_or_halt_after_rsod(); } +#endif // USE_BOOTARGS_RSOD + // 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. +#ifndef USE_BOOTARGS_RSOD system_emergency_rescue(&init_and_show_rsod, pminfo); - // The previous function call never returns +#else + reboot_with_rsod(pminfo); +#endif // USE_BOOTARGS_RSOD + // We never get here } int main(void) { @@ -318,11 +326,14 @@ int main(void) { // Release the coreapp resources applet_stop(&coreapp); +#ifndef USE_BOOTARGS_RSOD // Coreapp crashed, show RSOD show_rsod(&coreapp.task.pminfo); - // Reboots or halts (if RSOD_INFINITE_LOOP is defined) reboot_or_halt_after_rsod(); +#else + reboot_with_rsod(&coreapp.task.pminfo); +#endif // USE_BOOTARGS_RSOD return 0; } diff --git a/core/embed/sys/startup/inc/sys/bootargs.h b/core/embed/sys/startup/inc/sys/bootargs.h index dbdf3015af..e24174a59a 100644 --- a/core/embed/sys/startup/inc/sys/bootargs.h +++ b/core/embed/sys/startup/inc/sys/bootargs.h @@ -69,10 +69,4 @@ boot_command_t bootargs_get_command(); // Copies the boot arguments to the destination buffer void bootargs_get_args(boot_args_t* dest); -// Returns a pointer to the boot arguments structure. -// -// This function is intended to be used only in rescue mode, when the MPU -// is disabled and the caller has full access to the boot arguments area. -boot_args_t* bootargs_ptr(void); - #endif // TREZORHAL_BOOTARGS_H diff --git a/core/embed/sys/startup/inc/sys/bootutils.h b/core/embed/sys/startup/inc/sys/bootutils.h index 5fc0423e57..b3a41513f2 100644 --- a/core/embed/sys/startup/inc/sys/bootutils.h +++ b/core/embed/sys/startup/inc/sys/bootutils.h @@ -17,10 +17,9 @@ * along with this program. If not, see . */ -#ifndef TREZORHAL_BOOTUTILS_H -#define TREZORHAL_BOOTUTILS_H +#pragma once -#include +#include // Immediately resets the device and initiates the normal boot sequence as if // the device was powered on @@ -42,6 +41,13 @@ void __attribute__((noreturn)) reboot_to_bootloader(void); // with the firmware installation. void __attribute__((noreturn)) reboot_and_upgrade(const uint8_t hash[32]); +#ifdef USE_BOOTARGS_RSOD +// Resets the device with post-mortem information in bootargs +// so that the bootloader can display it. +void __attribute__((noreturn)) +reboot_with_rsod(const systask_postmortem_t *pminfo); +#endif + // Allows the user to read the displayed error message and then // reboots the device or waits for power-off. // @@ -57,5 +63,3 @@ void __attribute__((noreturn)) reboot_or_halt_after_rsod(void); // Before jumping, the function disables all interrupts and clears the // memory and registers that could contain sensitive information. void __attribute__((noreturn)) jump_to_next_stage(uint32_t vectbl_address); - -#endif // TREZORHAL_BOOTUTILS_H diff --git a/core/embed/sys/startup/stm32/bootutils.c b/core/embed/sys/startup/stm32/bootutils.c index 2877de7c54..d2727672ce 100644 --- a/core/embed/sys/startup/stm32/bootutils.c +++ b/core/embed/sys/startup/stm32/bootutils.c @@ -79,14 +79,6 @@ void bootargs_set(boot_command_t command, const void* args, size_t args_size) { mpu_restore(mode); } -boot_args_t* bootargs_ptr(void) { return &g_boot_args; } - -#ifdef BOOTLOADER -// Contains the current boot command saved during bootloader startup. -boot_command_t g_boot_command_saved; - -boot_command_t bootargs_get_command() { return g_boot_command_saved; } - void bootargs_get_args(boot_args_t* dest) { mpu_mode_t mode = mpu_reconfig(MPU_MODE_BOOTARGS); @@ -95,6 +87,12 @@ void bootargs_get_args(boot_args_t* dest) { mpu_restore(mode); } +#ifdef BOOTLOADER +// Contains the current boot command saved during bootloader startup. +boot_command_t g_boot_command_saved; + +boot_command_t bootargs_get_command() { return g_boot_command_saved; } + void bootargs_init(uint32_t r11_register) { #ifdef STM32U5 g_boot_command_saved = g_boot_command; @@ -220,6 +218,12 @@ __attribute__((noreturn)) void reboot_to_off(void) { reboot_with_args(BOOT_COMMAND_POWER_OFF, NULL, 0); } +__attribute__((noreturn)) void reboot_with_rsod( + const systask_postmortem_t* pminfo) { + // Set bootargs area to the new command and arguments + reboot_with_args(BOOT_COMMAND_SHOW_RSOD, pminfo, sizeof(*pminfo)); +} + __attribute__((noreturn)) void reboot_or_halt_after_rsod(void) { #ifndef RSOD_INFINITE_LOOP systick_delay_ms(10 * 1000); diff --git a/core/embed/sys/task/inc/sys/system.h b/core/embed/sys/task/inc/sys/system.h index c36b968fb2..f8921f0b99 100644 --- a/core/embed/sys/task/inc/sys/system.h +++ b/core/embed/sys/task/inc/sys/system.h @@ -47,6 +47,11 @@ void system_deinit(void); // // The system will be in a state similar to a reset when `main()` is called // (but with some hardware peripherals still initialized and running). +// +// If `error_handler` is NULL the system will be reset immediately after +// clearing the memory. If `USE_BOOTARGS_RSOD` is defined, the system will +// leave the postmortem information in the bootargs allowing the bootloader +// to display the RSOD. __attribute__((noreturn)) void system_emergency_rescue( systask_error_handler_t error_handler, const systask_postmortem_t* pminfo); diff --git a/core/embed/sys/task/stm32/system.c b/core/embed/sys/task/stm32/system.c index d484524dfb..92bb383dde 100644 --- a/core/embed/sys/task/stm32/system.c +++ b/core/embed/sys/task/stm32/system.c @@ -85,9 +85,12 @@ system_emergency_rescue_phase_2(uint32_t arg1, uint32_t arg2) { // Reset peripherals (so we are sure that no DMA is pending) reset_peripherals_and_interrupts(); - // Copy pminfo from to our stack - // MPU is now disable, we have full access to bootargs. - systask_postmortem_t pminfo = bootargs_ptr()->pminfo; + // Althought MPU is disabled, we need to change MPU driver state + mpu_reconfig(MPU_MODE_DISABLED); + + // Copy bootargs to our stack + boot_args_t bootargs; + bootargs_get_args(&bootargs); // Clear unused part of our stack clear_unused_stack(); @@ -97,10 +100,13 @@ system_emergency_rescue_phase_2(uint32_t arg1, uint32_t arg2) { uint32_t stack_chk_guard = __stack_chk_guard; // Clear all memory except our stack. - // NOTE: This also clear bootargs, so we don't pass pminfo structure - // to the bootloader for now. + // NOTE: This also clear bootargs, if the model doesn't support + // showing RSOD in the bootloader startup. memregion_t region = MEMREGION_ALL_ACCESSIBLE_RAM; MEMREGION_DEL_SECTION(®ion, _stack_section); +#ifdef USE_BOOTARGS_RSOD + MEMREGION_DEL_SECTION(®ion, _bootargs_ram); +#endif memregion_fill(®ion, 0); // Reinitialize .bss, .data, ... @@ -119,12 +125,16 @@ system_emergency_rescue_phase_2(uint32_t arg1, uint32_t arg2) { // in C code if (error_handler != NULL) { - error_handler(&pminfo); + error_handler(&bootargs.pminfo); + // We reach this point only if error_handler returns that's + // not expected to happen. We clear the memory again and reboot. + reboot_device(); } - // We reach this point only if error_handler is NULL or - // if it returns. Neither is expected to happen. - reboot_device(); + // We reach this point only if error_handler is NULL + // (if USE_BOOTARGS_RSOD is defined we leave postmortem info + // in bootargs, so it can be used by the bootloader) + NVIC_SystemReset(); } __attribute((naked, noreturn, no_stack_protector)) void system_emergency_rescue( diff --git a/core/embed/sys/task/unix/system.c b/core/embed/sys/task/unix/system.c index 61f52a0e35..6917931065 100644 --- a/core/embed/sys/task/unix/system.c +++ b/core/embed/sys/task/unix/system.c @@ -139,7 +139,9 @@ const char* system_fault_message(const system_fault_t* fault) { void system_emergency_rescue(systask_error_handler_t error_handler, const systask_postmortem_t* pminfo) { - error_handler(pminfo); + if (error_handler != NULL) { + error_handler(pminfo); + } // We should never reach this point reboot_device(); diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revA.py b/core/site_scons/models/T3W1/trezor_t3w1_revA.py index b87944f8f5..8cb7b83169 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revA.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revA.py @@ -39,6 +39,7 @@ def configure( ("USE_LSE", "1"), ("FIXED_HW_DEINIT", "1"), ("LOCKABLE_BOOTLOADER", "1"), + ("USE_BOOTARGS_RSOD", "1"), ("TERMINAL_FONT_SCALE", "2"), ("TERMINAL_X_PADDING", "4"), ("TERMINAL_Y_PADDING", "12"), diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py index 5bf3f07dc5..7944d5fd35 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py @@ -39,6 +39,7 @@ def configure( ("USE_LSE", "1"), ("FIXED_HW_DEINIT", "1"), ("LOCKABLE_BOOTLOADER", "1"), + ("USE_BOOTARGS_RSOD", "1"), ("TERMINAL_FONT_SCALE", "2"), ("TERMINAL_X_PADDING", "4"), ("TERMINAL_Y_PADDING", "12"), diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revC.py b/core/site_scons/models/T3W1/trezor_t3w1_revC.py index db3d5ded7d..b5bef1faab 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revC.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revC.py @@ -39,6 +39,7 @@ def configure( ("USE_LSE", "1"), ("FIXED_HW_DEINIT", "1"), ("LOCKABLE_BOOTLOADER", "1"), + ("USE_BOOTARGS_RSOD", "1"), ("TERMINAL_FONT_SCALE", "2"), ("TERMINAL_X_PADDING", "4"), ("TERMINAL_Y_PADDING", "12"),