Skip to content

Instantly share code, notes, and snippets.

@573
Last active January 29, 2024 21:24
Show Gist options
  • Save 573/2da25ed9bc9d8150016949cabde5bf5a to your computer and use it in GitHub Desktop.
Save 573/2da25ed9bc9d8150016949cabde5bf5a to your computer and use it in GitHub Desktop.
How to add host usb to qemu using monitor

This is all tested on windows 10 running wsl equipped with nix.

The vm doesn't boot w/o problems, so I decided to boot just the generated iso in qemu first (admin account bc I wanna use host usb later):

& $(scoop which qemu-system-x86_64.exe) -monitor tcp:localhost:55555,server,nowait -net nic,netdev=user.0,model=virtio -netdev user,id=user.0,hostfwd=tcp::2221-:22 -m 512 -device qemu-xhci,id=xhci -cdrom c:/temp/nixos.iso -boot d,menu=on -M pc

Regarding the monitor option read the excellent https://unix.stackexchange.com/questions/426652/connect-to-running-qemu-instance-with-qemu-monitor as well as https://wiki.ubuntu.com/QemuDiskHotplug I will add the usb devices using the monitor session. First run (normal user) a nix-shell equipped with the nc command:

wsl bash --login --init-file ~/.nix-profile/etc/profile.d/nix.sh -c "bash"
nix-shell -p netcat -I nixpkgs=channel:nixos-19.09

And now for the disk image file lying on your windows host somewhere just:

echo drive_add\ 0\ if=none,id=usbdisk1,file=C:/temp/8GB.vhd  |nc -N localhost 55555
echo device_add\ usb-storage,id=usbdisk1,drive=usbdisk1  |nc -N localhost 55555
echo info\ usb  |nc -N localhost 55555

