110 lines
4.3 KiB
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);
|
|
}
|