Merge pull request #64815 from abbradar/ipxe-efi

IPXE EFI netboot fix
This commit is contained in:
Nikolay Amiantov 2019-07-15 21:21:29 +03:00 committed by GitHub
commit b392c5ab4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 65 deletions

View File

@ -31,9 +31,12 @@ sub new {
if (!$startCommand) { if (!$startCommand) {
# !!! merge with qemu-vm.nix. # !!! merge with qemu-vm.nix.
my $netArgs = "";
$netArgs .= ",romfile=$args->{netRomFile}"
if defined $args->{netRomFile};
$startCommand = $startCommand =
"qemu-kvm -m 384 " . "qemu-kvm -m 384 " .
"-net nic,model=virtio \$QEMU_OPTS "; "-device virtio-net-pci,netdev=net0${netArgs} \$QEMU_OPTS ";
if (defined $args->{hda}) { if (defined $args->{hda}) {
if ($args->{hdaInterface} eq "scsi") { if ($args->{hdaInterface} eq "scsi") {

View File

@ -84,7 +84,7 @@ with lib;
system.build.netbootIpxeScript = pkgs.writeTextDir "netboot.ipxe" '' system.build.netbootIpxeScript = pkgs.writeTextDir "netboot.ipxe" ''
#!ipxe #!ipxe
kernel ${pkgs.stdenv.hostPlatform.platform.kernelTarget} init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} kernel ${pkgs.stdenv.hostPlatform.platform.kernelTarget} init=${config.system.build.toplevel}/init initrd=initrd ${toString config.boot.kernelParams}
initrd initrd initrd initrd
boot boot
''; '';

View File

@ -17,46 +17,33 @@ let
]; ];
}).config.system.build.isoImage; }).config.system.build.isoImage;
makeBootTest = name: machineConfig: perlAttrs = params: "{ ${concatStringsSep "," (mapAttrsToList (name: param: "${name} => '${toString param}'") params)} }";
makeTest {
inherit iso;
name = "boot-" + name;
nodes = { };
testScript =
''
my $machine = createMachine({ ${machineConfig}, qemuFlags => '-m 768' });
$machine->start;
$machine->waitForUnit("multi-user.target");
$machine->succeed("nix verify -r --no-trust /run/current-system");
# Test whether the channel got installed correctly. makeBootTest = name: extraConfig:
$machine->succeed("nix-instantiate --dry-run '<nixpkgs>' -A hello"); let
$machine->succeed("nix-env --dry-run -iA nixos.procps"); machineConfig = perlAttrs ({ qemuFlags = "-m 768"; } // extraConfig);
in
makeTest {
inherit iso;
name = "boot-" + name;
nodes = { };
testScript =
''
my $machine = createMachine(${machineConfig});
$machine->start;
$machine->waitForUnit("multi-user.target");
$machine->succeed("nix verify -r --no-trust /run/current-system");
$machine->shutdown; # Test whether the channel got installed correctly.
''; $machine->succeed("nix-instantiate --dry-run '<nixpkgs>' -A hello");
}; $machine->succeed("nix-env --dry-run -iA nixos.procps");
in {
biosCdrom = makeBootTest "bios-cdrom" '' $machine->shutdown;
cdrom => glob("${iso}/iso/*.iso") '';
''; };
biosUsb = makeBootTest "bios-usb" '' makeNetbootTest = name: extraConfig:
usb => glob("${iso}/iso/*.iso") let
'';
uefiCdrom = makeBootTest "uefi-cdrom" ''
cdrom => glob("${iso}/iso/*.iso"),
bios => '${pkgs.OVMF.fd}/FV/OVMF.fd'
'';
uefiUsb = makeBootTest "uefi-usb" ''
usb => glob("${iso}/iso/*.iso"),
bios => '${pkgs.OVMF.fd}/FV/OVMF.fd'
'';
netboot = let
config = (import ../lib/eval-config.nix { config = (import ../lib/eval-config.nix {
inherit system; inherit system;
modules = modules =
@ -65,35 +52,54 @@ in {
{ key = "serial"; } { key = "serial"; }
]; ];
}).config; }).config;
ipxeScriptDir = pkgs.writeTextFile {
name = "ipxeScriptDir";
text = ''
#!ipxe
dhcp
kernel bzImage init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} console=ttyS0
initrd initrd
boot
'';
destination = "/boot.ipxe";
};
ipxeBootDir = pkgs.symlinkJoin { ipxeBootDir = pkgs.symlinkJoin {
name = "ipxeBootDir"; name = "ipxeBootDir";
paths = [ paths = [
config.system.build.netbootRamdisk config.system.build.netbootRamdisk
config.system.build.kernel config.system.build.kernel
ipxeScriptDir config.system.build.netbootIpxeScript
]; ];
}; };
machineConfig = perlAttrs ({
qemuFlags = "-boot order=n -netdev user,id=net0,tftp=${ipxeBootDir}/,bootfile=netboot.ipxe -m 2000";
} // extraConfig);
in in
makeTest { makeTest {
name = "boot-netboot"; name = "boot-netboot-" + name;
nodes = { }; nodes = { };
testScript = testScript =
'' ''
my $machine = createMachine({ qemuFlags => '-boot order=n -net nic,model=e1000 -net user,tftp=${ipxeBootDir}/,bootfile=boot.ipxe -m 2000M' }); my $machine = createMachine(${machineConfig});
$machine->start; $machine->start;
$machine->waitForUnit("multi-user.target"); $machine->waitForUnit("multi-user.target");
$machine->shutdown; $machine->shutdown;
''; '';
}; };
in {
biosCdrom = makeBootTest "bios-cdrom" {
cdrom = ''glob("${iso}/iso/*.iso")'';
};
biosUsb = makeBootTest "bios-usb" {
usb = ''glob("${iso}/iso/*.iso")'';
};
uefiCdrom = makeBootTest "uefi-cdrom" {
cdrom = ''glob("${iso}/iso/*.iso"'';
bios = ''"${pkgs.OVMF.fd}/FV/OVMF.fd"'';
};
uefiUsb = makeBootTest "uefi-usb" {
usb = ''glob("${iso}/iso/*.iso")'';
bios = ''"${pkgs.OVMF.fd}/FV/OVMF.fd"'';
};
biosNetboot = makeNetbootTest "bios" {};
uefiNetboot = makeNetbootTest "uefi" {
bios = ''"${pkgs.OVMF.fd}/FV/OVMF.fd"'';
# Custom ROM is needed for EFI PXE boot. I failed to understand exactly why, because QEMU should still use iPXE for EFI.
netRomFile = ''"${pkgs.ipxe}/ipxe.efirom"'';
};
} }

View File

@ -1,23 +1,28 @@
{ stdenv, lib, fetchgit, perl, cdrkit, syslinux, xz, openssl, gnu-efi { stdenv, lib, fetchgit, perl, cdrkit, syslinux, xz, openssl, gnu-efi, mtools
, embedScript ? null , embedScript ? null
, additionalTargets ? {}
}: }:
let let
date = "20190318"; date = "20190318";
rev = "ebf2eaf515e46abd43bc798e7e4ba77bfe529218"; rev = "ebf2eaf515e46abd43bc798e7e4ba77bfe529218";
targets = (lib.optional stdenv.isx86_64 "bin-x86_64-efi/ipxe.efi") ++ [ targets = additionalTargets // lib.optionalAttrs stdenv.isx86_64 {
"bin/ipxe.dsk" "bin-x86_64-efi/ipxe.efi" = null;
"bin/ipxe.usb" "bin-x86_64-efi/ipxe.efirom" = null;
"bin/ipxe.iso" "bin-x86_64-efi/ipxe.usb" = "ipxe-efi.usb";
"bin/ipxe.lkrn" } // {
"bin/undionly.kpxe" "bin/ipxe.dsk" = null;
]; "bin/ipxe.usb" = null;
"bin/ipxe.iso" = null;
"bin/ipxe.lkrn" = null;
"bin/undionly.kpxe" = null;
};
in in
stdenv.mkDerivation { stdenv.mkDerivation {
name = "ipxe-${date}-${builtins.substring 0 7 rev}"; name = "ipxe-${date}-${builtins.substring 0 7 rev}";
buildInputs = [ perl cdrkit syslinux xz openssl gnu-efi ]; nativeBuildInputs = [ perl cdrkit syslinux xz openssl gnu-efi mtools ];
src = fetchgit { src = fetchgit {
url = https://git.ipxe.org/ipxe.git; url = https://git.ipxe.org/ipxe.git;
@ -37,7 +42,12 @@ stdenv.mkDerivation {
] ++ lib.optional (embedScript != null) "EMBED=${embedScript}"; ] ++ lib.optional (embedScript != null) "EMBED=${embedScript}";
enabledOptions = [ "DOWNLOAD_PROTO_HTTPS" ]; enabledOptions = [
"PING_CMD"
"IMAGE_TRUST_CMD"
"DOWNLOAD_PROTO_HTTP"
"DOWNLOAD_PROTO_HTTPS"
];
configurePhase = '' configurePhase = ''
runHook preConfigure runHook preConfigure
@ -49,11 +59,14 @@ stdenv.mkDerivation {
preBuild = "cd src"; preBuild = "cd src";
buildFlags = targets; buildFlags = lib.attrNames targets;
installPhase = '' installPhase = ''
mkdir -p $out mkdir -p $out
cp ${lib.concatStringsSep " " targets} $out ${lib.concatStringsSep "\n" (lib.mapAttrsToList (from: to:
if to == null
then "cp -v ${from} $out"
else "cp -v ${from} $out/${to}") targets)}
# Some PXE constellations especially with dnsmasq are looking for the file with .0 ending # Some PXE constellations especially with dnsmasq are looking for the file with .0 ending
# let's provide it as a symlink to be compatible in this case. # let's provide it as a symlink to be compatible in this case.
@ -67,6 +80,6 @@ stdenv.mkDerivation {
homepage = http://ipxe.org/; homepage = http://ipxe.org/;
license = licenses.gpl2; license = licenses.gpl2;
maintainers = with maintainers; [ ehmry ]; maintainers = with maintainers; [ ehmry ];
platforms = platforms.all; platforms = [ "x86_64-linux" "i686-linux" ];
}; };
} }