Merge pull request #90280 from danielfullmer/qemu-vm-uefi-aarch64
EFI improvements for qemu-vm.nix
This commit is contained in:
commit
f12ad780bf
@ -81,6 +81,7 @@ let
|
||||
|
||||
drivesCmdLine = drives: concatStringsSep " " (imap1 driveCmdline drives);
|
||||
|
||||
|
||||
# Creates a device name from a 1-based a numerical index, e.g.
|
||||
# * `driveDeviceName 1` -> `/dev/vda`
|
||||
# * `driveDeviceName 2` -> `/dev/vdb`
|
||||
@ -99,6 +100,13 @@ let
|
||||
addDeviceNames =
|
||||
imap1 (idx: drive: drive // { device = driveDeviceName idx; });
|
||||
|
||||
efiPrefix =
|
||||
if (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) then "${pkgs.OVMF.fd}/FV/OVMF"
|
||||
else if pkgs.stdenv.isAarch64 then "${pkgs.OVMF.fd}/FV/AAVMF"
|
||||
else throw "No EFI firmware available for platform";
|
||||
efiFirmware = "${efiPrefix}_CODE.fd";
|
||||
efiVarsDefault = "${efiPrefix}_VARS.fd";
|
||||
|
||||
# Shell script to start the VM.
|
||||
startVM =
|
||||
''
|
||||
@ -124,10 +132,14 @@ let
|
||||
# A writable boot disk can be booted from automatically.
|
||||
${qemu}/bin/qemu-img create -f qcow2 -b ${bootDisk}/disk.img $TMPDIR/disk.img || exit 1
|
||||
|
||||
NIX_EFI_VARS=$(readlink -f ''${NIX_EFI_VARS:-${cfg.efiVars}})
|
||||
|
||||
${if cfg.useEFIBoot then ''
|
||||
# VM needs a writable flash BIOS.
|
||||
cp ${bootDisk}/bios.bin $TMPDIR || exit 1
|
||||
chmod 0644 $TMPDIR/bios.bin || exit 1
|
||||
# VM needs writable EFI vars
|
||||
if ! test -e "$NIX_EFI_VARS"; then
|
||||
cp ${bootDisk}/efi-vars.fd "$NIX_EFI_VARS" || exit 1
|
||||
chmod 0644 "$NIX_EFI_VARS" || exit 1
|
||||
fi
|
||||
'' else ''
|
||||
''}
|
||||
'' else ''
|
||||
@ -172,21 +184,22 @@ let
|
||||
''
|
||||
mkdir $out
|
||||
diskImage=$out/disk.img
|
||||
bootFlash=$out/bios.bin
|
||||
${qemu}/bin/qemu-img create -f qcow2 $diskImage "40M"
|
||||
${qemu}/bin/qemu-img create -f qcow2 $diskImage "60M"
|
||||
${if cfg.useEFIBoot then ''
|
||||
cp ${pkgs.OVMF-CSM.fd}/FV/OVMF.fd $bootFlash
|
||||
chmod 0644 $bootFlash
|
||||
efiVars=$out/efi-vars.fd
|
||||
cp ${efiVarsDefault} $efiVars
|
||||
chmod 0644 $efiVars
|
||||
'' else ''
|
||||
''}
|
||||
'';
|
||||
buildInputs = [ pkgs.utillinux ];
|
||||
QEMU_OPTS = if cfg.useEFIBoot
|
||||
then "-pflash $out/bios.bin -nographic -serial pty"
|
||||
else "-nographic -serial pty";
|
||||
QEMU_OPTS = "-nographic -serial stdio -monitor none"
|
||||
+ lib.optionalString cfg.useEFIBoot (
|
||||
" -drive if=pflash,format=raw,unit=0,readonly=on,file=${efiFirmware}"
|
||||
+ " -drive if=pflash,format=raw,unit=1,file=$efiVars");
|
||||
}
|
||||
''
|
||||
# Create a /boot EFI partition with 40M and arbitrary but fixed GUIDs for reproducibility
|
||||
# Create a /boot EFI partition with 60M and arbitrary but fixed GUIDs for reproducibility
|
||||
${pkgs.gptfdisk}/bin/sgdisk \
|
||||
--set-alignment=1 --new=1:34:2047 --change-name=1:BIOSBootPartition --typecode=1:ef02 \
|
||||
--set-alignment=512 --largest-new=2 --change-name=2:EFISystem --typecode=2:ef00 \
|
||||
@ -210,6 +223,10 @@ let
|
||||
mkdir /boot
|
||||
mount /dev/vda2 /boot
|
||||
|
||||
${optionalString config.boot.loader.efi.canTouchEfiVariables ''
|
||||
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
|
||||
''}
|
||||
|
||||
# This is needed for GRUB 0.97, which doesn't know about virtio devices.
|
||||
mkdir /boot/grub
|
||||
echo '(hd0) /dev/vda' > /boot/grub/device.map
|
||||
@ -467,6 +484,16 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
virtualisation.efiVars =
|
||||
mkOption {
|
||||
default = "./${vmName}-efi-vars.fd";
|
||||
description =
|
||||
''
|
||||
Path to nvram image containing UEFI variables. The will be created
|
||||
on startup if it does not exist.
|
||||
'';
|
||||
};
|
||||
|
||||
virtualisation.bios =
|
||||
mkOption {
|
||||
default = null;
|
||||
@ -556,7 +583,8 @@ in
|
||||
''-append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.toplevel}/init regInfo=${regInfo}/registration ${consoles} $QEMU_KERNEL_PARAMS"''
|
||||
])
|
||||
(mkIf cfg.useEFIBoot [
|
||||
"-pflash $TMPDIR/bios.bin"
|
||||
"-drive if=pflash,format=raw,unit=0,readonly,file=${efiFirmware}"
|
||||
"-drive if=pflash,format=raw,unit=1,file=$NIX_EFI_VARS"
|
||||
])
|
||||
(mkIf (cfg.bios != null) [
|
||||
"-bios ${cfg.bios}/bios.bin"
|
||||
|
@ -323,7 +323,7 @@ in
|
||||
systemd = handleTest ./systemd.nix {};
|
||||
systemd-analyze = handleTest ./systemd-analyze.nix {};
|
||||
systemd-binfmt = handleTestOn ["x86_64-linux"] ./systemd-binfmt.nix {};
|
||||
systemd-boot = handleTestOn ["x86_64-linux"] ./systemd-boot.nix {};
|
||||
systemd-boot = handleTest ./systemd-boot.nix {};
|
||||
systemd-confinement = handleTest ./systemd-confinement.nix {};
|
||||
systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
|
||||
systemd-networkd-vrf = handleTest ./systemd-networkd-vrf.nix {};
|
||||
|
@ -11,6 +11,8 @@ let
|
||||
virtualisation.useBootLoader = true;
|
||||
virtualisation.useEFIBoot = true;
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
environment.systemPackages = [ pkgs.efibootmgr ];
|
||||
};
|
||||
in
|
||||
{
|
||||
@ -31,6 +33,36 @@ in
|
||||
machine.succeed(
|
||||
"test -e /sys/firmware/efi/efivars/LoaderEntrySelected-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"
|
||||
)
|
||||
|
||||
# "bootctl install" should have created an EFI entry
|
||||
machine.succeed('efibootmgr | grep "Linux Boot Manager"')
|
||||
'';
|
||||
};
|
||||
|
||||
# Boot without having created an EFI entry--instead using default "/EFI/BOOT/BOOTX64.EFI"
|
||||
fallback = makeTest {
|
||||
name = "systemd-boot-fallback";
|
||||
meta.maintainers = with pkgs.stdenv.lib.maintainers; [ danielfullmer ];
|
||||
|
||||
machine = { pkgs, lib, ... }: {
|
||||
imports = [ common ];
|
||||
boot.loader.efi.canTouchEfiVariables = mkForce false;
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.start()
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
|
||||
machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf")
|
||||
|
||||
# Ensure we actually booted using systemd-boot
|
||||
# Magic number is the vendor UUID used by systemd-boot.
|
||||
machine.succeed(
|
||||
"test -e /sys/firmware/efi/efivars/LoaderEntrySelected-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"
|
||||
)
|
||||
|
||||
# "bootctl install" should _not_ have created an EFI entry
|
||||
machine.fail('efibootmgr | grep "Linux Boot Manager"')
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -41,11 +41,14 @@ edk2.mkDerivation projectDscPath {
|
||||
mkdir -vp $fd/AAVMF
|
||||
mv -v $out/FV/QEMU_{EFI,VARS}.fd $fd/FV
|
||||
|
||||
# Uses Fedora dir layout: https://src.fedoraproject.org/cgit/rpms/edk2.git/tree/edk2.spec
|
||||
# FIXME: why is it different from Debian dir layout? https://salsa.debian.org/qemu-team/edk2/blob/debian/debian/rules
|
||||
dd of=$fd/AAVMF/QEMU_EFI-pflash.raw if=/dev/zero bs=1M count=64
|
||||
dd of=$fd/AAVMF/QEMU_EFI-pflash.raw if=$fd/FV/QEMU_EFI.fd conv=notrunc
|
||||
dd of=$fd/AAVMF/vars-template-pflash.raw if=/dev/zero bs=1M count=64
|
||||
# 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
|
||||
|
||||
# Also add symlinks for Fedora dir layout: https://src.fedoraproject.org/cgit/rpms/edk2.git/tree/edk2.spec
|
||||
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 ''
|
||||
mkdir -vp $fd/FV
|
||||
mv -v $out/FV/OVMF{,_CODE,_VARS}.fd $fd/FV
|
||||
|
Loading…
Reference in New Issue
Block a user