Observe that for the windows qemu port (https://qemu.weilnetz.de/doc/qemu-doc.html#pcsys_005fmonitor) the windows filename syntax works. Also tres cool is that adding host devices (passthrough) even works in the non-elevated user's account, example:

echo drive_add\ 0\ if=none,id=realusbstick1,file=//./PhysicalDrive1  |nc -N localhost 55555
echo device_add\ usb-storage,id=realusbstick1,drive=realusbstick1  |nc -N localhost 55555

Can do basically all things imaginable now:

mount /dev/sda1 /mnt/usbimage
scp -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa -P 2221 /mnt/c/temp/nixos.iso root@localhost:/mnt/usbimage/
# or even better
rsync -avz --no-perms --no-owner --no-group -e "ssh -i ~/.ssh/id_rsa -p 2221 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --progress /mnt/c/temp/nixos.iso root@localhost:/mnt/usbimage/
dd if=/mnt/usbimage/nixos.iso of=/dev/sdb status=progress

Booting the usbstick testwise in qemu (again admin account) is possible pretending it is a cdrom:

& $(scoop which qemu-system-x86_64.exe) -monitor tcp:localhost:55555,server,nowait -net nic,netdev=user.0,model=virtio -netdev user,id=user.0,hostfwd=tcp::2221-:22 -m 512 -device qemu-xhci,id=xhci -cdrom //./PhysicalDrive1 -boot d,menu=on -M pc

Also working:

& $(scoop which qemu-system-x86_64.exe) -monitor tcp:localhost:55555,server,nowait -net nic,netdev=user.0,model=virtio -netdev user,id=user.0,hostfwd=tcp::2221-:22 -m 512 -device qemu-xhci,id=xhci -drive file=//./PhysicalDrive1,if=none,id=bootstick -device usb-storage,drive=bootstick -boot d,menu=on -M pc

Use case:

Access usb devices via nixos-shell:

Starting nixos-shell with

hardware.sane.enable = true;
hardware.sane.extraBackends = [ pkgs.sane-airscan ];
virtualisation.qemu.options = [
  "-usb" "-device usb-host,productid=0x04A9,vendorid=0x220E"
];

settings accordingly you'd get:

/nix/store/xzdf0wav4ijr8m00jw3mg1ir32hfw3yp-nixos-vm qemu-system-x86_64: -device usb-host,productid=0x04A9,vendorid=0x220E: failed to init libusb

You could try the whole thing as Windows Administrator user but the above setup should do everything needed (in netcat equipped nix-shell):

virtualisation.qemu.options = [
   "-monitor tcp:localhost:55555,server,nowait"
];

(https://unix.stackexchange.com/questions/426652/connect-to-running-qemu-instance-with-qemu-monitor)

echo device_add\ usb-host,vendorid=0x220E,productid=0x04A9 |nc -N localhost 55555

with the nc available via scoop (in elevated powershell session):

echo "device_add usb-host,vendorid=0x220E,productid=0x04A9" |nc localhost 55555

But get as well (maybe we just need admin perms as well):

QEMU 5.2.0 monitor - type 'help' for more information (qemu) device_add usb-host,vendorid=0x220E,productid=0x04A9 Error: failed to init libusb (qemu)

Would sure involve setting up nix in the windows elevated account (https://github.com/gerardog/gsudo as well as wsl2).

https://qemu.readthedocs.io/en/latest/system/usb.html

q=qemu+passthrough+windows+host+failed+to+init+libusb

TODO Had that sort of issue solved using libvirt documented somewhere. discourse.nixos.org ?

WSL 2 Loose tips

requires Hyper-V
but: When Cisco-VPN is running, DNS won't work, probably also QEMU won't work as before (EDIT: qemu in wsl1 still works, in wsl2 not (yet)). So either disable VPN (temporarily) or try https://docs.microsoft.com/en-us/windows/wsl/troubleshooting#bash-loses-network-connectivity-once-connected-to-a-vpn (via microsoft/WSL#6457 (comment)):

  • VPN adapter is the one which has (german) "Beschreibung. . . . . . . . . . . : Cisco AnyConnect Secure Mobility Client Virtual Miniport Adapter for Windows x64": Doesn't work either, just temp. disable vpn

To initially install a WSL distribution at all you'll probably need the graphical login with your elevated account, setting up things via gsudo and powershell cmdlets didn't work for me (i. e. https://xuad.net/artikel/wsl-auf-version-2-heben).

https://github.com/Trundle/NixOS-WSL describes very well how the process is, best case you have a nix installation already, use:

NIX_PATH=nixpkgs=http://nixos.org/channels/nixpkgs-unstable/nixexprs.tar.xz nix-build -A system -A config.system.build.tarball ./nixos.nix

with the checked out repo and copy the archive somewhere to import via wsl. Latter is possible via gsudo again once wsl2 is set up correctly.

q=wsl2+cisco+vpn+ping+fails (this microsoft/WSL#5821 (comment) could work)

Scanner still not detected even after getting lsusb (qemu monitor device_add) to work in a wsl session via elevated user. at least there is no libusb error message.

Other possibilties

https://github.com/NixOS/nixpkgs/tree/master/pkgs/os-specific/linux/usbip
via https://gist.github.com/danvy/9486bf730371436131cb888ff4c2ceb6: https://www.heise.de/select/ix/2016/2/1454730392228766 (https://github.com/cezanne/usbip-win/releases/tag/v0.3.3-dev)
more on wsl2 dns maybe here https://superuser.com/questions/1533291/how-do-i-change-the-dns-settings-for-wsl2 (via q=wsl2+systemd-resolved)
or here microsoft/WSL#4285

Seems to work (promising): microsoft/WSL#4277 (comment) (also here https://gist.github.com/pyther/b7c03579a5ea55fe431561b502ec1ba8)
In pwsh with VPN active:

Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Hyper-V.*#2"}
Get-DnsClientServerAddress -AddressFamily ipv4 | Select-Object -ExpandProperty ServerAddresses

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment