Skip to content

Commit

Permalink
feat(core): implement rebooting after rsod, simplify shutdown code
Browse files Browse the repository at this point in the history
[no changelog]
  • Loading branch information
cepetr committed Jan 14, 2025
1 parent c612cd6 commit a3cdadf
Show file tree
Hide file tree
Showing 20 changed files with 401 additions and 447 deletions.
9 changes: 0 additions & 9 deletions core/embed/io/display/ltdc_dsi/display_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,15 +425,6 @@ bool display_init(display_content_mode_t mode) {
void display_deinit(display_content_mode_t mode) {
display_driver_t *drv = &g_display_driver;

if (mode == DISPLAY_RETAIN_CONTENT) {
// This is a temporary workaround for T3W1 to avoid clearing
// the display after drawing RSOD screen in `secure_shutdown()`
// function. The workaround should be removed once we have
// proper replacement for `secure_shutdown()` that resets the
// device instead of waiting for manual power off.
return;
}

GPIO_InitTypeDef GPIO_InitStructure = {0};

NVIC_DisableIRQ(LTDC_IRQn);
Expand Down
14 changes: 8 additions & 6 deletions core/embed/projects/kernel/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ static void show_rsod(const systask_postmortem_t *pminfo) {
applet_run(&coreapp);

if (coreapp.task.pminfo.reason == TASK_TERM_REASON_EXIT) {
// If the RSOD was shown successfully, proceed to shutdown
secure_shutdown();
// RSOD was shown successfully
return;
}
}
#endif
Expand All @@ -245,8 +245,9 @@ static void init_and_show_rsod(const systask_postmortem_t *pminfo) {
// Show RSOD
show_rsod(pminfo);

// Wait for the user to manually power off the device
secure_shutdown();
// Wait for the user to read the RSOD and then reboots
// (or enters an infinite loop if RSOD_INFINITE_LOOP is defined)
reboot_after_rsod();
}

// Kernel panic handler
Expand Down Expand Up @@ -285,8 +286,9 @@ int main(void) {
// Coreapp crashed, show RSOD
show_rsod(&coreapp.task.pminfo);

// Wait for the user to manually power off the device
secure_shutdown();
// Wait for the user to read the RSOD and then reboots
// (or enters an infinite loop if RSOD_INFINITE_LOOP is defined)
reboot_after_rsod();

return 0;
}
14 changes: 8 additions & 6 deletions core/embed/sys/startup/inc/sys/bootutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,21 @@ void __attribute__((noreturn)) reboot_to_bootloader(void);
// with the firmware installation.
void __attribute__((noreturn)) reboot_and_upgrade(const uint8_t hash[32]);

// Allows the user to see the displayed error message and then
// safely shuts down the device (clears secrets, memory, etc.).
// Allows the user to read the displayed error message and then
// reboots the device or waits for power-off.
//
// This function is called when the device enters an
// unrecoverable error state.
void __attribute__((noreturn)) secure_shutdown(void);
// The function's behavior depends on the `RSOD_INFINITE_LOOP` macro:
// 1) If `RSOD_INFINITE_LOOP` is defined, the function enters an infinite loop.
// 2) If `RSOD_INFINITE_LOOP` is not defined, the function waits for a
// specified duration and then resets the device.
void __attribute__((noreturn)) reboot_after_rsod(void);

// Jumps to the next booting stage (e.g. bootloader to firmware).
// `vectbl_address` points to the flash at the vector table of the next stage.
//
// Before jumping, the function disables all interrupts and clears the
// memory and registers that could contain sensitive information.
void jump_to_next_stage(uint32_t vectbl_address);
void __attribute__((noreturn)) jump_to_next_stage(uint32_t vectbl_address);

// Ensure compatible hardware settings before jumping to
// the different booting stage. This function is used to
Expand Down
69 changes: 47 additions & 22 deletions core/embed/sys/startup/stm32/bootutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,23 @@
#include <sys/bootutils.h>
#include <sys/irq.h>
#include <sys/mpu.h>
#include <sys/systick.h>
#include <util/image.h>

#include "bootutils_helpers.h"

#ifdef TREZOR_MODEL_T2T1
#include "../stm32f4/startup_init.h"
#endif

#ifdef KERNEL_MODE

// Battery powered devices (USE_POWERCTL) should not stall
// after showing RSOD, as it would drain the battery.
#ifndef USE_POWERCTL
#define RSOD_INFINITE_LOOP
#endif

#ifdef STM32U5
// Persistent variable that holds the 'command' for the next reboot.
boot_command_t __attribute__((section(".boot_command"))) g_boot_command;
Expand Down Expand Up @@ -86,7 +95,8 @@ void bootargs_get_args(boot_args_t* dest) {
// Deletes all secrets and SRAM2 where stack is located
// to prevent stack smashing error, do not return from function calling this
#ifdef STM32U5
static inline void __attribute__((always_inline)) delete_secrets(void) {
static inline void __attribute__((always_inline, no_stack_protector))
delete_secrets(void) {
__disable_irq();

// Disable SAES peripheral clock, so that we don't get tamper events
Expand All @@ -96,6 +106,28 @@ static inline void __attribute__((always_inline)) delete_secrets(void) {
}
#endif // STM32U5

// Clears USB FIFO memory to prevent data leakage of sensitive information
__attribute((used, no_stack_protector)) void clear_usb_fifo_memory(void) {
#ifdef STM32F4
// reference RM0090 section 35.12.1 Figure 413
#define USB_OTG_HS_DATA_FIFO_RAM (USB_OTG_HS_PERIPH_BASE + 0x20000U)
#define USB_OTG_HS_DATA_FIFO_SIZE (4096U)

// use the HAL version due to section 2.1.6 of STM32F42xx Errata sheet
__HAL_RCC_USB_OTG_HS_CLK_ENABLE(); // enable USB_OTG_HS peripheral clock so
// that the peripheral memory is
// accessible
__IO uint32_t* usb_fifo_ram = (__IO uint32_t*)USB_OTG_HS_DATA_FIFO_RAM;

for (uint32_t i = 0; i < USB_OTG_HS_DATA_FIFO_SIZE / 4; i++) {
usb_fifo_ram[i] = 0;
}

__HAL_RCC_USB_OTG_HS_CLK_DISABLE(); // disable USB OTG_HS peripheral clock as
// the peripheral is not needed right now
#endif // STM32F4
}

#ifdef STM32F4
// Ensure that we are running in privileged thread mode.
//
Expand Down Expand Up @@ -162,20 +194,16 @@ reboot_with_args(boot_command_t command, const void* args, size_t args_size) {

#ifdef STM32U5
delete_secrets();
NVIC_SystemReset();
wipe_all_and_reboot_with_args();
#else
display_deinit(DISPLAY_RESET_CONTENT);
ensure_compatible_settings();

mpu_reconfig(MPU_MODE_DISABLED);
clear_usb_fifo_memory();

mpu_reconfig(MPU_MODE_DISABLED);
ensure_thread_mode();

// from util.s
extern void jump_to_with_flag(uint32_t address, uint32_t reset_flag);
jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE, g_boot_command);
for (;;)
;
jump_to_bootloader(BOOTLOADER_START + IMAGE_HEADER_SIZE, g_boot_command);
#endif
}

Expand All @@ -188,27 +216,24 @@ void reboot_and_upgrade(const uint8_t hash[32]) {
}

void reboot_device(void) {
bootargs_set(BOOT_COMMAND_NONE, NULL, 0);

clear_usb_fifo_memory();
#ifdef STM32U5
delete_secrets();
#endif

NVIC_SystemReset();
wipe_all_and_reboot();
}

void __attribute__((noreturn)) secure_shutdown(void) {
display_deinit(DISPLAY_RETAIN_CONTENT);

void __attribute__((noreturn)) reboot_after_rsod(void) {
clear_usb_fifo_memory();
#ifdef STM32U5
delete_secrets();
#endif
// from util.s
extern void shutdown_privileged(void);
shutdown_privileged();

for (;;)
;
#ifdef RSOD_INFINITE_LOOP
wipe_all_and_stall();
#else
systick_delay_ms(10 * 1000);
wipe_all_and_reboot();
#endif
}

void ensure_compatible_settings(void) {
Expand Down
Loading

0 comments on commit a3cdadf

Please sign in to comment.