Skip to content

Commit

Permalink
Create a virtual machine with virtio-gpu device
Browse files Browse the repository at this point in the history
Signed-off-by: Yuri Nesterov <yuriy.nesterov@unikie.com>
  • Loading branch information
nesteroff committed May 13, 2024
1 parent c938efd commit 4c6bd3c
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 25 deletions.
1 change: 1 addition & 0 deletions modules/desktop/graphics/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
./window-manager.nix
./boot.nix
./hardware.nix
./waypipe.nix
];
}
39 changes: 39 additions & 0 deletions modules/desktop/graphics/waypipe.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
# SPDX-License-Identifier: Apache-2.0
#
{
pkgs,
lib,
config,
...
}: let
cfg = config.ghaf.waypipe;
in {
options.ghaf.waypipe = {
enable = lib.mkEnableOption "Waypipe";

port = lib.mkOption {
type = lib.types.int;
default = 1100;
description = ''
Waypipe port number to listen for incoming connections
'';
};
};

config = lib.mkIf cfg.enable {
systemd.user.services.waypipe = {
enable = true;
description = "waypipe";
after = ["weston.service" "labwc.service"];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.waypipe}/bin/waypipe --vsock -s ${toString cfg.port} client";
Restart = "always";
RestartSec = "1";
};
startLimitIntervalSec = 0;
wantedBy = ["ghaf-session.target"];
};
};
}
1 change: 1 addition & 0 deletions modules/microvm/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
./virtualization/microvm/guivm.nix
./networking.nix
./power-control.nix
./virtualization/microvm/virtgpuvm.nix
];
}
2 changes: 1 addition & 1 deletion modules/microvm/virtualization/microvm/appvm.nix
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
runWaypipe = with pkgs;
writeScriptBin "run-waypipe" ''
#!${runtimeShell} -e
${pkgs.waypipe}/bin/waypipe --vsock -s ${toString configHost.ghaf.virtualization.microvm.guivm.waypipePort} ${waypipeBorder} server $@
${pkgs.waypipe}/bin/waypipe --vsock -s ${toString configHost.ghaf.waypipe.port} ${waypipeBorder} server $@
'';
in {
ghaf = {
Expand Down
26 changes: 2 additions & 24 deletions modules/microvm/virtualization/microvm/guivm.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
graphics.labwc.lock.enable = false;
profiles.applications.enable = false;
windows-launcher.enable = false;
waypipe.enable = true;
development = {
ssh.daemon.enable = lib.mkDefault configHost.ghaf.development.ssh.daemon.enable;
debug.tools.enable = lib.mkDefault configHost.ghaf.development.debug.tools.enable;
Expand Down Expand Up @@ -117,21 +118,6 @@
../../../desktop
];

# Waypipe service runs in the GUIVM and listens for incoming connections from AppVMs
systemd.user.services.waypipe = {
enable = true;
description = "waypipe";
after = ["weston.service" "labwc.service"];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.waypipe}/bin/waypipe --vsock -s ${toString cfg.waypipePort} client";
Restart = "always";
RestartSec = "1";
};
startLimitIntervalSec = 0;
wantedBy = ["ghaf-session.target"];
};

