diff --git a/core/SConscript.boardloader b/core/SConscript.boardloader
index c067a83db8..c3a6ececc3 100644
--- a/core/SConscript.boardloader
+++ b/core/SConscript.boardloader
@@ -81,8 +81,13 @@ FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_
SOURCE_BOARDLOADER = [
'embed/projects/boardloader/main.c',
+ 'embed/projects/boardloader/bld_version.c',
]
+if 'sd_card' in FEATURES_AVAILABLE:
+ SOURCE_MOD += [
+ 'embed/projects/boardloader/sd_update.c',
+ ]
env.Replace(
CAT='cat',
diff --git a/core/embed/projects/boardloader/bld_version.c b/core/embed/projects/boardloader/bld_version.c
new file mode 100644
index 0000000000..3c99787487
--- /dev/null
+++ b/core/embed/projects/boardloader/bld_version.c
@@ -0,0 +1,36 @@
+/*
+ * 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 .
+ */
+#include
+#include
+
+#include
+
+#include "bld_version.h"
+
+uint8_t get_bootloader_min_version(void) {
+ uint8_t version = 0;
+ ensure(monoctr_read(MONOCTR_BOOTLOADER_VERSION, &version), "monoctr read");
+ return version;
+}
+
+void write_bootloader_min_version(uint8_t version) {
+ if (version > get_bootloader_min_version()) {
+ ensure(monoctr_write(MONOCTR_BOOTLOADER_VERSION, version), "monoctr write");
+ }
+}
diff --git a/core/embed/projects/boardloader/bld_version.h b/core/embed/projects/boardloader/bld_version.h
new file mode 100644
index 0000000000..3822cd0476
--- /dev/null
+++ b/core/embed/projects/boardloader/bld_version.h
@@ -0,0 +1,28 @@
+/*
+ * 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 .
+ */
+
+#pragma once
+
+#include
+
+// Read the minimum version of the bootloader that is allowed to run.
+uint8_t get_bootloader_min_version(void);
+
+// Write the minimum version of the bootloader that is allowed to run.
+void write_bootloader_min_version(uint8_t version);
diff --git a/core/embed/projects/boardloader/main.c b/core/embed/projects/boardloader/main.c
index bcfa3446cb..a64583ee21 100644
--- a/core/embed/projects/boardloader/main.c
+++ b/core/embed/projects/boardloader/main.c
@@ -20,18 +20,11 @@
#include
#include
-#include
-#include
-#include
#include
-#include
-#include
#include
#include
-#include
#include
#include
-#include
#include
#include
#include
@@ -47,10 +40,6 @@
#include
#endif
-#ifdef USE_SD_CARD
-#include
-#endif
-
#ifdef USE_HASH_PROCESSOR
#include
#endif
@@ -63,9 +52,13 @@
#include
#endif
-#include "memzero.h"
+#include "bld_version.h"
#include "version.h"
+#ifdef USE_SD_CARD
+#include "sd_update.h"
+#endif
+
const uint8_t BOARDLOADER_KEY_M = 2;
const uint8_t BOARDLOADER_KEY_N = 3;
static const uint8_t * const BOARDLOADER_KEYS[] = {
@@ -93,9 +86,6 @@ static void drivers_init(void) {
hash_processor_init();
#endif
display_init(DISPLAY_RESET_CONTENT);
-#ifdef USE_SD_CARD
- sdcard_init();
-#endif
}
static void drivers_deinit(void) {
@@ -108,18 +98,6 @@ static void drivers_deinit(void) {
#endif
}
-static uint8_t get_bootloader_min_version(void) {
- uint8_t version = 0;
- ensure(monoctr_read(MONOCTR_BOOTLOADER_VERSION, &version), "monoctr read");
- return version;
-}
-
-static void write_bootloader_min_version(uint8_t version) {
- if (version > get_bootloader_min_version()) {
- ensure(monoctr_write(MONOCTR_BOOTLOADER_VERSION, version), "monoctr write");
- }
-}
-
struct BoardCapabilities capabilities
__attribute__((section(".capabilities_section"))) = {
.header = CAPABILITIES_HEADER,
@@ -135,127 +113,6 @@ struct BoardCapabilities capabilities
.terminator_tag = TAG_TERMINATOR,
.terminator_length = 0};
-// we use SRAM as SD card read buffer (because DMA can't access the CCMRAM)
-__attribute__((section(".buf")))
-uint32_t sdcard_buf[BOOTLOADER_MAXSIZE / sizeof(uint32_t)];
-
-#if defined USE_SD_CARD
-static uint32_t check_sdcard(void) {
- if (sectrue != sdcard_power_on()) {
- return 0;
- }
-
- uint64_t cap = sdcard_get_capacity_in_bytes();
- if (cap < 1024 * 1024) {
- sdcard_power_off();
- return 0;
- }
-
- memzero(sdcard_buf, IMAGE_HEADER_SIZE);
-
- const secbool read_status =
- sdcard_read_blocks(sdcard_buf, 0, BOOTLOADER_MAXSIZE / SDCARD_BLOCK_SIZE);
-
- sdcard_power_off();
-
- if (sectrue == read_status) {
- const image_header *hdr =
- read_image_header((const uint8_t *)sdcard_buf, BOOTLOADER_IMAGE_MAGIC,
- BOOTLOADER_MAXSIZE);
-
- if (hdr != (const image_header *)sdcard_buf) {
- return 0;
- }
-
- if (sectrue != check_image_model(hdr)) {
- return 0;
- }
-
- if (sectrue != check_image_header_sig(hdr, BOARDLOADER_KEY_M,
- BOARDLOADER_KEY_N,
- BOARDLOADER_KEYS)) {
- return 0;
- }
-
- _Static_assert(IMAGE_CHUNK_SIZE >= BOOTLOADER_MAXSIZE,
- "BOOTLOADER IMAGE MAXSIZE too large for IMAGE_CHUNK_SIZE");
-
- const uint32_t code_start_offset = hdr->hdrlen;
-
- if (sectrue !=
- (check_single_hash(hdr->hashes,
- (const uint8_t *)sdcard_buf + code_start_offset,
- hdr->codelen))) {
- return 0;
- }
-
- for (int i = IMAGE_HASH_DIGEST_LENGTH; i < sizeof(hdr->hashes); i++) {
- if (hdr->hashes[i] != 0) {
- return 0;
- }
- }
-
- if (hdr->monotonic < get_bootloader_min_version()) {
- return 0;
- }
-
- return hdr->codelen;
- }
-
- return 0;
-}
-
-static void progress_callback(int pos, int len) { term_printf("."); }
-
-static secbool copy_sdcard(void) {
- display_set_backlight(255);
-
- term_printf("Trezor Boardloader\n");
- term_printf("==================\n\n");
-
- term_printf("bootloader found on the SD card\n\n");
- term_printf("applying bootloader in 10 seconds\n\n");
- term_printf("unplug now if you want to abort\n\n");
-
- uint32_t codelen;
-
- for (int i = 10; i >= 0; i--) {
- term_printf("%d ", i);
- hal_delay(1000);
- codelen = check_sdcard();
- if (0 == codelen) {
- term_printf("\n\nno SD card, aborting\n");
- return secfalse;
- }
- }
-
- term_printf("\n\nerasing flash:\n\n");
-
- // erase all flash (except boardloader)
- if (sectrue != erase_device(progress_callback)) {
- term_printf(" failed\n");
- return secfalse;
- }
- term_printf(" done\n\n");
-
- ensure(flash_unlock_write(), NULL);
-
- // copy bootloader from SD card to Flash
- term_printf("copying new bootloader from SD card\n\n");
-
- ensure(flash_area_write_data(&BOOTLOADER_AREA, 0, sdcard_buf,
- IMAGE_HEADER_SIZE + codelen),
- NULL);
-
- ensure(flash_lock_write(), NULL);
-
- term_printf("\ndone\n\n");
- term_printf("Unplug the device and remove the SD card\n");
-
- return sectrue;
-}
-#endif
-
int main(void) {
system_init(&rsod_panic_handler);
@@ -274,26 +131,8 @@ int main(void) {
drivers_init();
#ifdef USE_SD_CARD
- // If the bootloader is being updated from SD card, we need to preserve the
- // monotonic counter from the old bootloader. This is in case that the old
- // bootloader did not have the chance yet to write its monotonic counter to
- // the secret area - which normally happens later in the flow.
- const image_header *old_hdr = read_image_header(
- (const uint8_t *)BOOTLOADER_START, BOOTLOADER_IMAGE_MAGIC,
- flash_area_get_size(&BOOTLOADER_AREA));
-
- if ((old_hdr != NULL) &&
- (sectrue == check_image_header_sig(old_hdr, BOARDLOADER_KEY_M,
- BOARDLOADER_KEY_N,
- BOARDLOADER_KEYS)) &&
- (sectrue ==
- check_image_contents(old_hdr, IMAGE_HEADER_SIZE, &BOOTLOADER_AREA))) {
- write_bootloader_min_version(old_hdr->monotonic);
- }
-
- if (check_sdcard()) {
- return copy_sdcard() == sectrue ? 0 : 3;
- }
+ sd_update_check_and_update(BOARDLOADER_KEYS, BOARDLOADER_KEY_M,
+ BOARDLOADER_KEY_N);
#endif
const image_header *hdr = read_image_header(
diff --git a/core/embed/projects/boardloader/sd_update.c b/core/embed/projects/boardloader/sd_update.c
new file mode 100644
index 0000000000..fa5bd11fa7
--- /dev/null
+++ b/core/embed/projects/boardloader/sd_update.c
@@ -0,0 +1,166 @@
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "memzero.h"
+
+#include "bld_version.h"
+
+#ifdef USE_SD_CARD
+#include
+#endif
+
+#include "sd_update.h"
+
+// we use SRAM as SD card read buffer (because DMA can't access the CCMRAM)
+__attribute__((section(".buf")))
+uint32_t sdcard_buf[BOOTLOADER_MAXSIZE / sizeof(uint32_t)];
+
+static uint32_t check_sdcard(const uint8_t *const *keys, uint8_t key_m,
+ uint8_t key_n) {
+ if (sectrue != sdcard_power_on()) {
+ return 0;
+ }
+
+ uint64_t cap = sdcard_get_capacity_in_bytes();
+ if (cap < 1024 * 1024) {
+ sdcard_power_off();
+ return 0;
+ }
+
+ memzero(sdcard_buf, IMAGE_HEADER_SIZE);
+
+ const secbool read_status =
+ sdcard_read_blocks(sdcard_buf, 0, BOOTLOADER_MAXSIZE / SDCARD_BLOCK_SIZE);
+
+ sdcard_power_off();
+
+ if (sectrue == read_status) {
+ const image_header *hdr =
+ read_image_header((const uint8_t *)sdcard_buf, BOOTLOADER_IMAGE_MAGIC,
+ BOOTLOADER_MAXSIZE);
+
+ if (hdr != (const image_header *)sdcard_buf) {
+ return 0;
+ }
+
+ if (sectrue != check_image_model(hdr)) {
+ return 0;
+ }
+
+ if (sectrue != check_image_header_sig(hdr, key_m, key_n, keys)) {
+ return 0;
+ }
+
+ _Static_assert(IMAGE_CHUNK_SIZE >= BOOTLOADER_MAXSIZE,
+ "BOOTLOADER IMAGE MAXSIZE too large for IMAGE_CHUNK_SIZE");
+
+ const uint32_t code_start_offset = hdr->hdrlen;
+
+ if (sectrue !=
+ (check_single_hash(hdr->hashes,
+ (const uint8_t *)sdcard_buf + code_start_offset,
+ hdr->codelen))) {
+ return 0;
+ }
+
+ for (int i = IMAGE_HASH_DIGEST_LENGTH; i < sizeof(hdr->hashes); i++) {
+ if (hdr->hashes[i] != 0) {
+ return 0;
+ }
+ }
+
+ if (hdr->monotonic < get_bootloader_min_version()) {
+ return 0;
+ }
+
+ return hdr->codelen;
+ }
+
+ return 0;
+}
+
+static void progress_callback(int pos, int len) { term_printf("."); }
+
+static secbool copy_sdcard(const uint8_t *const *keys, uint8_t key_m,
+ uint8_t key_n) {
+ display_set_backlight(255);
+
+ term_printf("Trezor Boardloader\n");
+ term_printf("==================\n\n");
+
+ term_printf("bootloader found on the SD card\n\n");
+ term_printf("applying bootloader in 10 seconds\n\n");
+ term_printf("unplug now if you want to abort\n\n");
+
+ uint32_t codelen;
+
+ for (int i = 10; i >= 0; i--) {
+ term_printf("%d ", i);
+ hal_delay(1000);
+ codelen = check_sdcard(keys, key_m, key_n);
+ if (0 == codelen) {
+ term_printf("\n\nno SD card, aborting\n");
+ return secfalse;
+ }
+ }
+
+ term_printf("\n\nerasing flash:\n\n");
+
+ // erase all flash (except boardloader)
+ if (sectrue != erase_device(progress_callback)) {
+ term_printf(" failed\n");
+ return secfalse;
+ }
+ term_printf(" done\n\n");
+
+ ensure(flash_unlock_write(), NULL);
+
+ // copy bootloader from SD card to Flash
+ term_printf("copying new bootloader from SD card\n\n");
+
+ ensure(flash_area_write_data(&BOOTLOADER_AREA, 0, sdcard_buf,
+ IMAGE_HEADER_SIZE + codelen),
+ NULL);
+
+ ensure(flash_lock_write(), NULL);
+
+ term_printf("\ndone\n\n");
+ term_printf("Unplug the device and remove the SD card\n");
+
+ return sectrue;
+}
+
+void sd_update_check_and_update(const uint8_t *const *keys, uint8_t key_m,
+ uint8_t key_n) {
+ sdcard_init();
+
+ // If the bootloader is being updated from SD card, we need to preserve the
+ // monotonic counter from the old bootloader. This is in case that the old
+ // bootloader did not have the chance yet to write its monotonic counter to
+ // the secret area - which normally happens later in the flow.
+ const image_header *old_hdr = read_image_header(
+ (const uint8_t *)BOOTLOADER_START, BOOTLOADER_IMAGE_MAGIC,
+ flash_area_get_size(&BOOTLOADER_AREA));
+
+ if ((old_hdr != NULL) &&
+ (sectrue == check_image_header_sig(old_hdr, key_m, key_n, keys)) &&
+ (sectrue ==
+ check_image_contents(old_hdr, IMAGE_HEADER_SIZE, &BOOTLOADER_AREA))) {
+ write_bootloader_min_version(old_hdr->monotonic);
+ }
+
+ if (check_sdcard(keys, key_m, key_n) != 0) {
+ copy_sdcard(keys, key_m, key_n);
+ reboot_or_halt_after_rsod();
+ }
+}
diff --git a/core/embed/projects/boardloader/sd_update.h b/core/embed/projects/boardloader/sd_update.h
new file mode 100644
index 0000000000..0b1316dfad
--- /dev/null
+++ b/core/embed/projects/boardloader/sd_update.h
@@ -0,0 +1,27 @@
+/*
+ * 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 .
+ */
+
+#pragma once
+
+#include
+
+// Check the SD card for a valid bootloader image, and if found, update the
+// bootloader. Halts the execution after updating (successful or not).
+void sd_update_check_and_update(const uint8_t* const* keys, uint8_t key_m,
+ uint8_t key_n);