[qemu] Fix qmp capabilities calls on i686 (bz #1003162) Fix crash with -M isapc -cpu Haswell (bz #986790) F

Cole Robinson crobinso at fedoraproject.org
Tue Sep 3 18:49:49 UTC 2013


commit 9e0a86718c5c91e964eb4b2a87375926bd3a36cf
Author: Cole Robinson <crobinso at redhat.com>
Date:   Tue Sep 3 14:49:39 2013 -0400

    Fix qmp capabilities calls on i686 (bz #1003162)
    Fix crash with -M isapc -cpu Haswell (bz #986790)
    Fix crash in lsi_soft_reset (bz #1000947)
    Fix initial /dev/kvm permissions (bz #993491)

 ...pi-types.py-Fix-enum-struct-sizes-on-i686.patch |   38 +++++
 0003-isapc-disable-kvmvapic.patch                  |   36 +++++
 0004-pci-do-not-export-pci_bus_reset.patch         |   72 ++++++++++
 ...both-pre-and-post-order-vists-in-qdev-wal.patch |  141 +++++++++++++++++++
 0006-qdev-switch-reset-to-post-order.patch         |  143 ++++++++++++++++++++
 qemu.spec                                          |   29 ++++-
 6 files changed, 458 insertions(+), 1 deletions(-)
---
diff --git a/0002-qapi-types.py-Fix-enum-struct-sizes-on-i686.patch b/0002-qapi-types.py-Fix-enum-struct-sizes-on-i686.patch
new file mode 100644
index 0000000..607826c
--- /dev/null
+++ b/0002-qapi-types.py-Fix-enum-struct-sizes-on-i686.patch
@@ -0,0 +1,38 @@
+From f3e59ce7c471d3f0f1f293ecd0ef3e1797ce411f Mon Sep 17 00:00:00 2001
+From: Cole Robinson <crobinso at redhat.com>
+Date: Sat, 31 Aug 2013 18:25:01 -0400
+Subject: [PATCH] qapi-types.py: Fix enum struct sizes on i686
+
+Unlike other list types, enum wasn't adding any padding, which caused
+a mismatch between the generated struct size and GenericList struct
+size. More details in a678e26cbe89f7a27cbce794c2c2784571ee9d21
+
+This crashed qemu if calling qmp query-tpm-types for example, which
+upsets libvirt capabilities probing. Reproducer on i686:
+
+(sleep 5; printf '{"execute":"qmp_capabilities"}\n{"execute":"query-tpm-types"}\n') | ./i386-softmmu/qemu-system-i386 -S -nodefaults -nographic -M none -qmp stdio
+
+https://bugs.launchpad.net/qemu/+bug/1219207
+
+Cc: qemu-stable at nongnu.org
+(cherry picked from commit a9d960fb0b1bc104294ab965116a2d53038b4692)
+---
+ scripts/qapi-types.py | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
+index 5ee46ea..5d31b06 100644
+--- a/scripts/qapi-types.py
++++ b/scripts/qapi-types.py
+@@ -51,7 +51,10 @@ def generate_fwd_enum_struct(name, members):
+     return mcgen('''
+ typedef struct %(name)sList
+ {
+-    %(name)s value;
++    union {
++        %(name)s value;
++        uint64_t padding;
++    };
+     struct %(name)sList *next;
+ } %(name)sList;
+ ''',
diff --git a/0003-isapc-disable-kvmvapic.patch b/0003-isapc-disable-kvmvapic.patch
new file mode 100644
index 0000000..1fd2899
--- /dev/null
+++ b/0003-isapc-disable-kvmvapic.patch
@@ -0,0 +1,36 @@
+From 56cee96f3c71ffee457d8fbdf427c47824a12e05 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Tue, 13 Aug 2013 00:02:18 +0200
+Subject: [PATCH] isapc: disable kvmvapic
+
+vapic requires the VAPIC ROM to be mapped into RAM.  This is not
+possible without PAM hardware.  This fixes a segmentation fault
+running with -M isapc.
+
+Cc: qemu-stable at nongnu.org
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+
+(crobinso: s/kvmvapic/vapic/g)
+
+Signed-off-by: Cole Robinson <crobinso at redhat.com>
+---
+ hw/i386/pc_piix.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
+index 4fd5b6d..462d991 100644
+--- a/hw/i386/pc_piix.c
++++ b/hw/i386/pc_piix.c
+@@ -795,7 +795,11 @@ static QEMUMachine isapc_machine = {
+     .init = pc_init_isa,
+     .max_cpus = 1,
+     .compat_props = (GlobalProperty[]) {
+-        { /* end of list */ }
++        {
++            .driver   = "apic-common",
++            .property = "vapic",
++            .value    = "off",
++        },
+     },
+     DEFAULT_MACHINE_OPTIONS,
+ };
diff --git a/0004-pci-do-not-export-pci_bus_reset.patch b/0004-pci-do-not-export-pci_bus_reset.patch
new file mode 100644
index 0000000..a7fb21d
--- /dev/null
+++ b/0004-pci-do-not-export-pci_bus_reset.patch
@@ -0,0 +1,72 @@
+From b8decc166db51601a6ad6f1df1752e9a9dc4544c Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Thu, 2 May 2013 11:38:37 +0200
+Subject: [PATCH] pci: do not export pci_bus_reset
+
+qbus_reset_all can be used instead.  There is no semantic change
+because pcibus_reset returns 1 and takes care of the device
+tree traversal.
+
+This will be necessary once the traversal is done always in
+qbus_reset_all *before* invoking pcibus_reset itself.
+
+Tested-by: Claudio Bley <cbley at av-test.de>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+---
+ hw/pci/pci.c         | 8 ++------
+ hw/pci/pci_bridge.c  | 2 +-
+ include/hw/pci/pci.h | 1 -
+ 3 files changed, 3 insertions(+), 8 deletions(-)
+
+diff --git a/hw/pci/pci.c b/hw/pci/pci.c
+index 4c004f5..0389375 100644
+--- a/hw/pci/pci.c
++++ b/hw/pci/pci.c
+@@ -210,8 +210,9 @@ void pci_device_reset(PCIDevice *dev)
+  * Trigger pci bus reset under a given bus.
+  * To be called on RST# assert.
+  */
+-void pci_bus_reset(PCIBus *bus)
++static int pcibus_reset(BusState *qbus)
+ {
++    PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus);
+     int i;
+ 
+     for (i = 0; i < bus->nirq; i++) {
+@@ -222,11 +223,6 @@ void pci_bus_reset(PCIBus *bus)
+             pci_device_reset(bus->devices[i]);
+         }
+     }
+-}
+-
+-static int pcibus_reset(BusState *qbus)
+-{
+-    pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus));
+ 
+     /* topology traverse is done by pci_bus_reset().
+        Tell qbus/qdev walker not to traverse the tree */
+diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
+index a90671d..5d0e5ff 100644
+--- a/hw/pci/pci_bridge.c
++++ b/hw/pci/pci_bridge.c
+@@ -268,7 +268,7 @@ void pci_bridge_write_config(PCIDevice *d,
+     newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
+     if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) {
+         /* Trigger hot reset on 0->1 transition. */
+-        pci_bus_reset(&s->sec_bus);
++        qbus_reset_all(&s->sec_bus.qbus);
+     }
+ }
+ 
+diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
+index ccec2ba..32f1419 100644
+--- a/include/hw/pci/pci.h
++++ b/include/hw/pci/pci.h
+@@ -376,7 +376,6 @@ void pci_bus_fire_intx_routing_notifier(PCIBus *bus);
+ void pci_device_set_intx_routing_notifier(PCIDevice *dev,
+                                           PCIINTxRoutingNotifier notifier);
+ void pci_device_reset(PCIDevice *dev);
+-void pci_bus_reset(PCIBus *bus);
+ 
+ PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus,
+                         const char *default_model,
diff --git a/0005-qdev-allow-both-pre-and-post-order-vists-in-qdev-wal.patch b/0005-qdev-allow-both-pre-and-post-order-vists-in-qdev-wal.patch
new file mode 100644
index 0000000..a418e80
--- /dev/null
+++ b/0005-qdev-allow-both-pre-and-post-order-vists-in-qdev-wal.patch
@@ -0,0 +1,141 @@
+From 7dbd6881f10537bf586f1eedf5a3bda2e50174ca Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Thu, 2 May 2013 11:38:38 +0200
+Subject: [PATCH] qdev: allow both pre- and post-order vists in qdev walking
+ functions
+
+Resetting should be done in post-order, not pre-order.  However,
+qdev_walk_children and qbus_walk_children do not allow this.  Fix
+it by adding two extra arguments to the functions.
+
+Tested-by: Claudio Bley <cbley at av-test.de>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+---
+ hw/core/qdev.c         | 45 +++++++++++++++++++++++++++++++++------------
+ include/hw/qdev-core.h | 13 +++++++++----
+ 2 files changed, 42 insertions(+), 16 deletions(-)
+
+diff --git a/hw/core/qdev.c b/hw/core/qdev.c
+index 9190a7e..842804f 100644
+--- a/hw/core/qdev.c
++++ b/hw/core/qdev.c
+@@ -240,12 +240,12 @@ static int qbus_reset_one(BusState *bus, void *opaque)
+ 
+ void qdev_reset_all(DeviceState *dev)
+ {
+-    qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
++    qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL, NULL, NULL);
+ }
+ 
+ void qbus_reset_all(BusState *bus)
+ {
+-    qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
++    qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL, NULL, NULL);
+ }
+ 
+ void qbus_reset_all_fn(void *opaque)
+@@ -343,49 +343,70 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
+     return NULL;
+ }
+ 
+-int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
+-                       qbus_walkerfn *busfn, void *opaque)
++int qbus_walk_children(BusState *bus,
++                       qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
++                       qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
++                       void *opaque)
+ {
+     BusChild *kid;
+     int err;
+ 
+-    if (busfn) {
+-        err = busfn(bus, opaque);
++    if (pre_busfn) {
++        err = pre_busfn(bus, opaque);
+         if (err) {
+             return err;
+         }
+     }
+ 
+     QTAILQ_FOREACH(kid, &bus->children, sibling) {
+-        err = qdev_walk_children(kid->child, devfn, busfn, opaque);
++        err = qdev_walk_children(kid->child,
++                                 pre_devfn, pre_busfn,
++                                 post_devfn, post_busfn, opaque);
+         if (err < 0) {
+             return err;
+         }
+     }
+ 
++    if (post_busfn) {
++        err = post_busfn(bus, opaque);
++        if (err) {
++            return err;
++        }
++    }
++
+     return 0;
+ }
+ 
+-int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
+-                       qbus_walkerfn *busfn, void *opaque)
++int qdev_walk_children(DeviceState *dev,
++                       qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
++                       qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
++                       void *opaque)
+ {
+     BusState *bus;
+     int err;
+ 
+-    if (devfn) {
+-        err = devfn(dev, opaque);
++    if (pre_devfn) {
++        err = pre_devfn(dev, opaque);
+         if (err) {
+             return err;
+         }
+     }
+ 
+     QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+-        err = qbus_walk_children(bus, devfn, busfn, opaque);
++        err = qbus_walk_children(bus, pre_devfn, pre_busfn,
++                                 post_devfn, post_busfn, opaque);
+         if (err < 0) {
+             return err;
+         }
+     }
+ 
++    if (post_devfn) {
++        err = post_devfn(dev, opaque);
++        if (err) {
++            return err;
++        }
++    }
++
+     return 0;
+ }
+ 
+diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
+index 46972f4..c6c9b14 100644
+--- a/include/hw/qdev-core.h
++++ b/include/hw/qdev-core.h
+@@ -270,10 +270,15 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam
+ /* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
+  *         < 0 if either devfn or busfn terminate walk somewhere in cursion,
+  *           0 otherwise. */
+-int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
+-                       qbus_walkerfn *busfn, void *opaque);
+-int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
+-                       qbus_walkerfn *busfn, void *opaque);
++int qbus_walk_children(BusState *bus,
++                       qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
++                       qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
++                       void *opaque);
++int qdev_walk_children(DeviceState *dev,
++                       qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
++                       qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
++                       void *opaque);
++
+ void qdev_reset_all(DeviceState *dev);
+ 
+ /**
diff --git a/0006-qdev-switch-reset-to-post-order.patch b/0006-qdev-switch-reset-to-post-order.patch
new file mode 100644
index 0000000..4679fc5
--- /dev/null
+++ b/0006-qdev-switch-reset-to-post-order.patch
@@ -0,0 +1,143 @@
+From 59164410b2f021d53be2ce45630647e952ccf9c2 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Thu, 2 May 2013 11:38:39 +0200
+Subject: [PATCH] qdev: switch reset to post-order
+
+Post-order is the only sensible direction for the reset signals.
+For example, suppose pre-order is used and the parent has some data
+structures that cache children state (for example a list of active
+requests).  When the reset method is invoked on the parent, these caches
+could be in any state.
+
+If post-order is used, on the other hand, these will be in a known state
+when the reset method is invoked on the parent.
+
+This change means that it is no longer possible to block the visit of
+the devices, so the callback is changed to return void.  This is not
+a problem, because PCI was returning 1 exactly in order to achieve the
+same ordering that this patch implements.
+
+PCI can then rely on the qdev core having sent a "reset signal"
+(whatever that means) to the device, and only do the PCI-specific
+initialization with the new function pci_do_device_reset, extracted
+from pci_device_reset.  There is no change in the operation of FLR,
+which used and still uses pci_device_reset.
+
+Tested-by: Claudio Bley <cbley at av-test.de>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+---
+ hw/core/qdev.c         |  6 +++---
+ hw/pci/pci.c           | 31 ++++++++++++++++---------------
+ include/hw/qdev-core.h |  2 +-
+ 3 files changed, 20 insertions(+), 19 deletions(-)
+
+diff --git a/hw/core/qdev.c b/hw/core/qdev.c
+index 842804f..87d7e1e 100644
+--- a/hw/core/qdev.c
++++ b/hw/core/qdev.c
+@@ -233,19 +233,19 @@ static int qbus_reset_one(BusState *bus, void *opaque)
+ {
+     BusClass *bc = BUS_GET_CLASS(bus);
+     if (bc->reset) {
+-        return bc->reset(bus);
++        bc->reset(bus);
+     }
+     return 0;
+ }
+ 
+ void qdev_reset_all(DeviceState *dev)
+ {
+-    qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL, NULL, NULL);
++    qdev_walk_children(dev, NULL, NULL, qdev_reset_one, qbus_reset_one, NULL);
+ }
+ 
+ void qbus_reset_all(BusState *bus)
+ {
+-    qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL, NULL, NULL);
++    qbus_walk_children(bus, NULL, NULL, qdev_reset_one, qbus_reset_one, NULL);
+ }
+ 
+ void qbus_reset_all_fn(void *opaque)
+diff --git a/hw/pci/pci.c b/hw/pci/pci.c
+index 0389375..bbca696 100644
+--- a/hw/pci/pci.c
++++ b/hw/pci/pci.c
+@@ -46,7 +46,7 @@
+ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+ static char *pcibus_get_dev_path(DeviceState *dev);
+ static char *pcibus_get_fw_dev_path(DeviceState *dev);
+-static int pcibus_reset(BusState *qbus);
++static void pcibus_reset(BusState *qbus);
+ 
+ static Property pci_props[] = {
+     DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
+@@ -165,16 +165,10 @@ void pci_device_deassert_intx(PCIDevice *dev)
+     }
+ }
+ 
+-/*
+- * This function is called on #RST and FLR.
+- * FLR if PCI_EXP_DEVCTL_BCR_FLR is set
+- */
+-void pci_device_reset(PCIDevice *dev)
++static void pci_do_device_reset(PCIDevice *dev)
+ {
+     int r;
+ 
+-    qdev_reset_all(&dev->qdev);
+-
+     dev->irq_state = 0;
+     pci_update_irq_status(dev);
+     pci_device_deassert_intx(dev);
+@@ -207,10 +201,21 @@ void pci_device_reset(PCIDevice *dev)
+ }
+ 
+ /*
++ * This function is called on #RST and FLR.
++ * FLR if PCI_EXP_DEVCTL_BCR_FLR is set
++ */
++void pci_device_reset(PCIDevice *dev)
++{
++    qdev_reset_all(&dev->qdev);
++    pci_do_device_reset(dev);
++}
++
++/*
+  * Trigger pci bus reset under a given bus.
+- * To be called on RST# assert.
++ * Called via qbus_reset_all on RST# assert, after the devices
++ * have been reset qdev_reset_all-ed already.
+  */
+-static int pcibus_reset(BusState *qbus)
++static void pcibus_reset(BusState *qbus)
+ {
+     PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus);
+     int i;
+@@ -220,13 +225,9 @@ static int pcibus_reset(BusState *qbus)
+     }
+     for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
+         if (bus->devices[i]) {
+-            pci_device_reset(bus->devices[i]);
++            pci_do_device_reset(bus->devices[i]);
+         }
+     }
+-
+-    /* topology traverse is done by pci_bus_reset().
+-       Tell qbus/qdev walker not to traverse the tree */
+-    return 1;
+ }
+ 
+ static void pci_host_bus_register(PCIBus *bus, DeviceState *parent)
+diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
+index c6c9b14..89dcbad 100644
+--- a/include/hw/qdev-core.h
++++ b/include/hw/qdev-core.h
+@@ -174,7 +174,7 @@ struct BusClass {
+      * bindings can be found at http://playground.sun.com/1275/bindings/.
+      */
+     char *(*get_fw_dev_path)(DeviceState *dev);
+-    int (*reset)(BusState *bus);
++    void (*reset)(BusState *bus);
+     /* maximum devices allowed on the bus, 0: no limit. */
+     int max_dev;
+ };
diff --git a/qemu.spec b/qemu.spec
index 1f226f1..2b2147c 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -140,7 +140,7 @@
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
 Version: 1.6.0
-Release: 5%{?dist}
+Release: 6%{?dist}
 Epoch: 2
 License: GPLv2+ and LGPLv2+ and BSD
 Group: Development/Tools
@@ -183,6 +183,16 @@ Source13: qemu-kvm.sh
 
 # qemu-kvm migration compat (not for upstream, drop by Fedora 21?)
 Patch0001: 0001-Fix-migration-from-qemu-kvm.patch
+# Fix qmp capabilities calls on i686 (bz #1003162)
+# Patch posted upstream
+Patch0002: 0002-qapi-types.py-Fix-enum-struct-sizes-on-i686.patch
+# Fix crash with -M isapc -cpu Haswell (bz #986790)
+Patch0003: 0003-isapc-disable-kvmvapic.patch
+# Fix crash in lsi_soft_reset (bz #1000947)
+# Patches posted upstream
+Patch0004: 0004-pci-do-not-export-pci_bus_reset.patch
+Patch0005: 0005-qdev-allow-both-pre-and-post-order-vists-in-qdev-wal.patch
+Patch0006: 0006-qdev-switch-reset-to-post-order.patch
 
 BuildRequires: SDL-devel
 BuildRequires: zlib-devel
@@ -695,6 +705,16 @@ CAC emulation development files.
 
 # qemu-kvm migration compat (not for upstream, drop by Fedora 21?)
 %patch0001 -p1
+# Fix qmp capabilities calls on i686 (bz #1003162)
+# Patch posted upstream
+%patch0002 -p1
+# Fix crash with -M isapc -cpu Haswell (bz #986790)
+%patch0003 -p1
+# Fix crash in lsi_soft_reset (bz #1000947)
+# Patches posted upstream
+%patch0004 -p1
+%patch0005 -p1
+%patch0006 -p1
 
 
 %build
@@ -1003,6 +1023,7 @@ qemu-sanity-check --qemu=x86_64-softmmu/qemu-system-x86_64 || :
 # load kvm modules now, so we can make sure no reboot is needed.
 # If there's already a kvm module installed, we don't mess with it
 sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || :
+setfacl --remove-all /dev/kvm &> /dev/null || :
 udevadm trigger --subsystem-match=misc --sysname-match=kvm --action=add || :
 %endif
 
@@ -1399,6 +1420,12 @@ getent passwd qemu >/dev/null || \
 %endif
 
 %changelog
+* Tue Sep 03 2013 Cole Robinson <crobinso at redhat.com> - 2:1.6.0-6
+- Fix qmp capabilities calls on i686 (bz #1003162)
+- Fix crash with -M isapc -cpu Haswell (bz #986790)
+- Fix crash in lsi_soft_reset (bz #1000947)
+- Fix initial /dev/kvm permissions (bz #993491)
+
 * Wed Aug 28 2013 Richard W.M. Jones <rjones at redhat.com> - 2:1.6.0-5
 - Enable qemu-sanity-check, however do not fail the build if it fails.
 


More information about the scm-commits mailing list