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);
|
drivesCmdLine = drives: concatStringsSep " " (imap1 driveCmdline drives);
|
||||||
|
|
||||||
|
|
||||||
# Creates a device name from a 1-based a numerical index, e.g.
|
# Creates a device name from a 1-based a numerical index, e.g.
|
||||||
# * `driveDeviceName 1` -> `/dev/vda`
|
# * `driveDeviceName 1` -> `/dev/vda`
|
||||||
# * `driveDeviceName 2` -> `/dev/vdb`
|
# * `driveDeviceName 2` -> `/dev/vdb`
|
||||||
@ -99,6 +100,13 @@ let
|
|||||||
addDeviceNames =
|
addDeviceNames =
|
||||||
imap1 (idx: drive: drive // { device = driveDeviceName idx; });
|
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.
|
# Shell script to start the VM.
|
||||||
startVM =
|
startVM =
|
||||||
''
|
''
|
||||||
@ -124,10 +132,14 @@ let
|
|||||||
# A writable boot disk can be booted from automatically.
|
# 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
|
${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 ''
|
${if cfg.useEFIBoot then ''
|
||||||
# VM needs a writable flash BIOS.
|
# VM needs writable EFI vars
|
||||||
cp ${bootDisk}/bios.bin $TMPDIR || exit 1
|
if ! test -e "$NIX_EFI_VARS"; then
|
||||||
chmod 0644 $TMPDIR/bios.bin || exit 1
|
cp ${bootDisk}/efi-vars.fd "$NIX_EFI_VARS" || exit 1
|
||||||
|
chmod 0644 "$NIX_EFI_VARS" || exit 1
|
||||||
|
fi
|
||||||
'' else ''
|
'' else ''
|
||||||
''}
|
''}
|
||||||
'' else ''
|
'' else ''
|
||||||
@ -172,21 +184,22 @@ let
|
|||||||
''
|
''
|
||||||
mkdir $out
|
mkdir $out
|
||||||
diskImage=$out/disk.img
|
diskImage=$out/disk.img
|
||||||
bootFlash=$out/bios.bin
|
${qemu}/bin/qemu-img create -f qcow2 $diskImage "60M"
|
||||||
${qemu}/bin/qemu-img create -f qcow2 $diskImage "40M"
|
|
||||||
${if cfg.useEFIBoot then ''
|
${if cfg.useEFIBoot then ''
|
||||||
cp ${pkgs.OVMF-CSM.fd}/FV/OVMF.fd $bootFlash
|
efiVars=$out/efi-vars.fd
|
||||||
chmod 0644 $bootFlash
|
cp ${efiVarsDefault} $efiVars
|
||||||
|
chmod 0644 $efiVars
|
||||||
'' else ''
|
'' else ''
|
||||||
''}
|
''}
|
||||||
'';
|
'';
|
||||||
buildInputs = [ pkgs.utillinux ];
|
buildInputs = [ pkgs.utillinux ];
|
||||||
QEMU_OPTS = if cfg.useEFIBoot
|
QEMU_OPTS = "-nographic -serial stdio -monitor none"
|
||||||
then "-pflash $out/bios.bin -nographic -serial pty"
|
+ lib.optionalString cfg.useEFIBoot (
|
||||||
else "-nographic -serial pty";
|
" -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 \
|
${pkgs.gptfdisk}/bin/sgdisk \
|
||||||
--set-alignment=1 --new=1:34:2047 --change-name=1:BIOSBootPartition --typecode=1:ef02 \
|
--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 \
|
--set-alignment=512 --largest-new=2 --change-name=2:EFISystem --typecode=2:ef00 \
|
||||||
@ -210,6 +223,10 @@ let
|
|||||||
mkdir /boot
|
mkdir /boot
|
||||||
mount /dev/vda2 /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.
|
# This is needed for GRUB 0.97, which doesn't know about virtio devices.
|
||||||
mkdir /boot/grub
|
mkdir /boot/grub
|
||||||
echo '(hd0) /dev/vda' > /boot/grub/device.map
|
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 =
|
virtualisation.bios =
|
||||||
mkOption {
|
mkOption {
|
||||||
default = null;
|
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"''
|
''-append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.toplevel}/init regInfo=${regInfo}/registration ${consoles} $QEMU_KERNEL_PARAMS"''
|
||||||
])
|
])
|
||||||
(mkIf cfg.useEFIBoot [
|
(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) [
|
(mkIf (cfg.bios != null) [
|
||||||
"-bios ${cfg.bios}/bios.bin"
|
"-bios ${cfg.bios}/bios.bin"
|
||||||
|
@ -323,7 +323,7 @@ in
|
|||||||
systemd = handleTest ./systemd.nix {};
|
systemd = handleTest ./systemd.nix {};
|
||||||
systemd-analyze = handleTest ./systemd-analyze.nix {};
|
systemd-analyze = handleTest ./systemd-analyze.nix {};
|
||||||
systemd-binfmt = handleTestOn ["x86_64-linux"] ./systemd-binfmt.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-confinement = handleTest ./systemd-confinement.nix {};
|
||||||
systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
|
systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
|
||||||
systemd-networkd-vrf = handleTest ./systemd-networkd-vrf.nix {};
|
systemd-networkd-vrf = handleTest ./systemd-networkd-vrf.nix {};
|
||||||
|
@ -11,6 +11,8 @@ let
|
|||||||
virtualisation.useBootLoader = true;
|
virtualisation.useBootLoader = true;
|
||||||
virtualisation.useEFIBoot = true;
|
virtualisation.useEFIBoot = true;
|
||||||
boot.loader.systemd-boot.enable = true;
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
environment.systemPackages = [ pkgs.efibootmgr ];
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@ -31,6 +33,36 @@ in
|
|||||||
machine.succeed(
|
machine.succeed(
|
||||||
"test -e /sys/firmware/efi/efivars/LoaderEntrySelected-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"
|
"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
|
mkdir -vp $fd/AAVMF
|
||||||
mv -v $out/FV/QEMU_{EFI,VARS}.fd $fd/FV
|
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
|
# Use Debian dir layout: https://salsa.debian.org/qemu-team/edk2/blob/debian/debian/rules
|
||||||
# FIXME: why is it different from 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/AAVMF/QEMU_EFI-pflash.raw 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/AAVMF/QEMU_EFI-pflash.raw if=$fd/FV/QEMU_EFI.fd conv=notrunc
|
dd of=$fd/FV/AAVMF_VARS.fd if=/dev/zero bs=1M count=64
|
||||||
dd of=$fd/AAVMF/vars-template-pflash.raw 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 ''
|
'' else ''
|
||||||
mkdir -vp $fd/FV
|
mkdir -vp $fd/FV
|
||||||
mv -v $out/FV/OVMF{,_CODE,_VARS}.fd $fd/FV
|
mv -v $out/FV/OVMF{,_CODE,_VARS}.fd $fd/FV
|
||||||
|
Loading…
x
Reference in New Issue
Block a user