1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-19 05:58:09 +00:00

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

[no changelog]
This commit is contained in:
cepetr 2024-09-18 09:24:59 +02:00 committed by cepetr
parent 1c991339ce
commit 35c6f52133
57 changed files with 2010 additions and 520 deletions

View File

@ -79,6 +79,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:

View File

@ -118,6 +118,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',

View File

@ -111,6 +111,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',
'vendor/micropython/lib/uzlib/adler32.c',
'vendor/micropython/lib/uzlib/crc32.c',

View File

@ -113,6 +113,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',
@ -149,7 +150,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',
@ -157,6 +157,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',

View File

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

View File

@ -234,6 +234,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',

View File

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

View File

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

View File

@ -90,6 +90,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',
'vendor/micropython/lib/uzlib/adler32.c',
'vendor/micropython/lib/uzlib/crc32.c',

View File

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

View File

@ -21,19 +21,20 @@
#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 "flash_utils.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
@ -234,8 +235,7 @@ static secbool copy_sdcard(void) {
#endif
int main(void) {
systick_init();
systimer_init();
system_init(&rsod_panic_handler);
reset_flags_reset();
@ -261,8 +261,6 @@ int main(void) {
clear_otg_hs_memory();
#endif
fault_handlers_init();
#ifdef USE_SDRAM
sdram_init();
#endif

View File

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

View File

@ -25,7 +25,6 @@
#include "common.h"
#include "display.h"
#include "display_utils.h"
#include "fault_handlers.h"
#include "flash.h"
#include "flash_otp.h"
#include "flash_utils.h"
@ -33,8 +32,10 @@
#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
@ -356,8 +357,7 @@ int bootloader_main(void) {
#endif
secbool stay_in_bootloader = secfalse;
systick_init();
systimer_init();
system_init(&rsod_panic_handler);
rdi_init();
@ -396,8 +396,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)

View File

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

View File

@ -20,6 +20,7 @@
#include <string.h>
#include <sys/types.h>
#include "bootutils.h"
#include "common.h"
#include "display.h"
#include "display_draw.h"
@ -30,7 +31,9 @@
#include "mpu.h"
#include "random_delays.h"
#include "rng.h"
#include "rsod.h"
#include "secbool.h"
#include "system.h"
#ifdef USE_TOUCH
#include "touch.h"
#endif
@ -176,8 +179,7 @@ static secbool check_vendor_header_lock(const vendor_header *const vhdr) {
}
int main(void) {
systick_init();
systimer_init();
system_init(&rsod_panic_handler);
rdi_init();
#ifdef USE_TOUCH

View File

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

View File

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

View File

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

View File

@ -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
push {r0, r1}
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
// setup the stack protector with provided random value
ldr r0, = __stack_chk_guard
str r2, [r0]
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
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

View File

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

View File

@ -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
@ -125,8 +126,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();
@ -183,8 +183,6 @@ int main(void) {
// Init peripherals
fault_handlers_init();
#if defined TREZOR_MODEL_T
set_core_clock(CLOCK_180_MHZ);
#endif

View File

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

View File

@ -19,15 +19,14 @@
#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 "image.h"
#include "irq.h"
@ -36,11 +35,12 @@
#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"
@ -66,15 +66,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
@ -175,14 +166,92 @@ 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
if (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 init_and_show_rsod(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(&init_and_show_rsod, 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
if (!applet_reset(&coreapp, 0, NULL, 0)) {
error_shutdown("Cannot start coreapp");
}
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;
}

View File

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

View File

@ -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,9 @@ 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) {
title = "INTERNAL ERROR";
}
if (footer == NULL) {
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 +44,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) {

177
core/embed/lib/rsod.c Normal file
View File

@ -0,0 +1,177 @@
/*
* 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 "bootutils.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* pminfo) {
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 (pminfo->reason) {
case TASK_TERM_REASON_EXIT:
mini_snprintf(message_buf, sizeof(message_buf), RSOD_EXIT_MESSAGE,
pminfo->exit.code);
message = message_buf;
break;
case TASK_TERM_REASON_ERROR:
title = pminfo->error.title;
message = pminfo->error.message;
footer = pminfo->error.footer;
break;
case TASK_TERM_REASON_FATAL:
message = pminfo->fatal.expr;
file = pminfo->fatal.file;
line = pminfo->fatal.line;
break;
case TASK_TERM_REASON_FAULT:
message = system_fault_message(&pminfo->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)) && defined(FANCY_FATAL_ERROR)
#include "rust_ui.h"
void rsod_gui(const systask_postmortem_t* pminfo) {
const char* title = RSOD_DEFAULT_TITLE;
const char* message = RSOD_DEFAULT_MESSAGE;
const char* footer = RSOD_DEFAULT_FOOTER;
char message_buf[128] = {0};
switch (pminfo->reason) {
case TASK_TERM_REASON_EXIT:
mini_snprintf(message_buf, sizeof(message_buf), RSOD_EXIT_MESSAGE,
pminfo->exit.code);
message = message_buf;
break;
case TASK_TERM_REASON_ERROR:
title = pminfo->error.title;
message = pminfo->error.message;
footer = pminfo->error.footer;
break;
case TASK_TERM_REASON_FATAL:
message = pminfo->fatal.expr;
if (message[0] == '\0') {
mini_snprintf(message_buf, sizeof(message_buf), "%s:%u",
pminfo->fatal.file, (unsigned int)pminfo->fatal.line);
message = message_buf;
}
break;
case TASK_TERM_REASON_FAULT:
message = system_fault_message(&pminfo->fault);
break;
}
// Render the RSOD in Rust
display_rsod_rust(title, message, footer);
}
#endif
#ifdef KERNEL_MODE
// Initializes system in emergency mode and shows RSOD
static void init_and_show_rsod(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);
#if (defined(FIRMWARE) || defined(BOOTLOADER)) && defined(FANCY_FATAL_ERROR)
// Show the RSOD using Rust GUI
rsod_gui(pminfo);
#else
// Show the RSOD using terminal
rsod_terminal(pminfo);
#endif
// Wait for the user to manually power off the device
secure_shutdown();
}
// Universal panic handler
// (may be called from interrupt context)
void rsod_panic_handler(const systask_postmortem_t* pminfo) {
// Since the system state is unreliable, enter emergency mode
// and show the RSOD.
system_emergency_rescue(&init_and_show_rsod, pminfo);
// The previous function call never returns
}
#endif // KERNEL_MODE

View File

@ -17,6 +17,24 @@
* 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"
// Shows RSOD (Red Screen of Death) using terminal.
void rsod_terminal(const systask_postmortem_t* pminfo);
// Shows RSOD (Red Screen of Death) using Rust GUI.
void rsod_gui(const systask_postmortem_t* pminfo);
#ifdef KERNEL_MODE
// Universal panic handler that can be passed to `system_init()` function
// to show RSOD screen describing the system error.
// (may be called from interrupt context)
void rsod_panic_handler(const systask_postmortem_t* pminfo);
#endif // KERNEL_MODE
#endif // LIB_RSOD_H

View File

@ -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"
@ -40,9 +39,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"
@ -783,9 +784,8 @@ void cpuid_read(void) {
#define BACKLIGHT_NORMAL 150
int main(void) {
systick_init();
systimer_init();
rdi_init();
system_init(&rsod_panic_handler);
display_init(DISPLAY_RETAIN_CONTENT);
#ifdef STM32U5
@ -820,8 +820,6 @@ int main(void) {
pair_optiga();
#endif
fault_handlers_init();
display_clear();
draw_welcome_screen();

View File

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

View File

@ -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)];
@ -69,8 +72,7 @@ static void flash_from_sdcard(const flash_area_t* area, uint32_t source,
}
int main(void) {
systick_init();
systimer_init();
system_init(&rsod_panic_handler);
sdcard_init();
touch_init();

View File

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

View File

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

View File

@ -1,31 +1,28 @@
mod ffi {
extern "C" {
// trezorhal/bootuils.c
pub fn secure_shutdown() -> !;
// error_handling.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() }
}
// 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]);
/// 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() };
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 +43,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> {

View File

@ -10,19 +10,33 @@ 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]

View File

@ -0,0 +1,81 @@
/*
* 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.
//
// Returns `true` if the applet was successfully reset.
bool applet_reset(applet_t* applet, uint32_t cmd, const void* arg,
size_t arg_size);
#endif // SYSCALL_DISPATCH
#endif // TREZORHAL_APPLET_H

View File

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

View File

@ -0,0 +1,73 @@
/*
* 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;
}
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);
}
}
bool 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);
if (arg_copy == NULL) {
return false;
}
}
// Schedule the applet task run
uint32_t arg1 = cmd;
uint32_t arg2 = (uint32_t)arg_copy;
uint32_t arg3 = rng_get();
return systask_push_call(&applet->task, applet->header->startup, arg1, arg2,
arg3);
}
#endif // SYSCALL_DISPATCH

View File

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

View File

@ -17,40 +17,44 @@
* 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 arg1, uint32_t arg2, uint32_t arg3, void *callback) {
uint32_t arg1, uint32_t arg2, uint32_t arg3, void* callback) {
__asm__ volatile(
"push {r1-r12, lr} \n"
"mrs r12, PSP \n" // reserved frame on unprivileged stack (!@#
// TODO check PSP value???)
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
"mrs r12, PSPLIM \n" // Backup unprivileged stack limit
"push {r12} \n"
"sub r12, r12, #32 \n"
#endif
"mrs r12, PSP \n" // Backup unprivileged stack pointer
"push {r12} \n"
"sub r12, r12, #32 \n" // Reserve space for stack frame
"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
@ -58,14 +62,8 @@ __attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback(
"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.
"vmov r0, s0 \n" // Use FPU instruction to ensure lazy
// stacking
// return to Secure Thread mode (use Secure PSP)
"ldr lr, = 0xFFFFFFFD \n"
@ -73,133 +71,31 @@ __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) {
__attribute__((naked, no_stack_protector)) void return_from_app_callback(
uint32_t retval, uint32_t* msp) {
__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;
"MSR MSP, R1 \n"
"POP {R1} \n"
"MSR PSP, R1 \n"
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
"POP {R1} \n"
"MSR PSPLIM, R1 \n"
#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);
}
"LDR R1, = 0xE000EF34 \n" // FPU->FPCCR
"LDR R2, [R1] \n"
"BIC R2, R2, #1 \n" // Clear LSPACT to suppress repeated lazy
"STR R2, [R1] \n" // stacking that was already done
__attribute__((naked, no_stack_protector)) void SVC_Handler(void) {
__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) {
}
"POP {R1-R12, LR} \n"
"BX LR \n");
}
#endif // SYSCALL_DISPATCH

View File

@ -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,20 @@ 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
// Invokes the application callback from the syscall handler.
//
// This is a *temporary* helper function used to invoke application callbacks
// from the syscall handler. It will be removed once all callback arguments
// are eliminated from syscalls.
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);
// Internal function for returning from an application callback.
// This function is called from an unprivileged app via an SVC call. It restores
// the stack pointer and returns control to the privileged caller.
void return_from_app_callback(uint32_t retval, uint32_t* msp);
#else // KERNEL_MODE

View File

@ -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"
@ -61,8 +63,23 @@ static void firmware_hash_callback_wrapper(void *context, uint32_t progress,
firmware_hash_callback);
}
void syscall_handler(uint32_t *args, uint32_t syscall) {
__attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
uint32_t syscall) {
switch (syscall) {
case SYSCALL_SYSTEM_EXIT: {
systask_t *task = systask_active();
systask_exit(task, (int)args[0]);
} break;
case SYSCALL_SYSTEM_EXIT_ERROR: {
systask_t *task = systask_active();
systask_exit_error(task, (const char *)args[0], (const char *)args[1],
(const char *)args[2]);
} break;
case SYSCALL_SYSTEM_EXIT_FATAL: {
systask_t *task = systask_active();
systask_exit_fatal(task, (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;

View File

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

View File

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

View File

@ -0,0 +1,639 @@
/*
* 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
// Disable stack protector for this file since it may interfere
// with the stack manipulation and fault handling
#pragma GCC optimize("no-stack-protector")
#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;
// Kernel stack base pointer defined in linker script
extern uint8_t _sstack;
extern uint8_t _estack;
// Global task manager state
static systask_scheduler_t g_systask_scheduler = {
// This static initialization is required for exception handling
// to function correctly before the scheduler is initialized.
.active_task = &g_systask_scheduler.kernel_task,
.waiting_task = &g_systask_scheduler.kernel_task,
.kernel_task = {
.sp_lim = (uint32_t)&_sstack,
}};
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;
scheduler->kernel_task.sp_lim = (uint32_t)&_sstack;
// 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;
}
static void systask_yield(void) {
bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0;
if (handler_mode) {
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
__DSB();
} else {
// 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"
: // no output
: [svid] "i"(SVC_SYSTASK_YIELD)
: "memory");
}
}
void systask_yield_to(systask_t* task) {
systask_scheduler_t* scheduler = &g_systask_scheduler;
irq_key_t irq_key = irq_lock();
scheduler->waiting_task = task;
irq_unlock(irq_key);
systask_yield();
}
void systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size) {
memset(task, 0, sizeof(systask_t));
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) {
if (task->sp < task->sp_lim) {
// Stack overflow
return NULL;
}
uint32_t stack_remaining = task->sp - task->sp_lim;
if (stack_remaining < size) {
// Not enough space on the stack
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; }
bool systask_push_call(systask_t* task, void* entrypoint, uint32_t arg1,
uint32_t arg2, uint32_t arg3) {
uint32_t original_sp = task->sp;
// Align stack pointer to 8 bytes
task->sp &= ~7;
// FP extension context
if (systask_push_data(task, NULL, 0x48) == NULL) {
goto cleanup;
}
// Standard exception frame
uint32_t* stk_frame = systask_push_data(task, NULL, 0x20);
if (stk_frame == NULL) {
goto cleanup;
}
// Registers r4-r11
if (systask_push_data(task, NULL, 0x20) == NULL) {
goto cleanup;
}
// Registers s16-s31
if (systask_push_data(task, NULL, 0x40) == NULL) {
goto cleanup;
}
// 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
return true;
cleanup:
task->sp = original_sp;
return false;
}
static void systask_kill(systask_t* task) {
systask_scheduler_t* scheduler = &g_systask_scheduler;
task->killed = 1;
if (task == &scheduler->kernel_task) {
// Call panic handler
if (scheduler->error_handler != NULL) {
scheduler->error_handler(&task->pminfo);
}
secure_shutdown();
} else if (task == scheduler->active_task) {
// Switch to the kernel task
systask_yield_to(&scheduler->kernel_task);
}
}
void systask_exit(systask_t* task, int exit_code) {
systask_scheduler_t* scheduler = &g_systask_scheduler;
if (task == NULL) {
bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0;
task = handler_mode ? &scheduler->kernel_task : scheduler->active_task;
}
systask_postmortem_t* pminfo = &task->pminfo;
memset(pminfo, 0, sizeof(systask_postmortem_t));
pminfo->reason = TASK_TERM_REASON_EXIT;
pminfo->privileged = (task == &scheduler->kernel_task);
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_scheduler_t* scheduler = &g_systask_scheduler;
if (task == NULL) {
bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0;
task = handler_mode ? &scheduler->kernel_task : scheduler->active_task;
}
systask_postmortem_t* pminfo = &task->pminfo;
memset(pminfo, 0, sizeof(systask_postmortem_t));
pminfo->reason = TASK_TERM_REASON_ERROR;
pminfo->privileged = (task == &scheduler->kernel_task);
if (title != NULL) {
strncpy(pminfo->error.title, title, sizeof(pminfo->error.title) - 1);
}
if (message != NULL) {
strncpy(pminfo->error.message, message, sizeof(pminfo->error.message) - 1);
}
if (footer != NULL) {
strncpy(pminfo->error.footer, footer, sizeof(pminfo->error.footer) - 1);
}
systask_kill(task);
}
void systask_exit_fatal(systask_t* task, const char* message, const char* file,
int line) {
systask_scheduler_t* scheduler = &g_systask_scheduler;
if (task == NULL) {
bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0;
task = handler_mode ? &scheduler->kernel_task : scheduler->active_task;
}
systask_postmortem_t* pminfo = &task->pminfo;
memset(pminfo, 0, sizeof(systask_postmortem_t));
pminfo->reason = TASK_TERM_REASON_FATAL;
pminfo->privileged = (task == &scheduler->kernel_task);
if (message != NULL) {
strncpy(pminfo->fatal.expr, message, sizeof(pminfo->fatal.expr) - 1);
}
if (file != NULL) {
strncpy(pminfo->fatal.file, file, sizeof(pminfo->fatal.file) - 1);
}
pminfo->fatal.line = line;
systask_kill(task);
}
// Terminate active task from fault/exception handler
__attribute((used)) static void systask_exit_fault(bool privileged,
uint32_t sp) {
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
systask_scheduler_t* scheduler = &g_systask_scheduler;
systask_t* task =
privileged ? &scheduler->kernel_task : scheduler->active_task;
systask_postmortem_t* pminfo = &task->pminfo;
// Do not overwrite the reason if it is already set to fault
// (exception handlers may call this function multiple times, and
// we want to preserve the first reason)
if (pminfo->reason != TASK_TERM_REASON_FAULT) {
pminfo->reason = TASK_TERM_REASON_FAULT;
pminfo->privileged = privileged;
pminfo->fault.sp = sp;
#if !(defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__))
pminfo->fault.sp_lim = task->sp_lim;
#endif
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);
mpu_restore(mpu_mode);
}
// 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;
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
// sp_lim is not valid on ARMv7-M
prev_task->sp_lim = sp_lim;
#endif
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;
}
__attribute__((naked, no_stack_protector)) void PendSV_Handler(void) {
__asm__ volatile(
"LDR R0, =%[active_task] \n"
"LDR R1, =%[waiting_task]\n"
"CMP R0, R1 \n"
"BEQ 3f \n" // No task switch needed
"LDR R0, [R0] \n" // R0 = active_task
"LDR R0, [R0, #12] \n" // R0 = active_task->killed
"CMP R0, #0 \n"
"BEQ 1f \n" // =0 => normal processing
// We are switching from a killed task to the kernel task.
// Since the reason might be a stack overflow, we must not
// attempt to save the task context.
"LDR R1, = 0xE000EF34 \n" // FPU->FPCCR
"LDR R0, [R1] \n"
"BIC R0, R0, #1 \n" // Clear LSPACT to suppress later lazy
"STR R0, [R1] \n" // stacking to the killed task stack
"MOV R0, #0 \n" // Skip context save
"MOV R1, R0 \n" //
"MOV R2, R0 \n" //
"B 2f \n" //
"1: \n"
// Save the current task context on its stack before switching
"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
"IT EQ \n" // If using main stack:
"SUBEQ SP, SP, #0x60 \n" // reserve space for R4-11 and S16-S31
"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
"2: \n"
"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" // Return stack (1=>PSP, 0=>MSP)
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
"ITEE EQ \n"
"MSREQ MSP, R0 \n" // Update MSP
"MSRNE PSPLIM, R1 \n" // Update PSPLIM & PSP
"MSRNE PSP, R0 \n"
#else
"ITE EQ \n"
"MSREQ MSP, R0 \n" // Update the MSP
"MSRNE PSP, R0 \n" // Update the PSP
#endif
"3: "
"BX LR \n"
: // No output
: [active_task] "i"(&g_systask_scheduler.active_task), // Input
[waiting_task] "i"(&g_systask_scheduler.waiting_task) // Input
: // Clobber
);
}
__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];
#ifdef SYSCALL_DISPATCH
uint32_t args[6] = {stack[0], stack[1], stack[2], stack[3], r4, r5};
#endif
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:
// Yield to the waiting task
systask_yield();
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" // Return stack (1=>PSP, 0=>MSP)
"ITE EQ \n"
"MRSEQ R0, MSP \n" // `stack` argument
"MRSNE R0, PSP \n"
"TST LR, #0x20 \n"
"IT EQ \n"
"ADDEQ R0, R0, #0x40 \n"
"MRS R1, MSP \n" // `msp` argument
"MOV R2, LR \n" // `exc_return` argument
"MOV R3, R4 \n" // 'r4' argument
"PUSH {R5, R6} \n" // 'r5' and 'r6' arguments on stack
"BL svc_handler \n"
"POP {R5, R6} \n"
"BX R0 \n" // Branch to the returned value
);
}
__attribute__((naked, no_stack_protector)) 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.
__asm__ volatile(
"MRS R1, MSP \n" // R1 = MSP
"LDR R0, =%[estack] \n" // Reset main stack
"MSR MSP, R0 \n" //
"MOV R0, #1 \n" // R0 = 1 (Privileged)
"B systask_exit_fault \n" // Exit task with fault
:
: [estack] "i"(&_estack)
: "memory");
}
__attribute__((naked, no_stack_protector)) void MemManage_Handler(void) {
__asm__ volatile(
"TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP)
"ITTEE EQ \n"
"MOVEQ R0, #1 \n" // R0 = 1 (Privileged)
"MRSEQ R1, MSP \n" // R1 = MSP
"MOVNE R0, #0 \n" // R0 = 0 (Unprivileged)
"MRSNE R1, PSP \n" // R1 = PSP
#if !(defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__))
"CMP R0, #0 \n"
"BEQ 1f \n" // Skip stack ptr checking for PSP
"LDR R2, =%[sstack] \n"
"CMP R1, R2 \n" // Check if PSP is below the stack
"ITT LO \n" // base
"LDRLO R2, =%[estack] \n"
"MSRLO MSP, R2 \n" // Reset MSP
"1: \n"
#endif
"B systask_exit_fault \n" // Exit task with fault
:
: [estack] "i"(&_estack), [sstack] "i"((uint32_t)&_sstack + 256)
: "memory");
}
__attribute__((naked, no_stack_protector)) void BusFault_Handler(void) {
__asm__ volatile(
"TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP)
"ITTEE EQ \n"
"MOVEQ R0, #1 \n" // R0 = 1 (Privileged)
"MRSEQ R1, MSP \n" // R1 = MSP
"MOVNE R0, #0 \n" // R0 = 0 (Unprivileged)
"MRSNE R1, PSP \n" // R1 = PSP
"B systask_exit_fault \n" // Exit task with fault
);
}
__attribute__((naked, no_stack_protector)) void UsageFault_Handler(void) {
__asm__ volatile(
"TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP)
"ITTT NE \n"
"MOVNE R0, #0 \n" // R0 = 0 (Unprivileged)
"MRSNE R1, PSP \n" // R1 = PSP
"BNE systask_exit_fault \n" // Exit task with fault
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
"MRS R1, MSP \n" // R1 = MSP
"LDR R0, =0xE000ED28 \n" // SCB->CFSR
"LDR R0, [R0] \n"
"TST R0, #0x100000 \n" // STKOF bit set?
"ITT NE \n"
"LDRNE R0, =%[estack] \n" // Reset main stack in case of stack
"MSRNE MSP, R0 \n" // overflow
#endif
"MOV R0, #1 \n" // R0 = 1 (Privileged)
"B systask_exit_fault \n" // Exit task with fault
:
: [estack] "i"(&_estack)
: "memory");
}
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
__attribute__((naked, no_stack_protector)) void SecureFault_Handler(void) {
__asm__ volatile(
"TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP)
"ITTEE EQ \n"
"MOVEQ R0, #1 \n" // R0 = 1 (Privileged)
"MRSEQ R1, MSP \n" // R1 = MSP
"MOVNE R0, #0 \n" // R0 = 0 (Unprivileged)
"MRSNE R1, PSP \n" // R1 = PSP
"B systask_exit_fault \n" // Exit task with fault
);
}
#endif
#ifdef STM32U5
void GTZC_IRQHandler(void) { systask_exit_fault(true, __get_MSP()); }
#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(true, __get_MSP());
}
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

View File

@ -0,0 +1,310 @@
/*
* 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(NULL, exitcode); }
void system_exit_error(const char* title, const char* message,
const char* footer) {
systask_exit_error(NULL, title, message, footer);
}
void system_exit_fatal(const char* message, const char* file, int line) {
systask_exit_fatal(NULL, message, file, line);
}
#endif // KERNEL_MODE
#ifndef HardFault_IRQn
#define HardFault_IRQn (-13) // not defined in stm32lib/cmsis/stm32429xx.h
#endif
#ifdef STM32U5
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:
return (fault->cfsr & SCB_CFSR_STKOF_Msk) ? "(SO)" : "(UF)";
case SecureFault_IRQn:
return "(SF)";
case GTZC_IRQn:
return "(IA)";
case NonMaskableInt_IRQn:
return "(CS)";
default:
return "(FAULT)";
}
}
#else // STM32U5
const char* system_fault_message(const system_fault_t* fault) {
switch (fault->irqn) {
case HardFault_IRQn:
return "(HF)";
case MemoryManagement_IRQn:
return (fault->sp < fault->sp_lim) ? "(SO)" : "(MM)";
case BusFault_IRQn:
return "(BF)";
case UsageFault_IRQn:
return "(UF)";
case NonMaskableInt_IRQn:
return "(CS)";
default:
return "(FAULT)";
}
}
#endif // STM32U5
__attribute__((used)) static void emergency_reset(void) {
// TODO: reset peripherals (at least DMA, DMA2D)
// Disable all NVIC interrupts and clear pending flags
// so later the global interrupt can be re-enabled without
// firing any pending interrupt
for (int irqn = 0; irqn < 255; irqn++) {
NVIC_DisableIRQ(irqn);
NVIC_ClearPendingIRQ(irqn);
}
// Disable SysTick
SysTick->CTRL = 0;
// Clear PENDSV flag to prevent the PendSV_Handler call
SCB->ICSR &= ~SCB_ICSR_PENDSVSET_Msk;
// Clear SCB->SHCSR exception flags so we can return back
// to thread mode without any exception active
uint32_t preserved_flag = 0;
switch ((__get_IPSR() & IPSR_ISR_Msk) - 16) {
case MemoryManagement_IRQn:
preserved_flag = SCB_SHCSR_MEMFAULTACT_Msk;
break;
case BusFault_IRQn:
preserved_flag = SCB_SHCSR_BUSFAULTACT_Msk;
break;
case UsageFault_IRQn:
preserved_flag = SCB_SHCSR_USGFAULTACT_Msk;
break;
case PendSV_IRQn:
preserved_flag = SCB_SHCSR_PENDSVACT_Msk;
break;
case SysTick_IRQn:
preserved_flag = SCB_SHCSR_SYSTICKACT_Msk;
break;
case SVCall_IRQn:
preserved_flag = SCB_SHCSR_SVCALLACT_Msk;
break;
case HardFault_IRQn:
default:
break;
}
const uint32_t cleared_flags =
SCB_SHCSR_MEMFAULTACT_Msk | SCB_SHCSR_BUSFAULTACT_Msk |
SCB_SHCSR_USGFAULTACT_Msk | SCB_SHCSR_SVCALLACT_Msk |
SCB_SHCSR_MONITORACT_Msk | SCB_SHCSR_PENDSVACT_Msk |
SCB_SHCSR_SYSTICKACT_Msk;
SCB->SHCSR &= ~(cleared_flags & ~preserved_flag);
}
__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
// --------------------------------------------------------------
// 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" // Source
"MOV R5, R0 \n" // R5 = pminfo on the 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"
// --------------------------------------------------------------
// Reset critical hardware so we can safely enable interrupts
// --------------------------------------------------------------
"BL emergency_reset \n"
"CPSIE I \n" // Re-enable interrupts
// --------------------------------------------------------------
// Clear all VFP registers
// --------------------------------------------------------------
"LDR R1, = 0xE000EF34 \n" // FPU->FPCCR
"LDR R0, [R1] \n"
"BIC R0, R0, #1 \n" // Clear LSPACT to suppress lazy
// stacking
"STR R0, [R1] \n"
// TODO: clear VFP registers (maybe for ARMV7-M only)
// --------------------------------------------------------------
// Clear R7-R11 registers
// --------------------------------------------------------------
"MOV R0, #0 \n"
"MOV R7, R0 \n"
"MOV R8, R0 \n"
"MOV R9, R0 \n"
"MOV R10, R0 \n"
"MOV R11, R0 \n"
// --------------------------------------------------------------
// 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, =secure_shutdown\n"
"BXEQ R6 \n" // jump to error_handler directly
// --------------------------------------------------------------
// Return from exception to thread mode
// --------------------------------------------------------------
"MOV R0, SP \n" // Align stack pointer to 8 bytes
"AND R0, R0, #~7 \n"
"MOV SP, R0 \n"
"SUB SP, SP, #32 \n" // Allocate space for the stack 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, =secure_shutdown\n"
"STR R0, [SP, #20] \n" // future LR = secure_shutdown()
"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-R6
"MOV R5, R0 \n" // (R7-R11 are already cleared)
"MOV R6, R0 \n"
"MRS R0, CONTROL \n" // Clear SPSEL to use MSP for thread
"BIC R0, R0, #3 \n" // Clear nPRIV to run in privileged mode
"MSR CONTROL, R1 \n"
"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
);
}

View File

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

View File

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

View File

@ -0,0 +1 @@
../stm32f4/applet.c

View File

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

View File

@ -0,0 +1 @@
../stm32f4/systask.c

View File

@ -0,0 +1 @@
../stm32f4/system.c

View File

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

View File

@ -0,0 +1,182 @@
/*
* 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 <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "mpu.h"
// Termination reason for the task
typedef enum {
TASK_TERM_REASON_EXIT = 0,
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;
// Stack pointer at the time of the fault
// (MSP or PSP depending on the privilege level)
uint32_t sp;
#if !(defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__))
// Stack pointer limit (for the stack overflow detection)
uint32_t sp_lim;
#endif
} system_fault_t;
// Task post-mortem information
typedef struct {
// Reason for the task termination
systask_term_reason_t reason;
// Whether the error occurred in privileged mode
bool privileged;
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` and `killed` 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;
// Set to nonzero, if the task is killed
uint32_t killed;
// 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
// Return `true` in case of success, `false` otherwise
bool systask_push_call(systask_t* task, void* fn, uint32_t arg1, uint32_t arg2,
uint32_t arg3);
// Terminates the task with the given exit code
//
// If the task is not specified (NULL), it's automatically determined:
// 1) If the function is called in thread mode, the active task will be
// terminated.
// 2) If the function is called in handler mode, the kernel task will be
// terminated even if it is not the active task.
//
// If the terminated task is unprivileged, the kernel task will be scheduled
// next.
void systask_exit(systask_t* task, int exit_code);
// Terminates the task with an error message
//
// (see `systask_exit()` for more details)
void systask_exit_error(systask_t* task, const char* title, const char* message,
const char* footer);
// Terminates the task with a fatal error message
//
// (see `systask_exit()` for more details)
void systask_exit_fatal(systask_t* task, const char* message, const char* file,
int line);
#endif // KERNEL_MODE
#endif // TREZORHAL_SYSTASK_H

View File

@ -0,0 +1,68 @@
/*
* 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 task normally with the given exit code.
//
// If the current task is the kernel task, the error handler is called with the
// postmortem information. If the task is not the kernel task, the task is
// terminated immediately and the kernel task is scheduled.
void system_exit(int exitcode);
// Terminates the current task with an error message.
//
// See the notes for `system_exit` regarding the behavior of the error handler
void system_exit_error(const char* title, const char* message,
const char* footer);
// Terminates the current task with a fatal error message.
//
// See the notes for `system_exit` regarding the behavior of the error handler
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

View File

@ -0,0 +1,107 @@
/*
* 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;
if (g_error_handler != NULL) {
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);
strncpy(pminfo.error.message, message, sizeof(pminfo.error.message) - 1);
strncpy(pminfo.error.footer, footer, sizeof(pminfo.error.footer) - 1);
if (g_error_handler != NULL) {
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);
strncpy(pminfo.fatal.expr, message, sizeof(pminfo.fatal.expr) - 1);
pminfo.fatal.line = line;
if (g_error_handler != NULL) {
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);
}

View File

@ -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,6 +56,8 @@ 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",

View File

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