As part of a current project at Bootlin, we implemented A/B OTA updates (OTA) on an AA system based on the Raspberrypi 5 use Rough. In the end, we did not use submarine as boot loaders and instead rely exclusively on the Raspberrypi firmware as boot loaders. This article will deal with the details to achieve this and some advanced functions of RAUC.
Interface with the bootloader
Rough (Robust Auto-Update Controller) is a popular open source controller software for safe and safe updates for embedded systems. RAUC can use an A/B schema to provide updates secureThis means that an update is installed on the alternative slot (which is currently not booted), then temporary Make it a slit that has to be booted next. If the slot does not start, it should be marked as badAnd the system was supposed to return to the untouched, previously boted slot.
Of course, RAUC cannot be dependent on the operating system itself, since it is usually part of the update. It has to rely on a loaded piece of software beforeAnd has visibility in the operating system: the boot loader.
RAUC does this with Bootloader -Backendsand supports 4 boot loaders: BareboxPresent SubmarinePresent RodAnd (U) EFI. A large number of embedded systems use submarine, and this is exactly what our project started. Unfortunately, submarine does not have the PCIe support for the time at the time and at the time of writing Broadcom BCM2712The SoC that is the application processor of the RPI 5. This is a problem in our case, as this is the interface used M.2 Hut+ Make a connection to the NVME drive to save the operating system in our project.
The Raspberry Pi firmware as a boot loader
Starting with the Raspberry Pi 4, the boot loader of the second stage (which is executed on the GPU by video core) is included in one On-board eeprom. It can also be configured via text files, the most important being autoboot.txtPresent config.txt And cmdline.txt.
An important function of the boot loader is TrybootWith an RPI firmware flag for charging an alternative configuration file.
This can be determined by Userland with the Mailbox -property interfaceeg via the Raspberry Pi Utils’ VCMailbox Utility. As This commit Shows that 0x00038064 Tag sets the new start flag: vcmailbox 0x00038064 4 0 1.
This makes the Raspberry Pi firmware a good candidate for the implementation of A/B-updates without an submarine intervention.
Raucs interface to the RPI firmware
As already mentioned, RAUC needs an interface to the boot loader, but currently has no official RPI firmware -backing, even though there is one Remove request out for it. This means that after this letter a it needs a Custom backendWhich will:
- Implement
get-primaryby parsingautoboot.txtTo find the partition that is defined in whichallSection - Implement
set-primaryEither setting thetrybootFlag withvcmailboxor by swapping the partition in thealland thetrybootSections ofautoboot.txtConfiguration iftrybootis already active (the RPI firmware sets it in the DTB in the in the/proc/device-tree/chosen/bootloader/tryboot) - Implement
get-stateBy checking the partition, was booted. The RPI firmware defines this in the DTB/proc/device-tree/chosen/bootloader/partition - Implement
set-stateBy swapping the partition in thealland thetrybootSections ofautoboot.txtconfiguration
Activate Kernel updates
If the RPI firmware does not use an intermediate start loader such as submarine or an initramfs, the RPI firmware for charging and jumping is responsible directly to the Linux kernel.
The kernel must therefore be on a VfAT partition that is the only file system that supports the RPI firmware next to the config.txt Configuration file. Since it is unlikely on a embedded device that the root File system is VFAT, RAUC needs separate slots for VFAT start partition and the root file system. Since the RPI firmware does not have the root file system, but only through the booting partition (the VFAT One), we can not only test the root file system, and we test the kernel and the root file system at the same time, and if one is broken, or they are not compatible, both are compressed.
We can make this in the RAUC configuration by clarifying grouping A rootfs with a dedicated VfAT partition.
Each VfAT partition is therefore assigned for Rauc with a certain master file system. The RPI firmware will be thanks to the cmdline.txt File by determining them root= Argument to the root file system.
Restrictions and pitfalls
Unfortunately, the Raspberry Pi firmware does not reveal any script functions or a rich environment like submarine, from which Rauuc can benefit, which leads to some restrictions that we will discuss in the following sections.
Care of cmdline.txt
When providing an update, RAUC overwrites the alternative (not currently not currently booted) slot with the file system in the update bundle. If the update is provided on a device fleet, there is no way to know whether a single device provides the update for its A or B Slot. However if cmdline.txt Is overwritten with the wrong one root= Value that the slot grouping on which Rauc is dependent is broken.
We could therefore be booted on the A Slot, update the B Slot with a cmdline.txt written for the A Slot that points to the A Rootfs. At the restart of the B Rootfs would not be tested and the update could be applied with a broken application B Rootfs. If the next update had a broken rootfs, it would be applied to them A Slot, and both rootfs would now be broken and the device would be unbootable.
This shows that the maintenance cmdline.txt is of the greatest importance.
Option 1: RAUC -BUNDLE hook
Since we cannot make sure that cmdline.txt Will refer to the right rootfs, we could do it with a RAUC for the update time bundle post-install Hook to edit and remedy cmdline.txt.
Of course, this is slightly hacky, and it could be catastrophic to create a bundle without the right hook.
Option 2: The RPI firmware (boot_partition)
This is the more robust option, but is based on a currently undocumented function of the RPI 5 firmware.
In the publication 2025-03-10 the RPI-e-EpromRaspberry Pi introduced The (boot_partition=N) conditional where N is the number of partitions from which the system is booted.
This means that we can now use this construct:
(boot_partition=1) cmdline=cmdline-rootfs-A.txt (boot_partition=2) cmdline=cmdline-rootfs-B.txt
In config.txt point to the appropriate cmdline.txt Depending on the booted partition, which is dynamically determined by the RPI firmware.
We can therefore now send the same VfAT partition -update in the two slots without maintaining the relationship with the corresponding roots.
Mark the slot as good
The Raspberry Pi firmware does not follow the starting tests. This means that there is no way for the system to know whether there was an attempt to start the other slot and whether this attempt failed.
For this reason, the logic is marked by marking a slot as a slot Good or bad is rather elementary: when the slot is booted, it is GoodOtherwise it will be taken into account bad.
Source of truth for the starting slot
This is a little problem, this time on the RAUC page. The tool accepts several sources to determine which slot the currently booted. You are documented Here. Implementing when using a custom boot loader get-current Should be what Rauuc uses to determine the starting slot.
We could use this to focus on the DTB, which populated the Raspberry Pi firmware.
However, this is only the case if it is unable to determine it from the kernel command line, e.g. B. by parsing rauc.slot=.
One of the arguments that RAUC will unfortunately use is root=With which we point the kernel to the right rootfs. This means that there is no practical option that RACC uses the RPI firmware-populated DTB.
The RauC supervisors are consciouslyAnd consider to change this behavior.
Diploma
The Raspberry Pi firmware contains some functions (albeit experimentally) that make it reasonable not to use submarine as a secondary boot loader, while the ability to distribute updates with a sophisticated framework is retained.
That would only be true if RACC actually functions the RPI firmware as a backend, although some small restrictions may exist.