1 { stdenv, nixosTests, lib, edk2, util-linux, nasm, acpica-tools, llvmPackages
2 , fetchurl, python3, pexpect, xorriso, qemu, dosfstools, mtools
4 , fdSize4MB ? secureBoot
6 , systemManagementModeRequired ? secureBoot && stdenv.hostPlatform.isx86
7 # Whether to create an nvram variables template
8 # which includes the MSFT secure boot keys
9 , msVarsTemplate ? false
10 # When creating the nvram variables template with
11 # the MSFT keys, we also must provide a certificate
12 # to use as the PK and first KEK for the keystore.
14 # By default, we use Debian's cert. This default
15 # should chnage to a NixOS cert once we have our
16 # own secure boot signing infrastructure.
18 # Ignored if msVarsTemplate is false.
19 , vendorPkKek ? "$NIX_BUILD_TOP/debian/PkKek-1-Debian.pem"
24 # Usually, this option is broken, do not use it except if you know what you are
28 i686 = "OvmfPkg/OvmfPkgIa32.dsc";
29 x86_64 = "OvmfPkg/OvmfPkgX64.dsc";
30 aarch64 = "ArmVirtPkg/ArmVirtQemu.dsc";
31 riscv64 = "OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc";
32 }.${stdenv.hostPlatform.parsed.cpu.name}
33 or (throw "Unsupported OVMF `projectDscPath` on ${stdenv.hostPlatform.parsed.cpu.name}")
38 riscv64 = "RISCV_VIRT";
39 }.${stdenv.hostPlatform.parsed.cpu.name}
40 or (throw "Unsupported OVMF `fwPrefix` on ${stdenv.hostPlatform.parsed.cpu.name}")
41 , metaPlatforms ? edk2.meta.platforms
51 aarch64.msVarsArgs = {
57 cpuName = stdenv.hostPlatform.parsed.cpu.name;
59 inherit (platformSpecific.${cpuName}) msVarsArgs;
61 version = lib.getVersion edk2;
63 OvmfPkKek1AppPrefix = "4e32566d-8e9e-4f52-81d3-5bb9715f9727";
65 debian-edk-src = fetchurl {
66 url = "http://deb.debian.org/debian/pool/main/e/edk2/edk2_2023.11-5.debian.tar.xz";
67 sha256 = "1yxlab4md30pxvjadr6b4xn6cyfw0c292q63pyfv4vylvhsb24g4";
70 buildPrefix = "Build/*/*";
74 assert platformSpecific ? ${cpuName};
75 assert msVarsTemplate -> fdSize4MB;
76 assert msVarsTemplate -> platformSpecific.${cpuName} ? msVarsArgs;
78 edk2.mkDerivation projectDscPath (finalAttrs: {
82 outputs = [ "out" "fd" ];
84 nativeBuildInputs = [ util-linux nasm acpica-tools ]
85 ++ lib.optionals stdenv.cc.isClang [ llvmPackages.bintools llvmPackages.llvm ]
86 ++ lib.optionals msVarsTemplate [ python3 pexpect xorriso qemu dosfstools mtools ];
89 hardeningDisable = [ "format" "stackprotector" "pic" "fortify" ];
92 # IPv6 has no reason to be disabled.
93 [ "-D NETWORK_IP6_ENABLE=TRUE" ]
94 ++ lib.optionals debug [ "-D DEBUG_ON_SERIAL_PORT=TRUE" ]
95 ++ lib.optionals sourceDebug [ "-D SOURCE_DEBUG_ENABLE=TRUE" ]
96 ++ lib.optionals secureBoot [ "-D SECURE_BOOT_ENABLE=TRUE" ]
97 ++ lib.optionals systemManagementModeRequired [ "-D SMM_REQUIRE=TRUE" ]
98 ++ lib.optionals fdSize2MB ["-D FD_SIZE_2MB"]
99 ++ lib.optionals fdSize4MB ["-D FD_SIZE_4MB"]
100 ++ lib.optionals httpSupport [ "-D NETWORK_HTTP_ENABLE=TRUE" "-D NETWORK_HTTP_BOOT_ENABLE=TRUE" ]
101 ++ lib.optionals tlsSupport [ "-D NETWORK_TLS_ENABLE=TRUE" ]
102 ++ lib.optionals tpmSupport [ "-D TPM_ENABLE" "-D TPM2_ENABLE" "-D TPM2_CONFIG_ENABLE"];
104 buildConfig = if debug then "DEBUG" else "RELEASE";
105 env.NIX_CFLAGS_COMPILE = lib.optionalString stdenv.cc.isClang "-Qunused-arguments";
107 env.PYTHON_COMMAND = "python3";
109 postUnpack = lib.optionalDrvAttr msVarsTemplate ''
110 unpackFile ${debian-edk-src}
113 postConfigure = lib.optionalDrvAttr msVarsTemplate ''
114 tr -d '\n' < ${vendorPkKek} | sed \
115 -e 's/.*-----BEGIN CERTIFICATE-----/${OvmfPkKek1AppPrefix}:/' \
116 -e 's/-----END CERTIFICATE-----//' > vendor-cert-string
117 export PYTHONPATH=$NIX_BUILD_TOP/debian/python:$PYTHONPATH
120 postBuild = lib.optionalString stdenv.hostPlatform.isAarch ''
123 cp QEMU_EFI.fd ${fwPrefix}_CODE.fd
124 cp QEMU_VARS.fd ${fwPrefix}_VARS.fd
126 # QEMU expects 64MiB CODE and VARS files on ARM/AARCH64 architectures
127 # Truncate the firmware files to the expected size
128 truncate -s 64M ${fwPrefix}_CODE.fd
129 truncate -s 64M ${fwPrefix}_VARS.fd
131 '' + lib.optionalString stdenv.hostPlatform.isRiscV ''
132 truncate -s 32M ${buildPrefix}/FV/${fwPrefix}_CODE.fd
133 truncate -s 32M ${buildPrefix}/FV/${fwPrefix}_VARS.fd
134 '' + lib.optionalString msVarsTemplate ''
137 python3 $NIX_BUILD_TOP/debian/edk2-vars-generator.py \
138 --flavor ${msVarsArgs.flavor} \
139 --enrolldefaultkeys ${msVarsArgs.archDir}/EnrollDefaultKeys.efi \
140 --shell ${msVarsArgs.archDir}/Shell.efi \
141 --code FV/${fwPrefix}_CODE.fd \
142 --vars-template FV/${fwPrefix}_VARS.fd \
143 --certificate `< $NIX_BUILD_TOP/$sourceRoot/vendor-cert-string` \
144 --out-file FV/${fwPrefix}_VARS.ms.fd
148 # TODO: Usage of -bios OVMF.fd is discouraged: https://lists.katacontainers.io/pipermail/kata-dev/2021-January/001650.html
149 # We should remove the isx86-specifc block here once we're ready to update nixpkgs to stop using that and update the
150 # release notes accordingly.
153 '' + lib.optionalString (builtins.elem fwPrefix [
154 "OVMF" "AAVMF" "RISCV_VIRT"
156 mv -v $out/FV/${fwPrefix}_{CODE,VARS}.fd $fd/FV
157 '' + lib.optionalString stdenv.hostPlatform.isx86 ''
158 mv -v $out/FV/${fwPrefix}.fd $fd/FV
159 '' + lib.optionalString msVarsTemplate ''
160 mv -v $out/FV/${fwPrefix}_VARS.ms.fd $fd/FV
161 ln -sv $fd/FV/${fwPrefix}_CODE{,.ms}.fd
162 '' + lib.optionalString stdenv.hostPlatform.isAarch ''
163 mv -v $out/FV/QEMU_{EFI,VARS}.fd $fd/FV
164 # Add symlinks for Fedora dir layout: https://src.fedoraproject.org/cgit/rpms/edk2.git/tree/edk2.spec
166 ln -s $fd/FV/AAVMF_CODE.fd $fd/AAVMF/QEMU_EFI-pflash.raw
167 ln -s $fd/FV/AAVMF_VARS.fd $fd/AAVMF/vars-template-pflash.raw
174 prefix = "${finalAttrs.finalPackage.fd}/FV/${fwPrefix}";
176 firmware = "${prefix}_CODE.fd";
177 variables = "${prefix}_VARS.fd";
178 # This will test the EFI firmware for the host platform as part of the NixOS Tests setup.
179 tests.basic-systemd-boot = nixosTests.systemd-boot.basic;
180 tests.secureBoot-systemd-boot = nixosTests.systemd-boot.secureBoot;
181 inherit secureBoot systemManagementModeRequired;
185 description = "Sample UEFI firmware for QEMU and KVM";
186 homepage = "https://github.com/tianocore/tianocore.github.io/wiki/OVMF";
187 license = lib.licenses.bsd2;
188 platforms = metaPlatforms;
189 maintainers = with lib.maintainers; [ adamcstephens raitobezarius ];
190 broken = stdenv.isDarwin;