Chain's computar projects

I decided that I needed to document what I’m actually doing with stuff, so that I can more easily replicate that. Of course I could do that in a local document, but I thought that maybe some of the stuff here would be useful to other people.

There are several projects that I have in mind, but first of all I have to setup my laptop.

Mobile Workstation Background
I’m doing mostly mechanical design work and mechanical as well as thermo-mechanical simulations, so that means that I needed a pretty hefty cpu, and having a quadro would be a boon as well. I could have built a desktop with all of that, but I’m hoping to land a job in another part of Europe, so having a mobile workstation that I could easily take with me is perfect.
After thinking about it and analysing my options(which took me over a year) I decided to buy a Lenovo Thinkpad P1 Gen4 in pretty much it’s top configuration:

  • Xeon W-11855M
  • 64GB ECC ram
  • A2000 RTX GPU
  • 2TB nvme ssd(Crucial P5 plus)
  • 3840 x 2400 px, non glossy, non touch display

And then… It spent the last 8 months in its box, because I didn’t have time to set it all up…

Goals of the software setup

The thing is that most of the software that I need runs exclusively on Windows, but I’m more comfortable using Linux as a daily driver, and I like tinkering and customising my setups till I have them just the way I like it. So Linux it is.
The way I intend to set it up is to have Void Linux running with ZFS on root. I also want to run Windows 10 LTSB in a virtual machine. I’ll probably allocate 5(of the 6 available) cores and 48GB of RAM to the VM. I also intend to pass through the dedicated GPU to the windows VM. Looking glass is cool and all, but I want to have a seamless Windows applications on my desktop, so I’ll be accessing the VM through RDP with remoteapp. This setup also creates an interesting problem - I won’t be able to hookup external monitors to my laptop, because the hdmi output is wired directly to the dedicated GPU, and I’ll be using intel iGPU on my host system, so the solution that I came up with(it’s not a great one, I know) is to use displaylink. This complicates things, and I’ve read about the unreliability of those adapters, but I have sneaking suspicion that 4k capable displaylink adapters fail when they’re actually used with 4k displays(I’ve read through dozens of comments on amazon, and 90% of people with failed adapters had that use case). I think that the chip inside those things can barely handle 4k, and given that it has no cooling it simply dies. I have two external displays one 1920x1200 and another 1600x900(this one I’ll probably use in vertical mode), so my hope is that the displaylink chip won’t have to work very hard to drive them and it won’t die on me.
It’s also worth noting that I probably won’t need a dummy hdmi plug, because Nvidia’s professional GPUs allow for overriding EDIDs. I already have the EDID file, and I’ll import it in the VM.

Nice to haves

It would be nice to have a secure boot working, but I might try to tackle that at a later date. A second nvme with mirrored ZFS volume would be cool, but it’s not necessary now. I also intend to autostart wireguard, but also keep running a socks5 proxy that would bypass my vpn, so that I can use vpn for 90% of the stuff, but for internet banking and stuff like that I’ll be able to use my local proxy instead of turning the vpn off. I don’t really want the VM to have internet access, but when I decide to allow it internet access(only specific programs) I’ll force it through the socks5 proxy as well.

Order of operations

Setting everything up will take me days(if not weeks). I’m prepared for that, but it’s best if I tackle this complicated setup one step at a time.

  1. Partition the disk so that I have a separate swap partition(for suspend to disk) and Install Void Linux on ZFS, preferably without rEFInd. ZFS pool should be encrypted and divided into three filesystems: root, home, vms

  2. Perform post install setup: set up locales, keyboard inputs, change fonts(I’ll have to install terminus fonts and select the largest font available because of 4k), install doas, mksh, and set those up.

  3. WM and audio. Install pipewire(or alternatively setup alsa), rtkit, dbus, xorg. Perform initial xorg setup. Patch, modify and install dwm, dmenu, st, dwmblocks(not sure about that one yet). Potentially modify xorg config to make it work well(also at this point modify mouse keymap so that my trackball works the way I want it to). Install Librewolf using my script(I wrote a script that checks for the latest librewolf debian package, downloads it, converts it to xbps and installs it).

This stage will probably also require me to modify initrd so that dGPU is disabled by default.

  1. Experiment with multihead setup. Try to make displaylink work. Different scaling for different monitors will be required, so I expect I’ll spend some time playing around with xrandr.

  2. Power management. Acpid + TLB.

  3. VM setup and dGPU passthrough. Guest OS should think that it’s running on actual hardware. I might want to pin some CPU cores. Pass through the RTX A2000 to the VM, connect external monitor and load up EDID file. Setup file sharing with the host OS.

I expect more things will have to be done, but because this is a very involved setup I think it’s best to document what I’m doing.

Wish me luck.


VM Test run installation.

Here I’ll document the steps taken to install everything in a similar fashion that I intend to on real hardware. The only differences will be partition sizes and the fact that it’s running in a VM.

This particular setup is a synthesis of these four guides:
Installing Void on a ZFS Root(Official Void Linux Documentation)
Installation via chroot (x86/x86_64/aarch64)(Official Void Linux Documentation)
Void Linux Single disk UEFI(zfsbootmenu wiki)
UEFI Booting without an Intermediate Boot Manager(zfsbootmenu wiki)

Some steps are added by me(such as swap creation).

hrmpf iso is used as the installation medium in this procedure - this means that the procedure is limited to x86_64 systems and assumes glibc.

Boot the installation medium and proceed as follows.

ZFS prep work

Build and load ZFS modules

xbps-reconfigure -a
modprobe zfs

Generate /etc/hostid


Store pool passphrase in a key file

echo 'SomeKeyphrase' > /etc/zfs/zroot.key
chmod 000 /etc/zfs/zroot.key

This step got me thinking - what’s the use of FDE if my passphrase will be stored in cleartext, but it doesn’t exactly work like that. This file is later stored on the initramfs on the encrypted zfs filesystem. Zfsbootmenu will ask for the passphrase to unlock the disk, once that’s done you’ll be able to select from the available boot environments, snapshots, kernels etc… After the selection the final kernel and initramfs will be loaded into memory and the contents of the passphrase will be used to unlock the disk again(otherwise you’d have to type in the passphrase twice).

SSD prep work

bash-5.0# gdisk /dev/sda
GPT fdisk (gdisk) version 1.0.8

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries in memory.

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

Command (? for help): n
Partition number (1-128, default 1): 1
First sector (34-16777182, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-16777182, default = 16777182) or {+-}size{KMGTP}: +512M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): EF00
Changed type of partition to 'EFI System'

Command (? for help): n
Partition number (2-128, default 2): 2
First sector (34-16777182, default = 1050624) or {+-}size{KMGTP}: 
Last sector (1050624-16777182, default = 16777182) or {+-}size{KMGTP}: +1G
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 8200
Changed type of partition to 'Linux swap'

Command (? for help): n
Partition number (2-128, default 3): 3
First sector (34-16777182, default = 3147776) or {+-}size{KMGTP}: 
Last sector (3147776-16777182, default = 16777182) or {+-}size{KMGTP}: 
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sda.
The operation has completed successfully.

Here we have an 8GB virtual drive that we’ve partitioned as follows:

/dev/sda1   EFI system partition    fat32       512MB
/dev/sda2   Linux swap              linux-swap  1GB
/dev/sda3   Linux filesystem        zfs root    6.5GB

ZFS pool creation

zpool create -f -o ashift=12 \
 -O compression=lz4 \
 -O acltype=posixacl \
 -O xattr=sa \
 -O relatime=on \
 -O encryption=aes-256-gcm \
 -O keylocation=file:///etc/zfs/zroot.key \
 -O keyformat=passphrase \
 -o autotrim=on \
 -m none zroot /dev/disk/by-id/wwn-0x5000c500deadbeef-part3

The Official Void Linux documentation warns that using traditional device nodes like /dev/sda3 may cause intermittent import failures, so we’re using disk-by-id.

Also some notes from the zfsbootmenu guide:

It’s out of the scope of this guide to cover all of the pool creation options used - feel free to tailor them to suit your system. However, the following options need to be addressed:

  • encryption=aes-256-gcm - You can adjust the algorithm as you see fit, but this will likely be the most performant on modern x86_64 hardware.
  • keylocation=file:///etc/zfs/zroot.key - This sets our pool encryption passphrase to the file /etc/zfs/zroot.key , which we created in a previous step. This file will live inside your initramfs stored ON the ZFS boot environment.
  • keyformat=passphrase - By setting the format to passphrase , we can now force a prompt for this in zfsbootmenu . It’s critical that your passphrase be something you can type on your keyboard, since you will need to type it in to unlock the pool on boot.

Create our initial ZFS file systems

zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/void
zfs create -o mountpoint=/home zroot/home
zfs create -o mountpoint=/vms zroot/vms

Again, notes from the zfsbootmenu guide:

NOTE : It is important to set the property canmount=noauto on any file systems with mountpoint=/ (that is, on any additional boot environments you create). Without this property, Void will attempt to automount all ZFS file systems and fail when multiple file systems attempt to mount at / ; this will prevent your system from booting. Automatic mounting of / is not required because the root file system is explicitly mounted in the boot process.

Also note that, unlike many ZFS properties, canmount is not inheritable. Therefore, setting canmount=noauto on zroot/ROOT is not sufficient, as any subsequent boot environments you create will default to canmount=on . It is necessary to explicitly set the canmount=noauto on every boot environment you create.

Export, then re-import with a temporary mountpoint of /mnt

zpool export zroot
zpool import -N -R /mnt zroot
zfs load-key -L prompt zroot
zfs mount zroot/ROOT/void
zfs mount zroot/home

At this point we won’t use the vms filesystem, so we don’t worry about it.

Verify that everything is mounted correctly

# mount | grep mnt
zroot/ROOT/void on /mnt type zfs (rw,relatime,xattr,posixacl)
zroot/home on /mnt/home type zfs (rw,relatime,xattr,posixacl)

Install Void

Adjust the mirror / libc / package selection as you see fit

XBPS_ARCH=x86_64 xbps-install -S -R -r /mnt base-system vim efibootmgr gptfdisk linux5.19 linux5.19-headers

Copy our files into the new install

cp /etc/hostid /mnt/etc
cp /etc/resolv.conf /mnt/etc/
mkdir /mnt/etc/zfs
cp /etc/zfs/zroot.key /mnt/etc/zfs

Chroot into the new OS

mount -t proc proc /mnt/proc
mount -t sysfs sys /mnt/sys
mount -B /dev /mnt/dev
mount -t devpts pts /mnt/dev/pts
PS1='(chroot) # ' chroot /mnt/ /bin/bash

Basic Void configuration

Set the keymap, timezone and hardware clock

cat << EOF >> /etc/rc.conf

Configure your glibc locale

cat << EOF >> /etc/default/libc-locales
en_US.UTF-8 UTF-8
en_US ISO-8859-1
xbps-reconfigure -f glibc-locales

Set a root password


Obviously those locales, keymaps, etc should be adjusted accordingly.

ZFS Configuration

Install ZFS

xbps-install -S
xbps-install zfs

To more quickly discover and import pools on boot, we need to set a pool cachefile

zpool set cachefile=/etc/zfs/zpool.cache zroot

Configure our default boot environment

zpool set bootfs=zroot/ROOT/void zroot

Configure Dracut to load ZFS support

cat << EOF > /etc/dracut.conf.d/zol.conf
add_dracutmodules+=" zfs "
omit_dracutmodules+=" btrfs "
install_items+=" /etc/zfs/zroot.key "

Rebuild the initramfs

xbps-reconfigure -f linux5.19

I’m really not sure if this step is necessary at this point.

Install and configure ZFSBootMenu

  • Assign command-line arguments to be used when booting the final kernel. Because ZFS properties are inherited, assign the common properties to the ROOT dataset so all children will inherit common arguments by default.
zfs set org.zfsbootmenu:commandline="ro quiet" zroot/ROOT

It’s worth noting that it’s very cool that the kernel command line arguments can be adjusted by setting the zfs properties.

Create a vfat and swap filesystems

mkfs.vfat -F32 /dev/sda1
mkswap /dev/sda2

Create fstab entries and mount the efi partition

cat << EOF >> /etc/fstab
$( blkid | grep /dev/sda1 | cut -d ' ' -f 2 ) /boot/efi vfat defaults 0 0
$( blkid | grep /dev/sda2 | cut -d ' ' -f 2 ) none swap defaults 0 0
mkdir /boot/efi
mount /boot/efi

Install ZFSBootMenu and gummiboot-efistub

xbps-install zfsbootmenu gummiboot-efistub

Enable zfsbootmenu image creation

Edit /etc/zfsbootmenu/config.yaml and set:

  • ManageImages: true under the Global section
  • Versions: 3 and Enabled: true under the Components section
  • Enabled: true and Versions: false under EFI section

See generate-zbm(5) for more details.

Sample /etc/zfsbootmenu/config.yaml
  ManageImages: true
  BootMountPoint: /boot/efi
  DracutConfDir: /etc/zfsbootmenu/dracut.conf.d
  ImageDir: /boot/efi/EFI/void
  Versions: 3
  Enabled: true
    Config: /boot/syslinux/syslinux.cfg
    Enabled: false
  ImageDir: /boot/efi/EFI/void
  Versions: false
  Enabled: true
  CommandLine: ro quiet loglevel=0

Because zfsbootmenu is actually a minimal linux environment in itself we can modify its behaviour by modifying the config.yaml file and reconfiguring zfsbootmenu. So, for example if we want the timeout to be 5 seconds instead of 10 and we want to use a large font(if we’re using a HiDPI display), we can can modify the last lines of config.yaml like so:

  CommandLine: ro quiet loglevel=0 fbcon=font:TER16x32 zbm.timeout=5

You can refer to the official zfsbootmenu documentation for more zfsbootmenu specific options.

Generate the initial ZFSBootMenu initramfs

xbps-reconfigure -f zfsbootmenu
zfsbootmenu: configuring ...
Creating ZFS Boot Menu 2.0.0, from kernel /boot/vmlinuz-5.19.15_1
Created new UEFI image /boot/efi/EFI/void/vmlinuz.EFI
Created initramfs image /boot/efi/EFI/void/initramfs-2.0.0_1.img
Created kernel image /boot/efi/EFI/void/vmlinuz-2.0.0_1
zfsbootmenu: configured successfully. 

