diff options
Diffstat (limited to 'nixpkgs/pkgs/applications/virtualization/OVMF/default.nix')
-rw-r--r-- | nixpkgs/pkgs/applications/virtualization/OVMF/default.nix | 155 |
1 files changed, 113 insertions, 42 deletions
diff --git a/nixpkgs/pkgs/applications/virtualization/OVMF/default.nix b/nixpkgs/pkgs/applications/virtualization/OVMF/default.nix index 63c137c220c2..cff31a759a2b 100644 --- a/nixpkgs/pkgs/applications/virtualization/OVMF/default.nix +++ b/nixpkgs/pkgs/applications/virtualization/OVMF/default.nix @@ -1,8 +1,23 @@ { stdenv, nixosTests, lib, edk2, util-linux, nasm, acpica-tools, llvmPackages +, fetchurl, python3, pexpect, xorriso, qemu, dosfstools, mtools , csmSupport ? false, seabios , fdSize2MB ? csmSupport -, fdSize4MB ? false +, fdSize4MB ? secureBoot , secureBoot ? false +, systemManagementModeRequired ? secureBoot && stdenv.hostPlatform.isx86 +# Whether to create an nvram variables template +# which includes the MSFT secure boot keys +, msVarsTemplate ? false +# When creating the nvram variables template with +# the MSFT keys, we also must provide a certificate +# to use as the PK and first KEK for the keystore. +# +# By default, we use Debian's cert. This default +# should chnage to a NixOS cert once we have our +# own secure boot signing infrastructure. +# +# Ignored if msVarsTemplate is false. +, vendorPkKek ? "$NIX_BUILD_TOP/debian/PkKek-1-Debian.pem" , httpSupport ? false , tpmSupport ? false , tlsSupport ? false @@ -14,28 +29,56 @@ let - projectDscPath = if stdenv.isi686 then - "OvmfPkg/OvmfPkgIa32.dsc" - else if stdenv.isx86_64 then - "OvmfPkg/OvmfPkgX64.dsc" - else if stdenv.hostPlatform.isAarch then - "ArmVirtPkg/ArmVirtQemu.dsc" - else if stdenv.hostPlatform.isRiscV then - "OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc" - else - throw "Unsupported architecture"; + platformSpecific = { + i686 = { + projectDscPath = "OvmfPkg/OvmfPkgIa32.dsc"; + fwPrefix = "OVMF"; + }; + x86_64 = { + projectDscPath = "OvmfPkg/OvmfPkgX64.dsc"; + fwPrefix = "OVMF"; + msVarsArgs = { + flavor = "OVMF_4M"; + archDir = "X64"; + }; + }; + aarch64 = { + projectDscPath = "ArmVirtPkg/ArmVirtQemu.dsc"; + fwPrefix = "AAVMF"; + msVarsArgs = { + flavor = "AAVMF"; + archDir = "AARCH64"; + }; + }; + riscv64 = { + projectDscPath = "OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc"; + fwPrefix = "RISCV_VIRT"; + }; + }; + + cpuName = stdenv.hostPlatform.parsed.cpu.name; + + inherit (platformSpecific.${cpuName}) + projectDscPath fwPrefix msVarsArgs; version = lib.getVersion edk2; - suffixes = { - i686 = "FV/OVMF"; - x86_64 = "FV/OVMF"; - aarch64 = "FV/AAVMF"; - riscv64 = "FV/RISCV_VIRT"; + OvmfPkKek1AppPrefix = "4e32566d-8e9e-4f52-81d3-5bb9715f9727"; + + debian-edk-src = fetchurl { + url = "http://deb.debian.org/debian/pool/main/e/edk2/edk2_2023.11-5.debian.tar.xz"; + sha256 = "1yxlab4md30pxvjadr6b4xn6cyfw0c292q63pyfv4vylvhsb24g4"; }; + buildPrefix = "Build/*/*"; + in +assert platformSpecific ? ${cpuName}; +assert systemManagementModeRequired -> stdenv.hostPlatform.isx86; +assert msVarsTemplate -> fdSize4MB; +assert msVarsTemplate -> platformSpecific.${cpuName} ? msVarsArgs; + edk2.mkDerivation projectDscPath (finalAttrs: { pname = "OVMF"; inherit version; @@ -43,7 +86,8 @@ edk2.mkDerivation projectDscPath (finalAttrs: { outputs = [ "out" "fd" ]; nativeBuildInputs = [ util-linux nasm acpica-tools ] - ++ lib.optionals stdenv.cc.isClang [ llvmPackages.bintools llvmPackages.llvm ]; + ++ lib.optionals stdenv.cc.isClang [ llvmPackages.bintools llvmPackages.llvm ] + ++ lib.optionals msVarsTemplate [ python3 pexpect xorriso qemu dosfstools mtools ]; strictDeps = true; hardeningDisable = [ "format" "stackprotector" "pic" "fortify" ]; @@ -54,6 +98,7 @@ edk2.mkDerivation projectDscPath (finalAttrs: { ++ lib.optionals debug [ "-D DEBUG_ON_SERIAL_PORT=TRUE" ] ++ lib.optionals sourceDebug [ "-D SOURCE_DEBUG_ENABLE=TRUE" ] ++ lib.optionals secureBoot [ "-D SECURE_BOOT_ENABLE=TRUE" ] + ++ lib.optionals systemManagementModeRequired [ "-D SMM_REQUIRE=TRUE" ] ++ lib.optionals csmSupport [ "-D CSM_ENABLE" ] ++ lib.optionals fdSize2MB ["-D FD_SIZE_2MB"] ++ lib.optionals fdSize4MB ["-D FD_SIZE_4MB"] @@ -66,49 +111,75 @@ edk2.mkDerivation projectDscPath (finalAttrs: { env.PYTHON_COMMAND = "python3"; + postUnpack = lib.optionalDrvAttr msVarsTemplate '' + unpackFile ${debian-edk-src} + ''; + postPatch = lib.optionalString csmSupport '' cp ${seabios}/share/seabios/Csm16.bin OvmfPkg/Csm/Csm16/Csm16.bin ''; - postFixup = ( - if stdenv.hostPlatform.isAarch then '' - mkdir -vp $fd/FV - mkdir -vp $fd/AAVMF - mv -v $out/FV/QEMU_{EFI,VARS}.fd $fd/FV + postConfigure = lib.optionalDrvAttr msVarsTemplate '' + tr -d '\n' < ${vendorPkKek} | sed \ + -e 's/.*-----BEGIN CERTIFICATE-----/${OvmfPkKek1AppPrefix}:/' \ + -e 's/-----END CERTIFICATE-----//' > vendor-cert-string + export PYTHONPATH=$NIX_BUILD_TOP/debian/python:$PYTHONPATH + ''; - # Use Debian dir layout: https://salsa.debian.org/qemu-team/edk2/blob/debian/debian/rules - dd of=$fd/FV/AAVMF_CODE.fd if=/dev/zero bs=1M count=64 - dd of=$fd/FV/AAVMF_CODE.fd if=$fd/FV/QEMU_EFI.fd conv=notrunc - dd of=$fd/FV/AAVMF_VARS.fd if=/dev/zero bs=1M count=64 + postBuild = lib.optionalString stdenv.hostPlatform.isAarch '' + ( + cd ${buildPrefix}/FV + cp QEMU_EFI.fd ${fwPrefix}_CODE.fd + cp QEMU_VARS.fd ${fwPrefix}_VARS.fd + + # QEMU expects 64MiB CODE and VARS files on ARM/AARCH64 architectures + # Truncate the firmware files to the expected size + truncate -s 64M ${fwPrefix}_CODE.fd + truncate -s 64M ${fwPrefix}_VARS.fd + ) + '' + lib.optionalString stdenv.hostPlatform.isRiscV '' + truncate -s 32M ${buildPrefix}/FV/${fwPrefix}_CODE.fd + truncate -s 32M ${buildPrefix}/FV/${fwPrefix}_VARS.fd + '' + lib.optionalString msVarsTemplate '' + ( + cd ${buildPrefix} + python3 $NIX_BUILD_TOP/debian/edk2-vars-generator.py \ + --flavor ${msVarsArgs.flavor} \ + --enrolldefaultkeys ${msVarsArgs.archDir}/EnrollDefaultKeys.efi \ + --shell ${msVarsArgs.archDir}/Shell.efi \ + --code FV/${fwPrefix}_CODE.fd \ + --vars-template FV/${fwPrefix}_VARS.fd \ + --certificate `< $NIX_BUILD_TOP/$sourceRoot/vendor-cert-string` \ + --out-file FV/${fwPrefix}_VARS.ms.fd + ) + ''; - # Also add symlinks for Fedora dir layout: https://src.fedoraproject.org/cgit/rpms/edk2.git/tree/edk2.spec + postInstall = '' + mkdir -vp $fd/FV + mv -v $out/FV/${fwPrefix}_{CODE,VARS}.fd $fd/FV + '' + lib.optionalString msVarsTemplate '' + mv -v $out/FV/${fwPrefix}_VARS.ms.fd $fd/FV + ln -sv $fd/FV/${fwPrefix}_CODE{,.ms}.fd + '' + lib.optionalString stdenv.hostPlatform.isAarch '' + mv -v $out/FV/QEMU_{EFI,VARS}.fd $fd/FV + # Add symlinks for Fedora dir layout: https://src.fedoraproject.org/cgit/rpms/edk2.git/tree/edk2.spec + mkdir -vp $fd/AAVMF ln -s $fd/FV/AAVMF_CODE.fd $fd/AAVMF/QEMU_EFI-pflash.raw ln -s $fd/FV/AAVMF_VARS.fd $fd/AAVMF/vars-template-pflash.raw - '' - else if stdenv.hostPlatform.isRiscV then '' - mkdir -vp $fd/FV - - mv -v $out/FV/RISCV_VIRT_{CODE,VARS}.fd $fd/FV/ - truncate -s 32M $fd/FV/RISCV_VIRT_CODE.fd - truncate -s 32M $fd/FV/RISCV_VIRT_VARS.fd - '' - else '' - mkdir -vp $fd/FV - mv -v $out/FV/OVMF{,_CODE,_VARS}.fd $fd/FV - ''); + ''; dontPatchELF = true; passthru = let - cpuName = stdenv.hostPlatform.parsed.cpu.name; - suffix = suffixes."${cpuName}" or (throw "Host cpu name `${cpuName}` is not supported in this OVMF derivation!"); - prefix = "${finalAttrs.finalPackage.fd}/${suffix}"; + prefix = "${finalAttrs.finalPackage.fd}/FV/${fwPrefix}"; in { firmware = "${prefix}_CODE.fd"; variables = "${prefix}_VARS.fd"; # This will test the EFI firmware for the host platform as part of the NixOS Tests setup. tests.basic-systemd-boot = nixosTests.systemd-boot.basic; + tests.secureBoot-systemd-boot = nixosTests.systemd-boot.secureBoot; + inherit secureBoot systemManagementModeRequired; }; meta = { |