1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-22 22:38:08 +00:00

refactor(core/embed): simplify bootutils api

[no changelog]
This commit is contained in:
cepetr 2024-08-30 11:12:05 +02:00 committed by cepetr
parent 33a94d945d
commit ae4e195d6e
13 changed files with 235 additions and 133 deletions

View File

@ -2,8 +2,8 @@
#include <unistd.h>
#include TREZOR_BOARD
#include "bootargs.h"
#include "bootui.h"
#include "bootutils.h"
#include "common.h"
#include "display.h"
#include "flash.h"
@ -174,7 +174,7 @@ void mpu_config_bootloader(void) {}
void mpu_config_off(void) {}
__attribute__((noreturn)) void jump_to(uint32_t address) {
void jump_to(uint32_t address) {
bool storage_is_erased =
storage_empty(&STORAGE_AREAS[0]) && storage_empty(&STORAGE_AREAS[1]);

View File

@ -15,6 +15,6 @@ void emulator_poll_events(void);
void set_core_clock(int);
void mpu_config_bootloader(void);
void mpu_config_off(void);
void jump_to(void *addr);
__attribute__((noreturn)) void jump_to(uint32_t address);
#endif

View File

@ -20,6 +20,7 @@
#include <string.h>
#include <sys/types.h>
#include "bootargs.h"
#include "bootutils.h"
#include "common.h"
#include "display.h"
@ -342,11 +343,7 @@ void real_jump_to_firmware(void) {
__attribute__((noreturn)) void jump_to_fw_through_reset(void) {
display_fade(display_backlight(-1), 0, 200);
__disable_irq();
delete_secrets();
NVIC_SystemReset();
for (;;)
;
reboot();
}
#endif

View File

@ -24,7 +24,7 @@
#include <pb_encode.h>
#include "messages.pb.h"
#include "bootutils.h"
#include "bootargs.h"
#include "common.h"
#include "flash.h"
#include "image.h"

View File

@ -35,7 +35,7 @@ reset_handler:
// r11 contains the command passed to bootargs_set()
// function called when the firmware rebooted to the bootloader
ldr r0, =g_boot_command_shadow
ldr r0, =g_boot_command_saved
str r11, [r0]
// enter the application code

View File

@ -57,7 +57,7 @@ reset_handler:
// copy & clear g_boot_command
ldr r0, =g_boot_command
ldr r1, [r0]
ldr r0, =g_boot_command_shadow
ldr r0, =g_boot_command_saved
str r1, [r0]
ldr r0, =g_boot_command
mov r1, #0

View File

@ -284,31 +284,37 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_sd_hotswap_enabled_obj,
STATIC mp_obj_t mod_trezorutils_reboot_to_bootloader(size_t n_args,
const mp_obj_t *args) {
#ifndef TREZOR_EMULATOR
boot_command_t boot_command = BOOT_COMMAND_NONE;
mp_buffer_info_t boot_args = {0};
if (n_args > 0 && args[0] != mp_const_none) {
mp_int_t value = mp_obj_get_int(args[0]);
switch (value) {
case 0:
boot_command = BOOT_COMMAND_STOP_AND_WAIT;
// Reboot and stay in bootloader
reboot_to_bootloader();
break;
case 1:
boot_command = BOOT_COMMAND_INSTALL_UPGRADE;
// Reboot and continue with the firmware upgrade
mp_buffer_info_t hash = {0};
if (n_args > 1 && args[1] != mp_const_none) {
mp_get_buffer_raise(args[1], &hash, MP_BUFFER_READ);
}
if (hash.len != 32) {
mp_raise_ValueError("Invalid value.");
}
reboot_and_upgrade((uint8_t *)hash.buf);
break;
default:
mp_raise_ValueError("Invalid value.");
break;
}
} else {
// Just reboot and go through the normal boot sequence
reboot();
}
if (n_args > 1 && args[1] != mp_const_none) {
mp_get_buffer_raise(args[1], &boot_args, MP_BUFFER_READ);
}
bootargs_set(boot_command, boot_args.buf, boot_args.len);
reboot_to_bootloader();
#endif
return mp_const_none;
}

View File

@ -0,0 +1,57 @@
/*
* 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_BOOTARGS_H
#define TREZORHAL_BOOTARGS_H
#include <stddef.h>
#include <stdint.h>
// Defines boot command processed in bootloader on next reboot
typedef enum {
// Normal boot sequence
BOOT_COMMAND_NONE = 0x00000000,
// Stop and wait for further instructions
BOOT_COMMAND_STOP_AND_WAIT = 0x0FC35A96,
// Do not ask anything, install an upgrade
BOOT_COMMAND_INSTALL_UPGRADE = 0xFA4A5C8D,
} boot_command_t;
// Maximum size boot_args array
#define BOOT_ARGS_MAX_SIZE (256 - 8)
typedef union {
uint8_t raw[BOOT_ARGS_MAX_SIZE];
// firmware header hash, BOOT_COMMAND_INSTALL_UPGRADE
uint8_t hash[32];
} boot_args_t;
// Configures the boot command and associated arguments for the next reboot.
// The arguments must adhere to the boot_args_t structure layout.
void bootargs_set(boot_command_t command, const void* args, size_t args_size);
// Returns the last boot command saved during bootloader startup
boot_command_t bootargs_get_command();
// Returns the pointer to boot arguments
const boot_args_t* bootargs_get_args();
#endif // TREZORHAL_BOOTARGS_H

View File

@ -1,50 +1,49 @@
/*
* 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_BOOTUTILS_H
#define TREZORHAL_BOOTUTILS_H
#include <stddef.h>
#include <stdint.h>
// Defines boot command for 'reboot_to_bootloader()' function
typedef enum {
// Normal boot sequence
BOOT_COMMAND_NONE = 0x00000000,
// Stop and wait for further instructions
BOOT_COMMAND_STOP_AND_WAIT = 0x0FC35A96,
// Do not ask anything, install an upgrade
BOOT_COMMAND_INSTALL_UPGRADE = 0xFA4A5C8D,
} boot_command_t;
// Maximum size boot_args array
#define BOOT_ARGS_MAX_SIZE (256 - 8)
typedef union {
uint8_t raw[BOOT_ARGS_MAX_SIZE];
// firmware header hash, BOOT_COMMAND_INSTALL_UPGRADE
uint8_t hash[32];
} boot_args_t;
// Sets boot command and arguments for the next reboot
// arguments have too respect boot_args_t structure layout
// (function can be called multiple times before reboting)
void bootargs_set(boot_command_t command, const void* args, size_t args_size);
// Returns the last boot command set by bootargs_set_command()
boot_command_t bootargs_get_command();
// Returns the pointer to boot arguments
const boot_args_t* bootargs_get_args();
// Reboots the device into the bootloader.
// The bootloader will read the command set by `bootargs_set()`.
void __attribute__((noreturn)) reboot_to_bootloader(void);
// Causes immediate reset of the device.
// Immediately resets the device and initiates the normal boot sequence.
void __attribute__((noreturn)) reboot(void);
// Safely shuts down the device (clears secrets, memory, etc.).
// This function is called when the device is in an unrecoverable state.
// Resets the device and enters the bootloader,
// halting there and waiting for further user instructions.
void __attribute__((noreturn)) reboot_to_bootloader(void);
// Resets the device into the bootloader and automatically continues
// with the installation of new firmware (also known as an
// interaction-less upgrade).
//
// If the provided hash is NULL or invalid, the device will stop
// at the bootloader and will require user acknowledgment to proceed
// with the firmware installation.
void __attribute__((noreturn)) reboot_and_upgrade(const uint8_t hash[32]);
// Allows the user to see the displayed error message and then
// safely shuts down the device (clears secrets, memory, etc.).
//
// This function is called when the device enters an
// unrecoverable error state.
void __attribute__((noreturn)) secure_shutdown(void);
#endif // TREZORHAL_BOOTUTILS_H

View File

@ -1,33 +1,46 @@
/*
* 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 "../bootutils.h"
#include <common.h>
#include <string.h>
#include "bootargs.h"
#include "bootutils.h"
#include "common.h"
#include "display.h"
#include "irq.h"
#include "mpu.h"
// The 'g_boot_command_shadow' shadows a real boot command passed
// to the bootloader.
// 1. In the bootloader, its value is set in the startup code.
// 2. In the firmware it holds command for the next boot and it is used
// when reboot_to_bootloader() is called
boot_command_t g_boot_command_shadow;
#ifdef STM32U5
// The 'g_boot_command' is persistent variable that holds the 'command'
// for the next reboot/jump to the bootloader. Its value is set to
// g_boot_command_shadow when 'reboot_to_bootloader()' is called.
// Persistent variable that holds the 'command' for the next reboot.
boot_command_t __attribute__((section(".boot_command"))) g_boot_command;
#else
// Holds the 'command' for the next jump to the bootloader.
static boot_command_t g_boot_command = BOOT_COMMAND_NONE;
#endif
// The 'g_boot_args' is persistent array that stores extra arguments passed
// to the function bootargs_set.
// Persistent array that holds extra arguments for the command passed
// to the bootloader.
static boot_args_t __attribute__((section(".boot_args"))) g_boot_args;
void bootargs_set(boot_command_t command, const void* args, size_t args_size) {
// save boot command
g_boot_command_shadow = command;
g_boot_command = command;
size_t copy_size = 0;
// copy arguments up to BOOT_ARGS_MAX_SIZE
@ -43,17 +56,71 @@ void bootargs_set(boot_command_t command, const void* args, size_t args_size) {
}
}
boot_command_t bootargs_get_command() { return g_boot_command_shadow; }
#ifdef BOOTLOADER
// Contains the current boot command saved during bootloader startup.
boot_command_t g_boot_command_saved;
boot_command_t bootargs_get_command() { return g_boot_command_saved; }
const boot_args_t* bootargs_get_args() { return &g_boot_args; }
#endif
// Deletes all secrets and SRAM2 where stack is located
// to prevent stack smashing error, do not return from function calling this
#ifdef STM32U5
static inline void __attribute__((always_inline)) delete_secrets(void) {
__disable_irq();
// Disable SAES peripheral clock, so that we don't get tamper events
__HAL_RCC_SAES_CLK_DISABLE();
TAMP->CR2 |= TAMP_CR2_BKERASE;
}
#endif // STM32U5
// Reboots the device with the given boot command and arguments
static void __attribute__((noreturn))
reboot_with_args(boot_command_t command, const void* args, size_t args_size) {
bootargs_set(command, args, args_size);
#ifdef STM32U5
delete_secrets();
NVIC_SystemReset();
#else
display_deinit(DISPLAY_RESET_CONTENT);
#ifdef ENSURE_COMPATIBLE_SETTINGS
ensure_compatible_settings();
#endif
mpu_config_bootloader();
jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE, g_boot_command);
for (;;)
;
#endif
}
void reboot_to_bootloader(void) {
reboot_with_args(BOOT_COMMAND_STOP_AND_WAIT, NULL, 0);
}
void reboot_and_upgrade(const uint8_t hash[32]) {
reboot_with_args(BOOT_COMMAND_INSTALL_UPGRADE, hash, 32);
}
void reboot(void) {
bootargs_set(BOOT_COMMAND_NONE, NULL, 0);
#ifdef STM32U5
delete_secrets();
#endif
NVIC_SystemReset();
}
void __attribute__((noreturn)) secure_shutdown(void) {
display_deinit(DISPLAY_RETAIN_CONTENT);
#if defined(STM32U5)
__HAL_RCC_SAES_CLK_DISABLE();
// Erase all secrets
TAMP->CR2 |= TAMP_CR2_BKERASE;
#ifdef STM32U5
delete_secrets();
#endif
// from util.s
extern void shutdown_privileged(void);
@ -62,25 +129,3 @@ void __attribute__((noreturn)) secure_shutdown(void) {
for (;;)
;
}
void reboot_to_bootloader(void) {
boot_command_t boot_command = bootargs_get_command();
display_deinit(DISPLAY_RESET_CONTENT);
#ifdef ENSURE_COMPATIBLE_SETTINGS
ensure_compatible_settings();
#endif
#ifdef STM32U5
// extern uint32_t g_boot_command;
g_boot_command = boot_command;
__disable_irq();
delete_secrets();
NVIC_SystemReset();
#else
mpu_config_bootloader();
jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE, boot_command);
for (;;)
;
#endif
}
void reboot(void) { NVIC_SystemReset(); }

View File

@ -42,16 +42,6 @@ void jump_to_with_flag(uint32_t address, uint32_t register_flag);
extern uint32_t __stack_chk_guard;
// this deletes all secrets and SRAM2 where stack is located
// to prevent stack smashing error, do not return from function calling this
static inline void __attribute__((always_inline)) delete_secrets(void) {
// Disable SAES peripheral clock, so that we don't get tamper events
__HAL_RCC_SAES_CLK_DISABLE();
// Erase all
TAMP->CR2 |= TAMP_CR2_BKERASE;
}
void check_oem_keys(void);
#endif // TREZORHAL_STM32_H

View File

@ -1,6 +1,7 @@
#include "secret.h"
#include <stdbool.h>
#include <string.h>
#include "bootutils.h"
#include "common.h"
#include "flash.h"
#include "memzero.h"
@ -122,8 +123,7 @@ static secbool secret_present(uint32_t offset, uint32_t len) {
// read access to it.
static void secret_bhk_load(void) {
if (sectrue == secret_bhk_locked()) {
delete_secrets();
NVIC_SystemReset();
reboot();
}
uint32_t secret[SECRET_BHK_LEN / sizeof(uint32_t)] = {0};

View File

@ -1,26 +1,39 @@
/*
* 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 "../bootutils.h"
#include <common.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// The 'g_boot_command_shadow' variable stores the 'command' for the next
// reboot/jumping to the bootloadeer. It may be one of the
// 'BOOT_COMMAND_xxx' values defined in the enumeration, or it could
// be any other value that should be treated as a non-special action,
// in which case the bootloader should behave as if the device was
// just powered up.
#include <common.h>
#include "bootargs.h"
#include "bootutils.h"
static boot_command_t g_boot_command_shadow;
// Holds the 'command' for the next reboot.
static boot_command_t g_boot_command;
// The 'g_boot_args' array stores extra arguments passed
// function boot_args. It sits at section that persists jump to the bootloader.
// Holds extra arguments for the command passed to the bootloader.
static boot_args_t g_boot_args;
void bootargs_set(boot_command_t command, const void* args, size_t args_size) {
// save boot command
g_boot_command_shadow = command;
g_boot_command = command;
size_t copy_size = 0;
// copy arguments up to BOOT_ARGS_MAX_SIZE
@ -36,12 +49,7 @@ void bootargs_set(boot_command_t command, const void* args, size_t args_size) {
}
}
void bootargs_clear() {
g_boot_command_shadow = BOOT_COMMAND_NONE;
memset(&g_boot_args, 0, sizeof(g_boot_args));
}
boot_command_t bootargs_get_command() { return g_boot_command_shadow; }
boot_command_t bootargs_get_command() { return g_boot_command; }
const boot_args_t* bootargs_get_args() { return &g_boot_args; }