Booting the Bundled Executable

The efibootmgr utility provides a means to configure your firmware to boot the bundled executable. For example,

efibootmgr -c -d /dev/sda -p 1 -L "ZFSBootMenu" -l \\EFI\\VOID\\VMLINUZ.EFI

will create a new entry that will boot the executable written to /boot/efi/EFI/void/vmlinuz.EFI if your EFI system partition is /dev/sda1 and is mounted at /boot/efi . (Remember that the EFI system partition should be a FAT volume, so the path separators are backslashes and paths should be case-insensitive.) For good measure, create an alternative entry that points at the backup image:

efibootmgr -c -d /dev/sda -p 1 -L "ZFSBootMenu (Backup)" -l \\EFI\\VOID\\VMLINUZ-BACKUP.EFI

The firmware should provide some means to select between these alternatives.

It is also generally possible to configure the boot sequence from your firmware setup interface. Simply find and select the path to the bundled EFI executable from this interface.

It’s worth noting that at this point the backup entry will be pointing at a nonexistent file. This file will be generated next time zfsbootmenu is reconfigured, but if you want to be safe you can always do:

cp /boot/efi/EFI/void/vmlinuz.EFI /boot/efi/EFI/void/vmlinuz-backup.EFI

To makes sure that the boot order is correct it’s best to fist create the backup entry and then the main entry. Otherwise it might be necessary to reorder entries with something like:

efibootmgr -o 0004,0005,0000,0001,0003,0002

Also, if you’re trying to perform this procedure in a virtual machine as I have you might run into problems with running efibootmgr. At first it gave me EFI variables are not supported on this system. error message, so I left the chroot and mounted efivarfs:

mount -t efivarfs none /sys/firmware/efi/efivars

Then I entered the chroot again and mounted the efivarfs again using the same command.

Exit the chroot, unmount everything

umount -n /mnt/{dev/pts,dev,sys,proc}
umount /mnt/boot/efi

If you’ve mounted efivarfs now would be a good time to unmount that as well(first inside the chroot, and then in the installation environment).

Export the zpool and reboot

zpool export zroot
1 Like

How confident are you that you’ll be able to pass the dGPU to the VM and have it render properly through RDP or were you only going to be using the VM with an external monitor?

I have a similar setup for my ME work (even down to restricting VM internet access), but I’m doing it with server hardware. I remember unrestricted NVENC sessions were one of the key specs the graphics card needed to be used over RDP which the A2000 has.

The idea is to use the external monitor just for the initial setup(I have a 12 inch fullHD display that I got for free, it was broken but I’ve fixed it), and later on rely exclusively on RDP.
I’ll admit that the whole endeavour is a bit of a gamble, but I’d say that I’m about 70% confident that the passthrough will work. There are some guides on how to do that on laptops and, although there are no guarantees, many of them mention that higher end gear should work fine. People have done that on Lenovo Legion laptops, so I’m hopeful.

1 Like

FWIW I don’t see any problems in your approach.
I’m looking to upgrade my whole VDI setup hopefully soon and am also planning on using an A2000 so I’m going to keep an eye on this.

1 Like

Post installation - initial setup

After booting up for the first time I want to bring up the network, add the user, switch from sudo to doas, install mksh.


After booting into the fresh install the network won’t work - that’s because the dhcpcd isn’t running, so we start it up:

# ln -s /etc/sv/dhcpcd /var/service/

Install mksh

# xbps-install -S mksh

Adding the main user

# useradd -m -s /bin/mksh -U -G wheel,users,audio,video,cdrom,input chain
# passwd chain

Switch from sudo to doas

First we install doas

# xbps-install -S opendoas

Now we set it up so that anyone in wheel group can execute stuff as root. We’ll also allow anyone in wheel to poweroff and reboot the system without being prompted for a password.

# echo -e "permit persist :wheel\npermit nopass :wheel as root cmd poweroff\npermit nopass :wheel as root cmd reboot" > /etc/doas.conf
# chown -c root:root /etc/doas.conf
# chmod -c 0400 /etc/doas.conf
doas.conf should look like so

permit persist :wheel
permit nopass :wheel as root cmd poweroff
permit nopass :wheel as root cmd reboot

At this point it’s prudent to test it, because if we’ve made a mistake here(like a typo) we might get in trouble later after we disable the root account login.

# doas -C /etc/doas.conf && echo "config ok" || echo "config error" 

If that works then we can proceed.

At this point we’ll add sudo to the list of ignored packages and remove it, and fake its presence by creating a symlink:

# echo "ignorepkg=sudo" > /etc/xbps.d/ignore_sudo.conf 
# xbps-remove sudo
# ln -s /usr/bin/doas /usr/bin/sudo

Disable root account login

doas passwd --lock root

Install extra console fonts and increase font size to 16x32 (this is needed specifically for HiDPI displays)

