eBoot Developer Documentation v0.1.0
Secure A/B bootloader with CRC-protected boot control, slot management, image verification, rollback support, structured boot logging, and recovery mode. Headers: <eos_bootctl.h>, <eos_slot_manager.h>, <eos_boot_log.h>
📜 Structures & Types
Core data structures used throughout eBoot. Stored in flash, survive resets.
eos_bootctl_t
Persistent boot control block stored in a dedicated flash sector with CRC protection and dual-copy redundancy. All fields are 32-bit aligned for direct flash read/write.
magic | uint32_t | Must equal EOS_BOOTCTL_MAGIC (0x45425443). |
version | uint32_t | Format version. Current: EOS_BOOTCTL_VERSION (1). |
active_slot | uint32_t | Currently active slot. Cast to eos_slot_t: EOS_SLOT_A(0) or EOS_SLOT_B(1). |
pending_slot | uint32_t | Slot marked for test boot. EOS_SLOT_NONE(0xFF) if none. |
confirmed_slot | uint32_t | Last confirmed-good slot after app calls eos_bootctl_confirm(). |
boot_attempts | uint32_t | Consecutive boot attempts since last confirmation. |
max_attempts | uint32_t | Max allowed attempts before rollback. Default: 3. |
last_reset_reason | uint32_t | Last reset cause (eos_reset_reason_t). |
flags | uint32_t | EOS_FLAG_TEST_BOOT(0x01), RECOVERY(0x02), FACTORY_RESET(0x04), SECURE_BOOT(0x08). |
img_a_version | uint32_t | Firmware version in Slot A. |
img_b_version | uint32_t | Firmware version in Slot B. |
img_a_crc | uint32_t | CRC32 of Slot A image. |
img_b_crc | uint32_t | CRC32 of Slot B image. |
log_head | uint32_t | Ring buffer write pointer for boot log. |
boot_count | uint32_t | Total boot count since factory (never reset). |
reserved[7] | uint32_t[7] | Reserved. Must be zero. |
crc32 | uint32_t | CRC32 of all preceding fields. |
📋 Enums & Constants
eos_slot_t
EOS_SLOT_A | 0 | Primary firmware slot. |
EOS_SLOT_B | 1 | Secondary firmware slot (OTA target). |
EOS_SLOT_NONE | 0xFF | No slot selected. |
eos_slot_state_t
EOS_SLOT_EMPTY | 0 | Erased, no firmware. |
EOS_SLOT_VALID | 1 | Verified firmware image. |
EOS_SLOT_INVALID | 2 | Corrupt or incomplete image. |
EOS_SLOT_UPDATING | 3 | Being written during OTA. |
eos_reset_reason_t
EOS_RESET_POWER_ON | 0 | Cold power-on. |
EOS_RESET_WATCHDOG | 1 | Watchdog expiration. |
EOS_RESET_SOFTWARE | 2 | Software reset. |
EOS_RESET_PIN | 3 | External reset pin. |
EOS_RESET_BROWNOUT | 4 | Brownout detection. |
Return Codes
EOS_OK | 0 | Success. |
EOS_ERR_CRC | -1 | CRC validation failed. |
EOS_ERR_FLASH | -2 | Flash operation failed. |
EOS_ERR_NO_IMAGE | -3 | No valid image in slot. |
EOS_ERR_INVALID | -4 | Invalid parameter. |
Boot Log Events
EOS_LOG_BOOT_START | 0 | Boot cycle started. |
EOS_LOG_SLOT_SELECT | 1 | Slot selected for boot. |
EOS_LOG_IMG_VERIFY | 2 | Image CRC verification passed. |
EOS_LOG_IMG_FAIL | 3 | Image verification failed. |
EOS_LOG_ROLLBACK | 4 | Rollback to confirmed slot. |
EOS_LOG_RECOVERY | 5 | Entered recovery mode. |
EOS_LOG_OTA_START | 6 | OTA update started. |
EOS_LOG_OTA_DONE | 7 | OTA update completed. |
EOS_LOG_CONFIRM | 8 | Slot confirmed as good. |
🔒 Boot Control API
Persistent boot state management. Header: <eos_bootctl.h>. All functions operate on eos_bootctl_t stored in flash with CRC protection and dual-copy redundancy.
int eos_bootctl_load(eos_bootctl_t *bctl)Load the boot control block from flash. Reads the primary copy first; if CRC is invalid, falls back to the backup copy. Typically the first eBoot function called during boot.
Parameters
bctl | eos_bootctl_t * | Pointer to structure to populate. Must not be NULL. All fields overwritten on success. |
Returns
EOS_OK (0) on success. EOS_ERR_CRC (-1) if both copies are corrupt. EOS_ERR_FLASH (-2) on flash read failure.
Example
eos_bootctl_t bctl;
int rc = eos_bootctl_load(&bctl);
if (rc == EOS_ERR_CRC) {
eos_bootctl_init_defaults(&bctl);
eos_bootctl_save(&bctl);
} else if (rc != EOS_OK) {
enter_recovery_mode();
}
printf("Active: slot %s, boots: %u\n",
bctl.active_slot == EOS_SLOT_A ? "A" : "B", bctl.boot_count);int eos_bootctl_save(eos_bootctl_t *bctl)Save the boot control block to flash. Computes CRC32, then writes both primary and backup copies. Write order: erase primary, write primary, erase backup, write backup. Power-loss safe: at least one copy survives.
Parameters
bctl | eos_bootctl_t * | Pointer to structure to save. crc32 field is computed by this function. |
Returns
EOS_OK (0) on success. EOS_ERR_FLASH (-2) on write/erase failure.
Example
eos_bootctl_t bctl;
eos_bootctl_load(&bctl);
bctl.active_slot = EOS_SLOT_B;
bctl.boot_count++;
if (eos_bootctl_save(&bctl) != EOS_OK) {
eos_boot_log_append(EOS_LOG_IMG_FAIL, EOS_SLOT_NONE, -2);
}void eos_bootctl_init_defaults(eos_bootctl_t *bctl)Initialize with factory defaults: magic=EOS_BOOTCTL_MAGIC, version=1, active_slot=A, max_attempts=3, all counters=0, flags cleared. Does NOT write to flash.
Parameters
bctl | eos_bootctl_t * | Pointer to structure. All fields overwritten. |
Returns
None (void).
Example
eos_bootctl_t bctl;
eos_bootctl_init_defaults(&bctl);
eos_bootctl_save(&bctl); // Persist to flash
eos_boot_log_clear(); // Clear old log
NVIC_SystemReset(); // Reboot freshbool eos_bootctl_validate(const eos_bootctl_t *bctl)Validate CRC of a boot control block in memory. Computes CRC32 over all fields except crc32 and compares. Useful for verifying flash-loaded copies before modifying.
Parameters
bctl | const eos_bootctl_t * | Pointer to structure to validate. Not modified. |
Returns
true if CRC matches. false if mismatch or NULL.
int eos_bootctl_increment_attempts(eos_bootctl_t *bctl)Increment boot_attempts by one and save. Called early in boot before jumping to application. If boot_attempts exceeds max_attempts, bootloader should rollback.
Parameters
bctl | eos_bootctl_t * | Pointer to boot control block. boot_attempts incremented and saved. |
Returns
EOS_OK on success. EOS_ERR_FLASH on save failure.
Example
eos_bootctl_t bctl;
eos_bootctl_load(&bctl);
eos_bootctl_increment_attempts(&bctl);
if (bctl.boot_attempts > bctl.max_attempts) {
eos_boot_log_append(EOS_LOG_ROLLBACK, bctl.active_slot, bctl.boot_attempts);
bctl.active_slot = bctl.confirmed_slot;
bctl.flags &= ~EOS_FLAG_TEST_BOOT;
eos_bootctl_reset_attempts(&bctl);
eos_bootctl_save(&bctl);
}
jump_to_slot(bctl.active_slot);int eos_bootctl_reset_attempts(eos_bootctl_t *bctl)Reset boot_attempts to zero and save. Called after successful rollback or slot confirmation.
Parameters
bctl | eos_bootctl_t * | Pointer to boot control block. |
Returns
EOS_OK on success. EOS_ERR_FLASH on failure.
int eos_bootctl_set_pending(eos_bootctl_t *bctl, eos_slot_t slot)Mark a slot for test boot after OTA. On next reset, bootloader boots the pending slot with EOS_FLAG_TEST_BOOT. App must call eos_bootctl_confirm() within max_attempts boots or rollback occurs.
Parameters
bctl | eos_bootctl_t * | Pointer to boot control block. |
slot | eos_slot_t | Target slot: EOS_SLOT_A (0) or EOS_SLOT_B (1). |
Returns
EOS_OK on success. EOS_ERR_INVALID if slot invalid.
Example
// After OTA completes
eos_bootctl_t bctl;
eos_bootctl_load(&bctl);
eos_slot_t target = eos_bootctl_other_slot(bctl.active_slot);
eos_bootctl_set_pending(&bctl, target);
eos_bootctl_save(&bctl);
eos_boot_log_append(EOS_LOG_OTA_DONE, target, new_version);
NVIC_SystemReset();int eos_bootctl_clear_pending(eos_bootctl_t *bctl)Clear pending slot after failed verification. Sets pending_slot to EOS_SLOT_NONE and clears test boot flag.
Parameters
bctl | eos_bootctl_t * | Pointer to boot control block. |
Returns
EOS_OK on success.
int eos_bootctl_confirm(eos_bootctl_t *bctl)Confirm active slot as known-good. Application firmware MUST call this after successful self-test to prevent rollback. Clears EOS_FLAG_TEST_BOOT, sets confirmed_slot, resets boot_attempts.
Parameters
bctl | eos_bootctl_t * | Pointer to boot control block. |
Returns
EOS_OK on success. EOS_ERR_FLASH on failure.
Example
void app_main(void) {
eos_bootctl_t bctl;
eos_bootctl_load(&bctl);
if (self_test_passed()) {
eos_bootctl_confirm(&bctl);
EOS_INFO("Boot confirmed on slot %s",
bctl.active_slot == EOS_SLOT_A ? "A" : "B");
} else {
EOS_ERROR("Self-test failed - rollback on next reboot");
}
}int eos_bootctl_request_recovery(eos_bootctl_t *bctl)Set EOS_FLAG_RECOVERY. Next boot enters recovery mode (serial/USB reflash interface).
Parameters
bctl | eos_bootctl_t * | Pointer to boot control block. |
Returns
EOS_OK on success.
int eos_bootctl_request_factory_reset(eos_bootctl_t *bctl)Set EOS_FLAG_FACTORY_RESET. Next boot erases user data, reinitializes defaults, and boots Slot A.
Parameters
bctl | eos_bootctl_t * | Pointer to boot control block. |
Returns
EOS_OK on success.
eos_slot_t eos_bootctl_other_slot(eos_slot_t slot)Get the alternate slot. Returns B if given A, A if given B, NONE if invalid.
Parameters
slot | eos_slot_t | Current slot: EOS_SLOT_A(0) or EOS_SLOT_B(1). |
Returns
The other slot, or EOS_SLOT_NONE (0xFF) if invalid input.
🗃 Slot Manager API
Firmware slot inspection and management. Header: <eos_slot_manager.h>
int eos_slot_scan_all(void)Scan all firmware slots, read image headers, validate CRCs, and cache slot states. Must be called before any other slot manager function. Re-scanning is safe and updates cached state.
Returns
Number of valid slots found (0-2), or negative error code on flash failure.
Example
int valid = eos_slot_scan_all();
printf("Found %d valid firmware slots\n", valid);
if (valid == 0) {
enter_recovery_mode(); // No bootable image
}bool eos_slot_is_valid(eos_slot_t slot)Check if a slot contains a valid firmware image (header magic OK, CRC matches). Requires prior eos_slot_scan_all().
Parameters
slot | eos_slot_t | Slot to check: EOS_SLOT_A or EOS_SLOT_B. |
Returns
true if slot has a valid image. false if empty, corrupt, or invalid slot ID.
uint32_t eos_slot_get_version(eos_slot_t slot)Get firmware version number from a slot's image header. Returns 0 if the slot is empty or invalid.
Parameters
slot | eos_slot_t | Slot to query. |
Returns
Version number (e.g., 0x010200 for v1.2.0), or 0 if invalid.
int eos_slot_get_header(eos_slot_t slot, eos_image_header_t *out)Read the full image header from a slot. Contains version, size, CRC, build timestamp, and hardware compatibility info.
Parameters
slot | eos_slot_t | Slot to read from. |
out | eos_image_header_t * | Output buffer for image header. |
Returns
EOS_OK on success. EOS_ERR_NO_IMAGE if slot is empty.
Example
eos_image_header_t hdr;
if (eos_slot_get_header(EOS_SLOT_A, &hdr) == EOS_OK) {
printf("Slot A: v%u.%u.%u, size=%u bytes\n",
(hdr.version >> 16) & 0xFF,
(hdr.version >> 8) & 0xFF,
hdr.version & 0xFF, hdr.image_size);
}eos_slot_state_t eos_slot_get_state(eos_slot_t slot)Get the current state of a firmware slot: EMPTY, VALID, INVALID, or UPDATING.
Parameters
slot | eos_slot_t | Slot to query. |
Returns
eos_slot_state_t enum value.
int eos_slot_erase(eos_slot_t slot)Erase a firmware slot. Sets all bytes to 0xFF. Used before writing a new OTA image.
Parameters
slot | eos_slot_t | Slot to erase. |
Returns
EOS_OK on success. EOS_ERR_FLASH on failure.
📖 Boot Log API
Persistent ring-buffer boot log in flash. Header: <eos_boot_log.h>. Survives resets. Readable by application firmware.
int eos_boot_log_init(void)Initialize boot log subsystem. Reads log region from flash, validates header, locates write position. Formats with fresh header if corrupt or uninitialized.
Returns
EOS_OK on success. EOS_ERR_FLASH on read failure.
void eos_boot_log_append(uint32_t event, uint32_t slot, uint32_t detail)Append a timestamped entry to the boot log ring buffer. When full, oldest entry is overwritten. Flushed to flash immediately.
Parameters
event | uint32_t | Event code: EOS_LOG_BOOT_START(0)..EOS_LOG_CONFIRM(8). |
slot | uint32_t | Associated slot (EOS_SLOT_A, EOS_SLOT_B, or EOS_SLOT_NONE). |
detail | uint32_t | Event-specific: version number, error code, CRC, etc. |
Example
eos_boot_log_init();
eos_boot_log_append(EOS_LOG_BOOT_START, EOS_SLOT_NONE, 0);
eos_boot_log_append(EOS_LOG_SLOT_SELECT, EOS_SLOT_A, 0x010200);
eos_boot_log_append(EOS_LOG_IMG_VERIFY, EOS_SLOT_A, computed_crc);int eos_boot_log_read(eos_boot_log_entry_t *entries, uint32_t max_count)Read all boot log entries in chronological order (oldest first).
Parameters
entries | eos_boot_log_entry_t * | Output buffer. |
max_count | uint32_t | Max entries buffer can hold. |
Returns
Number of entries read, or negative error code.
Example
eos_boot_log_entry_t log[64];
int n = eos_boot_log_read(log, 64);
for (int i = 0; i < n; i++) {
printf("[%u ms] %s slot=%u detail=0x%08X\n",
log[i].timestamp,
eos_boot_log_event_name(log[i].event),
log[i].slot, log[i].detail);
}uint32_t eos_boot_log_count(void)Get number of entries currently stored in the boot log.
Returns
Entry count (0 to EOS_BOOT_LOG_MAX).
int eos_boot_log_clear(void)Clear all boot log entries. Erases log flash sector and writes fresh header.
Returns
EOS_OK on success. EOS_ERR_FLASH on erase failure.
int eos_boot_log_flush(void)Flush buffered entries to flash. Call before jumping to application to ensure persistence.
Returns
EOS_OK on success.
int eos_boot_log_get_latest(eos_boot_log_entry_t *entry)Get the most recent log entry.
Parameters
entry | eos_boot_log_entry_t * | Output buffer. |
Returns
EOS_OK on success. EOS_ERR_NO_IMAGE if log is empty.
const char * eos_boot_log_event_name(uint32_t event)Convert event code to human-readable string (e.g., "BOOT_START", "ROLLBACK").
Parameters
event | uint32_t | Event code (EOS_LOG_*). |
Returns
Static string describing the event, or "UNKNOWN".
🔄 Boot Flow
RESET
|
v
eos_boot_log_init()
eos_bootctl_load(&bctl) --- CRC fail ---> eos_bootctl_init_defaults() ---> save
|
v
Check flags: FACTORY_RESET? ---> erase all, init defaults, reboot
RECOVERY? ---> enter_recovery_mode()
|
v
eos_bootctl_increment_attempts(&bctl)
|
v
boot_attempts > max_attempts? ---> ROLLBACK to confirmed_slot
| log EOS_LOG_ROLLBACK
v reset attempts, reboot
pending_slot != NONE?
YES: active_slot = pending_slot, set TEST_BOOT flag
NO: use current active_slot
|
v
eos_slot_scan_all()
eos_slot_is_valid(active_slot)? ---> NO: try other slot, or recovery
|
v
log EOS_LOG_SLOT_SELECT, EOS_LOG_IMG_VERIFY
eos_boot_log_flush()
jump_to_slot(active_slot)
|
v
APPLICATION FIRMWARE
|
v
self_test_passed()? ---> eos_bootctl_confirm() // CRITICAL!
log EOS_LOG_CONFIRM🔧 Board Porting Guide
Flash Layout Requirements
eBoot requires the following flash regions configured in your linker script:
| Region | Size | Description |
BOOTLOADER | 32-64 KB | eBoot code (starts at 0x08000000 on STM32). |
BOOTCTL_PRIMARY | 4 KB (1 sector) | Primary boot control block. |
BOOTCTL_BACKUP | 4 KB (1 sector) | Backup boot control block. |
BOOT_LOG | 4 KB (1 sector) | Boot log ring buffer (EOS_BOOT_LOG_SECTOR_SIZE). |
SLOT_A | Variable | Primary firmware image (typically 256KB-1MB). |
SLOT_B | Variable | Secondary firmware image (same size as SLOT_A). |
Porting Steps
- Define flash addresses in
board_config.h:BOOTCTL_FLASH_ADDR,BOOTCTL_BACKUP_ADDR,BOOT_LOG_FLASH_ADDR,SLOT_A_ADDR,SLOT_B_ADDR,SLOT_SIZE. - Implement flash HAL:
eos_flash_read(),eos_flash_write(),eos_flash_erase_sector(). - Implement
jump_to_slot(eos_slot_t slot)— set VTOR, load SP from slot start, jump to reset vector. - Add watchdog initialization before jumping (to catch hung firmware).
- Call
eos_bootctl_confirm()from your application after self-test passes.
Example: board_config.h
#define BOOTCTL_FLASH_ADDR 0x08010000
#define BOOTCTL_BACKUP_ADDR 0x08011000
#define BOOT_LOG_FLASH_ADDR 0x08012000
#define SLOT_A_ADDR 0x08020000
#define SLOT_B_ADDR 0x08060000
#define SLOT_SIZE 0x00040000 // 256KB per slotThread Safety: Boot control functions are NOT thread-safe. All calls should be made from the bootloader main context before the RTOS starts, or from a single application task with appropriate locking.