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
|
result
|
||||||
|
/testvm*
|
||||||
|
/target
|
||||||
|
/micro-activate
|
||||||
.direnv/
|
.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.
|
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
|
## 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):
|
Working on muvm & munix locally (not built into the nix store):
|
||||||
|
|
||||||
```
|
```bash
|
||||||
cd muvm && cargo build --locked --release
|
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": {
|
"nodes": {
|
||||||
"flake-utils": {
|
"flake-parts": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"nixpkgs-lib": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1731533236,
|
"lastModified": 1769996383,
|
||||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
|
||||||
"owner": "numtide",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-parts",
|
||||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "numtide",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-parts",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-utils_2": {
|
"libkrun-src": {
|
||||||
"inputs": {
|
"flake": false,
|
||||||
"systems": "systems_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1710146030,
|
"lastModified": 1772170018,
|
||||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
"narHash": "sha256-pi4Mrx9wFE8zT8lx+0su2bP1tTkJBh5FaGNQjAFUAx4=",
|
||||||
"owner": "numtide",
|
"owner": "valpackett",
|
||||||
"repo": "flake-utils",
|
"repo": "libkrun",
|
||||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
"rev": "eeafbc55379b60379414168e7a22d5f95b73d7a0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "numtide",
|
"owner": "valpackett",
|
||||||
"repo": "flake-utils",
|
"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"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758078198,
|
"lastModified": 1770197578,
|
||||||
"narHash": "sha256-60ojlXp42UZYTOAgsiKPZUab1Aa8pXTIo+rz0zoaynI=",
|
"narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=",
|
||||||
"ref": "val/tsvwswkqrrsr",
|
"owner": "NixOS",
|
||||||
"rev": "1f0fc70eb049852a18a5203af2204bd9f5729f29",
|
"repo": "nixpkgs",
|
||||||
"shallow": true,
|
"rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2",
|
||||||
"submodules": true,
|
"type": "github"
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/valpackett/nixpkgs"
|
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"ref": "val/tsvwswkqrrsr",
|
"owner": "NixOS",
|
||||||
"shallow": true,
|
"ref": "nixos-unstable",
|
||||||
"submodules": true,
|
"repo": "nixpkgs",
|
||||||
"type": "git",
|
"type": "github"
|
||||||
"url": "https://github.com/valpackett/nixpkgs"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-parts": "flake-parts",
|
||||||
|
"libkrun-src": "libkrun-src",
|
||||||
|
"muvm-src": "muvm-src",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"virtwl": "virtwl"
|
"sidebus": "sidebus",
|
||||||
|
"wl-backdrop": "wl-backdrop"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"systems": {
|
"sidebus": {
|
||||||
"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": {
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_2",
|
"flake-parts": [
|
||||||
|
"flake-parts"
|
||||||
|
],
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758075582,
|
"lastModified": 1772183103,
|
||||||
"narHash": "sha256-o2lpXQLaM9QcZVr+sAxvh83CqJW1QkFhfja6K40ndmA=",
|
"narHash": "sha256-9jbqBtaLUdOeT95PVUMz45JdUpVeJ25ZYZHEOQn9XsI=",
|
||||||
"ref": "wip",
|
"ref": "main",
|
||||||
"rev": "5a5df73a11b2f6bf671a8fc89926ac993e0fbb78",
|
"rev": "c42eaef55440e2594677ede5279bd8c3eaf128f2",
|
||||||
"shallow": true,
|
"shallow": true,
|
||||||
"submodules": true,
|
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/valpackett/wayland-proxy-virtwl"
|
"url": "https://git.clan.lol/clan/sidebus"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"ref": "wip",
|
"ref": "main",
|
||||||
"shallow": true,
|
"shallow": true,
|
||||||
"submodules": true,
|
|
||||||
"type": "git",
|
"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 = {
|
nixConfig = {
|
||||||
self.submodules = true;
|
extra-substituters = [ "https://cache.clan.lol" ];
|
||||||
# nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
extra-trusted-public-keys = [ "cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28=" ];
|
||||||
# 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";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {self, nixpkgs, flake-utils, virtwl, ...}:
|
inputs = {
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
let
|
|
||||||
pkgs = import nixpkgs {
|
|
||||||
inherit system;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
|
|
||||||
packages.libkrunfw = pkgs.libkrunfw;
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
# packages.libkrunfw = (pkgs.libkrunfw.overrideAttrs {
|
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||||
# 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.libkrun = (pkgs.libkrun.override {
|
sidebus.url = "git+https://git.clan.lol/clan/sidebus?shallow=1&ref=main";
|
||||||
withBlk = true;
|
sidebus.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
withGpu = true;
|
sidebus.inputs.flake-parts.follows = "flake-parts";
|
||||||
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(?)
|
|
||||||
});
|
|
||||||
|
|
||||||
packages.muvm = (pkgs.muvm.override {
|
wl-backdrop.url = "git+https://git.clan.lol/valpackett/wl-backdrop?shallow=1&ref=main";
|
||||||
libkrun = self.packages.${system}.libkrun;
|
wl-backdrop.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
}).overrideAttrs (old: {
|
wl-backdrop.inputs.flake-parts.follows = "flake-parts";
|
||||||
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
|
# To override with local checkouts during development, use the --override-input CLI flag!
|
||||||
munixScript = (pkgs.writeScriptBin "munix" (builtins.readFile ./munix)).overrideAttrs(old: {
|
muvm-src = {
|
||||||
buildCommand = "${old.buildCommand}\n patchShebangs $out";
|
url = "github:valpackett/muvm/c68742bcedb96deb6f23ed5a83188022d1cdf71d"; # v0.5.0+custom-init+dbus
|
||||||
});
|
flake = false;
|
||||||
munixInitRootHook = (pkgs.writeScriptBin "munix-init-root" (builtins.readFile ./munix-init-root)).overrideAttrs(old: {
|
};
|
||||||
buildCommand = "${old.buildCommand}\n patchShebangs $out";
|
libkrun-src = {
|
||||||
});
|
url = "github:valpackett/libkrun/eeafbc55379b60379414168e7a22d5f95b73d7a0"; # PR #558 (map permission fix) + D-Bus WIP
|
||||||
munixInitUserHook = (pkgs.writeScriptBin "munix-init-user" (builtins.readFile ./munix-init-user)).overrideAttrs(old: {
|
flake = false;
|
||||||
buildCommand = "${old.buildCommand}\n patchShebangs $out";
|
};
|
||||||
});
|
# libkrunfw-src = {
|
||||||
in pkgs.symlinkJoin {
|
# url = "github:containers/libkrunfw/20484a2e60290acb74c43ccfd6e1ea4caf41d470"; # v5.1.0
|
||||||
name = "munix";
|
# flake = false;
|
||||||
paths = [ munixScript munixInitRootHook munixInitUserHook self.packages.${system}.muvm pkgs.passt pkgs.bubblewrap ];
|
# };
|
||||||
buildInputs = [ pkgs.makeWrapper ];
|
};
|
||||||
postBuild = ''
|
|
||||||
wrapProgram $out/bin/munix --prefix PATH : $out/bin
|
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
|
templates.musictest = {
|
||||||
projects = with self.packages.${system}; [ libkrun muvm ];
|
description = "Music player demo VM with MPD and Euphonica";
|
||||||
in pkgs.mkShell {
|
path = ./templates/musictest;
|
||||||
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 {
|
nixosConfigurations.testvm-x86_64 = nixpkgs.lib.nixosSystem {
|
||||||
vulkanDrivers = [
|
system = "x86_64-linux";
|
||||||
"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;
|
|
||||||
modules = [
|
modules = [
|
||||||
{
|
self.nixosModules.default
|
||||||
system.stateVersion = "25.11";
|
self.nixosModules.testvm
|
||||||
fileSystems."/".device = pkgs.lib.mkDefault "/dev/sda";
|
{ nixpkgs.config.allowUnfree = true; }
|
||||||
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
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
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))
|
SCRIPT_PATH=$(dirname $(realpath -s $0))
|
||||||
MUVM_PATH=$(dirname $(which muvm))
|
MUVM_PATH=$(dirname $(which muvm))
|
||||||
PASST_PATH=$(dirname $(which passt))
|
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
|
HOST_OPENGL_DRIVER=/run/opengl-driver
|
||||||
|
: "${MICROVM_DEFAULT_COMMAND:=bash}"
|
||||||
|
: "${MUNIX_SYSTEMD_UNITS:="${SCRIPT_PATH}/systemd"}"
|
||||||
MICROVM_CLOSURE=
|
MICROVM_CLOSURE=
|
||||||
MICROVM_COMMAND=()
|
MICROVM_COMMAND=()
|
||||||
MICROVM_UID=1337
|
MICROVM_UID=1337
|
||||||
MICROVM_GID=1337
|
MICROVM_GID=1337
|
||||||
BWRAP_ARGS=()
|
BWRAP_ARGS=()
|
||||||
MUVM_ARGS=()
|
MUVM_ARGS=()
|
||||||
|
SIDEBUS_ARGS=()
|
||||||
GPU=1
|
GPU=1
|
||||||
WAYLAND=1
|
WAYLAND=1
|
||||||
PIPEWIRE=1
|
PIPEWIRE=1
|
||||||
X11=0
|
X11=0
|
||||||
|
ENV_DEFAULTS=1
|
||||||
|
USING_PUBLISH=0
|
||||||
export TMP=/tmp TMPDIR=/tmp TEMP=/tmp TEMPDIR=/tmp LC_ALL=C
|
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
|
while [ "$#" -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-u|--uid) MICROVM_UID="$2"; shift 2;;
|
-u|--uid) MICROVM_UID="$2"; shift 2;;
|
||||||
|
|
@ -22,15 +49,20 @@ while [ "$#" -gt 0 ]; do
|
||||||
--no-gpu) GPU=0; shift 1;;
|
--no-gpu) GPU=0; shift 1;;
|
||||||
--no-wayland) WAYLAND=0; shift 1;;
|
--no-wayland) WAYLAND=0; shift 1;;
|
||||||
--no-pipewire) PIPEWIRE=0; shift 1;;
|
--no-pipewire) PIPEWIRE=0; shift 1;;
|
||||||
|
--no-env-defaults) ENV_DEFAULTS=0; shift 1;;
|
||||||
--x11) X11=1; shift 1;;
|
--x11) X11=1; shift 1;;
|
||||||
--bind) BWRAP_ARGS+=("--bind" "$2" "$3"); shift 3;;
|
-b|--bind) BWRAP_ARGS+=("--bind" "$2" "$3"); SIDEBUS_ARGS+=("--path-mapping" "$3=$2"); shift 3;;
|
||||||
--ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); shift 3;;
|
--ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); SIDEBUS_ARGS+=("--path-mapping" "$3=$2"); shift 3;;
|
||||||
--expose) BWRAP_ARGS+=("--bind" "$2" "$2"); shift 2;;
|
-e|--expose) BWRAP_ARGS+=("--bind" "$2" "$2"); SIDEBUS_ARGS+=("--path-mapping" "$2=$2"); shift 2;;
|
||||||
--ro-expose) BWRAP_ARGS+=("--ro-bind" "$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;;
|
--host-opengl-driver) HOST_OPENGL_DRIVER="$2"; shift 2;;
|
||||||
--munix-bin-dir) SCRIPT_PATH="$2"; shift 2;;
|
--munix-bin-dir) SCRIPT_PATH="$2"; shift 2;;
|
||||||
--muvm-bin-dir) MUVM_PATH="$2"; shift 2;;
|
--muvm-bin-dir) MUVM_PATH="$2"; shift 2;;
|
||||||
--passt-bin-dir) PASST_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;;
|
-*) echo "munix: unknown option: $1" >&2; exit 1;;
|
||||||
*)
|
*)
|
||||||
if [ "$MICROVM_CLOSURE" = "" ]; then
|
if [ "$MICROVM_CLOSURE" = "" ]; then
|
||||||
|
|
@ -47,8 +79,36 @@ if [ "$MICROVM_CLOSURE" = "" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
if [ ${#MICROVM_COMMAND[@]} -eq 0 ]; then
|
||||||
MICROVM_COMMAND=("bash")
|
MICROVM_COMMAND=("$MICROVM_DEFAULT_COMMAND")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$GPU" -eq 1 ]; then
|
if [ "$GPU" -eq 1 ]; then
|
||||||
|
|
@ -69,7 +129,7 @@ if [ "$GPU" -eq 1 ]; then
|
||||||
driver_mod="$(readlink "$driver_link")"
|
driver_mod="$(readlink "$driver_link")"
|
||||||
driver_name="${driver_mod##*/}"
|
driver_name="${driver_mod##*/}"
|
||||||
case "$driver_name" in
|
case "$driver_name" in
|
||||||
amdgpu|msm) # TODO: i915
|
amdgpu|msm_dpu) # TODO: i915
|
||||||
echo "munix: ${card##*/} gpu driver is '$driver_name', using vdrm" >&2;
|
echo "munix: ${card##*/} gpu driver is '$driver_name', using vdrm" >&2;
|
||||||
GPU_MODE=drm
|
GPU_MODE=drm
|
||||||
break;;
|
break;;
|
||||||
|
|
@ -84,9 +144,6 @@ if [ "$GPU" -eq 1 ]; then
|
||||||
GPU_MODE=software
|
GPU_MODE=software
|
||||||
fi
|
fi
|
||||||
MUVM_ARGS+=("--gpu-mode=$GPU_MODE")
|
MUVM_ARGS+=("--gpu-mode=$GPU_MODE")
|
||||||
if [ "$GPU_MODE" = "venus" ]; then
|
|
||||||
MUVM_ARGS+=("-e" "MESA_LOADER_DRIVER_OVERRIDE=zink")
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
BWRAP_ARGS+=("--dir" "/dev/dri")
|
BWRAP_ARGS+=("--dir" "/dev/dri")
|
||||||
MUVM_ARGS+=("--gpu-mode=software")
|
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"
|
"--bind" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"
|
||||||
"--setenv" "WAYLAND_DISPLAY" "$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
|
fi
|
||||||
|
|
||||||
if [ "$PIPEWIRE" -eq 1 ]; then
|
if [ "$PIPEWIRE" -eq 1 ]; then
|
||||||
|
|
@ -119,6 +184,11 @@ if [ "$PIPEWIRE" -eq 1 ]; then
|
||||||
PIPEWIRE_REMOTE=pipewire-0
|
PIPEWIRE_REMOTE=pipewire-0
|
||||||
fi
|
fi
|
||||||
BWRAP_ARGS+=("--bind" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE")
|
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
|
fi
|
||||||
|
|
||||||
if [ "$X11" -eq 1 ]; then
|
if [ "$X11" -eq 1 ]; then
|
||||||
|
|
@ -130,37 +200,87 @@ else
|
||||||
unset DISPLAY XAUTHORITY
|
unset DISPLAY XAUTHORITY
|
||||||
fi
|
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 \
|
--uid $MICROVM_UID --gid $MICROVM_GID \
|
||||||
--tmpfs / \
|
--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 \
|
--proc /proc --ro-bind /sys /sys \
|
||||||
--dev /dev --dir /dev/input --dev-bind /dev/kvm /dev/kvm \
|
--dev /dev --dir /dev/input --dev-bind /dev/kvm /dev/kvm \
|
||||||
--ro-bind "$MUVM_PATH" /run/munix/muvm \
|
--ro-bind "$MUVM_PATH" /run/munix/muvm \
|
||||||
--ro-bind "$PASST_PATH" /run/munix/passt \
|
--ro-bind "$PASST_PATH" /run/munix/passt \
|
||||||
--ro-bind "$MICROVM_CLOSURE/sw/bin/env" /usr/bin/env \
|
--ro-bind "$SCRIPT_PATH/micro-activate" /opt/bin/micro-activate \
|
||||||
--ro-bind "$SCRIPT_PATH/munix-init-root" /usr/bin/munix-init-root \
|
--ro-bind "$WL_PROXY_PATH/wl-cross-domain-proxy" /opt/bin/wl-cross-domain-proxy \
|
||||||
--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 \
|
||||||
|
--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 /nix/store /nix/store \
|
||||||
--ro-bind /run/systemd/resolve /run/systemd/resolve \
|
--file 13 /run/resolv.conf \
|
||||||
--ro-bind /etc/resolv.conf /etc/resolv.conf \
|
--file 14 /run/localtime \
|
||||||
--file 11 /etc/passwd \
|
|
||||||
--file 12 /etc/group \
|
|
||||||
--dir "$XDG_RUNTIME_DIR" \
|
--dir "$XDG_RUNTIME_DIR" \
|
||||||
--setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \
|
--setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \
|
||||||
"${BWRAP_ARGS[@]}" \
|
"${BWRAP_ARGS[@]}" \
|
||||||
muvm \
|
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[@]}" \
|
"${MUVM_ARGS[@]}" \
|
||||||
-e MICROVM_CLOSURE="$MICROVM_CLOSURE" -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \
|
-e container=munix \
|
||||||
-i -t "${MICROVM_COMMAND[@]}" \
|
-e MICROVM_CLOSURE="$MICROVM_CLOSURE" \
|
||||||
11< <(cat <<EOF
|
-e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \
|
||||||
munix:x:$MICROVM_UID:$MICROVM_GID:Hypervisor:/:/run/current-system/sw/bin/nologin
|
-e BOOT_TIME_OFFSET="$BOOT_TIME_OFFSET" \
|
||||||
nobody:x:65534:65534:Unprivileged account:/var/empty:/run/current-system/sw/bin/nologin
|
-i -t -- "${MICROVM_COMMAND[@]}" \
|
||||||
EOF
|
13< /etc/resolv.conf \
|
||||||
) \
|
14< /etc/localtime
|
||||||
12< <(cat <<EOF
|
|
||||||
munix:x:$MICROVM_GID:
|
|
||||||
nogroup:x:65534:
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -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