Update QEMU Nixos Virtual Machine

The Nixos Qemu VM that are used for VM tests can now start without
boot menu even when using a bootloader.
The Nixos Qemu VM with bootloader can emulate a EFI boot now.

+144 -23
+69 -18
nixos/modules/virtualisation/qemu-vm.nix
··· 36 36 ${toString config.virtualisation.diskSize}M || exit 1 37 37 fi 38 38 39 - # Create a directory for exchanging data with the VM. 39 + # Create a directory for storing temporary data of the running VM. 40 40 if [ -z "$TMPDIR" -o -z "$USE_TMPDIR" ]; then 41 41 TMPDIR=$(mktemp -d nix-vm.XXXXXXXXXX --tmpdir) 42 42 fi 43 - cd $TMPDIR 43 + # Create a directory for exchanging data with the VM. 44 44 mkdir -p $TMPDIR/xchg 45 45 46 + ${if cfg.useBootLoader then '' 47 + # Create a writable copy/snapshot of the boot disk 48 + # A writable boot disk can be booted from automatically 49 + ${pkgs.qemu_kvm}/bin/qemu-img create -f qcow2 -b ${bootDisk}/disk.img $TMPDIR/disk.img || exit 1 50 + 51 + ${if cfg.useEFIBoot then '' 52 + # VM needs a writable flash BIOS 53 + cp ${bootDisk}/bios.bin $TMPDIR || exit 1 54 + chmod 0644 $TMPDIR/bios.bin || exit 1 55 + '' else '' 56 + ''} 57 + '' else '' 58 + ''} 59 + 60 + cd $TMPDIR 46 61 idx=2 47 62 extraDisks="" 48 63 ${flip concatMapStrings cfg.emptyDiskImages (size: '' ··· 52 67 '')} 53 68 54 69 # Start QEMU. 55 - # "-boot menu=on" is there, because I don't know how to make qemu boot from 2nd hd. 56 70 exec ${pkgs.qemu_kvm}/bin/qemu-kvm \ 57 71 -name ${vmName} \ 58 72 -m ${toString config.virtualisation.memorySize} \ ··· 63 77 -virtfs local,path=''${SHARED_DIR:-$TMPDIR/xchg},security_model=none,mount_tag=shared \ 64 78 ${if cfg.useBootLoader then '' 65 79 -drive index=0,id=drive1,file=$NIX_DISK_IMAGE,if=virtio,cache=writeback,werror=report \ 66 - -drive index=1,id=drive2,file=${bootDisk}/disk.img,if=virtio,readonly \ 67 - -boot menu=on \ 80 + -drive index=1,id=drive2,file=$TMPDIR/disk.img,media=disk \ 81 + ${if cfg.useEFIBoot then '' 82 + -pflash $TMPDIR/bios.bin \ 83 + '' else '' 84 + ''} 68 85 '' else '' 69 86 -drive file=$NIX_DISK_IMAGE,if=virtio,cache=writeback,werror=report \ 70 87 -kernel ${config.system.build.toplevel}/kernel \ ··· 74 91 $extraDisks \ 75 92 ${qemuGraphics} \ 76 93 ${toString config.virtualisation.qemu.options} \ 77 - $QEMU_OPTS 94 + $QEMU_OPTS \ 95 + $@ 78 96 ''; 79 97 80 98 ··· 98 116 '' 99 117 mkdir $out 100 118 diskImage=$out/disk.img 101 - ${pkgs.qemu_kvm}/bin/qemu-img create -f qcow2 $diskImage "32M" 119 + bootFlash=$out/bios.bin 120 + ${pkgs.qemu_kvm}/bin/qemu-img create -f qcow2 $diskImage "40M" 121 + ${if cfg.useEFIBoot then '' 122 + cp ${pkgs.OVMF-CSM}/FV/OVMF.fd $bootFlash 123 + chmod 0644 $bootFlash 124 + '' else '' 125 + ''} 102 126 ''; 103 127 buildInputs = [ pkgs.utillinux ]; 128 + QEMU_OPTS = if cfg.useEFIBoot 129 + then "-pflash $out/bios.bin -nographic -serial pty" 130 + else "-nographic -serial pty"; 104 131 } 105 132 '' 106 - # Create a single /boot partition. 107 - ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos 108 - ${pkgs.parted}/sbin/parted /dev/vda -- mkpart primary ext2 1M -1s 109 - . /sys/class/block/vda1/uevent 110 - mknod /dev/vda1 b $MAJOR $MINOR 133 + # Create a /boot EFI partition with 40M 134 + ${pkgs.gptfdisk}/sbin/sgdisk -G /dev/vda 135 + ${pkgs.gptfdisk}/sbin/sgdisk -a 1 -n 1:34:2047 -c 1:"BIOS Boot Partition" -t 1:ef02 /dev/vda 136 + ${pkgs.gptfdisk}/sbin/sgdisk -a 512 -N 2 -c 2:"EFI System" -t 2:ef00 /dev/vda 137 + ${pkgs.gptfdisk}/sbin/sgdisk -A 1:set:1 /dev/vda 138 + ${pkgs.gptfdisk}/sbin/sgdisk -A 2:set:2 /dev/vda 139 + ${pkgs.gptfdisk}/sbin/sgdisk -h 2 /dev/vda 140 + ${pkgs.gptfdisk}/sbin/sgdisk -C /dev/vda 141 + ${pkgs.utillinux}/bin/sfdisk /dev/vda -A 2 142 + . /sys/class/block/vda2/uevent 143 + mknod /dev/vda2 b $MAJOR $MINOR 111 144 . /sys/class/block/vda/uevent 112 - ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L boot /dev/vda1 113 - ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1 145 + ${pkgs.dosfstools}/bin/mkfs.fat -F16 /dev/vda2 146 + export MTOOLS_SKIP_CHECK=1 147 + ${pkgs.mtools}/bin/mlabel -i /dev/vda2 ::boot 114 148 115 - # Mount /boot. 149 + # Mount /boot; load necessary modules first. 150 + ${pkgs.module_init_tools}/sbin/insmod ${pkgs.linux}/lib/modules/*/kernel/fs/nls/nls_cp437.ko || true 151 + ${pkgs.module_init_tools}/sbin/insmod ${pkgs.linux}/lib/modules/*/kernel/fs/nls/nls_iso8859-1.ko || true 152 + ${pkgs.module_init_tools}/sbin/insmod ${pkgs.linux}/lib/modules/*/kernel/fs/fat/fat.ko || true 153 + ${pkgs.module_init_tools}/sbin/insmod ${pkgs.linux}/lib/modules/*/kernel/fs/fat/vfat.ko || true 154 + ${pkgs.module_init_tools}/sbin/insmod ${pkgs.linux}/lib/modules/*/kernel/fs/efivarfs/efivarfs.ko || true 116 155 mkdir /boot 117 - mount /dev/vda1 /boot 156 + mount /dev/vda2 /boot 118 157 119 158 # This is needed for GRUB 0.97, which doesn't know about virtio devices. 120 159 mkdir /boot/grub ··· 287 326 ''; 288 327 }; 289 328 329 + virtualisation.useEFIBoot = 330 + mkOption { 331 + default = false; 332 + description = 333 + '' 334 + If enabled, the virtual machine will provide a EFI boot 335 + manager. 336 + useEFIBoot is ignored if useBootLoader == false. 337 + ''; 338 + }; 339 + 290 340 }; 291 341 292 342 config = { ··· 379 429 }; 380 430 } // optionalAttrs cfg.useBootLoader 381 431 { "/boot" = 382 - { device = "/dev/disk/by-label/boot"; 383 - fsType = "ext4"; 432 + { device = "/dev/vdb2"; 433 + fsType = "vfat"; 384 434 options = "ro"; 385 435 noCheck = true; # fsck fails on a r/o filesystem 386 436 }; ··· 413 463 414 464 # Wireless won't work in the VM. 415 465 networking.wireless.enable = mkVMOverride false; 466 + networking.connman.enable = mkVMOverride false; 416 467 417 468 # Speed up booting by not waiting for ARP. 418 469 networking.dhcpcd.extraConfig = "noarp";
+26 -4
pkgs/applications/virtualization/OVMF/default.nix
··· 1 - { stdenv, edk2, nasm, iasl }: 1 + { stdenv, edk2, nasm, iasl, seabios, openssl, secureBoot ? false }: 2 2 3 3 let 4 4 ··· 14 14 stdenv.mkDerivation (edk2.setup "OvmfPkg/OvmfPkg${targetArch}.dsc" { 15 15 name = "OVMF-2014-12-10"; 16 16 17 - buildInputs = [nasm iasl]; 17 + # TODO: properly include openssl for secureBoot 18 + buildInputs = [nasm iasl] ++ stdenv.lib.optionals (secureBoot == true) [ openssl ]; 19 + 18 20 unpackPhase = '' 19 21 for file in \ 20 - "${edk2.src}"/{OvmfPkg,UefiCpuPkg,MdeModulePkg,IntelFrameworkModulePkg,PcAtChipsetPkg,FatBinPkg,EdkShellBinPkg,MdePkg,ShellPkg,OptionRomPkg,IntelFrameworkPkg}; 22 + "${edk2.src}"/{UefiCpuPkg,MdeModulePkg,IntelFrameworkModulePkg,PcAtChipsetPkg,FatBinPkg,EdkShellBinPkg,MdePkg,ShellPkg,OptionRomPkg,IntelFrameworkPkg}; 21 23 do 22 24 ln -sv "$file" . 23 25 done 24 - ''; 26 + 27 + ${if (seabios == false) then '' 28 + ln -sv ${edk2.src}/OvmfPkg . 29 + '' else '' 30 + cp -r ${edk2.src}/OvmfPkg . 31 + chmod +w OvmfPkg/Csm/Csm16 32 + cp ${seabios}/Csm16.bin OvmfPkg/Csm/Csm16/Csm16.bin 33 + ''} 34 + 35 + ${if (secureBoot == true) then '' 36 + ln -sv ${edk2.src}/SecurityPkg . 37 + ln -sv ${edk2.src}/CryptoPkg . 38 + '' else '' 39 + ''} 40 + ''; 41 + 42 + buildPhase = if (seabios == false) then '' 43 + build ${if secureBoot then "-DSECURE_BOOT_ENABLE=TRUE" else ""} 44 + '' else '' 45 + build -D CSM_ENABLE -D FD_SIZE_2MB ${if secureBoot then "-DSECURE_BOOT_ENABLE=TRUE" else ""} 46 + ''; 25 47 26 48 meta = { 27 49 description = "Sample UEFI firmware for QEMU and KVM";
+44
pkgs/applications/virtualization/seabios/default.nix
··· 1 + { stdenv, fetchurl, iasl, python }: 2 + 3 + stdenv.mkDerivation rec { 4 + 5 + name = "seabios-${version}"; 6 + version = "1.7.5.2"; 7 + 8 + src = fetchurl { 9 + url = "http://code.coreboot.org/p/seabios/downloads/get/${name}.tar.gz"; 10 + sha256 = "1syd3gi5gq0gj2pjvmdis64xc3j1xf0jgy49ngymap0pdpm0cmh0"; 11 + }; 12 + 13 + buildInputs = [ iasl python ]; 14 + 15 + configurePhase = '' 16 + # build SeaBIOS for CSM 17 + cat > .config << EOF 18 + CONFIG_CSM=y 19 + CONFIG_QEMU_HARDWARE=y 20 + CONFIG_PERMIT_UNALIGNED_PCIROM=y 21 + EOF 22 + 23 + make olddefconfig 24 + ''; 25 + 26 + installPhase = '' 27 + mkdir $out 28 + cp out/Csm16.bin $out/Csm16.bin 29 + ''; 30 + 31 + meta = with stdenv.lib; { 32 + description = "Open source implementation of a 16bit X86 BIOS"; 33 + longDescription = '' 34 + SeaBIOS is an open source implementation of a 16bit X86 BIOS. 35 + It can run in an emulator or it can run natively on X86 hardware with the use of coreboot. 36 + SeaBIOS is the default BIOS for QEMU and KVM. 37 + ''; 38 + homepage = http://www.seabios.org; 39 + license = licenses.lgpl3; 40 + maintainers = [ maintainers.tstrobel ]; 41 + platforms = platforms.linux; 42 + }; 43 + } 44 +
+5 -1
pkgs/top-level/all-packages.nix
··· 8058 8058 8059 8059 oracleXE = callPackage ../servers/sql/oracle-xe { }; 8060 8060 8061 - OVMF = callPackage ../applications/virtualization/OVMF { }; 8061 + OVMF = callPackage ../applications/virtualization/OVMF { seabios=false; openssl=null; }; 8062 + OVMF-CSM = callPackage ../applications/virtualization/OVMF { openssl=null; }; 8063 + #WIP: OVMF-secureBoot = callPackage ../applications/virtualization/OVMF { seabios=false; secureBoot=true; }; 8064 + 8065 + seabios = callPackage ../applications/virtualization/seabios { }; 8062 8066 8063 8067 pgpool92 = callPackage ../servers/sql/pgpool/default.nix { 8064 8068 postgresql = postgresql92;