# Fixed IP-address for debugging subnet
systemd.network.networks."10-ethint0".addresses = [
{
Expand Down Expand Up @@ -173,14 +159,6 @@ in {
Context Identifier (CID) of the GUIVM VSOCK
'';
};

waypipePort = lib.mkOption {
type = lib.types.int;
default = 1100;
description = ''
Waypipe port number to listen for incoming connections from AppVMs
'';
};
};

config = lib.mkIf cfg.enable {
Expand Down Expand Up @@ -230,7 +208,7 @@ in {
Type = "simple";
};
serviceConfig = {
ExecStart = "${vsockproxy}/bin/vsockproxy ${toString cfg.waypipePort} ${toString cfg.vsockCID} ${toString cfg.waypipePort}";
ExecStart = "${vsockproxy}/bin/vsockproxy ${toString config.ghaf.waypipe.port} ${toString cfg.vsockCID} ${toString config.ghaf.waypipe.port}";
};
wantedBy = ["multi-user.target"];
};
Expand Down
161 changes: 161 additions & 0 deletions modules/microvm/virtualization/microvm/virtgpuvm.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
# SPDX-License-Identifier: Apache-2.0
{
config,
lib,
pkgs,
...
}: let
configHost = config;
vmName = "virtgpu-vm";
# The socket is created in /tmp because it is accessible to both microvm and ghaf users
gpuSocket = "/tmp/${vmName}-gpu.sock";
run-sommelier = with pkgs;
writeScriptBin "run-sommelier" ''
#!${runtimeShell} -e
exec ${sommelier}/bin/sommelier --virtgpu-channel -- $@
'';
run-wayland-proxy = with pkgs;
writeScriptBin "run-wayland-proxy" ''
#!${runtimeShell} -e
exec ${wayland-proxy-virtwl}/bin/wayland-proxy-virtwl --virtio-gpu -- $@
'';
run-waypipe = with pkgs;
writeScriptBin "run-waypipe" ''
#!${runtimeShell} -e
exec ${waypipe}/bin/waypipe --vsock -s 2:${toString config.ghaf.waypipe.port} server $@
'';
virtgpuvmBaseConfiguration = {
imports = [
(import ./common/vm-networking.nix {
inherit vmName;
macAddress = "02:00:00:03:05:01";
})
({
lib,
pkgs,
...
}: {
ghaf = {
users.accounts.enable = lib.mkDefault configHost.ghaf.users.accounts.enable;

development = {
ssh.daemon.enable = lib.mkDefault configHost.ghaf.development.ssh.daemon.enable;
debug.tools.enable = lib.mkDefault configHost.ghaf.development.debug.tools.enable;
nix-setup.enable = lib.mkDefault configHost.ghaf.development.nix-setup.enable;
};
};

system.stateVersion = lib.trivial.release;

nixpkgs.buildPlatform.system = configHost.nixpkgs.buildPlatform.system;
nixpkgs.hostPlatform.system = configHost.nixpkgs.hostPlatform.system;

environment.systemPackages = with pkgs; [
sommelier
wayland-proxy-virtwl
waypipe
run-sommelier
run-wayland-proxy
run-waypipe
zathura
chromium
firefox
wayland-utils
];

# DRM fbdev emulation is disabled to get rid of the popup console window that appears when running a VM with virtio-gpu device
boot.kernelParams = ["drm_kms_helper.fbdev_emulation=false"];

hardware.opengl.enable = true;

microvm = {
optimize.enable = false;
mem = 4096;
vcpu = 4;
hypervisor = "crosvm";
shares = [
{
tag = "ro-store";
source = "/nix/store";
mountPoint = "/nix/.ro-store";
proto = "virtiofs";
}
];

# GPU device is a separate service which is connected over vhost-user protocol
crosvm.extraArgs = ["--vhost-user" "gpu,socket=${gpuSocket}"];

# VSOCK is required for waypipe, 3 is the first available CID
vsock.cid = 3;
};

imports = [../../../common];
})
];
};
cfg = config.ghaf.virtualization.microvm.virtgpuvm;
in {
options.ghaf.virtualization.microvm.virtgpuvm = {
enable = lib.mkEnableOption "VirtgpuVM";

extraModules = lib.mkOption {
description = ''
List of additional modules to be imported and evaluated as part of
VirtgpuVM's NixOS configuration.
'';
default = [];
};
};

config = lib.mkIf cfg.enable {
microvm.vms."${vmName}" = {
config = virtgpuvmBaseConfiguration // {imports = virtgpuvmBaseConfiguration.imports ++ cfg.extraModules;};
specialArgs = {inherit lib;};
};

# This service creates a crosvm backend GPU device
systemd.user.services."${vmName}-gpu" = let
preStartScript = pkgs.writeShellScriptBin "prestart-crosvmgpu" ''
if [[ -z "$WAYLAND_DISPLAY" ]]; then
echo "WAYLAND_DISPLAY is not set"
exit 1
fi
WAYLAND_SOCK=$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY
if [[ ! -r "$WAYLAND_SOCK" ]]; then
echo "Wayland socket $WAYLAND_SOCK is not readable"
exit 1
fi
'';
startScript = pkgs.writeShellScriptBin "start-crosvmgpu" ''
rm -f ${gpuSocket}
${pkgs.crosvm}/bin/crosvm device gpu --socket ${gpuSocket} --wayland-sock $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY --params '{"context-types":"virgl:virgl2:cross-domain","egl":true,"vulkan":true}'
'';
postStartScript = pkgs.writeShellScriptBin "poststart-crosvmgpu" ''
while ! [ -S ${gpuSocket} ]; do
sleep .1
done
chgrp video ${gpuSocket}
chmod 775 ${gpuSocket}
'';
in {
enable = true;
description = "crosvm gpu device";
after = ["weston.service" "labwc.service"];
serviceConfig = {
Type = "simple";
ExecStartPre = "${preStartScript}/bin/prestart-crosvmgpu";
ExecStart = "${startScript}/bin/start-crosvmgpu";
ExecStartPost = "${postStartScript}/bin/poststart-crosvmgpu";
Restart = "always";
RestartSec = "1";
};
startLimitIntervalSec = 0;
wantedBy = ["ghaf-session.target"];
};

users.users."microvm".extraGroups = ["video"];

ghaf.waypipe.enable = true;
};
}
27 changes: 27 additions & 0 deletions overlays/custom-packages/crosvm/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
# SPDX-License-Identifier: Apache-2.0
{
final,
prev,
}:
prev.crosvm.overrideAttrs (_final: prevAttrs: rec {
version = "122.1";
src = prev.fetchgit {
url = "https://chromium.googlesource.com/chromiumos/platform/crosvm";
rev = "562d81eb28a49ed6e0d771a430c21a458cdd33f9";
sha256 = "sha256-l5sIUInOhhkn3ernQLIEwEpRCyICDH/1k4C/aidy1/I=";
fetchSubmodules = true;
};

patches = [];

cargoBuildFeatures = final.lib.lists.remove "virgl_renderer_next" prevAttrs.cargoBuildFeatures;
cargoCheckFeatures = final.lib.lists.remove "virgl_renderer_next" prevAttrs.cargoCheckFeatures;
CROSVM_USE_SYSTEM_MINIGBM = true;

cargoDeps = prevAttrs.cargoDeps.overrideAttrs (prev.lib.const {
inherit src;
name = "crosvm-vendor.tar.gz";
outputHash = "sha256-yTdho6lW+XqB/iGf+bT2iwnAdjz3TrrI7YAaLoenR1U=";
});
})
2 changes: 2 additions & 0 deletions overlays/custom-packages/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@
networkmanagerapplet = import ./networkmanagerapplet {inherit prev;};
htop = import ./htop {inherit prev;};
mitmweb-ui = final.callPackage ../../packages/mitmweb-ui {};
sommelier = import ./sommelier {inherit final prev;};
crosvm = import ./crosvm {inherit final prev;};
})
20 changes: 20 additions & 0 deletions overlays/custom-packages/sommelier/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
# SPDX-License-Identifier: Apache-2.0
{
final,
prev,
}:
prev.sommelier.overrideAttrs (_final: prevAttrs: {
version = "122.0";
src = prev.fetchzip rec {
url = "https://chromium.googlesource.com/chromiumos/platform2/+archive/${passthru.rev}/vm_tools/sommelier.tar.gz";
passthru.rev = "2d4f46c679da7a4e8c447c8cf68c74b80f9de3fe";
stripRoot = false;
sha256 = "sha256-LNGA1r2IO3Ekh+dK6HUge001qC2TFvxwjhM0iaY0DbU=";
};

nativeBuildInputs = prevAttrs.nativeBuildInputs ++ [final.python3 final.python3.pkgs.jinja2];
postPatch = ''
patchShebangs gen-shim.py
'';
})
6 changes: 6 additions & 0 deletions targets/generic-x86_64/flake-module.nix
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
#graphics.compositor = "labwc";
};
windows-launcher.enable = true;

# Uncomment this line to enable the virtgpu-vm with a virtio-gpu device:
#virtualization.microvm.virtgpuvm.enable = true;
};

#TODO: how to handle the majority of laptops that need a little
Expand All @@ -84,6 +87,9 @@
# Passthrough Intel WiFi card
"vfio-pci.ids=8086:a0f0"
];

# Enable DHCP on the host to be able to access network and connect to VMs by name, e.g. net-vm.ghaf
systemd.network.networks."10-virbr0".DHCP = "yes";
}
]
++ extraModules;
Expand Down

0 comments on commit 4c6bd3c

Please sign in to comment.