Files
templates/c/set-protocol/ports/stm32g474-usb-boot/boot_flash.c

110 lines
4.3 KiB
C

#include "boot_port.h"
#include "boot_image.h"
#include "boot_writer.h"
#include "stm32g4xx_hal.h"
#include <string.h>
#define COMMIT 0x53455442UL
static g474_writer writer;
static bool geometry_valid(void)
{
__HAL_RCC_SYSCFG_CLK_ENABLE();
return g474_geometry_supported(*(const uint16_t *)FLASHSIZE_BASE,
(FLASH->OPTR & FLASH_OPTR_DBANK) != 0,
(FLASH->OPTR & FLASH_OPTR_BFB2) != 0 ||
(SYSCFG->MEMRMP & SYSCFG_MEMRMP_FB_MODE) != 0);
}
static bool erase_page(uint32_t address)
{
FLASH_EraseInitTypeDef config = {0};
uint32_t bank, page, error;
if (!g474_flash_page(address, (FLASH->OPTR & FLASH_OPTR_DBANK) != 0,
&bank, &page)) return false;
config.TypeErase = FLASH_TYPEERASE_PAGES;
config.Banks = bank == 2U ? FLASH_BANK_2 : FLASH_BANK_1;
config.Page = page; config.NbPages = 1;
return HAL_FLASHEx_Erase(&config, &error) == HAL_OK;
}
static bool invalidate(void *user)
{
bool ok; (void)user;
if (!geometry_valid() || HAL_FLASH_Unlock() != HAL_OK) return false;
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
ok = erase_page(G474_META_BASE);
(void)HAL_FLASH_Lock(); return ok;
}
static bool erase(void *user, uint32_t size)
{
uint32_t address, step;
bool ok = true; (void)user;
if (size < 8 || size > G474_APP_SIZE || !geometry_valid()) return false;
g474_writer_init(&writer, size);
if (HAL_FLASH_Unlock() != HAL_OK) return false;
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
step = (FLASH->OPTR & FLASH_OPTR_DBANK) ? 2048U : 4096U;
for (address = G474_APP_BASE; address < G474_APP_BASE + size; address += step) {
if (!erase_page(address)) { ok = false; break; }
}
(void)HAL_FLASH_Lock(); return ok;
}
static bool program_word(void *user, uint32_t offset, uint64_t word)
{
uint64_t actual; (void)user;
if ((offset & 7U) || offset > G474_APP_SIZE - 8U) return false;
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, G474_APP_BASE + offset,
word) != HAL_OK) return false;
memcpy(&actual, (const void *)(G474_APP_BASE + offset), 8);
return actual == word;
}
static bool write(void *user, uint32_t offset, const uint8_t *data, uint16_t length)
{
bool ok; (void)user;
if (HAL_FLASH_Unlock() != HAL_OK) return false;
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
ok = g474_writer_write(&writer, offset, data, length, program_word, 0);
(void)HAL_FLASH_Lock(); return ok;
}
static bool verify(void *user, uint32_t size, uint32_t crc)
{
(void)user;
return !writer.failed && !writer.used && writer.received == size &&
writer.size == size &&
g474_vectors_valid((const uint8_t *)G474_APP_BASE, size) &&
setp_crc32((const uint8_t *)G474_APP_BASE, size) == crc;
}
static bool commit(void *user, uint32_t size, uint32_t crc)
{
uint32_t record[4] = {size, crc, ~size, COMMIT};
uint64_t word; unsigned i; bool ok = true; (void)user;
if (HAL_FLASH_Unlock() != HAL_OK) return false;
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
for (i = 0; i < sizeof(record); i += 8) {
memcpy(&word, (const uint8_t *)record + i, 8);
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, G474_META_BASE + i,
word) != HAL_OK) { ok = false; break; }
}
(void)HAL_FLASH_Lock();
return ok && !memcmp((const void *)G474_META_BASE, record, sizeof(record));
}
bool g474_app_valid(void)
{
/* Same reset policy as F407: SWD images need no USB commit record. */
return geometry_valid() &&
g474_vectors_valid((const uint8_t *)G474_APP_BASE, G474_APP_SIZE);
}
static void activate(void *user) { (void)user; }
const setp_boot_ops g474_boot_ops = {invalidate, erase, write, verify, commit, activate};
__attribute__((naked,noreturn)) static void enter(uint32_t sp, uint32_t pc)
{
__asm volatile("msr msp, r0\nmovs r2, #0\nmsr control, r2\ndsb\nisb\ncpsie i\nbx r1\n");
}
void g474_jump_app(void)
{
unsigned i;
uint32_t sp = *(const uint32_t *)G474_APP_BASE;
uint32_t pc = *(const uint32_t *)(G474_APP_BASE + 4);
__disable_irq(); SysTick->CTRL = 0;
for (i = 0; i < 8; ++i) { NVIC->ICER[i] = 0xffffffff; NVIC->ICPR[i] = 0xffffffff; }
SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk | SCB_ICSR_PENDSVCLR_Msk;
SCB->VTOR = G474_APP_BASE; enter(sp, pc);
}