Firmware Update Guide

Configure and perform BMC and host firmware updates on OpenBMC - comprehensive deep dive into update mechanisms, image formats, and flash management.

Table of Contents

  1. Overview
    1. Update Architecture
    2. Key Components
  2. Firmware Image Format
    1. Tarball Structure
    2. MANIFEST File Format
      1. MANIFEST Fields
    3. Image File Types
    4. Creating Firmware Images
    5. Signing Images
  3. Flash Layout & Storage
    1. BMC Flash Layout (ASPEED)
    2. Static MTD vs UBI Layout
      1. Static MTD Layout
      2. UBI (Unsorted Block Images) Layout
    3. Host Flash Layout (Intel/AMD BIOS)
    4. OpenPOWER PNOR Layout
  4. Setup & Configuration
    1. Build-Time Configuration (Yocto)
    2. phosphor-bmc-code-mgmt Meson Options
    3. Configuration Files and Paths
    4. Deploying Signing Keys via Yocto
    5. Enabling Field Mode
    6. Runtime Configuration
    7. D-Bus Software Interfaces
  5. Firmware Inventory
    1. View Current Versions
    2. Firmware Response
  6. Update Methods
    1. Redfish Update Service
    2. SimpleUpdate Action
    3. IPMI OEM Firmware Update
      1. phosphor-ipmi-flash Configuration
    4. PLDM Firmware Update (Type 5)
      1. PLDM Update Flow
    5. WebUI Update
    6. USB Code Update
    7. Command-Line Update Tools
  7. Dual Image Support
    1. Dual Image Architecture
    2. View Images via Redfish
    3. View Images via D-Bus
    4. Set Boot Priority
  8. U-Boot Environment & Boot Control
    1. Key U-Boot Environment Variables
    2. U-Boot Boot Logic
    3. Manual Boot Control
    4. Recovery via Serial Console
  9. Failsafe Behavior
    1. Automatic Boot Fallback
    2. Boot Health Check Service
    3. Recovery Mode
  10. Firmware Signing & Verification
    1. Signing Infrastructure Overview
    2. Generate Signing Keys
    3. Sign Firmware Components
    4. Configure Verification in Yocto
    5. Verification Flow
    6. Manual Signature Verification
    7. Signature Verification Logs
    8. Key Type Configuration
  11. Host Firmware Update
    1. BIOS/UEFI Update (Intel/AMD)
      1. Intel SPS/ME Firmware
    2. PNOR Update (OpenPOWER)
      1. openpower-pnor-code-mgmt
    3. PSU Firmware Update
    4. Component-Level Update (PLDM)
  12. Update Workflow Deep Dive
    1. Complete Update Sequence
    2. Activation States
    3. Monitor Update Progress
    4. Progress Indication
  13. Configuration Options
    1. Update Settings
    2. Apply Time Options
  14. Troubleshooting
    1. Upload Fails
    2. Signature Verification Failed
    3. Machine Name Mismatch
    4. Boot Fails After Update
    5. Image Not Activating
    6. Flash Write Errors
    7. Activation Progress Stuck
    8. Delete Failed/Stale Images
    9. Network Update Issues
  15. Rollback
    1. Rollback via D-Bus
    2. Rollback via Redfish
    3. Rollback via U-Boot
  16. Factory Reset
    1. Reset BMC Configuration
    2. Clear Persistent Data
    3. Full Flash Recovery
  17. Security Considerations
    1. Secure Boot Chain
    2. U-Boot Verified Boot Configuration
    3. Update Authentication
    4. Audit Logging
  18. Best Practices
    1. Pre-Update Checklist
    2. Update Procedure
    3. Post-Update Verification
  19. Examples
  20. References
    1. OpenBMC Repositories
    2. OpenBMC Documentation
    3. Standards
    4. U-Boot
  21. Deep Dive
    1. Flash Layout and MTD Partitions
    2. Update Image Verification
    3. Flash Programming Internals
    4. Recovery Mechanism
    5. Source Code Reference

Overview

OpenBMC supports firmware updates for BMC, BIOS/UEFI, and other platform components through multiple interfaces including Redfish, IPMI, PLDM, and command-line tools. This guide provides a deep dive into the update architecture, image formats, flash layouts, and troubleshooting procedures.

Update Architecture

---
title: Firmware Update Architecture
---
flowchart TB
    subgraph interfaces["Update Interfaces"]
        direction TB
        redfish["Redfish<br/>UpdateSvc"]
        ipmi["IPMI<br/>OEM Flash"]
        pldm["PLDM<br/>FW Update"]
        webui["WebUI<br/>Upload"]
        usb["USB<br/>Storage"]
    end

    subgraph codemgmt["phosphor-bmc-code-mgmt (Software Manager)"]
        direction LR
        subgraph row1[" "]
            direction TB
            item["ItemUpdater<br/>(BMC/Host/PSU)"]
            image["ImageManager<br/>(tar extract)"]
            activation["Activation<br/>(flash ops)"]
            version["Version<br/>(D-Bus)"]
        end
        subgraph row2[" "]
            direction TB
            sig["Signature<br/>Verification"]
            manifest["MANIFEST<br/>Parsing"]
            priority["Priority<br/>Management"]
        end
    end

    subgraph flash["Flash Storage Layer"]
        direction LR
        subgraph bmcflash["BMC Flash (SPI)"]
            direction TB
            ubi["UBI<br/>Volumes"]
            static["Static<br/>MTD"]
        end
        subgraph hostflash["Host Flash (LPC/SPI)"]
            direction TB
            pnor["PNOR"]
            bios["BIOS"]
        end
    end

    interfaces --> codemgmt
    codemgmt --> flash

    style row1 fill:none,stroke:none
    style row2 fill:none,stroke:none
ASCII-art version (for comparison)
┌──────────────────────────────────────────────────────────────────────────────┐
│                      Firmware Update Architecture                            │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │                         Update Interfaces                               │ │
│  │                                                                         │ │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐       │ │
│  │  │ Redfish  │ │   IPMI   │ │  PLDM    │ │  WebUI   │ │   USB    │       │ │
│  │  │UpdateSvc │ │OEM Flash │ │FW Update │ │ Upload   │ │ Storage  │       │ │
│  │  └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘       │ │
│  └───────┼────────────┼────────────┼────────────┼────────────┼─────────────┘ │
│          │            │            │            │            │               │
│          └────────────┴─────┬──────┴────────────┴────────────┘               │
│                             │                                                │
│  ┌──────────────────────────┴────────────────────────────────────────────┐   │
│  │              phosphor-bmc-code-mgmt (Software Manager)                │   │
│  │                                                                       │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌────────────┐ │   │
│  │  │ ItemUpdater  │  │ImageManager  │  │  Activation  │  │  Version   │ │   │
│  │  │(BMC/Host/PSU)│  │(tar extract) │  │  (flash ops) │  │  (D-Bus)   │ │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘  └────────────┘ │   │
│  │                                                                       │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                 │   │
│  │  │ Signature    │  │ MANIFEST     │  │ Priority     │                 │   │
│  │  │ Verification │  │ Parsing      │  │ Management   │                 │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘                 │   │
│  └───────────────────────────────────────────────────────────────────────┘   │
│                             │                                                │
│  ┌──────────────────────────┴────────────────────────────────────────────┐   │
│  │                        Flash Storage Layer                            │   │
│  │                                                                       │   │
│  │  ┌────────────────────────────┐  ┌────────────────────────────────┐   │   │
│  │  │      BMC Flash (SPI)       │  │      Host Flash (LPC/SPI)      │   │   │
│  │  │                            │  │                                │   │   │
│  │  │  ┌──────┐  ┌──────┐        │  │  ┌──────┐  ┌──────┐            │   │   │
│  │  │  │ UBI  │  │Static│        │  │  │ PNOR │  │ BIOS │            │   │   │
│  │  │  │Volumes│ │ MTD  │        │  │  │      │  │      │            │   │   │
│  │  │  └──────┘  └──────┘        │  │  └──────┘  └──────┘            │   │   │
│  │  └────────────────────────────┘  └────────────────────────────────┘   │   │
│  └───────────────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────────────────┘

Key Components

Component Repository Description
phosphor-bmc-code-mgmt openbmc/phosphor-bmc-code-mgmt Core BMC firmware management
phosphor-software-manager Part of code-mgmt D-Bus service for update operations
phosphor-ipmi-flash openbmc/phosphor-ipmi-flash IPMI OEM firmware update
pldmd openbmc/pldm PLDM Type 5 firmware update
phosphor-image-signing Part of code-mgmt Signature generation and verification

Firmware Image Format

Tarball Structure

OpenBMC firmware images are packaged as tarballs with a specific structure:

obmc-phosphor-image-<machine>.tar
├── MANIFEST                    # Metadata about the image
├── publickey                   # Public key for verification (optional)
├── image-kernel                # Linux kernel (FIT image or uImage)
├── image-rofs                  # Read-only root filesystem (squashfs)
├── image-rwfs                  # Read-write filesystem (ext4/ubifs)
├── image-u-boot                # U-Boot bootloader
├── image-bmc                   # Combined flash image (static.mtd)
└── *.sig                       # Signatures for each component

MANIFEST File Format

The MANIFEST file contains critical metadata parsed during update:

# Example MANIFEST file
purpose=xyz.openbmc_project.Software.Version.VersionPurpose.BMC
version=2.12.0-dev-123-gabcdef
KeyType=OpenBMC
HashType=RSA-SHA256
MachineName=romulus

# Extended version information (optional)
extended_version=OpenBMC for Romulus - master branch build 123

MANIFEST Fields

Field Required Description
purpose Yes BMC, Host, System, or custom
version Yes Semantic version string
MachineName Recommended Target machine (prevents wrong-machine updates)
KeyType If signed Signing key type (OpenBMC, ProductionKey, etc.)
HashType If signed Hash algorithm (RSA-SHA256, RSA-SHA512)
extended_version No Additional version details

Image File Types

File Format Description
image-kernel FIT/uImage Linux kernel, often with DTB
image-rofs SquashFS Compressed read-only root filesystem
image-rwfs ext4/UBIFS Persistent writable data
image-u-boot Binary U-Boot bootloader image
image-bmc static.mtd Complete flash image for recovery

Creating Firmware Images

# Build produces images in deploy directory
bitbake obmc-phosphor-image

# Find images
ls tmp/deploy/images/<machine>/
# obmc-phosphor-image-<machine>.tar
# obmc-phosphor-image-<machine>.static.mtd
# obmc-phosphor-image-<machine>.ubi.mtd

# Manual tarball creation (for testing)
cd tmp/deploy/images/<machine>/
tar -cvf custom-image.tar \
    MANIFEST \
    image-kernel \
    image-rofs \
    image-rwfs \
    image-u-boot

Signing Images

# Generate signing keys (one-time setup)
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -pubout -out publickey

# Sign each component
for file in image-kernel image-rofs image-rwfs image-u-boot MANIFEST; do
    openssl dgst -sha256 -sign private.pem -out ${file}.sig ${file}
done

# Create signed tarball
tar -cvf obmc-phosphor-image-signed.tar \
    MANIFEST MANIFEST.sig \
    publickey \
    image-kernel image-kernel.sig \
    image-rofs image-rofs.sig \
    image-rwfs image-rwfs.sig \
    image-u-boot image-u-boot.sig

Flash Layout & Storage

Understanding flash layout is essential for firmware update operations.

BMC Flash Layout (ASPEED)

Typical ASPEED AST2500/AST2600 flash layout:

┌──────────────────────────────────────────────────────────────────┐
│                    BMC SPI Flash (32MB/64MB)                     │
├──────────────────────────────────────────────────────────────────┤
│ Offset      │ Size    │ Name          │ Description              │
├─────────────┼─────────┼───────────────┼──────────────────────────┤
│ 0x00000000  │ 512KB   │ u-boot        │ Bootloader               │
│ 0x00080000  │ 64KB    │ u-boot-env    │ Environment variables    │
│ 0x00090000  │ 448KB   │ <reserved>    │ Future use               │
│ 0x00100000  │ 4MB     │ kernel-a      │ Kernel image A           │
│ 0x00500000  │ 20MB    │ rofs-a        │ Read-only rootfs A       │
│ 0x01900000  │ 4MB     │ kernel-b      │ Kernel image B           │
│ 0x01D00000  │ 20MB    │ rofs-b        │ Read-only rootfs B       │
│ 0x03100000  │ 4MB     │ rwfs          │ Persistent data          │
│ 0x03500000  │ 11MB    │ <reserved>    │ Future use               │
└─────────────┴─────────┴───────────────┴──────────────────────────┘

Static MTD vs UBI Layout

OpenBMC supports two flash management strategies:

Static MTD Layout

Traditional fixed-partition layout:

# In machine .conf
FLASH_SIZE = "32768"  # 32MB in KB

# Partition sizes (KB)
FLASH_UBOOT_OFFSET = "0"
FLASH_UBOOT_ENV_OFFSET = "512"
FLASH_KERNEL_OFFSET = "1024"
FLASH_ROFS_OFFSET = "5120"
FLASH_RWFS_OFFSET = "28160"
# View MTD partitions on target
cat /proc/mtd
# dev:    size   erasesize  name
# mtd0: 00080000 00001000 "u-boot"
# mtd1: 00010000 00001000 "u-boot-env"
# mtd2: 00400000 00001000 "kernel"
# mtd3: 01400000 00001000 "rofs"
# mtd4: 00400000 00001000 "rwfs"

UBI (Unsorted Block Images) Layout

Dynamic volume management with wear leveling:

# Enable UBI
IMAGE_FSTYPES += "ubi.mtd"
FLASH_UBI_OVERLAY_SIZE = "4096"  # KB
FLASH_UBI_RWFS_SIZE = "6144"     # KB
# View UBI volumes
ubinfo -a
# UBI version:                    1
# Volumes count:                  4
# Volume 0: kernel-a
# Volume 1: kernel-b
# Volume 2: rofs-a
# Volume 3: rofs-b

# Detailed volume info
ubinfo /dev/ubi0 -N rofs-a

Host Flash Layout (Intel/AMD BIOS)

┌──────────────────────────────────────────────────────────────────┐
│                    Host SPI Flash (16MB/32MB)                    │
├──────────────────────────────────────────────────────────────────┤
│ Region      │ Size    │ Description                              │
├─────────────┼─────────┼──────────────────────────────────────────┤
│ Descriptor  │ 4KB     │ Flash descriptor (regions, permissions)  │
│ BIOS        │ 8-16MB  │ UEFI firmware                            │
│ ME/PSP      │ 2-4MB   │ Intel ME / AMD PSP firmware              │
│ GbE         │ 8KB     │ Ethernet controller config               │
│ Platform    │ Varies  │ Platform-specific data                   │
└─────────────┴─────────┴──────────────────────────────────────────┘

OpenPOWER PNOR Layout

┌──────────────────────────────────────────────────────────────────┐
│                    PNOR Flash (64MB/128MB)                       │
├──────────────────────────────────────────────────────────────────┤
│ Partition   │ Size    │ Description                              │
├─────────────┼─────────┼──────────────────────────────────────────┤
│ TOC         │ 32KB    │ Table of Contents                        │
│ HBB         │ 1MB     │ Hostboot Base                            │
│ HBI         │ 16MB    │ Hostboot Extended Image                  │
│ HBRT        │ 4MB     │ Hostboot Runtime                         │
│ PAYLOAD     │ 1MB     │ OPAL Skiboot                             │
│ BOOTKERNEL  │ 32MB    │ Linux kernel + initramfs                 │
│ NVRAM       │ 576KB   │ Non-volatile settings                    │
│ GUARD       │ 16KB    │ Hardware guard records                   │
│ RINGOVD     │ 256KB   │ Ring override partition                  │
└─────────────┴─────────┴──────────────────────────────────────────┘

Setup & Configuration

Build-Time Configuration (Yocto)

# In your machine .conf or local.conf

# Include software management
IMAGE_INSTALL:append = " \
    phosphor-software-manager \
    phosphor-image-signing \
"

# Configure update options
EXTRA_OEMESON:pn-phosphor-bmc-code-mgmt = " \
    -Dfwupd-script=enabled \
    -Dsync-bmc-files=enabled \
    -Dverify-signature=enabled \
    -Dhost-bios-upgrade=enabled \
    -Dusb-code-update=enabled \
"

# Enable image signing
INHERIT += "image_types_phosphor"
IMAGE_TYPES += "static.mtd ubi.mtd"

# Configure flash layout
FLASH_SIZE = "32768"
FLASH_UBOOT_ENV_OFFSET_KB = "512"
FLASH_KERNEL_OFFSET_KB = "1024"

# Dual image support
OBMC_PHOSPHOR_IMAGE_DUAL = "1"

phosphor-bmc-code-mgmt Meson Options

Option Default Description
verify-signature enabled Require signed firmware
sync-bmc-files enabled Sync critical files between images
fwupd-script disabled Use external update script
host-bios-upgrade disabled Enable BIOS/UEFI updates
usb-code-update disabled Enable USB firmware update
side-switch-on-boot disabled Auto-switch on boot failure
software-update-dbus-interface enabled Expose D-Bus update interface
delete-images enabled Allow image deletion

Configuration Files and Paths

Config/Key File Install Path Description
Signing public key /etc/activationdata/OpenBMC/publickey Verify image signatures on the BMC
Hash type /etc/activationdata/OpenBMC/hashfunc Hash algorithm (e.g., RSA-SHA256)
MANIFEST Inside firmware tarball Image metadata (version, purpose, machine)
Field mode flag /var/lib/phosphor-bmc-code-mgmt/field-mode When present, restricts update to signed images

Deploying Signing Keys via Yocto

To enable signature verification, deploy your public key into the image:

# meta-myplatform/recipes-phosphor/flash/phosphor-bmc-code-mgmt/
# └── files/
# │   ├── publickey        # RSA public key
# │   └── hashfunc         # Contains "RSA-SHA256"
# └── phosphor-bmc-code-mgmt_%.bbappend

cat > phosphor-bmc-code-mgmt_%.bbappend << 'EOF'
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += " \
    file://publickey \
    file://hashfunc \
"

do_install:append() {
    install -d ${D}${sysconfdir}/activationdata/OpenBMC
    install -m 0444 ${WORKDIR}/publickey \
        ${D}${sysconfdir}/activationdata/OpenBMC/
    install -m 0444 ${WORKDIR}/hashfunc \
        ${D}${sysconfdir}/activationdata/OpenBMC/
}
EOF

Generate the key pair:

# One-time setup (keep private.pem secure!)
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -pubout -out publickey
echo "RSA-SHA256" > hashfunc

Enabling Field Mode

Field mode restricts the BMC to only accept signed firmware:

# Enable field mode (persists across reboots)
busctl set-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software \
    xyz.openbmc_project.Control.FieldMode FieldModeEnabled b true

# Verify field mode
busctl get-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software \
    xyz.openbmc_project.Control.FieldMode FieldModeEnabled

Runtime Configuration

# Check software manager status
systemctl status phosphor-software-manager@bmc
systemctl status phosphor-version-software-manager

# View update logs
journalctl -u phosphor-software-manager@bmc -f

# Check current firmware versions
busctl tree xyz.openbmc_project.Software.BMC.Updater

# List all software objects
busctl call xyz.openbmc_project.ObjectMapper \
    /xyz/openbmc_project/object_mapper \
    xyz.openbmc_project.ObjectMapper \
    GetSubTree sias "/xyz/openbmc_project/software" 0 1 \
    "xyz.openbmc_project.Software.Version"

D-Bus Software Interfaces

# Key interfaces exposed by phosphor-software-manager:

# Software.Version - Version information
busctl introspect xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<id> \
    xyz.openbmc_project.Software.Version

# Software.Activation - Activation state
busctl introspect xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<id> \
    xyz.openbmc_project.Software.Activation

# Software.RedundancyPriority - Boot priority
busctl introspect xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<id> \
    xyz.openbmc_project.Software.RedundancyPriority

Firmware Inventory

View Current Versions

# Via Redfish
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory

# Get specific firmware info
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/bmc_active

# Via D-Bus
busctl tree xyz.openbmc_project.Software.BMC.Updater

Firmware Response

{
    "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bmc_active",
    "Id": "bmc_active",
    "Name": "BMC Firmware",
    "Version": "2.12.0",
    "Status": {
        "Health": "OK",
        "State": "Enabled"
    },
    "Updateable": true
}

Update Methods

OpenBMC supports multiple update interfaces, each with specific use cases.

Redfish Update Service

The primary update method for modern deployments:

# Upload firmware image via HttpPushUri
curl -k -u root:0penBmc \
    -X POST \
    -H "Content-Type: application/octet-stream" \
    --data-binary @obmc-phosphor-image.tar \
    https://localhost/redfish/v1/UpdateService

# Check UpdateService status
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService

# Response shows update capabilities
{
    "@odata.id": "/redfish/v1/UpdateService",
    "HttpPushUri": "/redfish/v1/UpdateService",
    "HttpPushUriOptions": {
        "HttpPushUriApplyTime": {
            "ApplyTime": "OnReset"
        }
    },
    "MaxImageSizeBytes": 33554432,
    "ServiceEnabled": true
}

SimpleUpdate Action

For network-based updates:

# Update from TFTP server
curl -k -u root:0penBmc -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "TransferProtocol": "TFTP",
        "ImageURI": "tftp://192.168.1.100/firmware.tar"
    }' \
    https://localhost/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate

# Update from HTTPS server
curl -k -u root:0penBmc -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "TransferProtocol": "HTTPS",
        "ImageURI": "https://server.example.com/firmware.tar"
    }' \
    https://localhost/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate

# Update from SCP (requires credentials)
curl -k -u root:0penBmc -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "TransferProtocol": "SCP",
        "ImageURI": "scp://user@server.example.com/path/to/firmware.tar",
        "UserName": "user",
        "Password": "password"
    }' \
    https://localhost/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate

IPMI OEM Firmware Update

Using phosphor-ipmi-flash for IPMI-based updates:

# IPMI OEM firmware update commands (host-side)
# Uses OEM commands to transfer firmware via IPMI

# Start firmware transfer session
ipmitool raw 0x2e 0x00 0x00 0x00 0x01  # OEM start

# Transfer data in chunks (simplified)
ipmitool raw 0x2e 0x01 <offset> <data>  # OEM data

# Finalize and verify
ipmitool raw 0x2e 0x02  # OEM verify

# Activate firmware
ipmitool raw 0x2e 0x03  # OEM activate

phosphor-ipmi-flash Configuration

# Enable IPMI flash support
IMAGE_INSTALL:append = " phosphor-ipmi-flash"

# Configure supported transports
EXTRA_OEMESON:pn-phosphor-ipmi-flash = " \
    -Dlpc-type=nuvoton-lpc \
    -Dpci-bridge=true \
"
// /usr/share/ipmi-flash/config/config.json
{
    "handlers": [
        {
            "handler": "static",
            "path": "/run/initramfs/image-bmc"
        }
    ],
    "actions": [
        {
            "type": "systemd",
            "unit": "phosphor-ipmi-flash-bmc-update.target"
        }
    ]
}

PLDM Firmware Update (Type 5)

PLDM Type 5 firmware update for component updates:

# Query firmware devices
pldmtool fw_update GetFwParams -m <eid>

# Request firmware update
pldmtool fw_update RequestUpdate -m <eid> \
    --max_transfer_size 4096 \
    --num_comps 1 \
    --max_outstanding_transfer_req 2 \
    --pkg_data_len 0 \
    --comp_image_set_ver "1.0.0"

# Pass component table
pldmtool fw_update PassComponentTable -m <eid> \
    --transfer_flag 0x05 \
    --comp_classification 0x0A \
    --comp_identifier 0x0001 \
    --comp_classification_index 0 \
    --comp_comparison_stamp 0 \
    --comp_ver "1.0.0" \
    --comp_ver_str_type 1 \
    --comp_ver_str_len 5

# Update component
pldmtool fw_update UpdateComponent -m <eid> \
    --comp_classification 0x0A \
    --comp_identifier 0x0001 \
    --comp_classification_index 0

PLDM Update Flow

---
title: PLDM Update Flow
---
sequenceDiagram
    participant BMC as BMC (pldmd)
    participant Host as Update Agent (Host)

    Host->>BMC: QueryDeviceIdentifiers
    BMC->>Host: DeviceIdentifiers

    Host->>BMC: GetFirmwareParameters
    BMC->>Host: FirmwareParameters

    Host->>BMC: RequestUpdate
    BMC->>Host: RequestUpdateResp (ACK)

    Host->>BMC: PassComponentTable
    BMC->>Host: PassComponentTableResp

    Host->>BMC: UpdateComponent
    BMC->>Host: UpdateComponentResp

    loop Data Transfer
        BMC->>Host: RequestFirmwareData
        Host->>BMC: FirmwareData
    end

    BMC->>Host: TransferComplete
    Host->>BMC: TransferCompleteResp

    BMC->>Host: VerifyComplete
    Host->>BMC: VerifyCompleteResp

    BMC->>Host: ApplyComplete
    Host->>BMC: ApplyCompleteResp

    Host->>BMC: ActivateFirmware
    BMC->>Host: ActivateFirmwareResp
ASCII-art version (for comparison)
┌────────────┐                    ┌────────────────┐
│    BMC     │                    │  Update Agent  │
│  (pldmd)   │                    │    (Host)      │
└─────┬──────┘                    └───────┬────────┘
      │                                   │
      │      QueryDeviceIdentifiers       │
      │<──────────────────────────────────│
      │      DeviceIdentifiers            │
      │──────────────────────────────────>│
      │                                   │
      │      GetFirmwareParameters        │
      │<──────────────────────────────────│
      │      FirmwareParameters           │
      │──────────────────────────────────>│
      │                                   │
      │      RequestUpdate                │
      │<──────────────────────────────────│
      │      RequestUpdateResp (ACK)      │
      │──────────────────────────────────>│
      │                                   │
      │      PassComponentTable           │
      │<──────────────────────────────────│
      │      PassComponentTableResp       │
      │──────────────────────────────────>│
      │                                   │
      │      UpdateComponent              │
      │<──────────────────────────────────│
      │      UpdateComponentResp          │
      │──────────────────────────────────>│
      │                                   │
      │      RequestFirmwareData (loop)   │
      │──────────────────────────────────>│
      │      FirmwareData                 │
      │<──────────────────────────────────│
      │                                   │
      │      TransferComplete             │
      │──────────────────────────────────>│
      │      TransferCompleteResp         │
      │<──────────────────────────────────│
      │                                   │
      │      VerifyComplete               │
      │──────────────────────────────────>│
      │      VerifyCompleteResp           │
      │<──────────────────────────────────│
      │                                   │
      │      ApplyComplete                │
      │──────────────────────────────────>│
      │      ApplyCompleteResp            │
      │<──────────────────────────────────│
      │                                   │
      │      ActivateFirmware             │
      │<──────────────────────────────────│
      │      ActivateFirmwareResp         │
      │──────────────────────────────────>│

WebUI Update

  1. Login to WebUI at https://<bmc-ip>/
  2. Navigate to OperationsFirmware
  3. Click Upload firmware
  4. Select firmware file (.tar format)
  5. Wait for upload and verification
  6. Click Activate when ready
  7. Optionally select Reboot BMC after activation

USB Code Update

# USB code update directory structure:
# /mnt/usb/<usb-device>/
# └── firmware/
#     └── image-bmc               # Firmware tarball (renamed)

# BMC-side: Check for USB device
lsblk
# NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
# sda      8:0    1  7.5G  0 disk
# └─sda1   8:1    1  7.5G  0 part /media/usb

# Configuration in Yocto
EXTRA_OEMESON:pn-phosphor-bmc-code-mgmt:append = " -Dusb-code-update=enabled"

# USB monitor service watches for:
# - USB insertion events
# - Files matching firmware pattern
# - Triggers automatic update if policy allows

Command-Line Update Tools

# Direct flash update (recovery only)
# WARNING: Use only for recovery, bypasses safety checks

# Backup current image first
dd if=/dev/mtd0 of=/tmp/backup-kernel.bin
dd if=/dev/mtd1 of=/tmp/backup-rofs.bin

# Flash new image
flashcp -v /tmp/image-kernel /dev/mtd0
flashcp -v /tmp/image-rofs /dev/mtd1

# For UBI volumes
ubiupdatevol /dev/ubi0_0 /tmp/image-kernel
ubiupdatevol /dev/ubi0_1 /tmp/image-rofs

Dual Image Support

OpenBMC implements A/B redundant boot for high availability.

Dual Image Architecture

---
title: Dual Image Architecture - BMC SPI Flash
---
flowchart TB
    subgraph shared["Shared"]
        direction LR
        uboot["U-Boot<br/>(shared)"]
        ubootenv["U-Boot Env<br/>(shared)"]
        rwfs["Persistent Data<br/>(rwfs)"]
    end

    subgraph images[" "]
        direction LR
        subgraph imageA["Image A (Active)"]
            kernelA["kernel-a<br/>(FIT image)"]
            rofsA["rofs-a<br/>(SquashFS)"]
            versionA["Version: 2.12.0<br/>Priority: 0 (boot)"]
        end
        subgraph imageB["Image B (Standby)"]
            kernelB["kernel-b<br/>(FIT image)"]
            rofsB["rofs-b<br/>(SquashFS)"]
            versionB["Version: 2.11.0<br/>Priority: 1 (standby)"]
        end
    end

    shared --- images

    style images fill:none,stroke:none
ASCII-art version (for comparison)
┌─────────────────────────────────────────────────────────────────────────────┐
│                           BMC SPI Flash                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                           Shared                                    │    │
│  │  ┌────────────────┐  ┌────────────────┐  ┌────────────────┐         │    │
│  │  │    U-Boot      │  │   U-Boot Env   │  │  Persistent    │         │    │
│  │  │   (shared)     │  │   (shared)     │  │     Data       │         │    │
│  │  │                │  │                │  │    (rwfs)      │         │    │
│  │  └────────────────┘  └────────────────┘  └────────────────┘         │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                             │
│  ┌──────────────────────────┐  ┌──────────────────────────┐                 │
│  │       Image A            │  │       Image B            │                 │
│  │      (Active)            │  │      (Standby)           │                 │
│  │                          │  │                          │                 │
│  │  ┌──────────────────┐    │  │  ┌──────────────────┐    │                 │
│  │  │  kernel-a        │    │  │  │  kernel-b        │    │                 │
│  │  │  (FIT image)     │    │  │  │  (FIT image)     │    │                 │
│  │  └──────────────────┘    │  │  └──────────────────┘    │                 │
│  │                          │  │                          │                 │
│  │  ┌──────────────────┐    │  │  ┌──────────────────┐    │                 │
│  │  │  rofs-a          │    │  │  │  rofs-b          │    │                 │
│  │  │  (SquashFS)      │    │  │  │  (SquashFS)      │    │                 │
│  │  └──────────────────┘    │  │  └──────────────────┘    │                 │
│  │                          │  │                          │                 │
│  │  Version: 2.12.0         │  │  Version: 2.11.0         │                 │
│  │  Priority: 0 (boot)      │  │  Priority: 1 (standby)   │                 │
│  └──────────────────────────┘  └──────────────────────────┘                 │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

View Images via Redfish

# List all firmware
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory

# Response
{
    "Members": [
        {"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bmc_active"},
        {"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/abc12345"}
    ]
}

# Get active image details
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/bmc_active

View Images via D-Bus

# List software versions
busctl tree xyz.openbmc_project.Software.BMC.Updater
# /xyz/openbmc_project/software
# ├─ /xyz/openbmc_project/software/abc12345  (active)
# └─ /xyz/openbmc_project/software/def67890  (standby)

# Get version info
busctl get-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/abc12345 \
    xyz.openbmc_project.Software.Version Version
# s "2.12.0"

# Get activation state
busctl get-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/abc12345 \
    xyz.openbmc_project.Software.Activation Activation
# s "xyz.openbmc_project.Software.Activation.Activations.Active"

# Get boot priority (0 = primary, higher = lower priority)
busctl get-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/abc12345 \
    xyz.openbmc_project.Software.RedundancyPriority Priority
# u 0

Set Boot Priority

# Set image as primary (priority 0)
busctl set-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/def67890 \
    xyz.openbmc_project.Software.RedundancyPriority \
    Priority u 0

# Via Redfish - activate backup firmware
curl -k -u root:0penBmc -X POST \
    -H "Content-Type: application/json" \
    -d '{}' \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/def67890/Actions/SoftwareInventory.Activate

U-Boot Environment & Boot Control

Key U-Boot Environment Variables

# View all U-Boot environment variables
fw_printenv

# Key variables for firmware update:

# bootside - Which image to boot (a or b)
fw_printenv bootside
# bootside=a

# bootcount - Boot attempt counter
fw_printenv bootcount
# bootcount=0

# bootlimit - Max boot attempts before fallback
fw_printenv bootlimit
# bootlimit=3

# kernelname - Kernel partition name
fw_printenv kernelname
# kernelname=kernel-a

# rofsname - Root filesystem partition
fw_printenv rofsname
# rofsname=rofs-a

U-Boot Boot Logic

---
title: U-Boot Boot Flow
---
flowchart TB
    step1["1. Read bootside (a or b)"]
    step2["2. Increment bootcount"]
    step3{"3. bootcount > bootlimit?"}
    switch["Switch bootside<br/>Reset bootcount<br/>Retry boot"]
    step4["4. Load kernel from bootside"]
    step5["5. Boot Linux"]
    step6["6. User-space resets bootcount to 0<br/>(via init script or systemd service)"]

    step1 --> step2
    step2 --> step3
    step3 -->|Yes| switch
    switch --> step1
    step3 -->|No| step4
    step4 --> step5
    step5 --> step6
ASCII-art version (for comparison)
┌───────────────────────────────────────────────────────────────┐
│                    U-Boot Boot Flow                           │
├───────────────────────────────────────────────────────────────┤
│                                                               │
│  1. Read bootside (a or b)                                    │
│           │                                                   │
│           ▼                                                   │
│  2. Increment bootcount                                       │
│           │                                                   │
│           ▼                                                   │
│  3. bootcount > bootlimit?  ───Yes──► Switch bootside         │
│           │                           Reset bootcount         │
│          No                           Retry boot              │
│           │                                                   │
│           ▼                                                   │
│  4. Load kernel from bootside                                 │
│           │                                                   │
│           ▼                                                   │
│  5. Boot Linux                                                │
│           │                                                   │
│           ▼                                                   │
│  6. User-space resets bootcount to 0                          │
│           (via init script or systemd service)                │
│                                                               │
└───────────────────────────────────────────────────────────────┘

Manual Boot Control

# Force boot from specific side
fw_setenv bootside b
reboot

# Reset boot counter (call after successful boot)
fw_setenv bootcount 0

# Increase boot limit for debugging
fw_setenv bootlimit 5

# One-time boot override (doesn't change bootside)
fw_setenv bootonce b
reboot

# View boot arguments
fw_printenv bootargs
# bootargs=console=ttyS4,115200 root=/dev/mtdblock3 rootfstype=squashfs

Recovery via Serial Console

If boot fails and you have serial access:

# At U-Boot prompt (interrupt boot with key press)
=> printenv bootside
bootside=a

# Switch to other image
=> setenv bootside b
=> saveenv
=> reset

# Or boot directly without saving
=> setenv bootside b
=> run bootcmd

Failsafe Behavior

Automatic Boot Fallback

---
title: Boot Failure Recovery
---
flowchart TB
    subgraph attempt1["Boot Attempt 1 (Image A)"]
        direction LR
        a1s["Success → bootcount = 0, run normally"]
        a1f["Fail → bootcount++"]
    end

    subgraph attempt2["Boot Attempt 2 (Image A)"]
        direction LR
        a2s["Success → bootcount = 0"]
        a2f["Fail → bootcount++ (now 2)"]
    end

    subgraph attempt3["Boot Attempt 3 (Image A)"]
        direction LR
        a3s["Success → bootcount = 0"]
        a3f["Fail → bootcount++ (now 3)<br/>Switch bootside to B<br/>Reset bootcount to 0"]
    end

    subgraph attempt4["Boot Attempt 4 (Image B)"]
        direction LR
        a4s["Success → bootcount = 0, run from backup"]
        a4f["Fail → bootcount++"]
    end

    cont["... continues alternating ..."]

    attempt1 --> attempt2 --> attempt3 --> attempt4 --> cont
ASCII-art version (for comparison)
┌────────────────────────────────────────────────────────────────┐
│                  Boot Failure Recovery                         │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  Boot Attempt 1 (Image A)                                      │
│     ├─ Success → bootcount = 0, run normally                   │
│     └─ Fail → bootcount++                                      │
│                                                                │
│  Boot Attempt 2 (Image A)                                      │
│     ├─ Success → bootcount = 0                                 │
│     └─ Fail → bootcount++ (now 2)                              │
│                                                                │
│  Boot Attempt 3 (Image A)                                      │
│     ├─ Success → bootcount = 0                                 │
│     └─ Fail → bootcount++ (now 3, equals bootlimit)            │
│               Switch bootside to B                             │
│               Reset bootcount to 0                             │
│                                                                │
│  Boot Attempt 4 (Image B)                                      │
│     ├─ Success → bootcount = 0, run from backup                │
│     └─ Fail → bootcount++                                      │
│                                                                │
│  ... continues alternating ...                                 │
│                                                                │
└────────────────────────────────────────────────────────────────┘

Boot Health Check Service

# phosphor-software-manager runs boot health check
# On successful boot, clears boot counter

# Check service status
systemctl status obmc-flash-bmc-setenv@bootcount

# Manual reset
fw_setenv bootcount 0

# View boot health log
journalctl -u obmc-flash-bmc-setenv@bootcount

Recovery Mode

# Force recovery to backup image
fw_setenv bootside b
reboot

# Emergency: Use U-Boot to load recovery image from TFTP
# At U-Boot prompt:
=> setenv serverip 192.168.1.100
=> setenv ipaddr 192.168.1.50
=> tftp 0x83000000 recovery-image.bin
=> bootm 0x83000000

# Full factory recovery via static.mtd image
# At U-Boot prompt:
=> sf probe
=> tftp 0x83000000 obmc-phosphor-image.static.mtd
=> sf update 0x83000000 0x0 ${filesize}
=> reset

Firmware Signing & Verification

Signing Infrastructure Overview

---
title: Firmware Signing Infrastructure
---
flowchart LR
    subgraph buildserver["Build Server"]
        privkey["Private Key<br/>(kept secure)"]
        sign["Sign Components<br/>- MANIFEST<br/>- image-kernel<br/>- image-rofs<br/>- image-u-boot"]
        tarball["Create Tarball<br/>with signatures"]
        privkey --> sign --> tarball
    end

    subgraph bmctarget["BMC Target"]
        pubkey["Public Key<br/>(/etc/activation data/)"]
        verify["Verify Signatures<br/>- Compare hashes<br/>- Validate chain<br/>- Check key type"]
        decision["Accept/Reject<br/>Update"]
        pubkey --> verify --> decision
    end

    buildserver -->|"Transfer"| bmctarget
ASCII-art version (for comparison)
┌───────────────────────────────────────────────────────────────────────────┐
│                    Firmware Signing Infrastructure                        │
├───────────────────────────────────────────────────────────────────────────┤
│                                                                           │
│  Build Server                           BMC Target                        │
│  ┌───────────────────────────┐        ┌────────────────────────────┐      │
│  │                           │        │                            │      │
│  │  ┌──────────────────────┐ │        │  ┌──────────────────────┐  │      │
│  │  │   Private Key        │ │        │  │   Public Key         │  │      │
│  │  │   (kept secure)      │ │        │  │   (/etc/activation   │  │      │
│  │  └──────────┬───────────┘ │        │  │    data/)            │  │      │
│  │             │             │        │  └──────────┬───────────┘  │      │
│  │             ▼             │        │             │              │      │
│  │  ┌──────────────────────┐ │        │             ▼              │      │
│  │  │  Sign Components     │ │        │  ┌──────────────────────┐  │      │
│  │  │  - MANIFEST          │ │        │  │  Verify Signatures   │  │      │
│  │  │  - image-kernel      │ │  ───►  │  │  - Compare hashes    │  │      │
│  │  │  - image-rofs        │ │        │  │  - Validate chain    │  │      │
│  │  │  - image-u-boot      │ │        │  │  - Check key type    │  │      │
│  │  └──────────┬───────────┘ │        │  └──────────┬───────────┘  │      │
│  │             │             │        │             │              │      │
│  │             ▼             │        │             ▼              │      │
│  │  ┌──────────────────────┐ │        │  ┌──────────────────────┐  │      │
│  │  │  Create Tarball      │ │        │  │  Accept/Reject       │  │      │
│  │  │  with signatures     │ │        │  │  Update              │  │      │
│  │  └──────────────────────┘ │        │  └──────────────────────┘  │      │
│  │                           │        │                            │      │
│  └───────────────────────────┘        └────────────────────────────┘      │
│                                                                           │
└───────────────────────────────────────────────────────────────────────────┘

Generate Signing Keys

# Create 4096-bit RSA keypair for production
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -pubout -out publickey

# Create self-signed certificate (for key identification)
openssl req -new -x509 -key private.pem -out cert.pem -days 3650 \
    -subj "/CN=OpenBMC Firmware Signing/O=My Organization"

# View key information
openssl rsa -in publickey -pubin -text -noout

# For development/testing (weaker key)
openssl genrsa -out dev-private.pem 2048
openssl rsa -in dev-private.pem -pubout -out dev-publickey

Sign Firmware Components

# Sign each component with SHA-256 RSA signature
for file in MANIFEST image-kernel image-rofs image-rwfs image-u-boot; do
    if [ -f "$file" ]; then
        openssl dgst -sha256 -sign private.pem -out ${file}.sig ${file}
        echo "Signed: $file"
    fi
done

# Create MANIFEST with signature metadata
cat > MANIFEST << 'EOF'
purpose=xyz.openbmc_project.Software.Version.VersionPurpose.BMC
version=2.12.0
MachineName=romulus
KeyType=OpenBMC
HashType=RSA-SHA256
EOF

# Sign the MANIFEST itself
openssl dgst -sha256 -sign private.pem -out MANIFEST.sig MANIFEST

# Create signed tarball
tar -cvf obmc-phosphor-image-signed.tar \
    MANIFEST MANIFEST.sig \
    publickey \
    image-kernel image-kernel.sig \
    image-rofs image-rofs.sig \
    image-rwfs image-rwfs.sig \
    image-u-boot image-u-boot.sig

Configure Verification in Yocto

# In your distro or local.conf

# Enable signature verification
EXTRA_OEMESON:pn-phosphor-bmc-code-mgmt:append = " -Dverify-signature=enabled"

# Configure public key provider
PREFERRED_PROVIDER_virtual/phosphor-software-manager-system-public-key = \
    "phosphor-software-manager-public-key-${MACHINE}"

# Key installation location
# Keys installed to: /etc/activationdata/

# Custom key type name
SIGNING_KEY_TYPE = "OpenBMC"

Create a recipe for your public key:

# meta-mymachine/recipes-phosphor/software/phosphor-software-manager-public-key-mymachine.bb

SUMMARY = "Public key for firmware verification"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=..."

inherit allarch

SRC_URI = "file://publickey"

do_install() {
    install -d ${D}${sysconfdir}/activationdata
    install -m 0644 ${WORKDIR}/publickey \
        ${D}${sysconfdir}/activationdata/key-OpenBMC
}

FILES:${PN} = "${sysconfdir}/activationdata"

RPROVIDES:${PN} = "virtual/phosphor-software-manager-system-public-key"

Verification Flow

---
title: Signature Verification Flow
---
flowchart TB
    step1["1. Upload firmware tarball"]
    step2["2. Extract to /tmp/images/random-id/"]
    step3["3. Parse MANIFEST<br/>- Read KeyType → OpenBMC<br/>- Read HashType → RSA-SHA256<br/>- Validate MachineName"]
    step4{"4. Load public key from<br/>/etc/activationdata/key-KeyType"}
    reject1["REJECT<br/>(unless verify-signature=disabled)"]
    step5["5. Verify MANIFEST signature<br/>openssl dgst -sha256 -verify"]
    step6["6. Verify each component signature<br/>- image-kernel<br/>- image-rofs<br/>- image-rwfs<br/>- image-u-boot"]
    step7{"7. All signatures valid?"}
    accept["Proceed with activation"]
    reject2["REJECT, log error,<br/>delete extracted files"]

    step1 --> step2 --> step3 --> step4
    step4 -->|Key not found| reject1
    step4 -->|Key found| step5
    step5 --> step6 --> step7
    step7 -->|Yes| accept
    step7 -->|No| reject2
ASCII-art version (for comparison)
┌──────────────────────────────────────────────────────────────────────────┐
│                   Signature Verification Flow                            │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. Upload firmware tarball                                              │
│           │                                                              │
│           ▼                                                              │
│  2. Extract to /tmp/images/<random-id>/                                  │
│           │                                                              │
│           ▼                                                              │
│  3. Parse MANIFEST                                                       │
│     ├─ Read KeyType → "OpenBMC"                                          │
│     ├─ Read HashType → "RSA-SHA256"                                      │
│     └─ Read MachineName → validate against current machine               │
│           │                                                              │
│           ▼                                                              │
│  4. Load public key from /etc/activationdata/key-<KeyType>               │
│     └─ If key not found → REJECT (unless verify-signature=disabled)      │
│           │                                                              │
│           ▼                                                              │
│  5. Verify MANIFEST signature                                            │
│     └─ openssl dgst -sha256 -verify <pubkey> -signature MANIFEST.sig     │
│           │                                                              │
│           ▼                                                              │
│  6. Verify each component signature                                      │
│     ├─ image-kernel.sig vs image-kernel                                  │
│     ├─ image-rofs.sig vs image-rofs                                      │
│     ├─ image-rwfs.sig vs image-rwfs                                      │
│     └─ image-u-boot.sig vs image-u-boot                                  │
│           │                                                              │
│           ▼                                                              │
│  7. All signatures valid?                                                │
│     ├─ Yes → Proceed with activation                                     │
│     └─ No → REJECT, log error, delete extracted files                    │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘

Manual Signature Verification

# On the BMC, manually verify an image

# Extract tarball
mkdir -p /tmp/verify-test
cd /tmp/verify-test
tar -xvf /tmp/firmware.tar

# Check MANIFEST
cat MANIFEST

# Verify MANIFEST signature
openssl dgst -sha256 -verify /etc/activationdata/key-OpenBMC \
    -signature MANIFEST.sig MANIFEST

# Verify component signatures
for file in image-kernel image-rofs image-rwfs image-u-boot; do
    if [ -f "$file" ] && [ -f "${file}.sig" ]; then
        echo -n "Verifying $file: "
        openssl dgst -sha256 -verify /etc/activationdata/key-OpenBMC \
            -signature ${file}.sig ${file}
    fi
done

Signature Verification Logs

# Check verification results
journalctl -u phosphor-software-manager | grep -i -E "(signature|verify|key)"

# Example output for successful verification:
# phosphor-software-manager[1234]: Signature verification passed for image abc12345
# phosphor-software-manager[1234]: Image abc12345 is valid

# Example output for failed verification:
# phosphor-software-manager[1234]: Signature verification failed for MANIFEST
# phosphor-software-manager[1234]: Error: Invalid signature
# phosphor-software-manager[1234]: Rejecting image def67890

Key Type Configuration

Support multiple key types for different environments:

# /etc/activationdata/ structure
/etc/activationdata/
├── key-OpenBMC           # Development keys
├── key-ProductionKey     # Production keys
└── key-TestKey           # Test/staging keys

# MANIFEST selects which key to use:
# KeyType=ProductionKey → uses /etc/activationdata/key-ProductionKey

Host Firmware Update

BIOS/UEFI Update (Intel/AMD)

# Upload BIOS image via Redfish
curl -k -u root:0penBmc \
    -X POST \
    -H "Content-Type: application/octet-stream" \
    --data-binary @bios.bin \
    https://localhost/redfish/v1/UpdateService

# Check BIOS firmware inventory
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/bios

# Response
{
    "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios",
    "Id": "bios",
    "Name": "BIOS Firmware",
    "Version": "1.23.0",
    "Updateable": true,
    "Status": {
        "State": "Enabled",
        "Health": "OK"
    }
}

Intel SPS/ME Firmware

# Query ME firmware version
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/me

# ME update typically requires specific tools
# Coordinated with BIOS update

PNOR Update (OpenPOWER)

# Upload PNOR tarball
curl -k -u root:0penBmc \
    -X POST \
    -H "Content-Type: application/octet-stream" \
    --data-binary @pnor.tar \
    https://localhost/redfish/v1/UpdateService

# PNOR image structure
pnor.tar
├── MANIFEST           # purpose=Host, version, MachineName
├── HOST_FIRMWARE/
│   ├── HBB            # Hostboot Base
│   ├── HBI            # Hostboot Image
│   ├── HBRT           # Hostboot Runtime
│   ├── PAYLOAD        # Skiboot (OPAL)
│   └── BOOTKERNEL     # Linux kernel
└── *.sig              # Signatures

openpower-pnor-code-mgmt

# View PNOR partitions
pflash -i

# Read specific partition
pflash -P HBB -r /tmp/hbb.bin

# Services involved
systemctl status openpower-update-bios@0.service

PSU Firmware Update

# List PSU firmware
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory \
    | jq '.Members[] | select(.["@odata.id"] | contains("psu"))'

# PSU update via PMBUS or I2C
# Requires specific PSU support in OpenBMC

Component-Level Update (PLDM)

# Use pldmtool for component updates (VR, CPLD, etc.)
# Get supported components
pldmtool fw_update GetFwParams -m <eid>

# Component classifications:
# 0x00 - Unknown
# 0x01 - Other
# 0x02 - Driver
# 0x03 - Configuration
# 0x04 - Application
# 0x05 - Instrumentation
# 0x06 - Firmware/BIOS
# 0x07 - Diagnostic
# 0x0A - Firmware
# 0x0B - CPLD/FPGA
# 0x0C - VR

Update Workflow Deep Dive

Complete Update Sequence

---
title: Firmware Update Workflow
---
flowchart TB
    subgraph upload["1. UPLOAD"]
        u1["Receive via Redfish/IPMI/PLDM"]
        u2["Store in /tmp/images/random-id/"]
        u3["Create Software.Version D-Bus object"]
    end

    subgraph extract["2. EXTRACT & PARSE"]
        e1["Extract tarball contents"]
        e2["Parse MANIFEST file"]
        e3["Validate MachineName"]
        e4["Check version purpose"]
    end

    subgraph verify["3. VERIFY (if enabled)"]
        v1["Load public key"]
        v2["Verify MANIFEST signature"]
        v3["Verify component signatures"]
        v4["REJECT if any fails"]
    end

    subgraph ready["4. READY"]
        r1["Set Activation = Ready"]
        r2["Create RedundancyPriority"]
        r3["Wait for activation"]
    end

    subgraph activating["5. ACTIVATING"]
        a1["Set Activation = Activating"]
        a2["Erase standby partition"]
        a3["Write images to flash"]
        a4["Update U-Boot variables"]
    end

    subgraph active["6. ACTIVE"]
        ac1["Set Activation = Active"]
        ac2["Set Priority = 0"]
        ac3["Optional: trigger reboot"]
    end

    subgraph postverify["7. VERIFY (post-reboot)"]
        p1["Boot new image"]
        p2["Reset bootcount to 0"]
        p3["Log successful update"]
    end

    upload --> extract --> verify --> ready --> activating --> active --> postverify
ASCII-art version (for comparison)
┌─────────────────────────────────────────────────────────────────────────────┐
│                        Firmware Update Workflow                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1. UPLOAD                                                                  │
│     ├─ Receive via Redfish/IPMI/PLDM                                        │
│     ├─ Store in /tmp/images/<random-id>/                                    │
│     └─ Create Software.Version D-Bus object                                 │
│                                                                             │
│  2. EXTRACT & PARSE                                                         │
│     ├─ Extract tarball contents                                             │
│     ├─ Parse MANIFEST file                                                  │
│     ├─ Validate MachineName against current machine                         │
│     └─ Check version purpose (BMC/Host/System)                              │
│                                                                             │
│  3. VERIFY (if signature verification enabled)                              │
│     ├─ Load public key from /etc/activationdata/key-<KeyType>               │
│     ├─ Verify MANIFEST signature                                            │
│     ├─ Verify each component signature                                      │
│     └─ REJECT if any verification fails                                     │
│                                                                             │
│  4. READY                                                                   │
│     ├─ Set Activation = Ready                                               │
│     ├─ Create RedundancyPriority interface                                  │
│     └─ Wait for activation request                                          │
│                                                                             │
│  5. ACTIVATING                                                              │
│     ├─ Set Activation = Activating                                          │
│     ├─ Lock flash access                                                    │
│     ├─ Erase standby partition                                              │
│     ├─ Write image-kernel to kernel partition                               │
│     ├─ Write image-rofs to rofs partition                                   │
│     ├─ Write image-rwfs to rwfs partition (if present)                      │
│     └─ Update U-Boot variables                                              │
│                                                                             │
│  6. ACTIVE                                                                  │
│     ├─ Set Activation = Active                                              │
│     ├─ Set Priority = 0 (primary)                                           │
│     ├─ Demote previous image priority                                       │
│     └─ Optional: trigger reboot                                             │
│                                                                             │
│  7. VERIFY (post-reboot)                                                    │
│     ├─ Boot new image                                                       │
│     ├─ Reset bootcount to 0                                                 │
│     └─ Log successful update                                                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Activation States

State Description
NotReady Image uploaded but not yet processed
Invalid Image validation failed
Ready Image verified, waiting for activation
Activating Write in progress to flash
Active Image is installed and bootable
Failed Activation failed

Monitor Update Progress

# Via Redfish Task Service
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/TaskService/Tasks

# Get specific task
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/TaskService/Tasks/1

# Task states: New, Starting, Running, Completed, Exception

# Via D-Bus monitoring
busctl monitor xyz.openbmc_project.Software.BMC.Updater

# Watch activation progress
busctl get-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<id> \
    xyz.openbmc_project.Software.Activation Activation

# Watch for ActivationProgress (percentage)
busctl get-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<id> \
    xyz.openbmc_project.Software.ActivationProgress Progress

Progress Indication

# ActivationProgress interface shows percentage
# 0-10%: Extracting
# 10-20%: Verifying signatures
# 20-40%: Erasing flash
# 40-90%: Writing flash
# 90-100%: Finalizing

# Via journald
journalctl -u phosphor-software-manager@bmc -f
# [date] Progress: 25%
# [date] Writing kernel partition...
# [date] Progress: 50%
# [date] Writing rootfs partition...
# [date] Progress: 90%
# [date] Activation complete

Configuration Options

Update Settings

# Configure via Redfish
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{
        "HttpPushUriOptions": {
            "HttpPushUriApplyTime": {
                "ApplyTime": "Immediate"
            }
        }
    }' \
    https://localhost/redfish/v1/UpdateService

Apply Time Options

Option Description
Immediate Apply and reboot immediately
OnReset Apply on next BMC reboot
AtMaintenanceWindowStart Schedule for maintenance window

Troubleshooting

Upload Fails

# Check available space in /tmp
df -h /tmp
# Minimum required: image size + extraction overhead (~2x image size)

# Check bmcweb body size limit
# Default is typically 30MB, configurable in bmcweb
cat /etc/bmcweb_persistent_data.json | jq .http_body_limit

# Verify tarball integrity
file firmware.tar
# firmware.tar: POSIX tar archive (GNU)

tar -tvf firmware.tar
# -rw-r--r-- 0/0     123 2024-01-15 10:00 MANIFEST
# -rw-r--r-- 0/0 4194304 2024-01-15 10:00 image-kernel
# -rw-r--r-- 0/0 20971520 2024-01-15 10:00 image-rofs

# Check for required files
tar -tf firmware.tar | grep -E "^(MANIFEST|image-)"

# Common upload errors:
# - "413 Request Entity Too Large" → Image too big
# - "503 Service Unavailable" → Service overloaded
# - Connection reset → Timeout or memory issue

Signature Verification Failed

# Check installed public keys
ls -la /etc/activationdata/
# -rw-r--r-- 1 root root 800 Jan 15 10:00 key-OpenBMC

# Check MANIFEST KeyType matches installed key
tar -xOf firmware.tar MANIFEST | grep KeyType
# KeyType=OpenBMC
# → Needs /etc/activationdata/key-OpenBMC

# Verify signature manually
cd /tmp
tar -xf firmware.tar
openssl dgst -sha256 -verify /etc/activationdata/key-OpenBMC \
    -signature MANIFEST.sig MANIFEST
# Verified OK  or  Verification Failure

# Common signature errors:
# - "Public key not found" → Missing key file
# - "Verification Failure" → Wrong key or corrupted signature
# - "HashType mismatch" → MANIFEST HashType doesn't match key

Machine Name Mismatch

# Check current machine name
cat /etc/os-release | grep OPENBMC_TARGET_MACHINE
# OPENBMC_TARGET_MACHINE=romulus

# Check MANIFEST MachineName
tar -xOf firmware.tar MANIFEST | grep MachineName
# MachineName=romulus

# If mismatch, image is rejected
# Error: "Machine name doesn't match"

Boot Fails After Update

# Via serial console, check for:
# - Kernel panic
# - Filesystem mount failure
# - Init system failure

# Check U-Boot boot counter
fw_printenv bootcount
# If > 0, boot had issues

