Package | Source(s) | Maintainer(s) | |
---|---|---|---|
guix-patches | PTS Buildd Popcon |
Report forwarded
to guix-patches@gnu.org
:
bug#79248
; Package guix-patches
.
(Fri, 15 Aug 2025 20:06:02 GMT) (full text, mbox, link).
Acknowledgement sent
to Lilah Tascheter <lilah@lunabee.space>
:
New bug report received and forwarded. Copy sent to guix-patches@gnu.org
.
(Fri, 15 Aug 2025 20:06:02 GMT) (full text, mbox, link).
Message #5 received at submit@debbugs.gnu.org (full text, mbox, reply):
* 006-rebootload.md: New file. --- 006-rebootload.md | 324 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 006-rebootload.md diff --git a/006-rebootload.md b/006-rebootload.md new file mode 100644 index 0000000..5c1788b --- /dev/null +++ b/006-rebootload.md @@ -0,0 +1,324 @@ +title: Bootloader Subsystem Rewrite +id: 006 +status: draft +discussion: https://issues.guix.gnu.org/<number assigned by issue tracker> +authors: Lilah Tascheter +sponsors: <Sponsor Name> +date: <date when the discussion period starts> +SPDX-License-Identifier: CC-BY-SA-4.0 OR GFDL-1.3-no-invariants-or-later +--- + +# Summary + +Guix's bootloader handling was originally designed solely for GRUB but, with +greater adoption and widened system compatibility, this has proved insufficient. +Unfortunately, core aspects of bootloader handling have remained unchanged, +resulting in a system hard to fit new bootloaders into and confusing for +end-users to configure. + +We propose an in-depth rewrite in order to create a more flexible and easier to +understand interface for both end users and bootloader packagers. + +Prior work has been done as patchsets #69343, #73202, and #72457 on Mumi. This +GCD is a new proposal improving upon these patches. + +# Motivation + +We identify three main ways the current bootloader handling proves insufficient: +1. Structural assumptions of GRUB exist in both user-facing bootloader + configuration options as well as the packager-facing bootloader interface. +2. Multiple special cases exist in bootloader packaging and installation, making + it incredibly easy to package bootloaders that either install onto the host + during disk-image building or fail during system rollback. +3. Bootloader packaging is ill-documented and relies on a confusing interface, + which is especially bad for such a sensitive part of system configuration. + +Take, first, the user-facing side of things. 11/14 fields of the +`<bootloader-configuration>` record are only used in GRUB, with multiple having +no imaginable use for non-GRUB bootloaders in the first place. Theoretically, +new bootloaders could add fields to the record if they need their own +configuration, but any external channels would not be able to do even that. + +Disk image handling is not well-specified, especially when attempting to create +a disk image with a custom bootloader. Examples provide `/dev/vda1`, so a user +would assume that Guix looks for that magic string, but instead bootloader +handling uses a special install procedure. Notably, an unused target must be +specified anyway. + +The `<menu-entry>` record is, also, made solely with GRUB in mind, even though +dual-booting is theoretically something that should be supported by bootloaders +in general. Fields are documented with semantics based solely on how GRUB +interprets them. + +More notably, the current state of affairs hampers bootloader packaging +significantly. The `<bootloader>` record contains the following fields: +* `bootloader-name`: containing a symbol supposed to uniquely identify a + bootloader package, for use in rollbacks. Notably, u-boot bootloaders ignore + this requirement, to potentially disasterous consequences. It doesn't help + that the only time one would notice problems with this (for example, a + channel's bootloader defined outside gnu/bootloader, a bootloader defined as a + procedure, or reused `bootloader-name`s) is when you already need to roll + back to a different bootloader. +* `bootloader-package`: This is only useful for switching which GRUB package is + used for GRUB bootloaders. +* `bootloader-configuration-file`: This is the sole mechanism through which + rollbacks function. Few bootloaders utilize config file semantics, making + bootloader packaging a pain of trying to coerce semantics to fit in this rigid + box. This, also, prevents use of non-deterministic config files, such as those + containing signed data for secure boot systems. +* `bootloader-installer` and `bootloader-disk-image-installer`: `installer` is + meant to be used on mounted filesystems. `disk-image-installer` is meant to be + used on devices. `disk-image-installer` is used for disk image building or as + a fallback. Some bootloaders (even GRUB!) need access to both a filesystem and + disk, and the two separate code paths mean development can lead to poorly + tested bootloading code. The arguments to both procedures are, also, poorly + documented (and weird choices in general; root-index is purely used by GRUB). + +# Detailed Design + +## Bootloader Definition +First, we go over the general architecture of bootloader packaging. Each +bootloader will have two things associated to it: a `<bootloader>` record +denoting what functions it provides, and a configuration record unique to each +type of bootloader. The `<bootloader>` record defines functions taking in the +configuration record, as a way for the bootloader system to extract the +information it needs from each bootloader's config. + +Going into specifics, the `<bootloader>` record will be redefined as such: +* `bootloader-predicate`: A predicate denoting whether the configuration is of + the right type, used to verify whether users provided the correct record. +* `bootloader-installers`: A list of `<bootloader-installer>` records. + +`<bootloader-installer>` is a new record intended to split up individual +target installation methods. This is necessary as disk images do not have all +possible targets accessible at once (as the disk is generated strictly after +partitions). The record is defined as such: +* `<bootloader-installer-tag>`: An arbitrary symbol used by the bootloader to + identify this installer and its targets. A `<bootloader>` may not have two + `<bootloader-installers>` with the same tag. +* `<bootloader-installer-type>`: A symbol indicating the sort of values allowed + as targets. Allowed the following values: + - `'file`: Only strings allowed, interpreted as paths. + - `'block`: Strings (interpreted as block devices), `file-system-label`s, and + `uuid`s allowed. `uuid`s are interpreted as filesystem UUIDs, partition + UUIDs, or partition table UUIDs, attempted in that order. +* `<bootloader-installer-targets>`: A function from the bootloader's + configuration to a list of targets specified by the user. Typically this is + just a configuration record field accessor. +* `<bootloader-installer-installer>`: A function from the bootloader's + configuration, an alist of generation numbers to `<boot-parameters>`, the + current generation number, and the boot-time target map (see below), to a gexp + containing an installer procedure as specified below. + +Installers are gexps containing a procedure taking keyword arguments. The +procedure is called once for each target in the `<bootloader-installer>`, and +provided keyword arguments depending on the `<bootloader-installer-type>`. Each +keyword argument has a side, either boot-side or install-side. Install-side data +is only valid during installation of the bootloader, and should not be used +during bootup. This data is generated from system state at install-time. +Boot-side data is usable during bootup, and generated from a given system's +`<file-system>` records. However, if a `'block` type installer is provided a +path to a block device, boot-time data must be generated at install-time. For +this reason, usage of a path `'block` is not recommended. Keyword arguments are +as follows: +* `#:mount` (`'file`, install-time): Absolute path to the mount point of the + filesystem the file is stored on. +* `#:path` (`'file`, install-time): Absolute path to the specified file. +* `#:device` (`'block`, install-time): Device file for the block device. +* `#:offset` (`'file`, boot-time): Filesystem-relative path. Includes the btrfs + subvolume prefix when applicable, so `#:path` may not always be + `string-append`'ed `#:mount` and `#:offset`. +* `#:label` (all, boot-time): Filesystem label. +* `#:uuid` (all, boot-time): Filesystem uuid, unless `'block` and a partition + UUID or partition table UUID is provided. + +In the future, more installer types and keyword arguments may be provided +fully backwards-compatibly. + +The boot-time target map provieded to `bootloader-installers` is an alist of +tags to lists of boot-time data, one for each target. Boot-time data is +exactly the boot-time keyword arguments provided to installer gexp procedures, +but are provided here for certain installers to know about others (for example, +the GRUB early loader installed to a disk knowing about the full GRUB +installation's partition and location). + +## User Configuration +Users will specify the `<bootloader>` they wish to use directly in the +`operating-system-bootloader` field, which will be changed to allow `#f` (for no +bootloaders, as in virtualized images with direct linux booting). +`<operating-system>` will also receive a new +`operating-system-bootloader-configuration` field. This field will accept a +configuration used by the `operating-system-bootloader`, verified by +`bootloader-predicate`. + +All further bootloader configuration, including targets and additional boot +options, will be provided in the `operating-system-bootloader-configuration`. + +The current `<menu-entry>` and `<bootloader-configuration>` records will be +re-adapted into grub-specific configuration. + +## Rollbacks +As the entire bootloader install process exists in gexps, each generation will +simply save its combined bootloader install script as a GC root to be called on +rollback, the exact way it's called on install. This eliminates the need for +bootloader module search and bootloader configuration guessing (as is currently +used), as well as making bootloader rollbacks more reliable. + +Due to this, the following `<boot-parameters>` fields may be removed: +`boot-parameters-root-device`, `boot-parameter-bootloader-name`, and +`boot-parameter-menu-entries`. The record shall be updated to version 2 to +match. + +## Disk Images +While disk images will work automatically with the above system through the +keyword argument discovery mechanisms, one instance of special-casing is +unfortunately required. Any `<bootloader-installer>` with the tag `'disk` +will, instead of using targets from `bootloader-installer-targets`, provide +a single target, generated from the resulting disk image file. + +All other handling will be done invisibly to both end-users and bootloader +packagers, due to the above defined semantics of target conversion into keyword +arguments. + +## Cascading Changes +These changes will necessitate some edits to specific bootloaders and +supporting code. The current GRUB bootloader installer calls `grub-install`, +which guesses a lot of information about the system it's currently run on. This +approach, of course, does not work for disk images, and so manual image creation +is used there. We propose unifying the two approaches, manually creating disk +images with the information given to us by the new targeting system. + +Furthermore, a new utility procedure will be created to facilitate EFI +bootloaders, handling copying to the ESP, setting EFI boot options, +configuring removability, and ensuring sufficient storage space in the ESP. + +## Documentation +A page will be added to the manual under the `Programming Interface` section +describing the new bootloader interfaces. This page will note the default +modules provided to installer gexps and the special-casing of the `'disk` tag. + +The `Bootloader Configuration` page will be updated to act as a unified +documentation of the peculiarities of each bootloader and how to use it. Manual +pages pertaining to bootloader installation will be updated to document the new +user configuration format, and a blog post will be made to ease the transition. + +## Bootloading Team +Lastly, a bootloading team will be created as a point of contact and +implementation group for the above changes. This team would develop the proposed +changes in a public fork of Guix in order to facilitate user testing across the +wide range of supported hardware. Merging with mainline will be done once patch +review and sufficiently diverse testing as to minimize user impact has been completed. + +## Examples +```scheme +(define-record-type* <simple-configuration> + simple-configuration make-simple-configuration simple-configuration? + (copy-to simple-configuration-copy-to)) +(define (simple-bootloader-installer conf params current targets) + #~(lambda* (#:key path #:allow-other-keys) + (copy-file #$(file-append simple-bootloader-pkg "/share/config") path))) +(define simple-bootloader + (bootloader + (predicate simple-configuration?) + (installers (bootloader-installer + (tag 'copy-to) + (type 'file) + (targets (compose list simple-configuration-copy-to)) + (installer simple-bootloader-installer))))) +``` +```scheme +(operating-system + (bootloader simple-bootloader) + (bootloader-configuration (simple-configuration (copy-to "/boot/config")))) +``` + +# Migration +Even though bootloader management may be considered part of the Guix API +surface, we do not attempt to provide a clean migration path. Thus, upon merge +immediate incompatibilities will occur for all channels packaging bootloaders. +This, thankfully, proves to be a very small number. + +For operating system configuration, however, the existing +`<bootloader-configuration>` and `<menu-entry>` structures shall be deprecated. +`<operating-system>`s will go through a pass converting such structures into the +new format, through a `bootloader-migration` field in `<bootloader>` allowed to +be `#f`. This field may contain a function from `<bootloader-configuration>` to +the bootloader's configuration. The fixup procedure will operate as follows, +taking +```scheme +(operating-system + (bootloader (bootloader-configuration + (bootloader test-bootloader)))) +``` +to +```scheme +(operating-system + (bootloader test-bootloader) + (bootloader-configuration ((bootloader-migrate test-bootloader) + (bootloader-configuration + (bootloader test-bootloader))))) +``` + +Target handling would require little to no special-casing in such migration +functions. + +After a year, this deprecation will expire, and the fixup code, old records, and +`bootloader-migration` field may be removed. This way, existing +`<operating-system>`s may be used as-is for the period necessitated by the +Deprecation Policy. + +## Study of Affected Channels +We have taken an informal study of Guix channels as of 2025-08-13 in order to +estimate the impact of breaking API changes. 98 Guix channels were located +from the following roots: +* [whereiseverything channel toys](https://toys.whereis.social/channels) +* [Github awesome-guix](https://github.com/franzos/awesome-guix) +* [crafted-guix](https://codeberg.org/SystemCrafters/crafted-guix), an + additional channel found through internet search. +* [gooy-guix](https://git.squircle.space/gooy-guix.git), mentioned to me by Ada + Avery and posted on guix-devel. + +Of those 98, we were able to locate exactly 4 which add bootloaders, none of +which managed to fully support Guix's existing bootloader handling: +* [rosenthal](https://codeberg.org/hako/Rosenthal), which just packages GRUB + with an overridden package that supports LUKS2. Does not support rollbacks. +* [gooy-guix](https://git.squircle.space/gooy-guix.git), packaging a + systemd-boot EFI bootloader. It is impossible for this bootloader to support + disk images in the current system. +* [waggle](https://git.lunabee.space/waggle/files.html), my channel, which + adds p-boot for the Pinephone and a UKI bootloader, whose roundabout + implementation necessitated by the current system prompted me to begin this + rewrite in the first place. Does not support rollbacks, and I didn't realize + until after I needed one in the first place. It is impossible for these to + support disk images in the current system. +* [sakura](https://g.freya.cat/freya/sakura). The bootloader added is entirely + copied from my channel and the channel's owner has switched to Nix anyway. + +We thus conclude change to be necessary, and the potential impact of breaking +changes minimal. + +# Cost of Reverting +While these changes will drastically affect internals, the vast majority of +users should see a smooth transition. Similar methods to the above mentioned +migration path may be employed if this changeset needs to be reverted, at the +cost of another breaking change to bootloader-packaging channels. + +However, another roadblock in reverting could take place in the removal of boot +parameter options. Thus, we propose postponing the boot parameter changes until +after reverting is precluded as a possibility. Only then will the version be +incremented and unnecessary fields dropped. + +# Drawbacks and Open Issues +As these are bootloader changes, patches will need to be tested carefully in +order to ensure no devices get bricked. And, even then, there could still be a +risk due to how sensitiive bootloader installation and handling can be. This is +the main obstacle for implementation. It may be useful, then, to have a more +concrete procedure set in place to ensure proper testing after patch +development. + +The deprecation process is not ideal, especially with the removal of the +`bootloader-migrate` field resulting in two breaking changes to +bootloader-packaging channels. + +The special-casing of the `'disk` tag is also not ideal. We could not think of +any better method to provide such information. -- 2.50.0
Information forwarded
to guix-patches@gnu.org
:
bug#79248
; Package guix-patches
.
(Fri, 15 Aug 2025 20:15:02 GMT) (full text, mbox, link).
Message #8 received at 79248@debbugs.gnu.org (full text, mbox, reply):
hey everyone! about a year ago I proposed a patch series rewriting bootloader handling in Guix. seeing the new GCD process, I figured it was perfect for gathering discussion and consent for the rewrite. so, I rewrote the rewrite, and I'm proposing it here! this is a draft; if anyone has suggestions at this stage, please let me know! I'll need at least one sponsor, as well, for this to move to the discussion period. lilah title: Bootloader Subsystem Rewrite id: 006 status: draft discussion: https://issues.guix.gnu.org/79248 authors: Lilah Tascheter sponsors: <Sponsor Name> date: <date when the discussion period starts> SPDX-License-Identifier: CC-BY-SA-4.0 OR GFDL-1.3-no-invariants-or-later --- # Summary Guix's bootloader handling was originally designed solely for GRUB but, with greater adoption and widened system compatibility, this has proved insufficient. Unfortunately, core aspects of bootloader handling have remained unchanged, resulting in a system hard to fit new bootloaders into and confusing for end-users to configure. We propose an in-depth rewrite in order to create a more flexible and easier to understand interface for both end users and bootloader packagers. Prior work has been done as patchsets #69343, #73202, and #72457 on Mumi. This GCD is a new proposal improving upon these patches. # Motivation We identify three main ways the current bootloader handling proves insufficient: 1. Structural assumptions of GRUB exist in both user-facing bootloader configuration options as well as the packager-facing bootloader interface. 2. Multiple special cases exist in bootloader packaging and installation, making it incredibly easy to package bootloaders that either install onto the host during disk-image building or fail during system rollback. 3. Bootloader packaging is ill-documented and relies on a confusing interface, which is especially bad for such a sensitive part of system configuration. Take, first, the user-facing side of things. 11/14 fields of the `<bootloader-configuration>` record are only used in GRUB, with multiple having no imaginable use for non-GRUB bootloaders in the first place. Theoretically, new bootloaders could add fields to the record if they need their own configuration, but any external channels would not be able to do even that. Disk image handling is not well-specified, especially when attempting to create a disk image with a custom bootloader. Examples provide `/dev/vda1`, so a user would assume that Guix looks for that magic string, but instead bootloader handling uses a special install procedure. Notably, an unused target must be specified anyway. The `<menu-entry>` record is, also, made solely with GRUB in mind, even though dual-booting is theoretically something that should be supported by bootloaders in general. Fields are documented with semantics based solely on how GRUB interprets them. More notably, the current state of affairs hampers bootloader packaging significantly. The `<bootloader>` record contains the following fields: * `bootloader-name`: containing a symbol supposed to uniquely identify a bootloader package, for use in rollbacks. Notably, u-boot bootloaders ignore this requirement, to potentially disasterous consequences. It doesn't help that the only time one would notice problems with this (for example, a channel's bootloader defined outside gnu/bootloader, a bootloader defined as a procedure, or reused `bootloader-name`s) is when you already need to roll back to a different bootloader. * `bootloader-package`: This is only useful for switching which GRUB package is used for GRUB bootloaders. * `bootloader-configuration-file`: This is the sole mechanism through which rollbacks function. Few bootloaders utilize config file semantics, making bootloader packaging a pain of trying to coerce semantics to fit in this rigid box. This, also, prevents use of non-deterministic config files, such as those containing signed data for secure boot systems. * `bootloader-installer` and `bootloader-disk-image-installer`: `installer` is meant to be used on mounted filesystems. `disk-image-installer` is meant to be used on devices. `disk-image-installer` is used for disk image building or as a fallback. Some bootloaders (even GRUB!) need access to both a filesystem and disk, and the two separate code paths mean development can lead to poorly tested bootloading code. The arguments to both procedures are, also, poorly documented (and weird choices in general; root-index is purely used by GRUB). # Detailed Design ## Bootloader Definition First, we go over the general architecture of bootloader packaging. Each bootloader will have two things associated to it: a `<bootloader>` record denoting what functions it provides, and a configuration record unique to each type of bootloader. The `<bootloader>` record defines functions taking in the configuration record, as a way for the bootloader system to extract the information it needs from each bootloader's config. Going into specifics, the `<bootloader>` record will be redefined as such: * `bootloader-predicate`: A predicate denoting whether the configuration is of the right type, used to verify whether users provided the correct record. * `bootloader-installers`: A list of `<bootloader-installer>` records. `<bootloader-installer>` is a new record intended to split up individual target installation methods. This is necessary as disk images do not have all possible targets accessible at once (as the disk is generated strictly after partitions). The record is defined as such: * `<bootloader-installer-tag>`: An arbitrary symbol used by the bootloader to identify this installer and its targets. A `<bootloader>` may not have two `<bootloader-installers>` with the same tag. * `<bootloader-installer-type>`: A symbol indicating the sort of values allowed as targets. Allowed the following values: - `'file`: Only strings allowed, interpreted as paths. - `'block`: Strings (interpreted as block devices), `file-system-label`s, and `uuid`s allowed. `uuid`s are interpreted as filesystem UUIDs, partition UUIDs, or partition table UUIDs, attempted in that order. * `<bootloader-installer-targets>`: A function from the bootloader's configuration to a list of targets specified by the user. Typically this is just a configuration record field accessor. * `<bootloader-installer-installer>`: A function from the bootloader's configuration, an alist of generation numbers to `<boot-parameters>`, the current generation number, and the boot-time target map (see below), to a gexp containing an installer procedure as specified below. Installers are gexps containing a procedure taking keyword arguments. The procedure is called once for each target in the `<bootloader-installer>`, and provided keyword arguments depending on the `<bootloader-installer-type>`. Each keyword argument has a side, either boot-side or install-side. Install-side data is only valid during installation of the bootloader, and should not be used during bootup. This data is generated from system state at install-time. Boot-side data is usable during bootup, and generated from a given system's `<file-system>` records. However, if a `'block` type installer is provided a path to a block device, boot-time data must be generated at install-time. For this reason, usage of a path `'block` is not recommended. Keyword arguments are as follows: * `#:mount` (`'file`, install-time): Absolute path to the mount point of the filesystem the file is stored on. * `#:path` (`'file`, install-time): Absolute path to the specified file. * `#:device` (`'block`, install-time): Device file for the block device. * `#:offset` (`'file`, boot-time): Filesystem-relative path. Includes the btrfs subvolume prefix when applicable, so `#:path` may not always be `string-append`'ed `#:mount` and `#:offset`. * `#:label` (all, boot-time): Filesystem label. * `#:uuid` (all, boot-time): Filesystem uuid, unless `'block` and a partition UUID or partition table UUID is provided. In the future, more installer types and keyword arguments may be provided fully backwards-compatibly. The boot-time target map provieded to `bootloader-installers` is an alist of tags to lists of boot-time data, one for each target. Boot-time data is exactly the boot-time keyword arguments provided to installer gexp procedures, but are provided here for certain installers to know about others (for example, the GRUB early loader installed to a disk knowing about the full GRUB installation's partition and location). ## User Configuration Users will specify the `<bootloader>` they wish to use directly in the `operating-system-bootloader` field, which will be changed to allow `#f` (for no bootloaders, as in virtualized images with direct linux booting). `<operating-system>` will also receive a new `operating-system-bootloader-configuration` field. This field will accept a configuration used by the `operating-system-bootloader`, verified by `bootloader-predicate`. All further bootloader configuration, including targets and additional boot options, will be provided in the `operating-system-bootloader-configuration`. The current `<menu-entry>` and `<bootloader-configuration>` records will be re-adapted into grub-specific configuration. ## Rollbacks As the entire bootloader install process exists in gexps, each generation will simply save its combined bootloader install script as a GC root to be called on rollback, the exact way it's called on install. This eliminates the need for bootloader module search and bootloader configuration guessing (as is currently used), as well as making bootloader rollbacks more reliable. Due to this, the following `<boot-parameters>` fields may be removed: `boot-parameters-root-device`, `boot-parameter-bootloader-name`, and `boot-parameter-menu-entries`. The record shall be updated to version 2 to match. ## Disk Images While disk images will work automatically with the above system through the keyword argument discovery mechanisms, one instance of special-casing is unfortunately required. Any `<bootloader-installer>` with the tag `'disk` will, instead of using targets from `bootloader-installer-targets`, provide a single target, generated from the resulting disk image file. All other handling will be done invisibly to both end-users and bootloader packagers, due to the above defined semantics of target conversion into keyword arguments. ## Cascading Changes These changes will necessitate some edits to specific bootloaders and supporting code. The current GRUB bootloader installer calls `grub-install`, which guesses a lot of information about the system it's currently run on. This approach, of course, does not work for disk images, and so manual image creation is used there. We propose unifying the two approaches, manually creating disk images with the information given to us by the new targeting system. Furthermore, a new utility procedure will be created to facilitate EFI bootloaders, handling copying to the ESP, setting EFI boot options, configuring removability, and ensuring sufficient storage space in the ESP. ## Documentation A page will be added to the manual under the `Programming Interface` section describing the new bootloader interfaces. This page will note the default modules provided to installer gexps and the special-casing of the `'disk` tag. The `Bootloader Configuration` page will be updated to act as a unified documentation of the peculiarities of each bootloader and how to use it. Manual pages pertaining to bootloader installation will be updated to document the new user configuration format, and a blog post will be made to ease the transition. ## Bootloading Team Lastly, a bootloading team will be created as a point of contact and implementation group for the above changes. This team would develop the proposed changes in a public fork of Guix in order to facilitate user testing across the wide range of supported hardware. Merging with mainline will be done once patch review and sufficiently diverse testing as to minimize user impact has been completed. ## Examples ```scheme (define-record-type* <simple-configuration> simple-configuration make-simple-configuration simple-configuration? (copy-to simple-configuration-copy-to)) (define (simple-bootloader-installer conf params current targets) #~(lambda* (#:key path #:allow-other-keys) (copy-file #$(file-append simple-bootloader-pkg "/share/config") path))) (define simple-bootloader (bootloader (predicate simple-configuration?) (installers (bootloader-installer (tag 'copy-to) (type 'file) (targets (compose list simple-configuration-copy-to)) (installer simple-bootloader-installer))))) ``` ```scheme (operating-system (bootloader simple-bootloader) (bootloader-configuration (simple-configuration (copy-to "/boot/config")))) ``` # Migration Even though bootloader management may be considered part of the Guix API surface, we do not attempt to provide a clean migration path. Thus, upon merge immediate incompatibilities will occur for all channels packaging bootloaders. This, thankfully, proves to be a very small number. For operating system configuration, however, the existing `<bootloader-configuration>` and `<menu-entry>` structures shall be deprecated. `<operating-system>`s will go through a pass converting such structures into the new format, through a `bootloader-migration` field in `<bootloader>` allowed to be `#f`. This field may contain a function from `<bootloader-configuration>` to the bootloader's configuration. The fixup procedure will operate as follows, taking ```scheme (operating-system (bootloader (bootloader-configuration (bootloader test-bootloader)))) ``` to ```scheme (operating-system (bootloader test-bootloader) (bootloader-configuration ((bootloader-migrate test-bootloader) (bootloader-configuration (bootloader test-bootloader))))) ``` Target handling would require little to no special-casing in such migration functions. After a year, this deprecation will expire, and the fixup code, old records, and `bootloader-migration` field may be removed. This way, existing `<operating-system>`s may be used as-is for the period necessitated by the Deprecation Policy. ## Study of Affected Channels We have taken an informal study of Guix channels as of 2025-08-13 in order to estimate the impact of breaking API changes. 98 Guix channels were located from the following roots: * [whereiseverything channel toys](https://toys.whereis.social/channels) * [Github awesome-guix](https://github.com/franzos/awesome-guix) * [crafted-guix](https://codeberg.org/SystemCrafters/crafted-guix), an additional channel found through internet search. * [gooy-guix](https://git.squircle.space/gooy-guix.git), mentioned to me by Ada Avery and posted on guix-devel. Of those 98, we were able to locate exactly 4 which add bootloaders, none of which managed to fully support Guix's existing bootloader handling: * [rosenthal](https://codeberg.org/hako/Rosenthal), which just packages GRUB with an overridden package that supports LUKS2. Does not support rollbacks. * [gooy-guix](https://git.squircle.space/gooy-guix.git), packaging a systemd-boot EFI bootloader. It is impossible for this bootloader to support disk images in the current system. * [waggle](https://git.lunabee.space/waggle/files.html), my channel, which adds p-boot for the Pinephone and a UKI bootloader, whose roundabout implementation necessitated by the current system prompted me to begin this rewrite in the first place. Does not support rollbacks, and I didn't realize until after I needed one in the first place. It is impossible for these to support disk images in the current system. * [sakura](https://g.freya.cat/freya/sakura). The bootloader added is entirely copied from my channel and the channel's owner has switched to Nix anyway. We thus conclude change to be necessary, and the potential impact of breaking changes minimal. # Cost of Reverting While these changes will drastically affect internals, the vast majority of users should see a smooth transition. Similar methods to the above mentioned migration path may be employed if this changeset needs to be reverted, at the cost of another breaking change to bootloader-packaging channels. However, another roadblock in reverting could take place in the removal of boot parameter options. Thus, we propose postponing the boot parameter changes until after reverting is precluded as a possibility. Only then will the version be incremented and unnecessary fields dropped. # Drawbacks and Open Issues As these are bootloader changes, patches will need to be tested carefully in order to ensure no devices get bricked. And, even then, there could still be a risk due to how sensitiive bootloader installation and handling can be. This is the main obstacle for implementation. It may be useful, then, to have a more concrete procedure set in place to ensure proper testing after patch development. The deprecation process is not ideal, especially with the removal of the `bootloader-migrate` field resulting in two breaking changes to bootloader-packaging channels. The special-casing of the `'disk` tag is also not ideal. We could not think of any better method to provide such information.
Information forwarded
to guix-patches@gnu.org
:
bug#79248
; Package guix-patches
.
(Sun, 17 Aug 2025 20:04:01 GMT) (full text, mbox, link).
Message #11 received at 79248@debbugs.gnu.org (full text, mbox, reply):
[Message part 1 (text/plain, inline)]
Hi, On Fri, 15 Aug 2025 15:13:49 -0500 Lilah Tascheter <lilah@lunabee.space> wrote: > this is a draft; if anyone has suggestions at this stage, [...] I've some. I'm a bit confused in the state of support of non-x86 support in Guix, and as I understand just reading the code is insufficient as we need to take project decisions to clarify what we want to have at a given time in the first place. I'm also confused with this proposal for the same reasons. The quick summary of my problem is that there seems to be very important undocumented behavior, so this makes it hard to understand how to fix or modify because we don't even know what we're supposed to have right now, so because of that even discussing changes is hard. All that is not hard to fix with a very fast discussion ("this was the intended behavior" from people who contribute to u-boot-bootloader), which then enables to send patches to clarify that in the code and/or documentation, which later enables to discuss and fix things (because we know what we have). Background: ----------- Here's a first level of abstraction of what we have: User configuration (bootloader-configuration / image type) and documentation (guix manual) ^ | | v Guix code (grub-efi32-bootloader) and bootloaders(upstream GRUB, u-boot, arm-trusted-firmware, etc). ^ | | v Hardware and software interfaces to the bootloaders (BIOS, UEFI 32bit on x86_64, etc). In this model and in the current code/documentation, there are some missing things, like there is no "coreboot + GRUB" (users can still make it work by writing a custom installer function) or "Bios Boot partition with BIOS and GPT" image types but as I understand, this could just be fixed by adding new image types and configuration, so the current model doesn't break with these. Though I'm also unsure how to properly add a GRUB entry for something lime memtest86+ as I cannot put ungexp in the grub-menu definitions. Since I don't know how to fix, I cannot tell if it breaks the current model or not (the fix could just be to add something like (thunked) somewhere, I didn't look into it enough to know if that can work). Bootflow issue: --------------- How u-boot boots is documented in doc/develop/distro.rst and to make things simple, some time ago u-boot tried to load a boot.scr and if not found then loaded a syslinux configuration that Guix generated. There were also additional ways of booting but they require to do things to support them, so it was and it is still obvious that Guix doesn't support them yet. However u-boot then introduced the bootflow mechanism and things happened in Guix and boot was then broken for some ARM computers. 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), so we can send patches to document it in the manual or code and send patch to make things working again and/or decide what we want to change and document that. The "Background" above, Guix manual or code look insufficient to understand that. The problem is also that I'm unsure if the way of booting of each board is that unified. For instance some computers (like the TBS2910) also have compatibility with the vendor u-boot configuration. For instance that computer has that: > CONFIG_BOOTCOMMAND="mmc rescan; if run bootcmd_up1; then run > bootcmd_up2; else run bootcmd_mmc || run distro_bootcmd; fi" So it will run this code at boot instead of using the bootflow, so if we supported it in Guix, users won't see any issues while other board could see issues with bootflow. Another example is that I want to add the rock-4c-plus to Guix. And right now it hangs at boot because bootflow doesn't know where to boot from. Should I make sure it uses bootflow before using syslinux.cfg? Or is just using syslinux.cfg like before okay? Are other supported boards working? Given all that mess, the solution here is to at least document what we have, and document things if we intend to change them, so when things change unexpectly, we could simply revert to the old behavior or document the new one, making it easy to fix. Bootrom questions: ------------------ 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. Your proposal seems to address that at first sight but it doesn't mention it as such and I wonder how it would look like practically speaking. Having some way to report the constraints (like comments or records for SOCs bootroms / BIOS / EFI might) might work too as we need documentation somewhere in order to know the tradeoffs we are supposed to be doing. An example is that (reordered to fix 70 characters limit): > (define install-beaglebone-black-u-boot > ;;http://wiki.beyondlogic.org/index.php?title=BeagleBoneBlack_Upgrading_uBoot > ;; This first stage bootloader called MLO (U-Boot SPL) is expected at > ;; 0x20000 by BBB ROM code. The second stage bootloader will be > ;; loaded by the MLO and is expected at 0x60000. Write both first > ;; stage ("MLO") and second stage ("u-boot.img") images, read in > ;; BOOTLOADER directory, to the specified DEVICE. > (write-u-boot-image '(("MLO" 256 256) ("u-boot.img" 768 1024)) 512)) While this looks well documented, there is a lot of unknowns there. The OMAP3/OMAP4/AM335x, etc SOCs support multiple offsets and MLO can also be on a FAT partition, with special requirements for the partitioning table. All that is typically documented in u-boot and/or in the hardware documentation of the SOC (the name of the pdf often changes depending on the vendor, here it could be "Technical reference manual", and sometimes it's called "Datasheet" while other time "Datasheet" is just some basic facts about the chip, and sometimes this is reverse engineered, so it could even be in a wiki or in u-boot). And an additional issue is that as far as I know, the OMAP3430 has have less offsets available than an AM335x. So these could also be supported by the same code if we chose to. 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). So where can we document that? Is a big comment in the same file the right place to do that? Or can we somehow move that into some structure and abstractions where we clearly define why we choose this method over others? 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? Is it documented somewhere? Is this because on x86 there is update-grub that can find the bootloader but that, while code exists for some ARM SOCs (like some Allwinner chips), there is no tool to just do that (no update-u-boot)? New features that can potentially require API changes: ------------------------------------------------------ If we change the user facing API, how could we handle chained bootloaders? For instance [u-boot+EFI emulation] -> GRUB is possible. TowBoot does it. There are also other interfaces possible between u-boot and GRUB. And this is relevant to users here as "I want GRUB on ARM with u-boot" is not some implementation details, how "GRUB on ARM with u-boot" is done could be though. The user could also already have UEFI (for arm64) on the computer, so the user should be able to also select "I have UEFI, I just want GRUB arm64 like it is done on x86". Should we have lists of bootloaders where the first in the list loads the next one? Should we have some u-boot-then-grub bootloader? Do we even need to think about this now? This also brings the question of where the bootloader is installed and possible variations of booting due to that. For instance a bootloader on an SPI flash is different from one on a microSD and they might even require to be built differently due to different load addresses. However we could simply choose to not handle that yet given the challenge that we already have for the rest. In addition projects like GNU Boot could in the long run take care of things that go in the SPI flash, assuming that some people are interested in doing that. Denis.
[Message part 2 (application/pgp-signature, inline)]
Information forwarded
to guix-patches@gnu.org
:
bug#79248
; Package guix-patches
.
(Sun, 17 Aug 2025 21:30:02 GMT) (full text, mbox, link).
Message #14 received at 79248@debbugs.gnu.org (full text, mbox, reply):
Hello Lilah, Lilah Tascheter <lilah@lunabee.space> writes: > about a year ago I proposed a patch series rewriting bootloader handling > in Guix. seeing the new GCD process, I figured it was perfect for > gathering discussion and consent for the rewrite. so, I rewrote > the rewrite, and I'm proposing it here! I saw your patches before and also the recent message by Ada Avery: I very much agree with the need for change here! The current design indeed inherits from a GRUB-only vision (after all, the U in “GRUB” was meant to stand for “unified” :-)) and has become problematic, as this GCD clearly explains. Regarding the design, I wonder if the mapped-device/mapped-device-type pattern (or package/build-system pattern) is relevant. The other important matter is ensuring backwards-compatibility for user configs. At any rate, all the power for this GCD! Thanks, Ludo’.
Information forwarded
to guix-patches@gnu.org
:
bug#79248
; Package guix-patches
.
(Sun, 17 Aug 2025 23:22:02 GMT) (full text, mbox, link).
Message #17 received at 79248@debbugs.gnu.org (full text, mbox, reply):
[Message part 1 (text/plain, inline)]
Hi, Here are some more related comments on specific parts of the proposal. Though I've no idea yet if all that should go in a GCD or not (I need to think about it more, maybe other people have better ideas than me though). On Fri, 15 Aug 2025 15:13:49 -0500 Lilah Tascheter <lilah@lunabee.space> wrote: > ## User Configuration > [...] > ## Rollbacks > As the entire bootloader install process exists in gexps, each > generation will simply save its combined bootloader install script as > a GC root to be called on rollback, the exact way it's called on > install. This eliminates the need for bootloader module search and > bootloader configuration guessing (as is currently used), as well as > making bootloader rollbacks more reliable. If a user on x86_64 with GRUB has MBR, then switches to GPT (with gdisk) and runs 'guix system reconfigure' after potentially adjusting the system configuration, would a rollback still work (sudo guix system roll-back)? Or will GRUB only load the MBR specific module (because that was recorded before) and not the GPT one, making it impossible to access the rest of its modules? Right now I've no idea what works and what doesn't. Renaming an LVM partition that holds the rootfs probably breaks roll backs (after GRUB), but for the rest I'm not sure. An idea here could be to warn users that for instance changing the partition type can now break rollbacks, at least for GRUB. And while at it (if there is some interest) we could document what kind of things are (not) supported when rolling back and/or what guarantees the bootloaders managed by Guix are supposed (not) to give (when selecting older system generations at boot, we still use the new bootloader for instance, so only the kernel + its parameters and the initramfs change). > All other handling will be done invisibly to both end-users and > bootloader packagers, due to the above defined semantics of target > conversion into keyword arguments. Will the chosen code to install the bootloader depend on things like GPT vs MBR? Here I mostly have u-boot in mind. > ## Cascading Changes [...] > Furthermore, a new utility procedure will be created to facilitate EFI > bootloaders, handling copying to the ESP, setting EFI boot options, > configuring removability, and ensuring sufficient storage space in > the ESP. Will that generates the /boot partition by itself and take full control, including with 'guix system reconfigure'? > * [waggle](https://git.lunabee.space/waggle/files.html), my channel, > which adds p-boot for the Pinephone and a UKI bootloader, whose > roundabout implementation necessitated by the current system prompted > me to begin this rewrite in the first place. Does not support > rollbacks, and I didn't realize until after I needed one in the first > place. It is impossible for these to support disk images in the > current system. I'll try to look at it. > # Drawbacks and Open Issues > As these are bootloader changes, patches will need to be tested > carefully in order to ensure no devices get bricked. I assume that you mean that the rootfs won't boot anymore. I'm unsure if there is that much care taken right now for arm64. For instance is u-boot on arm64 already broken? It's been a while since I wanted to investigate but I didn't find enough time to fully dive into it. I've one device officially supported by Guix but it's also my mail server, so I'm a bit afraid of rebooting it right now without more guarantees. So I tired with that instead: > +(define-public u-boot-rock-4c-plus-rk3399 > + (let ((base (make-u-boot-rockchip-package > + "rock-4c-plus" 'rk3399 > + '("CONFIG_USB=y" > + ;; Disable SPL FIT signatures, due to GPLv2 and > + ;; OpenSSL license incompatibilities. > + "# CONFIG_SPL_FIT_SIGNATURE is not set")))) > + (package > + (inherit base)))) and: > +(define rock-4c-plus-installation-os > + (embedded-installation-os u-boot-rock-4c-plus-rk3399-bootloader > + "/dev/mmcblk0" ; SD card storage > + "ttyS2")) ;; Default UART as per [...] And here the boot is broken with the commit ac9c4da0581342bec3fa47a38130ebaabc3735f7 (Thu Aug 14). So I'm unsure if this is a real concern for arm64, and I'd like other people to give feedback here. But if it is really broken since many months, then as long as it makes things more reliable at the end, people would probably be happier. As for really breaking computers, it can happen with UEFI on x86 (and maybe some nonfree UEFI on ARM as well) but it needs some conditions: - The computer needs to boot with UEFI (we support UEFI, so let's assume it's true) - The bootloader or kernel needs to crash (it sometimes happen, so let's assume it will happen) - The bootloader and kernel needs to be configure to store crash logs inside the UEFI - The UEFI needs to be buggy (it sometimes happens, so let's assume it's true) So the solution here would be to just verify that we don't write crash logs inside the UEFI and we should be good. We would need to check the kernel and bootloaders though. In the case of u-boot on ARM, if u-boot (+ arm-trusted-firmware) is/are the only bootloaders parts, then there is probably not a lot of probability to break devices. Denis.
[Message part 2 (application/pgp-signature, inline)]
Information forwarded
to guix-patches@gnu.org
:
bug#79248
; Package guix-patches
.
(Wed, 03 Sep 2025 22:00:03 GMT) (full text, mbox, link).
Message #20 received at 79248@debbugs.gnu.org (full text, mbox, reply):
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
Send a report that this bug log contains spam.
Debbugs is free software and licensed under the terms of the GNU Public License version 2. The current version can be obtained from https://bugs.debian.org/debbugs-source/.
Copyright © 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson, 2005-2017 Don Armstrong, and many other contributors.