Skip to content

Commit

Permalink
change flash boot size for h503 to 24KB, H52x/6x/7x to 32KB. Correct …
Browse files Browse the repository at this point in the history
…protect mask for h52x/6x/7x
  • Loading branch information
hathach committed Dec 3, 2024
1 parent b57495c commit f7a2093
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 249 deletions.
18 changes: 13 additions & 5 deletions ports/stm32h5/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# TinyUF2 for STM32H5

TinyUF2 occupies 24KB. Therefore application should start at `0x08006000`

TinyUF2 occupies around 16Kb + 1KB for CF2 in flash. Since H5 has uniform sector size of 8KB, ideally we would have bootloader size set to 24KB. However, due to the fact that only H503 can protect/secure individual sector, the rest of H5 family (H52x, H56x) can only secure flash in 4-sector (group) unit. Therefore application should start at
- H503: `0x08006000`, boot size is 24KB
- H52x, H56x, H57x: `0x08008000`, boot size is 32KB
To create a UF2 image from a .bin file, either use family option `STM32H5` or its magic number as follows:

From hex
Expand All @@ -11,9 +12,16 @@ uf2conv.py -c -f 0x4e8f1c5d firmware.hex
uf2conv.py -c -f STM32H5 firmware.hex
```

From bin
From bin for H503

```
uf2conv.py -c -b 0x08006000 -f STM32H5 firmware.bin
uf2conv.py -c -b 0x08006000 -f 0x4e8f1c5d firmware.bin
```

From bin for H52x, H56x, H57x

```
uf2conv.py -c -b 0x08010000 -f STM32H5 firmware.bin
uf2conv.py -c -b 0x08010000 -f 0x4e8f1c5d firmware.bin
uf2conv.py -c -b 0x08008000 -f STM32H5 firmware.bin
uf2conv.py -c -b 0x08008000 -f 0x4e8f1c5d firmware.bin
```
242 changes: 72 additions & 170 deletions ports/stm32h5/board_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,229 +34,134 @@

#define FLASH_BASE_ADDR 0x08000000UL

// H503 is 1 bit per sector, the rest of the family H523/33/62/63 is 1 bit per 4 sectors
// TinyUF2 resides in the first 8 flash sectors on STM32H5s, therefore these are write protected
#define BOOTLOADER_SECTOR_MASK 0x3UL

/* flash parameters that we should not really know */
static const uint32_t sector_size[] =
{
// First 8 sectors are for bootloader (64KB)
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
// Application (BOARD_FLASH_APP_START) 64kB
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
8 * 1024,
};
#ifdef STM32H503xx
#define BOARD_FLASH_PROTECT_MASK 0x7u // protect 3 sector
#else
#define BOARD_FLASH_PROTECT_MASK 0x1u // protect 1 group of sector 0-3
#endif

enum
{
SECTOR_COUNT = sizeof(sector_size)/sizeof(sector_size[0])
// H5 has uniform sector size of 8KB, max is 2MB
enum {
SECTOR_COUNT = (2*1024*1024) / FLASH_SECTOR_SIZE
};

static uint8_t erased_sectors[SECTOR_COUNT] = { 0 };
static uint8_t erased_sectors[SECTOR_COUNT];

//--------------------------------------------------------------------+
// Internal Helper
//--------------------------------------------------------------------+

static inline uint32_t flash_sector_size(uint32_t sector)
{
return sector_size[sector];
}

static bool is_blank(uint32_t addr, uint32_t size)
{
for ( uint32_t i = 0; i < size; i += sizeof(uint32_t) )
{
if ( *(uint32_t*) (addr + i) != 0xffffffff )
{
static bool is_blank(uint32_t addr, uint32_t size) {
for (uint32_t i = 0; i < size; i += sizeof(uint32_t)) {
if (*(uint32_t*)(addr + i) != 0xffffffff) {
return false;
}
}
return true;
}

static uint32_t flash_get_bank(uint32_t addr)
{
uint32_t bank = 0;

if (READ_BIT(FLASH->OPTSR_CUR, FLASH_OPTSR_SWAP_BANK) == 0)
{
/* No Bank swap */
if (addr < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_1;
}
else
{
bank = FLASH_BANK_2;
}
}
else
{
/* Bank swap */
if (addr < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_2;
}
else
{
bank = FLASH_BANK_1;
}
}

return bank;
}
static bool flash_erase(uint32_t addr) {
TUF2_ASSERT(addr < FLASH_BASE_ADDR + BOARD_FLASH_SIZE);

static uint32_t flash_get_sector(uint32_t addr)
{
uint32_t sector = 0;
const uint32_t sector_addr = addr & ~(FLASH_SECTOR_SIZE - 1);
const uint32_t sector_id = (sector_addr - FLASH_BASE_ADDR) / FLASH_SECTOR_SIZE;

if((addr >= FLASH_BASE) && (addr < FLASH_BASE + FLASH_BANK_SIZE))
{
sector = (addr & ~FLASH_BASE) / FLASH_SECTOR_SIZE;
}
else if ((addr >= FLASH_BASE + FLASH_BANK_SIZE) && (addr < FLASH_BASE + FLASH_SIZE))
{
sector = ((addr & ~FLASH_BASE) - FLASH_BANK_SIZE) / FLASH_SECTOR_SIZE;
}
else
{
sector = 0xFFFFFFFF; /* Address out of range */
}
const uint8_t erased = erased_sectors[sector_id];
erased_sectors[sector_id] = 1; // mark as erased

return sector;
}
#ifndef TINYUF2_SELF_UPDATE
// skip erasing bootloader
TUF2_ASSERT(sector_addr >= BOARD_FLASH_APP_START);
#endif

static bool flash_erase(uint32_t addr)
{
// starting address from 0x08000000
uint32_t sector_addr = FLASH_BASE_ADDR;
bool erased = false;

uint32_t sector = 0;
uint32_t size = 0;
uint32_t bank;
uint32_t sector_to_erase;
uint32_t sector_error = 0;
FLASH_EraseInitTypeDef erase_struct;

for ( uint32_t i = 0; i < SECTOR_COUNT; i++ )
{
TUF2_ASSERT(sector_addr < FLASH_BASE_ADDR + BOARD_FLASH_SIZE);
if ( !erased && !is_blank(sector_addr, FLASH_SECTOR_SIZE) ) {
uint32_t bank;
uint32_t sector_to_erase;
const uint32_t sector_per_bank = FLASH_BANK_SIZE / FLASH_SECTOR_SIZE;

size = flash_sector_size(i);
if ( sector_addr + size > addr )
{
sector = i;
erased = erased_sectors[i];
erased_sectors[i] = 1; // don't erase anymore - we will continue writing here!
break;
if (sector_id < sector_per_bank) {
sector_to_erase = sector_id;
bank = FLASH_BANK_1;
} else {
sector_to_erase = sector_id - sector_per_bank;
bank = FLASH_BANK_2;
}
sector_addr += size;
}

#ifndef TINYUF2_SELF_UPDATE
// skip erasing sector0 if not self-update
TUF2_ASSERT(sector);
#endif

if ( !erased && !is_blank(sector_addr, size) )
{
bank = flash_get_bank(sector_addr);
sector_to_erase = flash_get_sector(sector_addr);
TUF2_LOG1("Erase: %08lX size = %lu KB, bank = %lu ... ", sector_addr, size / 1024, bank);
// bank swap
if (READ_BIT(FLASH->OPTSR_CUR, FLASH_OPTSR_SWAP_BANK)) {
bank = FLASH_BANK_BOTH - bank;
}

erase_struct.TypeErase = FLASH_TYPEERASE_SECTORS;
erase_struct.Banks = bank;
erase_struct.Sector = sector_to_erase;
erase_struct.NbSectors = 1;
FLASH_EraseInitTypeDef erase_struct= {
.TypeErase = FLASH_TYPEERASE_SECTORS,
.Banks = bank,
.Sector = sector_to_erase,
.NbSectors = 1
};

// FLASH_Erase_Sector(sector, bank);
// FLASH_WaitForLastOperation(HAL_MAX_DELAY);

HAL_FLASHEx_Erase(&erase_struct, &sector_error);
uint32_t sector_error;
TUF2_LOG1("Erase: %08lX size = %lu KB, bank = %lu ... ", sector_addr, FLASH_SECTOR_SIZE / 1024, bank);
TUF2_ASSERT(HAL_OK ==HAL_FLASHEx_Erase(&erase_struct, &sector_error));
(void) sector_error;

TUF2_LOG1("OK\r\n");
TUF2_ASSERT( is_blank(sector_addr, size) );
TUF2_ASSERT( is_blank(sector_addr, FLASH_SECTOR_SIZE) );
}

return true;
}

static void flash_write(uint32_t dst, const uint8_t *src, int len)
{
static void flash_write(uint32_t dst, const uint8_t* src, int len) {
flash_erase(dst);

TUF2_LOG1("Write flash at address %08lX\r\n", dst);
for ( int i = 0; i < len; i += 16 )
{
if ( HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, dst + i, (uint32_t) src + i) != HAL_OK )
{
for (int i = 0; i < len; i += 16) {
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, dst + i, (uint32_t)src + i) != HAL_OK) {
TUF2_LOG1("Failed to write flash at address %08lX\r\n", dst + i);
break;
}
}

// verify contents
if ( memcmp((void*) dst, src, len) != 0 )
{
if (memcmp((void*)dst, src, len) != 0) {
TUF2_LOG1("Failed to write\r\n");
}
}

//--------------------------------------------------------------------+
// Board API
//--------------------------------------------------------------------+
void board_flash_init(void)
{
HAL_FLASH_Unlock();
void board_flash_init(void) {
memset(erased_sectors, 0, sizeof(erased_sectors));
}

uint32_t board_flash_size(void)
{
uint32_t board_flash_size(void) {
return BOARD_FLASH_SIZE;
}

void board_flash_read(uint32_t addr, void* buffer, uint32_t len)
{
memcpy(buffer, (void*) addr, len);
void board_flash_read(uint32_t addr, void* buffer, uint32_t len) {
memcpy(buffer, (void*)addr, len);
}

void board_flash_flush(void)
{
void board_flash_flush(void) {
}

// TODO not working quite yet
bool board_flash_write(uint32_t addr, void const* data, uint32_t len)
{
// TODO skip matching contents
bool board_flash_write(uint32_t addr, void const* data, uint32_t len) {
// TODO skip matching contents need to compare a whole sector
HAL_FLASH_Unlock();
flash_write(addr, data, len);
HAL_FLASH_Lock();

return true;
}

void board_flash_erase_app(void)
{
// TODO implement later
void board_flash_erase_app(void) {
// erase 1st sector of app region is enough to invalid the app
flash_erase(BOARD_FLASH_APP_START);
}

bool board_flash_protect_bootloader(bool protect)
{
bool board_flash_protect_bootloader(bool protect) {
bool ret = true;

HAL_FLASH_OB_Unlock();
Expand All @@ -265,24 +170,21 @@ bool board_flash_protect_bootloader(bool protect)
HAL_FLASHEx_OBGetConfig(&ob_current);

// Flash sectors are protected if the bit is cleared
bool const already_protected = (ob_current.WRPSector & BOOTLOADER_SECTOR_MASK) == 0;
bool const already_protected = (ob_current.WRPSector & BOARD_FLASH_PROTECT_MASK) == 0;

TUF2_LOG1("Protection: current = %u, request = %u\r\n", already_protected, protect);

// request and current state mismatched --> require ob program
if (protect != already_protected)
{
FLASH_OBProgramInitTypeDef ob_update = {0};
if (protect != already_protected) {
FLASH_OBProgramInitTypeDef ob_update = { 0 };
ob_update.OptionType = OPTIONBYTE_WRP;
ob_update.Banks = FLASH_BANK_1;
ob_update.WRPSector = BOOTLOADER_SECTOR_MASK;
ob_update.WRPState = protect ? OB_WRPSTATE_ENABLE : OB_WRPSTATE_DISABLE;
ob_update.Banks = FLASH_BANK_1;
ob_update.WRPSector = BOARD_FLASH_PROTECT_MASK;
ob_update.WRPState = protect ? OB_WRPSTATE_ENABLE : OB_WRPSTATE_DISABLE;

if (HAL_FLASHEx_OBProgram(&ob_update) == HAL_OK)
{
if (HAL_FLASHEx_OBProgram(&ob_update) == HAL_OK) {
HAL_FLASH_OB_Launch();
}else
{
} else {
ret = false;
}
}
Expand Down
Loading

0 comments on commit f7a2093

Please sign in to comment.