Public bug reported:

# Ubuntu 26.04 on Raspberry Pi CM4: A/B kernel updates never apply

Two independent defects in the `piboot-try` A/B boot mechanism on Ubuntu 26.04
(resolute) for Raspberry Pi. Together they mean **no kernel update can ever be
applied** on an affected board: new kernels stage into `/boot/firmware/new/`, 
are
marked `bad`, and the system keeps booting the original kernel indefinitely.

Both were found on a Raspberry Pi Compute Module 4 while provisioning a motion
controller. They are reported together because the first masks the second.

## Environment

| Item | Value |
|---|---|
| OS | Ubuntu 26.04.1 LTS (resolute), arm64 |
| Board | Raspberry Pi Compute Module 4 Rev 1.1 (eMMC, CM4 IO board) |
| Bootloader EEPROM build | 2022-04-26 (tryboot-capable) |
| `piboot-try` | 1.1ubuntu0.1 |
| `systemd` | 259.5-0ubuntu3.4 |
| `linux-image-raspi` | 7.0.0-1019.19 |
| Running kernel | 7.0.0-1017-raspi |
| `linux-firmware-raspi` | 14-0ubuntu1.1 |
| `rpi-eeprom` | 28.14-0ubuntu1 |
| Boot partition | 505 MB vfat, 290 MB free |

`/boot/firmware/autoboot.txt` contains `tryboot_a_b=1`; `config.txt` contains
`os_prefix=current/` under `[all]` and `os_prefix=new/` under `[tryboot]`
(stock, unmodified).

---

## Bug 1 — `piboot-try` uses a reboot form systemd 259 rejects

### Description

`/usr/share/flash-kernel/functions-piboot` triggers the trial boot with a
positional argument:

```sh
# functions-piboot:411
reboot "$boot_partition tryboot"
```

systemd 259 no longer accepts a positional argument to the `reboot` verb; it was
replaced by an option. From the systemd NEWS file shipped in this release:

> `"systemctl reboot" takes the option "--reboot-argument="`

On the affected system:

```console
$ systemctl --dry-run reboot "0 tryboot"
Too many arguments.

$ systemctl --dry-run reboot --reboot-argument="0 tryboot"
Failed to write reboot parameter file: Permission denied     # parses; fails 
only on privilege
```

### Effect

The `piboot-try-reboot` service logs `Rebooting to test new boot assets` and the
machine reboots, but **without** the tryboot argument reaching the firmware. The
next boot is an ordinary boot from `current/`, so `piboot-try` observes
`tryboot=0` while `new/state` is `trying`, concludes the trial failed, and 
writes
`bad`:

```
piboot-try[693]: Marked new boot assets bad
```

`0/-/good/bad` is terminal — nothing retries the assets. The staged kernel is
never booted, and the user sees only the generic message:

```
New boot assets in /boot/firmware/new failed. Fallen back to known good state.
```

### Steps to reproduce

1. Install a kernel update on Ubuntu 26.04 for Raspberry Pi so assets stage into
   `/boot/firmware/new/`.
2. `piboot-try --test` returns 0 (a double boot is pending).
3. Reboot.
4. Observe: still on the old kernel; `/boot/firmware/new/state` contains `bad`;
   the journal shows `Marked new boot assets bad`.

Expected: the system double-boots, tests the staged assets, and promotes
them.

### Suggested fix

Use the supported form, with a fallback for older systemd:

```sh
if systemctl --version >/dev/null 2>&1; then
    systemctl reboot --reboot-argument="$boot_partition tryboot"
else
    reboot "$boot_partition tryboot"
fi
```

---

## Bug 2 — booting via `os_prefix=new/` fails, with a byte-identical
kernel

### Description

With Bug 1 worked around by hand, the tryboot **does** occur — and still fails.
Critically, it fails even when the staged assets are a byte-for-byte copy of the
assets that boot successfully from `current/`.

### Steps to reproduce

Starting from a working system:

```bash
# Make new/ hold exactly the kernel that current/ boots from
sudo cp /boot/firmware/current/vmlinuz /boot/firmware/current/initrd.img 
/boot/firmware/new/
sudo cp /boot/firmware/current/*.dtb /boot/firmware/new/
printf 'trying\n' | sudo tee /boot/firmware/new/state

# Trigger the trial boot using the form systemd 259 accepts
sudo systemctl reboot --reboot-argument="0 tryboot"
```

Verified identical before rebooting:

```console
$ md5sum /boot/firmware/current/vmlinuz /boot/firmware/new/vmlinuz
f24e8e4a12f1e15e61d8842ed3a98e78  /boot/firmware/current/vmlinuz
f24e8e4a12f1e15e61d8842ed3a98e78  /boot/firmware/new/vmlinuz
```

### Actual behaviour

On an attached HDMI monitor: the rainbow splash appears (so `start4.elf` loaded
and ran), the kernel never starts, the board resets, and a second boot comes up
normally from `current/`. `new/state` is then `bad`.

