bhyve: add xhci tablet support

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:

 - Introduces a new capability bit for XHCI support in bhyve
 - Adds an XHCI controller and tabled support with 1:1 mapping
   between them
 - Adds a couple of unit tests
This commit is contained in:
Roman Bogorodskiy 2017-03-20 17:58:51 +04:00
parent 9bf6b9dfa3
commit daecaea038
13 changed files with 197 additions and 2 deletions

View File

@ -310,6 +310,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)
{
@ -337,6 +349,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;

View File

@ -48,6 +48,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);

View File

@ -248,6 +248,45 @@ bhyveBuildAHCIControllerArgStr(const virDomainDef *def,
return ret;
}
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,
@ -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++) {

View File

@ -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;

View File

@ -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

View File

@ -0,0 +1,3 @@
/usr/sbin/bhyveload \
-m 214 \
-d /tmp/freebsd.img bhyve

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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");

View File

@ -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>

View File

@ -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);