diff --git a/core/SConscript.boardloader b/core/SConscript.boardloader
index 77548da7f43..696ba852971 100644
--- a/core/SConscript.boardloader
+++ b/core/SConscript.boardloader
@@ -50,6 +50,7 @@ SOURCE_MOD += [
'vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.c',
'vendor/trezor-crypto/memzero.c',
'vendor/trezor-crypto/sha2.c',
+ 'vendor/trezor-storage/flash_area.c',
]
# modtrezorui
diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader
index f42ade77355..a63d80714ba 100644
--- a/core/SConscript.bootloader
+++ b/core/SConscript.bootloader
@@ -71,6 +71,7 @@ SOURCE_MOD += [
'vendor/trezor-crypto/memzero.c',
'vendor/trezor-crypto/rand.c',
'vendor/trezor-crypto/sha2.c',
+ 'vendor/trezor-storage/flash_area.c',
]
# modtrezorui
diff --git a/core/SConscript.bootloader_ci b/core/SConscript.bootloader_ci
index d0cd4d676e4..4a695bae294 100644
--- a/core/SConscript.bootloader_ci
+++ b/core/SConscript.bootloader_ci
@@ -66,6 +66,7 @@ SOURCE_MOD += [
'vendor/trezor-crypto/memzero.c',
'vendor/trezor-crypto/rand.c',
'vendor/trezor-crypto/sha2.c',
+ 'vendor/trezor-storage/flash_area.c',
]
# modtrezorui
diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu
index 90d13ad6f96..a16c535d7e7 100644
--- a/core/SConscript.bootloader_emu
+++ b/core/SConscript.bootloader_emu
@@ -89,13 +89,9 @@ SOURCE_MOD += [
'vendor/micropython/lib/uzlib/adler32.c',
'vendor/micropython/lib/uzlib/crc32.c',
'vendor/micropython/lib/uzlib/tinflate.c',
+ 'vendor/trezor-storage/flash_area.c',
]
-if TREZOR_MODEL in ('1', 'T', 'R', 'DISC1'):
- SOURCE_MOD += [
- 'vendor/trezor-storage/flash_common_f4.c',
- ]
-
if TREZOR_MODEL in ('1', ):
SOURCE_MOD += [
'embed/models/model_T1B1_layout.c',
@@ -129,6 +125,7 @@ SOURCE_TREZORHAL = [
'embed/trezorhal/unix/display-unix.c',
'embed/trezorhal/unix/fault_handlers.c',
'embed/trezorhal/unix/flash.c',
+ 'embed/trezorhal/unix/flash_otp.c',
'embed/trezorhal/unix/common.c',
'embed/trezorhal/unix/touch/touch.c',
'embed/trezorhal/unix/rng.c',
diff --git a/core/SConscript.firmware b/core/SConscript.firmware
index ed971858258..579c48d8e64 100644
--- a/core/SConscript.firmware
+++ b/core/SConscript.firmware
@@ -57,6 +57,7 @@ SOURCE_MOD += [
'embed/extmod/modtrezorconfig/modtrezorconfig.c',
'vendor/trezor-storage/norcow.c',
'vendor/trezor-storage/storage.c',
+ 'vendor/trezor-storage/flash_area.c',
]
# modtrezorcrypto
diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest
index 901c1e56ed8..b3260e9cbbc 100644
--- a/core/SConscript.prodtest
+++ b/core/SConscript.prodtest
@@ -69,6 +69,7 @@ SOURCE_MOD += [
'vendor/trezor-crypto/secp256k1.c',
'vendor/trezor-crypto/sha2.c',
'vendor/trezor-crypto/tls_prf.c',
+ 'vendor/trezor-storage/flash_area.c',
]
# modtrezorui
diff --git a/core/SConscript.reflash b/core/SConscript.reflash
index dab756070e6..d5a286731f6 100644
--- a/core/SConscript.reflash
+++ b/core/SConscript.reflash
@@ -63,6 +63,7 @@ SOURCE_MOD += [
'vendor/micropython/lib/uzlib/adler32.c',
'vendor/micropython/lib/uzlib/crc32.c',
'vendor/micropython/lib/uzlib/tinflate.c',
+ 'vendor/trezor-storage/flash_area.c',
]
# fonts
diff --git a/core/SConscript.unix b/core/SConscript.unix
index cd995e38930..e394c4ab878 100644
--- a/core/SConscript.unix
+++ b/core/SConscript.unix
@@ -58,13 +58,9 @@ SOURCE_MOD += [
'embed/extmod/modtrezorconfig/modtrezorconfig.c',
'vendor/trezor-storage/norcow.c',
'vendor/trezor-storage/storage.c',
+ 'vendor/trezor-storage/flash_area.c',
]
-if TREZOR_MODEL in ('1', 'T', 'R', 'DISC1'):
- SOURCE_MOD += [
- 'vendor/trezor-storage/flash_common_f4.c',
- ]
-
# modtrezorcrypto
CCFLAGS_MOD += '-Wno-sequence-point '
CPPPATH_MOD += [
@@ -376,6 +372,7 @@ SOURCE_UNIX = [
'embed/trezorhal/unix/common.c',
'embed/trezorhal/unix/display-unix.c',
'embed/trezorhal/unix/flash.c',
+ 'embed/trezorhal/unix/flash_otp.c',
'embed/trezorhal/unix/random_delays.c',
'embed/trezorhal/unix/rng.c',
'embed/trezorhal/unix/usb.c',
diff --git a/core/embed/bootloader/emulator.c b/core/embed/bootloader/emulator.c
index 6b089ee39ae..f050fde6417 100644
--- a/core/embed/bootloader/emulator.c
+++ b/core/embed/bootloader/emulator.c
@@ -7,6 +7,7 @@
#include "common.h"
#include "display.h"
#include "flash.h"
+#include "flash_otp.h"
#include "model.h"
#include "rust_ui.h"
#ifdef USE_OPTIGA
@@ -111,6 +112,8 @@ __attribute__((noreturn)) void display_error_and_die(const char *message,
__attribute__((noreturn)) int main(int argc, char **argv) {
flash_init();
+ flash_otp_init();
+
FIRMWARE_START = (uint8_t *)flash_area_get_address(&FIRMWARE_AREA, 0, 0);
// simulate non-empty storage so that we know whether it was erased or not
diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c
index f147b7ce7c8..a1963700d82 100644
--- a/core/embed/bootloader/main.c
+++ b/core/embed/bootloader/main.c
@@ -25,6 +25,7 @@
#include "display.h"
#include "fault_handlers.h"
#include "flash.h"
+#include "flash_otp.h"
#include "image.h"
#include "lowlevel.h"
#include "messages.pb.h"
diff --git a/core/embed/bootloader_ci/main.c b/core/embed/bootloader_ci/main.c
index 8285a99af7d..6ad597d6bbc 100644
--- a/core/embed/bootloader_ci/main.c
+++ b/core/embed/bootloader_ci/main.c
@@ -23,6 +23,7 @@
#include "common.h"
#include "display.h"
#include "flash.h"
+#include "flash_otp.h"
#include "image.h"
#include "mini_printf.h"
#include "mpu.h"
diff --git a/core/embed/extmod/modtrezorio/modtrezorio-flash.h b/core/embed/extmod/modtrezorio/modtrezorio-flash.h
index 2c2c955d9ea..3815f1e7124 100644
--- a/core/embed/extmod/modtrezorio/modtrezorio-flash.h
+++ b/core/embed/extmod/modtrezorio/modtrezorio-flash.h
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-#include "flash.h"
+#include "flash_otp.h"
#include "embed/extmod/trezorobj.h"
diff --git a/core/embed/lib/unit_variant.c b/core/embed/lib/unit_variant.c
index 8e1b51a04d6..4cc3b567a8e 100644
--- a/core/embed/lib/unit_variant.c
+++ b/core/embed/lib/unit_variant.c
@@ -1,5 +1,5 @@
#include "unit_variant.h"
-#include "flash.h"
+#include "flash_otp.h"
#include "model.h"
static uint8_t unit_variant_color = 0;
diff --git a/core/embed/models/layout_common.h b/core/embed/models/layout_common.h
index bf887529ff7..c581b1bb509 100644
--- a/core/embed/models/layout_common.h
+++ b/core/embed/models/layout_common.h
@@ -1,7 +1,7 @@
#ifndef LAYOUT_COMMON_H
#define LAYOUT_COMMON_H
-#include "flash.h"
+#include "flash_area.h"
// OTP blocks allocation
#define FLASH_OTP_BLOCK_BATCH 0
diff --git a/core/embed/models/model_D002_layout.c b/core/embed/models/model_D002_layout.c
index eae23b69993..283e1f3f0fc 100644
--- a/core/embed/models/model_D002_layout.c
+++ b/core/embed/models/model_D002_layout.c
@@ -4,7 +4,6 @@
const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT] = {
{
.num_subareas = 1,
- .secure_area = true,
.subarea[0] =
{
.first_sector = 0x18,
@@ -13,7 +12,6 @@ const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT] = {
},
{
.num_subareas = 1,
- .secure_area = true,
.subarea[0] =
{
.first_sector = 0x20,
@@ -24,7 +22,6 @@ const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT] = {
const flash_area_t BOARDLOADER_AREA = {
.num_subareas = 1,
- .secure_area = true,
.subarea[0] =
{
.first_sector = 1,
@@ -34,7 +31,6 @@ const flash_area_t BOARDLOADER_AREA = {
const flash_area_t BOOTLOADER_AREA = {
.num_subareas = 1,
- .secure_area = true,
.subarea[0] =
{
.first_sector = 0x08,
@@ -44,7 +40,6 @@ const flash_area_t BOOTLOADER_AREA = {
const flash_area_t FIRMWARE_AREA = {
.num_subareas = 1,
- .secure_area = true,
.subarea[0] =
{
.first_sector = 0x28,
@@ -54,7 +49,6 @@ const flash_area_t FIRMWARE_AREA = {
const flash_area_t SECRET_AREA = {
.num_subareas = 1,
- .secure_area = true,
.subarea[0] =
{
.first_sector = 0,
@@ -64,7 +58,6 @@ const flash_area_t SECRET_AREA = {
const flash_area_t BHK_AREA = {
.num_subareas = 1,
- .secure_area = true,
.subarea[0] =
{
.first_sector = 1,
@@ -74,7 +67,6 @@ const flash_area_t BHK_AREA = {
const flash_area_t WIPE_AREA = {
.num_subareas = 1,
- .secure_area = true,
.subarea[0] =
{
.first_sector = 0x18,
@@ -84,7 +76,6 @@ const flash_area_t WIPE_AREA = {
const flash_area_t ALL_WIPE_AREA = {
.num_subareas = 1,
- .secure_area = true,
.subarea[0] =
{
.first_sector = 0x08,
diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c
index 2698249afe1..3728272e370 100644
--- a/core/embed/prodtest/main.c
+++ b/core/embed/prodtest/main.c
@@ -28,6 +28,7 @@
#include "display.h"
#include "fault_handlers.h"
#include "flash.h"
+#include "flash_otp.h"
#include "i2c.h"
#include "model.h"
#include "mpu.h"
diff --git a/core/embed/trezorhal/flash.h b/core/embed/trezorhal/flash.h
index 11b50f8c09f..2918b11ee55 100644
--- a/core/embed/trezorhal/flash.h
+++ b/core/embed/trezorhal/flash.h
@@ -22,50 +22,12 @@
#include
#include
+
#include "platform.h"
#include "secbool.h"
-#define FLASH_OTP_NUM_BLOCKS 16
-#define FLASH_OTP_BLOCK_SIZE 32
-
-/**
- * Flash driver interface is designed to abstract away differences between
- * various MCUs used in Trezor devices.
- *
- * Generally, flash memory is divided into sectors. On different MCUs, sectors
- * may have different sizes, and therefore, different number of sectors are used
- * for a given purpose. For example, on STM32F4, the sectors are relatively
- * large so we use single sector for Storage. On STM32U5, the sectors are
- * smaller, so we use multiple sectors for the Storage. Storage implementation
- * should not care about this, and should use flash_area_t interface to access
- * the flash memory.
- *
- * flash_area_t represents a location in flash memory. It may be contiguous, or
- * it may be composed of multiple non-contiguous subareas.
- *
- * flash_subarea_t represents a contiguous area in flash memory, specified by
- * first_sector and num_sectors.
- */
-
-#include "flash_common.h"
+#include "flash_ll.h"
void flash_init(void);
-uint32_t flash_wait_and_clear_status_flags(void);
-
-// Erases the single sector in the designated flash area
-// The 'offset' parameter must indicate the relative sector offset within the
-// flash area If 'offset' is outside the bounds of the flash area,
-// 'bytes_erased' is set to 0 otherwise, 'bytes_erased' is set to the size of
-// the erased sector
-secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset,
- uint32_t *bytes_erased);
-
-secbool __wur flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
- uint8_t datalen);
-secbool __wur flash_otp_write(uint8_t block, uint8_t offset,
- const uint8_t *data, uint8_t datalen);
-secbool __wur flash_otp_lock(uint8_t block);
-secbool __wur flash_otp_is_locked(uint8_t block);
-
#endif // TREZORHAL_FLASH_H
diff --git a/core/embed/trezorhal/flash_otp.h b/core/embed/trezorhal/flash_otp.h
new file mode 100644
index 00000000000..c3f8705ab4a
--- /dev/null
+++ b/core/embed/trezorhal/flash_otp.h
@@ -0,0 +1,18 @@
+#ifndef TREZORHAL_FLASH_OTP_H
+#define TREZORHAL_FLASH_OTP_H
+
+#include
+
+#define FLASH_OTP_NUM_BLOCKS 16
+#define FLASH_OTP_BLOCK_SIZE 32
+
+void flash_otp_init(void);
+
+secbool __wur flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
+ uint8_t datalen);
+secbool __wur flash_otp_write(uint8_t block, uint8_t offset,
+ const uint8_t *data, uint8_t datalen);
+secbool __wur flash_otp_lock(uint8_t block);
+secbool __wur flash_otp_is_locked(uint8_t block);
+
+#endif // TREZORHAL_FLASH_OTP_H
diff --git a/core/embed/trezorhal/stm32f4/common.c b/core/embed/trezorhal/stm32f4/common.c
index 427f10b0be7..d4c5866fac6 100644
--- a/core/embed/trezorhal/stm32f4/common.c
+++ b/core/embed/trezorhal/stm32f4/common.c
@@ -28,7 +28,7 @@
#ifdef FANCY_FATAL_ERROR
#include "rust_ui.h"
#endif
-#include "flash.h"
+#include "flash_otp.h"
#include "platform.h"
#include "rand.h"
#include "supervise.h"
diff --git a/core/embed/trezorhal/stm32f4/flash.c b/core/embed/trezorhal/stm32f4/flash.c
index a577c1d774f..0df6eca037d 100644
--- a/core/embed/trezorhal/stm32f4/flash.c
+++ b/core/embed/trezorhal/stm32f4/flash.c
@@ -78,26 +78,6 @@ static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = {
#endif
};
-uint32_t flash_wait_and_clear_status_flags(void) {
- while (FLASH->SR & FLASH_SR_BSY)
- ; // wait for all previous flash operations to complete
- const uint32_t result =
- FLASH->SR & FLASH_STATUS_ALL_FLAGS; // get the current status flags
- FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
- return result;
-}
-
-secbool flash_unlock_write(void) {
- HAL_FLASH_Unlock();
- FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
- return sectrue;
-}
-
-secbool flash_lock_write(void) {
- HAL_FLASH_Lock();
- return sectrue;
-}
-
const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) {
if (sector >= FLASH_SECTOR_COUNT) {
return NULL;
@@ -110,105 +90,71 @@ const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) {
return (const void *)addr;
}
-uint32_t flash_sector_size(uint16_t sector) {
- if (sector >= FLASH_SECTOR_COUNT) {
+uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) {
+ if (first_sector + sector_count > FLASH_SECTOR_COUNT) {
return 0;
}
- return FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
+ return FLASH_SECTOR_TABLE[first_sector + sector_count] -
+ FLASH_SECTOR_TABLE[first_sector];
}
-secbool flash_area_erase_bulk(const flash_area_t *area, int count,
- void (*progress)(int pos, int len)) {
- ensure(flash_unlock_write(), NULL);
- FLASH_EraseInitTypeDef EraseInitStruct = {0};
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
- EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
- EraseInitStruct.NbSectors = 1;
+uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) {
+ uint16_t sector = first_sector;
- int total_sectors = 0;
- int done_sectors = 0;
- for (int a = 0; a < count; a++) {
- for (int i = 0; i < area[a].num_subareas; i++) {
- total_sectors += area[a].subarea[i].num_sectors;
+ while (sector < FLASH_SECTOR_COUNT) {
+ uint32_t sector_size =
+ FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
+
+ if (offset < sector_size) {
+ break;
}
- }
- if (progress) {
- progress(0, total_sectors);
+ offset -= sector_size;
+ sector++;
}
- for (int a = 0; a < count; a++) {
- for (int s = 0; s < area[a].num_subareas; s++) {
- for (int i = 0; i < area[a].subarea[s].num_sectors; i++) {
- int sector = area[a].subarea[s].first_sector + i;
+ return sector;
+}
- EraseInitStruct.Sector = sector;
- uint32_t SectorError;
- if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
- ensure(flash_lock_write(), NULL);
- return secfalse;
- }
- // check whether the sector was really deleted (contains only 0xFF)
- const uint32_t addr_start = FLASH_SECTOR_TABLE[sector],
- addr_end = FLASH_SECTOR_TABLE[sector + 1];
- for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
- if (*((const uint32_t *)addr) != 0xFFFFFFFF) {
- ensure(flash_lock_write(), NULL);
- return secfalse;
- }
- }
- done_sectors++;
- if (progress) {
- progress(done_sectors, total_sectors);
- }
- }
- }
- }
- ensure(flash_lock_write(), NULL);
+secbool flash_unlock_write(void) {
+ HAL_FLASH_Unlock();
+ FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
return sectrue;
}
-secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset,
- uint32_t *bytes_erased) {
- uint32_t sector_offset = 0;
- *bytes_erased = 0;
-
- for (int s = 0; s < area->num_subareas; s++) {
- for (int i = 0; i < area->subarea[s].num_sectors; i++) {
- uint32_t sector_index = area->subarea[s].first_sector + i;
- uint32_t sector_size = FLASH_SECTOR_TABLE[sector_index + 1] -
- FLASH_SECTOR_TABLE[sector_index];
-
- if (offset == sector_offset) {
- ensure(flash_unlock_write(), NULL);
+secbool flash_lock_write(void) {
+ HAL_FLASH_Lock();
+ return sectrue;
+}
- FLASH_EraseInitTypeDef erase_init = {
- .TypeErase = FLASH_TYPEERASE_SECTORS,
- .VoltageRange = FLASH_VOLTAGE_RANGE_3,
- .Sector = sector_index,
- .NbSectors = 1};
+secbool flash_sector_erase(uint16_t sector) {
+ if (sector >= FLASH_SECTOR_COUNT) {
+ return secfalse;
+ }
- uint32_t sector_error;
+ FLASH_EraseInitTypeDef EraseInitStruct = {
+ .TypeErase = FLASH_TYPEERASE_SECTORS,
+ .VoltageRange = FLASH_VOLTAGE_RANGE_3,
+ .Sector = sector,
+ .NbSectors = 1,
+ };
- if (HAL_FLASHEx_Erase(&erase_init, §or_error) != HAL_OK) {
- ensure(flash_lock_write(), NULL);
- return secfalse;
- }
+ uint32_t sector_error;
- ensure(flash_lock_write(), NULL);
+ if (HAL_FLASHEx_Erase(&EraseInitStruct, §or_error) != HAL_OK) {
+ return secfalse;
+ }
- *bytes_erased = sector_size;
- return sectrue;
- }
+ // check whether the sector was really deleted (contains only 0xFF)
+ uint32_t addr_start = FLASH_SECTOR_TABLE[sector];
+ uint32_t addr_end = FLASH_SECTOR_TABLE[sector + 1];
- sector_offset += sector_size;
+ for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
+ if (*((const uint32_t *)addr) != 0xFFFFFFFF) {
+ return secfalse;
}
}
- if (offset == sector_offset) {
- return sectrue;
- }
-
- return secfalse;
+ return sectrue;
}
secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data) {
@@ -247,51 +193,3 @@ secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data) {
}
return sectrue;
}
-
-#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U
-
-secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
- uint8_t datalen) {
- if (block >= FLASH_OTP_NUM_BLOCKS ||
- offset + datalen > FLASH_OTP_BLOCK_SIZE) {
- return secfalse;
- }
- for (uint8_t i = 0; i < datalen; i++) {
- data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE +
- offset + i);
- }
- return sectrue;
-}
-
-secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
- uint8_t datalen) {
- if (block >= FLASH_OTP_NUM_BLOCKS ||
- offset + datalen > FLASH_OTP_BLOCK_SIZE) {
- return secfalse;
- }
- ensure(flash_unlock_write(), NULL);
- for (uint8_t i = 0; i < datalen; i++) {
- uint32_t address =
- FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i;
- ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
- address, data[i])),
- NULL);
- }
- ensure(flash_lock_write(), NULL);
- return sectrue;
-}
-
-secbool flash_otp_lock(uint8_t block) {
- if (block >= FLASH_OTP_NUM_BLOCKS) {
- return secfalse;
- }
- ensure(flash_unlock_write(), NULL);
- HAL_StatusTypeDef ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
- FLASH_OTP_LOCK_BASE + block, 0x00);
- ensure(flash_lock_write(), NULL);
- return sectrue * (ret == HAL_OK);
-}
-
-secbool flash_otp_is_locked(uint8_t block) {
- return sectrue * (0x00 == *(__IO uint8_t *)(FLASH_OTP_LOCK_BASE + block));
-}
diff --git a/core/embed/trezorhal/stm32f4/flash_otp.c b/core/embed/trezorhal/stm32f4/flash_otp.c
new file mode 100644
index 00000000000..28fbb34ffbf
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/flash_otp.c
@@ -0,0 +1,76 @@
+/*
+ * 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 STM32_HAL_H
+
+#include "flash_otp.h"
+#include "common.h"
+#include "flash.h"
+
+#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U
+
+void flash_otp_init() {
+ // intentionally left empty
+}
+
+secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
+ uint8_t datalen) {
+ if (block >= FLASH_OTP_NUM_BLOCKS ||
+ offset + datalen > FLASH_OTP_BLOCK_SIZE) {
+ return secfalse;
+ }
+ for (uint8_t i = 0; i < datalen; i++) {
+ data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE +
+ offset + i);
+ }
+ return sectrue;
+}
+
+secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
+ uint8_t datalen) {
+ if (block >= FLASH_OTP_NUM_BLOCKS ||
+ offset + datalen > FLASH_OTP_BLOCK_SIZE) {
+ return secfalse;
+ }
+ ensure(flash_unlock_write(), NULL);
+ for (uint8_t i = 0; i < datalen; i++) {
+ uint32_t address =
+ FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i;
+ ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
+ address, data[i])),
+ NULL);
+ }
+ ensure(flash_lock_write(), NULL);
+ return sectrue;
+}
+
+secbool flash_otp_lock(uint8_t block) {
+ if (block >= FLASH_OTP_NUM_BLOCKS) {
+ return secfalse;
+ }
+ ensure(flash_unlock_write(), NULL);
+ HAL_StatusTypeDef ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
+ FLASH_OTP_LOCK_BASE + block, 0x00);
+ ensure(flash_lock_write(), NULL);
+ return sectrue * (ret == HAL_OK);
+}
+
+secbool flash_otp_is_locked(uint8_t block) {
+ return sectrue * (0x00 == *(__IO uint8_t *)(FLASH_OTP_LOCK_BASE + block));
+}
diff --git a/core/embed/trezorhal/stm32f4/lowlevel.c b/core/embed/trezorhal/stm32f4/lowlevel.c
index 6170e69fbaf..31879238a0b 100644
--- a/core/embed/trezorhal/stm32f4/lowlevel.c
+++ b/core/embed/trezorhal/stm32f4/lowlevel.c
@@ -20,7 +20,7 @@
#include STM32_HAL_H
#include "lowlevel.h"
-#include "flash.h"
+#include "flash_otp.h"
#pragma GCC optimize( \
"no-stack-protector") // applies to all functions in this file
@@ -57,6 +57,19 @@
#define OPTION_BYTES_BANK1_WRP (*(volatile uint16_t* const)0x1FFFC008U)
#define OPTION_BYTES_BANK2_WRP (*(volatile uint16_t* const)0x1FFEC008U)
+#define FLASH_STATUS_ALL_FLAGS \
+ (FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | \
+ FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP)
+
+static uint32_t flash_wait_and_clear_status_flags(void) {
+ while (FLASH->SR & FLASH_SR_BSY)
+ ; // wait for all previous flash operations to complete
+ const uint32_t result =
+ FLASH->SR & FLASH_STATUS_ALL_FLAGS; // get the current status flags
+ FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
+ return result;
+}
+
secbool flash_check_option_bytes(void) {
flash_wait_and_clear_status_flags();
// check values stored in flash interface registers
diff --git a/core/embed/trezorhal/stm32u5/common.c b/core/embed/trezorhal/stm32u5/common.c
index c0cda4ce259..00da12043e6 100644
--- a/core/embed/trezorhal/stm32u5/common.c
+++ b/core/embed/trezorhal/stm32u5/common.c
@@ -27,7 +27,7 @@
#ifdef FANCY_FATAL_ERROR
#include "rust_ui.h"
#endif
-#include "flash.h"
+#include "flash_otp.h"
#include "model.h"
#include "platform.h"
#include "rand.h"
diff --git a/core/embed/trezorhal/stm32u5/flash.c b/core/embed/trezorhal/stm32u5/flash.c
index bce7e4511c6..a20cc579ade 100644
--- a/core/embed/trezorhal/stm32u5/flash.c
+++ b/core/embed/trezorhal/stm32u5/flash.c
@@ -19,6 +19,7 @@
#include STM32_HAL_H
+#include
#include
#include "common.h"
@@ -33,329 +34,100 @@
#define FLASH_STATUS_ALL_FLAGS \
(FLASH_NSSR_PGSERR | FLASH_NSSR_PGAERR | FLASH_NSSR_WRPERR | FLASH_NSSR_EOP)
-uint32_t flash_wait_and_clear_status_flags(void) {
- while (FLASH->NSSR & FLASH_NSSR_BSY)
- ; // wait for all previous flash operations to complete
-
- uint32_t result =
- FLASH->NSSR & FLASH_STATUS_ALL_FLAGS; // get the current status flags
- FLASH->NSSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
-
-#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
- while (FLASH->SECSR & FLASH_SECSR_BSY)
- ; // wait for all previous flash operations to complete
- result |=
- FLASH->SECSR & FLASH_STATUS_ALL_FLAGS; // get the current status flags
- FLASH->SECSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
-#endif
- return result;
-}
-
-secbool flash_unlock_write(void) {
- HAL_FLASH_Unlock();
- FLASH->NSSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
-#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
- FLASH->SECSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
-#endif
- return sectrue;
+static bool flash_sector_is_secure(uint32_t sector) {
+ // We always return true since the entire flash memory is currently secure -
+ // partially through option bytes and partially through FLASH controller
+ // settings
+ return true;
}
-secbool flash_lock_write(void) {
- HAL_FLASH_Lock();
- return sectrue;
-}
-
-const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size,
- bool secure_area) {
+const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) {
if (sector >= FLASH_SECTOR_COUNT) {
return NULL;
}
- uint32_t base_addr = FLASH_START_ADDRESS;
- if (secure_area) {
- base_addr = FLASH_SEC_START_ADDRESS;
- }
-
- const uint32_t addr = base_addr + (FLASH_PAGE_SIZE * sector) + offset;
- const uint32_t next = base_addr + (FLASH_PAGE_SIZE * (sector + 1));
- if (addr + size > next) {
+ if (offset + size > FLASH_PAGE_SIZE) {
return NULL;
}
- return (const void *)addr;
-}
-uint32_t flash_sector_size(uint16_t sector) {
- if (sector >= FLASH_SECTOR_COUNT) {
- return 0;
- }
- return FLASH_PAGE_SIZE;
-}
+ uint32_t base_addr = flash_sector_is_secure(sector) ? FLASH_SEC_START_ADDRESS
+ : FLASH_START_ADDRESS;
-uint32_t flash_subarea_get_size(const flash_subarea_t *sub) {
- return FLASH_PAGE_SIZE * sub->num_sectors;
+ return (const void *)(base_addr + FLASH_PAGE_SIZE * sector + offset);
}
-uint32_t flash_area_get_size(const flash_area_t *area) {
- uint32_t size = 0;
- for (int i = 0; i < area->num_subareas; i++) {
- size += flash_subarea_get_size(&area->subarea[i]);
+uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) {
+ if (first_sector + sector_count > FLASH_SECTOR_COUNT) {
+ return 0;
}
- return size;
+ return FLASH_PAGE_SIZE * sector_count;
}
-uint16_t flash_total_sectors(const flash_area_t *area) {
- uint16_t total = 0;
- for (int i = 0; i < area->num_subareas; i++) {
- total += area->subarea[i].num_sectors;
- }
- return total;
+uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) {
+ return first_sector + offset / FLASH_PAGE_SIZE;
}
-const void *flash_area_get_address(const flash_area_t *area, uint32_t offset,
- uint32_t size) {
- uint32_t tmp_offset = offset;
-
- for (int i = 0; i < area->num_subareas; i++) {
- uint16_t sector = area->subarea[i].first_sector;
-
- if (tmp_offset >= flash_subarea_get_size(area->subarea)) {
- tmp_offset -= flash_subarea_get_size(area->subarea);
- continue;
- }
-
- uint32_t base_addr = FLASH_START_ADDRESS;
-
- if (area->secure_area) {
- base_addr = FLASH_SEC_START_ADDRESS;
- }
-
- const uint32_t addr = base_addr + (FLASH_PAGE_SIZE * sector) + tmp_offset;
- const uint32_t area_end =
- base_addr + (FLASH_PAGE_SIZE * (area->subarea[i].first_sector +
- area->subarea[i].num_sectors));
- if (addr + size > area_end) {
- return NULL;
- }
- return (const void *)addr;
- }
- return NULL;
+secbool flash_unlock_write(void) {
+ HAL_FLASH_Unlock();
+ FLASH->NSSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
+#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
+ FLASH->SECSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
+#endif
+ return sectrue;
}
-int32_t flash_get_sector_num(const flash_area_t *area,
- uint32_t sector_inner_num) {
- uint16_t sector = 0;
- uint16_t remaining = sector_inner_num;
- for (int i = 0; i < area->num_subareas; i++) {
- if (remaining < area->subarea[i].num_sectors) {
- sector = area->subarea[i].first_sector + remaining;
- return sector;
- } else {
- remaining -= area->subarea[i].num_sectors;
- }
- }
-
- return -1;
+secbool flash_lock_write(void) {
+ HAL_FLASH_Lock();
+ return sectrue;
}
-secbool flash_area_erase(const flash_area_t *area,
- void (*progress)(int pos, int len)) {
- ensure(flash_unlock_write(), NULL);
- FLASH_EraseInitTypeDef EraseInitStruct;
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
- EraseInitStruct.NbPages = 1;
-
- int total_pages = 0;
- int done_pages = 0;
- for (int i = 0; i < area->num_subareas; i++) {
- total_pages += area->subarea[i].num_sectors;
+secbool flash_sector_erase(uint16_t sector) {
+ if (sector >= FLASH_SECTOR_COUNT) {
+ return secfalse;
}
- if (progress) {
- progress(0, total_pages);
- }
+ FLASH_EraseInitTypeDef EraseInitStruct = {
+ .TypeErase = FLASH_TYPEERASE_PAGES_NS,
+ .Banks = FLASH_BANK_1,
+ .Page = sector,
+ .NbPages = 1,
+ };
- for (int s = 0; s < area->num_subareas; s++) {
- for (int i = 0; i < area->subarea[s].num_sectors; i++) {
- int page = area->subarea[s].first_sector + i;
- uint32_t sec_start = 0;
- uint32_t sec_end = 0;
- uint32_t page_idx = 0;
- bool secure = area->secure_area;
- if (page >= 256) {
- EraseInitStruct.Banks = FLASH_BANK_2;
- page_idx = page - 256;
- sec_start = (FLASH->SECWM2R1 & FLASH_SECWM1R1_SECWM1_PSTRT) >>
- FLASH_SECWM1R1_SECWM1_PSTRT_Pos;
- sec_end = (FLASH->SECWM2R1 & FLASH_SECWM1R1_SECWM1_PEND) >>
- FLASH_SECWM1R1_SECWM1_PEND_Pos;
- } else {
- EraseInitStruct.Banks = FLASH_BANK_1;
- page_idx = page;
- sec_start = (FLASH->SECWM1R1 & FLASH_SECWM1R1_SECWM1_PSTRT) >>
- FLASH_SECWM1R1_SECWM1_PSTRT_Pos;
- sec_end = (FLASH->SECWM1R1 & FLASH_SECWM1R1_SECWM1_PEND) >>
- FLASH_SECWM1R1_SECWM1_PEND_Pos;
- }
-
- if (page_idx < sec_start || page_idx > sec_end) {
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES_NS;
- secure = false;
- } else {
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
- }
-
- EraseInitStruct.Page = page_idx;
- uint32_t SectorError;
- if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
- ensure(flash_lock_write(), NULL);
- return secfalse;
- }
- // check whether the sector was really deleted (contains only 0xFF)
- const uint32_t addr_start =
- (uint32_t)flash_get_address(page, 0, 0, secure);
- const uint32_t addr_end =
- (uint32_t)flash_get_address(page + 1, 0, 0, secure);
-
- for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
- if (*((const uint32_t *)addr) != 0xFFFFFFFF) {
- ensure(flash_lock_write(), NULL);
- return secfalse;
- }
- }
- done_pages++;
- if (progress && done_pages % 16 == 0) {
- progress(done_pages, total_pages);
- }
- }
+ if (sector >= 256) {
+ EraseInitStruct.Banks = FLASH_BANK_2;
+ EraseInitStruct.Page = sector - 256;
}
- ensure(flash_lock_write(), NULL);
- return sectrue;
-}
-secbool flash_area_erase_bulk(const flash_area_t *areas, int count,
- void (*progress)(int pos, int len)) {
- ensure(flash_unlock_write(), NULL);
- FLASH_EraseInitTypeDef EraseInitStruct;
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
- EraseInitStruct.NbPages = 1;
-
- int total_pages = 0;
- int done_pages = 0;
- for (int c = 0; c < count; c++) {
- for (int i = 0; i < areas[c].num_subareas; i++) {
- total_pages += areas[c].subarea[i].num_sectors;
- }
+ if (flash_sector_is_secure(sector)) {
+ EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
}
- if (progress) {
- progress(0, total_pages);
- }
+ uint32_t sector_error = 0;
- for (int c = 0; c < count; c++) {
- for (int s = 0; s < areas[c].num_subareas; s++) {
- for (int i = 0; i < areas[c].subarea[s].num_sectors; i++) {
- int page = areas[c].subarea[s].first_sector + i;
- if (page >= 256) {
- EraseInitStruct.Banks = FLASH_BANK_2;
- } else {
- EraseInitStruct.Banks = FLASH_BANK_1;
- }
- EraseInitStruct.Page = page;
- uint32_t SectorError;
- if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
- ensure(flash_lock_write(), NULL);
- return secfalse;
- }
- // check whether the sector was really deleted (contains only 0xFF)
- const uint32_t addr_start =
- (uint32_t)flash_get_address(page, 0, 0, areas[c].secure_area);
- const uint32_t addr_end =
- (uint32_t)flash_get_address(page + 1, 0, 0, areas[c].secure_area);
-
- for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
- if (*((const uint32_t *)addr) != 0xFFFFFFFF) {
- ensure(flash_lock_write(), NULL);
- return secfalse;
- }
- }
- done_pages++;
- if (progress) {
- progress(done_pages, total_pages);
- }
- }
- }
+ if (HAL_FLASHEx_Erase(&EraseInitStruct, §or_error) != HAL_OK) {
+ return secfalse;
}
- ensure(flash_lock_write(), NULL);
- return sectrue;
-}
-secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset,
- uint32_t *bytes_erased) {
- ensure(flash_unlock_write(), NULL);
- FLASH_EraseInitTypeDef EraseInitStruct;
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
- EraseInitStruct.NbPages = 1;
-
- *bytes_erased = 0;
- int32_t page = flash_get_sector_num(area, offset / FLASH_PAGE_SIZE);
-
- if (page >= 0 && page < FLASH_SECTOR_COUNT) {
- uint32_t sec_start = 0;
- uint32_t sec_end = 0;
- uint32_t page_idx = 0;
- bool secure = area->secure_area;
- if (page >= 256) {
- EraseInitStruct.Banks = FLASH_BANK_2;
- page_idx = page - 256;
- sec_start = (FLASH->SECWM2R1 & FLASH_SECWM1R1_SECWM1_PSTRT) >>
- FLASH_SECWM1R1_SECWM1_PSTRT_Pos;
- sec_end = (FLASH->SECWM2R1 & FLASH_SECWM1R1_SECWM1_PEND) >>
- FLASH_SECWM1R1_SECWM1_PEND_Pos;
- } else {
- EraseInitStruct.Banks = FLASH_BANK_1;
- page_idx = page;
- sec_start = (FLASH->SECWM1R1 & FLASH_SECWM1R1_SECWM1_PSTRT) >>
- FLASH_SECWM1R1_SECWM1_PSTRT_Pos;
- sec_end = (FLASH->SECWM1R1 & FLASH_SECWM1R1_SECWM1_PEND) >>
- FLASH_SECWM1R1_SECWM1_PEND_Pos;
- }
+ // check whether the sector was really deleted (contains only 0xFF)
+ const uint32_t *sector_start =
+ (const uint32_t *)flash_get_address(sector, 0, 0);
- if (page_idx < sec_start || page_idx > sec_end) {
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES_NS;
- secure = false;
- } else {
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
- }
+ const uint32_t *sector_end =
+ sector_start + flash_sector_size(sector, 1) / sizeof(uint32_t);
- EraseInitStruct.Page = page_idx;
- uint32_t SectorError;
- if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
- ensure(flash_lock_write(), NULL);
+ for (const uint32_t *addr = sector_start; addr < sector_end; addr++) {
+ if (*addr != 0xFFFFFFFF) {
return secfalse;
}
- // check whether the sector was really deleted (contains only 0xFF)
- const uint32_t addr_start = (uint32_t)flash_get_address(page, 0, 0, secure);
- const uint32_t addr_end =
- (uint32_t)flash_get_address(page + 1, 0, 0, secure);
-
- for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
- if (*((const uint32_t *)addr) != 0xFFFFFFFF) {
- ensure(flash_lock_write(), NULL);
- return secfalse;
- }
- }
- ensure(flash_lock_write(), NULL);
- *bytes_erased = FLASH_PAGE_SIZE;
- return sectrue;
}
- ensure(flash_lock_write(), NULL);
+
return sectrue;
}
secbool flash_write_quadword(uint16_t sector, uint32_t offset,
- const uint32_t *data, bool secure_area) {
- uint32_t address = (uint32_t)flash_get_address(
- sector, offset, 4 * sizeof(uint32_t), secure_area);
+ const uint32_t *data) {
+ uint32_t address =
+ (uint32_t)flash_get_address(sector, offset, 4 * sizeof(uint32_t));
if (address == 0) {
return secfalse;
}
@@ -394,9 +166,9 @@ secbool flash_write_quadword(uint16_t sector, uint32_t offset,
}
secbool flash_write_burst(uint16_t sector, uint32_t offset,
- const uint32_t *data, bool secure_area) {
- uint32_t address = (uint32_t)flash_get_address(
- sector, offset, 8 * 4 * sizeof(uint32_t), secure_area);
+ const uint32_t *data) {
+ uint32_t address =
+ (uint32_t)flash_get_address(sector, offset, 8 * 4 * sizeof(uint32_t));
if (address == 0) {
return secfalse;
}
@@ -434,129 +206,3 @@ secbool flash_write_burst(uint16_t sector, uint32_t offset,
}
return sectrue;
}
-
-secbool flash_area_write_quadword(const flash_area_t *area, uint32_t offset,
- const uint32_t *data) {
- uint32_t tmp_offset = offset;
- for (int i = 0; i < area->num_subareas; i++) {
- uint16_t sector = area->subarea[i].first_sector;
-
- uint32_t sub_size = flash_subarea_get_size(&area->subarea[i]);
- if (tmp_offset >= sub_size) {
- tmp_offset -= sub_size;
- continue;
- }
-
- // in correct subarea
- for (int s = 0; s < area->subarea[i].num_sectors; s++) {
- const uint32_t sector_size = flash_sector_size(sector);
- if (tmp_offset >= sector_size) {
- tmp_offset -= sector_size;
- sector++;
-
- if (s == area->subarea[i].num_sectors - 1) {
- return secfalse;
- }
- continue;
- }
- // in correct sector
- return flash_write_quadword(sector, tmp_offset, data, area->secure_area);
- }
- }
- return secfalse;
-}
-
-secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset,
- const uint32_t *data) {
- uint32_t tmp_offset = offset;
- for (int i = 0; i < area->num_subareas; i++) {
- uint16_t sector = area->subarea[i].first_sector;
-
- uint32_t sub_size = flash_subarea_get_size(&area->subarea[i]);
- if (tmp_offset >= sub_size) {
- tmp_offset -= sub_size;
- continue;
- }
-
- // in correct subarea
- for (int s = 0; s < area->subarea[i].num_sectors; s++) {
- const uint32_t sector_size = flash_sector_size(sector);
- if (tmp_offset >= sector_size) {
- tmp_offset -= sector_size;
- sector++;
-
- if (s == area->subarea[i].num_sectors - 1) {
- return secfalse;
- }
- continue;
- }
- // in correct sector
- return flash_write_burst(sector, tmp_offset, data, area->secure_area);
- }
- }
- return secfalse;
-}
-
-secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
- uint8_t datalen) {
- if (block >= FLASH_OTP_NUM_BLOCKS ||
- offset + datalen > FLASH_OTP_BLOCK_SIZE) {
- return secfalse;
- }
- for (uint8_t i = 0; i < datalen; i++) {
- data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE +
- offset + i);
- }
- return sectrue;
-}
-
-secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
- uint8_t datalen) {
- if (datalen % 16 != 0) {
- return secfalse;
- }
- if (block >= FLASH_OTP_NUM_BLOCKS ||
- offset + datalen > FLASH_OTP_BLOCK_SIZE) {
- return secfalse;
- }
- ensure(flash_unlock_write(), NULL);
- for (uint8_t i = 0; i < datalen; i++) {
- uint32_t address =
- FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i;
- ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD,
- address, (uint32_t)data)),
- NULL);
- }
- ensure(flash_lock_write(), NULL);
- return sectrue;
-}
-
-secbool flash_otp_lock(uint8_t block) {
- // check that all quadwords in the block have been written to
- volatile uint8_t *addr =
- (__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE);
-
- secbool qw_locked = secfalse;
- for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) {
- if (addr[i] != 0xFF) {
- qw_locked = sectrue;
- }
- if (i % 16 == 15 && qw_locked == secfalse) {
- return secfalse;
- }
- }
- return sectrue;
-}
-
-secbool flash_otp_is_locked(uint8_t block) {
- // considering block locked if any quadword in the block is non-0xFF
- volatile uint8_t *addr =
- (__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE);
-
- for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) {
- if (addr[i] != 0xFF) {
- return sectrue;
- }
- }
- return secfalse;
-}
diff --git a/core/embed/trezorhal/stm32u5/flash_otp.c b/core/embed/trezorhal/stm32u5/flash_otp.c
new file mode 100644
index 00000000000..d76044c9ccb
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/flash_otp.c
@@ -0,0 +1,92 @@
+/*
+ * 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 STM32_HAL_H
+
+#include "flash_otp.h"
+#include "common.h"
+#include "flash.h"
+
+void flash_otp_init() {
+ // intentionally left empty
+}
+
+secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
+ uint8_t datalen) {
+ if (block >= FLASH_OTP_NUM_BLOCKS ||
+ offset + datalen > FLASH_OTP_BLOCK_SIZE) {
+ return secfalse;
+ }
+ for (uint8_t i = 0; i < datalen; i++) {
+ data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE +
+ offset + i);
+ }
+ return sectrue;
+}
+
+secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
+ uint8_t datalen) {
+ if (datalen % 16 != 0) {
+ return secfalse;
+ }
+ if (block >= FLASH_OTP_NUM_BLOCKS ||
+ offset + datalen > FLASH_OTP_BLOCK_SIZE) {
+ return secfalse;
+ }
+ ensure(flash_unlock_write(), NULL);
+ for (uint8_t i = 0; i < datalen; i++) {
+ uint32_t address =
+ FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i;
+ ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD,
+ address, (uint32_t)data)),
+ NULL);
+ }
+ ensure(flash_lock_write(), NULL);
+ return sectrue;
+}
+
+secbool flash_otp_lock(uint8_t block) {
+ // check that all quadwords in the block have been written to
+ volatile uint8_t *addr =
+ (__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE);
+
+ secbool qw_locked = secfalse;
+ for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) {
+ if (addr[i] != 0xFF) {
+ qw_locked = sectrue;
+ }
+ if (i % 16 == 15 && qw_locked == secfalse) {
+ return secfalse;
+ }
+ }
+ return sectrue;
+}
+
+secbool flash_otp_is_locked(uint8_t block) {
+ // considering block locked if any quadword in the block is non-0xFF
+ volatile uint8_t *addr =
+ (__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE);
+
+ for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) {
+ if (addr[i] != 0xFF) {
+ return sectrue;
+ }
+ }
+ return secfalse;
+}
diff --git a/core/embed/trezorhal/stm32u5/lowlevel.c b/core/embed/trezorhal/stm32u5/lowlevel.c
index 8aa1e29b5db..f289368c19d 100644
--- a/core/embed/trezorhal/stm32u5/lowlevel.c
+++ b/core/embed/trezorhal/stm32u5/lowlevel.c
@@ -22,6 +22,7 @@
#include "lowlevel.h"
#include "common.h"
#include "flash.h"
+#include "flash_otp.h"
#include "model.h"
#include TREZOR_BOARD
@@ -84,6 +85,27 @@
SEC_AREA_2_PAGE_END << FLASH_SECWM1R1_SECWM1_PEND_Pos | 0xFF00FF00)
#define FLASH_SECWM2R2_VALUE (0x7F007F00)
+#define FLASH_STATUS_ALL_FLAGS \
+ (FLASH_NSSR_PGSERR | FLASH_NSSR_PGAERR | FLASH_NSSR_WRPERR | FLASH_NSSR_EOP)
+
+static uint32_t flash_wait_and_clear_status_flags(void) {
+ while (FLASH->NSSR & FLASH_NSSR_BSY)
+ ; // wait for all previous flash operations to complete
+
+ uint32_t result =
+ FLASH->NSSR & FLASH_STATUS_ALL_FLAGS; // get the current status flags
+ FLASH->NSSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
+
+#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
+ while (FLASH->SECSR & FLASH_SECSR_BSY)
+ ; // wait for all previous flash operations to complete
+ result |=
+ FLASH->SECSR & FLASH_STATUS_ALL_FLAGS; // get the current status flags
+ FLASH->SECSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
+#endif
+ return result;
+}
+
secbool flash_check_option_bytes(void) {
flash_wait_and_clear_status_flags();
// check values stored in flash interface registers
diff --git a/core/embed/trezorhal/stm32u5/secret.c b/core/embed/trezorhal/stm32u5/secret.c
index aac77080661..db18379646b 100644
--- a/core/embed/trezorhal/stm32u5/secret.c
+++ b/core/embed/trezorhal/stm32u5/secret.c
@@ -1,4 +1,5 @@
#include "secret.h"
+#include
#include
#include "common.h"
#include "flash.h"
diff --git a/core/embed/trezorhal/unix/flash.c b/core/embed/trezorhal/unix/flash.c
index 6d279b57bc2..35fbe6176d8 100644
--- a/core/embed/trezorhal/unix/flash.c
+++ b/core/embed/trezorhal/unix/flash.c
@@ -80,11 +80,6 @@ static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = {
static uint8_t *FLASH_BUFFER = NULL;
static uint32_t FLASH_SIZE;
-#define OTP_BLOCK_SIZE 32
-#define FLASH_SECTOR_OTP (FLASH_SECTOR_COUNT)
-
-static uint8_t OTP_BUFFER[OTP_BLOCK_SIZE * 64];
-
static void flash_exit(void) {
int r = munmap(FLASH_BUFFER, FLASH_SIZE);
ensure(sectrue * (r == 0), "munmap failed");
@@ -123,9 +118,6 @@ void flash_init(void) {
FLASH_BUFFER = (uint8_t *)map;
- // fill OTP buffer with ones
- memset(OTP_BUFFER, 0xFF, sizeof(OTP_BUFFER));
-
atexit(flash_exit);
}
@@ -145,79 +137,44 @@ const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) {
return FLASH_BUFFER + addr - FLASH_SECTOR_TABLE[0];
}
-uint32_t flash_sector_size(uint16_t sector) {
- if (sector >= FLASH_SECTOR_COUNT) {
+uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) {
+ if (first_sector + sector_count > FLASH_SECTOR_COUNT) {
return 0;
}
- return FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
+ return FLASH_SECTOR_TABLE[first_sector + sector_count] -
+ FLASH_SECTOR_TABLE[first_sector];
}
-secbool flash_area_erase_bulk(const flash_area_t *area, int count,
- void (*progress)(int pos, int len)) {
- ensure(flash_unlock_write(), NULL);
-
- int total_sectors = 0;
- int done_sectors = 0;
- for (int a = 0; a < count; a++) {
- for (int i = 0; i < area[a].num_subareas; i++) {
- total_sectors += area[a].subarea[i].num_sectors;
- }
- }
-
- if (progress) {
- progress(0, total_sectors);
- }
+uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) {
+ uint16_t sector = first_sector;
- for (int a = 0; a < count; a++) {
- for (int s = 0; s < area[a].num_subareas; s++) {
- for (int i = 0; i < area[a].subarea[s].num_sectors; i++) {
- int sector = area[a].subarea[s].first_sector + i;
+ while (sector < FLASH_SECTOR_COUNT) {
+ uint32_t sector_size =
+ FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
- const uint32_t offset =
- FLASH_SECTOR_TABLE[sector] - FLASH_SECTOR_TABLE[0];
- const uint32_t size =
- FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
- memset(FLASH_BUFFER + offset, 0xFF, size);
-
- done_sectors++;
- if (progress) {
- progress(done_sectors, total_sectors);
- }
- }
+ if (offset < sector_size) {
+ break;
}
+ offset -= sector_size;
+ sector++;
}
- ensure(flash_lock_write(), NULL);
- return sectrue;
-}
-secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset,
- uint32_t *bytes_erased) {
- uint32_t sector_offset = 0;
- *bytes_erased = 0;
+ return sector;
+}
- for (int s = 0; s < area->num_subareas; s++) {
- for (int i = 0; i < area->subarea[s].num_sectors; i++) {
- uint32_t sector_index = area->subarea[s].first_sector + i;
- uint32_t sector_size = FLASH_SECTOR_TABLE[sector_index + 1] -
- FLASH_SECTOR_TABLE[sector_index];
+secbool flash_sector_erase(uint16_t sector) {
+ if (sector >= FLASH_SECTOR_COUNT) {
+ return secfalse;
+ }
- if (offset == sector_offset) {
- uint8_t *flash =
- (uint8_t *)flash_get_address(sector_index, 0, sector_size);
- memset(flash, 0xFF, sector_size);
- *bytes_erased = sector_size;
- return sectrue;
- }
+ const uint32_t offset = FLASH_SECTOR_TABLE[sector] - FLASH_SECTOR_TABLE[0];
- sector_offset += sector_size;
- }
- }
+ const uint32_t size =
+ FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
- if (offset == sector_offset) {
- return sectrue;
- }
+ memset(FLASH_BUFFER + offset, 0xFF, size);
- return secfalse;
+ return sectrue;
}
secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data) {
@@ -246,33 +203,3 @@ secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data) {
flash[0] = data;
return sectrue;
}
-
-secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
- uint8_t datalen) {
- if (offset + datalen > OTP_BLOCK_SIZE) {
- return secfalse;
- }
- uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset;
- memcpy(data, OTP_BUFFER + offset_in_sector, datalen);
- return sectrue;
-}
-
-secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
- uint8_t datalen) {
- if (offset + datalen > OTP_BLOCK_SIZE) {
- return secfalse;
- }
- uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset;
- uint8_t *flash = OTP_BUFFER + offset_in_sector;
- for (int i = 0; i < datalen; i++) {
- if ((flash[i] & data[i]) != data[i]) {
- return secfalse; // we cannot change zeroes to ones
- }
- flash[i] = data[i];
- }
- return sectrue;
-}
-
-secbool flash_otp_lock(uint8_t block) { return secfalse; }
-
-secbool flash_otp_is_locked(uint8_t block) { return secfalse; }
diff --git a/core/embed/trezorhal/unix/flash_otp.c b/core/embed/trezorhal/unix/flash_otp.c
new file mode 100644
index 00000000000..1369e092937
--- /dev/null
+++ b/core/embed/trezorhal/unix/flash_otp.c
@@ -0,0 +1,62 @@
+/*
+ * 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 "../flash_otp.h"
+
+#define OTP_BLOCK_SIZE 32
+#define FLASH_SECTOR_OTP (FLASH_SECTOR_COUNT)
+
+static uint8_t OTP_BUFFER[OTP_BLOCK_SIZE * 64];
+
+void flash_otp_init(void) {
+ // fill OTP buffer with ones
+ memset(OTP_BUFFER, 0xFF, sizeof(OTP_BUFFER));
+}
+
+secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
+ uint8_t datalen) {
+ if (offset + datalen > OTP_BLOCK_SIZE) {
+ return secfalse;
+ }
+ uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset;
+ memcpy(data, OTP_BUFFER + offset_in_sector, datalen);
+ return sectrue;
+}
+
+secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
+ uint8_t datalen) {
+ if (offset + datalen > OTP_BLOCK_SIZE) {
+ return secfalse;
+ }
+ uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset;
+ uint8_t *flash = OTP_BUFFER + offset_in_sector;
+ for (int i = 0; i < datalen; i++) {
+ if ((flash[i] & data[i]) != data[i]) {
+ return secfalse; // we cannot change zeroes to ones
+ }
+ flash[i] = data[i];
+ }
+ return sectrue;
+}
+
+secbool flash_otp_lock(uint8_t block) { return secfalse; }
+
+secbool flash_otp_is_locked(uint8_t block) { return secfalse; }
diff --git a/core/embed/unix/main.c b/core/embed/unix/main.c
index a6c90fe414f..f7c6461ea8d 100644
--- a/core/embed/unix/main.c
+++ b/core/embed/unix/main.c
@@ -40,6 +40,7 @@
#include "extmod/misc.h"
#include "extmod/vfs_posix.h"
#include "flash.h"
+#include "flash_otp.h"
#include "genhdr/mpversion.h"
#include "input.h"
#include "py/builtin.h"
@@ -482,6 +483,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
// Map trezor.flash to memory.
flash_init();
+ flash_otp_init();
#if MICROPY_ENABLE_GC
char *heap = malloc(heap_size);
diff --git a/core/site_scons/boards/stm32f4_common.py b/core/site_scons/boards/stm32f4_common.py
index f6294295a0c..8265068c4b2 100644
--- a/core/site_scons/boards/stm32f4_common.py
+++ b/core/site_scons/boards/stm32f4_common.py
@@ -42,6 +42,7 @@ def stm32f4_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32f4/common.c",
"embed/trezorhal/stm32f4/fault_handlers.c",
"embed/trezorhal/stm32f4/flash.c",
+ "embed/trezorhal/stm32f4/flash_otp.c",
"embed/trezorhal/stm32f4/lowlevel.c",
"embed/trezorhal/stm32f4/mpu.c",
"embed/trezorhal/stm32f4/platform.c",
@@ -50,7 +51,6 @@ def stm32f4_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32f4/random_delays.c",
"embed/trezorhal/stm32f4/rng.c",
"embed/trezorhal/stm32f4/vectortable.s",
- "vendor/trezor-storage/flash_common_f4.c",
]
# boardloader needs separate assembler for some function unencumbered by various FW+bootloader hacks
diff --git a/core/site_scons/boards/stm32u5_common.py b/core/site_scons/boards/stm32u5_common.py
index 61c4184e4d2..f1594e3b2ec 100644
--- a/core/site_scons/boards/stm32u5_common.py
+++ b/core/site_scons/boards/stm32u5_common.py
@@ -52,6 +52,7 @@ def stm32u5_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32u5/common.c",
"embed/trezorhal/stm32u5/fault_handlers.c",
"embed/trezorhal/stm32u5/flash.c",
+ "embed/trezorhal/stm32u5/flash_otp.c",
"embed/trezorhal/stm32u5/lowlevel.c",
"embed/trezorhal/stm32u5/mpu.c",
"embed/trezorhal/stm32u5/platform.c",
diff --git a/legacy/Makefile b/legacy/Makefile
index 7795fd21e6a..d77354a04e9 100644
--- a/legacy/Makefile
+++ b/legacy/Makefile
@@ -20,7 +20,7 @@ OBJS += usb_standard.o
OBJS += util.o
OBJS += webusb.o
OBJS += winusb.o
-OBJS += vendor/trezor-storage/flash_common_f4.o
+OBJS += vendor/trezor-storage/flash_area.o
libtrezor.a: $(OBJS)
diff --git a/legacy/flash.c b/legacy/flash.c
index 4f3f1447176..4c3ce7c0329 100644
--- a/legacy/flash.c
+++ b/legacy/flash.c
@@ -22,6 +22,7 @@
#include "common.h"
#include "flash.h"
+#include "flash_area.h"
#include "memory.h"
#include "supervise.h"
@@ -88,11 +89,29 @@ const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) {
return (const void *)FLASH_PTR(addr);
}
-uint32_t flash_sector_size(uint16_t sector) {
- if (sector >= FLASH_SECTOR_COUNT) {
+uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) {
+ if (first_sector + sector_count >= FLASH_SECTOR_COUNT) {
return 0;
}
- return FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
+ return FLASH_SECTOR_TABLE[first_sector + sector_count] -
+ FLASH_SECTOR_TABLE[first_sector];
+}
+
+uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) {
+ uint16_t sector = first_sector;
+
+ while (sector < FLASH_SECTOR_COUNT) {
+ uint32_t sector_size =
+ FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
+
+ if (offset < sector_size) {
+ break;
+ }
+ offset -= sector_size;
+ sector++;
+ }
+
+ return sector;
}
secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data) {
@@ -139,42 +158,7 @@ secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data) {
return sectrue;
}
-secbool flash_area_erase_bulk(const flash_area_t *area, int count,
- void (*progress)(int pos, int len)) {
- ensure(flash_unlock_write(), NULL);
-
- int total_sectors = 0;
- int done_sectors = 0;
- for (int a = 0; a < count; a++) {
- for (int i = 0; i < area[a].num_subareas; i++) {
- total_sectors += area[a].subarea[i].num_sectors;
- }
- }
- if (progress) {
- progress(0, total_sectors);
- }
-
- for (int a = 0; a < count; a++) {
- for (int s = 0; s < area[a].num_subareas; s++) {
- for (int i = 0; i < area[a].subarea[s].num_sectors; i++) {
- int sector = area[a].subarea[s].first_sector + i;
- svc_flash_erase_sector(sector);
- // check whether the sector was really deleted (contains only 0xFF)
- const uint32_t addr_start = FLASH_SECTOR_TABLE[sector],
- addr_end = FLASH_SECTOR_TABLE[sector + 1];
- for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
- if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) {
- ensure(flash_lock_write(), NULL);
- return secfalse;
- }
- }
- done_sectors++;
- if (progress) {
- progress(done_sectors, total_sectors);
- }
- }
- }
- }
- ensure(flash_lock_write(), NULL);
+secbool flash_sector_erase(uint16_t sector) {
+ svc_flash_erase_sector(sector);
return sectrue;
}
diff --git a/legacy/flash.h b/legacy/flash.h
index 5559b6d89b9..f082908138d 100644
--- a/legacy/flash.h
+++ b/legacy/flash.h
@@ -27,7 +27,7 @@
#define FLASH_BYTE_ACCESS 1
#define FLASH_SECTOR_COUNT 24
-#include "flash_common.h"
+#include "flash_ll.h"
// note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427)
// (reference RM0090 section 3.7.5)
diff --git a/legacy/intermediate_fw/trezor.c b/legacy/intermediate_fw/trezor.c
index 18d3e9a1292..8f0d9866c05 100644
--- a/legacy/intermediate_fw/trezor.c
+++ b/legacy/intermediate_fw/trezor.c
@@ -35,8 +35,6 @@
#include "timer.h"
#include "util.h"
-const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size);
-
// legacy storage magic
#define LEGACY_STORAGE_SECTOR 2
static const uint32_t META_MAGIC_V10 = 0x525a5254; // 'TRZR'
diff --git a/legacy/memory.c b/legacy/memory.c
index 079ba50413d..a2b16329429 100644
--- a/legacy/memory.c
+++ b/legacy/memory.c
@@ -28,8 +28,6 @@
#define FLASH_OPTION_BYTES_1 (*(const uint64_t *)0x1FFFC000)
#define FLASH_OPTION_BYTES_2 (*(const uint64_t *)0x1FFFC008)
-const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size);
-
void memory_protect(void) {
#if PRODUCTION
#if BOOTLOADER_QA
@@ -110,7 +108,7 @@ int memory_firmware_hash(const uint8_t *challenge, uint32_t challenge_size,
}
for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) {
- uint32_t size = flash_sector_size(i);
+ uint32_t size = flash_sector_size(i, 1);
const void *data = flash_get_address(i, 0, size);
if (data == NULL) {
return 1;
diff --git a/legacy/norcow_config.h b/legacy/norcow_config.h
index 3a9545e19b0..d7416bb63bd 100644
--- a/legacy/norcow_config.h
+++ b/legacy/norcow_config.h
@@ -20,7 +20,7 @@
#ifndef __NORCOW_CONFIG_H__
#define __NORCOW_CONFIG_H__
-#include "flash.h"
+#include "flash_area.h"
#define NORCOW_SECTOR_COUNT 2
#define NORCOW_SECTOR_SIZE (16 * 1024)
diff --git a/storage/flash_area.c b/storage/flash_area.c
new file mode 100644
index 00000000000..bc1fb2d7887
--- /dev/null
+++ b/storage/flash_area.c
@@ -0,0 +1,243 @@
+/*
+ * 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 "flash_area.h"
+#include
+
+uint32_t flash_area_get_size(const flash_area_t *area) {
+ uint32_t size = 0;
+ for (int i = 0; i < area->num_subareas; i++) {
+ size += flash_sector_size(area->subarea[i].first_sector,
+ area->subarea[i].num_sectors);
+ }
+ return size;
+}
+
+uint16_t flash_area_total_sectors(const flash_area_t *area) {
+ uint16_t total = 0;
+ for (int i = 0; i < area->num_subareas; i++) {
+ total += area->subarea[i].num_sectors;
+ }
+ return total;
+}
+
+static secbool get_sector_and_offset(const flash_area_t *area, uint32_t offset,
+ uint16_t *sector_out,
+ uint32_t *offset_out) {
+ for (int i = 0; i < area->num_subareas; i++) {
+ // Get the sub-area parameters
+ uint16_t first_sector = area->subarea[i].first_sector;
+ uint16_t num_sectors = area->subarea[i].num_sectors;
+ uint32_t subarea_size = flash_sector_size(first_sector, num_sectors);
+ // Does the requested offset start in the sub-area?
+ if (offset < subarea_size) {
+ uint16_t found_sector = flash_sector_find(first_sector, offset);
+ *sector_out = found_sector;
+ *offset_out =
+ offset - flash_sector_size(first_sector, found_sector - first_sector);
+ return sectrue;
+ }
+ offset -= subarea_size;
+ }
+
+ return secfalse;
+}
+
+const void *flash_area_get_address(const flash_area_t *area, uint32_t offset,
+ uint32_t size) {
+ for (int i = 0; i < area->num_subareas; i++) {
+ // Get sub-area parameters
+ uint16_t first_sector = area->subarea[i].first_sector;
+ uint16_t num_sectors = area->subarea[i].num_sectors;
+ uint32_t subarea_size = flash_sector_size(first_sector, num_sectors);
+ // Does the requested block start in the sub-area?
+ if (offset < subarea_size) {
+ // Does the requested block fit in the sub-area?
+ if (offset + size <= subarea_size) {
+ const uint8_t *ptr =
+ (const uint8_t *)flash_get_address(first_sector, 0, 0);
+ // We expect that all sectors/pages in the sub-area make
+ // a continuous block of adresses with the same security atributes
+ return ptr + offset;
+ } else {
+ return NULL;
+ }
+ }
+ offset -= subarea_size;
+ }
+ return NULL;
+}
+
+#if defined FLASH_BYTE_ACCESS
+
+secbool flash_area_write_byte(const flash_area_t *area, uint32_t offset,
+ uint8_t data) {
+ uint16_t sector;
+ uint32_t sector_offset;
+ if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
+ return secfalse;
+ }
+ return flash_write_byte(sector, sector_offset, data);
+}
+
+secbool flash_area_write_word(const flash_area_t *area, uint32_t offset,
+ uint32_t data) {
+ uint16_t sector;
+ uint32_t sector_offset;
+ if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
+ return secfalse;
+ }
+ return flash_write_word(sector, sector_offset, data);
+}
+
+secbool flash_area_write_quadword(const flash_area_t *area, uint32_t offset,
+ const uint32_t *data) {
+ if (offset % 16 != 0) {
+ return secfalse;
+ }
+ for (int i = 0; i < 4; i++) {
+ if (sectrue !=
+ flash_area_write_word(area, offset + i * sizeof(uint32_t), data[i])) {
+ return secfalse;
+ }
+ }
+ return sectrue;
+}
+
+secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset,
+ const uint32_t *data) {
+ if (offset % (8 * 16) != 0) {
+ return secfalse;
+ }
+ for (int i = 0; i < (8 * 4); i++) {
+ if (sectrue !=
+ flash_area_write_word(area, offset + i * sizeof(uint32_t), data[i])) {
+ return secfalse;
+ }
+ }
+ return sectrue;
+}
+
+#else // not defined FLASH_BYTE_ACCESS
+
+secbool flash_area_write_quadword(const flash_area_t *area, uint32_t offset,
+ const uint32_t *data) {
+ uint16_t sector;
+ uint32_t sector_offset;
+ if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
+ return secfalse;
+ }
+ return flash_write_quadword(sector, sector_offset, data);
+}
+
+secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset,
+ const uint32_t *data) {
+ uint16_t sector;
+ uint32_t sector_offset;
+ if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
+ return secfalse;
+ }
+ return flash_write_burst(sector, sector_offset, data);
+}
+
+#endif // not defined FLASH_BYTE_ACCESS
+
+secbool flash_area_erase(const flash_area_t *area,
+ void (*progress)(int pos, int len)) {
+ return flash_area_erase_bulk(area, 1, progress);
+}
+
+static secbool erase_sector(uint16_t sector) {
+ secbool result = secfalse;
+
+ if (sectrue != flash_unlock_write()) {
+ return secfalse;
+ }
+
+ result = flash_sector_erase(sector);
+
+ if (sectrue != flash_lock_write()) {
+ return secfalse;
+ }
+
+ return result;
+}
+
+secbool flash_area_erase_bulk(const flash_area_t *area, int count,
+ void (*progress)(int pos, int len)) {
+ int total_sectors = 0;
+ int done_sectors = 0;
+ for (int a = 0; a < count; a++) {
+ for (int i = 0; i < area[a].num_subareas; i++) {
+ total_sectors += area[a].subarea[i].num_sectors;
+ }
+ }
+ if (progress) {
+ progress(0, total_sectors);
+ }
+
+ for (int a = 0; a < count; a++) {
+ for (int s = 0; s < area[a].num_subareas; s++) {
+ for (int i = 0; i < area[a].subarea[s].num_sectors; i++) {
+ int sector = area[a].subarea[s].first_sector + i;
+
+ if (sectrue != erase_sector(sector)) {
+ return secfalse;
+ }
+
+ done_sectors++;
+ if (progress) {
+ progress(done_sectors, total_sectors);
+ }
+ }
+ }
+ }
+
+ return sectrue;
+}
+
+secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset,
+ uint32_t *bytes_erased) {
+ uint32_t sector_offset = 0;
+ *bytes_erased = 0;
+
+ for (int s = 0; s < area->num_subareas; s++) {
+ for (int i = 0; i < area->subarea[s].num_sectors; i++) {
+ uint32_t sector = area->subarea[s].first_sector + i;
+ uint32_t sector_size = flash_sector_size(sector, 1);
+
+ if (offset == sector_offset) {
+ if (sectrue != erase_sector(sector)) {
+ return secfalse;
+ }
+
+ *bytes_erased = sector_size;
+ return sectrue;
+ }
+
+ sector_offset += sector_size;
+ }
+ }
+
+ if (offset == sector_offset) {
+ return sectrue;
+ }
+
+ return secfalse;
+}
diff --git a/storage/flash_area.h b/storage/flash_area.h
new file mode 100644
index 00000000000..02f8930fcb0
--- /dev/null
+++ b/storage/flash_area.h
@@ -0,0 +1,89 @@
+/*
+ * 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 .
+ */
+
+#ifndef FLASH_AREA_H
+#define FLASH_AREA_H
+
+#include
+#include "secbool.h"
+
+#include "flash.h"
+
+/**
+ * Flash driver interface is designed to abstract away differences between
+ * various MCUs used in Trezor devices.
+ *
+ * Generally, flash memory is divided into sectors. On different MCUs, sectors
+ * may have different sizes, and therefore, different number of sectors are used
+ * for a given purpose. For example, on STM32F4, the sectors are relatively
+ * large so we use single sector for Storage. On STM32U5, the sectors are
+ * smaller, so we use multiple sectors for the Storage. Storage implementation
+ * should not care about this, and should use flash_area_t interface to access
+ * the flash memory.
+ *
+ * flash_area_t represents a location in flash memory. It may be contiguous, or
+ * it may be composed of multiple non-contiguous subareas.
+ *
+ * flash_subarea_t represents a contiguous area in flash memory, specified by
+ * first_sector and num_sectors.
+ */
+
+typedef struct {
+ uint16_t first_sector;
+ uint16_t num_sectors;
+} flash_subarea_t;
+
+typedef struct {
+ flash_subarea_t subarea[4];
+ uint8_t num_subareas;
+} flash_area_t;
+
+uint32_t flash_area_get_size(const flash_area_t *area);
+
+uint16_t flash_area_total_sectors(const flash_area_t *area);
+
+const void *flash_area_get_address(const flash_area_t *area, uint32_t offset,
+ uint32_t size);
+
+#if defined FLASH_BYTE_ACCESS
+secbool __wur flash_area_write_byte(const flash_area_t *area, uint32_t offset,
+ uint8_t data);
+secbool __wur flash_area_write_word(const flash_area_t *area, uint32_t offset,
+ uint32_t data);
+#endif
+secbool __wur flash_area_write_quadword(const flash_area_t *area,
+ uint32_t offset, const uint32_t *data);
+
+secbool __wur flash_area_write_burst(const flash_area_t *area, uint32_t offset,
+ const uint32_t *data);
+
+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,
+ void (*progress)(int pos, int len));
+
+// Erases the single sector in the designated flash area
+// The 'offset' parameter must indicate the relative sector offset within the
+// flash area If 'offset' is outside the bounds of the flash area,
+// 'bytes_erased' is set to 0 otherwise, 'bytes_erased' is set to the size of
+// the erased sector
+secbool __wur flash_area_erase_partial(const flash_area_t *area,
+ uint32_t offset, uint32_t *bytes_erased);
+
+#endif // FLASH_AREA_H
diff --git a/storage/flash_common.h b/storage/flash_common.h
deleted file mode 100644
index f40bae00fdd..00000000000
--- a/storage/flash_common.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef FLASH_COMMON_H
-#define FLASH_COMMON_H
-
-#include
-#include
-#include "secbool.h"
-
-typedef struct {
- uint16_t first_sector;
- uint16_t num_sectors;
-} flash_subarea_t;
-
-typedef struct {
- flash_subarea_t subarea[4];
- uint8_t num_subareas;
- bool secure_area;
-} flash_area_t;
-
-void flash_init(void);
-
-secbool __wur flash_unlock_write(void);
-secbool __wur flash_lock_write(void);
-
-uint32_t flash_sector_size(uint16_t sector);
-uint16_t flash_total_sectors(const flash_area_t *area);
-int32_t flash_get_sector_num(const flash_area_t *area,
- uint32_t sector_inner_num);
-
-const void *flash_area_get_address(const flash_area_t *area, uint32_t offset,
- uint32_t size);
-uint32_t flash_area_get_size(const flash_area_t *area);
-
-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,
- void (*progress)(int pos, int len));
-
-#if defined FLASH_BYTE_ACCESS
-secbool __wur flash_area_write_byte(const flash_area_t *area, uint32_t offset,
- uint8_t data);
-secbool __wur flash_area_write_word(const flash_area_t *area, uint32_t offset,
- uint32_t data);
-#endif
-secbool __wur flash_area_write_quadword(const flash_area_t *area,
- uint32_t offset, const uint32_t *data);
-
-secbool __wur flash_area_write_burst(const flash_area_t *area, uint32_t offset,
- const uint32_t *data);
-
-#endif
diff --git a/storage/flash_common_f4.c b/storage/flash_common_f4.c
deleted file mode 100644
index 43e3b22e247..00000000000
--- a/storage/flash_common_f4.c
+++ /dev/null
@@ -1,150 +0,0 @@
-#include "flash.h"
-
-secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data);
-
-secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data);
-
-const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size);
-
-static uint32_t flash_subarea_get_size(const flash_subarea_t *subarea) {
- uint32_t size = 0;
- for (int s = 0; s < subarea->num_sectors; s++) {
- size += flash_sector_size(subarea->first_sector + s);
- }
- return size;
-}
-
-static secbool subarea_get_sector_and_offset(const flash_subarea_t *subarea,
- uint32_t offset,
- uint16_t *sector_out,
- uint32_t *offset_out) {
- uint32_t tmp_offset = offset;
- uint16_t sector = subarea->first_sector;
-
- // in correct subarea
- for (int s = 0; s < subarea->num_sectors; s++) {
- const uint32_t sector_size = flash_sector_size(sector);
- if (tmp_offset < sector_size) {
- *sector_out = sector;
- *offset_out = tmp_offset;
- return sectrue;
- }
- tmp_offset -= sector_size;
- sector++;
- }
- return secfalse;
-}
-
-uint32_t flash_area_get_size(const flash_area_t *area) {
- uint32_t size = 0;
- for (int i = 0; i < area->num_subareas; i++) {
- size += flash_subarea_get_size(&area->subarea[i]);
- }
- return size;
-}
-
-uint16_t flash_total_sectors(const flash_area_t *area) {
- uint16_t total = 0;
- for (int i = 0; i < area->num_subareas; i++) {
- total += area->subarea[i].num_sectors;
- }
- return total;
-}
-
-int32_t flash_get_sector_num(const flash_area_t *area,
- uint32_t sector_inner_num) {
- uint16_t sector = 0;
- uint16_t remaining = sector_inner_num;
- for (int i = 0; i < area->num_subareas; i++) {
- if (remaining < area->subarea[i].num_sectors) {
- sector = area->subarea[i].first_sector + remaining;
- return sector;
- } else {
- remaining -= area->subarea[i].num_sectors;
- }
- }
-
- return -1;
-}
-
-static secbool get_sector_and_offset(const flash_area_t *area, uint32_t offset,
- uint16_t *sector_out,
- uint32_t *offset_out) {
- uint32_t tmp_offset = offset;
- for (int i = 0; i < area->num_subareas; i++) {
- uint32_t sub_size = flash_subarea_get_size(&area->subarea[i]);
- if (tmp_offset >= sub_size) {
- tmp_offset -= sub_size;
- continue;
- }
-
- return subarea_get_sector_and_offset(&area->subarea[i], tmp_offset,
- sector_out, offset_out);
- }
- return secfalse;
-}
-
-const void *flash_area_get_address(const flash_area_t *area, uint32_t offset,
- uint32_t size) {
- uint16_t sector;
- uint32_t sector_offset;
-
- if (!get_sector_and_offset(area, offset, §or, §or_offset)) {
- return NULL;
- }
-
- return flash_get_address(sector, sector_offset, size);
-}
-
-secbool flash_area_erase(const flash_area_t *area,
- void (*progress)(int pos, int len)) {
- return flash_area_erase_bulk(area, 1, progress);
-}
-
-secbool flash_area_write_byte(const flash_area_t *area, uint32_t offset,
- uint8_t data) {
- uint16_t sector;
- uint32_t sector_offset;
- if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
- return secfalse;
- }
- return flash_write_byte(sector, sector_offset, data);
-}
-
-secbool flash_area_write_word(const flash_area_t *area, uint32_t offset,
- uint32_t data) {
- uint16_t sector;
- uint32_t sector_offset;
- if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
- return secfalse;
- }
- return flash_write_word(sector, sector_offset, data);
-}
-
-secbool flash_area_write_quadword(const flash_area_t *area, uint32_t offset,
- const uint32_t *data) {
- if (offset % 16 != 0) {
- return secfalse;
- }
- for (int i = 0; i < 4; i++) {
- if (sectrue !=
- flash_area_write_word(area, offset + i * sizeof(uint32_t), data[i])) {
- return secfalse;
- }
- }
- return sectrue;
-}
-
-secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset,
- const uint32_t *data) {
- if (offset % (8 * 16) != 0) {
- return secfalse;
- }
- for (int i = 0; i < (8 * 4); i++) {
- if (sectrue !=
- flash_area_write_word(area, offset + i * sizeof(uint32_t), data[i])) {
- return secfalse;
- }
- }
- return sectrue;
-}
diff --git a/storage/flash_ll.h b/storage/flash_ll.h
new file mode 100644
index 00000000000..af573df5075
--- /dev/null
+++ b/storage/flash_ll.h
@@ -0,0 +1,74 @@
+/*
+ * 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 .
+ */
+
+#ifndef FLASH_LL_H_
+#define FLASH_LL_H_
+
+#include
+#include
+
+// Flash memory low-level API, providing abstraction for
+// various flash archictures found on STM32 MCUs
+
+// The 'sector' parameter in this API can represent
+// 1. Non-uniform sector number on STM32F4
+// 2. Uniform page number on STM32U5
+
+// Returns the size of the a continuous area of sectors
+// Returns 0 if any of the sectors is out of range
+uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count);
+
+// Returns number of the sector/page at specified byte 'offset'
+// from the beginning of the 'first_sector'
+uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset);
+
+// Returns the physical address of a byte on specified 'offset' in the specified
+// 'sector'. Checks if it's possible to access continues space of 'size' bytes
+// Returns NULL i [offset, offset + size] is of out of the specified sector
+const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size);
+
+// Unlocks the flash memory for writes/erase operations
+// Flash must be locked again as soon as possible
+secbool __wur flash_unlock_write(void);
+
+// Locks the flash memory for writes/erase operations
+secbool __wur flash_lock_write(void);
+
+#if defined FLASH_BYTE_ACCESS
+
+// Writes a single byte to the specified 'offset' inside a flash 'sector'
+secbool __wur flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data);
+
+// Writes a single 32-bit word to the specified 'offset' inside a flash 'sector'
+secbool __wur flash_write_word(uint16_t sector, uint32_t offset, uint32_t data);
+
+#endif
+
+// Writes a 16-byte block to specified 'offset' inside a flash 'sector'
+secbool __wur flash_write_quadword(uint16_t sector, uint32_t offset,
+ const uint32_t *data);
+
+// Writes a 16-byte block to specified 'offset' inside a flash 'sector'
+secbool __wur flash_write_burst(uint16_t sector, uint32_t offset,
+ const uint32_t *data);
+
+// Erases a single sector/page of flash memory
+secbool __wur flash_sector_erase(uint16_t sector);
+
+#endif // FLASH_LL_H
diff --git a/storage/norcow.c b/storage/norcow.c
index 8bb639518ab..287eed58af6 100644
--- a/storage/norcow.c
+++ b/storage/norcow.c
@@ -20,7 +20,7 @@
#include
#include "common.h"
-#include "flash.h"
+#include "flash_area.h"
#include "norcow.h"
// NRC2 = 4e524332
diff --git a/storage/tests/c/Makefile b/storage/tests/c/Makefile
index 984faf2d09c..dd22e8bbdaa 100644
--- a/storage/tests/c/Makefile
+++ b/storage/tests/c/Makefile
@@ -14,7 +14,7 @@ SRC = storage/tests/c/flash.c
SRC += storage/tests/c/common.c
SRC += storage/tests/c/random_delays.c
SRC += storage/tests/c/test_layout.c
-SRC += storage/flash_common_f4.c
+SRC += storage/flash_area.c
SRC += storage/storage.c
SRC += storage/norcow.c
SRC += crypto/pbkdf2.c
diff --git a/storage/tests/c/flash.c b/storage/tests/c/flash.c
index 7ca193f8d2a..0b2369fcceb 100644
--- a/storage/tests/c/flash.c
+++ b/storage/tests/c/flash.c
@@ -63,11 +63,29 @@ secbool flash_unlock_write(void) { return sectrue; }
secbool flash_lock_write(void) { return sectrue; }
-uint32_t flash_sector_size(uint16_t sector) {
- if (sector >= FLASH_SECTOR_COUNT) {
+uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) {
+ if (first_sector + sector_count >= FLASH_SECTOR_COUNT) {
return 0;
}
- return FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
+ return FLASH_SECTOR_TABLE[first_sector + sector_count] -
+ FLASH_SECTOR_TABLE[first_sector];
+}
+
+uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) {
+ uint16_t sector = first_sector;
+
+ while (sector < FLASH_SECTOR_COUNT) {
+ uint32_t sector_size =
+ FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
+
+ if (offset < sector_size) {
+ break;
+ }
+ offset -= sector_size;
+ sector++;
+ }
+
+ return sector;
}
const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) {
@@ -82,67 +100,56 @@ const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) {
return FLASH_BUFFER + addr - FLASH_SECTOR_TABLE[0];
}
-secbool flash_area_erase_bulk(const flash_area_t *area, int count,
- void (*progress)(int pos, int len)) {
- ensure(flash_unlock_write(), NULL);
+secbool flash_sector_erase(uint16_t sector) {
+ if (sector >= FLASH_SECTOR_COUNT) {
+ return secfalse;
+ }
+ const uint32_t offset = FLASH_SECTOR_TABLE[sector] - FLASH_SECTOR_TABLE[0];
+ const uint32_t size =
+ FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
+ memset(FLASH_BUFFER + offset, 0xFF, size);
+ return sectrue;
+}
- int total_sectors = 0;
- int done_sectors = 0;
- for (int a = 0; a < count; a++) {
- for (int i = 0; i < area[a].num_subareas; i++) {
- total_sectors += area[a].subarea[i].num_sectors;
- }
+static secbool flash_write(uint16_t sector, uint32_t offset,
+ const uint8_t *data, size_t data_size) {
+ // check proper alignment
+ if ((offset % data_size) != 0) {
+ return secfalse;
}
- if (progress) {
- progress(0, total_sectors);
+ uint8_t *flash = (uint8_t *)flash_get_address(sector, offset, data_size);
+
+ if (flash == NULL) {
+ return secfalse;
}
- for (int a = 0; a < count; a++) {
- for (int s = 0; s < area[a].num_subareas; s++) {
- for (int i = 0; i < area[a].subarea[s].num_sectors; i++) {
- int sector = area[a].subarea[s].first_sector + i;
-
- const uint32_t offset =
- FLASH_SECTOR_TABLE[sector] - FLASH_SECTOR_TABLE[0];
- const uint32_t size =
- FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector];
- memset(FLASH_BUFFER + offset, 0xFF, size);
-
- done_sectors++;
- if (progress) {
- progress(done_sectors, total_sectors);
- }
- }
+ // check if not writing ones to zeroes
+ for (size_t i = 0; i < data_size; i++) {
+ if (data[i] != (data[i] & flash[i])) {
+ return secfalse;
}
}
- ensure(flash_lock_write(), NULL);
+
+ memcpy(flash, data, data_size);
+
return sectrue;
}
secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data) {
- uint8_t *flash = (uint8_t *)flash_get_address(sector, offset, 1);
- if (!flash) {
- return secfalse;
- }
- if ((flash[0] & data) != data) {
- return secfalse; // we cannot change zeroes to ones
- }
- flash[0] = data;
- return sectrue;
+ return flash_write(sector, offset, (uint8_t *)&data, sizeof(uint8_t));
}
secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data) {
- if (offset % 4) { // we write only at 4-byte boundary
- return secfalse;
- }
- uint32_t *flash = (uint32_t *)flash_get_address(sector, offset, sizeof(data));
- if (!flash) {
- return secfalse;
- }
- if ((flash[0] & data) != data) {
- return secfalse; // we cannot change zeroes to ones
- }
- flash[0] = data;
- return sectrue;
+ return flash_write(sector, offset, (uint8_t *)&data, sizeof(uint32_t));
+}
+
+secbool flash_write_quadword(uint16_t sector, uint32_t offset,
+ const uint32_t *data) {
+ return flash_write(sector, offset, (uint8_t *)data, 4 * sizeof(uint32_t));
+}
+
+secbool flash_write_burst(uint16_t sector, uint32_t offset,
+ const uint32_t *data) {
+ return flash_write(sector, offset, (uint8_t *)data, 32 * sizeof(uint32_t));
}
diff --git a/storage/tests/c/flash.h b/storage/tests/c/flash.h
index 132f85bcc81..38a2ea3845f 100644
--- a/storage/tests/c/flash.h
+++ b/storage/tests/c/flash.h
@@ -28,13 +28,6 @@
#define FLASH_BYTE_ACCESS 1
#endif
-#include "flash_common.h"
-#include "test_layout.h"
-
-uint32_t flash_sector_size(uint16_t sector);
-
-secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data);
-
-secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data);
+#include "flash_ll.h"
#endif
diff --git a/storage/tests/c/norcow_config.h b/storage/tests/c/norcow_config.h
index ea72a111572..f3b22d089f7 100644
--- a/storage/tests/c/norcow_config.h
+++ b/storage/tests/c/norcow_config.h
@@ -21,6 +21,7 @@
#define __NORCOW_CONFIG_H__
#include "flash.h"
+#include "test_layout.h"
#define NORCOW_SECTOR_COUNT 2
#define NORCOW_SECTOR_SIZE (64 * 1024)
diff --git a/storage/tests/c/test_layout.h b/storage/tests/c/test_layout.h
index 1223f198fc4..62e7cd25eed 100644
--- a/storage/tests/c/test_layout.h
+++ b/storage/tests/c/test_layout.h
@@ -3,7 +3,7 @@
#define STORAGE_AREAS_COUNT 2
-#include "flash_common.h"
+#include "flash_area.h"
extern const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT];