This is an old revision of the document!
Table of Contents
QEMU USB device passthrough
Come passare completamente la gestione di una periferica USB da un sistema virtualizzante (host) QEMU (GNU/Linux con KVM) ad un sistema virtualizzato (guest) Windows 10. Procedura sperimentata su Debian GNU/Linux 11 Bullseye.
Il programma emulatore qemu-system-x86_64 deve sapere quale periferica USB deve essere collegata alla macchina guest. È possibile identificare la periferica in tre modi diversi:
- Identificazione con vendorid e productid. Ogni periferica USB ha un identificativo produttore/prodotto che dovrebbe essere univoco. Il sistema operativo GNU/Linux mostra tali codici con il comando lsusb.
- Identificazione tramite hostbus e hostaddr. Quando una periferica viene connessa ad una porta USB, il sistema operativo GNU/Linux le assegna un indirizzo host relativo al bus USB (un PC generalmente ha diversi bus USB). L'indirizzo è univoco rispetto al bus; si tratta di un numero che si incrementa ad ogni nuova periferica aggiunta. Quindi una periferica che ha ricevuto ad esempio hostaddr 8, se viene scollegata e poi nuovamente collegata può ricevere hostaddr 9. Quando una periferica è connessa è possibile vedere quali hostbus e hostaddr le sono stati assegnati con il comando lsusb.
- Identificazione tramite hostbus e hostport. La posizione fisica di una porta USB è univocamente determinata da due identificatori: uno per il bus USB ed un altro per la porta. Questa modalità consente di determinare a priori la periferica USB da passare all'emulatore, senza sapere marca e modello della periferica e senza consultare quale address ha ricevuto dal kernel. Sarà sufficiente utilizzare sempre la stessa porta fisica per il collegamento. Per ispezionare la gerarchia di bus USB e porte è possibile utilizzare il comando lsusb -t.
Esempio: lettore di flash card USB
Identificare la periferica
Consideriamo come esempio un lettore di flash card. Inserendo il dispositivo in una porta USB, il sistema ospitante GNU/Linux lo identifica come segue (output del comando lsusb):
Bus 001 Device 026: ID 05e3:0723 Genesys Logic, Inc. GL827L SD/MMC/MS Flash Card Reader
In particolare notiamo:
- Bus 001 - La periferica è collegata al primo bus USB dell'host. Altre porte USB dell'host possono essere collegate a bus diversi.
- Device 026 - Il sistema operativo ha essegnato alla periferica indirizzo 26 sul bus #1. Tale indirizzo cambia se la periferica viene scollegata e quindi ricollegata.
- ID 05e3:0723 - I due numeri esadecimale sono il vendorid e productid codificati nell'hardware della periferica.
Se vogliamo conoscere la posizione fisica sul bus USB utilizziamo il comando lsusb -t:
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/6p, 480M |__ Port 1: Dev 26, If 0, Class=Mass Storage, Driver=usbfs, 480M
In questo caso notiamo:
- Bus 01 - Il bus USB è sempre il numero 1.
- Port 1.1 - La porta ha un identificativo gerarchico con il punto utilzzato come separatore: abbiamo l'hub numero 1 seguito dal numero della porta 1.
Assegnare i permessi
È possibile eseguire il programma qemu-system-x86_64
da utente non privilegiato, ma l'emulatore dovrà avere pieno accesso alla periferica USB di cui si desidera il passthrough a Windows. Dopo aver identificato hostbus e hostaddr assegnati dal kernel alla periferica, l'utente root potrà assegnare i permessi necessari. Ad esempio con:
chmod 0666 /dev/bus/usb/001/026
È possibile configurare il sistema in modo tale che una determinata periferica riceva gli opportuni permessi ad ogni connessione. Ad esempio si potrebbe volere che la periferica sia in lettura/scrittura per gli utenti che appartengono al gruppo plugdev (in Debian è il gruppo degli utenti autorizzati a montare e smontare i dispostivi rimuovibili). Per ottenere questo risultato si crea un file ad esempio /etc/udev/rules.d/99-flash-card-reader.rules con il seguente contenuto:
SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="05e3", ATTR{idProduct}=="0723", GROUP="plugdev", MODE="0660"
Per forzare il sistema udev a rileggere i file di configurazione si esegue:
udevadm control --reload-rules && udevadm trigger
Alla successiva connessione della periferica si può verificare che abbia ricevuto i giusti permessi.
Aggiungere la periferica all'avvio di QEMU
Se la periferica è già collegata all'host al momento dell'avvio di QEMU, è possibile passare dalla riga di comando gli opportuni parametri all'emulatore qemu-system-x86_64, in modo che la periferica venga aggiunta e compaia in Gesione dispositivi. Qui di seguito i parametri per fare il passthrough della periferica identificandola in uno dei tre modi possibili:
-usb -device usb-host,vendorid=0x05e3,productid=0x0723
-usb -device usb-host,hostbus=1,hostaddr=26
-usb -device usb-host,hostbus=1,hostport=1.1'
Ecco una riga di comando minimale, ma completa per avviare l'emulatore:
qemu-system-x86_64 -m 4096 -machine accel=kvm \ -device qemu-xhci \ -usb -device 'usb-host,vendorid=0x05e3,productid=0x0723' \ -drive 'file=win10_64bit_c.img,format=raw' -boot c
Notare la presenza del device qemu-xhci; se la macchina ospite supporta le specifiche hardware XHCI (ogni macchina successiva al 2010 dovrebbe) è opportuno caricare tale emulazione, che supporta con un solo controller le periferiche USB 1.1, USB 2.0 e USB 3.0. Utilizzando questo driver non è necessario aggiungere la specifica bus={usb-bus.0|ehci.0}
nei comandi che aggiungono le periferiche USB. Senza esplicitare quel device l'emulazione delle periferiche USB 3.0 non funziona e la periferica compare in Gestione dispositivi di Windows con un triangolo giallo con punto esclamativo.
Aggiungere la periferica dalla console QEMU
Se la periferica USB viene collegata dopo che QEMU è stato avviato, è possibile utilzzare la console di QEMU per aggiungere la periferica al sistema Windows guest.
Attivando Show Tabs dal menu View di QEMU sarà possibile accedere alla console compat_monitor0, quindi si possono eseguire i comandi info usbhost per verificare che a periferica sia stata riconosciuta:
(qemu) info usbhost Bus 1, Addr 26, Port 1.1, Speed 480 Mb/s Class 00: USB device 05e3:0723, USB Storage
ATTENZIONE! Se QEMU non ha identificato correttamente il tipo della periferica (USB Storage in questo caso), è possibile che manchino i permessi di lettura/scrittura sulla periferica stessa.
A questo punto la periferica può essere aggiunta con un comando del tipo:
(qemu) device_add usb-host,vendorid=0x05e3,productid=0x0723
Immediatamente il Gestione dispositivi di Windows dovrebbe riconoscere la nuova periferica.