diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/9pfs/9p-handle.c | 9 | ||||
| -rw-r--r-- | hw/9pfs/9p-proxy.c | 13 | ||||
| -rw-r--r-- | hw/9pfs/9p.c | 10 | ||||
| -rw-r--r-- | hw/alpha/typhoon.c | 2 | ||||
| -rw-r--r-- | hw/arm/boot.c | 17 | ||||
| -rw-r--r-- | hw/block/xen_disk.c | 42 | ||||
| -rw-r--r-- | hw/char/spapr_vty.c | 2 | ||||
| -rw-r--r-- | hw/core/generic-loader.c | 7 | ||||
| -rw-r--r-- | hw/pci-host/uninorth.c | 4 | ||||
| -rw-r--r-- | hw/ppc/spapr.c | 76 | ||||
| -rw-r--r-- | hw/ppc/spapr_ovec.c | 12 | ||||
| -rw-r--r-- | hw/ppc/spapr_pci.c | 35 | ||||
| -rw-r--r-- | hw/scsi/esp.c | 2 |
13 files changed, 206 insertions, 25 deletions
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/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/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; |