nixpkgs/pkgs/applications/virtualization/OVMF/default.nix
Raito Bezarius 99cf2d1e88 OVMF: remove invalid assert on SMM
Someone seems to believe that SMM implies x86, this is wrong.
aarch64 supports SMM too, see upstream QEMU code.

The proper way to do this is to signal support via QEMU itself, this is something
we cannot do because we have no way to communicate QEMU support itself (yet?).

Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
2024-03-01 23:40:36 +01:00

192 lines
6.6 KiB
Nix

{ stdenv, nixosTests, lib, edk2, util-linux, nasm, acpica-tools, llvmPackages
, fetchurl, python3, pexpect, xorriso, qemu, dosfstools, mtools
, fdSize2MB ? 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
, debug ? false
# Usually, this option is broken, do not use it except if you know what you are
# doing.
, sourceDebug ? false
}:
let
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;
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 msVarsTemplate -> fdSize4MB;
assert msVarsTemplate -> platformSpecific.${cpuName} ? msVarsArgs;
edk2.mkDerivation projectDscPath (finalAttrs: {
pname = "OVMF";
inherit version;
outputs = [ "out" "fd" ];
nativeBuildInputs = [ util-linux nasm acpica-tools ]
++ 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" ];
buildFlags =
# IPv6 has no reason to be disabled.
[ "-D NETWORK_IP6_ENABLE=TRUE" ]
++ 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 fdSize2MB ["-D FD_SIZE_2MB"]
++ lib.optionals fdSize4MB ["-D FD_SIZE_4MB"]
++ lib.optionals httpSupport [ "-D NETWORK_HTTP_ENABLE=TRUE" "-D NETWORK_HTTP_BOOT_ENABLE=TRUE" ]
++ lib.optionals tlsSupport [ "-D NETWORK_TLS_ENABLE=TRUE" ]
++ lib.optionals tpmSupport [ "-D TPM_ENABLE" "-D TPM2_ENABLE" "-D TPM2_CONFIG_ENABLE"];
buildConfig = if debug then "DEBUG" else "RELEASE";
env.NIX_CFLAGS_COMPILE = lib.optionalString stdenv.cc.isClang "-Qunused-arguments";
env.PYTHON_COMMAND = "python3";
postUnpack = lib.optionalDrvAttr msVarsTemplate ''
unpackFile ${debian-edk-src}
'';
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
'';
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
)
'';
# TODO: Usage of -bios OVMF.fd is discouraged: https://lists.katacontainers.io/pipermail/kata-dev/2021-January/001650.html
# We should remove the isx86-specifc block here once we're ready to update nixpkgs to stop using that and update the
# release notes accordingly.
postInstall = ''
mkdir -vp $fd/FV
mv -v $out/FV/${fwPrefix}_{CODE,VARS}.fd $fd/FV
'' + lib.optionalString stdenv.hostPlatform.isx86 ''
mv -v $out/FV/${fwPrefix}.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
'';
dontPatchELF = true;
passthru =
let
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 = {
description = "Sample UEFI firmware for QEMU and KVM";
homepage = "https://github.com/tianocore/tianocore.github.io/wiki/OVMF";
license = lib.licenses.bsd2;
inherit (edk2.meta) platforms;
maintainers = with lib.maintainers; [ adamcstephens raitobezarius ];
broken = stdenv.isDarwin;
};
})