mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-02 03:48:58 +00:00
refactor(core/embed): introduce system, tasks, applets and emergency mode
[no changelog]
This commit is contained in:
parent
854c4ae4d7
commit
4df485aa03
@ -78,6 +78,7 @@ SOURCE_MOD += [
|
|||||||
'embed/lib/gfx_bitblt_mono8.c',
|
'embed/lib/gfx_bitblt_mono8.c',
|
||||||
'embed/lib/image.c',
|
'embed/lib/image.c',
|
||||||
'embed/lib/mini_printf.c',
|
'embed/lib/mini_printf.c',
|
||||||
|
'embed/lib/rsod.c',
|
||||||
'embed/lib/terminal.c',
|
'embed/lib/terminal.c',
|
||||||
]
|
]
|
||||||
if NEW_RENDERING:
|
if NEW_RENDERING:
|
||||||
|
@ -117,6 +117,7 @@ SOURCE_MOD += [
|
|||||||
'embed/lib/gfx_bitblt_rgba8888.c',
|
'embed/lib/gfx_bitblt_rgba8888.c',
|
||||||
'embed/lib/image.c',
|
'embed/lib/image.c',
|
||||||
'embed/lib/mini_printf.c',
|
'embed/lib/mini_printf.c',
|
||||||
|
'embed/lib/rsod.c',
|
||||||
'embed/lib/terminal.c',
|
'embed/lib/terminal.c',
|
||||||
'embed/lib/unit_variant.c',
|
'embed/lib/unit_variant.c',
|
||||||
'vendor/micropython/lib/uzlib/adler32.c',
|
'vendor/micropython/lib/uzlib/adler32.c',
|
||||||
|
@ -112,6 +112,7 @@ SOURCE_MOD += [
|
|||||||
'embed/lib/gfx_bitblt_rgba8888.c',
|
'embed/lib/gfx_bitblt_rgba8888.c',
|
||||||
'embed/lib/image.c',
|
'embed/lib/image.c',
|
||||||
'embed/lib/mini_printf.c',
|
'embed/lib/mini_printf.c',
|
||||||
|
'embed/lib/rsod.c',
|
||||||
'embed/lib/terminal.c',
|
'embed/lib/terminal.c',
|
||||||
'embed/lib/unit_variant.c',
|
'embed/lib/unit_variant.c',
|
||||||
'vendor/micropython/lib/uzlib/adler32.c',
|
'vendor/micropython/lib/uzlib/adler32.c',
|
||||||
@ -148,7 +149,6 @@ SOURCE_BOOTLOADER = [
|
|||||||
SOURCE_TREZORHAL = [
|
SOURCE_TREZORHAL = [
|
||||||
'embed/trezorhal/unix/bootutils.c',
|
'embed/trezorhal/unix/bootutils.c',
|
||||||
'embed/trezorhal/unix/common.c',
|
'embed/trezorhal/unix/common.c',
|
||||||
'embed/trezorhal/unix/fault_handlers.c',
|
|
||||||
'embed/trezorhal/unix/flash.c',
|
'embed/trezorhal/unix/flash.c',
|
||||||
'embed/trezorhal/unix/flash_otp.c',
|
'embed/trezorhal/unix/flash_otp.c',
|
||||||
'embed/trezorhal/unix/mpu.c',
|
'embed/trezorhal/unix/mpu.c',
|
||||||
@ -156,6 +156,7 @@ SOURCE_TREZORHAL = [
|
|||||||
'embed/trezorhal/unix/random_delays.c',
|
'embed/trezorhal/unix/random_delays.c',
|
||||||
'embed/trezorhal/unix/rng.c',
|
'embed/trezorhal/unix/rng.c',
|
||||||
'embed/trezorhal/unix/secret.c',
|
'embed/trezorhal/unix/secret.c',
|
||||||
|
'embed/trezorhal/unix/system.c',
|
||||||
'embed/trezorhal/unix/systick.c',
|
'embed/trezorhal/unix/systick.c',
|
||||||
'embed/trezorhal/unix/systimer.c',
|
'embed/trezorhal/unix/systimer.c',
|
||||||
'embed/trezorhal/unix/usb.c',
|
'embed/trezorhal/unix/usb.c',
|
||||||
|
@ -235,6 +235,7 @@ SOURCE_MOD += [
|
|||||||
'embed/lib/gfx_bitblt_mono8.c',
|
'embed/lib/gfx_bitblt_mono8.c',
|
||||||
'embed/lib/image.c',
|
'embed/lib/image.c',
|
||||||
'embed/lib/mini_printf.c',
|
'embed/lib/mini_printf.c',
|
||||||
|
'embed/lib/rsod.c',
|
||||||
'embed/lib/terminal.c',
|
'embed/lib/terminal.c',
|
||||||
'embed/lib/translations.c',
|
'embed/lib/translations.c',
|
||||||
'embed/lib/unit_variant.c',
|
'embed/lib/unit_variant.c',
|
||||||
|
@ -237,6 +237,7 @@ SOURCE_MOD += [
|
|||||||
'embed/lib/gfx_bitblt_mono8.c',
|
'embed/lib/gfx_bitblt_mono8.c',
|
||||||
'embed/lib/image.c',
|
'embed/lib/image.c',
|
||||||
'embed/lib/mini_printf.c',
|
'embed/lib/mini_printf.c',
|
||||||
|
'embed/lib/rsod.c',
|
||||||
'embed/lib/terminal.c',
|
'embed/lib/terminal.c',
|
||||||
'embed/lib/translations.c',
|
'embed/lib/translations.c',
|
||||||
'embed/lib/unit_variant.c',
|
'embed/lib/unit_variant.c',
|
||||||
|
@ -222,6 +222,7 @@ SOURCE_MOD += [
|
|||||||
'embed/lib/gfx_bitblt_mono8.c',
|
'embed/lib/gfx_bitblt_mono8.c',
|
||||||
'embed/lib/image.c',
|
'embed/lib/image.c',
|
||||||
'embed/lib/mini_printf.c',
|
'embed/lib/mini_printf.c',
|
||||||
|
'embed/lib/rsod.c',
|
||||||
'embed/lib/terminal.c',
|
'embed/lib/terminal.c',
|
||||||
'embed/lib/translations.c',
|
'embed/lib/translations.c',
|
||||||
'embed/lib/unit_variant.c',
|
'embed/lib/unit_variant.c',
|
||||||
@ -246,7 +247,7 @@ CPPDEFINES_MOD += [
|
|||||||
|
|
||||||
if TREZOR_MODEL not in ('1', ):
|
if TREZOR_MODEL not in ('1', ):
|
||||||
CPPDEFINES_MOD += [
|
CPPDEFINES_MOD += [
|
||||||
# 'FANCY_FATAL_ERROR',
|
'FANCY_FATAL_ERROR',
|
||||||
]
|
]
|
||||||
|
|
||||||
CPPDEFINES_MOD += ['USE_SVC_SHUTDOWN']
|
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,
|
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,
|
CPPPATH=ALLPATHS,
|
||||||
CPPDEFINES=[
|
CPPDEFINES=[
|
||||||
'FIRMWARE',
|
'KERNEL',
|
||||||
'TREZOR_MODEL_'+TREZOR_MODEL,
|
'TREZOR_MODEL_'+TREZOR_MODEL,
|
||||||
'USE_HAL_DRIVER',
|
'USE_HAL_DRIVER',
|
||||||
'ARM_USER_MODE',
|
'ARM_USER_MODE',
|
||||||
|
@ -115,6 +115,7 @@ SOURCE_MOD += [
|
|||||||
'embed/lib/gfx_bitblt_mono8.c',
|
'embed/lib/gfx_bitblt_mono8.c',
|
||||||
'embed/lib/image.c',
|
'embed/lib/image.c',
|
||||||
'embed/lib/mini_printf.c',
|
'embed/lib/mini_printf.c',
|
||||||
|
'embed/lib/rsod.c',
|
||||||
'embed/lib/qr-code-generator/qrcodegen.c',
|
'embed/lib/qr-code-generator/qrcodegen.c',
|
||||||
'embed/lib/terminal.c',
|
'embed/lib/terminal.c',
|
||||||
'vendor/micropython/lib/uzlib/adler32.c',
|
'vendor/micropython/lib/uzlib/adler32.c',
|
||||||
|
@ -83,6 +83,7 @@ SOURCE_MOD += [
|
|||||||
'embed/lib/fonts/fonts.c',
|
'embed/lib/fonts/fonts.c',
|
||||||
'embed/lib/image.c',
|
'embed/lib/image.c',
|
||||||
'embed/lib/mini_printf.c',
|
'embed/lib/mini_printf.c',
|
||||||
|
'embed/lib/rsod.c',
|
||||||
'embed/lib/terminal.c',
|
'embed/lib/terminal.c',
|
||||||
'vendor/micropython/lib/uzlib/adler32.c',
|
'vendor/micropython/lib/uzlib/adler32.c',
|
||||||
'vendor/micropython/lib/uzlib/crc32.c',
|
'vendor/micropython/lib/uzlib/crc32.c',
|
||||||
|
@ -243,6 +243,7 @@ SOURCE_MOD += [
|
|||||||
'embed/lib/gfx_bitblt_mono8.c',
|
'embed/lib/gfx_bitblt_mono8.c',
|
||||||
'embed/lib/image.c',
|
'embed/lib/image.c',
|
||||||
'embed/lib/mini_printf.c',
|
'embed/lib/mini_printf.c',
|
||||||
|
'embed/lib/rsod.c',
|
||||||
'embed/lib/terminal.c',
|
'embed/lib/terminal.c',
|
||||||
'embed/lib/translations.c',
|
'embed/lib/translations.c',
|
||||||
'embed/lib/unit_variant.c',
|
'embed/lib/unit_variant.c',
|
||||||
@ -428,6 +429,7 @@ SOURCE_UNIX = [
|
|||||||
'embed/trezorhal/unix/mpu.c',
|
'embed/trezorhal/unix/mpu.c',
|
||||||
'embed/trezorhal/unix/random_delays.c',
|
'embed/trezorhal/unix/random_delays.c',
|
||||||
'embed/trezorhal/unix/rng.c',
|
'embed/trezorhal/unix/rng.c',
|
||||||
|
'embed/trezorhal/unix/system.c',
|
||||||
'embed/trezorhal/unix/systick.c',
|
'embed/trezorhal/unix/systick.c',
|
||||||
'embed/trezorhal/unix/systimer.c',
|
'embed/trezorhal/unix/systimer.c',
|
||||||
'embed/trezorhal/unix/time_estimate.c',
|
'embed/trezorhal/unix/time_estimate.c',
|
||||||
|
@ -21,18 +21,19 @@
|
|||||||
|
|
||||||
#include TREZOR_BOARD
|
#include TREZOR_BOARD
|
||||||
#include "board_capabilities.h"
|
#include "board_capabilities.h"
|
||||||
|
#include "bootutils.h"
|
||||||
#include "buffers.h"
|
#include "buffers.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compiler_traits.h"
|
#include "compiler_traits.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "display_draw.h"
|
#include "display_draw.h"
|
||||||
#include "fault_handlers.h"
|
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "mpu.h"
|
#include "mpu.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
#include "systimer.h"
|
#include "rsod.h"
|
||||||
|
#include "system.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
||||||
#ifdef USE_SD_CARD
|
#ifdef USE_SD_CARD
|
||||||
@ -232,9 +233,34 @@ static secbool copy_sdcard(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Initializes system in emergency mode and shows RSOD
|
||||||
|
static void enter_emergency_mode(const systask_postmortem_t *pminfo) {
|
||||||
|
// Initialize the system's core services
|
||||||
|
// (If the kernel crashes in emergency mode, we are out of options
|
||||||
|
// and show the RSOD without attempting to re-enter emergency mode)
|
||||||
|
system_init(&rsod_terminal);
|
||||||
|
|
||||||
|
// Initialize necessary drivers
|
||||||
|
display_init(DISPLAY_RESET_CONTENT);
|
||||||
|
|
||||||
|
// Show RSOD using the terminal
|
||||||
|
rsod_terminal(pminfo);
|
||||||
|
|
||||||
|
// Wait for the user to manually power off the device
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kernel panic handler
|
||||||
|
// (may be called from interrupt context)
|
||||||
|
static void kernel_panic(const systask_postmortem_t *pminfo) {
|
||||||
|
// Since the system state is unreliable, enter emergency mode
|
||||||
|
// and show the RSOD.
|
||||||
|
system_emergency_rescue(&enter_emergency_mode, pminfo);
|
||||||
|
// The previous function call never returns
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
systick_init();
|
system_init(&kernel_panic);
|
||||||
systimer_init();
|
|
||||||
|
|
||||||
reset_flags_reset();
|
reset_flags_reset();
|
||||||
|
|
||||||
@ -262,8 +288,6 @@ int main(void) {
|
|||||||
clear_otg_hs_memory();
|
clear_otg_hs_memory();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fault_handlers_init();
|
|
||||||
|
|
||||||
#ifdef USE_SDRAM
|
#ifdef USE_SDRAM
|
||||||
sdram_init();
|
sdram_init();
|
||||||
#endif
|
#endif
|
||||||
|
@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5);
|
|||||||
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
||||||
sram6_start = ORIGIN(SRAM6);
|
sram6_start = ORIGIN(SRAM6);
|
||||||
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
||||||
|
bss_start = ADDR(.bss);
|
||||||
|
bss_end = ADDR(.bss) + SIZEOF(.bss);
|
||||||
|
|
||||||
/* reserve 256 bytes for bootloader arguments */
|
/* reserve 256 bytes for bootloader arguments */
|
||||||
boot_args_start = ORIGIN(BOOT_ARGS);
|
boot_args_start = ORIGIN(BOOT_ARGS);
|
||||||
|
@ -25,15 +25,16 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "display_utils.h"
|
#include "display_utils.h"
|
||||||
#include "fault_handlers.h"
|
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "flash_otp.h"
|
#include "flash_otp.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "lowlevel.h"
|
#include "lowlevel.h"
|
||||||
#include "messages.pb.h"
|
#include "messages.pb.h"
|
||||||
#include "random_delays.h"
|
#include "random_delays.h"
|
||||||
|
#include "rsod.h"
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
#include "secret.h"
|
#include "secret.h"
|
||||||
|
#include "system.h"
|
||||||
#include "systimer.h"
|
#include "systimer.h"
|
||||||
|
|
||||||
#ifdef USE_DMA2D
|
#ifdef USE_DMA2D
|
||||||
@ -354,6 +355,35 @@ __attribute__((noreturn)) void jump_to_fw_through_reset(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Initializes system in emergency mode and shows RSOD
|
||||||
|
static void enter_emergency_mode(const systask_postmortem_t *pminfo) {
|
||||||
|
// Initialize the system's core services
|
||||||
|
// (If the kernel crashes in emergency mode, we are out of options
|
||||||
|
// and show the RSOD without attempting to re-enter emergency mode)
|
||||||
|
system_init(&rsod_terminal);
|
||||||
|
|
||||||
|
// Initialize necessary drivers
|
||||||
|
display_init(DISPLAY_RESET_CONTENT);
|
||||||
|
|
||||||
|
#ifdef FANCY_FATAL_ERROR
|
||||||
|
rsod_gui(pminfo);
|
||||||
|
#else
|
||||||
|
rsod_terminal(pminfo);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Wait for the user to manually power off the device
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kernel panic handler
|
||||||
|
// (may be called from interrupt context)
|
||||||
|
static void kernel_panic(const systask_postmortem_t *pminfo) {
|
||||||
|
// Since the system state is unreliable, enter emergency mode
|
||||||
|
// and show the RSOD.
|
||||||
|
system_emergency_rescue(&enter_emergency_mode, pminfo);
|
||||||
|
// The previous function call never returns
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef TREZOR_EMULATOR
|
#ifndef TREZOR_EMULATOR
|
||||||
int main(void) {
|
int main(void) {
|
||||||
#else
|
#else
|
||||||
@ -361,8 +391,7 @@ int bootloader_main(void) {
|
|||||||
#endif
|
#endif
|
||||||
secbool stay_in_bootloader = secfalse;
|
secbool stay_in_bootloader = secfalse;
|
||||||
|
|
||||||
systick_init();
|
system_init(&kernel_panic);
|
||||||
systimer_init();
|
|
||||||
|
|
||||||
rdi_init();
|
rdi_init();
|
||||||
|
|
||||||
@ -402,8 +431,6 @@ int bootloader_main(void) {
|
|||||||
|
|
||||||
ui_screen_boot_stage_1(false);
|
ui_screen_boot_stage_1(false);
|
||||||
|
|
||||||
fault_handlers_init();
|
|
||||||
|
|
||||||
#ifdef TREZOR_EMULATOR
|
#ifdef TREZOR_EMULATOR
|
||||||
// wait a bit so that the empty lock icon is visible
|
// wait a bit so that the empty lock icon is visible
|
||||||
// (on a real device, we are waiting for touch init which takes longer)
|
// (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);
|
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
||||||
sram6_start = ORIGIN(SRAM6);
|
sram6_start = ORIGIN(SRAM6);
|
||||||
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
||||||
|
bss_start = ADDR(.bss);
|
||||||
|
bss_end = ADDR(.bss) + SIZEOF(.bss);
|
||||||
|
|
||||||
/* reserve 256 bytes for bootloader arguments */
|
/* reserve 256 bytes for bootloader arguments */
|
||||||
boot_args_start = ORIGIN(BOOT_ARGS);
|
boot_args_start = ORIGIN(BOOT_ARGS);
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "random_delays.h"
|
#include "random_delays.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
|
#include "system.h"
|
||||||
#ifdef USE_TOUCH
|
#ifdef USE_TOUCH
|
||||||
#include "touch.h"
|
#include "touch.h"
|
||||||
#endif
|
#endif
|
||||||
@ -202,9 +203,36 @@ static void check_bootloader_version(void) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void error_handler(systask_t *task) { rsod_terminal(&task->pminfo); }
|
||||||
|
|
||||||
|
// Initializes system in emergency mode and shows RSOD
|
||||||
|
static void enter_emergency_mode(const systask_postmortem_t *pminfo) {
|
||||||
|
// Initialize the system's core services
|
||||||
|
// (If the kernel crashes in emergency mode, we are out of options
|
||||||
|
// and show the RSOD without attempting to re-enter emergency mode)
|
||||||
|
system_init(&rsod_terminal);
|
||||||
|
|
||||||
|
// Initialize necessary drivers
|
||||||
|
display_init(DISPLAY_RESET_CONTENT);
|
||||||
|
|
||||||
|
// Show RSOD using the terminal
|
||||||
|
rsod_terminal(pminfo);
|
||||||
|
|
||||||
|
// Wait for the user to manually power off the device
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kernel panic handler
|
||||||
|
// (may be called from interrupt context)
|
||||||
|
static void kernel_panic(const systask_postmortem_t *pminfo) {
|
||||||
|
// Since the system state is unreliable, enter emergency mode
|
||||||
|
// and show the RSOD.
|
||||||
|
system_emergency_rescue(&enter_emergency_mode, pminfo);
|
||||||
|
// The previous function call never returns
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
systick_init();
|
system_init(&kernel_panic);
|
||||||
systimer_init();
|
|
||||||
|
|
||||||
rdi_init();
|
rdi_init();
|
||||||
#ifdef USE_TOUCH
|
#ifdef USE_TOUCH
|
||||||
|
@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5);
|
|||||||
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
||||||
sram6_start = ORIGIN(SRAM6);
|
sram6_start = ORIGIN(SRAM6);
|
||||||
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
||||||
|
bss_start = ADDR(.bss);
|
||||||
|
bss_end = ADDR(.bss) + SIZEOF(.bss);
|
||||||
|
|
||||||
/* reserve 256 bytes for bootloader arguments */
|
/* reserve 256 bytes for bootloader arguments */
|
||||||
boot_args_start = ORIGIN(BOOT_ARGS);
|
boot_args_start = ORIGIN(BOOT_ARGS);
|
||||||
|
@ -37,16 +37,28 @@
|
|||||||
#include "ports/stm32/pendsv.h"
|
#include "ports/stm32/pendsv.h"
|
||||||
|
|
||||||
#include "error_handling.h"
|
#include "error_handling.h"
|
||||||
|
#include "rsod.h"
|
||||||
#include "rust_ui_common.h"
|
#include "rust_ui_common.h"
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
|
#include "systask.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
#ifdef USE_SECP256K1_ZKP
|
#ifdef USE_SECP256K1_ZKP
|
||||||
#include "zkp_context.h"
|
#include "zkp_context.h"
|
||||||
#endif
|
#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();
|
screen_boot_stage_2();
|
||||||
|
|
||||||
|
// uint32_t *p = 0;
|
||||||
|
// *p = 0;
|
||||||
|
|
||||||
#ifdef USE_SECP256K1_ZKP
|
#ifdef USE_SECP256K1_ZKP
|
||||||
ensure(sectrue * (zkp_context_init() == 0), NULL);
|
ensure(sectrue * (zkp_context_init() == 0), NULL);
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,15 +16,13 @@ MEMORY {
|
|||||||
main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */
|
main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */
|
||||||
_sstack = ORIGIN(SRAM2);
|
_sstack = ORIGIN(SRAM2);
|
||||||
_estack = main_stack_base;
|
_estack = main_stack_base;
|
||||||
|
_stack_size = SIZEOF(.stack);
|
||||||
|
|
||||||
/* used by the startup code to populate variables used by the C code */
|
/* used by the startup code to populate variables used by the C code */
|
||||||
data_lma = LOADADDR(.data);
|
data_lma = LOADADDR(.data);
|
||||||
data_vma = ADDR(.data);
|
data_vma = ADDR(.data);
|
||||||
data_size = SIZEOF(.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 */
|
/* used by the startup code to populate variables used by the C code */
|
||||||
confidential_lma = LOADADDR(.confidential);
|
confidential_lma = LOADADDR(.confidential);
|
||||||
confidential_vma = ADDR(.confidential);
|
confidential_vma = ADDR(.confidential);
|
||||||
@ -43,6 +41,8 @@ sram5_start = ORIGIN(SRAM5);
|
|||||||
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
||||||
sram6_start = ORIGIN(SRAM6);
|
sram6_start = ORIGIN(SRAM6);
|
||||||
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
||||||
|
bss_start = ADDR(.bss);
|
||||||
|
bss_end = ADDR(.bss) + SIZEOF(.bss);
|
||||||
|
|
||||||
/* reserve 256 bytes for bootloader arguments */
|
/* reserve 256 bytes for bootloader arguments */
|
||||||
boot_args_start = ORIGIN(BOOT_ARGS);
|
boot_args_start = ORIGIN(BOOT_ARGS);
|
||||||
|
@ -6,21 +6,17 @@
|
|||||||
.type reset_handler, STT_FUNC
|
.type reset_handler, STT_FUNC
|
||||||
reset_handler:
|
reset_handler:
|
||||||
|
|
||||||
// setup environment for subsequent stage of code
|
push {r0, r1}
|
||||||
ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM
|
|
||||||
ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM
|
|
||||||
ldr r2, =0 // r2 - the word-sized value to be written
|
|
||||||
bl memset_reg
|
|
||||||
|
|
||||||
ldr r0, =boot_args_start // r0 - point to beginning of BOOT_ARGS
|
// setup the stack protector with provided random value
|
||||||
ldr r1, =boot_args_end // r1 - point to byte after the end of BOOT_ARGS
|
ldr r0, = __stack_chk_guard
|
||||||
ldr r2, =0 // r2 - the word-sized value to be written
|
str r2, [r0]
|
||||||
bl memset_reg
|
|
||||||
|
|
||||||
ldr r0, =sram_start // r0 - point to beginning of SRAM
|
ldr r0, =bss_start
|
||||||
ldr r1, =sram_end // r1 - point to byte after the end of SRAM
|
ldr r1, =0
|
||||||
ldr r2, =0 // r2 - the word-sized value to be written
|
ldr r2, =bss_end
|
||||||
bl memset_reg
|
sub r2, r2, r0
|
||||||
|
bl memset
|
||||||
|
|
||||||
// copy data in from flash
|
// copy data in from flash
|
||||||
ldr r0, =data_vma // dst addr
|
ldr r0, =data_vma // dst addr
|
||||||
@ -28,15 +24,14 @@ reset_handler:
|
|||||||
ldr r2, =data_size // size in bytes
|
ldr r2, =data_size // size in bytes
|
||||||
bl memcpy
|
bl memcpy
|
||||||
|
|
||||||
// setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value
|
pop {r0, r1}
|
||||||
bl rng_get
|
|
||||||
ldr r1, = __stack_chk_guard
|
|
||||||
str r0, [r1]
|
|
||||||
|
|
||||||
// enter the application code
|
// enter the application code
|
||||||
|
// returns exit code in r0
|
||||||
bl main
|
bl main
|
||||||
|
|
||||||
b secure_shutdown
|
// terminate the application
|
||||||
|
// pass exit code in r0
|
||||||
|
b system_exit
|
||||||
|
|
||||||
.end
|
.end
|
||||||
|
@ -6,53 +6,38 @@
|
|||||||
.type reset_handler, STT_FUNC
|
.type reset_handler, STT_FUNC
|
||||||
reset_handler:
|
reset_handler:
|
||||||
|
|
||||||
// set the stack protection
|
push {r0, r1}
|
||||||
ldr r0, =_sstack
|
|
||||||
add r0, r0, #128 // safety margin for the exception frame
|
// setup the stack protector with provided random value
|
||||||
msr PSPLIM, r0
|
ldr r0, = __stack_chk_guard
|
||||||
|
str r2, [r0]
|
||||||
|
|
||||||
ldr r0, =bss_start
|
ldr r0, =bss_start
|
||||||
ldr r1, =bss_end
|
ldr r1, =0
|
||||||
ldr r2, =0
|
ldr r2, =bss_end
|
||||||
bl memset_reg
|
sub r2, r2, r0
|
||||||
|
bl memset
|
||||||
|
|
||||||
// copy data in from flash
|
// copy data in from flash
|
||||||
ldr r0, =data_vma // dst addr
|
ldr r0, =data_vma
|
||||||
ldr r1, =data_lma // src addr
|
ldr r1, =data_lma
|
||||||
ldr r2, =data_size // size in bytes
|
ldr r2, =data_size
|
||||||
bl memcpy
|
bl memcpy
|
||||||
|
|
||||||
// copy confidential data in from flash
|
// copy confidential data in from flash
|
||||||
ldr r0, =confidential_vma // dst addr
|
ldr r0, =confidential_vma
|
||||||
ldr r1, =confidential_lma // src addr
|
ldr r1, =confidential_lma
|
||||||
ldr r2, =confidential_size // size in bytes
|
ldr r2, =confidential_size
|
||||||
bl memcpy
|
bl memcpy
|
||||||
|
|
||||||
// setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value
|
pop {r0, r1}
|
||||||
bl rng_get
|
|
||||||
ldr r1, = __stack_chk_guard
|
|
||||||
str r0, [r1]
|
|
||||||
|
|
||||||
// enter the application code
|
// enter the application code
|
||||||
|
// returns exit code in r0
|
||||||
bl main
|
bl main
|
||||||
|
|
||||||
b secure_shutdown
|
// terminate the application
|
||||||
|
// pass exit code in r0
|
||||||
|
b system_exit
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
.end
|
.end
|
||||||
|
@ -42,15 +42,16 @@
|
|||||||
#include "compiler_traits.h"
|
#include "compiler_traits.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "entropy.h"
|
#include "entropy.h"
|
||||||
#include "fault_handlers.h"
|
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "memzero.h"
|
#include "memzero.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "mpu.h"
|
#include "mpu.h"
|
||||||
#include "random_delays.h"
|
#include "random_delays.h"
|
||||||
|
#include "rsod.h"
|
||||||
#include "rust_ui.h"
|
#include "rust_ui.h"
|
||||||
#include "secure_aes.h"
|
#include "secure_aes.h"
|
||||||
|
#include "system.h"
|
||||||
#include "systimer.h"
|
#include "systimer.h"
|
||||||
|
|
||||||
#include TREZOR_BOARD
|
#include TREZOR_BOARD
|
||||||
@ -128,8 +129,7 @@ static void optiga_log_hex(const char *prefix, const uint8_t *data,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
systick_init();
|
system_init(&rsod_gui);
|
||||||
systimer_init();
|
|
||||||
|
|
||||||
rdi_init();
|
rdi_init();
|
||||||
|
|
||||||
@ -186,8 +186,6 @@ int main(void) {
|
|||||||
|
|
||||||
// Init peripherals
|
// Init peripherals
|
||||||
|
|
||||||
fault_handlers_init();
|
|
||||||
|
|
||||||
#if defined TREZOR_MODEL_T
|
#if defined TREZOR_MODEL_T
|
||||||
set_core_clock(CLOCK_180_MHZ);
|
set_core_clock(CLOCK_180_MHZ);
|
||||||
#endif
|
#endif
|
||||||
|
@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5);
|
|||||||
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
||||||
sram6_start = ORIGIN(SRAM6);
|
sram6_start = ORIGIN(SRAM6);
|
||||||
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
||||||
|
bss_start = ADDR(.bss);
|
||||||
|
bss_end = ADDR(.bss) + SIZEOF(.bss);
|
||||||
|
|
||||||
/* reserve 256 bytes for bootloader arguments */
|
/* reserve 256 bytes for bootloader arguments */
|
||||||
boot_args_start = ORIGIN(BOOT_ARGS);
|
boot_args_start = ORIGIN(BOOT_ARGS);
|
||||||
|
@ -19,27 +19,29 @@
|
|||||||
|
|
||||||
#include STM32_HAL_H
|
#include STM32_HAL_H
|
||||||
|
|
||||||
#include "image.h"
|
#include <string.h>
|
||||||
#include "irq.h"
|
|
||||||
#include "syscall.h"
|
|
||||||
|
|
||||||
|
#include "applet.h"
|
||||||
#include "board_capabilities.h"
|
#include "board_capabilities.h"
|
||||||
|
#include "bootutils.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "dma2d.h"
|
#include "dma2d.h"
|
||||||
#include "entropy.h"
|
#include "entropy.h"
|
||||||
#include "fault_handlers.h"
|
|
||||||
#include "haptic.h"
|
#include "haptic.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "irq.h"
|
||||||
#include "memzero.h"
|
#include "memzero.h"
|
||||||
#include "mpu.h"
|
#include "mpu.h"
|
||||||
#include "optiga_commands.h"
|
#include "optiga_commands.h"
|
||||||
#include "optiga_transport.h"
|
#include "optiga_transport.h"
|
||||||
#include "random_delays.h"
|
#include "random_delays.h"
|
||||||
|
#include "rsod.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
#include "secret.h"
|
#include "secret.h"
|
||||||
#include "secure_aes.h"
|
#include "secure_aes.h"
|
||||||
|
#include "system.h"
|
||||||
#include "systick.h"
|
#include "systick.h"
|
||||||
#include "systimer.h"
|
|
||||||
#include "tamper.h"
|
#include "tamper.h"
|
||||||
#include "touch.h"
|
#include "touch.h"
|
||||||
#include "unit_variant.h"
|
#include "unit_variant.h"
|
||||||
@ -65,15 +67,6 @@ static void optiga_log_hex(const char *prefix, const uint8_t *data,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void drivers_init() {
|
void drivers_init() {
|
||||||
syscall_init();
|
|
||||||
|
|
||||||
systick_init();
|
|
||||||
systimer_init();
|
|
||||||
|
|
||||||
fault_handlers_init();
|
|
||||||
|
|
||||||
systick_delay_ms(10);
|
|
||||||
|
|
||||||
#if defined TREZOR_MODEL_T
|
#if defined TREZOR_MODEL_T
|
||||||
set_core_clock(CLOCK_180_MHZ);
|
set_core_clock(CLOCK_180_MHZ);
|
||||||
#endif
|
#endif
|
||||||
@ -178,14 +171,88 @@ void drivers_init() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initializes coreapp applet
|
||||||
|
static void coreapp_init(applet_t *applet) {
|
||||||
|
applet_header_t *coreapp_header =
|
||||||
|
(applet_header_t *)(COREAPP_START + IMAGE_HEADER_SIZE + 0x0400);
|
||||||
|
|
||||||
|
applet_layout_t coreapp_layout = {
|
||||||
|
0
|
||||||
|
/* .data1_start = COREAPP_RAM1_START,
|
||||||
|
.data1_size = COREAPP_RAM1_SIZE,
|
||||||
|
.data2_start = COREAPP_RAM2_START,
|
||||||
|
.data2_size = COREAPP_RAM2_SIZE,*/
|
||||||
|
};
|
||||||
|
|
||||||
|
applet_init(applet, coreapp_header, &coreapp_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows RSOD (Red Screen of Death)
|
||||||
|
static void show_rsod(const systask_postmortem_t *pminfo) {
|
||||||
|
#ifdef FANCY_FATAL_ERROR
|
||||||
|
applet_t coreapp;
|
||||||
|
coreapp_init(&coreapp);
|
||||||
|
|
||||||
|
// Reset and run the coreapp in RSOD mode
|
||||||
|
applet_reset(&coreapp, 1, pminfo, sizeof(systask_postmortem_t));
|
||||||
|
systask_yield_to(&coreapp.task);
|
||||||
|
|
||||||
|
if (coreapp.task.pminfo.reason == TASK_TERM_REASON_EXIT) {
|
||||||
|
// If the RSOD was shown successfully, proceed to shutdown
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If coreapp crashed, fallback to showing the error using a terminal
|
||||||
|
rsod_terminal(pminfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializes system in emergency mode and shows RSOD
|
||||||
|
static void enter_emergency_mode(const systask_postmortem_t *pminfo) {
|
||||||
|
// Initialize the system's core services
|
||||||
|
// (If the kernel crashes in emergency mode, we are out of options
|
||||||
|
// and show the RSOD without attempting to re-enter emergency mode)
|
||||||
|
system_init(&rsod_terminal);
|
||||||
|
|
||||||
|
// Initialize necessary drivers
|
||||||
|
display_init(DISPLAY_RESET_CONTENT);
|
||||||
|
|
||||||
|
// Show RSOD
|
||||||
|
show_rsod(pminfo);
|
||||||
|
|
||||||
|
// Wait for the user to manually power off the device
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kernel panic handler
|
||||||
|
// (may be called from interrupt context)
|
||||||
|
static void kernel_panic(const systask_postmortem_t *pminfo) {
|
||||||
|
// Since the system state is unreliable, enter emergency mode
|
||||||
|
// and show the RSOD.
|
||||||
|
system_emergency_rescue(&enter_emergency_mode, pminfo);
|
||||||
|
// The previous function call never returns
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
mpu_init();
|
// Initialize system's core services
|
||||||
|
system_init(&kernel_panic);
|
||||||
|
|
||||||
// Initialize hardware drivers
|
// Initialize hardware drivers
|
||||||
drivers_init();
|
drivers_init();
|
||||||
|
|
||||||
// Start unprivileged application
|
// Initialize coreapp task
|
||||||
start_unprivileged_app();
|
applet_t coreapp;
|
||||||
|
coreapp_init(&coreapp);
|
||||||
|
|
||||||
|
// Reset and run the coreapp
|
||||||
|
applet_reset(&coreapp, 0, NULL, 0);
|
||||||
|
systask_yield_to(&coreapp.task);
|
||||||
|
|
||||||
|
// Coreapp crashed, show RSOD
|
||||||
|
show_rsod(&coreapp.task.pminfo);
|
||||||
|
|
||||||
|
// Wait for the user to manually power off the device
|
||||||
|
secure_shutdown();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,9 @@ _estack = main_stack_base;
|
|||||||
data_lma = LOADADDR(.data);
|
data_lma = LOADADDR(.data);
|
||||||
data_vma = ADDR(.data);
|
data_vma = ADDR(.data);
|
||||||
data_size = SIZEOF(.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 */
|
/* used by the startup code to populate variables used by the C code */
|
||||||
confidential_lma = LOADADDR(.confidential);
|
confidential_lma = LOADADDR(.confidential);
|
||||||
|
@ -18,25 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#ifdef TREZOR_EMULATOR
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "bootutils.h"
|
|
||||||
#include "display.h"
|
|
||||||
#include "error_handling.h"
|
#include "error_handling.h"
|
||||||
#include "mini_printf.h"
|
#include "system.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
|
|
||||||
|
|
||||||
uint32_t __stack_chk_guard = 0;
|
uint32_t __stack_chk_guard = 0;
|
||||||
|
|
||||||
@ -48,26 +33,16 @@ void __attribute__((noreturn, used)) __stack_chk_fail(void) {
|
|||||||
|
|
||||||
void __attribute__((noreturn))
|
void __attribute__((noreturn))
|
||||||
error_shutdown_ex(const char *title, const char *message, const char *footer) {
|
error_shutdown_ex(const char *title, const char *message, const char *footer) {
|
||||||
if (title == NULL) {
|
if (title == NULL) { // !@# remove
|
||||||
title = "INTERNAL ERROR";
|
title = "INTERNAL ERROR";
|
||||||
}
|
}
|
||||||
if (footer == NULL) {
|
if (footer == NULL) { // !@# remove
|
||||||
footer = "PLEASE VISIT\nTREZOR.IO/RSOD";
|
footer = "PLEASE VISIT\nTREZOR.IO/RSOD";
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FANCY_FATAL_ERROR
|
system_exit_error(title, message, footer);
|
||||||
error_shutdown_rust(title, message, footer);
|
while (1)
|
||||||
#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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __attribute__((noreturn)) error_shutdown(const char *message) {
|
void __attribute__((noreturn)) error_shutdown(const char *message) {
|
||||||
@ -76,39 +51,9 @@ void __attribute__((noreturn)) error_shutdown(const char *message) {
|
|||||||
|
|
||||||
void __attribute__((noreturn))
|
void __attribute__((noreturn))
|
||||||
__fatal_error(const char *msg, const char *file, int line) {
|
__fatal_error(const char *msg, const char *file, int line) {
|
||||||
#ifdef TREZOR_EMULATOR
|
system_exit_fatal(msg, file, line);
|
||||||
fprintf(stderr, "FATAL ERROR: %s\n", msg);
|
while (1)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __attribute__((noreturn)) show_wipe_code_screen(void) {
|
void __attribute__((noreturn)) show_wipe_code_screen(void) {
|
||||||
|
141
core/embed/lib/rsod.c
Normal file
141
core/embed/lib/rsod.c
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rsod.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "mini_printf.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "terminal.h"
|
||||||
|
|
||||||
|
#define RSOD_DEFAULT_TITLE "INTERNAL ERROR";
|
||||||
|
#define RSOD_DEFAULT_MESSAGE "UNSPECIFIED";
|
||||||
|
#define RSOD_DEFAULT_FOOTER "PLEASE VISIT TREZOR.IO/RSOD";
|
||||||
|
#define RSOD_EXIT_MESSAGE "EXIT %d"
|
||||||
|
|
||||||
|
#ifdef KERNEL_MODE
|
||||||
|
|
||||||
|
#define RSOD_FG_COLOR COLOR_WHITE
|
||||||
|
|
||||||
|
#ifdef USE_RGB_COLORS
|
||||||
|
#define RSOD_BG_COLOR RGB16(0x7F, 0x00, 0x00)
|
||||||
|
#else
|
||||||
|
#define RSOD_BG_COLOR COLOR_BLACK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void rsod_terminal(const systask_postmortem_t* info) {
|
||||||
|
display_orientation(0);
|
||||||
|
term_set_color(RSOD_FG_COLOR, RSOD_BG_COLOR);
|
||||||
|
|
||||||
|
const char* title = RSOD_DEFAULT_TITLE;
|
||||||
|
const char* message = RSOD_DEFAULT_MESSAGE;
|
||||||
|
const char* footer = RSOD_DEFAULT_FOOTER;
|
||||||
|
const char* file = NULL;
|
||||||
|
char message_buf[32] = {0};
|
||||||
|
int line = 0;
|
||||||
|
|
||||||
|
switch (info->reason) {
|
||||||
|
case TASK_TERM_REASON_EXIT:
|
||||||
|
mini_snprintf(message_buf, sizeof(message_buf), RSOD_EXIT_MESSAGE,
|
||||||
|
info->exit.code);
|
||||||
|
message = message_buf;
|
||||||
|
break;
|
||||||
|
case TASK_TERM_REASON_ERROR:
|
||||||
|
title = info->error.title;
|
||||||
|
message = info->error.message;
|
||||||
|
footer = info->error.footer;
|
||||||
|
break;
|
||||||
|
case TASK_TERM_REASON_FATAL:
|
||||||
|
message = info->fatal.expr;
|
||||||
|
file = info->fatal.file;
|
||||||
|
line = info->fatal.line;
|
||||||
|
break;
|
||||||
|
case TASK_TERM_REASON_FAULT:
|
||||||
|
message = system_fault_message(&info->fault);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (title != NULL) {
|
||||||
|
term_printf("%s\n", title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message != NULL) {
|
||||||
|
term_printf("msg : %s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
term_printf("file: %s:%d\n", file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SCM_REVISION
|
||||||
|
const uint8_t* rev = (const uint8_t*)SCM_REVISION;
|
||||||
|
term_printf("rev : %02x%02x%02x%02x%02x\n", rev[0], rev[1], rev[2], rev[3],
|
||||||
|
rev[4]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (footer != NULL) {
|
||||||
|
term_printf("\n%s\n", footer);
|
||||||
|
}
|
||||||
|
|
||||||
|
display_backlight(255);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // KERNEL_MODE
|
||||||
|
|
||||||
|
#if defined(FIRMWARE) || defined(BOOTLOADER)
|
||||||
|
|
||||||
|
#include "rust_ui.h"
|
||||||
|
|
||||||
|
void rsod_gui(const systask_postmortem_t* info) {
|
||||||
|
const char* title = RSOD_DEFAULT_TITLE;
|
||||||
|
const char* message = RSOD_DEFAULT_MESSAGE;
|
||||||
|
const char* footer = RSOD_DEFAULT_FOOTER;
|
||||||
|
char message_buf[128] = {0};
|
||||||
|
|
||||||
|
switch (info->reason) {
|
||||||
|
case TASK_TERM_REASON_EXIT:
|
||||||
|
mini_snprintf(message_buf, sizeof(message_buf), RSOD_EXIT_MESSAGE,
|
||||||
|
info->exit.code);
|
||||||
|
message = message_buf;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TASK_TERM_REASON_ERROR:
|
||||||
|
title = info->error.title;
|
||||||
|
message = info->error.message;
|
||||||
|
footer = info->error.footer;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TASK_TERM_REASON_FATAL:
|
||||||
|
message = info->fatal.expr;
|
||||||
|
if (message[0] == '\0') {
|
||||||
|
mini_snprintf(message_buf, sizeof(message_buf), "%s:%u",
|
||||||
|
info->fatal.file, (unsigned int)info->fatal.line);
|
||||||
|
message = message_buf;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TASK_TERM_REASON_FAULT:
|
||||||
|
message = system_fault_message(&info->fault);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the RSOD in Rust
|
||||||
|
display_rsod_rust(title, message, footer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -17,6 +17,13 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <fault_handlers.h>
|
#ifndef LIB_RSOD_H
|
||||||
|
#define LIB_RSOD_H
|
||||||
|
|
||||||
void fault_handlers_init(void) {}
|
#include "systask.h"
|
||||||
|
|
||||||
|
void rsod_terminal(const systask_postmortem_t* info);
|
||||||
|
|
||||||
|
void rsod_gui(const systask_postmortem_t* info);
|
||||||
|
|
||||||
|
#endif // LIB_RSOD_H
|
@ -31,7 +31,6 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "display_draw.h"
|
#include "display_draw.h"
|
||||||
#include "display_utils.h"
|
#include "display_utils.h"
|
||||||
#include "fault_handlers.h"
|
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "flash_otp.h"
|
#include "flash_otp.h"
|
||||||
#include "fwutils.h"
|
#include "fwutils.h"
|
||||||
@ -41,9 +40,11 @@
|
|||||||
#include "mpu.h"
|
#include "mpu.h"
|
||||||
#include "prodtest_common.h"
|
#include "prodtest_common.h"
|
||||||
#include "random_delays.h"
|
#include "random_delays.h"
|
||||||
|
#include "rsod.h"
|
||||||
#include "sbu.h"
|
#include "sbu.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
|
#include "system.h"
|
||||||
#include "systimer.h"
|
#include "systimer.h"
|
||||||
#include "touch.h"
|
#include "touch.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
@ -778,10 +779,35 @@ void cpuid_read(void) {
|
|||||||
|
|
||||||
#define BACKLIGHT_NORMAL 150
|
#define BACKLIGHT_NORMAL 150
|
||||||
|
|
||||||
|
// Initializes system in emergency mode and shows RSOD
|
||||||
|
static void enter_emergency_mode(const systask_postmortem_t *pminfo) {
|
||||||
|
// Initialize the system's core services
|
||||||
|
// (If the kernel crashes in emergency mode, we are out of options
|
||||||
|
// and show the RSOD without attempting to re-enter emergency mode)
|
||||||
|
system_init(&rsod_terminal);
|
||||||
|
|
||||||
|
// Initialize necessary drivers
|
||||||
|
display_init(DISPLAY_RESET_CONTENT);
|
||||||
|
|
||||||
|
// Show RSOD
|
||||||
|
rsod_terminal(pminfo);
|
||||||
|
|
||||||
|
// Wait for the user to manually power off the device
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kernel panic handler
|
||||||
|
// (may be called from interrupt context)
|
||||||
|
static void kernel_panic(const systask_postmortem_t *pminfo) {
|
||||||
|
// Since the system state is unreliable, enter emergency mode
|
||||||
|
// and show the RSOD.
|
||||||
|
system_emergency_rescue(&enter_emergency_mode, pminfo);
|
||||||
|
// The previous function call never returns
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
systick_init();
|
system_init(&kernel_panic);
|
||||||
systimer_init();
|
|
||||||
rdi_init();
|
|
||||||
display_init(DISPLAY_RETAIN_CONTENT);
|
display_init(DISPLAY_RETAIN_CONTENT);
|
||||||
|
|
||||||
#ifdef STM32U5
|
#ifdef STM32U5
|
||||||
@ -819,8 +845,6 @@ int main(void) {
|
|||||||
pair_optiga();
|
pair_optiga();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fault_handlers_init();
|
|
||||||
|
|
||||||
display_clear();
|
display_clear();
|
||||||
draw_welcome_screen();
|
draw_welcome_screen();
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5);
|
|||||||
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
||||||
sram6_start = ORIGIN(SRAM6);
|
sram6_start = ORIGIN(SRAM6);
|
||||||
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
||||||
|
bss_start = ADDR(.bss);
|
||||||
|
bss_end = ADDR(.bss) + SIZEOF(.bss);
|
||||||
|
|
||||||
/* reserve 256 bytes for bootloader arguments */
|
/* reserve 256 bytes for bootloader arguments */
|
||||||
boot_args_start = ORIGIN(BOOT_ARGS);
|
boot_args_start = ORIGIN(BOOT_ARGS);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include STM32_HAL_H
|
#include STM32_HAL_H
|
||||||
|
|
||||||
|
#include "bootutils.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "display_draw.h"
|
#include "display_draw.h"
|
||||||
@ -30,9 +31,11 @@
|
|||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
|
#include "rsod.h"
|
||||||
#include "sbu.h"
|
#include "sbu.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
|
#include "system.h"
|
||||||
#include "systimer.h"
|
#include "systimer.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "touch.h"
|
#include "touch.h"
|
||||||
@ -43,7 +46,7 @@
|
|||||||
|
|
||||||
static void progress_callback(int pos, int len) { term_printf("."); }
|
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) {
|
uint32_t length) {
|
||||||
static uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)];
|
static uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)];
|
||||||
|
|
||||||
@ -68,9 +71,34 @@ static void flash_from_sdcard(const flash_area_t* area, uint32_t source,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initializes system in emergency mode and shows RSOD
|
||||||
|
static void enter_emergency_mode(const systask_postmortem_t *pminfo) {
|
||||||
|
// Initialize the system's core services
|
||||||
|
// (If the kernel crashes in emergency mode, we are out of options
|
||||||
|
// and show the RSOD without attempting to re-enter emergency mode)
|
||||||
|
system_init(&rsod_terminal);
|
||||||
|
|
||||||
|
// Initialize necessary drivers
|
||||||
|
display_init(DISPLAY_RESET_CONTENT);
|
||||||
|
|
||||||
|
// Show RSOD using the terminal
|
||||||
|
rsod_terminal(pminfo);
|
||||||
|
|
||||||
|
// Wait for the user to manually power off the device
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kernel panic handler
|
||||||
|
// (may be called from interrupt context)
|
||||||
|
static void kernel_panic(const systask_postmortem_t *pminfo) {
|
||||||
|
// Since the system state is unreliable, enter emergency mode
|
||||||
|
// and show the RSOD.
|
||||||
|
system_emergency_rescue(&enter_emergency_mode, pminfo);
|
||||||
|
// The previous function call never returns
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
systick_init();
|
system_init(&kernel_panic);
|
||||||
systimer_init();
|
|
||||||
|
|
||||||
sdcard_init();
|
sdcard_init();
|
||||||
touch_init();
|
touch_init();
|
||||||
|
@ -40,6 +40,8 @@ sram5_start = ORIGIN(SRAM5);
|
|||||||
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5);
|
||||||
sram6_start = ORIGIN(SRAM6);
|
sram6_start = ORIGIN(SRAM6);
|
||||||
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6);
|
||||||
|
bss_start = ADDR(.bss);
|
||||||
|
bss_end = ADDR(.bss) + SIZEOF(.bss);
|
||||||
|
|
||||||
/* reserve 256 bytes for bootloader arguments */
|
/* reserve 256 bytes for bootloader arguments */
|
||||||
boot_args_start = ORIGIN(BOOT_ARGS);
|
boot_args_start = ORIGIN(BOOT_ARGS);
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
__attribute__((noreturn)) void error_shutdown_rust(const char* title,
|
void display_rsod_rust(const char* title, const char* message,
|
||||||
const char* msg,
|
const char* footer);
|
||||||
const char* footer);
|
|
||||||
|
|
||||||
void screen_boot_stage_2(void);
|
void screen_boot_stage_2(void);
|
||||||
|
|
||||||
|
@ -1,31 +1,24 @@
|
|||||||
mod ffi {
|
mod ffi {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// trezorhal/bootuils.c
|
// bootutils.h
|
||||||
pub fn secure_shutdown() -> !;
|
pub fn error_shutdown(msg: *const cty::c_char) -> !;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::ui::{
|
pub fn error_shutdown(msg: &str) -> ! {
|
||||||
shape,
|
const MAX_LEN: usize = 63;
|
||||||
ui_features::{ModelUI, UIFeaturesCommon},
|
let mut buffer: [u8; MAX_LEN + 1] = [0; MAX_LEN + 1];
|
||||||
};
|
|
||||||
|
|
||||||
fn shutdown() -> ! {
|
// Copy the message to the buffer
|
||||||
unsafe { ffi::secure_shutdown() }
|
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.
|
unsafe {
|
||||||
pub fn error_shutdown(title: &str, msg: &str, footer: &str) -> ! {
|
// SAFETY: `buffer` is a valid null-terminated string
|
||||||
// SAFETY:
|
// and the function never returns.
|
||||||
// This is the only situation we are allowed use this function
|
ffi::error_shutdown(buffer.as_ptr() as *const cty::c_char);
|
||||||
// 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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows an error message on the screen and shuts down the device.
|
/// Shows an error message on the screen and shuts down the device.
|
||||||
@ -46,7 +39,7 @@ pub fn __fatal_error(msg: &str, _file: &str, _line: u32) -> ! {
|
|||||||
dbg_println!("===");
|
dbg_println!("===");
|
||||||
}
|
}
|
||||||
|
|
||||||
error_shutdown("INTERNAL_ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD");
|
error_shutdown(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UnwrapOrFatalError<T> {
|
pub trait UnwrapOrFatalError<T> {
|
||||||
|
@ -10,19 +10,32 @@ use crate::ui::{
|
|||||||
geometry::{Alignment2D, Point},
|
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]
|
#[no_mangle]
|
||||||
extern "C" fn error_shutdown_rust(
|
extern "C" fn display_rsod_rust(
|
||||||
title: *const cty::c_char,
|
title: *const cty::c_char,
|
||||||
msg: *const cty::c_char,
|
msg: *const cty::c_char,
|
||||||
footer: *const cty::c_char,
|
footer: *const cty::c_char,
|
||||||
) -> ! {
|
) {
|
||||||
let title = unsafe { from_c_str(title) }.unwrap_or("");
|
let title = unsafe { from_c_str(title) }.unwrap_or("");
|
||||||
let msg = unsafe { from_c_str(msg) }.unwrap_or("");
|
let msg = unsafe { from_c_str(msg) }.unwrap_or("");
|
||||||
let footer = unsafe { from_c_str(footer) }.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]
|
#[no_mangle]
|
||||||
|
79
core/embed/trezorhal/applet.h
Normal file
79
core/embed/trezorhal/applet.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TREZORHAL_APPLET_H
|
||||||
|
#define TREZORHAL_APPLET_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef SYSCALL_DISPATCH
|
||||||
|
|
||||||
|
#include "systask.h"
|
||||||
|
|
||||||
|
// Applet entry point
|
||||||
|
typedef void (*applet_startup_t)(const char* args, uint32_t random);
|
||||||
|
|
||||||
|
// Applet header found at the beginning of the applet binary
|
||||||
|
typedef struct {
|
||||||
|
// Stack area
|
||||||
|
uint32_t stack_start;
|
||||||
|
uint32_t stack_size;
|
||||||
|
// Applet entry point
|
||||||
|
applet_startup_t startup;
|
||||||
|
} applet_header_t;
|
||||||
|
|
||||||
|
// Applet memory layout
|
||||||
|
typedef struct {
|
||||||
|
// Data area 1
|
||||||
|
uint32_t data1_start;
|
||||||
|
uint32_t data1_size;
|
||||||
|
// Data area 2
|
||||||
|
uint32_t data2_start;
|
||||||
|
uint32_t data2_size;
|
||||||
|
|
||||||
|
} applet_layout_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// Points to the applet header found at the beginning of the applet binary
|
||||||
|
applet_header_t* header;
|
||||||
|
// Applet memory layout describing the memory areas
|
||||||
|
// the applet is allowed to use
|
||||||
|
applet_layout_t layout;
|
||||||
|
// Applet task
|
||||||
|
systask_t task;
|
||||||
|
|
||||||
|
// + privileges
|
||||||
|
|
||||||
|
} applet_t;
|
||||||
|
|
||||||
|
// Initializes the applet structure
|
||||||
|
void applet_init(applet_t* applet, applet_header_t* header,
|
||||||
|
applet_layout_t* layout);
|
||||||
|
|
||||||
|
// Resets the applet and prepares it for execution from its entry point.
|
||||||
|
//
|
||||||
|
// Applet does not start immediately, it needs to be scheduled by
|
||||||
|
// `systask_yield_to(&applet->task)` after calling this function.
|
||||||
|
void applet_reset(applet_t* applet, uint32_t cmd, const void* arg,
|
||||||
|
size_t arg_size);
|
||||||
|
|
||||||
|
#endif // SYSCALL_DISPATCH
|
||||||
|
|
||||||
|
#endif // TREZORHAL_APPLET_H
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef TREZORHAL_FAULT_HANDLERS_H
|
|
||||||
#define TREZORHAL_FAULT_HANDLERS_H
|
|
||||||
|
|
||||||
// Initializes and enables fault handlers
|
|
||||||
void fault_handlers_init(void);
|
|
||||||
|
|
||||||
#endif // TREZORHAL_FAULT_HANDLERS_H
|
|
71
core/embed/trezorhal/stm32f4/applet.c
Normal file
71
core/embed/trezorhal/stm32f4/applet.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "applet.h"
|
||||||
|
#include "mpu.h"
|
||||||
|
#include "rng.h"
|
||||||
|
#include "systask.h"
|
||||||
|
|
||||||
|
#ifdef SYSCALL_DISPATCH
|
||||||
|
|
||||||
|
void applet_init(applet_t* applet, applet_header_t* header,
|
||||||
|
applet_layout_t* layout) {
|
||||||
|
memset(applet, 0, sizeof(applet_t));
|
||||||
|
|
||||||
|
applet->header = header;
|
||||||
|
applet->layout = *layout;
|
||||||
|
|
||||||
|
// !@# check if header refs are valid and inside the layout memory
|
||||||
|
}
|
||||||
|
|
||||||
|
static void applet_clear_memory(applet_t* applet) {
|
||||||
|
if (applet->layout.data1_size > 0) {
|
||||||
|
memset((void*)applet->layout.data1_start, 0, applet->layout.data1_size);
|
||||||
|
}
|
||||||
|
if (applet->layout.data2_size > 0) {
|
||||||
|
memset((void*)applet->layout.data2_start, 0, applet->layout.data2_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void applet_reset(applet_t* applet, uint32_t cmd, const void* arg,
|
||||||
|
size_t arg_size) {
|
||||||
|
// Clear all memory the applet is allowed to use
|
||||||
|
applet_clear_memory(applet);
|
||||||
|
|
||||||
|
// Reset the applet task (stack pointer, etc.)
|
||||||
|
systask_init(&applet->task, applet->header->stack_start,
|
||||||
|
applet->header->stack_size);
|
||||||
|
|
||||||
|
// Copy the arguments onto the applet stack
|
||||||
|
void* arg_copy = NULL;
|
||||||
|
if (arg != NULL && arg_size > 0) {
|
||||||
|
arg_copy = systask_push_data(&applet->task, arg, arg_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule the applet task run
|
||||||
|
uint32_t arg1 = cmd;
|
||||||
|
uint32_t arg2 = (uint32_t)arg_copy;
|
||||||
|
uint32_t arg3 = rng_get();
|
||||||
|
|
||||||
|
systask_push_call(&applet->task, applet->header->startup, arg1, arg2, arg3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SYSCALL_DISPATCH
|
@ -1,58 +0,0 @@
|
|||||||
#include TREZOR_BOARD
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "mpu.h"
|
|
||||||
|
|
||||||
#ifdef KERNEL_MODE
|
|
||||||
|
|
||||||
void fault_handlers_init(void) {
|
|
||||||
// Enable BUS fault and USAGE fault handlers
|
|
||||||
SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HardFault_Handler(void) {
|
|
||||||
mpu_reconfig(MPU_MODE_DEFAULT);
|
|
||||||
error_shutdown("(HF)");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MemManage_Handler_MM(void) {
|
|
||||||
mpu_reconfig(MPU_MODE_DEFAULT);
|
|
||||||
error_shutdown("(MM)");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MemManage_Handler_SO(void) {
|
|
||||||
mpu_reconfig(MPU_MODE_DEFAULT);
|
|
||||||
error_shutdown("(SO)");
|
|
||||||
}
|
|
||||||
|
|
||||||
void BusFault_Handler(void) {
|
|
||||||
mpu_reconfig(MPU_MODE_DEFAULT);
|
|
||||||
error_shutdown("(BF)");
|
|
||||||
}
|
|
||||||
|
|
||||||
void UsageFault_Handler(void) {
|
|
||||||
mpu_reconfig(MPU_MODE_DEFAULT);
|
|
||||||
error_shutdown("(UF)");
|
|
||||||
}
|
|
||||||
|
|
||||||
void NMI_Handler(void) {
|
|
||||||
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
|
||||||
// Clock Security System triggered NMI
|
|
||||||
if ((RCC->CIR & RCC_CIR_CSSF) != 0) {
|
|
||||||
error_shutdown("(CS)");
|
|
||||||
}
|
|
||||||
mpu_restore(mpu_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// from util.s
|
|
||||||
extern void shutdown_privileged(void);
|
|
||||||
|
|
||||||
void PVD_IRQHandler(void) {
|
|
||||||
mpu_reconfig(MPU_MODE_DEFAULT);
|
|
||||||
#ifdef BACKLIGHT_PWM_TIM
|
|
||||||
BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = 0; // turn off display backlight
|
|
||||||
#endif
|
|
||||||
shutdown_privileged();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // KERNEL_MODE
|
|
@ -76,7 +76,6 @@ secbool monoctr_write(monoctr_type_t type, uint8_t value) {
|
|||||||
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP);
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_OTP);
|
||||||
ensure(flash_otp_write(block, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL);
|
ensure(flash_otp_write(block, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL);
|
||||||
mpu_restore(mpu_mode);
|
mpu_restore(mpu_mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
@ -131,9 +130,7 @@ secbool monoctr_read(monoctr_type_t type, uint8_t* value) {
|
|||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
*value = dummy_version;
|
||||||
*value = 0;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return sectrue;
|
return sectrue;
|
||||||
|
@ -17,23 +17,13 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include STM32_HAL_H
|
|
||||||
|
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "image.h"
|
|
||||||
#include "irq.h"
|
|
||||||
#include "mpu.h"
|
#include "mpu.h"
|
||||||
|
|
||||||
#ifdef SYSCALL_DISPATCH
|
#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(
|
__attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback(
|
||||||
uint32_t args1, uint32_t arg2, uint32_t arg3, void *callback) {
|
uint32_t args1, uint32_t arg2, uint32_t arg3, void* callback) {
|
||||||
__asm__ volatile(
|
__asm__ volatile(
|
||||||
"push {r1-r12, lr} \n"
|
"push {r1-r12, lr} \n"
|
||||||
|
|
||||||
@ -43,14 +33,24 @@ __attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback(
|
|||||||
"sub r12, r12, #32 \n"
|
"sub r12, r12, #32 \n"
|
||||||
"msr PSP, r12 \n"
|
"msr PSP, r12 \n"
|
||||||
|
|
||||||
"str r0, [r12, #0] \n" // r0
|
"str r0, [r12, #0] \n" // pass r0
|
||||||
"str r1, [r12, #4] \n" // r1"
|
"str r1, [r12, #4] \n" // pass r1
|
||||||
"str r2, [r12, #8] \n" // r2"
|
"str r2, [r12, #8] \n" // pass r2
|
||||||
|
|
||||||
"mov r1, #0 \n"
|
"mov r1, #0 \n"
|
||||||
"str r1, [r12, #12] \n" // r3"
|
|
||||||
"str r1, [r12, #16] \n" // r12"
|
"mov r4, r1 \n" // Clear registers r4-r11
|
||||||
"str r1, [r12, #20] \n" // lr"
|
"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"
|
"bic r3, r3, #1 \n"
|
||||||
"str r3, [r12, #24] \n" // return address
|
"str r3, [r12, #24] \n" // return address
|
||||||
@ -73,133 +73,21 @@ __attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback(
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t invoke_app_callback(uint32_t args1, uint32_t arg2, uint32_t arg3,
|
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);
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_APP);
|
||||||
uint32_t retval = _invoke_app_callback(args1, arg2, arg3, callback);
|
uint32_t retval = _invoke_app_callback(args1, arg2, arg3, callback);
|
||||||
mpu_reconfig(mpu_mode);
|
mpu_reconfig(mpu_mode);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jumps to reset vector of unprivileged application code
|
__attribute__((naked, no_stack_protector)) void return_from_app_callback(
|
||||||
//
|
uint32_t retval, uint32_t* msp) {
|
||||||
// Can be called only from an exception handler
|
|
||||||
__attribute__((naked, no_stack_protector)) static void start_app(
|
|
||||||
uint32_t app_start) {
|
|
||||||
__asm__ volatile(
|
__asm__ volatile(
|
||||||
"ldr r12, [r0, #0] \n" // stack pointer
|
"MSR MSP, R1 \n"
|
||||||
"sub r12, r12, #32 \n"
|
"POP {R1} \n"
|
||||||
"msr PSP, r12 \n"
|
"MSR PSP, R1 \n"
|
||||||
|
"POP {R1-R12, LR} \n"
|
||||||
"mov r1, #0 \n"
|
"BX LR \n");
|
||||||
"str r1, [r12, #0] \n" // r0
|
|
||||||
"str r1, [r12, #4] \n" // r1"
|
|
||||||
"str r1, [r12, #8] \n" // r2"
|
|
||||||
"str r1, [r12, #12] \n" // r3"
|
|
||||||
"str r1, [r12, #16] \n" // r12"
|
|
||||||
"str r1, [r12, #20] \n" // lr"
|
|
||||||
|
|
||||||
"ldr r1, [r0, #4] \n" // reset vector
|
|
||||||
"bic r1, r1, #1 \n"
|
|
||||||
"str r1, [r12, #24] \n" // return address
|
|
||||||
|
|
||||||
"ldr r1, = 0x01000000 \n"
|
|
||||||
"str r1, [r12, #28] \n" // xPSR
|
|
||||||
|
|
||||||
"ldr r1, = 0xE000EF34 \n" // FPU->FPPCCR
|
|
||||||
"ldr r0, [r1] \n"
|
|
||||||
"bic r0, r0, #1 \n" // Clear LSPACT to suppress lazy stacking to
|
|
||||||
"str r0, [r1] \n" // avoid potential PSP stack overwrite.
|
|
||||||
|
|
||||||
"mrs r1, CONTROL \n"
|
|
||||||
"bic r1, r1, #4 \n" // Clear FPCA to suppress lazy stacking to
|
|
||||||
"msr CONTROL, r1 \n" // avoid potential PSP stack overwrite.
|
|
||||||
|
|
||||||
"mrs r1, CONTROL \n" // Switch thread mode to unprivileged
|
|
||||||
"orr r1, r1, #1 \n" // by setting nPRIV bit in CONTROL register.
|
|
||||||
"msr CONTROL, r1 \n" // This applies after return from this
|
|
||||||
// handler.
|
|
||||||
|
|
||||||
// return to Secure Thread mode (use Secure PSP)
|
|
||||||
"ldr lr, = 0xFFFFFFFD \n"
|
|
||||||
"bx lr \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void SVC_C_Handler(uint32_t *stack, uint32_t r4, uint32_t r5, uint32_t r6) {
|
|
||||||
uint8_t svc_number = ((uint8_t *)stack[6])[-2];
|
|
||||||
uint32_t args[6] = {stack[0], stack[1], stack[2], stack[3], r4, r5};
|
|
||||||
|
|
||||||
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
|
||||||
|
|
||||||
switch (svc_number) {
|
|
||||||
#ifdef SYSTEM_VIEW
|
|
||||||
case SVC_GET_DWT_CYCCNT:
|
|
||||||
cyccnt_cycles = *DWT_CYCCNT_ADDR;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case SVC_START_APP:
|
|
||||||
mpu_reconfig(MPU_MODE_APP);
|
|
||||||
start_app(args[0]);
|
|
||||||
break;
|
|
||||||
case SVC_SYSCALL:
|
|
||||||
syscall_handler(args, r6);
|
|
||||||
stack[0] = args[0];
|
|
||||||
stack[1] = args[1];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stack[0] = 0xffffffff;
|
|
||||||
stack[1] = 0xffffffff;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mpu_restore(mpu_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((naked, no_stack_protector)) void SVC_Handler(void) {
|
|
||||||
__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) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SYSCALL_DISPATCH
|
#endif // SYSCALL_DISPATCH
|
||||||
|
@ -22,18 +22,16 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "applet.h"
|
||||||
#include "syscall_numbers.h"
|
#include "syscall_numbers.h"
|
||||||
|
|
||||||
// Reserved SVC numbers
|
// Reserved SVC numbers
|
||||||
#define SVC_SYSCALL 0
|
#define SVC_SYSCALL 0
|
||||||
#define SVC_START_APP 1
|
#define SVC_SYSTASK_YIELD 1
|
||||||
#define SVC_CALLBACK_RETURN 2
|
#define SVC_CALLBACK_RETURN 2
|
||||||
|
|
||||||
#ifdef KERNEL_MODE
|
#ifdef KERNEL_MODE
|
||||||
|
|
||||||
// Initializes the SVC/Syscall handlers
|
|
||||||
void syscall_init(void);
|
|
||||||
|
|
||||||
// Handles all syscall requests.
|
// Handles all syscall requests.
|
||||||
//
|
//
|
||||||
// `args` points to an array of six 32-bit arguments.
|
// `args` points to an array of six 32-bit arguments.
|
||||||
@ -44,14 +42,13 @@ void syscall_init(void);
|
|||||||
//
|
//
|
||||||
// Return values must be copied to `args[0]` and
|
// Return values must be copied to `args[0]` and
|
||||||
// `args[1]` (if returning a 64-bit value).
|
// `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 application callback from the syscall handler
|
||||||
uint32_t invoke_app_callback(uint32_t args1, uint32_t arg2, uint32_t arg3,
|
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 return_from_app_callback(uint32_t retval, uint32_t* msp);
|
||||||
void __attribute__((noreturn)) start_unprivileged_app(void);
|
|
||||||
|
|
||||||
#else // KERNEL_MODE
|
#else // KERNEL_MODE
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
#include "secret.h"
|
#include "secret.h"
|
||||||
|
#include "systask.h"
|
||||||
|
#include "system.h"
|
||||||
#include "systick.h"
|
#include "systick.h"
|
||||||
#include "touch.h"
|
#include "touch.h"
|
||||||
#include "translations.h"
|
#include "translations.h"
|
||||||
@ -63,6 +65,17 @@ static void firmware_hash_callback_wrapper(void *context, uint32_t progress,
|
|||||||
|
|
||||||
void syscall_handler(uint32_t *args, uint32_t syscall) {
|
void syscall_handler(uint32_t *args, uint32_t syscall) {
|
||||||
switch (syscall) {
|
switch (syscall) {
|
||||||
|
case SYSCALL_SYSTEM_EXIT: {
|
||||||
|
system_exit((int)args[0]);
|
||||||
|
} break;
|
||||||
|
case SYSCALL_SYSTEM_EXIT_ERROR: {
|
||||||
|
system_exit_error((const char *)args[0], (const char *)args[1],
|
||||||
|
(const char *)args[2]);
|
||||||
|
} break;
|
||||||
|
case SYSCALL_SYSTEM_EXIT_FATAL: {
|
||||||
|
system_exit_fatal((const char *)args[0], (const char *)args[1],
|
||||||
|
(int)args[2]);
|
||||||
|
} break;
|
||||||
case SYSCALL_SYSTICK_CYCLES: {
|
case SYSCALL_SYSTICK_CYCLES: {
|
||||||
uint64_t cycles = systick_cycles();
|
uint64_t cycles = systick_cycles();
|
||||||
args[0] = cycles & 0xFFFFFFFF;
|
args[0] = cycles & 0xFFFFFFFF;
|
||||||
|
@ -20,10 +20,14 @@
|
|||||||
#ifndef SYSCALL_NUMBERS_H
|
#ifndef SYSCALL_NUMBERS_H
|
||||||
#define SYSCALL_NUMBERS_H
|
#define SYSCALL_NUMBERS_H
|
||||||
|
|
||||||
|
// Syscall identifiers
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
||||||
// Syscalls numbers
|
SYSCALL_SYSTEM_EXIT = 1,
|
||||||
SYSCALL_SYSTICK_CYCLES = 1,
|
SYSCALL_SYSTEM_EXIT_ERROR,
|
||||||
|
SYSCALL_SYSTEM_EXIT_FATAL,
|
||||||
|
|
||||||
|
SYSCALL_SYSTICK_CYCLES,
|
||||||
SYSCALL_SYSTICK_MS,
|
SYSCALL_SYSTICK_MS,
|
||||||
SYSCALL_SYSTICK_US,
|
SYSCALL_SYSTICK_US,
|
||||||
SYSCALL_SYSTICK_US_TO_CYCLES,
|
SYSCALL_SYSTICK_US_TO_CYCLES,
|
||||||
|
@ -21,6 +21,33 @@
|
|||||||
|
|
||||||
#ifndef KERNEL_MODE
|
#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
|
// systick.h
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
470
core/embed/trezorhal/stm32f4/systask.c
Normal file
470
core/embed/trezorhal/stm32f4/systask.c
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include STM32_HAL_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "bootutils.h"
|
||||||
|
#include "irq.h"
|
||||||
|
#include "mpu.h"
|
||||||
|
#include "syscall.h"
|
||||||
|
#include "systask.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
#ifdef KERNEL_MODE
|
||||||
|
|
||||||
|
#define STK_FRAME_R0 0
|
||||||
|
#define STK_FRAME_R1 1
|
||||||
|
#define STK_FRAME_R2 2
|
||||||
|
#define STK_FRAME_R3 3
|
||||||
|
#define STK_FRAME_R12 4
|
||||||
|
#define STK_FRAME_LR 5
|
||||||
|
#define STK_FRAME_RET_ADDR 6
|
||||||
|
#define STK_FRAME_XPSR 7
|
||||||
|
|
||||||
|
// Task manager state
|
||||||
|
typedef struct {
|
||||||
|
// Error handler called when a kernel task terminates
|
||||||
|
systask_error_handler_t error_handler;
|
||||||
|
// Background kernel task
|
||||||
|
systask_t kernel_task;
|
||||||
|
// Currently running task
|
||||||
|
systask_t* active_task;
|
||||||
|
// Task to be scheduled next
|
||||||
|
systask_t* waiting_task;
|
||||||
|
} systask_scheduler_t;
|
||||||
|
|
||||||
|
// Global task manager state
|
||||||
|
systask_scheduler_t g_systask_scheduler = {0};
|
||||||
|
|
||||||
|
void systask_scheduler_init(systask_error_handler_t error_handler) {
|
||||||
|
systask_scheduler_t* scheduler = &g_systask_scheduler;
|
||||||
|
|
||||||
|
memset(scheduler, 0, sizeof(systask_scheduler_t));
|
||||||
|
|
||||||
|
scheduler->error_handler = error_handler;
|
||||||
|
scheduler->active_task = &scheduler->kernel_task;
|
||||||
|
scheduler->waiting_task = scheduler->active_task;
|
||||||
|
|
||||||
|
// SVCall priority should be the lowest since it is
|
||||||
|
// generally a blocking operation
|
||||||
|
NVIC_SetPriority(SVCall_IRQn, IRQ_PRI_LOWEST);
|
||||||
|
NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_LOWEST);
|
||||||
|
|
||||||
|
// Enable BusFault and UsageFault handlers
|
||||||
|
SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk);
|
||||||
|
}
|
||||||
|
|
||||||
|
systask_t* systask_active(void) {
|
||||||
|
systask_scheduler_t* scheduler = &g_systask_scheduler;
|
||||||
|
|
||||||
|
return scheduler->active_task;
|
||||||
|
}
|
||||||
|
|
||||||
|
void systask_yield_to(systask_t* task) {
|
||||||
|
systask_scheduler_t* scheduler = &g_systask_scheduler;
|
||||||
|
|
||||||
|
bool handler_mode = (__get_IPSR() & IPSR_ISR_Msk) != 0;
|
||||||
|
|
||||||
|
if (handler_mode) {
|
||||||
|
scheduler->waiting_task = task;
|
||||||
|
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
|
||||||
|
__DSB();
|
||||||
|
} else {
|
||||||
|
register uint32_t r0 __asm__("r0") = (uint32_t)task;
|
||||||
|
|
||||||
|
// SVC_SYSTASK_YIELD is the only SVC that is allowed to be invoked from
|
||||||
|
// kernel itself, and it is used to start the unprivileged application code.
|
||||||
|
__asm__ volatile("svc %[svid]\n"
|
||||||
|
: "=r"(r0)
|
||||||
|
: [svid] "i"(SVC_SYSTASK_YIELD), "r"(r0)
|
||||||
|
: "memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size) {
|
||||||
|
task->sp = stack_ptr + stack_size;
|
||||||
|
task->sp_lim = stack_ptr + 256;
|
||||||
|
task->exc_return = 0xFFFFFFED; // Thread mode, use PSP, pop FP context
|
||||||
|
task->mpu_mode = MPU_MODE_APP;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t* systask_push_data(systask_t* task, const void* data, size_t size) {
|
||||||
|
uint32_t stack_remaining = task->sp - task->sp_lim;
|
||||||
|
if (stack_remaining < size) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
task->sp -= size;
|
||||||
|
|
||||||
|
if (data != NULL) {
|
||||||
|
memcpy((void*)task->sp, data, size);
|
||||||
|
} else {
|
||||||
|
memset((void*)task->sp, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void*)task->sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void systask_pop_data(systask_t* task, size_t size) { task->sp += size; }
|
||||||
|
|
||||||
|
void systask_push_call(systask_t* task, void* entrypoint, uint32_t arg1,
|
||||||
|
uint32_t arg2, uint32_t arg3) {
|
||||||
|
// FP extension context
|
||||||
|
systask_push_data(task, NULL, 0x48);
|
||||||
|
// Standard exception frame
|
||||||
|
uint32_t* stk_frame = systask_push_data(task, NULL, 0x20);
|
||||||
|
// Registers r4-r11
|
||||||
|
systask_push_data(task, NULL, 0x20);
|
||||||
|
// Registers s16-s31
|
||||||
|
systask_push_data(task, NULL, 0x40);
|
||||||
|
|
||||||
|
// Return to thread mode, use PSP, pop FP context
|
||||||
|
task->exc_return = 0xFFFFFFED;
|
||||||
|
|
||||||
|
stk_frame[STK_FRAME_R0] = arg1;
|
||||||
|
stk_frame[STK_FRAME_R1] = arg2;
|
||||||
|
stk_frame[STK_FRAME_R2] = arg3;
|
||||||
|
stk_frame[STK_FRAME_RET_ADDR] = (uint32_t)entrypoint & ~1;
|
||||||
|
stk_frame[STK_FRAME_XPSR] = 0x01000000; // T (Thumb state) bit set
|
||||||
|
}
|
||||||
|
|
||||||
|
// C part of PendSV handler that switches tasks
|
||||||
|
//
|
||||||
|
// `sp` is the stack pointer of the current task
|
||||||
|
// `sp_lim` is the stack pointer limit of the current task
|
||||||
|
// `exc_return` is the execution state of the current task
|
||||||
|
//
|
||||||
|
// Returns the context struct of the next task
|
||||||
|
__attribute((no_stack_protector, used)) static uint32_t scheduler_pendsv(
|
||||||
|
uint32_t sp, uint32_t sp_lim, uint32_t exc_return) {
|
||||||
|
systask_scheduler_t* scheduler = &g_systask_scheduler;
|
||||||
|
|
||||||
|
// Save the current task context
|
||||||
|
systask_t* prev_task = scheduler->active_task;
|
||||||
|
prev_task->sp = sp;
|
||||||
|
prev_task->sp_lim = sp_lim;
|
||||||
|
prev_task->exc_return = exc_return;
|
||||||
|
prev_task->mpu_mode = mpu_get_mode();
|
||||||
|
|
||||||
|
// Switch to the next task
|
||||||
|
scheduler->active_task = scheduler->waiting_task;
|
||||||
|
|
||||||
|
// Load the scheduled task context
|
||||||
|
systask_t* next_task = scheduler->active_task;
|
||||||
|
|
||||||
|
// Set task privilege level
|
||||||
|
uint32_t control = __get_CONTROL();
|
||||||
|
if (next_task == &scheduler->kernel_task) {
|
||||||
|
control &= ~CONTROL_nPRIV_Msk;
|
||||||
|
} else {
|
||||||
|
control |= CONTROL_nPRIV_Msk;
|
||||||
|
}
|
||||||
|
__set_CONTROL(control);
|
||||||
|
|
||||||
|
// Setup the MPU for the new task
|
||||||
|
mpu_reconfig(next_task->mpu_mode);
|
||||||
|
|
||||||
|
return (uint32_t)next_task;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void systask_kill(systask_t* task) {
|
||||||
|
systask_scheduler_t* scheduler = &g_systask_scheduler;
|
||||||
|
|
||||||
|
if (task == &scheduler->kernel_task) {
|
||||||
|
if (scheduler->error_handler != NULL) {
|
||||||
|
scheduler->error_handler(&task->pminfo);
|
||||||
|
}
|
||||||
|
secure_shutdown();
|
||||||
|
} else if (task == scheduler->active_task) {
|
||||||
|
systask_yield_to(&scheduler->kernel_task);
|
||||||
|
} else {
|
||||||
|
// Inactive task
|
||||||
|
// !@# what to do?? mark it somehow??
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void systask_exit(systask_t* task, int exit_code) {
|
||||||
|
systask_postmortem_t* pminfo = &task->pminfo;
|
||||||
|
|
||||||
|
pminfo->reason = TASK_TERM_REASON_EXIT;
|
||||||
|
pminfo->exit.code = exit_code;
|
||||||
|
|
||||||
|
systask_kill(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void systask_exit_error(systask_t* task, const char* title, const char* message,
|
||||||
|
const char* footer) {
|
||||||
|
systask_postmortem_t* pminfo = &task->pminfo;
|
||||||
|
|
||||||
|
pminfo->reason = TASK_TERM_REASON_ERROR;
|
||||||
|
|
||||||
|
strncpy(pminfo->error.title, title, sizeof(pminfo->error.title) - 1);
|
||||||
|
pminfo->error.title[sizeof(pminfo->error.title) - 1] = '\0';
|
||||||
|
|
||||||
|
strncpy(pminfo->error.message, message, sizeof(pminfo->error.message) - 1);
|
||||||
|
pminfo->error.message[sizeof(pminfo->error.message) - 1] = '\0';
|
||||||
|
|
||||||
|
strncpy(pminfo->error.footer, footer, sizeof(pminfo->error.footer) - 1);
|
||||||
|
pminfo->error.footer[sizeof(pminfo->error.footer) - 1] = '\0';
|
||||||
|
|
||||||
|
systask_kill(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void systask_exit_fatal(systask_t* task, const char* message, const char* file,
|
||||||
|
int line) {
|
||||||
|
systask_postmortem_t* pminfo = &task->pminfo;
|
||||||
|
|
||||||
|
pminfo->reason = TASK_TERM_REASON_FATAL;
|
||||||
|
|
||||||
|
strncpy(pminfo->fatal.file, file, sizeof(pminfo->fatal.file) - 1);
|
||||||
|
pminfo->fatal.file[sizeof(pminfo->fatal.file) - 1] = '\0';
|
||||||
|
|
||||||
|
strncpy(pminfo->fatal.expr, message, sizeof(pminfo->fatal.expr) - 1);
|
||||||
|
pminfo->fatal.expr[sizeof(pminfo->fatal.expr) - 1] = '\0';
|
||||||
|
|
||||||
|
pminfo->fatal.line = line;
|
||||||
|
|
||||||
|
systask_kill(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate active task from fault/exception handler
|
||||||
|
static void systask_exit_fault(void) {
|
||||||
|
systask_scheduler_t* scheduler = &g_systask_scheduler;
|
||||||
|
systask_t* task = scheduler->active_task;
|
||||||
|
systask_postmortem_t* pminfo = &task->pminfo;
|
||||||
|
|
||||||
|
pminfo->reason = TASK_TERM_REASON_FAULT;
|
||||||
|
pminfo->fault.irqn = (__get_IPSR() & IPSR_ISR_Msk) - 16;
|
||||||
|
pminfo->fault.cfsr = SCB->CFSR;
|
||||||
|
pminfo->fault.mmfar = SCB->MMFAR;
|
||||||
|
pminfo->fault.bfar = SCB->BFAR;
|
||||||
|
pminfo->fault.hfsr = SCB->HFSR;
|
||||||
|
|
||||||
|
systask_kill(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((naked, no_stack_protector)) void PendSV_Handler(void) {
|
||||||
|
__asm__ volatile(
|
||||||
|
"TST LR, #0x4 \n" // Return stack (1=>PSP, 0=>MSP)
|
||||||
|
|
||||||
|
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
|
||||||
|
"ITTEE EQ \n"
|
||||||
|
"MRSEQ R0, MSP \n" // Get current SP
|
||||||
|
"MRSEQ R1, MSPLIM \n" // Get current SP Limit
|
||||||
|
"MRSNE R0, PSP \n"
|
||||||
|
"MRSNE R1, PSPLIM \n"
|
||||||
|
#else
|
||||||
|
"ITE EQ \n"
|
||||||
|
"MRSEQ R0, MSP \n" // Get current SP
|
||||||
|
"MRSNE R0, PSP \n"
|
||||||
|
"MOV R1, #0 \n" // (fake SPLIM)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
"MOV R2, LR \n" // Get current EXC_RETURN
|
||||||
|
|
||||||
|
"STMDB R0!, {R4-R11} \n" // Save R4-R11 to SP Frame Stack
|
||||||
|
"TST LR, #0x10 \n" // Check EXC_RETURN.Ftype bit to see if
|
||||||
|
// the current thread has a FP context
|
||||||
|
"IT EQ \n"
|
||||||
|
"VSTMDBEQ R0!, {S16-S31} \n" // If so, save S16-S31 FP addition
|
||||||
|
// context, that will also trigger lazy
|
||||||
|
// fp context preservation of S0-S15
|
||||||
|
|
||||||
|
"BL scheduler_pendsv \n" // Save SP value of current task
|
||||||
|
"LDR LR, [R0, #8] \n" // Get the EXC_RETURN value
|
||||||
|
"LDR R1, [R0, #4] \n" // Get the SP_LIM value
|
||||||
|
"LDR R0, [R0, #0] \n" // Get the SP value
|
||||||
|
|
||||||
|
"TST LR, #0x10 \n" // Check EXC_RETURN.Ftype bit to see if
|
||||||
|
// the next thread has a FP context
|
||||||
|
"IT EQ \n"
|
||||||
|
"VLDMIAEQ R0!, {S16-S31} \n" // If so, restore S16-S31
|
||||||
|
"LDMIA R0!, {R4-R11} \n" // Restore R4-R11
|
||||||
|
|
||||||
|
"TST LR, #0x4 \n" // Check EXC_RETURN to determine which
|
||||||
|
// SP the next thread is using
|
||||||
|
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
|
||||||
|
"ITT NE \n"
|
||||||
|
"MSRNE PSPLIM, R1 \n" // Update the SP Limit and SP since MSP
|
||||||
|
// won't be changed
|
||||||
|
"MSRNE PSP, R0 \n"
|
||||||
|
#else
|
||||||
|
"IT NE \n"
|
||||||
|
"MSRNE PSP, R0 \n" // Update the SP Limit and SP since MSP
|
||||||
|
// won't be changed
|
||||||
|
#endif
|
||||||
|
"BX LR \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((no_stack_protector, used)) static uint32_t svc_handler(
|
||||||
|
uint32_t* stack, uint32_t* msp, uint32_t exc_return, uint32_t r4,
|
||||||
|
uint32_t r5, uint32_t r6) {
|
||||||
|
uint8_t svc_number = ((uint8_t*)stack[6])[-2];
|
||||||
|
uint32_t args[6] = {stack[0], stack[1], stack[2], stack[3], r4, r5};
|
||||||
|
|
||||||
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
|
||||||
|
switch (svc_number) {
|
||||||
|
#ifdef SYSTEM_VIEW
|
||||||
|
case SVC_GET_DWT_CYCCNT:
|
||||||
|
cyccnt_cycles = *DWT_CYCCNT_ADDR;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case SVC_SYSTASK_YIELD:
|
||||||
|
systask_yield_to((systask_t*)args[0]);
|
||||||
|
break;
|
||||||
|
#ifdef SYSCALL_DISPATCH
|
||||||
|
case SVC_SYSCALL:
|
||||||
|
syscall_handler(args, r6);
|
||||||
|
stack[0] = args[0];
|
||||||
|
stack[1] = args[1];
|
||||||
|
break;
|
||||||
|
case SVC_CALLBACK_RETURN:
|
||||||
|
// g_return_value = args[0]
|
||||||
|
// exc_return = return_from_callback;
|
||||||
|
|
||||||
|
mpu_restore(mpu_mode);
|
||||||
|
return_from_app_callback(args[0], msp);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpu_restore(mpu_mode);
|
||||||
|
return exc_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute((naked, no_stack_protector)) void SVC_Handler(void) {
|
||||||
|
__asm__ volatile(
|
||||||
|
"TST LR, #0x4 \n" // Called from Process stack pointer?
|
||||||
|
"ITE EQ \n"
|
||||||
|
"MRSEQ R0, MSP \n"
|
||||||
|
"MRSNE R0, PSP \n"
|
||||||
|
"TST LR, #0x20 \n"
|
||||||
|
"IT EQ \n"
|
||||||
|
"ADDEQ R0, R0, #0x40 \n"
|
||||||
|
"MRS R1, MSP \n"
|
||||||
|
"MOV R2, LR \n"
|
||||||
|
"MOV R3, R4 \n"
|
||||||
|
"PUSH {R5, R6} \n"
|
||||||
|
"BL svc_handler \n"
|
||||||
|
"POP {R5, R6} \n"
|
||||||
|
"BX R0 \n" // Branch to the returned value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HardFault_Handler(void) {
|
||||||
|
// A HardFault may also be caused by exception escalation.
|
||||||
|
// To ensure we have enough space to handle the exception,
|
||||||
|
// we set the stack pointer to the end of the stack.
|
||||||
|
extern uint8_t _estack; // linker script symbol
|
||||||
|
// Fix stack pointer
|
||||||
|
__set_MSP((uint32_t)&_estack);
|
||||||
|
|
||||||
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
systask_exit_fault();
|
||||||
|
mpu_restore(mpu_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
.global MemManage_Handler
|
||||||
|
.type MemManage_Handler, STT_FUNC
|
||||||
|
MemManage_Handler:
|
||||||
|
ldr r2, =_sstack
|
||||||
|
mrs r1, msp
|
||||||
|
ldr r0, =_estack
|
||||||
|
msr msp, r0
|
||||||
|
cmp r1, r2
|
||||||
|
IT lt
|
||||||
|
bllt MemManage_Handler_SO
|
||||||
|
bl MemManage_Handler_MM
|
||||||
|
*/
|
||||||
|
|
||||||
|
void MemManage_Handler(void) {
|
||||||
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
systask_exit_fault();
|
||||||
|
mpu_restore(mpu_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusFault_Handler(void) {
|
||||||
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
systask_exit_fault();
|
||||||
|
mpu_restore(mpu_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsageFault_Handler(void) {
|
||||||
|
#ifdef STM32U5
|
||||||
|
if (SCB->CFSR & SCB_CFSR_STKOF_Msk) {
|
||||||
|
// Stack overflow
|
||||||
|
extern uint8_t _estack; // linker script symbol
|
||||||
|
// Fix stack pointer
|
||||||
|
__set_MSP((uint32_t)&_estack);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
systask_exit_fault();
|
||||||
|
mpu_restore(mpu_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef STM32U5
|
||||||
|
void SecureFault_Handler(void) {
|
||||||
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
systask_exit_fault();
|
||||||
|
mpu_restore(mpu_mode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STM32U5
|
||||||
|
void GTZC_IRQHandler(void) {
|
||||||
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
systask_exit_fault();
|
||||||
|
mpu_restore(mpu_mode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void NMI_Handler(void) {
|
||||||
|
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
#ifdef STM32U5
|
||||||
|
if ((RCC->CIFR & RCC_CIFR_CSSF) != 0) {
|
||||||
|
#else
|
||||||
|
if ((RCC->CIR & RCC_CIR_CSSF) != 0) {
|
||||||
|
#endif
|
||||||
|
// Clock Security System triggered NMI
|
||||||
|
systask_exit_fault();
|
||||||
|
}
|
||||||
|
mpu_restore(mpu_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from util.s
|
||||||
|
extern void shutdown_privileged(void);
|
||||||
|
|
||||||
|
void PVD_PVM_IRQHandler(void) {
|
||||||
|
mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
#ifdef BACKLIGHT_PWM_TIM
|
||||||
|
// Turn off display backlight
|
||||||
|
BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = 0;
|
||||||
|
#endif
|
||||||
|
shutdown_privileged();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // KERNEL_MODE
|
254
core/embed/trezorhal/stm32f4/system.c
Normal file
254
core/embed/trezorhal/stm32f4/system.c
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include STM32_HAL_H
|
||||||
|
|
||||||
|
#include "system.h"
|
||||||
|
#include "bootutils.h"
|
||||||
|
#include "mpu.h"
|
||||||
|
#include "systask.h"
|
||||||
|
#include "systick.h"
|
||||||
|
#include "systimer.h"
|
||||||
|
|
||||||
|
#ifdef KERNEL_MODE
|
||||||
|
|
||||||
|
void system_init(systask_error_handler_t error_handler) {
|
||||||
|
mpu_init();
|
||||||
|
mpu_reconfig(MPU_MODE_DEFAULT);
|
||||||
|
systask_scheduler_init(error_handler);
|
||||||
|
systick_init();
|
||||||
|
systimer_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_exit(int exitcode) { systask_exit(systask_active(), exitcode); }
|
||||||
|
|
||||||
|
void system_exit_error(const char* title, const char* message,
|
||||||
|
const char* footer) {
|
||||||
|
systask_exit_error(systask_active(), title, message, footer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_exit_fatal(const char* message, const char* file, int line) {
|
||||||
|
systask_exit_fatal(systask_active(), message, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // KERNEL_MODE
|
||||||
|
|
||||||
|
#ifndef HardFault_IRQn
|
||||||
|
#define HardFault_IRQn (-13) // not defined in stm32lib/cmsis/stm32429xx.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* system_fault_message(const system_fault_t* fault) {
|
||||||
|
switch (fault->irqn) {
|
||||||
|
case HardFault_IRQn:
|
||||||
|
return "(HF)";
|
||||||
|
case MemoryManagement_IRQn:
|
||||||
|
return "(MM)";
|
||||||
|
case BusFault_IRQn:
|
||||||
|
return "(BF)";
|
||||||
|
case UsageFault_IRQn:
|
||||||
|
#ifdef STM32U5
|
||||||
|
if (fault->cfsr & SCB_CFSR_STKOF_Msk) {
|
||||||
|
return "(SO)";
|
||||||
|
} else {
|
||||||
|
return "(UF)";
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return "(UF)";
|
||||||
|
#endif
|
||||||
|
#ifdef STM32U5
|
||||||
|
case SecureFault_IRQn:
|
||||||
|
return "(SF)";
|
||||||
|
case GTZC_IRQn:
|
||||||
|
return "(IA)";
|
||||||
|
#endif
|
||||||
|
case NonMaskableInt_IRQn:
|
||||||
|
return "(CS)";
|
||||||
|
}
|
||||||
|
return "(FAULT)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable all NVIC interrupts and clear pending flags
|
||||||
|
// so later the global interrupt can be re-enabled
|
||||||
|
__attribute__((used)) static void reset_nvic(void) {
|
||||||
|
// TODO: reset peripherals (at least DMA, DMA2D)
|
||||||
|
|
||||||
|
for (int irqn = 0; irqn < 255; irqn++) {
|
||||||
|
NVIC_DisableIRQ(irqn);
|
||||||
|
NVIC_ClearPendingIRQ(irqn);
|
||||||
|
}
|
||||||
|
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute((naked, no_stack_protector)) void system_emergency_rescue(
|
||||||
|
systask_error_handler_t error_handler, const systask_postmortem_t* pminfo) {
|
||||||
|
extern uint32_t __stack_chk_guard;
|
||||||
|
|
||||||
|
__asm__ volatile(
|
||||||
|
"MOV R5, R1 \n" // R5 = pminfo
|
||||||
|
"MOV R6, R0 \n" // R6 = error_handler
|
||||||
|
|
||||||
|
"CPSID I \n" // Disable interrupts
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Disable MPU
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"DMB 0xF \n" // Data memory barrier
|
||||||
|
"LDR R0, =0xE000ED94 \n" // MPU->CTRL
|
||||||
|
"MOV R1, #0 \n"
|
||||||
|
"STR R1, [R0] \n" // Disable MPU
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Disable SysTick
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"LDR R0, =0xE000E010 \n" // SysTick->CTRL
|
||||||
|
"MOV R1, #0 \n"
|
||||||
|
"STR R1, [R0] \n" // Disable SysTick
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Setup new stack
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"LDR R0, =_estack \n" // Setup new stack
|
||||||
|
"MSR MSP, R0 \n" // Set MSP
|
||||||
|
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
|
||||||
|
"LDR R0, =_sstack \n"
|
||||||
|
"ADD R0, R0, #256 \n" // Add safety margin
|
||||||
|
"MSR MSPLIM, R0 \n" // Set MSPLIM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Copy pminfo to new stack
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"LDR R2, =%[PMINFO_SIZE] \n" // Copy pminfo to new stack
|
||||||
|
"SUB SP, R2 \n" // Allocate space for pminfo
|
||||||
|
"MOV R0, SP \n" // Destination
|
||||||
|
"MOV R1, R5 \n"
|
||||||
|
"MOV R5, R0 \n" // R5 = pminfo on new stack
|
||||||
|
"BL memcpy \n"
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Save stack protector guard
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"LDR R0, =%[STK_GUARD] \n" // Save stack protector guard
|
||||||
|
"LDR R7, [R0] \n" // R7 = __stack_chk_guard
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Clear .bss, initialize .data, ...
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"LDR R0, =bss_start \n" // Clear .bss
|
||||||
|
"MOV R1, #0 \n"
|
||||||
|
"LDR R2, =bss_end \n"
|
||||||
|
"SUB R2, R2, R0 \n"
|
||||||
|
"BL memset \n"
|
||||||
|
|
||||||
|
"LDR R0, =data_vma \n" // Initialize .data
|
||||||
|
"LDR R1, =data_lma \n"
|
||||||
|
"LDR R2, =data_size \n"
|
||||||
|
"BL memcpy \n"
|
||||||
|
|
||||||
|
#ifdef STM32U5
|
||||||
|
"LDR R0, =confidential_vma \n" // Initialize .confidental
|
||||||
|
"LDR R1, =confidential_lma \n"
|
||||||
|
"LDR R2, =confidential_size \n"
|
||||||
|
"BL memcpy \n"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Restore stack protector guard
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"LDR R0, =%[STK_GUARD] \n" // Restore stack protector guard
|
||||||
|
"STR R7, [R0] \n"
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Disable NVIC interrupts and clear pending flags
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"BL reset_nvic \n" // Disable all NVIC interrupts
|
||||||
|
"CPSIE I \n" // Re-enable interrupts
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Check if we are in thread mode and if yes, jump to error_handler
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"LDR R1, =0x1FF \n" // Get lower 9 bits of IPSR
|
||||||
|
"MRS R0, IPSR \n"
|
||||||
|
"ANDS R0, R0, R1 \n"
|
||||||
|
"CMP R0, #0 \n" // == 0 if in thread mode
|
||||||
|
"ITTT EQ \n"
|
||||||
|
"MOVEQ R0, R5 \n" // R0 = pminfo
|
||||||
|
"LDREQ LR, =reboot \n"
|
||||||
|
"BXEQ R6 \n" // jump to error_handler directly
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
// Return from exception to thread mode
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
"SUB SP, SP, #32 \n" // Allocate space for exception frame
|
||||||
|
|
||||||
|
"MOV R0, #0 \n"
|
||||||
|
"STR R5, [SP, #0] \n" // future R0 = pminfo
|
||||||
|
"STR R0, [SP, #4] \n" // future R1 = 0
|
||||||
|
"STR R0, [SP, #8] \n" // future R2 = 0
|
||||||
|
"STR R0, [SP, #12] \n" // future R3 = 0
|
||||||
|
"STR R0, [SP, #16] \n" // future R12 = 0
|
||||||
|
"LDR R1, =reboot \n"
|
||||||
|
"STR R0, [SP, #20] \n" // future LR = reboot()
|
||||||
|
"BIC R6, R6, #1 \n"
|
||||||
|
"STR R6, [SP, #24] \n" // return address = error_handler()
|
||||||
|
"LDR R1, = 0x01000000 \n" // THUMB bit set
|
||||||
|
"STR R1, [SP, #28] \n" // future xPSR
|
||||||
|
|
||||||
|
"MOV R4, R0 \n" // Clear registers R4-R11
|
||||||
|
"MOV R5, R0 \n"
|
||||||
|
"MOV R6, R0 \n"
|
||||||
|
"MOV R7, R0 \n"
|
||||||
|
"MOV R8, R0 \n"
|
||||||
|
"MOV R9, R0 \n"
|
||||||
|
"MOV R10, R0 \n"
|
||||||
|
"MOV R11, R0 \n"
|
||||||
|
|
||||||
|
"MRS R0, CONTROL \n"
|
||||||
|
"BIC R0, R0, #4 \n" // Clear FPCA to suppress lazy stacking
|
||||||
|
// to avoid potential stack overwrite.
|
||||||
|
"BIC R0, R0, #2 \n" // Clear SPSEL to use MSP for thread
|
||||||
|
// mode
|
||||||
|
"BIC R0, R0, #1 \n" // Clear nPRIV to run in privileged mode
|
||||||
|
"MSR CONTROL, R1 \n"
|
||||||
|
|
||||||
|
"LDR R1, = 0xE000EF34 \n" // FPU->FPPCCR
|
||||||
|
"LDR R0, [R1] \n"
|
||||||
|
"BIC R0, R0, #1 \n" // Clear LSPACT to suppress lazy
|
||||||
|
// stacking to
|
||||||
|
"STR R0, [R1] \n" // avoid potential stack overwrite.
|
||||||
|
|
||||||
|
"LDR LR, = 0xFFFFFFF9 \n" // Return to Secure Thread mode, use MSP
|
||||||
|
"BX LR \n"
|
||||||
|
: // no output
|
||||||
|
: [PMINFO_SIZE] "i"(sizeof(systask_postmortem_t)),
|
||||||
|
[STK_GUARD] "i"(&__stack_chk_guard)
|
||||||
|
: // no clobber
|
||||||
|
);
|
||||||
|
}
|
@ -112,16 +112,4 @@ shutdown_privileged:
|
|||||||
ldr r0, =0
|
ldr r0, =0
|
||||||
b . // loop forever
|
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
|
.end
|
||||||
|
@ -132,7 +132,8 @@ vector_table:
|
|||||||
|
|
||||||
.section .vector_table, "a"
|
.section .vector_table, "a"
|
||||||
vector_table:
|
vector_table:
|
||||||
.word main_stack_base // defined in linker script
|
.word _sstack
|
||||||
|
.word _stack_size
|
||||||
.word reset_handler
|
.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"
|
.section .vector_table, "a"
|
||||||
vector_table:
|
vector_table:
|
||||||
.word main_stack_base // defined in linker script
|
.word _sstack
|
||||||
|
.word _stack_size
|
||||||
.word reset_handler
|
.word reset_handler
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
163
core/embed/trezorhal/systask.h
Normal file
163
core/embed/trezorhal/systask.h
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TREZORHAL_SYSTASK_H
|
||||||
|
#define TREZORHAL_SYSTASK_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "mpu.h"
|
||||||
|
|
||||||
|
// Termination reason for the task
|
||||||
|
typedef enum {
|
||||||
|
TASK_TERM_REASON_EXIT,
|
||||||
|
TASK_TERM_REASON_ERROR,
|
||||||
|
TASK_TERM_REASON_FATAL,
|
||||||
|
TASK_TERM_REASON_FAULT,
|
||||||
|
|
||||||
|
} systask_term_reason_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// Fault/exception number (-15..-1)
|
||||||
|
int irqn;
|
||||||
|
// Configurable Fault Status Register
|
||||||
|
// (combined UFSR/BFSR/MMFSR)
|
||||||
|
uint32_t cfsr;
|
||||||
|
// Hard Fault Status Register
|
||||||
|
uint32_t hfsr;
|
||||||
|
// Address associated with MemManage fault
|
||||||
|
uint32_t mmfar;
|
||||||
|
// Address associated with the BusFault
|
||||||
|
uint32_t bfar;
|
||||||
|
|
||||||
|
} system_fault_t;
|
||||||
|
|
||||||
|
// Task post-mortem information
|
||||||
|
typedef struct {
|
||||||
|
systask_term_reason_t reason;
|
||||||
|
|
||||||
|
union {
|
||||||
|
// Argument passed to `systask_exit()`
|
||||||
|
struct {
|
||||||
|
int code;
|
||||||
|
} exit;
|
||||||
|
|
||||||
|
// Fault information catched in `systask_exit_fault()`
|
||||||
|
system_fault_t fault;
|
||||||
|
|
||||||
|
// Arguments passed to `systask_exit_fatal()`
|
||||||
|
struct {
|
||||||
|
uint32_t line;
|
||||||
|
char file[64];
|
||||||
|
char expr[64];
|
||||||
|
} fatal;
|
||||||
|
|
||||||
|
// Arguments passed to `systask_exit_error()`
|
||||||
|
struct {
|
||||||
|
char title[64];
|
||||||
|
char message[64];
|
||||||
|
char footer[64];
|
||||||
|
} error;
|
||||||
|
};
|
||||||
|
|
||||||
|
} systask_postmortem_t;
|
||||||
|
|
||||||
|
// Error handler callback invoke when kernel task terminates.
|
||||||
|
//
|
||||||
|
// The purpose of this callbacks display RSOD (Red Screen of Death).
|
||||||
|
//
|
||||||
|
// The callback may be called from any context, including interrupt context.
|
||||||
|
typedef void (*systask_error_handler_t)(const systask_postmortem_t* pminfo);
|
||||||
|
|
||||||
|
#ifdef KERNEL_MODE
|
||||||
|
|
||||||
|
// Task context used by the kernel to save the state of each task
|
||||||
|
// when switching between them
|
||||||
|
typedef struct {
|
||||||
|
// sp, sp_lim, exc_return should at the beginning
|
||||||
|
// and in this order to be compatible with the PendSV_Handler
|
||||||
|
// Stack pointer value
|
||||||
|
uint32_t sp;
|
||||||
|
// Stack pointer limit (ARMv8-M only)
|
||||||
|
uint32_t sp_lim;
|
||||||
|
// Exception return value
|
||||||
|
uint32_t exc_return;
|
||||||
|
// MPU mode the task is running in
|
||||||
|
mpu_mode_t mpu_mode;
|
||||||
|
// Task post-mortem information
|
||||||
|
systask_postmortem_t pminfo;
|
||||||
|
|
||||||
|
} systask_t;
|
||||||
|
|
||||||
|
// Initializes the scheduler for tasks
|
||||||
|
//
|
||||||
|
// No other task functions should be called before this function
|
||||||
|
void systask_scheduler_init(systask_error_handler_t error_handler);
|
||||||
|
|
||||||
|
// Returns the currently running task
|
||||||
|
systask_t* systask_active(void);
|
||||||
|
|
||||||
|
// Makes the given task the currently running task
|
||||||
|
void systask_yield_to(systask_t* task);
|
||||||
|
|
||||||
|
// Initializes a task with the given stack pointer, stack size
|
||||||
|
//
|
||||||
|
// The task must be not be running when the function is called
|
||||||
|
void systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size);
|
||||||
|
|
||||||
|
// Pushes data onto the stack of the task
|
||||||
|
//
|
||||||
|
// The task must be not be running when the function is called
|
||||||
|
uint32_t* systask_push_data(systask_t* task, const void* data, size_t size);
|
||||||
|
|
||||||
|
// Pops data from the stack of the task
|
||||||
|
//
|
||||||
|
// The task must be not be running when the function is called
|
||||||
|
void systask_pop_data(systask_t* task, size_t size);
|
||||||
|
|
||||||
|
// Runs the task with the given entrypoint and arguments
|
||||||
|
//
|
||||||
|
// The task must be not be running when the function is called
|
||||||
|
void systask_push_call(systask_t* task, void* fn, uint32_t arg1, uint32_t arg2,
|
||||||
|
uint32_t arg3);
|
||||||
|
|
||||||
|
// Terminates the current task with the given exit code
|
||||||
|
//
|
||||||
|
// If the terminated task is the currently running task, the kernel task
|
||||||
|
// will be scheduled next
|
||||||
|
void systask_exit(systask_t* task, int exit_code);
|
||||||
|
|
||||||
|
// Terminates the current task with an error message
|
||||||
|
//
|
||||||
|
// If the terminated task is the currently running task, the kernel task
|
||||||
|
// will be scheduled next
|
||||||
|
void systask_exit_error(systask_t* task, const char* title, const char* message,
|
||||||
|
const char* footer);
|
||||||
|
|
||||||
|
// Terminates the current task with a fatal error message
|
||||||
|
//
|
||||||
|
// If the terminated task is the currently running task, the kernel task
|
||||||
|
// will be scheduled next
|
||||||
|
void systask_exit_fatal(systask_t* task, const char* message, const char* file,
|
||||||
|
int line);
|
||||||
|
|
||||||
|
#endif // KERNEL_MODE
|
||||||
|
|
||||||
|
#endif // TREZORHAL_SYSTASK_H
|
60
core/embed/trezorhal/system.h
Normal file
60
core/embed/trezorhal/system.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TREZORHAL_SYSTEM_H
|
||||||
|
#define TREZORHAL_SYSTEM_H
|
||||||
|
|
||||||
|
#include <systask.h>
|
||||||
|
|
||||||
|
// Initializes the fundamental system services
|
||||||
|
// (mpu, systick, systimer and task scheduler)
|
||||||
|
//
|
||||||
|
// `error_handler` is a callback that is called when a kernel task terminates
|
||||||
|
// with an error
|
||||||
|
void system_init(systask_error_handler_t error_handler);
|
||||||
|
|
||||||
|
// Terminates the current app normally with the given exit code
|
||||||
|
void system_exit(int exitcode);
|
||||||
|
|
||||||
|
// Terminates the current app with an error message
|
||||||
|
void system_exit_error(const char* title, const char* message,
|
||||||
|
const char* footer);
|
||||||
|
|
||||||
|
// Terminates the current app with a fatal error message
|
||||||
|
void system_exit_fatal(const char* message, const char* file, int line);
|
||||||
|
|
||||||
|
// Returns string representation of the system fault
|
||||||
|
const char* system_fault_message(const system_fault_t* fault);
|
||||||
|
|
||||||
|
// Calls the error handler in the emergency mode
|
||||||
|
//
|
||||||
|
// This function is called when the system encounters a critical error
|
||||||
|
// and needs to perform a useful action (such as displaying an error message)
|
||||||
|
// before it is reset or shut down.
|
||||||
|
//
|
||||||
|
// The function may be called from any context, including interrupt context.
|
||||||
|
// It completely resets stack pointers, clears the .bss segment, reinitializes
|
||||||
|
// the .data segment, and calls the `error_handler` callback.
|
||||||
|
//
|
||||||
|
// The system will be in a state similar to a reset when `main()` is called
|
||||||
|
// (but with some hardware peripherals still initialized and running).
|
||||||
|
__attribute__((noreturn)) void system_emergency_rescue(
|
||||||
|
systask_error_handler_t error_handler, const systask_postmortem_t* pminfo);
|
||||||
|
|
||||||
|
#endif // TREZORHAL_SYSTEM_H
|
112
core/embed/trezorhal/unix/system.c
Normal file
112
core/embed/trezorhal/unix/system.c
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "bootutils.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "systick.h"
|
||||||
|
#include "systimer.h"
|
||||||
|
|
||||||
|
systask_error_handler_t g_error_handler = NULL;
|
||||||
|
|
||||||
|
void system_init(systask_error_handler_t error_handler) {
|
||||||
|
g_error_handler = error_handler;
|
||||||
|
systick_init();
|
||||||
|
systimer_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_exit(int exitcode) {
|
||||||
|
if (g_error_handler != NULL) {
|
||||||
|
systask_postmortem_t pminfo = {0};
|
||||||
|
|
||||||
|
pminfo.reason = TASK_TERM_REASON_EXIT;
|
||||||
|
pminfo.exit.code = exitcode;
|
||||||
|
|
||||||
|
g_error_handler(&pminfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_exit_error(const char* title, const char* message,
|
||||||
|
const char* footer) {
|
||||||
|
fprintf(stderr, "ERROR: %s\n", message);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
if (g_error_handler != NULL) {
|
||||||
|
systask_postmortem_t pminfo = {0};
|
||||||
|
|
||||||
|
pminfo.reason = TASK_TERM_REASON_ERROR;
|
||||||
|
|
||||||
|
strncpy(pminfo.error.title, title, sizeof(pminfo.error.title) - 1);
|
||||||
|
pminfo.error.title[sizeof(pminfo.error.title) - 1] = '\0';
|
||||||
|
|
||||||
|
strncpy(pminfo.error.message, message, sizeof(pminfo.error.message) - 1);
|
||||||
|
pminfo.error.message[sizeof(pminfo.error.message) - 1] = '\0';
|
||||||
|
|
||||||
|
strncpy(pminfo.error.footer, footer, sizeof(pminfo.error.footer) - 1);
|
||||||
|
pminfo.error.footer[sizeof(pminfo.error.footer) - 1] = '\0';
|
||||||
|
|
||||||
|
g_error_handler(&pminfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_exit_fatal(const char* message, const char* file, int line) {
|
||||||
|
fprintf(stderr, "ERROR: %s\n", message);
|
||||||
|
if (file) {
|
||||||
|
fprintf(stderr, "FILE: %s:%d\n", file, line);
|
||||||
|
}
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
if (g_error_handler != NULL) {
|
||||||
|
systask_postmortem_t pminfo = {0};
|
||||||
|
|
||||||
|
pminfo.reason = TASK_TERM_REASON_FATAL;
|
||||||
|
|
||||||
|
strncpy(pminfo.fatal.file, file, sizeof(pminfo.fatal.file) - 1);
|
||||||
|
pminfo.fatal.file[sizeof(pminfo.fatal.file) - 1] = '\0';
|
||||||
|
|
||||||
|
strncpy(pminfo.fatal.expr, message, sizeof(pminfo.fatal.expr) - 1);
|
||||||
|
pminfo.fatal.expr[sizeof(pminfo.fatal.expr) - 1] = '\0';
|
||||||
|
|
||||||
|
pminfo.fatal.line = line;
|
||||||
|
|
||||||
|
g_error_handler(&pminfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
secure_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* system_fault_message(const system_fault_t* fault) {
|
||||||
|
// Not used in simulator
|
||||||
|
return "(FAULT)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_emergency_rescue(systask_error_handler_t error_handler,
|
||||||
|
const systask_postmortem_t* pminfo) {
|
||||||
|
error_handler(pminfo);
|
||||||
|
|
||||||
|
// We should never reach this point
|
||||||
|
exit(0);
|
||||||
|
}
|
@ -40,11 +40,11 @@ def stm32f4_common_files(env, defines, sources, paths):
|
|||||||
]
|
]
|
||||||
|
|
||||||
sources += [
|
sources += [
|
||||||
|
"embed/trezorhal/stm32f4/applet.c",
|
||||||
"embed/trezorhal/stm32f4/board_capabilities.c",
|
"embed/trezorhal/stm32f4/board_capabilities.c",
|
||||||
"embed/trezorhal/stm32f4/bootutils.c",
|
"embed/trezorhal/stm32f4/bootutils.c",
|
||||||
"embed/trezorhal/stm32f4/common.c",
|
"embed/trezorhal/stm32f4/common.c",
|
||||||
"embed/trezorhal/stm32f4/entropy.c",
|
"embed/trezorhal/stm32f4/entropy.c",
|
||||||
"embed/trezorhal/stm32f4/fault_handlers.c",
|
|
||||||
"embed/trezorhal/stm32f4/flash.c",
|
"embed/trezorhal/stm32f4/flash.c",
|
||||||
"embed/trezorhal/stm32f4/flash_otp.c",
|
"embed/trezorhal/stm32f4/flash_otp.c",
|
||||||
"embed/trezorhal/stm32f4/fwutils.c",
|
"embed/trezorhal/stm32f4/fwutils.c",
|
||||||
@ -56,11 +56,14 @@ def stm32f4_common_files(env, defines, sources, paths):
|
|||||||
"embed/trezorhal/stm32f4/syscall.c",
|
"embed/trezorhal/stm32f4/syscall.c",
|
||||||
"embed/trezorhal/stm32f4/syscall_dispatch.c",
|
"embed/trezorhal/stm32f4/syscall_dispatch.c",
|
||||||
"embed/trezorhal/stm32f4/syscall_stubs.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/systick.c",
|
||||||
"embed/trezorhal/stm32f4/systimer.c",
|
"embed/trezorhal/stm32f4/systimer.c",
|
||||||
"embed/trezorhal/stm32f4/time_estimate.c",
|
"embed/trezorhal/stm32f4/time_estimate.c",
|
||||||
"embed/trezorhal/stm32f4/random_delays.c",
|
"embed/trezorhal/stm32f4/random_delays.c",
|
||||||
"embed/trezorhal/stm32f4/rng.c",
|
"embed/trezorhal/stm32f4/rng.c",
|
||||||
|
|
||||||
"embed/trezorhal/stm32f4/vectortable.S",
|
"embed/trezorhal/stm32f4/vectortable.S",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -49,11 +49,11 @@ def stm32u5_common_files(env, defines, sources, paths):
|
|||||||
]
|
]
|
||||||
|
|
||||||
sources += [
|
sources += [
|
||||||
|
"embed/trezorhal/stm32u5/applet.c",
|
||||||
"embed/trezorhal/stm32u5/board_capabilities.c",
|
"embed/trezorhal/stm32u5/board_capabilities.c",
|
||||||
"embed/trezorhal/stm32u5/bootutils.c",
|
"embed/trezorhal/stm32u5/bootutils.c",
|
||||||
"embed/trezorhal/stm32u5/common.c",
|
"embed/trezorhal/stm32u5/common.c",
|
||||||
"embed/trezorhal/stm32u5/entropy.c",
|
"embed/trezorhal/stm32u5/entropy.c",
|
||||||
"embed/trezorhal/stm32u5/fault_handlers.c",
|
|
||||||
"embed/trezorhal/stm32u5/flash.c",
|
"embed/trezorhal/stm32u5/flash.c",
|
||||||
"embed/trezorhal/stm32u5/flash_otp.c",
|
"embed/trezorhal/stm32u5/flash_otp.c",
|
||||||
"embed/trezorhal/stm32u5/fwutils.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.c",
|
||||||
"embed/trezorhal/stm32u5/syscall_dispatch.c",
|
"embed/trezorhal/stm32u5/syscall_dispatch.c",
|
||||||
"embed/trezorhal/stm32u5/syscall_stubs.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/systick.c",
|
||||||
"embed/trezorhal/stm32u5/systimer.c",
|
"embed/trezorhal/stm32u5/systimer.c",
|
||||||
"embed/trezorhal/stm32u5/random_delays.c",
|
"embed/trezorhal/stm32u5/random_delays.c",
|
||||||
|
2
vendor/fido2-tests
vendored
2
vendor/fido2-tests
vendored
@ -1 +1 @@
|
|||||||
Subproject commit b9deb14b9e38cffa31b6d9a880c5e0d6855ef6ce
|
Subproject commit 9cfd22ef20fec2c34d0f0e5c16a5d5152da30861
|
Loading…
Reference in New Issue
Block a user