Skip to content

Commit

Permalink
feat(radio): improved UF2 & DFU bootloader
Browse files Browse the repository at this point in the history
  • Loading branch information
raphaelcoeffic committed Jan 17, 2025
1 parent 15ad5a2 commit 851a978
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 67 deletions.
81 changes: 56 additions & 25 deletions radio/src/drivers/uf2_ghostfat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,35 @@ static FAT_BootBlock const BootBlock = {
.FilesystemIdentifier = {'F','A','T','1','6',' ',' ',' '},
};

static uf2_fat_write_state_t _uf2_write_state;

void uf2_fat_reset_state()
{
memset(&_uf2_write_state, 0, sizeof(_uf2_write_state));
}

const uf2_fat_write_state_t* uf2_fat_get_state()
{
return &_uf2_write_state;
}

static inline bool is_firmware_length_valid(uint32_t len)
{
return len && len <= UF2_MAX_FW_SIZE;
}

static inline bool is_address_in_firmware(uintptr_t addr)
{
return (addr & FIRMWARE_ADDRESS) == FIRMWARE_ADDRESS;
}

static inline bool is_firmware_valid(firmware_description_t const* fw_desc)
{
return fw_desc && is_firmware_length_valid(fw_desc->length) &&
is_address_in_firmware(fw_desc->version_ptr) &&
is_address_in_firmware((uintptr_t)fw_desc->reset_handler);
}

