On 07/31/2013 10:14 PM, Cole Robinson wrote:
Starting with qemu 1.6, the qemu-system-arm vexpress-a9 model has a
hardcoded virtio-mmio transport which enables attaching all virtio
devices.
Okay, so there is something named "virtio-mmio" that is visible in the
qemu capabilities; it isn't added to the commandline anywhere, but its
presence means that all the virtio devices are available with the suffix
...-device rather than ...-device-whatever. A bit strange, but if that's
the way it works, that's the way it works...
This all looks okay to me, but somebody else should look too, as it's
getting pretty late here and I'm not certain I'm completely alert :-)
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 | 1 +
.../qemuxml2argv-arm-vexpressa9-virtio.xml | 45 +++++++++++++++
tests/qemuxml2argvtest.c | 4 ++
8 files changed, 124 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 5e423cc..25d356b 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",
@@ -2386,6 +2387,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:
@@ -3027,6 +3029,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);
@@ -3491,6 +3496,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,
@@ -5738,6 +5746,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"));
@@ -6349,6 +6358,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 978be16..4d90f84 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 51064e8..2b0e9fc 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -234,6 +234,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
"vnc-share-policy", /* 150 */
"device-del-event",
+ "virtio-mmio",
);
struct _virQEMUCaps {
@@ -1381,6 +1382,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
{ "pci-bridge", QEMU_CAPS_DEVICE_PCI_BRIDGE },
{ "vfio-pci", QEMU_CAPS_DEVICE_VFIO_PCI },
{ "scsi-generic", QEMU_CAPS_DEVICE_SCSI_GENERIC },
+ { "virtio-mmio", QEMU_CAPS_DEVICE_VIRTIO_MMIO },
};
static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioBlk[] = {
@@ -2814,17 +2816,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 machine types, but at least
- * the only supported serial devices of vexpress-a9 and versatilepb
- * 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 non-virtio serial devices of vexpress-a9 and versatilepb
+ * 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 56f8405..fdb61b0 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -190,6 +190,7 @@ enum virQEMUCapsFlags {
QEMU_CAPS_MLOCK = 149, /* -realtime mlock=on|off */
QEMU_CAPS_VNC_SHARE_POLICY = 150, /* set display sharing policy */
QEMU_CAPS_DEVICE_DEL_EVENT = 151, /* DEVICE_DELETED event */
+ QEMU_CAPS_DEVICE_VIRTIO_MMIO = 152, /* -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 f611940..9b037f5 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;
Urgh. Now I see why this shouldn't be put in qemu_capabilities.c :-/
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
"
@@ -1146,8 +1151,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'
@@ -1281,7 +1286,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()))
@@ -1296,7 +1301,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);
}
@@ -1319,6 +1324,18 @@ cleanup:
return ret;
}
+static int
+qemuDomainAssignARMVirtioMMIOAddresses(virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps)
Does this really need to be arm-specific? Isn't is possible that there
would be other machines/arches that also have a virtio-mmio controller
built-in, and user the virtio-xxx-device devices? Maybe this function
needs a more generic name, and to just check
QEMU_CAPS_DEVICE_VIRTIO_MMIO, rather than adding in the check for
os.arch and os.machine.
+{
+ if (def->os.arch == VIR_ARCH_ARMV7L &&
+ STREQ(def->os.machine, "vexpress-a9") &&
+ 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,
@@ -1833,6 +1850,10 @@ int qemuDomainAssignAddresses(virDomainDefPtr def,
if (rc)
return rc;
+ rc = qemuDomainAssignARMVirtioMMIOAddresses(def, qemuCaps);
+ if (rc)
+ return rc;
+
return qemuDomainAssignPCIAddresses(def, qemuCaps, obj);
}
@@ -3939,6 +3960,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");
}
@@ -4216,6 +4240,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;
@@ -4245,6 +4272,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");
}
@@ -4360,6 +4390,8 @@ qemuBuildNicDevStr(virDomainNetDefPtr net,
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";
@@ -4604,6 +4636,9 @@ qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev,
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'"),
@@ -5597,6 +5632,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);
@@ -6873,7 +6910,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,
@@ -6881,7 +6918,7 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
goto cleanup;
virCommandAddArgList(cmd, "-netdev", host, NULL);
}
- if (qemuDomainSupportsNicdev(def, qemuCaps)) {
+ if (qemuDomainSupportsNicdev(def, qemuCaps, net)) {
if (!(nic = qemuBuildNicDevStr(net, vlan, bootindex, qemuCaps)))
goto cleanup;
virCommandAddArgList(cmd, "-device", nic, NULL);
@@ -6890,7 +6927,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,
@@ -7883,7 +7920,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 0000000..349c758
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.args
@@ -0,0 +1 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /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 /f19-arm.dtb -device virtio-serial-device,id=virtio-serial0 -drive
file=/mnt/data/devel/images/f19-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 0000000..7709db9
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-arm-vexpressa9-virtio.xml
@@ -0,0 +1,45 @@
+<domain type="qemu">
+ <name>armtest</name>
+ <uuid>496d7ea8-9739-544b-4ebd-ef08be936e6a</uuid>
+ <memory>1048576</memory>
+ <currentMemory>1048576</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch="armv7l"
machine="vexpress-a9">hvm</type>
+ <kernel>/arm-kernel</kernel>
+ <initrd>/arm-initrd</initrd>
+ <dtb>/f19-arm.dtb</dtb>
+ <cmdline>console=ttyAMA0,115200n8 rw root=/dev/vda3 rootwait
physmap.enabled=0</cmdline>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <clock offset="utc"/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-arm</emulator>
+ <disk type='file' device='disk'>
+ <source file='/mnt/data/devel/images/f19-arm.raw'/>
+ <target dev='vda' bus='virtio'/>
+ </disk>
+ <interface type='user'>
+ <mac address='52:54:00:09:a4:37'/>
+ <model type='virtio'/>
+ </interface>
+ <console type='pty'/>
+ <console type='pty'>
+ <target type='virtio' port='0'/>
+ </console>
+ <memballoon model='virtio'/>
+ <!--
+ This actually doesn't work in practice because vexpress only has
+ 4 virtio slots available, rng makes 5 -->
+ <rng model='virtio'>
+ <backend model='random'>/dev/random</backend>
+ </rng>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 0bf2724..2bdd18e 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1032,6 +1032,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);