> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Capsule update in U-Boot

## Overview

This page is a hands-on walkthrough for performing a multi-image UEFI capsule update
from the U-Boot console. It complements the conceptual capsule pages in this chapter by
showing the exact commands to:

1. Discover which firmware images a board can update.
2. Build the `mkeficapsule` host tool.
3. Bundle several firmware payloads (U-Boot, TZ, XBL, and so on) into a single UEFI
   capsule, signed or unsigned.
4. Land the capsule on the EFI system partition (ESP), arm the update by setting
   `OsIndications`, and reboot to apply it.
5. Verify the result.

## Supported SoCs

The flow is identical across the following SoCs. Only the `defconfig` differs.

| SoC     | defconfig                |
| ------- | ------------------------ |
| QCS6490 | `qcm6490_defconfig`      |
| IQ-9075 | `qcom_lemans_defconfig`  |
| IQ-615  | `qcom_qcs615_defconfig`  |
| Monaco  | `qcom_qcs8300_defconfig` |
| Shikra  | `qcom_shikra_defconfig`  |

## Discover supported images

Flash U-Boot, stop at the U-Boot console, and run:

```text theme={null}
=> efidebug capsule images
```

This command walks every Firmware Management Protocol (FMP) instance and prints one row
per updatable image the board exposes:

```text theme={null}
Image Index    Firmware Name         Image Type GUID
===========    ===================== ====================================
          1    UBOOT_UEFI_PARTITION  400ffdcd-22e0-47e7-9a23-f16ed9382388
          2    QCOM-XBL              dea0ba2c-cbdd-4805-b4f9-f428251c3e98
          3    QCOM-TZ               a053aa7f-40b8-4b1c-ba08-2f68ac71a4f4
          ...
```

