From bf840c2b74b6d79e3eb02e863e2e761a077859c4 Mon Sep 17 00:00:00 2001 From: Niklas Dusenlund Date: Tue, 22 Apr 2025 23:52:42 +0200 Subject: [PATCH] bootloader-fw-link: Use RAM to communicate Instead of writing to non-volatile storage between mcu resets, write to a well-known location. RAM is random after hardware reset, but does not get cleared on MCU reset. --- bootloader.ld | 1 + firmware.ld | 1 + src/bootloader/bootloader.c | 12 +++++------- src/common_main.c | 8 ++++---- src/factorysetup.c | 16 +++------------- src/hardfault.c | 22 ++++++---------------- src/hardfault.h | 7 ------- src/memory/bitbox02_smarteeprom.c | 2 +- src/system.c | 14 ++++---------- src/system.h | 8 +++++++- 10 files changed, 32 insertions(+), 59 deletions(-) diff --git a/bootloader.ld b/bootloader.ld index 1e9d5faa2..f069ac96a 100644 --- a/bootloader.ld +++ b/bootloader.ld @@ -116,6 +116,7 @@ SECTIONS { . = ALIGN(4); _srtt = .; + *(.auto_enter); *(.segger_rtt); *(.segger_rtt_buf); _ertt = .; diff --git a/firmware.ld b/firmware.ld index f06a9d782..573d19052 100644 --- a/firmware.ld +++ b/firmware.ld @@ -115,6 +115,7 @@ SECTIONS { . = ALIGN(4); _srtt = .; + *(.auto_enter); *(.segger_rtt); *(.segger_rtt_buf); _ertt = .; diff --git a/src/bootloader/bootloader.c b/src/bootloader/bootloader.c index 2682d39be..83aefa48b 100644 --- a/src/bootloader/bootloader.c +++ b/src/bootloader/bootloader.c @@ -39,6 +39,9 @@ #include +// Section is fixed in ram, so can be used to communicate between fw/bl +volatile secbool_u32 auto_enter __attribute__((section(".auto_enter"))); + #define BOOT_OP_LEN 2u // 1 byte op code and 1 byte parameter #define BOOTLOADER_CMD (HID_VENDOR_FIRST + 0x03) // Hardware wallet command @@ -758,12 +761,7 @@ static size_t _api_versions(uint8_t* output) static void _api_reboot(void) { - chunk_shared_t shared_data; - memory_read_shared_bootdata(&shared_data); - if (shared_data.fields.auto_enter == sectrue_u8) { - shared_data.fields.auto_enter = secfalse_u8; - _write_chunk(FLASH_SHARED_DATA_START, shared_data.bytes); - } + auto_enter = secfalse_u32; _reset_mcu(); } @@ -977,7 +975,7 @@ void bootloader_jump(void) UG_FontSelect(&font_font_a_9X9); - if (shared_data.fields.auto_enter != sectrue_u8) { + if (auto_enter != sectrue_u32) { #ifdef BOOTLOADER_DEVDEVICE if (!_devdevice_enter(_firmware_verified_jump(&bootdata, secfalse_u32))) { _binary_exec(); diff --git a/src/common_main.c b/src/common_main.c index 002254c5a..44c73d32a 100644 --- a/src/common_main.c +++ b/src/common_main.c @@ -73,18 +73,18 @@ void common_main(void) mpu_bitbox02_init(); if (!memory_setup(&_memory_interface_functions)) { // If memory setup failed, this also might fail, but can't hurt to try. - AbortAutoenter("memory_setup failed"); + Abort("memory_setup failed"); } if (!_setup_wally()) { - AbortAutoenter("_setup_wally failed"); + Abort("_setup_wally failed"); } /* Enable/configure SmartEEPROM. */ smarteeprom_bb02_config(); if (!securechip_init()) { - AbortAutoenter("Failed to detect securechip"); + Abort("Failed to detect securechip"); } // securechip_setup must come after memory_setup, so the io/auth keys to be // used are already initialized. @@ -96,6 +96,6 @@ void common_main(void) sizeof(errmsg), "Securechip setup failed.\nError code: %i\nPlease contact support.", securechip_result); - AbortAutoenter(errmsg); + Abort(errmsg); } } diff --git a/src/factorysetup.c b/src/factorysetup.c index 39ba36773..c78d9681b 100644 --- a/src/factorysetup.c +++ b/src/factorysetup.c @@ -20,6 +20,7 @@ #include "platform_init.h" #include "screen.h" #include "securechip/securechip.h" +#include "system.h" #include "usb/usb.h" #include "usb/usb_packet.h" #include "usb/usb_processing.h" @@ -312,19 +313,8 @@ int main(void) screen_splash(); common_main(); - { - // Set to re-enter bootloader again, otherwise we are stuck with this - // firmware forever. - auto_enter_t auto_enter = { - .value = sectrue_u8, - }; - upside_down_t upside_down = { - .value = false, - }; - if (!memory_bootloader_set_flags(auto_enter, upside_down)) { - // Not much we can do here. - } - } + // After reset we prefer to stay in bootloader + auto_enter = sectrue_u32; SEGGER_RTT_Init(); diff --git a/src/hardfault.c b/src/hardfault.c index 3d2302ec2..e2105f0e4 100644 --- a/src/hardfault.c +++ b/src/hardfault.c @@ -13,6 +13,7 @@ // limitations under the License. #include "hardfault.h" +#include "system.h" #include "util.h" #include "utils_assert.h" #include @@ -47,20 +48,9 @@ void Abort(const char* msg) #endif // Break the program if we are debugging ASSERT(false); - while (1) { - } -} - -void AbortAutoenter(const char* msg) -{ - auto_enter_t auto_enter = { - .value = sectrue_u8, - }; - upside_down_t upside_down = { - .value = screen_is_upside_down(), - }; - if (!memory_bootloader_set_flags(auto_enter, upside_down)) { - // If this failed, we might not be able to reboot into the bootloader. - } - Abort(msg); + delay_ms(30000); + // Restart into bootloader + auto_enter = sectrue_u32; + _reset_mcu(); + while (1); } diff --git a/src/hardfault.h b/src/hardfault.h index c62186e21..35d94a3b2 100644 --- a/src/hardfault.h +++ b/src/hardfault.h @@ -26,11 +26,4 @@ void HardFault_Handler(void) __attribute__((weak)); // debugging. __attribute__((noreturn)) void Abort(const char* msg); -// Abort is for manual calls to stop execution, providing a message for debugging. It also sets -// autoenter to true, making sure that the device boots into the bootloader after reconnecting it. -// This should be called for any Abort during firmware startup, so a firmware update can be -// applied. Otherwise, if there is an Abort() during startup, there would no way to reboot into the -// bootloader and the device would be bricked. -__attribute__((noreturn)) void AbortAutoenter(const char* msg); - #endif diff --git a/src/memory/bitbox02_smarteeprom.c b/src/memory/bitbox02_smarteeprom.c index 1a4c322df..8549e29ad 100644 --- a/src/memory/bitbox02_smarteeprom.c +++ b/src/memory/bitbox02_smarteeprom.c @@ -110,7 +110,7 @@ void bitbox02_smarteeprom_init(void) */ char msg[200] = {0}; snprintf(msg, sizeof(msg), "Unrecognized SmartEEPROM version.\nGot %d", current_version); - AbortAutoenter(msg); + Abort(msg); } } diff --git a/src/system.c b/src/system.c index 432135dca..3ca7572a6 100644 --- a/src/system.c +++ b/src/system.c @@ -15,22 +15,16 @@ #include "system.h" #include #include +#include #ifndef TESTING #include #endif +volatile secbool_u32 auto_enter __attribute__((section(".auto_enter"))); + void reboot(void) { - auto_enter_t auto_enter = { - .value = sectrue_u8, - }; - upside_down_t upside_down = { - .value = screen_is_upside_down(), - }; - if (!memory_bootloader_set_flags(auto_enter, upside_down)) { - // If this failed, we might not be able to reboot into the bootloader. - // We will try anyway, no point in aborting here. - } + auto_enter = sectrue_u32; #ifndef TESTING _reset_mcu(); #endif diff --git a/src/system.h b/src/system.h index 322fbe8ef..d2fa5a15e 100644 --- a/src/system.h +++ b/src/system.h @@ -15,8 +15,14 @@ #ifndef _SYSTEM_H_ #define _SYSTEM_H_ +#include "util.h" + +// Set this to `sectrue_u32` to stay in bootloader, or anything else to jump to firmware + +extern volatile secbool_u32 auto_enter; + /** - * Reboots the device. + * Reboots the device into bootloader */ void reboot(void);