1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-04 13:52:35 +00:00

feat(core): allow passing postmortem info in bootargs

[no changelog]
This commit is contained in:
cepetr 2025-05-09 10:25:13 +02:00 committed by cepetr
parent cafed0d02b
commit 1a372b5019
12 changed files with 84 additions and 31 deletions

View File

@ -390,6 +390,16 @@ int bootloader_main(void) {
drivers_init(manufacturing_mode, &touch_initialized); 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); ui_screen_boot_stage_1(false);
#ifdef TREZOR_EMULATOR #ifdef TREZOR_EMULATOR

View File

@ -194,6 +194,16 @@ int main(void) {
drivers_init(); 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 #if PRODUCTION && !defined STM32U5
// for STM32U5, this check is moved to boardloader // for STM32U5, this check is moved to boardloader
ensure_bootloader_min_version(); ensure_bootloader_min_version();

View File

@ -238,6 +238,8 @@ static void coreapp_init(applet_t *applet) {
applet_init(applet, coreapp_header, &coreapp_layout, &coreapp_privileges); applet_init(applet, coreapp_header, &coreapp_layout, &coreapp_privileges);
} }
#ifndef USE_BOOTARGS_RSOD
// Shows RSOD (Red Screen of Death) // Shows RSOD (Red Screen of Death)
static void show_rsod(const systask_postmortem_t *pminfo) { static void show_rsod(const systask_postmortem_t *pminfo) {
#ifdef RSOD_IN_COREAPP #ifdef RSOD_IN_COREAPP
@ -281,13 +283,19 @@ static void init_and_show_rsod(const systask_postmortem_t *pminfo) {
reboot_or_halt_after_rsod(); reboot_or_halt_after_rsod();
} }
#endif // USE_BOOTARGS_RSOD
// Kernel panic handler // Kernel panic handler
// (may be called from interrupt context) // (may be called from interrupt context)
static void kernel_panic(const systask_postmortem_t *pminfo) { static void kernel_panic(const systask_postmortem_t *pminfo) {
// Since the system state is unreliable, enter emergency mode // Since the system state is unreliable, enter emergency mode
// and show the RSOD. // and show the RSOD.
#ifndef USE_BOOTARGS_RSOD
system_emergency_rescue(&init_and_show_rsod, pminfo); 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) { int main(void) {
@ -318,11 +326,14 @@ int main(void) {
// Release the coreapp resources // Release the coreapp resources
applet_stop(&coreapp); applet_stop(&coreapp);
#ifndef USE_BOOTARGS_RSOD
// Coreapp crashed, show RSOD // Coreapp crashed, show RSOD
show_rsod(&coreapp.task.pminfo); show_rsod(&coreapp.task.pminfo);
// Reboots or halts (if RSOD_INFINITE_LOOP is defined) // Reboots or halts (if RSOD_INFINITE_LOOP is defined)
reboot_or_halt_after_rsod(); reboot_or_halt_after_rsod();
#else
reboot_with_rsod(&coreapp.task.pminfo);
#endif // USE_BOOTARGS_RSOD
return 0; return 0;
} }

View File

@ -69,10 +69,4 @@ boot_command_t bootargs_get_command();
// Copies the boot arguments to the destination buffer // Copies the boot arguments to the destination buffer
void bootargs_get_args(boot_args_t* dest); 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 #endif // TREZORHAL_BOOTARGS_H

View File

@ -17,10 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef TREZORHAL_BOOTUTILS_H #pragma once
#define TREZORHAL_BOOTUTILS_H
#include <trezor_types.h> #include <sys/systask.h>
// Immediately resets the device and initiates the normal boot sequence as if // Immediately resets the device and initiates the normal boot sequence as if
// the device was powered on // the device was powered on
@ -42,6 +41,13 @@ void __attribute__((noreturn)) reboot_to_bootloader(void);
// with the firmware installation. // with the firmware installation.
void __attribute__((noreturn)) reboot_and_upgrade(const uint8_t hash[32]); 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 // Allows the user to read the displayed error message and then
// reboots the device or waits for power-off. // 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 // Before jumping, the function disables all interrupts and clears the
// memory and registers that could contain sensitive information. // memory and registers that could contain sensitive information.
void __attribute__((noreturn)) jump_to_next_stage(uint32_t vectbl_address); void __attribute__((noreturn)) jump_to_next_stage(uint32_t vectbl_address);
#endif // TREZORHAL_BOOTUTILS_H

View File

@ -79,14 +79,6 @@ void bootargs_set(boot_command_t command, const void* args, size_t args_size) {
mpu_restore(mode); 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) { void bootargs_get_args(boot_args_t* dest) {
mpu_mode_t mode = mpu_reconfig(MPU_MODE_BOOTARGS); mpu_mode_t mode = mpu_reconfig(MPU_MODE_BOOTARGS);
@ -95,6 +87,12 @@ void bootargs_get_args(boot_args_t* dest) {
mpu_restore(mode); 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) { void bootargs_init(uint32_t r11_register) {
#ifdef STM32U5 #ifdef STM32U5
g_boot_command_saved = g_boot_command; 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); 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) { __attribute__((noreturn)) void reboot_or_halt_after_rsod(void) {
#ifndef RSOD_INFINITE_LOOP #ifndef RSOD_INFINITE_LOOP
systick_delay_ms(10 * 1000); systick_delay_ms(10 * 1000);

View File

@ -47,6 +47,11 @@ void system_deinit(void);
// //
// The system will be in a state similar to a reset when `main()` is called // The system will be in a state similar to a reset when `main()` is called
// (but with some hardware peripherals still initialized and running). // (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( __attribute__((noreturn)) void system_emergency_rescue(
systask_error_handler_t error_handler, const systask_postmortem_t* pminfo); systask_error_handler_t error_handler, const systask_postmortem_t* pminfo);

View File

@ -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 (so we are sure that no DMA is pending)
reset_peripherals_and_interrupts(); reset_peripherals_and_interrupts();
// Copy pminfo from to our stack // Althought MPU is disabled, we need to change MPU driver state
// MPU is now disable, we have full access to bootargs. mpu_reconfig(MPU_MODE_DISABLED);
systask_postmortem_t pminfo = bootargs_ptr()->pminfo;
// Copy bootargs to our stack
boot_args_t bootargs;
bootargs_get_args(&bootargs);
// Clear unused part of our stack // Clear unused part of our stack
clear_unused_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; uint32_t stack_chk_guard = __stack_chk_guard;
// Clear all memory except our stack. // Clear all memory except our stack.
// NOTE: This also clear bootargs, so we don't pass pminfo structure // NOTE: This also clear bootargs, if the model doesn't support
// to the bootloader for now. // showing RSOD in the bootloader startup.
memregion_t region = MEMREGION_ALL_ACCESSIBLE_RAM; memregion_t region = MEMREGION_ALL_ACCESSIBLE_RAM;
MEMREGION_DEL_SECTION(&region, _stack_section); MEMREGION_DEL_SECTION(&region, _stack_section);
#ifdef USE_BOOTARGS_RSOD
MEMREGION_DEL_SECTION(&region, _bootargs_ram);
#endif
memregion_fill(&region, 0); memregion_fill(&region, 0);
// Reinitialize .bss, .data, ... // Reinitialize .bss, .data, ...
@ -119,12 +125,16 @@ system_emergency_rescue_phase_2(uint32_t arg1, uint32_t arg2) {
// in C code // in C code
if (error_handler != NULL) { 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 // We reach this point only if error_handler is NULL
// if it returns. Neither is expected to happen. // (if USE_BOOTARGS_RSOD is defined we leave postmortem info
reboot_device(); // in bootargs, so it can be used by the bootloader)
NVIC_SystemReset();
} }
__attribute((naked, noreturn, no_stack_protector)) void system_emergency_rescue( __attribute((naked, noreturn, no_stack_protector)) void system_emergency_rescue(

View File

@ -139,7 +139,9 @@ const char* system_fault_message(const system_fault_t* fault) {
void system_emergency_rescue(systask_error_handler_t error_handler, void system_emergency_rescue(systask_error_handler_t error_handler,
const systask_postmortem_t* pminfo) { const systask_postmortem_t* pminfo) {
error_handler(pminfo); if (error_handler != NULL) {
error_handler(pminfo);
}
// We should never reach this point // We should never reach this point
reboot_device(); reboot_device();

View File

@ -39,6 +39,7 @@ def configure(
("USE_LSE", "1"), ("USE_LSE", "1"),
("FIXED_HW_DEINIT", "1"), ("FIXED_HW_DEINIT", "1"),
("LOCKABLE_BOOTLOADER", "1"), ("LOCKABLE_BOOTLOADER", "1"),
("USE_BOOTARGS_RSOD", "1"),
("TERMINAL_FONT_SCALE", "2"), ("TERMINAL_FONT_SCALE", "2"),
("TERMINAL_X_PADDING", "4"), ("TERMINAL_X_PADDING", "4"),
("TERMINAL_Y_PADDING", "12"), ("TERMINAL_Y_PADDING", "12"),

View File

@ -39,6 +39,7 @@ def configure(
("USE_LSE", "1"), ("USE_LSE", "1"),
("FIXED_HW_DEINIT", "1"), ("FIXED_HW_DEINIT", "1"),
("LOCKABLE_BOOTLOADER", "1"), ("LOCKABLE_BOOTLOADER", "1"),
("USE_BOOTARGS_RSOD", "1"),
("TERMINAL_FONT_SCALE", "2"), ("TERMINAL_FONT_SCALE", "2"),
("TERMINAL_X_PADDING", "4"), ("TERMINAL_X_PADDING", "4"),
("TERMINAL_Y_PADDING", "12"), ("TERMINAL_Y_PADDING", "12"),

View File

@ -39,6 +39,7 @@ def configure(
("USE_LSE", "1"), ("USE_LSE", "1"),
("FIXED_HW_DEINIT", "1"), ("FIXED_HW_DEINIT", "1"),
("LOCKABLE_BOOTLOADER", "1"), ("LOCKABLE_BOOTLOADER", "1"),
("USE_BOOTARGS_RSOD", "1"),
("TERMINAL_FONT_SCALE", "2"), ("TERMINAL_FONT_SCALE", "2"),
("TERMINAL_X_PADDING", "4"), ("TERMINAL_X_PADDING", "4"),
("TERMINAL_Y_PADDING", "12"), ("TERMINAL_Y_PADDING", "12"),