User Tools

Site Tools


doc:appunti:linux:sa:qemu_usb_passthrough

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 automaticamente 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.

Web References

doc/appunti/linux/sa/qemu_usb_passthrough.txt · Last modified: 2022/11/03 12:49 by niccolo