[vfio-users] Trying to pass through USB controller.

Jonathan Scruggs j.scruggs at gmail.com
Tue Feb 23 16:38:08 UTC 2016


If I pass through 0:14, won't I loose USB on my host? I have a USB keyboard
and mouse and need USB for other things like thumb drives.

Jon
On 23 Feb 2016 15:57, "Samuel Holland" <samuel at sholland.org> wrote:

> Hello,
>
> On 02/23/2016 06:46 AM, Jonathan Scruggs wrote:
>
>> How can I pass through the USB ports to the guest so that the items
>> plugged into the ports appear to the guest?
>>
>
> In short, "sudo setpci -s0:14.0 0xd0.W=0x0000" will pass through all of
> your ports.
>
> I was planning to write a blog post about it this month, but I haven't
> gotten to it yet, so I guess I'll write it here. I have been using this
> setup since December, and everything works without any issues. I had
> done like you (playing with the firmware options) and gotten nowhere; I
> finally found a Google+ post[0] (the user appears to have been deleted)
> with a link to the 9 series PCH datasheet[1], which has been immensely
> useful.
>
> I have only tried this with an AsRock Z97E-ITX/ac. It might not work on
> your board if your firmware disables switching ports (see section
> 16.1.37). Your chipset datasheet is here[2]. The xHCI registers are in
> chapter 17 in your datasheet, so you will have to adapt the section
> references.
>
> Step 1: Map your USB ports
> ==========================
> This is easiest to do if you turn USB3 (xHCI) off completely. First, you
> need to map your EHCI controllers to USB buses as seen by the kernel.
> These numbers can change when you reboot your machine, so do this after
> you have disabled USB3. Run `lspci` and look at the numbers after the
> EHCI controllers (#1/#2). Then run the command below. You should get
> similar output.
>
> $ readlink -f /sys/bus/usb/devices/usb?
> /sys/devices/pci0000:00/0000:00:14.0/usb1
> /sys/devices/pci0000:00/0000:00:1a.0/usb2
> /sys/devices/pci0000:00/0000:00:1d.0/usb3
>
> Run `watch lsusb -t` in a terminal. Take a flash drive/mouse/etc. and
> plug it into each port on your machine. There are 14 of them. If you
> cannot find some, they might be in a mini-PCIe or M.2 slot, or just not
> connected.
>
> Use the bus numbers you found earlier, and the output of lsusb, to map
> physical ports to logical ports on controllers. Eight of them will be on
> the EHCI controller marked #1, and the other six will be on #2. Now sort
> them, starting with EHCI #1 port 1, and ending with EHCI #2 port 6.
>
> Next you should turn USB3 back on in your firmware settings.
>
> Step 2: Pass through your controller
> ====================================
> This is the easy part. Just add whichever controller you want to use in
> the VM to your libvirt XML or qemu command line. Personally, I only ever
> need to use USB2 devices in Windows, so I pass through both EHCI
> controllers. However, I believe the EHCI controllers on the PCH do not
> support MSI, so that may affect performance with devices like flash
> drives. With a keyboard or mouse, it shouldn't make any difference.
>
> Step 3: Route your USB ports
> ============================
> Looking at section 16.1.36, we can connect individual ports to either
> the EHCI or xHCI controller. On your sorted list of ports, mark which
> ones you want to have available in the VM, and which ones you want to
> use on the host. This is switchable at runtime, so you can create
> several lists--I have some ports that are routed to EHCI all of the
> time, and others I toggle back and forth.
>
> Turn each list of port routes into a binary mask: 0 for each EHCI port,
> and 1 for each xHCI port. The least significant bit is EHCI #1 port 1.
> Extend it to 16 bits by setting the two most significant bits to 0. Then
> convert it to hexadecimal. It should be something between 0x0000 and
> 0x3fff. Finally, run setpci (as root) to change the routing. Moved USB
> devices will reset immediately. The command is
>
> # setpci -s<xHCI PCI address> 0xd0.W=0x<the mask in hex>
>
> For example, to move everything to the xHCI controller:
>
> # setpci -s0:14.0 0xd0.W=0x3fff
>
> Again, even though you are running this command to configure the xHCI
> controller, the bits are in the order the ports appear to the EHCI
> controllers. If, for some reason, you cannot turn off xHCI to find that
> order, use table 2-2 in section 2.2 to map xHCI ports (what you see in
> lsusb minus 1) to EHCI ports.
>
> If you are connecting a USB3 (blue) port to a EHCI controller, there's
> one additional step you (probably) need to take. You will need to either
> 1) remember to never plug a USB3 device into the port, or 2) turn off
> USB3 on that port. See section 16.1.38 for the register to change. I
> have not needed to do this, so I am not certain, but I believe the port
> numbers here are as they appear to the xHCI controller.
>
> Step 4: Toggle your port mask
> =============================
> If you have more than one keyboard/mouse or a KVM switch or synergy, you
> are done. Personally, I use this method to avoid all of that, so I have
> to have a way to switch my keyboard back and forth while running the VM.
> The first step is to have a service running as root, that will run
> setpci for you when you tell it to switch ports. I use the following
> python script. You should only need to change the masks and port number
> (at the bottom). Hopefully it doesn't get mangled in the email.
>
> ----------------SNIP----------------
> #!/usr/bin/env python3
>
> import socketserver
> import subprocess
> import syslog
>
> def change_usb_state(action):
>     global state
>     if action == state: return
>     if action == "toggle": action = "guest" if state == "host" else "host"
>     syslog.syslog("Setting xHCI port routing mask to
> {:#x}".format(masks[action]))
>     if subprocess.call(["setpci", "-s0:14.0",
> "0xd0.L=0x{:08x}".format(masks[action])]) == 0: state = action
>     else: syslog.syslog("Calling setpci failed. Assuming routing is
> unchanged.")
>
> class PCIHandler(socketserver.StreamRequestHandler):
>     def handle(self):
>         for line in self.rfile:
>             action = line.strip().decode("utf-8")
>             syslog.syslog("Got action request: {}".format(action))
>             if action in ["guest", "host", "toggle"]:
> change_usb_state(action)
>
> class ThreadedTCPServer(socketserver.ThreadingMixIn,
> socketserver.TCPServer): pass
>
> masks = { "guest": 0x0fc, "host": 0x0ff }
> state = "host"
> server = ThreadedTCPServer(("127.0.0.1", 10), PCIHandler)
> server.serve_forever()
> ----------------SNIP----------------
>
> On Linux, you can then use netcat as any user to toggle your ports. I
> use i3, and have a key mapped like so, which toggles my USB ports and
> then locks my screen:
>
> ----------------SNIP----------------
> bindsym Control+Mod1+Menu exec --no-startup-id busybox nc 127.0.0.1 10 <<<
> toggle; exec --no-startup-id slock
> ----------------SNIP----------------
>
> The second part is to connect qemu to your service. (You could also have
> the service accept remote connections, but then anyone on your network
> could control your USB ports. I only recommend this if you have an
> isolated network to use with qemu, and you only have the service listen
> on that network.) The simple and secure way to do this is to connect a
> serial port in the VM to your service. I use Q35 and qemu directly; you
> will have to adapt this to libvirt yourself.
>
> ----------------SNIP----------------
>     -device isa-serial,chardev=com1,index=0 \
>       -chardev socket,host=127.0.0.1,id=com1,port=10
> ----------------SNIP----------------
>
> Third, you need some way to connect to the serial port from within the
> guest. On a Linux guest, you can use picocom, socat, etc. On Windows,
> the simple way is to use a PowerShell script:
>
> ----------------SNIP----------------
> $port = New-Object System.IO.Ports.SerialPort COM1,115200,None,8,One
> $port.Open()
> $port.WriteLine("toggle")
> $port.Close()
> ----------------SNIP----------------
>
> Personally, I use AutoHotKey to map the same key in Windows to switching
> my ports and locking my screen. I'd be happy to share it, but it is too
> long to paste here.
>
> Hopefully that should get you going. I apologize if this is too long,
> but I wanted to be thorough. It definitely took a weekend to get set up,
> but once it works, it is really rather seamless.
>
> [0]
> https://plus.google.com/wm/quevuelvamatt/app/basic/stream/z13ki3ixwvubfpk4e04chfi45r3lyv4zeiw
> [1]
> http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/9-series-chipset-pch-datasheet.pdf
> [2]
> http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/x99-chipset-pch-datasheet.pdf
>
> (See also sections 5.19-5.21 of the datasheet for more information.)
>
> --
> Regards,
> Samuel Holland <samuel at sholland.org>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/vfio-users/attachments/20160223/f970aa32/attachment.htm>


More information about the vfio-users mailing list