# Force boot to backup image
fw_setenv bootside b
fw_setenv bootcount 0
reboot

# Or at U-Boot prompt:
=> setenv bootside b
=> saveenv
=> reset

# If both images fail, use TFTP recovery:
=> setenv serverip 192.168.1.100
=> setenv ipaddr 192.168.1.50
=> tftp 0x80000000 obmc-phosphor-image.static.mtd
=> sf probe
=> sf update 0x80000000 0 ${filesize}
=> reset

Image Not Activating

# Check activation state
busctl get-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<id> \
    xyz.openbmc_project.Software.Activation Activation

# States:
# NotReady - Still processing
# Invalid - Validation failed
# Ready - Can be activated
# Activating - In progress
# Active - Successfully activated
# Failed - Activation failed

# Check for activation blockers
busctl get-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<id> \
    xyz.openbmc_project.Software.Activation RequestedActivation

# View detailed logs
journalctl -u phosphor-software-manager@bmc --since "5 minutes ago"

# Common activation issues:
# - Flash busy/locked
# - Insufficient space
# - Filesystem corruption
# - Service crash during write

Flash Write Errors

# Check MTD device status
cat /proc/mtd
mtd_debug info /dev/mtd0

# Check for bad blocks (UBI)
ubinfo -a
cat /sys/class/ubi/ubi0/bad_peb_count

# Manual flash test (DESTRUCTIVE)
# flashcp -v /dev/zero /dev/mtd0  # DO NOT RUN in production

# Check for flash busy
flock -n /run/lock/bmc_flash.lock echo "Flash not locked"
# If no output, flash is locked by another process

# View flash operations
journalctl | grep -i "mtd\|flash\|ubi"

Activation Progress Stuck

# Check if activation is stuck at specific percentage
busctl get-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<id> \
    xyz.openbmc_project.Software.ActivationProgress Progress

# Stuck at 0%: MANIFEST parsing or signature verification
# Stuck at 20%: Flash erase
# Stuck at 50%: Flash write
# Stuck at 90%: Finalization

# Check for service crash
systemctl status phosphor-software-manager@bmc
# If failed, restart and retry

