1{ stdenv, nixosTests, lib, edk2, util-linux, nasm, acpica-tools, llvmPackages
2, csmSupport ? false, seabios ? null
3, fdSize2MB ? csmSupport
4, fdSize4MB ? false
5, secureBoot ? false
6, httpSupport ? false
7, tpmSupport ? false
8, tlsSupport ? false
9, debug ? false
10, sourceDebug ? debug
11}:
12
13assert csmSupport -> seabios != null;
14
15let
16
17 projectDscPath = if stdenv.isi686 then
18 "OvmfPkg/OvmfPkgIa32.dsc"
19 else if stdenv.isx86_64 then
20 "OvmfPkg/OvmfPkgX64.dsc"
21 else if stdenv.hostPlatform.isAarch then
22 "ArmVirtPkg/ArmVirtQemu.dsc"
23 else
24 throw "Unsupported architecture";
25
26 version = lib.getVersion edk2;
27
28 suffixes = {
29 i686 = "FV/OVMF";
30 x86_64 = "FV/OVMF";
31 aarch64 = "FV/AAVMF";
32 };
33
34in
35
36edk2.mkDerivation projectDscPath (finalAttrs: {
37 pname = "OVMF";
38 inherit version;
39
40 outputs = [ "out" "fd" ];
41
42 nativeBuildInputs = [ util-linux nasm acpica-tools ]
43 ++ lib.optionals stdenv.cc.isClang [ llvmPackages.bintools llvmPackages.llvm ];
44 strictDeps = true;
45
46 hardeningDisable = [ "format" "stackprotector" "pic" "fortify" ];
47
48 buildFlags =
49 # IPv6 has no reason to be disabled.
50 [ "-D NETWORK_IP6_ENABLE=TRUE" ]
51 ++ lib.optionals debug [ "-D DEBUG_ON_SERIAL_PORT=TRUE" ]
52 ++ lib.optionals sourceDebug [ "-D SOURCE_DEBUG_ENABLE=TRUE" ]
53 ++ lib.optionals secureBoot [ "-D SECURE_BOOT_ENABLE=TRUE" ]
54 ++ lib.optionals csmSupport [ "-D CSM_ENABLE" ]
55 ++ lib.optionals fdSize2MB ["-D FD_SIZE_2MB"]
56 ++ lib.optionals fdSize4MB ["-D FD_SIZE_4MB"]
57 ++ lib.optionals httpSupport [ "-D NETWORK_HTTP_ENABLE=TRUE" "-D NETWORK_HTTP_BOOT_ENABLE=TRUE" ]
58 ++ lib.optionals tlsSupport [ "-D NETWORK_TLS_ENABLE=TRUE" ]
59 ++ lib.optionals tpmSupport [ "-D TPM_ENABLE" "-D TPM2_ENABLE" "-D TPM2_CONFIG_ENABLE"];
60
61 buildConfig = if debug then "DEBUG" else "RELEASE";
62 env.NIX_CFLAGS_COMPILE = lib.optionalString stdenv.cc.isClang "-Qunused-arguments";
63
64 env.PYTHON_COMMAND = "python3";
65
66 postPatch = lib.optionalString csmSupport ''
67 cp ${seabios}/Csm16.bin OvmfPkg/Csm/Csm16/Csm16.bin
68 '';
69
70 postFixup = if stdenv.hostPlatform.isAarch then ''
71 mkdir -vp $fd/FV
72 mkdir -vp $fd/AAVMF
73 mv -v $out/FV/QEMU_{EFI,VARS}.fd $fd/FV
74
75 # Use Debian dir layout: https://salsa.debian.org/qemu-team/edk2/blob/debian/debian/rules
76 dd of=$fd/FV/AAVMF_CODE.fd if=/dev/zero bs=1M count=64
77 dd of=$fd/FV/AAVMF_CODE.fd if=$fd/FV/QEMU_EFI.fd conv=notrunc
78 dd of=$fd/FV/AAVMF_VARS.fd if=/dev/zero bs=1M count=64
79
80 # Also add symlinks for Fedora dir layout: https://src.fedoraproject.org/cgit/rpms/edk2.git/tree/edk2.spec
81 ln -s $fd/FV/AAVMF_CODE.fd $fd/AAVMF/QEMU_EFI-pflash.raw
82 ln -s $fd/FV/AAVMF_VARS.fd $fd/AAVMF/vars-template-pflash.raw
83 '' else ''
84 mkdir -vp $fd/FV
85 mv -v $out/FV/OVMF{,_CODE,_VARS}.fd $fd/FV
86 '';
87
88 dontPatchELF = true;
89
90 passthru =
91 let
92 cpuName = stdenv.hostPlatform.parsed.cpu.name;
93 suffix = suffixes."${cpuName}" or (throw "Host cpu name `${cpuName}` is not supported in this OVMF derivation!");
94 prefix = "${finalAttrs.finalPackage.fd}/${suffix}";
95 in {
96 firmware = "${prefix}_CODE.fd";
97 variables = "${prefix}_VARS.fd";
98 # This will test the EFI firmware for the host platform as part of the NixOS Tests setup.
99 tests.basic-systemd-boot = nixosTests.systemd-boot.basic;
100 };
101
102 meta = {
103 description = "Sample UEFI firmware for QEMU and KVM";
104 homepage = "https://github.com/tianocore/tianocore.github.io/wiki/OVMF";
105 license = lib.licenses.bsd2;
106 inherit (edk2.meta) platforms;
107 maintainers = with lib.maintainers; [ adamcstephens raitobezarius ];
108 };
109})