Skip to content

Vanderhell/loxboot

Repository files navigation

loxboot — Bootloader Core

Version License: MIT C99 Tests No heap Platforms Status

Minimal, adapter-based bootloader core for bare-metal MCUs. Host-tested reference implementation with platform adapters for STM32, ESP32, and others.

Local verification in this workspace:

  • 15/15 CTest binaries passing
  • GitHub Actions: NOT RUN / unavailable locally
  • ESP32-S3 hardware verification: NOT VERIFIED locally

Status: Host-Core-Clean, Platform Hardening Required

⚠️ NOT PRODUCTION READY. This is a bootloader core suitable for:

  • Reference implementation and education
  • Foundation for vendor-specific platform adaptations
  • Development and testing of boot firmware infrastructure

Host core (port-agnostic) is verified locally: 15/15 CTest binaries passing.

Platform adapters (STM32, ESP32) require hardening:

  • Flash erase granularity model (sector vs. byte erase)
  • UART slot erase before firmware write
  • Firmware CRC verify via flash adapter (not direct memory)
  • Power-loss and corruption recovery validation
  • Hardware jump/reboot mechanism verification

Jump mechanism requires platform-specific code:

  • ARM Cortex-M: Implementation present, needs hardware validation
  • Xtensa/RISC-V: Architecture defined, code not yet implemented

Overview

loxboot is a C99, zero-heap bootloader core that provides:

  • Boot state management: Dual-copy read/write with CRC32 corruption recovery
  • Slot control: Firmware A/B with metadata (commit, invalidate, request, confirm)
  • Boot sequence: Full 8-step startup with crash loop detection and automatic rollback
  • UART transport: In-field firmware updates via frame protocol (v0.4.0+)
  • Hardware adapters: STM32 internal flash (v0.5.0) and ESP32 esp_partition (v0.6.0)

All hardware access is injected via adapter function pointers — no vendor-specific code in core.


Architecture

Core (src/)

  • loxboot_core.c — loxboot_run(), slot control, state management
  • loxboot_state.c — State read/write/validate with dual-copy recovery
  • loxboot_crc32.c — standard CRC32/IEEE implementation (polynomial 0xEDB88320)

Adapters (adapters/)

  • adapters/stm32/loxboot_flash_stm32.c — STM32 HAL flash driver
  • adapters/esp32/loxboot_flash_esp32.c — ESP32 esp_partition driver

Transport (ports/)

  • ports/uart/loxboot_uart.c — UART frame protocol (CRC16-CCITT, SOF | CMD | LEN | PAYLOAD | CRC16)

Headers (include/loxboot/)

  • loxboot.h — Public API (boot state, slot control, error codes)
  • loxboot_transport.h — Transport adapter interface
  • loxboot_version.h — Version constants

Quick Start

#include "loxboot/loxboot.h"

/* 1. Initialize adapters */
loxboot_t ctx = {0};

ctx.flash.read  = my_flash_read;
ctx.flash.write = my_flash_write;
ctx.flash.erase = my_flash_erase;
ctx.clock.now_ms = my_clock_now_ms;
ctx.hal.on_fatal = my_fatal;

/* 2. Set platform addresses */
ctx.platform.boot_state_primary_base = 0x08004000;
ctx.platform.boot_state_backup_base  = 0x08008000;
ctx.platform.slot_a_base             = 0x08020000;
ctx.platform.slot_b_base             = 0x08060000;
ctx.platform.slot_size               = 0x00040000;

/* 3. Initialize state */
if (loxboot_init(&ctx) != LOXBOOT_OK) {
    ctx.hal.on_fatal(&ctx, LOXBOOT_ERR_INVALID_STATE);
}

/* 4. Run bootloader (never returns on success) */
loxboot_run(&ctx);

In the application, after startup validation:

loxboot_confirm_boot(&ctx);  /* Resets crash counter */

Feature Matrix

Feature v0.1.0 v0.2.0 v0.3.0 v0.4.0 v0.5.0 v0.6.0
Public API + spec
CRC32, init, slot control spec
Boot sequence + rollback + crash detection spec
UART transport (CRC16, frame protocol) spec
STM32 flash adapter (HAL-based)
ESP32 flash adapter (esp_partition)

Build

Configure

cmake -S . -B build

Full local test profile:

cmake -S . -B build -DLOXBOOT_BUILD_UART_PORT=ON

Optional flags:

-DLOXBOOT_BUILD_UART_PORT=ON          # Include UART transport
-DLOXBOOT_BUILD_STM32_ADAPTER=ON      # Include STM32 flash adapter
-DLOXBOOT_BUILD_ESP32_ADAPTER=ON      # Include ESP32 flash adapter
-DLOXBOOT_MAX_BOOT_ATTEMPTS=3         # Rollback threshold (default: 3)
-DLOXBOOT_UART_LISTEN_MS=3000         # UART listen window ms (default: 3000)

