mothercup/Boot/src/main.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 (;;)
{
}
}