Home Learning Paths ECU Lab Assessments Interview Preparation Arena Pricing Log In Sign Up

The Bootloader's Role in ECU Reprogramming

ResponsibilityPrimary Bootloader (PBL)Secondary Bootloader (SBL)
LocationDedicated flash region; hardware write-protectedDownloaded to RAM or application flash area
Persistent?Always present; never erasedTemporary; downloaded by PBL; destroyed after use
Handles UDS?Minimal: session control, security access, SBL downloadFull: erase, download, verify, checksum routines
Can erase itself?No — PBL region is hardware-protectedYes — can erase application region
Size4–32 kB (small, simple, immutable)32–256 kB (full flash driver + UDS stack)
Loaded byFactory programming (JTAG/in-circuit)PBL over UDS during reprogramming session

Two-Stage Bootloader Architecture Rationale

Two-Stage Boot Architecture
  Power-on / Reset
        │
        ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │  PRIMARY BOOTLOADER (PBL) — always runs first                  │
  │  Region: 0x80000000–0x80007FFF (32 kB) — HARDWARE PROTECTED    │
  │                                                                  │
  │  Decision logic:                                                 │
  │  1. Is reprogramming flag set in NvM? → goto reprogramming mode  │
  │  2. Is application CRC valid?         → jump to application      │
  │  3. Is SBL present and valid?         → jump to SBL              │
  │  4. None of above                     → stay in PBL, await UDS  │
  └──────────────────────────────┬──────────────────────────────────┘
                                  │
              ┌───────────────────┼───────────────────┐
              ▼                   ▼                   ▼
  ┌─────────────────┐  ┌──────────────────┐  ┌───────────────────┐
  │  APPLICATION    │  │  SBL (in RAM or  │  │  REPROGRAMMING    │
  │  0x80020000+    │  │  SBL flash area) │  │  MODE (PBL only)  │
  │  Normal run     │  │  Handles erase/  │  │  Awaits DoIP/CAN  │
  │                 │  │  download/verify │  │  tester           │
  └─────────────────┘  └──────────────────┘  └───────────────────┘

  Why two stages?
  - PBL is never erased → always recoverable even if app is corrupt
  - SBL contains the flash driver → can erase/write application flash
  - SBL lives in RAM → can program its own flash region (no self-erase)
  - SBL is verified by PBL before execution → chain of trust

Flash Memory Layout: Aurix TC3xx Example

Aurix TC397 Flash Map (8 MB PFlash)
  Address          Size    Region          Protection   Contents
  0x80000000  ──   32 kB   PBL             HW locked    Primary bootloader
  0x80008000  ──   64 kB   SBL header      Lockable     SBL metadata + signature
  0x80018000  ── 256 kB   SBL body        Lockable     Secondary bootloader code
  0x80058000  ──   32 kB   Bootloader data Lockable     Config, fingerprints, NvM
  0x80060000  ──    4 kB   Boot flags      Write-once   Reprogramming trigger flags
  0x80061000  ──    3 kB   Reserved        —            —
  0x80064000  ── 7424 kB  Application     Erasable     Application + AUTOSAR SWC
  0x80780000  ── 512 kB   Calibration     Erasable     Online/offline calibration
  0x80800000  ── [DFLASH] Data Flash       Various      NvM, VIN, mileage, security

  Key constraints:
  - PBL sector(s): fused/OTP-locked at factory → cannot be erased in field
  - Boot flags sector: written in programming session; read at every POR
  - Application region: erased by SBL RoutineControl 0xFF00 before download
  - Calibration region: can be updated independently (no app re-flash needed)

Vector Table and Interrupt Relocation

Cvector_relocation.c
/* Problem: both PBL and Application have a vector table */
/* ARM Cortex-M: VTOR register selects which vector table is active */
/* Aurix TriCore: trap table controlled by BTV CSR */

/* PBL starts with its own vector table at flash base (0x80000000) */
/* When jumping to application: must redirect interrupts to app's vector table */

#include 

/* Cortex-M: SCB->VTOR register at 0xE000ED08 */
#define SCB_VTOR    (*(volatile uint32_t *)0xE000ED08u)
#define APP_BASE    0x80020000u   /* application start address */

void Pbl_JumpToApplication(void)
{
    /* Step 1: Disable all interrupts */
    __disable_irq();

    /* Step 2: Relocate vector table to application's vector table */
    SCB_VTOR = APP_BASE;        /* app vector table starts at app base */

    /* Step 3: Get application stack pointer and reset handler */
    uint32_t *app_vectors = (uint32_t *)APP_BASE;
    uint32_t  app_sp      = app_vectors[0];  /* initial stack pointer */
    uint32_t  app_reset   = app_vectors[1];  /* reset handler address */

    /* Step 4: Set stack pointer */
    __set_MSP(app_sp);

    /* Step 5: Jump to application reset handler */
    void (*app_entry)(void) = (void (*)(void))(app_reset | 1u); /* thumb bit */
    app_entry();
    /* never returns */
}

/* Aurix TriCore: BTV (Base address of Trap Vector table) */
/* __MTCR(BTV, APP_BASE); */
/* __MTCR(BIV, APP_INTERRUPT_BASE); */

Summary

The two-stage bootloader architecture is universal in automotive ECUs because it solves the self-erase problem: the PBL is hardware-protected and can never be erased, so it is always available to re-download a corrupt SBL or application. The SBL contains the flash driver and runs from RAM or a protected flash region, so it can safely erase and program the application area. Vector table relocation is mandatory before jumping to the application — without it, all interrupts and exceptions after the jump will use the PBL's handlers, which typically call fault handlers or reset the ECU.

