diff --git a/bootloader.ld b/bootloader.ld index 1e9d5faa20..f069ac96a1 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 f06a9d782b..573d190529 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 3791fe4e72..6e7916f9ed 100644 --- a/src/bootloader/bootloader.c +++ b/src/bootloader/bootloader.c @@ -51,6 +51,10 @@ #include +// Section is fixed in ram, so can be used to communicate between fw/bl +// Must stay synchronized with system.c, bootloader.ld, firmware.ld +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 @@ -845,12 +849,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(); } @@ -1076,7 +1075,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 3825de67f3..5cc2c81814 100644 --- a/src/common_main.c +++ b/src/common_main.c @@ -56,14 +56,14 @@ 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"); } /* 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. @@ -75,6 +75,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 24185c255e..f872ef4943 100644 --- a/src/factorysetup.c +++ b/src/factorysetup.c @@ -27,6 +27,7 @@ #include "rust/rust.h" #include "screen.h" #include "securechip/securechip.h" +#include "system.h" #include "uart.h" #include "usb/usb.h" #include "usb/usb_packet.h" @@ -581,19 +582,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; if (memory_get_platform() == MEMORY_PLATFORM_BITBOX02_PLUS) { _ble_result = _setup_ble(); diff --git a/src/hardfault.c b/src/hardfault.c index 6bd5460526..8718034db1 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 @@ -27,6 +28,7 @@ #endif #ifndef TESTING +#define ABORT_COUNTDOWN 30 void HardFault_Handler(void) { Abort("Unexpected error.\nPlease contact support."); @@ -46,29 +48,18 @@ void Abort(const char* msg) #else util_log("%s", msg); screen_print_debug(msg, 0); - usb_stop(); -#if defined(BOOTLOADER) - bootloader_close_interfaces(); -#else - system_close_interfaces(); -#endif // Break the program if we are debugging ASSERT(false); - while (1) { + char buf[30] = {0}; + for (int i = 0; i < ABORT_COUNTDOWN; i++) { + snprintf(buf, sizeof(buf), "Enter bootloader in %02d", ABORT_COUNTDOWN - i); + UG_PutStringCentered(0, 56, 128, 8, buf, false); + UG_SendBuffer(); + delay_ms(1000); } + // Restart into bootloader + auto_enter = sectrue_u32; + _reset_mcu(); + while (1); #endif } - -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); -} diff --git a/src/hardfault.h b/src/hardfault.h index c62186e21b..35d94a3b2a 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 1a4c322dfa..8549e29adf 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 40e9dc0736..ad53cc910b 100644 --- a/src/system.c +++ b/src/system.c @@ -18,11 +18,16 @@ #include #include #include +#include #ifndef TESTING #include "uart.h" #include #endif +// Section is fixed in ram, so can be used to communicate between fw/bl +// Must stay synchronized with bootloader.c, bootloader.ld, firmware.ld +volatile secbool_u32 auto_enter __attribute__((section(".auto_enter"))); + static void _ble_clear_product(void) { struct ringbuffer uart_queue; @@ -43,16 +48,7 @@ void reboot_to_bootloader(void) if (memory_get_platform() == MEMORY_PLATFORM_BITBOX02_PLUS) { _ble_clear_product(); } - 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 b56e2773d9..272e5555fc 100644 --- a/src/system.h +++ b/src/system.h @@ -15,6 +15,12 @@ #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 to bootloader */ diff --git a/src/usb/usb_processing.c b/src/usb/usb_processing.c index 4045e9d0e5..4e7de0edb6 100644 --- a/src/usb/usb_processing.c +++ b/src/usb/usb_processing.c @@ -423,7 +423,7 @@ void usb_processing_init(void) void usb_processing_lock(struct usb_processing* ctx) { if (_usb_state.blocking_ctx) { - AbortAutoenter("Tried to lock the USB stack while locked."); + Abort("Tried to lock the USB stack while locked."); } _usb_state.blocking_ctx = ctx; } @@ -436,7 +436,7 @@ void usb_processing_timeout_reset(int16_t val) void usb_processing_unlock(void) { if (!_usb_state.blocking_ctx) { - AbortAutoenter("Tried to unlock the USB stack while not locked."); + Abort("Tried to unlock the USB stack while not locked."); } _usb_state.blocking_ctx = NULL; }