Along with video and VNC support, bhyve has introduced USB tablet
support as an input device. This tablet is exposed to a guest
as a device on an XHCI controller.
At present, tablet is the only supported device on the XHCI controller
in bhyve, so to make things simple, it's allowed to only have a
single XHCI controller with a single tablet device.
In detail, this commit:
- Introduce a new capability bit for XHCI support in bhyve
- Add an XHCI controller and tabled support with 1:1 mapping
between them
- Add a couple of unit tests
---
src/bhyve/bhyve_capabilities.c | 15 +++++++
src/bhyve/bhyve_capabilities.h | 1 +
src/bhyve/bhyve_command.c | 50 ++++++++++++++++++++++
src/bhyve/bhyve_device.c | 4 +-
.../bhyvexml2argv-input-xhci-tablet.args | 9 ++++
.../bhyvexml2argv-input-xhci-tablet.ldargs | 3 ++
.../bhyvexml2argv-input-xhci-tablet.xml | 18 ++++++++
.../bhyvexml2argv-xhci-multiple-controllers.xml | 19 ++++++++
.../bhyvexml2argv-xhci-multiple-devs.xml | 19 ++++++++
.../bhyvexml2argv-xhci-no-devs.xml | 17 ++++++++
tests/bhyvexml2argvtest.c | 10 ++++-
.../bhyvexml2xmlout-input-xhci-tablet.xml | 31 ++++++++++++++
tests/bhyvexml2xmltest.c | 3 ++
13 files changed, 197 insertions(+), 2 deletions(-)
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.args
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.ldargs
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.xml
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-xhci-multiple-controllers.xml
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-xhci-multiple-devs.xml
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-xhci-no-devs.xml
create mode 100644 tests/bhyvexml2xmloutdata/bhyvexml2xmlout-input-xhci-tablet.xml
diff --git a/src/bhyve/bhyve_capabilities.c b/src/bhyve/bhyve_capabilities.c
index f72fdea41..a34c596f0 100644
--- a/src/bhyve/bhyve_capabilities.c
+++ b/src/bhyve/bhyve_capabilities.c
@@ -286,6 +286,18 @@ bhyveProbeCapsFramebuffer(unsigned int *caps, char *binary)
BHYVE_CAP_FBUF);
}
+
+static int
+bhyveProbeCapsXHCIController(unsigned int *caps, char *binary)
+{
+ return bhyveProbeCapsDeviceHelper(caps, binary,
+ "-s",
+ "0,xhci",
+ "pci slot 0:0: unknown device
\"xhci\"",
+ BHYVE_CAP_FBUF);
+}
+
+
int
virBhyveProbeCaps(unsigned int *caps)
{
@@ -313,6 +325,9 @@ virBhyveProbeCaps(unsigned int *caps)
if ((ret = bhyveProbeCapsFramebuffer(caps, binary)))
goto out;
+ if ((ret = bhyveProbeCapsXHCIController(caps, binary)))
+ goto out;
+
out:
VIR_FREE(binary);
return ret;
diff --git a/src/bhyve/bhyve_capabilities.h b/src/bhyve/bhyve_capabilities.h
index 3db4f1b88..3db51af02 100644
--- a/src/bhyve/bhyve_capabilities.h
+++ b/src/bhyve/bhyve_capabilities.h
@@ -45,6 +45,7 @@ typedef enum {
BHYVE_CAP_NET_E1000 = 1 << 2,
BHYVE_CAP_LPC_BOOTROM = 1 << 3,
BHYVE_CAP_FBUF = 1 << 4,
+ BHYVE_CAP_XHCI = 1 << 5,
} virBhyveCapsFlags;
int virBhyveProbeGrubCaps(virBhyveGrubCapsFlags *caps);
diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c
index ec7a71572..e0528ed77 100644
--- a/src/bhyve/bhyve_command.c
+++ b/src/bhyve/bhyve_command.c
@@ -249,6 +249,45 @@ bhyveBuildAHCIControllerArgStr(const virDomainDef *def,
}
static int
+bhyveBuildUSBControllerArgStr(const virDomainDef *def,
+ virDomainControllerDefPtr controller,
+ virCommandPtr cmd)
+{
+ size_t i;
+ int ndevices = 0;
+
+ for (i = 0; i < def->ninputs; i++) {
+ virDomainInputDefPtr input = def->inputs[i];
+
+ if (input->bus != VIR_DOMAIN_INPUT_BUS_USB) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("only USB input devices are supported"));
+ return -1;
+ }
+
+ if (input->type != VIR_DOMAIN_INPUT_TYPE_TABLET) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("only tablet input devices are supported"));
+ return -1;
+ }
+ ndevices++;
+ }
+
+ if (ndevices != 1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("only single input device is supported"));
+ return -1;
+ }
+
+ virCommandAddArg(cmd, "-s");
+ virCommandAddArgFormat(cmd, "%d:%d,xhci,tablet",
+ controller->info.addr.pci.slot,
+ controller->info.addr.pci.function);
+
+ return 0;
+}
+
+static int
bhyveBuildVirtIODiskArgStr(const virDomainDef *def ATTRIBUTE_UNUSED,
virDomainDiskDefPtr disk,
virConnectPtr conn,
@@ -392,6 +431,7 @@ virBhyveProcessBuildBhyveCmd(virConnectPtr conn,
*/
size_t i;
bool add_lpc = false;
+ int nusbcontrollers = 0;
virCommandPtr cmd = virCommandNew(BHYVE);
@@ -476,6 +516,16 @@ virBhyveProcessBuildBhyveCmd(virConnectPtr conn,
if (bhyveBuildAHCIControllerArgStr(def, controller, conn, cmd) < 0)
goto error;
break;
+ case VIR_DOMAIN_CONTROLLER_TYPE_USB:
+ if (++nusbcontrollers > 1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("only single USB controller
is supported"));
+ goto error;
+ }
+
+ if (bhyveBuildUSBControllerArgStr(def, controller, cmd) < 0)
+ goto error;
+ break;
}
}
for (i = 0; i < def->nnets; i++) {
diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c
index a3a263b7e..fdfd512e1 100644
--- a/src/bhyve/bhyve_device.c
+++ b/src/bhyve/bhyve_device.c
@@ -106,7 +106,9 @@ bhyveAssignDevicePCISlots(virDomainDefPtr def,
for (i = 0; i < def->ncontrollers; i++) {
if ((def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) ||
- (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA)) {
+ (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA) ||
+ ((def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
&&
+ (def->controllers[i]->model ==
VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI))) {
if (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT
||
!virDeviceInfoPCIAddressWanted(&def->controllers[i]->info))
continue;
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.args
b/tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.args
new file mode 100644
index 000000000..b1c0c94d0
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.args
@@ -0,0 +1,9 @@
+/usr/sbin/bhyve \
+-c 1 \
+-m 214 \
+-u \
+-H \
+-P \
+-s 0:0,hostbridge \
+-s 2:0,xhci,tablet \
+-s 3:0,ahci-hd,/tmp/freebsd.img bhyve
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.ldargs
b/tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.ldargs
new file mode 100644
index 000000000..32538b558
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.ldargs
@@ -0,0 +1,3 @@
+/usr/sbin/bhyveload \
+-m 214 \
+-d /tmp/freebsd.img bhyve
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.xml
b/tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.xml
new file mode 100644
index 000000000..95492e6cb
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-input-xhci-tablet.xml
@@ -0,0 +1,18 @@
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ </os>
+ <devices>
+ <disk type='file'>
+ <driver name='file' type='raw'/>
+ <source file='/tmp/freebsd.img'/>
+ <target dev='hda' bus='sata'/>
+ </disk>
+ <controller type='usb' model='nec-xhci'/>
+ <input type='tablet' bus='usb'/>
+ </devices>
+</domain>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-xhci-multiple-controllers.xml
b/tests/bhyvexml2argvdata/bhyvexml2argv-xhci-multiple-controllers.xml
new file mode 100644
index 000000000..b3f259226
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-xhci-multiple-controllers.xml
@@ -0,0 +1,19 @@
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ </os>
+ <devices>
+ <disk type='file'>
+ <driver name='file' type='raw'/>
+ <source file='/tmp/freebsd.img'/>
+ <target dev='hda' bus='sata'/>
+ </disk>
+ <controller type='usb' model='nec-xhci'/>
+ <controller type='usb' model='nec-xhci'/>
+ <input type='tablet' bus='usb'/>
+ </devices>
+</domain>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-xhci-multiple-devs.xml
b/tests/bhyvexml2argvdata/bhyvexml2argv-xhci-multiple-devs.xml
new file mode 100644
index 000000000..b0828f632
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-xhci-multiple-devs.xml
@@ -0,0 +1,19 @@
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ </os>
+ <devices>
+ <disk type='file'>
+ <driver name='file' type='raw'/>
+ <source file='/tmp/freebsd.img'/>
+ <target dev='hda' bus='sata'/>
+ </disk>
+ <controller type='usb' model='nec-xhci'/>
+ <input type='tablet' bus='usb'/>
+ <input type='tablet' bus='usb'/>
+ </devices>
+</domain>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-xhci-no-devs.xml
b/tests/bhyvexml2argvdata/bhyvexml2argv-xhci-no-devs.xml
new file mode 100644
index 000000000..323063354
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-xhci-no-devs.xml
@@ -0,0 +1,17 @@
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ </os>
+ <devices>
+ <disk type='file'>
+ <driver name='file' type='raw'/>
+ <source file='/tmp/freebsd.img'/>
+ <target dev='hda' bus='sata'/>
+ </disk>
+ <controller type='usb' model='nec-xhci'/>
+ </devices>
+</domain>
diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c
index 4cbc398b7..475e62666 100644
--- a/tests/bhyvexml2argvtest.c
+++ b/tests/bhyvexml2argvtest.c
@@ -167,7 +167,7 @@ mymain(void)
driver.grubcaps = BHYVE_GRUB_CAP_CONSDEV;
driver.bhyvecaps = BHYVE_CAP_RTC_UTC | BHYVE_CAP_AHCI32SLOT | \
BHYVE_CAP_NET_E1000 | BHYVE_CAP_LPC_BOOTROM | \
- BHYVE_CAP_FBUF;
+ BHYVE_CAP_FBUF | BHYVE_CAP_XHCI;
DO_TEST("base");
DO_TEST("acpiapic");
@@ -207,6 +207,14 @@ mymain(void)
DO_TEST("addr-no32devs-multiple-sata-disks");
DO_TEST_FAILURE("addr-no32devs-more-than-32-sata-disks");
+ /* USB xhci tablet */
+ DO_TEST("input-xhci-tablet");
+ DO_TEST_FAILURE("xhci-multiple-controllers");
+ DO_TEST_FAILURE("xhci-no-devs");
+ DO_TEST_FAILURE("xhci-multiple-devs");
+ driver.bhyvecaps ^= BHYVE_CAP_XHCI;
+ DO_TEST_FAILURE("input-xhci-tablet");
+
driver.grubcaps = 0;
DO_TEST("serial-grub-nocons");
diff --git a/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-input-xhci-tablet.xml
b/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-input-xhci-tablet.xml
new file mode 100644
index 000000000..797868e7f
--- /dev/null
+++ b/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-input-xhci-tablet.xml
@@ -0,0 +1,31 @@
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='x86_64'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <disk type='file' device='disk'>
+ <driver name='file' type='raw'/>
+ <source file='/tmp/freebsd.img'/>
+ <target dev='hda' bus='sata'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0' model='nec-xhci'>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x02' function='0x0'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <controller type='sata' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
+ </controller>
+ <input type='tablet' bus='usb'/>
+ </devices>
+</domain>
diff --git a/tests/bhyvexml2xmltest.c b/tests/bhyvexml2xmltest.c
index ba9af2996..3270fee3c 100644
--- a/tests/bhyvexml2xmltest.c
+++ b/tests/bhyvexml2xmltest.c
@@ -118,6 +118,9 @@ mymain(void)
DO_TEST_DIFFERENT("addr-no32devs-multiple-sata-disks");
DO_TEST_FAILURE("addr-no32devs-more-than-32-sata-disks");
+ /* USB xhci tablet */
+ DO_TEST_DIFFERENT("input-xhci-tablet");
+
virObjectUnref(driver.caps);
virObjectUnref(driver.xmlopt);
--
2.11.0