🔬 ECU Flash Memory Layout — Detailed Breakdown

Understanding the exact memory layout of a bootloader-enabled ECU is fundamental to designing a robust OTA update system. A typical Cortex-M / TriCore ECU has the following flash regions:

  • Interrupt Vector Table (IVT) / Reset Vector (0x00000000): The first few KB of flash. On reset, the CPU fetches the reset handler address from this location. The bootloader IVT lives here — if it is corrupt, the ECU cannot boot at all. This region must be write-protected (hardware flash block protection) and must never be erased during application flashing.
  • Bootloader code region: Typically 16–64 KB. Contains the UDS programming session handler, flash driver (loaded to RAM), and crypto verification logic. Should be in a separate flash sector from the application so application erase cannot touch it.
  • Application code region: The main ECU software. This is what gets erased and reprogrammed during OTA/EOL flashing. Typically 1–4 MB on modern ECUs.
  • Calibration data region: Read-only calibration maps (A2L data). Separate region allows calibration updates without full software reflash. Usually the last few hundred KB before the NvM region.
  • NvM / Data Flash region: Typically a separate data flash or emulated EEPROM area. Stores DTC history, odometer, adaptation values, and VIN. Must never be erased during software programming — erase of this region is a critical production error.
  • Boot Status Block: A small (32–256 byte) region written by the bootloader to track: programming attempt count, last programming result (SUCCESS/FAIL), valid application fingerprint. Used for anti-rollback and brick recovery logic.

🏭 Production Bootloader Lessons

  • Dual-bank (A/B) flash: High-end ECUs (e.g., TriCore TC399 with 8 MB flash) use two complete application banks. The bootloader flashes bank B while the ECU runs from bank A. After verification, the boot bank pointer is atomically updated. If verification fails, the ECU continues on bank A. This eliminates the 'brick' risk present in single-bank designs.
  • Write protection in production: Once the bootloader has been flashed and verified at EOL, hardware write-protect bits in the flash controller (PFLASH/DFLASH protection registers) are set to prevent any overwrite of the bootloader region. These bits are one-time-programmable on some MCUs (NXP S32K) — misconfiguring them permanently bricks the ECU.
  • CRC verification performance: A CRC32 over a 4 MB application image takes ~2 seconds in software on a 40 MHz CPU. At EOL with 100 ECUs per hour, this adds 200 seconds/hour of wasted time. Hardware CRC accelerators (available on TriCore, S32K, RH850) reduce this to ~100 ms.

⚠️ Bootloader Design Pitfalls

  1. Bootloader and application sharing the same flash sector: An application erase command that targets the first flash sector will erase the bootloader. The ECU becomes unrecoverable without physical programmer access. Always place bootloader in a dedicated sector with hardware protection.
  2. No boot validity check on application: If the application CRC/signature is not verified before jumping from bootloader to application, a partially written application (from an interrupted flash sequence) will execute corrupted code. Always check the application fingerprint in the Boot Status Block before every reset.
  3. NvM erased during application reflash: An erase command with an address range that extends into the Data Flash region will erase customer NvM data (DTC history, mileage, VIN). This is an EOL programming defect that causes warranty claims. Validate address range strictly: StartAddress + Length must not exceed ApplicationEndAddress.
  4. Anti-rollback not implemented: Without anti-rollback protection, an attacker with access to the UDS programming interface can reflash an older vulnerable firmware version — bypassing security fixes. Implement a monotonically increasing software version counter stored in NvM, and reject flashing any image with a lower version number.

📊 Industry Note

In 2020, a European OEM recalled 500,000 vehicles because their bootloader did not validate the application CRC before jumping. Corrupted OTA updates caused ECUs to enter an infinite reset loop with the application partially written. The cost of the recall vastly exceeded the 2-day engineering effort required to add proper CRC validation.

🧠 Knowledge Check — Click each question to reveal the answer

❓ Why must the flash driver be copied to RAM before execution during a flash programming sequence?

✅ The flash driver contains the code that erases and programs the flash memory. While erasing or writing a flash sector, the flash controller on most MCUs (NXP S32K, Infineon TriCore, Renesas RH850) cannot simultaneously execute code from flash — the flash bus is busy. If the flash driver runs from flash, the ECU will stall or crash mid-erase. Copying the flash driver to RAM allows uninterrupted execution while the flash operation is in progress.

❓ What information should a Boot Status Block contain, and why is it important for OTA update reliability?

✅ The Boot Status Block should contain: (1) Programming attempt counter (incremented at start, cleared on success) — detects interrupted flashing. (2) Last programming result (SUCCESS/FAIL/IN_PROGRESS) — allows recovery action on next boot. (3) Application software version number — enables anti-rollback check. (4) Application CRC/hash — for post-boot integrity verification without re-running the full UDS check. This allows the bootloader to make a reliable boot/no-boot decision on every reset, preventing half-written firmware from executing.

❓ An ECU supports dual-bank (A/B) flash updates. The OTA update to bank B fails mid-programming. Describe the exact recovery sequence.

✅ On the next reset: (1) Bootloader reads the Boot Status Block — result = IN_PROGRESS for bank B. (2) Bootloader checks bank A integrity (CRC/signature) — bank A is untouched and valid. (3) Bootloader sets boot pointer to bank A. (4) Application from bank A starts normally. (5) Bank B remains in partially-written state until the next successful OTA update attempt reprograms it. The ECU remains fully functional on bank A throughout. The OTA Master (cloud or vehicle OTA controller) detects the failure via the DTC set in step 1 and schedules a retry.
Next →Boot Sequence & Application Jump