80 lines
2.3 KiB
C
80 lines
2.3 KiB
C
/**
|
|
* @file main.c
|
|
* @brief CAIIC minimal bootloader: bootsetting arbitration, vector sanity
|
|
* check, vector remap and jump to the active application bank.
|
|
*
|
|
* No interrupts, no peripherals: flash is read through the memory map only.
|
|
*
|
|
* Policy: the application image CRC is verified during the OTA process
|
|
* (app_ota.c) BEFORE bootsetting is switched - boot itself never validates
|
|
* image contents, it only trusts the bootsetting sector integrity
|
|
* (magic + own CRC32) to pick the active bank, then jumps straight to it.
|
|
* If the chosen vector table looks dead the CPU stays here forever
|
|
* (recover via SWD).
|
|
*/
|
|
#include <stddef.h>
|
|
#include "n32wb03x.h"
|
|
|
|
#include "dfu_layout.h"
|
|
#include "boot_crc32.h"
|
|
|
|
/**
|
|
* @brief Sanity check of an app vector table at @p base.
|
|
* @return 1 if MSP points into SRAM and the reset vector into the bank.
|
|
*/
|
|
static int bank_vector_ok(uint32_t base)
|
|
{
|
|
uint32_t msp = *(volatile uint32_t*)base;
|
|
uint32_t reset = *(volatile uint32_t*)(base + 4) & ~1u;
|
|
|
|
return ((msp & 0xFFFF0000u) == 0x20000000u) &&
|
|
(reset >= base) && (reset < base + CAIIC_APP_BANK_SIZE);
|
|
}
|
|
|
|
/**
|
|
* @brief Remap the vector table to the app and jump to it. Never returns.
|
|
*/
|
|
static void jump_to_app(uint32_t base)
|
|
{
|
|
typedef void (*app_entry_t)(void);
|
|
|
|
__disable_irq();
|
|
PWR->VTOR_REG = CAIIC_VTOR_EN | base; /* Cortex-M0 has no SCB->VTOR */
|
|
__set_MSP(*(volatile uint32_t*)base);
|
|
((app_entry_t)(*(volatile uint32_t*)(base + 4)))();
|
|
|
|
for (;;)
|
|
{
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Main program.
|
|
*/
|
|
int main(void)
|
|
{
|
|
const caiic_bootsetting_t* bs = (const caiic_bootsetting_t*)CAIIC_BOOTSETTING_ADDR;
|
|
uint32_t target = CAIIC_APP1_BASE; /* default bank */
|
|
|
|
/* Pick the active bank. Only the bootsetting sector integrity is
|
|
* checked (magic + its own CRC32); the app image itself is NOT
|
|
* verified here - it was already verified at OTA time before this
|
|
* record was written. */
|
|
if (bs->magic == CAIIC_BOOT_MAGIC &&
|
|
bs->crc32 == caiic_crc32((const uint8_t*)bs, offsetof(caiic_bootsetting_t, crc32)) &&
|
|
bs->active_bank == CAIIC_ACTIVE_BANK2)
|
|
{
|
|
target = CAIIC_APP2_BASE;
|
|
}
|
|
|
|
/* Last-resort sanity: never jump into a blank/garbage vector table */
|
|
if (bank_vector_ok(target))
|
|
{
|
|
jump_to_app(target);
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
}
|
|
}
|