doas zfs set org.zfsbootmenu:commandline="ro quiet fbcon=font:TER16x32" zroot/ROOT
doas xbps-install -S terminus-font
doas echo "FONT=ter-232b.psf.gz" >> /etc/rc.conf
1 Like

Setting up mksh

Because we’ve installed mksh first, and created the user account later, the home directory should already contain .mkshrc file, but if it doesn’t we can copy it over:

cp /etc/skel/.mkshrc ~/

Afterwards we probably want to modify it somewhat. Open it in your favourite editor and add stuff before the line that says:

\: place customisations above this line 

This is what I’ve added to my .mkshrc:

builtin set -U 

alias ls='ls --color=auto'
alias reboot='doas reboot'
alias poweroff='doas poweroff'


Obviously ufetch won’t work if it’s not installed on the system:

doas xbps-install -S ufetch
1 Like

Librewolf installation and update script

Since void linux maintainers refuse to package unpopular browsers(which is understandable, they’re already short handed when it comes to maintainers, and building packages that barely anyone would use isn’t the most reasonable use of their resources), you can either use an Appimage, flatpack, install it through nixpkgs, build it from source yourself, or do what I did.

So this is the script that I use to install and update librewolf on void linux. (1.2 KB)

It requires curl and xdeb to work. It works by going to the official librewolf debian(bullseye) repository, takes the latest available version and downloads it, converts it to xbps package format and installs it. Very simple stuff, but it works.

I didn’t spend too much time working on this script, so I’m sure it can be improved, but here’s the source:

LATEST=$( curl -s $REPOURL | grep -o '"librewolf.*deb" ' | sed s/\"//g | sort -r -V | head -1 )
INSTALLED_VER=$( xbps-query -p pkgver librewolf )
LATEST_VER=$( echo $LATEST | sed -e 's/_/-/1' -e 's/_.*\.deb//' | rev | sed -e 's/-/_/1' | rev )
#LATEST=$( curl -s | grep -o '"librewolf.*deb" ' | sed s/\"//g | sort -r -V | head -1 )

if [ -z $INSTALLED_VER ] || [ $INSTALLED_VER != $LATEST_VER ]; then 
	TEMP=$( mktemp )
	xdeb -Sedr --arch=x86_64 ./$LATEST | tee $TEMP
	INSTALL_CMD=$( grep "Install using" $TEMP | cut -d '`' -f 2 )
	rm $TEMP

	while true; do
	read -p "Do you want to install the package now? (y/n) " yn 
	case $yn in 
		[yY] ) doas $INSTALL_CMD;
		[nN] ) exit;; 
		* ) echo invalid response;; 

	while true; do 
	read -p "Do you want to clean up? (y/n) " yn 
	case $yn in 
		[yY] ) xdeb -Cbq ./$LATEST;
		[nN] ) exit;;
		* ) echo invalid response;; 
#	xdeb -Cbq ./$LATEST
	echo "Latest available version already installed."

So at this point I’ve completed the first two steps of my plan for this thing. The procedure was tested in a virtual machine, and everything seems to work great, so I have a basic Void Linux Install ready to go in a VM. The thing is that setting up X and pipewire will differ on real hardware, so I’m not sure if I should continue with the VM, or switch to working on actual hardware at this point.

Some other thoughts that I have.
I’ve tried setting up pipe wire in my VM and it’s kind of a mess. I can make it work, but not with wireplumber, and because I don’t use any seat management rtkit has problems setting nice levels. But do I really need seat management? Really? It’s a laptop for Christ’s sake! And honestly the whole seat management thing seems to me like a solution looking for a problem. Of course I could skip seat management and pipewire altogether and go with alsa, but that’s another set of problems(again - it’s a laptop, so I expect to plug and unplug audio devices from which makes the alsa approach even more complicated than it would otherwise be).

Also dbus annoys me. Having to put:

dbus-run-session dwm

in .xinitrc is idiotic.

1 Like

A man of culture, I see. I assume you already know of hrmpf.

I used this to install Void on ZFS on my TR box that serves as my virtualization and gaming PC. I’m using the recommended rEFInd bootloader, unfortunately my 2nd boot partition needs rsync-ing manually, but that is ok with me. I have NVME ZFS mirror, but the boot partition is ext4 and boot-efi is vfat (on each SSD), so the secondary drive needs manual updating of the files.

You could use GRUB, but do you really want to?
I see you used gummiboot efistub.

How much more based can this guy be? I use oksh, but mksh is nice too.

Note: to uninstall sudo and bash, add in /etc/xbps.d/xbps.conf


Then xbps-remove -Ro bash sudo. Besides neofetch, I never had issues with removing bash, as the system using dash as the default shell.

Pipewire works. I use sway, can’t comment on xorg, but it’s xorg, of course it works.

Not hard to do, just a dracut away. Add to /etc/dracut.conf.d/vfio.conf

