Skip to content

[FEAT] Support tryboot helpers without ramdisk #1940

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bryceschober opened this issue Feb 1, 2025 · 11 comments
Open

[FEAT] Support tryboot helpers without ramdisk #1940

bryceschober opened this issue Feb 1, 2025 · 11 comments

Comments

@bryceschober
Copy link

I'm digesting the implications of the tryboot_a_b update flow, and it's becoming clear that it is more designed for boot systems that depend on a ramdisk. Since the ramdisk would be named the same on the A/B boot partitions, it doesn't need any differences in cmdline.txt, and init logic within it can then use the device tree's chosen/bootloader properties to drive its dynamic logic.

But for systems that would prefer not to have a separate ramdisk, they are currently required to modify their kernel cmdline appropriately for the A/B partition that is being booted, and set up for that during their update process along with modifying the autoboot.txt.

I can think of two possible ways that the rpi firmware could support this use-case:

  1. Support the cmdline setting in the autoboot.txt in addition to the config.txt. This way, the A/B boot partitions could be identical and contain both cmdline_A.txt and cmdline_B.txt files with the appropriate root= values.
  2. Support a [boot_partition=n] filter in config.txt that would be filled by the active configuration from the autoboot.txt logic. This way, the config.txt could conditionally point to an appropriate cmdline*.txt next to it.
@bryceschober
Copy link
Author

bryceschober commented Feb 6, 2025

  1. Support the cmdline setting in the autoboot.txt in addition to the config.txt. This way, the A/B boot partitions could be identical and contain both cmdline_A.txt and cmdline_B.txt files with the appropriate root= values.

Now that I'm reading this again, I see that this wouldn't be a great option, since the config.txt "downstream" could easily want a different cmdline setting based on other conditions.

Perhaps a third option would be to enable a way for the user to set part of the cmdline contents independently of the cmdline.txt file(s). Perhaps something like this, in autoboot.txt:

[all]
tryboot_a_b=1
boot_partition=2
cmdline_opts=root=/dev/mmcblk0p4
[tryboot]
boot_partition=3
cmdline_opts=root=/dev/mmcblk0p5

@timg236 I notice that you had submitted the rpi-eeprom package to buildroot recently... What do you think the chances are of this use-case gaining support in the rpi firmware?

@jluebbe
Copy link

jluebbe commented Feb 7, 2025

2. Support a [boot_partition=n] filter in config.txt that would be filled by the active configuration from the autoboot.txt logic. This way, the config.txt could conditionally point to an appropriate cmdline*.txt next to it.

This seems the better choice when combined with secure boot, as otherwise unauthenticated cmdline arguments could be injected via autoboot.txt

@learmj
Copy link

learmj commented Feb 7, 2025

Hi. Are you suggesting that in the following case:

[all]
tryboot_a_b=1
boot_partition=2
[tryboot]
boot_partition=3

..you would have a config.txt on both p2 and p3, but rather than read cmdline.txt from p2 (or p3), have something like the following in each config.txt (example below for p2):

[boot_partition=2]
<cmdline args specific to p2>

?