Build & Test

cmake --build build
ctest --test-dir build -C Debug --output-on-failure

Compiler Requirements

  • C99 standard
  • No heap (no malloc, calloc, realloc, free)
  • No external dependencies (only stdint.h, stddef.h, stdbool.h, string.h)
  • Zero warnings: -Wall -Wextra -Wpedantic -Werror (GCC/Clang) or /W4 /WX (MSVC)

Documentation

Document Purpose
docs/SPEC.md Full technical specification (all versions)
docs/PORTING.md How to write a flash or transport adapter
docs/MEMORY_LAYOUT.md Flash and RAM layout reference
docs/INTEGRATION.md Ecosystem integration (loxruntime, panicdump, nvlog)

Test Coverage

Local test coverage: 15/15 CTest binaries passing in this workspace with -DLOXBOOT_BUILD_UART_PORT=ON.

  • Boot sequence
  • State management
  • UART frame
  • UART session
  • Slot operations
  • Init/CRC/rollback
  • ESP32 platform stub tests
  • E2E simulator test

GitHub Actions: NOT RUN / unavailable locally. Hardware adapters (STM32, ESP32): not hardware verified locally.


API Reference

Boot Sequence

loxboot_err_t loxboot_init(loxboot_t *ctx);
loxboot_err_t loxboot_run(loxboot_t *ctx);  /* Never returns on success */

Slot Control

loxboot_err_t loxboot_commit_slot(loxboot_t *ctx, loxboot_slot_id_t slot, uint32_t firmware_size, uint32_t firmware_crc32);
loxboot_err_t loxboot_invalidate_slot(loxboot_t *ctx, loxboot_slot_id_t slot);
loxboot_err_t loxboot_request_slot(loxboot_t *ctx, loxboot_slot_id_t slot);
loxboot_err_t loxboot_confirm_boot(loxboot_t *ctx);

State Access

loxboot_err_t loxboot_state_read(loxboot_t *ctx, loxboot_state_t *out_state);
loxboot_err_t loxboot_get_slot_state(loxboot_t *ctx, loxboot_slot_id_t slot, loxboot_slot_state_t *out_state);
loxboot_boot_reason_t loxboot_get_boot_reason(const loxboot_t *ctx);

Error Codes

LOXBOOT_OK                  = 0
LOXBOOT_ERR_INVALID_ARG     = 1
LOXBOOT_ERR_FLASH_READ      = 2
LOXBOOT_ERR_FLASH_WRITE     = 3
LOXBOOT_ERR_FLASH_ERASE     = 4
LOXBOOT_ERR_CRC_MISMATCH    = 5
LOXBOOT_ERR_NO_VALID_SLOT   = 6
LOXBOOT_ERR_TIMEOUT         = 7
LOXBOOT_ERR_TRANSPORT       = 8
LOXBOOT_ERR_INVALID_STATE   = 9
LOXBOOT_ERR_RECORD_CORRUPT  = 10

Configuration

Boot State Region

Minimum 2 copies of loxboot_state_t (typically ~60 bytes each):

boot_state_primary_base  = 0x08004000
boot_state_backup_base   = 0x08008000

On flash with large sector sizes, allocate one sector per copy.

Firmware Slots

slot_a_base = 0x08020000  (Slot A)
slot_b_base = 0x08060000  (Slot B)
slot_size   = 0x00040000  (256 KB each)

Minimum 4 KB per slot (practical minimum: 32 KB for typical firmware).

Boot Attempts Threshold

Default: LOXBOOT_MAX_BOOT_ATTEMPTS = 3

If firmware fails to call loxboot_confirm_boot() within 3 boots, automatic rollback triggers.

UART Listen Window

Default: LOXBOOT_UART_LISTEN_MS = 3000 (3 seconds)

After this timeout with no UART activity, boot proceeds normally.


Constraints

  • C99 only — no C11+ features (no atomics, no threads)
  • Zero heap — all data structures are stack-allocated or static
  • No external dependencies — bootloader is self-contained
  • Adapter injection — all hardware access via function pointers
  • Deterministic — no floating-point, no randomness (except UART timing)
  • Synchronous — all operations block until complete (no async model)

License

MIT

About

Minimal, zero-heap C99 bootloader core for bare-metal MCUs - A/B slots, CRC32 recovery, crash-loop rollback, and UART firmware updates, with adapters for STM32 and ESP32-S3.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors