diff options
30 files changed, 260 insertions, 44 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/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; 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/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 Binary files differindex 9847e7b30f..95f1167261 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex adc7b8abeb..675968ea62 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex 1a7059bf6a..d4b95326fe 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 diff --git a/roms/openbios b/roms/openbios -Subproject 1dc4f162efc0f00a36126cab8e7b906335f6b70 +Subproject ef8a14e8afb47635c9c5f7524a52c3251827e29 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(); } |