diff options
Diffstat (limited to 'hw')
75 files changed, 605 insertions, 216 deletions
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 56b302c122..3b0b6a9b1d 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -14,6 +14,7 @@ #include "hw/virtio/virtio.h" #include "virtio-9p.h" #include "virtio-9p-xattr.h" +#include "fsdev/qemu-fsdev.h" /* local_ops */ #include <arpa/inet.h> #include <pwd.h> #include <grp.h> diff --git a/hw/9pfs/virtio-9p-synth.c b/hw/9pfs/virtio-9p-synth.c index 840e4ebb5a..71262bccd2 100644 --- a/hw/9pfs/virtio-9p-synth.c +++ b/hw/9pfs/virtio-9p-synth.c @@ -21,7 +21,7 @@ #include <sys/stat.h> /* Root node for synth file system */ -V9fsSynthNode v9fs_synth_root = { +static V9fsSynthNode v9fs_synth_root = { .name = "/", .actual_attr = { .mode = 0555 | S_IFDIR, diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index f80c48008c..3b143b371b 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -63,16 +63,18 @@ typedef struct AcpiPciHpFind { static int acpi_pcihp_get_bsel(PCIBus *bus) { - QObject *o = object_property_get_qobject(OBJECT(bus), - ACPI_PCIHP_PROP_BSEL, NULL); - int64_t bsel = -1; - if (o) { - bsel = qint_get_int(qobject_to_qint(o)); - } - if (bsel < 0) { + Error *local_err = NULL; + int64_t bsel = object_property_get_int(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, + &local_err); + + if (local_err || bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) { + if (local_err) { + error_free(local_err); + } return -1; + } else { + return bsel; } - return bsel; } static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 04291488e4..e0cd847b95 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -732,7 +732,7 @@ static void pxa2xx_ssp_save(QEMUFile *f, void *opaque) static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) { PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - int i; + int i, v; s->enable = qemu_get_be32(f); @@ -746,7 +746,11 @@ static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->ssrsa); qemu_get_8s(f, &s->ssacd); - s->rx_level = qemu_get_byte(f); + v = qemu_get_byte(f); + if (v < 0 || v > ARRAY_SIZE(s->rx_fifo)) { + return -EINVAL; + } + s->rx_level = v; s->rx_start = 0; for (i = 0; i < s->rx_level; i ++) s->rx_fifo[i] = qemu_get_byte(f); diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index 28eed81280..5dd739e541 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -86,6 +86,7 @@ typedef struct { #ifndef HAS_YMF262 FM_OPL *opl; #endif + PortioList port_list; } AdlibState; static AdlibState *glob_adlib; @@ -293,7 +294,6 @@ static MemoryRegionPortio adlib_portio_list[] = { static void adlib_realizefn (DeviceState *dev, Error **errp) { AdlibState *s = ADLIB(dev); - PortioList *port_list = g_new(PortioList, 1); struct audsettings as; if (glob_adlib) { @@ -349,8 +349,8 @@ static void adlib_realizefn (DeviceState *dev, Error **errp) adlib_portio_list[0].offset = s->port; adlib_portio_list[1].offset = s->port + 8; - portio_list_init (port_list, OBJECT(s), adlib_portio_list, s, "adlib"); - portio_list_add (port_list, isa_address_space_io(&s->parent_obj), 0); + portio_list_init (&s->port_list, OBJECT(s), adlib_portio_list, s, "adlib"); + portio_list_add (&s->port_list, isa_address_space_io(&s->parent_obj), 0); } static Property adlib_properties[] = { diff --git a/hw/block/xen_blkif.h b/hw/block/xen_blkif.h index c0f4136228..711b692742 100644 --- a/hw/block/xen_blkif.h +++ b/hw/block/xen_blkif.h @@ -79,6 +79,12 @@ static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_reque dst->handle = src->handle; dst->id = src->id; dst->sector_number = src->sector_number; + if (src->operation == BLKIF_OP_DISCARD) { + struct blkif_request_discard *s = (void *)src; + struct blkif_request_discard *d = (void *)dst; + d->nr_sectors = s->nr_sectors; + return; + } if (n > src->nr_segments) n = src->nr_segments; for (i = 0; i < n; i++) @@ -94,6 +100,12 @@ static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_reque dst->handle = src->handle; dst->id = src->id; dst->sector_number = src->sector_number; + if (src->operation == BLKIF_OP_DISCARD) { + struct blkif_request_discard *s = (void *)src; + struct blkif_request_discard *d = (void *)dst; + d->nr_sectors = s->nr_sectors; + return; + } if (n > src->nr_segments) n = src->nr_segments; for (i = 0; i < n; i++) diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index a8fea72edf..aed5b5b3e9 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -114,6 +114,7 @@ struct XenBlkDev { int requests_finished; /* Persistent grants extension */ + gboolean feature_discard; gboolean feature_persistent; GTree *persistent_gnts; unsigned int persistent_gnt_count; @@ -253,6 +254,8 @@ static int ioreq_parse(struct ioreq *ioreq) case BLKIF_OP_WRITE: ioreq->prot = PROT_READ; /* from memory */ break; + case BLKIF_OP_DISCARD: + return 0; default: xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n", ioreq->req.operation); @@ -492,6 +495,7 @@ static void qemu_aio_complete(void *opaque, int ret) case BLKIF_OP_READ: bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct); break; + case BLKIF_OP_DISCARD: default: break; } @@ -532,6 +536,15 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) &ioreq->v, ioreq->v.size / BLOCK_SIZE, qemu_aio_complete, ioreq); break; + case BLKIF_OP_DISCARD: + { + struct blkif_request_discard *discard_req = (void *)&ioreq->req; + ioreq->aio_inflight++; + bdrv_aio_discard(blkdev->bs, + discard_req->sector_number, discard_req->nr_sectors, + qemu_aio_complete, ioreq); + break; + } default: /* unknown operation (shouldn't happen -- parse catches this) */ goto err; @@ -710,6 +723,21 @@ static void blk_alloc(struct XenDevice *xendev) } } +static void blk_parse_discard(struct XenBlkDev *blkdev) +{ + int enable; + + blkdev->feature_discard = true; + + if (xenstore_read_be_int(&blkdev->xendev, "discard-enable", &enable) == 0) { + blkdev->feature_discard = !!enable; + } + + if (blkdev->feature_discard) { + xenstore_write_be_int(&blkdev->xendev, "feature-discard", 1); + } +} + static int blk_init(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); @@ -777,6 +805,8 @@ static int blk_init(struct XenDevice *xendev) xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1); xenstore_write_be_int(&blkdev->xendev, "info", info); + blk_parse_discard(blkdev); + g_free(directiosafe); return 0; @@ -812,6 +842,9 @@ static int blk_connect(struct XenDevice *xendev) qflags |= BDRV_O_RDWR; readonly = false; } + if (blkdev->feature_discard) { + qflags |= BDRV_O_UNMAP; + } /* init qemu block driver */ index = (blkdev->xendev.dev - 202 * 256) / 16; diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index de835612f0..404cf1843d 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -338,13 +338,13 @@ PropertyInfo qdev_prop_vlan = { int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) { - Error *errp = NULL; + Error *err = NULL; const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; object_property_set_str(OBJECT(dev), bdrv_name, - name, &errp); - if (errp) { - qerror_report_err(errp); - error_free(errp); + name, &err); + if (err) { + qerror_report_err(err); + error_free(err); return -1; } return 0; diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 585a8e902e..d8cb5408c3 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -751,6 +751,7 @@ static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque, Property *prop = opaque; uint32_t *alenptr = qdev_get_prop_ptr(dev, prop); void **arrayptr = (void *)dev + prop->arrayoffset; + Error *local_err = NULL; void *eltptr; const char *arrayname; int i; @@ -764,8 +765,9 @@ static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque, name); return; } - visit_type_uint32(v, alenptr, name, errp); - if (error_is_set(errp)) { + visit_type_uint32(v, alenptr, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } if (!*alenptr) { @@ -802,8 +804,9 @@ static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque, arrayprop->prop.info->get, arrayprop->prop.info->set, array_element_release, - arrayprop, errp); - if (error_is_set(errp)) { + arrayprop, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } } diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 60f9df1ed9..936eae6412 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -174,14 +174,14 @@ int qdev_init(DeviceState *dev) return 0; } -static void device_realize(DeviceState *dev, Error **err) +static void device_realize(DeviceState *dev, Error **errp) { DeviceClass *dc = DEVICE_GET_CLASS(dev); if (dc->init) { int rc = dc->init(dev); if (rc < 0) { - error_setg(err, "Device initialization failed."); + error_setg(errp, "Device initialization failed."); return; } } @@ -504,14 +504,14 @@ static void bus_unparent(Object *obj) } } -static bool bus_get_realized(Object *obj, Error **err) +static bool bus_get_realized(Object *obj, Error **errp) { BusState *bus = BUS(obj); return bus->realized; } -static void bus_set_realized(Object *obj, bool value, Error **err) +static void bus_set_realized(Object *obj, bool value, Error **errp) { BusState *bus = BUS(obj); BusClass *bc = BUS_GET_CLASS(bus); @@ -540,7 +540,7 @@ static void bus_set_realized(Object *obj, bool value, Error **err) return; error: - error_propagate(err, local_err); + error_propagate(errp, local_err); } void qbus_create_inplace(void *bus, size_t size, const char *typename, @@ -660,8 +660,8 @@ static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque, * Legacy properties are string versions of other OOM properties. The format * of the string depends on the property type. */ -void qdev_property_add_legacy(DeviceState *dev, Property *prop, - Error **errp) +static void qdev_property_add_legacy(DeviceState *dev, Property *prop, + Error **errp) { gchar *name; @@ -724,13 +724,13 @@ void qdev_property_add_static(DeviceState *dev, Property *prop, } } -static bool device_get_realized(Object *obj, Error **err) +static bool device_get_realized(Object *obj, Error **errp) { DeviceState *dev = DEVICE(obj); return dev->realized; } -static void device_set_realized(Object *obj, bool value, Error **err) +static void device_set_realized(Object *obj, bool value, Error **errp) { DeviceState *dev = DEVICE(obj); DeviceClass *dc = DEVICE_GET_CLASS(dev); @@ -738,7 +738,7 @@ static void device_set_realized(Object *obj, bool value, Error **err) Error *local_err = NULL; if (dev->hotplugged && !dc->hotpluggable) { - error_set(err, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj)); + error_set(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj)); return; } @@ -797,14 +797,14 @@ static void device_set_realized(Object *obj, bool value, Error **err) } if (local_err != NULL) { - error_propagate(err, local_err); + error_propagate(errp, local_err); return; } dev->realized = value; } -static bool device_get_hotpluggable(Object *obj, Error **err) +static bool device_get_hotpluggable(Object *obj, Error **errp) { DeviceClass *dc = DEVICE_GET_CLASS(obj); DeviceState *dev = DEVICE(obj); diff --git a/hw/display/qxl.c b/hw/display/qxl.c index e9c54d7399..7fb83e4eaf 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2055,7 +2055,6 @@ static int qxl_init_primary(PCIDevice *dev) { PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); VGACommonState *vga = &qxl->vga; - PortioList *qxl_vga_port_list = g_new(PortioList, 1); int rc; qxl->id = 0; @@ -2064,10 +2063,10 @@ static int qxl_init_primary(PCIDevice *dev) vga_common_init(vga, OBJECT(dev), true); vga_init(vga, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev), false); - portio_list_init(qxl_vga_port_list, OBJECT(dev), qxl_vga_portio_list, + portio_list_init(&qxl->vga_port_list, OBJECT(dev), qxl_vga_portio_list, vga, "vga"); - portio_list_set_flush_coalesced(qxl_vga_port_list); - portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); + portio_list_set_flush_coalesced(&qxl->vga_port_list); + portio_list_add(&qxl->vga_port_list, pci_address_space_io(dev), 0x3b0); vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl); qemu_spice_display_init_common(&qxl->ssd); diff --git a/hw/display/qxl.h b/hw/display/qxl.h index c5de3d7075..412e346b68 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -32,6 +32,7 @@ enum qxl_mode { typedef struct PCIQXLDevice { PCIDevice pci; + PortioList vga_port_list; SimpleSpiceDisplay ssd; int id; uint32_t debug; diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index 971152edbd..97270077e2 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -312,18 +312,42 @@ static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) return -EINVAL; s->cmd_len = qemu_get_be32(f); + if (s->cmd_len < 0 || s->cmd_len > ARRAY_SIZE(s->cmd_data)) { + return -EINVAL; + } s->cmd = qemu_get_be32(f); for (i = 0; i < 8; i++) s->cmd_data[i] = qemu_get_be32(f); s->row = qemu_get_be32(f); + if (s->row < 0 || s->row >= 80) { + return -EINVAL; + } s->row_start = qemu_get_be32(f); + if (s->row_start < 0 || s->row_start >= 80) { + return -EINVAL; + } s->row_end = qemu_get_be32(f); + if (s->row_end < 0 || s->row_end >= 80) { + return -EINVAL; + } s->col = qemu_get_be32(f); + if (s->col < 0 || s->col >= 64) { + return -EINVAL; + } s->col_start = qemu_get_be32(f); + if (s->col_start < 0 || s->col_start >= 64) { + return -EINVAL; + } s->col_end = qemu_get_be32(f); + if (s->col_end < 0 || s->col_end >= 64) { + return -EINVAL; + } s->redraw = qemu_get_be32(f); s->remap = qemu_get_be32(f); s->mode = qemu_get_be32(f); + if (s->mode != SSD0323_CMD && s->mode != SSD0323_DATA) { + return -EINVAL; + } qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); ss->cs = qemu_get_be32(f); diff --git a/hw/display/vga.c b/hw/display/vga.c index c4c3238d5f..8cd6afe83a 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -2355,8 +2355,6 @@ void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space, { MemoryRegion *vga_io_memory; const MemoryRegionPortio *vga_ports, *vbe_ports; - PortioList *vga_port_list = g_new(PortioList, 1); - PortioList *vbe_port_list = g_new(PortioList, 1); qemu_register_reset(vga_reset, s); @@ -2371,13 +2369,13 @@ void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space, 1); memory_region_set_coalescing(vga_io_memory); if (init_vga_ports) { - portio_list_init(vga_port_list, obj, vga_ports, s, "vga"); - portio_list_set_flush_coalesced(vga_port_list); - portio_list_add(vga_port_list, address_space_io, 0x3b0); + portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga"); + portio_list_set_flush_coalesced(&s->vga_port_list); + portio_list_add(&s->vga_port_list, address_space_io, 0x3b0); } if (vbe_ports) { - portio_list_init(vbe_port_list, obj, vbe_ports, s, "vbe"); - portio_list_add(vbe_port_list, address_space_io, 0x1ce); + portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe"); + portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce); } } diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index d42ac926e3..5320abdc07 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -124,6 +124,8 @@ typedef struct VGACommonState { void (*get_resolution)(struct VGACommonState *s, int *pwidth, int *pheight); + PortioList vga_port_list; + PortioList vbe_port_list; /* bochs vbe state */ uint16_t vbe_index; uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; diff --git a/hw/dma/i82374.c b/hw/dma/i82374.c index dc7a767ee2..b8ad2e64ec 100644 --- a/hw/dma/i82374.c +++ b/hw/dma/i82374.c @@ -39,6 +39,7 @@ do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0) typedef struct I82374State { uint8_t commands[8]; qemu_irq out; + PortioList port_list; } I82374State; static const VMStateDescription vmstate_i82374 = { @@ -137,10 +138,10 @@ static void i82374_isa_realize(DeviceState *dev, Error **errp) { ISAi82374State *isa = I82374(dev); I82374State *s = &isa->state; - PortioList *port_list = g_new(PortioList, 1); - portio_list_init(port_list, OBJECT(isa), i82374_portio_list, s, "i82374"); - portio_list_add(port_list, isa_address_space_io(&isa->parent_obj), + portio_list_init(&s->port_list, OBJECT(isa), i82374_portio_list, s, + "i82374"); + portio_list_add(&s->port_list, isa_address_space_io(&isa->parent_obj), isa->iobase); i82374_realize(s, errp); diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 14b887bfa8..cc90eb5110 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -534,24 +534,24 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev); XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM( &s->rx_control_dev); - Error *local_errp = NULL; + Error *local_err = NULL; object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA, (Object **)&ds->dma, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, - &local_errp); + &local_err); object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA, (Object **)&cs->dma, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, - &local_errp); - if (local_errp) { + &local_err); + if (local_err) { goto xilinx_axidma_realize_fail; } - object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_errp); - object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_errp); - if (local_errp) { + object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_err); + object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_err); + if (local_err) { goto xilinx_axidma_realize_fail; } @@ -567,7 +567,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) xilinx_axidma_realize_fail: if (!*errp) { - *errp = local_errp; + *errp = local_err; } } diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c index dc79a8baa6..8e2ce049de 100644 --- a/hw/gpio/zaurus.c +++ b/hw/gpio/zaurus.c @@ -203,6 +203,15 @@ static bool is_version_0 (void *opaque, int version_id) return version_id == 0; } +static bool vmstate_scoop_validate(void *opaque, int version_id) +{ + ScoopInfo *s = opaque; + + return !(s->prev_level & 0xffff0000) && + !(s->gpio_level & 0xffff0000) && + !(s->gpio_dir & 0xffff0000); +} + static const VMStateDescription vmstate_scoop_regs = { .name = "scoop", .version_id = 1, @@ -215,6 +224,7 @@ static const VMStateDescription vmstate_scoop_regs = { VMSTATE_UINT32(gpio_level, ScoopInfo), VMSTATE_UINT32(gpio_dir, ScoopInfo), VMSTATE_UINT32(prev_level, ScoopInfo), + VMSTATE_VALIDATE("irq levels are 16 bit", vmstate_scoop_validate), VMSTATE_UINT16(mcr, ScoopInfo), VMSTATE_UINT16(cdr, ScoopInfo), VMSTATE_UINT16(ccr, ScoopInfo), diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c index 9f50067735..fedb5fb4d4 100644 --- a/hw/i2c/pm_smbus.c +++ b/hw/i2c/pm_smbus.c @@ -60,59 +60,78 @@ static void smb_transaction(PMSMBus *s) uint8_t cmd = s->smb_cmd; uint8_t addr = s->smb_addr >> 1; I2CBus *bus = s->smbus; + int ret; SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); /* Transaction isn't exec if STS_DEV_ERR bit set */ if ((s->smb_stat & STS_DEV_ERR) != 0) { - goto error; - } + goto error; + } switch(prot) { case 0x0: - smbus_quick_command(bus, addr, read); - s->smb_stat |= STS_BYTE_DONE | STS_INTR; - break; + ret = smbus_quick_command(bus, addr, read); + goto done; case 0x1: if (read) { - s->smb_data0 = smbus_receive_byte(bus, addr); + ret = smbus_receive_byte(bus, addr); + goto data8; } else { - smbus_send_byte(bus, addr, cmd); + ret = smbus_send_byte(bus, addr, cmd); + goto done; } - s->smb_stat |= STS_BYTE_DONE | STS_INTR; - break; case 0x2: if (read) { - s->smb_data0 = smbus_read_byte(bus, addr, cmd); + ret = smbus_read_byte(bus, addr, cmd); + goto data8; } else { - smbus_write_byte(bus, addr, cmd, s->smb_data0); + ret = smbus_write_byte(bus, addr, cmd, s->smb_data0); + goto done; } - s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; case 0x3: if (read) { - uint16_t val; - val = smbus_read_word(bus, addr, cmd); - s->smb_data0 = val; - s->smb_data1 = val >> 8; + ret = smbus_read_word(bus, addr, cmd); + goto data16; } else { - smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); + ret = smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); + goto done; } - s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; case 0x5: if (read) { - s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data); + ret = smbus_read_block(bus, addr, cmd, s->smb_data); + goto data8; } else { - smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); + ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); + goto done; } - s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; default: goto error; } + abort(); + +data16: + if (ret < 0) { + goto error; + } + s->smb_data1 = ret >> 8; +data8: + if (ret < 0) { + goto error; + } + s->smb_data0 = ret; +done: + if (ret < 0) { + goto error; + } + s->smb_stat |= STS_BYTE_DONE | STS_INTR; return; - error: +error: s->smb_stat |= STS_DEV_ERR; + return; + } static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c index 3febf3c258..6e27ae8bd2 100644 --- a/hw/i2c/smbus.c +++ b/hw/i2c/smbus.c @@ -208,34 +208,44 @@ static int smbus_device_init(I2CSlave *i2c) } /* Master device commands. */ -void smbus_quick_command(I2CBus *bus, uint8_t addr, int read) +int smbus_quick_command(I2CBus *bus, uint8_t addr, int read) { - i2c_start_transfer(bus, addr, read); + if (i2c_start_transfer(bus, addr, read)) { + return -1; + } i2c_end_transfer(bus); + return 0; } -uint8_t smbus_receive_byte(I2CBus *bus, uint8_t addr) +int smbus_receive_byte(I2CBus *bus, uint8_t addr) { uint8_t data; - i2c_start_transfer(bus, addr, 1); + if (i2c_start_transfer(bus, addr, 1)) { + return -1; + } data = i2c_recv(bus); i2c_nack(bus); i2c_end_transfer(bus); return data; } -void smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data) +int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data) { - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, data); i2c_end_transfer(bus); + return 0; } -uint8_t smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) +int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) { uint8_t data; - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); data = i2c_recv(bus); @@ -244,18 +254,23 @@ uint8_t smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) return data; } -void smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data) +int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data) { - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_send(bus, data); i2c_end_transfer(bus); + return 0; } -uint16_t smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) +int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) { uint16_t data; - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); data = i2c_recv(bus); @@ -265,13 +280,16 @@ uint16_t smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) return data; } -void smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data) +int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data) { - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_send(bus, data & 0xff); i2c_send(bus, data >> 8); i2c_end_transfer(bus); + return 0; } int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data) @@ -279,33 +297,41 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data) int len; int i; - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); len = i2c_recv(bus); - if (len > 32) + if (len > 32) { len = 0; - for (i = 0; i < len; i++) + } + for (i = 0; i < len; i++) { data[i] = i2c_recv(bus); + } i2c_nack(bus); i2c_end_transfer(bus); return len; } -void smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, - int len) +int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, + int len) { int i; if (len > 32) len = 32; - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_send(bus, len); - for (i = 0; i < len; i++) + for (i = 0; i < len; i++) { i2c_send(bus, data[i]); + } i2c_end_transfer(bus); + return 0; } static void smbus_device_class_init(ObjectClass *klass, void *data) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 3df1612651..f66c349508 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -2,7 +2,7 @@ obj-$(CONFIG_KVM) += kvm/ obj-y += multiboot.o smbios.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o -obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o +obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o obj-y += acpi-build.o diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index c98df88cd2..9fac589033 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -156,18 +156,21 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) } else { pm->s3_disabled = false; } + qobject_decref(o); o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_DISABLED, NULL); if (o) { pm->s4_disabled = qint_get_int(qobject_to_qint(o)); } else { pm->s4_disabled = false; } + qobject_decref(o); o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_VAL, NULL); if (o) { pm->s4_val = qint_get_int(qobject_to_qint(o)); } else { pm->s4_val = false; } + qobject_decref(o); /* Fill in mandatory properties */ pm->sci_int = object_property_get_int(obj, ACPI_PM_PROP_SCI_INT, NULL); @@ -973,6 +976,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state) } } + qobject_decref(bsel); build_free_array(bus_table); build_pci_bus_state_cleanup(child); g_free(child); @@ -1362,10 +1366,12 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return false; } mcfg->mcfg_base = qint_get_int(qobject_to_qint(o)); + qobject_decref(o); o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL); assert(o); mcfg->mcfg_size = qint_get_int(qobject_to_qint(o)); + qobject_decref(o); return true; } @@ -1410,15 +1416,16 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) /* ACPI tables pointed to by RSDT */ acpi_add_table(table_offsets, tables->table_data); build_fadt(tables->table_data, tables->linker, &pm, facs, dsdt); - acpi_add_table(table_offsets, tables->table_data); + acpi_add_table(table_offsets, tables->table_data); build_ssdt(tables->table_data, tables->linker, &cpu, &pm, &misc, &pci, guest_info); - acpi_add_table(table_offsets, tables->table_data); - build_madt(tables->table_data, tables->linker, &cpu, guest_info); acpi_add_table(table_offsets, tables->table_data); + build_madt(tables->table_data, tables->linker, &cpu, guest_info); + if (misc.has_hpet) { + acpi_add_table(table_offsets, tables->table_data); build_hpet(tables->table_data, tables->linker); } if (guest_info->numa_nodes) { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index ea72502420..eaf3e61994 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -414,6 +414,10 @@ static QEMUMachine pc_i440fx_machine_v2_0 = { PC_I440FX_2_0_MACHINE_OPTIONS, .name = "pc-i440fx-2.0", .init = pc_init_pci_2_0, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_2_0, + { /* end of list */ } + }, }; #define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 3306f89b9e..9517ec653f 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -327,6 +327,10 @@ static QEMUMachine pc_q35_machine_v2_0 = { PC_Q35_2_0_MACHINE_OPTIONS, .name = "pc-q35-2.0", .init = pc_q35_init_2_0, + .compat_props = (GlobalProperty[]) { + PC_Q35_COMPAT_2_0, + { /* end of list */ } + }, }; #define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS diff --git a/hw/i386/xen/Makefile.objs b/hw/i386/xen/Makefile.objs new file mode 100644 index 0000000000..801a68d326 --- /dev/null +++ b/hw/i386/xen/Makefile.objs @@ -0,0 +1 @@ +obj-y += xen_platform.o xen_apic.o xen_pvdevice.o diff --git a/hw/xen/xen_apic.c b/hw/i386/xen/xen_apic.c index 63bb7f77c6..63bb7f77c6 100644 --- a/hw/xen/xen_apic.c +++ b/hw/i386/xen/xen_apic.c diff --git a/hw/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 1d9d0e9f25..1d9d0e9f25 100644 --- a/hw/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c diff --git a/hw/xen/xen_pvdevice.c b/hw/i386/xen/xen_pvdevice.c index c2189473ba..c2189473ba 100644 --- a/hw/xen/xen_pvdevice.c +++ b/hw/i386/xen/xen_pvdevice.c diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 50327ffdf1..e57c5837d2 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1293,7 +1293,7 @@ const VMStateDescription vmstate_ahci = { VMSTATE_UINT32(control_regs.impl, AHCIState), VMSTATE_UINT32(control_regs.version, AHCIState), VMSTATE_UINT32(idp_index, AHCIState), - VMSTATE_INT32(ports, AHCIState), + VMSTATE_INT32_EQUAL(ports, AHCIState), VMSTATE_END_OF_LIST() }, }; diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index 485c9e5753..aa5b6886ea 100644 --- a/hw/input/tsc210x.c +++ b/hw/input/tsc210x.c @@ -1070,9 +1070,21 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) s->enabled = qemu_get_byte(f); s->host_mode = qemu_get_byte(f); s->function = qemu_get_byte(f); + if (s->function < 0 || s->function >= ARRAY_SIZE(mode_regs)) { + return -EINVAL; + } s->nextfunction = qemu_get_byte(f); + if (s->nextfunction < 0 || s->nextfunction >= ARRAY_SIZE(mode_regs)) { + return -EINVAL; + } s->precision = qemu_get_byte(f); + if (s->precision < 0 || s->precision >= ARRAY_SIZE(resolution)) { + return -EINVAL; + } s->nextprecision = qemu_get_byte(f); + if (s->nextprecision < 0 || s->nextprecision >= ARRAY_SIZE(resolution)) { + return -EINVAL; + } s->filter = qemu_get_byte(f); s->pin_func = qemu_get_byte(f); s->ref = qemu_get_byte(f); diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 2f40cbad2d..ef19e5515c 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -675,7 +675,7 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr) val = s->id << 24; break; case 0x03: /* version */ - val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */ + val = s->version | ((APIC_LVT_NB - 1) << 16); break; case 0x08: apic_sync_vapic(s, SYNC_FROM_VAPIC); diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 7ecce2dcce..71376533ca 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -380,6 +380,7 @@ static const VMStateDescription vmstate_apic_common = { static Property apic_properties_common[] = { DEFINE_PROP_UINT8("id", APICCommonState, id, -1), + DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14), DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT, true), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 955b8d4945..1532ef9482 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -797,9 +797,11 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) GICState *s = ARM_GIC(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); ARMGICClass *agc = ARM_GIC_GET_CLASS(s); + Error *local_err = NULL; - agc->parent_realize(dev, errp); - if (error_is_set(errp)) { + agc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 719d2277ec..5038885afd 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -517,10 +517,12 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) GICState *s = KVM_ARM_GIC(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); + Error *local_err = NULL; int ret; - kgc->parent_realize(dev, errp); - if (error_is_set(errp)) { + kgc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index f5b0c3be6f..9aa8ab208f 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -474,14 +474,16 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) { nvic_state *s = NVIC(dev); NVICClass *nc = NVIC_GET_CLASS(s); + Error *local_err = NULL; /* The NVIC always has only one CPU */ s->gic.num_cpu = 1; /* Tell the common code we're an NVIC */ s->gic.revision = 0xffffffff; s->num_irq = s->gic.num_irq; - nc->parent_realize(dev, errp); - if (error_is_set(errp)) { + nc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } gic_init_irqs_and_distributor(&s->gic, s->num_irq); diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index c6f248b145..d0b0c52b97 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -265,7 +265,8 @@ static void pic_ioport_write(void *opaque, hwaddr addr64, s->init4 = val & 1; s->single_mode = val & 2; if (val & 0x08) { - hw_error("level sensitive irq not supported"); + qemu_log_mask(LOG_UNIMP, + "i8259: level sensitive irq not supported\n"); } } else if (val & 0x08) { if (val & 0x04) { @@ -412,7 +413,7 @@ static const MemoryRegionOps pic_elcr_ioport_ops = { }, }; -static void pic_realize(DeviceState *dev, Error **err) +static void pic_realize(DeviceState *dev, Error **errp) { PICCommonState *s = PIC_COMMON(dev); PICClass *pc = PIC_GET_CLASS(dev); @@ -425,7 +426,7 @@ static void pic_realize(DeviceState *dev, Error **err) qdev_init_gpio_out(dev, s->int_out, ARRAY_SIZE(s->int_out)); qdev_init_gpio_in(dev, pic_set_irq, 8); - pc->parent_realize(dev, err); + pc->parent_realize(dev, errp); } void pic_info(Monitor *mon, const QDict *qdict) diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index be76fbd78f..17136c9333 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -41,6 +41,7 @@ #include "hw/sysbus.h" #include "hw/pci/msi.h" #include "qemu/bitops.h" +#include "qapi/qmp/qerror.h" //#define DEBUG_OPENPIC @@ -1416,7 +1417,7 @@ static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) static int openpic_load(QEMUFile* f, void *opaque, int version_id) { OpenPICState *opp = (OpenPICState *)opaque; - unsigned int i; + unsigned int i, nb_cpus; if (version_id != 1) { return -EINVAL; @@ -1428,7 +1429,11 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->spve); qemu_get_be32s(f, &opp->tfrr); - qemu_get_be32s(f, &opp->nb_cpus); + qemu_get_be32s(f, &nb_cpus); + if (opp->nb_cpus != nb_cpus) { + return -EINVAL; + } + assert(nb_cpus > 0 && nb_cpus <= MAX_CPU); for (i = 0; i < opp->nb_cpus; i++) { qemu_get_sbe32s(f, &opp->dst[i].ctpr); @@ -1567,6 +1572,13 @@ static void openpic_realize(DeviceState *dev, Error **errp) {NULL} }; + if (opp->nb_cpus > MAX_CPU) { + error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, + TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus, + (uint64_t)0, (uint64_t)MAX_CPU); + return; + } + switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: default: diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 55d01008d3..b28981bfde 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -108,15 +108,20 @@ void isa_register_portio_list(ISADevice *dev, uint16_t start, const MemoryRegionPortio *pio_start, void *opaque, const char *name) { - PortioList *piolist = g_new(PortioList, 1); + PortioList piolist; /* START is how we should treat DEV, regardless of the actual contents of the portio array. This is how the old code actually handled e.g. the FDC device. */ isa_init_ioport(dev, start); - portio_list_init(piolist, OBJECT(dev), pio_start, opaque, name); - portio_list_add(piolist, isabus->address_space_io, start); + /* FIXME: the device should store created PortioList in its state. Note + that DEV can be NULL here and that single device can register several + portio lists. Current implementation is leaking memory allocated + in portio_list_init. The leak is not critical because it happens only + at initialization time. */ + portio_list_init(&piolist, OBJECT(dev), pio_start, opaque, name); + portio_list_add(&piolist, isabus->address_space_io, start); } static void isa_device_init(Object *obj) diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index e1551aabe2..30d9f19df7 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -211,7 +211,7 @@ static void main_cpu_reset(void *opaque) } } -uint8_t eeprom_spd[0x80] = { +static const uint8_t eeprom_spd[0x80] = { 0x80,0x08,0x07,0x0d,0x09,0x02,0x40,0x00,0x04,0x70, 0x70,0x00,0x82,0x10,0x00,0x01,0x0e,0x04,0x0c,0x01, 0x02,0x20,0x80,0x75,0x70,0x00,0x00,0x50,0x3c,0x50, diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c index 63aa3d6277..636ee97b16 100644 --- a/hw/misc/tmp105.c +++ b/hw/misc/tmp105.c @@ -68,10 +68,12 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { TMP105State *s = TMP105(obj); + Error *local_err = NULL; int64_t temp; - visit_type_int(v, &temp, name, errp); - if (error_is_set(errp)) { + visit_type_int(v, &temp, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } if (temp >= 128000 || temp < -128000) { diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index e34b25e734..cdb18253b6 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -388,7 +388,7 @@ typedef struct GemState { } GemState; /* The broadcast MAC address: 0xFFFFFFFFFFFF */ -const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* * gem_init_register_masks: diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 33bd233a2d..940a7cfe54 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1362,10 +1362,17 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) { qemu_get_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); - } else if (n->mac_table.in_use) { - uint8_t *buf = g_malloc0(n->mac_table.in_use); - qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN); - g_free(buf); + } else { + int64_t i; + + /* Overflow detected - can happen if source has a larger MAC table. + * We simply set overflow flag so there's no need to maintain the + * table of addresses, discard them all. + * Note: 64 bit math to avoid integer overflow. + */ + for (i = 0; i < (int64_t)n->mac_table.in_use * ETH_ALEN; ++i) { + qemu_get_byte(f); + } n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1; n->mac_table.in_use = 0; } @@ -1407,6 +1414,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } n->curr_queues = qemu_get_be16(f); + if (n->curr_queues > n->max_queues) { + error_report("virtio-net: curr_queues %x > max_queues %x", + n->curr_queues, n->max_queues); + return -1; + } for (i = 1; i < n->curr_queues; i++) { n->vqs[i].tx_waiting = qemu_get_be32(f); } diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index ddcee4bd21..1bb9259df2 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2305,7 +2305,7 @@ static void vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size) vmxnet3_put_tx_stats_to_file(f, &r->txq_stats); } -const VMStateInfo txq_descr_info = { +static const VMStateInfo txq_descr_info = { .name = "txq_descr", .get = vmxnet3_get_txq_descr, .put = vmxnet3_put_txq_descr @@ -2397,7 +2397,7 @@ static int vmxnet3_post_load(void *opaque, int version_id) return 0; } -const VMStateInfo rxq_descr_info = { +static const VMStateInfo rxq_descr_info = { .name = "rxq_descr", .get = vmxnet3_get_rxq_descr, .put = vmxnet3_put_rxq_descr @@ -2423,7 +2423,7 @@ static void vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size) qemu_put_byte(f, r->is_asserted); } -const VMStateInfo int_state_info = { +static const VMStateInfo int_state_info = { .name = "int_state", .get = vmxnet3_get_int_state, .put = vmxnet3_put_int_state diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index 9384fa0c5c..88349ac6a2 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -152,7 +152,7 @@ typedef struct XgmacState { uint32_t regs[R_MAX]; } XgmacState; -const VMStateDescription vmstate_rxtx_stats = { +static const VMStateDescription vmstate_rxtx_stats = { .name = "xgmac_stats", .version_id = 1, .minimum_version_id = 1, diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index dbeb3c9a25..cd952d2514 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -945,24 +945,24 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev); XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM( &s->rx_control_dev); - Error *local_errp = NULL; + Error *local_err = NULL; object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", (Object **) &ds->enet, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, - &local_errp); + &local_err); object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet", (Object **) &cs->enet, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, - &local_errp); - if (local_errp) { + &local_err); + if (local_err) { goto xilinx_enet_realize_fail; } - object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_errp); - object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_errp); - if (local_errp) { + object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_err); + object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_err); + if (local_err) { goto xilinx_enet_realize_fail; } @@ -981,7 +981,7 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) xilinx_enet_realize_fail: if (!*errp) { - *errp = local_errp; + *errp = local_err; } } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 2a9f08eb0a..517ff2a21b 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -475,7 +475,7 @@ const VMStateDescription vmstate_pci_device = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_INT32_LE(version_id, PCIDevice), + VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice), VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, vmstate_info_pci_config, PCI_CONFIG_SPACE_SIZE), @@ -492,7 +492,7 @@ const VMStateDescription vmstate_pcie_device = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_INT32_LE(version_id, PCIDevice), + VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice), VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, vmstate_info_pci_config, PCIE_CONFIG_SPACE_SIZE), diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index 991502e517..535be2c08a 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -795,6 +795,13 @@ static const VMStateDescription vmstate_pcie_aer_err = { } }; +static bool pcie_aer_state_log_num_valid(void *opaque, int version_id) +{ + PCIEAERLog *s = opaque; + + return s->log_num <= s->log_max; +} + const VMStateDescription vmstate_pcie_aer_log = { .name = "PCIE_AER_ERROR_LOG", .version_id = 1, @@ -802,7 +809,8 @@ const VMStateDescription vmstate_pcie_aer_log = { .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT16(log_num, PCIEAERLog), - VMSTATE_UINT16(log_max, PCIEAERLog), + VMSTATE_UINT16_EQUAL(log_max, PCIEAERLog), + VMSTATE_VALIDATE("log_num <= log_max", pcie_aer_state_log_num_valid), VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num, vmstate_pcie_aer_err, PCIEAERErr), VMSTATE_END_OF_LIST() diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index e2436512f7..585937321f 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -361,6 +361,8 @@ static const MemoryRegionPortio prep_portio_list[] = { PORTIO_END_OF_LIST(), }; +static PortioList prep_port_list; + /* PowerPC PREP hardware initialisation */ static void ppc_prep_init(QEMUMachineInitArgs *args) { @@ -375,7 +377,6 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) CPUPPCState *env = NULL; nvram_t nvram; M48t59State *m48t59; - PortioList *port_list = g_new(PortioList, 1); #if 0 MemoryRegion *xcsr = g_new(MemoryRegion, 1); #endif @@ -542,8 +543,8 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) cpu = POWERPC_CPU(first_cpu); sysctrl->reset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET]; - portio_list_init(port_list, NULL, prep_portio_list, sysctrl, "prep"); - portio_list_add(port_list, isa_address_space_io(isa), 0x0); + portio_list_init(&prep_port_list, NULL, prep_portio_list, sysctrl, "prep"); + portio_list_add(&prep_port_list, isa_address_space_io(isa), 0x0); /* PowerPC control and status register group */ #if 0 diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index a11e1217b9..b4ce950bbd 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1419,19 +1419,6 @@ static int spapr_kvm_type(const char *vm_type) exit(1); } -static QEMUMachine spapr_machine = { - .name = "pseries", - .desc = "pSeries Logical Partition (PAPR compliant)", - .is_default = 1, - .init = ppc_spapr_init, - .reset = ppc_spapr_reset, - .block_default_type = IF_SCSI, - .max_cpus = MAX_CPUS, - .no_parallel = 1, - .default_boot_order = NULL, - .kvm_type = spapr_kvm_type, -}; - /* * Implementation of an interface to adjust firmware patch * for the bootindex property handling. @@ -1494,7 +1481,17 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) MachineClass *mc = MACHINE_CLASS(oc); FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); - mc->qemu_machine = data; + mc->name = "pseries"; + mc->desc = "pSeries Logical Partition (PAPR compliant)"; + mc->is_default = 1; + mc->init = ppc_spapr_init; + mc->reset = ppc_spapr_reset; + mc->block_default_type = IF_SCSI; + mc->max_cpus = MAX_CPUS; + mc->no_parallel = 1; + mc->default_boot_order = NULL; + mc->kvm_type = spapr_kvm_type; + fwc->get_dev_path = spapr_get_fw_dev_path; } @@ -1502,7 +1499,6 @@ static const TypeInfo spapr_machine_info = { .name = TYPE_SPAPR_MACHINE, .parent = TYPE_MACHINE, .class_init = spapr_machine_class_init, - .class_data = &spapr_machine, .interfaces = (InterfaceInfo[]) { { TYPE_FW_PATH_PROVIDER }, { } diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index d9fe946818..72493d802a 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -35,7 +35,7 @@ enum sPAPRTCEAccess { SPAPR_TCE_RW = 3, }; -QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; +static QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn) { diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 73860d0486..ea4a2b2698 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -272,7 +272,7 @@ static struct rtas_call { spapr_rtas_fn fn; } rtas_table[TOKEN_MAX]; -struct rtas_call *rtas_next = rtas_table; +static struct rtas_call *rtas_next = rtas_table; target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 7074d2b3d5..122cc7e66f 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -140,7 +140,6 @@ static void sch_handle_clear_func(SubchDev *sch) s->flags &= ~SCSW_FLAGS_MASK_PNO; /* We always 'attempt to issue the clear signal', and we always succeed. */ - sch->orb = NULL; sch->channel_prog = 0x0; sch->last_cmd_valid = false; s->ctrl &= ~SCSW_ACTL_CLEAR_PEND; @@ -163,7 +162,6 @@ static void sch_handle_halt_func(SubchDev *sch) path = 0x80; /* We always 'attempt to issue the halt signal', and we always succeed. */ - sch->orb = NULL; sch->channel_prog = 0x0; sch->last_cmd_valid = false; s->ctrl &= ~SCSW_ACTL_HALT_PEND; @@ -317,12 +315,11 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) return ret; } -static void sch_handle_start_func(SubchDev *sch) +static void sch_handle_start_func(SubchDev *sch, ORB *orb) { PMCW *p = &sch->curr_status.pmcw; SCSW *s = &sch->curr_status.scsw; - ORB *orb = sch->orb; int path; int ret; @@ -331,6 +328,7 @@ static void sch_handle_start_func(SubchDev *sch) if (!(s->ctrl & SCSW_ACTL_SUSP)) { /* Look at the orb and try to execute the channel program. */ + assert(orb != NULL); /* resume does not pass an orb */ p->intparm = orb->intparm; if (!(orb->lpm & path)) { /* Generate a deferred cc 3 condition. */ @@ -406,7 +404,7 @@ static void sch_handle_start_func(SubchDev *sch) * read/writes) asynchronous later on if we start supporting more than * our current very simple devices. */ -static void do_subchannel_work(SubchDev *sch) +static void do_subchannel_work(SubchDev *sch, ORB *orb) { SCSW *s = &sch->curr_status.scsw; @@ -416,7 +414,7 @@ static void do_subchannel_work(SubchDev *sch) } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) { sch_handle_halt_func(sch); } else if (s->ctrl & SCSW_FCTL_START_FUNC) { - sch_handle_start_func(sch); + sch_handle_start_func(sch, orb); } else { /* Cannot happen. */ return; @@ -594,7 +592,6 @@ int css_do_xsch(SubchDev *sch) SCSW_ACTL_SUSP); sch->channel_prog = 0x0; sch->last_cmd_valid = false; - sch->orb = NULL; s->dstat = 0; s->cstat = 0; ret = 0; @@ -618,7 +615,7 @@ int css_do_csch(SubchDev *sch) s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL); s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_CLEAR_FUNC; - do_subchannel_work(sch); + do_subchannel_work(sch, NULL); ret = 0; out: @@ -659,7 +656,7 @@ int css_do_hsch(SubchDev *sch) } s->ctrl |= SCSW_ACTL_HALT_PEND; - do_subchannel_work(sch); + do_subchannel_work(sch, NULL); ret = 0; out: @@ -721,13 +718,12 @@ int css_do_ssch(SubchDev *sch, ORB *orb) if (channel_subsys->chnmon_active) { css_update_chnmon(sch); } - sch->orb = orb; sch->channel_prog = orb->cpa; /* Trigger the start function. */ s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND); s->flags &= ~SCSW_FLAGS_MASK_PNO; - do_subchannel_work(sch); + do_subchannel_work(sch, orb); ret = 0; out: @@ -957,7 +953,7 @@ int css_do_rsch(SubchDev *sch) } s->ctrl |= SCSW_ACTL_RESUME_PEND; - do_subchannel_work(sch); + do_subchannel_work(sch, NULL); ret = 0; out: @@ -1267,7 +1263,6 @@ void css_reset_sch(SubchDev *sch) sch->channel_prog = 0x0; sch->last_cmd_valid = false; - sch->orb = NULL; sch->thinint_active = false; } diff --git a/hw/s390x/css.h b/hw/s390x/css.h index e9b440540d..220169e7c3 100644 --- a/hw/s390x/css.h +++ b/hw/s390x/css.h @@ -76,7 +76,6 @@ struct SubchDev { hwaddr channel_prog; CCW1 last_cmd; bool last_cmd_valid; - ORB *orb; bool thinint_active; /* transport-provided data: */ int (*ccw_cb) (SubchDev *, CCW1); diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 0777a93916..2e9e62fe1f 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -32,7 +32,7 @@ struct SCLPEventFacility { unsigned int receive_mask; }; -SCLPEvent cpu_hotplug; +static SCLPEvent cpu_hotplug; /* return true if any child has event pending set */ static bool event_pending(SCLPEventFacility *ef) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 2bf0af8f0a..1cb4e2c2f8 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -559,7 +559,6 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev) /* Initialize subchannel structure. */ sch->channel_prog = 0x0; sch->last_cmd_valid = false; - sch->orb = NULL; sch->thinint_active = false; /* * Use a device number if provided. Otherwise, fall back to subchannel diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index ae921a6a75..abe73022c0 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1179,7 +1179,7 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd) return lba; } -int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) { int rc; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index b0d7517cb1..175219376c 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -147,6 +147,15 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) qemu_get_be32s(f, &n); assert(n < vs->conf.num_queues); qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); + /* TODO: add a way for SCSIBusInfo's load_request to fail, + * and fail migration instead of asserting here. + * When we do, we might be able to re-enable NDEBUG below. + */ +#ifdef NDEBUG +#error building with NDEBUG is not supported +#endif + assert(req->elem.in_num <= ARRAY_SIZE(req->elem.in_sg)); + assert(req->elem.out_num <= ARRAY_SIZE(req->elem.out_sg)); virtio_scsi_parse_req(s, vs->cmd_vqs[n], req); scsi_req_ref(sreq); diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 3273c8a31f..b012e57f64 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -230,8 +230,17 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) for (i = 0; i < 5; i++) s->response[i] = qemu_get_be32(f); s->arglen = qemu_get_be32(f); + if (s->mode == SSI_SD_CMDARG && + (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) { + return -EINVAL; + } s->response_pos = qemu_get_be32(f); s->stopping = qemu_get_be32(f); + if (s->mode == SSI_SD_RESPONSE && + (s->response_pos < 0 || s->response_pos >= ARRAY_SIZE(s->response) || + (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) { + return -EINVAL; + } ss->cs = qemu_get_be32(f); diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c index fd479effb9..b19bc7174a 100644 --- a/hw/ssi/pl022.c +++ b/hw/ssi/pl022.c @@ -240,11 +240,25 @@ static const MemoryRegionOps pl022_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static int pl022_post_load(void *opaque, int version_id) +{ + PL022State *s = opaque; + + if (s->tx_fifo_head < 0 || + s->tx_fifo_head >= ARRAY_SIZE(s->tx_fifo) || + s->rx_fifo_head < 0 || + s->rx_fifo_head >= ARRAY_SIZE(s->rx_fifo)) { + return -1; + } + return 0; +} + static const VMStateDescription vmstate_pl022 = { .name = "pl022_ssp", .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, + .post_load = pl022_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32(cr0, PL022State), VMSTATE_UINT32(cr1, PL022State), diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index e15d6bcac7..2792f89c66 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -239,6 +239,18 @@ static int hpet_pre_load(void *opaque) return 0; } +static bool hpet_validate_num_timers(void *opaque, int version_id) +{ + HPETState *s = opaque; + + if (s->num_timers < HPET_MIN_TIMERS) { + return false; + } else if (s->num_timers > HPET_MAX_TIMERS) { + return false; + } + return true; +} + static int hpet_post_load(void *opaque, int version_id) { HPETState *s = opaque; @@ -307,6 +319,7 @@ static const VMStateDescription vmstate_hpet = { VMSTATE_UINT64(isr, HPETState), VMSTATE_UINT64(hpet_counter, HPETState), VMSTATE_UINT8_V(num_timers, HPETState, 2), + VMSTATE_VALIDATE("num_timers in range", hpet_validate_num_timers), VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0, vmstate_hpet_timer, HPETTimer), VMSTATE_END_OF_LIST() diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c index 28152d88ea..3450c98637 100644 --- a/hw/timer/i8254.c +++ b/hw/timer/i8254.c @@ -322,7 +322,7 @@ static void pit_post_load(PITCommonState *s) } } -static void pit_realizefn(DeviceState *dev, Error **err) +static void pit_realizefn(DeviceState *dev, Error **errp) { PITCommonState *pit = PIT_COMMON(dev); PITClass *pc = PIT_GET_CLASS(dev); @@ -338,7 +338,7 @@ static void pit_realizefn(DeviceState *dev, Error **err) qdev_init_gpio_in(dev, pit_irq_control, 1); - pc->parent_realize(dev, err); + pc->parent_realize(dev, errp); } static Property pit_properties[] = { diff --git a/hw/usb/bus.c b/hw/usb/bus.c index fe70429304..e48b19fc29 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -49,7 +49,9 @@ static int usb_device_post_load(void *opaque, int version_id) } else { dev->attached = 1; } - if (dev->setup_index >= sizeof(dev->data_buf) || + if (dev->setup_index < 0 || + dev->setup_len < 0 || + dev->setup_index >= sizeof(dev->data_buf) || dev->setup_len >= sizeof(dev->data_buf)) { return -EINVAL; } diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 8b44032900..943f930404 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -50,6 +50,7 @@ enum mtp_code { RES_INVALID_TRANSACTION_ID = 0x2004, RES_OPERATION_NOT_SUPPORTED = 0x2005, RES_PARAMETER_NOT_SUPPORTED = 0x2006, + RES_INCOMPLETE_TRANSFER = 0x2007, RES_INVALID_STORAGE_ID = 0x2008, RES_INVALID_OBJECT_HANDLE = 0x2009, RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014, @@ -294,7 +295,7 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle, goto ignore; } - fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path); + trace_usb_mtp_object_alloc(s->dev.addr, o->handle, o->path); QTAILQ_INSERT_TAIL(&s->objects, o, next); return o; @@ -310,7 +311,7 @@ static void usb_mtp_object_free(MTPState *s, MTPObject *o) { int i; - fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path); + trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path); QTAILQ_REMOVE(&s->objects, o, next); for (i = 0; i < o->nchildren; i++) { @@ -416,7 +417,7 @@ static void usb_mtp_add_u32(MTPData *data, uint32_t val) static void usb_mtp_add_u64(MTPData *data, uint64_t val) { - usb_mtp_realloc(data, 4); + usb_mtp_realloc(data, 8); data->data[data->length++] = (val >> 0) & 0xff; data->data[data->length++] = (val >> 8) & 0xff; data->data[data->length++] = (val >> 16) & 0xff; @@ -424,7 +425,7 @@ static void usb_mtp_add_u64(MTPData *data, uint64_t val) data->data[data->length++] = (val >> 32) & 0xff; data->data[data->length++] = (val >> 40) & 0xff; data->data[data->length++] = (val >> 48) & 0xff; - data->data[data->length++] = (val >> 54) & 0xff; + data->data[data->length++] = (val >> 56) & 0xff; } static void usb_mtp_add_u16_array(MTPData *data, uint32_t len, @@ -533,7 +534,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c) trace_usb_mtp_op_get_device_info(s->dev.addr); - usb_mtp_add_u16(d, 0x0100); + usb_mtp_add_u16(d, 100); usb_mtp_add_u32(d, 0xffffffff); usb_mtp_add_u16(d, 0x0101); usb_mtp_add_wstr(d, L""); @@ -548,7 +549,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c) usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER); usb_mtp_add_wstr(d, L"" MTP_PRODUCT); usb_mtp_add_wstr(d, L"0.1"); - usb_mtp_add_wstr(d, L"123456789abcdef123456789abcdef"); + usb_mtp_add_wstr(d, L"0123456789abcdef0123456789abcdef"); return d; } @@ -669,6 +670,7 @@ static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c, d->fd = open(o->path, O_RDONLY); if (d->fd == -1) { + usb_mtp_data_free(d); return NULL; } d->length = o->stat.st_size; @@ -688,6 +690,7 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c, d->fd = open(o->path, O_RDONLY); if (d->fd == -1) { + usb_mtp_data_free(d); return NULL; } @@ -843,8 +846,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) res0 = data_in->length; break; default: - fprintf(stderr, "%s: unknown command code 0x%04x\n", - __func__, c->code); + trace_usb_mtp_op_unknown(s->dev.addr, c->code); usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED, c->trans, 0, 0, 0); return; @@ -892,6 +894,7 @@ static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p, static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p) { + /* we don't use async packets, so this should never be called */ fprintf(stderr, "%s\n", __func__); } @@ -944,7 +947,8 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) } rc = read(d->fd, d->data, dlen); if (rc != dlen) { - fprintf(stderr, "%s: TODO: handle read error\n", __func__); + memset(d->data, 0, dlen); + s->result->code = RES_INCOMPLETE_TRANSFER; } usb_packet_copy(p, d->data, dlen); } @@ -996,6 +1000,14 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) cmd.argc = (le32_to_cpu(container.length) - sizeof(container)) / sizeof(uint32_t); cmd.trans = le32_to_cpu(container.trans); + if (cmd.argc > ARRAY_SIZE(cmd.argv)) { + cmd.argc = ARRAY_SIZE(cmd.argv); + } + if (p->iov.size < sizeof(container) + cmd.argc * sizeof(uint32_t)) { + trace_usb_mtp_stall(s->dev.addr, "packet too small"); + p->status = USB_RET_STALL; + return; + } usb_packet_copy(p, ¶ms, cmd.argc * sizeof(uint32_t)); for (i = 0; i < cmd.argc; i++) { cmd.argv[i] = le32_to_cpu(params[i]); @@ -1009,8 +1021,7 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) usb_mtp_command(s, &cmd); break; default: - iov_hexdump(p->iov.iov, p->iov.niov, stderr, "mtp-out", 32); - trace_usb_mtp_stall(s->dev.addr, "TODO: implement data-out"); + /* not needed as long as the mtp device is read-only */ p->status = USB_RET_STALL; return; } @@ -1044,7 +1055,7 @@ static int usb_mtp_initfn(USBDevice *dev) QTAILQ_INIT(&s->objects); if (s->desc == NULL) { s->desc = strrchr(s->root, '/'); - if (s->desc) { + if (s->desc && s->desc[0]) { s->desc = g_strdup(s->desc + 1); } else { s->desc = g_strdup("none"); diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 93f186f5e7..cd87074862 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -80,13 +80,13 @@ typedef struct { uint32_t bulk_head, bulk_cur; uint32_t per_cur; uint32_t done; - int done_count; + int32_t done_count; /* Frame counter partition */ - uint32_t fsmps:15; - uint32_t fit:1; - uint32_t fi:14; - uint32_t frt:1; + uint16_t fsmps; + uint8_t fit; + uint16_t fi; + uint8_t frt; uint16_t frame_number; uint16_t padding; uint32_t pstart; @@ -111,7 +111,7 @@ typedef struct { USBPacket usb_packet; uint8_t usb_buf[8192]; uint32_t async_td; - int async_complete; + bool async_complete; } OHCIState; @@ -693,7 +693,7 @@ static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) #ifdef DEBUG_PACKET DPRINTF("Async packet complete\n"); #endif - ohci->async_complete = 1; + ohci->async_complete = true; ohci_process_lists(ohci, 1); } @@ -1058,7 +1058,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) #endif if (completion) { ohci->async_td = 0; - ohci->async_complete = 0; + ohci->async_complete = false; } else { if (ohci->async_td) { /* ??? The hardware should allow one active packet per @@ -1984,6 +1984,108 @@ static Property ohci_pci_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_ohci_state_port = { + .name = "ohci-core/port", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(ctrl, OHCIPort), + VMSTATE_END_OF_LIST() + }, +}; + +static bool ohci_eof_timer_needed(void *opaque) +{ + OHCIState *ohci = opaque; + + return ohci->eof_timer != NULL; +} + +static int ohci_eof_timer_pre_load(void *opaque) +{ + OHCIState *ohci = opaque; + + ohci_bus_start(ohci); + + return 0; +} + +static const VMStateDescription vmstate_ohci_eof_timer = { + .name = "ohci-core/eof-timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_load = ohci_eof_timer_pre_load, + .fields = (VMStateField []) { + VMSTATE_TIMER(eof_timer, OHCIState), + VMSTATE_END_OF_LIST() + }, +}; + +const VMStateDescription vmstate_ohci_state = { + .name = "ohci-core", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(sof_time, OHCIState), + VMSTATE_UINT32(ctl, OHCIState), + VMSTATE_UINT32(status, OHCIState), + VMSTATE_UINT32(intr_status, OHCIState), + VMSTATE_UINT32(intr, OHCIState), + VMSTATE_UINT32(hcca, OHCIState), + VMSTATE_UINT32(ctrl_head, OHCIState), + VMSTATE_UINT32(ctrl_cur, OHCIState), + VMSTATE_UINT32(bulk_head, OHCIState), + VMSTATE_UINT32(bulk_cur, OHCIState), + VMSTATE_UINT32(per_cur, OHCIState), + VMSTATE_UINT32(done, OHCIState), + VMSTATE_INT32(done_count, OHCIState), + VMSTATE_UINT16(fsmps, OHCIState), + VMSTATE_UINT8(fit, OHCIState), + VMSTATE_UINT16(fi, OHCIState), + VMSTATE_UINT8(frt, OHCIState), + VMSTATE_UINT16(frame_number, OHCIState), + VMSTATE_UINT16(padding, OHCIState), + VMSTATE_UINT32(pstart, OHCIState), + VMSTATE_UINT32(lst, OHCIState), + VMSTATE_UINT32(rhdesc_a, OHCIState), + VMSTATE_UINT32(rhdesc_b, OHCIState), + VMSTATE_UINT32(rhstatus, OHCIState), + VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0, + vmstate_ohci_state_port, OHCIPort), + VMSTATE_UINT32(hstatus, OHCIState), + VMSTATE_UINT32(hmask, OHCIState), + VMSTATE_UINT32(hreset, OHCIState), + VMSTATE_UINT32(htest, OHCIState), + VMSTATE_UINT32(old_ctl, OHCIState), + VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192), + VMSTATE_UINT32(async_td, OHCIState), + VMSTATE_BOOL(async_complete, OHCIState), + VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_ohci_eof_timer, + .needed = ohci_eof_timer_needed, + } , { + /* empty */ + } + } +}; + +static const VMStateDescription vmstate_ohci = { + .name = "ohci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState), + VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState), + VMSTATE_END_OF_LIST() + } +}; + static void ohci_pci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1997,6 +2099,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data) dc->desc = "Apple USB Controller"; dc->props = ohci_pci_properties; dc->hotpluggable = false; + dc->vmsd = &vmstate_ohci; } static const TypeInfo ohci_pci_info = { diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index a470a0b3a6..971a921777 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -142,10 +142,12 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v, Error **errp) { VirtIOBalloon *s = opaque; + Error *local_err = NULL; int64_t value; - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { + visit_type_int(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index aeabf3a459..7f4e7eca0e 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -430,6 +430,12 @@ void virtqueue_map_sg(struct iovec *sg, hwaddr *addr, unsigned int i; hwaddr len; + if (num_sg >= VIRTQUEUE_MAX_SIZE) { + error_report("virtio: map attempt out of bounds: %zd > %d", + num_sg, VIRTQUEUE_MAX_SIZE); + exit(1); + } + for (i = 0; i < num_sg; i++) { len = sg[i].iov_len; sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write); @@ -891,7 +897,9 @@ int virtio_set_features(VirtIODevice *vdev, uint32_t val) int virtio_load(VirtIODevice *vdev, QEMUFile *f) { - int num, i, ret; + int i, ret; + int32_t config_len; + uint32_t num; uint32_t features; uint32_t supported_features; BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); @@ -906,6 +914,9 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) qemu_get_8s(f, &vdev->status); qemu_get_8s(f, &vdev->isr); qemu_get_be16s(f, &vdev->queue_sel); + if (vdev->queue_sel >= VIRTIO_PCI_QUEUE_MAX) { + return -1; + } qemu_get_be32s(f, &features); if (virtio_set_features(vdev, features) < 0) { @@ -914,11 +925,21 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) features, supported_features); return -1; } - vdev->config_len = qemu_get_be32(f); + config_len = qemu_get_be32(f); + if (config_len != vdev->config_len) { + error_report("Unexpected config length 0x%x. Expected 0x%zx", + config_len, vdev->config_len); + return -1; + } qemu_get_buffer(f, vdev->config, vdev->config_len); num = qemu_get_be32(f); + if (num > VIRTIO_PCI_QUEUE_MAX) { + error_report("Invalid number of PCI queues: 0x%x", num); + return -1; + } + for (i = 0; i < num; i++) { vdev->vq[i].vring.num = qemu_get_be32(f); if (k->has_variable_vring_alignment) { diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c index bc994a4c32..68b33e12be 100644 --- a/hw/watchdog/wdt_ib700.c +++ b/hw/watchdog/wdt_ib700.c @@ -42,6 +42,8 @@ typedef struct IB700state { ISADevice parent_obj; QEMUTimer *timer; + + PortioList port_list; } IB700State; /* This is the timer. We use a global here because the watchdog @@ -106,14 +108,13 @@ static const MemoryRegionPortio wdt_portio_list[] = { static void wdt_ib700_realize(DeviceState *dev, Error **errp) { IB700State *s = IB700(dev); - PortioList *port_list = g_new(PortioList, 1); ib700_debug("watchdog init\n"); s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ib700_timer_expired, s); - portio_list_init(port_list, OBJECT(s), wdt_portio_list, s, "ib700"); - portio_list_add(port_list, isa_address_space_io(&s->parent_obj), 0); + portio_list_init(&s->port_list, OBJECT(s), wdt_portio_list, s, "ib700"); + portio_list_add(&s->port_list, isa_address_space_io(&s->parent_obj), 0); } static void wdt_ib700_reset(DeviceState *dev) diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index ce640c61a5..a0ca0aa3df 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,6 +1,5 @@ # xen backend driver support common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o -obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index 197795ffe1..3cd45b407c 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -45,7 +45,6 @@ /* public */ XenXC xen_xc = XC_HANDLER_INITIAL_VALUE; -XenGnttab xen_xcg = XC_HANDLER_INITIAL_VALUE; struct xs_handle *xenstore = NULL; const char *xen_protocol; diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index 8ccc2e4b9c..de9a20f437 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -1123,8 +1123,8 @@ static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s, msi->mapped = true; } msi->flags |= PCI_MSI_FLAGS_ENABLE; - } else { - msi->flags &= ~PCI_MSI_FLAGS_ENABLE; + } else if (msi->mapped) { + xen_pt_msi_disable(s); } /* pass through MSI_ENABLE bit */ @@ -1397,6 +1397,8 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s, if ((*val & PCI_MSIX_FLAGS_ENABLE) && !(*val & PCI_MSIX_FLAGS_MASKALL)) { xen_pt_msix_update(s); + } else if (!(*val & PCI_MSIX_FLAGS_ENABLE) && s->msix->enabled) { + xen_pt_msix_disable(s); } debug_msix_enabled_old = s->msix->enabled; diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c index 6fbe0cc86b..12b4c4560c 100644 --- a/hw/xen/xen_pt_msi.c +++ b/hw/xen/xen_pt_msi.c @@ -282,7 +282,8 @@ void xen_pt_msi_disable(XenPCIPassthroughState *s) msi->initialized); /* clear msi info */ - msi->flags = 0; + msi->flags &= ~PCI_MSI_FLAGS_ENABLE; + msi->initialized = false; msi->mapped = false; msi->pirq = XEN_PT_UNASSIGNED_PIRQ; } @@ -446,7 +447,8 @@ static void pci_msix_write(void *opaque, hwaddr addr, if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) { const volatile uint32_t *vec_ctrl; - if (get_entry_value(entry, offset) == val) { + if (get_entry_value(entry, offset) == val + && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) { return; } diff --git a/hw/xenpv/Makefile.objs b/hw/xenpv/Makefile.objs new file mode 100644 index 0000000000..49f6e9e3c5 --- /dev/null +++ b/hw/xenpv/Makefile.objs @@ -0,0 +1,2 @@ +# Xen PV machine support +obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o diff --git a/hw/i386/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c index c0ab7537df..c0ab7537df 100644 --- a/hw/i386/xen_domainbuild.c +++ b/hw/xenpv/xen_domainbuild.c diff --git a/hw/i386/xen_domainbuild.h b/hw/xenpv/xen_domainbuild.h index 29a91ea7b1..29a91ea7b1 100644 --- a/hw/i386/xen_domainbuild.h +++ b/hw/xenpv/xen_domainbuild.h diff --git a/hw/i386/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 9adb57fc14..9adb57fc14 100644 --- a/hw/i386/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c |