mothercup/Boot/src/main.c

109 lines
2.9 KiB
C

/**
* @file main.c
* @brief CAIIC minimal bootloader: bootsetting arbitration, image CRC32
* check, vector remap and jump to the active application bank.
*
* No interrupts, no peripherals: flash is read through the memory map only.
* If nothing valid is found 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 Check a bank image against its bootsetting CRC32 record.
*/
static int bank_crc_ok(const caiic_bank_t* bank, uint32_t base)
{
if (bank->size == 0 || bank->size > CAIIC_APP_BANK_SIZE)
{
return 0;
}
return bank->crc32 == caiic_crc32((const uint8_t*)base, 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 = 0;
if (bs->magic == CAIIC_BOOT_MAGIC &&
bs->crc32 == caiic_crc32((const uint8_t*)bs, offsetof(caiic_bootsetting_t, crc32)))
{
/* Bootsetting valid: jump to the active bank if its image checks out */
if (bs->active_bank == CAIIC_ACTIVE_BANK1 && bank_crc_ok(&bs->bank1, CAIIC_APP1_BASE))
{
target = CAIIC_APP1_BASE;
}
else if (bs->active_bank == CAIIC_ACTIVE_BANK2 && bank_crc_ok(&bs->bank2, CAIIC_APP2_BASE))
{
target = CAIIC_APP2_BASE;
}
/* Active bank corrupted: fall back to any bank with a valid image */
else if (bank_crc_ok(&bs->bank1, CAIIC_APP1_BASE))
{
target = CAIIC_APP1_BASE;
}
else if (bank_crc_ok(&bs->bank2, CAIIC_APP2_BASE))
{
target = CAIIC_APP2_BASE;
}
}
else
{
/* Blank/invalid bootsetting (first flash): vector sanity check only */
if (bank_vector_ok(CAIIC_APP1_BASE))
{
target = CAIIC_APP1_BASE;
}
else if (bank_vector_ok(CAIIC_APP2_BASE))
{
target = CAIIC_APP2_BASE;
}
}
if (target != 0)
{
jump_to_app(target);
}
for (;;)
{
}
}