-
Notifications
You must be signed in to change notification settings - Fork 228
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
base: master
Are you sure you want to change the base?
bootchooser: add Raspberry Pi firmware initial support #1599
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
Very interesting! I just took a quick look:
|
Codecov ReportAttention: Patch coverage is
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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
src/bootchooser.c
Outdated
return FALSE; | ||
} | ||
|
||
if (g_rename(filename_tmp, filename) == -1) { |
There was a problem hiding this comment.
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?
-
Can the autoboot.txt file disappear? Apparently, yes.
-
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 byboot_partition
to read the fileconfig.txt
(ortryboot.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.
There was a problem hiding this comment.
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.
There was a problem hiding this 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?
Well, yes, the backend is able to generate the file from its own since I have all the I take the current I have implemented the backend to just do the bare minimal to handle the raspberrypi
Oh, I jumped your comment. I am sorry. I do not deal the command line at all. It adds some complications to modify the Do you think it's worth it?
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.
It depends on the behavior we agree to be correct :) |
This comment was marked as outdated.
This comment was marked as outdated.
a8dc573
to
c437c62
Compare
Hello Gaël, thank you for your work on this! I was myself looking at supporting the same use-case. One particular issue I noticed that I think is not addressed in your PR is maintaining the parental relationship between the 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
My point is what happens when you deploy a This would lead to the system booting with an updated kernel from All of this to say that I think |
src/bootchooser.c
Outdated
@@ -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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
Hello @oli-ben
My pleasure. I am learning more about the RAUC internal in doing this.
I have mentioned this in the integration documentation, maybe it is not clear enough:
And it is part of the example. So I strongly guess I have to insist on that part. Or...
Indeed you assumed it correctly :)
... okay, I get the point: I dedicate this to a slot hook. My first intention is to address the rootfs only in a first instance. The update of the
I am not yet convinced to hard-code this to the backend, mostly for this reasons:
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 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 |
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? |
Hello again, thanks for you super quick response
Very fair. I hope my feedback did not come across as criticism.
Also fair = )
Jan appears to be with you on this one.
Well, if you're using
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.
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'm also not saying you are wrong, just raising a point I thought was potentially interesting. |
That is true, as it seems that secure boot on RPi necessiates a signed ramdisk containing at least the kernel and config.txt
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:
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.
Although it is true that |
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.
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 :
I wonder if the the newly introduced artifact feature may help (with some changes, thinking about porting the new 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
Indeed it is fair to impose few things in RAUC. I am trying to find a flexible solution first.
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 ;) |
Good to hear! = D
Fair. My main argument is, that I think a user having a RAUC configuration specifying:
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 That second usecase should probably be supported, but I think we might not want it to be the default.
From what I can tell, that is correct. And definitely regrettable. ><
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.
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. 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.
sounds like it to me
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.
Yes, I agree that it should definitely be optional. I think I'd just default to it being |
@gportay and I talked about this at FOSDEM. Some points from our discussion:
|
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. |
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? |
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 ;) |
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>
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>
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>
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>
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>
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>
I do not think they did. My impression is, that they directly modify |
There are some great news on this front: the RPi people came back on the feature request, and introduced a conditional in There is therefore no need for RAUC to maintain the parental relationship, as the RPi bootloader can now take care of it. |
This is lovely indeed. |
34fabd3
to
e92b8d1
Compare
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. |
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:
|
@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 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 |
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.
I have probably missed something, but what is the difference with the EFI backend? |
For EFI, 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 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. |
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>
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>
d10d5da
to
fdc22a4
Compare
This adds an initial backend support for the Raspberry Pi firmware.