summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/nbd-client.c4
-rw-r--r--fsdev/file-op-9p.h1
-rw-r--r--hw/9pfs/9p-handle.c9
-rw-r--r--hw/9pfs/9p-proxy.c13
-rw-r--r--hw/9pfs/9p.c10
-rw-r--r--hw/alpha/typhoon.c2
-rw-r--r--hw/arm/boot.c17
-rw-r--r--hw/audio/pcspk.c10
-rw-r--r--hw/block/xen_disk.c42
-rw-r--r--hw/char/spapr_vty.c2
-rw-r--r--hw/core/generic-loader.c7
-rw-r--r--hw/i386/kvm/pci-assign.c4
-rw-r--r--hw/pci-host/uninorth.c4
-rw-r--r--hw/ppc/spapr.c76
-rw-r--r--hw/ppc/spapr_ovec.c12
-rw-r--r--hw/ppc/spapr_pci.c35
-rw-r--r--hw/scsi/esp.c2
-rw-r--r--hw/scsi/megasas.c58
-rw-r--r--include/exec/cpu_ldst.h2
-rw-r--r--include/hw/i386/pc.h5
-rw-r--r--include/hw/pci-host/spapr.h6
-rw-r--r--include/hw/ppc/spapr_ovec.h4
-rw-r--r--include/migration/cpu.h4
-rw-r--r--pc-bios/openbios-ppcbin750840 -> 750840 bytes
-rw-r--r--pc-bios/openbios-sparc32bin382048 -> 382048 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1593408 -> 1593408 bytes
m---------roms/openbios0
-rw-r--r--rules.mak2
-rw-r--r--target-i386/cpu.c7
-rw-r--r--target-m68k/translate.c8
-rw-r--r--target-ppc/cpu.h7
-rw-r--r--target-ppc/helper_regs.h11
-rw-r--r--target-ppc/int_helper.c4
-rw-r--r--target-ppc/machine.c39
-rw-r--r--target-ppc/translate_init.c6
-rw-r--r--tests/postcopy-test.c12
-rw-r--r--xen-hvm.c22
37 files changed, 364 insertions, 83 deletions
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 2a302de674..3779c6c999 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -415,6 +415,10 @@ int nbd_client_init(BlockDriverState *bs,
}
if (client->nbdflags & NBD_FLAG_SEND_FUA) {
bs->supported_write_flags = BDRV_REQ_FUA;
+ bs->supported_zero_flags |= BDRV_REQ_FUA;
+ }
+ if (client->nbdflags & NBD_FLAG_SEND_WRITE_ZEROES) {
+ bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP;
}
qemu_co_mutex_init(&client->send_mutex);
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 6db9feac8f..a56dc8488d 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -100,6 +100,7 @@ struct FileOperations
{
int (*parse_opts)(QemuOpts *, struct FsDriverEntry *);
int (*init)(struct FsContext *);
+ void (*cleanup)(struct FsContext *);
int (*lstat)(FsContext *, V9fsPath *, struct stat *);
ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t);
int (*chmod)(FsContext *, V9fsPath *, FsCred *);
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c
index 3d77594f92..1687661bc9 100644
--- a/hw/9pfs/9p-handle.c
+++ b/hw/9pfs/9p-handle.c
@@ -649,6 +649,14 @@ out:
return ret;
}
+static void handle_cleanup(FsContext *ctx)
+{
+ struct handle_data *data = ctx->private;
+
+ close(data->mountfd);
+ g_free(data);
+}
+
static int handle_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
{
const char *sec_model = qemu_opt_get(opts, "security_model");
@@ -671,6 +679,7 @@ static int handle_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
FileOperations handle_ops = {
.parse_opts = handle_parse_opts,
.init = handle_init,
+ .cleanup = handle_cleanup,
.lstat = handle_lstat,
.readlink = handle_readlink,
.close = handle_close,
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
index f2417b7fd7..f4aa7a9d70 100644
--- a/hw/9pfs/9p-proxy.c
+++ b/hw/9pfs/9p-proxy.c
@@ -1168,9 +1168,22 @@ static int proxy_init(FsContext *ctx)
return 0;
}
+static void proxy_cleanup(FsContext *ctx)
+{
+ V9fsProxy *proxy = ctx->private;
+
+ g_free(proxy->out_iovec.iov_base);
+ g_free(proxy->in_iovec.iov_base);
+ if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
+ close(proxy->sockfd);
+ }
+ g_free(proxy);
+}
+
FileOperations proxy_ops = {
.parse_opts = proxy_parse_opts,
.init = proxy_init,
+ .cleanup = proxy_cleanup,
.lstat = proxy_lstat,
.readlink = proxy_readlink,
.close = proxy_close,
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index aea7e9d392..faebd91f5f 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -3521,8 +3521,11 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp)
rc = 0;
out:
if (rc) {
- g_free(s->ctx.fs_root);
+ if (s->ops->cleanup && s->ctx.private) {
+ s->ops->cleanup(&s->ctx);
+ }
g_free(s->tag);
+ g_free(s->ctx.fs_root);
v9fs_path_free(&path);
}
return rc;
@@ -3530,8 +3533,11 @@ out:
void v9fs_device_unrealize_common(V9fsState *s, Error **errp)
{
- g_free(s->ctx.fs_root);
+ if (s->ops->cleanup) {
+ s->ops->cleanup(&s->ctx);
+ }
g_free(s->tag);
+ g_free(s->ctx.fs_root);
}
typedef struct VirtfsCoResetData {
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index 883db13f96..f50f5cf186 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -376,7 +376,7 @@ static void cchip_write(void *opaque, hwaddr addr,
break;
case 0x0240: /* DIM1 */
/* DIM: Device Interrupt Mask Register, CPU1. */
- s->cchip.dim[0] = val;
+ s->cchip.dim[1] = val;
cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
break;
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 942416d95a..ff621e4b6a 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -9,6 +9,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include <libfdt.h>
#include "hw/hw.h"
#include "hw/arm/arm.h"
#include "hw/arm/linux-boot-if.h"
@@ -486,6 +487,17 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
g_free(nodename);
}
} else {
+ Error *err = NULL;
+
+ rc = fdt_path_offset(fdt, "/memory");
+ if (rc < 0) {
+ qemu_fdt_add_subnode(fdt, "/memory");
+ }
+
+ if (!qemu_fdt_getprop(fdt, "/memory", "device_type", NULL, &err)) {
+ qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
+ }
+
rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg",
acells, binfo->loader_start,
scells, binfo->ram_size);
@@ -495,6 +507,11 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
}
}
+ rc = fdt_path_offset(fdt, "/chosen");
+ if (rc < 0) {
+ qemu_fdt_add_subnode(fdt, "/chosen");
+ }
+
if (binfo->kernel_cmdline && *binfo->kernel_cmdline) {
rc = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
binfo->kernel_cmdline);
diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c
index 984534b2d1..798002277b 100644
--- a/hw/audio/pcspk.c
+++ b/hw/audio/pcspk.c
@@ -54,6 +54,7 @@ typedef struct {
unsigned int play_pos;
uint8_t data_on;
uint8_t dummy_refresh_clock;
+ bool migrate;
} PCSpkState;
static const char *s_spk = "pcspk";
@@ -187,11 +188,19 @@ static void pcspk_realizefn(DeviceState *dev, Error **errp)
pcspk_state = s;
}
+static bool migrate_needed(void *opaque)
+{
+ PCSpkState *s = opaque;
+
+ return s->migrate;
+}
+
static const VMStateDescription vmstate_spk = {
.name = "pcspk",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
+ .needed = migrate_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(data_on, PCSpkState),
VMSTATE_UINT8(dummy_refresh_clock, PCSpkState),
@@ -201,6 +210,7 @@ static const VMStateDescription vmstate_spk = {
static Property pcspk_properties[] = {
DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1),
+ DEFINE_PROP_BOOL("migrate", PCSpkState, migrate, true),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 3a7dc194e2..456a2d5694 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -660,6 +660,38 @@ static void qemu_aio_complete(void *opaque, int ret)
qemu_bh_schedule(ioreq->blkdev->bh);
}
+static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number,
+ uint64_t nr_sectors)
+{
+ struct XenBlkDev *blkdev = ioreq->blkdev;
+ int64_t byte_offset;
+ int byte_chunk;
+ uint64_t byte_remaining, limit;
+ uint64_t sec_start = sector_number;
+ uint64_t sec_count = nr_sectors;
+
+ /* Wrap around, or overflowing byte limit? */
+ if (sec_start + sec_count < sec_count ||
+ sec_start + sec_count > INT64_MAX >> BDRV_SECTOR_BITS) {
+ return false;
+ }
+
+ limit = BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS;
+ byte_offset = sec_start << BDRV_SECTOR_BITS;
+ byte_remaining = sec_count << BDRV_SECTOR_BITS;
+
+ do {
+ byte_chunk = byte_remaining > limit ? limit : byte_remaining;
+ ioreq->aio_inflight++;
+ blk_aio_pdiscard(blkdev->blk, byte_offset, byte_chunk,
+ qemu_aio_complete, ioreq);
+ byte_remaining -= byte_chunk;
+ byte_offset += byte_chunk;
+ } while (byte_remaining > 0);
+
+ return true;
+}
+
static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
{
struct XenBlkDev *blkdev = ioreq->blkdev;
@@ -708,12 +740,10 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
break;
case BLKIF_OP_DISCARD:
{
- struct blkif_request_discard *discard_req = (void *)&ioreq->req;
- ioreq->aio_inflight++;
- blk_aio_pdiscard(blkdev->blk,
- discard_req->sector_number << BDRV_SECTOR_BITS,
- discard_req->nr_sectors << BDRV_SECTOR_BITS,
- qemu_aio_complete, ioreq);
+ struct blkif_request_discard *req = (void *)&ioreq->req;
+ if (!blk_split_discard(ioreq, req->sector_number, req->nr_sectors)) {
+ goto err;
+ }
break;
}
default:
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 06b9b3917f..7c22b8bd0e 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -25,7 +25,7 @@ static int vty_can_receive(void *opaque)
{
VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque);
- return (dev->in - dev->out) < VTERM_BUFSIZE;
+ return VTERM_BUFSIZE - (dev->in - dev->out);
}
static void vty_receive(void *opaque, const uint8_t *buf, int size)
diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c
index 79ab6df357..208f549dff 100644
--- a/hw/core/generic-loader.c
+++ b/hw/core/generic-loader.c
@@ -93,7 +93,12 @@ static void generic_loader_realize(DeviceState *dev, Error **errp)
"image");
return;
}
- s->set_pc = true;
+ /* The user specified a file, only set the PC if they also specified
+ * a CPU to use.
+ */
+ if (s->cpu_num != CPU_NONE) {
+ s->set_pc = true;
+ }
} else if (s->addr) {
/* User is setting the PC */
if (s->data || s->data_len || s->data_be) {
diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c
index 8238fbc630..87dcbdd51a 100644
--- a/hw/i386/kvm/pci-assign.c
+++ b/hw/i386/kvm/pci-assign.c
@@ -1251,6 +1251,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)
error_propagate(errp, local_err);
return -ENOTSUP;
}
+ dev->dev.cap_present |= QEMU_PCI_CAP_MSI;
dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI;
/* Only 32-bit/no-mask currently supported */
ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSI, pos, 10,
@@ -1285,6 +1286,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)
error_propagate(errp, local_err);
return -ENOTSUP;
}
+ dev->dev.cap_present |= QEMU_PCI_CAP_MSIX;
dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX;
ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSIX, pos, 12,
&local_err);
@@ -1648,6 +1650,7 @@ static void assigned_dev_register_msix_mmio(AssignedDevice *dev, Error **errp)
dev->msix_table = NULL;
return;
}
+ dev->dev.msix_table = (uint8_t *)dev->msix_table;
assigned_dev_msix_reset(dev);
@@ -1665,6 +1668,7 @@ static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev)
error_report("error unmapping msix_table! %s", strerror(errno));
}
dev->msix_table = NULL;
+ dev->dev.msix_table = NULL;
}
static const VMStateDescription vmstate_assigned_device = {
diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c
index 7aac4d67a4..df342ac3cb 100644
--- a/hw/pci-host/uninorth.c
+++ b/hw/pci-host/uninorth.c
@@ -62,9 +62,7 @@ typedef struct UNINState {
static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
{
- int devfn = pci_dev->devfn & 0x00FFFFFF;
-
- return (((devfn >> 11) & 0x1F) + irq_num) & 3;
+ return (irq_num + (pci_dev->devfn >> 3)) & 3;
}
static void pci_unin_set_irq(void *opaque, int irq_num, int level)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 0cbab24c91..c3269c7f50 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1267,6 +1267,68 @@ static bool version_before_3(void *opaque, int version_id)
return version_id < 3;
}
+static bool spapr_ov5_cas_needed(void *opaque)
+{
+ sPAPRMachineState *spapr = opaque;
+ sPAPROptionVector *ov5_mask = spapr_ovec_new();
+ sPAPROptionVector *ov5_legacy = spapr_ovec_new();
+ sPAPROptionVector *ov5_removed = spapr_ovec_new();
+ bool cas_needed;
+
+ /* Prior to the introduction of sPAPROptionVector, we had two option
+ * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
+ * Both of these options encode machine topology into the device-tree
+ * in such a way that the now-booted OS should still be able to interact
+ * appropriately with QEMU regardless of what options were actually
+ * negotiatied on the source side.
+ *
+ * As such, we can avoid migrating the CAS-negotiated options if these
+ * are the only options available on the current machine/platform.
+ * Since these are the only options available for pseries-2.7 and
+ * earlier, this allows us to maintain old->new/new->old migration
+ * compatibility.
+ *
+ * For QEMU 2.8+, there are additional CAS-negotiatable options available
+ * via default pseries-2.8 machines and explicit command-line parameters.
+ * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
+ * of the actual CAS-negotiated values to continue working properly. For
+ * example, availability of memory unplug depends on knowing whether
+ * OV5_HP_EVT was negotiated via CAS.
+ *
+ * Thus, for any cases where the set of available CAS-negotiatable
+ * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
+ * include the CAS-negotiated options in the migration stream.
+ */
+ spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
+ spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
+
+ /* spapr_ovec_diff returns true if bits were removed. we avoid using
+ * the mask itself since in the future it's possible "legacy" bits may be
+ * removed via machine options, which could generate a false positive
+ * that breaks migration.
+ */
+ spapr_ovec_intersect(ov5_legacy, spapr->ov5, ov5_mask);
+ cas_needed = spapr_ovec_diff(ov5_removed, spapr->ov5, ov5_legacy);
+
+ spapr_ovec_cleanup(ov5_mask);
+ spapr_ovec_cleanup(ov5_legacy);
+ spapr_ovec_cleanup(ov5_removed);
+
+ return cas_needed;
+}
+
+static const VMStateDescription vmstate_spapr_ov5_cas = {
+ .name = "spapr_option_vector_ov5_cas",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = spapr_ov5_cas_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_POINTER_V(ov5_cas, sPAPRMachineState, 1,
+ vmstate_spapr_ovec, sPAPROptionVector),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static const VMStateDescription vmstate_spapr = {
.name = "spapr",
.version_id = 3,
@@ -1282,6 +1344,10 @@ static const VMStateDescription vmstate_spapr = {
VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2),
VMSTATE_END_OF_LIST()
},
+ .subsections = (const VMStateDescription*[]) {
+ &vmstate_spapr_ov5_cas,
+ NULL
+ }
};
static int htab_save_setup(QEMUFile *f, void *opaque)
@@ -2701,6 +2767,16 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", true);
.driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \
.property = "mem64_win_size", \
.value = "0", \
+ }, \
+ { \
+ .driver = TYPE_POWERPC_CPU, \
+ .property = "pre-2.8-migration", \
+ .value = "on", \
+ }, \
+ { \
+ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \
+ .property = "pre-2.8-migration", \
+ .value = "on", \
},
static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index,
diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c
index c2a0d18577..3eb1d5976f 100644
--- a/hw/ppc/spapr_ovec.c
+++ b/hw/ppc/spapr_ovec.c
@@ -37,6 +37,17 @@
*/
struct sPAPROptionVector {
unsigned long *bitmap;
+ int32_t bitmap_size; /* only used for migration */
+};
+
+const VMStateDescription vmstate_spapr_ovec = {
+ .name = "spapr_option_vector",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BITMAP(bitmap, sPAPROptionVector, 1, bitmap_size),
+ VMSTATE_END_OF_LIST()
+ }
};
sPAPROptionVector *spapr_ovec_new(void)
@@ -45,6 +56,7 @@ sPAPROptionVector *spapr_ovec_new(void)
ov = g_new0(sPAPROptionVector, 1);
ov->bitmap = bitmap_new(OV_MAXBITS);
+ ov->bitmap_size = OV_MAXBITS;
return ov;
}
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index f9661b7d1a..fd6fc1d953 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1590,6 +1590,8 @@ static Property spapr_phb_properties[] = {
DEFINE_PROP_UINT64("pgsz", sPAPRPHBState, page_size_mask,
(1ULL << 12) | (1ULL << 16)),
DEFINE_PROP_UINT32("numa_node", sPAPRPHBState, numa_node, -1),
+ DEFINE_PROP_BOOL("pre-2.8-migration", sPAPRPHBState,
+ pre_2_8_migration, false),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1636,6 +1638,20 @@ static void spapr_pci_pre_save(void *opaque)
sphb->msi_devs[i].key = *(uint32_t *) key;
sphb->msi_devs[i].value = *(spapr_pci_msi *) value;
}
+
+ if (sphb->pre_2_8_migration) {
+ sphb->mig_liobn = sphb->dma_liobn[0];
+ sphb->mig_mem_win_addr = sphb->mem_win_addr;
+ sphb->mig_mem_win_size = sphb->mem_win_size;
+ sphb->mig_io_win_addr = sphb->io_win_addr;
+ sphb->mig_io_win_size = sphb->io_win_size;
+
+ if ((sphb->mem64_win_size != 0)
+ && (sphb->mem64_win_addr
+ == (sphb->mem_win_addr + sphb->mem_win_size))) {
+ sphb->mig_mem_win_size += sphb->mem64_win_size;
+ }
+ }
}
static int spapr_pci_post_load(void *opaque, int version_id)
@@ -1658,25 +1674,26 @@ static int spapr_pci_post_load(void *opaque, int version_id)
return 0;
}
-static bool version_before_3(void *opaque, int version_id)
+static bool pre_2_8_migration(void *opaque, int version_id)
{
- return version_id < 3;
+ sPAPRPHBState *sphb = opaque;
+
+ return sphb->pre_2_8_migration;
}
static const VMStateDescription vmstate_spapr_pci = {
.name = "spapr_pci",
- .version_id = 3,
+ .version_id = 2,
.minimum_version_id = 2,
.pre_save = spapr_pci_pre_save,
.post_load = spapr_pci_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState),
- VMSTATE_UNUSED_TEST(version_before_3,
- sizeof(uint32_t) /* dma_liobn[0] */
- + sizeof(uint64_t) /* mem_win_addr */
- + sizeof(uint64_t) /* mem_win_size */
- + sizeof(uint64_t) /* io_win_addr */
- + sizeof(uint64_t) /* io_win_size */),
+ VMSTATE_UINT32_TEST(mig_liobn, sPAPRPHBState, pre_2_8_migration),
+ VMSTATE_UINT64_TEST(mig_mem_win_addr, sPAPRPHBState, pre_2_8_migration),
+ VMSTATE_UINT64_TEST(mig_mem_win_size, sPAPRPHBState, pre_2_8_migration),
+ VMSTATE_UINT64_TEST(mig_io_win_addr, sPAPRPHBState, pre_2_8_migration),
+ VMSTATE_UINT64_TEST(mig_io_win_size, sPAPRPHBState, pre_2_8_migration),
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
VMSTATE_INT32(msi_devs_num, sPAPRPHBState),
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 1f2f2d33dd..5a5a4e946a 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -406,11 +406,9 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
/* Data out. */
qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
s->rregs[ESP_FIFO] = 0;
- esp_raise_irq(s);
} else if (s->ti_rptr < s->ti_wptr) {
s->ti_size--;
s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
- esp_raise_irq(s);
}
if (s->ti_rptr == s->ti_wptr) {
s->ti_rptr = 0;
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 52a41239cf..67fc1e7893 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -300,12 +300,6 @@ unmap:
return iov_count - i;
}
-static void megasas_unmap_sgl(MegasasCmd *cmd)
-{
- qemu_sglist_destroy(&cmd->qsg);
- cmd->iov_offset = 0;
-}
-
/*
* passthrough sense and io sense are at the same offset
*/
@@ -461,9 +455,12 @@ static void megasas_unmap_frame(MegasasState *s, MegasasCmd *cmd)
{
PCIDevice *p = PCI_DEVICE(s);
- pci_dma_unmap(p, cmd->frame, cmd->pa_size, 0, 0);
+ if (cmd->pa_size) {
+ pci_dma_unmap(p, cmd->frame, cmd->pa_size, 0, 0);
+ }
cmd->frame = NULL;
cmd->pa = 0;
+ cmd->pa_size = 0;
clear_bit(cmd->index, s->frame_map);
}
@@ -577,6 +574,20 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context)
}
}
+static void megasas_complete_command(MegasasCmd *cmd)
+{
+ qemu_sglist_destroy(&cmd->qsg);
+ cmd->iov_size = 0;
+ cmd->iov_offset = 0;
+
+ cmd->req->hba_private = NULL;
+ scsi_req_unref(cmd->req);
+ cmd->req = NULL;
+
+ megasas_unmap_frame(cmd->state, cmd);
+ megasas_complete_frame(cmd->state, cmd->context);
+}
+
static void megasas_reset_frames(MegasasState *s)
{
int i;
@@ -593,9 +604,9 @@ static void megasas_reset_frames(MegasasState *s)
static void megasas_abort_command(MegasasCmd *cmd)
{
- if (cmd->req) {
+ /* Never abort internal commands. */
+ if (cmd->req != NULL) {
scsi_req_cancel(cmd->req);
- cmd->req = NULL;
}
}
@@ -686,9 +697,6 @@ static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size)
{
trace_megasas_finish_dcmd(cmd->index, iov_size);
- if (cmd->frame->header.sge_count) {
- qemu_sglist_destroy(&cmd->qsg);
- }
if (iov_size > cmd->iov_size) {
if (megasas_frame_is_ieee_sgl(cmd)) {
cmd->frame->dcmd.sgl.sg_skinny->len = cpu_to_le32(iov_size);
@@ -698,7 +706,6 @@ static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size)
cmd->frame->dcmd.sgl.sg32->len = cpu_to_le32(iov_size);
}
}
- cmd->iov_size = 0;
}
static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
@@ -1586,7 +1593,6 @@ static int megasas_finish_internal_dcmd(MegasasCmd *cmd,
int lun = req->lun;
opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
- scsi_req_unref(req);
trace_megasas_dcmd_internal_finish(cmd->index, opcode, lun);
switch (opcode) {
case MFI_DCMD_PD_GET_INFO:
@@ -1857,7 +1863,11 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
trace_megasas_command_complete(cmd->index, status, resid);
- if (cmd->req != req) {
+ if (req->io_canceled) {
+ return;
+ }
+
+ if (cmd->req == NULL) {
/*
* Internal command complete
*/
@@ -1876,25 +1886,21 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
megasas_copy_sense(cmd);
}
- megasas_unmap_sgl(cmd);
cmd->frame->header.scsi_status = req->status;
- scsi_req_unref(cmd->req);
- cmd->req = NULL;
}
cmd->frame->header.cmd_status = cmd_status;
- megasas_unmap_frame(cmd->state, cmd);
- megasas_complete_frame(cmd->state, cmd->context);
+ megasas_complete_command(cmd);
}
-static void megasas_command_cancel(SCSIRequest *req)
+static void megasas_command_cancelled(SCSIRequest *req)
{
MegasasCmd *cmd = req->hba_private;
- if (cmd) {
- megasas_abort_command(cmd);
- } else {
- scsi_req_unref(req);
+ if (!cmd) {
+ return;
}
+ cmd->frame->header.cmd_status = MFI_STAT_SCSI_IO_FAILED;
+ megasas_complete_command(cmd);
}
static int megasas_handle_abort(MegasasState *s, MegasasCmd *cmd)
@@ -2313,7 +2319,7 @@ static const struct SCSIBusInfo megasas_scsi_info = {
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
- .cancel = megasas_command_cancel,
+ .cancel = megasas_command_cancelled,
};
static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index b573df53b0..6eb5fe80dc 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -401,7 +401,7 @@ static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
int access_type, int mmu_idx)
{
#if defined(CONFIG_USER_ONLY)
- return g2h(vaddr);
+ return g2h(addr);
#else
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
CPUTLBEntry *tlbentry = &env->tlb_table[mmu_idx][index];
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 67a1a9e786..4b74130559 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -395,6 +395,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "Opteron_G3" "-" TYPE_X86_CPU,\
.property = "stepping",\
.value = "1",\
+ },\
+ {\
+ .driver = "isa-pcspk",\
+ .property = "migrate",\
+ .value = "off",\
},
#define PC_COMPAT_2_6 \
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
index b92c1b59f1..092294ed5a 100644
--- a/include/hw/pci-host/spapr.h
+++ b/include/hw/pci-host/spapr.h
@@ -79,6 +79,12 @@ struct sPAPRPHBState {
uint64_t dma64_win_addr;
uint32_t numa_node;
+
+ /* Fields for migration compatibility hacks */
+ bool pre_2_8_migration;
+ uint32_t mig_liobn;
+ hwaddr mig_mem_win_addr, mig_mem_win_size;
+ hwaddr mig_io_win_addr, mig_io_win_size;
};
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h
index 6a06da32e6..355a34411f 100644
--- a/include/hw/ppc/spapr_ovec.h
+++ b/include/hw/ppc/spapr_ovec.h
@@ -37,6 +37,7 @@
#define _SPAPR_OVEC_H
#include "cpu.h"
+#include "migration/vmstate.h"
typedef struct sPAPROptionVector sPAPROptionVector;
@@ -64,4 +65,7 @@ sPAPROptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector);
int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
sPAPROptionVector *ov, const char *name);
+/* migration */
+extern const VMStateDescription vmstate_spapr_ovec;
+
#endif /* !defined (_SPAPR_OVEC_H) */
diff --git a/include/migration/cpu.h b/include/migration/cpu.h
index f3abbab650..f3d5dfcf61 100644
--- a/include/migration/cpu.h
+++ b/include/migration/cpu.h
@@ -18,6 +18,8 @@
VMSTATE_UINT64_EQUAL_V(_f, _s, _v)
#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)
+#define VMSTATE_UINTTL_TEST(_f, _s, _t) \
+ VMSTATE_UINT64_TEST(_f, _s, _t)
#define vmstate_info_uinttl vmstate_info_uint64
#else
#define qemu_put_betl qemu_put_be32
@@ -35,6 +37,8 @@
VMSTATE_UINT32_EQUAL_V(_f, _s, _v)
#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)
+#define VMSTATE_UINTTL_TEST(_f, _s, _t) \
+ VMSTATE_UINT32_TEST(_f, _s, _t)
#define vmstate_info_uinttl vmstate_info_uint32
#endif
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 9847e7b30f..95f1167261 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index adc7b8abeb..675968ea62 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 1a7059bf6a..d4b95326fe 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/roms/openbios b/roms/openbios
-Subproject 1dc4f162efc0f00a36126cab8e7b906335f6b70
+Subproject ef8a14e8afb47635c9c5f7524a52c3251827e29
diff --git a/rules.mak b/rules.mak
index 0333ae3c95..545ebd9c68 100644
--- a/rules.mak
+++ b/rules.mak
@@ -93,7 +93,7 @@ module-common.o: CFLAGS += $(DSO_OBJ_CFLAGS)
$(if $(findstring /,$@),$(call quiet-command,cp $@ $(subst /,-,$@),"CP","$(subst /,-,$@)"))
-LD_REL := $(CC) -nostdlib -Wl,-r $(LD_REL_FLAGS)
+LD_REL := $(CC) -nostdlib -r $(LD_REL_FLAGS)
%.mo:
$(call quiet-command,$(LD_REL) -o $@ $^,"LD","$(TARGET_DIR)$@")
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 6eec5dc86d..de1f30eeda 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2001,7 +2001,6 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
Error **errp)
{
char *featurestr; /* Single 'key=value" string being parsed */
- Error *local_err = NULL;
static bool cpu_globals_initialized;
bool ambiguous = false;
@@ -2015,7 +2014,7 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
}
for (featurestr = strtok(features, ",");
- featurestr && !local_err;
+ featurestr;
featurestr = strtok(NULL, ",")) {
const char *name;
const char *val = NULL;
@@ -2086,10 +2085,6 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
error_report("warning: Compatibility of ambiguous CPU model "
"strings won't be kept on future QEMU versions");
}
-
- if (local_err) {
- error_propagate(errp, local_err);
- }
}
static void x86_cpu_load_features(X86CPU *cpu, Error **errp);
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 9ad974f86a..d6ed883882 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1186,7 +1186,7 @@ DISAS_INSN(mulw)
SRC_EA(env, src, OS_WORD, sign, NULL);
tcg_gen_mul_i32(tmp, tmp, src);
tcg_gen_mov_i32(reg, tmp);
- gen_logic_cc(s, tmp, OS_WORD);
+ gen_logic_cc(s, tmp, OS_LONG);
}
DISAS_INSN(divw)
@@ -2170,7 +2170,7 @@ DISAS_INSN(cmpa)
}
SRC_EA(env, src, opsize, 1, NULL);
reg = AREG(insn, 9);
- gen_update_cc_cmp(s, reg, src, opsize);
+ gen_update_cc_cmp(s, reg, src, OS_LONG);
}
DISAS_INSN(eor)
@@ -2198,13 +2198,13 @@ static void do_exg(TCGv reg1, TCGv reg2)
tcg_temp_free(temp);
}
-DISAS_INSN(exg_aa)
+DISAS_INSN(exg_dd)
{
/* exchange Dx and Dy */
do_exg(DREG(insn, 9), DREG(insn, 0));
}
-DISAS_INSN(exg_dd)
+DISAS_INSN(exg_aa)
{
/* exchange Ax and Ay */
do_exg(AREG(insn, 9), AREG(insn, 0));
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 1c90adb5d7..2a50c43689 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1166,6 +1166,13 @@ struct PowerPCCPU {
int cpu_dt_id;
uint32_t max_compat;
uint32_t cpu_version;
+
+ /* Fields related to migration compatibility hacks */
+ bool pre_2_8_migration;
+ target_ulong mig_msr_mask;
+ uint64_t mig_insns_flags;
+ uint64_t mig_insns_flags2;
+ uint32_t mig_nb_BATs;
};
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h
index bb9ce60436..62138163a5 100644
--- a/target-ppc/helper_regs.h
+++ b/target-ppc/helper_regs.h
@@ -131,11 +131,14 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
}
/* If PR=1 then EE, IR and DR must be 1
*
- * Note: We only enforce this on 64-bit processors. It appears that
- * 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS
- * exploits it.
+ * Note: We only enforce this on 64-bit server processors.
+ * It appears that:
+ * - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS
+ * exploits it.
+ * - 64-bit embedded implementations do not need any operation to be
+ * performed when PR is set.
*/
- if ((env->insns_flags & PPC_64B) && ((value >> MSR_PR) & 1)) {
+ if ((env->insns_flags & PPC_SEGMENT_64B) && ((value >> MSR_PR) & 1)) {
value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR);
}
#endif
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index 9ac204a393..2d57c9a1c2 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -2572,7 +2572,7 @@ static int bcd_cmp_zero(ppc_avr_t *bcd)
static uint16_t get_national_digit(ppc_avr_t *reg, int n)
{
#if defined(HOST_WORDS_BIGENDIAN)
- return reg->u16[8 - n];
+ return reg->u16[7 - n];
#else
return reg->u16[n];
#endif
@@ -2581,7 +2581,7 @@ static uint16_t get_national_digit(ppc_avr_t *reg, int n)
static void set_national_digit(ppc_avr_t *reg, uint8_t val, int n)
{
#if defined(HOST_WORDS_BIGENDIAN)
- reg->u16[8 - n] = val;
+ reg->u16[7 - n] = val;
#else
reg->u16[n] = val;
#endif
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index e43cb6c39d..18c16d2512 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -135,11 +135,33 @@ static const VMStateInfo vmstate_info_avr = {
#define VMSTATE_AVR_ARRAY(_f, _s, _n) \
VMSTATE_AVR_ARRAY_V(_f, _s, _n, 0)
+static bool cpu_pre_2_8_migration(void *opaque, int version_id)
+{
+ PowerPCCPU *cpu = opaque;
+
+ return cpu->pre_2_8_migration;
+}
+
static void cpu_pre_save(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
int i;
+ uint64_t insns_compat_mask =
+ PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB
+ | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES
+ | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES
+ | PPC_FLOAT_STFIWX | PPC_FLOAT_EXT
+ | PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ
+ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC
+ | PPC_64B | PPC_64BX | PPC_ALTIVEC
+ | PPC_SEGMENT_64B | PPC_SLBI | PPC_POPCNTB | PPC_POPCNTWD;
+ uint64_t insns_compat_mask2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX
+ | PPC2_PERM_ISA206 | PPC2_DIVE_ISA206
+ | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206
+ | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207
+ | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207
+ | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | PPC2_TM;
env->spr[SPR_LR] = env->lr;
env->spr[SPR_CTR] = env->ctr;
@@ -161,6 +183,14 @@ static void cpu_pre_save(void *opaque)
env->spr[SPR_IBAT4U + 2*i] = env->IBAT[0][i+4];
env->spr[SPR_IBAT4U + 2*i + 1] = env->IBAT[1][i+4];
}
+
+ /* Hacks for migration compatibility between 2.6, 2.7 & 2.8 */
+ if (cpu->pre_2_8_migration) {
+ cpu->mig_msr_mask = env->msr_mask;
+ cpu->mig_insns_flags = env->insns_flags & insns_compat_mask;
+ cpu->mig_insns_flags2 = env->insns_flags2 & insns_compat_mask2;
+ cpu->mig_nb_BATs = env->nb_BATs;
+ }
}
static int cpu_post_load(void *opaque, int version_id)
@@ -561,10 +591,11 @@ const VMStateDescription vmstate_ppc_cpu = {
/* FIXME: access_type? */
/* Sanity checking */
- VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU),
- VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU),
- VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU),
- VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU),
+ VMSTATE_UINTTL_TEST(mig_msr_mask, PowerPCCPU, cpu_pre_2_8_migration),
+ VMSTATE_UINT64_TEST(mig_insns_flags, PowerPCCPU, cpu_pre_2_8_migration),
+ VMSTATE_UINT64_TEST(mig_insns_flags2, PowerPCCPU,
+ cpu_pre_2_8_migration),
+ VMSTATE_UINT32_TEST(mig_nb_BATs, PowerPCCPU, cpu_pre_2_8_migration),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 208fa1ea53..626e03186c 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -10520,6 +10520,11 @@ static gchar *ppc_gdb_arch_name(CPUState *cs)
#endif
}
+static Property ppc_cpu_properties[] = {
+ DEFINE_PROP_BOOL("pre-2.8-migration", PowerPCCPU, pre_2_8_migration, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void ppc_cpu_class_init(ObjectClass *oc, void *data)
{
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -10532,6 +10537,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_always;
dc->realize = ppc_cpu_realizefn;
dc->unrealize = ppc_cpu_unrealizefn;
+ dc->props = ppc_cpu_properties;
pcc->parent_reset = cc->reset;
cc->reset = ppc_cpu_reset;
diff --git a/tests/postcopy-test.c b/tests/postcopy-test.c
index d6613c5fa4..dafe8beba4 100644
--- a/tests/postcopy-test.c
+++ b/tests/postcopy-test.c
@@ -380,17 +380,21 @@ static void test_migrate(void)
" -incoming %s",
tmpfs, bootpath, uri);
} else if (strcmp(arch, "ppc64") == 0) {
+ const char *accel;
+
+ /* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
+ accel = access("/sys/module/kvm_hv", F_OK) ? "tcg" : "kvm:tcg";
init_bootfile_ppc(bootpath);
- cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 256M"
+ cmd_src = g_strdup_printf("-machine accel=%s -m 256M"
" -name pcsource,debug-threads=on"
" -serial file:%s/src_serial"
" -drive file=%s,if=pflash,format=raw",
- tmpfs, bootpath);
- cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 256M"
+ accel, tmpfs, bootpath);
+ cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
" -name pcdest,debug-threads=on"
" -serial file:%s/dest_serial"
" -incoming %s",
- tmpfs, uri);
+ accel, tmpfs, uri);
} else {
g_assert_not_reached();
}
diff --git a/xen-hvm.c b/xen-hvm.c
index 99b8ee8a4f..0892361cc2 100644
--- a/xen-hvm.c
+++ b/xen-hvm.c
@@ -995,6 +995,9 @@ static int handle_buffered_iopage(XenIOState *state)
}
memset(&req, 0x00, sizeof(req));
+ req.state = STATE_IOREQ_READY;
+ req.count = 1;
+ req.dir = IOREQ_WRITE;
for (;;) {
uint32_t rdptr = buf_page->read_pointer, wrptr;
@@ -1009,18 +1012,16 @@ static int handle_buffered_iopage(XenIOState *state)
break;
}
buf_req = &buf_page->buf_ioreq[rdptr % IOREQ_BUFFER_SLOT_NUM];
- req.size = 1UL << buf_req->size;
- req.count = 1;
+ req.size = 1U << buf_req->size;
req.addr = buf_req->addr;
req.data = buf_req->data;
- req.state = STATE_IOREQ_READY;
- req.dir = buf_req->dir;
- req.df = 1;
req.type = buf_req->type;
- req.data_is_ptr = 0;
xen_rmb();
qw = (req.size == 8);
if (qw) {
+ if (rdptr + 1 == wrptr) {
+ hw_error("Incomplete quad word buffered ioreq");
+ }
buf_req = &buf_page->buf_ioreq[(rdptr + 1) %
IOREQ_BUFFER_SLOT_NUM];
req.data |= ((uint64_t)buf_req->data) << 32;
@@ -1029,6 +1030,15 @@ static int handle_buffered_iopage(XenIOState *state)
handle_ioreq(state, &req);
+ /* Only req.data may get updated by handle_ioreq(), albeit even that
+ * should not happen as such data would never make it to the guest (we
+ * can only usefully see writes here after all).
+ */
+ assert(req.state == STATE_IOREQ_READY);
+ assert(req.count == 1);
+ assert(req.dir == IOREQ_WRITE);
+ assert(!req.data_is_ptr);
+
atomic_add(&buf_page->read_pointer, qw + 1);
}