From 18da57f0400205f2a944b2f24814d22cb4b31961 Mon Sep 17 00:00:00 2001 From: MrNerdHair Date: Tue, 19 Apr 2022 22:41:53 -0400 Subject: [PATCH] feat: UpdateAfter is busted, add reset parameter for triggering update --- include/keepkey/board/keepkey_board.h | 6 ++++- lib/board/keepkey_board.c | 5 +++- tools/blupdater/main.c | 35 +++------------------------ tools/bootloader/main.c | 26 +++++++++++++++++++- tools/bootloader/startup.s | 16 ++++++++++++ 5 files changed, 54 insertions(+), 34 deletions(-) diff --git a/include/keepkey/board/keepkey_board.h b/include/keepkey/board/keepkey_board.h index eaa2b730a..dd4fe5248 100644 --- a/include/keepkey/board/keepkey_board.h +++ b/include/keepkey/board/keepkey_board.h @@ -61,6 +61,10 @@ #define VERSION_NUM(x) #x #define VERSION_STR(x) VERSION_NUM(x) +#define RESET_PARAM_NONE 0 +// This is the ASCII string "UPDT" interpreted as an integer in little-endian form. +#define RESET_PARAM_REQUEST_UPDATE 0x54445055 + /* Flash metadata structure which will contains unique identifier information that spans device resets. */ typedef struct _Metadata { @@ -79,7 +83,7 @@ typedef struct _Cache { extern uintptr_t __stack_chk_guard; -void board_reset(void); +void board_reset(uint32_t reset_param); void board_init(void); void kk_board_init(void); diff --git a/lib/board/keepkey_board.c b/lib/board/keepkey_board.c index cfc957a65..c2e83fa57 100644 --- a/lib/board/keepkey_board.c +++ b/lib/board/keepkey_board.c @@ -79,8 +79,11 @@ void nmi_handler(void) { * OUTPUT * none */ -void board_reset(void) { +void board_reset(uint32_t reset_param) { #ifndef EMULATOR + _param_1 = reset_param; + _param_2 = ~reset_param; + _param_3 = reset_param; scb_reset_system(); #endif } diff --git a/tools/blupdater/main.c b/tools/blupdater/main.c index 4980fd979..c60cc0cb3 100644 --- a/tools/blupdater/main.c +++ b/tools/blupdater/main.c @@ -91,17 +91,17 @@ static bool write_bootloader(void) { flash_unlock(); // erase the bootloader sectors, do not use flash_erase_word() - layoutProgress("Updating bootloader. DO NOT UNPLUG", 0); + layoutProgress("Updating Bootloader. DO NOT UNPLUG", 0); flash_erase_sector(5, FLASH_CR_PROGRAM_X32); flash_wait_for_last_operation(); - layoutProgress("Updating bootloader. DO NOT UNPLUG", 100); + layoutProgress("Updating Bootloader. DO NOT UNPLUG", 100); flash_erase_sector(6, FLASH_CR_PROGRAM_X32); flash_wait_for_last_operation(); // Write into the sector. for (int chunkstart = 0; chunkstart < _binary_payload_bin_size; chunkstart += CHUNK_SIZE) { - layoutProgress("Updating bootloader. DO NOT UNPLUG", + layoutProgress("Updating Bootloader. DO NOT UNPLUG", 200 + chunkstart * 800 / _binary_payload_bin_size); size_t chunksize; @@ -162,39 +162,12 @@ static bool unknown_bootloader(void) { /// \brief Success: everything went smoothly as expected, and the device has a /// new bootloader installed. static void success(void) { - for (int i = 0; i < NUM_RETRIES; ++i) { - // Enable writing to the read-only sectors - memory_unlock(); - flash_unlock(); - - flash_program_word(FLASH_META_FLAGS, META_FLAGS | 1); - flash_wait_for_last_operation(); - - if ((META_FLAGS & 1) == 1) { - break; - } - } - - // Disallow writing to flash. - flash_lock(); - - // Ignore any reported errors, we only care about the end result. - flash_clear_status_flags(); - - if ((META_FLAGS & 1) != 1) { - layout_standard_notification("Bootloader Update Complete", - "Please unplug your device.", - NOTIFICATION_CONFIRMED); - display_refresh(); - shutdown(); - } - layout_standard_notification("Bootloader Update Complete", "Your device will now restart", NOTIFICATION_CONFIRMED); display_refresh(); delay_ms(3000); - board_reset(); + board_reset(RESET_PARAM_REQUEST_UPDATE); } /// \brief Hard Failure: something went wrong during the write, and it's diff --git a/tools/bootloader/main.c b/tools/bootloader/main.c index 97e8cc392..5677d203f 100644 --- a/tools/bootloader/main.c +++ b/tools/bootloader/main.c @@ -143,6 +143,26 @@ static inline void __attribute__((noreturn)) jump_to_firmware(int trust) { ; } +uint32_t reset_param = 0; + +void capture_reset_param(void) { + // Capture the reset parameter value. Because SRAM starts up from a cold boot + // in an undefined state, a simple redundancy-based check is used to validate + // that a parameter was in fact passed: _param_1 and _param_3 must match, and + // _param_2 must be their bitwise inverse. + // + // Currently, this is only used by the blupdater to request that the firmware + // enter update mode, by passing RESET_PARAM_REQUEST_UPDATE. + if (_param_1 == ~_param_2 && _param_1 == _param_3) { + reset_param = _param_1; + } + + // Clear the shared memory section used for communicating the reset parameter. + _param_1 = 0; + _param_2 = 0; + _param_3 = 0; +} + /// Bootloader Board Initialization static void bootloader_init(void) { cm_enable_interrupts(); @@ -156,6 +176,7 @@ static void bootloader_init(void) { storage_sectorInit(); display_hw_init(); layout_init(display_canvas_init()); + capture_reset_param(); } /// Enable the timer interrupts @@ -175,6 +196,9 @@ static void clock_init(void) { /// \returns true iff the device should enter firmware update mode. static bool isFirmwareUpdateMode(void) { + // Firmware asked for an update. + if (reset_param == RESET_PARAM_REQUEST_UPDATE) return true; + // User asked for an update. if (keepkey_button_down()) return true; @@ -280,7 +304,7 @@ static void update_fw(void) { NOTIFICATION_CONFIRMED); display_refresh(); delay_ms(3000); - board_reset(); + board_reset(RESET_PARAM_NONE); } else { layout_standard_notification( "Firmware Update Failure", diff --git a/tools/bootloader/startup.s b/tools/bootloader/startup.s index 856c95154..ff3a7e954 100644 --- a/tools/bootloader/startup.s +++ b/tools/bootloader/startup.s @@ -26,12 +26,28 @@ reset_handler: ldr r0, [r0] msr msp, r0 + // Save any reset parameters from the SRAM wipe + ldr r0, =_param_1 + ldr r3, [r0] + ldr r0, =_param_2 + ldr r4, [r0] + ldr r0, =_param_3 + ldr r5, [r0] + ldr r0, =_ram_start // r0 - point to beginning of SRAM // ldr r1, =_ram_end // r1 - point to byte after the end of SRAM ldr r1, =_comram_end ldr r2, =0 // r2 - the byte-sized value to be written bl memset_reg + // Restore any reset parameters + ldr r0, =_param_1 + str r3, [r0] + ldr r0, =_param_2 + str r4, [r0] + ldr r0, =_param_3 + str r5, [r0] + // copy .data section from flash to SRAM ldr r0, =_data // dst addr ldr r1, =_data_loadaddr // src addr