A/B boot on Ubuntu for Raspberry Pi¶
From Ubuntu questing (25.10) onwards, the boot sequence for Ubuntu on the
Raspberry Pi includes a fallback mechanism (commonly known as an A/B boot
mechanism). This is implemented by a new command, piboot-try
and
two “one-shot” systemd services, piboot-try-reboot.service
and
piboot-try-validate.service
. This mechanism is enabled on all Pi models
supported by Ubuntu.
The bootloader assets themselves are not protected by this mechanism [1]. However, other boot assets, including the base device-trees, device-tree overlays, the Linux kernel, and the initramfs are covered.
File layout¶
The layout of files on the boot partition is (as of 25.10) as follows:
- Bootloader assets
The bootloader itself is stored in EEPROM on the Pi 5, partially in EEPROM on the Pi 4, and in the following files on all earlier models, placed in the root of the boot partition,
/boot/firmware
:autoboot.txt
– The early bootloader configuration filebootcode.bin
– The second stage bootloader (on models prior to the Pi 4)start*.elf
andfixup*.dat
– The third stage bootloader (on models prior to the Pi 5)config.txt
– The main bootloader configuration file
- Cloud-init configuration
These are not boot assets, but are used by cloud-init to configure the machine on the first boot only. They are also present in the root of the boot partition (
/boot/firmware
) and are listed here for completeness only:meta-data
– The cloud-init meta-configuration, describing where to find the other configuration files (locally by default)network-config
– The network configuration for cloud-inituser-data
– The main cloud-init configuration file, specifying users to create, packages to install, files to write, etc.
- Boot assets
These consist of the Linux kernel, the initramfs, the base device-tree, and any device-tree overlays:
vmlinuz
– The Linux kernelcmdline.txt
– The Linux kernel command lineinitrd.img
– The initramfs*.dtb
– The base device-tree(s)overlays/*.dtbo
– All device-tree overlays
In older releases of Ubuntu, the boot assets were all placed in the root of the
boot partition, /boot/firmware
, alongside the bootloader assets and
cloud-init configuration. From questing (25.10) onwards, copies of the boot
assets (and only the boot assets) will be placed in the following folders on
the boot partition:
old/
folderHolds older copies of “known good” boot assets. This folder is not always present; it is removed to make space when new boot assets are written.
current/
folderThis folder is always present and at runtime always holds the currently booted assets.
new/
folderHolds newly written “untested” boot assets, or boot assets that were tested but failed to boot properly. This is replaced when new boot assets are written, or is renamed to
current/
after assets are tested and validated.
Typical operation¶
In each of the folders on the boot partition, a state
file will be
present which records the state of the boot assets in that folder. This file
may contain one of the following strings:
- good
The boot assets have been booted successfully and validated. The
current/state
and optionalold/state
files should always contain “good”- unknown
The boot assets have not yet been booted. The
new/state
file will contain this immediately after a run offlash-kernel
.- trying
The boot assets are currently being tested. The
new/state
file will contain this only when the machine is booting in the “tryboot” mode (or just immediately prior to rebooting into this mode).- bad
The boot assets have been tested, but failed. The
new/state
file will contain this if a “tryboot” attempt fell back to the assets incurrent/
.
Normally, the system will boot using the assets from the current/
folder. The other folders may or may not exist, depending on the state of the
system, but will never be used to boot under normal conditions.
Testing new boot assets¶
Installation of new boot assets is handled, as ever, by the
flash-kernel
command. This is automatically called in response to
several changes, including installation of a new kernel version, re-building of
the initramfs, or upgrades of flash-kernel itself. It may also be called
manually to write new copies of the boot assets to the boot partition.
From questing (25.10), rather than those files being written to the root of the
boot partition, the following will occur when flash-kernel
is executed:
If present, the
old/
folder will be removed [2]If present, the
new/
folder will be removed [3]The
new/
folder will be createdNew boot assets will copied into the
new/
folderThe
new/state
file will be created, containing “unknown”
Note
Note that flash-kernel
never touches the files under current/
.
If flash-kernel
is executed again before rebooting, the new boot assets
will simply replace those currently under new/
.
With the new boot assets in place, we come to the role of the systemd services.
When the system is next booted (or rebooted), the boot will initially use the
assets under current/
. However, at some point during this boot, the
piboot-try-reboot
service will note that boot assets exist under
new/
with the state “unknown”. It will immediately update that status
to “trying”, and reboot the machine into the “tryboot” mode. In this mode, the
config.txt
file will direct the bootloader to read assets from the
new/
folder instead.
Note that the “tryboot” status is ephemeral [4]. Any failure at
this point will result in the next boot (whether warm or cold) using the assets
from current/
instead.
However, if the “tryboot” boot succeeds, and reaches the point where the
piboot-try-validate
service runs [5] then the boot state
will be validated (see Boot asset validation below). If successful, the
service will perform the following:
“good” is written to the
new/state
fileThe
current/
folder is renamedold/
The
new/
folder is renamedcurrent/
[6]
Boot asset failure¶
Failure may occur in several places, and as noted previously not all assets are
covered. This section will not consider bootloader asset failure as, at least
on later models, they are only in EEPROM and not affected by flash-kernel
.
- Pre-kernel failure
In the event that the Linux kernel fails to start, the Pi’s hardware watchdog (enabled by
dtparam=watchdog=on
inconfig.txt
) will hard-reset the Pi, and the “known good” assets undercurrent/
will be used instead.- Kernel failure
From questing (25.10), the kernel’s command line (in
current/cmdline.txt
) containspanic=10
. In the event of a fatal error in the kernel, it should pause for 10 seconds, then reboot the machine, causing a fallback to the “known good” assets undercurrent/
. If the fatal error prevents even the panic mechanism from working, the hardware watchdog (above) will reboot the machine.Note
Note that on the Pi 5 there is a failure mode in which a corrupted kernel is not recognized as “Pi 5 compatible”. In this case, unfortunately, the bootloader simply freezes. Still, a power-cycle will reliably fallback in this scenario.
- Initramfs failure
In the event that the initramfs fails, the default behaviour in prior releases is to drop to a busybox shell for remediation. In questing (25.10) onwards, the aforementioned
panic=10
setting prevents this and causes a reset instead, falling back to the “known good” assets [7].
During fallback, the piboot-try-reboot
service will note that the machine
is no longer in the “tryboot” state, and yet the new/state
file
contains “trying”. As this indicates boot failure, the service will write “bad”
to new/state
.
Boot asset validation¶
The piboot-try-validate
service relies on the
/etc/flash-kernel/piboot-validate
script to determine whether boot
assets have booted “successfully”. By default, this script simply runs “true”
(which returns 0, meaning “success”). This may seem overly simplistic, but
there is little else that can be done by default here, and even this actually
represents quite a bit of functionality. For the piboot-try-validate
service to be running:
The kernel must have started successfully
The initramfs must have run successfully, mounting the “real” rootfs
Systemd must have reached the
multi-user.target
where the service is installed
If you have requirements beyond this, you are encouraged to add additional tests to this script. Some examples are provided (as comments) within it. However, exercise caution when adding such tests. In particular, be aware that a failing test will cause reversion to older boot assets, potentially containing unpatched issues.
It is reasonable, especially for remote headless machines, to add a test ensuring that expected network interfaces are present (for example, that an “eth0” interface exists). For example:
#!/bin/sh
set -e
# Test whether the eth0 device is present
ip link show eth0 >/dev/null
It is tempting to add a further test ensuring such an interface is operating successfully; continuing the example, that “eth0” is up, and has an IPv4 address:
#!/bin/sh
set -e
# Test whether the eth0 device is present
ip link show eth0 >/dev/null
# Test if eth0 has an IPv4 address
ip --json addr show eth0 | \
jq -e '[.[0].addr_info[].family == "inet"] | any' >/dev/null
However, be aware that, as the test now depends on something external to the machine (e.g. a DHCP server), anything which could prevent the machine receiving an IP address can also cause it to fail validation of a kernel update (potentially containing security fixes). These concerns do not apply universally, though. Such a test is safer on an interface with a statically configured address, for instance.
If you have a headless, remote machine, you should consider tailoring the validation script to suit your needs.
Advanced operation¶
If required, the double-boot can be avoided by using the
piboot-try
command. This has a number of options that can be used
to check the status of boot assets, to force a reboot into the “tryboot”
mode immediately, to restore prior state, and reset failed assets.
Avoiding the double-boot¶
The --test
option returns zero (indicating success) if new, untested boot
assets are present, and non-zero otherwise. In other words, this can be used be
determine the next boot will be a double boot.
When untested boot assets are present, the --reboot
option will immediately
force a reboot into the tryboot mode, testing the new assets and avoiding the
double boot (if untested boot assets are not present, it will do nothing).
If you have a system that is ready to reboot, you could combine these options in a script to ensure the reboot will avoid the double boot like so:
#!/bin/sh
if piboot-try --test; then
piboot-try --reboot
else
reboot
fi
Testing new boot configuration¶
The boot configuration is largely controlled through two files:
config.txt
in the root of the boot partition, and cmdline.txt
(which exists under the “old”, “current”, and “new” folders).
If you wish to test a new boot configuration in config.txt
:
Run
sudo flash-kernel
to set up new boot assetsPlace the new (or changed) configuration lines under a
[tryboot]
conditional section at the end ofconfig.txt
Reboot (or use
piboot-try --reboot
to force the “tryboot” mode immediately)If the boot completes successfully, move the new (or changed) configuration lines out of the
[tryboot]
section into an[all]
section (or other appropriate section)
Alternately, if you need to test a new configuration in cmdline.txt
:
Run
sudo flash-kernel
to set up new boot assets (note thatcurrent/cmdline.txt
is copied to createnew/cmdline.txt
)Edit
new/cmdline.txt
Reboot (or use
piboot-try --reboot
to force the “tryboot” mode immediately)If the boot completes successfully, then
new/cmdline.txt
becomescurrent/cmdline.txt
Restore old assets¶
Sometimes bad configuration is not immediately obvious. If the “old” folder
still exists on the boot partition (if flash-kernel
has not been run
since the latest boot), it can be restored to being the “current” folder with
piboot-try --restore-old
. This moves “current” to “new” and “old” to
“current” on the boot partition.
Note that in this situation the new/state
file indicates a “good” state
because the “new” assets are already known good. In this state, the next boot
will use the assets from “current” (because the “new” assets are not untested).
In order to switch back to “new” assets you can use piboot-try --reset-new
.
This action re-writes new/state
to “unknown” causing the next boot to
double-boot to (re-)test the assets.