diff --git a/nixos/doc/manual/release-notes/rl-2611.section.md b/nixos/doc/manual/release-notes/rl-2611.section.md index 2b7750602776..846e6ef796f0 100644 --- a/nixos/doc/manual/release-notes/rl-2611.section.md +++ b/nixos/doc/manual/release-notes/rl-2611.section.md @@ -140,6 +140,8 @@ - `security.run0.persistentAuth` options have been added to support persistent Authentication of session. Timeout configurable via `security.polkit.settings.Polkitd.ExpirationSeconds`. +- [`virtualisation.qemu.firmware.enable`](#opt-virtualisation.qemu.firmware.enable) has been added to install QEMU firmware descriptors to {file}`/etc/qemu/firmware`, making the corresponding firmware images discoverable by tools such as `systemd-vmspawn`. By default this exposes the firmware bundled with QEMU. Further firmware can be added via [`virtualisation.qemu.firmware.packages`](#opt-virtualisation.qemu.firmware.packages), for example the new `OVMF-amdsev` and `OVMF-inteltdx` packages, which provide UEFI firmware for AMD SEV-SNP and Intel TDX confidential VMs. + - `boot.loader.systemd-boot` gained support for [Automatic Boot Assessment](https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT/) via the new [`boot.loader.systemd-boot.bootCounting`](#opt-boot.loader.systemd-boot.bootCounting.enable) options, allowing automatic detection of and recovery from bad NixOS generations. As part of this change, boot loader entries on the ESP/XBOOTLDR partition are now named `nixos-.conf` instead of `nixos-generation-.conf`; existing entries are migrated automatically on the next `nixos-rebuild boot`/`switch`. - `services.nginx` gained a [`lua`](#opt-services.nginx.lua.enable) option to enable Lua scripting via OpenResty's lua-nginx-module on a stock nginx, configuring `lua_package_path`/`lua_package_cpath` from the packages listed in [`services.nginx.lua.extraPackages`](#opt-services.nginx.lua.extraPackages). Use this to add Lua to a regular nginx; for the full OpenResty platform (libraries that rely on its bundled lualib, such as `lua-resty-openidc`), set `services.nginx.package` to `pkgs.openresty` instead — the option configures the Lua search path for it too. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index de6172266d5e..871579e1d094 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -2052,6 +2052,7 @@ ./virtualisation/openvswitch.nix ./virtualisation/parallels-guest.nix ./virtualisation/podman/default.nix + ./virtualisation/qemu-firmware.nix ./virtualisation/qemu-guest-agent.nix ./virtualisation/rosetta.nix ./virtualisation/spice-usb-redirection.nix diff --git a/nixos/modules/tasks/filesystems/envfs.nix b/nixos/modules/tasks/filesystems/envfs.nix index 4b1846f5c1a8..6c16008e72c0 100644 --- a/nixos/modules/tasks/filesystems/envfs.nix +++ b/nixos/modules/tasks/filesystems/envfs.nix @@ -69,7 +69,7 @@ in config = lib.mkIf (cfg.enable) { environment.systemPackages = [ cfg.package ]; # we also want these mounts in virtual machines. - fileSystems = if config.virtualisation ? qemu then lib.mkVMOverride mounts else mounts; + fileSystems = if config.virtualisation.qemu ? package then lib.mkVMOverride mounts else mounts; # We no longer need those when using envfs system.activationScripts.usrbinenv = lib.mkForce ""; diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix index de2cb3d2afc8..3a24c9272a6b 100644 --- a/nixos/modules/testing/test-instrumentation.nix +++ b/nixos/modules/testing/test-instrumentation.nix @@ -196,7 +196,7 @@ in # that do not specify any nodes, or an empty attr set as nodes) will not # have the QEMU module loaded and thuse these options can't and should not # be set. - virtualisation = lib.optionalAttrs (options ? virtualisation.qemu) { + virtualisation = lib.optionalAttrs (options ? virtualisation.qemu.package) { qemu = { # NOTE: optionalAttrs # test-instrumentation.nix appears to be used without qemu-vm.nix, so diff --git a/nixos/modules/virtualisation/qemu-firmware.nix b/nixos/modules/virtualisation/qemu-firmware.nix new file mode 100644 index 000000000000..9be3708171ac --- /dev/null +++ b/nixos/modules/virtualisation/qemu-firmware.nix @@ -0,0 +1,50 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.virtualisation.qemu.firmware; +in + +{ + options.virtualisation.qemu.firmware = { + enable = lib.mkEnableOption "QEMU firmware descriptors in {file}`/etc/qemu/firmware`"; + + packages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ pkgs.qemu ]; + defaultText = lib.literalExpression "[ pkgs.qemu ]"; + example = lib.literalExpression "[ pkgs.qemu pkgs.OVMF-amdsev.fd ]"; + description = '' + Packages providing QEMU firmware descriptors under + {file}`share/qemu/firmware`, following the QEMU firmware interop + convention (see {file}`docs/interop/firmware.json` in the QEMU + source tree). The descriptors are merged and linked to + {file}`/etc/qemu/firmware`, where tools like + {command}`systemd-vmspawn` discover the firmware available for + running virtual machines. + + The default exposes the descriptors of the firmware images + bundled with QEMU. Note that setting this option replaces the + default, so include `pkgs.qemu` when adding further firmware. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + environment.etc."qemu/firmware".source = + let + merged = pkgs.buildEnv { + name = "qemu-firmware-descriptors"; + paths = cfg.packages; + pathsToLink = [ "/share/qemu/firmware" ]; + }; + in + "${merged}/share/qemu/firmware"; + }; + + meta.maintainers = [ lib.maintainers.katexochen ]; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index a74e80ca39e8..78f9940fb6fd 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1449,6 +1449,7 @@ in pykms = runTest ./pykms.nix; qbittorrent = runTest ./qbittorrent.nix; qboot = runTestOn [ "x86_64-linux" "i686-linux" ] ./qboot.nix; + qemu-firmware = runTestOn [ "x86_64-linux" ] ./qemu-firmware.nix; qemu-vm-external-disk-image = runTest ./qemu-vm-external-disk-image.nix; qemu-vm-restrictnetwork = handleTest ./qemu-vm-restrictnetwork.nix { }; qemu-vm-store = runTest ./qemu-vm-store.nix; diff --git a/nixos/tests/qemu-firmware.nix b/nixos/tests/qemu-firmware.nix new file mode 100644 index 000000000000..c6ed6b9f0029 --- /dev/null +++ b/nixos/tests/qemu-firmware.nix @@ -0,0 +1,41 @@ +{ lib, ... }: + +{ + name = "qemu-firmware"; + meta.maintainers = [ lib.maintainers.katexochen ]; + + nodes.machine = + { pkgs, ... }: + { + virtualisation.qemu.firmware = { + enable = true; + packages = [ + pkgs.qemu + pkgs.OVMF-amdsev.fd + pkgs.OVMF-inteltdx.fd + ]; + }; + environment.systemPackages = [ pkgs.jq ]; + }; + + testScript = '' + machine.wait_for_unit("multi-user.target") + + with subtest("descriptors are merged into /etc/qemu/firmware"): + machine.succeed("test -e /etc/qemu/firmware/60-edk2-x86_64.json") + machine.succeed("test -e /etc/qemu/firmware/61-edk2-ovmf-x64-amdsev.json") + machine.succeed("test -e /etc/qemu/firmware/61-edk2-ovmf-x64-inteltdx.json") + + with subtest("descriptors reference existing firmware images"): + machine.succeed( + "jq -er '.mapping | .filename // .executable.filename' " + + "/etc/qemu/firmware/*.json | xargs stat --" + ) + + with subtest("systemd-vmspawn discovers the descriptors"): + listed = machine.succeed("systemd-vmspawn --firmware=list") + assert "61-edk2-ovmf-x64-amdsev.json" in listed + assert "61-edk2-ovmf-x64-inteltdx.json" in listed + assert "60-edk2-x86_64.json" in listed + ''; +}