diff --git a/examples/dummy.nix b/examples/dummy.nix index 7d8c813..02254c9 100644 --- a/examples/dummy.nix +++ b/examples/dummy.nix @@ -5,6 +5,28 @@ modulesPath, ... }: +let + uvmsPkgs = pkgs.callPackage ../pkgs { }; + waylandSock = "/run/user/1000/wayland-1"; + env = { + XDG_RUNTIME_DIR = "/run/user/1000"; + WAYLAND_DISPLAY = "wayland-1"; + + MESA_LOADER_DRIVER_OVERRIDE = "zink"; + + # WAYLAND_DEBUG = "1"; + # WAYLAND_DEBUG_PROXY = "1"; + + ELECTRON_OZONE_PLATFORM_HINT = "wayland"; + MOZ_ENABLE_WAYLAND = "1"; + QT_QPA_PLATFORM = "wayland"; # Qt Applications + GDK_BACKEND = "wayland"; # GTK Applications + XDG_SESSION_TYPE = "wayland"; # Electron Applications + SDL_VIDEODRIVER = "wayland"; + CLUTTER_BACKEND = "wayland"; + NIXOS_OZONE_WL = "1"; + }; +in { imports = [ ../profiles/all.nix @@ -18,30 +40,117 @@ vmapps.enable = true; _module.args.inputs = import ../npins; - # following microvm.nix: + # boot.isContainer = true; + # boot.initrd.enable = true; boot.loader.grub.enable = false; boot.initrd.systemd.enable = true; + services.logrotate.enable = false; + services.udisks2.enable = false; + system.tools.nixos-generate-config.enable = false; + # system.activationScripts.specialfs = lib.mkForce ""; + systemd.coredump.enable = false; + # networking.firewall.enable = false; + powerManagement.enable = false; + boot.kexec.enable = false; + # console.enable = false; + # system.switch.enable = false; + # services.udev.packages = lib.mkDefault [ ]; + services.resolved.enable = false; + systemd.services.generate-shutdown-ramfs.enable = lib.mkForce false; + systemd.services.systemd-remount-fs.enable = lib.mkForce false; + systemd.services.systemd-pstore.enable = lib.mkForce false; + systemd.services.lastlog2-import.enable = lib.mkForce false; + systemd.services.suid-sgid-wrappers.enable = lib.mkForce false; + fileSystems."/" = lib.mkDefault { device = "rootfs"; # how does this work? does this assign a label to the tmpfs? fsType = "tmpfs"; options = [ "size=20%,mode=0755" ]; neededForBoot = true; }; - boot.initrd.systemd.settings.Manager.DefaultTimeoutStartSec = 30; + boot.initrd.systemd.settings.Manager.DefaultTimeoutStartSec = 5; systemd.settings.Manager.DefaultTimeoutStopSec = 10; networking.useNetworkd = true; networking.nftables.enable = true; uvms.cloud-hypervisor.enable = true; + systemd.sysusers.enable = false; + services.userborn.enable = true; # nikstur it users.mutableUsers = false; + users.groups.user = { }; + users.users.user = { + isNormalUser = true; + password = "hacktheplanet!"; + extraGroups = [ + "video" + "render" + ]; + }; users.users.root.password = "hacktheplanet!"; - services.getty.autologinUser = "root"; systemd.services."suid-sgid-wrappers".serviceConfig = { StandardOutput = "journal+console"; StandardError = "journal+console"; }; + environment.variables = env; + systemd.globalEnvironment = env; + systemd.tmpfiles.settings."10-xdg" = { + ${env.XDG_RUNTIME_DIR}.d = { + user = "user"; + group = "user"; + mode = "0755"; + }; + }; + systemd.sockets."wayland-proxy" = { + listenStreams = [ + waylandSock + ]; + socketConfig = { + SocketUser = "user"; + SocketGroup = "user"; + FileDescriptorName = "wayland"; + }; + wantedBy = [ "sockets.target" ]; + partOf = [ "wayland-proxy.service" ]; + }; + systemd.services."wayland-proxy" = { + wantedBy = [ "default.target" ]; + serviceConfig = { + User = "user"; + Group = "user"; + ExecStart = "${lib.getExe pkgs.wayland-proxy-virtwl} --virtio-gpu"; + # ExecStart = "${lib.getExe uvmsPkgs.wl-cross-domain-proxy} --listen-fd --filter-global wp_presentation"; + ExecStartPre = [ + "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128" + ]; + StandardOutput = "journal+console"; + StandardError = "journal+console"; + Restart = "on-failure"; + RestartSec = 5; + }; + }; + fonts.enableDefaultPackages = true; + + systemd.services."terminal" = { + wantedBy = [ "multi-user.target" ]; + wants = [ "wayland-proxy.service" ]; + after = [ "wayland-proxy.service" ]; + environment = env; + serviceConfig = { + User = "user"; + WorkingDirectory = "/home/user"; + ExecStart = lib.getExe pkgs.alacritty; + StandardOutput = "journal+console"; + StandardError = "journal+console"; + }; + }; + boot.kernelModules = [ + "drm" + "virtio_gpu" + ]; + hardware.graphics.enable = true; + # TODO: cmdline, kernel, initrd, fileSystems } diff --git a/profiles/ch-runner.nix b/profiles/ch-runner.nix index 1b46f22..55be70a 100644 --- a/profiles/ch-runner.nix +++ b/profiles/ch-runner.nix @@ -22,13 +22,7 @@ let getBin ; - package = pkgs.cloud-hypervisor.overrideAttrs (oldAttrs: { - patches = oldAttrs.patches or [ ] ++ [ - # ../patches/ch.patch - ]; - buildType = "debug"; - dontStrip = true; - }); + package = uvmsPkgs.cloud-hypervisor-gpu; uvmsPkgs = pkgs.callPackage ../pkgs { }; chSettingsFile = (pkgs.formats.json { }).generate "vm.json" cfg.settings; @@ -279,11 +273,20 @@ in (lib.getBin pkgs.virtiofsd) (lib.getBin pkgs.bubblewrap) (lib.getBin pkgs.strace) + (lib.getBin pkgs.crosvm) uvmsPkgs.taps ]; superviseVm = getExe superviseVm'; superviseVm' = pkgs.writers.writePython3Bin "supervise-vm" { } '' + # NOTE: This would have been bash, + # and this was execlineb previously, + # but it was just easier to reason in terms of context managers + # and try-except-finally branches for the cleanup bit, + # than in terms of traps or such. + # Treat this as bash. + # Treat this as throwaway shitcode. + import os import subprocess import socket @@ -320,8 +323,10 @@ in **{ k: v for k, v in os.environ.items() - if k.startswith("RUST") + if k.startswith("RUST_") or k.startswith("WAYLAND") + or k.startswith("XDG_") + or k.startswith("DBUS_") or k in [ "TAPS_SOCK", ] @@ -356,6 +361,8 @@ in def alive_after(proc, timeout): + if proc is None: + return False if proc.returncode is not None: return False try: @@ -410,6 +417,7 @@ in kwargs["stdin"] = kwargs.get("stdin", subprocess.DEVNULL) kwargs["stdout"] = kwargs.get("stdout", subprocess.DEVNULL) kwargs["stderr"] = kwargs.get("stderr", subprocess.DEVNULL) + proc = None try: proc = subprocess.Popen( args, @@ -421,7 +429,8 @@ in finally: if alive_after(proc, 0.125): proc.terminate() - proc.wait() + if proc is not None: + proc.wait() @contextmanager def bwrap( @@ -550,7 +559,7 @@ in *args, bind=[self.prefix], # Probably just need the path to vmlinux - ro_bind=("/nix/store",), # A give up + ro_bind=["/nix/store"], # I give up unshare_net=False, shell=False, stderr=None, @@ -575,6 +584,35 @@ in if os.path.exists(p): os.remove(p) + @contextmanager + def start_gpu( + self, + ): + sock_path = self.prefix + "/gpu.sock" + args = [ + SOCKETBINDER_PATH, + "-b", "1", + sock_path, + "s6-ipcserverd", + "-1c1", + # "${lib.getExe pkgs.strace}", # noqa: E501 + # "-Z", + # "-ff", + "${lib.getExe pkgs.crosvm}", # noqa: E501 + "--no-syslog", + "device", "gpu", + "--fd", "0", + "--wayland-sock", + f'{PASSTHRU_ENV["XDG_RUNTIME_DIR"]}/{PASSTHRU_ENV["WAYLAND_DISPLAY"]}', # noqa: E501 + "--params", + "{ \"context-types\": \"cross-domain:virgl2:venus\" }", + ] + with self.popen( + *args, + stderr=None, + ) as proc, removing(sock_path): + yield proc, sock_path + @contextmanager def start_virtiofsd( self, @@ -652,11 +690,26 @@ in f() + @contextmanager + def removing(*paths): + try: + yield + finally: + for p in paths: + if os.path.exists(p): + os.remove(p) + + if __name__ == "__main__": args, args_next = parser.parse_known_args() preprocess_args(args) + send_dir = PASSTHRU_ENV["HOME"] + f"/send/{args.vm}" + + os.makedirs(send_dir, exist_ok=True) os.makedirs(args.prefix, exist_ok=True) + os.makedirs(args.prefix + "/pts", exist_ok=True) + ps = Processes( prefix=args.prefix, vm=args.vm, @@ -670,13 +723,14 @@ in with ExitStack() as cleanup: - send_dir = PASSTHRU_ENV["HOME"] + f"/send/{args.vm}" - os.makedirs(send_dir, exist_ok=True) vfsd, vfsd_path = cleanup.enter_context( ps.start_virtiofsd( send_dir, tag="send", )) + gpud, gpud_path = cleanup.enter_context( + ps.start_gpu() + ) ch = cleanup.enter_context(ps.run_ch()) ps.exec(*ch_remote, "create", args.vm_config) @@ -686,6 +740,7 @@ in "id=wan,fd=3,mac=00:00:00:00:00:01") ps.exec(*ch_remote, "add-fs", f"tag=send,socket={vfsd_path},id=send") + ps.exec(*ch_remote, "add-gpu", f"socket={gpud_path}") ps.exec(*ch_remote, "boot") ps.exec(*ch_remote, "info") try: diff --git a/profiles/vmapp-demo.nix b/profiles/vmapp-demo.nix index 2f960b2..3af62bc 100644 --- a/profiles/vmapp-demo.nix +++ b/profiles/vmapp-demo.nix @@ -212,9 +212,9 @@ in ''} %i"; }; - boot.initrd.systemd.settings.Manager.DefaultTimeoutStartSec = 30; - systemd.settings.Manager.DefaultTimeoutStopSec = 10; - systemd.services."user@".serviceConfig.TimeoutStopSec = 10; + boot.initrd.systemd.settings.Manager.DefaultTimeoutStartSec = lib.mkDefault 30; + systemd.settings.Manager.DefaultTimeoutStopSec = lib.mkDefault 10; + systemd.services."user@".serviceConfig.TimeoutStopSec = lib.mkDefault 10; services.openssh.enable = true; diff --git a/shell.nix b/shell.nix index a1f6174..83b3391 100644 --- a/shell.nix +++ b/shell.nix @@ -12,7 +12,7 @@ mkShell.override { stdenv = stdenvNoCC; } { ]; packages = map lib.getBin [ - cloud-hypervisor + uvmPkgs.cloud-hypervisor-gpu virtiofsd crosvm # virtio-gpu npins