// get current.uf2 flash size in bytes, round up to 256 bytes
static uint32_t current_flash_size(void)
{
Expand All @@ -227,11 +256,11 @@ static uint32_t current_flash_size(void)
firmware_description_t const *fw_desc =
(firmware_description_t const *)FIRMWARE_ADDRESS;

if (fw_desc && fw_desc->length) {
// round up to 256 bytes
result = (fw_desc->length + BOOTLOADER_SIZE + 255U) & (~255U);
if (is_firmware_valid(fw_desc)) {
// round up to 256 bytes
result = (fw_desc->length + BOOTLOADER_SIZE + 255U) & (~255U);
} else {
result = UF2_MAX_FW_SIZE;
result = UF2_MAX_FW_SIZE;
}
flash_sz = result; // presumes atomic 32-bit read/write and static result
}
Expand Down Expand Up @@ -329,7 +358,7 @@ void uf2_fat_read_block(uint32_t block_no, uint8_t *data)

uint32_t addr = 0;
if (sectionIdx >= UF2_MAX_FW_SIZE / 256) return;

UF2_Block *bl = (UF2_Block *)data;
bl->magicStart0 = UF2_MAGIC_START0;
bl->magicStart1 = UF2_MAGIC_START1;
Expand Down Expand Up @@ -369,8 +398,9 @@ void uf2_fat_read_block(uint32_t block_no, uint8_t *data)
* -1 : if not an uf2 block
* 512 : write is successful
*/
int uf2_fat_write_block(uint32_t block_no, uint8_t *data, uf2_fat_write_state_t *state)
int uf2_fat_write_block(uint32_t block_no, uint8_t *data)
{
uf2_fat_write_state_t *wr_st = &_uf2_write_state;
UF2_Block *bl = (UF2_Block *)data;
// TRACE("Write magic: %x", bl->magicStart0);

Expand All @@ -394,12 +424,12 @@ int uf2_fat_write_block(uint32_t block_no, uint8_t *data, uf2_fat_write_state_t
uint32_t wr_block = bl->blockNo;
if (wr_block >= BOOTLOADER_SIZE / 256) wr_block--;

uint32_t sector = wr_block / (UF2_ERASE_BLOCK_SIZE / 256);
uint32_t mask = 1 << (sector & 0x1F);
uint32_t pos = sector >> 5;
uint32_t erase_sector = wr_block / (UF2_ERASE_BLOCK_SIZE / 256);
uint32_t mask = 1 << (erase_sector & 0x1F);
uint32_t pos = erase_sector >> 5;

uint32_t addr = bl->targetAddr;
if (state && !(state->erased_mask[pos] & mask)) {
if (wr_st && !(wr_st->erased_mask[pos] & mask)) {
TRACE_DEBUG("[UF2] erase 0x%08x\n", bl->targetAddr);

auto drv = flashFindDriver(addr);
Expand All @@ -409,14 +439,15 @@ int uf2_fat_write_block(uint32_t block_no, uint8_t *data, uf2_fat_write_state_t
// mark additional erased sectors
uint32_t sector = drv->get_sector(addr);
uint32_t sect_len = drv->get_sector_size(sector);
uint32_t erased_sectors =
sect_len / (UF2_ERASE_BLOCK_SIZE / 256);
uint32_t media_len = flashGetSize(addr);
if (media_len < sect_len) sect_len = media_len;
uint32_t erased_sectors = sect_len / UF2_ERASE_BLOCK_SIZE;

while (erased_sectors-- != 0) {
pos = sector >> 5;
mask = 1 << (sector & 0x1F);
state->erased_mask[pos] |= mask;
sector++;
pos = erase_sector >> 5;
mask = 1 << (erase_sector & 0x1F);
wr_st->erased_mask[pos] |= mask;
erase_sector++;
}
}
}
Expand All @@ -431,24 +462,24 @@ int uf2_fat_write_block(uint32_t block_no, uint8_t *data, uf2_fat_write_state_t
}
}

if (state && bl->numBlocks) {
if (state->num_blocks != bl->numBlocks) {
if (bl->numBlocks >= UF2_MAX_BLOCKS || state->num_blocks) {
state->num_blocks = 0xffffffff;
if (wr_st && bl->numBlocks) {
if (wr_st->num_blocks != bl->numBlocks) {
if (bl->numBlocks >= UF2_MAX_BLOCKS || wr_st->num_blocks) {
wr_st->num_blocks = UF2_INVALID_NUM_BLOCKS;
} else {
state->num_blocks = bl->numBlocks;
wr_st->num_blocks = bl->numBlocks;
}
}
if (bl->blockNo < UF2_MAX_BLOCKS) {
uint32_t mask = 1 << (bl->blockNo & 0x1F);
uint32_t pos = bl->blockNo >> 5;
if (!(state->written_mask[pos] & mask)) {
state->written_mask[pos] |= mask;
state->num_written++;
if (!(wr_st->written_mask[pos] & mask)) {
wr_st->written_mask[pos] |= mask;
wr_st->num_written++;
TRACE_DEBUG("[UF2] wr #%d (%d / %d)\n", bl->blockNo,
state->num_written, bl->numBlocks);
}
if (state->num_written >= state->num_blocks) {
if (wr_st->num_written >= wr_st->num_blocks) {
TRACE_DEBUG("[UF2] done: reboot\n");
}
}
Expand Down
8 changes: 6 additions & 2 deletions radio/src/drivers/uf2_ghostfat.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@
#include <stdint.h>

#define UF2_NUM_BLOCKS 32768 // at least 16MB
#define UF2_INVALID_NUM_BLOCKS 0xFFFFFFFF

#if !defined(UF2_MAX_FW_SIZE)
#define UF2_MAX_FW_SIZE (2 * 1024 * 1024)
#endif

#define UF2_MAX_BLOCKS (UF2_MAX_FW_SIZE / 256)

#define UF2_ERASE_BLOCK_SIZE (8 * 1024)
#define UF2_ERASE_BLOCK_SIZE (4 * 1024)
#define UF2_ERASE_BLOCKS (UF2_MAX_FW_SIZE / UF2_ERASE_BLOCK_SIZE)

typedef struct {
Expand All @@ -41,5 +42,8 @@ typedef struct {
uint32_t erased_mask[UF2_ERASE_BLOCKS / 32];
} uf2_fat_write_state_t;

void uf2_fat_reset_state();
const uf2_fat_write_state_t* uf2_fat_get_state();

void uf2_fat_read_block(uint32_t block_no, uint8_t *data);
int uf2_fat_write_block(uint32_t block_no, uint8_t *data, uf2_fat_write_state_t *state);
int uf2_fat_write_block(uint32_t block_no, uint8_t *data);
12 changes: 12 additions & 0 deletions radio/src/hal/flash_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,15 @@ const etx_flash_driver_t* flashFindDriver(uint32_t addr)

return nullptr;
}

uint32_t flashGetSize(uint32_t addr)
{
for (int i = 0; i < 2; i++) {
const flash_media_t& fm = _flash_media[i];
if (!fm.drv) continue;
if (fm.start_addr <= addr && fm.end_addr >= addr)
return fm.end_addr - fm.start_addr + 1;
}

return 0;
}
1 change: 1 addition & 0 deletions radio/src/hal/flash_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ void flashRegisterDriver(uint32_t start_addr, uint32_t length,
const etx_flash_driver_t* drv);

const etx_flash_driver_t* flashFindDriver(uint32_t addr);
uint32_t flashGetSize(uint32_t addr);
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set(BOOTLOADER_SRC ${BOOTLOADER_SRC}
if(FIRMWARE_FORMAT_UF2)
set(BOOTLOADER_SRC ${BOOTLOADER_SRC}
boot_uf2.cpp
boot_dfu.cpp
${RADIO_SRC_DIR}/io/uf2.cpp
${RADIO_SRC_DIR}/drivers/uf2_ghostfat.cpp
)
Expand Down
9 changes: 8 additions & 1 deletion radio/src/targets/common/arm/stm32/bootloader/boot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ void bootloaderInitApp()
}
} else {
#if defined(FIRMWARE_QSPI)
setSelectedUsbMode(USB_DFU_MODE);
abnormalRebootResetCmd();
setSelectedUsbMode(USB_DFU_MODE);
#endif
}

Expand Down Expand Up @@ -146,6 +147,12 @@ int bootloaderMain()
// init screen
bootloaderInitScreen();

#if defined(FIRMWARE_FORMAT_UF2)
if (getSelectedUsbMode() == USB_DFU_MODE) {
bootloaderDFU();
}
#endif

#if defined(PWR_BUTTON_PRESS)
// wait until power button is released
while (pwrPressed()) {}
Expand Down
5 changes: 5 additions & 0 deletions radio/src/targets/common/arm/stm32/bootloader/boot.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ void bootloaderMenu();
// non-interactive UF2 bootloader
void bootloaderUF2();

// non-interactive DFU bootloader
void bootloaderDFU();

// Declarations of functions that need to be implemented
// for each target with a bootloader

Expand All @@ -89,5 +92,7 @@ uint32_t bootloaderGetMenuItemCount(int baseCount);
// returns true on submenu exit
bool bootloaderRadioMenu(uint32_t menuItem, event_t event);

void bootloaderDrawDFUScreen();

void sdInit();
void blExit();
26 changes: 26 additions & 0 deletions radio/src/targets/common/arm/stm32/bootloader/boot_dfu.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "stm32_hal.h"

#include "boot.h"
#include "hal/usb_driver.h"
#include "lcd.h"

extern volatile uint8_t tenms;

void bootloaderDFU()
{
usbPlugged();
usbStart();

bootloaderDrawDFUScreen();

for (;;) {
if (tenms) {
if (!usbPlugged()) break;
bootloaderDrawDFUScreen();
lcdRefresh();
}
}

blExit();
NVIC_SystemReset();
}
39 changes: 31 additions & 8 deletions radio/src/targets/common/arm/stm32/bootloader/boot_uf2.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
#include "boot.h"

#include "hal/usb_driver.h"
#include "hal/storage.h"
#include "hal/fatfs_diskio.h"

#include "thirdparty/FatFs/diskio.h"
#include "drivers/uf2_ghostfat.h"

#include "board.h"
#include "lcd.h"

extern uf2_fat_write_state_t _uf2_write_state;

volatile tmr10ms_t g_tmr10ms;
volatile uint8_t tenms = 1;

Expand All @@ -23,9 +27,7 @@ void bootloaderUF2()
{
BootloaderState state = ST_START;

// TODO: register UF2 drive
// fatfsRegisterDriver(drv, 0);

// register SD storage
storageInit();
disk_initialize(0);

Expand All @@ -34,35 +36,56 @@ void bootloaderUF2()
if (tenms) {
tenms = 0;

if (state != ST_USB && state != ST_FLASHING
&& state != ST_FLASH_DONE && state != ST_RADIO_MENU) {
if (state != ST_USB && state != ST_FLASHING && state != ST_FLASH_DONE) {
if (usbPlugged()) {
state = ST_USB;
#if !defined(SIMU)
usbStart();
#endif
} else if (pwrOffPressed()) {
storageDeInit();
boardOff();
}
}

if (state == ST_USB) {
if (state == ST_USB || state == ST_FLASH_DONE) {
if (usbPlugged() == 0) {
#if !defined(SIMU)
usbStop();
#endif
state = ST_START;
state = (state == ST_FLASH_DONE) ? ST_REBOOT : ST_START;
} else {
auto wr_st = uf2_fat_get_state();
if (wr_st->num_blocks != 0 && wr_st->num_blocks <= UF2_MAX_BLOCKS) {
state = ST_FLASHING;
}
}
bootloaderDrawScreen(state, 0);
}

if (state == ST_START) {
bootloaderDrawScreen(state, 0);
} else if (state == ST_FLASHING) {
auto wr_st = uf2_fat_get_state();
if (wr_st->num_blocks == 0 || wr_st->num_blocks > UF2_MAX_BLOCKS) {
state = ST_USB;
} else {
uint32_t progress = (wr_st->num_written * 100) / wr_st->num_blocks;
if (wr_st->num_written == wr_st->num_blocks) {
state = ST_FLASH_DONE;
uf2_fat_reset_state();
}
bootloaderDrawScreen(state, progress);
}
} else if (state == ST_FLASH_DONE) {
bootloaderDrawScreen(state, 100);
}

lcdRefresh();
}


if (state == ST_REBOOT) {
storageDeInit();
#if !defined(SIMU)
blExit();
NVIC_SystemReset();
Expand Down
5 changes: 4 additions & 1 deletion radio/src/targets/common/arm/stm32/h7/system_stm32h7xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@
* @param None
* @retval None
*/
void SystemInit (void)

#define BOOTSTRAP __attribute__((section(".bootstrap")))

BOOTSTRAP void SystemInit (void)
{
#if defined (DATA_IN_D2_SRAM)
__IO uint32_t tmpreg;
Expand Down
6 changes: 2 additions & 4 deletions radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@

#if USE_UF2_DRIVE
#include "drivers/uf2_ghostfat.h"
uf2_fat_write_state_t _uf2_write_state;
#endif

enum MassstorageLuns {
Expand Down Expand Up @@ -134,7 +133,7 @@ int8_t STORAGE_Init(uint8_t lun)
{
#if USE_UF2_DRIVE
if (lun == STORAGE_UF2_LUN) {
memset(&_uf2_write_state, 0, sizeof(_uf2_write_state));
uf2_fat_reset_state();
return USBD_OK;
}
#endif
Expand Down Expand Up @@ -263,8 +262,7 @@ int8_t STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_
#if USE_UF2_DRIVE
if (lun == STORAGE_UF2_LUN) {
int wr_ret;
while ((blk_len--) && (wr_ret = uf2_fat_write_block(
blk_addr, buf, &_uf2_write_state)) > 0) {
while ((blk_len--) && (wr_ret = uf2_fat_write_block(blk_addr, buf)) > 0) {
blk_addr += 512;
buf += 512;
}
Expand Down
Loading

0 comments on commit 851a978

Please sign in to comment.