dd_dracutmodules+=" vfio "
force_drivers+=" vfio vfio-pci vfio_iommu_type1 vfio_virqfd "
install_items="/etc/modprobe.d/vfio.conf /usr/sbin/ /usr/bin/find /usr/bin/dirname"

Add to /etc/dracut.conf.d/zol.conf

add_dracutmodules+=" zfs "
omit_dracutmodules+=" btrfs "

To /etc/modprobe.d/vfio.conf

options vfio-pci ids=id:1,id:2,id:etc

To /usr/sbin/

DEVS="id:1 id:2 id:etc"

for DEV in $DEVS; do
    echo "vfio-pci" > /sys/bus/pci/devices/$DEV/driver_override

modprobe -i vfio-pci

I have some other things I could share, but they don’t come to mind now.

I will take some time later to read everything here.


Limited to x86? Sure. Assumes glibc? I used hrmpf to install the musl version of Void and it works just fine.

Before I forget, to get VMs going, in order to get VMs to run in libvirt, I need to

echo 1 > /sys/module/kvm/parameters/ignore_msrs

I do this on each startup, I should put it in rc.local. Without this, VMs just don’t start.

That is generally applicable for any ZFS pool.

I don’t know what this is, I wish I could help. Pipewire works fine for me on the RPi with HDMI audio. I haven’t tested on my TR box. I had sway running on it at some point, but it became headless after I passed through the GPU.

Not even seatd? I wish my setup would go this minimal, but sway would just refuse to start without one. Initially I had elogind (been using it for a long time), but since seatd came along, it got better. Some time ago, I used to just create my own /run/user/1000 directory and chown and chmod it in a startup script, but after some time, sway just refused to work without a seat management.


Firefox dropped support for alsa altogether, you can’t use it without pulseaudio. I suppose this is the same for librewolf. I use FF with pipewire-pulse. Some people had success in making it work with apulse, but I couldn’t make it to work, so I just succumbed. With pipewire and seatd, things have been stable and not making me go bald anymore.

Oh, you tell me? Last time I tried to get rid of it altogether, I hate it. But I had things not work because of that, because so many stuff integrate with it. For example, without dbus, mako (my wayland notification pop-up utility) doesn’t work. And I use mako to get thunderbird notifications. Initially I was planning to use mako + notify-send to show notifications for updates, but I got a better solution by doing it in swaybar.

Speaking of the update notifications, it is a bit janky, but it works. I have this script in root’s crontab to run every couple of hours

/usr/bin/xbps-install -S
/usr/bin/xbps-install -Su --dry-run | /usr/bin/wc -l > /tmp/updates.txt

First sync the repo, then dry-run update. If the amount of lines is higher then 0, updates are available. I have this in my swaybar script that just echos the variable bellow

VAR_UPDATES_AVAILABLE=$(cat /tmp/updates.txt)
[ ${VAR_UPDATES_AVAILABLE} -eq 0 ] && VAR_UPDATE_INFO="up-to-date ✅" || VAR_UPDATE_INFO="updates-available 🔄"

Oh… Well, I guess you have your own issues.

In all honesty, Void in VMs has never worked well for me, but when I actually put it on real hardware, it just works and it works very well! I tried doing a Void gaming VM using the glibc version, but I can’t get it to show any output on my second GPU.

I just bought 2 USB PCI-E cards and will pass those through to VMs (I got 2 GPUs and now 2 USB cards, I have a Gigabyte monitor with a built-in 2-port KVM switch), I will be verifying the vfio IDs once again, although my PC doesn’t output anything when it finally boots into the system, so I’d think the driver is blacklisted properly. In all honesty, for a gaming VM, I was planning to use something like Artix s6, or maybe use Fedora again, but I’d really like to get Void to work as a VM. I can SSH into it just fine, but I can’t do much on it. I know that the bootup process is hanging a bit because of the GPU, it does have some errors, I never managed to fix it.

Well, the hrmpf isos are 64-bit only, and what I meant by “assumes glibc” is that the steps that I’ve documented are for installing the glibc version of Void, thus glibc is assumed. Of course you’re right and the steps can be easily modified to install the musl version.

If you do this every time, wouldn’t adding kvm.ignore_msrs =1 to your kernel commandline work better?

By default pipewire on Void uses pipewire-media-session as it’s session and policy manager. I’ve read that it’s an example implementation and they’re planning to deprecate it in favour of wireplumber(which you can switch to right now). The thing is that wireplumber doesn’t work in a VM for some reason.

I made it work without seatd in my VM, but honestly I’m not 100% sure yet if I’ll run it this way or just install seatd. The thing is that I don’t need any of that stuff. The only benefit I’d get from installing seatd would be not having to edit several config files, which isn’t that big of deal anyway. I’ll have to think about it.

That was my initial plan as well.

Some people have tried running a modern desktops without dbus, but I think that Gentoo is most conductive to such modifications. Why don’t we all use plan9 plumber instead of dbus again?


I wasn’t even sure if they way I intend to install it will work, so I decided to try it in a VM first, and if it works just repeat the steps with real hardware. Amazingly everything works perfectly, so I’ll be moving on to the actual installation soon.

1 Like

Now that you point it out, I didn’t realize it was a kernel config. Well, I should have realized it, it is kvm… The only problem?

$ cat 
echo 1 > /sys/module/kvm/parameters/ignore_msrs

$ cat /sys/module/kvm/parameters/ignore_msrs 

$ doas sysctl -a | grep -i msr
$ doas sysctl -n kvm.ignore_msrs
sysctl: cannot stat /proc/sys/kvm/ignore_msrs: error code 2

$ doas sysctl -n kvm.parameters.ignore_msrs
sysctl: cannot stat /proc/sys/kvm/parameters/ignore_msrs: error code 2

The kernel looks into /proc, the parameter is in /sys.

ps -ef|grep pipe | grep -v grep
root       374   350  0 Oct09 ?        00:00:00 runsv pipewire
root       379   350  0 Oct09 ?        00:00:00 runsv pipewire-pulse
_pipewi+   387   374  0 Oct09 ?        00:00:00 pipewire
_pipewi+   388   379  0 Oct09 ?        00:00:00 pipewire-pulse
_pipewi+   418     1  0 Oct09 ?        00:00:03 /usr/bin/pipewire-media-session

Oh wow, ok, time to break my audio again.

I’m not familiar with plan9 stuff, but I heard it was pretty revolutionary, yet nobody uses it. If I was more technically apt, I would probably try it. Maybe in the future.

I’m glad you have a better experience than me. I managed to get Void on barely supported hardware, like Odroid N2+ and HC4 with some hacks and runs great on the RockPro64, not to mention in LXD it was always flawless (Void in LXD on Void on the RPi 4, my daily driver).

I also had it on the RPi 2, RPi 3 and before it was an official image, I built Void using piraty’s void_mklive git fork and have been running it since. The updates on xbps are so well executed that even using this unofficial image and going through a few kernel modification changes (on both the Pi 2 and the Pi 4, once the different kernel build for each Pi was made), the system is still going strong (and have had a recent upgrade from 5.10 to 5.15).

But running Void in a VM? I had plenty of desktop Void VMs before and they all were terrible. From being awfully slow, to having no GPU acceleration (so xorg JWM wouldn’t start, let alone sway / wayland), to not booting properly after kernel / initramfs updates, I only had terrible experiences. So I’m glad you are having it easier.

I still have Void headless VMs (one still has that issue with not booting anything other than kernel 5.9, even though all other VMs worked well with more recent kernels, exactly same config), but I’m planning to move to LXD on the N2+. Samba, Prometheus + Grafana and other stuff will just become containers.

I still prefer Void for its simplicity and because xbps and xbps-src are so amazeballs. If only I could get Void to run in modloop from the initramfs in a tmpfs, like Alpine diskless install does, I’d be the happiest. It is the only reason I use Alpine from time to time. Used to run Alpine on the RPi 3 for about 7-8 months, used it as a router, not having to write to the SD card is nice - replaced it with a RockPro64 2GB version as the router now.

Was planning to use OpenBSD, but it didn’t boot properly, so I moved to FreeBSD, but found out the USB WiFi 5 I have doesn’t have drivers for FreeBSD, so Void it is. It’s been running nice for a month or 2. Well, initially I had a 4GB version, but was barely using 134MB, so I got the this and the 4GB one will be a NAS. Got eMMC now, so running Void is not that big of a deal hardware-wise anymore.

I managed to get ZFS on Void on aarch64 after a lot of pain, but I went with FreeBSD on the NAS, just because ZFS is a first-class citizen there. And if drivers become available, I might move to OpenBSD on the router (probably in, idk, 3-4 years? maybe more, when they catch up). Still Void runs so well on the N2+, the RPi 4 and my TR, I really wouldn’t switch to anything else on these.

Yup. Looks like it.

PipeWire Media Session

PipeWire Media Session is an example session manager for PipeWire.

Note that we recommend the use of WirePlumber instead.

Still if it works - it works. I don’t think there’s any rush to switch over just yet.

Honestly I’m using VirtualBox, so that might explain why my Void VM works.

Alpine is an awesome distro as well, but I think that that Void is more suitable for daily driving on a desktop. I used to administer a server running OpenBSD, and it’s my favourite bsd flavour(or tied with NetBSD).

I intend to set up a fileserver running FreeBSD in the future though(same reason as you - ZFS), and I think that I’ll document that effort here as well.

1 Like

I installed it. Kept failing to start after I made the symlink to runsvdir. I had to manually kill the pipewire-media-session manually. It sems to work fine. I then rebooted, but the media session gets started automatically. Not ideal to have to kill it myself.

