Compare commits
81 commits
__assets__
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7fe813f17 | ||
|
|
38a96b79b3 | ||
|
|
604ebc1356 | ||
|
|
e00609ce73 | ||
|
|
beeb5f5d9f | ||
|
|
adf2d24b60 | ||
|
|
981393443b | ||
|
|
8c3878f117 | ||
|
|
322b6efc1c | ||
|
|
820fcd3da1 | ||
|
|
53f827553f | ||
|
|
09f1eb76de | ||
|
|
9708e5fb64 | ||
|
|
67666b8f46 | ||
|
|
585970fe92 | ||
|
|
a82b0de310 | ||
|
|
8113c269cb | ||
|
|
38213f4ada | ||
|
|
425ff896c8 | ||
|
|
9911b15fb7 | ||
|
|
13b2afcc14 | ||
|
|
c89c9e4d9b | ||
|
|
40d82a0fd8 | ||
|
|
c11c6c6292 | ||
|
|
447ccad362 | ||
|
|
2d7860294d | ||
|
|
06a26e7dee | ||
|
|
214d4c4500 | ||
|
|
612453a3bc | ||
|
|
787ca12b1e | ||
|
|
f336a0d5ff | ||
|
|
1d864e0ded | ||
|
|
ced0559be8 | ||
|
|
2d721419e6 | ||
|
|
fb53769c7a | ||
|
|
ab5f412524 | ||
|
|
20e7e88e07 | ||
|
|
bfb8352c55 | ||
|
|
cc135479ef | ||
|
|
bfc037e615 | ||
|
|
73d2501781 | ||
|
|
fd771dd95f | ||
|
|
2a98ae83af | ||
|
|
d2070a1bec | ||
|
|
5f1783b9bb | ||
|
|
c7ec9872ca | ||
|
|
57b8ae3424 | ||
|
|
6e8e4b9fda | ||
|
|
7aa9f614da | ||
|
|
9a6cf18cc1 | ||
|
|
0bd986f97f | ||
|
|
3d2f6c4732 | ||
|
|
a93ab32aea | ||
|
|
f831c9d958 | ||
|
|
9b23ae8094 | ||
|
|
93ba3d8fc4 | ||
|
|
bd6307ded5 | ||
|
|
83db4d6074 | ||
|
|
87691a5747 | ||
|
|
73fdfca030 | ||
|
|
23b91f1d6d | ||
|
|
59137223a9 | ||
|
|
c164db06c1 | ||
|
|
77028b04da | ||
|
|
9f0f835fce | ||
|
|
030503f23b | ||
|
|
8d2596d7cc | ||
|
|
8d178b21ef | ||
|
|
d8d531aa00 | ||
|
|
7c0825b46c | ||
|
|
f295e7b32a | ||
|
|
181e675f02 | ||
|
|
c32be2f8c8 | ||
|
|
b70a166e8b | ||
|
|
505e85b9c5 | ||
|
|
6f7f3f2461 | ||
|
|
46edb4b7e9 | ||
|
|
348cedab1a | ||
|
|
790dd0d1f4 | ||
|
|
c4d462ea20 | ||
|
|
146430d8cd |
34 changed files with 1210 additions and 354 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,2 +1,5 @@
|
|||
result
|
||||
/testvm*
|
||||
/target
|
||||
/micro-activate
|
||||
.direnv/
|
||||
|
|
|
|||
6
.gitmodules
vendored
6
.gitmodules
vendored
|
|
@ -1,6 +0,0 @@
|
|||
[submodule "muvm"]
|
||||
path = muvm
|
||||
url = https://github.com/valpackett/muvm
|
||||
[submodule "libkrun"]
|
||||
path = libkrun
|
||||
url = https://github.com/valpackett/libkrun
|
||||
74
README.md
74
README.md
|
|
@ -2,23 +2,69 @@
|
|||
|
||||
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
|
||||
```
|
||||
|
||||
**Create a custom VM:**
|
||||
|
||||
Use the template to bootstrap a new munix project:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
This creates a `flake.nix` with a music player demo (MPD + Euphonica). Edit the module to customize your VM.
|
||||
|
||||
## 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
|
||||
|
||||
## Known Issues
|
||||
|
|
|
|||
49
devShells/default.nix
Normal file
49
devShells/default.nix
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
mkShell,
|
||||
lib,
|
||||
systemd,
|
||||
cargo,
|
||||
rust-analyzer,
|
||||
rustfmt,
|
||||
passt,
|
||||
bubblewrap,
|
||||
libkrun,
|
||||
muvm,
|
||||
sidebus-broker,
|
||||
wl-cross-domain-proxy,
|
||||
wl-backdrop,
|
||||
pkgs,
|
||||
}:
|
||||
|
||||
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
|
||||
sidebus-broker
|
||||
wl-cross-domain-proxy
|
||||
wl-backdrop
|
||||
]
|
||||
++ (with pkgs; [
|
||||
meson
|
||||
wayland
|
||||
wayland-protocols
|
||||
wayland-scanner
|
||||
cairo
|
||||
libgbm
|
||||
]);
|
||||
# Enough things to compile wl-cross-domain-proxy, muvm, etc. in development
|
||||
}
|
||||
165
flake.lock
generated
165
flake.lock
generated
|
|
@ -1,120 +1,133 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
"nixpkgs-lib": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"lastModified": 1769996383,
|
||||
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"libkrun-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"lastModified": 1772170018,
|
||||
"narHash": "sha256-pi4Mrx9wFE8zT8lx+0su2bP1tTkJBh5FaGNQjAFUAx4=",
|
||||
"owner": "valpackett",
|
||||
"repo": "libkrun",
|
||||
"rev": "eeafbc55379b60379414168e7a22d5f95b73d7a0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"owner": "valpackett",
|
||||
"repo": "libkrun",
|
||||
"rev": "eeafbc55379b60379414168e7a22d5f95b73d7a0",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"muvm-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1772176363,
|
||||
"narHash": "sha256-aSWulv3ml4XmMYnFOkZCd2YBLIY0Rr8CUHK1NDYk5jw=",
|
||||
"owner": "valpackett",
|
||||
"repo": "muvm",
|
||||
"rev": "c68742bcedb96deb6f23ed5a83188022d1cdf71d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "valpackett",
|
||||
"repo": "muvm",
|
||||
"rev": "c68742bcedb96deb6f23ed5a83188022d1cdf71d",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"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": 1770197578,
|
||||
"narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2",
|
||||
"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": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"flake-parts": "flake-parts",
|
||||
"libkrun-src": "libkrun-src",
|
||||
"muvm-src": "muvm-src",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"virtwl": "virtwl"
|
||||
"sidebus": "sidebus",
|
||||
"wl-backdrop": "wl-backdrop"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"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": {
|
||||
"sidebus": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"flake-parts": [
|
||||
"flake-parts"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758075582,
|
||||
"narHash": "sha256-o2lpXQLaM9QcZVr+sAxvh83CqJW1QkFhfja6K40ndmA=",
|
||||
"ref": "wip",
|
||||
"rev": "5a5df73a11b2f6bf671a8fc89926ac993e0fbb78",
|
||||
"lastModified": 1772183103,
|
||||
"narHash": "sha256-9jbqBtaLUdOeT95PVUMz45JdUpVeJ25ZYZHEOQn9XsI=",
|
||||
"ref": "main",
|
||||
"rev": "c42eaef55440e2594677ede5279bd8c3eaf128f2",
|
||||
"shallow": true,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/valpackett/wayland-proxy-virtwl"
|
||||
"url": "https://git.clan.lol/clan/sidebus"
|
||||
},
|
||||
"original": {
|
||||
"ref": "wip",
|
||||
"ref": "main",
|
||||
"shallow": true,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/valpackett/wayland-proxy-virtwl"
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
281
flake.nix
281
flake.nix
|
|
@ -1,167 +1,146 @@
|
|||
{
|
||||
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";
|
||||
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";
|
||||
nixConfig = {
|
||||
extra-substituters = [ "https://cache.clan.lol" ];
|
||||
extra-trusted-public-keys = [ "cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28=" ];
|
||||
};
|
||||
|
||||
outputs = {self, nixpkgs, flake-utils, virtwl, ...}:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
in {
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
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 = "";
|
||||
# });
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||
|
||||
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;
|
||||
};
|
||||
# mesonFlags = [ (pkgs.lib.mesonOption "decoders" "gles,vulkan,composer") ]; # no magma(?)
|
||||
});
|
||||
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";
|
||||
|
||||
packages.muvm = (pkgs.muvm.override {
|
||||
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;
|
||||
};
|
||||
});
|
||||
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";
|
||||
|
||||
packages.munix = let
|
||||
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 ];
|
||||
buildInputs = [ pkgs.makeWrapper ];
|
||||
postBuild = ''
|
||||
wrapProgram $out/bin/munix --prefix PATH : $out/bin
|
||||
'';
|
||||
# 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
|
||||
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;
|
||||
# };
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs@{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-parts,
|
||||
sidebus,
|
||||
wl-backdrop,
|
||||
muvm-src,
|
||||
libkrun-src,
|
||||
# libkrunfw-src,
|
||||
...
|
||||
}:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
|
||||
flake = {
|
||||
nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { };
|
||||
nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix {
|
||||
inherit self;
|
||||
};
|
||||
|
||||
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
|
||||
]);
|
||||
templates.musictest = {
|
||||
description = "Music player demo VM with MPD and Euphonica";
|
||||
path = ./templates/musictest;
|
||||
};
|
||||
|
||||
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
|
||||
});
|
||||
|
||||
nixosConfigurations.testvm = nixpkgs.lib.nixosSystem {
|
||||
inherit system;
|
||||
nixosConfigurations.testvm-x86_64 = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
{
|
||||
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;
|
||||
}
|
||||
];
|
||||
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.kdePackages.kate
|
||||
pkgs.adwaita-fonts
|
||||
pkgs.adwaita-icon-theme
|
||||
pkgs.gnome-text-editor
|
||||
pkgs.firefox
|
||||
pkgs.ffmpeg-full
|
||||
pkgs.mpv
|
||||
pkgs.libva-utils
|
||||
];
|
||||
}
|
||||
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;
|
||||
};
|
||||
|
||||
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;
|
||||
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;
|
||||
};
|
||||
|
||||
wl-cross-domain-proxy = pkgs.callPackage ./packages/wl-cross-domain-proxy { };
|
||||
};
|
||||
|
||||
devShells.default = pkgs.callPackage ./devShells {
|
||||
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;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
1
libkrun
1
libkrun
|
|
@ -1 +0,0 @@
|
|||
Subproject commit bd97a39bfaa46147933beca7e16513b6820bb031
|
||||
155
micro-activate.rs
Normal file
155
micro-activate.rs
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
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;
|
||||
|
||||
const CLONE_NEWTIME: c_int = 0x80;
|
||||
|
||||
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 getrandom(buf: *mut u8, buflen: usize, flags: u32) -> c_int;
|
||||
fn unshare(flags: c_int) -> 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)> {
|
||||
// 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 localtime = std::fs::read("/run/localtime")?;
|
||||
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/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"))
|
||||
{
|
||||
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() as *const c_char,
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
184
munix
184
munix
|
|
@ -2,19 +2,46 @@
|
|||
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"}"
|
||||
MICROVM_CLOSURE=
|
||||
MICROVM_COMMAND=()
|
||||
MICROVM_UID=1337
|
||||
MICROVM_GID=1337
|
||||
BWRAP_ARGS=()
|
||||
MUVM_ARGS=()
|
||||
SIDEBUS_ARGS=()
|
||||
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
|
||||
|
||||
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;;
|
||||
|
|
@ -22,15 +49,20 @@ 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;;
|
||||
--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;;
|
||||
--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;;
|
||||
--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;;
|
||||
*)
|
||||
if [ "$MICROVM_CLOSURE" = "" ]; then
|
||||
|
|
@ -47,8 +79,36 @@ 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
|
||||
|
||||
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 [ "$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
|
||||
fi
|
||||
|
||||
# Resolve symlinks automatically
|
||||
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
|
||||
|
|
@ -69,7 +129,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;;
|
||||
|
|
@ -84,9 +144,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")
|
||||
|
|
@ -101,7 +158,15 @@ 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"
|
||||
"-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
|
||||
|
|
@ -119,6 +184,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
|
||||
|
|
@ -130,37 +200,87 @@ 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/*
|
||||
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=( # 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
|
||||
--setenv "RUTABAGA_DBUS_CLIENT_SOCKET" /mnt/munix-doc-portal/port.sock
|
||||
)
|
||||
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
|
||||
fi
|
||||
|
||||
# xxx: some time is lost to the starting process..
|
||||
[[ "$(</proc/uptime)" =~ ([0-9]+)\.([0-9]+) ]]
|
||||
BOOT_TIME_OFFSET="${BASH_REMATCH[1]} $(( ${BASH_REMATCH[2]} * 1000000 ))"
|
||||
|
||||
# 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 --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 "$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 "$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 \
|
||||
--symlink "$MICROVM_CLOSURE" /run/current-system \
|
||||
--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 /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[@]}" \
|
||||
muvm \
|
||||
-x /usr/bin/munix-init-root -X /usr/bin/munix-init-user --udevd-path="$MICROVM_CLOSURE/sw/bin/true" \
|
||||
--custom-init-cmdline "/opt/bin/micro-activate $MICROVM_CLOSURE/sw/sbin/init --log-target=console" \
|
||||
"${MUVM_ARGS[@]}" \
|
||||
-e MICROVM_CLOSURE="$MICROVM_CLOSURE" -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \
|
||||
-i -t "${MICROVM_COMMAND[@]}" \
|
||||
11< <(cat <<EOF
|
||||
munix:x:$MICROVM_UID:$MICROVM_GID:Hypervisor:/:/run/current-system/sw/bin/nologin
|
||||
nobody:x:65534:65534:Unprivileged account:/var/empty:/run/current-system/sw/bin/nologin
|
||||
EOF
|
||||
) \
|
||||
12< <(cat <<EOF
|
||||
munix:x:$MICROVM_GID:
|
||||
nogroup:x:65534:
|
||||
EOF
|
||||
)
|
||||
-e container=munix \
|
||||
-e MICROVM_CLOSURE="$MICROVM_CLOSURE" \
|
||||
-e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \
|
||||
-e BOOT_TIME_OFFSET="$BOOT_TIME_OFFSET" \
|
||||
-i -t -- "${MICROVM_COMMAND[@]}" \
|
||||
13< /etc/resolv.conf \
|
||||
14< /etc/localtime
|
||||
|
|
|
|||
|
|
@ -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!"
|
||||
|
|
@ -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 &
|
||||
1
muvm
1
muvm
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 53d416fb3f96b04a5bd3dd40f94fa4d8fbf1d7f1
|
||||
204
nixosModules/default.nix
Normal file
204
nixosModules/default.nix
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
{
|
||||
self,
|
||||
}:
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
utils,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
runtimeDir = "/run/vm-user";
|
||||
system = pkgs.stdenv.hostPlatform.system;
|
||||
in
|
||||
{
|
||||
options.virtualisation.munix.defaultCommand = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "bash";
|
||||
description = "Default command to run when starting the VM without arguments.";
|
||||
};
|
||||
|
||||
config = {
|
||||
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;
|
||||
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 [ ];
|
||||
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";
|
||||
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" ];
|
||||
}
|
||||
);
|
||||
|
||||
# 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";
|
||||
};
|
||||
};
|
||||
|
||||
# Configure user accounts
|
||||
systemd.sysusers.enable = false;
|
||||
services.userborn.enable = true;
|
||||
services.userborn.static = true;
|
||||
users.mutableUsers = false;
|
||||
users.users.appvm = {
|
||||
uid = 1337;
|
||||
group = "appvm";
|
||||
isNormalUser = false;
|
||||
isSystemUser = true;
|
||||
home = "/home/appvm";
|
||||
description = "microVM User";
|
||||
shell = pkgs.bash; # not nologin, despite being a "system" user
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"video"
|
||||
"input"
|
||||
"systemd-journal"
|
||||
];
|
||||
};
|
||||
users.groups.appvm.gid = 1337;
|
||||
users.allowNoPasswordLogin = true;
|
||||
|
||||
# Configure services
|
||||
|
||||
systemd.settings.Manager.DefaultEnvironment = "XDG_RUNTIME_DIR=${runtimeDir}";
|
||||
|
||||
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 = {
|
||||
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";
|
||||
};
|
||||
};
|
||||
|
||||
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}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
44
nixosModules/testvm.nix
Normal file
44
nixosModules/testvm.nix
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{ }:
|
||||
{ pkgs, ... }: {
|
||||
system.stateVersion = "26.05";
|
||||
|
||||
fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ];
|
||||
programs.dconf.enable = true;
|
||||
environment.systemPackages = [
|
||||
pkgs.fastfetch
|
||||
pkgs.htop
|
||||
pkgs.wayland-utils
|
||||
pkgs.weston
|
||||
pkgs.waycheck
|
||||
pkgs.vulkan-tools
|
||||
pkgs.glmark2
|
||||
pkgs.mesa-demos
|
||||
pkgs.xorg.xeyes
|
||||
pkgs.xterm
|
||||
pkgs.vkquake
|
||||
# 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.pipewire # cli
|
||||
pkgs.tailscale
|
||||
pkgs.zerotierone
|
||||
pkgs.localsend
|
||||
pkgs.ashpd-demo
|
||||
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
|
||||
];
|
||||
}
|
||||
32
packages/libkrun/default.nix
Normal file
32
packages/libkrun/default.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
libkrun,
|
||||
libkrunfw,
|
||||
libkrun-src,
|
||||
rustPlatform,
|
||||
libcap_ng,
|
||||
variant ? null,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
libkrunfw' = libkrunfw.override { inherit variant; };
|
||||
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";
|
||||
};
|
||||
buildInputs = old.buildInputs ++ [ libcap_ng ]; # new dep
|
||||
})
|
||||
22
packages/libkrunfw/default.nix
Normal file
22
packages/libkrunfw/default.nix
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
libkrunfw,
|
||||
# libkrunfw-src,
|
||||
# fetchurl,
|
||||
variant ? null,
|
||||
...
|
||||
}:
|
||||
|
||||
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=";
|
||||
# };
|
||||
# })
|
||||
10
packages/mesa/default.nix
Normal file
10
packages/mesa/default.nix
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{ mesa, lib, stdenv }:
|
||||
|
||||
(mesa.override {
|
||||
# nothing currently
|
||||
}).overrideAttrs (new: old: {
|
||||
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 ++ [ ];
|
||||
})
|
||||
36
packages/munix/default.nix
Normal file
36
packages/munix/default.nix
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{ 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: {
|
||||
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;
|
||||
dontUnpack = true;
|
||||
nativeBuildInputs = [ rustc ];
|
||||
buildPhase = ''
|
||||
rustc -C opt-level=s -C panic=abort --edition 2024 -o micro-activate $src
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
mv micro-activate $out/bin
|
||||
'';
|
||||
};
|
||||
in symlinkJoin {
|
||||
name = "munix";
|
||||
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}
|
||||
'';
|
||||
}
|
||||
12
packages/muvm/default.nix
Normal file
12
packages/muvm/default.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{ 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;
|
||||
cargoDeps = rustPlatform.importCargoLock {
|
||||
lockFile = "${muvm-src}/Cargo.lock";
|
||||
};
|
||||
})
|
||||
44
packages/wl-cross-domain-proxy/default.nix
Normal file
44
packages/wl-cross-domain-proxy/default.nix
Normal file
|
|
@ -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 ];
|
||||
};
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
From c2fd030644cf2074f9d2ffd155839b2e943473d0 Mon Sep 17 00:00:00 2001
|
||||
From: Val Packett <val@packett.cool>
|
||||
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 <val@invisiblethingslab.com>
|
||||
---
|
||||
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
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
../muvm-configure-network.service
|
||||
1
systemd/microvm.target.wants/muvm-remote.service
Normal file
1
systemd/microvm.target.wants/muvm-remote.service
Normal file
|
|
@ -0,0 +1 @@
|
|||
../muvm-remote.service
|
||||
1
systemd/microvm.target.wants/pipewire-bridge.socket
Normal file
1
systemd/microvm.target.wants/pipewire-bridge.socket
Normal file
|
|
@ -0,0 +1 @@
|
|||
../pipewire-bridge.socket
|
||||
1
systemd/microvm.target.wants/session-bus-bridge.service
Normal file
1
systemd/microvm.target.wants/session-bus-bridge.service
Normal file
|
|
@ -0,0 +1 @@
|
|||
../session-bus-bridge.service
|
||||
1
systemd/microvm.target.wants/wayland-bridge.socket
Normal file
1
systemd/microvm.target.wants/wayland-bridge.socket
Normal file
|
|
@ -0,0 +1 @@
|
|||
../wayland-bridge.socket
|
||||
6
systemd/muvm-configure-network.service
Normal file
6
systemd/muvm-configure-network.service
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[Unit]
|
||||
Description=microVM Network configuration
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/opt/bin/muvm-configure-network
|
||||
33
systemd/muvm-remote.service
Normal file
33
systemd/muvm-remote.service
Normal file
|
|
@ -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
|
||||
12
systemd/pipewire-bridge.service
Normal file
12
systemd/pipewire-bridge.service
Normal file
|
|
@ -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
|
||||
8
systemd/pipewire-bridge.socket
Normal file
8
systemd/pipewire-bridge.socket
Normal file
|
|
@ -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
|
||||
11
systemd/session-bus-bridge.service
Normal file
11
systemd/session-bus-bridge.service
Normal file
|
|
@ -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
|
||||
13
systemd/wayland-bridge.service
Normal file
13
systemd/wayland-bridge.service
Normal file
|
|
@ -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
|
||||
9
systemd/wayland-bridge.socket
Normal file
9
systemd/wayland-bridge.socket
Normal file
|
|
@ -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
|
||||
71
templates/musictest/flake.nix
Normal file
71
templates/musictest/flake.nix
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
{
|
||||
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 =
|
||||
{
|
||||
nixpkgs,
|
||||
munix,
|
||||
...
|
||||
}:
|
||||
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";
|
||||
|
||||
nixpkgs.hostPlatform = system;
|
||||
|
||||
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";
|
||||
settings.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";
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
};
|
||||
in
|
||||
{
|
||||
packages = forAllSystems (system: {
|
||||
default = (musictest-vm system).config.system.build.munix;
|
||||
});
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue