Files
gps/soc/software/bootloader/main.c
T
2026-07-12 11:01:51 +03:00

126 lines
2.9 KiB
C

#include <stdint.h>
#include <stddef.h>
#include "bsp/soc.h"
#include "bsp/spi_flash.h"
#include "bsp/uart.h"
#ifndef APP_FLASH_OFFSET
#define APP_FLASH_OFFSET 0x06000000UL
#endif
#define BOOT_IMAGE_MAGIC 0x54425652u
#define BOOT_IMAGE_VERSION 1u
#define BOOT_HEADER_SIZE 64u
struct boot_image_header {
uint32_t magic;
uint32_t version;
uint32_t header_size;
uint32_t flags;
uint32_t payload_flash_offset;
uint32_t load_addr;
uint32_t entry;
uint32_t size;
uint32_t crc32;
uint32_t reserved[7];
};
static void uart_puts(const char *s)
{
while (*s != '\0') {
bsp_uart_putc(*s++);
}
}
static void uart_puthex32(uint32_t value)
{
static const char hex[] = "0123456789abcdef";
for (int shift = 28; shift >= 0; shift -= 4) {
bsp_uart_putc(hex[(value >> shift) & 0xfU]);
}
}
static uint32_t crc32_update(uint32_t crc, const uint8_t *data, uint32_t len)
{
crc = ~crc;
for (uint32_t i = 0; i < len; ++i) {
crc ^= data[i];
for (uint32_t bit = 0; bit < 8; ++bit) {
uint32_t mask = 0U - (crc & 1U);
crc = (crc >> 1) ^ (0xedb88320U & mask);
}
}
return ~crc;
}
static void die(const char *message, uint32_t value)
{
uart_puts("BOOT ERROR: ");
uart_puts(message);
uart_puts(" 0x");
uart_puthex32(value);
uart_puts("\n");
while (1) {
asm volatile ("wfi");
}
}
int main(void)
{
struct boot_image_header header;
uart_puts("\nRocket flash bootloader\n");
uart_puts("Header offset: 0x");
uart_puthex32((uint32_t)APP_FLASH_OFFSET);
uart_puts("\n");
bsp_spi_flash_init();
bsp_spi_flash_reset();
uint32_t flash_id = bsp_spi_flash_read_id();
uart_puts("Flash JEDEC ID: 0x");
uart_puthex32(flash_id);
uart_puts("\n");
bsp_spi_flash_read((uint32_t)APP_FLASH_OFFSET, &header, sizeof(header));
if (header.magic != BOOT_IMAGE_MAGIC) {
die("bad image magic", header.magic);
}
if (header.version != BOOT_IMAGE_VERSION || header.header_size != BOOT_HEADER_SIZE) {
die("bad image version/header", header.version);
}
if (header.size == 0U || header.size > 0x000f0000U) {
die("bad image size", header.size);
}
if (header.load_addr < BSP_DTIM_BASE || (header.load_addr + header.size) > (BSP_DTIM_BASE + BSP_DTIM_SIZE)) {
die("image outside DTIM", header.load_addr);
}
uart_puts("Load: flash 0x");
uart_puthex32(header.payload_flash_offset);
uart_puts(" -> mem 0x");
uart_puthex32(header.load_addr);
uart_puts(", size 0x");
uart_puthex32(header.size);
uart_puts("\n");
bsp_spi_flash_read(header.payload_flash_offset, (void *)(uintptr_t)header.load_addr, header.size);
uint32_t crc = crc32_update(0U, (const uint8_t *)(uintptr_t)header.load_addr, header.size);
if (crc != header.crc32) {
die("crc mismatch", crc);
}
uart_puts("CRC ok, jumping 0x");
uart_puthex32(header.entry);
uart_puts("\n");
asm volatile ("fence.i" ::: "memory");
void (*entry)(void) = (void (*)(void))(uintptr_t)header.entry;
entry();
return 0;
}