Just for the luls, I disabled the runit services and killed any remaining processes, sound still works somehow. Not sure if I want to deal with wireplumber. Since Void works fine with the symlinks, I will probably just keep it. Haven’t tried the pipewire.desktop thingy, but I don’t know if sway executes the XDG stuff (kinda doubt it).

It’s possible that pipewire starts pipewire-media-session automatically. It’s kind of important to track what gets started where(service? pipewire config? .xinitrc?).

You might find this and this usefull.


Right, it was taking default config from /usr/share/pipewire/pipewire.conf, since the /etc/pipewire folder did not exist and the conf either. Modified that for plumber. Will have to reboot to see how it goes.

So, I’ve managed to replicate the installation on actual hardware. Obviously it’s partitioned a bit differently(96Gb swap :hushed: ).

There are some notes regarding hardware installation however.
First, connecting the wifi from commandline isn’t difficult, but these are extra steps that I had to take that weren’t documented earlier:

wpa_passphrase SSID PASSWORD >> /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
wpa_supplicant -B -iwlan0 -c/etc/wpa_supplicant/wpa_supplicant-wlan0.conf

Secondly, I should have installed the wireless-tools package along with the base install - I didn’t do that, so I had to boot from hrmpf again, import the zfs pool, mount the filesystem, and install it there that way.
After that was done the interface name was different so I had to check it before configuring wpa_supplicant.

Now on to step 3 - xorg, WM, audio, dwm, st, dwmblocks etc…

1 Like

Xorg and pipewire installation and configuration

Xorg installation was simple:

doas xbps-install -S xorg picom xterm fluxbox

Fluxbox was installed temporarily(or maybe I’ll leave it as backup).

At this point I needed scaling, so I’ve created

sleep 1 
xrandr --output eDP1 --scale 0.7499x0.7499

And this is how I’ve setup my .xinitrc:

picom -b 
~/ &
exec dbus-launch --exit-with-x11 fluxbox

Pipewire with wireplumber

So I’ve tried several ways to make it work, and at this point I can’t make rtkit work. Apparently it’s pretty tightly integrated with elogind which I don’t intend to use, so rtkit warnings would most likely still show up even if I used seatd.


First we install dumb runtime dir:

xbps-install -S dumb_runtime_dir

Now we install pipewire and everything required to make it work(ffmpeg is needed to get sound in librewolf/firefox):

xbps-install -S dbus pipewire alsa-pipewire wireplumber pavucontrol ffmpeg

Enable dbus:

ln -s /etc/sv/dbus /var/service

Enable alsa integration:

mkdir -p /etc/alsa/conf.d
ln -s /usr/share/alsa/alsa.conf.d/50-pipewire.conf /etc/alsa/conf.d
ln -s /usr/share/alsa/alsa.conf.d/99-pipewire-default.conf /etc/alsa/conf.d

Configure pipewire:

mkdir -p /etc/pipewire
cp /usr/share/pipewire/pipewire.conf /etc/pipewire/

Now edit /etc/pipewire/pipewire.conf so that the context.exec block looks like this:

context.exec = [
    { path = "/usr/bin/wireplumber" args = "" }
    { path = "/usr/bin/pipewire" args = "-c pipewire-pulse.conf" }

At this point we can start pipewire by adding pipewire & to our .xinitrc

Remaining issues

Disabling rtkit in pipewire.conf doesn’t solve the issue, neither does not installing or removing rtkit. I even tried modifying /usr/share/polkit-1/actions/org.freedesktop.RealtimeKit1.policy in accordance with this post, and tried creating the rules mentioned in the response to it as well, but no matter what rtkit keeps giving me error messages. At this point I’m not sure if rtkit is usable without elogind or even full blown systemd.

I’ve spent my free time(and not so free actually) to set up the WM. Patching dwm, st, and dmenu took a while, especially since new versions were recently released and most of the patches listed at dont apply cleanly, so I had to tinker with it a little bit. I don’t mind that kind of work, especially since I enjoy C, but I have to admit that it took me a lot of time, and I expect it to take some more of it.
At this point I don’t intend to document what patches I’m applying and in what order and what needs fixing afterwards, but I may upload shell scripts that automate patch application here, and possibly fixed patches that apply cleanly. No promises.

I have to admit that I haven’t daily driven linux on the desktop for years, but always felt most comfortable when I had the opportunity to do it, so switching from windows straight to dwm is a bit of a change of pace, so one of the first things that I did to my dwm was to implement help, which is kind of funny I guess, because it jives with the suckless philosophy to the extent that if you need help - you need to provide it to yourself.
It’s a simple keybinding(F1) that launches xterm with a bunch of switches and executes less pointed at a help file that I’ve written for myself(~/.help). It was an interesting learning exercise that pushed me to test out all of the keybindings and dwm and figure out how to describe what they do.

I definitely want to put more effort into documenting setting up the bar, tray etc…

1 Like