diff --git a/core/embed/boardloader/main.c b/core/embed/boardloader/main.c index 43044ec62..875056c77 100644 --- a/core/embed/boardloader/main.c +++ b/core/embed/boardloader/main.c @@ -227,11 +227,9 @@ static secbool copy_sdcard(void) { // copy bootloader from SD card to Flash term_printf("copying new bootloader from SD card\n\n"); - for (int j = 0; j < (IMAGE_HEADER_SIZE + codelen) / FLASH_BURST_SIZE; j++) { - ensure(flash_area_write_burst(&BOOTLOADER_AREA, j * FLASH_BURST_SIZE, - &sdcard_buf[j * FLASH_BURST_WORDS]), - NULL); - } + ensure(flash_area_write_data(&BOOTLOADER_AREA, 0, sdcard_buf, + IMAGE_HEADER_SIZE + codelen), + NULL); ensure(flash_lock_write(), NULL); diff --git a/core/embed/bootloader/messages.c b/core/embed/bootloader/messages.c index 08621bb3a..12e027502 100644 --- a/core/embed/bootloader/messages.c +++ b/core/embed/bootloader/messages.c @@ -730,7 +730,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, // offset into the FIRMWARE_AREA part of the flash uint32_t write_offset = firmware_block * IMAGE_CHUNK_SIZE; - ensure((chunk_size % FLASH_BURST_SIZE == 0) * sectrue, NULL); + ensure((chunk_size % FLASH_BLOCK_SIZE == 0) * sectrue, NULL); while (bytes_remaining > 0) { // erase flash before writing @@ -749,17 +749,15 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, // write the received data uint32_t bytes_to_write = MIN(bytes_erased, bytes_remaining); - uint32_t write_end = write_offset + bytes_to_write; - ensure(flash_unlock_write(), NULL); - while (write_offset < write_end) { - // write a block to the flash - ensure(flash_area_write_burst(&FIRMWARE_AREA, write_offset, src), NULL); - write_offset += FLASH_BURST_SIZE; - src += FLASH_BURST_WORDS; - } + ensure(flash_area_write_data(&FIRMWARE_AREA, write_offset, src, + bytes_to_write), + NULL); ensure(flash_lock_write(), NULL); + write_offset += bytes_to_write; + src += bytes_to_write / sizeof(uint32_t); + bytes_remaining -= bytes_to_write; } diff --git a/core/embed/firmware/bl_check.c b/core/embed/firmware/bl_check.c index 72500051e..2e1891b52 100644 --- a/core/embed/firmware/bl_check.c +++ b/core/embed/firmware/bl_check.c @@ -217,27 +217,20 @@ void check_and_replace_bootloader(void) { do { uint32_t *p = decomp_out; - uint32_t last_whole_word_addr = (((uint32_t)decomp.dest) & ~0x7F); - while ((uint32_t)p < last_whole_word_addr) { - ensure(flash_area_write_burst(&BOOTLOADER_AREA, offset, p), NULL); - p += FLASH_BURST_WORDS; - offset += FLASH_BURST_WORDS * sizeof(uint32_t); - } - if ((uint8_t *)p < decomp.dest) { - // last few bytes in case of unaligned data - uint32_t d[FLASH_BURST_WORDS] = {0}; - memcpy(&d, p, (uint32_t)decomp.dest - (uint32_t)p); - ensure(flash_area_write_burst(&BOOTLOADER_AREA, offset, d), NULL); - offset += FLASH_BURST_WORDS * sizeof(uint32_t); - } + uint32_t size = decomp.dest - (uint8_t *)decomp_out; + uint32_t size_padded = FLASH_ALIGN(size); + ensure(flash_area_write_data_padded(&BOOTLOADER_AREA, offset, p, size, 0, + size_padded), + NULL); + offset += size_padded; decomp.dest = (uint8_t *)decomp_out; } while (uzlib_uncompress(&decomp) >= 0); - uint32_t d[FLASH_BURST_WORDS] = {0}; - // fill the rest of the bootloader area with 0x00 - while (offset < bl_len) { - ensure(flash_area_write_burst(&BOOTLOADER_AREA, offset, d), NULL); - offset += FLASH_BURST_WORDS * sizeof(uint32_t); + if (offset < bl_len) { + // fill the rest of the bootloader area with 0x00 + ensure(flash_area_write_data_padded(&BOOTLOADER_AREA, offset, NULL, 0, 0, + bl_len - offset), + NULL); } ensure(flash_lock_write(), NULL); diff --git a/core/embed/lib/translations.c b/core/embed/lib/translations.c index 108b318a6..d00fa0d48 100644 --- a/core/embed/lib/translations.c +++ b/core/embed/lib/translations.c @@ -13,24 +13,10 @@ bool translations_write(const uint8_t* data, uint32_t offset, uint32_t len) { } ensure(flash_unlock_write(), "translations_write unlock"); - for (int i = 0; i < (len / FLASH_BLOCK_SIZE); i++) { - // todo consider alignment - ensure(flash_area_write_block(&TRANSLATIONS_AREA, - offset + (i * FLASH_BLOCK_SIZE), - (const uint32_t*)&data[i * FLASH_BLOCK_SIZE]), - "translations_write write"); - } - - if (len % FLASH_BLOCK_SIZE) { - flash_block_t block = {0}; - memset(block, 0xFF, FLASH_BLOCK_SIZE); - memcpy(block, data + (len / FLASH_BLOCK_SIZE) * FLASH_BLOCK_SIZE, - len % FLASH_BLOCK_SIZE); - ensure(flash_area_write_block( - &TRANSLATIONS_AREA, - offset + (len / FLASH_BLOCK_SIZE) * FLASH_BLOCK_SIZE, block), - "translations_write write rest"); - } + // todo consider alignment + ensure(flash_area_write_data_padded(&TRANSLATIONS_AREA, offset, data, len, + 0xFF, FLASH_ALIGN(len)), + "translations_write write"); ensure(flash_lock_write(), "translations_write lock"); return true; } diff --git a/core/embed/trezorhal/flash.h b/core/embed/trezorhal/flash.h index e014c01aa..2918b11ee 100644 --- a/core/embed/trezorhal/flash.h +++ b/core/embed/trezorhal/flash.h @@ -28,9 +28,6 @@ #include "flash_ll.h" -#define FLASH_BURST_WORDS (4 * 8) -#define FLASH_BURST_SIZE (FLASH_BURST_WORDS * sizeof(uint32_t)) - void flash_init(void); #endif // TREZORHAL_FLASH_H diff --git a/core/embed/trezorhal/stm32f4/flash.c b/core/embed/trezorhal/stm32f4/flash.c index 7d0761f10..8a34cc694 100644 --- a/core/embed/trezorhal/stm32f4/flash.c +++ b/core/embed/trezorhal/stm32f4/flash.c @@ -194,20 +194,6 @@ secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data) { return sectrue; } -secbool flash_write_burst(uint16_t sector, uint32_t offset, - const uint32_t *data) { - if ((offset % FLASH_BURST_SIZE) != 0) { - return secfalse; - } - for (int i = 0; i < FLASH_BURST_WORDS; i++) { - if (sectrue != - flash_write_word(sector, offset + i * sizeof(uint32_t), data[i])) { - return secfalse; - } - } - return sectrue; -} - secbool flash_write_block(uint16_t sector, uint32_t offset, const flash_block_t block) { return flash_write_word(sector, offset, block[0]); diff --git a/core/embed/trezorhal/stm32u5/flash.c b/core/embed/trezorhal/stm32u5/flash.c index 808caa1a9..3f72031cf 100644 --- a/core/embed/trezorhal/stm32u5/flash.c +++ b/core/embed/trezorhal/stm32u5/flash.c @@ -130,22 +130,22 @@ secbool flash_sector_erase(uint16_t sector) { secbool flash_write_quadword(uint16_t sector, uint32_t offset, const uint32_t *data) { uint32_t address = - (uint32_t)flash_get_address(sector, offset, 4 * sizeof(uint32_t)); + (uint32_t)flash_get_address(sector, offset, FLASH_QUADWORD_SIZE); if (address == 0) { return secfalse; } - if (offset % (4 * sizeof(uint32_t))) { // we write only at 16-byte boundary + if (offset % FLASH_QUADWORD_SIZE) { // we write only at 16-byte boundary return secfalse; } - for (int i = 0; i < 4; i++) { + for (int i = 0; i < FLASH_QUADWORD_WORDS; i++) { if (data[i] != (data[i] & *((const uint32_t *)address + i))) { return secfalse; } } secbool all_match = sectrue; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < FLASH_QUADWORD_WORDS; i++) { if (data[i] != *((const uint32_t *)address + i)) { all_match = secfalse; break; @@ -160,7 +160,7 @@ secbool flash_write_quadword(uint16_t sector, uint32_t offset, return secfalse; } - for (int i = 0; i < 4; i++) { + for (int i = 0; i < FLASH_QUADWORD_WORDS; i++) { if (data[i] != *((const uint32_t *)address + i)) { return secfalse; } @@ -175,7 +175,7 @@ secbool flash_write_burst(uint16_t sector, uint32_t offset, if (address == 0) { return secfalse; } - if (offset % FLASH_BURST_SIZE) { + if (offset % FLASH_BURST_SIZE) { // we write only at 128-byte boundary return secfalse; } diff --git a/core/embed/trezorhal/stm32u5/platform.h b/core/embed/trezorhal/stm32u5/platform.h index 233a367dd..bfb7e0499 100644 --- a/core/embed/trezorhal/stm32u5/platform.h +++ b/core/embed/trezorhal/stm32u5/platform.h @@ -25,6 +25,12 @@ #define SENSITIVE __attribute__((section(".sensitive"))) +#define FLASH_QUADWORD_WORDS (4) +#define FLASH_QUADWORD_SIZE (FLASH_QUADWORD_WORDS * sizeof(uint32_t)) + +#define FLASH_BURST_WORDS (8 * FLASH_QUADWORD_WORDS) +#define FLASH_BURST_SIZE (FLASH_BURST_WORDS * sizeof(uint32_t)) + typedef enum { CLOCK_160_MHZ = 0, } clock_settings_t; diff --git a/core/embed/trezorhal/unix/flash.c b/core/embed/trezorhal/unix/flash.c index 59dca876e..afee94018 100644 --- a/core/embed/trezorhal/unix/flash.c +++ b/core/embed/trezorhal/unix/flash.c @@ -228,20 +228,6 @@ secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data) { return sectrue; } -secbool flash_write_burst(uint16_t sector, uint32_t offset, - const uint32_t *data) { - if ((offset % FLASH_BURST_SIZE) != 0) { - return secfalse; - } - for (int i = 0; i < FLASH_BURST_WORDS; i++) { - if (sectrue != - flash_write_word(sector, offset + i * sizeof(uint32_t), data[i])) { - return secfalse; - } - } - return sectrue; -} - secbool flash_write_block(uint16_t sector, uint32_t offset, const flash_block_t block) { if (offset % (sizeof(uint32_t) * diff --git a/legacy/flash.c b/legacy/flash.c index b43954fd3..37a9f62d3 100644 --- a/legacy/flash.c +++ b/legacy/flash.c @@ -26,9 +26,6 @@ #include "memory.h" #include "supervise.h" -#define FLASH_BURST_WORDS (4 * 8) -#define FLASH_BURST_SIZE (FLASH_BURST_WORDS * sizeof(uint32_t)) - #define STORAGE_AREAS_COUNT 2 static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { @@ -161,20 +158,6 @@ secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data) { return sectrue; } -secbool flash_write_burst(uint16_t sector, uint32_t offset, - const uint32_t *data) { - if ((offset % FLASH_BURST_SIZE) != 0) { - return secfalse; - } - for (int i = 0; i < FLASH_BURST_WORDS; i++) { - if (sectrue != - flash_write_word(sector, offset + i * sizeof(uint32_t), data[i])) { - return secfalse; - } - } - return sectrue; -} - secbool flash_write_block(uint16_t sector, uint32_t offset, const flash_block_t block) { return flash_write_word(sector, offset, block[0]); diff --git a/storage/flash_area.c b/storage/flash_area.c index bf7691177..f4953cf0c 100644 --- a/storage/flash_area.c +++ b/storage/flash_area.c @@ -18,7 +18,9 @@ */ #include "flash_area.h" +#include #include +#include uint32_t flash_area_get_size(const flash_area_t *area) { uint32_t size = 0; @@ -120,6 +122,7 @@ secbool flash_area_write_quadword(const flash_area_t *area, uint32_t offset, #endif // not defined FLASH_BIT_ACCESS +#ifdef FLASH_BURST_SIZE secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset, const uint32_t *data) { uint16_t sector; @@ -129,6 +132,7 @@ secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset, } return flash_write_burst(sector, sector_offset, data); } +#endif secbool flash_area_write_block(const flash_area_t *area, uint32_t offset, const flash_block_t block) { @@ -145,6 +149,81 @@ secbool flash_area_write_block(const flash_area_t *area, uint32_t offset, return flash_write_block(sector, sector_offset, block); } +secbool __wur flash_area_write_data(const flash_area_t *area, uint32_t offset, + const void *data, uint32_t size) { + return flash_area_write_data_padded(area, offset, data, size, 0, size); +} + +secbool __wur flash_area_write_data_padded(const flash_area_t *area, + uint32_t offset, const void *data, + uint32_t data_size, uint8_t padding, + uint32_t total_size) { + if (offset % FLASH_BLOCK_SIZE) { + return secfalse; + } + if (total_size % FLASH_BLOCK_SIZE) { + return secfalse; + } + if (data_size > total_size) { + return secfalse; + } + if (offset + total_size > flash_area_get_size(area)) { + return secfalse; + } + + const uint32_t *data32 = (const uint32_t *)data; + + while (total_size > 0) { +#ifdef FLASH_BURST_SIZE + if ((offset % FLASH_BURST_SIZE) == 0 && + (offset + FLASH_BURST_SIZE) <= total_size) { + if (data_size >= FLASH_BURST_SIZE) { + if (flash_area_write_burst(area, offset, data32) != sectrue) { + return secfalse; + } + data_size -= FLASH_BURST_SIZE; + data32 += FLASH_BURST_WORDS; + } else { + uint32_t burst[FLASH_BURST_WORDS]; + memset(burst, padding, sizeof(burst)); + if (data_size > 0) { + memcpy(burst, data32, data_size); + data_size = 0; + } + if (flash_area_write_burst(area, offset, burst) != sectrue) { + return secfalse; + } + } + offset += FLASH_BURST_SIZE; + total_size -= FLASH_BURST_SIZE; + } else +#endif + { + if (data_size >= FLASH_BLOCK_SIZE) { + if (flash_area_write_block(area, offset, data32) != sectrue) { + return secfalse; + } + data_size -= FLASH_BLOCK_SIZE; + data32 += FLASH_BLOCK_WORDS; + } else { + uint32_t block[FLASH_BLOCK_WORDS]; + memset(block, padding, sizeof(block)); + if (data_size > 0) { + memcpy(block, data32, data_size); + data_size = 0; + } + if (flash_area_write_block(area, offset, block) != sectrue) { + return secfalse; + } + } + offset += FLASH_BLOCK_SIZE; + total_size -= FLASH_BLOCK_SIZE; + } + } + + return sectrue; +} + secbool flash_area_erase(const flash_area_t *area, void (*progress)(int pos, int len)) { return flash_area_erase_bulk(area, 1, progress); diff --git a/storage/flash_area.h b/storage/flash_area.h index d88f2e8e5..6d0edd7a9 100644 --- a/storage/flash_area.h +++ b/storage/flash_area.h @@ -76,6 +76,23 @@ secbool __wur flash_area_write_burst(const flash_area_t *area, uint32_t offset, secbool __wur flash_area_write_block(const flash_area_t *area, uint32_t offset, const flash_block_t block); +// Writes data to specified 'offset' inside a flash area +// Data is written in efficient way, using the smallest possible number of +// flash operations on the given architecture. +// Data and its size must be aligned to size of one flash block +secbool __wur flash_area_write_data(const flash_area_t *area, uint32_t offset, + const void *data, uint32_t size); + +// Writes data to specified 'offset' inside a flash area +// Data is written in efficient way, using the smallest possible number of +// flash operations on the given architecture. +// Data and total size must be aligned to size of one flash block +// The difference between data_size and total_size is padded with 'padding' +secbool __wur flash_area_write_data_padded(const flash_area_t *area, + uint32_t offset, const void *data, + uint32_t data_size, uint8_t padding, + uint32_t total_size); + secbool __wur flash_area_erase(const flash_area_t *area, void (*progress)(int pos, int len)); secbool __wur flash_area_erase_bulk(const flash_area_t *area, int count,