nixos/libvirtd: Make all OVMF images from QEMU package available

- Make OVMF firmware images distributed with QEMU available under
/run/libvirt/nix-ovmf directory

- Repackage OVMF firmware metadata JSON files from QEMU package,
  patching the image file locations to point to stable
  /run/libvirt/nix-ovmf rather than the nix store path of QEMU package.

  And make them available at /var/lib/qemu/firmware, the path libvirt
  uses to verify domain configuration.

- Remove now obsolete `nvram` entry from qemu.conf.
  It was removed by upstream in Nov 2019.
  Eliminates log spam from libvirtd.service.

Fixes #378894
This commit is contained in:
Berk D. Demir
2025-06-22 22:10:54 -07:00
parent be3c621150
commit e744158bf0
2 changed files with 70 additions and 71 deletions

View File

@@ -144,6 +144,22 @@
- `virtualisation.lxd` has been removed due to lack of Nixpkgs maintenance. Users can migrate to `virtualisation.incus`, a fork of LXD, as a replacement. See [Incus migration documentation](https://linuxcontainers.org/incus/docs/main/howto/server_migrate_lxd/) for migration information.
- `virtualisation.libvirtd` now uses OVMF images shipped with QEMU for UEFI machines. `virtualisation.libvirtd.qemu.ovmf` has been removed.
- OVMF images from underlying QEMU package are now made available under '/run/libvirt/nix-ovmf', fixing prior issues when using QEMU's automatic EFI firmware and feature handling, relied upon by GNOME Boxes, virsh, virt-manager, etc.
- Domains that rely on automatic firmware and feature handling, i.e. `<os firmware='efi'>` need to trigger an update to `<loader>` and `<nvram>` entries.
Using `virsh edit <domain>` and deleting aforementioned tags will cause libvirt to replace them with the new paths.
- Configurations that relied on `virtualisation.libvirtd.qemu.ovmf` and had domains that did not use automatic firmware and feature handling, require a manual change to their domain configuration, updating `<loader>` and `<nvram>` entries from old path to the new path.
| Old Path | New Path |
|----------------------------------------|--------------------------------------------------|
| /run/libvirt/nix-ovmf/OVMF_CODE.fd | /run/libvirt/nix-ovmf/edk2-x86_64-code.fd |
| /run/libvirt/nix-ovmf/OVMF_VARS.fd | /run/libvirt/nix-ovmf/edk2-i386-vars.fd |
| /run/libvirt/nix-ovmf/OVMF_CODE.ms.fd | /run/libvirt/nix-ovmf/edk2-x86_64-secure-code.fd |
| /run/libvirt/nix-ovmf/OVMF_VARS.ms.fd | /run/libvirt/nix-ovmf/edk2-i386-vars.fd |
| /run/libvirt/nix-ovmf/AAVMF_CODE.fd | /run/libvirt/nix-ovmf/edk2-aarch64-code.fd |
| /run/libvirt/nix-ovmf/AAVMF_VARS.fd | /run/libvirt/nix-ovmf/edk2-arm-vars.fd |
| /run/libvirt/nix-ovmf/AAVMF_CODE.ms.fd | /run/libvirt/nix-ovmf/edk2-aarch64-code.fd |
| /run/libvirt/nix-ovmf/AAVMF_VARS.ms.fd | /run/libvirt/nix-ovmf/edk2-arm-vars.fd |
- The non-LTS Forgejo package (`forgejo`) has been updated to 12.0.0. This release contains breaking changes, see the [release blog post](https://forgejo.org/2025-07-release-v12-0/)
for all the details and how to ensure smooth upgrades.

View File

@@ -17,14 +17,6 @@ let
${cfg.extraConfig}
'';
qemuConfigFile = pkgs.writeText "qemu.conf" ''
${optionalString cfg.qemu.ovmf.enable ''
nvram = [
"/run/libvirt/nix-ovmf/AAVMF_CODE.fd:/run/libvirt/nix-ovmf/AAVMF_VARS.fd",
"/run/libvirt/nix-ovmf/AAVMF_CODE.ms.fd:/run/libvirt/nix-ovmf/AAVMF_VARS.ms.fd",
"/run/libvirt/nix-ovmf/OVMF_CODE.fd:/run/libvirt/nix-ovmf/OVMF_VARS.fd",
"/run/libvirt/nix-ovmf/OVMF_CODE.ms.fd:/run/libvirt/nix-ovmf/OVMF_VARS.ms.fd"
]
''}
${optionalString (!cfg.qemu.runAsRoot) ''
user = "qemu-libvirtd"
group = "qemu-libvirtd"
@@ -38,36 +30,6 @@ let
dirName = "libvirt";
subDirs = list: [ dirName ] ++ map (e: "${dirName}/${e}") list;
ovmfModule = types.submodule {
options = {
enable = mkOption {
type = types.bool;
default = true;
description = ''
Allows libvirtd to take advantage of OVMF when creating new
QEMU VMs with UEFI boot.
'';
};
# mkRemovedOptionModule does not work in submodules, do it manually
package = mkOption {
type = types.nullOr types.package;
default = null;
internal = true;
};
packages = mkOption {
type = types.listOf types.package;
default = [ pkgs.OVMF.fd ];
defaultText = literalExpression "[ pkgs.OVMF.fd ]";
example = literalExpression "[ pkgs.OVMFFull.fd pkgs.pkgsCross.aarch64-multiplatform.OVMF.fd ]";
description = ''
List of OVMF packages to use. Each listed package must contain files names FV/OVMF_CODE.fd and FV/OVMF_VARS.fd or FV/AAVMF_CODE.fd and FV/AAVMF_VARS.fd
'';
};
};
};
swtpmModule = types.submodule {
options = {
enable = mkOption {
@@ -116,11 +78,28 @@ let
};
ovmf = mkOption {
type = ovmfModule;
type = types.submodule {
options = {
enable = mkOption {
type = types.nullOr types.bool;
default = null;
internal = true;
};
package = mkOption {
type = types.nullOr types.package;
default = null;
internal = true;
};
packages = mkOption {
type = types.nullOr (types.listOf types.package);
default = null;
internal = true;
};
};
};
default = { };
description = ''
QEMU's OVMF options.
'';
internal = true;
description = "This submodule is deprecated and has been removed";
};
swtpm = mkOption {
@@ -220,6 +199,21 @@ let
};
};
};
qemuOvmfMetadata = pkgs.stdenv.mkDerivation {
name = "qemu-ovmf-metadata";
version = cfg.qemu.package.version;
nativeBuildInputs = [ cfg.qemu.package ];
dontBuild = true;
dontUnpack = true;
installPhase = ''
mkdir -p $out
cp ${cfg.qemu.package}/share/qemu/firmware/*.json $out
substituteInPlace $out/*.json \
--replace-fail "${cfg.qemu.package}/share/qemu/" "/run/${dirName}/nix-ovmf/"
'';
};
in
{
@@ -241,17 +235,16 @@ in
[ "virtualisation" "libvirtd" "qemuVerbatimConfig" ]
[ "virtualisation" "libvirtd" "qemu" "verbatimConfig" ]
)
(mkRenamedOptionModule
[ "virtualisation" "libvirtd" "qemuOvmf" ]
[ "virtualisation" "libvirtd" "qemu" "ovmf" "enable" ]
)
(mkRemovedOptionModule [ "virtualisation" "libvirtd" "qemuOvmfPackage" ]
"If this option was set to `foo`, set the option `virtualisation.libvirtd.qemu.ovmf.packages' to `[foo.fd]` instead."
)
(mkRenamedOptionModule
[ "virtualisation" "libvirtd" "qemuSwtpm" ]
[ "virtualisation" "libvirtd" "qemu" "swtpm" "enable" ]
)
(mkRemovedOptionModule [ "virtualisation" "libvirtd" "qemuOvmf" ]
"The 'virtualisation.libvirtd.qemuOvmf' option has been removed. All OVMF images distributed with QEMU are now available by default."
)
(mkRemovedOptionModule [ "virtualisation" "libvirtd" "qemuOvmfPackage" ]
"The 'virtualisation.libvirtd.qemuOvmfPackage' option has been removed. All OVMF images distributed with QEMU are now available by default."
)
];
###### interface
@@ -408,17 +401,15 @@ in
config = mkIf cfg.enable {
assertions = [
{
assertion = config.virtualisation.libvirtd.qemu.ovmf.package == null;
message = ''
The option virtualisation.libvirtd.qemu.ovmf.package is superseded by virtualisation.libvirtd.qemu.ovmf.packages.
If this option was set to `foo`, set the option `virtualisation.libvirtd.qemu.ovmf.packages' to `[foo.fd]` instead.
'';
}
{
assertion = config.security.polkit.enable;
message = "The libvirtd module currently requires Polkit to be enabled ('security.polkit.enable = true').";
}
{
assertion = ((lib.filterAttrs (n: v: v != null) cfg.qemu.ovmf) == { });
message = "The 'virtualisation.libvirtd.qemu.ovmf' submodule has been removed. All OVMF images distributed with QEMU are now available by default.";
}
];
environment = {
@@ -488,20 +479,12 @@ in
ln -s --force ${cfg.qemu.package}/bin/qemu-pr-helper /run/${dirName}/nix-helpers/
${optionalString cfg.qemu.ovmf.enable (
let
ovmfpackage = pkgs.buildEnv {
name = "qemu-ovmf";
paths = cfg.qemu.ovmf.packages;
};
in
''
ln -s --force ${ovmfpackage}/FV/AAVMF_CODE{,.ms}.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/OVMF_CODE{,.ms}.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/AAVMF_VARS{,.ms}.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/OVMF_VARS{,.ms}.fd /run/${dirName}/nix-ovmf/
''
)}
# Symlink to OVMF firmware code and variable template images distributed with QEMU
cp -sfv $(
${pkgs.jq}/bin/jq -rs \
'[.[] | .mapping.executable.filename, .mapping."nvram-template".filename] | unique | .[]' \
${cfg.qemu.package}/share/qemu/firmware/* \
) /run/${dirName}/nix-ovmf
# Symlink hooks to /var/lib/libvirt
${concatStringsSep "\n" (
@@ -620,7 +603,7 @@ in
in
[
"L+ /var/lib/qemu/vhost-user - - - - ${vhostUserCollection}/share/qemu/vhost-user"
"L+ /var/lib/qemu/firmware - - - - ${cfg.qemu.package}/share/qemu/firmware"
"L+ /var/lib/qemu/firmware - - - - ${qemuOvmfMetadata}"
];
security.polkit = {