[libvirt] [PATCH 9/9] qemu: Support virtio-mmio transport for virtio on ARM

Cole Robinson crobinso at redhat.com
Thu Aug 1 02:14:39 UTC 2013


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        |  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;
 
     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)
+{
+    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);
-- 
1.8.3.1




More information about the libvir-list mailing list