OTA Bootloaders

 Updating Embedded Devices in the Field


Introduction


Once an embedded device ships, the code inside it doesn't have to be final. Bugs need fixing, security vulnerabilities need patching, and features need adding — often on devices that are already deployed in homes, vehicles, factories, or remote infrastructure with no physical access. This is the problem Over-The-Air (OTA) updates solve, and the component that makes it possible is the bootloader. This post explains how OTA bootloaders work, the design decisions behind them, and the practices that separate a reliable update mechanism from one that bricks devices in the field.


What Is a Bootloader, and Why Does OTA Need One?


A bootloader is the first code that runs when a microcontroller powers on, before the main application. Its normal job is simple: verify the application is valid and jump to it. An OTA bootloader extends that job. It becomes the trusted gatekeeper responsible for:

  • Receiving and storing new firmware images over a network or wireless link

  • Verifying the integrity and authenticity of a new image before trusting it

  • Deciding which firmware image to boot — the current one or a newly downloaded one

  • Rolling back to a known-good image if the new firmware fails to start correctly Because the bootloader runs before the application and controls what code executes next, it is the single most safety-critical piece of firmware on the device. If the bootloader itself is broken, no future update can fix it remotely.






The Anatomy of an OTA Update


1. Memory Partitioning


Most OTA-capable devices split flash memory into distinct regions:





























Partition Purpose
Bootloader Fixed, rarely-updated code that controls boot selection
Slot A (active) Currently running application
Slot B (inactive) Staging area for the new firmware image
Metadata/Config Stores boot flags, version info, rollback counters
This is commonly called an A/B (or dual-bank) partition scheme. The device always has a known-good image in one slot while writing the new one to the other, so a failed download or corrupted write never touches the currently running firmware.

2. Download and Storage


The new firmware image is transferred over Wi-Fi, cellular, BLE, Ethernet, or even a mesh network, and written into the inactive slot in chunks. This process typically happens while the application continues running normally, so the update is invisible to the end user until a reboot is required.

3. Verification


Before the bootloader ever boots a new image, it must confirm two things:

  • Integrity — the image wasn't corrupted in transit (checksum or hash, e.g., SHA-256)

  • Authenticity — the image actually came from a trusted source (digital signature verification using public-key cryptography, e.g., RSA or ECDSA) Skipping this step is one of the most common — and most dangerous — shortcuts in embedded systems, since it opens the door to malicious firmware being installed on the device.


4. Boot Selection and Rollback


After verification, the bootloader flips a flag marking the new slot as "pending boot" and resets the device. On the next boot:

  • If the new firmware boots and confirms it's healthy (a "mark good" step, often after passing self-tests or successfully connecting to the network), the update is finalized.

  • If the device fails to boot, crashes repeatedly, or never confirms health within a timeout, the bootloader automatically reverts to the previous known-good slot. This automatic rollback mechanism is what prevents a bad update from turning a fleet of deployed devices into unrecoverable bricks.






Example: A Simplified Boot Selection Routine


typedef struct {
uint32_t slot_a_version;
uint32_t slot_b_version;
uint8_t pending_slot; // 0 = none, 1 = A, 2 = B
uint8_t boot_attempts;
uint8_t slot_b_confirmed;
} boot_metadata_t;
void bootloader_main(void) {
boot_metadata_t meta = read_boot_metadata();
if (meta.pending_slot == SLOT_B && !meta.slot_b_confirmed) {
if (meta.boot_attempts >= MAX_BOOT_ATTEMPTS) {
// New image keeps failing — roll back
meta.pending_slot = SLOT_NONE;
write_boot_metadata(&meta);
jump_to_application(SLOT_A_ADDRESS);
}
meta.boot_attempts++;
write_boot_metadata(&meta);
jump_to_application(SLOT_B_ADDRESS);
}
jump_to_application(SLOT_A_ADDRESS);
}

This is intentionally simplified, but it captures the core logic: track boot attempts, trust the new image cautiously, and always have a documented path back to safety.


Common OTA Bootloader Architectures



  • A/B (dual-bank) updates — Full redundancy; requires roughly 2x flash for two application slots, but offers the safest rollback story. Common in automotive ECUs and consumer IoT.

  • Single-bank with backup region — Used on flash-constrained microcontrollers; the bootloader downloads a compressed or delta image and reconstructs the application in place, often with a smaller recovery partition instead of a full second copy.

  • Delta/differential updates — Only the binary difference between old and new firmware is transmitted, dramatically reducing bandwidth and update time over constrained links like cellular or LoRaWAN.

  • A/B with staged rollout — Used at fleet scale: a new image is pushed to a small percentage of devices first, monitored for health metrics, and only rolled out further if no regressions are detected.






Design Considerations and Pitfalls



  1. Never skip signature verification. Checksum alone only catches corruption, not malicious tampering.

  2. Protect against power loss mid-write. Flash writes must be structured so a power cut during an update never leaves the bootloader or metadata in an inconsistent state — this usually means writing new data before atomically flipping a single "commit" flag.

  3. Reserve enough flash for two images (or a workable alternative). Underestimating flash budget is a common reason teams retrofit OTA into a product too late.

  4. Set a bounded rollback timeout. "Never confirmed healthy" needs a hard limit, or a subtly broken image can sit in limbo indefinitely.

  5. Version and metadata integrity matter as much as the application image. Corrupted metadata can be just as damaging as corrupted firmware.

  6. Secure the transport, not just the image. TLS or another authenticated channel prevents interception and downgrade attacks during download, even though the image itself is separately signed.

  7. Test power-loss and network-loss scenarios explicitly. These are the failure modes that occur constantly in real fleets and rarely occur in a lab.






Bootloader Security in Practice


Security-conscious OTA implementations typically layer several protections:

  • Secure boot chain — the bootloader itself is verified by an immutable first-stage loader (often in ROM), so even the bootloader can't be tampered with.

  • Anti-rollback protection — prevents an attacker from re-installing an old, vulnerable firmware version, usually via a monotonic version counter stored in secure/write-protected memory.

  • Hardware root of trust — secure elements or MCU-integrated crypto engines store keys in a way that's resistant to extraction, keeping signing keys off the device entirely. These layers matter most in regulated or high-stakes domains — automotive, medical devices, and industrial control — where an unauthenticated firmware update is a genuine safety and security risk, not just an inconvenience.






Conclusion


An OTA bootloader is deceptively small in terms of code size but outsized in responsibility — it's the one component standing between a smooth remote update and a fleet of bricked devices. Getting it right means treating verification, redundancy, and rollback as non-negotiable from day one, not features bolted on after a product ships. For any connected embedded product expected to live in the field for years, a well-designed OTA bootloader isn't optional — it's the mechanism that keeps the product maintainable long after it leaves the factory.

Leave a Reply

Your email address will not be published. Required fields are marked *