NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
18.37k stars 14.33k forks source link

UKI direct boot #341357

Open ilya-fedin opened 2 months ago

ilya-fedin commented 2 months ago

Issue description

Currently NixOS lets to load UKI only with systemd-boot, there's no alternative to the virt-firmware's kernel-install hook that users of e.g. Fedora can use to have boot entries directly in the UEFI boot menu.

Steps to reproduce

  1. Try to build a UKI

Technical details

surfaceflinger commented 2 months ago

boot entries directly in the UEFI boot menu

in case of boot.loader.efi.canTouchEfiVariables = false; current generation could be instead put as /EFI/BOOT/BOOTX64.efi and older ones could be accessible using boot from file functionality in firmware

misuzu commented 2 months ago

and older ones could be accessible using boot from file functionality in firmware

The kernel requires the init= argument pointing to the required system generation.

ilya-fedin commented 2 months ago

in case of boot.loader.efi.canTouchEfiVariables = false; current generation could be instead put as /EFI/BOOT/BOOTX64.efi and older ones could be accessible using boot from file functionality in firmware

How to choose other configurations? :thinking: The point is to have all the generations in UEFI boot menu and conveniently siwtch between them.

surfaceflinger commented 2 months ago

The kernel requires the init= argument pointing to the required system generation.

UKIs can contain cmdline too and are the only used cmdline when secureboot is on

Huge amounts of generations would waste lots of space tho but it would still be possible to do

misuzu commented 2 months ago

This should be possible to implement using the bootspec + efibootmgr + a script à la systemd-boot-builder.py

msanft commented 2 months ago

You could just use an activation script to add the boot entry via EFI variables if I get your question right here.

I don't think this is something that upstream-NixOS should support, as most users will just have a boot menu. But feel free to open a PR adding such a hook if you think that this is useful.

ilya-fedin commented 2 months ago

I don't think this is something that upstream-NixOS should support

That's quite sad. Fedora seem to move in the direction of having such setup by default and it would be very disappointing if this wouldn't be possible to get with upstream module.

Personally I really like the boot menu my UEFI has and systemd-boot feels like an unnecessary middleware.

msanft commented 2 months ago

Is there a specification for variables that will be considered by such firmware-built-in boot menus for their versions? I'm open to have such a thing per se, but it shouldn't be scoped to a single firmware vendor

ilya-fedin commented 2 months ago

Is there a specification for variables that will be considered by such firmware-built-in boot menus for their versions?

I'm not sure... Aren't those the ones efibootmgr shows/manipulates?

SigmaSquadron commented 2 months ago

@ilya-fedin A small question: are you proposing that the UKIs pack both the kernel and initrd used by each generation? We faced a similar conundrum in #324911 where a full UKI would cost almost 100MiB per specialisation per profile per generation on the ESP. The solution we achieved there was to just pack the EFI executable and the configuration file containing the path to the kernel/initrd and the cmdline in a tiny 2MiB UKI.

Packing the whole kernel would make it significantly easier to manage the generations, while only using small UKIs that point to separate kernel files would mean that the UKIs are dependent on files with possibly varying path names.

ilya-fedin commented 2 months ago

A small question: are you proposing that the UKIs pack both the kernel and initrd used by each generation?

What I propose should be orthogonal to how UKIs are created? All I propose is NixOS scripts adding/removing each boot entry to UEFI instead of boot loader.

msanft commented 2 months ago

I think we could add something that simply does a bootctl set-default on each activation, which would probably handle deltas in EFI variable naming between different implementations, if any.

ilya-fedin commented 2 months ago

I think we could add something that simply does a bootctl set-default on each activation

Not sure how that would fulfill the request given that it is about bypassing systemd-boot or any other boot loader

msanft commented 2 months ago

I think we could add something that simply does a bootctl set-default on each activation

Not sure how that would fulfill the request given that it is about bypassing systemd-boot or any other boot loader

I think this should only use EFI variables, which are not really coupled to systemd-boot?

ilya-fedin commented 2 months ago

It seem to operate on systemd-boot's own EFI variables? The only generic EFI commands seem to be:

Generic EFI Firmware/Boot Loader Commands:
  status               Show status of installed boot loader and EFI variables
  reboot-to-firmware [BOOL]
                       Query or set reboot-to-firmware EFI flag
msanft commented 2 months ago

Hmm. Looks like that when scrolling through their code. I'd have expected this to be generic. Another possibility would be to replace the /EFI/BOOT/BOOTX64.EFI in the ESP directly. That would - however - also make your system non-recoverable if anything goes wrong in the early boot stages (i.e. before the emergency shell or if the emergency shell is deactivated)

ilya-fedin commented 2 months ago

why couldn't just the same scripts (from virt-firmware package) or efibootmgr be used?

surfaceflinger commented 3 weeks ago

With systemd v257, we provide a middle ground now: UKIs may now contain multiple "profiles": multiple sets of PE sections can be combined in different ways and then labelled as different profiles. Typically this would be used to build a single UKI that contains 1 kernel and 1 initrd, but 4 different kernel command lines, which would then be combined in 4 profiles, always combining the kernel/initrd and a different command line.

is it possible to pick a profile automatically using eg. only efi vars or by passing an argument in efi shell? or are these completely "dumb" and meant to be parsed by a separate executable?

you can invoke a UKI and prefix its command line with a string like @4 to pick profile number 4. The rules are relatively strict and separate from the usual command line syntax, since we profile is parsed and remove from the cmdline before measurement. (the chosen profile is measured separetly).

https://mastodon.social/@pid_eins/113431706149996315