mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 22:38:08 +00:00
refactor(core/embed): introduce system, tasks, applets and emergency mode
[no changelog]
This commit is contained in:
parent
1c991339ce
commit
35c6f52133
@ -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:
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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,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
|
||||
|
@ -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,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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
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
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
@ -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,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;
|
||||
}
|
||||
|
@ -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,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
177
core/embed/lib/rsod.c
Normal 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
|
@ -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
|
@ -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();
|
||||
|
||||
|
@ -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)];
|
||||
|
||||
@ -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();
|
||||
|
@ -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,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> {
|
||||
|
@ -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]
|
||||
|
81
core/embed/trezorhal/applet.h
Normal file
81
core/embed/trezorhal/applet.h
Normal 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
|
@ -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
|
73
core/embed/trezorhal/stm32f4/applet.c
Normal file
73
core/embed/trezorhal/stm32f4/applet.c
Normal 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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
// =============================================================================
|
||||
|
639
core/embed/trezorhal/stm32f4/systask.c
Normal file
639
core/embed/trezorhal/stm32f4/systask.c
Normal 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
|
310
core/embed/trezorhal/stm32f4/system.c
Normal file
310
core/embed/trezorhal/stm32f4/system.c
Normal 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
|
||||
);
|
||||
}
|
@ -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
core/embed/trezorhal/stm32u5/applet.c
Symbolic link
1
core/embed/trezorhal/stm32u5/applet.c
Symbolic link
@ -0,0 +1 @@
|
||||
../stm32f4/applet.c
|
@ -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
|
1
core/embed/trezorhal/stm32u5/systask.c
Symbolic link
1
core/embed/trezorhal/stm32u5/systask.c
Symbolic link
@ -0,0 +1 @@
|
||||
../stm32f4/systask.c
|
1
core/embed/trezorhal/stm32u5/system.c
Symbolic link
1
core/embed/trezorhal/stm32u5/system.c
Symbolic link
@ -0,0 +1 @@
|
||||
../stm32f4/system.c
|
@ -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
|
||||
|
182
core/embed/trezorhal/systask.h
Normal file
182
core/embed/trezorhal/systask.h
Normal 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
|
68
core/embed/trezorhal/system.h
Normal file
68
core/embed/trezorhal/system.h
Normal 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
|
107
core/embed/trezorhal/unix/system.c
Normal file
107
core/embed/trezorhal/unix/system.c
Normal 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);
|
||||
}
|
@ -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",
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user