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"),