This list is board-specific (built from that board's GPT), so not every board shows every
component. Only images that appear here can be updated by capsule on that board.

Note the `image-guid` and `image-index` values that this command reports for each
component — they're used in the capsule config in the subsequent sections. The
`image-guid` is what selects the target partition at apply time.

## Build the `mkeficapsule` tool

First, get the source:

```bash theme={null}
# Download the U-Boot source code
git clone https://github.com/qualcomm-linux/u-boot.git

# Go to the U-Boot source directory
cd u-boot

# Switch to the qcom-next branch
git checkout qcom-next
```

Then build the host tool into a `.output` folder:

```bash theme={null}
make O=.output tools-only_defconfig
make O=.output tools
```

The binary is produced at `.output/tools/mkeficapsule`. All commands below invoke it by
path.

## Set up the capsule folder

Create a working folder for the board with the following structure:

```text theme={null}
generate_capsules/
  capsule_cfg.txt
  Images/
    u-boot.mbn
    tz.mbn
    xbl.elf
    ...
```

* `capsule_cfg.txt` — the capsule config file (see [Capsule config-file
  format](#capsule-config-file-format)).
* `Images/` — the firmware payloads.

Only include the payloads for the images to be updated. Each must appear in the
`efidebug capsule images` output.

## Capsule config-file format

The config is a series of `{ … }` blocks, each a set of `key: value` pairs. One block
describes one payload.

| Key                 | Meaning                                                                                                                                            |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `image-guid`        | Image Type GUID from `efidebug capsule images`. The key used to match the payload to its target partition.                                         |
| `image-index`       | Image index — set to the value `efidebug capsule images` reports for the component. Matching is by GUID, so this need only identify the component. |
| `fw-version`        | Firmware version for this payload.                                                                                                                 |
| `payload`           | Path to the payload binary (relative to where the tool is run).                                                                                    |
| `capsule`           | Output capsule filename.                                                                                                                           |
| `hardware-instance` | Hardware instance (typically `0`).                                                                                                                 |
| `monotonic-count`   | Monotonic count (signed capsules).                                                                                                                 |
| `private-key`       | Path to signing private key (signed capsules only).                                                                                                |
| `pub-key-cert`      | Path to signing public cert (signed capsules only).                                                                                                |

**Grouping rule:** payloads that share the same `capsule:` filename are bundled into a
single multi-image capsule. Different filenames produce separate capsules.

A ready-made sample config to model the config on is at
`test/py/tests/test_efi_capsule/sandbox_capsule_cfg.txt`.

### Unsigned multi-image capsule

Example using values reported by `efidebug capsule images`. The `image-guid` is what
selects the target partition; set each `image-index` to the value the command reports for
that component:

```text theme={null}
{
    image-guid: 400ffdcd-22e0-47e7-9a23-f16ed9382388
    image-index: 1
    hardware-instance: 0
    fw-version: 1
    payload: Images/u-boot.mbn
    capsule: Unsigned.cap
}
{
    image-guid: dea0ba2c-cbdd-4805-b4f9-f428251c3e98
    image-index: 2
    hardware-instance: 0
    fw-version: 1
    payload: Images/xbl.elf
    capsule: Unsigned.cap
}
{
    image-guid: a053aa7f-40b8-4b1c-ba08-2f68ac71a4f4
    image-index: 3
    hardware-instance: 0
    fw-version: 1
    payload: Images/tz.mbn
    capsule: Unsigned.cap
}
...
```

All three blocks use `capsule: Unsigned.cap`, so the tool packs all three payloads
into that one file.

### Signed multi-image capsule

First, generate a signing key and a self-signed public certificate with OpenSSL. The
private key signs each payload; the certificate is embedded in the U-Boot image (see
[Enable authentication for signed capsules](#enable-authentication-for-signed-capsules))
and used on the board to verify the signature:

```bash theme={null}
openssl req -x509 -sha256 -newkey rsa:2048 -subj "/CN=Capsule Signing Key/" -keyout capsule_priv.key -out capsule_pub.crt -nodes -days 365
```

Then add `private-key:` / `pub-key-cert:` (and `monotonic-count:`) to each block,
pointing at the key and certificate generated above:

```text theme={null}
{
    image-guid: 400ffdcd-22e0-47e7-9a23-f16ed9382388
    image-index: 1
    hardware-instance: 0
    fw-version: 1
    monotonic-count: 1
    payload: Images/u-boot.mbn
    private-key: capsule_priv.key
    pub-key-cert: capsule_pub.crt
    capsule: Signed.cap
}
{
    image-guid: dea0ba2c-cbdd-4805-b4f9-f428251c3e98
    image-index: 2
    hardware-instance: 0
    fw-version: 1
    monotonic-count: 1
    payload: Images/xbl.elf
    private-key: capsule_priv.key
    pub-key-cert: capsule_pub.crt
    capsule: Signed.cap
}
{
    image-guid: a053aa7f-40b8-4b1c-ba08-2f68ac71a4f4
    image-index: 3
    hardware-instance: 0
    fw-version: 1
    monotonic-count: 1
    payload: Images/tz.mbn
    private-key: capsule_priv.key
    pub-key-cert: capsule_pub.crt
    capsule: Signed.cap
}
...
```

<Note>
  Verifying a signed capsule on the board additionally requires the U-Boot image to be
  built with capsule authentication enabled and the matching public cert. See
  [Enable authentication for signed capsules](#enable-authentication-for-signed-capsules).
</Note>

## Generate the capsule

Run the tool from inside the board folder so the `payload:`/`capsule:` relative paths
resolve:

```bash theme={null}
cd generate_capsules
../.output/tools/mkeficapsule -f capsule_cfg.txt
```

For a multi-image config, the output is:

```text theme={null}
Generating multi-payload capsule: Unsigned.cap (3 payloads)
Multi-payload capsule created successfully: Unsigned.cap
  Total size: <N> bytes
  Payloads: 3
```

Verify the capsule structure by dumping its headers:

```bash theme={null}
../.output/tools/mkeficapsule --dump-capsule Unsigned.cap
```

Confirm that `EFI_FMP_HDR.PAYLOAD_ITEM_COUNT` equals the payload count, and that each
`FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID` / `UPDATE_IMAGE_INDEX` matches the config.
For a signed capsule, each payload additionally shows an `EFI_FIRMWARE_IMAGE_AUTH` block.

## Enable authentication for signed capsules

<Note>
  Skip this section for unsigned capsules. The shipped board image already has
  `EFI_CAPSULE_ON_DISK` and `EFI_CAPSULE_FIRMWARE_RAW` enabled, so go straight to
  [Get the capsule onto the ESP](#get-the-capsule-onto-the-esp).
</Note>

Signed capsules require capsule authentication in the U-Boot image, which isn't enabled
by default, so this must be done before applying the capsule:

1. Clone the `qualcomm-linux/u-boot` repo and switch to `qcom-next` (skip if the checkout
   from [Build the `mkeficapsule` tool](#build-the-mkeficapsule-tool) already exists):

   ```bash theme={null}
   git clone https://github.com/qualcomm-linux/u-boot.git
   cd u-boot
   git checkout qcom-next
   ```

2. Copy the generated public certificate (`capsule_pub.crt`) into the U-Boot tree,
   then add the capsule authentication options to the board's defconfig
   (`configs/<board>_defconfig`, for example `configs/qcom_lemans_defconfig`), pointing
   `CONFIG_EFI_CAPSULE_CRT_FILE` at that certificate (path relative to the U-Boot tree):

   ```text theme={null}
   CONFIG_EFI_CAPSULE_AUTHENTICATE=y
   CONFIG_EFI_CAPSULE_CRT_FILE="<path-to>/capsule_pub.crt"
   ```

3. Build U-Boot (see [U-Boot on Qualcomm Linux](./u-boot-on-qualcomm-linux)) and flash the
   resulting image to the board's `uefi` partition.

<Note>
  A capsule signed with a key that doesn't match the embedded cert is rejected at apply
  time.
</Note>

## Get the capsule onto the ESP

Place the `.cap` in `\EFI\UpdateCapsule\` on the ESP. Use whatever transfer mechanism the
board supports to copy the file there — for example, mount the ESP
(`mount /dev/disk/by-partlabel/efi /mnt/esp`), create the `EFI/UpdateCapsule` directory if
it doesn't exist, and copy the capsule into it.

Capsule-on-disk only runs when `OsIndications` has the bit
`EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED` (`0x4`) set. U-Boot
(`check_run_capsules()` in `lib/efi_loader/efi_capsule.c`) clears the bit after applying,
so re-arm before every apply. On the next boot, capsule-on-disk auto-discovers
`\EFI\UpdateCapsule\*.cap`, applies every payload, clears the file, and clears the
`OsIndications` bit — no U-Boot console command is needed to kick it off.

Once the capsule is in place, arm the update from the kernel prompt and reboot:

```sh theme={null}
# Arm: set OsIndications bit 0x4 (64-bit LE value 0x0000000000000004).
# -f is raw variable data (no attribute header); -A 0x7 = NV|BS|RT, the set
# U-Boot uses. efivar persists it to ubootefi.var on the ESP via VarToFile.
printf '\x04\x00\x00\x00\x00\x00\x00\x00' > /tmp/osindications.bin
efivar -w -n 8be4df61-93ca-11d2-aa0d-00e098032b8c-OsIndications \
       -f /tmp/osindications.bin -A 0x7
efivar -p -n 8be4df61-93ca-11d2-aa0d-00e098032b8c-OsIndications   # verify

sync
reboot
```

## Verify the result

After the apply boot, at the U-Boot console:

```text theme={null}
=> efidebug capsule esrt
```

Confirm, per updated image, that `fw_version` advanced to the config's `fw-version` and
`last_attempt_status = success`.

```text theme={null}
=> efidebug capsule result
```

Shows the per-capsule result code from the last apply.

```text theme={null}
=> efidebug capsule images
```

Re-confirms the image set and reflects the updated versions.