The same kernel image boots without issue from `current/`.

### Expected behaviour

The trial boot should start the staged kernel, reach `multi-user.target`, and
`piboot-try-validate` should promote `new/` to `current/`.

### Ruled out

- **Corrupt or truncated assets.** `gzip -t` passes on `new/vmlinuz`; `zstd -t`
  passes on `new/initrd.img`; the initrd size matches
  `/boot/initrd.img-7.0.0-1019-raspi` exactly.
- **Missing assets.** `new/` is a strict superset of `current/`.
- **Boot partition full.** 290 MB free.
- **Malformed `cmdline.txt`.** `current/cmdline.txt` and `new/cmdline.txt` are
  identical.
- **EEPROM too old for tryboot.** Bootloader build 2022-04-26, well after 
tryboot
  support landed.
- **Kernel lacking tryboot support.** The string `tryboot` is present in both
  kernel images.
- **A bad 1019 kernel.** The failure reproduces with the 1017 kernel that boots
  fine from `current/`.

### Remaining lead (not yet tested)

After the experiment above, the only structural difference between the two slots
is that `new/` contains 17 GPU firmware files that `current/` does not:

```
bootcode.bin  fixup.dat  fixup4.dat  fixup4cd.dat  fixup4db.dat  fixup4x.dat
fixup_cd.dat  fixup_db.dat  fixup_x.dat  start.elf  start4.elf  start4cd.elf
start4db.elf  start4x.elf  start_cd.elf  start_db.elf  start_x.elf
```

These are byte-identical to the copies at the root of the boot partition
(`start4.elf` md5 `37ce15a4f86e3c063a6cef29d62aa1da` in both places).
`find_bootloader_assets` in `functions-piboot` (lines 82–84) copies them into 
the
slot deliberately, while `current/` lacks them because it was produced by the
migration from the older flat layout.

This asymmetry is worth investigating: booting with `os_prefix=new/` causes the
firmware to load `start*.elf` from the prefixed directory, a path that a normal
boot from `current/` never exercises. Deleting the firmware blobs from `new/`, 
so
that the slot matches `current/`, would confirm or eliminate this.

`new/overlays` also holds 371 files against `current/`'s 370, though both 
contain
the overlays required for this board.

---

## Impact

- No kernel update can be applied. Security updates to `linux-raspi` install 
into
  `/boot/firmware/new/` and are never booted. `uname -r` stays pinned to 
whatever
  kernel first shipped on the image.
- Switching kernel flavours is impossible — this was found while trying to adopt
  `linux-image-raspi-realtime` (PREEMPT_RT) for a robotics workload.
- The user-facing message names no cause, and `piboot-try --reset-new` simply
  repeats the failure, so the condition looks like faulty hardware.

## Workarounds

Neither is complete: the first fixes only Bug 1, and Bug 2 then blocks
the boot.

```bash
# Clear the terminal "bad" state
sudo piboot-try --reset-new

# Drive the trial boot with the argument form systemd 259 accepts
printf 'trying\n' | sudo tee /boot/firmware/new/state
sudo systemctl reboot --reboot-argument="0 tryboot"
```

## Attachments worth collecting

- `journalctl -b -u piboot-try-reboot -u piboot-try-validate`
- `/boot/firmware/config.txt`, `/boot/firmware/autoboot.txt`
- `ls -la /boot/firmware/current /boot/firmware/new`
- `cat /boot/firmware/{current,new}/state`
- `od -An -tu4 --endian=big /proc/device-tree/chosen/bootloader/tryboot`

> Note: timestamps in early-boot journal entries on a CM4 are misleading. The
> board has no RTC, so entries before chrony syncs carry a stale date. Messages
> that appear to be weeks old are frequently from the current boot.

ProblemType: Bug
DistroRelease: Ubuntu 26.04
Package: piboot-try 1.1ubuntu0.1
ProcVersionSignature: Ubuntu 7.0.0-1017.17-raspi 7.0.12
Uname: Linux 7.0.0-1017-raspi aarch64
ApportVersion: 2.34.1-0ubuntu0.1
Architecture: arm64
CasperMD5CheckResult: unknown
CloudArchitecture: aarch64
CloudID: nocloud
CloudName: unknown
CloudPlatform: nocloud
CloudSubPlatform: config-disk (/dev/mmcblk0p1)
Date: Sat Sep 19 11:41:53 2026
ImageMediaBuild: 20260826
SourcePackage: piboot-try
UpgradeStatus: No upgrade log present (probably fresh install)

** Affects: piboot-try (Ubuntu)
     Importance: Undecided
         Status: New


** Tags: apport-bug arm64 arm64-image raspi-image resolute

** Attachment added: "piboot-try-diagnostics.txt"
   
https://bugs.launchpad.net/bugs/2167775/+attachment/6001249/+files/piboot-try-diagnostics.txt

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2167775

Title:
  Ubuntu 26.04 on Raspberry Pi CM4: A/B kernel updates never apply

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/piboot-try/+bug/2167775/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to