<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Another attempt at blogging</title>
    <link>http://longhouse.vikings.scot/uefi/qemu-usb-passthrough.html</link>
    <description>ARM, open source and stuff...</description>
    <language>en</language>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>blosxom/2.1.2</generator>

  <item>
    <title>QEMU USB host device pass-through</title>
    <pubDate>Tue, 13 Dec 2016 18:09:00 +0000</pubDate>
    <link>http://longhouse.vikings.scot/2016/12/13#qemu-usb-passthrough</link>
    <category>/uefi</category>
    <guid isPermaLink="false">http://longhouse.vikings.scot/uefi/qemu-usb-passthrough</guid>
    <description>
&lt;h2&gt;Speeding up UEFI driver development&lt;/h2&gt;
&lt;p/&gt;While working on the ChaosKey UEFI driver, I once again found myself in a situation of tedium: how to simplify driver development when the target for my device driver is firmware. Moving around a USB key with a FAT filesystem may be a completely valid thing to do in order to install a pre-existing driver. But when you are trying to learn how to write drivers for a new platform (and write &lt;a href=&quot;http://blog.eciton.net/uefi/uefi-driver-part1.html&quot;&gt;blog posts about it&lt;/a&gt;), the &lt;i&gt;modify -&gt; compile -&gt; copy -&gt; reboot -&gt; load -&gt; fail -&gt; try again&lt;/i&gt; cycle gets quite tedious. As usual, QEMU has/is the answer, letting you pass a USB device controlled by the host over to the guest.

&lt;h3&gt;Make sure your QEMU is built with libusb support&lt;/h3&gt;
&lt;p/&gt;Unsurprisingly, in order to support passing through USB device access to guests, QEMU needs to know how to deal with USB - and it does this using libusb. Most Linux distributions package a version of QEMU with libusb support enabled, but if you are building your own version from source, make sure the output from configure contains &lt;pre&gt;libusb            yes&lt;/pre&gt; If it does not, under Debian, &lt;code&gt;$ sudo apt-get build-dep qemu&lt;/code&gt; should do the trick - anywhere else make sure you manually install libusb v1.0 or later (Debian&apos;s &lt;code&gt;libusb-dev&lt;/code&gt; package is v0.1, which will not work), with development headers.
Without libusb support, you&apos;ll get the error message &lt;code&gt;&apos;usb-host&apos; is not a valid device model name&lt;/code&gt; when following the below instructions.

&lt;h3&gt;Identifying your device&lt;/h3&gt;
&lt;p/&gt;Once your QEMU is ready, in order to pass a device through to a guest, you must first locate it on the host.
&lt;pre&gt;$ lsusb
...
Bus 008 Device 002: ID 1d50:60c6 OpenMoko, Inc
Bus 008 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
....&lt;/pre&gt;
The vendor ID (1d50) of ChaosKey is taken from the &lt;a href=&quot;http://wiki.openmoko.org/wiki/USB_Product_IDs&quot;&gt;OpenMoko project&lt;/a&gt;, which has repurposed their otherwise unused device registry space for various community/homebrew devices.

&lt;p/&gt;If you want to be able to access the device as non-root, ensure the device node under &lt;pre&gt;/dev/bus/usb/&amp;lt;bus&amp;gt;/&amp;lt;device&amp;gt;&lt;/pre&gt; (in this case &lt;code&gt;/dev/bus/usb/008/002&lt;/code&gt;) has suitable read-write access for your user.

&lt;h3&gt;Launching QEMU&lt;/h3&gt;
&lt;p/&gt;Unlike the x86 default &quot;pc&quot; machine, QEMU has no default machine type for ARM. The &quot;generic virtualized platform&quot; type &lt;i&gt;virt&lt;/i&gt; has no USB attached by default, so we need to manually add one. &lt;code&gt;ich-usb-uhci1&lt;/code&gt; supports high-speed, and so is needed for some devices to work under emulation. Using the &quot;virtual FAT&quot; support in QEMU is the easiest way to get a driver into UEFI without recompiling. The example below uses a subdirectory called &lt;code&gt;fatdir&lt;/code&gt; which QEMU generates an emulated FAT filesystem from.

&lt;p/&gt;
&lt;pre&gt;
USB_HOST_BUS=8
USB_HOST_PORT=2
AARCH64_OPTS=&quot;-pflash QEMU_EFI.fd -cpu cortex-a57 -M virt -usb -device ich9-usb-uhci1&quot;
X86_OPTS=&quot;-pflash OVMF.fd -usb&quot;
COMMON_OPTS=&quot;-device usb-host,bus=usb-bus.0,hostbus=$USB_HOST_BUS,hostport=$USB_HOST_PORT -nographic -net none -hda fat:fatdir/&quot;
&lt;/pre&gt;

&lt;p/&gt;
This can then be executed as&lt;br/&gt;
&lt;code&gt;$ qemu-system-x86_64 $X86_OPTS $COMMON_OPTS&lt;/code&gt;&lt;br/&gt;
or&lt;br/&gt;
&lt;code&gt;$ qemu-system-aarch64 $AARCH64_OPTS $COMMON_OPTS&lt;/code&gt;&lt;br/&gt;
respectively.&lt;br/&gt;

&lt;p/&gt;
&lt;b&gt;Note:&lt;/b&gt; Ordering of some of the above options is important.&lt;br/&gt;
&lt;b&gt;Note2:&lt;/b&gt; That AARCH64 &lt;code&gt;QEMU_EFI.fd&lt;/code&gt; needs to be extended to 64MB in order for QEMU to be happy with it. &lt;a href=&quot;http://blog.eciton.net/uefi/qemu-arm-uefi.html&quot;&gt;See this older post for an example.&lt;/a&gt;

&lt;p/&gt;
My usage then looks like the following, after having been dropped into the UEFI shell, with a bunch of overly verbose debug messages in my last compiled version of the driver:
&lt;pre&gt;
Shell&gt; load fs0:\ChaosKeyDxe.efi
*** Installed ChaosKey driver! ***
Image &apos;FS0:\ChaosKeyDxe.efi&apos; loaded at 47539000 - Success
Shell&gt; y (0x1D50:0x60C6) is my homeboy!
1 supported languages
0: 0409
Manufacturer: altusmetrum.org
Product: ChaosKey-hw-1.0-sw-1.6.6
Serial: 001c00325346430b20333632
&lt;/pre&gt;

&lt;p/&gt;
And, yes, those last three lines are actually read from the USB device connected to host QEMU is running on.

&lt;h3&gt;Final comments&lt;/h3&gt;
&lt;p/&gt;
One thing that is unsurprising, but very cool and useful, is that this works well cross-architecture. So you can test that your drivers are truly portable by building (and testing) them for AARCH64, EBC and X64 without having to move around between physical machines.

&lt;p/&gt;
Oh, and another useful command in this cycle is &lt;code&gt;reset -s&lt;/code&gt; in the UEFI shell, which &quot;powers down&quot; the machine and exits QEMU.</description>
  </item>
  </channel>
</rss>
