From 4fa172215de536495239605b9cc2afcc18cb1b55 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Wed, 31 Jul 2013 21:40:35 -0400 Subject: [PATCH] qemu: Support virtio-mmio transport for virtio on ARM Starting with qemu 1.6, the qemu-system-arm vexpress-a9 model has a hardcoded virtio-mmio transport which enables attaching all virtio devices. On the command line, we have to use virtio-XXX-device rather than virtio-XXX-pci, thankfully s390 already set the precedent here so it's fairly straight forward. At the XML level, this adds a new device address type virtio-mmio. The controller and addressing don't have any subelements at the moment because we they aren't needed for this usecase, but could be added later if needed. Add a test case for an ARM guest with one of every virtio device enabled. --- src/conf/domain_conf.c | 12 +++- src/conf/domain_conf.h | 1 + src/qemu/qemu_capabilities.c | 16 +++-- src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 65 +++++++++++++++---- .../qemuxml2argv-arm-vexpressa9-virtio.args | 14 ++++ .../qemuxml2argv-arm-vexpressa9-virtio.xml | 45 +++++++++++++ tests/qemuxml2argvtest.c | 4 ++ 8 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.xml diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a13b42c215..e412f28ddd 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -210,7 +210,8 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "usb", "spapr-vio", "virtio-s390", - "ccw") + "ccw", + "virtio-mmio") VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST, "block", @@ -2390,6 +2391,7 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, return 1; case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390: + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO: return 1; case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW: @@ -3031,6 +3033,9 @@ virDomainDeviceInfoFormat(virBufferPtr buf, info->addr.ccw.devno); break; + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO: + break; + default: virReportError(VIR_ERR_INTERNAL_ERROR, _("unknown address type '%d'"), info->type); @@ -3495,6 +3500,9 @@ virDomainDeviceInfoParseXML(xmlNodePtr node, goto cleanup; break; + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO: + break; + default: /* Should not happen */ virReportError(VIR_ERR_INTERNAL_ERROR, @@ -5848,6 +5856,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO && def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW && def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 && + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO && def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Controllers must use the 'pci' address type")); @@ -6408,6 +6417,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO && def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW && def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 && + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO && def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Network interfaces must use 'pci' address type")); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 048b3a883b..539bc1c8af 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -207,6 +207,7 @@ enum virDomainDeviceAddressType { VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW, + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST }; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 981b8d6e6f..d94188a461 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -240,6 +240,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "usb-storage", /* 155 */ "usb-storage.removable", + "virtio-mmio", ); struct _virQEMUCaps { @@ -1389,6 +1390,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "scsi-generic", QEMU_CAPS_DEVICE_SCSI_GENERIC }, { "i82801b11-bridge", QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE }, { "usb-storage", QEMU_CAPS_DEVICE_USB_STORAGE }, + { "virtio-mmio", QEMU_CAPS_DEVICE_VIRTIO_MMIO }, }; static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioBlk[] = { @@ -2842,17 +2844,19 @@ virQEMUCapsUsedQMP(virQEMUCapsPtr qemuCaps) bool virQEMUCapsSupportsChardev(virDomainDefPtr def, virQEMUCapsPtr qemuCaps, - virDomainChrDefPtr chr ATTRIBUTE_UNUSED) + virDomainChrDefPtr chr) { if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) || !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) return false; - /* This may not be true for all ARM machine types, but at least - * the only supported serial devices of vexpress and versatile - * don't have the -chardev property wired up. */ if (def->os.arch != VIR_ARCH_ARMV7L) - return false; + return true; - return true; + /* This may not be true for all ARM machine types, but at least + * the only supported non-virtio serial devices of vexpress and versatile + * don't have the -chardev property wired up. */ + return (chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO || + (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && + chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO)); } diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 4a6a8ee9b1..f3c8fa86bf 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -195,6 +195,7 @@ enum virQEMUCapsFlags { QEMU_CAPS_Q35_PCI_HOLE64_SIZE = 154, /* q35-pcihost.pci-hole64-size */ QEMU_CAPS_DEVICE_USB_STORAGE = 155, /* -device usb-storage */ QEMU_CAPS_USB_STORAGE_REMOVABLE = 156, /* usb-storage.removable */ + QEMU_CAPS_DEVICE_VIRTIO_MMIO = 157, /* -device virtio-mmio */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6ac460eb07..459b03e43e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -418,22 +418,27 @@ cleanup: } static bool -qemuDomainSupportsNicdev(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) +qemuDomainSupportsNicdev(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps, + virDomainNetDefPtr net) { if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) return false; - /* arm boards require legacy -net nic */ - if (def->os.arch == VIR_ARCH_ARMV7L) + /* non-virtio ARM nics require legacy -net nic */ + if (def->os.arch == VIR_ARCH_ARMV7L && + net->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) return false; return true; } static bool -qemuDomainSupportsNetdev(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) +qemuDomainSupportsNetdev(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps, + virDomainNetDefPtr net) { - if (!qemuDomainSupportsNicdev(def, qemuCaps)) + if (!qemuDomainSupportsNicdev(def, qemuCaps, net)) return false; return virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV); } @@ -474,7 +479,7 @@ qemuOpenVhostNet(virDomainDefPtr def, * option), don't try to open the device. */ if (!(virQEMUCapsGet(qemuCaps, QEMU_CAPS_VHOST_NET) && - qemuDomainSupportsNetdev(def, qemuCaps))) { + qemuDomainSupportsNetdev(def, qemuCaps, net))) { if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("vhost-net is not supported with " @@ -1154,8 +1159,8 @@ cleanup: } static void -qemuDomainPrimeS390VirtioDevices(virDomainDefPtr def, - enum virDomainDeviceAddressType type) +qemuDomainPrimeVirtioDeviceAddresses(virDomainDefPtr def, + enum virDomainDeviceAddressType type) { /* declare address-less virtio devices to be of address type 'type' @@ -1289,7 +1294,7 @@ qemuDomainAssignS390Addresses(virDomainDefPtr def, if (STREQLEN(def->os.machine, "s390-ccw", 8) && virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_CCW)) { - qemuDomainPrimeS390VirtioDevices( + qemuDomainPrimeVirtioDeviceAddresses( def, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW); if (!(addrs = qemuDomainCCWAddressSetCreate())) @@ -1304,7 +1309,7 @@ qemuDomainAssignS390Addresses(virDomainDefPtr def, goto cleanup; } else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390)) { /* deal with legacy virtio-s390 */ - qemuDomainPrimeS390VirtioDevices( + qemuDomainPrimeVirtioDeviceAddresses( def, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390); } @@ -1327,6 +1332,18 @@ cleanup: return ret; } +static int +qemuDomainAssignARMVirtioMMIOAddresses(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps) +{ + if (def->os.arch == VIR_ARCH_ARMV7L && + STRPREFIX(def->os.machine, "vexpress-") && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_MMIO)) { + qemuDomainPrimeVirtioDeviceAddresses( + def, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO); + } + return 0; +} static int qemuSpaprVIOFindByReg(virDomainDefPtr def ATTRIBUTE_UNUSED, @@ -1912,6 +1929,10 @@ int qemuDomainAssignAddresses(virDomainDefPtr def, if (rc) return rc; + rc = qemuDomainAssignARMVirtioMMIOAddresses(def, qemuCaps); + if (rc) + return rc; + return qemuDomainAssignPCIAddresses(def, qemuCaps, obj); } @@ -4367,6 +4388,9 @@ qemuBuildDriveDevStr(virDomainDefPtr def, } else if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) { virBufferAddLit(&opt, "virtio-blk-s390"); + } else if (disk->info.type == + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) { + virBufferAddLit(&opt, "virtio-blk-device"); } else { virBufferAddLit(&opt, "virtio-blk-pci"); } @@ -4668,6 +4692,9 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef, else if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) virBufferAddLit(&buf, "virtio-scsi-s390"); + else if (def->info.type == + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) + virBufferAddLit(&buf, "virtio-scsi-device"); else virBufferAddLit(&buf, "virtio-scsi-pci"); break; @@ -4697,6 +4724,9 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef, } else if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) { virBufferAddLit(&buf, "virtio-serial-s390"); + } else if (def->info.type == + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) { + virBufferAddLit(&buf, "virtio-serial-device"); } else { virBufferAddLit(&buf, "virtio-serial"); } @@ -4829,6 +4859,8 @@ qemuBuildNicDevStr(virDomainDefPtr def, nic = "virtio-net-ccw"; else if (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) nic = "virtio-net-s390"; + else if (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) + nic = "virtio-net-device"; else nic = "virtio-net-pci"; @@ -5077,6 +5109,9 @@ qemuBuildMemballoonDevStr(virDomainDefPtr def, case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW: virBufferAddLit(&buf, "virtio-balloon-ccw"); break; + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO: + virBufferAddLit(&buf, "virtio-balloon-device"); + break; default: virReportError(VIR_ERR_XML_ERROR, _("memballoon unsupported with address type '%s'"), @@ -6078,6 +6113,8 @@ qemuBuildRNGDeviceArgs(virCommandPtr cmd, virBufferAsprintf(&buf, "virtio-rng-ccw,rng=%s", dev->info.alias); else if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) virBufferAsprintf(&buf, "virtio-rng-s390,rng=%s", dev->info.alias); + else if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) + virBufferAsprintf(&buf, "virtio-rng-device,rng=%s", dev->info.alias); else virBufferAsprintf(&buf, "virtio-rng-pci,rng=%s", dev->info.alias); @@ -7354,7 +7391,7 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, * * NB, no support for -netdev without use of -device */ - if (qemuDomainSupportsNetdev(def, qemuCaps)) { + if (qemuDomainSupportsNetdev(def, qemuCaps, net)) { if (!(host = qemuBuildHostNetStr(net, driver, ',', vlan, tapfdName, tapfdSize, @@ -7362,7 +7399,7 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, goto cleanup; virCommandAddArgList(cmd, "-netdev", host, NULL); } - if (qemuDomainSupportsNicdev(def, qemuCaps)) { + if (qemuDomainSupportsNicdev(def, qemuCaps, net)) { bool multiqueue = tapfdSize > 1 || vhostfdSize > 1; if (!(nic = qemuBuildNicDevStr(def, net, vlan, bootindex, @@ -7374,7 +7411,7 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, goto cleanup; virCommandAddArgList(cmd, "-net", nic, NULL); } - if (!qemuDomainSupportsNetdev(def, qemuCaps)) { + if (!qemuDomainSupportsNetdev(def, qemuCaps, net)) { if (!(host = qemuBuildHostNetStr(net, driver, ',', vlan, tapfdName, tapfdSize, @@ -8425,7 +8462,7 @@ qemuBuildCommandLine(virConnectPtr conn, int vlan; /* VLANs are not used with -netdev, so don't record them */ - if (qemuDomainSupportsNetdev(def, qemuCaps)) + if (qemuDomainSupportsNetdev(def, qemuCaps, net)) vlan = -1; else vlan = i; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.args b/tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.args new file mode 100644 index 0000000000..62de9d36bd --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.args @@ -0,0 +1,14 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-arm -S -M vexpress-a9 -m 1024 -smp 1 -nographic \ +-nodefconfig -nodefaults -monitor unix:/tmp/test-monitor,server,nowait \ +-boot c -kernel /arm.kernel -initrd /arm.initrd -append \ +'console=ttyAMA0,115200n8 rw root=/dev/vda3 rootwait physmap.enabled=0' \ +-dtb /arm.dtb -device virtio-serial-device,id=virtio-serial0 -usb \ +-drive file=/arm.raw,if=none,id=drive-virtio-disk0 \ +-device virtio-blk-device,drive=drive-virtio-disk0,id=virtio-disk0 \ +-device virtio-net-device,vlan=0,id=net0,mac=52:54:00:09:a4:37 \ +-net user,vlan=0,name=hostnet0 -serial pty -chardev pty,id=charconsole1 \ +-device virtconsole,chardev=charconsole1,id=console1 \ +-device virtio-balloon-device,id=balloon0 \ +-object rng-random,id=rng0,filename=/dev/random \ +-device virtio-rng-device,rng=rng0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.xml b/tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.xml new file mode 100644 index 0000000000..2acf3c9680 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.xml @@ -0,0 +1,45 @@ + + armtest + 496d7ea8-9739-544b-4ebd-ef08be936e6a + 1048576 + 1048576 + 1 + + hvm + /arm.kernel + /arm.initrd + /arm.dtb + console=ttyAMA0,115200n8 rw root=/dev/vda3 rootwait physmap.enabled=0 + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-arm + + + + + + + + + + + + + + + + /dev/random + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index cf039967cf..c21aca9f23 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1066,6 +1066,10 @@ mymain(void) DO_TEST("arm-vexpressa9-basic", QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DTB, QEMU_CAPS_DRIVE); + DO_TEST("arm-vexpressa9-virtio", + QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DTB, + QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE_VIRTIO_MMIO, + QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM); virObjectUnref(driver.config); virObjectUnref(driver.caps);