From 146430d8cd5031e10b82fd35354657b234196bb8 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 26 Sep 2025 06:09:41 -0300 Subject: [PATCH 01/81] Add '--' arg separator --- munix | 1 + 1 file changed, 1 insertion(+) diff --git a/munix b/munix index e828fa3..8249ce4 100755 --- a/munix +++ b/munix @@ -31,6 +31,7 @@ while [ "$#" -gt 0 ]; do --munix-bin-dir) SCRIPT_PATH="$2"; shift 2;; --muvm-bin-dir) MUVM_PATH="$2"; shift 2;; --passt-bin-dir) PASST_PATH="$2"; shift 2;; + --) shift 1; MICROVM_COMMAND+=("$@"); break;; -*) echo "munix: unknown option: $1" >&2; exit 1;; *) if [ "$MICROVM_CLOSURE" = "" ]; then From c4d462ea20d3039e72891f7e61f79e7402eec72a Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 3 Oct 2025 01:37:22 -0300 Subject: [PATCH 02/81] Update muvm --- munix | 9 ++++----- muvm | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/munix b/munix index 8249ce4..b15e3e0 100755 --- a/munix +++ b/munix @@ -85,9 +85,6 @@ if [ "$GPU" -eq 1 ]; then GPU_MODE=software fi MUVM_ARGS+=("--gpu-mode=$GPU_MODE") - if [ "$GPU_MODE" = "venus" ]; then - MUVM_ARGS+=("-e" "MESA_LOADER_DRIVER_OVERRIDE=zink") - fi else BWRAP_ARGS+=("--dir" "/dev/dri") MUVM_ARGS+=("--gpu-mode=software") @@ -151,9 +148,11 @@ exec bwrap --unshare-all --share-net \ --setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \ "${BWRAP_ARGS[@]}" \ muvm \ - -x /usr/bin/munix-init-root -X /usr/bin/munix-init-user --udevd-path="$MICROVM_CLOSURE/sw/bin/true" \ + -x /usr/bin/munix-init-root -X /usr/bin/munix-init-user \ "${MUVM_ARGS[@]}" \ - -e MICROVM_CLOSURE="$MICROVM_CLOSURE" -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \ + -e MUVM_UDEVD_PATH="$MICROVM_CLOSURE/sw/bin/true" \ + -e MICROVM_CLOSURE="$MICROVM_CLOSURE" \ + -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \ -i -t "${MICROVM_COMMAND[@]}" \ 11< <(cat < Date: Fri, 31 Oct 2025 04:44:28 -0300 Subject: [PATCH 03/81] Integrate systemd Not fully optimized yet, but shouldn't have any regressions --- .gitmodules | 5 +- flake.lock | 23 ++-- flake.nix | 296 +++++++++++++++++++++++++++++++++++++++--------- libkrun | 2 +- libkrunfw | 1 + munix | 18 +-- munix-init-root | 27 ----- munix-init-user | 4 - muvm | 2 +- 9 files changed, 270 insertions(+), 108 deletions(-) create mode 160000 libkrunfw delete mode 100755 munix-init-root delete mode 100755 munix-init-user diff --git a/.gitmodules b/.gitmodules index af2cfdd..a1452cd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,7 @@ url = https://github.com/valpackett/muvm [submodule "libkrun"] path = libkrun - url = https://github.com/valpackett/libkrun + url = https://github.com/containers/libkrun +[submodule "libkrunfw"] + path = libkrunfw + url = https://github.com/valpackett/libkrunfw diff --git a/flake.lock b/flake.lock index becdabc..d60e81e 100644 --- a/flake.lock +++ b/flake.lock @@ -38,21 +38,18 @@ }, "nixpkgs": { "locked": { - "lastModified": 1758078198, - "narHash": "sha256-60ojlXp42UZYTOAgsiKPZUab1Aa8pXTIo+rz0zoaynI=", - "ref": "val/tsvwswkqrrsr", - "rev": "1f0fc70eb049852a18a5203af2204bd9f5729f29", - "shallow": true, - "submodules": true, - "type": "git", - "url": "https://github.com/valpackett/nixpkgs" + "lastModified": 1761672384, + "narHash": "sha256-o9KF3DJL7g7iYMZq9SWgfS1BFlNbsm6xplRjVlOCkXI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "08dacfca559e1d7da38f3cf05f1f45ee9bfd213c", + "type": "github" }, "original": { - "ref": "val/tsvwswkqrrsr", - "shallow": true, - "submodules": true, - "type": "git", - "url": "https://github.com/valpackett/nixpkgs" + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" } }, "root": { diff --git a/flake.nix b/flake.nix index 9ab4655..62ecfee 100644 --- a/flake.nix +++ b/flake.nix @@ -1,37 +1,246 @@ { inputs = { self.submodules = true; - # nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - # https://github.com/NixOS/nixpkgs/pull/444133 - nixpkgs.url = "git+https://github.com/valpackett/nixpkgs?shallow=1&submodules=1&ref=val/tsvwswkqrrsr"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # nixpkgs.url = "git+https://github.com/valpackett/nixpkgs?shallow=1&submodules=1&ref=.."; flake-utils.url = "github:numtide/flake-utils"; virtwl.url = "git+https://github.com/valpackett/wayland-proxy-virtwl?shallow=1&submodules=1&ref=wip"; virtwl.inputs.nixpkgs.follows = "nixpkgs"; }; - outputs = {self, nixpkgs, flake-utils, virtwl, ...}: - flake-utils.lib.eachDefaultSystem (system: + outputs = { self, nixpkgs, flake-utils, virtwl, ... }: { + nixosModules.default = { pkgs, lib, utils, config, ... }: let + useTTY = { + TTYPath = "/dev/hvc0"; + StandardOutput = "tty"; + StandardInput = "tty"; + StandardError = "tty"; + }; + runtimeDir = "/run/vm-user"; + in { + boot.isContainer = true; + fileSystems."/".device = lib.mkDefault "/dev/sda"; # dummy + + # Disable unused things + environment.defaultPackages = lib.mkDefault [ ]; + documentation = { + enable = lib.mkDefault false; + doc.enable = lib.mkDefault false; + info.enable = lib.mkDefault false; + man.enable = lib.mkDefault false; + nixos.enable = lib.mkDefault false; + }; + 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; + + # Configure activation / systemd + boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd + system.etc.overlay.enable = true; # erofs + system.etc.overlay.mutable = false; + systemd.sysusers.enable = true; + services.userborn.enable = false; + services.udev.enable = lib.mkDefault true; + services.udev.packages = lib.mkDefault []; + environment.etc."resolv.conf".text = "# to be overridden with mount"; + environment.etc."machine-id".text = "# to be overridden with mount"; + environment.etc."systemd/system".source = lib.mkForce (utils.systemdUtils.lib.generateUnits { + type = "system"; + units = config.systemd.units; + upstreamUnits = [ + "sysinit.target" + "local-fs.target" + "nss-user-lookup.target" + "umount.target" + "shutdown.target" + "reboot.target" + "exit.target" + "final.target" + "systemd-exit.service" + "systemd-journald.socket" + "systemd-journald-audit.socket" + "systemd-journald-dev-log.socket" + "systemd-journald.service" + "systemd-sysusers.service" + "systemd-udevd-kernel.socket" + "systemd-udevd-control.socket" + "systemd-udevd.service" + "systemd-tmpfiles-setup.service" + "user.slice" + ]; + upstreamWants = ["multi-user.target.wants"]; + }); + + # systemd.package = pkgs.systemdMinimal; # no sysusers + systemd.defaultUnit = "microvm.target"; + systemd.targets.microvm = { + description = "Minimal microVM system"; + wants = ["systemd-journald.socket" "systemd-udevd.service" "dbus.socket"]; + unitConfig.AllowIsolate = "yes"; + }; + 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; + systemd.services.systemd-sysusers.serviceConfig = { + ExecStartPre = lib.mkForce []; + ExecStartPost = lib.mkForce []; + }; + systemd.services.microvm-nixos-activation = { + enable = true; + description = "NixOS Activation"; + wantedBy = ["local-fs.target"]; + before = ["systemd-tmpfiles-setup.service" "systemd-sysusers.service"]; + requires = ["systemd-tmpfiles-setup.service" "systemd-sysusers.service"]; + unitConfig.DefaultDependencies = false; + serviceConfig = { + Type = "oneshot"; + PassEnvironment = ["MICROVM_CLOSURE" "MICROVM_UID" "MICROVM_GID"]; + } // useTTY; + script = '' + PATH=$MICROVM_CLOSURE/sw/bin + cp /etc/resolv.conf /run/ + $MICROVM_CLOSURE/activate || true + mount --bind /run/resolv.conf /etc/resolv.conf + mount --bind /run/machine-id /etc/machine-id + chown 1337:1337 /run + ''; + }; + + # Configure user account + users.mutableUsers = false; + users.users.appvm = { + uid = 1337; + group = "appvm"; + isNormalUser = false; + isSystemUser = true; + home = "/home/appvm"; + description = "microVM User"; + extraGroups = [ "wheel" "video" "input" "systemd-journal" ]; + }; + users.groups.appvm.gid = 1337; + users.allowNoPasswordLogin = true; + systemd.tmpfiles.rules = ["d ${runtimeDir} 1337 1337 -"]; + + # Configure services + + systemd.services.muvm-remote = { + enable = true; + description = "microVM Application runner"; + onFailure = ["exit.target"]; + onSuccess = ["exit.target"]; + after = ["microvm-nixos-activation.service"]; + wantedBy = ["microvm.target"]; + serviceConfig = { + Type = "exec"; + PassEnvironment = ["TERM" "MUVM_REMOTE_CONFIG"]; # "KRUN_CONFIG"]; + Environment = ["XDG_RUNTIME_DIR=${runtimeDir}" "WAYLAND_DISPLAY=wayland-1" "PATH=/run/current-system/sw/bin"]; + User = "appvm"; + Group = "appvm"; + ExecStart = "/opt/bin/muvm-remote"; + ExecStopPost = ''+${pkgs.python3}/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"''; + } // useTTY; + }; + + systemd.services.muvm-configure-network = { + enable = true; + description = "microVM Network configuration"; + wantedBy = ["microvm.target"]; + serviceConfig.Type = "oneshot"; + serviceConfig.ExecStart = "/opt/bin/muvm-configure-network"; + }; + + systemd.sockets.muvm-pwbridge = { + enable = true; + description = "PipeWire cross-domain proxy socket"; + wantedBy = ["microvm.target"]; + partOf = ["muvm-pwbridge.service"]; + listenStreams = [ "${runtimeDir}/pipewire-0" ]; + socketConfig = { + SocketUser = "appvm"; + SocketGroup = "appvm"; + }; + }; + systemd.services.muvm-pwbridge = { + enable = true; + description = "PipeWire cross-domain proxy"; + requires = ["muvm-pwbridge.socket"]; + serviceConfig.Type = "exec"; + serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge"; + }; + + systemd.services.wait-for-udev = { + enable = true; + description = "Wait for device rules being applied"; + wantedBy = ["microvm.target"]; + requires = ["systemd-udevd.service"]; + after = ["systemd-udevd.service"]; + serviceConfig = { + Type = "oneshot"; + ExecStart = [ + "udevadm trigger --action=add" + "udevadm settle" + ]; + }; + }; + systemd.sockets.wayland-proxy-virtwl = { + enable = true; + description = "Wayland cross-domain proxy socket"; + wantedBy = ["microvm.target"]; + partOf = ["wayland-proxy-virtwl.service"]; + listenStreams = [ "${runtimeDir}/wayland-1" ]; + socketConfig = { + SocketUser = "appvm"; + SocketGroup = "appvm"; + FileDescriptorName = "wayland"; + }; + }; + systemd.services.wayland-proxy-virtwl = { + enable = true; + description = "Wayland cross-domain proxy"; + after = ["wait-for-udev.service"]; + requires = ["wayland-proxy-virtwl.socket" "wait-for-udev.service"]; + serviceConfig = { + ExecStart = "${virtwl.packages.x86_64-linux.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; + Environment = ["XDG_RUNTIME_DIR=${runtimeDir}"]; + User = "appvm"; + Group = "appvm"; + }; + }; + + hardware.graphics.enable = true; + hardware.graphics.package = self.packages.${pkgs.system}.mesa; + }; + } // flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; + config.allowUnfree = true; }; in { - packages.libkrunfw = pkgs.libkrunfw; - # packages.libkrunfw = (pkgs.libkrunfw.overrideAttrs { - # version = "4.10.0"; - # src = pkgs.fetchFromGitHub { - # owner = "containers"; - # repo = "libkrunfw"; - # tag = "v4.10.0"; - # hash = "sha256-mq2gw0+xL6qUZE/fk0vLT3PEpzPV8p+iwRFJHXVOMnk="; - # }; - # kernelSrc = pkgs.fetchurl { - # url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.34.tar.xz"; - # hash = "sha256-p/P+OB9n7KQXLptj77YaFL1/nhJ44DYD0P9ak/Jwwk0="; - # }; - # cargoHash = ""; - # }); + # packages.libkrunfw = pkgs.libkrunfw; + packages.libkrunfw = pkgs.libkrunfw.overrideAttrs (old: { + version = "5.0.0"; + src = ./libkrunfw; + # src = pkgs.fetchFromGitHub { + # owner = "containers"; + # repo = "libkrunfw"; + # tag = "v4.10.0"; + # hash = "sha256-mq2gw0+xL6qUZE/fk0vLT3PEpzPV8p+iwRFJHXVOMnk="; + # }; + kernelSrc = pkgs.fetchurl { + url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.44.tar.xz"; + hash = "sha256-tlAhDtMCeyJJadFIqjd0Uqmq065/KFGr7dMa3+8Wva4="; + }; + # buildInputs = old.buildInputs; + }); packages.libkrun = (pkgs.libkrun.override { withBlk = true; @@ -62,15 +271,9 @@ munixScript = (pkgs.writeScriptBin "munix" (builtins.readFile ./munix)).overrideAttrs(old: { buildCommand = "${old.buildCommand}\n patchShebangs $out"; }); - munixInitRootHook = (pkgs.writeScriptBin "munix-init-root" (builtins.readFile ./munix-init-root)).overrideAttrs(old: { - buildCommand = "${old.buildCommand}\n patchShebangs $out"; - }); - munixInitUserHook = (pkgs.writeScriptBin "munix-init-user" (builtins.readFile ./munix-init-user)).overrideAttrs(old: { - buildCommand = "${old.buildCommand}\n patchShebangs $out"; - }); in pkgs.symlinkJoin { name = "munix"; - paths = [ munixScript munixInitRootHook munixInitUserHook self.packages.${system}.muvm pkgs.passt pkgs.bubblewrap ]; + paths = [ munixScript self.packages.${system}.muvm pkgs.passt pkgs.bubblewrap ]; buildInputs = [ pkgs.makeWrapper ]; postBuild = '' wrapProgram $out/bin/munix --prefix PATH : $out/bin @@ -111,55 +314,40 @@ nixosConfigurations.testvm = nixpkgs.lib.nixosSystem { inherit system; modules = [ - { + self.nixosModules.default + ({ ... }: { system.stateVersion = "25.11"; - fileSystems."/".device = pkgs.lib.mkDefault "/dev/sda"; - boot.isContainer = true; - users.mutableUsers = false; - users.users.appvm = { - uid = 1337; - isNormalUser = true; - home = "/home/appvm"; - description = "microVM User"; - extraGroups = [ "wheel" "video" "input" ]; - }; - users.groups.appvm.gid = 1337; - users.allowNoPasswordLogin = true; - - hardware.graphics.enable = true; - hardware.graphics.package = self.packages.${system}.mesa; - system.replaceDependencies.replacements = [ - { - original = pkgs.mesa; - replacement = self.packages.${system}.mesa; - } - ]; + fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ]; environment.systemPackages = [ pkgs.fastfetch pkgs.htop - pkgs.radeontop virtwl.packages.x86_64-linux.proxy pkgs.wayland-utils pkgs.weston pkgs.waycheck pkgs.vulkan-tools - pkgs.glxinfo pkgs.glmark2 pkgs.mesa-demos pkgs.xorg.xeyes pkgs.xterm - pkgs.vkquake + # pkgs.vkquake # build broken: Program 'spirv-remap' not found + pkgs.veloren pkgs.kdePackages.kate - pkgs.adwaita-fonts pkgs.adwaita-icon-theme + pkgs.amberol + pkgs.bustle + pkgs.d-spy pkgs.gnome-text-editor pkgs.firefox pkgs.ffmpeg-full pkgs.mpv pkgs.libva-utils + pkgs.tailscale + pkgs.zerotierone + pkgs.localsend ]; - } + }) ]; }; diff --git a/libkrun b/libkrun index bd97a39..72b8b08 160000 --- a/libkrun +++ b/libkrun @@ -1 +1 @@ -Subproject commit bd97a39bfaa46147933beca7e16513b6820bb031 +Subproject commit 72b8b0870c3ecad0388f52150a68f79083fcc86f diff --git a/libkrunfw b/libkrunfw new file mode 160000 index 0000000..4b98077 --- /dev/null +++ b/libkrunfw @@ -0,0 +1 @@ +Subproject commit 4b98077866355ecfed46781ab6143d21127bf977 diff --git a/munix b/munix index b15e3e0..18354bb 100755 --- a/munix +++ b/munix @@ -136,21 +136,22 @@ exec bwrap --unshare-all --share-net \ --dev /dev --dir /dev/input --dev-bind /dev/kvm /dev/kvm \ --ro-bind "$MUVM_PATH" /run/munix/muvm \ --ro-bind "$PASST_PATH" /run/munix/passt \ - --ro-bind "$MICROVM_CLOSURE/sw/bin/env" /usr/bin/env \ - --ro-bind "$SCRIPT_PATH/munix-init-root" /usr/bin/munix-init-root \ - --ro-bind "$SCRIPT_PATH/munix-init-user" /usr/bin/munix-init-user \ + --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-remote \ + --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-configure-network \ + --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-pwbridge \ + --symlink "$MICROVM_CLOSURE/etc/systemd" /etc/systemd \ --ro-bind /nix/store /nix/store \ --ro-bind /run/systemd/resolve /run/systemd/resolve \ - --ro-bind /etc/resolv.conf /etc/resolv.conf \ --file 11 /etc/passwd \ --file 12 /etc/group \ + --file 13 /etc/resolv.conf \ --dir "$XDG_RUNTIME_DIR" \ --setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \ "${BWRAP_ARGS[@]}" \ muvm \ - -x /usr/bin/munix-init-root -X /usr/bin/munix-init-user \ + --custom-init-cmdline "$MICROVM_CLOSURE/sw/sbin/init --log-target=console" \ "${MUVM_ARGS[@]}" \ - -e MUVM_UDEVD_PATH="$MICROVM_CLOSURE/sw/bin/true" \ + -e container=munix \ -e MICROVM_CLOSURE="$MICROVM_CLOSURE" \ -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \ -i -t "${MICROVM_COMMAND[@]}" \ @@ -163,4 +164,7 @@ EOF munix:x:$MICROVM_GID: nogroup:x:65534: EOF -) +) \ + 13< /etc/resolv.conf + +# --log-level=debug diff --git a/munix-init-root b/munix-init-root deleted file mode 100755 index 71af6ea..0000000 --- a/munix-init-root +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -unset LANGUAGE LC_ALL LC_CTYPE LC_NUMERIC LC_COLLATE LC_TIME LC_MESSAGES LC_MONETARY LC_ADDRESS LC_IDENTIFICATION LC_MEASUREMENT LC_PAPER LC_TELEPHONE LC_NAME LANG 2>/dev/null # perl, calm down -PATH=$MICROVM_CLOSURE/sw/bin - -echo "=> Initializing microVM environment" - -mkdir /run/log - -# Prepare mounts for paths that activation writes to -mount -t tmpfs tmpfs /etc -cp /run/muvm-host/etc/resolv.conf /etc/resolv.conf -mount -t tmpfs tmpfs /usr/bin -cp /run/muvm-host/usr/bin/munix-init-user /usr/bin/munix-init-user -mount -t tmpfs tmpfs /dev/shm # tries to remount, fails on virtiofs due to unexpected opts - -$MICROVM_CLOSURE/activate >/run/log/activate.spam 2>&1 - -umount /dev/shm # restore the original virtiofs dax shm though - -chown $MICROVM_UID:$MICROVM_GID /run /dev # avoid "Detected unsafe path transition" -systemd-tmpfiles --create >/run/log/tmpfiles.spam 2>&1 - -systemd-machine-id-setup >/dev/null 2>&1 - -$MICROVM_CLOSURE/sw/lib/systemd/systemd-udevd >/run/log/udevd.spam 2>&1 & - -echo "=> microVM environment ready!" diff --git a/munix-init-user b/munix-init-user deleted file mode 100755 index 2e7b672..0000000 --- a/munix-init-user +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -PATH=$MICROVM_CLOSURE/sw/bin -mkdir -p ~/.var/log -wayland-proxy-virtwl --virtio-gpu >~/.var/log/wayland-proxy.log 2>&1 & diff --git a/muvm b/muvm index e2512d1..d6c7496 160000 --- a/muvm +++ b/muvm @@ -1 +1 @@ -Subproject commit e2512d119e2d3959ed06afd5f586af65de1fe0a7 +Subproject commit d6c7496fdb40d825f5fdd0777f1e613432c5a1b2 From 348cedab1a0cba95bb441178e55f1e1e2ef68777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 3 Nov 2025 15:43:47 +0100 Subject: [PATCH 04/81] Refactor testvm into reusable nixosModule for multiple architectures This extracts the testvm configuration into a shared nixosModules.testvm module that can be reused across different architectures. The module is now used by both testvm-x86_64 and testvm-aarch64 nixosConfigurations, eliminating code duplication. Additionally, nixosConfigurations have been moved to the top-level flake outputs to follow Nix conventions, rather than being nested inside eachDefaultSystem. The virtwl proxy reference now uses ${pkgs.system} instead of hardcoded x86_64-linux to support both architectures. --- flake.nix | 90 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/flake.nix b/flake.nix index 62ecfee..a24f2f0 100644 --- a/flake.nix +++ b/flake.nix @@ -9,6 +9,40 @@ }; outputs = { self, nixpkgs, flake-utils, virtwl, ... }: { + nixosModules.testvm = { pkgs, ... }: { + system.stateVersion = "25.11"; + + fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ]; + environment.systemPackages = [ + pkgs.fastfetch + pkgs.htop + virtwl.packages.${pkgs.system}.proxy + pkgs.wayland-utils + pkgs.weston + pkgs.waycheck + pkgs.vulkan-tools + pkgs.glmark2 + pkgs.mesa-demos + pkgs.xorg.xeyes + pkgs.xterm + # pkgs.vkquake # build broken: Program 'spirv-remap' not found + pkgs.veloren + pkgs.kdePackages.kate + pkgs.adwaita-icon-theme + pkgs.amberol + pkgs.bustle + pkgs.d-spy + pkgs.gnome-text-editor + pkgs.firefox + pkgs.ffmpeg-full + pkgs.mpv + pkgs.libva-utils + pkgs.tailscale + pkgs.zerotierone + pkgs.localsend + ]; + }; + nixosModules.default = { pkgs, lib, utils, config, ... }: let useTTY = { TTYPath = "/dev/hvc0"; @@ -217,6 +251,22 @@ hardware.graphics.enable = true; hardware.graphics.package = self.packages.${pkgs.system}.mesa; }; + + nixosConfigurations.testvm-x86_64 = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + self.nixosModules.default + self.nixosModules.testvm + ]; + }; + + nixosConfigurations.testvm-aarch64 = nixpkgs.lib.nixosSystem { + system = "aarch64-linux"; + modules = [ + self.nixosModules.default + self.nixosModules.testvm + ]; + }; } // flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { @@ -311,45 +361,5 @@ patches = old.patches ++ [ ./radvmmio.patch ]; # already merged to git }); - nixosConfigurations.testvm = nixpkgs.lib.nixosSystem { - inherit system; - modules = [ - self.nixosModules.default - ({ ... }: { - system.stateVersion = "25.11"; - - fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ]; - environment.systemPackages = [ - pkgs.fastfetch - pkgs.htop - virtwl.packages.x86_64-linux.proxy - pkgs.wayland-utils - pkgs.weston - pkgs.waycheck - pkgs.vulkan-tools - pkgs.glmark2 - pkgs.mesa-demos - pkgs.xorg.xeyes - pkgs.xterm - # pkgs.vkquake # build broken: Program 'spirv-remap' not found - pkgs.veloren - pkgs.kdePackages.kate - pkgs.adwaita-icon-theme - pkgs.amberol - pkgs.bustle - pkgs.d-spy - pkgs.gnome-text-editor - pkgs.firefox - pkgs.ffmpeg-full - pkgs.mpv - pkgs.libva-utils - pkgs.tailscale - pkgs.zerotierone - pkgs.localsend - ]; - }) - ]; - }; - }); } From 46edb4b7e9979be1f157819573061b0908c0b361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 3 Nov 2025 15:45:39 +0100 Subject: [PATCH 05/81] Add flake checks for CI/CD validation This adds a checks attribute to enable automated validation of all build outputs. Checks are included for all packages, devShells, and nixosConfigurations, with appropriate prefixes (package-, devShell-, nixos-) for clarity and organization. --- flake.nix | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/flake.nix b/flake.nix index a24f2f0..0bf8f5e 100644 --- a/flake.nix +++ b/flake.nix @@ -275,6 +275,16 @@ }; in { + checks = + (pkgs.lib.mapAttrs' (n: pkgs.lib.nameValuePair "package-${n}") self.packages.${system}) + // (pkgs.lib.mapAttrs' (n: pkgs.lib.nameValuePair "devShell-${n}") self.devShells.${system}) + // (pkgs.lib.optionalAttrs (system == "x86_64-linux") { + nixos-testvm = self.nixosConfigurations.testvm-x86_64.config.system.build.toplevel; + }) + // (pkgs.lib.optionalAttrs (system == "aarch64-linux") { + nixos-testvm = self.nixosConfigurations.testvm-aarch64.config.system.build.toplevel; + }); + # packages.libkrunfw = pkgs.libkrunfw; packages.libkrunfw = pkgs.libkrunfw.overrideAttrs (old: { version = "5.0.0"; From 6f7f3f24614600ea5d0915b0499310a9af027fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 3 Nov 2025 16:04:20 +0100 Subject: [PATCH 06/81] Restrict flake to Linux systems and enable allowUnfree for nixosConfigurations This project is Linux-specific (microVMs, libkrun, systemd, etc.), so the flake now only exports packages and checks for x86_64-linux and aarch64-linux systems. This prevents Darwin build failures. Additionally, nixosConfigurations now set allowUnfree = true to allow packages like zerotierone that have unfree licenses. --- flake.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 0bf8f5e..c151f0c 100644 --- a/flake.nix +++ b/flake.nix @@ -257,6 +257,7 @@ modules = [ self.nixosModules.default self.nixosModules.testvm + { nixpkgs.config.allowUnfree = true; } ]; }; @@ -265,9 +266,10 @@ modules = [ self.nixosModules.default self.nixosModules.testvm + { nixpkgs.config.allowUnfree = true; } ]; }; - } // flake-utils.lib.eachDefaultSystem (system: + } // flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system: let pkgs = import nixpkgs { inherit system; From 505e85b9c546f54421960fd13c545897960e8544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 3 Nov 2025 17:14:28 +0100 Subject: [PATCH 07/81] flake.nix: extract packages/devshells/modules into smaller files --- devShells/default.nix | 16 ++ flake.nix | 344 ++------------------------------- nixosModules/default.nix | 209 ++++++++++++++++++++ nixosModules/testvm.nix | 34 ++++ packages/libkrun/default.nix | 19 ++ packages/libkrunfw/default.nix | 19 ++ packages/mesa/default.nix | 16 ++ packages/munix/default.nix | 14 ++ packages/muvm/default.nix | 12 ++ 9 files changed, 360 insertions(+), 323 deletions(-) create mode 100644 devShells/default.nix create mode 100644 nixosModules/default.nix create mode 100644 nixosModules/testvm.nix create mode 100644 packages/libkrun/default.nix create mode 100644 packages/libkrunfw/default.nix create mode 100644 packages/mesa/default.nix create mode 100644 packages/munix/default.nix create mode 100644 packages/muvm/default.nix diff --git a/devShells/default.nix b/devShells/default.nix new file mode 100644 index 0000000..9cc518d --- /dev/null +++ b/devShells/default.nix @@ -0,0 +1,16 @@ +{ mkShell, lib, systemd, cargo, rust-analyzer, rustfmt, passt, bubblewrap, libkrun, muvm }: + +let + projects = [ libkrun muvm ]; +in mkShell { + MUVM_UDEVD_PATH = "${systemd}/lib/systemd/systemd-udevd"; + nativeBuildInputs = lib.concatMap (pkg: pkg.nativeBuildInputs) projects; + buildInputs = (lib.concatMap (pkg: pkg.buildInputs) projects) ++ [ + # virglrenderer + cargo + rust-analyzer + rustfmt + passt + bubblewrap + ]; +} diff --git a/flake.nix b/flake.nix index c151f0c..f6fa286 100644 --- a/flake.nix +++ b/flake.nix @@ -9,248 +9,8 @@ }; outputs = { self, nixpkgs, flake-utils, virtwl, ... }: { - nixosModules.testvm = { pkgs, ... }: { - system.stateVersion = "25.11"; - - fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ]; - environment.systemPackages = [ - pkgs.fastfetch - pkgs.htop - virtwl.packages.${pkgs.system}.proxy - pkgs.wayland-utils - pkgs.weston - pkgs.waycheck - pkgs.vulkan-tools - pkgs.glmark2 - pkgs.mesa-demos - pkgs.xorg.xeyes - pkgs.xterm - # pkgs.vkquake # build broken: Program 'spirv-remap' not found - pkgs.veloren - pkgs.kdePackages.kate - pkgs.adwaita-icon-theme - pkgs.amberol - pkgs.bustle - pkgs.d-spy - pkgs.gnome-text-editor - pkgs.firefox - pkgs.ffmpeg-full - pkgs.mpv - pkgs.libva-utils - pkgs.tailscale - pkgs.zerotierone - pkgs.localsend - ]; - }; - - nixosModules.default = { pkgs, lib, utils, config, ... }: let - useTTY = { - TTYPath = "/dev/hvc0"; - StandardOutput = "tty"; - StandardInput = "tty"; - StandardError = "tty"; - }; - runtimeDir = "/run/vm-user"; - in { - boot.isContainer = true; - fileSystems."/".device = lib.mkDefault "/dev/sda"; # dummy - - # Disable unused things - environment.defaultPackages = lib.mkDefault [ ]; - documentation = { - enable = lib.mkDefault false; - doc.enable = lib.mkDefault false; - info.enable = lib.mkDefault false; - man.enable = lib.mkDefault false; - nixos.enable = lib.mkDefault false; - }; - 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; - - # Configure activation / systemd - boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd - system.etc.overlay.enable = true; # erofs - system.etc.overlay.mutable = false; - systemd.sysusers.enable = true; - services.userborn.enable = false; - services.udev.enable = lib.mkDefault true; - services.udev.packages = lib.mkDefault []; - environment.etc."resolv.conf".text = "# to be overridden with mount"; - environment.etc."machine-id".text = "# to be overridden with mount"; - environment.etc."systemd/system".source = lib.mkForce (utils.systemdUtils.lib.generateUnits { - type = "system"; - units = config.systemd.units; - upstreamUnits = [ - "sysinit.target" - "local-fs.target" - "nss-user-lookup.target" - "umount.target" - "shutdown.target" - "reboot.target" - "exit.target" - "final.target" - "systemd-exit.service" - "systemd-journald.socket" - "systemd-journald-audit.socket" - "systemd-journald-dev-log.socket" - "systemd-journald.service" - "systemd-sysusers.service" - "systemd-udevd-kernel.socket" - "systemd-udevd-control.socket" - "systemd-udevd.service" - "systemd-tmpfiles-setup.service" - "user.slice" - ]; - upstreamWants = ["multi-user.target.wants"]; - }); - - # systemd.package = pkgs.systemdMinimal; # no sysusers - systemd.defaultUnit = "microvm.target"; - systemd.targets.microvm = { - description = "Minimal microVM system"; - wants = ["systemd-journald.socket" "systemd-udevd.service" "dbus.socket"]; - unitConfig.AllowIsolate = "yes"; - }; - 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; - systemd.services.systemd-sysusers.serviceConfig = { - ExecStartPre = lib.mkForce []; - ExecStartPost = lib.mkForce []; - }; - systemd.services.microvm-nixos-activation = { - enable = true; - description = "NixOS Activation"; - wantedBy = ["local-fs.target"]; - before = ["systemd-tmpfiles-setup.service" "systemd-sysusers.service"]; - requires = ["systemd-tmpfiles-setup.service" "systemd-sysusers.service"]; - unitConfig.DefaultDependencies = false; - serviceConfig = { - Type = "oneshot"; - PassEnvironment = ["MICROVM_CLOSURE" "MICROVM_UID" "MICROVM_GID"]; - } // useTTY; - script = '' - PATH=$MICROVM_CLOSURE/sw/bin - cp /etc/resolv.conf /run/ - $MICROVM_CLOSURE/activate || true - mount --bind /run/resolv.conf /etc/resolv.conf - mount --bind /run/machine-id /etc/machine-id - chown 1337:1337 /run - ''; - }; - - # Configure user account - users.mutableUsers = false; - users.users.appvm = { - uid = 1337; - group = "appvm"; - isNormalUser = false; - isSystemUser = true; - home = "/home/appvm"; - description = "microVM User"; - extraGroups = [ "wheel" "video" "input" "systemd-journal" ]; - }; - users.groups.appvm.gid = 1337; - users.allowNoPasswordLogin = true; - systemd.tmpfiles.rules = ["d ${runtimeDir} 1337 1337 -"]; - - # Configure services - - systemd.services.muvm-remote = { - enable = true; - description = "microVM Application runner"; - onFailure = ["exit.target"]; - onSuccess = ["exit.target"]; - after = ["microvm-nixos-activation.service"]; - wantedBy = ["microvm.target"]; - serviceConfig = { - Type = "exec"; - PassEnvironment = ["TERM" "MUVM_REMOTE_CONFIG"]; # "KRUN_CONFIG"]; - Environment = ["XDG_RUNTIME_DIR=${runtimeDir}" "WAYLAND_DISPLAY=wayland-1" "PATH=/run/current-system/sw/bin"]; - User = "appvm"; - Group = "appvm"; - ExecStart = "/opt/bin/muvm-remote"; - ExecStopPost = ''+${pkgs.python3}/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"''; - } // useTTY; - }; - - systemd.services.muvm-configure-network = { - enable = true; - description = "microVM Network configuration"; - wantedBy = ["microvm.target"]; - serviceConfig.Type = "oneshot"; - serviceConfig.ExecStart = "/opt/bin/muvm-configure-network"; - }; - - systemd.sockets.muvm-pwbridge = { - enable = true; - description = "PipeWire cross-domain proxy socket"; - wantedBy = ["microvm.target"]; - partOf = ["muvm-pwbridge.service"]; - listenStreams = [ "${runtimeDir}/pipewire-0" ]; - socketConfig = { - SocketUser = "appvm"; - SocketGroup = "appvm"; - }; - }; - systemd.services.muvm-pwbridge = { - enable = true; - description = "PipeWire cross-domain proxy"; - requires = ["muvm-pwbridge.socket"]; - serviceConfig.Type = "exec"; - serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge"; - }; - - systemd.services.wait-for-udev = { - enable = true; - description = "Wait for device rules being applied"; - wantedBy = ["microvm.target"]; - requires = ["systemd-udevd.service"]; - after = ["systemd-udevd.service"]; - serviceConfig = { - Type = "oneshot"; - ExecStart = [ - "udevadm trigger --action=add" - "udevadm settle" - ]; - }; - }; - systemd.sockets.wayland-proxy-virtwl = { - enable = true; - description = "Wayland cross-domain proxy socket"; - wantedBy = ["microvm.target"]; - partOf = ["wayland-proxy-virtwl.service"]; - listenStreams = [ "${runtimeDir}/wayland-1" ]; - socketConfig = { - SocketUser = "appvm"; - SocketGroup = "appvm"; - FileDescriptorName = "wayland"; - }; - }; - systemd.services.wayland-proxy-virtwl = { - enable = true; - description = "Wayland cross-domain proxy"; - after = ["wait-for-udev.service"]; - requires = ["wayland-proxy-virtwl.socket" "wait-for-udev.service"]; - serviceConfig = { - ExecStart = "${virtwl.packages.x86_64-linux.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; - Environment = ["XDG_RUNTIME_DIR=${runtimeDir}"]; - User = "appvm"; - Group = "appvm"; - }; - }; - - hardware.graphics.enable = true; - hardware.graphics.package = self.packages.${pkgs.system}.mesa; - }; + nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { inherit virtwl; }; + nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { inherit self virtwl; }; nixosConfigurations.testvm-x86_64 = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; @@ -287,91 +47,29 @@ nixos-testvm = self.nixosConfigurations.testvm-aarch64.config.system.build.toplevel; }); - # packages.libkrunfw = pkgs.libkrunfw; - packages.libkrunfw = pkgs.libkrunfw.overrideAttrs (old: { - version = "5.0.0"; - src = ./libkrunfw; - # src = pkgs.fetchFromGitHub { - # owner = "containers"; - # repo = "libkrunfw"; - # tag = "v4.10.0"; - # hash = "sha256-mq2gw0+xL6qUZE/fk0vLT3PEpzPV8p+iwRFJHXVOMnk="; - # }; - kernelSrc = pkgs.fetchurl { - url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.44.tar.xz"; - hash = "sha256-tlAhDtMCeyJJadFIqjd0Uqmq065/KFGr7dMa3+8Wva4="; - }; - # buildInputs = old.buildInputs; - }); + packages = { + # Packages support variant parameter: null (default), "sev", or "tdx" + # To build a variant: packages.libkrunfw.override { variant = "sev"; } + libkrunfw = pkgs.callPackage ./packages/libkrunfw { }; - packages.libkrun = (pkgs.libkrun.override { - withBlk = true; - withGpu = true; - withSound = true; - withNet = true; - libkrunfw = self.packages.${system}.libkrunfw; - }).overrideAttrs (old: { - src = ./libkrun; - cargoDeps = pkgs.rustPlatform.importCargoLock { - lockFile = ./libkrun/Cargo.lock; + libkrun = pkgs.callPackage ./packages/libkrun { + libkrunfw = self.packages.${system}.libkrunfw; }; - # mesonFlags = [ (pkgs.lib.mesonOption "decoders" "gles,vulkan,composer") ]; # no magma(?) - }); - packages.muvm = (pkgs.muvm.override { + mesa = pkgs.callPackage ./packages/mesa { }; + + muvm = pkgs.callPackage ./packages/muvm { + libkrun = self.packages.${system}.libkrun; + }; + + munix = pkgs.callPackage ./packages/munix { + muvm = self.packages.${system}.muvm; + }; + }; + + devShells.default = pkgs.callPackage ./devShells { libkrun = self.packages.${system}.libkrun; - }).overrideAttrs (old: { - postPatch = ""; # no more sysctl; udevd now takes the var anyway; XXX: fex - MUVM_UDEVD_PATH = "${pkgs.systemd}/lib/systemd/systemd-udevd"; - src = ./muvm; - cargoDeps = pkgs.rustPlatform.importCargoLock { - lockFile = ./muvm/Cargo.lock; - }; - }); - - packages.munix = let - munixScript = (pkgs.writeScriptBin "munix" (builtins.readFile ./munix)).overrideAttrs(old: { - buildCommand = "${old.buildCommand}\n patchShebangs $out"; - }); - in pkgs.symlinkJoin { - name = "munix"; - paths = [ munixScript self.packages.${system}.muvm pkgs.passt pkgs.bubblewrap ]; - buildInputs = [ pkgs.makeWrapper ]; - postBuild = '' - wrapProgram $out/bin/munix --prefix PATH : $out/bin - ''; + muvm = self.packages.${system}.muvm; }; - - devShells.default = let - projects = with self.packages.${system}; [ libkrun muvm ]; - in pkgs.mkShell { - MUVM_UDEVD_PATH = "${pkgs.systemd}/lib/systemd/systemd-udevd"; - nativeBuildInputs = pkgs.lib.concatMap (pkg: pkg.nativeBuildInputs) projects; - buildInputs = (pkgs.lib.concatMap (pkg: pkg.buildInputs) projects) ++ (with self.packages.${system}; [ - # virglrenderer - ]) ++ (with pkgs; [ - cargo - rust-analyzer - rustfmt - passt - bubblewrap - ]); - }; - - packages.mesa = (pkgs.mesa.override { - vulkanDrivers = [ - "amd" - "intel" - "microsoft-experimental" # removing this breaks the build - "nouveau" - "swrast" - "virtio" - "gfxstream" # probably not going to use this though - ]; - }).overrideAttrs (new: old: { - mesonFlags = old.mesonFlags ++ [ (pkgs.lib.mesonBool "amdgpu-virtio" true) ]; - patches = old.patches ++ [ ./radvmmio.patch ]; # already merged to git - }); - }); } diff --git a/nixosModules/default.nix b/nixosModules/default.nix new file mode 100644 index 0000000..bb70c2d --- /dev/null +++ b/nixosModules/default.nix @@ -0,0 +1,209 @@ +{ self, virtwl }: +{ pkgs, lib, utils, config, ... }: let + useTTY = { + TTYPath = "/dev/hvc0"; + StandardOutput = "tty"; + StandardInput = "tty"; + StandardError = "tty"; + }; + runtimeDir = "/run/vm-user"; +in { + boot.isContainer = true; + fileSystems."/".device = lib.mkDefault "/dev/sda"; # dummy + + # Disable unused things + environment.defaultPackages = lib.mkDefault [ ]; + documentation = { + enable = lib.mkDefault false; + doc.enable = lib.mkDefault false; + info.enable = lib.mkDefault false; + man.enable = lib.mkDefault false; + nixos.enable = lib.mkDefault false; + }; + 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; + + # Configure activation / systemd + boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd + system.etc.overlay.enable = true; # erofs + system.etc.overlay.mutable = false; + systemd.sysusers.enable = true; + services.userborn.enable = false; + services.udev.enable = lib.mkDefault true; + services.udev.packages = lib.mkDefault []; + environment.etc."resolv.conf".text = "# to be overridden with mount"; + environment.etc."machine-id".text = "# to be overridden with mount"; + environment.etc."systemd/system".source = lib.mkForce (utils.systemdUtils.lib.generateUnits { + type = "system"; + units = config.systemd.units; + upstreamUnits = [ + "sysinit.target" + "local-fs.target" + "nss-user-lookup.target" + "umount.target" + "shutdown.target" + "reboot.target" + "exit.target" + "final.target" + "systemd-exit.service" + "systemd-journald.socket" + "systemd-journald-audit.socket" + "systemd-journald-dev-log.socket" + "systemd-journald.service" + "systemd-sysusers.service" + "systemd-udevd-kernel.socket" + "systemd-udevd-control.socket" + "systemd-udevd.service" + "systemd-tmpfiles-setup.service" + "user.slice" + ]; + upstreamWants = ["multi-user.target.wants"]; + }); + + # systemd.package = pkgs.systemdMinimal; # no sysusers + systemd.defaultUnit = "microvm.target"; + systemd.targets.microvm = { + description = "Minimal microVM system"; + wants = ["systemd-journald.socket" "systemd-udevd.service" "dbus.socket"]; + unitConfig.AllowIsolate = "yes"; + }; + 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; + systemd.services.systemd-sysusers.serviceConfig = { + ExecStartPre = lib.mkForce []; + ExecStartPost = lib.mkForce []; + }; + systemd.services.microvm-nixos-activation = { + enable = true; + description = "NixOS Activation"; + wantedBy = ["local-fs.target"]; + before = ["systemd-tmpfiles-setup.service" "systemd-sysusers.service"]; + requires = ["systemd-tmpfiles-setup.service" "systemd-sysusers.service"]; + unitConfig.DefaultDependencies = false; + serviceConfig = { + Type = "oneshot"; + PassEnvironment = ["MICROVM_CLOSURE" "MICROVM_UID" "MICROVM_GID"]; + } // useTTY; + script = '' + PATH=$MICROVM_CLOSURE/sw/bin + cp /etc/resolv.conf /run/ + $MICROVM_CLOSURE/activate || true + mount --bind /run/resolv.conf /etc/resolv.conf + mount --bind /run/machine-id /etc/machine-id + chown 1337:1337 /run + ''; + }; + + # Configure user account + users.mutableUsers = false; + users.users.appvm = { + uid = 1337; + group = "appvm"; + isNormalUser = false; + isSystemUser = true; + home = "/home/appvm"; + description = "microVM User"; + extraGroups = [ "wheel" "video" "input" "systemd-journal" ]; + }; + users.groups.appvm.gid = 1337; + users.allowNoPasswordLogin = true; + systemd.tmpfiles.rules = ["d ${runtimeDir} 1337 1337 -"]; + + # Configure services + + systemd.services.muvm-remote = { + enable = true; + description = "microVM Application runner"; + onFailure = ["exit.target"]; + onSuccess = ["exit.target"]; + after = ["microvm-nixos-activation.service"]; + wantedBy = ["microvm.target"]; + serviceConfig = { + Type = "exec"; + PassEnvironment = ["TERM" "MUVM_REMOTE_CONFIG"]; # "KRUN_CONFIG"]; + Environment = ["XDG_RUNTIME_DIR=${runtimeDir}" "WAYLAND_DISPLAY=wayland-1" "PATH=/run/current-system/sw/bin"]; + User = "appvm"; + Group = "appvm"; + ExecStart = "/opt/bin/muvm-remote"; + ExecStopPost = ''+${pkgs.python3}/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"''; + } // useTTY; + }; + + systemd.services.muvm-configure-network = { + enable = true; + description = "microVM Network configuration"; + wantedBy = ["microvm.target"]; + serviceConfig.Type = "oneshot"; + serviceConfig.ExecStart = "/opt/bin/muvm-configure-network"; + }; + + systemd.sockets.muvm-pwbridge = { + enable = true; + description = "PipeWire cross-domain proxy socket"; + wantedBy = ["microvm.target"]; + partOf = ["muvm-pwbridge.service"]; + listenStreams = [ "${runtimeDir}/pipewire-0" ]; + socketConfig = { + SocketUser = "appvm"; + SocketGroup = "appvm"; + }; + }; + systemd.services.muvm-pwbridge = { + enable = true; + description = "PipeWire cross-domain proxy"; + requires = ["muvm-pwbridge.socket"]; + serviceConfig.Type = "exec"; + serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge"; + }; + + systemd.services.wait-for-udev = { + enable = true; + description = "Wait for device rules being applied"; + wantedBy = ["microvm.target"]; + requires = ["systemd-udevd.service"]; + after = ["systemd-udevd.service"]; + serviceConfig = { + Type = "oneshot"; + ExecStart = [ + "udevadm trigger --action=add" + "udevadm settle" + ]; + }; + }; + systemd.sockets.wayland-proxy-virtwl = { + enable = true; + description = "Wayland cross-domain proxy socket"; + wantedBy = ["microvm.target"]; + partOf = ["wayland-proxy-virtwl.service"]; + listenStreams = [ "${runtimeDir}/wayland-1" ]; + socketConfig = { + SocketUser = "appvm"; + SocketGroup = "appvm"; + FileDescriptorName = "wayland"; + }; + }; + systemd.services.wayland-proxy-virtwl = { + enable = true; + description = "Wayland cross-domain proxy"; + after = ["wait-for-udev.service"]; + requires = ["wayland-proxy-virtwl.socket" "wait-for-udev.service"]; + serviceConfig = { + ExecStart = "${virtwl.packages.x86_64-linux.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; + Environment = ["XDG_RUNTIME_DIR=${runtimeDir}"]; + User = "appvm"; + Group = "appvm"; + }; + }; + + hardware.graphics.enable = true; + hardware.graphics.package = self.packages.${pkgs.system}.mesa; +} diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix new file mode 100644 index 0000000..94465a9 --- /dev/null +++ b/nixosModules/testvm.nix @@ -0,0 +1,34 @@ +{ virtwl }: +{ pkgs, ... }: { + system.stateVersion = "25.11"; + + fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ]; + environment.systemPackages = [ + pkgs.fastfetch + pkgs.htop + virtwl.packages.${pkgs.system}.proxy + pkgs.wayland-utils + pkgs.weston + pkgs.waycheck + pkgs.vulkan-tools + pkgs.glmark2 + pkgs.mesa-demos + pkgs.xorg.xeyes + pkgs.xterm + # pkgs.vkquake # build broken: Program 'spirv-remap' not found + pkgs.veloren + pkgs.kdePackages.kate + pkgs.adwaita-icon-theme + pkgs.amberol + pkgs.bustle + pkgs.d-spy + pkgs.gnome-text-editor + pkgs.firefox + pkgs.ffmpeg-full + pkgs.mpv + pkgs.libva-utils + pkgs.tailscale + pkgs.zerotierone + pkgs.localsend + ]; +} diff --git a/packages/libkrun/default.nix b/packages/libkrun/default.nix new file mode 100644 index 0000000..0a2bf9d --- /dev/null +++ b/packages/libkrun/default.nix @@ -0,0 +1,19 @@ +{ libkrun, libkrunfw, rustPlatform, variant ? null, ... }: + +let + libkrunfw' = libkrunfw.override { inherit variant; }; +in +(libkrun.override { + withBlk = true; + withGpu = true; + withSound = true; + withNet = true; + inherit variant; + libkrunfw = libkrunfw'; +}).overrideAttrs (old: { + src = ../../libkrun; + cargoDeps = rustPlatform.importCargoLock { + lockFile = ../../libkrun/Cargo.lock; + }; + # mesonFlags = [ (lib.mesonOption "decoders" "gles,vulkan,composer") ]; # no magma(?) +}) diff --git a/packages/libkrunfw/default.nix b/packages/libkrunfw/default.nix new file mode 100644 index 0000000..8be0930 --- /dev/null +++ b/packages/libkrunfw/default.nix @@ -0,0 +1,19 @@ +{ libkrunfw, fetchurl, variant ? null, ... }: + +(libkrunfw.override { + inherit variant; +}).overrideAttrs (old: { + version = "5.0.0"; + src = ../../libkrunfw; + # src = fetchFromGitHub { + # owner = "containers"; + # repo = "libkrunfw"; + # tag = "v4.10.0"; + # hash = "sha256-mq2gw0+xL6qUZE/fk0vLT3PEpzPV8p+iwRFJHXVOMnk="; + # }; + kernelSrc = fetchurl { + url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.44.tar.xz"; + hash = "sha256-tlAhDtMCeyJJadFIqjd0Uqmq065/KFGr7dMa3+8Wva4="; + }; + # buildInputs = old.buildInputs; +}) diff --git a/packages/mesa/default.nix b/packages/mesa/default.nix new file mode 100644 index 0000000..51c2d79 --- /dev/null +++ b/packages/mesa/default.nix @@ -0,0 +1,16 @@ +{ mesa, lib }: + +(mesa.override { + vulkanDrivers = [ + "amd" + "intel" + "microsoft-experimental" # removing this breaks the build + "nouveau" + "swrast" + "virtio" + "gfxstream" # probably not going to use this though + ]; +}).overrideAttrs (new: old: { + mesonFlags = old.mesonFlags ++ [ (lib.mesonBool "amdgpu-virtio" true) ]; + patches = old.patches ++ [ ../../radvmmio.patch ]; # already merged to git +}) diff --git a/packages/munix/default.nix b/packages/munix/default.nix new file mode 100644 index 0000000..13aac3e --- /dev/null +++ b/packages/munix/default.nix @@ -0,0 +1,14 @@ +{ writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap }: + +let + munixScript = (writeScriptBin "munix" (builtins.readFile ../../munix)).overrideAttrs(old: { + buildCommand = "${old.buildCommand}\n patchShebangs $out"; + }); +in symlinkJoin { + name = "munix"; + paths = [ munixScript muvm passt bubblewrap ]; + buildInputs = [ makeWrapper ]; + postBuild = '' + wrapProgram $out/bin/munix --prefix PATH : $out/bin + ''; +} diff --git a/packages/muvm/default.nix b/packages/muvm/default.nix new file mode 100644 index 0000000..1fc8766 --- /dev/null +++ b/packages/muvm/default.nix @@ -0,0 +1,12 @@ +{ muvm, libkrun, systemd, rustPlatform }: + +(muvm.override { + libkrun = libkrun; +}).overrideAttrs (old: { + postPatch = ""; # no more sysctl; udevd now takes the var anyway; XXX: fex + MUVM_UDEVD_PATH = "${systemd}/lib/systemd/systemd-udevd"; + src = ../../muvm; + cargoDeps = rustPlatform.importCargoLock { + lockFile = ../../muvm/Cargo.lock; + }; +}) From b70a166e8b4bbd07f205e8efb6560a770ed8dfdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 3 Nov 2025 17:36:02 +0100 Subject: [PATCH 08/81] add binary cache --- flake.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/flake.nix b/flake.nix index f6fa286..c06aa16 100644 --- a/flake.nix +++ b/flake.nix @@ -1,4 +1,9 @@ { + nixConfig = { + extra-substituters = [ "https://cache.clan.lol" ]; + extra-trusted-public-keys = [ "cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28=" ]; + }; + inputs = { self.submodules = true; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; From c32be2f8c8ce80f071266947202a65cf6ceebaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 3 Nov 2025 17:56:25 +0100 Subject: [PATCH 09/81] README: add usage information --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 6a770f9..8c1563e 100644 --- a/README.md +++ b/README.md @@ -2,23 +2,55 @@ WIP: A microVM runner for NixOS systems with desktop integration, powered by muvm/libkrun. +## Quick Start + +**1. Build a test VM:** +```bash +nix build '.#nixosConfigurations.testvm-x86_64.config.system.build.toplevel' -o testvm +``` + +**2. Run the VM:** +```bash +nix run '.#munix' -- testvm +``` + +This will start an interactive bash session inside the microVM. + +**Run a specific command:** +```bash +nix run '.#munix' -- testvm fastfetch +``` + +## munix Options + +- `--uid UID`, `-u UID` - Set microVM UID (default: 1337) +- `--gid GID`, `-g GID` - Set microVM GID (default: 1337) +- `--no-gpu` - Disable GPU acceleration +- `--no-wayland` - Disable Wayland support +- `--no-pipewire` - Disable PipeWire audio +- `--x11` - Enable X11 support +- `--bind SRC DST` - Bind mount SRC to DST in the VM +- `--ro-bind SRC DST` - Read-only bind mount +- `--expose PATH` - Expose PATH in the VM at the same location +- `--ro-expose PATH` - Expose PATH read-only + +Example with options: +```bash +nix run '.#munix' -- --no-gpu --ro-expose /home/user/data testvm htop +``` + ## Development -Building an example closure: - -``` -nix build '.#nixosConfigurations.x86_64-linux.testvm.config.system.build.toplevel' -``` - -Running the nix build: - -``` -nix run '.#packages.x86_64-linux.munix' $(readlink result) -``` - Working on muvm & munix locally (not built into the nix store): -``` +```bash cd muvm && cargo build --locked --release -PATH=$PWD/muvm/target/release:$PATH ./munix $(readlink result) +PATH=$PWD/muvm/target/release:$PATH ./munix testvm ``` + +## Requirements + +- Linux system with KVM support (`/dev/kvm`) +- For GPU acceleration: Kernel 6.13+ with compatible drivers (amdgpu, msm) +- For Wayland: `XDG_RUNTIME_DIR` and `WAYLAND_DISPLAY` set +- For audio: PipeWire running with `PIPEWIRE_RUNTIME_DIR` or `XDG_RUNTIME_DIR` From 181e675f02f905640f83b12d261a6948a59d1a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 3 Nov 2025 17:57:08 +0100 Subject: [PATCH 10/81] munix: run realpath on nixos closure before running this is more convinent when using `nix build`. --- munix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/munix b/munix index 18354bb..4c5e9c4 100755 --- a/munix +++ b/munix @@ -48,6 +48,9 @@ if [ "$MICROVM_CLOSURE" = "" ]; then exit 1 fi +# Resolve symlinks automatically +MICROVM_CLOSURE=$(realpath "$MICROVM_CLOSURE") + if [ ${#MICROVM_COMMAND[@]} -eq 0 ]; then MICROVM_COMMAND=("bash") fi From f295e7b32af2d024afd9439c4e49e02407f42f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 3 Nov 2025 18:05:16 +0100 Subject: [PATCH 11/81] README: document pipewire not working --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c1563e..86e5096 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,7 @@ PATH=$PWD/muvm/target/release:$PATH ./munix testvm - Linux system with KVM support (`/dev/kvm`) - For GPU acceleration: Kernel 6.13+ with compatible drivers (amdgpu, msm) - For Wayland: `XDG_RUNTIME_DIR` and `WAYLAND_DISPLAY` set -- For audio: PipeWire running with `PIPEWIRE_RUNTIME_DIR` or `XDG_RUNTIME_DIR` + +## Known Issues + +- **PipeWire audio**: Not yet working. From 7c0825b46cc6b7a6ed6de3a1cb9de602368d9b1a Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 7 Nov 2025 06:11:10 -0300 Subject: [PATCH 12/81] Update muvm with PipeWire fix See https://github.com/AsahiLinux/muvm/pull/204 --- README.md | 2 -- muvm | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 86e5096..9411e79 100644 --- a/README.md +++ b/README.md @@ -55,5 +55,3 @@ PATH=$PWD/muvm/target/release:$PATH ./munix testvm - For Wayland: `XDG_RUNTIME_DIR` and `WAYLAND_DISPLAY` set ## Known Issues - -- **PipeWire audio**: Not yet working. diff --git a/muvm b/muvm index d6c7496..0d9c748 160000 --- a/muvm +++ b/muvm @@ -1 +1 @@ -Subproject commit d6c7496fdb40d825f5fdd0777f1e613432c5a1b2 +Subproject commit 0d9c74842b2f2d1f0e9df5e5da86a7aece4acc51 From d8d531aa00394fdcf7814a52b217e5d4812e5fe2 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 14 Nov 2025 02:09:04 -0300 Subject: [PATCH 13/81] Fix tmpfiles entry for runtime dir --- nixosModules/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index bb70c2d..fd79f61 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -116,7 +116,7 @@ in { }; users.groups.appvm.gid = 1337; users.allowNoPasswordLogin = true; - systemd.tmpfiles.rules = ["d ${runtimeDir} 1337 1337 -"]; + systemd.tmpfiles.rules = ["d ${runtimeDir} 0755 1337 1337 -"]; # Configure services From 8d178b21ef0fc35d7427236cde129446223dfbe4 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 14 Nov 2025 02:10:19 -0300 Subject: [PATCH 14/81] Temporarily fork libkrun to add systemd mount propagation fix --- .gitmodules | 2 +- libkrun | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index a1452cd..5420066 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/valpackett/muvm [submodule "libkrun"] path = libkrun - url = https://github.com/containers/libkrun + url = https://github.com/valpackett/libkrun [submodule "libkrunfw"] path = libkrunfw url = https://github.com/valpackett/libkrunfw diff --git a/libkrun b/libkrun index 72b8b08..e9b536b 160000 --- a/libkrun +++ b/libkrun @@ -1 +1 @@ -Subproject commit 72b8b0870c3ecad0388f52150a68f79083fcc86f +Subproject commit e9b536bd332c70fa730dd4ef70ff62e3702d4b70 From 8d2596d7cc11bfde21e15dc8ccb64ef525c99f45 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 14 Nov 2025 02:11:11 -0300 Subject: [PATCH 15/81] testvm: add a couple more test tools --- nixosModules/testvm.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix index 94465a9..6b0a075 100644 --- a/nixosModules/testvm.nix +++ b/nixosModules/testvm.nix @@ -27,8 +27,10 @@ pkgs.ffmpeg-full pkgs.mpv pkgs.libva-utils + pkgs.pipewire # cli pkgs.tailscale pkgs.zerotierone pkgs.localsend + pkgs.ashpd-demo ]; } From 030503f23baa0348563388ae43f295778373b37e Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 14 Nov 2025 06:17:34 -0300 Subject: [PATCH 16/81] Unhardcode x86_64 in virtwl package --- nixosModules/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index fd79f61..a69ba3d 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -197,7 +197,7 @@ in { after = ["wait-for-udev.service"]; requires = ["wayland-proxy-virtwl.socket" "wait-for-udev.service"]; serviceConfig = { - ExecStart = "${virtwl.packages.x86_64-linux.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; + ExecStart = "${virtwl.packages.${pkgs.system}.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; Environment = ["XDG_RUNTIME_DIR=${runtimeDir}"]; User = "appvm"; Group = "appvm"; From 9f0f835fce6efa3054a65448bfeefd62df2360cf Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 14 Nov 2025 06:20:44 -0300 Subject: [PATCH 17/81] Add sidebus integration --- devShells/default.nix | 3 +- flake.lock | 81 +++++++++++++++++++++++++++++++++++++- flake.nix | 8 +++- munix | 35 +++++++++++++--- nixosModules/default.nix | 34 +++++++++++++++- packages/munix/default.nix | 4 +- 6 files changed, 152 insertions(+), 13 deletions(-) diff --git a/devShells/default.nix b/devShells/default.nix index 9cc518d..7648228 100644 --- a/devShells/default.nix +++ b/devShells/default.nix @@ -1,4 +1,4 @@ -{ mkShell, lib, systemd, cargo, rust-analyzer, rustfmt, passt, bubblewrap, libkrun, muvm }: +{ mkShell, lib, systemd, cargo, rust-analyzer, rustfmt, passt, bubblewrap, libkrun, muvm, sidebus-broker }: let projects = [ libkrun muvm ]; @@ -12,5 +12,6 @@ in mkShell { rustfmt passt bubblewrap + sidebus-broker ]; } diff --git a/flake.lock b/flake.lock index d60e81e..ac9f9ce 100644 --- a/flake.lock +++ b/flake.lock @@ -22,6 +22,24 @@ "inputs": { "systems": "systems_2" }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, "locked": { "lastModified": 1710146030, "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", @@ -56,9 +74,55 @@ "inputs": { "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", + "sidebus": "sidebus", "virtwl": "virtwl" } }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "sidebus", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1763087910, + "narHash": "sha256-eB9Z1mWd1U6N61+F8qwDggX0ihM55s4E0CluwNukJRU=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "cf4a68749733d45c0420726596367acd708eb2e8", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "sidebus": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1763111523, + "narHash": "sha256-IVhoKXRTU46W94zfdx9QAJk806RXMfWhxG8bJBzIoyg=", + "ref": "main", + "rev": "fa0bf056d03d764ca742e89018a0e38d52db9473", + "shallow": true, + "type": "git", + "url": "https://git.clan.lol/clan/sidebus" + }, + "original": { + "ref": "main", + "shallow": true, + "type": "git", + "url": "https://git.clan.lol/clan/sidebus" + } + }, "systems": { "locked": { "lastModified": 1681028828, @@ -89,9 +153,24 @@ "type": "github" } }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "virtwl": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils_3", "nixpkgs": [ "nixpkgs" ] diff --git a/flake.nix b/flake.nix index c06aa16..5ac3b0f 100644 --- a/flake.nix +++ b/flake.nix @@ -11,11 +11,13 @@ flake-utils.url = "github:numtide/flake-utils"; virtwl.url = "git+https://github.com/valpackett/wayland-proxy-virtwl?shallow=1&submodules=1&ref=wip"; virtwl.inputs.nixpkgs.follows = "nixpkgs"; + sidebus.url = "git+https://git.clan.lol/clan/sidebus?shallow=1&ref=main"; + sidebus.inputs.nixpkgs.follows = "nixpkgs"; }; - outputs = { self, nixpkgs, flake-utils, virtwl, ... }: { + outputs = { self, nixpkgs, flake-utils, virtwl, sidebus, ... }: { nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { inherit virtwl; }; - nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { inherit self virtwl; }; + nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { inherit self virtwl sidebus; }; nixosConfigurations.testvm-x86_64 = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; @@ -69,12 +71,14 @@ munix = pkgs.callPackage ./packages/munix { muvm = self.packages.${system}.muvm; + sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; }; devShells.default = pkgs.callPackage ./devShells { libkrun = self.packages.${system}.libkrun; muvm = self.packages.${system}.muvm; + sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; }); } diff --git a/munix b/munix index 4c5e9c4..649f1ba 100755 --- a/munix +++ b/munix @@ -131,10 +131,37 @@ else unset DISPLAY XAUTHORITY fi -exec bwrap --unshare-all --share-net \ +declare -a BG_PIDS + +cleanup() { + for pid in "${BG_PIDS[@]}"; do + if kill -0 "$pid" 2>/dev/null; then + echo "Killing process $pid" + kill -INT "$pid" + wait "$pid" 2>/dev/null + fi + done + exit +} + +trap cleanup EXIT INT TERM + +HOST_RUNTIME_DIR="$XDG_RUNTIME_DIR/munix.$$" +mkdir -p $HOST_RUNTIME_DIR +rm $HOST_RUNTIME_DIR/* +sidebus-broker --guest-mountpoint /mnt/munix-doc-portal/doc --runtime-dir "$HOST_RUNTIME_DIR" --unix-path "$HOST_RUNTIME_DIR/port.sock" >/dev/null 2>&1 & +BG_PIDS+=("$!") +while [ ! -S "$HOST_RUNTIME_DIR/port.sock" ]; do sleep 0.1; done +BWRAP_ARGS+=( + --bind "$HOST_RUNTIME_DIR" /mnt/munix-doc-portal + --bind "$HOST_RUNTIME_DIR/port.sock" "$XDG_RUNTIME_DIR/krun/socket/port-50000" +) + +# do not 'exec' because of cleanup :) +bwrap --unshare-all --share-net \ --uid $MICROVM_UID --gid $MICROVM_GID \ --tmpfs / \ - --dir /run --dir /var --symlink /run /var/run --dir /tmp \ + --dir /run --dir /var --symlink /run /var/run --dir /tmp --dir /mnt \ --proc /proc --ro-bind /sys /sys \ --dev /dev --dir /dev/input --dev-bind /dev/kvm /dev/kvm \ --ro-bind "$MUVM_PATH" /run/munix/muvm \ @@ -152,7 +179,7 @@ exec bwrap --unshare-all --share-net \ --setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \ "${BWRAP_ARGS[@]}" \ muvm \ - --custom-init-cmdline "$MICROVM_CLOSURE/sw/sbin/init --log-target=console" \ + --custom-init-cmdline "$MICROVM_CLOSURE/sw/sbin/init --log-target=console systemd.set_credential=sidebus.port:50000" \ "${MUVM_ARGS[@]}" \ -e container=munix \ -e MICROVM_CLOSURE="$MICROVM_CLOSURE" \ @@ -169,5 +196,3 @@ nogroup:x:65534: EOF ) \ 13< /etc/resolv.conf - -# --log-level=debug diff --git a/nixosModules/default.nix b/nixosModules/default.nix index a69ba3d..03e3cea 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -1,4 +1,4 @@ -{ self, virtwl }: +{ self, virtwl, sidebus }: { pkgs, lib, utils, config, ... }: let useTTY = { TTYPath = "/dev/hvc0"; @@ -130,7 +130,12 @@ in { serviceConfig = { Type = "exec"; PassEnvironment = ["TERM" "MUVM_REMOTE_CONFIG"]; # "KRUN_CONFIG"]; - Environment = ["XDG_RUNTIME_DIR=${runtimeDir}" "WAYLAND_DISPLAY=wayland-1" "PATH=/run/current-system/sw/bin"]; + Environment = [ + "XDG_RUNTIME_DIR=${runtimeDir}" + "WAYLAND_DISPLAY=wayland-1" + "DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/sidebus.sock" + "PATH=/run/current-system/sw/bin" + ]; User = "appvm"; Group = "appvm"; ExecStart = "/opt/bin/muvm-remote"; @@ -179,6 +184,7 @@ in { ]; }; }; + systemd.sockets.wayland-proxy-virtwl = { enable = true; description = "Wayland cross-domain proxy socket"; @@ -204,6 +210,30 @@ in { }; }; + systemd.sockets.sidebus-agent = { + enable = true; + description = "D-Bus cross-domain proxy socket"; + wantedBy = ["microvm.target"]; + partOf = ["sidebus-agent.service"]; + listenStreams = [ "${runtimeDir}/sidebus.sock" ]; + socketConfig = { + SocketUser = "appvm"; + SocketGroup = "appvm"; + }; + }; + systemd.services.sidebus-agent = { + enable = true; + description = "D-Bus cross-domain proxy"; + requires = ["sidebus-agent.socket"]; + serviceConfig = { + ImportCredential = "sidebus.port"; + ExecStartPre = "/run/current-system/sw/bin/env"; + ExecStart = "${sidebus.packages.${pkgs.system}.sidebus-agent}/bin/sidebus-agent"; + User = "appvm"; + Group = "appvm"; + }; + }; + hardware.graphics.enable = true; hardware.graphics.package = self.packages.${pkgs.system}.mesa; } diff --git a/packages/munix/default.nix b/packages/munix/default.nix index 13aac3e..175b82c 100644 --- a/packages/munix/default.nix +++ b/packages/munix/default.nix @@ -1,4 +1,4 @@ -{ writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap }: +{ writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap, sidebus-broker }: let munixScript = (writeScriptBin "munix" (builtins.readFile ../../munix)).overrideAttrs(old: { @@ -6,7 +6,7 @@ let }); in symlinkJoin { name = "munix"; - paths = [ munixScript muvm passt bubblewrap ]; + paths = [ munixScript muvm passt bubblewrap sidebus-broker ]; buildInputs = [ makeWrapper ]; postBuild = '' wrapProgram $out/bin/munix --prefix PATH : $out/bin From 77028b04da9b1495d7d8e953b4bf4154dbd1145c Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 27 Nov 2025 20:33:07 -0300 Subject: [PATCH 18/81] Add error messages for missing muvm/passt --- munix | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/munix b/munix index 649f1ba..eeb7f83 100755 --- a/munix +++ b/munix @@ -48,6 +48,16 @@ if [ "$MICROVM_CLOSURE" = "" ]; then exit 1 fi +if [ "$MUVM_PATH" = "" ]; then + echo "munix: muvm not found, provide a --muvm-bin-dir or fix \$PATH" >&2 + exit 1 +fi + +if [ "$PASST_PATH" = "" ]; then + echo "munix: passt not found, provide a --passt-bin-dir or fix \$PATH" >&2 + exit 1 +fi + # Resolve symlinks automatically MICROVM_CLOSURE=$(realpath "$MICROVM_CLOSURE") From c164db06c1c7a2a4c61bac65b6de538795dffd73 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 27 Nov 2025 20:33:44 -0300 Subject: [PATCH 19/81] Fix msm driver name to msm_dpu --- munix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/munix b/munix index eeb7f83..e99d8e9 100755 --- a/munix +++ b/munix @@ -83,7 +83,7 @@ if [ "$GPU" -eq 1 ]; then driver_mod="$(readlink "$driver_link")" driver_name="${driver_mod##*/}" case "$driver_name" in - amdgpu|msm) # TODO: i915 + amdgpu|msm_dpu) # TODO: i915 echo "munix: ${card##*/} gpu driver is '$driver_name', using vdrm" >&2; GPU_MODE=drm break;; From 59137223a9e520f2a3ff7eff7d6f61c0ec2001e9 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 27 Nov 2025 21:59:05 -0300 Subject: [PATCH 20/81] Add fallback to our mesa package for non-NixOS hosts --- flake.nix | 1 + munix | 9 +++++++++ packages/munix/default.nix | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 5ac3b0f..7161105 100644 --- a/flake.nix +++ b/flake.nix @@ -70,6 +70,7 @@ }; munix = pkgs.callPackage ./packages/munix { + mesa = self.packages.${system}.mesa; muvm = self.packages.${system}.muvm; sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; diff --git a/munix b/munix index e99d8e9..2cf6257 100755 --- a/munix +++ b/munix @@ -15,6 +15,10 @@ PIPEWIRE=1 X11=0 export TMP=/tmp TMPDIR=/tmp TEMP=/tmp TEMPDIR=/tmp LC_ALL=C +if [ ! -e "$HOST_OPENGL_DRIVER" ]; then + HOST_OPENGL_DRIVER="$FALLBACK_OPENGL_DRIVER" +fi + while [ "$#" -gt 0 ]; do case "$1" in -u|--uid) MICROVM_UID="$2"; shift 2;; @@ -58,6 +62,11 @@ if [ "$PASST_PATH" = "" ]; then exit 1 fi +if [ ! -e "$HOST_OPENGL_DRIVER" ]; then + echo "munix: host graphics driver not found, provide a --host-opengl-driver" >&2 + exit 1 +fi + # Resolve symlinks automatically MICROVM_CLOSURE=$(realpath "$MICROVM_CLOSURE") diff --git a/packages/munix/default.nix b/packages/munix/default.nix index 175b82c..1cc1214 100644 --- a/packages/munix/default.nix +++ b/packages/munix/default.nix @@ -1,4 +1,4 @@ -{ writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap, sidebus-broker }: +{ writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap, sidebus-broker, mesa }: let munixScript = (writeScriptBin "munix" (builtins.readFile ../../munix)).overrideAttrs(old: { @@ -9,6 +9,6 @@ in symlinkJoin { paths = [ munixScript muvm passt bubblewrap sidebus-broker ]; buildInputs = [ makeWrapper ]; postBuild = '' - wrapProgram $out/bin/munix --prefix PATH : $out/bin + wrapProgram $out/bin/munix --prefix PATH : $out/bin --set FALLBACK_OPENGL_DRIVER ${mesa} ''; } From 23b91f1d6d2b1b117e06a371eb49585f31b73cc2 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 01:34:32 -0300 Subject: [PATCH 21/81] Update libkrun and libkrunfw to latest upstream (merged MS_SHARED and EROFS) --- .gitmodules | 4 ++-- libkrun | 2 +- libkrunfw | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitmodules b/.gitmodules index 5420066..b8605b1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/valpackett/muvm [submodule "libkrun"] path = libkrun - url = https://github.com/valpackett/libkrun + url = https://github.com/containers/libkrun [submodule "libkrunfw"] path = libkrunfw - url = https://github.com/valpackett/libkrunfw + url = https://github.com/containers/libkrunfw diff --git a/libkrun b/libkrun index e9b536b..8a14673 160000 --- a/libkrun +++ b/libkrun @@ -1 +1 @@ -Subproject commit e9b536bd332c70fa730dd4ef70ff62e3702d4b70 +Subproject commit 8a1467394189b51f5b0ec601352a0c3fd719d850 diff --git a/libkrunfw b/libkrunfw index 4b98077..8a8c33f 160000 --- a/libkrunfw +++ b/libkrunfw @@ -1 +1 @@ -Subproject commit 4b98077866355ecfed46781ab6143d21127bf977 +Subproject commit 8a8c33f24f72aa6ca017347dc2be45b6fa612af5 From 73fdfca030860812e8cb0f350d5bccecb96ebed1 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 01:53:29 -0300 Subject: [PATCH 22/81] Update muvm fork (proper pwbridge fix) --- muvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/muvm b/muvm index 0d9c748..3ec4c90 160000 --- a/muvm +++ b/muvm @@ -1 +1 @@ -Subproject commit 0d9c74842b2f2d1f0e9df5e5da86a7aece4acc51 +Subproject commit 3ec4c90bbfb6d0111f91b898a7f17deb562f4f92 From 87691a5747539f65332ec1bb940c11fa6201efa2 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 01:54:58 -0300 Subject: [PATCH 23/81] Do not wait for udev to settle Relying on udev to assign permissions to the virtgpu was very "proper" but really excessive. We have a simple static configuration, built into the kernel, so there are no dynamic shenanigans, we can always reliably just chmod/chown the permissions. Let's go back to faster booting. --- nixosModules/default.nix | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 03e3cea..a114b3a 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -170,21 +170,6 @@ in { serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge"; }; - systemd.services.wait-for-udev = { - enable = true; - description = "Wait for device rules being applied"; - wantedBy = ["microvm.target"]; - requires = ["systemd-udevd.service"]; - after = ["systemd-udevd.service"]; - serviceConfig = { - Type = "oneshot"; - ExecStart = [ - "udevadm trigger --action=add" - "udevadm settle" - ]; - }; - }; - systemd.sockets.wayland-proxy-virtwl = { enable = true; description = "Wayland cross-domain proxy socket"; @@ -200,9 +185,9 @@ in { systemd.services.wayland-proxy-virtwl = { enable = true; description = "Wayland cross-domain proxy"; - after = ["wait-for-udev.service"]; - requires = ["wayland-proxy-virtwl.socket" "wait-for-udev.service"]; + requires = ["wayland-proxy-virtwl.socket"]; serviceConfig = { + ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"; ExecStart = "${virtwl.packages.${pkgs.system}.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; Environment = ["XDG_RUNTIME_DIR=${runtimeDir}"]; User = "appvm"; From 83db4d6074f113c32a3b9ef26e9c04c2c2af0fbc Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 01:57:59 -0300 Subject: [PATCH 24/81] Remove leftover debug env invocation --- nixosModules/default.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index a114b3a..2693bd7 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -212,7 +212,6 @@ in { requires = ["sidebus-agent.socket"]; serviceConfig = { ImportCredential = "sidebus.port"; - ExecStartPre = "/run/current-system/sw/bin/env"; ExecStart = "${sidebus.packages.${pkgs.system}.sidebus-agent}/bin/sidebus-agent"; User = "appvm"; Group = "appvm"; From bd6307ded5400843ff71528741c72906dc0c1420 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 02:00:34 -0300 Subject: [PATCH 25/81] Symlink resolv.conf and machine-id instead of mounting Works fine after all. Let's avoid mount calls to boot faster. --- nixosModules/default.nix | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 2693bd7..9012eac 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -38,8 +38,8 @@ in { services.userborn.enable = false; services.udev.enable = lib.mkDefault true; services.udev.packages = lib.mkDefault []; - environment.etc."resolv.conf".text = "# to be overridden with mount"; - environment.etc."machine-id".text = "# to be overridden with mount"; + environment.etc."resolv.conf".source = "/run/resolv.conf"; + environment.etc."machine-id".source = "/run/machine-id"; environment.etc."systemd/system".source = lib.mkForce (utils.systemdUtils.lib.generateUnits { type = "system"; units = config.systemd.units; @@ -97,8 +97,6 @@ in { PATH=$MICROVM_CLOSURE/sw/bin cp /etc/resolv.conf /run/ $MICROVM_CLOSURE/activate || true - mount --bind /run/resolv.conf /etc/resolv.conf - mount --bind /run/machine-id /etc/machine-id chown 1337:1337 /run ''; }; From 93ba3d8fc41c5fef8ddf79fb4ab5a6dc708a87c4 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 02:06:09 -0300 Subject: [PATCH 26/81] Switch from sysusers to new "baked" userborn usage Avoid spending ~100ms of userspace boot time on unnecessary regeneration of entirely static /etc/{passwd,group,shadow}. This will be proposed to nixpkgs. --- nixosModules/default.nix | 46 ++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 9012eac..d3763a5 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -7,6 +7,29 @@ StandardError = "tty"; }; runtimeDir = "/run/vm-user"; + userbornConfig = { + groups = lib.mapAttrsToList (username: opts: { + inherit (opts) name gid members; + }) config.users.groups; + users = lib.mapAttrsToList (username: opts: { + inherit (opts) + name + uid + group + description + home + password + hashedPassword + hashedPasswordFile + initialPassword + initialHashedPassword + ; + isNormal = opts.isNormalUser; + shell = utils.toShellPath opts.shell; + }) (lib.filterAttrs (_: u: u.enable) config.users.users); + }; + userbornConfigJson = pkgs.writeText "userborn.json" (builtins.toJSON userbornConfig); + userbornResults = pkgs.runCommand "baked userborn" {} "mkdir -p $out; ${lib.getExe pkgs.userborn} ${userbornConfigJson} $out"; in { boot.isContainer = true; fileSystems."/".device = lib.mkDefault "/dev/sda"; # dummy @@ -34,8 +57,6 @@ in { boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd system.etc.overlay.enable = true; # erofs system.etc.overlay.mutable = false; - systemd.sysusers.enable = true; - services.userborn.enable = false; services.udev.enable = lib.mkDefault true; services.udev.packages = lib.mkDefault []; environment.etc."resolv.conf".source = "/run/resolv.conf"; @@ -57,7 +78,6 @@ in { "systemd-journald-audit.socket" "systemd-journald-dev-log.socket" "systemd-journald.service" - "systemd-sysusers.service" "systemd-udevd-kernel.socket" "systemd-udevd-control.socket" "systemd-udevd.service" @@ -67,7 +87,7 @@ in { upstreamWants = ["multi-user.target.wants"]; }); - # systemd.package = pkgs.systemdMinimal; # no sysusers + # systemd.package = pkgs.systemdMinimal; # no analyze systemd.defaultUnit = "microvm.target"; systemd.targets.microvm = { description = "Minimal microVM system"; @@ -78,16 +98,12 @@ in { 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; - systemd.services.systemd-sysusers.serviceConfig = { - ExecStartPre = lib.mkForce []; - ExecStartPost = lib.mkForce []; - }; systemd.services.microvm-nixos-activation = { enable = true; description = "NixOS Activation"; wantedBy = ["local-fs.target"]; - before = ["systemd-tmpfiles-setup.service" "systemd-sysusers.service"]; - requires = ["systemd-tmpfiles-setup.service" "systemd-sysusers.service"]; + before = ["systemd-tmpfiles-setup.service"]; + requires = ["systemd-tmpfiles-setup.service"]; unitConfig.DefaultDependencies = false; serviceConfig = { Type = "oneshot"; @@ -101,7 +117,15 @@ in { ''; }; - # Configure user account + # Configure user accounts + # The immutable overlay wants userborn or sysusers.. we just want baked-in files w/o running a service. + # So we can just run userborn at system closure build time! + systemd.sysusers.enable = false; + services.userborn.enable = true; + systemd.services.userborn.enable = false; + environment.etc."passwd" = lib.mkForce { source = "${userbornResults}/passwd"; mode = "0444"; }; + environment.etc."group" = lib.mkForce { source = "${userbornResults}/group"; mode = "0444"; }; + environment.etc."shadow" = lib.mkForce { source = "${userbornResults}/shadow"; mode = "0440"; }; users.mutableUsers = false; users.users.appvm = { uid = 1337; From 9b23ae80941b43e1438d4b01f222eaf0a8e1724c Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 00:01:24 -0300 Subject: [PATCH 27/81] gitignore testvm --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4812d58..9cb78cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ result +/testvm* .direnv/ From f831c9d958796275aa74d8fdc694481c53ceb0c6 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 01:19:10 -0300 Subject: [PATCH 28/81] Update nixpkgs / dependencies (mesa-25.3.0) Almost no need to touch mesa anymore.. except for the radeon virtio flag --- flake.lock | 6 +++--- nixosModules/testvm.nix | 2 +- packages/mesa/default.nix | 18 ++++++----------- radvmmio.patch | 42 --------------------------------------- 4 files changed, 10 insertions(+), 58 deletions(-) delete mode 100644 radvmmio.patch diff --git a/flake.lock b/flake.lock index ac9f9ce..0d3256f 100644 --- a/flake.lock +++ b/flake.lock @@ -56,11 +56,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1761672384, - "narHash": "sha256-o9KF3DJL7g7iYMZq9SWgfS1BFlNbsm6xplRjVlOCkXI=", + "lastModified": 1763966396, + "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "08dacfca559e1d7da38f3cf05f1f45ee9bfd213c", + "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", "type": "github" }, "original": { diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix index 6b0a075..a70f41a 100644 --- a/nixosModules/testvm.nix +++ b/nixosModules/testvm.nix @@ -16,7 +16,7 @@ pkgs.xorg.xeyes pkgs.xterm # pkgs.vkquake # build broken: Program 'spirv-remap' not found - pkgs.veloren + # pkgs.veloren # broken after update? pkgs.kdePackages.kate pkgs.adwaita-icon-theme pkgs.amberol diff --git a/packages/mesa/default.nix b/packages/mesa/default.nix index 51c2d79..d76f1b5 100644 --- a/packages/mesa/default.nix +++ b/packages/mesa/default.nix @@ -1,16 +1,10 @@ -{ mesa, lib }: +{ mesa, lib, stdenv }: (mesa.override { - vulkanDrivers = [ - "amd" - "intel" - "microsoft-experimental" # removing this breaks the build - "nouveau" - "swrast" - "virtio" - "gfxstream" # probably not going to use this though - ]; + # nothing currently }).overrideAttrs (new: old: { - mesonFlags = old.mesonFlags ++ [ (lib.mesonBool "amdgpu-virtio" true) ]; - patches = old.patches ++ [ ../../radvmmio.patch ]; # already merged to git + mesonFlags = old.mesonFlags ++ + lib.optionals stdenv.hostPlatform.isx86_64 [ (lib.mesonBool "amdgpu-virtio" true) ]; + # not that amdgpu can't be found on aarch64 but let's avoid rebuilds for now + # patches = old.patches ++ [ ]; }) diff --git a/radvmmio.patch b/radvmmio.patch deleted file mode 100644 index c3ff0bf..0000000 --- a/radvmmio.patch +++ /dev/null @@ -1,42 +0,0 @@ -From c2fd030644cf2074f9d2ffd155839b2e943473d0 Mon Sep 17 00:00:00 2001 -From: Val Packett -Date: Wed, 10 Sep 2025 15:44:41 -0300 -Subject: [PATCH] radv: detect platform:virtio-mmio devices for virtgpu native - context - -VirtIO devices can be configured as platform devices instead of PCI, -which is especially common in microVM projects like libkrun. - -Let's allow RADV to probe MMIO virtgpu devices. - -Signed-off-by: Val Packett ---- - src/amd/vulkan/radv_physical_device.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/src/amd/vulkan/radv_physical_device.c b/src/amd/vulkan/radv_physical_device.c -index 07b5b000b3ae..cd6f4c3488a1 100644 ---- a/src/amd/vulkan/radv_physical_device.c -+++ b/src/amd/vulkan/radv_physical_device.c -@@ -2507,14 +2507,15 @@ create_drm_physical_device(struct vk_instance *vk_instance, struct _drmDevice *d - #ifndef _WIN32 - bool supported_device = false; - -- if (!(device->available_nodes & (1 << DRM_NODE_RENDER)) || device->bustype != DRM_BUS_PCI) -+ if (!(device->available_nodes & (1 << DRM_NODE_RENDER))) - return VK_ERROR_INCOMPATIBLE_DRIVER; - - #ifdef HAVE_AMDGPU_VIRTIO -- supported_device |= device->deviceinfo.pci->vendor_id == VIRTGPU_PCI_VENDOR_ID; -+ supported_device |= device->bustype == DRM_BUS_PCI && device->deviceinfo.pci->vendor_id == VIRTGPU_PCI_VENDOR_ID; -+ supported_device |= device->bustype == DRM_BUS_PLATFORM; /* virtio-mmio */ - #endif - -- supported_device |= device->deviceinfo.pci->vendor_id == ATI_VENDOR_ID; -+ supported_device |= device->bustype == DRM_BUS_PCI && device->deviceinfo.pci->vendor_id == ATI_VENDOR_ID; - - if (!supported_device) - return VK_ERROR_INCOMPATIBLE_DRIVER; --- -2.50.1 - From a93ab32aeaf2ef888ffc00a3a98fa698a47a5de2 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 03:55:42 -0300 Subject: [PATCH 29/81] Pass MESA_LOADER_DRIVER_OVERRIDE to muvm-remote The Zink override for Venus in muvm was being eaten by systemd.. until now --- nixosModules/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index d3763a5..1a33eb2 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -151,7 +151,7 @@ in { wantedBy = ["microvm.target"]; serviceConfig = { Type = "exec"; - PassEnvironment = ["TERM" "MUVM_REMOTE_CONFIG"]; # "KRUN_CONFIG"]; + PassEnvironment = ["TERM" "MESA_LOADER_DRIVER_OVERRIDE" "MUVM_REMOTE_CONFIG"]; # "KRUN_CONFIG"]; Environment = [ "XDG_RUNTIME_DIR=${runtimeDir}" "WAYLAND_DISPLAY=wayland-1" From 3d2f6c47322819f806e104c3803fdc19b50156ca Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 28 Nov 2025 05:48:53 -0300 Subject: [PATCH 30/81] systemd: disable generate-shutdown-ramfs --- nixosModules/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 1a33eb2..fe11794 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -94,6 +94,7 @@ in { wants = ["systemd-journald.socket" "systemd-udevd.service" "dbus.socket"]; unitConfig.AllowIsolate = "yes"; }; + 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; From 0bd986f97fcdc0235bf1854998c16cd51336e256 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 4 Dec 2025 06:59:50 -0300 Subject: [PATCH 31/81] Introduce micro-activate (RIIR activate script + tiny bit of tmpfiles) Instead of interpreting all that shell and running actual tmpfiles, use a tiny stage before systemd that mounts a tmpfs at /run (preventing systemd from doing the same), populates it with NixOS symlinks and preserved resolv.conf, and mounts the immutable /etc overlay before passing control over to systemd. --- .gitignore | 2 + micro-activate.rs | 124 +++++++++++++++++++++++++++++++++++++ munix | 27 +++----- nixosModules/default.nix | 21 ------- packages/munix/default.nix | 17 ++++- 5 files changed, 151 insertions(+), 40 deletions(-) create mode 100644 micro-activate.rs diff --git a/.gitignore b/.gitignore index 9cb78cc..90acb92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ result /testvm* +/target +/micro-activate .direnv/ diff --git a/micro-activate.rs b/micro-activate.rs new file mode 100644 index 0000000..73d7e3c --- /dev/null +++ b/micro-activate.rs @@ -0,0 +1,124 @@ +use std::os::raw::{c_char, c_int, c_ulong, c_void}; +use std::os::unix::ffi::OsStrExt; +use std::os::unix::process::CommandExt; + +const MS_RDONLY: c_ulong = 0x01; +const MS_NOSUID: c_ulong = 0x02; +const MS_NODEV: c_ulong = 0x04; +const MS_RELATIME: c_ulong = 0x200000; +const MS_STRICTATIME: c_ulong = 0x1000000; + +unsafe extern "C" { + fn mount( + src: *const c_char, + target: *const c_char, + fstype: *const c_char, + flags: c_ulong, + data: *const c_void, + ) -> c_int; +} + +fn parse_tmpfiles_line(line: &str) -> Option<(&str, &str)> { + // NOTE: does not support actual whitespace inside quotes + // (that's not gonna appear in these files we parse) + let mut it = line + .split_whitespace() + .map(|s| s.trim_start_matches('\'').trim_end_matches('\'')); + let instr = it.next()?; + if !instr.starts_with('L') { + return None; + } + let src = it.next()?; + let _ = it.next()?; + let _ = it.next()?; + let _ = it.next()?; + let _ = it.next()?; + let dst = it.next()?; + Some((src, dst)) +} + +fn link_tmpfiles(contents: &[u8]) -> Result<(), std::io::Error> { + for (src, dst) in str::from_utf8(contents) + .unwrap() + .lines() + .flat_map(parse_tmpfiles_line) + { + std::os::unix::fs::symlink(dst, src)?; + } + Ok(()) +} + +fn main() -> Result<(), std::io::Error> { + let closure = std::env::var("MICROVM_CLOSURE").unwrap(); + + // systemd really wants /run to be a mountpoint and will mount a tmpfs on its own + // if it's not already a mountpoint. Well, it's correct: reaching into virtiofs + // (which is what not-mounting would entail) for /run stuff is not great. + // + // Let's preserve the fixed passed-in files and set up the NixOS symlinks in the new mount. + let resolv_conf = std::fs::read("/run/resolv.conf")?; + let machine_id = std::fs::read("/run/machine-id")?; + assert_eq!( + unsafe { + mount( + c"tmpfs".as_ptr(), + c"/run".as_ptr(), + c"tmpfs".as_ptr(), + MS_NOSUID | MS_NODEV | MS_STRICTATIME, + std::ptr::null(), + ) + }, + 0 + ); + std::fs::write("/run/resolv.conf", &resolv_conf)?; + std::fs::write("/run/machine-id", &machine_id)?; + std::os::unix::fs::symlink(&closure, "/run/current-system")?; + if let Ok(tmp_graphics) = + std::fs::read(format!("{closure}/etc/tmpfiles.d/graphics-driver.conf")) + { + link_tmpfiles(&tmp_graphics)?; + } else { + eprintln!("[micro-activate] Could not find the closure's graphics-driver.conf!"); + } + + // We need the /etc metadata overlay not just for abstract correctness, but even just to + // allow the regular user to run systemctl (it doesn't like passwd being owned by non-root).. + let metadata_img = std::fs::read_link(format!("{closure}/etc-metadata-image")) + .expect("The closure must use an immutable /etc overlay!"); + let basedir = std::fs::read_link(format!("{closure}/etc-basedir")) + .expect("The closure must use an immutable /etc overlay!"); + let overlay_opts = std::ffi::CString::new(format!( + "redirect_dir=on,metacopy=on,lowerdir=/run/etc.meta::{}", + basedir.display() + )) + .unwrap(); + std::fs::create_dir("/run/etc.meta")?; + std::fs::remove_file("/etc")?; + std::fs::create_dir("/etc")?; + unsafe { + assert_eq!( + mount( + metadata_img.as_os_str().as_bytes().as_ptr(), + c"/run/etc.meta".as_ptr(), + c"erofs".as_ptr(), + MS_RDONLY | MS_NODEV | MS_NOSUID, + std::ptr::null(), + ), + 0 + ); + assert_eq!( + mount( + c"overlay".as_ptr(), + c"/etc".as_ptr(), + c"overlay".as_ptr(), + MS_NODEV | MS_NOSUID | MS_RELATIME, + overlay_opts.as_ptr() as *const c_void, + ), + 0 + ); + } + + let mut args = std::env::args_os().skip(1); + let cmd = args.next().unwrap(); + Err(std::process::Command::new(cmd).args(args).exec()) +} diff --git a/munix b/munix index 2cf6257..4bdf635 100755 --- a/munix +++ b/munix @@ -180,38 +180,31 @@ BWRAP_ARGS+=( bwrap --unshare-all --share-net \ --uid $MICROVM_UID --gid $MICROVM_GID \ --tmpfs / \ - --dir /run --dir /var --symlink /run /var/run --dir /tmp --dir /mnt \ + --dir /run --dir /var --symlink /run /var/run --dir /tmp --dir /mnt --dir /bin --dir /usr/bin \ --proc /proc --ro-bind /sys /sys \ --dev /dev --dir /dev/input --dev-bind /dev/kvm /dev/kvm \ --ro-bind "$MUVM_PATH" /run/munix/muvm \ --ro-bind "$PASST_PATH" /run/munix/passt \ + --ro-bind "$SCRIPT_PATH/micro-activate" /opt/bin/micro-activate \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-remote \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-configure-network \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-pwbridge \ - --symlink "$MICROVM_CLOSURE/etc/systemd" /etc/systemd \ + --symlink "$MICROVM_CLOSURE/etc" /etc \ + --symlink "$MICROVM_CLOSURE/sw/bin/sh" /bin/sh \ + --symlink "$MICROVM_CLOSURE/sw/bin/env" /usr/bin/env \ + --symlink "$MICROVM_CLOSURE" /run/current-system \ --ro-bind /nix/store /nix/store \ - --ro-bind /run/systemd/resolve /run/systemd/resolve \ - --file 11 /etc/passwd \ - --file 12 /etc/group \ - --file 13 /etc/resolv.conf \ + --file 12 /run/machine-id \ + --file 13 /run/resolv.conf \ --dir "$XDG_RUNTIME_DIR" \ --setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \ "${BWRAP_ARGS[@]}" \ muvm \ - --custom-init-cmdline "$MICROVM_CLOSURE/sw/sbin/init --log-target=console systemd.set_credential=sidebus.port:50000" \ + --custom-init-cmdline "/opt/bin/micro-activate $MICROVM_CLOSURE/sw/sbin/init --log-target=console systemd.set_credential=sidebus.port:50000" \ "${MUVM_ARGS[@]}" \ -e container=munix \ -e MICROVM_CLOSURE="$MICROVM_CLOSURE" \ -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \ -i -t "${MICROVM_COMMAND[@]}" \ - 11< <(cat < Date: Thu, 4 Dec 2025 07:19:37 -0300 Subject: [PATCH 32/81] micro-activate: x86_64 type fix --- micro-activate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micro-activate.rs b/micro-activate.rs index 73d7e3c..bb2dd24 100644 --- a/micro-activate.rs +++ b/micro-activate.rs @@ -98,7 +98,7 @@ fn main() -> Result<(), std::io::Error> { unsafe { assert_eq!( mount( - metadata_img.as_os_str().as_bytes().as_ptr(), + metadata_img.as_os_str().as_bytes().as_ptr() as *const c_char, c"/run/etc.meta".as_ptr(), c"erofs".as_ptr(), MS_RDONLY | MS_NODEV | MS_NOSUID, From 7aa9f614da43c4b3e1f46328a34c63512a40ce54 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 4 Dec 2025 23:48:17 -0300 Subject: [PATCH 33/81] systemd: get udevd out of the critical chain We don't need to wait for it at all --- nixosModules/default.nix | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index c2307e1..ad397d9 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -80,7 +80,6 @@ in { "systemd-journald.service" "systemd-udevd-kernel.socket" "systemd-udevd-control.socket" - "systemd-udevd.service" "user.slice" ]; upstreamWants = ["multi-user.target.wants"]; @@ -98,6 +97,39 @@ in { 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; + systemd.services.systemd-udevd = { + # Redefine to remove the Before deps and get out of the critical chain + enable = true; + description = "Rule-based Manager for Device Events and Files"; + unitConfig.DefaultDependencies = "no"; + serviceConfig = { + CapabilityBoundingSet = "~CAP_SYS_TIME CAP_WAKE_ALARM"; + Delegate = ""; + DelegateSubgroup = "udev"; + Type = "notify-reload"; + OOMScoreAdjust = "-1000"; + Sockets = "systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd-varlink.socket"; + Restart = "always"; + RestartSec = "0"; + ExecStart = "${pkgs.systemd}/lib/systemd/systemd-udevd"; + FileDescriptorStoreMax = "512"; + FileDescriptorStorePreserve = "yes"; + KillMode = "mixed"; + TasksMax = "infinity"; + PrivateMounts = "yes"; + ProtectHostname = "yes"; + MemoryDenyWriteExecute = "yes"; + RestrictAddressFamilies = "AF_UNIX AF_NETLINK AF_INET AF_INET6"; + RestrictRealtime = "yes"; + RestrictSUIDSGID = "yes"; + SystemCallFilter = ["@system-service @module @raw-io bpf" "~@clock"]; + SystemCallErrorNumber = "EPERM"; + SystemCallArchitectures = "native"; + LockPersonality = "yes"; + IPAddressDeny = "any"; + WatchdogSec = "3min"; + }; + }; # Configure user accounts # The immutable overlay wants userborn or sysusers.. we just want baked-in files w/o running a service. From 6e8e4b9fdacd36c8cddd41c1ac22253f1703d97f Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 4 Dec 2025 07:24:51 -0300 Subject: [PATCH 34/81] nix: replace pkgs.system with pkgs.stdenv.hostPlatform.system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit evaluation warning: ‘system’ has been renamed to/replaced by ‘stdenv.hostPlatform.system’ --- nixosModules/default.nix | 7 ++++--- nixosModules/testvm.nix | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index ad397d9..9fd8d4c 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -30,6 +30,7 @@ }; userbornConfigJson = pkgs.writeText "userborn.json" (builtins.toJSON userbornConfig); userbornResults = pkgs.runCommand "baked userborn" {} "mkdir -p $out; ${lib.getExe pkgs.userborn} ${userbornConfigJson} $out"; + system = pkgs.stdenv.hostPlatform.system; in { boot.isContainer = true; fileSystems."/".device = lib.mkDefault "/dev/sda"; # dummy @@ -222,7 +223,7 @@ in { requires = ["wayland-proxy-virtwl.socket"]; serviceConfig = { ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"; - ExecStart = "${virtwl.packages.${pkgs.system}.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; + ExecStart = "${virtwl.packages.${system}.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; Environment = ["XDG_RUNTIME_DIR=${runtimeDir}"]; User = "appvm"; Group = "appvm"; @@ -246,12 +247,12 @@ in { requires = ["sidebus-agent.socket"]; serviceConfig = { ImportCredential = "sidebus.port"; - ExecStart = "${sidebus.packages.${pkgs.system}.sidebus-agent}/bin/sidebus-agent"; + ExecStart = "${sidebus.packages.${system}.sidebus-agent}/bin/sidebus-agent"; User = "appvm"; Group = "appvm"; }; }; hardware.graphics.enable = true; - hardware.graphics.package = self.packages.${pkgs.system}.mesa; + hardware.graphics.package = self.packages.${system}.mesa; } diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix index a70f41a..3f4e88a 100644 --- a/nixosModules/testvm.nix +++ b/nixosModules/testvm.nix @@ -6,7 +6,7 @@ environment.systemPackages = [ pkgs.fastfetch pkgs.htop - virtwl.packages.${pkgs.system}.proxy + virtwl.packages.${pkgs.stdenv.hostPlatform.system}.proxy pkgs.wayland-utils pkgs.weston pkgs.waycheck From 57b8ae34244f20a1928f409d6ca37afdc3291930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Fri, 28 Nov 2025 16:19:52 +0100 Subject: [PATCH 35/81] switch from git submodules to flake inputs --- .gitmodules | 9 ----- flake.lock | 60 ++++++++++++++++++++++++++++++++-- flake.nix | 25 +++++++++++--- libkrun | 1 - libkrunfw | 1 - muvm | 1 - packages/libkrun/default.nix | 7 ++-- packages/libkrunfw/default.nix | 11 ++----- packages/muvm/default.nix | 6 ++-- 9 files changed, 86 insertions(+), 35 deletions(-) delete mode 100644 .gitmodules delete mode 160000 libkrun delete mode 160000 libkrunfw delete mode 160000 muvm diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index b8605b1..0000000 --- a/.gitmodules +++ /dev/null @@ -1,9 +0,0 @@ -[submodule "muvm"] - path = muvm - url = https://github.com/valpackett/muvm -[submodule "libkrun"] - path = libkrun - url = https://github.com/containers/libkrun -[submodule "libkrunfw"] - path = libkrunfw - url = https://github.com/containers/libkrunfw diff --git a/flake.lock b/flake.lock index 0d3256f..cd293d4 100644 --- a/flake.lock +++ b/flake.lock @@ -54,13 +54,64 @@ "type": "github" } }, + "libkrun-src": { + "flake": false, + "locked": { + "lastModified": 1764170836, + "narHash": "sha256-95B4otgPNoAD2WtAVYFeIwvDWCMvVCSFj5V8Obuk+Ks=", + "owner": "containers", + "repo": "libkrun", + "rev": "8a1467394189b51f5b0ec601352a0c3fd719d850", + "type": "github" + }, + "original": { + "owner": "containers", + "repo": "libkrun", + "rev": "8a1467394189b51f5b0ec601352a0c3fd719d850", + "type": "github" + } + }, + "libkrunfw-src": { + "flake": false, + "locked": { + "lastModified": 1762790667, + "narHash": "sha256-tVQ0jGef8uJNo2L4Pmhy3ajVRKJ2Gs9oi44eOYAnmds=", + "owner": "containers", + "repo": "libkrunfw", + "rev": "8a8c33f24f72aa6ca017347dc2be45b6fa612af5", + "type": "github" + }, + "original": { + "owner": "containers", + "repo": "libkrunfw", + "rev": "8a8c33f24f72aa6ca017347dc2be45b6fa612af5", + "type": "github" + } + }, + "muvm-src": { + "flake": false, + "locked": { + "lastModified": 1763708092, + "narHash": "sha256-8K9XDnQbl/fh1Bsx1SwFuo5WVy5BztCjMPT6NW01lXQ=", + "owner": "valpackett", + "repo": "muvm", + "rev": "3ec4c90bbfb6d0111f91b898a7f17deb562f4f92", + "type": "github" + }, + "original": { + "owner": "valpackett", + "repo": "muvm", + "rev": "3ec4c90bbfb6d0111f91b898a7f17deb562f4f92", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1763966396, - "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", + "lastModified": 1764242076, + "narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", + "rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4", "type": "github" }, "original": { @@ -73,6 +124,9 @@ "root": { "inputs": { "flake-utils": "flake-utils", + "libkrun-src": "libkrun-src", + "libkrunfw-src": "libkrunfw-src", + "muvm-src": "muvm-src", "nixpkgs": "nixpkgs", "sidebus": "sidebus", "virtwl": "virtwl" diff --git a/flake.nix b/flake.nix index 7161105..7352d48 100644 --- a/flake.nix +++ b/flake.nix @@ -5,17 +5,30 @@ }; inputs = { - self.submodules = true; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - # nixpkgs.url = "git+https://github.com/valpackett/nixpkgs?shallow=1&submodules=1&ref=.."; flake-utils.url = "github:numtide/flake-utils"; virtwl.url = "git+https://github.com/valpackett/wayland-proxy-virtwl?shallow=1&submodules=1&ref=wip"; virtwl.inputs.nixpkgs.follows = "nixpkgs"; sidebus.url = "git+https://git.clan.lol/clan/sidebus?shallow=1&ref=main"; sidebus.inputs.nixpkgs.follows = "nixpkgs"; + + # Sources for packages (replaces git submodules) + # Pinned to the same commits as the original submodules + muvm-src = { + url = "github:valpackett/muvm/3ec4c90bbfb6d0111f91b898a7f17deb562f4f92"; + flake = false; + }; + libkrun-src = { + url = "github:containers/libkrun/8a1467394189b51f5b0ec601352a0c3fd719d850"; + flake = false; + }; + libkrunfw-src = { + url = "github:containers/libkrunfw/8a8c33f24f72aa6ca017347dc2be45b6fa612af5"; + flake = false; + }; }; - outputs = { self, nixpkgs, flake-utils, virtwl, sidebus, ... }: { + outputs = { self, nixpkgs, flake-utils, virtwl, sidebus, muvm-src, libkrun-src, libkrunfw-src, ... }: { nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { inherit virtwl; }; nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { inherit self virtwl sidebus; }; @@ -57,16 +70,20 @@ packages = { # Packages support variant parameter: null (default), "sev", or "tdx" # To build a variant: packages.libkrunfw.override { variant = "sev"; } - libkrunfw = pkgs.callPackage ./packages/libkrunfw { }; + libkrunfw = pkgs.callPackage ./packages/libkrunfw { + libkrunfw-src = libkrunfw-src; + }; libkrun = pkgs.callPackage ./packages/libkrun { libkrunfw = self.packages.${system}.libkrunfw; + libkrun-src = libkrun-src; }; mesa = pkgs.callPackage ./packages/mesa { }; muvm = pkgs.callPackage ./packages/muvm { libkrun = self.packages.${system}.libkrun; + muvm-src = muvm-src; }; munix = pkgs.callPackage ./packages/munix { diff --git a/libkrun b/libkrun deleted file mode 160000 index 8a14673..0000000 --- a/libkrun +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8a1467394189b51f5b0ec601352a0c3fd719d850 diff --git a/libkrunfw b/libkrunfw deleted file mode 160000 index 8a8c33f..0000000 --- a/libkrunfw +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8a8c33f24f72aa6ca017347dc2be45b6fa612af5 diff --git a/muvm b/muvm deleted file mode 160000 index 3ec4c90..0000000 --- a/muvm +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3ec4c90bbfb6d0111f91b898a7f17deb562f4f92 diff --git a/packages/libkrun/default.nix b/packages/libkrun/default.nix index 0a2bf9d..dde2c4c 100644 --- a/packages/libkrun/default.nix +++ b/packages/libkrun/default.nix @@ -1,4 +1,4 @@ -{ libkrun, libkrunfw, rustPlatform, variant ? null, ... }: +{ libkrun, libkrunfw, libkrun-src, rustPlatform, variant ? null, ... }: let libkrunfw' = libkrunfw.override { inherit variant; }; @@ -11,9 +11,8 @@ in inherit variant; libkrunfw = libkrunfw'; }).overrideAttrs (old: { - src = ../../libkrun; + src = libkrun-src; cargoDeps = rustPlatform.importCargoLock { - lockFile = ../../libkrun/Cargo.lock; + lockFile = "${libkrun-src}/Cargo.lock"; }; - # mesonFlags = [ (lib.mesonOption "decoders" "gles,vulkan,composer") ]; # no magma(?) }) diff --git a/packages/libkrunfw/default.nix b/packages/libkrunfw/default.nix index 8be0930..668e016 100644 --- a/packages/libkrunfw/default.nix +++ b/packages/libkrunfw/default.nix @@ -1,19 +1,12 @@ -{ libkrunfw, fetchurl, variant ? null, ... }: +{ libkrunfw, libkrunfw-src, fetchurl, variant ? null, ... }: (libkrunfw.override { inherit variant; }).overrideAttrs (old: { version = "5.0.0"; - src = ../../libkrunfw; - # src = fetchFromGitHub { - # owner = "containers"; - # repo = "libkrunfw"; - # tag = "v4.10.0"; - # hash = "sha256-mq2gw0+xL6qUZE/fk0vLT3PEpzPV8p+iwRFJHXVOMnk="; - # }; + src = libkrunfw-src; kernelSrc = fetchurl { url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.44.tar.xz"; hash = "sha256-tlAhDtMCeyJJadFIqjd0Uqmq065/KFGr7dMa3+8Wva4="; }; - # buildInputs = old.buildInputs; }) diff --git a/packages/muvm/default.nix b/packages/muvm/default.nix index 1fc8766..dd678d8 100644 --- a/packages/muvm/default.nix +++ b/packages/muvm/default.nix @@ -1,12 +1,12 @@ -{ muvm, libkrun, systemd, rustPlatform }: +{ muvm, libkrun, muvm-src, systemd, rustPlatform }: (muvm.override { libkrun = libkrun; }).overrideAttrs (old: { postPatch = ""; # no more sysctl; udevd now takes the var anyway; XXX: fex MUVM_UDEVD_PATH = "${systemd}/lib/systemd/systemd-udevd"; - src = ../../muvm; + src = muvm-src; cargoDeps = rustPlatform.importCargoLock { - lockFile = ../../muvm/Cargo.lock; + lockFile = "${muvm-src}/Cargo.lock"; }; }) From c7ec9872cae1efcb4278445add219378e3d3e534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Fri, 28 Nov 2025 17:03:44 +0100 Subject: [PATCH 36/81] fix: disable systemd-resolved (not needed, DNS comes from host via passt) --- nixosModules/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 9fd8d4c..9d4f6f2 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -60,6 +60,7 @@ in { system.etc.overlay.mutable = false; services.udev.enable = lib.mkDefault true; services.udev.packages = lib.mkDefault []; + services.resolved.enable = false; environment.etc."resolv.conf".source = "/run/resolv.conf"; environment.etc."machine-id".source = "/run/machine-id"; environment.etc."systemd/system".source = lib.mkForce (utils.systemdUtils.lib.generateUnits { From 5f1783b9bbf8458a3fe485cc26afe51513e20372 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 4 Dec 2025 23:52:31 -0300 Subject: [PATCH 37/81] nix: update flake comment to mention --override-input --- flake.nix | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 7352d48..5f76bec 100644 --- a/flake.nix +++ b/flake.nix @@ -12,8 +12,7 @@ sidebus.url = "git+https://git.clan.lol/clan/sidebus?shallow=1&ref=main"; sidebus.inputs.nixpkgs.follows = "nixpkgs"; - # Sources for packages (replaces git submodules) - # Pinned to the same commits as the original submodules + # To override with local checkouts during development, use the --override-input CLI flag! muvm-src = { url = "github:valpackett/muvm/3ec4c90bbfb6d0111f91b898a7f17deb562f4f92"; flake = false; From d2070a1becbc20f2582f969ec44c06399c0db657 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 5 Dec 2025 00:08:54 -0300 Subject: [PATCH 38/81] nix: set system.switch.enable = false Will be required by the upstreamed static userborn, and shouldn've been part of the initial research anyway :) --- nixosModules/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 9d4f6f2..3817d65 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -58,6 +58,7 @@ in { boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd system.etc.overlay.enable = true; # erofs system.etc.overlay.mutable = false; + system.switch.enable = false; services.udev.enable = lib.mkDefault true; services.udev.packages = lib.mkDefault []; services.resolved.enable = false; From 2a98ae83af5b68c752ee65e99480e3273ac033cd Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 5 Dec 2025 00:09:44 -0300 Subject: [PATCH 39/81] nix: update libkrun (aarch64 fixes) --- flake.lock | 8 ++++---- flake.nix | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/flake.lock b/flake.lock index cd293d4..307bc62 100644 --- a/flake.lock +++ b/flake.lock @@ -57,17 +57,17 @@ "libkrun-src": { "flake": false, "locked": { - "lastModified": 1764170836, - "narHash": "sha256-95B4otgPNoAD2WtAVYFeIwvDWCMvVCSFj5V8Obuk+Ks=", + "lastModified": 1764837222, + "narHash": "sha256-Q4uFc3gvo6AuN1fAuUWU8k/+idOuDEj8Pkhm80wE798=", "owner": "containers", "repo": "libkrun", - "rev": "8a1467394189b51f5b0ec601352a0c3fd719d850", + "rev": "b250ee6fff7d959da3d55bb62ffe09d87248651c", "type": "github" }, "original": { "owner": "containers", "repo": "libkrun", - "rev": "8a1467394189b51f5b0ec601352a0c3fd719d850", + "rev": "b250ee6fff7d959da3d55bb62ffe09d87248651c", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 5f76bec..8e1d432 100644 --- a/flake.nix +++ b/flake.nix @@ -18,7 +18,7 @@ flake = false; }; libkrun-src = { - url = "github:containers/libkrun/8a1467394189b51f5b0ec601352a0c3fd719d850"; + url = "github:containers/libkrun/b250ee6fff7d959da3d55bb62ffe09d87248651c"; flake = false; }; libkrunfw-src = { From fd771dd95fbd8a5bd66c0b1d3499d339ca5b251f Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 5 Dec 2025 00:31:24 -0300 Subject: [PATCH 40/81] munix: make the default command overridable via env This is convenient for app launch wrappers that would want to set their own default command but still allow overriding it --- munix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/munix b/munix index 4bdf635..18d3013 100755 --- a/munix +++ b/munix @@ -3,6 +3,7 @@ SCRIPT_PATH=$(dirname $(realpath -s $0)) MUVM_PATH=$(dirname $(which muvm)) PASST_PATH=$(dirname $(which passt)) HOST_OPENGL_DRIVER=/run/opengl-driver +: "${MICROVM_DEFAULT_COMMAND:=bash}" MICROVM_CLOSURE= MICROVM_COMMAND=() MICROVM_UID=1337 @@ -71,7 +72,7 @@ fi MICROVM_CLOSURE=$(realpath "$MICROVM_CLOSURE") if [ ${#MICROVM_COMMAND[@]} -eq 0 ]; then - MICROVM_COMMAND=("bash") + MICROVM_COMMAND=("$MICROVM_DEFAULT_COMMAND") fi if [ "$GPU" -eq 1 ]; then From 73d2501781f74075396df7dc4f37b49b696ff17d Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 5 Dec 2025 04:06:37 -0300 Subject: [PATCH 41/81] systemd: use sockets.target This allows using normal nix-managed services that register sockets for lazy activation. Also brings in some red errors about starting services that we don't have, but that will be fixed --- nixosModules/default.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 3817d65..7ae6754 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -72,6 +72,7 @@ in { "local-fs.target" "nss-user-lookup.target" "umount.target" + "sockets.target" "shutdown.target" "reboot.target" "exit.target" @@ -163,6 +164,8 @@ in { description = "microVM Application runner"; onFailure = ["exit.target"]; onSuccess = ["exit.target"]; + wants = ["sockets.target"]; + after = ["sockets.target"]; wantedBy = ["microvm.target"]; serviceConfig = { Type = "exec"; From bfc037e615298a83bd6ae9287cd137ee703fa4ad Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 5 Dec 2025 04:08:27 -0300 Subject: [PATCH 42/81] systemd: hoist XDG_RUNTIME_DIR up to manager defaults In some cases it might be needed in arbitrary services.. such as mpd needing PipeWire to play sound into --- nixosModules/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 7ae6754..101d4ce 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -159,6 +159,8 @@ in { # Configure services + systemd.settings.Manager.DefaultEnvironment = "XDG_RUNTIME_DIR=${runtimeDir}"; + systemd.services.muvm-remote = { enable = true; description = "microVM Application runner"; @@ -171,7 +173,6 @@ in { Type = "exec"; PassEnvironment = ["TERM" "MESA_LOADER_DRIVER_OVERRIDE" "MUVM_REMOTE_CONFIG"]; # "KRUN_CONFIG"]; Environment = [ - "XDG_RUNTIME_DIR=${runtimeDir}" "WAYLAND_DISPLAY=wayland-1" "DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/sidebus.sock" "PATH=/run/current-system/sw/bin" @@ -229,7 +230,6 @@ in { serviceConfig = { ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"; ExecStart = "${virtwl.packages.${system}.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; - Environment = ["XDG_RUNTIME_DIR=${runtimeDir}"]; User = "appvm"; Group = "appvm"; }; From cc135479efdf0a1b3b48e5c92ea984781a2fe1b6 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 5 Dec 2025 04:09:32 -0300 Subject: [PATCH 43/81] systemd: chown XDG_RUNTIME_DIR again This was temporarily gone due to refactorings (throwing out tmpfiles). --- nixosModules/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 101d4ce..5866fb0 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -179,6 +179,7 @@ in { ]; User = "appvm"; Group = "appvm"; + ExecStartPre = "+/run/current-system/sw/bin/chown appvm:appvm ${runtimeDir}"; ExecStart = "/opt/bin/muvm-remote"; ExecStopPost = ''+${pkgs.python3}/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"''; } // useTTY; From bfb8352c55b2b250fad93944fb354c9ca77482fd Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 5 Dec 2025 04:10:24 -0300 Subject: [PATCH 44/81] nix: update sidebus (unhardcode user/group IDs) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 307bc62..818e0f7 100644 --- a/flake.lock +++ b/flake.lock @@ -162,10 +162,10 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1763111523, - "narHash": "sha256-IVhoKXRTU46W94zfdx9QAJk806RXMfWhxG8bJBzIoyg=", + "lastModified": 1764921491, + "narHash": "sha256-bGBcDZCNu9Nq0rKnOQ5SmHMm5j9dPjggSVMI5V5XlJg=", "ref": "main", - "rev": "fa0bf056d03d764ca742e89018a0e38d52db9473", + "rev": "ea34b7b08c13ca1e189a6282d0d923181db6cfb0", "shallow": true, "type": "git", "url": "https://git.clan.lol/clan/sidebus" From 20e7e88e073e415bfd13de4037628a1d6813dccd Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 5 Dec 2025 05:00:37 -0300 Subject: [PATCH 45/81] Update sidebus (now reverse-client to a session bus in the guest) --- flake.lock | 6 +++--- flake.nix | 2 ++ nixosModules/default.nix | 27 +++++++++++++++++---------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index 818e0f7..0815175 100644 --- a/flake.lock +++ b/flake.lock @@ -162,10 +162,10 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1764921491, - "narHash": "sha256-bGBcDZCNu9Nq0rKnOQ5SmHMm5j9dPjggSVMI5V5XlJg=", + "lastModified": 1764933524, + "narHash": "sha256-yland30CesTKgckWiWNMasfotzTspQzVaDqoKbrC4Fo=", "ref": "main", - "rev": "ea34b7b08c13ca1e189a6282d0d923181db6cfb0", + "rev": "52c3ea7cd36c816e00a6057e91cd945afda177d0", "shallow": true, "type": "git", "url": "https://git.clan.lol/clan/sidebus" diff --git a/flake.nix b/flake.nix index 8e1d432..fa88918 100644 --- a/flake.nix +++ b/flake.nix @@ -90,6 +90,8 @@ muvm = self.packages.${system}.muvm; sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; + + sidebus-agent = sidebus.packages.${system}.sidebus-agent; }; devShells.default = pkgs.callPackage ./devShells { diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 5866fb0..d6cf925 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -174,7 +174,7 @@ in { PassEnvironment = ["TERM" "MESA_LOADER_DRIVER_OVERRIDE" "MUVM_REMOTE_CONFIG"]; # "KRUN_CONFIG"]; Environment = [ "WAYLAND_DISPLAY=wayland-1" - "DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/sidebus.sock" + "DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock" "PATH=/run/current-system/sw/bin" ]; User = "appvm"; @@ -236,28 +236,35 @@ in { }; }; - systemd.sockets.sidebus-agent = { + systemd.sockets.session-bus = { enable = true; - description = "D-Bus cross-domain proxy socket"; + description = "D-Bus session bus socket"; wantedBy = ["microvm.target"]; - partOf = ["sidebus-agent.service"]; - listenStreams = [ "${runtimeDir}/sidebus.sock" ]; + partOf = ["session-bus.service"]; + listenStreams = [ "${runtimeDir}/dbus.sock" ]; socketConfig = { SocketUser = "appvm"; SocketGroup = "appvm"; }; }; - systemd.services.sidebus-agent = { + systemd.services.session-bus = { enable = true; - description = "D-Bus cross-domain proxy"; - requires = ["sidebus-agent.socket"]; + description = "D-Bus session bus"; + requires = ["session-bus.socket"]; serviceConfig = { - ImportCredential = "sidebus.port"; - ExecStart = "${sidebus.packages.${system}.sidebus-agent}/bin/sidebus-agent"; + ImportCredential = "sidebus.port"; # inherited by the activated agent.. + ExecStart = "${pkgs.dbus}/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --syslog-only"; # no systemd activation, we don't run a *session* systemd User = "appvm"; Group = "appvm"; }; }; + services.dbus.packages = [ + (pkgs.writeTextDir "/share/dbus-1/services/org.freedesktop.portal.Desktop.service" '' + [D-BUS Service] + Name=org.freedesktop.portal.Desktop + Exec=${sidebus.packages.${system}.sidebus-agent}/bin/sidebus-agent + '') + ]; hardware.graphics.enable = true; hardware.graphics.package = self.packages.${system}.mesa; From ab5f4125249633833301ab118208de1d403e728d Mon Sep 17 00:00:00 2001 From: Val Packett Date: Tue, 9 Dec 2025 06:08:32 -0300 Subject: [PATCH 46/81] Add dconf to testvm Pretty much required by GTK apps --- nixosModules/testvm.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix index 3f4e88a..786d915 100644 --- a/nixosModules/testvm.nix +++ b/nixosModules/testvm.nix @@ -3,6 +3,7 @@ system.stateVersion = "25.11"; fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ]; + programs.dconf.enable = true; environment.systemPackages = [ pkgs.fastfetch pkgs.htop From fb53769c7a27b8c9f67d26b9261021ba5ebd6748 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Tue, 9 Dec 2025 06:41:20 -0300 Subject: [PATCH 47/81] readme: add basic initial example of defining a vm (fix #8) Starting point to simplify --- README.md | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/README.md b/README.md index 9411e79..ce1fa27 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,94 @@ This will start an interactive bash session inside the microVM. nix run '.#munix' -- testvm fastfetch ``` +**Create a custom VM:** + +Create a `flake.nix` in a new directory using this flake as an input providing the necessary NixOS module: + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + munix.url = "git+https://git.clan.lol/clan/munix?shallow=1&ref=main"; + munix.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = { self, nixpkgs, munix, ... }: { + # First, define system configuration in a module: + nixosModules.musictest = { pkgs, ... }: { + system.stateVersion = "26.05"; + programs.dconf.enable = true; + fonts.packages = with pkgs; [ adwaita-fonts ]; + environment.systemPackages = with pkgs; [ euphonica ]; + # Local background service as a demo that doesn't require network creds :) + services.mpd = { + enable = true; + startWhenNeeded = true; + musicDirectory = "/etc/demo-music"; + user = "appvm"; + group = "appvm"; + extraConfig = '' + audio_output { + type "pipewire" + name "Pipewire Output" + } + ''; + }; + environment.etc."demo-music/0101GhostsI.ogg".source = pkgs.fetchurl { + # just a CC-BY-SA licensed example + url = "https://archive.org/download/NineInchNailsGhostsI-Iv24bit48khz/0101GhostsI.ogg"; + sha256 = "0iijm1c191aqkxybl4a4gvlpnf72hk4896lwvp0xixkhds88qzxi"; + }; + }; + + # And then define system closures per arch using the module above: + nixosConfigurations.musictest-aarch64 = nixpkgs.lib.nixosSystem { + system = "aarch64-linux"; + modules = [ + munix.nixosModules.default + self.nixosModules.musictest + ]; + }; + nixosConfigurations.musictest-x86_64 = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + munix.nixosModules.default + self.nixosModules.musictest + ]; + }; + + apps.aarch64-linux.default = { + type = "app"; + program = "${nixpkgs.legacyPackages.aarch64-linux.symlinkJoin { + name = "munix"; + paths = [ munix.packages.aarch64-linux.munix ]; + buildInputs = [ nixpkgs.legacyPackages.aarch64-linux.makeWrapper ]; + postBuild = '' + wrapProgram $out/bin/munix --add-flags ${self.nixosConfigurations.musictest-aarch64.config.system.build.toplevel} --set MICROVM_DEFAULT_COMMAND euphonica + ''; + }}/bin/munix"; + meta.description = "Run Music Demo App"; + }; + apps.x86_64-linux.default = { + type = "app"; + program = "${nixpkgs.legacyPackages.x86_64-linux.symlinkJoin { + name = "munix"; + paths = [ munix.packages.x86_64-linux.munix ]; + buildInputs = [ nixpkgs.legacyPackages.x86_64-linux.makeWrapper ]; + postBuild = '' + wrapProgram $out/bin/munix --add-flags ${self.nixosConfigurations.musictest-x86_64.config.system.build.toplevel} --set MICROVM_DEFAULT_COMMAND euphonica + ''; + }}/bin/munix"; + meta.description = "Run Music Demo App"; + }; + }; +} +``` + +And `nix run`! + +(TODO: helpers will be provided to reduce the necessary boilerplate) + ## munix Options - `--uid UID`, `-u UID` - Set microVM UID (default: 1337) From 2d721419e6e063ef4cf74d4e11b374940004b8cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 15 Dec 2025 16:12:53 +0100 Subject: [PATCH 48/81] readme: move example to flake template Replace inline flake.nix example with a proper flake template that users can instantiate with `nix flake init`. This makes it easier to get started and we can easier test the example. --- README.md | 89 +++----------------------------- flake.nix | 67 ++++++++++++++++-------- templates/musictest/flake.nix | 96 +++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 104 deletions(-) create mode 100644 templates/musictest/flake.nix diff --git a/README.md b/README.md index ce1fa27..e98d7df 100644 --- a/README.md +++ b/README.md @@ -23,91 +23,16 @@ nix run '.#munix' -- testvm fastfetch **Create a custom VM:** -Create a `flake.nix` in a new directory using this flake as an input providing the necessary NixOS module: +Use the template to bootstrap a new munix project: -```nix -{ - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - munix.url = "git+https://git.clan.lol/clan/munix?shallow=1&ref=main"; - munix.inputs.nixpkgs.follows = "nixpkgs"; - }; - - outputs = { self, nixpkgs, munix, ... }: { - # First, define system configuration in a module: - nixosModules.musictest = { pkgs, ... }: { - system.stateVersion = "26.05"; - programs.dconf.enable = true; - fonts.packages = with pkgs; [ adwaita-fonts ]; - environment.systemPackages = with pkgs; [ euphonica ]; - # Local background service as a demo that doesn't require network creds :) - services.mpd = { - enable = true; - startWhenNeeded = true; - musicDirectory = "/etc/demo-music"; - user = "appvm"; - group = "appvm"; - extraConfig = '' - audio_output { - type "pipewire" - name "Pipewire Output" - } - ''; - }; - environment.etc."demo-music/0101GhostsI.ogg".source = pkgs.fetchurl { - # just a CC-BY-SA licensed example - url = "https://archive.org/download/NineInchNailsGhostsI-Iv24bit48khz/0101GhostsI.ogg"; - sha256 = "0iijm1c191aqkxybl4a4gvlpnf72hk4896lwvp0xixkhds88qzxi"; - }; - }; - - # And then define system closures per arch using the module above: - nixosConfigurations.musictest-aarch64 = nixpkgs.lib.nixosSystem { - system = "aarch64-linux"; - modules = [ - munix.nixosModules.default - self.nixosModules.musictest - ]; - }; - nixosConfigurations.musictest-x86_64 = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ - munix.nixosModules.default - self.nixosModules.musictest - ]; - }; - - apps.aarch64-linux.default = { - type = "app"; - program = "${nixpkgs.legacyPackages.aarch64-linux.symlinkJoin { - name = "munix"; - paths = [ munix.packages.aarch64-linux.munix ]; - buildInputs = [ nixpkgs.legacyPackages.aarch64-linux.makeWrapper ]; - postBuild = '' - wrapProgram $out/bin/munix --add-flags ${self.nixosConfigurations.musictest-aarch64.config.system.build.toplevel} --set MICROVM_DEFAULT_COMMAND euphonica - ''; - }}/bin/munix"; - meta.description = "Run Music Demo App"; - }; - apps.x86_64-linux.default = { - type = "app"; - program = "${nixpkgs.legacyPackages.x86_64-linux.symlinkJoin { - name = "munix"; - paths = [ munix.packages.x86_64-linux.munix ]; - buildInputs = [ nixpkgs.legacyPackages.x86_64-linux.makeWrapper ]; - postBuild = '' - wrapProgram $out/bin/munix --add-flags ${self.nixosConfigurations.musictest-x86_64.config.system.build.toplevel} --set MICROVM_DEFAULT_COMMAND euphonica - ''; - }}/bin/munix"; - meta.description = "Run Music Demo App"; - }; - }; -} +```bash +mkdir my-vm && cd my-vm +nix flake init -t 'git+https://git.clan.lol/clan/munix#musictest' +git init && git add flake.nix +nix run ``` -And `nix run`! - -(TODO: helpers will be provided to reduce the necessary boilerplate) +This creates a `flake.nix` with a music player demo (MPD + Euphonica). Edit the module to customize your VM. ## munix Options diff --git a/flake.nix b/flake.nix index fa88918..da67b2a 100644 --- a/flake.nix +++ b/flake.nix @@ -27,34 +27,56 @@ }; }; - outputs = { self, nixpkgs, flake-utils, virtwl, sidebus, muvm-src, libkrun-src, libkrunfw-src, ... }: { - nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { inherit virtwl; }; - nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { inherit self virtwl sidebus; }; + outputs = + { + self, + nixpkgs, + flake-utils, + virtwl, + sidebus, + muvm-src, + libkrun-src, + libkrunfw-src, + ... + }: + { + nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { inherit virtwl; }; + nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { + inherit self virtwl sidebus; + }; - nixosConfigurations.testvm-x86_64 = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ - self.nixosModules.default - self.nixosModules.testvm - { nixpkgs.config.allowUnfree = true; } - ]; - }; + templates.musictest = { + description = "Music player demo VM with MPD and Euphonica"; + path = ./templates/musictest; + }; - nixosConfigurations.testvm-aarch64 = nixpkgs.lib.nixosSystem { - system = "aarch64-linux"; - modules = [ - self.nixosModules.default - self.nixosModules.testvm - { nixpkgs.config.allowUnfree = true; } - ]; - }; - } // flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system: + nixosConfigurations.testvm-x86_64 = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + self.nixosModules.default + self.nixosModules.testvm + { nixpkgs.config.allowUnfree = true; } + ]; + }; + + nixosConfigurations.testvm-aarch64 = nixpkgs.lib.nixosSystem { + system = "aarch64-linux"; + modules = [ + self.nixosModules.default + self.nixosModules.testvm + { nixpkgs.config.allowUnfree = true; } + ]; + }; + } + // flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] ( + system: let pkgs = import nixpkgs { inherit system; config.allowUnfree = true; }; - in { + in + { checks = (pkgs.lib.mapAttrs' (n: pkgs.lib.nameValuePair "package-${n}") self.packages.${system}) @@ -99,5 +121,6 @@ muvm = self.packages.${system}.muvm; sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; - }); + } + ); } diff --git a/templates/musictest/flake.nix b/templates/musictest/flake.nix new file mode 100644 index 0000000..6f0d3ae --- /dev/null +++ b/templates/musictest/flake.nix @@ -0,0 +1,96 @@ +{ + nixConfig = { + extra-substituters = [ "https://cache.clan.lol" ]; + extra-trusted-public-keys = [ + "cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28=" + ]; + }; + + inputs = { + munix.url = "git+https://git.clan.lol/clan/munix?shallow=1&ref=main"; + nixpkgs.follows = "munix/nixpkgs"; + }; + + outputs = + { + self, + nixpkgs, + munix, + ... + }: + { + # First, define system configuration in a module: + nixosModules.musictest = + { pkgs, ... }: + { + system.stateVersion = "26.05"; + programs.dconf.enable = true; + fonts.packages = with pkgs; [ adwaita-fonts ]; + environment.systemPackages = with pkgs; [ euphonica ]; + # Local background service as a demo that doesn't require network creds :) + services.mpd = { + enable = true; + startWhenNeeded = true; + musicDirectory = "/etc/demo-music"; + user = "appvm"; + group = "appvm"; + extraConfig = '' + audio_output { + type "pipewire" + name "Pipewire Output" + } + ''; + }; + environment.etc."demo-music/0101GhostsI.ogg".source = pkgs.fetchurl { + # just a CC-BY-SA licensed example + url = "https://archive.org/download/NineInchNailsGhostsI-Iv24bit48khz/0101GhostsI.ogg"; + sha256 = "0iijm1c191aqkxybl4a4gvlpnf72hk4896lwvp0xixkhds88qzxi"; + }; + }; + + # And then define system closures per arch using the module above: + nixosConfigurations.musictest-aarch64 = nixpkgs.lib.nixosSystem { + system = "aarch64-linux"; + modules = [ + munix.nixosModules.default + self.nixosModules.musictest + ]; + }; + nixosConfigurations.musictest-x86_64 = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + munix.nixosModules.default + self.nixosModules.musictest + ]; + }; + + apps.aarch64-linux.default = { + type = "app"; + program = "${ + nixpkgs.legacyPackages.aarch64-linux.symlinkJoin { + name = "munix"; + paths = [ munix.packages.aarch64-linux.munix ]; + buildInputs = [ nixpkgs.legacyPackages.aarch64-linux.makeWrapper ]; + postBuild = '' + wrapProgram $out/bin/munix --add-flags ${self.nixosConfigurations.musictest-aarch64.config.system.build.toplevel} --set MICROVM_DEFAULT_COMMAND euphonica + ''; + } + }/bin/munix"; + meta.description = "Run Music Demo App"; + }; + apps.x86_64-linux.default = { + type = "app"; + program = "${ + nixpkgs.legacyPackages.x86_64-linux.symlinkJoin { + name = "munix"; + paths = [ munix.packages.x86_64-linux.munix ]; + buildInputs = [ nixpkgs.legacyPackages.x86_64-linux.makeWrapper ]; + postBuild = '' + wrapProgram $out/bin/munix --add-flags ${self.nixosConfigurations.musictest-x86_64.config.system.build.toplevel} --set MICROVM_DEFAULT_COMMAND euphonica + ''; + } + }/bin/munix"; + meta.description = "Run Music Demo App"; + }; + }; +} From ced0559be8bf8292328ad0bca5b34fba9200c0af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 15 Dec 2025 16:20:04 +0100 Subject: [PATCH 49/81] nixos: add munix.defaultCommand option and system.build.munix Add a NixOS option to configure the default command for the VM and provide a system.build.munix output that wraps munix with the correct toplevel and default command. This reduces boilerplate in downstream flakes since they no longer need to manually wrap munix. The template now uses these new features, significantly simplifying the apps definition. --- nixosModules/default.nix | 563 +++++++++++++++++++--------------- templates/musictest/flake.nix | 29 +- 2 files changed, 317 insertions(+), 275 deletions(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index d6cf925..e81cde8 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -1,5 +1,16 @@ -{ self, virtwl, sidebus }: -{ pkgs, lib, utils, config, ... }: let +{ + self, + virtwl, + sidebus, +}: +{ + pkgs, + lib, + utils, + config, + ... +}: +let useTTY = { TTYPath = "/dev/hvc0"; StandardOutput = "tty"; @@ -7,265 +18,315 @@ StandardError = "tty"; }; runtimeDir = "/run/vm-user"; - userbornConfig = { - groups = lib.mapAttrsToList (username: opts: { - inherit (opts) name gid members; - }) config.users.groups; - users = lib.mapAttrsToList (username: opts: { - inherit (opts) - name - uid - group - description - home - password - hashedPassword - hashedPasswordFile - initialPassword - initialHashedPassword - ; - isNormal = opts.isNormalUser; - shell = utils.toShellPath opts.shell; - }) (lib.filterAttrs (_: u: u.enable) config.users.users); - }; - userbornConfigJson = pkgs.writeText "userborn.json" (builtins.toJSON userbornConfig); - userbornResults = pkgs.runCommand "baked userborn" {} "mkdir -p $out; ${lib.getExe pkgs.userborn} ${userbornConfigJson} $out"; + userbornConfig = { + groups = lib.mapAttrsToList (username: opts: { + inherit (opts) name gid members; + }) config.users.groups; + users = lib.mapAttrsToList (username: opts: { + inherit (opts) + name + uid + group + description + home + password + hashedPassword + hashedPasswordFile + initialPassword + initialHashedPassword + ; + isNormal = opts.isNormalUser; + shell = utils.toShellPath opts.shell; + }) (lib.filterAttrs (_: u: u.enable) config.users.users); + }; + userbornConfigJson = pkgs.writeText "userborn.json" (builtins.toJSON userbornConfig); + userbornResults = + pkgs.runCommand "baked userborn" { } + "mkdir -p $out; ${lib.getExe pkgs.userborn} ${userbornConfigJson} $out"; system = pkgs.stdenv.hostPlatform.system; -in { - boot.isContainer = true; - fileSystems."/".device = lib.mkDefault "/dev/sda"; # dummy - - # Disable unused things - environment.defaultPackages = lib.mkDefault [ ]; - documentation = { - enable = lib.mkDefault false; - doc.enable = lib.mkDefault false; - info.enable = lib.mkDefault false; - man.enable = lib.mkDefault false; - nixos.enable = lib.mkDefault false; +in +{ + options.virtualisation.munix.defaultCommand = lib.mkOption { + type = lib.types.str; + default = "bash"; + description = "Default command to run when starting the VM without arguments."; }; - 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; - # Configure activation / systemd - boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd - system.etc.overlay.enable = true; # erofs - system.etc.overlay.mutable = false; - system.switch.enable = false; - services.udev.enable = lib.mkDefault true; - services.udev.packages = lib.mkDefault []; - services.resolved.enable = false; - environment.etc."resolv.conf".source = "/run/resolv.conf"; - environment.etc."machine-id".source = "/run/machine-id"; - environment.etc."systemd/system".source = lib.mkForce (utils.systemdUtils.lib.generateUnits { - type = "system"; - units = config.systemd.units; - upstreamUnits = [ - "sysinit.target" - "local-fs.target" - "nss-user-lookup.target" - "umount.target" - "sockets.target" - "shutdown.target" - "reboot.target" - "exit.target" - "final.target" - "systemd-exit.service" - "systemd-journald.socket" - "systemd-journald-audit.socket" - "systemd-journald-dev-log.socket" - "systemd-journald.service" - "systemd-udevd-kernel.socket" - "systemd-udevd-control.socket" - "user.slice" - ]; - upstreamWants = ["multi-user.target.wants"]; - }); + config = { + boot.isContainer = true; + fileSystems."/".device = lib.mkDefault "/dev/sda"; # dummy - # systemd.package = pkgs.systemdMinimal; # no analyze - systemd.defaultUnit = "microvm.target"; - systemd.targets.microvm = { - description = "Minimal microVM system"; - wants = ["systemd-journald.socket" "systemd-udevd.service" "dbus.socket"]; - unitConfig.AllowIsolate = "yes"; - }; - 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; - systemd.services.systemd-udevd = { - # Redefine to remove the Before deps and get out of the critical chain - enable = true; - description = "Rule-based Manager for Device Events and Files"; - unitConfig.DefaultDependencies = "no"; - serviceConfig = { - CapabilityBoundingSet = "~CAP_SYS_TIME CAP_WAKE_ALARM"; - Delegate = ""; - DelegateSubgroup = "udev"; - Type = "notify-reload"; - OOMScoreAdjust = "-1000"; - Sockets = "systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd-varlink.socket"; - Restart = "always"; - RestartSec = "0"; - ExecStart = "${pkgs.systemd}/lib/systemd/systemd-udevd"; - FileDescriptorStoreMax = "512"; - FileDescriptorStorePreserve = "yes"; - KillMode = "mixed"; - TasksMax = "infinity"; - PrivateMounts = "yes"; - ProtectHostname = "yes"; - MemoryDenyWriteExecute = "yes"; - RestrictAddressFamilies = "AF_UNIX AF_NETLINK AF_INET AF_INET6"; - RestrictRealtime = "yes"; - RestrictSUIDSGID = "yes"; - SystemCallFilter = ["@system-service @module @raw-io bpf" "~@clock"]; - SystemCallErrorNumber = "EPERM"; - SystemCallArchitectures = "native"; - LockPersonality = "yes"; - IPAddressDeny = "any"; - WatchdogSec = "3min"; + # Disable unused things + environment.defaultPackages = lib.mkDefault [ ]; + documentation = { + enable = lib.mkDefault false; + doc.enable = lib.mkDefault false; + info.enable = lib.mkDefault false; + man.enable = lib.mkDefault false; + nixos.enable = lib.mkDefault false; }; - }; + 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; - # Configure user accounts - # The immutable overlay wants userborn or sysusers.. we just want baked-in files w/o running a service. - # So we can just run userborn at system closure build time! - systemd.sysusers.enable = false; - services.userborn.enable = true; - systemd.services.userborn.enable = false; - environment.etc."passwd" = lib.mkForce { source = "${userbornResults}/passwd"; mode = "0444"; }; - environment.etc."group" = lib.mkForce { source = "${userbornResults}/group"; mode = "0444"; }; - environment.etc."shadow" = lib.mkForce { source = "${userbornResults}/shadow"; mode = "0440"; }; - users.mutableUsers = false; - users.users.appvm = { - uid = 1337; - group = "appvm"; - isNormalUser = false; - isSystemUser = true; - home = "/home/appvm"; - description = "microVM User"; - extraGroups = [ "wheel" "video" "input" "systemd-journal" ]; - }; - users.groups.appvm.gid = 1337; - users.allowNoPasswordLogin = true; + # Configure activation / systemd + boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd + system.etc.overlay.enable = true; # erofs + system.etc.overlay.mutable = false; + system.switch.enable = false; + services.udev.enable = lib.mkDefault true; + services.udev.packages = lib.mkDefault [ ]; + services.resolved.enable = false; + environment.etc."resolv.conf".source = "/run/resolv.conf"; + environment.etc."machine-id".source = "/run/machine-id"; + environment.etc."systemd/system".source = lib.mkForce ( + utils.systemdUtils.lib.generateUnits { + type = "system"; + units = config.systemd.units; + upstreamUnits = [ + "sysinit.target" + "local-fs.target" + "nss-user-lookup.target" + "umount.target" + "sockets.target" + "shutdown.target" + "reboot.target" + "exit.target" + "final.target" + "systemd-exit.service" + "systemd-journald.socket" + "systemd-journald-audit.socket" + "systemd-journald-dev-log.socket" + "systemd-journald.service" + "systemd-udevd-kernel.socket" + "systemd-udevd-control.socket" + "user.slice" + ]; + upstreamWants = [ "multi-user.target.wants" ]; + } + ); - # Configure services - - systemd.settings.Manager.DefaultEnvironment = "XDG_RUNTIME_DIR=${runtimeDir}"; - - systemd.services.muvm-remote = { - enable = true; - description = "microVM Application runner"; - onFailure = ["exit.target"]; - onSuccess = ["exit.target"]; - wants = ["sockets.target"]; - after = ["sockets.target"]; - wantedBy = ["microvm.target"]; - serviceConfig = { - Type = "exec"; - PassEnvironment = ["TERM" "MESA_LOADER_DRIVER_OVERRIDE" "MUVM_REMOTE_CONFIG"]; # "KRUN_CONFIG"]; - Environment = [ - "WAYLAND_DISPLAY=wayland-1" - "DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock" - "PATH=/run/current-system/sw/bin" + # systemd.package = pkgs.systemdMinimal; # no analyze + systemd.defaultUnit = "microvm.target"; + systemd.targets.microvm = { + description = "Minimal microVM system"; + wants = [ + "systemd-journald.socket" + "systemd-udevd.service" + "dbus.socket" ]; - User = "appvm"; - Group = "appvm"; - ExecStartPre = "+/run/current-system/sw/bin/chown appvm:appvm ${runtimeDir}"; - ExecStart = "/opt/bin/muvm-remote"; - ExecStopPost = ''+${pkgs.python3}/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"''; - } // useTTY; - }; + unitConfig.AllowIsolate = "yes"; + }; + 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; + systemd.services.systemd-udevd = { + # Redefine to remove the Before deps and get out of the critical chain + enable = true; + description = "Rule-based Manager for Device Events and Files"; + unitConfig.DefaultDependencies = "no"; + serviceConfig = { + CapabilityBoundingSet = "~CAP_SYS_TIME CAP_WAKE_ALARM"; + Delegate = ""; + DelegateSubgroup = "udev"; + Type = "notify-reload"; + OOMScoreAdjust = "-1000"; + Sockets = "systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd-varlink.socket"; + Restart = "always"; + RestartSec = "0"; + ExecStart = "${pkgs.systemd}/lib/systemd/systemd-udevd"; + FileDescriptorStoreMax = "512"; + FileDescriptorStorePreserve = "yes"; + KillMode = "mixed"; + TasksMax = "infinity"; + PrivateMounts = "yes"; + ProtectHostname = "yes"; + MemoryDenyWriteExecute = "yes"; + RestrictAddressFamilies = "AF_UNIX AF_NETLINK AF_INET AF_INET6"; + RestrictRealtime = "yes"; + RestrictSUIDSGID = "yes"; + SystemCallFilter = [ + "@system-service @module @raw-io bpf" + "~@clock" + ]; + SystemCallErrorNumber = "EPERM"; + SystemCallArchitectures = "native"; + LockPersonality = "yes"; + IPAddressDeny = "any"; + WatchdogSec = "3min"; + }; + }; - systemd.services.muvm-configure-network = { - enable = true; - description = "microVM Network configuration"; - wantedBy = ["microvm.target"]; - serviceConfig.Type = "oneshot"; - serviceConfig.ExecStart = "/opt/bin/muvm-configure-network"; - }; + # Configure user accounts + # The immutable overlay wants userborn or sysusers.. we just want baked-in files w/o running a service. + # So we can just run userborn at system closure build time! + systemd.sysusers.enable = false; + services.userborn.enable = true; + systemd.services.userborn.enable = false; + environment.etc."passwd" = lib.mkForce { + source = "${userbornResults}/passwd"; + mode = "0444"; + }; + environment.etc."group" = lib.mkForce { + source = "${userbornResults}/group"; + mode = "0444"; + }; + environment.etc."shadow" = lib.mkForce { + source = "${userbornResults}/shadow"; + mode = "0440"; + }; + users.mutableUsers = false; + users.users.appvm = { + uid = 1337; + group = "appvm"; + isNormalUser = false; + isSystemUser = true; + home = "/home/appvm"; + description = "microVM User"; + extraGroups = [ + "wheel" + "video" + "input" + "systemd-journal" + ]; + }; + users.groups.appvm.gid = 1337; + users.allowNoPasswordLogin = true; - systemd.sockets.muvm-pwbridge = { - enable = true; - description = "PipeWire cross-domain proxy socket"; - wantedBy = ["microvm.target"]; - partOf = ["muvm-pwbridge.service"]; - listenStreams = [ "${runtimeDir}/pipewire-0" ]; - socketConfig = { - SocketUser = "appvm"; - SocketGroup = "appvm"; + # Configure services + + systemd.settings.Manager.DefaultEnvironment = "XDG_RUNTIME_DIR=${runtimeDir}"; + + systemd.services.muvm-remote = { + enable = true; + description = "microVM Application runner"; + onFailure = [ "exit.target" ]; + onSuccess = [ "exit.target" ]; + wants = [ "sockets.target" ]; + after = [ "sockets.target" ]; + wantedBy = [ "microvm.target" ]; + serviceConfig = { + Type = "exec"; + PassEnvironment = [ + "TERM" + "MESA_LOADER_DRIVER_OVERRIDE" + "MUVM_REMOTE_CONFIG" + ]; # "KRUN_CONFIG"]; + Environment = [ + "WAYLAND_DISPLAY=wayland-1" + "DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock" + "PATH=/run/current-system/sw/bin" + ]; + User = "appvm"; + Group = "appvm"; + ExecStartPre = "+/run/current-system/sw/bin/chown appvm:appvm ${runtimeDir}"; + ExecStart = "/opt/bin/muvm-remote"; + ExecStopPost = ''+${pkgs.python3}/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"''; + } + // useTTY; + }; + + systemd.services.muvm-configure-network = { + enable = true; + description = "microVM Network configuration"; + wantedBy = [ "microvm.target" ]; + serviceConfig.Type = "oneshot"; + serviceConfig.ExecStart = "/opt/bin/muvm-configure-network"; + }; + + systemd.sockets.muvm-pwbridge = { + enable = true; + description = "PipeWire cross-domain proxy socket"; + wantedBy = [ "microvm.target" ]; + partOf = [ "muvm-pwbridge.service" ]; + listenStreams = [ "${runtimeDir}/pipewire-0" ]; + socketConfig = { + SocketUser = "appvm"; + SocketGroup = "appvm"; + }; + }; + systemd.services.muvm-pwbridge = { + enable = true; + description = "PipeWire cross-domain proxy"; + requires = [ "muvm-pwbridge.socket" ]; + serviceConfig.Type = "exec"; + serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge"; + }; + + systemd.sockets.wayland-proxy-virtwl = { + enable = true; + description = "Wayland cross-domain proxy socket"; + wantedBy = [ "microvm.target" ]; + partOf = [ "wayland-proxy-virtwl.service" ]; + listenStreams = [ "${runtimeDir}/wayland-1" ]; + socketConfig = { + SocketUser = "appvm"; + SocketGroup = "appvm"; + FileDescriptorName = "wayland"; + }; + }; + systemd.services.wayland-proxy-virtwl = { + enable = true; + description = "Wayland cross-domain proxy"; + requires = [ "wayland-proxy-virtwl.socket" ]; + serviceConfig = { + ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"; + ExecStart = "${virtwl.packages.${system}.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; + User = "appvm"; + Group = "appvm"; + }; + }; + + systemd.sockets.session-bus = { + enable = true; + description = "D-Bus session bus socket"; + wantedBy = [ "microvm.target" ]; + partOf = [ "session-bus.service" ]; + listenStreams = [ "${runtimeDir}/dbus.sock" ]; + socketConfig = { + SocketUser = "appvm"; + SocketGroup = "appvm"; + }; + }; + systemd.services.session-bus = { + enable = true; + description = "D-Bus session bus"; + requires = [ "session-bus.socket" ]; + serviceConfig = { + ImportCredential = "sidebus.port"; # inherited by the activated agent.. + ExecStart = "${pkgs.dbus}/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --syslog-only"; # no systemd activation, we don't run a *session* systemd + User = "appvm"; + Group = "appvm"; + }; + }; + services.dbus.packages = [ + (pkgs.writeTextDir "/share/dbus-1/services/org.freedesktop.portal.Desktop.service" '' + [D-BUS Service] + Name=org.freedesktop.portal.Desktop + Exec=${sidebus.packages.${system}.sidebus-agent}/bin/sidebus-agent + '') + ]; + + hardware.graphics.enable = true; + hardware.graphics.package = self.packages.${system}.mesa; + + system.build.munix = pkgs.symlinkJoin { + name = "munix"; + paths = [ self.packages.${system}.munix ]; + buildInputs = [ pkgs.makeWrapper ]; + postBuild = '' + wrapProgram $out/bin/munix \ + --add-flags ${config.system.build.toplevel} \ + --set MICROVM_DEFAULT_COMMAND ${lib.escapeShellArg config.virtualisation.munix.defaultCommand} + ''; }; }; - systemd.services.muvm-pwbridge = { - enable = true; - description = "PipeWire cross-domain proxy"; - requires = ["muvm-pwbridge.socket"]; - serviceConfig.Type = "exec"; - serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge"; - }; - - systemd.sockets.wayland-proxy-virtwl = { - enable = true; - description = "Wayland cross-domain proxy socket"; - wantedBy = ["microvm.target"]; - partOf = ["wayland-proxy-virtwl.service"]; - listenStreams = [ "${runtimeDir}/wayland-1" ]; - socketConfig = { - SocketUser = "appvm"; - SocketGroup = "appvm"; - FileDescriptorName = "wayland"; - }; - }; - systemd.services.wayland-proxy-virtwl = { - enable = true; - description = "Wayland cross-domain proxy"; - requires = ["wayland-proxy-virtwl.socket"]; - serviceConfig = { - ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"; - ExecStart = "${virtwl.packages.${system}.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; - User = "appvm"; - Group = "appvm"; - }; - }; - - systemd.sockets.session-bus = { - enable = true; - description = "D-Bus session bus socket"; - wantedBy = ["microvm.target"]; - partOf = ["session-bus.service"]; - listenStreams = [ "${runtimeDir}/dbus.sock" ]; - socketConfig = { - SocketUser = "appvm"; - SocketGroup = "appvm"; - }; - }; - systemd.services.session-bus = { - enable = true; - description = "D-Bus session bus"; - requires = ["session-bus.socket"]; - serviceConfig = { - ImportCredential = "sidebus.port"; # inherited by the activated agent.. - ExecStart = "${pkgs.dbus}/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --syslog-only"; # no systemd activation, we don't run a *session* systemd - User = "appvm"; - Group = "appvm"; - }; - }; - services.dbus.packages = [ - (pkgs.writeTextDir "/share/dbus-1/services/org.freedesktop.portal.Desktop.service" '' - [D-BUS Service] - Name=org.freedesktop.portal.Desktop - Exec=${sidebus.packages.${system}.sidebus-agent}/bin/sidebus-agent - '') - ]; - - hardware.graphics.enable = true; - hardware.graphics.package = self.packages.${system}.mesa; } diff --git a/templates/musictest/flake.nix b/templates/musictest/flake.nix index 6f0d3ae..4178615 100644 --- a/templates/musictest/flake.nix +++ b/templates/musictest/flake.nix @@ -19,14 +19,16 @@ ... }: { - # First, define system configuration in a module: nixosModules.musictest = { pkgs, ... }: { system.stateVersion = "26.05"; + virtualisation.munix.defaultCommand = "euphonica"; + programs.dconf.enable = true; fonts.packages = with pkgs; [ adwaita-fonts ]; environment.systemPackages = with pkgs; [ euphonica ]; + # Local background service as a demo that doesn't require network creds :) services.mpd = { enable = true; @@ -48,7 +50,6 @@ }; }; - # And then define system closures per arch using the module above: nixosConfigurations.musictest-aarch64 = nixpkgs.lib.nixosSystem { system = "aarch64-linux"; modules = [ @@ -66,31 +67,11 @@ apps.aarch64-linux.default = { type = "app"; - program = "${ - nixpkgs.legacyPackages.aarch64-linux.symlinkJoin { - name = "munix"; - paths = [ munix.packages.aarch64-linux.munix ]; - buildInputs = [ nixpkgs.legacyPackages.aarch64-linux.makeWrapper ]; - postBuild = '' - wrapProgram $out/bin/munix --add-flags ${self.nixosConfigurations.musictest-aarch64.config.system.build.toplevel} --set MICROVM_DEFAULT_COMMAND euphonica - ''; - } - }/bin/munix"; - meta.description = "Run Music Demo App"; + program = "${self.nixosConfigurations.musictest-aarch64.config.system.build.munix}/bin/munix"; }; apps.x86_64-linux.default = { type = "app"; - program = "${ - nixpkgs.legacyPackages.x86_64-linux.symlinkJoin { - name = "munix"; - paths = [ munix.packages.x86_64-linux.munix ]; - buildInputs = [ nixpkgs.legacyPackages.x86_64-linux.makeWrapper ]; - postBuild = '' - wrapProgram $out/bin/munix --add-flags ${self.nixosConfigurations.musictest-x86_64.config.system.build.toplevel} --set MICROVM_DEFAULT_COMMAND euphonica - ''; - } - }/bin/munix"; - meta.description = "Run Music Demo App"; + program = "${self.nixosConfigurations.musictest-x86_64.config.system.build.munix}/bin/munix"; }; }; } From 1d864e0dedde3e920ca8b1544155d53864ca3f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 15 Dec 2025 16:48:58 +0100 Subject: [PATCH 50/81] template: simplify with forAllSystems and inline module Use the forAllSystems pattern to reduce duplication and inline the NixOS module directly in nixosSystem call. This eliminates the need for separate nixosModules and nixosConfigurations outputs, making the template more concise and easier to understand. Also use virtualisation.munix namespace for the option. --- templates/musictest/flake.nix | 98 ++++++++++++++++------------------- 1 file changed, 46 insertions(+), 52 deletions(-) diff --git a/templates/musictest/flake.nix b/templates/musictest/flake.nix index 4178615..a2c7759 100644 --- a/templates/musictest/flake.nix +++ b/templates/musictest/flake.nix @@ -13,65 +13,59 @@ outputs = { - self, nixpkgs, munix, ... }: - { - nixosModules.musictest = - { pkgs, ... }: - { - system.stateVersion = "26.05"; - virtualisation.munix.defaultCommand = "euphonica"; + let + forAllSystems = nixpkgs.lib.genAttrs [ + "x86_64-linux" + "aarch64-linux" + ]; + musictest-vm = + system: + nixpkgs.lib.nixosSystem { + modules = [ + munix.nixosModules.default + ( + { pkgs, ... }: + { + system.stateVersion = "26.05"; + virtualisation.munix.defaultCommand = "euphonica"; - programs.dconf.enable = true; - fonts.packages = with pkgs; [ adwaita-fonts ]; - environment.systemPackages = with pkgs; [ euphonica ]; + nixpkgs.hostPlatform = system; - # Local background service as a demo that doesn't require network creds :) - services.mpd = { - enable = true; - startWhenNeeded = true; - musicDirectory = "/etc/demo-music"; - user = "appvm"; - group = "appvm"; - extraConfig = '' - audio_output { - type "pipewire" - name "Pipewire Output" + programs.dconf.enable = true; + fonts.packages = with pkgs; [ adwaita-fonts ]; + environment.systemPackages = with pkgs; [ euphonica ]; + + # Local background service as a demo that doesn't require network creds :) + services.mpd = { + enable = true; + startWhenNeeded = true; + musicDirectory = "/etc/demo-music"; + user = "appvm"; + group = "appvm"; + extraConfig = '' + audio_output { + type "pipewire" + name "Pipewire Output" + } + ''; + }; + environment.etc."demo-music/0101GhostsI.ogg".source = pkgs.fetchurl { + # just a CC-BY-SA licensed example + url = "https://archive.org/download/NineInchNailsGhostsI-Iv24bit48khz/0101GhostsI.ogg"; + sha256 = "0iijm1c191aqkxybl4a4gvlpnf72hk4896lwvp0xixkhds88qzxi"; + }; } - ''; - }; - environment.etc."demo-music/0101GhostsI.ogg".source = pkgs.fetchurl { - # just a CC-BY-SA licensed example - url = "https://archive.org/download/NineInchNailsGhostsI-Iv24bit48khz/0101GhostsI.ogg"; - sha256 = "0iijm1c191aqkxybl4a4gvlpnf72hk4896lwvp0xixkhds88qzxi"; - }; + ) + ]; }; - - nixosConfigurations.musictest-aarch64 = nixpkgs.lib.nixosSystem { - system = "aarch64-linux"; - modules = [ - munix.nixosModules.default - self.nixosModules.musictest - ]; - }; - nixosConfigurations.musictest-x86_64 = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ - munix.nixosModules.default - self.nixosModules.musictest - ]; - }; - - apps.aarch64-linux.default = { - type = "app"; - program = "${self.nixosConfigurations.musictest-aarch64.config.system.build.munix}/bin/munix"; - }; - apps.x86_64-linux.default = { - type = "app"; - program = "${self.nixosConfigurations.musictest-x86_64.config.system.build.munix}/bin/munix"; - }; + in + { + packages = forAllSystems (system: { + default = (musictest-vm system).config.system.build.munix; + }); }; } From f336a0d5ff44dcbc8a184c4850b6cf6b5bf17265 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Tue, 9 Dec 2025 06:46:51 -0300 Subject: [PATCH 51/81] micro-activate: generate machine-id randomly D-Bus is supposed to (?) use it to decide whether it can use FD passing, shared memory, etc. and while we do a lot of cross-domain magic it's not quite seamless :) so let's not reuse the host one. --- micro-activate.rs | 17 +++++++++++++++-- munix | 2 -- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/micro-activate.rs b/micro-activate.rs index bb2dd24..d9d829c 100644 --- a/micro-activate.rs +++ b/micro-activate.rs @@ -16,6 +16,20 @@ unsafe extern "C" { flags: c_ulong, data: *const c_void, ) -> c_int; + fn getrandom(buf: *mut u8, buflen: usize, flags: u32) -> c_int; +} + +fn gen_machine_id() -> String { + use std::fmt::Write as _; + let mut bytes: [u8; 16] = [0; 16]; + if unsafe { getrandom(bytes.as_mut_ptr(), 16, 0) } == -1 { + eprintln!("[micro-activate] getrandom failed!"); + } + let mut result = String::with_capacity(32); + for b in bytes { + let _ = write!(result, "{:02x}", b); + } + result } fn parse_tmpfiles_line(line: &str) -> Option<(&str, &str)> { @@ -57,7 +71,6 @@ fn main() -> Result<(), std::io::Error> { // // Let's preserve the fixed passed-in files and set up the NixOS symlinks in the new mount. let resolv_conf = std::fs::read("/run/resolv.conf")?; - let machine_id = std::fs::read("/run/machine-id")?; assert_eq!( unsafe { mount( @@ -71,7 +84,7 @@ fn main() -> Result<(), std::io::Error> { 0 ); std::fs::write("/run/resolv.conf", &resolv_conf)?; - std::fs::write("/run/machine-id", &machine_id)?; + std::fs::write("/run/machine-id", &gen_machine_id())?; std::os::unix::fs::symlink(&closure, "/run/current-system")?; if let Ok(tmp_graphics) = std::fs::read(format!("{closure}/etc/tmpfiles.d/graphics-driver.conf")) diff --git a/munix b/munix index 18d3013..3921ca9 100755 --- a/munix +++ b/munix @@ -195,7 +195,6 @@ bwrap --unshare-all --share-net \ --symlink "$MICROVM_CLOSURE/sw/bin/env" /usr/bin/env \ --symlink "$MICROVM_CLOSURE" /run/current-system \ --ro-bind /nix/store /nix/store \ - --file 12 /run/machine-id \ --file 13 /run/resolv.conf \ --dir "$XDG_RUNTIME_DIR" \ --setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \ @@ -207,5 +206,4 @@ bwrap --unshare-all --share-net \ -e MICROVM_CLOSURE="$MICROVM_CLOSURE" \ -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \ -i -t "${MICROVM_COMMAND[@]}" \ - 12< /etc/machine-id \ 13< /etc/resolv.conf From 787ca12b1e32c8dbf0ccc16136c214372f369acf Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 12 Dec 2025 05:10:52 -0300 Subject: [PATCH 52/81] Start sidebus-agent strictly before the apps Gtk uses G_DBUS_CALL_FLAGS_NO_AUTO_START in all the (early) portal calls so we basically get a version of https://gitlab.gnome.org/GNOME/gtk/-/issues/7379 if we try to lazily start the agent.. --- nixosModules/default.nix | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index e81cde8..813a1f9 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -301,19 +301,25 @@ in description = "D-Bus session bus"; requires = [ "session-bus.socket" ]; serviceConfig = { - ImportCredential = "sidebus.port"; # inherited by the activated agent.. ExecStart = "${pkgs.dbus}/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --syslog-only"; # no systemd activation, we don't run a *session* systemd User = "appvm"; Group = "appvm"; }; }; - services.dbus.packages = [ - (pkgs.writeTextDir "/share/dbus-1/services/org.freedesktop.portal.Desktop.service" '' - [D-BUS Service] - Name=org.freedesktop.portal.Desktop - Exec=${sidebus.packages.${system}.sidebus-agent}/bin/sidebus-agent - '') - ]; + systemd.services.sidebus-agent = { + enable = true; + description = "D-Bus session bus"; + wantedBy = ["microvm.target"]; + requires = ["session-bus.socket" "session-bus.service"]; + after = ["session-bus.service"]; + serviceConfig = { + ImportCredential = "sidebus.port"; + Environment = ["DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock"]; + ExecStart = "${sidebus.packages.${system}.sidebus-agent}/bin/sidebus-agent"; + User = "appvm"; + Group = "appvm"; + }; + }; hardware.graphics.enable = true; hardware.graphics.package = self.packages.${system}.mesa; From 612453a3bc9af833685344274056b5cc4e37a6d6 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 12 Dec 2025 06:00:51 -0300 Subject: [PATCH 53/81] Update sidebus --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 0815175..174dfc0 100644 --- a/flake.lock +++ b/flake.lock @@ -162,10 +162,10 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1764933524, - "narHash": "sha256-yland30CesTKgckWiWNMasfotzTspQzVaDqoKbrC4Fo=", + "lastModified": 1765527875, + "narHash": "sha256-QKsl+TAjdd1qk8Nd9mlByz07S+kGi8voSxxTdUNjt6A=", "ref": "main", - "rev": "52c3ea7cd36c816e00a6057e91cd945afda177d0", + "rev": "c9095421c6ec33e7293879d2df9d050991200803", "shallow": true, "type": "git", "url": "https://git.clan.lol/clan/sidebus" From 214d4c450093025eb4a85f9ff83d3d21a8d25337 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 18 Dec 2025 04:29:53 -0300 Subject: [PATCH 54/81] nixos: set shell for appvm user Surprisingly, gdb of all things uses the login shell from /etc/passwd to launch the program under test, so I was seeing the "This account is currently not available" message there. --- nixosModules/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 813a1f9..9fb752c 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -191,6 +191,7 @@ in isSystemUser = true; home = "/home/appvm"; description = "microVM User"; + shell = pkgs.bash; # not nologin, despite being a "system" user extraGroups = [ "wheel" "video" From 06a26e7deedeeee5f003f686b724082176ee67c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Thu, 15 Jan 2026 17:09:43 +0100 Subject: [PATCH 55/81] munix: add -- before command args to prevent option parsing muvm was interpreting command arguments like '-c' (from /bin/sh -c) as its own options. Adding '--' separates muvm options from the command and its arguments. --- munix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/munix b/munix index 3921ca9..d10e091 100755 --- a/munix +++ b/munix @@ -205,5 +205,5 @@ bwrap --unshare-all --share-net \ -e container=munix \ -e MICROVM_CLOSURE="$MICROVM_CLOSURE" \ -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \ - -i -t "${MICROVM_COMMAND[@]}" \ + -i -t -- "${MICROVM_COMMAND[@]}" \ 13< /etc/resolv.conf From 2d7860294d3e0f6dfb07aa59fee649e8058ee60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Fri, 16 Jan 2026 15:10:12 +0100 Subject: [PATCH 56/81] switch from flake-utils to flake-parts there is not so much of a difference in this project, but it means adding this project to clan, one less flake input and also more consistency with other projects in clan. --- flake.lock | 59 ++++++++----------- flake.nix | 166 +++++++++++++++++++++++++++++------------------------ 2 files changed, 113 insertions(+), 112 deletions(-) diff --git a/flake.lock b/flake.lock index 174dfc0..a5802ed 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,25 @@ { "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1768135262, + "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -22,24 +42,6 @@ "inputs": { "systems": "systems_2" }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_3": { - "inputs": { - "systems": "systems_3" - }, "locked": { "lastModified": 1710146030, "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", @@ -123,7 +125,7 @@ }, "root": { "inputs": { - "flake-utils": "flake-utils", + "flake-parts": "flake-parts", "libkrun-src": "libkrun-src", "libkrunfw-src": "libkrunfw-src", "muvm-src": "muvm-src", @@ -155,7 +157,7 @@ }, "sidebus": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils", "nixpkgs": [ "nixpkgs" ], @@ -207,24 +209,9 @@ "type": "github" } }, - "systems_3": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "virtwl": { "inputs": { - "flake-utils": "flake-utils_3", + "flake-utils": "flake-utils_2", "nixpkgs": [ "nixpkgs" ] diff --git a/flake.nix b/flake.nix index da67b2a..99ac54b 100644 --- a/flake.nix +++ b/flake.nix @@ -6,9 +6,13 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; + + flake-parts.url = "github:hercules-ci/flake-parts"; + flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; + virtwl.url = "git+https://github.com/valpackett/wayland-proxy-virtwl?shallow=1&submodules=1&ref=wip"; virtwl.inputs.nixpkgs.follows = "nixpkgs"; + sidebus.url = "git+https://git.clan.lol/clan/sidebus?shallow=1&ref=main"; sidebus.inputs.nixpkgs.follows = "nixpkgs"; @@ -28,10 +32,10 @@ }; outputs = - { + inputs@{ self, nixpkgs, - flake-utils, + flake-parts, virtwl, sidebus, muvm-src, @@ -39,88 +43,98 @@ libkrunfw-src, ... }: - { - nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { inherit virtwl; }; - nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { - inherit self virtwl sidebus; - }; + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ + "x86_64-linux" + "aarch64-linux" + ]; - templates.musictest = { - description = "Music player demo VM with MPD and Euphonica"; - path = ./templates/musictest; - }; - - nixosConfigurations.testvm-x86_64 = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ - self.nixosModules.default - self.nixosModules.testvm - { nixpkgs.config.allowUnfree = true; } - ]; - }; - - nixosConfigurations.testvm-aarch64 = nixpkgs.lib.nixosSystem { - system = "aarch64-linux"; - modules = [ - self.nixosModules.default - self.nixosModules.testvm - { nixpkgs.config.allowUnfree = true; } - ]; - }; - } - // flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] ( - system: - let - pkgs = import nixpkgs { - inherit system; - config.allowUnfree = true; + flake = { + nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { inherit virtwl; }; + nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { + inherit self virtwl sidebus; }; - in - { - checks = - (pkgs.lib.mapAttrs' (n: pkgs.lib.nameValuePair "package-${n}") self.packages.${system}) - // (pkgs.lib.mapAttrs' (n: pkgs.lib.nameValuePair "devShell-${n}") self.devShells.${system}) - // (pkgs.lib.optionalAttrs (system == "x86_64-linux") { - nixos-testvm = self.nixosConfigurations.testvm-x86_64.config.system.build.toplevel; - }) - // (pkgs.lib.optionalAttrs (system == "aarch64-linux") { - nixos-testvm = self.nixosConfigurations.testvm-aarch64.config.system.build.toplevel; - }); + templates.musictest = { + description = "Music player demo VM with MPD and Euphonica"; + path = ./templates/musictest; + }; - packages = { - # Packages support variant parameter: null (default), "sev", or "tdx" - # To build a variant: packages.libkrunfw.override { variant = "sev"; } - libkrunfw = pkgs.callPackage ./packages/libkrunfw { - libkrunfw-src = libkrunfw-src; + nixosConfigurations.testvm-x86_64 = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + self.nixosModules.default + self.nixosModules.testvm + { nixpkgs.config.allowUnfree = true; } + ]; + }; + + nixosConfigurations.testvm-aarch64 = nixpkgs.lib.nixosSystem { + system = "aarch64-linux"; + modules = [ + self.nixosModules.default + self.nixosModules.testvm + { nixpkgs.config.allowUnfree = true; } + ]; + }; + }; + + perSystem = + { + pkgs, + system, + self', + ... + }: + { + _module.args.pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; }; - libkrun = pkgs.callPackage ./packages/libkrun { - libkrunfw = self.packages.${system}.libkrunfw; - libkrun-src = libkrun-src; + checks = + (pkgs.lib.mapAttrs' (n: pkgs.lib.nameValuePair "package-${n}") self'.packages) + // (pkgs.lib.mapAttrs' (n: pkgs.lib.nameValuePair "devShell-${n}") self'.devShells) + // (pkgs.lib.optionalAttrs (system == "x86_64-linux") { + nixos-testvm = self.nixosConfigurations.testvm-x86_64.config.system.build.toplevel; + }) + // (pkgs.lib.optionalAttrs (system == "aarch64-linux") { + nixos-testvm = self.nixosConfigurations.testvm-aarch64.config.system.build.toplevel; + }); + + packages = { + # Packages support variant parameter: null (default), "sev", or "tdx" + # To build a variant: packages.libkrunfw.override { variant = "sev"; } + libkrunfw = pkgs.callPackage ./packages/libkrunfw { + libkrunfw-src = libkrunfw-src; + }; + + libkrun = pkgs.callPackage ./packages/libkrun { + libkrunfw = self'.packages.libkrunfw; + libkrun-src = libkrun-src; + }; + + mesa = pkgs.callPackage ./packages/mesa { }; + + muvm = pkgs.callPackage ./packages/muvm { + libkrun = self'.packages.libkrun; + muvm-src = muvm-src; + }; + + munix = pkgs.callPackage ./packages/munix { + mesa = self'.packages.mesa; + muvm = self'.packages.muvm; + sidebus-broker = sidebus.packages.${system}.sidebus-broker; + }; + + sidebus-agent = sidebus.packages.${system}.sidebus-agent; }; - mesa = pkgs.callPackage ./packages/mesa { }; - - muvm = pkgs.callPackage ./packages/muvm { - libkrun = self.packages.${system}.libkrun; - muvm-src = muvm-src; - }; - - munix = pkgs.callPackage ./packages/munix { - mesa = self.packages.${system}.mesa; - muvm = self.packages.${system}.muvm; + devShells.default = pkgs.callPackage ./devShells { + libkrun = self'.packages.libkrun; + muvm = self'.packages.muvm; sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; - - sidebus-agent = sidebus.packages.${system}.sidebus-agent; }; - - devShells.default = pkgs.callPackage ./devShells { - libkrun = self.packages.${system}.libkrun; - muvm = self.packages.${system}.muvm; - sidebus-broker = sidebus.packages.${system}.sidebus-broker; - }; - } - ); + }; } From 447ccad362e8d3c93b81b3a6da3ac4f0c0431a1e Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 9 Jan 2026 06:55:11 -0300 Subject: [PATCH 57/81] nix: devShell: add packages for proxy development --- devShells/default.nix | 52 +++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/devShells/default.nix b/devShells/default.nix index 7648228..382eb7b 100644 --- a/devShells/default.nix +++ b/devShells/default.nix @@ -1,17 +1,45 @@ -{ mkShell, lib, systemd, cargo, rust-analyzer, rustfmt, passt, bubblewrap, libkrun, muvm, sidebus-broker }: +{ + mkShell, + lib, + systemd, + cargo, + rust-analyzer, + rustfmt, + passt, + bubblewrap, + libkrun, + muvm, + sidebus-broker, + pkgs, +}: let - projects = [ libkrun muvm ]; -in mkShell { + projects = [ + libkrun + muvm + ]; +in +mkShell { MUVM_UDEVD_PATH = "${systemd}/lib/systemd/systemd-udevd"; nativeBuildInputs = lib.concatMap (pkg: pkg.nativeBuildInputs) projects; - buildInputs = (lib.concatMap (pkg: pkg.buildInputs) projects) ++ [ - # virglrenderer - cargo - rust-analyzer - rustfmt - passt - bubblewrap - sidebus-broker - ]; + buildInputs = + (lib.concatMap (pkg: pkg.buildInputs) projects) + ++ [ + # virglrenderer + cargo + rust-analyzer + rustfmt + passt + bubblewrap + sidebus-broker + ] + ++ (with pkgs; [ + meson + wayland + wayland-protocols + wayland-scanner + cairo + libgbm + ]); + # Enough things to compile wl-cross-domain-proxy, muvm, etc. in development } From c11c6c62920c2cedee75e31e1366b6b199bc207f Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 29 Jan 2026 20:54:42 -0300 Subject: [PATCH 58/81] nix: update inputs --- flake.lock | 30 +++++++++++++++--------------- flake.nix | 6 +++--- packages/libkrunfw/default.nix | 6 +++--- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/flake.lock b/flake.lock index a5802ed..ffed8c6 100644 --- a/flake.lock +++ b/flake.lock @@ -59,61 +59,61 @@ "libkrun-src": { "flake": false, "locked": { - "lastModified": 1764837222, - "narHash": "sha256-Q4uFc3gvo6AuN1fAuUWU8k/+idOuDEj8Pkhm80wE798=", + "lastModified": 1767965092, + "narHash": "sha256-6HBSL5Zu29sDoEbZeQ6AsNIXUcqXVVGMk0AR2X6v1yU=", "owner": "containers", "repo": "libkrun", - "rev": "b250ee6fff7d959da3d55bb62ffe09d87248651c", + "rev": "376f25637c49f26231ec92532f31a24b99236aa6", "type": "github" }, "original": { "owner": "containers", "repo": "libkrun", - "rev": "b250ee6fff7d959da3d55bb62ffe09d87248651c", + "rev": "376f25637c49f26231ec92532f31a24b99236aa6", "type": "github" } }, "libkrunfw-src": { "flake": false, "locked": { - "lastModified": 1762790667, - "narHash": "sha256-tVQ0jGef8uJNo2L4Pmhy3ajVRKJ2Gs9oi44eOYAnmds=", + "lastModified": 1765874399, + "narHash": "sha256-x9HQP+EqCteoCq2Sl/TQcfdzQC5iuE4gaSKe7tN5dAA=", "owner": "containers", "repo": "libkrunfw", - "rev": "8a8c33f24f72aa6ca017347dc2be45b6fa612af5", + "rev": "20484a2e60290acb74c43ccfd6e1ea4caf41d470", "type": "github" }, "original": { "owner": "containers", "repo": "libkrunfw", - "rev": "8a8c33f24f72aa6ca017347dc2be45b6fa612af5", + "rev": "20484a2e60290acb74c43ccfd6e1ea4caf41d470", "type": "github" } }, "muvm-src": { "flake": false, "locked": { - "lastModified": 1763708092, - "narHash": "sha256-8K9XDnQbl/fh1Bsx1SwFuo5WVy5BztCjMPT6NW01lXQ=", + "lastModified": 1769336998, + "narHash": "sha256-ZFtAYwr3AaD8WsDmXJ6eU12UojzfMm50UBWmWIXstl0=", "owner": "valpackett", "repo": "muvm", - "rev": "3ec4c90bbfb6d0111f91b898a7f17deb562f4f92", + "rev": "ae7dbd49aac04e9732a14a424572e99a81eb1298", "type": "github" }, "original": { "owner": "valpackett", "repo": "muvm", - "rev": "3ec4c90bbfb6d0111f91b898a7f17deb562f4f92", + "rev": "ae7dbd49aac04e9732a14a424572e99a81eb1298", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1764242076, - "narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=", + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 99ac54b..48acdaf 100644 --- a/flake.nix +++ b/flake.nix @@ -18,15 +18,15 @@ # To override with local checkouts during development, use the --override-input CLI flag! muvm-src = { - url = "github:valpackett/muvm/3ec4c90bbfb6d0111f91b898a7f17deb562f4f92"; + url = "github:valpackett/muvm/ae7dbd49aac04e9732a14a424572e99a81eb1298"; # v0.5.0+custom-init flake = false; }; libkrun-src = { - url = "github:containers/libkrun/b250ee6fff7d959da3d55bb62ffe09d87248651c"; + url = "github:containers/libkrun/376f25637c49f26231ec92532f31a24b99236aa6"; # v1.17.0 flake = false; }; libkrunfw-src = { - url = "github:containers/libkrunfw/8a8c33f24f72aa6ca017347dc2be45b6fa612af5"; + url = "github:containers/libkrunfw/20484a2e60290acb74c43ccfd6e1ea4caf41d470"; # v5.1.0 flake = false; }; }; diff --git a/packages/libkrunfw/default.nix b/packages/libkrunfw/default.nix index 668e016..d17d3b7 100644 --- a/packages/libkrunfw/default.nix +++ b/packages/libkrunfw/default.nix @@ -3,10 +3,10 @@ (libkrunfw.override { inherit variant; }).overrideAttrs (old: { - version = "5.0.0"; + version = "5.1.0"; src = libkrunfw-src; kernelSrc = fetchurl { - url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.44.tar.xz"; - hash = "sha256-tlAhDtMCeyJJadFIqjd0Uqmq065/KFGr7dMa3+8Wva4="; + url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.62.tar.xz"; + hash = "sha256-E+LGhayPq13Zkt0QVzJVTa5RSu81DCqMdBjnt062LBM="; }; }) From 40d82a0fd82a621d67acebbf49a0283b50f0a429 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Thu, 29 Jan 2026 23:26:36 -0300 Subject: [PATCH 59/81] nix: use static userborn as it's upstream now --- nixosModules/default.nix | 41 +--------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 9fb752c..78c7238 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -18,31 +18,6 @@ let StandardError = "tty"; }; runtimeDir = "/run/vm-user"; - userbornConfig = { - groups = lib.mapAttrsToList (username: opts: { - inherit (opts) name gid members; - }) config.users.groups; - users = lib.mapAttrsToList (username: opts: { - inherit (opts) - name - uid - group - description - home - password - hashedPassword - hashedPasswordFile - initialPassword - initialHashedPassword - ; - isNormal = opts.isNormalUser; - shell = utils.toShellPath opts.shell; - }) (lib.filterAttrs (_: u: u.enable) config.users.users); - }; - userbornConfigJson = pkgs.writeText "userborn.json" (builtins.toJSON userbornConfig); - userbornResults = - pkgs.runCommand "baked userborn" { } - "mkdir -p $out; ${lib.getExe pkgs.userborn} ${userbornConfigJson} $out"; system = pkgs.stdenv.hostPlatform.system; in { @@ -166,23 +141,9 @@ in }; # Configure user accounts - # The immutable overlay wants userborn or sysusers.. we just want baked-in files w/o running a service. - # So we can just run userborn at system closure build time! systemd.sysusers.enable = false; services.userborn.enable = true; - systemd.services.userborn.enable = false; - environment.etc."passwd" = lib.mkForce { - source = "${userbornResults}/passwd"; - mode = "0444"; - }; - environment.etc."group" = lib.mkForce { - source = "${userbornResults}/group"; - mode = "0444"; - }; - environment.etc."shadow" = lib.mkForce { - source = "${userbornResults}/shadow"; - mode = "0440"; - }; + services.userborn.static = true; users.mutableUsers = false; users.users.appvm = { uid = 1337; From c89c9e4d9b4b067cf8ae915c35abfd6fb5ec76bd Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 30 Jan 2026 01:39:11 -0300 Subject: [PATCH 60/81] nix: testvm: more test apps --- nixosModules/testvm.nix | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix index 786d915..5acee69 100644 --- a/nixosModules/testvm.nix +++ b/nixosModules/testvm.nix @@ -16,8 +16,8 @@ pkgs.mesa-demos pkgs.xorg.xeyes pkgs.xterm - # pkgs.vkquake # build broken: Program 'spirv-remap' not found - # pkgs.veloren # broken after update? + pkgs.vkquake + # pkgs.veloren pkgs.kdePackages.kate pkgs.adwaita-icon-theme pkgs.amberol @@ -33,5 +33,6 @@ pkgs.zerotierone pkgs.localsend pkgs.ashpd-demo + pkgs.wl-clipboard-rs ]; } From 13b2afcc14cb03a9d1cacf24c89616df2efba204 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 30 Jan 2026 03:16:06 -0300 Subject: [PATCH 61/81] nix: add package for wl-cross-domain-proxy --- flake.nix | 2 + packages/wl-cross-domain-proxy/default.nix | 44 ++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 packages/wl-cross-domain-proxy/default.nix diff --git a/flake.nix b/flake.nix index 48acdaf..7b3fdbd 100644 --- a/flake.nix +++ b/flake.nix @@ -128,6 +128,8 @@ }; sidebus-agent = sidebus.packages.${system}.sidebus-agent; + + wl-cross-domain-proxy = pkgs.callPackage ./packages/wl-cross-domain-proxy { }; }; devShells.default = pkgs.callPackage ./devShells { diff --git a/packages/wl-cross-domain-proxy/default.nix b/packages/wl-cross-domain-proxy/default.nix new file mode 100644 index 0000000..0ca436b --- /dev/null +++ b/packages/wl-cross-domain-proxy/default.nix @@ -0,0 +1,44 @@ +{ + lib, + rustPlatform, + # fetchpatch, + fetchFromGitea, + pkg-config, + libdrm, +}: + +# TODO: upstream +rustPlatform.buildRustPackage { + pname = "wl-cross-domain-proxy"; + version = "0-unstable-2026-01-30"; + + src = fetchFromGitea { + domain = "codeberg.org"; + owner = "drakulix"; + repo = "wl-cross-domain-proxy"; + rev = "c6ce1ca89fb4d6f4f18d3aaf88324d40d4589177"; + hash = "sha256-ydyT4DFzWzhzOZR591UOgLjVQt/v6hRSNjzM3QtohlU="; + }; + + nativeBuildInputs = [ pkg-config ]; + + buildInputs = [ libdrm ]; + + cargoHash = "sha256-k3dmxIuCQoOrn/VwauTdzuRw/XKQB6LPLgO5ql0rE7E="; + cargoPatches = [ + # (fetchpatch { + # name = "XXX.patch"; + # url = "https://codeberg.org/drakulix/wl-cross-domain-proxy/pulls/XXX.patch"; + # hash = lib.fakeHash; + # }) + ]; + + meta = { + homepage = "https://codeberg.org/drakulix/wl-cross-domain-proxy"; + description = "Proxy for the wayland protocol across virtio-gpu cross-domain context"; + mainProgram = "wl-cross-domain-proxy"; + platforms = lib.platforms.linux; + license = [ lib.licenses.mit ]; + maintainers = [ lib.maintainers.valpackett ]; + }; +} From 9911b15fb7301c27a23be76daf11a9131229d868 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 30 Jan 2026 03:16:48 -0300 Subject: [PATCH 62/81] nix: switch to wl-cross-domain-proxy --- nixosModules/default.nix | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 78c7238..f56a5f0 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -1,6 +1,5 @@ { self, - virtwl, sidebus, }: { @@ -223,11 +222,11 @@ in serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge"; }; - systemd.sockets.wayland-proxy-virtwl = { + systemd.sockets.wayland-proxy = { enable = true; description = "Wayland cross-domain proxy socket"; wantedBy = [ "microvm.target" ]; - partOf = [ "wayland-proxy-virtwl.service" ]; + partOf = [ "wayland-proxy.service" ]; listenStreams = [ "${runtimeDir}/wayland-1" ]; socketConfig = { SocketUser = "appvm"; @@ -235,13 +234,13 @@ in FileDescriptorName = "wayland"; }; }; - systemd.services.wayland-proxy-virtwl = { + systemd.services.wayland-proxy = { enable = true; description = "Wayland cross-domain proxy"; - requires = [ "wayland-proxy-virtwl.socket" ]; + requires = [ "wayland-proxy.socket" ]; serviceConfig = { ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"; - ExecStart = "${virtwl.packages.${system}.proxy}/bin/wayland-proxy-virtwl --virtio-gpu"; + ExecStart = "${self.packages.${system}.wl-cross-domain-proxy}/bin/wl-cross-domain-proxy --listen-fd --filter-global wp_presentation"; User = "appvm"; Group = "appvm"; }; From 425ff896c80773b40cef7c1c65f502eedcaecb62 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 30 Jan 2026 04:27:46 -0300 Subject: [PATCH 63/81] nix: deorbit virtwl-proxy --- flake.lock | 61 +---------------------------------------- flake.nix | 8 ++---- nixosModules/testvm.nix | 3 +- 3 files changed, 4 insertions(+), 68 deletions(-) diff --git a/flake.lock b/flake.lock index ffed8c6..5192622 100644 --- a/flake.lock +++ b/flake.lock @@ -38,24 +38,6 @@ "type": "github" } }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "libkrun-src": { "flake": false, "locked": { @@ -130,8 +112,7 @@ "libkrunfw-src": "libkrunfw-src", "muvm-src": "muvm-src", "nixpkgs": "nixpkgs", - "sidebus": "sidebus", - "virtwl": "virtwl" + "sidebus": "sidebus" } }, "rust-overlay": { @@ -193,46 +174,6 @@ "repo": "default", "type": "github" } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "virtwl": { - "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1758075582, - "narHash": "sha256-o2lpXQLaM9QcZVr+sAxvh83CqJW1QkFhfja6K40ndmA=", - "ref": "wip", - "rev": "5a5df73a11b2f6bf671a8fc89926ac993e0fbb78", - "shallow": true, - "submodules": true, - "type": "git", - "url": "https://github.com/valpackett/wayland-proxy-virtwl" - }, - "original": { - "ref": "wip", - "shallow": true, - "submodules": true, - "type": "git", - "url": "https://github.com/valpackett/wayland-proxy-virtwl" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 7b3fdbd..c4ef335 100644 --- a/flake.nix +++ b/flake.nix @@ -10,9 +10,6 @@ flake-parts.url = "github:hercules-ci/flake-parts"; flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; - virtwl.url = "git+https://github.com/valpackett/wayland-proxy-virtwl?shallow=1&submodules=1&ref=wip"; - virtwl.inputs.nixpkgs.follows = "nixpkgs"; - sidebus.url = "git+https://git.clan.lol/clan/sidebus?shallow=1&ref=main"; sidebus.inputs.nixpkgs.follows = "nixpkgs"; @@ -36,7 +33,6 @@ self, nixpkgs, flake-parts, - virtwl, sidebus, muvm-src, libkrun-src, @@ -50,9 +46,9 @@ ]; flake = { - nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { inherit virtwl; }; + nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { }; nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { - inherit self virtwl sidebus; + inherit self sidebus; }; templates.musictest = { diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix index 5acee69..4fa8c0d 100644 --- a/nixosModules/testvm.nix +++ b/nixosModules/testvm.nix @@ -1,4 +1,4 @@ -{ virtwl }: +{ }: { pkgs, ... }: { system.stateVersion = "25.11"; @@ -7,7 +7,6 @@ environment.systemPackages = [ pkgs.fastfetch pkgs.htop - virtwl.packages.${pkgs.stdenv.hostPlatform.system}.proxy pkgs.wayland-utils pkgs.weston pkgs.waycheck From 38213f4adab988424a6f124838c9b9903787b092 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 30 Jan 2026 04:35:25 -0300 Subject: [PATCH 64/81] munix: add publish argument for port forwarding, fix #11 TODO: fix https://github.com/AsahiLinux/muvm/issues/178 as well --- munix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/munix b/munix index d10e091..e10b715 100755 --- a/munix +++ b/munix @@ -14,6 +14,7 @@ GPU=1 WAYLAND=1 PIPEWIRE=1 X11=0 +USING_PUBLISH=0 export TMP=/tmp TMPDIR=/tmp TEMP=/tmp TEMPDIR=/tmp LC_ALL=C if [ ! -e "$HOST_OPENGL_DRIVER" ]; then @@ -32,6 +33,7 @@ while [ "$#" -gt 0 ]; do --ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); shift 3;; --expose) BWRAP_ARGS+=("--bind" "$2" "$2"); shift 2;; --ro-expose) BWRAP_ARGS+=("--ro-bind" "$2" "$2"); shift 2;; + -p|--publish) USING_PUBLISH=1; MUVM_ARGS+=("--publish=$2"); shift 2;; --host-opengl-driver) HOST_OPENGL_DRIVER="$2"; shift 2;; --munix-bin-dir) SCRIPT_PATH="$2"; shift 2;; --muvm-bin-dir) MUVM_PATH="$2"; shift 2;; @@ -177,6 +179,10 @@ BWRAP_ARGS+=( --bind "$HOST_RUNTIME_DIR/port.sock" "$XDG_RUNTIME_DIR/krun/socket/port-50000" ) +if [ "$USING_PUBLISH" -eq 1 ]; then + printf "\n\n\n\e[1mNote: due to a \e[31mBUG\e[39m with port publishing (-p) you have to send the first outgoing packet (e.g. ping -c1 8.8.8.8) before your ports start receiving traffic. Sorry for the inconvenience!\e[39;0m\n\n\n\n" >&2 +fi + # do not 'exec' because of cleanup :) bwrap --unshare-all --share-net \ --uid $MICROVM_UID --gid $MICROVM_GID \ From 8113c269cb738ea3e63131f081e744593b80c171 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 30 Jan 2026 05:45:02 -0300 Subject: [PATCH 65/81] munix: add more arg shorthands --- munix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/munix b/munix index e10b715..14e777d 100755 --- a/munix +++ b/munix @@ -29,9 +29,9 @@ while [ "$#" -gt 0 ]; do --no-wayland) WAYLAND=0; shift 1;; --no-pipewire) PIPEWIRE=0; shift 1;; --x11) X11=1; shift 1;; - --bind) BWRAP_ARGS+=("--bind" "$2" "$3"); shift 3;; + -b|--bind) BWRAP_ARGS+=("--bind" "$2" "$3"); shift 3;; --ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); shift 3;; - --expose) BWRAP_ARGS+=("--bind" "$2" "$2"); shift 2;; + -e|--expose) BWRAP_ARGS+=("--bind" "$2" "$2"); shift 2;; --ro-expose) BWRAP_ARGS+=("--ro-bind" "$2" "$2"); shift 2;; -p|--publish) USING_PUBLISH=1; MUVM_ARGS+=("--publish=$2"); shift 2;; --host-opengl-driver) HOST_OPENGL_DRIVER="$2"; shift 2;; From a82b0de3101c6167a9483cf6c07247c2e18d1b53 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 30 Jan 2026 05:47:28 -0300 Subject: [PATCH 66/81] munix: set wayland/pw/portal enablement variables for toolkits by default --- munix | 22 ++++++++++++++++++++++ nixosModules/default.nix | 13 +++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/munix b/munix index 14e777d..241073b 100755 --- a/munix +++ b/munix @@ -14,6 +14,7 @@ GPU=1 WAYLAND=1 PIPEWIRE=1 X11=0 +ENV_DEFAULTS=1 USING_PUBLISH=0 export TMP=/tmp TMPDIR=/tmp TEMP=/tmp TEMPDIR=/tmp LC_ALL=C @@ -28,6 +29,7 @@ while [ "$#" -gt 0 ]; do --no-gpu) GPU=0; shift 1;; --no-wayland) WAYLAND=0; shift 1;; --no-pipewire) PIPEWIRE=0; shift 1;; + --no-env-defaults) ENV_DEFAULTS=0; shift 1;; --x11) X11=1; shift 1;; -b|--bind) BWRAP_ARGS+=("--bind" "$2" "$3"); shift 3;; --ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); shift 3;; @@ -125,6 +127,15 @@ if [ "$WAYLAND" -eq 1 ]; then "--setenv" "WAYLAND_DISPLAY" "$WAYLAND_DISPLAY" ) MUVM_ARGS+=("-e" "WAYLAND_DISPLAY=wayland-1") # the proxy is managed by us, not muvm + if [ "$ENV_DEFAULTS" -eq 1 ]; then + MUVM_ARGS+=( + "-e" "XDG_SESSION_TYPE=wayland" + "-e" "SDL_VIDEODRIVER=wayland" + "-e" "QT_QPA_PLATFORM=wayland" + "-e" "_JAVA_AWT_WM_NONREPARENTING=1" # e.g. with xwayland-satellite + "-e" "ELECTRON_OZONE_PLATFORM_HINT=wayland" # 28 < Electron < 39; newer should work by default + ) + fi fi if [ "$PIPEWIRE" -eq 1 ]; then @@ -142,6 +153,11 @@ if [ "$PIPEWIRE" -eq 1 ]; then PIPEWIRE_REMOTE=pipewire-0 fi BWRAP_ARGS+=("--bind" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE") + if [ "$ENV_DEFAULTS" -eq 1 ]; then + MUVM_ARGS+=( + "-e" "SDL_AUDIO_DRIVER=pipewire" + ) + fi fi if [ "$X11" -eq 1 ]; then @@ -178,6 +194,12 @@ BWRAP_ARGS+=( --bind "$HOST_RUNTIME_DIR" /mnt/munix-doc-portal --bind "$HOST_RUNTIME_DIR/port.sock" "$XDG_RUNTIME_DIR/krun/socket/port-50000" ) +if [ "$ENV_DEFAULTS" -eq 1 ]; then + MUVM_ARGS+=( + "-e" "GTK_USE_PORTAL=1" # GTK 3 including Firefox + "-e" "QT_QPA_PLATFORMTHEME=xdgdesktopportal" + ) +fi if [ "$USING_PUBLISH" -eq 1 ]; then printf "\n\n\n\e[1mNote: due to a \e[31mBUG\e[39m with port publishing (-p) you have to send the first outgoing packet (e.g. ping -c1 8.8.8.8) before your ports start receiving traffic. Sorry for the inconvenience!\e[39;0m\n\n\n\n" >&2 diff --git a/nixosModules/default.nix b/nixosModules/default.nix index f56a5f0..217a3ed 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -177,10 +177,19 @@ in serviceConfig = { Type = "exec"; PassEnvironment = [ - "TERM" "MESA_LOADER_DRIVER_OVERRIDE" "MUVM_REMOTE_CONFIG" - ]; # "KRUN_CONFIG"]; + # "KRUN_CONFIG" + + "TERM" + "XDG_SESSION_TYPE" + "SDL_VIDEODRIVER" + "QT_QPA_PLATFORM" + "_JAVA_AWT_WM_NONREPARENTING" + "ELECTRON_OZONE_PLATFORM_HINT" + "GTK_USE_PORTAL" + "QT_QPA_PLATFORMTHEME" + ]; Environment = [ "WAYLAND_DISPLAY=wayland-1" "DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock" From 585970fe9204fe43d695b048da773252d2777af3 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 30 Jan 2026 06:11:21 -0300 Subject: [PATCH 67/81] munix: do not set display from the script It is now entirely managed by systemd. --- munix | 1 - 1 file changed, 1 deletion(-) diff --git a/munix b/munix index 241073b..9c67084 100755 --- a/munix +++ b/munix @@ -126,7 +126,6 @@ if [ "$WAYLAND" -eq 1 ]; then "--bind" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "--setenv" "WAYLAND_DISPLAY" "$WAYLAND_DISPLAY" ) - MUVM_ARGS+=("-e" "WAYLAND_DISPLAY=wayland-1") # the proxy is managed by us, not muvm if [ "$ENV_DEFAULTS" -eq 1 ]; then MUVM_ARGS+=( "-e" "XDG_SESSION_TYPE=wayland" From 67666b8f46fbbb59d0756bcaf1fc964101bf8fe8 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 30 Jan 2026 06:12:47 -0300 Subject: [PATCH 68/81] nix: update sidebus and flake-parts sidebus now uses flake-parts too --- flake.lock | 73 ++++++++---------------------------------------------- flake.nix | 1 + 2 files changed, 11 insertions(+), 63 deletions(-) diff --git a/flake.lock b/flake.lock index 5192622..7f03055 100644 --- a/flake.lock +++ b/flake.lock @@ -7,11 +7,11 @@ ] }, "locked": { - "lastModified": 1768135262, - "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", + "lastModified": 1769996383, + "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", + "rev": "57928607ea566b5db3ad13af0e57e921e6b12381", "type": "github" }, "original": { @@ -20,24 +20,6 @@ "type": "github" } }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "libkrun-src": { "flake": false, "locked": { @@ -115,40 +97,20 @@ "sidebus": "sidebus" } }, - "rust-overlay": { + "sidebus": { "inputs": { + "flake-parts": [ + "flake-parts" + ], "nixpkgs": [ - "sidebus", "nixpkgs" ] }, "locked": { - "lastModified": 1763087910, - "narHash": "sha256-eB9Z1mWd1U6N61+F8qwDggX0ihM55s4E0CluwNukJRU=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "cf4a68749733d45c0420726596367acd708eb2e8", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "sidebus": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": [ - "nixpkgs" - ], - "rust-overlay": "rust-overlay" - }, - "locked": { - "lastModified": 1765527875, - "narHash": "sha256-QKsl+TAjdd1qk8Nd9mlByz07S+kGi8voSxxTdUNjt6A=", + "lastModified": 1770365107, + "narHash": "sha256-rp2hDKF3pwHN0lBr09ckMNaMSJnwNolQmiad8C7u41Q=", "ref": "main", - "rev": "c9095421c6ec33e7293879d2df9d050991200803", + "rev": "26261306592f6173fb844083b396bebf8140cb2b", "shallow": true, "type": "git", "url": "https://git.clan.lol/clan/sidebus" @@ -159,21 +121,6 @@ "type": "git", "url": "https://git.clan.lol/clan/sidebus" } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index c4ef335..687042e 100644 --- a/flake.nix +++ b/flake.nix @@ -12,6 +12,7 @@ sidebus.url = "git+https://git.clan.lol/clan/sidebus?shallow=1&ref=main"; sidebus.inputs.nixpkgs.follows = "nixpkgs"; + sidebus.inputs.flake-parts.follows = "flake-parts"; # To override with local checkouts during development, use the --override-input CLI flag! muvm-src = { From 9708e5fb6464ea1d9f8f5928c2eb843ff6f33746 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sat, 7 Feb 2026 00:17:41 -0300 Subject: [PATCH 69/81] nix: update nixpkgs now includes the most recent libkrun(fw) releases --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 7f03055..321368e 100644 --- a/flake.lock +++ b/flake.lock @@ -73,11 +73,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1769461804, - "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "lastModified": 1770197578, + "narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", + "rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2", "type": "github" }, "original": { From 09f1eb76de75d892d60280231a9350d4700a7a15 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sat, 7 Feb 2026 00:21:36 -0300 Subject: [PATCH 70/81] nix: comment out libkrun(fw) source overrides As we're currently using entirely upstream ones right now. Let's reuse the cache.nixos.org builds. --- flake.lock | 36 ------------------------------ flake.nix | 24 ++++++++++---------- packages/libkrun/default.nix | 40 ++++++++++++++++++++++------------ packages/libkrunfw/default.nix | 30 ++++++++++++++++--------- 4 files changed, 58 insertions(+), 72 deletions(-) diff --git a/flake.lock b/flake.lock index 321368e..ebbd7e5 100644 --- a/flake.lock +++ b/flake.lock @@ -20,40 +20,6 @@ "type": "github" } }, - "libkrun-src": { - "flake": false, - "locked": { - "lastModified": 1767965092, - "narHash": "sha256-6HBSL5Zu29sDoEbZeQ6AsNIXUcqXVVGMk0AR2X6v1yU=", - "owner": "containers", - "repo": "libkrun", - "rev": "376f25637c49f26231ec92532f31a24b99236aa6", - "type": "github" - }, - "original": { - "owner": "containers", - "repo": "libkrun", - "rev": "376f25637c49f26231ec92532f31a24b99236aa6", - "type": "github" - } - }, - "libkrunfw-src": { - "flake": false, - "locked": { - "lastModified": 1765874399, - "narHash": "sha256-x9HQP+EqCteoCq2Sl/TQcfdzQC5iuE4gaSKe7tN5dAA=", - "owner": "containers", - "repo": "libkrunfw", - "rev": "20484a2e60290acb74c43ccfd6e1ea4caf41d470", - "type": "github" - }, - "original": { - "owner": "containers", - "repo": "libkrunfw", - "rev": "20484a2e60290acb74c43ccfd6e1ea4caf41d470", - "type": "github" - } - }, "muvm-src": { "flake": false, "locked": { @@ -90,8 +56,6 @@ "root": { "inputs": { "flake-parts": "flake-parts", - "libkrun-src": "libkrun-src", - "libkrunfw-src": "libkrunfw-src", "muvm-src": "muvm-src", "nixpkgs": "nixpkgs", "sidebus": "sidebus" diff --git a/flake.nix b/flake.nix index 687042e..a7bacf1 100644 --- a/flake.nix +++ b/flake.nix @@ -19,14 +19,14 @@ url = "github:valpackett/muvm/ae7dbd49aac04e9732a14a424572e99a81eb1298"; # v0.5.0+custom-init flake = false; }; - libkrun-src = { - url = "github:containers/libkrun/376f25637c49f26231ec92532f31a24b99236aa6"; # v1.17.0 - flake = false; - }; - libkrunfw-src = { - url = "github:containers/libkrunfw/20484a2e60290acb74c43ccfd6e1ea4caf41d470"; # v5.1.0 - flake = false; - }; + # libkrun-src = { + # url = "github:containers/libkrun/376f25637c49f26231ec92532f31a24b99236aa6"; # v1.17.0 + # flake = false; + # }; + # libkrunfw-src = { + # url = "github:containers/libkrunfw/20484a2e60290acb74c43ccfd6e1ea4caf41d470"; # v5.1.0 + # flake = false; + # }; }; outputs = @@ -36,8 +36,8 @@ flake-parts, sidebus, muvm-src, - libkrun-src, - libkrunfw-src, + # libkrun-src, + # libkrunfw-src, ... }: flake-parts.lib.mkFlake { inherit inputs; } { @@ -103,12 +103,12 @@ # Packages support variant parameter: null (default), "sev", or "tdx" # To build a variant: packages.libkrunfw.override { variant = "sev"; } libkrunfw = pkgs.callPackage ./packages/libkrunfw { - libkrunfw-src = libkrunfw-src; + # libkrunfw-src = libkrunfw-src; }; libkrun = pkgs.callPackage ./packages/libkrun { libkrunfw = self'.packages.libkrunfw; - libkrun-src = libkrun-src; + # libkrun-src = libkrun-src; }; mesa = pkgs.callPackage ./packages/mesa { }; diff --git a/packages/libkrun/default.nix b/packages/libkrun/default.nix index dde2c4c..205f8d2 100644 --- a/packages/libkrun/default.nix +++ b/packages/libkrun/default.nix @@ -1,18 +1,30 @@ -{ libkrun, libkrunfw, libkrun-src, rustPlatform, variant ? null, ... }: +{ + libkrun, + libkrunfw, + # libkrun-src, + # rustPlatform, + variant ? null, + ... +}: let libkrunfw' = libkrunfw.override { inherit variant; }; -in -(libkrun.override { - withBlk = true; - withGpu = true; - withSound = true; - withNet = true; - inherit variant; - libkrunfw = libkrunfw'; -}).overrideAttrs (old: { - src = libkrun-src; - cargoDeps = rustPlatform.importCargoLock { - lockFile = "${libkrun-src}/Cargo.lock"; + libkrun' = libkrun.override { + withBlk = true; + withNet = true; + withGpu = true; + # --- stick to the override used in nixpkgs' muvm package to reuse nixos.org cache when not overriding src --- + # withSound = true; # not for pipewire forwarding, anyway + # withTimesync = true; # why not?.. + # --------- + inherit variant; + libkrunfw = libkrunfw'; }; -}) +in +libkrun' +# libkrun'.overrideAttrs (old: { +# src = libkrun-src; +# cargoDeps = rustPlatform.importCargoLock { +# lockFile = "${libkrun-src}/Cargo.lock"; +# }; +# }) diff --git a/packages/libkrunfw/default.nix b/packages/libkrunfw/default.nix index d17d3b7..c805728 100644 --- a/packages/libkrunfw/default.nix +++ b/packages/libkrunfw/default.nix @@ -1,12 +1,22 @@ -{ libkrunfw, libkrunfw-src, fetchurl, variant ? null, ... }: +{ + libkrunfw, + # libkrunfw-src, + # fetchurl, + variant ? null, + ... +}: -(libkrunfw.override { - inherit variant; -}).overrideAttrs (old: { - version = "5.1.0"; - src = libkrunfw-src; - kernelSrc = fetchurl { - url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.62.tar.xz"; - hash = "sha256-E+LGhayPq13Zkt0QVzJVTa5RSu81DCqMdBjnt062LBM="; +let + libkrunfw' = libkrunfw.override { + inherit variant; }; -}) +in +libkrunfw' +# libkrunfw'.overrideAttrs (old: { +# version = "5.1.0"; +# src = libkrunfw-src; +# kernelSrc = fetchurl { +# url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.62.tar.xz"; +# hash = "sha256-E+LGhayPq13Zkt0QVzJVTa5RSu81DCqMdBjnt062LBM="; +# }; +# }) From 53f827553f9f98fe1f2509fba0c137d8b91271d9 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sat, 7 Feb 2026 01:17:24 -0300 Subject: [PATCH 71/81] nix: add nautilus to testvm Will be useful for testing drag-out --- nixosModules/testvm.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix index 4fa8c0d..b38340a 100644 --- a/nixosModules/testvm.nix +++ b/nixosModules/testvm.nix @@ -32,6 +32,7 @@ pkgs.zerotierone pkgs.localsend pkgs.ashpd-demo + pkgs.nautilus pkgs.wl-clipboard-rs ]; } From 820fcd3da1b98bb99c84a4138062daffc8efccdf Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sat, 7 Feb 2026 01:25:06 -0300 Subject: [PATCH 72/81] nix: chase removal of etc overlay symlinks, fixes #14 --- nixosModules/default.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 217a3ed..3b229dd 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -53,6 +53,11 @@ in boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd system.etc.overlay.enable = true; # erofs system.etc.overlay.mutable = false; + system.systemBuilderCommands = # XXX: removed with the introduction of nixos-init + '' + ln -s ${config.system.build.etcMetadataImage} $out/etc-metadata-image + ln -s ${config.system.build.etcBasedir} $out/etc-basedir + ''; system.switch.enable = false; services.udev.enable = lib.mkDefault true; services.udev.packages = lib.mkDefault [ ]; From 322b6efc1c9d26f238cfbe9266f6c3d099e909fa Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 13 Feb 2026 14:55:32 -0300 Subject: [PATCH 73/81] nix: testvm: update stateVersion, add rewaita (theme coloring for demos) --- nixosModules/testvm.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix index b38340a..466cff5 100644 --- a/nixosModules/testvm.nix +++ b/nixosModules/testvm.nix @@ -1,6 +1,6 @@ { }: { pkgs, ... }: { - system.stateVersion = "25.11"; + system.stateVersion = "26.05"; fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ]; programs.dconf.enable = true; @@ -33,6 +33,7 @@ pkgs.localsend pkgs.ashpd-demo pkgs.nautilus + pkgs.rewaita pkgs.wl-clipboard-rs ]; } From 8c3878f117b1e30f3eb97d95f1095fb74ce634d9 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 13 Feb 2026 14:55:52 -0300 Subject: [PATCH 74/81] Pass timezone through to the VM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What a way to discover that this was missing- PipeWire camera was freezing unless something on the host was already streaming it… gstclock.c:1086:gst_clock_get_internal_time: internal time 1:01:04.622699903 gstclock.c:1129:gst_clock_get_time: adjusted time 5123776:20:12.866176008 Well, that wasn't even caused by the TZ but it made me think to fix it.. NOTE for local dev, rebuild micro-activate now --- micro-activate.rs | 2 ++ munix | 4 +++- nixosModules/default.nix | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/micro-activate.rs b/micro-activate.rs index d9d829c..0806e96 100644 --- a/micro-activate.rs +++ b/micro-activate.rs @@ -71,6 +71,7 @@ fn main() -> Result<(), std::io::Error> { // // Let's preserve the fixed passed-in files and set up the NixOS symlinks in the new mount. let resolv_conf = std::fs::read("/run/resolv.conf")?; + let localtime = std::fs::read("/run/localtime")?; assert_eq!( unsafe { mount( @@ -83,6 +84,7 @@ fn main() -> Result<(), std::io::Error> { }, 0 ); + std::fs::write("/run/localtime", &localtime)?; std::fs::write("/run/resolv.conf", &resolv_conf)?; std::fs::write("/run/machine-id", &gen_machine_id())?; std::os::unix::fs::symlink(&closure, "/run/current-system")?; diff --git a/munix b/munix index 9c67084..89d79c3 100755 --- a/munix +++ b/munix @@ -223,6 +223,7 @@ bwrap --unshare-all --share-net \ --symlink "$MICROVM_CLOSURE" /run/current-system \ --ro-bind /nix/store /nix/store \ --file 13 /run/resolv.conf \ + --file 14 /run/localtime \ --dir "$XDG_RUNTIME_DIR" \ --setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \ "${BWRAP_ARGS[@]}" \ @@ -233,4 +234,5 @@ bwrap --unshare-all --share-net \ -e MICROVM_CLOSURE="$MICROVM_CLOSURE" \ -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \ -i -t -- "${MICROVM_COMMAND[@]}" \ - 13< /etc/resolv.conf + 13< /etc/resolv.conf \ + 14< /etc/localtime diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 3b229dd..15a5a08 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -64,6 +64,7 @@ in services.resolved.enable = false; environment.etc."resolv.conf".source = "/run/resolv.conf"; environment.etc."machine-id".source = "/run/machine-id"; + environment.etc."localtime".source = "/run/localtime"; environment.etc."systemd/system".source = lib.mkForce ( utils.systemdUtils.lib.generateUnits { type = "system"; From 981393443b1baf5538698351516300d9e5c0a1c7 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 20 Feb 2026 04:12:54 -0300 Subject: [PATCH 75/81] Set up a monotonic clock boot time offset in the VM --- micro-activate.rs | 14 ++++++++++++++ munix | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/micro-activate.rs b/micro-activate.rs index 0806e96..776dae4 100644 --- a/micro-activate.rs +++ b/micro-activate.rs @@ -8,6 +8,8 @@ const MS_NODEV: c_ulong = 0x04; const MS_RELATIME: c_ulong = 0x200000; const MS_STRICTATIME: c_ulong = 0x1000000; +const CLONE_NEWTIME: c_int = 0x80; + unsafe extern "C" { fn mount( src: *const c_char, @@ -17,6 +19,7 @@ unsafe extern "C" { data: *const c_void, ) -> c_int; fn getrandom(buf: *mut u8, buflen: usize, flags: u32) -> c_int; + fn unshare(flags: c_int) -> c_int; } fn gen_machine_id() -> String { @@ -133,6 +136,17 @@ fn main() -> Result<(), std::io::Error> { ); } + if let Ok(offset) = std::env::var("BOOT_TIME_OFFSET") { + if unsafe { unshare(CLONE_NEWTIME) } != 0 { + eprintln!("[micro-activate] Could not unshare time!"); + } else { + std::fs::write( + "/proc/self/timens_offsets", + format!("monotonic {offset}\nboottime {offset}\n"), + )?; + } + } + let mut args = std::env::args_os().skip(1); let cmd = args.next().unwrap(); Err(std::process::Command::new(cmd).args(args).exec()) diff --git a/munix b/munix index 89d79c3..4f26980 100755 --- a/munix +++ b/munix @@ -204,6 +204,10 @@ if [ "$USING_PUBLISH" -eq 1 ]; then printf "\n\n\n\e[1mNote: due to a \e[31mBUG\e[39m with port publishing (-p) you have to send the first outgoing packet (e.g. ping -c1 8.8.8.8) before your ports start receiving traffic. Sorry for the inconvenience!\e[39;0m\n\n\n\n" >&2 fi +# xxx: some time is lost to the starting process.. +[[ "$( Date: Tue, 24 Feb 2026 11:08:33 +0100 Subject: [PATCH 76/81] fix(template): use structured settings for MPD audio output Replace deprecated extraConfig with settings.audio_output --- templates/musictest/flake.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/musictest/flake.nix b/templates/musictest/flake.nix index a2c7759..406049b 100644 --- a/templates/musictest/flake.nix +++ b/templates/musictest/flake.nix @@ -46,12 +46,12 @@ musicDirectory = "/etc/demo-music"; user = "appvm"; group = "appvm"; - extraConfig = '' - audio_output { - type "pipewire" - name "Pipewire Output" + settings.audio_output = [ + { + type = "pipewire"; + name = "Pipewire Output"; } - ''; + ]; }; environment.etc."demo-music/0101GhostsI.ogg".source = pkgs.fetchurl { # just a CC-BY-SA licensed example From beeb5f5d9ffbcaf1fb6aec66ac74e34a0148b31c Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 20 Feb 2026 05:17:28 -0300 Subject: [PATCH 77/81] Fork libkrun again to fix buffer mapping permission issue (fix #18) Initial D-Bus WIP is also there.. --- flake.lock | 18 ++++++++++++++++++ flake.nix | 12 ++++++------ packages/libkrun/default.nix | 20 +++++++++++--------- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index ebbd7e5..84f1720 100644 --- a/flake.lock +++ b/flake.lock @@ -20,6 +20,23 @@ "type": "github" } }, + "libkrun-src": { + "flake": false, + "locked": { + "lastModified": 1772170018, + "narHash": "sha256-pi4Mrx9wFE8zT8lx+0su2bP1tTkJBh5FaGNQjAFUAx4=", + "owner": "valpackett", + "repo": "libkrun", + "rev": "eeafbc55379b60379414168e7a22d5f95b73d7a0", + "type": "github" + }, + "original": { + "owner": "valpackett", + "repo": "libkrun", + "rev": "eeafbc55379b60379414168e7a22d5f95b73d7a0", + "type": "github" + } + }, "muvm-src": { "flake": false, "locked": { @@ -56,6 +73,7 @@ "root": { "inputs": { "flake-parts": "flake-parts", + "libkrun-src": "libkrun-src", "muvm-src": "muvm-src", "nixpkgs": "nixpkgs", "sidebus": "sidebus" diff --git a/flake.nix b/flake.nix index a7bacf1..84c3166 100644 --- a/flake.nix +++ b/flake.nix @@ -19,10 +19,10 @@ url = "github:valpackett/muvm/ae7dbd49aac04e9732a14a424572e99a81eb1298"; # v0.5.0+custom-init flake = false; }; - # libkrun-src = { - # url = "github:containers/libkrun/376f25637c49f26231ec92532f31a24b99236aa6"; # v1.17.0 - # flake = false; - # }; + libkrun-src = { + url = "github:valpackett/libkrun/eeafbc55379b60379414168e7a22d5f95b73d7a0"; # PR #558 (map permission fix) + D-Bus WIP + flake = false; + }; # libkrunfw-src = { # url = "github:containers/libkrunfw/20484a2e60290acb74c43ccfd6e1ea4caf41d470"; # v5.1.0 # flake = false; @@ -36,7 +36,7 @@ flake-parts, sidebus, muvm-src, - # libkrun-src, + libkrun-src, # libkrunfw-src, ... }: @@ -108,7 +108,7 @@ libkrun = pkgs.callPackage ./packages/libkrun { libkrunfw = self'.packages.libkrunfw; - # libkrun-src = libkrun-src; + libkrun-src = libkrun-src; }; mesa = pkgs.callPackage ./packages/mesa { }; diff --git a/packages/libkrun/default.nix b/packages/libkrun/default.nix index 205f8d2..00d655c 100644 --- a/packages/libkrun/default.nix +++ b/packages/libkrun/default.nix @@ -1,8 +1,9 @@ { libkrun, libkrunfw, - # libkrun-src, - # rustPlatform, + libkrun-src, + rustPlatform, + libcap_ng, variant ? null, ... }: @@ -21,10 +22,11 @@ let libkrunfw = libkrunfw'; }; in -libkrun' -# libkrun'.overrideAttrs (old: { -# src = libkrun-src; -# cargoDeps = rustPlatform.importCargoLock { -# lockFile = "${libkrun-src}/Cargo.lock"; -# }; -# }) +# libkrun' +libkrun'.overrideAttrs (old: { + src = libkrun-src; + cargoDeps = rustPlatform.importCargoLock { + lockFile = "${libkrun-src}/Cargo.lock"; + }; + buildInputs = old.buildInputs ++ [ libcap_ng ]; # new dep +}) From e00609ce7360ca56ecc13b4ec401fef9c247bae5 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 27 Feb 2026 02:50:30 -0300 Subject: [PATCH 78/81] nix: add some camera/pw testing tools to testvm --- nixosModules/testvm.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nixosModules/testvm.nix b/nixosModules/testvm.nix index 466cff5..aaf30d3 100644 --- a/nixosModules/testvm.nix +++ b/nixosModules/testvm.nix @@ -35,5 +35,10 @@ pkgs.nautilus pkgs.rewaita pkgs.wl-clipboard-rs + pkgs.snapshot + pkgs.gst_all_1.gst-plugins-base + pkgs.gst_all_1.gst-plugins-good + pkgs.gst_all_1.gst-plugins-bad + pkgs.gst_all_1.gstreamer ]; } From 604ebc1356c204a267e230bd5090505e119d1814 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 27 Feb 2026 02:51:07 -0300 Subject: [PATCH 79/81] [BREAKING] Switch to virtgpu-based D-Bus tunneling This introduces support for drag&drop and printing portals, and later camera/screencasting should be possible as well. However we break backwards compatibility with already built closures because the nixosModule needs to be changed. In the next commit, the runtime environment related services will be removed from the nixosModule to prevent unnecessary future breakage. --- flake.lock | 14 +++++++------- flake.nix | 6 ++---- munix | 26 ++++++++++++++++++-------- nixosModules/default.nix | 7 +++---- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/flake.lock b/flake.lock index 84f1720..165ec30 100644 --- a/flake.lock +++ b/flake.lock @@ -40,17 +40,17 @@ "muvm-src": { "flake": false, "locked": { - "lastModified": 1769336998, - "narHash": "sha256-ZFtAYwr3AaD8WsDmXJ6eU12UojzfMm50UBWmWIXstl0=", + "lastModified": 1772176363, + "narHash": "sha256-aSWulv3ml4XmMYnFOkZCd2YBLIY0Rr8CUHK1NDYk5jw=", "owner": "valpackett", "repo": "muvm", - "rev": "ae7dbd49aac04e9732a14a424572e99a81eb1298", + "rev": "c68742bcedb96deb6f23ed5a83188022d1cdf71d", "type": "github" }, "original": { "owner": "valpackett", "repo": "muvm", - "rev": "ae7dbd49aac04e9732a14a424572e99a81eb1298", + "rev": "c68742bcedb96deb6f23ed5a83188022d1cdf71d", "type": "github" } }, @@ -89,10 +89,10 @@ ] }, "locked": { - "lastModified": 1770365107, - "narHash": "sha256-rp2hDKF3pwHN0lBr09ckMNaMSJnwNolQmiad8C7u41Q=", + "lastModified": 1772183103, + "narHash": "sha256-9jbqBtaLUdOeT95PVUMz45JdUpVeJ25ZYZHEOQn9XsI=", "ref": "main", - "rev": "26261306592f6173fb844083b396bebf8140cb2b", + "rev": "c42eaef55440e2594677ede5279bd8c3eaf128f2", "shallow": true, "type": "git", "url": "https://git.clan.lol/clan/sidebus" diff --git a/flake.nix b/flake.nix index 84c3166..e7904a2 100644 --- a/flake.nix +++ b/flake.nix @@ -16,7 +16,7 @@ # To override with local checkouts during development, use the --override-input CLI flag! muvm-src = { - url = "github:valpackett/muvm/ae7dbd49aac04e9732a14a424572e99a81eb1298"; # v0.5.0+custom-init + url = "github:valpackett/muvm/c68742bcedb96deb6f23ed5a83188022d1cdf71d"; # v0.5.0+custom-init+dbus flake = false; }; libkrun-src = { @@ -49,7 +49,7 @@ flake = { nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { }; nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { - inherit self sidebus; + inherit self; }; templates.musictest = { @@ -124,8 +124,6 @@ sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; - sidebus-agent = sidebus.packages.${system}.sidebus-agent; - wl-cross-domain-proxy = pkgs.callPackage ./packages/wl-cross-domain-proxy { }; }; diff --git a/munix b/munix index 4f26980..ecd7920 100755 --- a/munix +++ b/munix @@ -10,6 +10,7 @@ MICROVM_UID=1337 MICROVM_GID=1337 BWRAP_ARGS=() MUVM_ARGS=() +SIDEBUS_ARGS=() GPU=1 WAYLAND=1 PIPEWIRE=1 @@ -31,10 +32,10 @@ while [ "$#" -gt 0 ]; do --no-pipewire) PIPEWIRE=0; shift 1;; --no-env-defaults) ENV_DEFAULTS=0; shift 1;; --x11) X11=1; shift 1;; - -b|--bind) BWRAP_ARGS+=("--bind" "$2" "$3"); shift 3;; - --ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); shift 3;; - -e|--expose) BWRAP_ARGS+=("--bind" "$2" "$2"); shift 2;; - --ro-expose) BWRAP_ARGS+=("--ro-bind" "$2" "$2"); shift 2;; + -b|--bind) BWRAP_ARGS+=("--bind" "$2" "$3"); SIDEBUS_ARGS+=("--path-mapping" "$3=$2"); shift 3;; + --ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); SIDEBUS_ARGS+=("--path-mapping" "$3=$2"); shift 3;; + -e|--expose) BWRAP_ARGS+=("--bind" "$2" "$2"); SIDEBUS_ARGS+=("--path-mapping" "$2=$2"); shift 2;; + --ro-expose) BWRAP_ARGS+=("--ro-bind" "$2" "$2"); SIDEBUS_ARGS+=("--path-mapping" "$2=$2"); shift 2;; -p|--publish) USING_PUBLISH=1; MUVM_ARGS+=("--publish=$2"); shift 2;; --host-opengl-driver) HOST_OPENGL_DRIVER="$2"; shift 2;; --munix-bin-dir) SCRIPT_PATH="$2"; shift 2;; @@ -186,12 +187,20 @@ trap cleanup EXIT INT TERM HOST_RUNTIME_DIR="$XDG_RUNTIME_DIR/munix.$$" mkdir -p $HOST_RUNTIME_DIR rm $HOST_RUNTIME_DIR/* -sidebus-broker --guest-mountpoint /mnt/munix-doc-portal/doc --runtime-dir "$HOST_RUNTIME_DIR" --unix-path "$HOST_RUNTIME_DIR/port.sock" >/dev/null 2>&1 & +mkdir -p "$HOST_RUNTIME_DIR/home" +RUST_LOG=debug sidebus-broker \ + --path-mapping "/home=$HOST_RUNTIME_DIR/home" \ + "${SIDEBUS_ARGS[@]}" \ + --guest-mountpoint /mnt/munix-doc-portal/doc \ + --runtime-dir "$HOST_RUNTIME_DIR" \ + --unix-path "$HOST_RUNTIME_DIR/port.sock" & # >/dev/null 2>&1 & BG_PIDS+=("$!") while [ ! -S "$HOST_RUNTIME_DIR/port.sock" ]; do sleep 0.1; done -BWRAP_ARGS+=( +BWRAP_ARGS=( # prepend home mount before other mounts to not override custom bind mounts under /home + --bind "$HOST_RUNTIME_DIR/home" /home + "${BWRAP_ARGS[@]}" --bind "$HOST_RUNTIME_DIR" /mnt/munix-doc-portal - --bind "$HOST_RUNTIME_DIR/port.sock" "$XDG_RUNTIME_DIR/krun/socket/port-50000" + --setenv "RUTABAGA_DBUS_CLIENT_SOCKET" /mnt/munix-doc-portal/port.sock ) if [ "$ENV_DEFAULTS" -eq 1 ]; then MUVM_ARGS+=( @@ -221,6 +230,7 @@ bwrap --unshare-all --share-net \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-remote \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-configure-network \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-pwbridge \ + --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-dbusbridge \ --symlink "$MICROVM_CLOSURE/etc" /etc \ --symlink "$MICROVM_CLOSURE/sw/bin/sh" /bin/sh \ --symlink "$MICROVM_CLOSURE/sw/bin/env" /usr/bin/env \ @@ -232,7 +242,7 @@ bwrap --unshare-all --share-net \ --setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \ "${BWRAP_ARGS[@]}" \ muvm \ - --custom-init-cmdline "/opt/bin/micro-activate $MICROVM_CLOSURE/sw/sbin/init --log-target=console systemd.set_credential=sidebus.port:50000" \ + --custom-init-cmdline "/opt/bin/micro-activate $MICROVM_CLOSURE/sw/sbin/init --log-target=console" \ "${MUVM_ARGS[@]}" \ -e container=munix \ -e MICROVM_CLOSURE="$MICROVM_CLOSURE" \ diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 15a5a08..e670144 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -1,6 +1,5 @@ { self, - sidebus, }: { pkgs, @@ -282,16 +281,16 @@ in Group = "appvm"; }; }; - systemd.services.sidebus-agent = { + systemd.services.session-bus-bridge = { enable = true; description = "D-Bus session bus"; wantedBy = ["microvm.target"]; requires = ["session-bus.socket" "session-bus.service"]; after = ["session-bus.service"]; serviceConfig = { - ImportCredential = "sidebus.port"; Environment = ["DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock"]; - ExecStart = "${sidebus.packages.${system}.sidebus-agent}/bin/sidebus-agent"; + ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"; + ExecStart = "/opt/bin/muvm-dbusbridge"; User = "appvm"; Group = "appvm"; }; From 38a96b79b36de600ec7ba2472a8b6e878dd4a29d Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 6 Mar 2026 04:53:30 -0300 Subject: [PATCH 80/81] [BREAKING] Provide runtime environment systemd services from munix These services evolve as munix evolves, so they should not be part of the system closures themselves. Mount them into /run/systemd instead. (Yes, making /run/systemd/system a symlink to RO files is unfortunate, that could be changed in the future. FS prep code is annoying too..) --- devShells/default.nix | 2 + flake.nix | 2 + micro-activate.rs | 2 + munix | 10 ++ nixosModules/default.nix | 109 ------------------ packages/munix/default.nix | 15 ++- .../muvm-configure-network.service | 1 + .../microvm.target.wants/muvm-remote.service | 1 + .../pipewire-bridge.socket | 1 + .../session-bus-bridge.service | 1 + .../wayland-bridge.socket | 1 + systemd/muvm-configure-network.service | 6 + systemd/muvm-remote.service | 33 ++++++ systemd/pipewire-bridge.service | 12 ++ systemd/pipewire-bridge.socket | 8 ++ systemd/session-bus-bridge.service | 11 ++ systemd/wayland-bridge.service | 13 +++ systemd/wayland-bridge.socket | 9 ++ 18 files changed, 125 insertions(+), 112 deletions(-) create mode 100644 systemd/microvm.target.wants/muvm-configure-network.service create mode 100644 systemd/microvm.target.wants/muvm-remote.service create mode 100644 systemd/microvm.target.wants/pipewire-bridge.socket create mode 100644 systemd/microvm.target.wants/session-bus-bridge.service create mode 100644 systemd/microvm.target.wants/wayland-bridge.socket create mode 100644 systemd/muvm-configure-network.service create mode 100644 systemd/muvm-remote.service create mode 100644 systemd/pipewire-bridge.service create mode 100644 systemd/pipewire-bridge.socket create mode 100644 systemd/session-bus-bridge.service create mode 100644 systemd/wayland-bridge.service create mode 100644 systemd/wayland-bridge.socket diff --git a/devShells/default.nix b/devShells/default.nix index 382eb7b..0798e86 100644 --- a/devShells/default.nix +++ b/devShells/default.nix @@ -10,6 +10,7 @@ libkrun, muvm, sidebus-broker, + wl-cross-domain-proxy, pkgs, }: @@ -32,6 +33,7 @@ mkShell { passt bubblewrap sidebus-broker + wl-cross-domain-proxy ] ++ (with pkgs; [ meson diff --git a/flake.nix b/flake.nix index e7904a2..cbc0887 100644 --- a/flake.nix +++ b/flake.nix @@ -121,6 +121,7 @@ munix = pkgs.callPackage ./packages/munix { mesa = self'.packages.mesa; muvm = self'.packages.muvm; + wl-cross-domain-proxy = self'.packages.wl-cross-domain-proxy; sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; @@ -130,6 +131,7 @@ devShells.default = pkgs.callPackage ./devShells { libkrun = self'.packages.libkrun; muvm = self'.packages.muvm; + wl-cross-domain-proxy = self'.packages.wl-cross-domain-proxy; sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; }; diff --git a/micro-activate.rs b/micro-activate.rs index 776dae4..765fb30 100644 --- a/micro-activate.rs +++ b/micro-activate.rs @@ -90,6 +90,8 @@ fn main() -> Result<(), std::io::Error> { std::fs::write("/run/localtime", &localtime)?; std::fs::write("/run/resolv.conf", &resolv_conf)?; std::fs::write("/run/machine-id", &gen_machine_id())?; + std::fs::create_dir("/run/systemd")?; + std::os::unix::fs::symlink("/opt/systemd", "/run/systemd/system")?; std::os::unix::fs::symlink(&closure, "/run/current-system")?; if let Ok(tmp_graphics) = std::fs::read(format!("{closure}/etc/tmpfiles.d/graphics-driver.conf")) diff --git a/munix b/munix index ecd7920..7fbd9b0 100755 --- a/munix +++ b/munix @@ -2,8 +2,10 @@ SCRIPT_PATH=$(dirname $(realpath -s $0)) MUVM_PATH=$(dirname $(which muvm)) PASST_PATH=$(dirname $(which passt)) +WL_PROXY_PATH=$(dirname $(which wl-cross-domain-proxy)) HOST_OPENGL_DRIVER=/run/opengl-driver : "${MICROVM_DEFAULT_COMMAND:=bash}" +: "${MUNIX_SYSTEMD_UNITS:="${SCRIPT_PATH}/systemd"}" MICROVM_CLOSURE= MICROVM_COMMAND=() MICROVM_UID=1337 @@ -41,6 +43,7 @@ while [ "$#" -gt 0 ]; do --munix-bin-dir) SCRIPT_PATH="$2"; shift 2;; --muvm-bin-dir) MUVM_PATH="$2"; shift 2;; --passt-bin-dir) PASST_PATH="$2"; shift 2;; + --wl-proxy-bin-dir) WL_PROXY_PATH="$2"; shift 2;; --) shift 1; MICROVM_COMMAND+=("$@"); break;; -*) echo "munix: unknown option: $1" >&2; exit 1;; *) @@ -68,6 +71,11 @@ if [ "$PASST_PATH" = "" ]; then exit 1 fi +if [ "$WL_PROXY_PATH" = "" ]; then + echo "munix: wl-cross-domain-proxy not found, provide a --wl-proxy-bin-dir or fix \$PATH" >&2 + exit 1 +fi + if [ ! -e "$HOST_OPENGL_DRIVER" ]; then echo "munix: host graphics driver not found, provide a --host-opengl-driver" >&2 exit 1 @@ -227,10 +235,12 @@ bwrap --unshare-all --share-net \ --ro-bind "$MUVM_PATH" /run/munix/muvm \ --ro-bind "$PASST_PATH" /run/munix/passt \ --ro-bind "$SCRIPT_PATH/micro-activate" /opt/bin/micro-activate \ + --ro-bind "$WL_PROXY_PATH/wl-cross-domain-proxy" /opt/bin/wl-cross-domain-proxy \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-remote \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-configure-network \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-pwbridge \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-dbusbridge \ + --ro-bind "$MUNIX_SYSTEMD_UNITS" /opt/systemd \ --symlink "$MICROVM_CLOSURE/etc" /etc \ --symlink "$MICROVM_CLOSURE/sw/bin/sh" /bin/sh \ --symlink "$MICROVM_CLOSURE/sw/bin/env" /usr/bin/env \ diff --git a/nixosModules/default.nix b/nixosModules/default.nix index e670144..35398b8 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -9,12 +9,6 @@ ... }: let - useTTY = { - TTYPath = "/dev/hvc0"; - StandardOutput = "tty"; - StandardInput = "tty"; - StandardError = "tty"; - }; runtimeDir = "/run/vm-user"; system = pkgs.stdenv.hostPlatform.system; in @@ -171,95 +165,6 @@ in systemd.settings.Manager.DefaultEnvironment = "XDG_RUNTIME_DIR=${runtimeDir}"; - systemd.services.muvm-remote = { - enable = true; - description = "microVM Application runner"; - onFailure = [ "exit.target" ]; - onSuccess = [ "exit.target" ]; - wants = [ "sockets.target" ]; - after = [ "sockets.target" ]; - wantedBy = [ "microvm.target" ]; - serviceConfig = { - Type = "exec"; - PassEnvironment = [ - "MESA_LOADER_DRIVER_OVERRIDE" - "MUVM_REMOTE_CONFIG" - # "KRUN_CONFIG" - - "TERM" - "XDG_SESSION_TYPE" - "SDL_VIDEODRIVER" - "QT_QPA_PLATFORM" - "_JAVA_AWT_WM_NONREPARENTING" - "ELECTRON_OZONE_PLATFORM_HINT" - "GTK_USE_PORTAL" - "QT_QPA_PLATFORMTHEME" - ]; - Environment = [ - "WAYLAND_DISPLAY=wayland-1" - "DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock" - "PATH=/run/current-system/sw/bin" - ]; - User = "appvm"; - Group = "appvm"; - ExecStartPre = "+/run/current-system/sw/bin/chown appvm:appvm ${runtimeDir}"; - ExecStart = "/opt/bin/muvm-remote"; - ExecStopPost = ''+${pkgs.python3}/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"''; - } - // useTTY; - }; - - systemd.services.muvm-configure-network = { - enable = true; - description = "microVM Network configuration"; - wantedBy = [ "microvm.target" ]; - serviceConfig.Type = "oneshot"; - serviceConfig.ExecStart = "/opt/bin/muvm-configure-network"; - }; - - systemd.sockets.muvm-pwbridge = { - enable = true; - description = "PipeWire cross-domain proxy socket"; - wantedBy = [ "microvm.target" ]; - partOf = [ "muvm-pwbridge.service" ]; - listenStreams = [ "${runtimeDir}/pipewire-0" ]; - socketConfig = { - SocketUser = "appvm"; - SocketGroup = "appvm"; - }; - }; - systemd.services.muvm-pwbridge = { - enable = true; - description = "PipeWire cross-domain proxy"; - requires = [ "muvm-pwbridge.socket" ]; - serviceConfig.Type = "exec"; - serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge"; - }; - - systemd.sockets.wayland-proxy = { - enable = true; - description = "Wayland cross-domain proxy socket"; - wantedBy = [ "microvm.target" ]; - partOf = [ "wayland-proxy.service" ]; - listenStreams = [ "${runtimeDir}/wayland-1" ]; - socketConfig = { - SocketUser = "appvm"; - SocketGroup = "appvm"; - FileDescriptorName = "wayland"; - }; - }; - systemd.services.wayland-proxy = { - enable = true; - description = "Wayland cross-domain proxy"; - requires = [ "wayland-proxy.socket" ]; - serviceConfig = { - ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"; - ExecStart = "${self.packages.${system}.wl-cross-domain-proxy}/bin/wl-cross-domain-proxy --listen-fd --filter-global wp_presentation"; - User = "appvm"; - Group = "appvm"; - }; - }; - systemd.sockets.session-bus = { enable = true; description = "D-Bus session bus socket"; @@ -281,20 +186,6 @@ in Group = "appvm"; }; }; - systemd.services.session-bus-bridge = { - enable = true; - description = "D-Bus session bus"; - wantedBy = ["microvm.target"]; - requires = ["session-bus.socket" "session-bus.service"]; - after = ["session-bus.service"]; - serviceConfig = { - Environment = ["DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock"]; - ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"; - ExecStart = "/opt/bin/muvm-dbusbridge"; - User = "appvm"; - Group = "appvm"; - }; - }; hardware.graphics.enable = true; hardware.graphics.package = self.packages.${system}.mesa; diff --git a/packages/munix/default.nix b/packages/munix/default.nix index ed82b9a..d7ff431 100644 --- a/packages/munix/default.nix +++ b/packages/munix/default.nix @@ -1,9 +1,18 @@ -{ stdenv, writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap, sidebus-broker, mesa, rustc }: +{ stdenv, writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap, sidebus-broker, wl-cross-domain-proxy, mesa, rustc }: let munixScript = (writeScriptBin "munix" (builtins.readFile ../../munix)).overrideAttrs(old: { buildCommand = "${old.buildCommand}\n patchShebangs $out"; }); + munixSystemd = stdenv.mkDerivation { + name = "munix-systemd"; + src = ../../systemd; + dontUnpack = true; + installPhase = '' + mkdir -p $out + cp -aR $src/* $out + ''; + }; microActivate = stdenv.mkDerivation { name = "micro-activate"; src = ../../micro-activate.rs; @@ -19,9 +28,9 @@ let }; in symlinkJoin { name = "munix"; - paths = [ munixScript microActivate muvm passt bubblewrap sidebus-broker ]; + paths = [ munixScript microActivate muvm passt bubblewrap sidebus-broker wl-cross-domain-proxy ]; buildInputs = [ makeWrapper ]; postBuild = '' - wrapProgram $out/bin/munix --prefix PATH : $out/bin --set FALLBACK_OPENGL_DRIVER ${mesa} + wrapProgram $out/bin/munix --prefix PATH : $out/bin --set FALLBACK_OPENGL_DRIVER ${mesa} --set MUNIX_SYSTEMD_UNITS ${munixSystemd} ''; } diff --git a/systemd/microvm.target.wants/muvm-configure-network.service b/systemd/microvm.target.wants/muvm-configure-network.service new file mode 100644 index 0000000..ca93c89 --- /dev/null +++ b/systemd/microvm.target.wants/muvm-configure-network.service @@ -0,0 +1 @@ +../muvm-configure-network.service \ No newline at end of file diff --git a/systemd/microvm.target.wants/muvm-remote.service b/systemd/microvm.target.wants/muvm-remote.service new file mode 100644 index 0000000..4f9f550 --- /dev/null +++ b/systemd/microvm.target.wants/muvm-remote.service @@ -0,0 +1 @@ +../muvm-remote.service \ No newline at end of file diff --git a/systemd/microvm.target.wants/pipewire-bridge.socket b/systemd/microvm.target.wants/pipewire-bridge.socket new file mode 100644 index 0000000..95e1850 --- /dev/null +++ b/systemd/microvm.target.wants/pipewire-bridge.socket @@ -0,0 +1 @@ +../pipewire-bridge.socket \ No newline at end of file diff --git a/systemd/microvm.target.wants/session-bus-bridge.service b/systemd/microvm.target.wants/session-bus-bridge.service new file mode 100644 index 0000000..faa559d --- /dev/null +++ b/systemd/microvm.target.wants/session-bus-bridge.service @@ -0,0 +1 @@ +../session-bus-bridge.service \ No newline at end of file diff --git a/systemd/microvm.target.wants/wayland-bridge.socket b/systemd/microvm.target.wants/wayland-bridge.socket new file mode 100644 index 0000000..4bcb084 --- /dev/null +++ b/systemd/microvm.target.wants/wayland-bridge.socket @@ -0,0 +1 @@ +../wayland-bridge.socket \ No newline at end of file diff --git a/systemd/muvm-configure-network.service b/systemd/muvm-configure-network.service new file mode 100644 index 0000000..3a67ff4 --- /dev/null +++ b/systemd/muvm-configure-network.service @@ -0,0 +1,6 @@ +[Unit] +Description=microVM Network configuration + +[Service] +Type=oneshot +ExecStart=/opt/bin/muvm-configure-network diff --git a/systemd/muvm-remote.service b/systemd/muvm-remote.service new file mode 100644 index 0000000..6164434 --- /dev/null +++ b/systemd/muvm-remote.service @@ -0,0 +1,33 @@ +[Unit] +After=sockets.target +Description=microVM Application runner +OnFailure=exit.target +OnSuccess=exit.target +Wants=sockets.target + +[Service] +Type=exec +# Environment="LOCALE_ARCHIVE=/nix/store/1hilqf0v1nm2w8xj87pwpm0rgq6lvhlv-glibc-locales-2.42-47/lib/locale/locale-archive" +# Environment="TZDIR=/nix/store/80izpiglrlqv2zb7rd7m5274k2dr142l-tzdata-2025c/share/zoneinfo" +Environment=WAYLAND_DISPLAY=wayland-1 +Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/vm-user/dbus.sock +Environment=PATH=/run/current-system/sw/bin +PassEnvironment=MESA_LOADER_DRIVER_OVERRIDE +PassEnvironment=MUVM_REMOTE_CONFIG +PassEnvironment=TERM +PassEnvironment=XDG_SESSION_TYPE +PassEnvironment=SDL_VIDEODRIVER +PassEnvironment=QT_QPA_PLATFORM +PassEnvironment=_JAVA_AWT_WM_NONREPARENTING +PassEnvironment=ELECTRON_OZONE_PLATFORM_HINT +PassEnvironment=GTK_USE_PORTAL +PassEnvironment=QT_QPA_PLATFORMTHEME +ExecStartPre=+/run/current-system/sw/bin/chown appvm:appvm /run/vm-user +ExecStart=/opt/bin/muvm-remote +ExecStopPost=+/nix/store/ygzfhw5nxrn7qqfqmz2s9p6cikcjqqkh-python3-3.13.11/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))" +User=appvm +Group=appvm +StandardError=tty +StandardInput=tty +StandardOutput=tty +TTYPath=/dev/hvc0 diff --git a/systemd/pipewire-bridge.service b/systemd/pipewire-bridge.service new file mode 100644 index 0000000..25c53e2 --- /dev/null +++ b/systemd/pipewire-bridge.service @@ -0,0 +1,12 @@ +[Unit] +Description=PipeWire VM bridge +Requires=pipewire-bridge.socket + +[Service] +Type=exec +ExecStart=/opt/bin/muvm-pwbridge + +# Environment=RUST_LOG=debug +# StandardError=tty +# StandardOutput=tty +# TTYPath=/dev/hvc0 diff --git a/systemd/pipewire-bridge.socket b/systemd/pipewire-bridge.socket new file mode 100644 index 0000000..998e661 --- /dev/null +++ b/systemd/pipewire-bridge.socket @@ -0,0 +1,8 @@ +[Unit] +Description=PipeWire VM bridge socket +PartOf=pipewire-bridge.service + +[Socket] +SocketGroup=appvm +SocketUser=appvm +ListenStream=/run/vm-user/pipewire-0 diff --git a/systemd/session-bus-bridge.service b/systemd/session-bus-bridge.service new file mode 100644 index 0000000..9b12a85 --- /dev/null +++ b/systemd/session-bus-bridge.service @@ -0,0 +1,11 @@ +[Unit] +After=session-bus.service +Description=D-Bus VM integration bridge +Requires=session-bus.socket session-bus.service + +[Service] +Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/vm-user/dbus.sock +ExecStartPre=+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128 +ExecStart=/opt/bin/muvm-dbusbridge +Group=appvm +User=appvm diff --git a/systemd/wayland-bridge.service b/systemd/wayland-bridge.service new file mode 100644 index 0000000..c74ba4e --- /dev/null +++ b/systemd/wayland-bridge.service @@ -0,0 +1,13 @@ +[Unit] +Description=Wayland VM bridge +Requires=wayland-bridge.socket + +[Service] +ExecStartPre=+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128 +ExecStart=/opt/bin/wl-cross-domain-proxy --listen-fd --filter-global wp_presentation +User=appvm +Group=appvm + +StandardError=tty +StandardOutput=tty +TTYPath=/dev/hvc0 diff --git a/systemd/wayland-bridge.socket b/systemd/wayland-bridge.socket new file mode 100644 index 0000000..2706a2b --- /dev/null +++ b/systemd/wayland-bridge.socket @@ -0,0 +1,9 @@ +[Unit] +Description=Wayland VM bridge socket +PartOf=wayland-bridge.service + +[Socket] +FileDescriptorName=wayland +SocketGroup=appvm +SocketUser=appvm +ListenStream=/run/vm-user/wayland-1 From a7fe813f1776e546ec505f5e89ae36174b42f377 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 6 Mar 2026 05:55:47 -0300 Subject: [PATCH 81/81] Add wl-backdrop (WIP) --bg-color option --- devShells/default.nix | 2 ++ flake.lock | 28 +++++++++++++++++++++++++++- flake.nix | 7 +++++++ munix | 23 +++++++++++++++++++++++ packages/munix/default.nix | 4 ++-- 5 files changed, 61 insertions(+), 3 deletions(-) diff --git a/devShells/default.nix b/devShells/default.nix index 0798e86..c288f30 100644 --- a/devShells/default.nix +++ b/devShells/default.nix @@ -11,6 +11,7 @@ muvm, sidebus-broker, wl-cross-domain-proxy, + wl-backdrop, pkgs, }: @@ -34,6 +35,7 @@ mkShell { bubblewrap sidebus-broker wl-cross-domain-proxy + wl-backdrop ] ++ (with pkgs; [ meson diff --git a/flake.lock b/flake.lock index 165ec30..234a180 100644 --- a/flake.lock +++ b/flake.lock @@ -76,7 +76,8 @@ "libkrun-src": "libkrun-src", "muvm-src": "muvm-src", "nixpkgs": "nixpkgs", - "sidebus": "sidebus" + "sidebus": "sidebus", + "wl-backdrop": "wl-backdrop" } }, "sidebus": { @@ -103,6 +104,31 @@ "type": "git", "url": "https://git.clan.lol/clan/sidebus" } + }, + "wl-backdrop": { + "inputs": { + "flake-parts": [ + "flake-parts" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1772781884, + "narHash": "sha256-epVLmAHnJi4EoZea5DUmxB3r6SPSMu3Nzki7JzbK0sA=", + "ref": "main", + "rev": "20e3910ef60aa627933a5d750b60cc3dcd0653cf", + "shallow": true, + "type": "git", + "url": "https://git.clan.lol/valpackett/wl-backdrop" + }, + "original": { + "ref": "main", + "shallow": true, + "type": "git", + "url": "https://git.clan.lol/valpackett/wl-backdrop" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index cbc0887..6b9191b 100644 --- a/flake.nix +++ b/flake.nix @@ -14,6 +14,10 @@ sidebus.inputs.nixpkgs.follows = "nixpkgs"; sidebus.inputs.flake-parts.follows = "flake-parts"; + wl-backdrop.url = "git+https://git.clan.lol/valpackett/wl-backdrop?shallow=1&ref=main"; + wl-backdrop.inputs.nixpkgs.follows = "nixpkgs"; + wl-backdrop.inputs.flake-parts.follows = "flake-parts"; + # To override with local checkouts during development, use the --override-input CLI flag! muvm-src = { url = "github:valpackett/muvm/c68742bcedb96deb6f23ed5a83188022d1cdf71d"; # v0.5.0+custom-init+dbus @@ -35,6 +39,7 @@ nixpkgs, flake-parts, sidebus, + wl-backdrop, muvm-src, libkrun-src, # libkrunfw-src, @@ -122,6 +127,7 @@ mesa = self'.packages.mesa; muvm = self'.packages.muvm; wl-cross-domain-proxy = self'.packages.wl-cross-domain-proxy; + wl-backdrop = wl-backdrop.packages.${system}.wl-backdrop; sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; @@ -132,6 +138,7 @@ libkrun = self'.packages.libkrun; muvm = self'.packages.muvm; wl-cross-domain-proxy = self'.packages.wl-cross-domain-proxy; + wl-backdrop = wl-backdrop.packages.${system}.wl-backdrop; sidebus-broker = sidebus.packages.${system}.sidebus-broker; }; }; diff --git a/munix b/munix index 7fbd9b0..619a38f 100755 --- a/munix +++ b/munix @@ -3,6 +3,7 @@ SCRIPT_PATH=$(dirname $(realpath -s $0)) MUVM_PATH=$(dirname $(which muvm)) PASST_PATH=$(dirname $(which passt)) WL_PROXY_PATH=$(dirname $(which wl-cross-domain-proxy)) +WL_BACKDROP_PATH=$(dirname $(which wl-backdrop)) HOST_OPENGL_DRIVER=/run/opengl-driver : "${MICROVM_DEFAULT_COMMAND:=bash}" : "${MUNIX_SYSTEMD_UNITS:="${SCRIPT_PATH}/systemd"}" @@ -25,6 +26,22 @@ if [ ! -e "$HOST_OPENGL_DRIVER" ]; then HOST_OPENGL_DRIVER="$FALLBACK_OPENGL_DRIVER" fi +# A little bit cursed: pre-pass to relaunch with new env var.. +BG_COLOR= +pargs=() +while [ "$#" -gt 0 ]; do + case "$1" in + --bg-color) BG_COLOR="$2"; shift 2;; + --wl-backdrop-bin-dir) WL_BACKDROP_PATH="$2"; shift 2;; + *) pargs+=("$1"); shift;; + esac +done +if [ "$BG_COLOR" = "" ]; then + set -- "${pargs[@]}" +else + exec "$WL_BACKDROP_PATH/wl-backdrop" --background "$BG_COLOR" -- "$(readlink -f "$0")" "${pargs[@]}" +fi + while [ "$#" -gt 0 ]; do case "$1" in -u|--uid) MICROVM_UID="$2"; shift 2;; @@ -44,6 +61,7 @@ while [ "$#" -gt 0 ]; do --muvm-bin-dir) MUVM_PATH="$2"; shift 2;; --passt-bin-dir) PASST_PATH="$2"; shift 2;; --wl-proxy-bin-dir) WL_PROXY_PATH="$2"; shift 2;; + --wl-backdrop-bin-dir) shift 2;; --) shift 1; MICROVM_COMMAND+=("$@"); break;; -*) echo "munix: unknown option: $1" >&2; exit 1;; *) @@ -76,6 +94,11 @@ if [ "$WL_PROXY_PATH" = "" ]; then exit 1 fi +if [ "$WL_BACKDROP_PATH" = "" ]; then + echo "munix: wl-backdrop not found, provide a --wl-backdrop-bin-dir or fix \$PATH" >&2 + exit 1 +fi + if [ ! -e "$HOST_OPENGL_DRIVER" ]; then echo "munix: host graphics driver not found, provide a --host-opengl-driver" >&2 exit 1 diff --git a/packages/munix/default.nix b/packages/munix/default.nix index d7ff431..e0b848e 100644 --- a/packages/munix/default.nix +++ b/packages/munix/default.nix @@ -1,4 +1,4 @@ -{ stdenv, writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap, sidebus-broker, wl-cross-domain-proxy, mesa, rustc }: +{ stdenv, writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap, sidebus-broker, wl-cross-domain-proxy, wl-backdrop, mesa, rustc }: let munixScript = (writeScriptBin "munix" (builtins.readFile ../../munix)).overrideAttrs(old: { @@ -28,7 +28,7 @@ let }; in symlinkJoin { name = "munix"; - paths = [ munixScript microActivate muvm passt bubblewrap sidebus-broker wl-cross-domain-proxy ]; + paths = [ munixScript microActivate muvm passt bubblewrap sidebus-broker wl-cross-domain-proxy wl-backdrop ]; buildInputs = [ makeWrapper ]; postBuild = '' wrapProgram $out/bin/munix --prefix PATH : $out/bin --set FALLBACK_OPENGL_DRIVER ${mesa} --set MUNIX_SYSTEMD_UNITS ${munixSystemd}