|
| 1 | +--- |
| 2 | +feature: non_legacy_boot |
| 3 | +start-date: 2023-06-16 |
| 4 | +author: Ryan Lahfa |
| 5 | +co-authors: (find a buddy later to help out with the RFC) |
| 6 | +shepherd-team: (names, to be nominated and accepted by RFC steering committee) |
| 7 | +shepherd-leader: (name to be appointed by RFC steering committee) |
| 8 | +related-issues: (will contain links to implementation PRs) |
| 9 | +--- |
| 10 | + |
| 11 | +# Summary |
| 12 | +[summary]: #summary |
| 13 | + |
| 14 | +NixOS will have first-class support for UEFI |
| 15 | +and uses it as a default boot environment, for supported architectures, |
| 16 | +even in situations where only BIOS Boot Specification's legacy boot is available, |
| 17 | +via a dual-stage payload consisting of a polyfill bootloader/firmware and a standard |
| 18 | +UEFI bootloader. |
| 19 | + |
| 20 | +To achieve this, it will downgrade the GRUB privileged position |
| 21 | +in the project and offer it as a "best effort" basis alternative bootloader. |
| 22 | + |
| 23 | +# Motivation |
| 24 | +[motivation]: #motivation |
| 25 | + |
| 26 | +Legacy boot is defined by the BIOS Boot specification, written in 1996: https://www.scs.stanford.edu/nyu/04fa/lab/specsbbs101.pdf. |
| 27 | +Nowadays, computers are defaulting to UEFI more and more for the extended features provided (e.g. SecureBoot, native network boot, etc.). |
| 28 | + |
| 29 | +Nevertheless, many legacy boots machines or machines that does not have support for UEFI are used with NixOS: Single Board Computers for example |
| 30 | +on other architectures. |
| 31 | + |
| 32 | +Let's put aside non-legacy boot payloads such as [Linuxboot](https://www.linuxboot.org/), [Ownerboot](https://sr.ht/~amjoseph/ownerboot/) and any similar payloads, |
| 33 | +those are not legacy and they definitely have their places in the project, though, at the time of writing, no such payload is offered in NixOS. |
| 34 | + |
| 35 | +In nixpkgs, legacy boot forces a dichotomy between `boot.loader.efi` and... at least two legacy bootloaders **in tree**: GRUB and a family of UBoot/extlinux-compatible/etc. |
| 36 | + |
| 37 | +In the case of GRUB, there are increasing problems with this bootloader: |
| 38 | + |
| 39 | +- Upstream do not do releases anymore: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/tools/misc/grub/default.nix#L62-L350 |
| 40 | +- Co-maintenance / release work with other ecosystems such as the kernel is simply not done: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/tools/misc/grub/default.nix#L345-L349 causing GRUB's drivers to explode in production for our users: https://github.com/NixOS/nixpkgs/pull/235222 |
| 41 | +- Our own maintenance of GRUB is subpar: https://github.com/NixOS/nixpkgs/pull/227741 https://github.com/NixOS/nixpkgs/pull/226821 https://github.com/NixOS/nixpkgs/pull/195805 https://github.com/NixOS/nixpkgs/pull/95901 https://github.com/NixOS/nixpkgs/pull/236027 |
| 42 | +- GRUB installation procedure uses `install-grub.pl`, one of the remaining Perl script: https://github.com/NixOS/nixpkgs/pull/95901#issuecomment-756702696 offered to rewrite it with sponsoring, but no one took the offer yet, it is also very complicated to integrate with it: https://github.com/nix-community/lanzaboote/pull/96 |
| 43 | +- GRUB installation procedure for UEFI-only is still confusing because our scripts does not handle well UEFI-only (you have to pass `nodev` and this is not very well documented). See https://github.com/NixOS/nixpkgs/issues/222491 |
| 44 | + |
| 45 | +The worse about this, is this is our **default** bootloader for our install images **because** of legacy boot. |
| 46 | + |
| 47 | +In the case of UBoot/extlinux-compatible/etc. : we should definitely keep it, polish it and improve it for a better support of embedded systems, e.g. merging the differences |
| 48 | +between Raspberry Pi's bootloader and extlinux-compatible's ones. |
| 49 | + |
| 50 | +Getting rid of legacy boot opens up the way to get rid of GRUB as a default and offering an UEFI environment opens up the way to: |
| 51 | + |
| 52 | +- having a default ISO booting systemd-boot which is a maintained (by systemd) bootloader with active releases, smaller code footprint, maintained also by Systemd team in Nixpkgs |
| 53 | +- Features like https://github.com/NixOS/nixpkgs/pull/84204 could also be enabled for legacy boot users |
| 54 | +- Users who wants to use GRUB drivers to mount non-standard ESP can make use of https://efi.akeo.ie/ which is compatible with any UEFI bootloader |
| 55 | +- Boot testing can split into 2 ways: legacy boot compatibility layer tests and UEFI boot tests |
| 56 | +- Successful adoption gives a positive signal to others distribution to consider it, provide development resources to improve it rather than being held by the existing things, etc. |
| 57 | + |
| 58 | +# Detailed design |
| 59 | +[design]: #detailed-design |
| 60 | + |
| 61 | +Currently, most x86 computers^[For a more complete reference, read: https://safeboot.dev/chain-of-trust/] boot in a similar way to this **on a very high level** : |
| 62 | + |
| 63 | +```mermaid |
| 64 | +flowchart |
| 65 | + subgraph Firmware |
| 66 | + A((Power On)) --->|boots Intel Management Engine| M |
| 67 | + M((Intel Management Engine)) ---->|starts x86 CPU| C((x86 CPU)) |
| 68 | + C -->|starts OEM payload: BIOS or UEFI| O((BIOS or UEFI)) |
| 69 | + end |
| 70 | + subgraph Distribution |
| 71 | + O -->|boot further bootloaders| BL((GRUB or systemd-boot)) |
| 72 | + BL -->|boot operating system| OS((NixOS)) |
| 73 | + end |
| 74 | +``` |
| 75 | + |
| 76 | +In other platforms, you can see extra payloads like <https://github.com/ARM-software/arm-trusted-firmware> or <https://github.com/riscv-software-src/opensbi> |
| 77 | +before the distribution part, sometimes, it can be part of the distribution if control can be exerted. |
| 78 | + |
| 79 | +Some machines does even have control on the OEM payload or a good subset of the firmware, for example, via <https://www.coreboot.org/> or |
| 80 | +<https://github.com/oreboot/oreboot>. |
| 81 | + |
| 82 | +The idea is to transform this flowchart into: |
| 83 | + |
| 84 | +```mermaid |
| 85 | +flowchart |
| 86 | + subgraph Firmware |
| 87 | + A((Power On)) --->|boots Intel Management Engine| M |
| 88 | + M((Intel Management Engine)) ---->|starts x86 CPU| C((x86 CPU)) |
| 89 | + C -->|starts OEM payload: BIOS| O((BIOS)) |
| 90 | + end |
| 91 | + subgraph Distribution |
| 92 | + O -->|boot UEFI environment| UB((U-Boot)) |
| 93 | + UB -->|boot further bootloaders| BL((any UEFI-enabled bootloader)) |
| 94 | + BL -->|boot operating system| OS((NixOS)) |
| 95 | + end |
| 96 | +``` |
| 97 | + |
| 98 | +and keep it the old way whenever the OEM payload is UEFI already. |
| 99 | + |
| 100 | +If we take a step back, we can notice this 2-stage payload boot story can be generalized in those situations: |
| 101 | + |
| 102 | +```mermaid |
| 103 | +flowchart |
| 104 | + subgraph Firmware |
| 105 | + A((Power On)) --->|boots some evil chip| M |
| 106 | + M((Evil Chip 2000)) ---->|starts some architecture CPU| C(($arch CPU)) |
| 107 | + end |
| 108 | + subgraph Distribution |
| 109 | + C -->|starts user-provided firmware| CBL((coreboot)) |
| 110 | + CBL -->|starts user-provided payload| O((TianoCore, LinuxBoot, OwnerBoot, etc.)) |
| 111 | + O -->|boot Linux operating system| OS((U-Boot)) |
| 112 | + end |
| 113 | +``` |
| 114 | + |
| 115 | +In this situation, (c)oreboot could be a replacement of U-Boot environment and any UEFI-enabled bootloader could be replaced by any payload. |
| 116 | + |
| 117 | +Therefore, the design has to be general enough to support both usecases. |
| 118 | + |
| 119 | +Removing legacy boot will use a deprecation schedule and proceed into multiple steps. This RFC is dependent on accepted minimal implementations, where 'minimal' has to |
| 120 | +be defined in this RFC. |
| 121 | + |
| 122 | +# Examples and Interactions |
| 123 | +[examples-and-interactions]: #examples-and-interactions |
| 124 | + |
| 125 | +Fedora is considering doing this: https://lists.fedoraproject.org/archives/list/[email protected]/thread/GOETDM5SWINBX5ZDV37SWMHIPRRUVVTT/. |
| 126 | + |
| 127 | +Asahi Linux is booting UEFI via UBoot without EFI variables and it has been great for them. |
| 128 | + |
| 129 | +People who want to boot off strange partitions at boot-time can exploit UEFI drivers capability to load any filesystem driver and |
| 130 | +open the EFI System Partition in ZFS if they really insist. |
| 131 | + |
| 132 | +# Drawbacks |
| 133 | +[drawbacks]: #drawbacks |
| 134 | + |
| 135 | +- 2-stage boot for legacy BIOS systems is more than 1-stage boot |
| 136 | +- Increased internal complexity in the boot story of NixOS |
| 137 | +- Increased load and reliance on UBoot |
| 138 | +- The runtime service `SetVariable` will probably stay highly unstable for a while (variable storage) |
| 139 | + |
| 140 | +# Alternatives |
| 141 | +[alternatives]: #alternatives |
| 142 | + |
| 143 | +- Keeping legacy BIOS, doing nothing |
| 144 | + Then, we will continue to have users relying on bootloaders with shady maintenance stories and a skewed perception of what a bootloader can do (e.g. boot on a ZFS partition?). |
| 145 | + |
| 146 | +- Keeping legacy BIOS, offering this new way as an option |
| 147 | + Then, we will continue to have users relying on bootloaders with shady maintenance stories and a skewed perception of what a bootloader can do (e.g. boot on a ZFS partition?). |
| 148 | + |
| 149 | +- Keeping legacy BIOS, offering this new way as an option, deprecating legacy BIOS on a time schedule |
| 150 | + It is a minor variant of the proposal. |
| 151 | + |
| 152 | +- Keeping legacy BIOS, switching only new users to this mechanism without any deprecation of legacy BIOS for the time being |
| 153 | + This turns the problem into maintenance in-tree of GRUB2, which is fine by me. |
| 154 | + |
| 155 | +- Removing legacy BIOS, switching all users to this mechanism |
| 156 | + This does not have any deprecation schedule. |
| 157 | + |
| 158 | +# Unresolved questions |
| 159 | +[unresolved]: #unresolved-questions |
| 160 | + |
| 161 | +- How to migrate existing installs without any GPT partition table? |
| 162 | +- How to migrate existing installs with a GPT partition table but without a supported EFI System Partition, e.g. LVM |
| 163 | + - NTFS, XFS, exFAT, Amiga FFS/SFS, BFS, UFS, ZFS are handled via https://efi.akeo.ie/ which is an EFI driver that can be loaded |
| 164 | + - Subquestion: how to load EFI drivers for unsupported EFI System Partition? |
| 165 | + - Answer: Build EDK2 or UBoot with https://github.com/pbatard/efifs them. |
| 166 | +- When to do it? |
| 167 | +- What to do about variable storage (Asahi Linux showed this is not that important for a start)? |
| 168 | +- What to do about (>)dual boot configurations if variable storage is not available? (writing the EFI fallback directory will break the dual boot configuration.) |
| 169 | +- Design architecture in nixpkgs? |
| 170 | + |
| 171 | +# Future work |
| 172 | +[future]: #future-work |
| 173 | + |
| 174 | +- Improved support for UEFI features on non-UEFI native systems |
0 commit comments