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);