ch-runner: add wayland-proxy

This commit is contained in:
Else Someone 2026-02-25 17:37:06 +02:00
parent e077ad6858
commit 660bda3a4a
4 changed files with 183 additions and 19 deletions

View file

@ -5,6 +5,28 @@
modulesPath,
...
}:
let
uvmsPkgs = pkgs.callPackage ../pkgs { };
waylandSock = "/run/user/1000/wayland-1";
env = {
XDG_RUNTIME_DIR = "/run/user/1000";
WAYLAND_DISPLAY = "wayland-1";
MESA_LOADER_DRIVER_OVERRIDE = "zink";
# WAYLAND_DEBUG = "1";
# WAYLAND_DEBUG_PROXY = "1";
ELECTRON_OZONE_PLATFORM_HINT = "wayland";
MOZ_ENABLE_WAYLAND = "1";
QT_QPA_PLATFORM = "wayland"; # Qt Applications
GDK_BACKEND = "wayland"; # GTK Applications
XDG_SESSION_TYPE = "wayland"; # Electron Applications
SDL_VIDEODRIVER = "wayland";
CLUTTER_BACKEND = "wayland";
NIXOS_OZONE_WL = "1";
};
in
{
imports = [
../profiles/all.nix
@ -18,30 +40,117 @@
vmapps.enable = true;
_module.args.inputs = import ../npins;
# following microvm.nix:
# boot.isContainer = true;
# boot.initrd.enable = true;
boot.loader.grub.enable = false;
boot.initrd.systemd.enable = true;
services.logrotate.enable = false;
services.udisks2.enable = false;
system.tools.nixos-generate-config.enable = false;
# system.activationScripts.specialfs = lib.mkForce "";
systemd.coredump.enable = false;
# networking.firewall.enable = false;
powerManagement.enable = false;
boot.kexec.enable = false;
# console.enable = false;
# system.switch.enable = false;
# services.udev.packages = lib.mkDefault [ ];
services.resolved.enable = false;
systemd.services.generate-shutdown-ramfs.enable = lib.mkForce false;
systemd.services.systemd-remount-fs.enable = lib.mkForce false;
systemd.services.systemd-pstore.enable = lib.mkForce false;
systemd.services.lastlog2-import.enable = lib.mkForce false;
systemd.services.suid-sgid-wrappers.enable = lib.mkForce false;
fileSystems."/" = lib.mkDefault {
device = "rootfs"; # how does this work? does this assign a label to the tmpfs?
fsType = "tmpfs";
options = [ "size=20%,mode=0755" ];
neededForBoot = true;
};
boot.initrd.systemd.settings.Manager.DefaultTimeoutStartSec = 30;
boot.initrd.systemd.settings.Manager.DefaultTimeoutStartSec = 5;
systemd.settings.Manager.DefaultTimeoutStopSec = 10;
networking.useNetworkd = true;
networking.nftables.enable = true;
uvms.cloud-hypervisor.enable = true;
systemd.sysusers.enable = false;
services.userborn.enable = true; # nikstur it
users.mutableUsers = false;
users.groups.user = { };
users.users.user = {
isNormalUser = true;
password = "hacktheplanet!";
extraGroups = [
"video"
"render"
];
};
users.users.root.password = "hacktheplanet!";
services.getty.autologinUser = "root";
systemd.services."suid-sgid-wrappers".serviceConfig = {
StandardOutput = "journal+console";
StandardError = "journal+console";
};
environment.variables = env;
systemd.globalEnvironment = env;
systemd.tmpfiles.settings."10-xdg" = {
${env.XDG_RUNTIME_DIR}.d = {
user = "user";
group = "user";
mode = "0755";
};
};
systemd.sockets."wayland-proxy" = {
listenStreams = [
waylandSock
];
socketConfig = {
SocketUser = "user";
SocketGroup = "user";
FileDescriptorName = "wayland";
};
wantedBy = [ "sockets.target" ];
partOf = [ "wayland-proxy.service" ];
};
systemd.services."wayland-proxy" = {
wantedBy = [ "default.target" ];
serviceConfig = {
User = "user";
Group = "user";
ExecStart = "${lib.getExe pkgs.wayland-proxy-virtwl} --virtio-gpu";
# ExecStart = "${lib.getExe uvmsPkgs.wl-cross-domain-proxy} --listen-fd --filter-global wp_presentation";
ExecStartPre = [
"+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"
];
StandardOutput = "journal+console";
StandardError = "journal+console";
Restart = "on-failure";
RestartSec = 5;
};
};
fonts.enableDefaultPackages = true;
systemd.services."terminal" = {
wantedBy = [ "multi-user.target" ];
wants = [ "wayland-proxy.service" ];
after = [ "wayland-proxy.service" ];
environment = env;
serviceConfig = {
User = "user";
WorkingDirectory = "/home/user";
ExecStart = lib.getExe pkgs.alacritty;
StandardOutput = "journal+console";
StandardError = "journal+console";
};
};
boot.kernelModules = [
"drm"
"virtio_gpu"
];
hardware.graphics.enable = true;
# TODO: cmdline, kernel, initrd, fileSystems
}

View file

@ -22,13 +22,7 @@ let
getBin
;
package = pkgs.cloud-hypervisor.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [
# ../patches/ch.patch
];
buildType = "debug";
dontStrip = true;
});
package = uvmsPkgs.cloud-hypervisor-gpu;
uvmsPkgs = pkgs.callPackage ../pkgs { };
chSettingsFile = (pkgs.formats.json { }).generate "vm.json" cfg.settings;
@ -279,11 +273,20 @@ in
(lib.getBin pkgs.virtiofsd)
(lib.getBin pkgs.bubblewrap)
(lib.getBin pkgs.strace)
(lib.getBin pkgs.crosvm)
uvmsPkgs.taps
];
superviseVm = getExe superviseVm';
superviseVm' = pkgs.writers.writePython3Bin "supervise-vm" { } ''
# NOTE: This would have been bash,
# and this was execlineb previously,
# but it was just easier to reason in terms of context managers
# and try-except-finally branches for the cleanup bit,
# than in terms of traps or such.
# Treat this as bash.
# Treat this as throwaway shitcode.
import os
import subprocess
import socket
@ -320,8 +323,10 @@ in
**{
k: v
for k, v in os.environ.items()
if k.startswith("RUST")
if k.startswith("RUST_")
or k.startswith("WAYLAND")
or k.startswith("XDG_")
or k.startswith("DBUS_")
or k in [
"TAPS_SOCK",
]
@ -356,6 +361,8 @@ in
def alive_after(proc, timeout):
if proc is None:
return False
if proc.returncode is not None:
return False
try:
@ -410,6 +417,7 @@ in
kwargs["stdin"] = kwargs.get("stdin", subprocess.DEVNULL)
kwargs["stdout"] = kwargs.get("stdout", subprocess.DEVNULL)
kwargs["stderr"] = kwargs.get("stderr", subprocess.DEVNULL)
proc = None
try:
proc = subprocess.Popen(
args,
@ -421,7 +429,8 @@ in
finally:
if alive_after(proc, 0.125):
proc.terminate()
proc.wait()
if proc is not None:
proc.wait()
@contextmanager
def bwrap(
@ -550,7 +559,7 @@ in
*args,
bind=[self.prefix],
# Probably just need the path to vmlinux
ro_bind=("/nix/store",), # A give up
ro_bind=["/nix/store"], # I give up
unshare_net=False,
shell=False,
stderr=None,
@ -575,6 +584,35 @@ in
if os.path.exists(p):
os.remove(p)
@contextmanager
def start_gpu(
self,
):
sock_path = self.prefix + "/gpu.sock"
args = [
SOCKETBINDER_PATH,
"-b", "1",
sock_path,
"s6-ipcserverd",
"-1c1",
# "${lib.getExe pkgs.strace}", # noqa: E501
# "-Z",
# "-ff",
"${lib.getExe pkgs.crosvm}", # noqa: E501
"--no-syslog",
"device", "gpu",
"--fd", "0",
"--wayland-sock",
f'{PASSTHRU_ENV["XDG_RUNTIME_DIR"]}/{PASSTHRU_ENV["WAYLAND_DISPLAY"]}', # noqa: E501
"--params",
"{ \"context-types\": \"cross-domain:virgl2:venus\" }",
]
with self.popen(
*args,
stderr=None,
) as proc, removing(sock_path):
yield proc, sock_path
@contextmanager
def start_virtiofsd(
self,
@ -652,11 +690,26 @@ in
f()
@contextmanager
def removing(*paths):
try:
yield
finally:
for p in paths:
if os.path.exists(p):
os.remove(p)
if __name__ == "__main__":
args, args_next = parser.parse_known_args()
preprocess_args(args)
send_dir = PASSTHRU_ENV["HOME"] + f"/send/{args.vm}"
os.makedirs(send_dir, exist_ok=True)
os.makedirs(args.prefix, exist_ok=True)
os.makedirs(args.prefix + "/pts", exist_ok=True)
ps = Processes(
prefix=args.prefix,
vm=args.vm,
@ -670,13 +723,14 @@ in
with ExitStack() as cleanup:
send_dir = PASSTHRU_ENV["HOME"] + f"/send/{args.vm}"
os.makedirs(send_dir, exist_ok=True)
vfsd, vfsd_path = cleanup.enter_context(
ps.start_virtiofsd(
send_dir,
tag="send",
))
gpud, gpud_path = cleanup.enter_context(
ps.start_gpu()
)
ch = cleanup.enter_context(ps.run_ch())
ps.exec(*ch_remote, "create", args.vm_config)
@ -686,6 +740,7 @@ in
"id=wan,fd=3,mac=00:00:00:00:00:01")
ps.exec(*ch_remote, "add-fs", f"tag=send,socket={vfsd_path},id=send")
ps.exec(*ch_remote, "add-gpu", f"socket={gpud_path}")
ps.exec(*ch_remote, "boot")
ps.exec(*ch_remote, "info")
try:

View file

@ -212,9 +212,9 @@ in
''} %i";
};
boot.initrd.systemd.settings.Manager.DefaultTimeoutStartSec = 30;
systemd.settings.Manager.DefaultTimeoutStopSec = 10;
systemd.services."user@".serviceConfig.TimeoutStopSec = 10;
boot.initrd.systemd.settings.Manager.DefaultTimeoutStartSec = lib.mkDefault 30;
systemd.settings.Manager.DefaultTimeoutStopSec = lib.mkDefault 10;
systemd.services."user@".serviceConfig.TimeoutStopSec = lib.mkDefault 10;
services.openssh.enable = true;

View file

@ -12,7 +12,7 @@ mkShell.override { stdenv = stdenvNoCC; } {
];
packages =
map lib.getBin [
cloud-hypervisor
uvmPkgs.cloud-hypervisor-gpu
virtiofsd
crosvm # virtio-gpu
npins