diff options
Diffstat (limited to 'hw')
58 files changed, 1092 insertions, 222 deletions
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 138d8e825d..99e94723b9 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -979,6 +979,7 @@ static void coroutine_fn v9fs_attach(void *opaque) size_t offset = 7; V9fsQID qid; ssize_t err; + Error *local_err = NULL; v9fs_string_init(&uname); v9fs_string_init(&aname); @@ -1007,26 +1008,36 @@ static void coroutine_fn v9fs_attach(void *opaque) clunk_fid(s, fid); goto out; } - err = pdu_marshal(pdu, offset, "Q", &qid); - if (err < 0) { - clunk_fid(s, fid); - goto out; - } - err += offset; - memcpy(&s->root_qid, &qid, sizeof(qid)); - trace_v9fs_attach_return(pdu->tag, pdu->id, - qid.type, qid.version, qid.path); + /* * disable migration if we haven't done already. * attach could get called multiple times for the same export. */ if (!s->migration_blocker) { - s->root_fid = fid; error_setg(&s->migration_blocker, "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'", s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag); - migrate_add_blocker(s->migration_blocker); + err = migrate_add_blocker(s->migration_blocker, &local_err); + if (local_err) { + error_free(local_err); + error_free(s->migration_blocker); + s->migration_blocker = NULL; + clunk_fid(s, fid); + goto out; + } + s->root_fid = fid; + } + + err = pdu_marshal(pdu, offset, "Q", &qid); + if (err < 0) { + clunk_fid(s, fid); + goto out; } + err += offset; + + memcpy(&s->root_qid, &qid, sizeof(qid)); + trace_v9fs_attach_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path); out: put_fid(pdu, fidp); out_nofid: diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index e90451496e..2d6eb46a04 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -147,7 +147,7 @@ typedef struct FlashPartInfo { #define CFG_DUMMY_CLK_LEN 4 #define NVCFG_DUMMY_CLK_POS 12 #define VCFG_DUMMY_CLK_POS 4 -#define EVCFG_OUT_DRIVER_STRENGHT_DEF 7 +#define EVCFG_OUT_DRIVER_STRENGTH_DEF 7 #define EVCFG_VPP_ACCELERATOR (1 << 3) #define EVCFG_RESET_HOLD_ENABLED (1 << 4) #define NVCFG_DUAL_IO_MASK (1 << 2) @@ -747,7 +747,7 @@ static void reset_memory(Flash *s) ); s->enh_volatile_cfg = 0; - s->enh_volatile_cfg |= EVCFG_OUT_DRIVER_STRENGHT_DEF; + s->enh_volatile_cfg |= EVCFG_OUT_DRIVER_STRENGTH_DEF; s->enh_volatile_cfg |= EVCFG_VPP_ACCELERATOR; s->enh_volatile_cfg |= EVCFG_RESET_HOLD_ENABLED; if (s->nonvolatile_cfg & NVCFG_DUAL_IO_MASK) { diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index 208f549dff..58f1f02902 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -27,7 +27,7 @@ * this it needs a backend to manage the datas, the same as other * memory-related devices. In this case as the backend is so trivial we * have merged it with the frontend instead of creating and maintaining a - * seperate backend. + * separate backend. */ #include "qemu/osdep.h" @@ -79,7 +79,7 @@ static void generic_loader_realize(DeviceState *dev, Error **errp) "loading memory values"); return; } else if (!s->data_len) { - /* We cant' check for !data here as a value of 0 is still valid. */ + /* We can't check for !data here as a value of 0 is still valid. */ error_setg(errp, "Both data and data-len must be specified"); return; } else if (s->data_len > 8) { diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 2a82768067..6ab4265eb4 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -711,7 +711,7 @@ static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name, /* * Catch "invalid" device reference from vfio-pci and allow the - * default buffer representing the non-existant device to be used. + * default buffer representing the non-existent device to be used. */ if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) { rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d", diff --git a/hw/display/framebuffer.c b/hw/display/framebuffer.c index df51358e72..25aa46c8c7 100644 --- a/hw/display/framebuffer.c +++ b/hw/display/framebuffer.c @@ -78,7 +78,7 @@ void framebuffer_update_display( i = *first_row; *first_row = -1; - src_len = src_width * rows; + src_len = (hwaddr)src_width * rows; mem = mem_section->mr; if (!mem) { diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c index 5c666f9b24..920374b985 100644 --- a/hw/display/milkymist-tmu2.c +++ b/hw/display/milkymist-tmu2.c @@ -257,7 +257,7 @@ static void tmu2_start(MilkymistTMU2State *s) glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f); /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */ - fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES]; + fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES]; fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0); if (fb == NULL) { glDeleteTextures(1, &texture); diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 7a15c61c76..444ca064c1 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1003,7 +1003,8 @@ static const VMStateDescription vmstate_virtio_gpu_scanouts = { }, }; -static void virtio_gpu_save(QEMUFile *f, void *opaque, size_t size) +static int virtio_gpu_save(QEMUFile *f, void *opaque, size_t size, + VMStateField *field, QJSON *vmdesc) { VirtIOGPU *g = opaque; struct virtio_gpu_simple_resource *res; @@ -1028,9 +1029,12 @@ static void virtio_gpu_save(QEMUFile *f, void *opaque, size_t size) qemu_put_be32(f, 0); /* end of list */ vmstate_save_state(f, &vmstate_virtio_gpu_scanouts, g, NULL); + + return 0; } -static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size) +static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, + VMStateField *field) { VirtIOGPU *g = opaque; struct virtio_gpu_simple_resource *res; @@ -1132,6 +1136,7 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(qdev); VirtIOGPU *g = VIRTIO_GPU(qdev); bool have_virgl; + Error *local_err = NULL; int i; if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { @@ -1139,14 +1144,6 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) return; } - g->config_size = sizeof(struct virtio_gpu_config); - g->virtio_config.num_scanouts = g->conf.max_outputs; - virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, - g->config_size); - - g->req_state[0].width = 1024; - g->req_state[0].height = 768; - g->use_virgl_renderer = false; #if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN) have_virgl = false; @@ -1158,6 +1155,24 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) } if (virtio_gpu_virgl_enabled(g->conf)) { + error_setg(&g->migration_blocker, "virgl is not yet migratable"); + migrate_add_blocker(g->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(g->migration_blocker); + return; + } + } + + g->config_size = sizeof(struct virtio_gpu_config); + g->virtio_config.num_scanouts = g->conf.max_outputs; + virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, + g->config_size); + + g->req_state[0].width = 1024; + g->req_state[0].height = 768; + + if (virtio_gpu_virgl_enabled(g->conf)) { /* use larger control queue in 3d mode */ g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb); g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb); @@ -1183,11 +1198,6 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) dpy_gfx_replace_surface(g->scanout[i].con, NULL); } } - - if (virtio_gpu_virgl_enabled(g->conf)) { - error_setg(&g->migration_blocker, "virgl is not yet migratable"); - migrate_add_blocker(g->migration_blocker); - } } static void virtio_gpu_device_unrealize(DeviceState *qdev, Error **errp) diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index f43eb09304..f7b7b80c68 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -555,7 +555,7 @@ static void xlnx_dp_recreate_surface(XlnxDPState *s) if ((width != 0) && (height != 0)) { /* * As dpy_gfx_replace_surface calls qemu_free_displaysurface on the - * surface we need to be carefull and don't free the surface associated + * surface we need to be careful and don't free the surface associated * to the console or double free will happen. */ if (s->bout_plane.surface != current_console_surface) { @@ -1160,7 +1160,7 @@ static void xlnx_dp_update_display(void *opaque) */ if (!xlnx_dpdma_start_operation(s->dpdma, 3, false)) { /* - * An error occured don't do anything with the data.. + * An error occurred don't do anything with the data.. * Trigger an underflow interrupt. */ s->core_registers[DP_INT_STATUS] |= (1 << 21); diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index 2f767b620e..702e281dc8 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -535,7 +535,6 @@ static int patch_hypercalls(VAPICROMState *s) uint8_t alternates[2]; const uint8_t *pattern; const uint8_t *patch; - int patches = 0; off_t pos; uint8_t *rom; @@ -566,11 +565,6 @@ static int patch_hypercalls(VAPICROMState *s) } g_free(rom); - - if (patches != 0 && patches != 2) { - return -1; - } - return 0; } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index c949cf0ecc..706e2330ac 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1777,7 +1777,7 @@ static int pc_apic_cmp(const void *a, const void *b) /* returns pointer to CPUArchId descriptor that matches CPU's apic_id * in pcms->possible_cpus->cpus, if pcms->possible_cpus->cpus has no - * entry correponding to CPU's apic_id returns NULL. + * entry corresponding to CPU's apic_id returns NULL. */ static CPUArchId *pc_find_cpu_slot(PCMachineState *pcms, CPUState *cpu, int *idx) diff --git a/hw/i386/pci-assign-load-rom.c b/hw/i386/pci-assign-load-rom.c index 0d8e4b2826..fd59076e7a 100644 --- a/hw/i386/pci-assign-load-rom.c +++ b/hw/i386/pci-assign-load-rom.c @@ -39,19 +39,19 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev, struct Object *owner, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom", domain, bus, slot, function); - if (stat(rom_file, &st)) { - if (errno != ENOENT) { - error_report("pci-assign: Invalid ROM."); - } - return NULL; - } - /* Write "1" to the ROM file to enable it */ fp = fopen(rom_file, "r+"); if (fp == NULL) { - error_report("pci-assign: Cannot open %s: %s", rom_file, strerror(errno)); + if (errno != ENOENT) { + error_report("pci-assign: Cannot open %s: %s", rom_file, strerror(errno)); + } return NULL; } + if (fstat(fileno(fp), &st) == -1) { + error_report("pci-assign: Cannot stat %s: %s", rom_file, strerror(errno)); + goto close_rom; + } + val = 1; if (fwrite(&val, 1, 1, fp) != 1) { goto close_rom; diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 2f44a2da26..8948106ac4 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -41,3 +41,4 @@ obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o obj-$(CONFIG_ASPEED_SOC) += aspeed_vic.o obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o obj-$(CONFIG_MIPS_CPS) += mips_gic.o +obj-$(CONFIG_NIOS2) += nios2_iic.o diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 11729ee902..ec952ece93 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -510,6 +510,17 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) return; } + if (!kvm_arm_gic_can_save_restore(s)) { + error_setg(&s->migration_blocker, "This operating system kernel does " + "not support vGICv2 migration"); + migrate_add_blocker(s->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(s->migration_blocker); + return; + } + } + gic_init_irqs_and_mmio(s, kvm_arm_gicv2_set_irq, NULL); for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) { @@ -558,12 +569,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) KVM_VGIC_V2_ADDR_TYPE_CPU, s->dev_fd); - if (!kvm_arm_gic_can_save_restore(s)) { - error_setg(&s->migration_blocker, "This operating system kernel does " - "not support vGICv2 migration"); - migrate_add_blocker(s->migration_blocker); - } - if (kvm_has_gsi_routing()) { /* set up irq routing */ kvm_init_irq_routing(kvm_state); diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index fc246e0cb5..bd4f3aafc6 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -56,6 +56,19 @@ static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid) static void kvm_arm_its_realize(DeviceState *dev, Error **errp) { GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + Error *local_err = NULL; + + /* + * Block migration of a KVM GICv3 ITS device: the API for saving and + * restoring the state in the kernel is not yet available + */ + error_setg(&s->migration_blocker, "vITS migration is not implemented"); + migrate_add_blocker(s->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(s->migration_blocker); + return; + } s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false); if (s->dev_fd < 0) { @@ -73,13 +86,6 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) gicv3_its_init_mmio(s, NULL); - /* - * Block migration of a KVM GICv3 ITS device: the API for saving and - * restoring the state in the kernel is not yet available - */ - error_setg(&s->migration_blocker, "vITS migration is not implemented"); - migrate_add_blocker(s->migration_blocker); - kvm_msi_use_devid = true; kvm_gsi_direct_mapping = false; kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 199a439ccf..d69dc47370 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -103,6 +103,18 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL); + /* Block migration of a KVM GICv3 device: the API for saving and restoring + * the state in the kernel is not yet finalised in the kernel or + * implemented in QEMU. + */ + error_setg(&s->migration_blocker, "vGICv3 migration is not implemented"); + migrate_add_blocker(s->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(s->migration_blocker); + return; + } + /* Try to create the device via the device control API */ s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false); if (s->dev_fd < 0) { @@ -122,13 +134,6 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd); - /* Block migration of a KVM GICv3 device: the API for saving and restoring - * the state in the kernel is not yet finalised in the kernel or - * implemented in QEMU. - */ - error_setg(&s->migration_blocker, "vGICv3 migration is not implemented"); - migrate_add_blocker(s->migration_blocker); - if (kvm_has_gsi_routing()) { /* set up irq routing */ kvm_init_irq_routing(kvm_state); diff --git a/hw/intc/nios2_iic.c b/hw/intc/nios2_iic.c new file mode 100644 index 0000000000..818ab1b315 --- /dev/null +++ b/hw/intc/nios2_iic.c @@ -0,0 +1,103 @@ +/* + * QEMU Altera Internal Interrupt Controller. + * + * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qapi/error.h" + +#include "hw/sysbus.h" +#include "cpu.h" + +#define TYPE_ALTERA_IIC "altera,iic" +#define ALTERA_IIC(obj) \ + OBJECT_CHECK(AlteraIIC, (obj), TYPE_ALTERA_IIC) + +typedef struct AlteraIIC { + SysBusDevice parent_obj; + void *cpu; + qemu_irq parent_irq; +} AlteraIIC; + +static void update_irq(AlteraIIC *pv) +{ + CPUNios2State *env = &((Nios2CPU *)(pv->cpu))->env; + + qemu_set_irq(pv->parent_irq, + env->regs[CR_IPENDING] & env->regs[CR_IENABLE]); +} + +static void irq_handler(void *opaque, int irq, int level) +{ + AlteraIIC *pv = opaque; + CPUNios2State *env = &((Nios2CPU *)(pv->cpu))->env; + + env->regs[CR_IPENDING] &= ~(1 << irq); + env->regs[CR_IPENDING] |= !!level << irq; + + update_irq(pv); +} + +static void altera_iic_init(Object *obj) +{ + AlteraIIC *pv = ALTERA_IIC(obj); + + qdev_init_gpio_in(DEVICE(pv), irq_handler, 32); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &pv->parent_irq); +} + +static Property altera_iic_properties[] = { + DEFINE_PROP_PTR("cpu", AlteraIIC, cpu), + DEFINE_PROP_END_OF_LIST(), +}; + +static void altera_iic_realize(DeviceState *dev, Error **errp) +{ + struct AlteraIIC *pv = ALTERA_IIC(dev); + + if (!pv->cpu) { + error_setg(errp, "altera,iic: CPU not connected"); + return; + } +} + +static void altera_iic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = altera_iic_properties; + /* Reason: pointer property "cpu" */ + dc->cannot_instantiate_with_device_add_yet = true; + dc->realize = altera_iic_realize; +} + +static TypeInfo altera_iic_info = { + .name = "altera,iic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AlteraIIC), + .instance_init = altera_iic_init, + .class_init = altera_iic_class_init, +}; + +static void altera_iic_register(void) +{ + type_register_static(&altera_iic_info); +} + +type_init(altera_iic_register) diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index c313166fbe..da8e4dfab6 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -286,7 +286,8 @@ static void kvm_s390_release_adapter_routes(S390FLICState *fs, * increase until buffer is sufficient or maxium size is * reached */ -static void kvm_flic_save(QEMUFile *f, void *opaque, size_t size) +static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size, + VMStateField *field, QJSON *vmdesc) { KVMS390FLICState *flic = opaque; int len = FLIC_SAVE_INITIAL_SIZE; @@ -319,6 +320,8 @@ static void kvm_flic_save(QEMUFile *f, void *opaque, size_t size) count * sizeof(struct kvm_s390_irq)); } g_free(buf); + + return 0; } /** @@ -331,7 +334,8 @@ static void kvm_flic_save(QEMUFile *f, void *opaque, size_t size) * Note: Do nothing when no interrupts where stored * in QEMUFile */ -static int kvm_flic_load(QEMUFile *f, void *opaque, size_t size) +static int kvm_flic_load(QEMUFile *f, void *opaque, size_t size, + VMStateField *field) { uint64_t len = 0; uint64_t count = 0; diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 9d07b118c0..0ffbc8dd28 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -219,6 +219,7 @@ static void isabus_bridge_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "isa"; } diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index abeaf3da08..fd14d7a07e 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -840,6 +840,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) uint8_t *pci_conf; uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH; + Error *local_err = NULL; /* IRQFD requires MSI */ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) && @@ -903,9 +904,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) } } - vmstate_register_ram(s->ivshmem_bar2, DEVICE(s)); - pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2); - if (s->master == ON_OFF_AUTO_AUTO) { s->master = s->vm_id == 0 ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } @@ -913,8 +911,16 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) if (!ivshmem_is_master(s)) { error_setg(&s->migration_blocker, "Migration is disabled when using feature 'peer mode' in device 'ivshmem'"); - migrate_add_blocker(s->migration_blocker); + migrate_add_blocker(s->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(s->migration_blocker); + return; + } } + + vmstate_register_ram(s->ivshmem_bar2, DEVICE(s)); + pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2); } static void ivshmem_exit(PCIDevice *dev) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 7915732f74..e99d4544a2 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -896,7 +896,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size); - /* Find which queue we are targetting */ + /* Find which queue we are targeting */ q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize); while (bytes_to_copy) { diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index 77a4b3e5bf..0e9a25b7ab 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -593,7 +593,7 @@ static const VMStateDescription e1000e_vmstate = { .pre_save = e1000e_pre_save, .post_load = e1000e_post_load, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj, E1000EState), + VMSTATE_PCI_DEVICE(parent_obj, E1000EState), VMSTATE_MSIX(parent_obj, E1000EState), VMSTATE_UINT32(ioaddr, E1000EState), diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 01ecb02773..058908d8d7 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -105,7 +105,7 @@ typedef struct VIOsPAPRVLANDevice { uint32_t add_buf_ptr, use_buf_ptr, rx_bufs; hwaddr rxq_ptr; QEMUTimer *rxp_timer; - uint32_t compat_flags; /* Compatability flags for migration */ + uint32_t compat_flags; /* Compatibility flags for migration */ RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */ } VIOsPAPRVLANDevice; @@ -559,7 +559,7 @@ static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev, if (pool < 0) { /* * No matching pool found? Try to use a new one. If the guest used all - * pools before, but changed the size of one pool inbetween, we might + * pools before, but changed the size of one pool in the meantime, we might * need to recycle that pool here (if it's empty already). Thus scan * all buffer pools now, starting with the last (likely empty) one. */ diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 92f6af9620..2cb2731e29 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2451,7 +2451,8 @@ static void vmxnet3_put_tx_stats_to_file(QEMUFile *f, qemu_put_be64(f, tx_stat->pktsTxDiscard); } -static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { Vmxnet3TxqDescr *r = pv; @@ -2465,7 +2466,8 @@ static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size) return 0; } -static void vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { Vmxnet3TxqDescr *r = pv; @@ -2474,6 +2476,8 @@ static void vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size) qemu_put_byte(f, r->intr_idx); qemu_put_be64(f, r->tx_stats_pa); vmxnet3_put_tx_stats_to_file(f, &r->txq_stats); + + return 0; } static const VMStateInfo txq_descr_info = { @@ -2512,7 +2516,8 @@ static void vmxnet3_put_rx_stats_to_file(QEMUFile *f, qemu_put_be64(f, rx_stat->pktsRxError); } -static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { Vmxnet3RxqDescr *r = pv; int i; @@ -2530,7 +2535,8 @@ static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size) return 0; } -static void vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { Vmxnet3RxqDescr *r = pv; int i; @@ -2543,6 +2549,8 @@ static void vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size) qemu_put_byte(f, r->intr_idx); qemu_put_be64(f, r->rx_stats_pa); vmxnet3_put_rx_stats_to_file(f, &r->rxq_stats); + + return 0; } static int vmxnet3_post_load(void *opaque, int version_id) @@ -2575,7 +2583,8 @@ static const VMStateInfo rxq_descr_info = { .put = vmxnet3_put_rxq_descr }; -static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { Vmxnet3IntState *r = pv; @@ -2586,13 +2595,16 @@ static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size) return 0; } -static void vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { Vmxnet3IntState *r = pv; qemu_put_byte(f, r->is_masked); qemu_put_byte(f, r->is_pending); qemu_put_byte(f, r->is_asserted); + + return 0; } static const VMStateInfo int_state_info = { @@ -2619,7 +2631,7 @@ static const VMStateDescription vmstate_vmxnet3_pcie_device = { .minimum_version_id = 1, .needed = vmxnet3_vmstate_need_pcie_device, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj, VMXNET3State), + VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State), VMSTATE_END_OF_LIST() } }; diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c new file mode 100644 index 0000000000..62e5738b65 --- /dev/null +++ b/hw/nios2/10m50_devboard.c @@ -0,0 +1,126 @@ +/* + * Altera 10M50 Nios2 GHRD + * + * Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com> + * + * Based on LabX device code + * + * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/char/serial.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "qemu/config-file.h" + +#include "boot.h" + +#define BINARY_DEVICE_TREE_FILE "10m50-devboard.dtb" + +static void nios2_10m50_ghrd_init(MachineState *machine) +{ + Nios2CPU *cpu; + DeviceState *dev; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *phys_tcm = g_new(MemoryRegion, 1); + MemoryRegion *phys_tcm_alias = g_new(MemoryRegion, 1); + MemoryRegion *phys_ram = g_new(MemoryRegion, 1); + MemoryRegion *phys_ram_alias = g_new(MemoryRegion, 1); + ram_addr_t tcm_base = 0x0; + ram_addr_t tcm_size = 0x1000; /* 1 kiB, but QEMU limit is 4 kiB */ + ram_addr_t ram_base = 0x08000000; + ram_addr_t ram_size = 0x08000000; + qemu_irq *cpu_irq, irq[32]; + int i; + + /* Physical TCM (tb_ram_1k) with alias at 0xc0000000 */ + memory_region_init_ram(phys_tcm, NULL, "nios2.tcm", tcm_size, &error_abort); + memory_region_init_alias(phys_tcm_alias, NULL, "nios2.tcm.alias", + phys_tcm, 0, tcm_size); + vmstate_register_ram_global(phys_tcm); + memory_region_add_subregion(address_space_mem, tcm_base, phys_tcm); + memory_region_add_subregion(address_space_mem, 0xc0000000 + tcm_base, + phys_tcm_alias); + + /* Physical DRAM with alias at 0xc0000000 */ + memory_region_init_ram(phys_ram, NULL, "nios2.ram", ram_size, &error_abort); + memory_region_init_alias(phys_ram_alias, NULL, "nios2.ram.alias", + phys_ram, 0, ram_size); + vmstate_register_ram_global(phys_ram); + memory_region_add_subregion(address_space_mem, ram_base, phys_ram); + memory_region_add_subregion(address_space_mem, 0xc0000000 + ram_base, + phys_ram_alias); + + /* Create CPU -- FIXME */ + cpu = cpu_nios2_init("nios2"); + + /* Register: CPU interrupt controller (PIC) */ + cpu_irq = nios2_cpu_pic_init(cpu); + + /* Register: Internal Interrupt Controller (IIC) */ + dev = qdev_create(NULL, "altera,iic"); + qdev_prop_set_ptr(dev, "cpu", cpu); + qdev_init_nofail(dev); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(dev, i); + } + + /* Register: Altera 16550 UART */ + serial_mm_init(address_space_mem, 0xf8001600, 2, irq[1], 115200, + serial_hds[0], DEVICE_NATIVE_ENDIAN); + + /* Register: Timer sys_clk_timer */ + dev = qdev_create(NULL, "ALTR.timer"); + qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xf8001440); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[0]); + + /* Register: Timer sys_clk_timer_1 */ + dev = qdev_create(NULL, "ALTR.timer"); + qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xe0000880); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[5]); + + /* Configure new exception vectors and reset CPU for it to take effect. */ + cpu->reset_addr = 0xd4000000; + cpu->exception_addr = 0xc8000120; + cpu->fast_tlb_miss_addr = 0xc0000100; + + nios2_load_kernel(cpu, ram_base, ram_size, machine->initrd_filename, + BINARY_DEVICE_TREE_FILE, NULL); +} + +static void nios2_10m50_ghrd_machine_init(struct MachineClass *mc) +{ + mc->desc = "Altera 10M50 GHRD Nios II design"; + mc->init = nios2_10m50_ghrd_init; + mc->is_default = 1; +} + +DEFINE_MACHINE("10m50-ghrd", nios2_10m50_ghrd_machine_init); diff --git a/hw/nios2/Makefile.objs b/hw/nios2/Makefile.objs new file mode 100644 index 0000000000..6b5c421760 --- /dev/null +++ b/hw/nios2/Makefile.objs @@ -0,0 +1 @@ +obj-y = boot.o cpu_pic.o 10m50_devboard.o diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c new file mode 100644 index 0000000000..e0a9aff2f4 --- /dev/null +++ b/hw/nios2/boot.c @@ -0,0 +1,223 @@ +/* + * Nios2 kernel loader + * + * Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com> + * + * Based on microblaze kernel loader + * + * Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@petalogix.com> + * Copyright (c) 2012 PetaLogix + * Copyright (c) 2009 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" +#include "qemu/option.h" +#include "qemu/config-file.h" +#include "qemu/error-report.h" +#include "qemu-common.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "hw/loader.h" +#include "elf.h" +#include "qemu/cutils.h" + +#include "boot.h" + +#define NIOS2_MAGIC 0x534f494e + +static struct nios2_boot_info { + void (*machine_cpu_reset)(Nios2CPU *); + uint32_t bootstrap_pc; + uint32_t cmdline; + uint32_t initrd_start; + uint32_t initrd_end; + uint32_t fdt; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ + Nios2CPU *cpu = opaque; + CPUState *cs = CPU(cpu); + CPUNios2State *env = &cpu->env; + + cpu_reset(CPU(cpu)); + + env->regs[R_ARG0] = NIOS2_MAGIC; + env->regs[R_ARG1] = boot_info.initrd_start; + env->regs[R_ARG2] = boot_info.fdt; + env->regs[R_ARG3] = boot_info.cmdline; + + cpu_set_pc(cs, boot_info.bootstrap_pc); + if (boot_info.machine_cpu_reset) { + boot_info.machine_cpu_reset(cpu); + } +} + +static uint64_t translate_kernel_address(void *opaque, uint64_t addr) +{ + return addr - 0xc0000000LL; +} + +static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize, + const char *kernel_cmdline, const char *dtb_filename) +{ + int fdt_size; + void *fdt = NULL; + int r; + + if (dtb_filename) { + fdt = load_device_tree(dtb_filename, &fdt_size); + } + if (!fdt) { + return 0; + } + + if (kernel_cmdline) { + r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + kernel_cmdline); + if (r < 0) { + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + } + } + + if (bi.initrd_start) { + qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", + translate_kernel_address(NULL, bi.initrd_start)); + + qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", + translate_kernel_address(NULL, bi.initrd_end)); + } + + cpu_physical_memory_write(bi.fdt, fdt, fdt_size); + return fdt_size; +} + +void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base, + uint32_t ramsize, + const char *initrd_filename, + const char *dtb_filename, + void (*machine_cpu_reset)(Nios2CPU *)) +{ + QemuOpts *machine_opts; + const char *kernel_filename; + const char *kernel_cmdline; + const char *dtb_arg; + char *filename = NULL; + + machine_opts = qemu_get_machine_opts(); + kernel_filename = qemu_opt_get(machine_opts, "kernel"); + kernel_cmdline = qemu_opt_get(machine_opts, "append"); + dtb_arg = qemu_opt_get(machine_opts, "dtb"); + /* default to pcbios dtb as passed by machine_init */ + if (!dtb_arg) { + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename); + } + + boot_info.machine_cpu_reset = machine_cpu_reset; + qemu_register_reset(main_cpu_reset, cpu); + + if (kernel_filename) { + int kernel_size, fdt_size; + uint64_t entry, low, high; + uint32_t base32; + int big_endian = 0; + +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#endif + + /* Boots a kernel elf binary. */ + kernel_size = load_elf(kernel_filename, NULL, NULL, + &entry, &low, &high, + big_endian, EM_ALTERA_NIOS2, 0, 0); + base32 = entry; + if (base32 == 0xc0000000) { + kernel_size = load_elf(kernel_filename, translate_kernel_address, + NULL, &entry, NULL, NULL, + big_endian, EM_ALTERA_NIOS2, 0, 0); + } + + /* Always boot into physical ram. */ + boot_info.bootstrap_pc = ddr_base + 0xc0000000 + (entry & 0x07ffffff); + + /* If it wasn't an ELF image, try an u-boot image. */ + if (kernel_size < 0) { + hwaddr uentry, loadaddr; + + kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0, + NULL, NULL); + boot_info.bootstrap_pc = uentry; + high = loadaddr + kernel_size; + } + + /* Not an ELF image nor an u-boot image, try a RAW image. */ + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, ddr_base, + ram_size); + boot_info.bootstrap_pc = ddr_base; + high = ddr_base + kernel_size; + } + + high = ROUND_UP(high, 1024 * 1024); + + /* If initrd is available, it goes after the kernel, aligned to 1M. */ + if (initrd_filename) { + int initrd_size; + uint32_t initrd_offset; + + boot_info.initrd_start = high; + initrd_offset = boot_info.initrd_start - ddr_base; + + initrd_size = load_ramdisk(initrd_filename, + boot_info.initrd_start, + ram_size - initrd_offset); + if (initrd_size < 0) { + initrd_size = load_image_targphys(initrd_filename, + boot_info.initrd_start, + ram_size - initrd_offset); + } + if (initrd_size < 0) { + error_report("qemu: could not load initrd '%s'", + initrd_filename); + exit(EXIT_FAILURE); + } + high += initrd_size; + } + high = ROUND_UP(high, 4); + boot_info.initrd_end = high; + + /* Device tree must be placed right after initrd (if available) */ + boot_info.fdt = high; + fdt_size = nios2_load_dtb(boot_info, ram_size, kernel_cmdline, + /* Preference a -dtb argument */ + dtb_arg ? dtb_arg : filename); + high += fdt_size; + + /* Kernel command is at the end, 4k aligned. */ + boot_info.cmdline = ROUND_UP(high, 4096); + if (kernel_cmdline && strlen(kernel_cmdline)) { + pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline); + } + } + g_free(filename); +} diff --git a/hw/nios2/boot.h b/hw/nios2/boot.h new file mode 100644 index 0000000000..3116753818 --- /dev/null +++ b/hw/nios2/boot.h @@ -0,0 +1,11 @@ +#ifndef NIOS2_BOOT_H +#define NIOS2_BOOT_H + +#include "hw/hw.h" +#include "cpu.h" + +void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base, uint32_t ramsize, + const char *initrd_filename, const char *dtb_filename, + void (*machine_cpu_reset)(Nios2CPU *)); + +#endif /* NIOS2_BOOT_H */ diff --git a/hw/nios2/cpu_pic.c b/hw/nios2/cpu_pic.c new file mode 100644 index 0000000000..0f95987ef3 --- /dev/null +++ b/hw/nios2/cpu_pic.c @@ -0,0 +1,70 @@ +/* + * Altera Nios2 CPU PIC + * + * Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" + +#include "qemu/config-file.h" + +#include "boot.h" + +static void nios2_pic_cpu_handler(void *opaque, int irq, int level) +{ + Nios2CPU *cpu = opaque; + CPUNios2State *env = &cpu->env; + CPUState *cs = CPU(cpu); + int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; + + if (type == CPU_INTERRUPT_HARD) { + env->irq_pending = level; + + if (level && (env->regs[CR_STATUS] & CR_STATUS_PIE)) { + env->irq_pending = 0; + cpu_interrupt(cs, type); + } else if (!level) { + env->irq_pending = 0; + cpu_reset_interrupt(cs, type); + } + } else { + if (level) { + cpu_interrupt(cs, type); + } else { + cpu_reset_interrupt(cs, type); + } + } +} + +void nios2_check_interrupts(CPUNios2State *env) +{ + Nios2CPU *cpu = nios2_env_get_cpu(env); + CPUState *cs = CPU(cpu); + + if (env->irq_pending) { + env->irq_pending = 0; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +qemu_irq *nios2_cpu_pic_init(Nios2CPU *cpu) +{ + return qemu_allocate_irqs(nios2_pic_cpu_handler, cpu, 2); +} diff --git a/hw/nvram/eeprom93xx.c b/hw/nvram/eeprom93xx.c index 2c16fc23df..848692abc0 100644 --- a/hw/nvram/eeprom93xx.c +++ b/hw/nvram/eeprom93xx.c @@ -94,18 +94,22 @@ struct _eeprom_t { This is a Big hack, but it is how the old state did it. */ -static int get_uint16_from_uint8(QEMUFile *f, void *pv, size_t size) +static int get_uint16_from_uint8(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { uint16_t *v = pv; *v = qemu_get_ubyte(f); return 0; } -static void put_unused(QEMUFile *f, void *pv, size_t size) +static int put_unused(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) { fprintf(stderr, "uint16_from_uint8 is used only for backwards compatibility.\n"); fprintf(stderr, "Never should be used to write a new state.\n"); exit(0); + + return 0; } static const VMStateInfo vmstate_hack_uint16_from_uint8 = { diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 523d585dcf..316fca9bc1 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -555,17 +555,21 @@ static void fw_cfg_reset(DeviceState *d) Or we broke compatibility in the state, or we can't use struct tm */ -static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size) +static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { uint32_t *v = pv; *v = qemu_get_be16(f); return 0; } -static void put_unused(QEMUFile *f, void *pv, size_t size) +static int put_unused(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) { fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n"); fprintf(stderr, "This functions shouldn't be called.\n"); + + return 0; } static const VMStateInfo vmstate_hack_uint32_as_uint16 = { diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index 84b7946c31..0eef87a4f8 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -180,7 +180,7 @@ static const VMStateDescription vmstate_ioh3420 = { .minimum_version_id = 1, .post_load = pcie_cap_slot_post_load, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), + VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log, PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog), VMSTATE_END_OF_LIST() diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index 04b8e5b847..cfe8a3657f 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -166,7 +166,7 @@ static const VMStateDescription vmstate_xio3130_downstream = { .minimum_version_id = 1, .post_load = pcie_cap_slot_post_load, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), + VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log, PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog), VMSTATE_END_OF_LIST() diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index d1f59c8834..401c78452b 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -138,7 +138,7 @@ static const VMStateDescription vmstate_xio3130_upstream = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj.parent_obj, PCIEPort), + VMSTATE_PCI_DEVICE(parent_obj.parent_obj, PCIEPort), VMSTATE_STRUCT(parent_obj.parent_obj.exp.aer_log, PCIEPort, 0, vmstate_pcie_aer_log, PCIEAERLog), VMSTATE_END_OF_LIST() diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 0ec1cb14fc..ee1714d2cf 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -587,12 +587,16 @@ void msix_unset_vector_notifiers(PCIDevice *dev) dev->msix_vector_poll_notifier = NULL; } -static void put_msix_state(QEMUFile *f, void *pv, size_t size) +static int put_msix_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { msix_save(pv, f); + + return 0; } -static int get_msix_state(QEMUFile *f, void *pv, size_t size) +static int get_msix_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { msix_load(pv, f); return 0; diff --git a/hw/pci/pci.c b/hw/pci/pci.c index fe9acecbbf..47ca3af69a 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -445,7 +445,8 @@ int pci_bus_numa_node(PCIBus *bus) return PCI_BUS_GET_CLASS(bus)->numa_node(bus); } -static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) +static int get_pci_config_device(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { PCIDevice *s = container_of(pv, PCIDevice, config); PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(s); @@ -484,11 +485,14 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) } /* just put buffer */ -static void put_pci_config_device(QEMUFile *f, void *pv, size_t size) +static int put_pci_config_device(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { const uint8_t **v = pv; assert(size == pci_config_size(container_of(pv, PCIDevice, config))); qemu_put_buffer(f, *v, size); + + return 0; } static VMStateInfo vmstate_info_pci_config = { @@ -497,7 +501,8 @@ static VMStateInfo vmstate_info_pci_config = { .put = put_pci_config_device, }; -static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) +static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { PCIDevice *s = container_of(pv, PCIDevice, irq_state); uint32_t irq_state[PCI_NUM_PINS]; @@ -518,7 +523,8 @@ static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) return 0; } -static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) +static int put_pci_irq_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { int i; PCIDevice *s = container_of(pv, PCIDevice, irq_state); @@ -526,6 +532,8 @@ static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) for (i = 0; i < PCI_NUM_PINS; ++i) { qemu_put_be32(f, pci_irq_state(s, i)); } + + return 0; } static VMStateInfo vmstate_info_pci_irq_state = { @@ -534,30 +542,29 @@ static VMStateInfo vmstate_info_pci_irq_state = { .put = put_pci_irq_state, }; +static bool migrate_is_pcie(void *opaque, int version_id) +{ + return pci_is_express((PCIDevice *)opaque); +} + +static bool migrate_is_not_pcie(void *opaque, int version_id) +{ + return !pci_is_express((PCIDevice *)opaque); +} + const VMStateDescription vmstate_pci_device = { .name = "PCIDevice", .version_id = 2, .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice), - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, - vmstate_info_pci_config, + VMSTATE_BUFFER_UNSAFE_INFO_TEST(config, PCIDevice, + migrate_is_not_pcie, + 0, vmstate_info_pci_config, PCI_CONFIG_SPACE_SIZE), - VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, - vmstate_info_pci_irq_state, - PCI_NUM_PINS * sizeof(int32_t)), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_pcie_device = { - .name = "PCIEDevice", - .version_id = 2, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice), - VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, - vmstate_info_pci_config, + VMSTATE_BUFFER_UNSAFE_INFO_TEST(config, PCIDevice, + migrate_is_pcie, + 0, vmstate_info_pci_config, PCIE_CONFIG_SPACE_SIZE), VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, vmstate_info_pci_irq_state, @@ -566,10 +573,6 @@ const VMStateDescription vmstate_pcie_device = { } }; -static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s) -{ - return pci_is_express(s) ? &vmstate_pcie_device : &vmstate_pci_device; -} void pci_device_save(PCIDevice *s, QEMUFile *f) { @@ -578,7 +581,7 @@ void pci_device_save(PCIDevice *s, QEMUFile *f) * This makes us compatible with old devices * which never set or clear this bit. */ s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; - vmstate_save_state(f, pci_get_vmstate(s), s, NULL); + vmstate_save_state(f, &vmstate_pci_device, s, NULL); /* Restore the interrupt status bit. */ pci_update_irq_status(s); } @@ -586,7 +589,7 @@ void pci_device_save(PCIDevice *s, QEMUFile *f) int pci_device_load(PCIDevice *s, QEMUFile *f) { int ret; - ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); + ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id); /* Restore the interrupt status bit. */ pci_update_irq_status(s); return ret; diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index adeda04036..cbd4bb4f8c 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -656,7 +656,7 @@ static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) } /* - * caller must supply valid (offset, size) * such that the range shouldn't + * Caller must supply valid (offset, size) such that the range wouldn't * overlap with other capability or other registers. * This function doesn't check it. */ diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index 3dcd472eba..42fafac91b 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -695,13 +695,16 @@ void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) shpc_cap_update_dword(d); } -static void shpc_save(QEMUFile *f, void *pv, size_t size) +static int shpc_save(QEMUFile *f, void *pv, size_t size, VMStateField *field, + QJSON *vmdesc) { PCIDevice *d = container_of(pv, PCIDevice, shpc); qemu_put_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); + + return 0; } -static int shpc_load(QEMUFile *f, void *pv, size_t size) +static int shpc_load(QEMUFile *f, void *pv, size_t size, VMStateField *field) { PCIDevice *d = container_of(pv, PCIDevice, shpc); int ret = qemu_get_buffer(f, d->shpc->config, SHPC_SIZEOF(d)); diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index a0c44ee593..2de6377cca 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -59,7 +59,7 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc, trace_spapr_drc_set_isolation_state(get_index(drc), state); if (state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) { - /* cannot unisolate a non-existant resource, and, or resources + /* cannot unisolate a non-existent resource, and, or resources * which are in an 'UNUSABLE' allocation state. (PAPR 2.7, 13.5.3.5) */ if (!drc->dev || diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index b0adefa788..0aad9cc272 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -183,8 +183,8 @@ enum ZpciIoatDtype { * may enter an error state * blocked: ignore all DMA and interrupts; transition back to enabled or from * error state via mpcifc - * error: an error occured; transition back to enabled via mpcifc - * permanent error: an unrecoverable error occured; transition to standby via + * error: an error occurred; transition back to enabled via mpcifc + * permanent error: an unrecoverable error occurred; transition to standby via * sclp deconfigure */ typedef enum { diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 6233865494..6aad7c9a06 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2289,7 +2289,7 @@ static const VMStateDescription vmstate_megasas_gen2 = { .minimum_version_id = 0, .minimum_version_id_old = 0, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj, MegasasState), + VMSTATE_PCI_DEVICE(parent_obj, MegasasState), VMSTATE_MSIX(parent_obj, MegasasState), VMSTATE_INT32(fw_state, MegasasState), diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 297216dfcb..5940cb160c 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1945,7 +1945,8 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun) /* SCSI request list. For simplicity, pv points to the whole device */ -static void put_scsi_requests(QEMUFile *f, void *pv, size_t size) +static int put_scsi_requests(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { SCSIDevice *s = pv; SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus); @@ -1968,9 +1969,12 @@ static void put_scsi_requests(QEMUFile *f, void *pv, size_t size) } } qemu_put_sbyte(f, 0); + + return 0; } -static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) +static int get_scsi_requests(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { SCSIDevice *s = pv; SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index c080888413..cc06fe5f6c 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2157,6 +2157,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) DPRINTF("Write %s(sector %" PRId64 ", count %u)\n", (command & 0xe) == 0xe ? "And Verify " : "", r->req.cmd.lba, len); + /* fall through */ case VERIFY_10: case VERIFY_12: case VERIFY_16: diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 5b2694615f..c491ece1f2 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -238,8 +238,16 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) vhost_dummy_handle_output); if (err != NULL) { error_propagate(errp, err); - close(vhostfd); - return; + goto close_fd; + } + + error_setg(&s->migration_blocker, + "vhost-scsi does not support migration"); + migrate_add_blocker(s->migration_blocker, &err); + if (err) { + error_propagate(errp, err); + error_free(s->migration_blocker); + goto close_fd; } s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; @@ -252,7 +260,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) if (ret < 0) { error_setg(errp, "vhost-scsi: vhost initialization failed: %s", strerror(-ret)); - return; + goto free_vqs; } /* At present, channel and lun both are 0 for bootable vhost-scsi disk */ @@ -261,9 +269,14 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) /* Note: we can also get the minimum tpgt from kernel */ s->target = vs->conf.boot_tpgt; - error_setg(&s->migration_blocker, - "vhost-scsi does not support migration"); - migrate_add_blocker(s->migration_blocker); + return; + + free_vqs: + migrate_del_blocker(s->migration_blocker); + g_free(s->dev.vqs); + close_fd: + close(vhostfd); + return; } static void vhost_scsi_unrealize(DeviceState *dev, Error **errp) diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index a5ce7dea8e..75575461e2 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1207,7 +1207,7 @@ static const VMStateDescription vmstate_pvscsi_pcie_device = { .name = "pvscsi/pcie", .needed = pvscsi_vmstate_need_pcie_device, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj, PVSCSIState), + VMSTATE_PCI_DEVICE(parent_obj, PVSCSIState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index c1e93a3924..71994f2d88 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -18,6 +18,7 @@ common-obj-$(CONFIG_IMX) += imx_gpt.o common-obj-$(CONFIG_LM32) += lm32_timer.o common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o +obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o diff --git a/hw/timer/altera_timer.c b/hw/timer/altera_timer.c new file mode 100644 index 0000000000..6d4862661d --- /dev/null +++ b/hw/timer/altera_timer.c @@ -0,0 +1,237 @@ +/* + * QEMU model of the Altera timer. + * + * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qapi/error.h" + +#include "hw/sysbus.h" +#include "sysemu/sysemu.h" +#include "hw/ptimer.h" + +#define R_STATUS 0 +#define R_CONTROL 1 +#define R_PERIODL 2 +#define R_PERIODH 3 +#define R_SNAPL 4 +#define R_SNAPH 5 +#define R_MAX 6 + +#define STATUS_TO 0x0001 +#define STATUS_RUN 0x0002 + +#define CONTROL_ITO 0x0001 +#define CONTROL_CONT 0x0002 +#define CONTROL_START 0x0004 +#define CONTROL_STOP 0x0008 + +#define TYPE_ALTERA_TIMER "ALTR.timer" +#define ALTERA_TIMER(obj) \ + OBJECT_CHECK(AlteraTimer, (obj), TYPE_ALTERA_TIMER) + +typedef struct AlteraTimer { + SysBusDevice busdev; + MemoryRegion mmio; + qemu_irq irq; + uint32_t freq_hz; + QEMUBH *bh; + ptimer_state *ptimer; + uint32_t regs[R_MAX]; +} AlteraTimer; + +static int timer_irq_state(AlteraTimer *t) +{ + bool irq = (t->regs[R_STATUS] & STATUS_TO) && + (t->regs[R_CONTROL] & CONTROL_ITO); + return irq; +} + +static uint64_t timer_read(void *opaque, hwaddr addr, + unsigned int size) +{ + AlteraTimer *t = opaque; + uint64_t r = 0; + + addr >>= 2; + + switch (addr) { + case R_CONTROL: + r = t->regs[R_CONTROL] & (CONTROL_ITO | CONTROL_CONT); + break; + + default: + if (addr < ARRAY_SIZE(t->regs)) { + r = t->regs[addr]; + } + break; + } + + return r; +} + +static void timer_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + AlteraTimer *t = opaque; + uint64_t tvalue; + uint32_t count = 0; + int irqState = timer_irq_state(t); + + addr >>= 2; + + switch (addr) { + case R_STATUS: + /* The timeout bit is cleared by writing the status register. */ + t->regs[R_STATUS] &= ~STATUS_TO; + break; + + case R_CONTROL: + t->regs[R_CONTROL] = value & (CONTROL_ITO | CONTROL_CONT); + if ((value & CONTROL_START) && + !(t->regs[R_STATUS] & STATUS_RUN)) { + ptimer_run(t->ptimer, 1); + t->regs[R_STATUS] |= STATUS_RUN; + } + if ((value & CONTROL_STOP) && (t->regs[R_STATUS] & STATUS_RUN)) { + ptimer_stop(t->ptimer); + t->regs[R_STATUS] &= ~STATUS_RUN; + } + break; + + case R_PERIODL: + case R_PERIODH: + t->regs[addr] = value & 0xFFFF; + if (t->regs[R_STATUS] & STATUS_RUN) { + ptimer_stop(t->ptimer); + t->regs[R_STATUS] &= ~STATUS_RUN; + } + tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL]; + ptimer_set_limit(t->ptimer, tvalue + 1, 1); + break; + + case R_SNAPL: + case R_SNAPH: + count = ptimer_get_count(t->ptimer); + t->regs[R_SNAPL] = count & 0xFFFF; + t->regs[R_SNAPH] = count >> 16; + break; + + default: + break; + } + + if (irqState != timer_irq_state(t)) { + qemu_set_irq(t->irq, timer_irq_state(t)); + } +} + +static const MemoryRegionOps timer_ops = { + .read = timer_read, + .write = timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4 + } +}; + +static void timer_hit(void *opaque) +{ + AlteraTimer *t = opaque; + const uint64_t tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL]; + + t->regs[R_STATUS] |= STATUS_TO; + + ptimer_set_limit(t->ptimer, tvalue + 1, 1); + + if (!(t->regs[R_CONTROL] & CONTROL_CONT)) { + t->regs[R_STATUS] &= ~STATUS_RUN; + ptimer_set_count(t->ptimer, tvalue); + } else { + ptimer_run(t->ptimer, 1); + } + + qemu_set_irq(t->irq, timer_irq_state(t)); +} + +static void altera_timer_realize(DeviceState *dev, Error **errp) +{ + AlteraTimer *t = ALTERA_TIMER(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + if (t->freq_hz == 0) { + error_setg(errp, "\"clock-frequency\" property must be provided."); + return; + } + + t->bh = qemu_bh_new(timer_hit, t); + t->ptimer = ptimer_init(t->bh, PTIMER_POLICY_DEFAULT); + ptimer_set_freq(t->ptimer, t->freq_hz); + + memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, + TYPE_ALTERA_TIMER, R_MAX * sizeof(uint32_t)); + sysbus_init_mmio(sbd, &t->mmio); +} + +static void altera_timer_init(Object *obj) +{ + AlteraTimer *t = ALTERA_TIMER(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + sysbus_init_irq(sbd, &t->irq); +} + +static void altera_timer_reset(DeviceState *dev) +{ + AlteraTimer *t = ALTERA_TIMER(dev); + + ptimer_stop(t->ptimer); + ptimer_set_limit(t->ptimer, 0xffffffff, 1); + memset(t->regs, 0, ARRAY_SIZE(t->regs)); +} + +static Property altera_timer_properties[] = { + DEFINE_PROP_UINT32("clock-frequency", AlteraTimer, freq_hz, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void altera_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = altera_timer_realize; + dc->props = altera_timer_properties; + dc->reset = altera_timer_reset; +} + +static const TypeInfo altera_timer_info = { + .name = TYPE_ALTERA_TIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AlteraTimer), + .instance_init = altera_timer_init, + .class_init = altera_timer_class_init, +}; + +static void altera_timer_register(void) +{ + type_register_static(&altera_timer_info); +} + +type_init(altera_timer_register) diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c index b8d914e49b..c0aa8ae3de 100644 --- a/hw/timer/twl92230.c +++ b/hw/timer/twl92230.c @@ -749,17 +749,21 @@ static int menelaus_rx(I2CSlave *i2c) Or we broke compatibility in the state, or we can't use struct tm */ -static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size) +static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { int *v = pv; *v = qemu_get_be16(f); return 0; } -static void put_int32_as_uint16(QEMUFile *f, void *pv, size_t size) +static int put_int32_as_uint16(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { int *v = pv; qemu_put_be16(f, *v); + + return 0; } static const VMStateInfo vmstate_hack_int32_as_uint16 = { diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 25913ad488..1dcc35c8f8 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -8,6 +8,7 @@ #include "monitor/monitor.h" #include "trace.h" #include "qemu/cutils.h" +#include "migration/migration.h" static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); @@ -686,6 +687,8 @@ USBDevice *usbdevice_create(const char *cmdline) const char *params; int len; USBDevice *dev; + ObjectClass *klass; + DeviceClass *dc; params = strchr(cmdline,':'); if (params) { @@ -720,6 +723,22 @@ USBDevice *usbdevice_create(const char *cmdline) return NULL; } + klass = object_class_by_name(f->name); + if (klass == NULL) { + error_report("Device '%s' not found", f->name); + return NULL; + } + + dc = DEVICE_CLASS(klass); + + if (only_migratable) { + if (dc->vmsd->unmigratable) { + error_report("Device %s is not migratable, but --only-migratable " + "was specified", f->name); + return NULL; + } + } + if (f->usbdevice_init) { dev = f->usbdevice_init(bus, params); } else { diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 9cb0f50750..94c2e94f10 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -1093,7 +1093,7 @@ static MTPData *usb_mtp_get_object_prop_value(MTPState *s, MTPControl *c, } break; case PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER: - /* Should be persistant between sessions, + /* Should be persistent between sessions, * but using our objedt ID is "good enough" * for now */ usb_mtp_add_u64(d, 0x0000000000000000); @@ -1580,6 +1580,8 @@ static void usb_mtp_class_initfn(ObjectClass *klass, void *data) uc->handle_reset = usb_mtp_handle_reset; uc->handle_control = usb_mtp_handle_control; uc->handle_data = usb_mtp_handle_data; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->desc = "USB Media Transfer Protocol device"; dc->fw_name = "mtp"; dc->vmsd = &vmstate_usb_mtp; dc->props = mtp_properties; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 4acf0c6dd8..e0b516987f 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3894,7 +3894,7 @@ static const VMStateDescription vmstate_xhci = { .version_id = 1, .post_load = usb_xhci_post_load, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj, XHCIState), + VMSTATE_PCI_DEVICE(parent_obj, XHCIState), VMSTATE_MSIX(parent_obj, XHCIState), VMSTATE_STRUCT_VARRAY_UINT32(ports, XHCIState, numports, 1, diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index a65723781e..4a0ebbfb32 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2165,7 +2165,8 @@ static int usbredir_post_load(void *priv, int version_id) } /* For usbredirparser migration */ -static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) +static int usbredir_put_parser(QEMUFile *f, void *priv, size_t unused, + VMStateField *field, QJSON *vmdesc) { USBRedirDevice *dev = priv; uint8_t *data; @@ -2173,7 +2174,7 @@ static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) if (dev->parser == NULL) { qemu_put_be32(f, 0); - return; + return 0; } usbredirparser_serialize(dev->parser, &data, &len); @@ -2183,9 +2184,12 @@ static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) qemu_put_buffer(f, data, len); free(data); + + return 0; } -static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) +static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused, + VMStateField *field) { USBRedirDevice *dev = priv; uint8_t *data; @@ -2228,7 +2232,8 @@ static const VMStateInfo usbredir_parser_vmstate_info = { /* For buffered packets (iso/irq) queue migration */ -static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) +static int usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused, + VMStateField *field, QJSON *vmdesc) { struct endp_data *endp = priv; USBRedirDevice *dev = endp->dev; @@ -2246,9 +2251,12 @@ static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) i++; } assert(i == endp->bufpq_size); + + return 0; } -static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) +static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused, + VMStateField *field) { struct endp_data *endp = priv; USBRedirDevice *dev = endp->dev; @@ -2351,7 +2359,8 @@ static const VMStateDescription usbredir_ep_vmstate = { /* For PacketIdQueue migration */ -static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) +static int usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused, + VMStateField *field, QJSON *vmdesc) { struct PacketIdQueue *q = priv; USBRedirDevice *dev = q->dev; @@ -2365,9 +2374,12 @@ static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) remain--; } assert(remain == 0); + + return 0; } -static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) +static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused, + VMStateField *field) { struct PacketIdQueue *q = priv; USBRedirDevice *dev = q->dev; diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 811eecd1b4..6c771f778b 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1171,7 +1171,7 @@ static int vfio_pci_igd_host_init(VFIOPCIDevice *vdev, * IGD LPC/ISA bridge support code. The vBIOS needs this, but we can't write * arbitrary values into just any bridge, so we must create our own. We try * to handle if the user has created it for us, which they might want to do - * to enable multifuction so we don't occupy the whole PCI slot. + * to enable multifunction so we don't occupy the whole PCI slot. */ static void vfio_pci_igd_lpc_bridge_realize(PCIDevice *pdev, Error **errp) { diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index d7dbe0e3e0..882d3a91b6 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1881,8 +1881,8 @@ static void vfio_add_ext_cap(VFIOPCIDevice *vdev) * 0 is reserved for this since absence of capabilities is indicated by * 0 for the ID, version, AND next pointer. However, pcie_add_capability() * uses ID 0 as reserved for list management and will incorrectly match and - * assert if we attempt to pre-load the head of the chain with with this - * ID. Use ID 0xFFFF temporarily since it is also seems to be reserved in + * assert if we attempt to pre-load the head of the chain with this ID. + * Use ID 0xFFFF temporarily since it is also seems to be reserved in * part for identifying absence of capabilities in a root complex register * block. If the ID still exists after adding capabilities, switch back to * zero. We'll mark this entire first dword as emulated for this purpose. diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 9cacf557f2..b124d97d7c 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1176,6 +1176,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, { uint64_t features; int i, r, n_initialized_vqs = 0; + Error *local_err = NULL; hdev->vdev = NULL; hdev->migration_blocker = NULL; @@ -1256,7 +1257,12 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, } if (hdev->migration_blocker != NULL) { - migrate_add_blocker(hdev->migration_blocker); + r = migrate_add_blocker(hdev->migration_blocker, &local_err); + if (local_err) { + error_report_err(local_err); + error_free(hdev->migration_blocker); + goto fail_busyloop; + } } hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions)); diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index 296472fc6e..0353eb6d5d 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -786,7 +786,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) vcrypto->max_queues = MAX(vcrypto->cryptodev->conf.peers.queues, 1); if (vcrypto->max_queues + 1 > VIRTIO_QUEUE_MAX) { error_setg(errp, "Invalid number of queues (= %" PRIu32 "), " - "must be a postive integer less than %d.", + "must be a positive integer less than %d.", vcrypto->max_queues, VIRTIO_QUEUE_MAX); return; } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 09230c05df..b5af2a00f3 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -108,7 +108,8 @@ static bool virtio_pci_has_extra_state(DeviceState *d) return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA; } -static int get_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size) +static int get_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { VirtIOPCIProxy *proxy = pv; int i; @@ -137,7 +138,8 @@ static void virtio_pci_save_modern_queue_state(VirtIOPCIQueue *vq, qemu_put_be32(f, vq->used[1]); } -static void put_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size) +static int put_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { VirtIOPCIProxy *proxy = pv; int i; @@ -149,6 +151,8 @@ static void put_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size) for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { virtio_pci_save_modern_queue_state(&proxy->vqs[i], f); } + + return 0; } static const VMStateInfo vmstate_info_virtio_pci_modern_state = { diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index cc17b97899..f292a53940 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1555,7 +1555,8 @@ static const VMStateDescription vmstate_virtio_ringsize = { } }; -static int get_extra_state(QEMUFile *f, void *pv, size_t size) +static int get_extra_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { VirtIODevice *vdev = pv; BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); @@ -1568,13 +1569,15 @@ static int get_extra_state(QEMUFile *f, void *pv, size_t size) } } -static void put_extra_state(QEMUFile *f, void *pv, size_t size) +static int put_extra_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { VirtIODevice *vdev = pv; BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); k->save_extra_state(qbus->parent, f); + return 0; } static const VMStateInfo vmstate_info_extra_state = { @@ -1709,13 +1712,17 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) } /* A wrapper for use as a VMState .put function */ -static void virtio_device_put(QEMUFile *f, void *opaque, size_t size) +static int virtio_device_put(QEMUFile *f, void *opaque, size_t size, + VMStateField *field, QJSON *vmdesc) { virtio_save(VIRTIO_DEVICE(opaque), f); + + return 0; } /* A wrapper for use as a VMState .get function */ -static int virtio_device_get(QEMUFile *f, void *opaque, size_t size) +static int virtio_device_get(QEMUFile *f, void *opaque, size_t size, + VMStateField *field) { VirtIODevice *vdev = VIRTIO_DEVICE(opaque); DeviceClass *dc = DEVICE_CLASS(VIRTIO_DEVICE_GET_CLASS(vdev)); diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index 2bed64f15b..0e812d7f06 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -31,22 +31,6 @@ #include "qemu/log.h" #include "qemu/timer.h" -void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d) -{ - uint32_t old_ccount = env->sregs[CCOUNT] + 1; - - env->sregs[CCOUNT] += d; - - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { - int i; - for (i = 0; i < env->config->nccompare; ++i) { - if (env->sregs[CCOMPARE + i] - old_ccount < d) { - xtensa_timer_irq(env, i, 1); - } - } - } -} - void check_interrupts(CPUXtensaState *env) { CPUState *cs = CPU(xtensa_env_get_cpu(env)); @@ -54,17 +38,6 @@ void check_interrupts(CPUXtensaState *env) uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE]; int level; - /* If the CPU is halted advance CCOUNT according to the QEMU_CLOCK_VIRTUAL time - * elapsed since the moment when it was advanced last time. - */ - if (cs->halted) { - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - xtensa_advance_ccount(env, - muldiv64(now - env->halt_clock, - env->config->clock_freq_khz, 1000000)); - env->halt_clock = now; - } for (level = env->config->nlevel; level > minlevel; --level) { if (env->config->level_mask[level] & int_set_enabled) { env->pending_irq_level = level; @@ -109,49 +82,29 @@ void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active) qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active); } -void xtensa_rearm_ccompare_timer(CPUXtensaState *env) -{ - int i; - uint32_t wake_ccount = env->sregs[CCOUNT] - 1; - - for (i = 0; i < env->config->nccompare; ++i) { - if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] < - wake_ccount - env->sregs[CCOUNT]) { - wake_ccount = env->sregs[CCOMPARE + i]; - } - } - env->wake_ccount = wake_ccount; - timer_mod(env->ccompare_timer, env->halt_clock + - (uint64_t)(wake_ccount - env->sregs[CCOUNT]) * - 1000000 / env->config->clock_freq_khz); -} - static void xtensa_ccompare_cb(void *opaque) { - XtensaCPU *cpu = opaque; - CPUXtensaState *env = &cpu->env; - CPUState *cs = CPU(cpu); + XtensaCcompareTimer *ccompare = opaque; + CPUXtensaState *env = ccompare->env; + unsigned i = ccompare - env->ccompare; - if (cs->halted) { - env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); - if (!cpu_has_work(cs)) { - env->sregs[CCOUNT] = env->wake_ccount + 1; - xtensa_rearm_ccompare_timer(env); - } - } + xtensa_timer_irq(env, i, 1); } void xtensa_irq_init(CPUXtensaState *env) { - XtensaCPU *cpu = xtensa_env_get_cpu(env); - env->irq_inputs = (void **)qemu_allocate_irqs( xtensa_set_irq, env, env->config->ninterrupt); - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) && - env->config->nccompare > 0) { - env->ccompare_timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, &xtensa_ccompare_cb, cpu); + if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { + unsigned i; + + env->time_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + env->ccount_base = env->sregs[CCOUNT]; + for (i = 0; i < env->config->nccompare; ++i) { + env->ccompare[i].env = env; + env->ccompare[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + xtensa_ccompare_cb, env->ccompare + i); + } } } |