# Force cleanup and retry
rm -rf /tmp/images/*
systemctl restart phosphor-software-manager@bmc

Delete Failed/Stale Images

# List all software objects
busctl tree xyz.openbmc_project.Software.BMC.Updater

# Delete specific image via D-Bus
busctl call xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<id> \
    xyz.openbmc_project.Object.Delete Delete

# Or via Redfish
curl -k -u root:0penBmc -X DELETE \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/<id>

# Clean up /tmp/images manually if needed
rm -rf /tmp/images/<id>

Network Update Issues

# TFTP update fails
# Check network connectivity
ping <tftp-server>

# Check TFTP server is running
tftp <tftp-server>
tftp> get firmware.tar
tftp> quit

# Check firewall
# TFTP uses UDP port 69

# HTTPS update fails
# Check certificate trust
curl -v https://<server>/firmware.tar

# Check proxy settings
echo $http_proxy $https_proxy

Rollback

Rollback via D-Bus

# List all images to find backup ID
busctl tree xyz.openbmc_project.Software.BMC.Updater

# Get version info for each image
for obj in $(busctl tree xyz.openbmc_project.Software.BMC.Updater --list | grep software/); do
    echo "=== $obj ==="
    busctl get-property xyz.openbmc_project.Software.BMC.Updater \
        "$obj" xyz.openbmc_project.Software.Version Version 2>/dev/null
    busctl get-property xyz.openbmc_project.Software.BMC.Updater \
        "$obj" xyz.openbmc_project.Software.RedundancyPriority Priority 2>/dev/null
done

# Activate backup image (set as primary)
busctl call xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<backup_id> \
    xyz.openbmc_project.Software.Activation \
    RequestedActivation s \
    "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"

# Or set priority directly (0 = primary)
busctl set-property xyz.openbmc_project.Software.BMC.Updater \
    /xyz/openbmc_project/software/<backup_id> \
    xyz.openbmc_project.Software.RedundancyPriority \
    Priority u 0

# Reboot BMC to activate
obmcutil bmcreboot

Rollback via Redfish

# List all firmware inventory
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory | jq

# Find backup image (non-active BMC image)
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/<backup_id>

# Activate backup (method varies by implementation)
# Some implementations use PATCH:
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{"Status": {"State": "Enabled"}}' \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/<backup_id>

# Others use Actions:
curl -k -u root:0penBmc -X POST \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/<backup_id>/Actions/SoftwareInventory.Activate

# Reboot via Redfish
curl -k -u root:0penBmc -X POST \
    -d '{"ResetType": "GracefulRestart"}' \
    https://localhost/redfish/v1/Managers/bmc/Actions/Manager.Reset

Rollback via U-Boot

# If Linux is accessible, use fw_setenv
fw_setenv bootside b
reboot

# At U-Boot prompt (serial console)
=> printenv bootside
bootside=a
=> setenv bootside b
=> saveenv
=> reset

Factory Reset

Reset BMC Configuration

# Via Redfish - reset to factory defaults
curl -k -u root:0penBmc -X POST \
    -H "Content-Type: application/json" \
    -d '{"ResetType": "ResetAll"}' \
    https://localhost/redfish/v1/Managers/bmc/Actions/Manager.ResetToDefaults

# Reset types:
# - ResetAll: Reset all settings to factory defaults
# - PreserveNetworkAndUsers: Keep network and user settings
# - PreserveNetwork: Keep only network settings

Clear Persistent Data

# Clear read-write filesystem (preserves firmware)
# WARNING: Loses all BMC configuration

# Method 1: Via systemd
systemctl start obmc-factory-reset.target

# Method 2: Manual (requires reboot)
rm -rf /var/lib/*
rm -rf /etc/machine-id
reboot

# Method 3: Via U-Boot (most thorough)
# At U-Boot prompt:
=> setenv openbmconce factory-reset
=> saveenv
=> reset
# BMC will clear rwfs on next boot

Full Flash Recovery

# Complete flash re-image (via TFTP and U-Boot)
# WARNING: Erases EVERYTHING

# At U-Boot prompt:
=> setenv serverip 192.168.1.100
=> setenv ipaddr 192.168.1.50
=> setenv netmask 255.255.255.0

# Download full image
=> tftp 0x80000000 obmc-phosphor-image.static.mtd

# Probe SPI flash
=> sf probe

# Erase and write entire flash
=> sf erase 0 0x2000000  # Adjust size for your flash
=> sf write 0x80000000 0 ${filesize}

# Reset
=> reset

Security Considerations

Secure Boot Chain

---
title: Secure Boot Chain
---
flowchart TB
    hw["1. Hardware Root of Trust<br/>SoC verifies U-Boot signature using OTP-fused key"]
    uboot["2. U-Boot (Verified Boot)<br/>Verifies FIT image signature (kernel + DTB + initramfs)"]
    kernel["3. Linux Kernel<br/>dm-verity protects read-only rootfs"]
    userspace["4. User Space<br/>phosphor-software-manager verifies update signatures"]

    hw --> uboot --> kernel --> userspace
ASCII-art version (for comparison)
┌────────────────────────────────────────────────────────────────────────────┐
│                        Secure Boot Chain                                   │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                            │
│  1. Hardware Root of Trust                                                 │
│     └─ SoC verifies U-Boot signature using OTP-fused key                   │
│                                                                            │
│  2. U-Boot (Verified Boot)                                                 │
│     └─ Verifies FIT image signature (kernel + DTB + initramfs)             │
│                                                                            │
│  3. Linux Kernel                                                           │
│     └─ dm-verity protects read-only rootfs                                 │
│                                                                            │
│  4. User Space                                                             │
│     └─ phosphor-software-manager verifies update signatures                │
│                                                                            │
└────────────────────────────────────────────────────────────────────────────┘

U-Boot Verified Boot Configuration

# In U-Boot config (defconfig)
CONFIG_FIT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_RSA=y

# FIT image with signature node
/dts-v1/;

/ {
    images {
        kernel {
            data = /incbin/("Image");
            type = "kernel";
            arch = "arm";
            compression = "none";
            hash {
                algo = "sha256";
            };
        };
    };
    configurations {
        default = "conf";
        conf {
            kernel = "kernel";
            signature {
                algo = "sha256,rsa4096";
                key-name-hint = "dev-key";
                sign-images = "kernel", "fdt";
            };
        };
    };
};

Update Authentication

# Redfish authentication requirements
# - All update endpoints require authentication
# - Use HTTPS only (port 443)
# - Implement rate limiting to prevent brute force

# Enable mTLS for automated updates
# In bmcweb configuration:
# ssl_verify_mode = SSL_VERIFY_PEER

# RBAC for firmware updates
# Only Administrator role can perform updates
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/AccountService/Accounts/root | jq .RoleId
# "Administrator"

Audit Logging

# Firmware update events are logged
journalctl -u phosphor-software-manager | grep -i "activat"

# Redfish audit log
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/Managers/bmc/LogServices/CELog/Entries

# Key events to monitor:
# - Firmware upload
# - Signature verification result
# - Activation start/complete
# - Boot failures
# - Factory reset

Best Practices

Pre-Update Checklist

  1. Verify backup image - Ensure standby image is known-good
  2. Check storage space - Minimum 2x image size in /tmp
  3. Verify network connectivity - For network-based updates
  4. Document current version - For rollback reference
  5. Schedule maintenance window - BMC reboot affects management

Update Procedure

# 1. Record current version
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/bmc_active \
    | jq .Version > /tmp/before_version.txt

# 2. Verify backup image is bootable
fw_printenv bootside
# Ensure alternate side has valid image

# 3. Upload new image
curl -k -u root:0penBmc \
    -X POST \
    -H "Content-Type: application/octet-stream" \
    --data-binary @firmware.tar \
    https://localhost/redfish/v1/UpdateService

# 4. Monitor activation
watch -n 5 'curl -sk -u root:0penBmc \
    https://localhost/redfish/v1/TaskService/Tasks | jq'

# 5. Verify after reboot
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/UpdateService/FirmwareInventory/bmc_active \
    | jq .Version

Post-Update Verification

# Verify boot success
fw_printenv bootcount
# Should be 0

# Check system health
obmcutil state
# Should show Ready

# Verify all services running
systemctl --failed
# Should be empty

# Test critical functionality
curl -k -u root:0penBmc https://localhost/redfish/v1/Systems/system
ipmitool -I lanplus -H <bmc-ip> -U root -P 0penBmc chassis status

Examples

Working examples are available in the examples/firmware-update directory:

  • firmware-update.sh - Firmware update helper script
  • version-check.sh - Check current firmware versions

References

OpenBMC Repositories

OpenBMC Documentation

Standards

U-Boot


Deep Dive

Advanced implementation details for firmware update developers.

Flash Layout and MTD Partitions

  • Typical BMC Flash Layout (32MB)
Offset Size Partition Description
0x0000000 512KB u-boot Bootloader
0x0080000 128KB u-boot-env U-Boot environment
0x00A0000 4.5MB kernel FIT image (kernel+dtb)
0x0520000 25MB rofs Read-only rootfs
0x1DC0000 2MB rwfs Persistent read-write
  • Dual-Flash Configuration (A/B):
Flash 0 (Current) Flash 1 (Alternate)
u-boot (shared) (reserved)
u-boot-env  
kernel-a (active) kernel-b
rofs-a (active) rofs-b
rwfs (shared)  
  • Linux MTD Devices:
      /dev/mtd0 = u-boot          
      /dev/mtd1 = u-boot-env      
      /dev/mtd2 = kernel          
      /dev/mtd3 = rofs            
      /dev/mtd4 = rwfs           
    
ASCII-art version (for comparison)
┌─────────────────────────────────────────────────────────────────────────┐
│                    Typical BMC Flash Layout (32MB)                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   Offset     Size        Partition        Description                   │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ 0x0000000│ 512KB     │ u-boot        │ Bootloader               │   │
│   ├──────────┼───────────┼───────────────┼──────────────────────────┤   │
│   │ 0x0080000│ 128KB     │ u-boot-env    │ U-Boot environment       │   │
│   ├──────────┼───────────┼───────────────┼──────────────────────────┤   │
│   │ 0x00A0000│ 4.5MB     │ kernel        │ FIT image (kernel+dtb)   │   │
│   ├──────────┼───────────┼───────────────┼──────────────────────────┤   │
│   │ 0x0520000│ 25MB      │ rofs          │ Read-only rootfs         │   │
│   ├──────────┼───────────┼───────────────┼──────────────────────────┤   │
│   │ 0x1DC0000│ 2MB       │ rwfs          │ Persistent read-write    │   │
│   └──────────┴───────────┴───────────────┴──────────────────────────┘   │
│                                                                         │
│   Dual-Flash Configuration (A/B):                                       │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ Flash 0 (Current)     │ Flash 1 (Alternate)                     │   │
│   ├───────────────────────┼─────────────────────────────────────────┤   │
│   │ u-boot (shared)       │ (reserved)                              │   │
│   │ u-boot-env            │                                         │   │
│   │ kernel-a (active)     │ kernel-b                                │   │
│   │ rofs-a (active)       │ rofs-b                                  │   │
│   │ rwfs (shared)         │                                         │   │
│   └───────────────────────┴─────────────────────────────────────────┘   │
│                                                                         │
│   Linux MTD Devices:                                                    │
│   /dev/mtd0 = u-boot                                                    │
│   /dev/mtd1 = u-boot-env                                                │
│   /dev/mtd2 = kernel                                                    │
│   /dev/mtd3 = rofs                                                      │
│   /dev/mtd4 = rwfs                                                      │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Update Image Verification

┌─────────────────────────────────────────────────────────────────────────┐
│                    Image Verification Process                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   Update Image Structure:                                               │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ MANIFEST (text)        │ Version info, purpose, sha256 hashes   │   │
│   ├─────────────────────────────────────────────────────────────────┤   │
│   │ publickey (optional)   │ Public key for signature verification  │   │
│   ├─────────────────────────────────────────────────────────────────┤   │
│   │ image-kernel           │ FIT image with kernel and DTB          │   │
│   ├─────────────────────────────────────────────────────────────────┤   │
│   │ image-rofs             │ Read-only root filesystem (squashfs)   │   │
│   ├─────────────────────────────────────────────────────────────────┤   │
│   │ image-u-boot           │ U-Boot binary (optional)               │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│   MANIFEST File Example:                                                │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ purpose=xyz.openbmc_project.Software.Version.VersionPurpose.BMC │   │
│   │ version=2.12.0                                                  │   │
│   │ MachineName=romulus                                             │   │
│   │ KeyType=OpenBMC                                                 │   │
│   │ HashType=RSA-SHA256                                             │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│   Verification Flow:                                                    │
│   ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐          │
│   │ Receive  │───▶│ Verify   │───▶│ Verify   │───▶│ Verify   │          │
│   │ Image    │    │ MANIFEST │    │ Signature│    │ Hashes   │          │
│   └──────────┘    └──────────┘    └──────────┘    └──────────┘          │
│                        │              │               │                 │
│                        ▼              ▼               ▼                 │
│                   Check          RSA verify      SHA256 each            │
│                   required       against        component vs            │
│                   fields         pubkey         MANIFEST                │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Flash Programming Internals

┌─────────────────────────────────────────────────────────────────────────┐
│                    Flash Write Process                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   MTD Write Operation:                                                  │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ 1. Erase sector (typically 64KB)                                │   │
│   │    ioctl(mtd_fd, MEMERASE, &erase_info)                         │   │
│   │    └─ Sector erased to 0xFF                                     │   │
│   │                                                                 │   │
│   │ 2. Write data (page-aligned, typically 256 bytes)               │   │
│   │    write(mtd_fd, data, page_size)                               │   │
│   │    └─ Data written to erased sector                             │   │
│   │                                                                 │   │
│   │ 3. Verify (optional, MEMVERIFY ioctl)                           │   │
│   │    read-back and compare                                        │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│   Update Daemon (phosphor-bmc-code-mgmt) Flow:                          │
│   ┌────────────────────────────────────────────────────────────────┐    │
│   │ 1. Image uploaded to /tmp/images/                              │    │
│   │ 2. Item Updater detects new image via inotify                  │    │
│   │ 3. Verify signature and hashes                                 │    │
│   │ 4. Create D-Bus Version object (Ready)                         │    │
│   │ 5. User activates: RequestedActivation = Active                │    │
│   │ 6. Write image components to alternate flash                   │    │
│   │ 7. Update U-Boot env to boot from new image                    │    │
│   │ 8. Set Activation = Activating, then Active                    │    │
│   │ 9. Reboot (if requested)                                       │    │
│   └────────────────────────────────────────────────────────────────┘    │
│                                                                         │
│   U-Boot Environment (dual-boot):                                       │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ bootside=a           # Currently running: a or b                │   │
│   │ bootcount=0          # Failed boot attempts                     │   │
│   │ bootlimit=3          # Max failures before fallback             │   │
│   │ bootcmd=             # Selects kernel-a or kernel-b             │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Recovery Mechanism

┌─────────────────────────────────────────────────────────────────────────┐
│                    Boot Failure Recovery                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   Recovery Flow:                                                        │
│   ┌──────────────────────────────────────────────────────────────────┐  │
│   │                                                                  │  │
│   │  U-Boot Power On                                                 │  │
│   │       │                                                          │  │
│   │       ▼                                                          │  │
│   │  bootcount++                                                     │  │
│   │       │                                                          │  │
│   │       ▼                                                          │  │
│   │  bootcount > bootlimit? ───Yes──▶ Switch to alternate image      │  │
│   │       │                           Reset bootcount                │  │
│   │       No                          Boot alternate                 │  │
│   │       │                                                          │  │
│   │       ▼                                                          │  │
│   │  Boot current image                                              │  │
│   │       │                                                          │  │
│   │       ▼                                                          │  │
│   │  Linux boots successfully?                                       │  │
│   │       │                                                          │  │
│   │      Yes                                                         │  │
│   │       │                                                          │  │
│   │       ▼                                                          │  │
│   │  systemd reaches multi-user.target                               │  │
│   │       │                                                          │  │
│   │       ▼                                                          │  │
│   │  obmc-flash-bmc-setenv@bootcount=0.service                       │  │
│   │  (Reset bootcount to indicate successful boot)                   │  │
│   │                                                                  │  │
│   └──────────────────────────────────────────────────────────────────┘  │
│                                                                         │
│   Manual Recovery Commands:                                             │
│   # From U-Boot prompt (serial console):                                │
│   => setenv bootside b        # Switch to alternate                     │
│   => saveenv                                                            │
│   => reset                                                              │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Source Code Reference

Key implementation files:

Repository File/Directory Description
phosphor-bmc-code-mgmt item_updater.cpp Main update logic
phosphor-bmc-code-mgmt activation.cpp Activation state machine
phosphor-bmc-code-mgmt image_verify.cpp Signature verification
phosphor-bmc-code-mgmt flash.cpp Flash write operations
openbmc/meta-phosphor recipes-phosphor/flash/ Flash recipes
u-boot board/aspeed/ ASPEED board support

Tested on: OpenBMC master, QEMU romulus (limited dual-flash functionality), ASPEED AST2500/AST2600 EVB


Back to top

OpenBMC Guide Tutorial is not affiliated with the OpenBMC project. Content is provided for educational purposes.

This site uses Just the Docs, a documentation theme for Jekyll.