refactor(core/embed): introduce system, tasks, applets and emergency mode

[no changelog]
tychovrahe/coresplit/merged
cepetr 2 weeks ago
parent 854c4ae4d7
commit 4df485aa03

@ -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:

@ -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',

@ -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',

@ -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',

@ -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',

@ -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',

@ -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',

@ -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',

@ -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',

@ -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

@ -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);

@ -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)

@ -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);

@ -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

@ -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);

@ -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

@ -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);

@ -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

@ -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

@ -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

@ -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);

@ -19,27 +19,29 @@
#include STM32_HAL_H
#include "image.h"
#include "irq.h"
#include "syscall.h"
#include <string.h>
#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;
}

@ -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);

@ -18,25 +18,10 @@
*/
#include <stddef.h>
#ifdef TREZOR_EMULATOR
#include <stdio.h>
#endif
#include <stdint.h>
#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) {

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

@ -17,6 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fault_handlers.h>
#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

@ -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();

@ -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);

@ -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();

@ -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);

@ -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);

@ -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<T> {

@ -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]

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_APPLET_H
#define TREZORHAL_APPLET_H
#include <stddef.h>
#include <stdint.h>
#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

@ -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

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#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

@ -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

@ -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;

@ -17,23 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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

@ -22,18 +22,16 @@
#include <stdint.h>
#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

@ -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;

@ -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,

@ -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
// =============================================================================

@ -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 <http://www.gnu.org/licenses/>.
*/
#include STM32_HAL_H
#include <stdbool.h>
#include <string.h>
#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

@ -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 <http://www.gnu.org/licenses/>.
*/
#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
);
}

@ -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

@ -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

@ -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

@ -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

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_SYSTASK_H
#define TREZORHAL_SYSTASK_H
#include <stddef.h>
#include <stdint.h>
#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

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_SYSTEM_H
#define TREZORHAL_SYSTEM_H
#include <systask.h>
// 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

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
}

@ -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",
]

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

@ -1 +1 @@
Subproject commit b9deb14b9e38cffa31b6d9a880c5e0d6855ef6ce
Subproject commit 9cfd22ef20fec2c34d0f0e5c16a5d5152da30861
Loading…
Cancel
Save