What advantage would that give you over what's supported today? If the bootloader has been instructed to boot from p2 it loads config.txt from p2 and the cmdline.txt found on p2 can be generated at build time to be specific to the OS that's loaded from p2 (e.g. it can can specify a root device that's associated to OS boot from p2 via UUID=xxx or by-label etc). I don't know what you'd gain from having a [boot_partition=2] filter in a config.txt on p2?

@bryceschober
Copy link
Author

Hi @learmj, let me explain the option 2 in a bit more detail:

First, the use-case I'm targeting is where the tryboot_a_b feature is used to switch between partitions that are identical in purpose, integrating with a software update mechanism that executes out of one set of partitions, and supports updating a new version of firmware into the other set of partitions. Because the raspberrypi firmware requires a FAT partition for the "firmware" components, this ends up meaning that an A/B-swapping update system with a separate rootfs partition will have a total of at least 5 partitions, for example on an SD card:

  1. mmcblk0p1: (FAT) shared boot partition with only autoboot.txt
  2. mmcblk0p2: (FAT) firmware "slot" 0 with config.txt, cmdline.txt, and kernel image
  3. mmcblk0p3: (FAT) firmware "slot" 1 with config.txt, cmdline.txt, and kernel image
  4. mmcblk0p4: (WhateverFS) root filesystem "slot" 0 with the remainder of the system
  5. mmcblk0p5: (WhateverFS) root filesystem "slot" 1 with the remainder of the system

(FYI, I noticed that I had the wrong root= parameters in my previous comment, which might have caused confusion, so I've fixed it.)

These "slot" 0/1 partitions must be selected in tandem. The firmware configurations and kernel image for slot 1 are built to go together with the rootfs for slot 1, and it is the responsibility of the sw update integration to maintain them in tandem.

The software update system needs to build and deliver "images" (of whatever variety) for the firmware partition that are capable of executing from either partition slot. As it is, the software update mechanism is required to modify the contents of the config.txt after installing it in a particular partition (let's say the "slot" 1), so that it can boot the corresponding rootfs partition.

What I'm suggesting for option 2 is that the firmware partition images would contain a config.txt:

...
# Select rootfs partition matching the firmware partition we're executing from
[boot_partition=2]
cmdline=cmdline.slot0.txt
[boot_partition=3]
cmdline=cmdline.slot1.txt
[all]
...

And every firmware partition image will contain both a cmdline.slot1.txt with:

root=/dev/mmcblk0p4 ...

and also a cmdline.slot2.txt with:

root=/dev/mmcblk0p5 ...

What advantage would that give you over what's supported today? If the bootloader has been instructed to boot from p2 it loads config.txt from p2 and the cmdline.txt found on p2 can be generated at build time to be specific to the OS that's loaded from p2 (e.g. it can can specify a root device that's associated to OS boot from p2 via UUID=xxx or by-label etc). I don't know what you'd gain from having a [boot_partition=2] filter in a config.txt on p2?

And now that I've written all of the above explanation, I see that you're suggesting that the software update builds generate a unique UUID or label for each build of the rootfs partition image, and that the matching cmdline.txt in the matching firmware partition image use the unique filesystem UUID or label to address the matching rootfs partition.

Is that what you meant, @learmj? I guess that does sound like it could just work at the current level of support. Our partition image generation might get a bit more complex, but that's not a big deal.

@learmj
Copy link

learmj commented Feb 18, 2025

Is that what you meant

Yes.

The software update system needs to build and deliver "images" (of whatever variety) for the firmware partition that are capable of executing from either partition slot.

IMHO that should be a mandatory requirement for any system intended to generate and deploy updates to a device.

As it is, the software update mechanism is required to modify the contents of the config.txt after installing it in a particular partition (let's say the "slot" 1), so that it can boot the corresponding rootfs partition.

IMHO that should not be required because since there is a config.txt per boot partition (the bootloader looks for this when booting from the partition), this file (and others like cmdline.txt) can be generated offline and as part of the build. This is also stated by the tryboot_a_b documentation

This enables the tryboot switch to be made at the partition level rather than the file-level without having to modify configuration files in the A/B partitions.

I'm afraid I don't agree with your initial view that the tryboot_a_b scheme favours a ramdisk boot.

But for systems that would prefer not to have a separate ramdisk, they are currently required to modify their kernel cmdline appropriately for the A/B partition that is being booted

As I mentioned above, it's possible to generate cmdline.txt offline as part of the build and as you wrote above, generating a known UUID or disk label ahead of time (ie baked into the image by the build system) allows you to embed that in the cmdline.txt, meaning there is no on-device modification required and the update can be written and booted as-is.

@oli-ben
Copy link

oli-ben commented Mar 13, 2025

| As I mentioned above, it's possible to generate cmdline.txt offline as part of the build and as you wrote above, generating a known UUID or disk label ahead of time (ie baked into the image by the build system) allows you to embed that in the cmdline.txt, meaning there is no on-device modification required and the update can be written and booted as-is.

@learmj Looking into using root=UUID= or root=LABEL=, this does not seem to be supported by the kernel directly, meaning that one needs a ramdisk to use those options. The kernel itself only supports a device name (e.g. /dev/nvme0n1p1) or root=PARTUUID=.

So without a ramdisk, your suggestion of having the build generate a known UUID or disk label is not applicable, as far as I can tell.

Using root=PARTUUID= is an option, but will be problematic for updates.
Indeed, the PARTUUID will be specific to the partition on which an update will be installed. However, in order to support an A/B update scheme, this decision will need to be taken at runtime, not at buildtime, so it cannot be embedded in the update's cmdline,txt.

Once deployed, the cmdline.txt will still need to be edited to make sure that the root=PARTUUID= option on the bootFS matches the UUID of the partition on which the updated rootFS was installed

Did I miss something?

@timg236
Copy link

timg236 commented Mar 13, 2025

The latest Pi5 bootloader release adds an experimental feature to config.txt (not autoboot!) so you can write conditionals.

boot_partition here is the partition number that the boot.img was loaded from

[boot_partition=1]
cmdline=cmdline-rootfs-A.txt

[boot_partition=2]
cmdline=cmdline-rootfs-B.txt

@oli-ben
Copy link

oli-ben commented Mar 13, 2025

@timg236 This is exactly what we are looking for!

If I read this correctly, the release you are referring to is pieeprom-2025-03-10, as can be seen in this commit

@timg236
Copy link

timg236 commented Mar 13, 2025

Yes 2025-03-10.

oli-ben added a commit to DynonAvionics/buildroot that referenced this issue Mar 17, 2025
Raspberry Pi introduced a partition ID-based switch in config.txt,
which allows to use a different cmdline.txt depending on which
boot partition was booted.
See raspberrypi/firmware#1940 for details.

This commit add a new "RPI_FIRMWARE_AB_CMDLINE_FILES" config option
to support copying multiple cmdline files to the rpi firmware.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
bryceschober pushed a commit to DynonAvionics/buildroot that referenced this issue Mar 17, 2025
Raspberry Pi introduced a partition ID-based switch in config.txt,
which allows to use a different cmdline.txt depending on which
boot partition was booted.
See raspberrypi/firmware#1940 for details.

This commit add a new "RPI_FIRMWARE_AB_CMDLINE_FILES" config option
to support copying multiple cmdline files to the rpi firmware.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
oli-ben added a commit to DynonAvionics/buildroot that referenced this issue Mar 18, 2025
Raspberry Pi introduced a partition ID-based switch in config.txt,
which allows to use a different cmdline.txt depending on which
boot partition was booted.
See raspberrypi/firmware#1940 for details.

This commit add a new "RPI_FIRMWARE_AB_CMDLINE_FILES" config option
to support copying multiple cmdline files to the rpi firmware.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
@bryceschober
Copy link
Author

@timg236 Thanks for the feature! (Though I see as you've documented in the changelog, it's also not just for non-ramdisk boot.) We have verified that the new [boot_partition=<n>] filter works as expected in config.txt, and we're currently building a rauc backend around it.

What are the chances of making this feature available also in the RPi 4 / CM4 boot-loader?

@timg236
Copy link

timg236 commented Mar 21, 2025

The latest version of start4.elf in rpi-update supports "boot_partition" so if you update the start4.elf in your boot.img ramdisk it should work.

N.B. boot_partition doesn't do anything (useful) before the boot-partition is fully resolved, i.e. after EEPROM config, file-system enumeration partition walk.

These features are pretty new and I can't rule out small behavioral tweaks for corner cases. However, I am using for some internal projects so it's good to get feedback from more users.

oli-ben added a commit to DynonAvionics/buildroot that referenced this issue Apr 15, 2025
Raspberry Pi introduced a partition ID-based switch in config.txt,
which allows to use a different cmdline.txt depending on which
boot partition was booted.
See raspberrypi/firmware#1940 for details.

This commit add a new "RPI_FIRMWARE_AB_CMDLINE_FILES" config option
to support copying multiple cmdline files to the rpi firmware.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
oli-ben added a commit to DynonAvionics/buildroot that referenced this issue May 7, 2025
Raspberry Pi introduced a partition ID-based switch in config.txt,
which allows to use a different cmdline.txt depending on which
boot partition was booted.
See raspberrypi/firmware#1940 for details.

This commit add a new "RPI_FIRMWARE_AB_CMDLINE_FILES" config option
to support copying multiple cmdline files to the rpi firmware.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants