aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpus.c18
-rw-r--r--docs/qapi-code-gen.txt15
-rw-r--r--hmp.c12
-rw-r--r--hw/net/vhost_net.c52
-rw-r--r--hw/net/virtio-net.c68
-rw-r--r--hw/pci-bridge/dec.c6
-rw-r--r--hw/pci-bridge/i82801b11.c5
-rw-r--r--hw/pci-bridge/ioh3420.c6
-rw-r--r--hw/pci-bridge/pci_bridge_dev.c8
-rw-r--r--hw/pci-bridge/xio3130_downstream.c6
-rw-r--r--hw/pci-bridge/xio3130_upstream.c6
-rw-r--r--hw/pci-host/apb.c7
-rw-r--r--hw/pci/msix.c4
-rw-r--r--hw/pci/pci_bridge.c3
-rw-r--r--hw/virtio/vhost.c36
-rw-r--r--hw/virtio/virtio-pci.c14
-rw-r--r--hw/virtio/virtio.c1
-rw-r--r--include/hw/pci/pci_bridge.h2
-rw-r--r--include/hw/virtio/virtio-access.h28
-rw-r--r--include/hw/virtio/virtio-net.h1
-rw-r--r--include/hw/virtio/virtio.h1
-rw-r--r--include/qapi/visitor-impl.h21
-rw-r--r--include/qapi/visitor.h63
-rw-r--r--qapi/opts-visitor.c16
-rw-r--r--qapi/qapi-dealloc-visitor.c42
-rw-r--r--qapi/qapi-visit-core.c45
-rw-r--r--qapi/qmp-input-visitor.c43
-rw-r--r--qapi/qmp-output-visitor.c3
-rw-r--r--qapi/string-input-visitor.c4
-rw-r--r--qapi/string-output-visitor.c2
-rw-r--r--rules.mak2
-rw-r--r--scripts/qapi-types.py33
-rw-r--r--scripts/qapi-visit.py253
-rw-r--r--scripts/qapi.py29
-rw-r--r--tests/Makefile6
-rw-r--r--tests/bios-tables-test.c72
-rw-r--r--tests/boot-sector.c119
-rw-r--r--tests/boot-sector.h26
-rw-r--r--tests/pxe-test.c69
-rw-r--r--tests/qapi-schema/alternate-any.err1
-rw-r--r--tests/qapi-schema/alternate-any.exit1
-rw-r--r--tests/qapi-schema/alternate-any.json4
-rw-r--r--tests/qapi-schema/alternate-any.out0
-rw-r--r--tests/qapi-schema/alternate-empty.err1
-rw-r--r--tests/qapi-schema/alternate-empty.exit2
-rw-r--r--tests/qapi-schema/alternate-empty.json2
-rw-r--r--tests/qapi-schema/alternate-empty.out5
-rw-r--r--tests/qapi-schema/flat-union-empty.err1
-rw-r--r--tests/qapi-schema/flat-union-empty.exit2
-rw-r--r--tests/qapi-schema/flat-union-empty.json2
-rw-r--r--tests/qapi-schema/flat-union-empty.out9
-rw-r--r--tests/qapi-schema/qapi-schema-test.json13
-rw-r--r--tests/qapi-schema/qapi-schema-test.out11
-rw-r--r--tests/qapi-schema/union-empty.err1
-rw-r--r--tests/qapi-schema/union-empty.exit2
-rw-r--r--tests/qapi-schema/union-empty.json2
-rw-r--r--tests/qapi-schema/union-empty.out6
-rw-r--r--tests/test-qmp-input-visitor.c39
-rw-r--r--tests/test-qmp-output-visitor.c27
-rw-r--r--tests/vhost-user-bridge.c92
60 files changed, 787 insertions, 583 deletions
diff --git a/cpus.c b/cpus.c
index 898426ca56..9592163ff4 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1568,28 +1568,22 @@ CpuInfoList *qmp_query_cpus(Error **errp)
info->value->thread_id = cpu->thread_id;
#if defined(TARGET_I386)
info->value->arch = CPU_INFO_ARCH_X86;
- info->value->u.x86 = g_new0(CpuInfoX86, 1);
- info->value->u.x86->pc = env->eip + env->segs[R_CS].base;
+ info->value->u.x86.pc = env->eip + env->segs[R_CS].base;
#elif defined(TARGET_PPC)
info->value->arch = CPU_INFO_ARCH_PPC;
- info->value->u.ppc = g_new0(CpuInfoPPC, 1);
- info->value->u.ppc->nip = env->nip;
+ info->value->u.ppc.nip = env->nip;
#elif defined(TARGET_SPARC)
info->value->arch = CPU_INFO_ARCH_SPARC;
- info->value->u.q_sparc = g_new0(CpuInfoSPARC, 1);
- info->value->u.q_sparc->pc = env->pc;
- info->value->u.q_sparc->npc = env->npc;
+ info->value->u.q_sparc.pc = env->pc;
+ info->value->u.q_sparc.npc = env->npc;
#elif defined(TARGET_MIPS)
info->value->arch = CPU_INFO_ARCH_MIPS;
- info->value->u.q_mips = g_new0(CpuInfoMIPS, 1);
- info->value->u.q_mips->PC = env->active_tc.PC;
+ info->value->u.q_mips.PC = env->active_tc.PC;
#elif defined(TARGET_TRICORE)
info->value->arch = CPU_INFO_ARCH_TRICORE;
- info->value->u.tricore = g_new0(CpuInfoTricore, 1);
- info->value->u.tricore->PC = env->PC;
+ info->value->u.tricore.PC = env->PC;
#else
info->value->arch = CPU_INFO_ARCH_OTHER;
- info->value->u.other = g_new0(CpuInfoOther, 1);
#endif
/* XXX: waiting for the qapi to support GSList */
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 128f074a2d..999f3b98f0 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -187,11 +187,11 @@ prevent incomplete include files.
Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME }
-A struct is a dictionary containing a single 'data' key whose
-value is a dictionary. This corresponds to a struct in C or an Object
-in JSON. Each value of the 'data' dictionary must be the name of a
-type, or a one-element array containing a type name. An example of a
-struct is:
+A struct is a dictionary containing a single 'data' key whose value is
+a dictionary; the dictionary may be empty. This corresponds to a
+struct in C or an Object in JSON. Each value of the 'data' dictionary
+must be the name of a type, or a one-element array containing a type
+name. An example of a struct is:
{ 'struct': 'MyType',
'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
@@ -288,9 +288,10 @@ or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME,
Union types are used to let the user choose between several different
variants for an object. There are two flavors: simple (no
-discriminator or base), flat (both discriminator and base). A union
+discriminator or base), and flat (both discriminator and base). A union
type is defined using a data dictionary as explained in the following
-paragraphs.
+paragraphs. The data dictionary for either type of union must not
+be empty.
A simple union type defines a mapping from automatic discriminator
values to data types like in this example:
diff --git a/hmp.c b/hmp.c
index 996cb91027..bfbd667033 100644
--- a/hmp.c
+++ b/hmp.c
@@ -314,22 +314,22 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict)
switch (cpu->value->arch) {
case CPU_INFO_ARCH_X86:
- monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.x86->pc);
+ monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.x86.pc);
break;
case CPU_INFO_ARCH_PPC:
- monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->u.ppc->nip);
+ monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->u.ppc.nip);
break;
case CPU_INFO_ARCH_SPARC:
monitor_printf(mon, " pc=0x%016" PRIx64,
- cpu->value->u.q_sparc->pc);
+ cpu->value->u.q_sparc.pc);
monitor_printf(mon, " npc=0x%016" PRIx64,
- cpu->value->u.q_sparc->npc);
+ cpu->value->u.q_sparc.npc);
break;
case CPU_INFO_ARCH_MIPS:
- monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.q_mips->PC);
+ monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.q_mips.PC);
break;
case CPU_INFO_ARCH_TRICORE:
- monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.tricore->PC);
+ monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.tricore.PC);
break;
default:
break;
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 3940a04b65..6e1032fc18 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -36,7 +36,6 @@
#include "standard-headers/linux/virtio_ring.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-access.h"
struct vhost_net {
struct vhost_dev dev;
@@ -197,27 +196,6 @@ static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
net->dev.vq_index = vq_index;
}
-static int vhost_net_set_vnet_endian(VirtIODevice *dev, NetClientState *peer,
- bool set)
-{
- int r = 0;
-
- if (virtio_vdev_has_feature(dev, VIRTIO_F_VERSION_1) ||
- (virtio_legacy_is_cross_endian(dev) && !virtio_is_big_endian(dev))) {
- r = qemu_set_vnet_le(peer, set);
- if (r) {
- error_report("backend does not support LE vnet headers");
- }
- } else if (virtio_legacy_is_cross_endian(dev)) {
- r = qemu_set_vnet_be(peer, set);
- if (r) {
- error_report("backend does not support BE vnet headers");
- }
- }
-
- return r;
-}
-
static int vhost_net_start_one(struct vhost_net *net,
VirtIODevice *dev)
{
@@ -298,25 +276,32 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
VirtioBusState *vbus = VIRTIO_BUS(qbus);
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
- int r, e, i, j;
+ int r, e, i;
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
return -ENOSYS;
}
- for (j = 0; j < total_queues; j++) {
- r = vhost_net_set_vnet_endian(dev, ncs[j].peer, true);
- if (r < 0) {
- goto err_endian;
+ for (i = 0; i < total_queues; i++) {
+ struct vhost_net *net;
+
+ net = get_vhost_net(ncs[i].peer);
+ vhost_net_set_vq_index(net, i * 2);
+
+ /* Suppress the masking guest notifiers on vhost user
+ * because vhost user doesn't interrupt masking/unmasking
+ * properly.
+ */
+ if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
+ dev->use_guest_notifier_mask = false;
}
- vhost_net_set_vq_index(get_vhost_net(ncs[j].peer), j * 2);
- }
+ }
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
if (r < 0) {
error_report("Error binding guest notifier: %d", -r);
- goto err_endian;
+ goto err;
}
for (i = 0; i < total_queues; i++) {
@@ -338,10 +323,7 @@ err_start:
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
fflush(stderr);
}
-err_endian:
- while (--j >= 0) {
- vhost_net_set_vnet_endian(dev, ncs[j].peer, false);
- }
+err:
return r;
}
@@ -363,8 +345,6 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
fflush(stderr);
}
assert(r >= 0);
-
- assert(vhost_net_set_vnet_endian(dev, ncs[0].peer, false) >= 0);
}
void vhost_net_cleanup(struct vhost_net *net)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index de696e8dd0..5798f87d8e 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -129,6 +129,13 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
if (!n->vhost_started) {
int r, i;
+ if (n->needs_vnet_hdr_swap) {
+ error_report("backend does not support %s vnet headers; "
+ "falling back on userspace virtio",
+ virtio_is_big_endian(vdev) ? "BE" : "LE");
+ return;
+ }
+
/* Any packets outstanding? Purge them to avoid touching rings
* when vhost is running.
*/
@@ -153,6 +160,59 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
}
}
+static int virtio_net_set_vnet_endian_one(VirtIODevice *vdev,
+ NetClientState *peer,
+ bool enable)
+{
+ if (virtio_is_big_endian(vdev)) {
+ return qemu_set_vnet_be(peer, enable);
+ } else {
+ return qemu_set_vnet_le(peer, enable);
+ }
+}
+
+static bool virtio_net_set_vnet_endian(VirtIODevice *vdev, NetClientState *ncs,
+ int queues, bool enable)
+{
+ int i;
+
+ for (i = 0; i < queues; i++) {
+ if (virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, enable) < 0 &&
+ enable) {
+ while (--i >= 0) {
+ virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, false);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
+ int queues = n->multiqueue ? n->max_queues : 1;
+
+ if (virtio_net_started(n, status)) {
+ /* Before using the device, we tell the network backend about the
+ * endianness to use when parsing vnet headers. If the backend
+ * can't do it, we fallback onto fixing the headers in the core
+ * virtio-net code.
+ */
+ n->needs_vnet_hdr_swap = virtio_net_set_vnet_endian(vdev, n->nic->ncs,
+ queues, true);
+ } else if (virtio_net_started(n, vdev->status)) {
+ /* After using the device, we need to reset the network backend to
+ * the default (guest native endianness), otherwise the guest may
+ * lose network connectivity if it is rebooted into a different
+ * endianness.
+ */
+ virtio_net_set_vnet_endian(vdev, n->nic->ncs, queues, false);
+ }
+}
+
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
{
VirtIONet *n = VIRTIO_NET(vdev);
@@ -160,6 +220,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
int i;
uint8_t queue_status;
+ virtio_net_vnet_endian_status(n, status);
virtio_net_vhost_status(n, status);
for (i = 0; i < n->max_queues; i++) {
@@ -963,7 +1024,10 @@ static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
void *wbuf = (void *)buf;
work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
size - n->host_hdr_len);
- virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf);
+
+ if (n->needs_vnet_hdr_swap) {
+ virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf);
+ }
iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
} else {
struct virtio_net_hdr hdr = {
@@ -1184,7 +1248,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
error_report("virtio-net header incorrect");
exit(1);
}
- if (virtio_needs_swap(vdev)) {
+ if (n->needs_vnet_hdr_swap) {
virtio_net_hdr_swap(vdev, (void *) &mhdr);
sg2[0].iov_base = &mhdr;
sg2[0].iov_len = n->guest_hdr_len;
diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c
index 40ff0d0632..840c96198a 100644
--- a/hw/pci-bridge/dec.c
+++ b/hw/pci-bridge/dec.c
@@ -52,9 +52,9 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
return irq_num;
}
-static int dec_pci_bridge_initfn(PCIDevice *pci_dev)
+static void dec_pci_bridge_realize(PCIDevice *pci_dev, Error **errp)
{
- return pci_bridge_initfn(pci_dev, TYPE_PCI_BUS);
+ pci_bridge_initfn(pci_dev, TYPE_PCI_BUS);
}
static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
@@ -62,7 +62,7 @@ static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->init = dec_pci_bridge_initfn;
+ k->realize = dec_pci_bridge_realize;
k->exit = pci_bridge_exitfn;
k->vendor_id = PCI_VENDOR_ID_DEC;
k->device_id = PCI_DEVICE_ID_DEC_21154;
diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c
index b143f8cb79..5c40708ba8 100644
--- a/hw/pci-bridge/i82801b11.c
+++ b/hw/pci-bridge/i82801b11.c
@@ -62,10 +62,7 @@ static int i82801b11_bridge_initfn(PCIDevice *d)
{
int rc;
- rc = pci_bridge_initfn(d, TYPE_PCI_BUS);
- if (rc < 0) {
- return rc;
- }
+ pci_bridge_initfn(d, TYPE_PCI_BUS);
rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET,
I82801ba_SSVID_SVID, I82801ba_SSVID_SSID);
diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c
index 8ac4240bb1..9e048ebe35 100644
--- a/hw/pci-bridge/ioh3420.c
+++ b/hw/pci-bridge/ioh3420.c
@@ -98,11 +98,7 @@ static int ioh3420_initfn(PCIDevice *d)
PCIESlot *s = PCIE_SLOT(d);
int rc;
- rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
- if (rc < 0) {
- return rc;
- }
-
+ pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);
rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index c9a7e2b2a3..100bb5ebf6 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -53,10 +53,8 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);
int err;
- err = pci_bridge_initfn(dev, TYPE_PCI_BUS);
- if (err) {
- goto bridge_error;
- }
+ pci_bridge_initfn(dev, TYPE_PCI_BUS);
+
if (bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_SHPC_REQ)) {
dev->config[PCI_INTERRUPT_PIN] = 0x1;
memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar",
@@ -95,7 +93,7 @@ slotid_error:
}
shpc_error:
pci_bridge_exitfn(dev);
-bridge_error:
+
return err;
}
diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c
index 9eb3d8895f..c32f2712c8 100644
--- a/hw/pci-bridge/xio3130_downstream.c
+++ b/hw/pci-bridge/xio3130_downstream.c
@@ -61,11 +61,7 @@ static int xio3130_downstream_initfn(PCIDevice *d)
PCIESlot *s = PCIE_SLOT(d);
int rc;
- rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
- if (rc < 0) {
- return rc;
- }
-
+ pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);
rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c
index 7d255a6d52..19798c09a8 100644
--- a/hw/pci-bridge/xio3130_upstream.c
+++ b/hw/pci-bridge/xio3130_upstream.c
@@ -57,11 +57,7 @@ static int xio3130_upstream_initfn(PCIDevice *d)
PCIEPort *p = PCIE_PORT(d);
int rc;
- rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
- if (rc < 0) {
- return rc;
- }
-
+ pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);
rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
index 75dee50bc3..aaef7bb3a1 100644
--- a/hw/pci-host/apb.c
+++ b/hw/pci-host/apb.c
@@ -635,12 +635,7 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
static int apb_pci_bridge_initfn(PCIDevice *dev)
{
- int rc;
-
- rc = pci_bridge_initfn(dev, TYPE_PCI_BUS);
- if (rc < 0) {
- return rc;
- }
+ pci_bridge_initfn(dev, TYPE_PCI_BUS);
/*
* command register:
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index eb4ef113d1..537fdba747 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -80,10 +80,10 @@ static void msix_clr_pending(PCIDevice *dev, int vector)
static bool msix_vector_masked(PCIDevice *dev, unsigned int vector, bool fmask)
{
unsigned offset = vector * PCI_MSIX_ENTRY_SIZE;
- uint32_t *data = (uint32_t *)&dev->msix_table[offset + PCI_MSIX_ENTRY_DATA];
+ uint8_t *data = &dev->msix_table[offset + PCI_MSIX_ENTRY_DATA];
/* MSIs on Xen can be remapped into pirqs. In those cases, masking
* and unmasking go through the PV evtchn path. */
- if (xen_is_pirq_msi(*data)) {
+ if (xen_enabled() && xen_is_pirq_msi(pci_get_long(data))) {
return false;
}
return fmask || dev->msix_table[offset + PCI_MSIX_ENTRY_VECTOR_CTRL] &
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
index 7eab9d57c5..3cf30bd334 100644
--- a/hw/pci/pci_bridge.c
+++ b/hw/pci/pci_bridge.c
@@ -333,7 +333,7 @@ void pci_bridge_reset(DeviceState *qdev)
}
/* default qdev initialization function for PCI-to-PCI bridge */
-int pci_bridge_initfn(PCIDevice *dev, const char *typename)
+void pci_bridge_initfn(PCIDevice *dev, const char *typename)
{
PCIBus *parent = dev->bus;
PCIBridge *br = PCI_BRIDGE(dev);
@@ -379,7 +379,6 @@ int pci_bridge_initfn(PCIDevice *dev, const char *typename)
br->windows = pci_bridge_region_init(br);
QLIST_INIT(&sec_bus->child);
QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
- return 0;
}
/* default qdev clean up function for PCI-to-PCI bridge */
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 7dff75547d..72d0c9e9ae 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -749,6 +749,27 @@ static void vhost_log_stop(MemoryListener *listener,
/* FIXME: implement */
}
+/* The vhost driver natively knows how to handle the vrings of non
+ * cross-endian legacy devices and modern devices. Only legacy devices
+ * exposed to a bi-endian guest may require the vhost driver to use a
+ * specific endianness.
+ */
+static inline bool vhost_needs_vring_endian(VirtIODevice *vdev)
+{
+ if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+ return false;
+ }
+#ifdef TARGET_IS_BIENDIAN
+#ifdef HOST_WORDS_BIGENDIAN
+ return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_LITTLE;
+#else
+ return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG;
+#endif
+#else
+ return false;
+#endif
+}
+
static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev,
bool is_big_endian,
int vhost_vq_index)
@@ -799,8 +820,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
return -errno;
}
- if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
- virtio_legacy_is_cross_endian(vdev)) {
+ if (vhost_needs_vring_endian(vdev)) {
r = vhost_virtqueue_set_vring_endian_legacy(dev,
virtio_is_big_endian(vdev),
vhost_vq_index);
@@ -855,6 +875,14 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
/* Clear and discard previous events if any. */
event_notifier_test_and_clear(&vq->masked_notifier);
+ /* Init vring in unmasked state, unless guest_notifier_mask
+ * will do it later.
+ */
+ if (!vdev->use_guest_notifier_mask) {
+ /* TODO: check and handle errors. */
+ vhost_virtqueue_mask(dev, vdev, idx, false);
+ }
+
return 0;
fail_kick:
@@ -896,8 +924,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
/* In the cross-endian case, we need to reset the vring endianness to
* native as legacy devices expect so by default.
*/
- if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
- virtio_legacy_is_cross_endian(vdev)) {
+ if (vhost_needs_vring_endian(vdev)) {
r = vhost_virtqueue_set_vring_endian_legacy(dev,
!virtio_is_big_endian(vdev),
vhost_vq_index);
@@ -1148,6 +1175,7 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
struct vhost_vring_file file;
if (mask) {
+ assert(vdev->use_guest_notifier_mask);
file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier);
} else {
file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 5494ff4a49..440776c06c 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -806,7 +806,7 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
/* If guest supports masking, set up irqfd now.
* Otherwise, delay until unmasked in the frontend.
*/
- if (k->guest_notifier_mask) {
+ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
if (ret < 0) {
kvm_virtio_pci_vq_vector_release(proxy, vector);
@@ -822,7 +822,7 @@ undo:
if (vector >= msix_nr_vectors_allocated(dev)) {
continue;
}
- if (k->guest_notifier_mask) {
+ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
}
kvm_virtio_pci_vq_vector_release(proxy, vector);
@@ -849,7 +849,7 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
/* If guest supports masking, clean up irqfd now.
* Otherwise, it was cleaned when masked in the frontend.
*/
- if (k->guest_notifier_mask) {
+ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
}
kvm_virtio_pci_vq_vector_release(proxy, vector);
@@ -882,7 +882,7 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
/* If guest supports masking, irqfd is already setup, unmask it.
* Otherwise, set it up now.
*/
- if (k->guest_notifier_mask) {
+ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
k->guest_notifier_mask(vdev, queue_no, false);
/* Test after unmasking to avoid losing events. */
if (k->guest_notifier_pending &&
@@ -905,7 +905,7 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
/* If guest supports masking, keep irqfd but mask it.
* Otherwise, clean it up now.
*/
- if (k->guest_notifier_mask) {
+ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
k->guest_notifier_mask(vdev, queue_no, true);
} else {
kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
@@ -1022,7 +1022,9 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
event_notifier_cleanup(notifier);
}
- if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
+ if (!msix_enabled(&proxy->pci_dev) &&
+ vdev->use_guest_notifier_mask &&
+ vdc->guest_notifier_mask) {
vdc->guest_notifier_mask(vdev, n, !assign);
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 90f25451d0..e365960bd7 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1677,6 +1677,7 @@ void virtio_init(VirtIODevice *vdev, const char *name,
vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
vdev);
vdev->device_endian = virtio_default_endian();
+ vdev->use_guest_notifier_mask = true;
}
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
index 93b621cef3..ed4aff6cd2 100644
--- a/include/hw/pci/pci_bridge.h
+++ b/include/hw/pci/pci_bridge.h
@@ -48,7 +48,7 @@ void pci_bridge_disable_base_limit(PCIDevice *dev);
void pci_bridge_reset_reg(PCIDevice *dev);
void pci_bridge_reset(DeviceState *qdev);
-int pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
+void pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
void pci_bridge_exitfn(PCIDevice *pci_dev);
diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
index 8aec843c8f..8dc84f5203 100644
--- a/include/hw/virtio/virtio-access.h
+++ b/include/hw/virtio/virtio-access.h
@@ -19,32 +19,19 @@
static inline bool virtio_access_is_big_endian(VirtIODevice *vdev)
{
+#if defined(TARGET_IS_BIENDIAN)
+ return virtio_is_big_endian(vdev);
+#elif defined(TARGET_WORDS_BIGENDIAN)
if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
/* Devices conforming to VIRTIO 1.0 or later are always LE. */
return false;
}
-#if defined(TARGET_IS_BIENDIAN)
- return virtio_is_big_endian(vdev);
-#elif defined(TARGET_WORDS_BIGENDIAN)
return true;
#else
return false;
#endif
}
-static inline bool virtio_legacy_is_cross_endian(VirtIODevice *vdev)
-{
-#ifdef TARGET_IS_BIENDIAN
-#ifdef HOST_WORDS_BIGENDIAN
- return !virtio_is_big_endian(vdev);
-#else
- return virtio_is_big_endian(vdev);
-#endif
-#else
- return false;
-#endif
-}
-
static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa)
{
if (virtio_access_is_big_endian(vdev)) {
@@ -143,15 +130,6 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
}
}
-static inline bool virtio_needs_swap(VirtIODevice *vdev)
-{
-#ifdef HOST_WORDS_BIGENDIAN
- return virtio_access_is_big_endian(vdev) ? false : true;
-#else
- return virtio_access_is_big_endian(vdev) ? true : false;
-#endif
-}
-
static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
{
#ifdef HOST_WORDS_BIGENDIAN
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 2ce3b03bd4..0cabdb6822 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -94,6 +94,7 @@ typedef struct VirtIONet {
uint64_t curr_guest_offloads;
QEMUTimer *announce_timer;
int announce_counter;
+ bool needs_vnet_hdr_swap;
} VirtIONet;
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 108cdb0f48..c38a2fef04 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -90,6 +90,7 @@ struct VirtIODevice
VMChangeStateEntry *vmstate;
char *bus_name;
uint8_t device_endian;
+ bool use_guest_notifier_mask;
QLIST_HEAD(, VirtQueue) *vector_queues;
};
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index ea252f8e3a..6a1ddfbd9a 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -22,22 +22,23 @@ struct Visitor
size_t size, Error **errp);
void (*end_struct)(Visitor *v, Error **errp);
- void (*start_implicit_struct)(Visitor *v, void **obj, size_t size,
- Error **errp);
- /* May be NULL */
- void (*end_implicit_struct)(Visitor *v);
-
void (*start_list)(Visitor *v, const char *name, Error **errp);
/* Must be set */
- GenericList *(*next_list)(Visitor *v, GenericList **list);
+ GenericList *(*next_list)(Visitor *v, GenericList **list, size_t size);
/* Must be set */
void (*end_list)(Visitor *v);
+ /* Optional, needed for input and dealloc visitors. */
+ void (*start_alternate)(Visitor *v, const char *name,
+ GenericAlternate **obj, size_t size,
+ bool promote_int, Error **errp);
+
+ /* Optional, needed for dealloc visitor. */
+ void (*end_alternate)(Visitor *v);
+
+ /* Must be set. */
void (*type_enum)(Visitor *v, const char *name, int *obj,
const char *const strings[], Error **errp);
- /* May be NULL; only needed for input visitors. */
- void (*get_next_type)(Visitor *v, const char *name, QType *type,
- bool promote_int, Error **errp);
/* Must be set. */
void (*type_int64)(Visitor *v, const char *name, int64_t *obj,
@@ -58,8 +59,6 @@ struct Visitor
/* May be NULL; most useful for input visitors. */
void (*optional)(Visitor *v, const char *name, bool *present);
-
- bool (*start_union)(Visitor *v, bool data_present, Error **errp);
};
void input_type_enum(Visitor *v, const char *name, int *obj,
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 5e581dcf7e..83cad74c88 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -19,26 +19,60 @@
#include "qapi/error.h"
#include <stdlib.h>
-typedef struct GenericList
-{
- union {
- void *value;
- uint64_t padding;
- };
+/* This struct is layout-compatible with all other *List structs
+ * created by the qapi generator. It is used as a typical
+ * singly-linked list. */
+typedef struct GenericList {
struct GenericList *next;
+ char padding[];
} GenericList;
+/* This struct is layout-compatible with all Alternate types
+ * created by the qapi generator. */
+typedef struct GenericAlternate {
+ QType type;
+ char padding[];
+} GenericAlternate;
+
void visit_start_struct(Visitor *v, const char *name, void **obj,
size_t size, Error **errp);
void visit_end_struct(Visitor *v, Error **errp);
-void visit_start_implicit_struct(Visitor *v, void **obj, size_t size,
- Error **errp);
-void visit_end_implicit_struct(Visitor *v);
void visit_start_list(Visitor *v, const char *name, Error **errp);
-GenericList *visit_next_list(Visitor *v, GenericList **list);
+GenericList *visit_next_list(Visitor *v, GenericList **list, size_t size);
void visit_end_list(Visitor *v);
+/*
+ * Start the visit of an alternate @obj with the given @size.
+ *
+ * @name specifies the relationship to the containing struct (ignored
+ * for a top level visit, the name of the key if this alternate is
+ * part of an object, or NULL if this alternate is part of a list).
+ *
+ * @obj must not be NULL. Input visitors will allocate @obj and
+ * determine the qtype of the next thing to be visited, stored in
+ * (*@obj)->type. Other visitors will leave @obj unchanged.
+ *
+ * If @promote_int, treat integers as QTYPE_FLOAT.
+ *
+ * If successful, this must be paired with visit_end_alternate(), even
+ * if visiting the contents of the alternate fails.
+ */
+void visit_start_alternate(Visitor *v, const char *name,
+ GenericAlternate **obj, size_t size,
+ bool promote_int, Error **errp);
+
+/*
+ * Finish visiting an alternate type.
+ *
+ * Must be called after a successful visit_start_alternate(), even if
+ * an error occurred in the meantime.
+ *
+ * TODO: Should all the visit_end_* interfaces take obj parameter, so
+ * that dealloc visitor need not track what was passed in visit_start?
+ */
+void visit_end_alternate(Visitor *v);
+
/**
* Check if an optional member @name of an object needs visiting.
* For input visitors, set *@present according to whether the
@@ -47,14 +81,6 @@ void visit_end_list(Visitor *v);
*/
bool visit_optional(Visitor *v, const char *name, bool *present);
-/**
- * Determine the qtype of the item @name in the current object visit.
- * For input visitors, set *@type to the correct qtype of a qapi
- * alternate type; for other visitors, leave *@type unchanged.
- * If @promote_int, treat integers as QTYPE_FLOAT.
- */
-void visit_get_next_type(Visitor *v, const char *name, QType *type,
- bool promote_int, Error **errp);
void visit_type_enum(Visitor *v, const char *name, int *obj,
const char *const strings[], Error **errp);
void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp);
@@ -80,6 +106,5 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp);
void visit_type_number(Visitor *v, const char *name, double *obj,
Error **errp);
void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp);
-bool visit_start_union(Visitor *v, bool data_present, Error **errp);
#endif
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index d54f75b5e7..73e4acea7b 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -157,17 +157,11 @@ opts_start_struct(Visitor *v, const char *name, void **obj,
}
-static gboolean
-ghr_true(gpointer ign_key, gpointer ign_value, gpointer ign_user_data)
-{
- return TRUE;
-}
-
-
static void
opts_end_struct(Visitor *v, Error **errp)
{
OptsVisitor *ov = to_ov(v);
+ GHashTableIter iter;
GQueue *any;
if (--ov->depth > 0) {
@@ -175,8 +169,8 @@ opts_end_struct(Visitor *v, Error **errp)
}
/* we should have processed all (distinct) QemuOpt instances */
- any = g_hash_table_find(ov->unprocessed_opts, &ghr_true, NULL);
- if (any) {
+ g_hash_table_iter_init(&iter, ov->unprocessed_opts);
+ if (g_hash_table_iter_next(&iter, NULL, (void **)&any)) {
const QemuOpt *first;
first = g_queue_peek_head(any);
@@ -221,7 +215,7 @@ opts_start_list(Visitor *v, const char *name, Error **errp)
static GenericList *
-opts_next_list(Visitor *v, GenericList **list)
+opts_next_list(Visitor *v, GenericList **list, size_t size)
{
OptsVisitor *ov = to_ov(v);
GenericList **link;
@@ -264,7 +258,7 @@ opts_next_list(Visitor *v, GenericList **list)
abort();
}
- *link = g_malloc0(sizeof **link);
+ *link = g_malloc0(size);
return *link;
}
diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
index 2659d3fcca..69221794ec 100644
--- a/qapi/qapi-dealloc-visitor.c
+++ b/qapi/qapi-dealloc-visitor.c
@@ -76,16 +76,15 @@ static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
}
}
-static void qapi_dealloc_start_implicit_struct(Visitor *v,
- void **obj,
- size_t size,
- Error **errp)
+static void qapi_dealloc_start_alternate(Visitor *v, const char *name,
+ GenericAlternate **obj, size_t size,
+ bool promote_int, Error **errp)
{
QapiDeallocVisitor *qov = to_qov(v);
qapi_dealloc_push(qov, obj);
}
-static void qapi_dealloc_end_implicit_struct(Visitor *v)
+static void qapi_dealloc_end_alternate(Visitor *v)
{
QapiDeallocVisitor *qov = to_qov(v);
void **obj = qapi_dealloc_pop(qov);
@@ -100,7 +99,8 @@ static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
qapi_dealloc_push(qov, NULL);
}
-static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp)
+static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp,
+ size_t size)
{
GenericList *list = *listp;
QapiDeallocVisitor *qov = to_qov(v);
@@ -168,31 +168,6 @@ static void qapi_dealloc_type_enum(Visitor *v, const char *name, int *obj,
{
}
-/* If there's no data present, the dealloc visitor has nothing to free.
- * Thus, indicate to visitor code that the subsequent union fields can
- * be skipped. This is not an error condition, since the cleanup of the
- * rest of an object can continue unhindered, so leave errp unset in
- * these cases.
- *
- * NOTE: In cases where we're attempting to deallocate an object that
- * may have missing fields, the field indicating the union type may
- * be missing. In such a case, it's possible we don't have enough
- * information to differentiate data_present == false from a case where
- * data *is* present but happens to be a scalar with a value of 0.
- * This is okay, since in the case of the dealloc visitor there's no
- * work that needs to done in either situation.
- *
- * The current inability in QAPI code to more thoroughly verify a union
- * type in such cases will likely need to be addressed if we wish to
- * implement this interface for other types of visitors in the future,
- * however.
- */
-static bool qapi_dealloc_start_union(Visitor *v, bool data_present,
- Error **errp)
-{
- return data_present;
-}
-
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
{
return &v->visitor;
@@ -211,8 +186,8 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
v->visitor.start_struct = qapi_dealloc_start_struct;
v->visitor.end_struct = qapi_dealloc_end_struct;
- v->visitor.start_implicit_struct = qapi_dealloc_start_implicit_struct;
- v->visitor.end_implicit_struct = qapi_dealloc_end_implicit_struct;
+ v->visitor.start_alternate = qapi_dealloc_start_alternate;
+ v->visitor.end_alternate = qapi_dealloc_end_alternate;
v->visitor.start_list = qapi_dealloc_start_list;
v->visitor.next_list = qapi_dealloc_next_list;
v->visitor.end_list = qapi_dealloc_end_list;
@@ -223,7 +198,6 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
v->visitor.type_str = qapi_dealloc_type_str;
v->visitor.type_number = qapi_dealloc_type_number;
v->visitor.type_any = qapi_dealloc_type_anything;
- v->visitor.start_union = qapi_dealloc_start_union;
QTAILQ_INIT(&v->stack);
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index f856286461..856606b253 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -30,29 +30,15 @@ void visit_end_struct(Visitor *v, Error **errp)
v->end_struct(v, errp);
}
-void visit_start_implicit_struct(Visitor *v, void **obj, size_t size,
- Error **errp)
-{
- if (v->start_implicit_struct) {
- v->start_implicit_struct(v, obj, size, errp);
- }
-}
-
-void visit_end_implicit_struct(Visitor *v)
-{
- if (v->end_implicit_struct) {
- v->end_implicit_struct(v);
- }
-}
-
void visit_start_list(Visitor *v, const char *name, Error **errp)
{
v->start_list(v, name, errp);
}
-GenericList *visit_next_list(Visitor *v, GenericList **list)
+GenericList *visit_next_list(Visitor *v, GenericList **list, size_t size)
{
- return v->next_list(v, list);
+ assert(list && size >= sizeof(GenericList));
+ return v->next_list(v, list, size);
}
void visit_end_list(Visitor *v)
@@ -60,28 +46,29 @@ void visit_end_list(Visitor *v)
v->end_list(v);
}
-bool visit_start_union(Visitor *v, bool data_present, Error **errp)
+void visit_start_alternate(Visitor *v, const char *name,
+ GenericAlternate **obj, size_t size,
+ bool promote_int, Error **errp)
{
- if (v->start_union) {
- return v->start_union(v, data_present, errp);
+ assert(obj && size >= sizeof(GenericAlternate));
+ if (v->start_alternate) {
+ v->start_alternate(v, name, obj, size, promote_int, errp);
}
- return true;
}
-bool visit_optional(Visitor *v, const char *name, bool *present)
+void visit_end_alternate(Visitor *v)
{
- if (v->optional) {
- v->optional(v, name, present);
+ if (v->end_alternate) {
+ v->end_alternate(v);
}
- return *present;
}
-void visit_get_next_type(Visitor *v, const char *name, QType *type,
- bool promote_int, Error **errp)
+bool visit_optional(Visitor *v, const char *name, bool *present)
{
- if (v->get_next_type) {
- v->get_next_type(v, name, type, promote_int, errp);
+ if (v->optional) {
+ v->optional(v, name, present);
}
+ return *present;
}
void visit_type_enum(Visitor *v, const char *name, int *obj,
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index 362a1a33a8..e6598327c3 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -90,12 +90,6 @@ static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
qiv->nb_stack++;
}
-/** Only for qmp_input_pop. */
-static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey)
-{
- *(const char **)user_pkey = (const char *)key;
- return TRUE;
-}
static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
{
@@ -104,9 +98,11 @@ static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
if (qiv->strict) {
GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
if (top_ht) {
- if (g_hash_table_size(top_ht)) {
- const char *key;
- g_hash_table_find(top_ht, always_true, &key);
+ GHashTableIter iter;
+ const char *key;
+
+ g_hash_table_iter_init(&iter, top_ht);
+ if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
}
g_hash_table_unref(top_ht);
@@ -147,14 +143,6 @@ static void qmp_input_end_struct(Visitor *v, Error **errp)
qmp_input_pop(qiv, errp);
}
-static void qmp_input_start_implicit_struct(Visitor *v, void **obj,
- size_t size, Error **errp)
-{
- if (obj) {
- *obj = g_malloc0(size);
- }
-}
-
static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
@@ -169,7 +157,8 @@ static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
qmp_input_push(qiv, qobj, errp);
}
-static GenericList *qmp_input_next_list(Visitor *v, GenericList **list)
+static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
+ size_t size)
{
QmpInputVisitor *qiv = to_qiv(v);
GenericList *entry;
@@ -188,7 +177,7 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList **list)
return NULL;
}
- entry = g_malloc0(sizeof(*entry));
+ entry = g_malloc0(size);
if (first) {
*list = entry;
} else {
@@ -205,19 +194,22 @@ static void qmp_input_end_list(Visitor *v)
qmp_input_pop(qiv, &error_abort);
}
-static void qmp_input_get_next_type(Visitor *v, const char *name, QType *type,
- bool promote_int, Error **errp)
+static void qmp_input_start_alternate(Visitor *v, const char *name,
+ GenericAlternate **obj, size_t size,
+ bool promote_int, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, false);
if (!qobj) {
+ *obj = NULL;
error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
return;
}
- *type = qobject_type(qobj);
- if (promote_int && *type == QTYPE_QINT) {
- *type = QTYPE_QFLOAT;
+ *obj = g_malloc0(size);
+ (*obj)->type = qobject_type(qobj);
+ if (promote_int && (*obj)->type == QTYPE_QINT) {
+ (*obj)->type = QTYPE_QFLOAT;
}
}
@@ -348,10 +340,10 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
v->visitor.start_struct = qmp_input_start_struct;
v->visitor.end_struct = qmp_input_end_struct;
- v->visitor.start_implicit_struct = qmp_input_start_implicit_struct;
v->visitor.start_list = qmp_input_start_list;
v->visitor.next_list = qmp_input_next_list;
v->visitor.end_list = qmp_input_end_list;
+ v->visitor.start_alternate = qmp_input_start_alternate;
v->visitor.type_enum = input_type_enum;
v->visitor.type_int64 = qmp_input_type_int64;
v->visitor.type_uint64 = qmp_input_type_uint64;
@@ -360,7 +352,6 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
v->visitor.type_number = qmp_input_type_number;
v->visitor.type_any = qmp_input_type_any;
v->visitor.optional = qmp_input_optional;
- v->visitor.get_next_type = qmp_input_get_next_type;
qmp_input_push(v, obj, NULL);
qobject_incref(obj);
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index f47eefa626..d44c676317 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -126,7 +126,8 @@ static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
qmp_output_push(qov, list);
}
-static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp)
+static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
+ size_t size)
{
GenericList *list = *listp;
QmpOutputVisitor *qov = to_qov(v);
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
index 18b9339768..59eb5dc4e3 100644
--- a/qapi/string-input-visitor.c
+++ b/qapi/string-input-visitor.c
@@ -139,7 +139,7 @@ start_list(Visitor *v, const char *name, Error **errp)
}
}
-static GenericList *next_list(Visitor *v, GenericList **list)
+static GenericList *next_list(Visitor *v, GenericList **list, size_t size)
{
StringInputVisitor *siv = to_siv(v);
GenericList **link;
@@ -173,7 +173,7 @@ static GenericList *next_list(Visitor *v, GenericList **list)
link = &(*list)->next;
}
- *link = g_malloc0(sizeof **link);
+ *link = g_malloc0(size);
return *link;
}
diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c
index b980bd3265..c2e5c5b92b 100644
--- a/qapi/string-output-visitor.c
+++ b/qapi/string-output-visitor.c
@@ -276,7 +276,7 @@ start_list(Visitor *v, const char *name, Error **errp)
sov->head = true;
}
-static GenericList *next_list(Visitor *v, GenericList **list)
+static GenericList *next_list(Visitor *v, GenericList **list, size_t size)
{
StringOutputVisitor *sov = to_sov(v);
GenericList *ret = NULL;
diff --git a/rules.mak b/rules.mak
index fc5ee41e47..d1ff311254 100644
--- a/rules.mak
+++ b/rules.mak
@@ -102,7 +102,7 @@ LD_REL := $(CC) -nostdlib -Wl,-r
modules:
%$(EXESUF): %.o
- $(call LINK,$^)
+ $(call LINK,$(filter %.o %.a %.mo, $^))
%.a:
$(call quiet-command,rm -f $@ && $(AR) rcs $@ $^," AR $(TARGET_DIR)$@")
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 7b0dca8c72..eac90d2fe9 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -2,7 +2,7 @@
# QAPI types generator
#
# Copyright IBM, Corp. 2011
-# Copyright (c) 2013-2015 Red Hat Inc.
+# Copyright (c) 2013-2016 Red Hat Inc.
#
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
@@ -14,6 +14,11 @@
from qapi import *
+# variants must be emitted before their container; track what has already
+# been output
+objects_seen = set()
+
+
def gen_fwd_object_or_array(name):
return mcgen('''
@@ -26,11 +31,8 @@ def gen_array(name, element_type):
return mcgen('''
struct %(c_name)s {
- union {
- %(c_type)s value;
- uint64_t padding;
- };
%(c_name)s *next;
+ %(c_type)s value;
};
''',
c_name=c_name(name), c_type=element_type.c_type())
@@ -52,11 +54,23 @@ def gen_struct_fields(members):
def gen_object(name, base, members, variants):
- ret = mcgen('''
+ if name in objects_seen:
+ return ''
+ objects_seen.add(name)
+
+ ret = ''
+ if variants:
+ for v in variants.variants:
+ if (isinstance(v.type, QAPISchemaObjectType) and
+ not v.type.is_implicit()):
+ ret += gen_object(v.type.name, v.type.base,
+ v.type.local_members, v.type.variants)
+
+ ret += mcgen('''
struct %(c_name)s {
''',
- c_name=c_name(name))
+ c_name=c_name(name))
if base:
ret += mcgen('''
@@ -118,11 +132,12 @@ def gen_variants(variants):
for var in variants.variants:
# Ugly special case for simple union TODO get rid of it
- typ = var.simple_union_type() or var.type
+ simple_union_type = var.simple_union_type()
+ typ = simple_union_type or var.type
ret += mcgen('''
%(c_type)s %(c_name)s;
''',
- c_type=typ.c_type(),
+ c_type=typ.c_type(is_unboxed=not simple_union_type),
c_name=c_name(var.name))
ret += mcgen('''
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 0cc9b08b14..2308268a62 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -15,10 +15,6 @@
from qapi import *
import re
-# visit_type_FOO_implicit() is emitted as needed; track if it has already
-# been output.
-implicit_structs_seen = set()
-
# visit_type_FOO_fields() is always emitted; track if a forward declaration
# or implementation has already been output.
struct_fields_seen = set()
@@ -35,52 +31,31 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error **
def gen_visit_fields_decl(typ):
- ret = ''
- if typ.name not in struct_fields_seen:
- ret += mcgen('''
-
-static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
-''',
- c_type=typ.c_name())
- struct_fields_seen.add(typ.name)
- return ret
-
-
-def gen_visit_implicit_struct(typ):
- if typ in implicit_structs_seen:
+ if typ.name in struct_fields_seen:
return ''
- implicit_structs_seen.add(typ)
-
- ret = gen_visit_fields_decl(typ)
-
- ret += mcgen('''
-
-static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error **errp)
-{
- Error *err = NULL;
+ struct_fields_seen.add(typ.name)
+ return mcgen('''
- visit_start_implicit_struct(v, (void **)obj, sizeof(%(c_type)s), &err);
- if (!err) {
- visit_type_%(c_type)s_fields(v, obj, errp);
- visit_end_implicit_struct(v);
- }
- error_propagate(errp, err);
-}
+static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s *obj, Error **errp);
''',
c_type=typ.c_name())
- return ret
-def gen_visit_struct_fields(name, base, members):
+def gen_visit_struct_fields(name, base, members, variants):
ret = ''
if base:
ret += gen_visit_fields_decl(base)
+ if variants:
+ for var in variants.variants:
+ # Ugly special case for simple union TODO get rid of it
+ if not var.simple_union_type():
+ ret += gen_visit_fields_decl(var.type)
struct_fields_seen.add(name)
ret += mcgen('''
-static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp)
+static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **errp)
{
Error *err = NULL;
@@ -89,57 +64,61 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **e
if base:
ret += mcgen('''
- visit_type_%(c_type)s_fields(v, (%(c_type)s **)obj, &err);
+ visit_type_%(c_type)s_fields(v, (%(c_type)s *)obj, &err);
''',
c_type=base.c_name())
ret += gen_err_check()
- ret += gen_visit_fields(members, prefix='(*obj)->')
+ ret += gen_visit_fields(members, prefix='obj->')
- # 'goto out' produced for base, and by gen_visit_fields() for each member
- if base or members:
+ if variants:
ret += mcgen('''
+ switch (obj->%(c_name)s) {
+''',
+ c_name=c_name(variants.tag_member.name))
-out:
-''')
- ret += mcgen('''
- error_propagate(errp, err);
-}
+ for var in variants.variants:
+ # TODO ugly special case for simple union
+ simple_union_type = var.simple_union_type()
+ ret += mcgen('''
+ case %(case)s:
+''',
+ case=c_enum_const(variants.tag_member.type.name,
+ var.name,
+ variants.tag_member.type.prefix))
+ if simple_union_type:
+ ret += mcgen('''
+ visit_type_%(c_type)s(v, "data", &obj->u.%(c_name)s, &err);
+''',
+ c_type=simple_union_type.c_name(),
+ c_name=c_name(var.name))
+ else:
+ ret += mcgen('''
+ visit_type_%(c_type)s_fields(v, &obj->u.%(c_name)s, &err);
+''',
+ c_type=var.type.c_name(),
+ c_name=c_name(var.name))
+ ret += mcgen('''
+ break;
''')
- return ret
-
-def gen_visit_struct(name, base, members):
- ret = gen_visit_struct_fields(name, base, members)
-
- # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
- # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
- # rather than leaving it non-NULL. As currently written, the caller must
- # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
- ret += mcgen('''
+ ret += mcgen('''
+ default:
+ abort();
+ }
+''')
-void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
-{
- Error *err = NULL;
+ # 'goto out' produced for base, by gen_visit_fields() for each member,
+ # and if variants were present
+ if base or members or variants:
+ ret += mcgen('''
- visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), &err);
- if (err) {
- goto out;
- }
- if (!*obj) {
- goto out_obj;
- }
- visit_type_%(c_name)s_fields(v, obj, &err);
- error_propagate(errp, err);
- err = NULL;
-out_obj:
- visit_end_struct(v, &err);
out:
+''')
+ ret += mcgen('''
error_propagate(errp, err);
}
-''',
- c_name=c_name(name))
-
+''')
return ret
@@ -161,7 +140,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
}
for (prev = (GenericList **)obj;
- !err && (i = visit_next_list(v, prev)) != NULL;
+ !err && (i = visit_next_list(v, prev, sizeof(**obj))) != NULL;
prev = &i) {
%(c_name)s *native_i = (%(c_name)s *)i;
visit_type_%(c_elt_type)s(v, NULL, &native_i->value, &err);
@@ -190,45 +169,62 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s *obj, Error
def gen_visit_alternate(name, variants):
promote_int = 'true'
+ ret = ''
for var in variants.variants:
if var.type.alternate_qtype() == 'QTYPE_QINT':
promote_int = 'false'
+ if isinstance(var.type, QAPISchemaObjectType):
+ ret += gen_visit_fields_decl(var.type)
- ret = mcgen('''
+ ret += mcgen('''
void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
{
Error *err = NULL;
- visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err);
+ visit_start_alternate(v, name, (GenericAlternate **)obj, sizeof(**obj),
+ %(promote_int)s, &err);
if (err) {
goto out;
}
- visit_get_next_type(v, name, &(*obj)->type, %(promote_int)s, &err);
- if (err) {
- goto out_obj;
- }
switch ((*obj)->type) {
''',
- c_name=c_name(name), promote_int=promote_int)
+ c_name=c_name(name), promote_int=promote_int)
for var in variants.variants:
ret += mcgen('''
case %(case)s:
+''',
+ case=var.type.alternate_qtype())
+ if isinstance(var.type, QAPISchemaObjectType):
+ ret += mcgen('''
+ visit_start_struct(v, name, NULL, 0, &err);
+ if (err) {
+ break;
+ }
+ visit_type_%(c_type)s_fields(v, &(*obj)->u.%(c_name)s, &err);
+ error_propagate(errp, err);
+ err = NULL;
+ visit_end_struct(v, &err);
+''',
+ c_type=var.type.c_name(),
+ c_name=c_name(var.name))
+ else:
+ ret += mcgen('''
visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, &err);
- break;
''',
- case=var.type.alternate_qtype(),
- c_type=var.type.c_name(),
- c_name=c_name(var.name))
+ c_type=var.type.c_name(),
+ c_name=c_name(var.name))
+ ret += mcgen('''
+ break;
+''')
ret += mcgen('''
default:
error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"%(name)s");
}
-out_obj:
- visit_end_implicit_struct(v);
+ visit_end_alternate(v);
out:
error_propagate(errp, err);
}
@@ -238,17 +234,13 @@ out:
return ret
-def gen_visit_union(name, base, variants):
- ret = ''
-
- if base:
- ret += gen_visit_fields_decl(base)
-
- for var in variants.variants:
- # Ugly special case for simple union TODO get rid of it
- if not var.simple_union_type():
- ret += gen_visit_implicit_struct(var.type)
+def gen_visit_object(name, base, members, variants):
+ ret = gen_visit_struct_fields(name, base, members, variants)
+ # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
+ # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
+ # rather than leaving it non-NULL. As currently written, the caller must
+ # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
ret += mcgen('''
void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
@@ -262,66 +254,16 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
if (!*obj) {
goto out_obj;
}
-''',
- c_name=c_name(name))
-
- if base:
- ret += mcgen('''
- visit_type_%(c_name)s_fields(v, (%(c_name)s **)obj, &err);
-''',
- c_name=base.c_name())
- else:
- ret += mcgen('''
- visit_type_%(c_type)s(v, "%(name)s", &(*obj)->%(c_name)s, &err);
-''',
- c_type=variants.tag_member.type.c_name(),
- c_name=c_name(variants.tag_member.name),
- name=variants.tag_member.name)
- ret += gen_err_check(label='out_obj')
- ret += mcgen('''
- if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
- goto out_obj;
- }
- switch ((*obj)->%(c_name)s) {
-''',
- c_name=c_name(variants.tag_member.name))
-
- for var in variants.variants:
- # TODO ugly special case for simple union
- simple_union_type = var.simple_union_type()
- ret += mcgen('''
- case %(case)s:
-''',
- case=c_enum_const(variants.tag_member.type.name,
- var.name))
- if simple_union_type:
- ret += mcgen('''
- visit_type_%(c_type)s(v, "data", &(*obj)->u.%(c_name)s, &err);
-''',
- c_type=simple_union_type.c_name(),
- c_name=c_name(var.name))
- else:
- ret += mcgen('''
- visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err);
-''',
- c_type=var.type.c_name(),
- c_name=c_name(var.name))
- ret += mcgen('''
- break;
-''')
-
- ret += mcgen('''
- default:
- abort();
- }
-out_obj:
+ visit_type_%(c_name)s_fields(v, *obj, &err);
error_propagate(errp, err);
err = NULL;
+out_obj:
visit_end_struct(v, &err);
out:
error_propagate(errp, err);
}
-''')
+''',
+ c_name=c_name(name))
return ret
@@ -375,14 +317,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
def visit_object_type(self, name, info, base, members, variants):
self.decl += gen_visit_decl(name)
- if variants:
- if members:
- # Members other than variants.tag_member not implemented
- assert len(members) == 1
- assert members[0] == variants.tag_member
- self.defn += gen_visit_union(name, base, variants)
- else:
- self.defn += gen_visit_struct(name, base, members)
+ self.defn += gen_visit_object(name, base, members, variants)
def visit_alternate_type(self, name, info, variants):
self.decl += gen_visit_decl(name)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index f40dc9e777..8497777d94 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -590,7 +590,10 @@ def check_union(expr, expr_info):
"Discriminator '%s' must be of enumeration "
"type" % discriminator)
- # Check every branch
+ # Check every branch; don't allow an empty union
+ if len(members) == 0:
+ raise QAPIExprError(expr_info,
+ "Union '%s' cannot have empty 'data'" % name)
for (key, value) in members.items():
check_name(expr_info, "Member of union '%s'" % name, key)
@@ -613,7 +616,11 @@ def check_alternate(expr, expr_info):
members = expr['data']
types_seen = {}
- # Check every branch
+ # Check every branch; require at least two branches
+ if len(members) < 2:
+ raise QAPIExprError(expr_info,
+ "Alternate '%s' should have at least two branches "
+ "in 'data'" % name)
for (key, value) in members.items():
check_name(expr_info, "Member of alternate '%s'" % name, key)
@@ -622,7 +629,10 @@ def check_alternate(expr, expr_info):
value,
allow_metas=['built-in', 'union', 'struct', 'enum'])
qtype = find_alternate_member_qtype(value)
- assert qtype
+ if not qtype:
+ raise QAPIExprError(expr_info,
+ "Alternate '%s' member '%s' cannot use "
+ "type '%s'" % (name, key, value))
if qtype in types_seen:
raise QAPIExprError(expr_info,
"Alternate '%s' member '%s' can't "
@@ -814,7 +824,7 @@ class QAPISchemaVisitor(object):
class QAPISchemaType(QAPISchemaEntity):
- def c_type(self, is_param=False):
+ def c_type(self, is_param=False, is_unboxed=False):
return c_name(self.name) + pointer_suffix
def c_null(self):
@@ -847,7 +857,7 @@ class QAPISchemaBuiltinType(QAPISchemaType):
def c_name(self):
return self.name
- def c_type(self, is_param=False):
+ def c_type(self, is_param=False, is_unboxed=False):
if is_param and self.name == 'str':
return 'const ' + self._c_type_name
return self._c_type_name
@@ -881,7 +891,7 @@ class QAPISchemaEnumType(QAPISchemaType):
# See QAPISchema._make_implicit_enum_type()
return self.name.endswith('Kind')
- def c_type(self, is_param=False):
+ def c_type(self, is_param=False, is_unboxed=False):
return c_name(self.name)
def member_names(self):
@@ -977,9 +987,11 @@ class QAPISchemaObjectType(QAPISchemaType):
assert not self.is_implicit()
return QAPISchemaType.c_name(self)
- def c_type(self, is_param=False):
+ def c_type(self, is_param=False, is_unboxed=False):
assert not self.is_implicit()
- return QAPISchemaType.c_type(self)
+ if is_unboxed:
+ return c_name(self.name)
+ return c_name(self.name) + pointer_suffix
def json_type(self):
return 'object'
@@ -1059,6 +1071,7 @@ class QAPISchemaObjectTypeVariants(object):
assert bool(tag_member) != bool(tag_name)
assert (isinstance(tag_name, str) or
isinstance(tag_member, QAPISchemaObjectTypeMember))
+ assert len(variants) > 0
for v in variants:
assert isinstance(v, QAPISchemaObjectTypeVariant)
self.tag_name = tag_name
diff --git a/tests/Makefile b/tests/Makefile
index c1c605fc63..04e34b5c7e 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -173,6 +173,7 @@ check-qtest-i386-y += tests/hd-geo-test$(EXESUF)
gcov-files-i386-y += hw/block/hd-geometry.c
check-qtest-i386-y += tests/boot-order-test$(EXESUF)
check-qtest-i386-y += tests/bios-tables-test$(EXESUF)
+check-qtest-i386-y += tests/pxe-test$(EXESUF)
check-qtest-i386-y += tests/rtc-test$(EXESUF)
check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF)
check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF)
@@ -241,6 +242,7 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
check-qtest-generic-y += tests/qom-test$(EXESUF)
+qapi-schema += alternate-any.json
qapi-schema += alternate-array.json
qapi-schema += alternate-base.json
qapi-schema += alternate-clash.json
@@ -518,7 +520,9 @@ tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o
tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o
tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
-tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y)
+tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
+ tests/boot-sector.o $(libqos-obj-y)
+tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 7155fecdbf..0a80ddf04b 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -18,6 +18,7 @@
#include "hw/acpi/acpi-defs.h"
#include "hw/smbios/smbios.h"
#include "qemu/bitmap.h"
+#include "boot-sector.h"
#define MACHINE_PC "pc"
#define MACHINE_Q35 "q35"
@@ -51,13 +52,6 @@ typedef struct {
struct smbios_21_entry_point smbios_ep_table;
} test_data;
-#define LOW(x) ((x) & 0xff)
-#define HIGH(x) ((x) >> 8)
-
-#define SIGNATURE 0xdead
-#define SIGNATURE_OFFSET 0x10
-#define BOOT_SECTOR_ADDRESS 0x7c00
-
#define ACPI_READ_FIELD(field, addr) \
do { \
switch (sizeof(field)) { \
@@ -117,35 +111,6 @@ typedef struct {
g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
} while (0)
-/* Boot sector code: write SIGNATURE into memory,
- * then halt.
- * Q35 machine requires a minimum 0x7e000 bytes disk.
- * (bug or feature?)
- */
-static uint8_t boot_sector[0x7e000] = {
- /* 7c00: mov $0xdead,%ax */
- [0x00] = 0xb8,
- [0x01] = LOW(SIGNATURE),
- [0x02] = HIGH(SIGNATURE),
- /* 7c03: mov %ax,0x7c10 */
- [0x03] = 0xa3,
- [0x04] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET),
- [0x05] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET),
- /* 7c06: cli */
- [0x06] = 0xfa,
- /* 7c07: hlt */
- [0x07] = 0xf4,
- /* 7c08: jmp 0x7c07=0x7c0a-3 */
- [0x08] = 0xeb,
- [0x09] = LOW(-3),
- /* We mov 0xdead here: set value to make debugging easier */
- [SIGNATURE_OFFSET] = LOW(0xface),
- [SIGNATURE_OFFSET + 1] = HIGH(0xface),
- /* End of boot sector marker */
- [0x1FE] = 0x55,
- [0x1FF] = 0xAA,
-};
-
static const char *disk = "tests/acpi-test-disk.raw";
static const char *data_dir = "tests/acpi-test-data";
#ifdef CONFIG_IASL
@@ -737,10 +702,6 @@ static void test_smbios_structs(test_data *data)
static void test_acpi_one(const char *params, test_data *data)
{
char *args;
- uint8_t signature_low;
- uint8_t signature_high;
- uint16_t signature;
- int i;
args = g_strdup_printf("-net none -display none %s "
"-drive id=hd0,if=none,file=%s,format=raw "
@@ -749,24 +710,7 @@ static void test_acpi_one(const char *params, test_data *data)
qtest_start(args);
- /* Wait at most 1 minute */
-#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
-#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1)
-
- /* Poll until code has run and modified memory. Once it has we know BIOS
- * initialization is done. TODO: check that IP reached the halt
- * instruction.
- */
- for (i = 0; i < TEST_CYCLES; ++i) {
- signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET);
- signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1);
- signature = (signature_high << 8) | signature_low;
- if (signature == SIGNATURE) {
- break;
- }
- g_usleep(TEST_DELAY);
- }
- g_assert_cmphex(signature, ==, SIGNATURE);
+ boot_sector_test();
test_acpi_rsdp_address(data);
test_acpi_rsdp_table(data);
@@ -840,15 +784,11 @@ static void test_acpi_q35_tcg_bridge(void)
int main(int argc, char *argv[])
{
const char *arch = qtest_get_arch();
- FILE *f = fopen(disk, "w");
int ret;
- if (!f) {
- fprintf(stderr, "Couldn't open \"%s\": %s", disk, strerror(errno));
- return 1;
- }
- fwrite(boot_sector, 1, sizeof boot_sector, f);
- fclose(f);
+ ret = boot_sector_init(disk);
+ if(ret)
+ return ret;
g_test_init(&argc, &argv, NULL);
@@ -859,6 +799,6 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/tcg/bridge", test_acpi_q35_tcg_bridge);
}
ret = g_test_run();
- unlink(disk);
+ boot_sector_cleanup(disk);
return ret;
}
diff --git a/tests/boot-sector.c b/tests/boot-sector.c
new file mode 100644
index 0000000000..0b48bb34bf
--- /dev/null
+++ b/tests/boot-sector.c
@@ -0,0 +1,119 @@
+/*
+ * QEMU boot sector testing helpers.
+ *
+ * Copyright (c) 2016 Red Hat Inc.
+ *
+ * Authors:
+ * Michael S. Tsirkin <mst@redhat.com>
+ * Victor Kaplansky <victork@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "boot-sector.h"
+#include <string.h>
+#include <stdio.h>
+#include "qemu-common.h"
+#include "libqtest.h"
+
+#define LOW(x) ((x) & 0xff)
+#define HIGH(x) ((x) >> 8)
+
+#define SIGNATURE 0xdead
+#define SIGNATURE_OFFSET 0x10
+#define BOOT_SECTOR_ADDRESS 0x7c00
+
+/* Boot sector code: write SIGNATURE into memory,
+ * then halt.
+ * Q35 machine requires a minimum 0x7e000 bytes disk.
+ * (bug or feature?)
+ */
+static uint8_t boot_sector[0x7e000] = {
+ /* The first sector will be placed at RAM address 00007C00, and
+ * the BIOS transfers control to 00007C00
+ */
+
+ /* Data Segment register should be initialized, since pxe
+ * boot loader can leave it dirty.
+ */
+
+ /* 7c00: move $0000,%ax */
+ [0x00] = 0xb8,
+ [0x01] = 0x00,
+ [0x02] = 0x00,
+ /* 7c03: move %ax,%ds */
+ [0x03] = 0x8e,
+ [0x04] = 0xd8,
+
+ /* 7c05: mov $0xdead,%ax */
+ [0x05] = 0xb8,
+ [0x06] = LOW(SIGNATURE),
+ [0x07] = HIGH(SIGNATURE),
+ /* 7c08: mov %ax,0x7c10 */
+ [0x08] = 0xa3,
+ [0x09] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET),
+ [0x0a] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET),
+
+ /* 7c0b cli */
+ [0x0b] = 0xfa,
+ /* 7c0c: hlt */
+ [0x0c] = 0xf4,
+ /* 7c0e: jmp 0x7c07=0x7c0f-3 */
+ [0x0d] = 0xeb,
+ [0x0e] = LOW(-3),
+ /* We mov 0xdead here: set value to make debugging easier */
+ [SIGNATURE_OFFSET] = LOW(0xface),
+ [SIGNATURE_OFFSET + 1] = HIGH(0xface),
+ /* End of boot sector marker */
+ [0x1FE] = 0x55,
+ [0x1FF] = 0xAA,
+};
+
+/* Create boot disk file. */
+int boot_sector_init(const char *fname)
+{
+ FILE *f = fopen(fname, "w");
+
+ if (!f) {
+ fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno));
+ return 1;
+ }
+ fwrite(boot_sector, 1, sizeof boot_sector, f);
+ fclose(f);
+ return 0;
+}
+
+/* Loop until signature in memory is OK. */
+void boot_sector_test(void)
+{
+ uint8_t signature_low;
+ uint8_t signature_high;
+ uint16_t signature;
+ int i;
+
+ /* Wait at most 1 minute */
+#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
+#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1)
+
+ /* Poll until code has run and modified memory. Once it has we know BIOS
+ * initialization is done. TODO: check that IP reached the halt
+ * instruction.
+ */
+ for (i = 0; i < TEST_CYCLES; ++i) {
+ signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET);
+ signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1);
+ signature = (signature_high << 8) | signature_low;
+ if (signature == SIGNATURE) {
+ break;
+ }
+ g_usleep(TEST_DELAY);
+ }
+
+ g_assert_cmphex(signature, ==, SIGNATURE);
+}
+
+/* unlink boot disk file. */
+void boot_sector_cleanup(const char *fname)
+{
+ unlink(fname);
+}
diff --git a/tests/boot-sector.h b/tests/boot-sector.h
new file mode 100644
index 0000000000..38be0290e3
--- /dev/null
+++ b/tests/boot-sector.h
@@ -0,0 +1,26 @@
+/*
+ * QEMU boot sector testing helpers.
+ *
+ * Copyright (c) 2016 Red Hat Inc.
+ *
+ * Authors:
+ * Michael S. Tsirkin <mst@redhat.com>
+ * Victor Kaplansky <victork@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TEST_BOOT_SECTOR
+#define TEST_BOOT_SECTOR
+
+/* Create boot disk file. */
+int boot_sector_init(const char *fname);
+
+/* Loop until signature in memory is OK. */
+void boot_sector_test(void);
+
+/* unlink boot disk file. */
+void boot_sector_cleanup(const char *fname);
+
+#endif /* TEST_BOOT_SECTOR */
diff --git a/tests/pxe-test.c b/tests/pxe-test.c
new file mode 100644
index 0000000000..fa430958ea
--- /dev/null
+++ b/tests/pxe-test.c
@@ -0,0 +1,69 @@
+/*
+ * PXE test cases.
+ *
+ * Copyright (c) 2016 Red Hat Inc.
+ *
+ * Authors:
+ * Michael S. Tsirkin <mst@redhat.com>,
+ * Victor Kaplansky <victork@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include "qemu-common.h"
+#include "libqtest.h"
+#include "boot-sector.h"
+
+#define NETNAME "net0"
+
+static const char *disk = "tests/pxe-test-disk.raw";
+
+static void test_pxe_one(const char *params)
+{
+ char *args;
+
+ args = g_strdup_printf("-machine accel=tcg "
+ "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s "
+ "%s ",
+ disk, params);
+
+ qtest_start(args);
+ boot_sector_test();
+ qtest_quit(global_qtest);
+ g_free(args);
+}
+
+static void test_pxe_e1000(void)
+{
+ test_pxe_one("-device e1000,netdev=" NETNAME);
+}
+
+static void test_pxe_virtio_pci(void)
+{
+ test_pxe_one("-device virtio-net-pci,netdev=" NETNAME);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ const char *arch = qtest_get_arch();
+
+ ret = boot_sector_init(disk);
+ if(ret)
+ return ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+ qtest_add_func("pxe/e1000", test_pxe_e1000);
+ qtest_add_func("pxe/virtio", test_pxe_virtio_pci);
+ }
+ ret = g_test_run();
+ boot_sector_cleanup(disk);
+ return ret;
+}
diff --git a/tests/qapi-schema/alternate-any.err b/tests/qapi-schema/alternate-any.err
new file mode 100644
index 0000000000..aaa0154731
--- /dev/null
+++ b/tests/qapi-schema/alternate-any.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one' cannot use type 'any'
diff --git a/tests/qapi-schema/alternate-any.exit b/tests/qapi-schema/alternate-any.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/alternate-any.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/alternate-any.json b/tests/qapi-schema/alternate-any.json
new file mode 100644
index 0000000000..e47a73a116
--- /dev/null
+++ b/tests/qapi-schema/alternate-any.json
@@ -0,0 +1,4 @@
+# we do not allow the 'any' type as an alternate branch
+{ 'alternate': 'Alt',
+ 'data': { 'one': 'any',
+ 'two': 'int' } }
diff --git a/tests/qapi-schema/alternate-any.out b/tests/qapi-schema/alternate-any.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/alternate-any.out
diff --git a/tests/qapi-schema/alternate-empty.err b/tests/qapi-schema/alternate-empty.err
index e69de29bb2..bb06c5bfec 100644
--- a/tests/qapi-schema/alternate-empty.err
+++ b/tests/qapi-schema/alternate-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data'
diff --git a/tests/qapi-schema/alternate-empty.exit b/tests/qapi-schema/alternate-empty.exit
index 573541ac97..d00491fd7e 100644
--- a/tests/qapi-schema/alternate-empty.exit
+++ b/tests/qapi-schema/alternate-empty.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/alternate-empty.json b/tests/qapi-schema/alternate-empty.json
index db3820f841..fff15baf16 100644
--- a/tests/qapi-schema/alternate-empty.json
+++ b/tests/qapi-schema/alternate-empty.json
@@ -1,2 +1,2 @@
-# FIXME - alternates should list at least two types to be useful
+# alternates must list at least two types to be useful
{ 'alternate': 'Alt', 'data': { 'i': 'int' } }
diff --git a/tests/qapi-schema/alternate-empty.out b/tests/qapi-schema/alternate-empty.out
index f78f174111..e69de29bb2 100644
--- a/tests/qapi-schema/alternate-empty.out
+++ b/tests/qapi-schema/alternate-empty.out
@@ -1,5 +0,0 @@
-object :empty
-alternate Alt
- case i: int
-enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
- prefix QTYPE
diff --git a/tests/qapi-schema/flat-union-empty.err b/tests/qapi-schema/flat-union-empty.err
index e69de29bb2..15754f54eb 100644
--- a/tests/qapi-schema/flat-union-empty.err
+++ b/tests/qapi-schema/flat-union-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data'
diff --git a/tests/qapi-schema/flat-union-empty.exit b/tests/qapi-schema/flat-union-empty.exit
index 573541ac97..d00491fd7e 100644
--- a/tests/qapi-schema/flat-union-empty.exit
+++ b/tests/qapi-schema/flat-union-empty.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/flat-union-empty.json b/tests/qapi-schema/flat-union-empty.json
index 67dd2978eb..77f1d9abfb 100644
--- a/tests/qapi-schema/flat-union-empty.json
+++ b/tests/qapi-schema/flat-union-empty.json
@@ -1,4 +1,4 @@
-# FIXME - flat unions should not be empty
+# flat unions cannot be empty
{ 'enum': 'Empty', 'data': [ ] }
{ 'struct': 'Base', 'data': { 'type': 'Empty' } }
{ 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
diff --git a/tests/qapi-schema/flat-union-empty.out b/tests/qapi-schema/flat-union-empty.out
index eade2d5ac6..e69de29bb2 100644
--- a/tests/qapi-schema/flat-union-empty.out
+++ b/tests/qapi-schema/flat-union-empty.out
@@ -1,9 +0,0 @@
-object :empty
-object Base
- member type: Empty optional=False
-enum Empty []
-enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
- prefix QTYPE
-object Union
- base Base
- tag type
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 4b895275c7..632964a6ec 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -73,17 +73,22 @@
'base': 'UserDefZero',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
+{ 'struct': 'UserDefUnionBase2',
+ 'base': 'UserDefZero',
+ 'data': { 'string': 'str', 'enum1': 'QEnumTwo' } }
+
# this variant of UserDefFlatUnion defaults to a union that uses fields with
# allocated types to test corner cases in the cleanup/dealloc visitor
{ 'union': 'UserDefFlatUnion2',
- 'base': 'UserDefUnionBase',
+ 'base': 'UserDefUnionBase2',
'discriminator': 'enum1',
'data': { 'value1' : 'UserDefC', # intentional forward reference
- 'value2' : 'UserDefB',
- 'value3' : 'UserDefA' } }
+ 'value2' : 'UserDefB' } }
+{ 'struct': 'WrapAlternate',
+ 'data': { 'alt': 'UserDefAlternate' } }
{ 'alternate': 'UserDefAlternate',
- 'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } }
+ 'data': { 'udfu': 'UserDefFlatUnion', 's': 'str', 'i': 'int' } }
{ 'struct': 'UserDefC',
'data': { 'string1': 'str', 'string2': 'str' } }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 2c546b708a..f5e2a73c30 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -105,7 +105,7 @@ object UserDefA
member boolean: bool optional=False
member a_b: int optional=True
alternate UserDefAlternate
- case uda: UserDefA
+ case udfu: UserDefFlatUnion
case s: str
case i: int
object UserDefB
@@ -121,11 +121,10 @@ object UserDefFlatUnion
case value2: UserDefB
case value3: UserDefB
object UserDefFlatUnion2
- base UserDefUnionBase
+ base UserDefUnionBase2
tag enum1
case value1: UserDefC
case value2: UserDefB
- case value3: UserDefA
object UserDefNativeListUnion
member type: UserDefNativeListUnionKind optional=False
case integer: :obj-intList-wrapper
@@ -167,8 +166,14 @@ object UserDefUnionBase
base UserDefZero
member string: str optional=False
member enum1: EnumOne optional=False
+object UserDefUnionBase2
+ base UserDefZero
+ member string: str optional=False
+ member enum1: QEnumTwo optional=False
object UserDefZero
member integer: int optional=False
+object WrapAlternate
+ member alt: UserDefAlternate optional=False
event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
alternate __org.qemu_x-Alt
case __org.qemu_x-branch: str
diff --git a/tests/qapi-schema/union-empty.err b/tests/qapi-schema/union-empty.err
index e69de29bb2..12c20221bd 100644
--- a/tests/qapi-schema/union-empty.err
+++ b/tests/qapi-schema/union-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data'
diff --git a/tests/qapi-schema/union-empty.exit b/tests/qapi-schema/union-empty.exit
index 573541ac97..d00491fd7e 100644
--- a/tests/qapi-schema/union-empty.exit
+++ b/tests/qapi-schema/union-empty.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/union-empty.json b/tests/qapi-schema/union-empty.json
index 1785007113..1f0b13ca21 100644
--- a/tests/qapi-schema/union-empty.json
+++ b/tests/qapi-schema/union-empty.json
@@ -1,2 +1,2 @@
-# FIXME - unions should not be empty
+# unions cannot be empty
{ 'union': 'Union', 'data': { } }
diff --git a/tests/qapi-schema/union-empty.out b/tests/qapi-schema/union-empty.out
index bdf17e5b29..e69de29bb2 100644
--- a/tests/qapi-schema/union-empty.out
+++ b/tests/qapi-schema/union-empty.out
@@ -1,6 +0,0 @@
-object :empty
-enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
- prefix QTYPE
-object Union
- member type: UnionKind optional=False
-enum UnionKind []
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index c72cdad563..b05da5baa1 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -1,7 +1,7 @@
/*
* QMP Input Visitor unit-tests.
*
- * Copyright (C) 2011, 2015 Red Hat Inc.
+ * Copyright (C) 2011-2016 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
@@ -295,7 +295,7 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data,
g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
g_assert_cmpstr(tmp->string, ==, "str");
g_assert_cmpint(tmp->integer, ==, 41);
- g_assert_cmpint(tmp->u.value1->boolean, ==, true);
+ g_assert_cmpint(tmp->u.value1.boolean, ==, true);
base = qapi_UserDefFlatUnion_base(tmp);
g_assert(&base->enum1 == &tmp->enum1);
@@ -309,6 +309,7 @@ static void test_visitor_in_alternate(TestInputVisitorData *data,
Visitor *v;
Error *err = NULL;
UserDefAlternate *tmp;
+ WrapAlternate *wrap;
v = visitor_input_test_init(data, "42");
visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
@@ -322,10 +323,44 @@ static void test_visitor_in_alternate(TestInputVisitorData *data,
g_assert_cmpstr(tmp->u.s, ==, "string");
qapi_free_UserDefAlternate(tmp);
+ v = visitor_input_test_init(data, "{'integer':1, 'string':'str', "
+ "'enum1':'value1', 'boolean':true}");
+ visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
+ g_assert_cmpint(tmp->type, ==, QTYPE_QDICT);
+ g_assert_cmpint(tmp->u.udfu.integer, ==, 1);
+ g_assert_cmpstr(tmp->u.udfu.string, ==, "str");
+ g_assert_cmpint(tmp->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
+ g_assert_cmpint(tmp->u.udfu.u.value1.boolean, ==, true);
+ g_assert_cmpint(tmp->u.udfu.u.value1.has_a_b, ==, false);
+ qapi_free_UserDefAlternate(tmp);
+
v = visitor_input_test_init(data, "false");
visit_type_UserDefAlternate(v, NULL, &tmp, &err);
error_free_or_abort(&err);
qapi_free_UserDefAlternate(tmp);
+
+ v = visitor_input_test_init(data, "{ 'alt': 42 }");
+ visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
+ g_assert_cmpint(wrap->alt->type, ==, QTYPE_QINT);
+ g_assert_cmpint(wrap->alt->u.i, ==, 42);
+ qapi_free_WrapAlternate(wrap);
+
+ v = visitor_input_test_init(data, "{ 'alt': 'string' }");
+ visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
+ g_assert_cmpint(wrap->alt->type, ==, QTYPE_QSTRING);
+ g_assert_cmpstr(wrap->alt->u.s, ==, "string");
+ qapi_free_WrapAlternate(wrap);
+
+ v = visitor_input_test_init(data, "{ 'alt': {'integer':1, 'string':'str', "
+ "'enum1':'value1', 'boolean':true} }");
+ visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
+ g_assert_cmpint(wrap->alt->type, ==, QTYPE_QDICT);
+ g_assert_cmpint(wrap->alt->u.udfu.integer, ==, 1);
+ g_assert_cmpstr(wrap->alt->u.udfu.string, ==, "str");
+ g_assert_cmpint(wrap->alt->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
+ g_assert_cmpint(wrap->alt->u.udfu.u.value1.boolean, ==, true);
+ g_assert_cmpint(wrap->alt->u.udfu.u.value1.has_a_b, ==, false);
+ qapi_free_WrapAlternate(wrap);
}
static void test_visitor_in_alternate_number(TestInputVisitorData *data,
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index 965f298e11..a7f8b45c77 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -1,7 +1,7 @@
/*
* QMP Output Visitor unit-tests.
*
- * Copyright (C) 2011, 2015 Red Hat Inc.
+ * Copyright (C) 2011-2016 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
@@ -403,9 +403,8 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion));
tmp->enum1 = ENUM_ONE_VALUE1;
tmp->string = g_strdup("str");
- tmp->u.value1 = g_malloc0(sizeof(UserDefA));
tmp->integer = 41;
- tmp->u.value1->boolean = true;
+ tmp->u.value1.boolean = true;
visit_type_UserDefFlatUnion(data->ov, NULL, &tmp, &error_abort);
arg = qmp_output_get_qobject(data->qov);
@@ -427,6 +426,7 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
{
QObject *arg;
UserDefAlternate *tmp;
+ QDict *qdict;
tmp = g_new0(UserDefAlternate, 1);
tmp->type = QTYPE_QINT;
@@ -453,6 +453,27 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
qapi_free_UserDefAlternate(tmp);
qobject_decref(arg);
+
+ tmp = g_new0(UserDefAlternate, 1);
+ tmp->type = QTYPE_QDICT;
+ tmp->u.udfu.integer = 1;
+ tmp->u.udfu.string = g_strdup("str");
+ tmp->u.udfu.enum1 = ENUM_ONE_VALUE1;
+ tmp->u.udfu.u.value1.boolean = true;
+
+ visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort);
+ arg = qmp_output_get_qobject(data->qov);
+
+ g_assert_cmpint(qobject_type(arg), ==, QTYPE_QDICT);
+ qdict = qobject_to_qdict(arg);
+ g_assert_cmpint(qdict_size(qdict), ==, 4);
+ g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 1);
+ g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str");
+ g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1");
+ g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true);
+
+ qapi_free_UserDefAlternate(tmp);
+ qobject_decref(arg);
}
static void test_visitor_out_empty(TestOutputVisitorData *data,
diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c
index 9a1ad5a1bb..f2b6c67e5b 100644
--- a/tests/vhost-user-bridge.c
+++ b/tests/vhost-user-bridge.c
@@ -37,6 +37,7 @@
#include <sys/eventfd.h>
#include <arpa/inet.h>
#include <netdb.h>
+#include <qemu/osdep.h>
#include <linux/vhost.h>
@@ -176,6 +177,8 @@ typedef struct VubrVirtq {
#define VHOST_MEMORY_MAX_NREGIONS 8
#define VHOST_USER_F_PROTOCOL_FEATURES 30
+/* v1.0 compliant. */
+#define VIRTIO_F_VERSION_1 32
#define VHOST_LOG_PAGE 4096
@@ -284,6 +287,7 @@ typedef struct VubrDev {
struct sockaddr_in backend_udp_dest;
int ready;
uint64_t features;
+ int hdrlen;
} VubrDev;
static const char *vubr_request_str[] = {
@@ -474,7 +478,8 @@ vubr_backend_udp_recvbuf(VubrDev *dev, uint8_t *buf, size_t buflen)
static void
vubr_consume_raw_packet(VubrDev *dev, uint8_t *buf, uint32_t len)
{
- int hdrlen = sizeof(struct virtio_net_hdr_v1);
+ int hdrlen = dev->hdrlen;
+ DPRINT(" hdrlen = %d\n", dev->hdrlen);
if (VHOST_USER_BRIDGE_DEBUG) {
print_buffer(buf, len);
@@ -536,6 +541,7 @@ vubr_post_buffer(VubrDev *dev, VubrVirtq *vq, uint8_t *buf, int32_t len)
struct vring_avail *avail = vq->avail;
struct vring_used *used = vq->used;
uint64_t log_guest_addr = vq->log_guest_addr;
+ int32_t remaining_len = len;
unsigned int size = vq->size;
@@ -550,36 +556,49 @@ vubr_post_buffer(VubrDev *dev, VubrVirtq *vq, uint8_t *buf, int32_t len)
uint16_t d_index = avail->ring[a_index];
int i = d_index;
+ uint32_t written_len = 0;
- DPRINT("Post packet to guest on vq:\n");
- DPRINT(" size = %d\n", vq->size);
- DPRINT(" last_avail_index = %d\n", vq->last_avail_index);
- DPRINT(" last_used_index = %d\n", vq->last_used_index);
- DPRINT(" a_index = %d\n", a_index);
- DPRINT(" u_index = %d\n", u_index);
- DPRINT(" d_index = %d\n", d_index);
- DPRINT(" desc[%d].addr = 0x%016"PRIx64"\n", i, desc[i].addr);
- DPRINT(" desc[%d].len = %d\n", i, desc[i].len);
- DPRINT(" desc[%d].flags = %d\n", i, desc[i].flags);
- DPRINT(" avail->idx = %d\n", avail_index);
- DPRINT(" used->idx = %d\n", used->idx);
-
- if (!(desc[i].flags & VRING_DESC_F_WRITE)) {
- /* FIXME: we should find writable descriptor. */
- fprintf(stderr, "Error: descriptor is not writable. Exiting.\n");
- exit(1);
- }
+ do {
+ DPRINT("Post packet to guest on vq:\n");
+ DPRINT(" size = %d\n", vq->size);
+ DPRINT(" last_avail_index = %d\n", vq->last_avail_index);
+ DPRINT(" last_used_index = %d\n", vq->last_used_index);
+ DPRINT(" a_index = %d\n", a_index);
+ DPRINT(" u_index = %d\n", u_index);
+ DPRINT(" d_index = %d\n", d_index);
+ DPRINT(" desc[%d].addr = 0x%016"PRIx64"\n", i, desc[i].addr);
+ DPRINT(" desc[%d].len = %d\n", i, desc[i].len);
+ DPRINT(" desc[%d].flags = %d\n", i, desc[i].flags);
+ DPRINT(" avail->idx = %d\n", avail_index);
+ DPRINT(" used->idx = %d\n", used->idx);
+
+ if (!(desc[i].flags & VRING_DESC_F_WRITE)) {
+ /* FIXME: we should find writable descriptor. */
+ fprintf(stderr, "Error: descriptor is not writable. Exiting.\n");
+ exit(1);
+ }
- void *chunk_start = (void *)gpa_to_va(dev, desc[i].addr);
- uint32_t chunk_len = desc[i].len;
+ void *chunk_start = (void *)gpa_to_va(dev, desc[i].addr);
+ uint32_t chunk_len = desc[i].len;
+ uint32_t chunk_write_len = MIN(remaining_len, chunk_len);
- if (len <= chunk_len) {
- memcpy(chunk_start, buf, len);
- vubr_log_write(dev, desc[i].addr, len);
- } else {
- fprintf(stderr,
- "Received too long packet from the backend. Dropping...\n");
- return;
+ memcpy(chunk_start, buf + written_len, chunk_write_len);
+ vubr_log_write(dev, desc[i].addr, chunk_write_len);
+ remaining_len -= chunk_write_len;
+ written_len += chunk_write_len;
+
+ if ((remaining_len == 0) || !(desc[i].flags & VRING_DESC_F_NEXT)) {
+ break;
+ }
+
+ i = desc[i].next;
+ } while (1);
+
+ if (remaining_len > 0) {
+ fprintf(stderr,
+ "Too long packet for RX, remaining_len = %d, Dropping...\n",
+ remaining_len);
+ return;
}
/* Add descriptor to the used ring. */
@@ -687,7 +706,7 @@ vubr_backend_recv_cb(int sock, void *ctx)
VubrVirtq *rx_vq = &dev->vq[0];
uint8_t buf[4096];
struct virtio_net_hdr_v1 *hdr = (struct virtio_net_hdr_v1 *)buf;
- int hdrlen = sizeof(struct virtio_net_hdr_v1);
+ int hdrlen = dev->hdrlen;
int buflen = sizeof(buf);
int len;
@@ -696,6 +715,7 @@ vubr_backend_recv_cb(int sock, void *ctx)
}
DPRINT("\n\n *** IN UDP RECEIVE CALLBACK ***\n\n");
+ DPRINT(" hdrlen = %d\n", hdrlen);
uint16_t avail_index = atomic_mb_read(&rx_vq->avail->idx);
@@ -707,10 +727,12 @@ vubr_backend_recv_cb(int sock, void *ctx)
return;
}
+ memset(buf, 0, hdrlen);
+ /* TODO: support mergeable buffers. */
+ if (hdrlen == 12)
+ hdr->num_buffers = 1;
len = vubr_backend_udp_recvbuf(dev, buf + hdrlen, buflen - hdrlen);
- *hdr = (struct virtio_net_hdr_v1) { };
- hdr->num_buffers = 1;
vubr_post_buffer(dev, rx_vq, buf, len + hdrlen);
}
@@ -758,7 +780,15 @@ static int
vubr_set_features_exec(VubrDev *dev, VhostUserMsg *vmsg)
{
DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64);
+
dev->features = vmsg->payload.u64;
+ if ((dev->features & (1ULL << VIRTIO_F_VERSION_1)) ||
+ (dev->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF))) {
+ dev->hdrlen = 12;
+ } else {
+ dev->hdrlen = 10;
+ }
+
return 0;
}