8000 bootchooser: add Raspberry Pi firmware initial support by gportay · Pull Request #1599 · rauc/rauc · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

bootchooser: add Raspberry Pi firmware initial support #1599

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
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

gportay
Copy link
Contributor
@gportay gportay commented Jan 16, 2025

This adds an initial backend support for the Raspberry Pi firmware.

@gportay

This comment was marked as resolved.

@jluebbe jluebbe added the enhancement Adds new functionality or enhanced handling to RAUC label Jan 16, 2025
@jluebbe
Copy link
Member
jluebbe commented Jan 16, 2025

Very interesting!

I just took a quick look:

  • Would it be possible to use the partition index as RAUC bootname (setting it on the firmware partitions)? In that case, the currently booted partition could be detected by reading ``/chosen/bootloader/partition` in a RPi-sepecific implementation similar to get_custom_bootname(), which would be enabled for with this bootloader backend. That should also remove the limitation of having the three partitions first.
  • Please use Semantic Line Breaks in the docs.
  • Read the DT property directly from sysfs instead of using ftdget, which needs to unflatten the FTD again, which is already done by the kernel. We already do that in other places like https://github.com/rauc/rauc/blob/master/src/context.c#L266

Copy link
codecov bot commented Jan 16, 2025

Codecov Report

Attention: Patch coverage is 79.22849% with 70 lines in your changes missing coverage. Please review.

Project coverage is 84.44%. Comparing base (a86560c) to head (fdc22a4).

Files with missing lines Patch % Lines
src/bootloaders/raspberrypi.c 67.27% 54 Missing ⚠️
test/context.c 63.63% 8 Missing ⚠️
test/bootchooser.c 95.08% 6 Missing ⚠️
src/config_file.c 77.77% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1599      +/-   ##
==========================================
- Coverage   84.50%   84.44%   -0.07%     
==========================================
  Files          76       77       +1     
  Lines       22381    22717     +336     
==========================================
+ Hits        18913    19183     +270     
- Misses       3468     3534      +66     
Flag Coverage Δ
service=false 80.99% <79.22%> (-0.01%) ⬇️
service=true 84.39% <79.22%> (-0.07%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gportay

This comment was marked as resolved.

@gportay

This comment was marked as resolved.

@jluebbe

This comment was marked as resolved.

@jluebbe

This comment was marked as resolved.

@jluebbe

This comment was marked as resolved.

return FALSE;
}

if (g_rename(filename_tmp, filename) == -1) {
Copy link
Contributor
@a3f a3f Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fair to expect that by the time rauc status mark-good returns, the change is actually persistent on disk, so you need at least a call to fsync after this as we can't be sure the FAT is sync mounted. g_file_set_contents_full with G_FILE_SET_CONTENTS_DURABLE does fsync internally, but that's Glib >= 2.66, which is higher than RAUC's current minimum version (2.56).


I have been thinking about this a bit in relation to power-fail safety. The tryboot mechanism looks ok, it's apparently either either a warm-reboot-surviving memory-mapped register or persisted to EEPROM and cleared on next early boot (Generic DT abstractions for that is syscon-reboot-mode and nvmem-reboot-mode respectively).

The mark-good here is more difficult, FAT has no journal and even if it had, bootloaders tend to not implement journal playback anyway, so what happens here if the fsync is interrupted by a power cut?

  1. Can the autoboot.txt file disappear? Apparently, yes.

  2. Can the FAT filesystem itself become corrupt? I am not sure

Now what are the implications of a lost autoboot.txt? Could we deal with this gracefully? Should RAUC recreate this file to recover?

Anyhow, it may make sense to reduce the operations that we expect to be atomic to the bare minimum. Instead of rewriting autoboot.txt and moving it, we could expect an oldboot.txt with the other set of values and use Linux v6.0's support for renameat2(2) RENAME_EXCHANGE on FAT to exchange these files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fair to expect that by the time rauc status mark-good returns, the change is actually persistent on disk, so you need at least a call to fsync after this as we can't be sure the FAT is sync mounted. g_file_set_contents_full with G_FILE_SET_CONTENTS_DURABLE does fsync internally, but that's Glib >= 2.66, which is higher than RAUC's current minimum version (2.56).

I have tried to address this in 035eb31.

Anyhow, it may make sense to reduce the operations that we expect to be atomic to the bare minimum. Instead of rewriting autoboot.txt and moving it, we could expect an oldboot.txt with the other set of values and use Linux v6.0's support for renameat2(2) RENAME_EXCHANGE on FAT to exchange these files.

Hum, I understand the idea. That file could be generated using autoboot.txt if it does not exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now what are the implications of a lost autoboot.txt? Could we deal with this gracefully? Should RAUC recreate this file to recover?

With my observations... the firmware iterates over the FAT filesystems, looking for the file autoboot.txt or config.txt.

  • If the file autoboot.txt is found, it mounts the nth filesystem given by boot_partition to read the file config.txt (or tryboot.txt) and continue booting.
  • If the file config.txt is found, it reads it and continue booting.

My 2 cents... if the file autoboot.txt vanishes on 1st fat filesystem, the firmware mounts the 2nd fat filesystem and reads the config.txt (if it has not vanished as well, or it mounts the 3rd fat filesystem and reads the config.txt... or it continues the romcode boot sequence, maybe it ends in netboot).

So in short, it should boot the system A.

In order to make the system more resilient to autoboot.txt disappearance, a services should regenerate it from the system.conf. I leave this duty to the system, something on top of RAUC, but not an inner thing from the raspberrypi backend.

Copy link
Member
@jluebbe jluebbe Jan 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@a3f Do we really benefit from using RENAME_EXCHANGE here? We don't need the old file anymore, so a normale rename should be enough.

Copy link
Member
@jluebbe jluebbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't you generate the autoboot.txt file from scratch when writing, as RAUC should have all the required information in memory already?

It's still unclear to me how you generate the root= entry in the command line differently for A/B (see #1599 (comment)).

As far as I can see, you're not reading from /chosen/bootloader/partition in the context setup. How does RAUC detect the boot slot?

Do you handle multiple installations without rebooting correctly?

@gportay
Copy link
Contributor Author
gportay commented Jan 22, 2025

Couldn't you generate the autoboot.txt file from scratch when writing, as RAUC should have all the required information in memory already?

Well, yes, the backend is able to generate the file from its own since I have all the boot_partition= defined with their values in the system.conf. Also, there is that property tryboot_a_b=1 to hardcode in the section [all]; that property is not filled in the system.conf file.

I take the current autoboot.txt and swap the boot_partition= lines only. I think this is more future proof if some properties pop up later or if the user needs to adds extra properties for its own purpose like tryboot_a_b=1.

I have implemented the backend to just do the bare minimal to handle the raspberrypi autoboot.txt+tryboot feature:

  • swap the boot_partition
  • set the tryboot flag

It's still unclear to me how you generate the root= entry in the command line differently for A/B (see #1599 (comment)).

Oh, I jumped your comment. I am sorry.

I do not deal the command line at all.
That file is stored in the second and third boot_partition filesystems (cmdline.txt).
I have preferred to trust the content of those FAT filesystems and to not alter them if it is not necessary.

It adds some complications to modify the cmdline.txt files. The filesystem must be mounted and its path must be set in system.conf to locate file config.txt.

Do you think it's worth it?

As far as I can see, you're not reading from /chosen/bootloader/partition in the context setup. How does RAUC detect the boot slot?

So, I guess I have probably missed something. How does RAUC sets up?

I guess I have missed it by the mark-good systemd service at startup.

Or at least, it is guessed from the kernel command-line.

EDIT; Hum, I think I have understood the point. I will post something today.

Do you handle multiple installations without rebooting correctly?

It depends on the behavior we agree to be correct :) rauc install bundle.raucb always installs the bundle to the same slot(s). Is that the correct behavior? I guess yes as the second run for rauc install would install it on the booted slots, it is like shooting himself in the foot, right?

@gportay

This comment was marked as outdated.

@gportay gportay force-pushed the bootchooser-add-raspberrypi-firmware-initial-support branch from a8dc573 to c437c62 Compare January 22, 2025 17:28
@oli-ben
Copy link
oli-ben commented Jan 23, 2025

Hello Gaël,

thank you for your work on this! I was myself looking at supporting the same use-case.
I had however started supporting this via a bootloader-custom backend.

One particular issue I noticed that I think is not addressed in your PR is maintaining the parental relationship between the rootfs and firmware slots.

Indeed, unless I am mistaken and you have a way to instruct/script the RPi firmware at runtime (in which case disregard this), I think that most likely, that relationship is enforced by the kernel command line, that is specified in cmdline.txt on each of your firmware partitions.
I am now making slight assumptions about your system, please correct me if I'm wrong:

  • the kernel command line config.txt on firmware.0 points it to /dev/mmcblk0p5 (rootfs.0)
  • the kernel command line config.txt on firmware.1 points it to /dev/mmcblk0p6 (rootfs.1)

My point is what happens when you deploy a firmware update which contains a config.txt file:
that file was generated at build time, and must point the kernel to a rootfs in order for the system to be able to boot, but it cannot know at build time which slot RAUC will choose to deploy the update, so there is a 50/50 chance that the parental relationship will be broken because the file will point to rootfs.0 but will be installed on firmware.1.

This would lead to the system booting with an updated kernel from firmware.1 and an old rootfs from rootfs.0.
That means that rootfs.1 could be broken, which would not be detected, and the next update to slot 0 could brick the system if it failed, if it now broke rootfs.0.

All of this to say that I think raspberrypi_set_primary should enforce the parental relationship by making sure that the rootfs device on the kernel command line in cmdline.txt is the device configured for that slot's child in the RAUC configuration.

@@ -975,6 +978,485 @@ static gboolean uboot_set_primary(RaucSlot *slot, GError **error)
return TRUE;
}

static RaucSlot *raspberrypi_find_config_slot_by_boot_partition(RaucConfig *config, gint boot_partition)
{
g_autofree gchar *name = g_strdup_printf("%u", boot_partition);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes it mandatory for the name of the slot to be the partition number.

I might have missed it, but I don't think I saw that explicitly documented in docs/integration.rst, and this requirement for other setups.
It might also be useful as a comment in the example configuration files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See that comment.

The documentation says:

If the slot is bootable, then you also need

  • the bootname which is the name the bootloader uses to refer to this slot device.

That could be interpreted the bootname is how the names/references it.
In a sense, for the raspberrypi firmware, it is the boot_partition index. For barebox, it is the bootchooser/bootstate. For other backend, it is free.

It might also be useful as a comment in the example configuration files.

This should be that point.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It uses the slot's bootname, which is how RAUC knows how the slot is "called" by the bootloader (or firmware in this case).

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My apologies, it looks like I should just read more thoroughly.

@gportay
Copy link
Contributor Author
gportay commented Jan 23, 2025

Hello @oli-ben

Hello Gaël,

thank you for your work on this! I was myself looking at supporting the same use-case. I had however started supporting this via a bootloader-custom backend.

My pleasure. I am learning more about the RAUC internal in doing this.
I have written my own custom backend before that as a PoC.

One particular issue I noticed that I think is not addressed in your PR is maintaining the parental relationship between the rootfs and firmware slots.

I have mentioned this in the integration documentation, maybe it is not clear enough:

Those rootfs slots are parented to their FAT filesystem slot.

And it is part of the example.

So I strongly guess I have to insist on that part. Or...

Indeed, unless I am mistaken and you have a way to instruct/script the RPi firmware at runtime (in which case disregard this), I think that most likely, that relationship is enforced by the kernel command line, that is specified in cmdline.txt on each of your firmware partitions. I am now making slight assumptions about your system, please correct me if I'm wrong:

* the kernel command line `config.txt` on `firmware.0` points it to `/dev/mmcblk0p5` (`rootfs.0`)

* the kernel command line `config.txt` on `firmware.1` points it to `/dev/mmcblk0p6` (`rootfs.1`)

Indeed you assumed it correctly :)

My point is what happens when you deploy a firmware update which contains a config.txt file: that file was generated at build time, and must point the kernel to a rootfs in order for the system to be able to boot, but it cannot know at build time which slot RAUC will choose to deploy the update, so there is a 50/50 chance that the parental relationship will be broken because the file will point to rootfs.0 but will be installed on firmware.1.

This would lead to the system booting with an updated kernel from firmware.1 and an old rootfs from rootfs.0. That means that rootfs.1 could be broken, which would not be detected, and the next update to slot 0 could brick the system if it failed, if it now broke rootfs.0.

... okay, I get the point: I dedicate this to a slot hook.
But I have not mentioned it yet. The integration documentation remains incomplete.

My first intention is to address the rootfs only in a first instance.
This assumes the system.conf matches the two firmware slots (i.e. cmdline.txt).

The update of the firmware slots requires an hook to set the appropriate root= to cmdline.txt once the filesystem is written to the device and mounted.

All of this to say that I think raspberrypi_set_primary should enforce the parental relationship by making sure that the rootfs device on the kernel command line in cmdline.txt is the device configured for that slot's child in the RAUC configuration.

I am not yet convinced to hard-code this to the backend, mostly for this reasons:

  • how to use dm-verity (root= -> systemd.verity_root_data=, systemd.verity_root_hash=, systemd.verity_root_data=...)
  • does the backend force the use of config.txt for tryboot (tryboot.txt, see autoboot.txt's option tryboot_a_b=1)?
  • does the backend force the use of cmdline.txt for the kernel command line (see config.txt's option cmdline)?

I have not yet explore all these possibilities 😭 I cannot tell what is the best solution, and I have preferred to limit the backend to the bare minimum and use the bundle hooks as an exit for now.

I am not saying you are wrong, all of you raise good points, and maybe this should be part of the backend after all...

@jluebbe
Copy link
Member
jluebbe commented Jan 23, 2025

The update of the firmware slots requires an hook to set the appropriate root= to cmdline.txt once the filesystem is written to the device and mounted.

I think that using a (post-install) hook is fine. Compared to the alternatives, it's very simple and easy to implement.

More complex cases (e.g. secure boot) wouldn't allow customizing the cmdline from unsigned config files, so you'd need a signed kernel+initramfs. In that case, I'd probably look at reading /chosen/bootloader/partition from DT and deriving the rootfs partition from that. This way, the contents of the firmware partition image doesn't need to be modified.

@gportay
Copy link
Contributor Author
gportay commented Jan 23, 2025

It's still unclear to me how you generate the root= entry in the command line differently for A/B (see #1599 (comment)).

Do you think it worth to create that function r_boot_get_bootname() and calls it at setup? So I can get the root device from the device-tree on the raspberrypi backend.

@jluebbe It is somehow what you expected?

@oli-ben
Copy link
oli-ben commented Jan 23, 2025

Hello again, thanks for you super quick response

... okay, I get the point: I dedicate this to a slot hook. But I have not mentioned it yet. The integration documentation remains incomplete.

Very fair. I hope my feedback did not come across as criticism.

My first intention is to address the rootfs only in a first instance. This assumes the system.conf matches the two firmware slots (i.e. cmdline.txt).

The update of the firmware slots requires an hook to set the appropriate root= to cmdline.txt once the filesystem is written to the device and mounted.

Also fair = )

I am not yet convinced to hard-code this to the backend, mostly for this reasons:

Jan appears to be with you on this one.

* how to use `dm-verity` (`root=` -> `systemd.verity_root_data=`, `systemd.verity_root_hash=`, `systemd.verity_root_data=`...)

Well, if you're using dm-verity in this setup, my impression is, that you'd then have to update the root hash, which should be co-located with the kernel, on the firmware partitions, because that's where the RPi firmware will expect it.
This only reinforces the fact that someone would have to maintain the parent relationship, as a firmware will only have the hashes of their child rootFS.
From where I stand, that could be either the backend or a post-install hook, but as a naive user, I would expect the backend to be doing that for me, since RAUC is aware of that relationship.

* does the backend force the use of `config.txt` for tryboot (`tryboot.txt`, see `autoboot.txt`'s option [tryboot_a_b=1](https://www.raspberrypi.com/documentation/computers/config_txt.html#tryboot_a_b))?

I wouldn't see a problem with this: this is all assuming that we are doing a A/B setup, which is what this option was intended for.

* does the backend force the use of `cmdline.txt` for the kernel command line (see `config.txt`'s option [cmdline](https://www.raspberrypi.com/documentation/computers/config_txt.html#cmdline))?

I also would not particularly see a problem with this: imho it's fair for RAUC to impose some configuration, especially when it seems to be the "usual" way of using the RPi firmware

I have not yet explore all these possibilities 😭 I cannot tell what is the best solution, and I have preferred to limit the backend to the bare minimum and use the bundle hooks as an exit for now.

I am not saying you are wrong, all of you raise good points, and maybe this should be part of the backend after all...

I'm also not saying you are wrong, just raising a point I thought was potentially interesting.
If you're not interested in looking further into this, I'd be happy to potentially give it a shot after this PR is merged = )

@oli-ben
Copy link
oli-ben commented Jan 23, 2025

The update of the firmware slots requires an hook to set the appropriate root= to cmdline.txt once the filesystem is written to the device and mounted.

I think that using a (post-install) hook is fine. Compared to the alternatives, it's very simple and easy to implement.

More complex cases (e.g. secure boot) wouldn't allow customizing the cmdline from unsigned config files, so you'd need a signed kernel+initramfs. In that case,

That is true, as it seems that secure boot on RPi necessiates a signed ramdisk containing at least the kernel and config.txt

tryboot is pretty explicit in needing partitions and I have not seen anything mention using it with secure boot, so my impression is, that they might be incompatible.

In that case, I'd probably look at reading /chosen/bootloader/partition from DT and deriving the rootfs partition from that.

I think that'd be great, and this is what I did when using UBoot, but when using the RPi firmware directly to load the kernel, the only options we'd have to do this are:

  • within the kernel somehow
  • by having the RPi firmware call essentially a tiny bootloader that would simply read the DTB and load the kernel passing it the correct command line

This seems like a large amount of effort, and while this might solve the secure boot usecase, might be a tad too complicated for the normal one.

This way, the contents of the firmware partition image doesn't need to be modified.

Although it is true that cmdline.txt would no longer need to be modified, I think that might not be true for a dm-verity setup, as it would need to update the firmare partition image to include the correct root hash.

@gportay
Copy link
Contributor Author
gportay commented Jan 31, 2025

Very fair. I hope my feedback did not come across as criticism.

No worries.

I liked your feedback and I had to take the time for reflection. I did that months ago, and I do not recall all the pieces that led me to that implementation.

Well, if you're using dm-verity in this setup, my impression is, that you'd then have to update the root hash, which should be co-located with the kernel, on the firmware partitions, because that's where the RPi firmware will expect it. This only reinforces the fact that someone would have to maintain the parent relationship, as a firmware will only have the hashes of their child rootFS. From where I stand, that could be either the backend or a post-install hook, but as a naive user, I would expect the backend to be doing that for me, since RAUC is aware of that relationship.

I really do understand you opinion; I am still perplex about having an all-in-one backend solution or having some hooks :/

If I am right, the issue lies in the fact that :

  • the raspberry bootloader stores the cmdline and the kernel at the same place, in a FAT filesystem (that is even worth)
  • RAUC works by slots and cannot write files to an existing filesystem (i.e. without wiping the whole partition).

I wonder if the the newly introduced artifact feature may help (with some changes, thinking about porting the new files/tree types a new slot handlers).
This way, the backend can update the rootfs slots, and updates the kernel and the dtb{,o} in the firmware filesystem slots.
Does it look correct?

Also, I do not think the other backends deal with the kernel command line, mostly because they do not need to, the bootloader and kernel files are somehow decorelated, or tools exists to update the pieces separately, am I still correct?

OOS: I guess I will throw an eye to the artifacts once I have free time. I have plan to test it to update the bootcode.bin of the former Raspberry Pis (< 4) that should be a good candidate.

* does the backend force the use of `cmdline.txt` for the kernel command line (see `config.txt`'s option [cmdline](https://www.raspberrypi.com/documentation/computers/config_txt.html#cmdline))?

I also would not particularly see a problem with this: imho it's fair for RAUC to impose some configuration, especially when it seems to be the "usual" way of using the RPi firmware

Indeed it is fair to impose few things in RAUC. I am trying to find a flexible solution first.

I'm also not saying you are wrong, just raising a point I thought was potentially interesting. If you're not interested in looking further into this, I'd be happy to potentially give it a shot after this PR is merged = )

It's great to share our own solutions. And it is not I am not interested, in my head, the wind blows in the direction of not rewriting the kernel cmdline in the backend.

And I do not mind if you do it course ;)
Think about a way to deactive it; for example, do not rewrite the cmdline.txt if raspberrypi-config-txt is unset in system.conf.

@oli-ben
Copy link
oli-ben commented Feb 4, 2025

Very fair. I hope my feedback did not come across as criticism.

No worries.

I liked your feedback and I had to take the time for reflection. I did that months ago, and I do not recall all the pieces that led me to that implementation.

Good to hear! = D

I really do understand you opinion; I am still perplex about having an all-in-one backend solution or having some hooks :/

Fair. My main argument is, that I think a user having a RAUC configuration specifying:

  • to use a backend specific for the RPi bootloader
  • a parent/child relationship between boot and root FS
  • redundant A/B slots

is more likely to expect RAUC to maintain the parent/child relationship between the boot and root FS automatically than actively wanting RAUC to leave the cmdline.txt completely unchanged, down to the init argument.

That second usecase should probably be supported, but I think we might not want it to be the default.

If I am right, the issue lies in the fact that :

* the raspberry bootloader stores the cmdline and the kernel at the same place, in a FAT filesystem (that is even worth)

* RAUC works by slots and cannot write files to an existing filesystem (i.e. without wiping the whole partition).

From what I can tell, that is correct. And definitely regrettable. ><

I wonder if the the newly introduced artifact feature may help (with some changes, thinking about porting the new files/tree types a new slot handlers). This way, the backend can update the rootfs slots, and updates the kernel and the dtb{,o} in the firmware filesystem slots. Does it look correct?

I haven't used that feature, but it might be the right way to handle this. Especially if the overall decision is, that having the backend rewrite cmdline.txt is not ok.

Also, I do not think the other backends deal with the kernel command line, mostly because they do not need to, the bootloader and kernel files are somehow decorelated, or tools exists to update the pieces separately, am I still correct?

Yes. The core issue here, in my opinion, is that the RPi bootloader can only load the kernel from the same partition as cmdline.txt.
That means, that if we want to be able to update the kernel using a "normal"m slot-based approach, we're going to have to update cmdline.txt as well, even though it's related to the bootloader. Some of the configuration in that file (the init argument) is slot-specific, but we can't know when building the bundle which slot it will be installed on.

UBoot could work around this, because it has scripting capabilities, and could therefore dynamically determine the partition it was started from by parsing the DTB, and adjust the command line accordingly.

OOS: I guess I will throw an eye to the artifacts once I have free time. I have plan to test it to update the bootcode.bin of the former Raspberry Pis (< 4) that should be a good candidate.

sounds like it to me

It's great to share our own solutions. And it is not I am not interested, in my head, the wind blows in the direction of not rewriting the kernel cmdline in the backend.

Yes, it sound like we mostly have a different image of what the "default"/"normal"/"common" (or whatever we want to call it) usecase looks like.

And I do not mind if you do it course ;) Think about a way to deactive it; for example, do not rewrite the cmdline.txt if raspberrypi-config-txt is unset in system.conf.

Yes, I agree that it should definitely be optional. I think I'd just default to it being opt-out rather than opt-in, because not wanting it seems to me like the more exotic usecase.

@jluebbe
Copy link
Member
jluebbe commented Feb 5, 2025

@gportay and I talked about this at FOSDEM. Some points from our discussion:

  • Artifact updates won't help here. It is for SW components used by both A/B rootfs slots, which do not depend on a specific rootfs version (e.g. containers or statically linked applications).
  • src/bootchooser.c should be split up, but that's independent of this PR.
  • Introducing r_boot_get_bootname() is a good approach, but we don't need the identical "not implemented" functions. Instead only add the supported cases to the if/else cascade. The refactoring could be merged early in a separate PR to reduce the size of this one.
  • The proper way to have a fixed kernel boot image seems to be an initramfs which determines the root device based on /chosen/bootloader/partition in the device tree (as in Raspberry Pi 5 /chosen/bootloader/partition is set to 0 raspberrypi/rpi-eeprom#575). This will be compatible with signed boot images (for secure boot) as well.
  • The autoboot.txt file should probably be generated from scratch instead of parsing and updating it. That would avoid a broken system if it gets damaged or removed in some way. If there is a need for custom properties in autoboot.txt, support for that could be added later with the appropriate justification.

@bryceschober
Copy link

Yeah, I came to that conclusion myself, and opened a case to help support non-initramfs A/B tryboot integrations over at raspberrypi/firmware#1940. I don't expect them to care about the use-case of A/B updates without an initramfs, though.

@jluebbe
Copy link
Member
jluebbe commented Feb 28, 2025

I need the following change, otherwise the context reads the kernel command line first and assumes a rootfs slot as a primary slot; the rootfs slots are parented to the firmware slots, that are the slots with bootname.

Hmm, giving the bootchooser backend priority over the generic code sounds sensible. After all, it should know best. One corner-case would be indicating boot from NFS or "external". I'll need to think about this some more. @ejoerns?

@djr-spectrummfg
Copy link
10000 Contributor

To get rauc working on the RPi CM4 I used a simple shell script: https://gist.github.com/djr-spectrummfg/a427e318e376f98245f5d3ff9c1fb835

It also uses the autoboot functionality to select which boot partition to use. However I never had much luck getting tryboot to work properly so I did not use that.

@gportay
Copy link
Contributor Author
gportay commented Mar 10, 2025

To get rauc working on the RPi CM4 I used a simple shell script: https://gist.github.com/djr-spectrummfg/a427e318e376f98245f5d3ff9c1fb835

It also uses the autoboot functionality to select which boot partition to use. However I never had much luck getting tryboot to work properly so I did not use that.

How did you set the tryboot flag?

The only way I found is to use vcmailbox using the linux-raspberrypi kernel.

You should update the eeprom, IIRC the tryboot flag can be cleared/lost.

Also, you ça give a try to that implementation ;)

oli-ben added a commit to DynonAvionics/buildroot that referenced this pull request Mar 18, 2025
As discussed in
rauc/rauc#1599 (comment),
swapping two versions of autoboot.txt is a better option than
modifying autoboot.txt.
My previous modifications to the rpi-firmware package assumed
that there would only be one autoboot.txt, but we now need two.

Add an option in rpi-firmware to put two autoboot.txt files in
the boot partition, as autoboot.txt and autoboot_alt.txt.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
oli-ben added a commit to DynonAvionics/buildroot that referenced this pull request Mar 18, 2025
As discussed in
rauc/rauc#1599 (comment),
swapping two versions of autoboot.txt is a better option than
modifying autoboot.txt.
My previous modifications to the rpi-firmware package assumed
that there would only be one autoboot.txt, but we now need two.

Add an option in rpi-firmware to put two autoboot.txt files in
the boot partition, as autoboot.txt and autoboot_alt.txt.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
oli-ben added a commit to DynonAvionics/buildroot that referenced this pull request Mar 18, 2025
As discussed in
rauc/rauc#1599 (comment),
swapping two versions of autoboot.txt is a better option than
modifying autoboot.txt.
My previous modifications to the rpi-firmware package assumed
that there would only be one autoboot.txt, but we now need to
also include the configuration for the slots, which will be
swapped in place of autoboot.txt upon update.

Add an option in rpi-firmware to put aditional autoboot files
in the boot partition.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
oli-ben added a commit to DynonAvionics/buildroot that referenced this pull request Mar 19, 2025
As discussed in
rauc/rauc#1599 (comment),
swapping two versions of autoboot.txt is a better option than
modifying autoboot.txt.
My previous modifications to the rpi-firmware package assumed
that there would only be one autoboot.txt, but we now need to
also include the configuration for the slots, which will be
swapped in place of autoboot.txt upon update.

Add an option in rpi-firmware to put additional autoboot files
in the boot partition.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
oli-ben added a commit to DynonAvionics/buildroot that referenced this pull request Mar 19, 2025
As discussed in
rauc/rauc#1599 (comment),
swapping two versions of autoboot.txt is a better option than
modifying autoboot.txt.
My previous modifications to the rpi-firmware package assumed
that there would only be one autoboot.txt, but we now need to
also include the configuration for the slots, which will be
swapped in place of autoboot.txt upon update.

Add an option in rpi-firmware to put additional autoboot files
in the boot partition.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
oli-ben added a commit to DynonAvionics/buildroot that referenced this pull request Mar 19, 2025
As discussed in
rauc/rauc#1599 (comment),
swapping two versions of autoboot.txt is a better option than
modifying autoboot.txt.
My previous modifications to the rpi-firmware package assumed
that there would only be one autoboot.txt, but we now need to
also include the configuration for the slots, which will be
swapped in place of autoboot.txt upon update.

Add an option in rpi-firmware to put additional autoboot files
in the boot partition.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
@oli-ben
Copy link
oli-ben commented Mar 20, 2025

To get rauc working on the RPi CM4 I used a simple shell script: https://gist.github.com/djr-spectrummfg/a427e318e376f98245f5d3ff9c1fb835
It also uses the autoboot functionality to select which boot partition to use. However I never had much luck getting tryboot to work properly so I did not use that.

How did you set the tryboot flag?

I do not think they did. My impression is, that they directly modify autoboot.txt to make the other partition the next one to boot.
I do not think this is wise, as that means that if the update is faulty, the device will be in an irrecoverable state.
That is, iiuc, the entire point of the tryboot functionality.

@oli-ben
Copy link
oli-ben commented Mar 20, 2025

Yeah, I came to that conclusion myself, and opened a case to help support non-initramfs A/B tryboot integrations over at raspberrypi/firmware#1940. I don't expect them to care about the use-case of A/B updates without an initramfs, though.

There are some great news on this front: the RPi people came back on the feature request, and introduced a conditional in config.txt, which can be used to set cmdline depending on the chosen partition.
It was introduced as an experimental feature in version 2025-03-10 of the bootloader, and eliminates the need to have a different config.txt file on boot partition A and boot partition B: both partitions can now be identical and have cmdline-A.txt and cmdline-B.txt, and config.txt will pick one or the other depending on the booted partition.

There is therefore no need for RAUC to maintain the parental relationship, as the RPi bootloader can now take care of it.

@gportay
Copy link
Contributor Author
gportay commented Mar 20, 2025

It was introduced as an experimental feature in version 2025-03-10 of the bootloader, and eliminates the need to have a different config.txt file on boot partition A and boot partition B: both partitions can now be identical and have cmdline-A.txt and cmdline-B.txt, and config.txt will pick one or the other depending on the booted partition.

This is lovely indeed.

@gportay
Copy link
Contributor Author
gportay commented Mar 20, 2025

Hmm, giving the bootchooser backend priority over the generic code sounds sensible. After all, it should know best. One corner-case would be indicating boot from NFS or "external". I'll need to think about this some more. @ejoerns?

@jluebbe, @ejoerns: I have made this PR #1669.

@gportay gportay force-pushed the bootchooser-add-raspberrypi-firmware-initial-support branch from 34fabd3 to e92b8d1 Compare March 20, 2025 14:54
@djr-spectrummfg
Copy link
Contributor

To get rauc working on the RPi CM4 I used a simple shell script: https://gist.github.com/djr-spectrummfg/a427e318e376f98245f5d3ff9c1fb835
It also uses the autoboot functionality to select which boot partition to use. However I never had much luck getting tryboot to work properly so I did not use that.

How did you set the tryboot flag?

I do not think they did. My impression is, that they directly modify autoboot.txt to make the other partition the next one to boot. I do not think this is wise, as that means that if the update is faulty, the device will be in an irrecoverable state. That is, iiuc, the entire point of the tryboot functionality.

I did try it at one point, but I don't remember the details other than it wasn't working for me and I gave up. The script implementation I shared does not use tryboot.

My view on it is that tryboot is not really necessary, because the only case where it would help is if I were to issue an update file that did not boot, which is easily avoidable by testing.

@bryceschober
Copy link

It was introduced as an experimental feature in version 2025-03-10 of the bootloader, and eliminates the need to have a different config.txt file on boot partition A and boot partition B: both partitions can now be identical and have cmdline-A.txt and cmdline-B.txt, and config.txt will pick one or the other depending on the booted partition.

This is lovely

But unfortunately, that support is only for the RPi5 (2712), not also for the RPi4 (2711), at least for now.

@bryceschober
Copy link

But unfortunately, that support is only for the RPi5 (2712), not also for the RPi4 (2711), at least for now.

FWIW, in another update, the maintainer commented on raspberrypi/firmware#1940 that:

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.

@jluebbe jluebbe modified the milestones: Release v1.14, Release v1.15 Apr 2, 2025
@jluebbe
Copy link
Member
jluebbe commented Apr 2, 2025

@ejoerns and myself looked at this to find out if we can merge it for v1.14. The main issue we see is with the mapping of the RPi bootloaders behavior to RAUC's concepts. While the current implementation would basically work, it might be surprising when using RAUC on multiple different bootloaders.

For example r_raspberrypi_get_primary() only looks at the information from devicetree, so if a user runs mark-good booted and mark-good other, the autoboot.txt is only written once (due to the slot == primary check in r_raspberrypi_set_primary()). Also the good/bad state depends on which slot was booted, which isn't the case for other bootloaders.

We don't have a good idea how to fix that easily, so we could merge this after the v1.14 release with a warning that the behavior differs from other bootloaders until this is consolidated (perhaps by introducing an explicit tryboot concept).

@gportay
Copy link
Contributor Author
gportay commented Apr 2, 2025

@ejoerns and myself looked at this to find out if we can merge it for v1.14. The main issue we see is with the mapping of the RPi bootloaders behavior to RAUC's concepts. While the current implementation would basically work, it might be surprising when using RAUC on multiple different bootloaders.

I do not mind to post-pone the merged for to 1.15.

Furthermore, this backend needs this to get merged first, and I have not get the time to address that.

For example r_raspberrypi_get_primary() only looks at the information from devicetree, so if a user runs mark-good booted and mark-good other, the autoboot.txt is only written once (due to the slot == primary check in r_raspberrypi_set_primary()). Also the good/bad state depends on which slot was booted, which isn't the case for other bootloaders.

I have probably missed something, but what is the difference with the EFI backend?

@ejoerns
Copy link
Member
ejoerns commented Apr 2, 2025

For example r_raspberrypi_get_primary() only looks at the information from devicetree, so if a user runs mark-good booted and mark-good other, the autoboot.txt is only written once (due to the slot == primary check in r_raspberrypi_set_primary()). Also the good/bad state depends on which slot was booted, which isn't the case for other bootloaders.

I have probably missed something, but what is the difference with the EFI backend?

For EFI, get_primary() returns the first known element in BootOrder. If BootNext is set, this is returned instead.
I.e. it returns the target that would be booted when powering off the device.

For Raspberry this would mean it needs to look at the content of the autoboot.txt as this dictates which target to boot.

The good/bad state for EFI is also returned by inspecting if the boot target appears in BootOrder, thus if one could potentially boot it. For RPI the bad-marking part (i.e. inhibiting slot boot) would require removing it from the autoboot.txt. Otherwise, one could simply switch into it using tryboot.

Admittedly, the concepts we currently have do not fully match the general tryboot-approach anyway, thus it might need more to fully support it. However, as a first PoC it should be fine to be merged and refined in master.

oli-ben added a commit to DynonAvionics/buildroot that referenced this pull request Apr 15, 2025
As discussed in
rauc/rauc#1599 (comment),
swapping two versions of autoboot.txt is a better option than
modifying autoboot.txt.
My previous modifications to the rpi-firmware package assumed
that there would only be one autoboot.txt, but we now need to
also include the configuration for the slots, which will be
swapped in place of autoboot.txt upon update.

Add an option in rpi-firmware to put additional autoboot files
in the boot partition.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
oli-ben added a commit to DynonAvionics/buildroot that referenced this pull request May 7, 2025
As discussed in
rauc/rauc#1599 (comment),
swapping two versions of autoboot.txt is a better option than
modifying autoboot.txt.
My previous modifications to the rpi-firmware package assumed
that there would only be one autoboot.txt, but we now need to
also include the configuration for the slots, which will be
swapped in place of autoboot.txt upon update.

Add an option in rpi-firmware to put additional autoboot files
in the boot partition.

Signed-off-by: Olivier Benjamin <olivier.benjamin@bootlin.com>
This adds an initial backend support for the Raspberry Pi firmware.

Signed-off-by: Gaël PORTAY <gael.portay@rtone.fr>
@gportay gportay force-pushed the bootchooser-add-raspberrypi-firmware-initial-support branch from d10d5da to fdc22a4 Compare May 25, 2025 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Adds new functionality or enhanced handling to RAUC
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants
0