Subject: [bug#79248] GCD006: Rewrite bootloader subsystem

From: Danny Milosavljevic <[email-masked]>
Date: Wed, 03 Sep 2025 23:58:52 +0200

Hi,

>The "fix" here is to document what the people who contributed to this bootloader API wanted in the first place (syslinux or bootflow or
something else)

For the (original) u-boot support in Guix, what I wanted is for u-boot to use extlinux (syslinux-like configuration) for a menu and for booting older generations.  That's it.  It's intentionally modeled just like grub in Guix so I don't have to boil the ocean.

Traditional RISC machines are famously simple and you usually just put u-boot itself at some fixed sector, the end[1].  U-boot will see the extlinux configuration we generated, show a menu.  User chooses entry.  That's it.

I have intentionally not added chainloading back then, after asking whether anyone needs it and getting a "no".

It is very easy to overdo it in this space--and the Guix and Nix way of having whole-system configuration, while nice (and I really like it) is not what a user wants for reconfiguring the chainloader that loads Debian or Windows on the same machine, for example (that is, the first loader should NOT be reconfigured by Guix.  Ideally, Guix wouldn't need to know it exists).  Also, I question whether we want to support this use case in 2025.  There should be project decisions about it.

Personally, I just use qemu-system-x86_64 and emulate other systems (Windows and MacOS X) that way, and I use podman to emulate Debian, RedHat and stuff.  So I don't need to have a weird system I don't trust on the bare metal.  At that point, I don't need chainloading or weird foreign menu-entry support either.

To summarize, we should decide whether we boot only Guix.  If we do, boot only Guix.  That's it.  No chainloading required.

That's not to say that the USER can't configure the system so it boots something other than Guix--just that Guix doesn't do that.  What I mean to say, where does the Guix-responsible time begin when booting?

(For memtest86, UEFI can just have an extra file in the EFI boot volume for that.  Or we can just always provide memtest86 in Guix and add it to our boot config; or boot it from DVD, or from USB flash drive the one time you need it...)

Also, if you make it too complicated (and that happens earlier than you think... *hides*), you WILL eventually cause all your users not to be able to boot their computers anymore (due to a bug).

Anyway, booting is usually harder on CISC systems.
So there's the UEFI standard.  Even u-boot supports it (see Embedded Base Boot Requirements (EBBR) specification; including graphics), and it's mandatory for RISC-V servers.

amd64 BIOS machines are now probably all in the museum.  But we can boot those with grub without chainloading.
Or we could boot u-boot on bare metal (on amd64!), then chainload grub-efi from that using u-boot's UEFI providing.  But why?

>On ARM, Bootroms often support multiple way of booting (like multiple offsets from the start of the block device, MBR + fat32 partition, etc), and sometime a given way is incompatible with what the user wants (GPT instead of MBR). I'm unsure if Guix managed to not have situations that shows this or not.

Guix does not explicitly have abstractions like "from here to here on the disk A, there's this magical blob, don't stomp on it" and so on.

(There's already the buildroot project.  We could scrape how to boot systems (especially configuration, from which we could infer what magical blobs are where) from there.  Also, which u-boot version to use.  Which IS important.  Otherwise it won't boot)

>MLO can also be on a FAT partition, with special requirements for the partitioning table.

Exactly.  Constraints like this are common--and often for good reason.  Do you want to support loading OS bootloaders on extended partitions in the CPU's mask rom bootloader?  Probably not.  How about exfat?   Hell no.  Even the reader for loading a kernel from FAT16 is very hard to get small (and secure) enough (it's possible, though).  What if the first partition you boot is so far in the disk that you need more than a 32-bit sector number?  That would be annoying.  And so on.

Thankfully, there is no business incentive for CPU vendors to make this more complicated than it needs to be since there is no advantage in "hey we boot in this weird way".  That's why they are trying to standardize on UEFI, and usually contribute the implementation themselves.

>Now these are important to document I think, especially when the offset can end up inside GPT or MBR partitions, especially if the u-boot image becomes too big over time.

>(if we don't already, we'd need a check for that, and your proposal seems to enable to do that in a more elegant way).

We don't check for that.

Also, I think the bigger problem is if the number of used GPT entries (specifically, the entries in the GPT "directory"; specifically not necessarily the partition contents themselves) become too many and it scribbles over u-boot (or grub) that way.

>Or can we somehow move that into some structure and abstractions where we clearly define why we choose this method over others?

We could--but should a distribution do that on its own?  It's a LOT of work to maintain that--and new CPUs come out regularily (so many models!!!  So many!).

I'm totally for it if someone wants to maintain it--I just want to stress that this is not a fire-and-forget thing.

>This also brings the next question about /boot. In some cases that looks 100% controlled by Guix and it is re-generated during reconfiguration in certain cases. Is that on purpose?

Yes.  What else would we do?  After all, /boot/grub/grub.cfg (etc) has to be a GC root.

Note that, on Guix, usually /boot is on / anyway, and for example I boot "/" with full disk encryption.

If you mean /boot/efi , we should totally be a good tenant there (I think we are) and not zap everyone else.

>that, while code exists for some ARM SOCs (like some Allwinner chips), there is no tool to just do that (no update-u-boot)?

There's no tool to do that for most ARM 32-bit.  Traditionally, that's because the installation process is so simple nobody bothered to write scripts for *that*.  Also, totally inane differences like "this SOC reads from 0x60000 at boot", "that SOC reads from 0x67000 at boot", that someone has to maintain.  SIGH.

Anyway, in general I like this GCD.

Half-punting the installation to grub-install and half- to genimage and guix has always rubbed me the wrong way (what if they disagree?).  I guess in practical systems a kind of hybrid will happen since once it works once nobody wants to touch it again.

I'm in favor of cleaning it up.

Please let's also think about the case when you switch bootloaders and then go back to a generation which had the previous bootloader.  Will that use the new bootloader?  There are good arguments for yes, and good arguments for no.

[1] Not that simple in "trusted firmware" stuff anymore