Merge pull request #180222 from YorikSar/qemu-vm-darwin-pkgs

nixos/qemu-vm: Allow to build and run VMs on Darwin

Changed files
+66 -19
nixos
lib
modules
virtualisation
+47 -15
nixos/lib/qemu-common.nix
···
let
zeroPad = n:
lib.optionalString (n < 16) "0" +
-
(if n > 255
-
then throw "Can't have more than 255 nets or nodes!"
-
else lib.toHexString n);
in
rec {
qemuNicMac = net: machine: "52:54:00:12:${zeroPad net}:${zeroPad machine}";
qemuNICFlags = nic: net: machine:
-
[ "-device virtio-net-pci,netdev=vlan${toString nic},mac=${qemuNicMac net machine}"
''-netdev vde,id=vlan${toString nic},sock="$QEMU_VDE_SOCKET_${toString net}"''
];
-
qemuSerialDevice = if pkgs.stdenv.hostPlatform.isx86 || pkgs.stdenv.hostPlatform.isRiscV then "ttyS0"
-
else if (with pkgs.stdenv.hostPlatform; isAarch || isPower) then "ttyAMA0"
-
else throw "Unknown QEMU serial device for system '${pkgs.stdenv.hostPlatform.system}'";
-
qemuBinary = qemuPkg: {
-
x86_64-linux = "${qemuPkg}/bin/qemu-kvm -cpu max";
-
armv7l-linux = "${qemuPkg}/bin/qemu-system-arm -machine virt,accel=kvm:tcg -cpu max";
-
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt,gic-version=max,accel=kvm:tcg -cpu max";
-
powerpc64le-linux = "${qemuPkg}/bin/qemu-system-ppc64 -machine powernv";
-
powerpc64-linux = "${qemuPkg}/bin/qemu-system-ppc64 -machine powernv";
-
x86_64-darwin = "${qemuPkg}/bin/qemu-kvm -cpu max";
-
}.${pkgs.stdenv.hostPlatform.system} or "${qemuPkg}/bin/qemu-kvm";
}
···
let
zeroPad = n:
lib.optionalString (n < 16) "0" +
+
(if n > 255
+
then throw "Can't have more than 255 nets or nodes!"
+
else lib.toHexString n);
in
rec {
qemuNicMac = net: machine: "52:54:00:12:${zeroPad net}:${zeroPad machine}";
qemuNICFlags = nic: net: machine:
+
[
+
"-device virtio-net-pci,netdev=vlan${toString nic},mac=${qemuNicMac net machine}"
''-netdev vde,id=vlan${toString nic},sock="$QEMU_VDE_SOCKET_${toString net}"''
];
+
qemuSerialDevice =
+
if pkgs.stdenv.hostPlatform.isx86 || pkgs.stdenv.hostPlatform.isRiscV then "ttyS0"
+
else if (with pkgs.stdenv.hostPlatform; isAarch || isPower) then "ttyAMA0"
+
else throw "Unknown QEMU serial device for system '${pkgs.stdenv.hostPlatform.system}'";
+
+
qemuBinary = qemuPkg:
+
let
+
hostStdenv = qemuPkg.stdenv;
+
hostSystem = hostStdenv.system;
+
guestSystem = pkgs.stdenv.hostPlatform.system;
+
linuxHostGuestMatrix = {
+
x86_64-linux = "${qemuPkg}/bin/qemu-kvm -cpu max";
+
armv7l-linux = "${qemuPkg}/bin/qemu-system-arm -machine virt,accel=kvm:tcg -cpu max";
+
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt,gic-version=max,accel=kvm:tcg -cpu max";
+
powerpc64le-linux = "${qemuPkg}/bin/qemu-system-ppc64 -machine powernv";
+
powerpc64-linux = "${qemuPkg}/bin/qemu-system-ppc64 -machine powernv";
+
x86_64-darwin = "${qemuPkg}/bin/qemu-kvm -cpu max";
+
};
+
otherHostGuestMatrix = {
+
aarch64-darwin = {
+
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt,gic-version=2,accel=hvf:tcg -cpu max";
+
};
+
x86_64-darwin = {
+
x86_64-linux = "${qemuPkg}/bin/qemu-system-x86_64 -machine type=q35,accel=hvf:tcg -cpu max";
+
};
+
};
+
+
throwUnsupportedHostSystem =
+
let
+
supportedSystems = [ "linux" ] ++ (lib.attrNames otherHostGuestMatrix);
+
in
+
throw "Unsupported host system ${hostSystem}, supported: ${lib.concatStringsSep ", " supportedSystems}";
+
throwUnsupportedGuestSystem = guestMap:
+
throw "Unsupported guest system ${guestSystem} for host ${hostSystem}, supported: ${lib.concatStringsSep ", " (lib.attrNames guestMap)}";
+
in
+
if hostStdenv.isLinux then
+
linuxHostGuestMatrix.${guestSystem} or "${qemuPkg}/bin/qemu-kvm"
+
else
+
let
+
guestMap = (otherHostGuestMatrix.${hostSystem} or throwUnsupportedHostSystem);
+
in
+
(guestMap.${guestSystem} or (throwUnsupportedGuestSystem guestMap));
}
+19 -4
nixos/modules/virtualisation/qemu-vm.nix
···
# Shell script to start the VM.
startVM =
''
-
#! ${pkgs.runtimeShell}
set -e
···
description = "Primary IP address used in /etc/hosts.";
};
virtualisation.qemu = {
package =
mkOption {
type = types.package;
-
default = pkgs.qemu_kvm;
example = "pkgs.qemu_test";
description = lib.mdDoc "QEMU package to use.";
};
···
services.qemuGuest.enable = cfg.qemu.guestAgent.enable;
-
system.build.vm = pkgs.runCommand "nixos-vm" {
preferLocalBuild = true;
meta.mainProgram = "run-${config.system.name}-vm";
}
''
mkdir -p $out/bin
ln -s ${config.system.build.toplevel} $out/system
-
ln -s ${pkgs.writeScript "run-nixos-vm" startVM} $out/bin/run-${config.system.name}-vm
'';
# When building a regular system configuration, override whatever
···
# Shell script to start the VM.
startVM =
''
+
#! ${cfg.host.pkgs.runtimeShell}
+
+
export PATH=${makeBinPath [ cfg.host.pkgs.coreutils ]}''${PATH:+:}$PATH
set -e
···
description = "Primary IP address used in /etc/hosts.";
};
+
virtualisation.host.pkgs = mkOption {
+
type = options.nixpkgs.pkgs.type;
+
default = pkgs;
+
defaultText = "pkgs";
+
example = literalExpression ''
+
import pkgs.path { system = "x86_64-darwin"; }
+
'';
+
description = ''
+
pkgs set to use for the host-specific packages of the vm runner.
+
Changing this to e.g. a Darwin package set allows running NixOS VMs on Darwin.
+
'';
+
};
+
virtualisation.qemu = {
package =
mkOption {
type = types.package;
+
default = cfg.host.pkgs.qemu_kvm;
example = "pkgs.qemu_test";
description = lib.mdDoc "QEMU package to use.";
};
···
services.qemuGuest.enable = cfg.qemu.guestAgent.enable;
+
system.build.vm = cfg.host.pkgs.runCommand "nixos-vm" {
preferLocalBuild = true;
meta.mainProgram = "run-${config.system.name}-vm";
}
''
mkdir -p $out/bin
ln -s ${config.system.build.toplevel} $out/system
+
ln -s ${cfg.host.pkgs.writeScript "run-nixos-vm" startVM} $out/bin/run-${config.system.name}-vm
'';
# When building a regular system configuration, override whatever