diff options
Diffstat (limited to 'hw')
211 files changed, 2163 insertions, 952 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/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 83e4e93983..9aa6725f09 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -987,8 +987,9 @@ static void v9fs_attach(void *opaque) */ if (!s->migration_blocker) { s->root_fid = fid; - error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION, - s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag); + 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); } out: 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/highbank.c b/hw/arm/highbank.c index 46b9f1e0c0..24231e5448 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -134,7 +134,6 @@ static VMStateDescription vmstate_highbank_regs = { .name = "highbank-regs", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS), VMSTATE_END_OF_LIST(), diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index de542010aa..2a27a19d76 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -405,7 +405,6 @@ static const VMStateDescription mv88w8618_eth_vmsd = { .name = "mv88w8618_eth", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(smir, mv88w8618_eth_state), VMSTATE_UINT32(icr, mv88w8618_eth_state), @@ -642,7 +641,6 @@ static const VMStateDescription musicpal_lcd_vmsd = { .name = "musicpal_lcd", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(brightness, musicpal_lcd_state), VMSTATE_UINT32(mode, musicpal_lcd_state), @@ -769,7 +767,6 @@ static const VMStateDescription mv88w8618_pic_vmsd = { .name = "mv88w8618_pic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(level, mv88w8618_pic_state), VMSTATE_UINT32(enabled, mv88w8618_pic_state), @@ -940,7 +937,6 @@ static const VMStateDescription mv88w8618_timer_vmsd = { .name = "timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_PTIMER(ptimer, mv88w8618_timer_state), VMSTATE_UINT32(limit, mv88w8618_timer_state), @@ -952,7 +948,6 @@ static const VMStateDescription mv88w8618_pit_vmsd = { .name = "mv88w8618_pit", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1, mv88w8618_timer_vmsd, mv88w8618_timer_state), @@ -1041,7 +1036,6 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = { .name = "mv88w8618_flashcfg", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state), VMSTATE_END_OF_LIST() @@ -1381,7 +1375,6 @@ static const VMStateDescription musicpal_gpio_vmsd = { .name = "musicpal_gpio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state), VMSTATE_UINT32(out_state, musicpal_gpio_state), @@ -1548,7 +1541,6 @@ static const VMStateDescription musicpal_key_vmsd = { .name = "musicpal_key", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(kbd_extended, musicpal_key_state), VMSTATE_UINT32(pressed_keys, musicpal_key_state), diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index b433748c60..b28e0521b4 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -2709,8 +2709,8 @@ static void omap_rtc_write(void *opaque, hwaddr addr, s->ti += ti[1]; } else { /* A less accurate version */ - s->ti -= (s->current_tm.tm_year % 100) * 31536000; - s->ti += from_bcd(value) * 31536000; + s->ti -= (time_t)(s->current_tm.tm_year % 100) * 31536000; + s->ti += (time_t)from_bcd(value) * 31536000; } return; diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 04291488e4..2d28a11d5e 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -148,8 +148,7 @@ static const VMStateDescription vmstate_pxa2xx_pm = { .name = "pxa2xx_pm", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40), VMSTATE_END_OF_LIST() } @@ -215,8 +214,7 @@ static const VMStateDescription vmstate_pxa2xx_cm = { .name = "pxa2xx_cm", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4), VMSTATE_UINT32(clkcfg, PXA2xxState), VMSTATE_UINT32(pmnc, PXA2xxState), @@ -440,8 +438,7 @@ static const VMStateDescription vmstate_pxa2xx_mm = { .name = "pxa2xx_mm", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a), VMSTATE_END_OF_LIST() } @@ -732,7 +729,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 +743,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); @@ -1168,7 +1169,6 @@ static const VMStateDescription vmstate_pxa2xx_rtc_regs = { .name = "pxa2xx_rtc", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .pre_save = pxa2xx_rtc_pre_save, .post_load = pxa2xx_rtc_post_load, .fields = (VMStateField[]) { @@ -1432,8 +1432,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c_slave = { .name = "pxa2xx_i2c_slave", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState), VMSTATE_END_OF_LIST() } @@ -1443,8 +1442,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c = { .name = "pxa2xx_i2c", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(control, PXA2xxI2CState), VMSTATE_UINT16(status, PXA2xxI2CState), VMSTATE_UINT8(ibmr, PXA2xxI2CState), @@ -1701,8 +1699,7 @@ static const VMStateDescription vmstate_pxa2xx_i2s = { .name = "pxa2xx_i2s", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2), VMSTATE_UINT32(status, PXA2xxI2SState), VMSTATE_UINT32(mask, PXA2xxI2SState), diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c index 07274285ab..7f75f05137 100644 --- a/hw/arm/pxa2xx_gpio.c +++ b/hw/arm/pxa2xx_gpio.c @@ -313,8 +313,7 @@ static const VMStateDescription vmstate_pxa2xx_gpio_regs = { .name = "pxa2xx-gpio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(lines, PXA2xxGPIOInfo), VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index d37fb543e8..9cfc714874 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -296,7 +296,6 @@ static VMStateDescription vmstate_pxa2xx_pic_regs = { .name = "pxa2xx_pic", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = pxa2xx_pic_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2), diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 392ca84c81..a179c1d694 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -1006,8 +1006,7 @@ static VMStateDescription vmstate_sl_nand_info = { .name = "sl-nand", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(ctl, SLNANDState), VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState), VMSTATE_END_OF_LIST(), @@ -1041,9 +1040,8 @@ static VMStateDescription vmstate_spitz_kbd = { .name = "spitz-keyboard", .version_id = 1, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = spitz_keyboard_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(sense_state, SpitzKeyboardState), VMSTATE_UINT16(strobe_state, SpitzKeyboardState), VMSTATE_UNUSED_TEST(is_version_0, 5), @@ -1076,8 +1074,7 @@ static const VMStateDescription vmstate_corgi_ssp_regs = { .name = "corgi-ssp", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState), VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3), VMSTATE_END_OF_LIST(), @@ -1105,8 +1102,7 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = { .name = "spitz-lcdtg", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG), VMSTATE_UINT32(bl_intensity, SpitzLCDTG), VMSTATE_UINT32(bl_power, SpitzLCDTG), diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index d6cc77b458..a2095c0e84 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -185,12 +185,19 @@ static uint64_t gptm_read(void *opaque, hwaddr offset, case 0x44: /* TBPMR */ return s->match_prescale[1]; case 0x48: /* TAR */ - if (s->control == 1) + if (s->config == 1) { return s->rtc; + } + qemu_log_mask(LOG_UNIMP, + "GPTM: read of TAR but timer read not supported"); + return 0; case 0x4c: /* TBR */ - hw_error("TODO: Timer value read\n"); + qemu_log_mask(LOG_UNIMP, + "GPTM: read of TBR but timer read not supported"); + return 0; default: - hw_error("gptm_read: Bad offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "GPTM: read at bad offset 0x%x\n", (int)offset); return 0; } } @@ -286,8 +293,7 @@ static const VMStateDescription vmstate_stellaris_gptm = { .name = "stellaris_gptm", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(config, gptm_state), VMSTATE_UINT32_ARRAY(mode, gptm_state, 2), VMSTATE_UINT32(control, gptm_state), @@ -643,9 +649,8 @@ static const VMStateDescription vmstate_stellaris_sys = { .name = "stellaris_sys", .version_id = 2, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = stellaris_sys_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(pborctl, ssys_state), VMSTATE_UINT32(ldopctl, ssys_state), VMSTATE_UINT32(int_mask, ssys_state), @@ -851,8 +856,7 @@ static const VMStateDescription vmstate_stellaris_i2c = { .name = "stellaris_i2c", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(msa, stellaris_i2c_state), VMSTATE_UINT32(mcs, stellaris_i2c_state), VMSTATE_UINT32(mdr, stellaris_i2c_state), @@ -1121,8 +1125,7 @@ static const VMStateDescription vmstate_stellaris_adc = { .name = "stellaris_adc", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(actss, stellaris_adc_state), VMSTATE_UINT32(ris, stellaris_adc_state), VMSTATE_UINT32(im, stellaris_adc_state), diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index 170d0ce267..0da9015333 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -199,7 +199,6 @@ static VMStateDescription vmstate_strongarm_pic_regs = { .name = "strongarm_pic", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = strongarm_pic_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32(pending, StrongARMPICState), @@ -424,7 +423,6 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = { .name = "strongarm-rtc", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .pre_save = strongarm_rtc_pre_save, .post_load = strongarm_rtc_post_load, .fields = (VMStateField[]) { @@ -670,7 +668,6 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = { .name = "strongarm-gpio", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_UINT32(ilevel, StrongARMGPIOInfo), VMSTATE_UINT32(olevel, StrongARMGPIOInfo), @@ -842,7 +839,6 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = { .name = "strongarm-ppc", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_UINT32(ilevel, StrongARMPPCInfo), VMSTATE_UINT32(olevel, StrongARMPPCInfo), @@ -1293,7 +1289,6 @@ static const VMStateDescription vmstate_strongarm_uart_regs = { .name = "strongarm-uart", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = strongarm_uart_post_load, .fields = (VMStateField[]) { VMSTATE_UINT8(utcr0, StrongARMUARTState), @@ -1553,7 +1548,6 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = { .name = "strongarm-ssp", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = strongarm_ssp_post_load, .fields = (VMStateField[]) { VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2), diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 2bbc9313d2..ea4f02d32e 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -75,8 +75,6 @@ typedef struct MemMapEntry { typedef struct VirtBoardInfo { struct arm_boot_info bootinfo; const char *cpu_model; - const char *qdevname; - const char *gic_compatible; const MemMapEntry *memmap; const int *irqmap; int smp_cpus; @@ -98,10 +96,10 @@ typedef struct VirtBoardInfo { static const MemMapEntry a15memmap[] = { /* Space up to 0x8000000 is reserved for a boot ROM */ [VIRT_FLASH] = { 0, 0x8000000 }, - [VIRT_CPUPERIPHS] = { 0x8000000, 0x8000 }, + [VIRT_CPUPERIPHS] = { 0x8000000, 0x20000 }, /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */ - [VIRT_GIC_DIST] = { 0x8001000, 0x1000 }, - [VIRT_GIC_CPU] = { 0x8002000, 0x1000 }, + [VIRT_GIC_DIST] = { 0x8000000, 0x10000 }, + [VIRT_GIC_CPU] = { 0x8010000, 0x10000 }, [VIRT_UART] = { 0x9000000, 0x1000 }, [VIRT_MMIO] = { 0xa000000, 0x200 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ @@ -117,16 +115,16 @@ static const int a15irqmap[] = { static VirtBoardInfo machines[] = { { .cpu_model = "cortex-a15", - .qdevname = "a15mpcore_priv", - .gic_compatible = "arm,cortex-a15-gic", + .memmap = a15memmap, + .irqmap = a15irqmap, + }, + { + .cpu_model = "cortex-a57", .memmap = a15memmap, .irqmap = a15irqmap, }, { .cpu_model = "host", - /* We use the A15 private peripheral model to get a V2 GIC */ - .qdevname = "a15mpcore_priv", - .gic_compatible = "arm,cortex-a15-gic", .memmap = a15memmap, .irqmap = a15irqmap, }, @@ -251,8 +249,9 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi) qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle); qemu_fdt_add_subnode(vbi->fdt, "/intc"); + /* 'cortex-a15-gic' means 'GIC v2' */ qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", - vbi->gic_compatible); + "arm,cortex-a15-gic"); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3); qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0); qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", @@ -263,6 +262,56 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi) qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle); } +static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) +{ + /* We create a standalone GIC v2 */ + DeviceState *gicdev; + SysBusDevice *gicbusdev; + const char *gictype = "arm_gic"; + int i; + + if (kvm_irqchip_in_kernel()) { + gictype = "kvm-arm-gic"; + } + + gicdev = qdev_create(NULL, gictype); + qdev_prop_set_uint32(gicdev, "revision", 2); + qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus); + /* Note that the num-irq property counts both internal and external + * interrupts; there are always 32 of the former (mandated by GIC spec). + */ + qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32); + qdev_init_nofail(gicdev); + gicbusdev = SYS_BUS_DEVICE(gicdev); + sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base); + sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); + + /* Wire the outputs from each CPU's generic timer to the + * appropriate GIC PPI inputs, and the GIC's IRQ output to + * the CPU's IRQ input. + */ + for (i = 0; i < smp_cpus; i++) { + DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); + int ppibase = NUM_IRQS + i * 32; + /* physical timer; we wire it up to the non-secure timer's ID, + * since a real A15 always has TrustZone but QEMU doesn't. + */ + qdev_connect_gpio_out(cpudev, 0, + qdev_get_gpio_in(gicdev, ppibase + 30)); + /* virtual timer */ + qdev_connect_gpio_out(cpudev, 1, + qdev_get_gpio_in(gicdev, ppibase + 27)); + + sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); + } + + for (i = 0; i < NUM_IRQS; i++) { + pic[i] = qdev_get_gpio_in(gicdev, i); + } + + fdt_add_gic_node(vbi); +} + static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) { char *nodename; @@ -340,8 +389,6 @@ static void machvirt_init(QEMUMachineInitArgs *args) MemoryRegion *sysmem = get_system_memory(); int n; MemoryRegion *ram = g_new(MemoryRegion, 1); - DeviceState *dev; - SysBusDevice *busdev; const char *cpu_model = args->cpu_model; VirtBoardInfo *vbi; @@ -404,25 +451,7 @@ static void machvirt_init(QEMUMachineInitArgs *args) vmstate_register_ram_global(ram); memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram); - dev = qdev_create(NULL, vbi->qdevname); - qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - /* Note that the num-irq property counts both internal and external - * interrupts; there are always 32 of the former (mandated by GIC spec). - */ - qdev_prop_set_uint32(dev, "num-irq", NUM_IRQS + 32); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, vbi->memmap[VIRT_CPUPERIPHS].base); - fdt_add_gic_node(vbi); - for (n = 0; n < smp_cpus; n++) { - DeviceState *cpudev = DEVICE(qemu_get_cpu(n)); - - sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); - } - - for (n = 0; n < NUM_IRQS; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } + create_gic(vbi, pic); create_uart(vbi, pic); diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 67c1be84ac..5df014b15e 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -164,7 +164,6 @@ static VMStateDescription vmstate_zipit_lcd_state = { .name = "zipit-lcd", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(ssidev, ZipitLCD), VMSTATE_INT32(selected, ZipitLCD), @@ -275,7 +274,6 @@ static VMStateDescription vmstate_aer915_state = { .name = "aer915", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_INT32(len, AER915State), VMSTATE_BUFFER(buf, AER915State), 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/audio/hda-codec.c b/hw/audio/hda-codec.c index a67ca91ca7..48c6eadb03 100644 --- a/hw/audio/hda-codec.c +++ b/hw/audio/hda-codec.c @@ -261,6 +261,9 @@ static void hda_audio_set_amp(HDAAudioStream *st) left = left * 255 / QEMU_HDA_AMP_STEPS; right = right * 255 / QEMU_HDA_AMP_STEPS; + if (!st->state->mixer) { + return; + } if (st->output) { AUD_set_volume_out(st->voice.out, muted, left, right); } else { diff --git a/hw/audio/lm4549.c b/hw/audio/lm4549.c index d75f7ec21f..380ef603bd 100644 --- a/hw/audio/lm4549.c +++ b/hw/audio/lm4549.c @@ -324,9 +324,8 @@ const VMStateDescription vmstate_lm4549_state = { .name = "lm4549_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .post_load = &lm4549_post_load, - .fields = (VMStateField[]) { + .post_load = lm4549_post_load, + .fields = (VMStateField[]) { VMSTATE_UINT32(voice_is_active, lm4549_state), VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128), VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE), diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c index cdce238f55..86992677e3 100644 --- a/hw/audio/marvell_88w8618.c +++ b/hw/audio/marvell_88w8618.c @@ -259,7 +259,6 @@ static const VMStateDescription mv88w8618_audio_vmsd = { .name = "mv88w8618_audio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(playback_mode, mv88w8618_audio_state), VMSTATE_UINT32(status, mv88w8618_audio_state), diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c index 9c0f7a092d..28f55e8535 100644 --- a/hw/audio/milkymist-ac97.c +++ b/hw/audio/milkymist-ac97.c @@ -316,9 +316,8 @@ static const VMStateDescription vmstate_milkymist_ac97 = { .name = "milkymist-ac97", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = ac97_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c index ed82be54e8..19982f2477 100644 --- a/hw/audio/pl041.c +++ b/hw/audio/pl041.c @@ -561,8 +561,7 @@ static const VMStateDescription vmstate_pl041_regfile = { .name = "pl041_regfile", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { #define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile), #include "pl041.hx" #undef REGISTER @@ -574,8 +573,7 @@ static const VMStateDescription vmstate_pl041_fifo = { .name = "pl041_fifo", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(level, pl041_fifo), VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH), VMSTATE_END_OF_LIST() @@ -586,8 +584,7 @@ static const VMStateDescription vmstate_pl041_channel = { .name = "pl041_channel", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_STRUCT(tx_fifo, pl041_channel, 0, vmstate_pl041_fifo, pl041_fifo), VMSTATE_UINT8(tx_enabled, pl041_channel), diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c index c18f2457a1..b50b331402 100644 --- a/hw/audio/wm8750.c +++ b/hw/audio/wm8750.c @@ -583,10 +583,9 @@ static const VMStateDescription vmstate_wm8750 = { .name = CODEC, .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .pre_save = wm8750_pre_save, .post_load = wm8750_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2), VMSTATE_INT32(i2c_len, WM8750State), VMSTATE_INT32(enable, WM8750State), diff --git a/hw/block/ecc.c b/hw/block/ecc.c index 8c888cc12a..10bb233089 100644 --- a/hw/block/ecc.c +++ b/hw/block/ecc.c @@ -81,8 +81,7 @@ VMStateDescription vmstate_ecc_state = { .name = "ecc-state", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(cp, ECCState), VMSTATE_UINT16_ARRAY(lp, ECCState, 2), VMSTATE_UINT16(count, ECCState), diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index e29a738d23..4076114b32 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -653,7 +653,6 @@ static const VMStateDescription vmstate_m25p80 = { .name = "xilinx_spi", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = m25p80_pre_save, .fields = (VMStateField[]) { VMSTATE_UINT8(state, Flash), diff --git a/hw/block/nand.c b/hw/block/nand.c index 6d7c804f01..38eefd436d 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -346,10 +346,9 @@ static const VMStateDescription vmstate_nand = { .name = "nand", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = nand_pre_save, .post_load = nand_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(cle, NANDFlashState), VMSTATE_UINT8(ale, NANDFlashState), VMSTATE_UINT8(ce, NANDFlashState), diff --git a/hw/block/onenand.c b/hw/block/onenand.c index aae9ee7536..60d5311d04 100644 --- a/hw/block/onenand.c +++ b/hw/block/onenand.c @@ -169,7 +169,6 @@ static const VMStateDescription vmstate_onenand = { .name = "onenand", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = onenand_pre_save, .post_load = onenand_post_load, .fields = (VMStateField[]) { 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/char/cadence_uart.c b/hw/char/cadence_uart.c index 1012f1ad64..bf0c853499 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -504,7 +504,6 @@ static const VMStateDescription vmstate_cadence_uart = { .name = "cadence_uart", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .post_load = cadence_uart_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(r, UartState, R_MAX), diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c index fd8e07713d..8abe944de6 100644 --- a/hw/char/digic-uart.c +++ b/hw/char/digic-uart.c @@ -162,7 +162,6 @@ static const VMStateDescription vmstate_digic_uart = { .name = "digic-uart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(reg_rx, DigicUartState), VMSTATE_UINT32(reg_st, DigicUartState), diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index 19b59ccddb..7614e5860f 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -560,7 +560,6 @@ static const VMStateDescription vmstate_exynos4210_uart_fifo = { .name = "exynos4210.uart.fifo", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(sp, Exynos4210UartFIFO), VMSTATE_UINT32(rp, Exynos4210UartFIFO), @@ -573,7 +572,6 @@ static const VMStateDescription vmstate_exynos4210_uart = { .name = "exynos4210.uart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT(rx, Exynos4210UartState, 1, vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO), diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index 7f16835aeb..f3fbc776be 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -76,7 +76,6 @@ static const VMStateDescription vmstate_imx_serial = { .name = "imx-serial", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_INT32(readbuff, IMXSerialState), VMSTATE_UINT32(usr1, IMXSerialState), diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c index f9c388ed0b..c8d5cdb361 100644 --- a/hw/char/ipoctal232.c +++ b/hw/char/ipoctal232.c @@ -124,8 +124,7 @@ static const VMStateDescription vmstate_scc2698_channel = { .name = "scc2698_channel", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(rx_enabled, SCC2698Channel), VMSTATE_UINT8_ARRAY(mr, SCC2698Channel, 2), VMSTATE_UINT8(mr_idx, SCC2698Channel), @@ -141,8 +140,7 @@ static const VMStateDescription vmstate_scc2698_block = { .name = "scc2698_block", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(imr, SCC2698Block), VMSTATE_UINT8(isr, SCC2698Block), VMSTATE_END_OF_LIST() @@ -153,8 +151,7 @@ static const VMStateDescription vmstate_ipoctal = { .name = "ipoctal232", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_IPACK_DEVICE(parent_obj, IPOctalState), VMSTATE_STRUCT_ARRAY(ch, IPOctalState, N_CHANNELS, 1, vmstate_scc2698_channel, SCC2698Channel), diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c index 380cb5dbea..628a86fc06 100644 --- a/hw/char/lm32_juart.c +++ b/hw/char/lm32_juart.c @@ -129,8 +129,7 @@ static const VMStateDescription vmstate_lm32_juart = { .name = "lm32-juart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(jtx, LM32JuartState), VMSTATE_UINT32(jrx, LM32JuartState), VMSTATE_END_OF_LIST() diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c index 84c2549cb7..4f2096637d 100644 --- a/hw/char/lm32_uart.c +++ b/hw/char/lm32_uart.c @@ -270,8 +270,7 @@ static const VMStateDescription vmstate_lm32_uart = { .name = "lm32-uart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c index da51f82eac..d05b825340 100644 --- a/hw/char/milkymist-uart.c +++ b/hw/char/milkymist-uart.c @@ -221,8 +221,7 @@ static const VMStateDescription vmstate_milkymist_uart = { .name = "milkymist-uart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 644aad7cf0..0a451150e5 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -251,8 +251,7 @@ static const VMStateDescription vmstate_pl011 = { .name = "pl011", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(readbuff, PL011State), VMSTATE_UINT32(flags, PL011State), VMSTATE_UINT32(lcr, PL011State), diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c index a2dc1c63b0..80dd0a9e13 100644 --- a/hw/char/sclpconsole-lm.c +++ b/hw/char/sclpconsole-lm.c @@ -291,8 +291,7 @@ static const VMStateDescription vmstate_sclplmconsole = { .name = "sclplmconsole", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(event.event_pending, SCLPConsoleLM), VMSTATE_UINT32(write_errors, SCLPConsoleLM), VMSTATE_UINT32(length, SCLPConsoleLM), diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index ce406730a5..fca105db4e 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -185,8 +185,7 @@ static const VMStateDescription vmstate_sclpconsole = { .name = "sclpconsole", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(event.event_pending, SCLPConsole), VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220), VMSTATE_UINT32(iov_sclp, SCLPConsole), diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 3036bde1f3..466e543b3d 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -206,8 +206,7 @@ const VMStateDescription vmstate_ptimer = { .name = "ptimer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(enabled, ptimer_state), VMSTATE_UINT64(limit, ptimer_state), VMSTATE_UINT64(delta, ptimer_state), 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 c67acf58b5..d8cb5408c3 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -587,8 +587,9 @@ static void set_blocksize(Object *obj, Visitor *v, void *opaque, /* We rely on power-of-2 blocksizes for bitmasks */ if ((value & (value - 1)) != 0) { - error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2, - dev->id?:"", name, (int64_t)value); + error_setg(errp, + "Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2", + dev->id ?: "", name, (int64_t)value); return; } @@ -750,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; @@ -763,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) { @@ -801,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; } } @@ -853,7 +857,7 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, { switch (ret) { case -EEXIST: - error_set(errp, QERR_PROPERTY_VALUE_IN_USE, + error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use", object_get_typename(OBJECT(dev)), prop->name, value); break; default: @@ -862,7 +866,7 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, object_get_typename(OBJECT(dev)), prop->name, value); break; case -ENOENT: - error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, + error_setg(errp, "Property '%s.%s' can't find value '%s'", object_get_typename(OBJECT(dev)), prop->name, value); break; case 0: 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/ads7846.c b/hw/display/ads7846.c index 85252a2329..3f35369bb4 100644 --- a/hw/display/ads7846.c +++ b/hw/display/ads7846.c @@ -121,9 +121,8 @@ static const VMStateDescription vmstate_ads7846 = { .name = "ads7846", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = ads7856_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(ssidev, ADS7846State), VMSTATE_INT32_ARRAY(input, ADS7846State, 8), VMSTATE_INT32(noise, ADS7846State), diff --git a/hw/display/cg3.c b/hw/display/cg3.c index a042b9ecbe..f5a8299e5e 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -324,7 +324,7 @@ static const VMStateDescription vmstate_cg3 = { .version_id = 1, .minimum_version_id = 1, .post_load = vmstate_cg3_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT16(height, CG3State), VMSTATE_UINT16(width, CG3State), VMSTATE_UINT16(depth, CG3State), diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 0d3127da21..d1afc765fb 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -2913,7 +2913,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp) ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev); VGACommonState *s = &d->cirrus_vga.vga; - vga_common_init(s, OBJECT(dev)); + vga_common_init(s, OBJECT(dev), true); cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0, isa_address_space(isadev), isa_address_space_io(isadev)); @@ -2960,7 +2960,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) int16_t device_id = pc->device_id; /* setup VGA */ - vga_common_init(&s->vga, OBJECT(dev)); + vga_common_init(&s->vga, OBJECT(dev), true); cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev), pci_address_space_io(dev)); s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga); diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index 9750330c25..45c62afac1 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -1845,7 +1845,7 @@ static const VMStateDescription exynos4210_fimd_window_vmstate = { .name = "exynos4210.fimd_window", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(wincon, Exynos4210fimdWindow), VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3), VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3), @@ -1875,7 +1875,7 @@ static const VMStateDescription exynos4210_fimd_vmstate = { .version_id = 1, .minimum_version_id = 1, .post_load = exynos4210_fimd_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4), VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4), VMSTATE_UINT32(shadowcon, Exynos4210fimdState), diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index 5c6a2d3605..46f7b41211 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -459,7 +459,6 @@ static const VMStateDescription vmstate_g364fb = { .name = "g364fb", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = g364fb_post_load, .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size), diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c index f9e7d7c981..e9bb005413 100644 --- a/hw/display/jazz_led.c +++ b/hw/display/jazz_led.c @@ -250,7 +250,6 @@ static const VMStateDescription vmstate_jazz_led = { .name = "jazz-led", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = jazz_led_post_load, .fields = (VMStateField[]) { VMSTATE_UINT8(segments, LedState), diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c index b2a5fba0ff..3e1d0b9c20 100644 --- a/hw/display/milkymist-tmu2.c +++ b/hw/display/milkymist-tmu2.c @@ -463,8 +463,7 @@ static const VMStateDescription vmstate_milkymist_tmu2 = { .name = "milkymist-tmu2", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c index 603537aabb..9b35e76ff1 100644 --- a/hw/display/milkymist-vgafb.c +++ b/hw/display/milkymist-vgafb.c @@ -305,9 +305,8 @@ static const VMStateDescription vmstate_milkymist_vgafb = { .name = "milkymist-vgafb", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = vgafb_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c index 09cdf17ab9..80edb70676 100644 --- a/hw/display/pxa2xx_lcd.c +++ b/hw/display/pxa2xx_lcd.c @@ -932,8 +932,7 @@ static const VMStateDescription vmstate_dma_channel = { .name = "dma_channel", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(branch, struct DMAChannel), VMSTATE_UINT8(up, struct DMAChannel), VMSTATE_BUFFER(pbuffer, struct DMAChannel), @@ -959,9 +958,8 @@ static const VMStateDescription vmstate_pxa2xx_lcdc = { .name = "pxa2xx_lcdc", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = pxa2xx_lcdc_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(irqlevel, PXA2xxLCDState), VMSTATE_INT32(transp, PXA2xxLCDState), VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6), diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 47bbf1f1fe..7fb83e4eaf 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2055,19 +2055,18 @@ 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; qxl_init_ramsize(qxl); vga->vram_size_mb = qxl->vga.vram_size >> 20; - vga_common_init(vga, OBJECT(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/ssd0303.c b/hw/display/ssd0303.c index c2eea04934..f6804fb51b 100644 --- a/hw/display/ssd0303.c +++ b/hw/display/ssd0303.c @@ -272,8 +272,7 @@ static const VMStateDescription vmstate_ssd0303 = { .name = "ssd0303_oled", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(row, ssd0303_state), VMSTATE_INT32(col, ssd0303_state), VMSTATE_INT32(start_line, ssd0303_state), 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/tcx.c b/hw/display/tcx.c index 2b37ffac4c..2551b677aa 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -416,9 +416,8 @@ static const VMStateDescription vmstate_tcx = { .name ="tcx", .version_id = 4, .minimum_version_id = 4, - .minimum_version_id_old = 4, .post_load = vmstate_tcx_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(height, TCXState), VMSTATE_UINT16(width, TCXState), VMSTATE_UINT16(depth, TCXState), diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c index afc46b8c9d..4efc222789 100644 --- a/hw/display/vga-isa-mm.c +++ b/hw/display/vga-isa-mm.c @@ -132,7 +132,7 @@ int isa_vga_mm_init(hwaddr vram_base, s = g_malloc0(sizeof(*s)); s->vga.vram_size_mb = VGA_RAM_SIZE >> 20; - vga_common_init(&s->vga, NULL); + vga_common_init(&s->vga, NULL, true); vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space); s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s); diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 1d9ea6b51d..2b480bd44d 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -56,7 +56,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp) MemoryRegion *vga_io_memory; const MemoryRegionPortio *vga_ports, *vbe_ports; - vga_common_init(s, OBJECT(dev)); + vga_common_init(s, OBJECT(dev), true); s->legacy_address_space = isa_address_space(isadev); vga_io_memory = vga_init_io(s, OBJECT(dev), &vga_ports, &vbe_ports); isa_register_portio_list(isadev, 0x3b0, vga_ports, s, "vga"); diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 574ea0e7f9..0865dc490e 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -147,7 +147,7 @@ static int pci_std_vga_initfn(PCIDevice *dev) VGACommonState *s = &d->vga; /* vga + console init */ - vga_common_init(s, OBJECT(dev)); + vga_common_init(s, OBJECT(dev), true); vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev), true); @@ -179,12 +179,51 @@ static int pci_std_vga_initfn(PCIDevice *dev) return 0; } +static int pci_secondary_vga_initfn(PCIDevice *dev) +{ + PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); + VGACommonState *s = &d->vga; + + /* vga + console init */ + vga_common_init(s, OBJECT(dev), false); + s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s); + + /* mmio bar */ + memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio", 4096); + memory_region_init_io(&d->ioport, OBJECT(dev), &pci_vga_ioport_ops, d, + "vga ioports remapped", PCI_VGA_IOPORT_SIZE); + memory_region_init_io(&d->bochs, OBJECT(dev), &pci_vga_bochs_ops, d, + "bochs dispi interface", PCI_VGA_BOCHS_SIZE); + + memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET, + &d->ioport); + memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET, + &d->bochs); + + pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); + pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); + + return 0; +} + +static void pci_secondary_vga_reset(DeviceState *dev) +{ + PCIVGAState *d = DO_UPCAST(PCIVGAState, dev.qdev, dev); + + vga_common_reset(&d->vga); +} + static Property vga_pci_properties[] = { DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16), DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true), DEFINE_PROP_END_OF_LIST(), }; +static Property secondary_pci_properties[] = { + DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16), + DEFINE_PROP_END_OF_LIST(), +}; + static void vga_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -201,6 +240,20 @@ static void vga_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } +static void secondary_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_secondary_vga_initfn; + k->vendor_id = PCI_VENDOR_ID_QEMU; + k->device_id = PCI_DEVICE_ID_QEMU_VGA; + k->class_id = PCI_CLASS_DISPLAY_OTHER; + dc->vmsd = &vmstate_vga_pci; + dc->props = secondary_pci_properties; + dc->reset = pci_secondary_vga_reset; +} + static const TypeInfo vga_info = { .name = "VGA", .parent = TYPE_PCI_DEVICE, @@ -208,9 +261,17 @@ static const TypeInfo vga_info = { .class_init = vga_class_init, }; +static const TypeInfo secondary_info = { + .name = "secondary-vga", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIVGAState), + .class_init = secondary_class_init, +}; + static void vga_register_types(void) { type_register_static(&vga_info); + type_register_static(&secondary_info); } type_init(vga_register_types) diff --git a/hw/display/vga.c b/hw/display/vga.c index 063319d34d..8cd6afe83a 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -171,6 +171,10 @@ static void vga_update_memory_access(VGACommonState *s) MemoryRegion *region, *old_region = s->chain4_alias; hwaddr base, offset, size; + if (s->legacy_address_space == NULL) { + return; + } + s->chain4_alias = NULL; if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) == @@ -2252,7 +2256,7 @@ static const GraphicHwOps vga_ops = { .text_update = vga_update_text, }; -void vga_common_init(VGACommonState *s, Object *obj) +void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate) { int i, j, v, b; @@ -2289,7 +2293,7 @@ void vga_common_init(VGACommonState *s, Object *obj) s->is_vbe_vmstate = 1; memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size); - vmstate_register_ram_global(&s->vram); + vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj)); xen_register_framebuffer(&s->vram); s->vram_ptr = memory_region_get_ram_ptr(&s->vram); s->get_bpp = vga_get_bpp; @@ -2351,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); @@ -2367,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 e6418906a7..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]; @@ -177,7 +179,7 @@ static inline int c6_to_8(int v) return (v << 2) | (b << 1) | b; } -void vga_common_init(VGACommonState *s, Object *obj); +void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate); void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space, MemoryRegion *address_space_io, bool init_vga_ports); MemoryRegion *vga_init_io(VGACommonState *s, Object *obj, diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 6ae3348deb..9ba47e6c63 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1207,7 +1207,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s, vmstate_register_ram_global(&s->fifo_ram); s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram); - vga_common_init(&s->vga, OBJECT(dev)); + vga_common_init(&s->vga, OBJECT(dev), true); vga_init(&s->vga, OBJECT(dev), address_space, io, true); vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga); s->new_depth = 32; 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/omap_dma.c b/hw/dma/omap_dma.c index 0e8cccd27f..0f35c42c05 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -973,7 +973,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, case 0x22: /* DMA_COLOR_U */ ch->color &= 0xffff; - ch->color |= value << 16; + ch->color |= (uint32_t)value << 16; break; case 0x24: /* DMA_CCR2 */ @@ -1043,7 +1043,7 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0xbca: /* TOP_B1_U */ s->src_f1_top &= 0x0000ffff; - s->src_f1_top |= value << 16; + s->src_f1_top |= (uint32_t)value << 16; break; case 0xbcc: /* BOT_B1_L */ @@ -1265,7 +1265,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ s->src_f1_top &= 0x0000ffff; - s->src_f1_top |= value << 16; + s->src_f1_top |= (uint32_t)value << 16; break; case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ @@ -1275,7 +1275,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ s->src_f1_bottom &= 0x0000ffff; - s->src_f1_bottom |= value << 16; + s->src_f1_bottom |= (uint32_t)value << 16; break; case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ @@ -1285,7 +1285,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ s->src_f2_top &= 0x0000ffff; - s->src_f2_top |= value << 16; + s->src_f2_top |= (uint32_t)value << 16; break; case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ @@ -1295,7 +1295,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ s->src_f2_bottom &= 0x0000ffff; - s->src_f2_bottom |= value << 16; + s->src_f2_bottom |= (uint32_t)value << 16; break; default: diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index 608a58c47d..6b6eaaeb47 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -138,7 +138,6 @@ static const VMStateDescription vmstate_pl330_chan = { .name = "pl330_chan", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(src, PL330Chan), VMSTATE_UINT32(dst, PL330Chan), @@ -170,7 +169,6 @@ static const VMStateDescription vmstate_pl330_fifo = { .name = "pl330_chan", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size), VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size), @@ -195,7 +193,6 @@ static const VMStateDescription vmstate_pl330_queue_entry = { .name = "pl330_queue_entry", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(addr, PL330QueueEntry), VMSTATE_UINT32(len, PL330QueueEntry), @@ -218,7 +215,6 @@ static const VMStateDescription vmstate_pl330_queue = { .name = "pl330_queue", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1, vmstate_pl330_queue_entry, PL330QueueEntry), @@ -279,7 +275,6 @@ static const VMStateDescription vmstate_pl330 = { .name = "pl330", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan), VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0, diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c index c013abb313..d4501fb4cb 100644 --- a/hw/dma/pxa2xx_dma.c +++ b/hw/dma/pxa2xx_dma.c @@ -514,7 +514,6 @@ static VMStateDescription vmstate_pxa2xx_dma_chan = { .name = "pxa2xx_dma_chan", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(descr, PXA2xxDMAChannel), VMSTATE_UINT32(src, PXA2xxDMAChannel), @@ -530,7 +529,6 @@ static VMStateDescription vmstate_pxa2xx_dma = { .name = "pxa2xx_dma", .version_id = 1, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_UNUSED_TEST(is_version_0, 4), VMSTATE_UINT32(stopintr, PXA2xxDMAState), diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index eac338f1bc..e6a453ce5c 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -263,8 +263,7 @@ static const VMStateDescription vmstate_dma = { .name ="sparc32_dma", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(dmaregs, DMAState, DMA_REGS), VMSTATE_END_OF_LIST() } diff --git a/hw/dma/sun4m_iommu.c b/hw/dma/sun4m_iommu.c index 899d454353..ec7c2efcd9 100644 --- a/hw/dma/sun4m_iommu.c +++ b/hw/dma/sun4m_iommu.c @@ -327,8 +327,7 @@ static const VMStateDescription vmstate_iommu = { .name ="iommu", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, IOMMUState, IOMMU_NREGS), VMSTATE_UINT64(iostart, IOMMUState), VMSTATE_END_OF_LIST() 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/max7310.c b/hw/gpio/max7310.c index cfcd89ca2b..7fbf313ce8 100644 --- a/hw/gpio/max7310.c +++ b/hw/gpio/max7310.c @@ -152,8 +152,7 @@ static const VMStateDescription vmstate_max7310 = { .name = "max7310", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(i2c_command_byte, MAX7310State), VMSTATE_INT32(len, MAX7310State), VMSTATE_UINT8(level, MAX7310State), diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c index dc79a8baa6..94083424f8 100644 --- a/hw/gpio/zaurus.c +++ b/hw/gpio/zaurus.c @@ -203,18 +203,27 @@ 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, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = scoop_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(status, ScoopInfo), VMSTATE_UINT16(power, ScoopInfo), 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/core.c b/hw/i2c/core.c index efd8b4fafb..5a64026347 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -52,10 +52,9 @@ static const VMStateDescription vmstate_i2c_bus = { .name = "i2c_bus", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = i2c_bus_pre_save, .post_load = i2c_bus_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(saved_address, I2CBus), VMSTATE_END_OF_LIST() } @@ -194,9 +193,8 @@ const VMStateDescription vmstate_i2c_slave = { .name = "I2CSlave", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = i2c_slave_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(address, I2CSlave), VMSTATE_END_OF_LIST() } 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/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index 295b62ed29..0803dc4d18 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -48,7 +48,6 @@ static const VMStateDescription vmstate_ich9_smbus = { .name = "ich9_smb", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState), VMSTATE_END_OF_LIST() 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/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index a825871d8a..de33657563 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -394,9 +394,10 @@ static uint8_t pci_find_cap_offset(PCIDevice *d, uint8_t cap, uint8_t start) return 0; } -static int assigned_dev_register_regions(PCIRegion *io_regions, - unsigned long regions_num, - AssignedDevice *pci_dev) +static void assigned_dev_register_regions(PCIRegion *io_regions, + unsigned long regions_num, + AssignedDevice *pci_dev, + Error **errp) { uint32_t i; PCIRegion *cur_region = io_regions; @@ -425,9 +426,9 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) { pci_dev->v_addrs[i].u.r_virtbase = NULL; - error_report("%s: Error: Couldn't mmap 0x%" PRIx64 "!", - __func__, cur_region->base_addr); - return -1; + error_setg_errno(errp, errno, "Couldn't mmap 0x%" PRIx64 "!", + cur_region->base_addr); + return; } pci_dev->v_addrs[i].r_size = cur_region->size; @@ -496,10 +497,10 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, } /* success */ - return 0; } -static int get_real_id(const char *devpath, const char *idname, uint16_t *val) +static void get_real_id(const char *devpath, const char *idname, uint16_t *val, + Error **errp) { FILE *f; char name[128]; @@ -508,39 +509,39 @@ static int get_real_id(const char *devpath, const char *idname, uint16_t *val) snprintf(name, sizeof(name), "%s%s", devpath, idname); f = fopen(name, "r"); if (f == NULL) { - error_report("%s: %s: %m", __func__, name); - return -1; + error_setg_file_open(errp, errno, name); + return; } if (fscanf(f, "%li\n", &id) == 1) { *val = id; } else { - fclose(f); - return -1; + error_setg(errp, "Failed to parse contents of '%s'", name); } fclose(f); - - return 0; } -static int get_real_vendor_id(const char *devpath, uint16_t *val) +static void get_real_vendor_id(const char *devpath, uint16_t *val, + Error **errp) { - return get_real_id(devpath, "vendor", val); + get_real_id(devpath, "vendor", val, errp); } -static int get_real_device_id(const char *devpath, uint16_t *val) +static void get_real_device_id(const char *devpath, uint16_t *val, + Error **errp) { - return get_real_id(devpath, "device", val); + get_real_id(devpath, "device", val, errp); } -static int get_real_device(AssignedDevice *pci_dev) +static void get_real_device(AssignedDevice *pci_dev, Error **errp) { char dir[128], name[128]; - int fd, r = 0, v; + int fd, r = 0; FILE *f; uint64_t start, end, size, flags; uint16_t id; PCIRegion *rp; PCIDevRegions *dev = &pci_dev->real_device; + Error *local_err = NULL; dev->region_number = 0; @@ -551,16 +552,19 @@ static int get_real_device(AssignedDevice *pci_dev) snprintf(name, sizeof(name), "%sconfig", dir); if (pci_dev->configfd_name && *pci_dev->configfd_name) { - dev->config_fd = monitor_handle_fd_param(cur_mon, pci_dev->configfd_name); - if (dev->config_fd < 0) { - return 1; + dev->config_fd = monitor_handle_fd_param2(cur_mon, + pci_dev->configfd_name, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } } else { dev->config_fd = open(name, O_RDWR); if (dev->config_fd == -1) { - error_report("%s: %s: %m", __func__, name); - return 1; + error_setg_file_open(errp, errno, name); + return; } } again: @@ -570,7 +574,10 @@ again: if (errno == EINTR || errno == EAGAIN) { goto again; } - error_report("%s: read failed, errno = %d", __func__, errno); + error_setg_errno(errp, errno, "read(\"%s\")", + (pci_dev->configfd_name && *pci_dev->configfd_name) ? + pci_dev->configfd_name : name); + return; } /* Restore or clear multifunction, this is always controlled by qemu */ @@ -590,8 +597,8 @@ again: f = fopen(name, "r"); if (f == NULL) { - error_report("%s: %s: %m", __func__, name); - return 1; + error_setg_file_open(errp, errno, name); + return; } for (r = 0; r < PCI_ROM_SLOT; r++) { @@ -634,17 +641,19 @@ again: fclose(f); /* read and fill vendor ID */ - v = get_real_vendor_id(dir, &id); - if (v) { - return 1; + get_real_vendor_id(dir, &id, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } pci_dev->dev.config[0] = id & 0xff; pci_dev->dev.config[1] = (id & 0xff00) >> 8; /* read and fill device ID */ - v = get_real_device_id(dir, &id); - if (v) { - return 1; + get_real_device_id(dir, &id, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } pci_dev->dev.config[2] = id & 0xff; pci_dev->dev.config[3] = (id & 0xff00) >> 8; @@ -653,7 +662,6 @@ again: PCI_COMMAND_MASTER | PCI_COMMAND_INTX_DISABLE); dev->region_number = r; - return 0; } static void free_msi_virqs(AssignedDevice *dev) @@ -726,11 +734,17 @@ static void free_assigned_device(AssignedDevice *dev) free_msi_virqs(dev); } -static void assign_failed_examine(AssignedDevice *dev) +/* This function tries to determine the cause of the PCI assignment failure. It + * always returns the cause as a dynamically allocated, human readable string. + * If the function fails to determine the cause for any internal reason, then + * the returned string will state that fact. + */ +static char *assign_failed_examine(const AssignedDevice *dev) { char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns; uint16_t vendor_id, device_id; int r; + Error *local_err = NULL; snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/", dev->host.domain, dev->host.bus, dev->host.slot, @@ -751,13 +765,17 @@ static void assign_failed_examine(AssignedDevice *dev) ns++; - if (get_real_vendor_id(dir, &vendor_id) || - get_real_device_id(dir, &device_id)) { + if ((get_real_vendor_id(dir, &vendor_id, &local_err), local_err) || + (get_real_device_id(dir, &device_id, &local_err), local_err)) { + /* We're already analyzing an assignment error, so we suppress this + * one just like the others above. + */ + error_free(local_err); goto fail; } - error_printf("*** The driver '%s' is occupying your device " - "%04x:%02x:%02x.%x.\n" + return g_strdup_printf( + "*** The driver '%s' is occupying your device %04x:%02x:%02x.%x.\n" "***\n" "*** You can try the following commands to free it:\n" "***\n" @@ -773,13 +791,11 @@ static void assign_failed_examine(AssignedDevice *dev) ns, dev->host.domain, dev->host.bus, dev->host.slot, dev->host.function, vendor_id, device_id); - return; - fail: - error_report("Couldn't find out why."); + return g_strdup("Couldn't find out why."); } -static int assign_device(AssignedDevice *dev) +static void assign_device(AssignedDevice *dev, Error **errp) { uint32_t flags = KVM_DEV_ASSIGN_ENABLE_IOMMU; int r; @@ -787,15 +803,15 @@ static int assign_device(AssignedDevice *dev) /* Only pass non-zero PCI segment to capable module */ if (!kvm_check_extension(kvm_state, KVM_CAP_PCI_SEGMENT) && dev->host.domain) { - error_report("Can't assign device inside non-zero PCI segment " - "as this KVM module doesn't support it."); - return -ENODEV; + error_setg(errp, "Can't assign device inside non-zero PCI segment " + "as this KVM module doesn't support it."); + return; } if (!kvm_check_extension(kvm_state, KVM_CAP_IOMMU)) { - error_report("No IOMMU found. Unable to assign device \"%s\"", - dev->dev.qdev.id); - return -ENODEV; + error_setg(errp, "No IOMMU found. Unable to assign device \"%s\"", + dev->dev.qdev.id); + return; } if (dev->features & ASSIGNED_DEVICE_SHARE_INTX_MASK && @@ -805,36 +821,39 @@ static int assign_device(AssignedDevice *dev) r = kvm_device_pci_assign(kvm_state, &dev->host, flags, &dev->dev_id); if (r < 0) { - error_report("Failed to assign device \"%s\" : %s", - dev->dev.qdev.id, strerror(-r)); - switch (r) { - case -EBUSY: - assign_failed_examine(dev); + case -EBUSY: { + char *cause; + + cause = assign_failed_examine(dev); + error_setg_errno(errp, -r, "Failed to assign device \"%s\"\n%s", + dev->dev.qdev.id, cause); + g_free(cause); break; + } default: + error_setg_errno(errp, -r, "Failed to assign device \"%s\"", + dev->dev.qdev.id); break; } } - return r; } -static bool check_irqchip_in_kernel(void) +static void verify_irqchip_in_kernel(Error **errp) { if (kvm_irqchip_in_kernel()) { - return true; + return; } - error_report("pci-assign: error: requires KVM with in-kernel irqchip " - "enabled"); - return false; + error_setg(errp, "pci-assign requires KVM with in-kernel irqchip enabled"); } -static int assign_intx(AssignedDevice *dev) +static int assign_intx(AssignedDevice *dev, Error **errp) { AssignedIRQType new_type; PCIINTxRoute intx_route; bool intx_host_msi; int r; + Error *local_err = NULL; /* Interrupt PIN 0 means don't use INTx */ if (assigned_dev_pci_read_byte(&dev->dev, PCI_INTERRUPT_PIN) == 0) { @@ -842,7 +861,9 @@ static int assign_intx(AssignedDevice *dev) return 0; } - if (!check_irqchip_in_kernel()) { + verify_irqchip_in_kernel(&local_err); + if (local_err) { + error_propagate(errp, local_err); return -ENOTSUP; } @@ -905,10 +926,11 @@ retry: dev->features |= ASSIGNED_DEVICE_PREFER_MSI_MASK; goto retry; } - error_report("Failed to assign irq for \"%s\": %s", - dev->dev.qdev.id, strerror(-r)); - error_report("Perhaps you are assigning a device " - "that shares an IRQ with another device?"); + error_setg_errno(errp, -r, + "Failed to assign irq for \"%s\"\n" + "Perhaps you are assigning a device " + "that shares an IRQ with another device?", + dev->dev.qdev.id); return r; } @@ -934,8 +956,11 @@ static void assigned_dev_update_irq_routing(PCIDevice *dev) Error *err = NULL; int r; - r = assign_intx(assigned_dev); + r = assign_intx(assigned_dev, &err); if (r < 0) { + error_report("%s", error_get_pretty(err)); + error_free(err); + err = NULL; qdev_unplug(&dev->qdev, &err); assert(!err); } @@ -986,7 +1011,13 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev) assigned_dev->intx_route.irq = -1; assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSI; } else { - assign_intx(assigned_dev); + Error *local_err = NULL; + + assign_intx(assigned_dev, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + error_free(local_err); + } } } @@ -1128,7 +1159,13 @@ static void assigned_dev_update_msix(PCIDevice *pci_dev) assigned_dev->intx_route.irq = -1; assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSIX; } else { - assign_intx(assigned_dev); + Error *local_err = NULL; + + assign_intx(assigned_dev, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + error_free(local_err); + } } } @@ -1214,11 +1251,12 @@ static void assigned_dev_setup_cap_read(AssignedDevice *dev, uint32_t offset, assigned_dev_emulate_config_read(dev, offset + PCI_CAP_LIST_NEXT, 1); } -static int assigned_device_pci_cap_init(PCIDevice *pci_dev) +static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) { AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); PCIRegion *pci_region = dev->real_device.regions; int ret, pos; + Error *local_err = NULL; /* Clear initial capabilities pointer and status copied from hw */ pci_set_byte(pci_dev->config + PCI_CAPABILITY_LIST, 0); @@ -1230,13 +1268,17 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) * MSI capability is the 1st capability in capability config */ pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0); if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) { - if (!check_irqchip_in_kernel()) { + verify_irqchip_in_kernel(&local_err); + if (local_err) { + error_propagate(errp, local_err); return -ENOTSUP; } dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI; /* Only 32-bit/no-mask currently supported */ - ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSI, pos, 10); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSI, pos, 10, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } pci_dev->msi_cap = pos; @@ -1258,20 +1300,26 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) if (pos != 0 && kvm_device_msix_supported(kvm_state)) { int bar_nr; uint32_t msix_table_entry; + uint16_t msix_max; - if (!check_irqchip_in_kernel()) { + verify_irqchip_in_kernel(&local_err); + if (local_err) { + error_propagate(errp, local_err); return -ENOTSUP; } dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX; - ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSIX, pos, 12); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSIX, pos, 12, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } pci_dev->msix_cap = pos; - pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, - pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) & - PCI_MSIX_FLAGS_QSIZE); + msix_max = (pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) & + PCI_MSIX_FLAGS_QSIZE) + 1; + msix_max = MIN(msix_max, KVM_MAX_MSIX_PER_DEV); + pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, msix_max - 1); /* Only enable and function mask bits are writable */ pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS, @@ -1281,9 +1329,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK; msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK; dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry; - dev->msix_max = pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS); - dev->msix_max &= PCI_MSIX_FLAGS_QSIZE; - dev->msix_max += 1; + dev->msix_max = msix_max; } /* Minimal PM support, nothing writable, device appears to NAK changes */ @@ -1291,8 +1337,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) if (pos) { uint16_t pmc; - ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1330,8 +1378,8 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) */ size = MIN(0x3c, PCI_CONFIG_SPACE_SIZE - pos); if (size < 0x34) { - error_report("%s: Invalid size PCIe cap-id 0x%x", - __func__, PCI_CAP_ID_EXP); + error_setg(errp, "Invalid size PCIe cap-id 0x%x", + PCI_CAP_ID_EXP); return -EINVAL; } else if (size != 0x3c) { error_report("WARNING, %s: PCIe cap-id 0x%x has " @@ -1352,13 +1400,15 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) } if (size == 0) { - error_report("%s: Unsupported PCI express capability version %d", - __func__, version); + error_setg(errp, "Unsupported PCI express capability version %d", + version); return -EINVAL; } - ret = pci_add_capability(pci_dev, PCI_CAP_ID_EXP, pos, size); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_EXP, pos, size, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1368,8 +1418,8 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) type = (type & PCI_EXP_FLAGS_TYPE) >> 4; if (type != PCI_EXP_TYPE_ENDPOINT && type != PCI_EXP_TYPE_LEG_END && type != PCI_EXP_TYPE_RC_END) { - error_report("Device assignment only supports endpoint assignment," - " device type %d", type); + error_setg(errp, "Device assignment only supports endpoint " + "assignment, device type %d", type); return -EINVAL; } @@ -1431,8 +1481,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) uint32_t status; /* Only expose the minimum, 8 byte capability */ - ret = pci_add_capability(pci_dev, PCI_CAP_ID_PCIX, pos, 8); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PCIX, pos, 8, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1457,8 +1509,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VPD, 0); if (pos) { /* Direct R/W passthrough */ - ret = pci_add_capability(pci_dev, PCI_CAP_ID_VPD, pos, 8); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VPD, pos, 8, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1473,8 +1527,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) pos += PCI_CAP_LIST_NEXT) { uint8_t len = pci_get_byte(pci_dev->config + pos + PCI_CAP_FLAGS); /* Direct R/W passthrough */ - ret = pci_add_capability(pci_dev, PCI_CAP_ID_VNDR, pos, len); + ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VNDR, pos, len, + &local_err); if (ret < 0) { + error_propagate(errp, local_err); return ret; } @@ -1602,20 +1658,20 @@ static void assigned_dev_msix_reset(AssignedDevice *dev) } } -static int assigned_dev_register_msix_mmio(AssignedDevice *dev) +static void assigned_dev_register_msix_mmio(AssignedDevice *dev, Error **errp) { dev->msix_table = mmap(NULL, MSIX_PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); if (dev->msix_table == MAP_FAILED) { - error_report("fail allocate msix_table! %s", strerror(errno)); - return -EFAULT; + error_setg_errno(errp, errno, "failed to allocate msix_table"); + dev->msix_table = NULL; + return; } assigned_dev_msix_reset(dev); memory_region_init_io(&dev->mmio, OBJECT(dev), &assigned_dev_msix_mmio_ops, dev, "assigned-dev-msix", MSIX_PAGE_SIZE); - return 0; } static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev) @@ -1698,16 +1754,17 @@ static int assigned_initfn(struct PCIDevice *pci_dev) AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); uint8_t e_intx; int r; + Error *local_err = NULL; if (!kvm_enabled()) { - error_report("pci-assign: error: requires KVM support"); - return -1; + error_setg(&local_err, "pci-assign requires KVM support"); + goto exit_with_error; } if (!dev->host.domain && !dev->host.bus && !dev->host.slot && !dev->host.function) { - error_report("pci-assign: error: no host device specified"); - return -1; + error_setg(&local_err, "no host device specified"); + goto exit_with_error; } /* @@ -1730,27 +1787,28 @@ static int assigned_initfn(struct PCIDevice *pci_dev) memcpy(dev->emulate_config_write, dev->emulate_config_read, sizeof(dev->emulate_config_read)); - if (get_real_device(dev)) { - error_report("pci-assign: Error: Couldn't get real device (%s)!", - dev->dev.qdev.id); + get_real_device(dev, &local_err); + if (local_err) { goto out; } - if (assigned_device_pci_cap_init(pci_dev) < 0) { + if (assigned_device_pci_cap_init(pci_dev, &local_err) < 0) { goto out; } /* intercept MSI-X entry page in the MMIO */ if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) { - if (assigned_dev_register_msix_mmio(dev)) { + assigned_dev_register_msix_mmio(dev, &local_err); + if (local_err) { goto out; } } /* handle real device's MMIO/PIO BARs */ - if (assigned_dev_register_regions(dev->real_device.regions, - dev->real_device.region_number, - dev)) { + assigned_dev_register_regions(dev->real_device.regions, + dev->real_device.region_number, dev, + &local_err); + if (local_err) { goto out; } @@ -1761,13 +1819,13 @@ static int assigned_initfn(struct PCIDevice *pci_dev) dev->intx_route.irq = -1; /* assign device to guest */ - r = assign_device(dev); - if (r < 0) { + assign_device(dev, &local_err); + if (local_err) { goto out; } /* assign legacy INTx to the device */ - r = assign_intx(dev); + r = assign_intx(dev, &local_err); if (r < 0) { goto assigned_out; } @@ -1780,8 +1838,14 @@ static int assigned_initfn(struct PCIDevice *pci_dev) assigned_out: deassign_device(dev); + out: free_assigned_device(dev); + +exit_with_error: + assert(local_err); + qerror_report_err(local_err); + error_free(local_err); return -1; } diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index a1c3d1cb85..a967b48965 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -124,14 +124,14 @@ static const TPRInstruction tpr_instr[] = { static void read_guest_rom_state(VAPICROMState *s) { - cpu_physical_memory_rw(s->rom_state_paddr, (void *)&s->rom_state, - sizeof(GuestROMState), 0); + cpu_physical_memory_read(s->rom_state_paddr, &s->rom_state, + sizeof(GuestROMState)); } static void write_guest_rom_state(VAPICROMState *s) { - cpu_physical_memory_rw(s->rom_state_paddr, (void *)&s->rom_state, - sizeof(GuestROMState), 1); + cpu_physical_memory_write(s->rom_state_paddr, &s->rom_state, + sizeof(GuestROMState)); } static void update_guest_rom_state(VAPICROMState *s) @@ -311,16 +311,14 @@ static int update_rom_mapping(VAPICROMState *s, CPUX86State *env, target_ulong i for (pos = le32_to_cpu(s->rom_state.fixup_start); pos < le32_to_cpu(s->rom_state.fixup_end); pos += 4) { - cpu_physical_memory_rw(paddr + pos - s->rom_state.vaddr, - (void *)&offset, sizeof(offset), 0); + cpu_physical_memory_read(paddr + pos - s->rom_state.vaddr, + &offset, sizeof(offset)); offset = le32_to_cpu(offset); - cpu_physical_memory_rw(paddr + offset, (void *)&patch, - sizeof(patch), 0); + cpu_physical_memory_read(paddr + offset, &patch, sizeof(patch)); patch = le32_to_cpu(patch); patch += rom_state_vaddr - le32_to_cpu(s->rom_state.vaddr); patch = cpu_to_le32(patch); - cpu_physical_memory_rw(paddr + offset, (void *)&patch, - sizeof(patch), 1); + cpu_physical_memory_write(paddr + offset, &patch, sizeof(patch)); } read_guest_rom_state(s); s->vapic_paddr = paddr + le32_to_cpu(s->rom_state.vapic_vaddr) - @@ -364,8 +362,8 @@ static int vapic_enable(VAPICROMState *s, X86CPU *cpu) } vapic_paddr = s->vapic_paddr + (((hwaddr)cpu_number) << VAPIC_CPU_SHIFT); - cpu_physical_memory_rw(vapic_paddr + offsetof(VAPICState, enabled), - (void *)&enabled, sizeof(enabled), 1); + cpu_physical_memory_write(vapic_paddr + offsetof(VAPICState, enabled), + &enabled, sizeof(enabled)); apic_enable_vapic(cpu->apic_state, vapic_paddr); s->state = VAPIC_ACTIVE; @@ -535,7 +533,7 @@ static int patch_hypercalls(VAPICROMState *s) uint8_t *rom; rom = g_malloc(s->rom_size); - cpu_physical_memory_rw(rom_paddr, rom, s->rom_size, 0); + cpu_physical_memory_read(rom_paddr, rom, s->rom_size); for (pos = 0; pos < s->rom_size - sizeof(vmcall_pattern); pos++) { if (kvm_irqchip_in_kernel()) { @@ -551,8 +549,7 @@ static int patch_hypercalls(VAPICROMState *s) } if (memcmp(rom + pos, pattern, 7) == 0 && (rom[pos + 7] == alternates[0] || rom[pos + 7] == alternates[1])) { - cpu_physical_memory_rw(rom_paddr + pos + 5, (uint8_t *)patch, - 3, 1); + cpu_physical_memory_write(rom_paddr + pos + 5, patch, 3); /* * Don't flush the tb here. Under ordinary conditions, the patched * calls are miles away from the current IP. Under malicious @@ -760,8 +757,8 @@ static int vapic_post_load(void *opaque, int version_id) run_on_cpu(first_cpu, do_vapic_enable, s); } else { zero = g_malloc0(s->rom_state.vapic_size); - cpu_physical_memory_rw(s->vapic_paddr, zero, - s->rom_state.vapic_size, 1); + cpu_physical_memory_write(s->vapic_paddr, zero, + s->rom_state.vapic_size); g_free(zero); } } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 14f0d91f76..e6369d5be6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -471,11 +471,12 @@ static void port92_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { Port92State *s = opaque; + int oldval = s->outport; DPRINTF("port92: write 0x%02x\n", val); s->outport = val; qemu_set_irq(*s->a20_out, (val >> 1) & 1); - if (val & 1) { + if ((val & 1) && !(oldval & 1)) { qemu_system_reset_request(); } } @@ -612,6 +613,21 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) return e820_entries; } +int e820_get_num_entries(void) +{ + return e820_entries; +} + +bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *length) +{ + if (idx < e820_entries && e820_table[idx].type == cpu_to_le32(type)) { + *address = le64_to_cpu(e820_table[idx].address); + *length = le64_to_cpu(e820_table[idx].length); + return true; + } + return false; +} + /* Calculates the limit to CPU APIC ID values * * This function returns the limit for the APIC ID value, so that all @@ -627,8 +643,8 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus) static FWCfgState *bochs_bios_init(void) { FWCfgState *fw_cfg; - uint8_t *smbios_table; - size_t smbios_len; + uint8_t *smbios_tables, *smbios_anchor; + size_t smbios_tables_len, smbios_anchor_len; uint64_t *numa_fw_cfg; int i, j; unsigned int apic_id_limit = pc_apic_id_limit(max_cpus); @@ -655,10 +671,21 @@ static FWCfgState *bochs_bios_init(void) acpi_tables, acpi_tables_len); fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override()); - smbios_table = smbios_get_table(&smbios_len); - if (smbios_table) + smbios_tables = smbios_get_table_legacy(&smbios_tables_len); + if (smbios_tables) { fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, - smbios_table, smbios_len); + smbios_tables, smbios_tables_len); + } + + smbios_get_tables(&smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len); + if (smbios_anchor) { + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } + fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, &e820_reserve, sizeof(e820_reserve)); fw_cfg_add_file(fw_cfg, "etc/e820", e820_table, @@ -1027,6 +1054,9 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge) sysbus_mmio_map_overlap(SYS_BUS_DEVICE(icc_bridge), 0, APIC_DEFAULT_ADDRESS, 0x1000); } + + /* tell smbios about cpuid version and features */ + smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]); } /* pci-info ROM file. Little endian format */ diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 7930a26c1e..eaf3e61994 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -60,7 +60,8 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; static bool has_pci_info; static bool has_acpi_build = true; -static bool smbios_type1_defaults = true; +static bool smbios_defaults = true; +static bool smbios_legacy_mode; /* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to * host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte * pages in the host. @@ -143,10 +144,10 @@ static void pc_init1(QEMUMachineInitArgs *args, guest_info->has_pci_info = has_pci_info; guest_info->isapc_ram_fw = !pci_enabled; - if (smbios_type1_defaults) { + if (smbios_defaults) { /* These values are guest ABI, do not change */ - smbios_set_type1_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)", - args->machine->name); + smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)", + args->machine->name, smbios_legacy_mode); } /* allocate ram and load rom/bios */ @@ -262,9 +263,15 @@ static void pc_init_pci(QEMUMachineInitArgs *args) pc_init1(args, 1, 1); } +static void pc_compat_2_0(QEMUMachineInitArgs *args) +{ + smbios_legacy_mode = true; +} + static void pc_compat_1_7(QEMUMachineInitArgs *args) { - smbios_type1_defaults = false; + pc_compat_2_0(args); + smbios_defaults = false; gigabyte_align = false; option_rom_has_mr = true; x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC); @@ -303,6 +310,12 @@ static void pc_compat_1_2(QEMUMachineInitArgs *args) x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); } +static void pc_init_pci_2_0(QEMUMachineInitArgs *args) +{ + pc_compat_2_0(args); + pc_init_pci(args); +} + static void pc_init_pci_1_7(QEMUMachineInitArgs *args) { pc_compat_1_7(args); @@ -345,7 +358,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) { has_pci_info = false; has_acpi_build = false; - smbios_type1_defaults = false; + smbios_defaults = false; x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); enable_compat_apic_id_mode(); pc_init1(args, 1, 0); @@ -355,7 +368,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args) { has_pci_info = false; has_acpi_build = false; - smbios_type1_defaults = false; + smbios_defaults = false; if (!args->cpu_model) { args->cpu_model = "486"; } @@ -383,18 +396,30 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args) .desc = "Standard PC (i440FX + PIIX, 1996)", \ .hot_add_cpu = pc_hot_add_cpu -#define PC_I440FX_2_0_MACHINE_OPTIONS \ +#define PC_I440FX_2_1_MACHINE_OPTIONS \ PC_I440FX_MACHINE_OPTIONS, \ .default_machine_opts = "firmware=bios-256k.bin" -static QEMUMachine pc_i440fx_machine_v2_0 = { - PC_I440FX_2_0_MACHINE_OPTIONS, - .name = "pc-i440fx-2.0", +static QEMUMachine pc_i440fx_machine_v2_1 = { + PC_I440FX_2_1_MACHINE_OPTIONS, + .name = "pc-i440fx-2.1", .alias = "pc", .init = pc_init_pci, .is_default = 1, }; +#define PC_I440FX_2_0_MACHINE_OPTIONS PC_I440FX_2_1_MACHINE_OPTIONS + +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 static QEMUMachine pc_i440fx_machine_v1_7 = { @@ -817,6 +842,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { + qemu_register_machine(&pc_i440fx_machine_v2_1); qemu_register_machine(&pc_i440fx_machine_v2_0); qemu_register_machine(&pc_i440fx_machine_v1_7); qemu_register_machine(&pc_i440fx_machine_v1_6); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index c844dc2a9f..9517ec653f 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -50,7 +50,8 @@ static bool has_pci_info; static bool has_acpi_build = true; -static bool smbios_type1_defaults = true; +static bool smbios_defaults = true; +static bool smbios_legacy_mode; /* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to * host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte * pages in the host. @@ -130,10 +131,10 @@ static void pc_q35_init(QEMUMachineInitArgs *args) guest_info->isapc_ram_fw = false; guest_info->has_acpi_build = has_acpi_build; - if (smbios_type1_defaults) { + if (smbios_defaults) { /* These values are guest ABI, do not change */ - smbios_set_type1_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)", - args->machine->name); + smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)", + args->machine->name, smbios_legacy_mode); } /* allocate ram and load rom/bios */ @@ -240,9 +241,15 @@ static void pc_q35_init(QEMUMachineInitArgs *args) } } +static void pc_compat_2_0(QEMUMachineInitArgs *args) +{ + smbios_legacy_mode = true; +} + static void pc_compat_1_7(QEMUMachineInitArgs *args) { - smbios_type1_defaults = false; + pc_compat_2_0(args); + smbios_defaults = false; gigabyte_align = false; option_rom_has_mr = true; x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC); @@ -268,6 +275,12 @@ static void pc_compat_1_4(QEMUMachineInitArgs *args) x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); } +static void pc_q35_init_2_0(QEMUMachineInitArgs *args) +{ + pc_compat_2_0(args); + pc_q35_init(args); +} + static void pc_q35_init_1_7(QEMUMachineInitArgs *args) { pc_compat_1_7(args); @@ -297,15 +310,27 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args) .desc = "Standard PC (Q35 + ICH9, 2009)", \ .hot_add_cpu = pc_hot_add_cpu -#define PC_Q35_2_0_MACHINE_OPTIONS \ +#define PC_Q35_2_1_MACHINE_OPTIONS \ PC_Q35_MACHINE_OPTIONS, \ .default_machine_opts = "firmware=bios-256k.bin" +static QEMUMachine pc_q35_machine_v2_1 = { + PC_Q35_2_1_MACHINE_OPTIONS, + .name = "pc-q35-2.1", + .alias = "q35", + .init = pc_q35_init, +}; + +#define PC_Q35_2_0_MACHINE_OPTIONS PC_Q35_2_1_MACHINE_OPTIONS + static QEMUMachine pc_q35_machine_v2_0 = { PC_Q35_2_0_MACHINE_OPTIONS, .name = "pc-q35-2.0", - .alias = "q35", - .init = pc_q35_init, + .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 @@ -358,6 +383,7 @@ static QEMUMachine pc_q35_machine_v1_4 = { static void pc_q35_machine_init(void) { + qemu_register_machine(&pc_q35_machine_v2_1); qemu_register_machine(&pc_q35_machine_v2_0); qemu_register_machine(&pc_q35_machine_v1_7); qemu_register_machine(&pc_q35_machine_v1_6); diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c index e8f41ad435..76607181c3 100644 --- a/hw/i386/smbios.c +++ b/hw/i386/smbios.c @@ -18,12 +18,13 @@ #include "qemu/config-file.h" #include "qemu/error-report.h" #include "sysemu/sysemu.h" +#include "sysemu/cpus.h" +#include "hw/i386/pc.h" #include "hw/i386/smbios.h" #include "hw/loader.h" -/* - * Structures shared with the BIOS - */ + +/* legacy structures and constants for <= 2.0 machines */ struct smbios_header { uint16_t length; uint8_t type; @@ -46,14 +47,23 @@ struct smbios_table { static uint8_t *smbios_entries; static size_t smbios_entries_len; +static bool smbios_legacy = true; +/* end: legacy structures & constants for <= 2.0 machines */ + + +static uint8_t *smbios_tables; +static size_t smbios_tables_len; +static unsigned smbios_table_max; +static unsigned smbios_table_cnt; +static struct smbios_entry_point ep; + static int smbios_type4_count = 0; static bool smbios_immutable; +static bool smbios_have_defaults; +static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets; -static struct { - bool seen; - int headertype; - Location loc; -} first_opt[2]; +static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1); +static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1); static struct { const char *vendor, *version, *date; @@ -66,6 +76,22 @@ static struct { /* uuid is in qemu_uuid[] */ } type1; +static struct { + const char *manufacturer, *product, *version, *serial, *asset, *location; +} type2; + +static struct { + const char *manufacturer, *version, *serial, *asset, *sku; +} type3; + +static struct { + const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part; +} type4; + +static struct { + const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part; +} type17; + static QemuOptsList qemu_smbios_opts = { .name = "smbios", .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head), @@ -149,6 +175,134 @@ static const QemuOptDesc qemu_smbios_type1_opts[] = { { /* end of list */ } }; +static const QemuOptDesc qemu_smbios_type2_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "manufacturer", + .type = QEMU_OPT_STRING, + .help = "manufacturer name", + },{ + .name = "product", + .type = QEMU_OPT_STRING, + .help = "product name", + },{ + .name = "version", + .type = QEMU_OPT_STRING, + .help = "version number", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "serial number", + },{ + .name = "asset", + .type = QEMU_OPT_STRING, + .help = "asset tag number", + },{ + .name = "location", + .type = QEMU_OPT_STRING, + .help = "location in chassis", + }, + { /* end of list */ } +}; + +static const QemuOptDesc qemu_smbios_type3_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "manufacturer", + .type = QEMU_OPT_STRING, + .help = "manufacturer name", + },{ + .name = "version", + .type = QEMU_OPT_STRING, + .help = "version number", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "serial number", + },{ + .name = "asset", + .type = QEMU_OPT_STRING, + .help = "asset tag number", + },{ + .name = "sku", + .type = QEMU_OPT_STRING, + .help = "SKU number", + }, + { /* end of list */ } +}; + +static const QemuOptDesc qemu_smbios_type4_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "sock_pfx", + .type = QEMU_OPT_STRING, + .help = "socket designation string prefix", + },{ + .name = "manufacturer", + .type = QEMU_OPT_STRING, + .help = "manufacturer name", + },{ + .name = "version", + .type = QEMU_OPT_STRING, + .help = "version number", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "serial number", + },{ + .name = "asset", + .type = QEMU_OPT_STRING, + .help = "asset tag number", + },{ + .name = "part", + .type = QEMU_OPT_STRING, + .help = "part number", + }, + { /* end of list */ } +}; + +static const QemuOptDesc qemu_smbios_type17_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "loc_pfx", + .type = QEMU_OPT_STRING, + .help = "device locator string prefix", + },{ + .name = "bank", + .type = QEMU_OPT_STRING, + .help = "bank locator string", + },{ + .name = "manufacturer", + .type = QEMU_OPT_STRING, + .help = "manufacturer name", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "serial number", + },{ + .name = "asset", + .type = QEMU_OPT_STRING, + .help = "asset tag number", + },{ + .name = "part", + .type = QEMU_OPT_STRING, + .help = "part number", + }, + { /* end of list */ } +}; + static void smbios_register_config(void) { qemu_add_opts(&qemu_smbios_opts); @@ -158,35 +312,17 @@ machine_init(smbios_register_config); static void smbios_validate_table(void) { - if (smbios_type4_count && smbios_type4_count != smp_cpus) { - error_report("Number of SMBIOS Type 4 tables must match cpu count"); + uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets; + + if (smbios_type4_count && smbios_type4_count != expect_t4_count) { + error_report("Expected %d SMBIOS Type 4 tables, got %d instead", + expect_t4_count, smbios_type4_count); exit(1); } } -/* - * To avoid unresolvable overlaps in data, don't allow both - * tables and fields for the same smbios type. - */ -static void smbios_check_collision(int type, int entry) -{ - if (type < ARRAY_SIZE(first_opt)) { - if (first_opt[type].seen) { - if (first_opt[type].headertype != entry) { - error_report("Can't mix file= and type= for same type"); - loc_push_restore(&first_opt[type].loc); - error_report("This is the conflicting setting"); - loc_pop(&first_opt[type].loc); - exit(1); - } - } else { - first_opt[type].seen = true; - first_opt[type].headertype = entry; - loc_save(&first_opt[type].loc); - } - } -} +/* legacy setup functions for <= 2.0 machines */ static void smbios_add_field(int type, int offset, const void *data, size_t len) { struct smbios_field *field; @@ -256,22 +392,13 @@ static void smbios_build_type_1_fields(void) } } -void smbios_set_type1_defaults(const char *manufacturer, - const char *product, const char *version) +uint8_t *smbios_get_table_legacy(size_t *length) { - if (!type1.manufacturer) { - type1.manufacturer = manufacturer; - } - if (!type1.product) { - type1.product = product; - } - if (!type1.version) { - type1.version = version; + if (!smbios_legacy) { + *length = 0; + return NULL; } -} -uint8_t *smbios_get_table(size_t *length) -{ if (!smbios_immutable) { smbios_build_type_0_fields(); smbios_build_type_1_fields(); @@ -281,6 +408,458 @@ uint8_t *smbios_get_table(size_t *length) *length = smbios_entries_len; return smbios_entries; } +/* end: legacy setup functions for <= 2.0 machines */ + + +static bool smbios_skip_table(uint8_t type, bool required_table) +{ + if (test_bit(type, have_binfile_bitmap)) { + return true; /* user provided their own binary blob(s) */ + } + if (test_bit(type, have_fields_bitmap)) { + return false; /* user provided fields via command line */ + } + if (smbios_have_defaults && required_table) { + return false; /* we're building tables, and this one's required */ + } + return true; +} + +#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \ + struct smbios_type_##tbl_type *t; \ + size_t t_off; /* table offset into smbios_tables */ \ + int str_index = 0; \ + do { \ + /* should we skip building this table ? */ \ + if (smbios_skip_table(tbl_type, tbl_required)) { \ + return; \ + } \ + \ + /* use offset of table t within smbios_tables */ \ + /* (pointer must be updated after each realloc) */ \ + t_off = smbios_tables_len; \ + smbios_tables_len += sizeof(*t); \ + smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \ + t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ + \ + t->header.type = tbl_type; \ + t->header.length = sizeof(*t); \ + t->header.handle = tbl_handle; \ + } while (0) + +#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \ + do { \ + int len = (value != NULL) ? strlen(value) + 1 : 0; \ + if (len > 1) { \ + smbios_tables = g_realloc(smbios_tables, \ + smbios_tables_len + len); \ + memcpy(smbios_tables + smbios_tables_len, value, len); \ + smbios_tables_len += len; \ + /* update pointer post-realloc */ \ + t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ + t->field = ++str_index; \ + } else { \ + t->field = 0; \ + } \ + } while (0) + +#define SMBIOS_BUILD_TABLE_POST \ + do { \ + size_t term_cnt, t_size; \ + \ + /* add '\0' terminator (add two if no strings defined) */ \ + term_cnt = (str_index == 0) ? 2 : 1; \ + smbios_tables = g_realloc(smbios_tables, \ + smbios_tables_len + term_cnt); \ + memset(smbios_tables + smbios_tables_len, 0, term_cnt); \ + smbios_tables_len += term_cnt; \ + \ + /* update smbios max. element size */ \ + t_size = smbios_tables_len - t_off; \ + if (t_size > smbios_table_max) { \ + smbios_table_max = t_size; \ + } \ + \ + /* update smbios element count */ \ + smbios_table_cnt++; \ + } while (0) + +static void smbios_build_type_0_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */ + + SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor); + SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version); + + t->bios_starting_address_segment = 0xE800; /* hardcoded in SeaBIOS */ + + SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date); + + t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */ + + /* BIOS characteristics not supported */ + memset(t->bios_characteristics, 0, 8); + t->bios_characteristics[0] = 0x08; + + /* Enable targeted content distribution (needed for SVVP, per SeaBIOS) */ + t->bios_characteristics_extension_bytes[0] = 0; + t->bios_characteristics_extension_bytes[1] = 4; + + if (type0.have_major_minor) { + t->system_bios_major_release = type0.major; + t->system_bios_minor_release = type0.minor; + } else { + t->system_bios_major_release = 0; + t->system_bios_minor_release = 0; + } + + /* hardcoded in SeaBIOS */ + t->embedded_controller_major_release = 0xFF; + t->embedded_controller_minor_release = 0xFF; + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_1_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */ + + SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer); + SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product); + SMBIOS_TABLE_SET_STR(1, version_str, type1.version); + SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial); + if (qemu_uuid_set) { + memcpy(t->uuid, qemu_uuid, 16); + } else { + memset(t->uuid, 0, 16); + } + t->wake_up_type = 0x06; /* power switch */ + SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku); + SMBIOS_TABLE_SET_STR(1, family_str, type1.family); + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_2_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */ + + SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer); + SMBIOS_TABLE_SET_STR(2, product_str, type2.product); + SMBIOS_TABLE_SET_STR(2, version_str, type2.version); + SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial); + SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset); + t->feature_flags = 0x01; /* Motherboard */ + SMBIOS_TABLE_SET_STR(2, location_str, type2.location); + t->chassis_handle = 0x300; /* Type 3 (System enclosure) */ + t->board_type = 0x0A; /* Motherboard */ + t->contained_element_count = 0; + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_3_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */ + + SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer); + t->type = 0x01; /* Other */ + SMBIOS_TABLE_SET_STR(3, version_str, type3.version); + SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial); + SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset); + t->boot_up_state = 0x03; /* Safe */ + t->power_supply_state = 0x03; /* Safe */ + t->thermal_state = 0x03; /* Safe */ + t->security_status = 0x02; /* Unknown */ + t->oem_defined = 0; + t->height = 0; + t->number_of_power_cords = 0; + t->contained_element_count = 0; + SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku); + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_4_table(unsigned instance) +{ + char sock_str[128]; + + SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */ + + snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance); + SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str); + t->processor_type = 0x03; /* CPU */ + SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer); + t->processor_id[0] = smbios_cpuid_version; + t->processor_id[1] = smbios_cpuid_features; + SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version); + t->voltage = 0; + t->external_clock = 0; /* Unknown */ + t->max_speed = 0; /* Unknown */ + t->current_speed = 0; /* Unknown */ + t->status = 0x41; /* Socket populated, CPU enabled */ + t->processor_upgrade = 0x01; /* Other */ + t->l1_cache_handle = 0xFFFF; /* N/A */ + t->l2_cache_handle = 0xFFFF; /* N/A */ + t->l3_cache_handle = 0xFFFF; /* N/A */ + SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial); + SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset); + SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part); + t->core_count = t->core_enabled = smp_cores; + t->thread_count = smp_threads; + t->processor_characteristics = 0x02; /* Unknown */ + t->processor_family = t->processor_family2 = 0x01; /* Other */ + + SMBIOS_BUILD_TABLE_POST; + smbios_type4_count++; +} + +#define ONE_KB ((ram_addr_t)1 << 10) +#define ONE_MB ((ram_addr_t)1 << 20) +#define ONE_GB ((ram_addr_t)1 << 30) + +#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */ + +static void smbios_build_type_16_table(unsigned dimm_cnt) +{ + ram_addr_t size_kb; + + SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */ + + t->location = 0x01; /* Other */ + t->use = 0x03; /* System memory */ + t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */ + size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB; + if (size_kb < MAX_T16_STD_SZ) { + t->maximum_capacity = size_kb; + t->extended_maximum_capacity = 0; + } else { + t->maximum_capacity = MAX_T16_STD_SZ; + t->extended_maximum_capacity = ram_size; + } + t->memory_error_information_handle = 0xFFFE; /* Not provided */ + t->number_of_memory_devices = dimm_cnt; + + SMBIOS_BUILD_TABLE_POST; +} + +#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */ +#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */ + +static void smbios_build_type_17_table(unsigned instance, ram_addr_t size) +{ + char loc_str[128]; + ram_addr_t size_mb; + + SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */ + + t->physical_memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */ + t->memory_error_information_handle = 0xFFFE; /* Not provided */ + t->total_width = 0xFFFF; /* Unknown */ + t->data_width = 0xFFFF; /* Unknown */ + size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB; + if (size_mb < MAX_T17_STD_SZ) { + t->size = size_mb; + t->extended_size = 0; + } else { + assert(size_mb < MAX_T17_EXT_SZ); + t->size = MAX_T17_STD_SZ; + t->extended_size = size_mb; + } + t->form_factor = 0x09; /* DIMM */ + t->device_set = 0; /* Not in a set */ + snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance); + SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str); + SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank); + t->memory_type = 0x07; /* RAM */ + t->type_detail = 0x02; /* Other */ + t->speed = 0; /* Unknown */ + SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer); + SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial); + SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset); + SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part); + t->attributes = 0; /* Unknown */ + t->configured_clock_speed = 0; /* Unknown */ + t->minimum_voltage = 0; /* Unknown */ + t->maximum_voltage = 0; /* Unknown */ + t->configured_voltage = 0; /* Unknown */ + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_19_table(unsigned instance, + ram_addr_t start, ram_addr_t size) +{ + ram_addr_t end, start_kb, end_kb; + + SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */ + + end = start + size - 1; + assert(end > start); + start_kb = start / ONE_KB; + end_kb = end / ONE_KB; + if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) { + t->starting_address = start_kb; + t->ending_address = end_kb; + t->extended_starting_address = t->extended_ending_address = 0; + } else { + t->starting_address = t->ending_address = UINT32_MAX; + t->extended_starting_address = start; + t->extended_ending_address = end; + } + t->memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */ + t->partition_width = 1; /* One device per row */ + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_32_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */ + + memset(t->reserved, 0, 6); + t->boot_status = 0; /* No errors detected */ + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_127_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */ + SMBIOS_BUILD_TABLE_POST; +} + +void smbios_set_cpuid(uint32_t version, uint32_t features) +{ + smbios_cpuid_version = version; + smbios_cpuid_features = features; +} + +#define SMBIOS_SET_DEFAULT(field, value) \ + if (!field) { \ + field = value; \ + } + +#define G_FREE_UNLESS_NULL(ptr) \ + if (ptr != NULL) { \ + g_free(ptr); \ + } + +void smbios_set_defaults(const char *manufacturer, const char *product, + const char *version, bool legacy_mode) +{ + smbios_have_defaults = true; + smbios_legacy = legacy_mode; + + /* drop unwanted version of command-line file blob(s) */ + if (smbios_legacy) { + G_FREE_UNLESS_NULL(smbios_tables); + /* in legacy mode, also complain if fields were given for types > 1 */ + if (find_next_bit(have_fields_bitmap, + SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) { + error_report("can't process fields for smbios " + "types > 1 on machine versions < 2.1!"); + exit(1); + } + } else { + G_FREE_UNLESS_NULL(smbios_entries); + } + + SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type1.product, product); + SMBIOS_SET_DEFAULT(type1.version, version); + SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type2.product, product); + SMBIOS_SET_DEFAULT(type2.version, version); + SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type3.version, version); + SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU"); + SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type4.version, version); + SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM"); + SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer); +} + +static void smbios_entry_point_setup(void) +{ + memcpy(ep.anchor_string, "_SM_", 4); + memcpy(ep.intermediate_anchor_string, "_DMI_", 5); + ep.length = sizeof(struct smbios_entry_point); + ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */ + memset(ep.formatted_area, 0, 5); + + /* compliant with smbios spec v2.8 */ + ep.smbios_major_version = 2; + ep.smbios_minor_version = 8; + ep.smbios_bcd_revision = 0x28; + + /* set during table construction, but BIOS may override: */ + ep.structure_table_length = smbios_tables_len; + ep.max_structure_size = smbios_table_max; + ep.number_of_structures = smbios_table_cnt; + + /* BIOS must recalculate: */ + ep.checksum = 0; + ep.intermediate_checksum = 0; + ep.structure_table_address = 0; /* where BIOS has copied smbios_tables */ +} + +void smbios_get_tables(uint8_t **tables, size_t *tables_len, + uint8_t **anchor, size_t *anchor_len) +{ + unsigned i, dimm_cnt, instance; + + if (smbios_legacy) { + *tables = *anchor = NULL; + *tables_len = *anchor_len = 0; + return; + } + + if (!smbios_immutable) { + smbios_build_type_0_table(); + smbios_build_type_1_table(); + smbios_build_type_2_table(); + smbios_build_type_3_table(); + + smbios_smp_sockets = smp_cpus / (smp_cores * smp_threads); + assert(smbios_smp_sockets >= 1); + + for (i = 0; i < smbios_smp_sockets; i++) { + smbios_build_type_4_table(i); + } + +#define MAX_DIMM_SZ (16ll * ONE_GB) +#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ : ram_size % MAX_DIMM_SZ) + + dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ; + + smbios_build_type_16_table(dimm_cnt); + + for (i = 0; i < dimm_cnt; i++) { + smbios_build_type_17_table(i, GET_DIMM_SZ); + } + + for (i = 0, instance = 0; i < e820_get_num_entries(); i++) { + uint64_t address, length; + if (e820_get_entry(i, E820_RAM, &address, &length)) { + smbios_build_type_19_table(instance++, address, length); + } + } + + smbios_build_type_32_table(); + smbios_build_type_127_table(); + + smbios_validate_table(); + smbios_entry_point_setup(); + smbios_immutable = true; + } + + /* return tables blob and entry point (anchor), and their sizes */ + *tables = smbios_tables; + *tables_len = smbios_tables_len; + *anchor = (uint8_t *)&ep; + *anchor_len = sizeof(struct smbios_entry_point); +} static void save_opt(const char **dest, QemuOpts *opts, const char *name) { @@ -297,11 +876,12 @@ void smbios_entry_add(QemuOpts *opts) const char *val; assert(!smbios_immutable); + val = qemu_opt_get(opts, "file"); if (val) { struct smbios_structure_header *header; - struct smbios_table *table; int size; + struct smbios_table *table; /* legacy mode only */ qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err); if (local_err) { @@ -315,31 +895,60 @@ void smbios_entry_add(QemuOpts *opts) exit(1); } - if (!smbios_entries) { - smbios_entries_len = sizeof(uint16_t); - smbios_entries = g_malloc0(smbios_entries_len); - } - - smbios_entries = g_realloc(smbios_entries, smbios_entries_len + - sizeof(*table) + size); - table = (struct smbios_table *)(smbios_entries + smbios_entries_len); - table->header.type = SMBIOS_TABLE_ENTRY; - table->header.length = cpu_to_le16(sizeof(*table) + size); + /* + * NOTE: standard double '\0' terminator expected, per smbios spec. + * (except in legacy mode, where the second '\0' is implicit and + * will be inserted by the BIOS). + */ + smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size); + header = (struct smbios_structure_header *)(smbios_tables + + smbios_tables_len); - if (load_image(val, table->data) != size) { + if (load_image(val, (uint8_t *)header) != size) { error_report("Failed to load SMBIOS file %s", val); exit(1); } - header = (struct smbios_structure_header *)(table->data); - smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY); + if (test_bit(header->type, have_fields_bitmap)) { + error_report("can't load type %d struct, fields already specified!", + header->type); + exit(1); + } + set_bit(header->type, have_binfile_bitmap); + if (header->type == 4) { smbios_type4_count++; } + smbios_tables_len += size; + if (size > smbios_table_max) { + smbios_table_max = size; + } + smbios_table_cnt++; + + /* add a copy of the newly loaded blob to legacy smbios_entries */ + /* NOTE: This code runs before smbios_set_defaults(), so we don't + * yet know which mode (legacy vs. aggregate-table) will be + * required. We therefore add the binary blob to both legacy + * (smbios_entries) and aggregate (smbios_tables) tables, and + * delete the one we don't need from smbios_set_defaults(), + * once we know which machine version has been requested. + */ + if (!smbios_entries) { + smbios_entries_len = sizeof(uint16_t); + smbios_entries = g_malloc0(smbios_entries_len); + } + smbios_entries = g_realloc(smbios_entries, smbios_entries_len + + size + sizeof(*table)); + table = (struct smbios_table *)(smbios_entries + smbios_entries_len); + table->header.type = SMBIOS_TABLE_ENTRY; + table->header.length = cpu_to_le16(sizeof(*table) + size); + memcpy(table->data, header, size); smbios_entries_len += sizeof(*table) + size; (*(uint16_t *)smbios_entries) = cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); + /* end: add a copy of the newly loaded blob to legacy smbios_entries */ + return; } @@ -347,7 +956,16 @@ void smbios_entry_add(QemuOpts *opts) if (val) { unsigned long type = strtoul(val, NULL, 0); - smbios_check_collision(type, SMBIOS_FIELD_ENTRY); + if (type > SMBIOS_MAX_TYPE) { + error_report("out of range!"); + exit(1); + } + + if (test_bit(type, have_binfile_bitmap)) { + error_report("can't add fields, binary file already loaded!"); + exit(1); + } + set_bit(type, have_fields_bitmap); switch (type) { case 0: @@ -391,6 +1009,57 @@ void smbios_entry_add(QemuOpts *opts) qemu_uuid_set = true; } return; + case 2: + qemu_opts_validate(opts, qemu_smbios_type2_opts, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + exit(1); + } + save_opt(&type2.manufacturer, opts, "manufacturer"); + save_opt(&type2.product, opts, "product"); + save_opt(&type2.version, opts, "version"); + save_opt(&type2.serial, opts, "serial"); + save_opt(&type2.asset, opts, "asset"); + save_opt(&type2.location, opts, "location"); + return; + case 3: + qemu_opts_validate(opts, qemu_smbios_type3_opts, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + exit(1); + } + save_opt(&type3.manufacturer, opts, "manufacturer"); + save_opt(&type3.version, opts, "version"); + save_opt(&type3.serial, opts, "serial"); + save_opt(&type3.asset, opts, "asset"); + save_opt(&type3.sku, opts, "sku"); + return; + case 4: + qemu_opts_validate(opts, qemu_smbios_type4_opts, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + exit(1); + } + save_opt(&type4.sock_pfx, opts, "sock_pfx"); + save_opt(&type4.manufacturer, opts, "manufacturer"); + save_opt(&type4.version, opts, "version"); + save_opt(&type4.serial, opts, "serial"); + save_opt(&type4.asset, opts, "asset"); + save_opt(&type4.part, opts, "part"); + return; + case 17: + qemu_opts_validate(opts, qemu_smbios_type17_opts, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + exit(1); + } + save_opt(&type17.loc_pfx, opts, "loc_pfx"); + save_opt(&type17.bank, opts, "bank"); + save_opt(&type17.manufacturer, opts, "manufacturer"); + save_opt(&type17.serial, opts, "serial"); + save_opt(&type17.asset, opts, "asset"); + save_opt(&type17.part, opts, "part"); + return; default: error_report("Don't know how to build fields for SMBIOS type %ld", type); 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/ide/core.c b/hw/ide/core.c index c943a4d764..1cac5f53dc 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2342,8 +2342,7 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = { .name ="ide_drive/atapi/gesn_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_BOOL(events.new_media, IDEState), VMSTATE_BOOL(events.eject_request, IDEState), VMSTATE_END_OF_LIST() @@ -2354,7 +2353,6 @@ static const VMStateDescription vmstate_ide_tray_state = { .name = "ide_drive/tray_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_BOOL(tray_open, IDEState), VMSTATE_BOOL(tray_locked, IDEState), @@ -2366,10 +2364,9 @@ static const VMStateDescription vmstate_ide_drive_pio_state = { .name = "ide_drive/pio_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = ide_drive_pio_pre_save, .post_load = ide_drive_pio_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(req_nb_sectors, IDEState), VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1, vmstate_info_uint8, uint8_t), @@ -2386,9 +2383,8 @@ const VMStateDescription vmstate_ide_drive = { .name = "ide_drive", .version_id = 3, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = ide_drive_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(mult_sectors, IDEState), VMSTATE_INT32(identify_set, IDEState), VMSTATE_BUFFER_TEST(identify_data, IDEState, is_identify_set), @@ -2431,8 +2427,7 @@ static const VMStateDescription vmstate_ide_error_status = { .name ="ide_bus/error", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(error_status, IDEBus), VMSTATE_END_OF_LIST() } @@ -2442,8 +2437,7 @@ const VMStateDescription vmstate_ide_bus = { .name = "ide_bus", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(cmd, IDEBus), VMSTATE_UINT8(unit, IDEBus), VMSTATE_END_OF_LIST() diff --git a/hw/ide/macio.c b/hw/ide/macio.c index da94580aac..1c20616f5a 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -480,8 +480,7 @@ static const VMStateDescription vmstate_pmac = { .name = "ide", .version_id = 3, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_IDE_BUS(bus, MACIOIDEState), VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState), VMSTATE_END_OF_LIST() diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 21d6495817..f24946ddf6 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -332,8 +332,7 @@ static const VMStateDescription vmstate_microdrive = { .name = "microdrive", .version_id = 3, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(opt, MicroDriveState), VMSTATE_UINT8(stat, MicroDriveState), VMSTATE_UINT8(pins, MicroDriveState), diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 9f66a52599..01c1d0e6ce 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -109,8 +109,7 @@ static const VMStateDescription vmstate_ide_mmio = { .name = "mmio-ide", .version_id = 3, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_IDE_BUS(bus, MMIOState), VMSTATE_IDE_DRIVES(bus.ifs, MMIOState), VMSTATE_END_OF_LIST() diff --git a/hw/input/adb.c b/hw/input/adb.c index a75d3fd7b9..34c8058fc2 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -303,8 +303,7 @@ static const VMStateDescription vmstate_adb_kbd = { .name = "adb_kbd", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BUFFER(data, KBDState), VMSTATE_INT32(rptr, KBDState), VMSTATE_INT32(wptr, KBDState), @@ -518,8 +517,7 @@ static const VMStateDescription vmstate_adb_mouse = { .name = "adb_mouse", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(buttons_state, MouseState), VMSTATE_INT32(last_buttons_state, MouseState), VMSTATE_INT32(dx, MouseState), diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c index 4ae1cd9c80..9eb68e87cb 100644 --- a/hw/input/lm832x.c +++ b/hw/input/lm832x.c @@ -432,9 +432,8 @@ static const VMStateDescription vmstate_lm_kbd = { .name = "LM8323", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = lm_kbd_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_I2C_SLAVE(parent_obj, LM823KbdState), VMSTATE_UINT8(i2c_dir, LM823KbdState), VMSTATE_UINT8(i2c_cycle, LM823KbdState), diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c index ecde33cb95..53ba71410d 100644 --- a/hw/input/milkymist-softusb.c +++ b/hw/input/milkymist-softusb.c @@ -295,8 +295,7 @@ static const VMStateDescription vmstate_milkymist_softusb = { .name = "milkymist-softusb", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX), VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState), VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState), diff --git a/hw/input/pxa2xx_keypad.c b/hw/input/pxa2xx_keypad.c index b90b0ba102..85011145e6 100644 --- a/hw/input/pxa2xx_keypad.c +++ b/hw/input/pxa2xx_keypad.c @@ -291,8 +291,7 @@ static const VMStateDescription vmstate_pxa2xx_keypad = { .name = "pxa2xx_keypad", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(kpc, PXA2xxKeyPadState), VMSTATE_UINT32(kpdk, PXA2xxKeyPadState), VMSTATE_UINT32(kprec, PXA2xxKeyPadState), diff --git a/hw/input/stellaris_input.c b/hw/input/stellaris_input.c index 4e407922a0..0609e80868 100644 --- a/hw/input/stellaris_input.c +++ b/hw/input/stellaris_input.c @@ -51,8 +51,7 @@ static const VMStateDescription vmstate_stellaris_button = { .name = "stellaris_button", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(pressed, gamepad_button), VMSTATE_END_OF_LIST() } @@ -62,8 +61,7 @@ static const VMStateDescription vmstate_stellaris_gamepad = { .name = "stellaris_gamepad", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(extension, gamepad_state), VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0, vmstate_stellaris_button, gamepad_button), 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/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c index 0924d9855c..de820b9723 100644 --- a/hw/intc/allwinner-a10-pic.c +++ b/hw/intc/allwinner-a10-pic.c @@ -97,6 +97,7 @@ static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value, switch (offset) { case AW_A10_PIC_BASE_ADDR: s->base_addr = value & ~0x3; + break; case AW_A10_PIC_PROTECT: s->protect = value; break; @@ -141,7 +142,6 @@ static const VMStateDescription vmstate_aw_a10_pic = { .name = "a10.pic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(vector, AwA10PICState), VMSTATE_UINT32(base_addr, AwA10PICState), diff --git a/hw/intc/apic.c b/hw/intc/apic.c index b8c061bdaa..ef19e5515c 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -98,8 +98,8 @@ static void apic_sync_vapic(APICCommonState *s, int sync_type) return; } if (sync_type & SYNC_FROM_VAPIC) { - cpu_physical_memory_rw(s->vapic_paddr, (void *)&vapic_state, - sizeof(vapic_state), 0); + cpu_physical_memory_read(s->vapic_paddr, &vapic_state, + sizeof(vapic_state)); s->tpr = vapic_state.tpr; } if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) { @@ -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..ce3d903b13 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -200,7 +200,7 @@ void apic_init_reset(DeviceState *dev) s->initial_count = 0; s->initial_count_load_time = 0; s->next_time = 0; - s->wait_for_sipi = 1; + s->wait_for_sipi = !cpu_is_bsp(s->cpu); if (s->timer) { timer_del(s->timer); @@ -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 6066fa6838..75d9c6e41e 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -173,7 +173,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) return 10000; case 0xd00: /* CPUID Base. */ cpu = ARM_CPU(current_cpu); - return cpu->env.cp15.c0_cpuid; + return cpu->midr; case 0xd04: /* Interrupt Control State. */ /* VECTACTIVE */ val = s->gic.running_irq[0]; @@ -443,8 +443,7 @@ static const VMStateDescription vmstate_nvic = { .name = "armv7m_nvic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(systick.control, nvic_state), VMSTATE_UINT32(systick.reload, nvic_state), VMSTATE_INT64(systick.tick, nvic_state), @@ -474,14 +473,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/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index 3287479456..a6b7028906 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -77,7 +77,6 @@ static const VMStateDescription vmstate_exynos4210_combiner_group_state = { .name = "exynos4210.combiner.groupstate", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT8(src_mask, CombinerGroupState), VMSTATE_UINT8(src_pending, CombinerGroupState), @@ -89,7 +88,6 @@ static const VMStateDescription vmstate_exynos4210_combiner = { .name = "exynos4210.combiner", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(group, Exynos4210CombinerState, IIC_NGRP, 0, vmstate_exynos4210_combiner_group_state, CombinerGroupState), diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index 5b913f786e..0590d5dfb8 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -394,7 +394,6 @@ static const VMStateDescription vmstate_exynos4210_irq_gate = { .name = "exynos4210.irq_gate", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in), VMSTATE_END_OF_LIST() 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/imx_avic.c b/hw/intc/imx_avic.c index fb00e910f6..ec5f9ad815 100644 --- a/hw/intc/imx_avic.c +++ b/hw/intc/imx_avic.c @@ -77,7 +77,6 @@ static const VMStateDescription vmstate_imx_avic = { .name = "imx-avic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT64(pending, IMXAVICState), VMSTATE_UINT64(enabled, IMXAVICState), diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c index 32d009f678..72fc9ef674 100644 --- a/hw/intc/lm32_pic.c +++ b/hw/intc/lm32_pic.c @@ -169,8 +169,7 @@ static const VMStateDescription vmstate_lm32_pic = { .name = "lm32-pic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(im, LM32PicState), VMSTATE_UINT32(ip, LM32PicState), VMSTATE_UINT32(irq_state, LM32PicState), 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/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c index 6635407b8b..585ab4ff20 100644 --- a/hw/intc/openpic_kvm.c +++ b/hw/intc/openpic_kvm.c @@ -234,13 +234,9 @@ static void kvm_openpic_realize(DeviceState *dev, Error **errp) int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs) { KVMOpenPICState *opp = KVM_OPENPIC(d); - struct kvm_enable_cap encap = {}; - encap.cap = KVM_CAP_IRQ_MPIC; - encap.args[0] = opp->fd; - encap.args[1] = kvm_arch_vcpu_id(cs); - - return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap); + return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd, + kvm_arch_vcpu_id(cs)); } static Property kvm_openpic_properties[] = { diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index b10fb66b8d..f22aba0313 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -381,8 +381,7 @@ static const VMStateDescription vmstate_intctl_cpu = { .name ="slavio_intctl_cpu", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState), VMSTATE_END_OF_LIST() } @@ -392,9 +391,8 @@ static const VMStateDescription vmstate_intctl = { .name ="slavio_intctl", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = vmstate_intctl_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1, vmstate_intctl_cpu, SLAVIO_CPUINTCTLState), VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState), diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index c93dae053d..09476ae34d 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -331,15 +331,11 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu) if (icpkvm->kernel_xics_fd != -1) { int ret; - struct kvm_enable_cap xics_enable_cap = { - .cap = KVM_CAP_IRQ_XICS, - .flags = 0, - .args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0}, - }; ss->cs = cs; - ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap); + ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, + icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs)); if (ret < 0) { error_report("Unable to connect CPU%ld to kernel XICS: %s", kvm_arch_vcpu_id(cs), strerror(errno)); diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c index 1b228ff4e0..c3682f1b20 100644 --- a/hw/intc/xilinx_intc.c +++ b/hw/intc/xilinx_intc.c @@ -121,6 +121,9 @@ pic_write(void *opaque, hwaddr addr, case R_CIE: p->regs[R_IER] &= ~value; /* Atomic clear ie. */ break; + case R_MER: + p->regs[R_MER] = value & 0x3; + break; case R_ISR: if ((p->regs[R_MER] & 2)) { break; diff --git a/hw/ipack/ipack.c b/hw/ipack/ipack.c index ed63d2ac61..ef032e6604 100644 --- a/hw/ipack/ipack.c +++ b/hw/ipack/ipack.c @@ -89,8 +89,7 @@ const VMStateDescription vmstate_ipack_device = { .name = "ipack_device", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(slot, IPackDevice), VMSTATE_END_OF_LIST() } diff --git a/hw/ipack/tpci200.c b/hw/ipack/tpci200.c index e1b69b4552..42ca923c7d 100644 --- a/hw/ipack/tpci200.c +++ b/hw/ipack/tpci200.c @@ -629,8 +629,7 @@ static const VMStateDescription vmstate_tpci200 = { .name = "tpci200", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, TPCI200State), VMSTATE_BOOL_ARRAY(big_endian, TPCI200State, 3), VMSTATE_UINT8_ARRAY(ctrl, TPCI200State, N_MODULES), 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/microblaze/boot.c b/hw/microblaze/boot.c index 48d9e7afa4..6bf36d046f 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -148,7 +148,7 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, big_endian, ELF_MACHINE, 0); } /* Always boot into physical ram. */ - boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff); + boot_info.bootstrap_pc = (uint32_t)entry; /* If it wasn't an ELF image, try an u-boot image. */ if (kernel_size < 0) { @@ -174,9 +174,15 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, high = ROUND_UP(high + kernel_size, 4); boot_info.initrd_start = high; initrd_offset = boot_info.initrd_start - ddr_base; - initrd_size = load_image_targphys(initrd_filename, - boot_info.initrd_start, - ram_size - initrd_offset); + + 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'\n", initrd_filename); 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/eccmemctl.c b/hw/misc/eccmemctl.c index 549431cb13..8bad6f682b 100644 --- a/hw/misc/eccmemctl.c +++ b/hw/misc/eccmemctl.c @@ -266,8 +266,7 @@ static const VMStateDescription vmstate_ecc = { .name ="ECC", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, ECCState, ECC_NREGS), VMSTATE_BUFFER(diag, ECCState), VMSTATE_UINT32(version, ECCState), diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c index 5ec14d1c86..2b118c7255 100644 --- a/hw/misc/exynos4210_pmu.c +++ b/hw/misc/exynos4210_pmu.c @@ -471,7 +471,7 @@ static const VMStateDescription exynos4210_pmu_vmstate = { .name = "exynos4210.pmu", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(reg, Exynos4210PmuState, PMU_NUM_OF_REGISTERS), VMSTATE_END_OF_LIST() } diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c index 63e33a41da..750b9061db 100644 --- a/hw/misc/imx_ccm.c +++ b/hw/misc/imx_ccm.c @@ -57,7 +57,6 @@ static const VMStateDescription vmstate_imx_ccm = { .name = "imx-ccm", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(ccmr, IMXCCMState), VMSTATE_UINT32(pdr0, IMXCCMState), diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 8d144baa1e..768e5288bc 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -684,8 +684,8 @@ static int pci_ivshmem_init(PCIDevice *dev) } if (s->role_val == IVSHMEM_PEER) { - error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, - "peer mode", "ivshmem"); + error_setg(&s->migration_blocker, + "Migration is disabled when using feature 'peer mode' in device 'ivshmem'"); migrate_add_blocker(s->migration_blocker); } diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c index e394f2e63b..778eb6e042 100644 --- a/hw/misc/lm32_sys.c +++ b/hw/misc/lm32_sys.c @@ -141,8 +141,7 @@ static const VMStateDescription vmstate_lm32_sys = { .name = "lm32-sys", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX), VMSTATE_BUFFER(testname, LM32SysState), VMSTATE_END_OF_LIST() diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index bc71aa7ccd..ff6051defe 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -617,8 +617,7 @@ static const VMStateDescription vmstate_cuda_timer = { .name = "cuda_timer", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT16(latch, CUDATimer), VMSTATE_UINT16(counter_value, CUDATimer), VMSTATE_INT64(load_time, CUDATimer), @@ -632,8 +631,7 @@ static const VMStateDescription vmstate_cuda = { .name = "cuda", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(a, CUDAState), VMSTATE_UINT8(b, CUDAState), VMSTATE_UINT8(dira, CUDAState), diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c index f47a736182..3335476c29 100644 --- a/hw/misc/macio/mac_dbdma.c +++ b/hw/misc/macio/mac_dbdma.c @@ -719,8 +719,7 @@ static const VMStateDescription vmstate_dbdma_channel = { .name = "dbdma_channel", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS), VMSTATE_END_OF_LIST() } @@ -730,8 +729,7 @@ static const VMStateDescription vmstate_dbdma = { .name = "dbdma", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1, vmstate_dbdma_channel, DBDMA_channel), VMSTATE_END_OF_LIST() diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c index bba87c2ec5..bef3651d6e 100644 --- a/hw/misc/max111x.c +++ b/hw/misc/max111x.c @@ -110,8 +110,7 @@ static const VMStateDescription vmstate_max111x = { .name = "max111x", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(parent_obj, MAX111xState), VMSTATE_UINT8(tb1, MAX111xState), VMSTATE_UINT8(rb2, MAX111xState), diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c index aef135e572..f5f4c1b343 100644 --- a/hw/misc/milkymist-hpdmc.c +++ b/hw/misc/milkymist-hpdmc.c @@ -143,8 +143,7 @@ static const VMStateDescription vmstate_milkymist_hpdmc = { .name = "milkymist-hpdmc", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c index b3b2143d51..609f33f9cd 100644 --- a/hw/misc/milkymist-pfpu.c +++ b/hw/misc/milkymist-pfpu.c @@ -513,8 +513,7 @@ static const VMStateDescription vmstate_milkymist_pfpu = { .name = "milkymist-pfpu", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX), VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128), VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS), diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c index c96810fec1..d5090799f8 100644 --- a/hw/misc/mst_fpga.c +++ b/hw/misc/mst_fpga.c @@ -219,12 +219,11 @@ static int mst_fpga_init(SysBusDevice *sbd) } static VMStateDescription vmstate_mst_fpga_regs = { - .name = "mainstone_fpga", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .post_load = mst_fpga_post_load, - .fields = (VMStateField []) { + .name = "mainstone_fpga", + .version_id = 0, + .minimum_version_id = 0, + .post_load = mst_fpga_post_load, + .fields = (VMStateField[]) { VMSTATE_UINT32(prev_level, mst_irq_state), VMSTATE_UINT32(leddat1, mst_irq_state), VMSTATE_UINT32(leddat2, mst_irq_state), diff --git a/hw/misc/omap_gpmc.c b/hw/misc/omap_gpmc.c index 2047274123..cddea241d4 100644 --- a/hw/misc/omap_gpmc.c +++ b/hw/misc/omap_gpmc.c @@ -242,6 +242,10 @@ static void fill_prefetch_fifo(struct omap_gpmc_s *s) if (bytes > s->prefetch.count) { bytes = s->prefetch.count; } + if (is16bit) { + bytes &= ~1; + } + s->prefetch.count -= bytes; s->prefetch.fifopointer += bytes; fptr = 64 - s->prefetch.fifopointer; diff --git a/hw/misc/slavio_misc.c b/hw/misc/slavio_misc.c index 767544eca1..50985958a4 100644 --- a/hw/misc/slavio_misc.c +++ b/hw/misc/slavio_misc.c @@ -400,8 +400,7 @@ static const VMStateDescription vmstate_misc = { .name ="slavio_misc", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(dummy, MiscState), VMSTATE_UINT8(config, MiscState), VMSTATE_UINT8(aux1, MiscState), diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c index 63aa3d6277..f3fe8b81fd 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) { @@ -197,9 +199,8 @@ static const VMStateDescription vmstate_tmp105 = { .name = "TMP105", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = tmp105_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(len, TMP105State), VMSTATE_UINT8_ARRAY(buf, TMP105State, 2), VMSTATE_UINT8(pointer, TMP105State), diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index 2e53a2e21f..964f2532ff 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -428,8 +428,7 @@ static const VMStateDescription vmstate_zynq_slcr = { .name = "zynq_slcr", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, ZynqSLCRState, ZYNQ_SLCR_NUM_REGS), VMSTATE_END_OF_LIST() } diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index e34b25e734..47e70381fe 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: @@ -717,7 +717,6 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) rxbuf_ptr = (void *)buf; } else { unsigned crc_val; - int crc_offset; /* The application wants the FCS field, which QEMU does not provide. * We must try and caclculate one. @@ -727,12 +726,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) memset(rxbuf + size, 0, sizeof(rxbuf) - size); rxbuf_ptr = rxbuf; crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60))); - if (size < 60) { - crc_offset = 60; - } else { - crc_offset = size; - } - memcpy(rxbuf + crc_offset, &crc_val, sizeof(crc_val)); + memcpy(rxbuf + size, &crc_val, sizeof(crc_val)); bytes_to_copy += 4; size += 4; @@ -1257,8 +1251,7 @@ static const VMStateDescription vmstate_cadence_gem = { .name = "cadence_gem", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, GemState, GEM_MAXREG), VMSTATE_UINT16_ARRAY(phy_regs, GemState, 32), VMSTATE_UINT8(phy_loop, GemState), diff --git a/hw/net/lance.c b/hw/net/lance.c index fe18564e1e..7811a9edc2 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -110,8 +110,7 @@ static const VMStateDescription vmstate_lance = { .name = "pcnet", .version_id = 3, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_STRUCT(state, SysBusPCNetState, 0, vmstate_pcnet, PCNetState), VMSTATE_END_OF_LIST() } diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c index 1e9237984d..c023351c0d 100644 --- a/hw/net/milkymist-minimac2.c +++ b/hw/net/milkymist-minimac2.c @@ -492,8 +492,7 @@ static const VMStateDescription vmstate_milkymist_minimac2_mdio = { .name = "milkymist-minimac2-mdio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState), VMSTATE_INT32(count, MilkymistMinimac2MdioState), VMSTATE_UINT32(data, MilkymistMinimac2MdioState), @@ -509,8 +508,7 @@ static const VMStateDescription vmstate_milkymist_minimac2 = { .name = "milkymist-minimac2", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX), VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX), VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0, diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index e421b867e7..b26c369178 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -198,8 +198,7 @@ static const VMStateDescription vmstate_mipsnet = { .name = "mipsnet", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(busy, MIPSnetState), VMSTATE_UINT32(rx_count, MIPSnetState), VMSTATE_UINT32(rx_read, MIPSnetState), diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index 7cb47b3f1f..ebe505784d 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -718,7 +718,6 @@ static void pcnet_s_reset(PCNetState *s) s->csr[94] = 0x0000; s->csr[100] = 0x0200; s->csr[103] = 0x0105; - s->csr[103] = 0x0105; s->csr[112] = 0x0000; s->csr[114] = 0x0000; s->csr[122] = 0x0000; diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index a8e29b3b42..d1dca8f4e2 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -54,7 +54,7 @@ static const VMStateDescription vmstate_smc91c111 = { .name = "smc91c111", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(tcr, smc91c111_state), VMSTATE_UINT16(rcr, smc91c111_state), VMSTATE_UINT16(cr, smc91c111_state), diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index d04e6a46f8..c9ee5d3f10 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -47,6 +47,11 @@ do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0) OBJECT_CHECK(stellaris_enet_state, (obj), TYPE_STELLARIS_ENET) typedef struct { + uint8_t data[2048]; + uint32_t len; +} StellarisEnetRxFrame; + +typedef struct { SysBusDevice parent_obj; uint32_t ris; @@ -59,29 +64,159 @@ typedef struct { uint32_t mtxd; uint32_t mrxd; uint32_t np; - int tx_frame_len; - int tx_fifo_len; + uint32_t tx_fifo_len; uint8_t tx_fifo[2048]; /* Real hardware has a 2k fifo, which works out to be at most 31 packets. We implement a full 31 packet fifo. */ - struct { - uint8_t data[2048]; - int len; - } rx[31]; - uint8_t *rx_fifo; - int rx_fifo_len; - int next_packet; + StellarisEnetRxFrame rx[31]; + uint32_t rx_fifo_offset; + uint32_t next_packet; NICState *nic; NICConf conf; qemu_irq irq; MemoryRegion mmio; } stellaris_enet_state; +static const VMStateDescription vmstate_rx_frame = { + .name = "stellaris_enet/rx_frame", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(data, StellarisEnetRxFrame, 2048), + VMSTATE_UINT32(len, StellarisEnetRxFrame), + VMSTATE_END_OF_LIST() + } +}; + +static int stellaris_enet_post_load(void *opaque, int version_id) +{ + stellaris_enet_state *s = opaque; + int i; + + /* Sanitize inbound state. Note that next_packet is an index but + * np is a size; hence their valid upper bounds differ. + */ + if (s->next_packet >= ARRAY_SIZE(s->rx)) { + return -1; + } + + if (s->np > ARRAY_SIZE(s->rx)) { + return -1; + } + + for (i = 0; i < ARRAY_SIZE(s->rx); i++) { + if (s->rx[i].len > ARRAY_SIZE(s->rx[i].data)) { + return -1; + } + } + + if (s->rx_fifo_offset > ARRAY_SIZE(s->rx[0].data) - 4) { + return -1; + } + + if (s->tx_fifo_len > ARRAY_SIZE(s->tx_fifo)) { + return -1; + } + + return 0; +} + +static const VMStateDescription vmstate_stellaris_enet = { + .name = "stellaris_enet", + .version_id = 2, + .minimum_version_id = 2, + .post_load = stellaris_enet_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ris, stellaris_enet_state), + VMSTATE_UINT32(im, stellaris_enet_state), + VMSTATE_UINT32(rctl, stellaris_enet_state), + VMSTATE_UINT32(tctl, stellaris_enet_state), + VMSTATE_UINT32(thr, stellaris_enet_state), + VMSTATE_UINT32(mctl, stellaris_enet_state), + VMSTATE_UINT32(mdv, stellaris_enet_state), + VMSTATE_UINT32(mtxd, stellaris_enet_state), + VMSTATE_UINT32(mrxd, stellaris_enet_state), + VMSTATE_UINT32(np, stellaris_enet_state), + VMSTATE_UINT32(tx_fifo_len, stellaris_enet_state), + VMSTATE_UINT8_ARRAY(tx_fifo, stellaris_enet_state, 2048), + VMSTATE_STRUCT_ARRAY(rx, stellaris_enet_state, 31, 1, + vmstate_rx_frame, StellarisEnetRxFrame), + VMSTATE_UINT32(rx_fifo_offset, stellaris_enet_state), + VMSTATE_UINT32(next_packet, stellaris_enet_state), + VMSTATE_END_OF_LIST() + } +}; + static void stellaris_enet_update(stellaris_enet_state *s) { qemu_set_irq(s->irq, (s->ris & s->im) != 0); } +/* Return the data length of the packet currently being assembled + * in the TX fifo. + */ +static inline int stellaris_txpacket_datalen(stellaris_enet_state *s) +{ + return s->tx_fifo[0] | (s->tx_fifo[1] << 8); +} + +/* Return true if the packet currently in the TX FIFO is complete, +* ie the FIFO holds enough bytes for the data length, ethernet header, +* payload and optionally CRC. +*/ +static inline bool stellaris_txpacket_complete(stellaris_enet_state *s) +{ + int framelen = stellaris_txpacket_datalen(s); + framelen += 16; + if (!(s->tctl & SE_TCTL_CRC)) { + framelen += 4; + } + /* Cover the corner case of a 2032 byte payload with auto-CRC disabled: + * this requires more bytes than will fit in the FIFO. It's not totally + * clear how the h/w handles this, but if using threshold-based TX + * it will definitely try to transmit something. + */ + framelen = MIN(framelen, ARRAY_SIZE(s->tx_fifo)); + return s->tx_fifo_len >= framelen; +} + +/* Return true if the TX FIFO threshold is enabled and the FIFO + * has filled enough to reach it. + */ +static inline bool stellaris_tx_thr_reached(stellaris_enet_state *s) +{ + return (s->thr < 0x3f && + (s->tx_fifo_len >= 4 * (s->thr * 8 + 1))); +} + +/* Send the packet currently in the TX FIFO */ +static void stellaris_enet_send(stellaris_enet_state *s) +{ + int framelen = stellaris_txpacket_datalen(s); + + /* Ethernet header is in the FIFO but not in the datacount. + * We don't implement explicit CRC, so just ignore any + * CRC value in the FIFO. + */ + framelen += 14; + if ((s->tctl & SE_TCTL_PADEN) && framelen < 60) { + memset(&s->tx_fifo[framelen + 2], 0, 60 - framelen); + framelen = 60; + } + /* This MIN will have no effect unless the FIFO data is corrupt + * (eg bad data from an incoming migration); otherwise the check + * on the datalen at the start of writing the data into the FIFO + * will have caught this. Silently write a corrupt half-packet, + * which is what the hardware does in FIFO underrun situations. + */ + framelen = MIN(framelen, ARRAY_SIZE(s->tx_fifo) - 2); + qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo + 2, framelen); + s->tx_fifo_len = 0; + s->ris |= SE_INT_TXEMP; + stellaris_enet_update(s); + DPRINTF("Done TX\n"); +} + /* TODO: Implement MAC address filtering. */ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size) { @@ -97,7 +232,7 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si return -1; } - DPRINTF("Received packet len=%d\n", size); + DPRINTF("Received packet len=%zu\n", size); n = s->next_packet + s->np; if (n >= 31) n -= 31; @@ -152,21 +287,21 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset, case 0x0c: /* TCTL */ return s->tctl; case 0x10: /* DATA */ - if (s->rx_fifo_len == 0) { - if (s->np == 0) { - BADF("RX underflow\n"); - return 0; - } - s->rx_fifo_len = s->rx[s->next_packet].len; - s->rx_fifo = s->rx[s->next_packet].data; - DPRINTF("RX FIFO start packet len=%d\n", s->rx_fifo_len); + { + uint8_t *rx_fifo; + + if (s->np == 0) { + BADF("RX underflow\n"); + return 0; } - val = s->rx_fifo[0] | (s->rx_fifo[1] << 8) | (s->rx_fifo[2] << 16) - | (s->rx_fifo[3] << 24); - s->rx_fifo += 4; - s->rx_fifo_len -= 4; - if (s->rx_fifo_len <= 0) { - s->rx_fifo_len = 0; + + rx_fifo = s->rx[s->next_packet].data + s->rx_fifo_offset; + + val = rx_fifo[0] | (rx_fifo[1] << 8) | (rx_fifo[2] << 16) + | (rx_fifo[3] << 24); + s->rx_fifo_offset += 4; + if (s->rx_fifo_offset >= s->rx[s->next_packet].len) { + s->rx_fifo_offset = 0; s->next_packet++; if (s->next_packet >= 31) s->next_packet = 0; @@ -174,6 +309,7 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset, DPRINTF("RX done np=%d\n", s->np); } return val; + } case 0x14: /* IA0 */ return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8) | (s->conf.macaddr.a[2] << 16) @@ -212,22 +348,23 @@ static void stellaris_enet_write(void *opaque, hwaddr offset, switch (offset) { case 0x00: /* IACK */ s->ris &= ~value; - DPRINTF("IRQ ack %02x/%02x\n", value, s->ris); + DPRINTF("IRQ ack %02" PRIx64 "/%02x\n", value, s->ris); stellaris_enet_update(s); /* Clearing TXER also resets the TX fifo. */ - if (value & SE_INT_TXER) - s->tx_frame_len = -1; + if (value & SE_INT_TXER) { + s->tx_fifo_len = 0; + } break; case 0x04: /* IM */ - DPRINTF("IRQ mask %02x/%02x\n", value, s->ris); + DPRINTF("IRQ mask %02" PRIx64 "/%02x\n", value, s->ris); s->im = value; stellaris_enet_update(s); break; case 0x08: /* RCTL */ s->rctl = value; if (value & SE_RCTL_RSTFIFO) { - s->rx_fifo_len = 0; s->np = 0; + s->rx_fifo_offset = 0; stellaris_enet_update(s); } break; @@ -235,43 +372,26 @@ static void stellaris_enet_write(void *opaque, hwaddr offset, s->tctl = value; break; case 0x10: /* DATA */ - if (s->tx_frame_len == -1) { - s->tx_frame_len = value & 0xffff; - if (s->tx_frame_len > 2032) { - DPRINTF("TX frame too long (%d)\n", s->tx_frame_len); - s->tx_frame_len = 0; + if (s->tx_fifo_len == 0) { + /* The first word is special, it contains the data length */ + int framelen = value & 0xffff; + if (framelen > 2032) { + DPRINTF("TX frame too long (%d)\n", framelen); s->ris |= SE_INT_TXER; stellaris_enet_update(s); - } else { - DPRINTF("Start TX frame len=%d\n", s->tx_frame_len); - /* The value written does not include the ethernet header. */ - s->tx_frame_len += 14; - if ((s->tctl & SE_TCTL_CRC) == 0) - s->tx_frame_len += 4; - s->tx_fifo_len = 0; - s->tx_fifo[s->tx_fifo_len++] = value >> 16; - s->tx_fifo[s->tx_fifo_len++] = value >> 24; + break; } - } else { + } + + if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) { s->tx_fifo[s->tx_fifo_len++] = value; s->tx_fifo[s->tx_fifo_len++] = value >> 8; s->tx_fifo[s->tx_fifo_len++] = value >> 16; s->tx_fifo[s->tx_fifo_len++] = value >> 24; - if (s->tx_fifo_len >= s->tx_frame_len) { - /* We don't implement explicit CRC, so just chop it off. */ - if ((s->tctl & SE_TCTL_CRC) == 0) - s->tx_frame_len -= 4; - if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) { - memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len); - s->tx_fifo_len = 60; - } - qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo, - s->tx_frame_len); - s->tx_frame_len = -1; - s->ris |= SE_INT_TXEMP; - stellaris_enet_update(s); - DPRINTF("Done TX\n"); - } + } + + if (stellaris_tx_thr_reached(s) && stellaris_txpacket_complete(s)) { + stellaris_enet_send(s); } break; case 0x14: /* IA0 */ @@ -299,9 +419,13 @@ static void stellaris_enet_write(void *opaque, hwaddr offset, case 0x2c: /* MTXD */ s->mtxd = value & 0xff; break; + case 0x38: /* TR */ + if (value & 1) { + stellaris_enet_send(s); + } + break; case 0x30: /* MRXD */ case 0x34: /* NP */ - case 0x38: /* TR */ /* Ignored. */ case 0x3c: /* Undocuented: Timestamp? */ /* Ignored. */ @@ -324,68 +448,7 @@ static void stellaris_enet_reset(stellaris_enet_state *s) s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP | SE_INT_TXER | SE_INT_RX; s->thr = 0x3f; - s->tx_frame_len = -1; -} - -static void stellaris_enet_save(QEMUFile *f, void *opaque) -{ - stellaris_enet_state *s = (stellaris_enet_state *)opaque; - int i; - - qemu_put_be32(f, s->ris); - qemu_put_be32(f, s->im); - qemu_put_be32(f, s->rctl); - qemu_put_be32(f, s->tctl); - qemu_put_be32(f, s->thr); - qemu_put_be32(f, s->mctl); - qemu_put_be32(f, s->mdv); - qemu_put_be32(f, s->mtxd); - qemu_put_be32(f, s->mrxd); - qemu_put_be32(f, s->np); - qemu_put_be32(f, s->tx_frame_len); - qemu_put_be32(f, s->tx_fifo_len); - qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); - for (i = 0; i < 31; i++) { - qemu_put_be32(f, s->rx[i].len); - qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); - - } - qemu_put_be32(f, s->next_packet); - qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data); - qemu_put_be32(f, s->rx_fifo_len); -} - -static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) -{ - stellaris_enet_state *s = (stellaris_enet_state *)opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - s->ris = qemu_get_be32(f); - s->im = qemu_get_be32(f); - s->rctl = qemu_get_be32(f); - s->tctl = qemu_get_be32(f); - s->thr = qemu_get_be32(f); - s->mctl = qemu_get_be32(f); - s->mdv = qemu_get_be32(f); - s->mtxd = qemu_get_be32(f); - s->mrxd = qemu_get_be32(f); - s->np = qemu_get_be32(f); - s->tx_frame_len = qemu_get_be32(f); - s->tx_fifo_len = qemu_get_be32(f); - qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); - for (i = 0; i < 31; i++) { - s->rx[i].len = qemu_get_be32(f); - qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); - - } - s->next_packet = qemu_get_be32(f); - s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f); - s->rx_fifo_len = qemu_get_be32(f); - - return 0; + s->tx_fifo_len = 0; } static void stellaris_enet_cleanup(NetClientState *nc) @@ -419,8 +482,6 @@ static int stellaris_enet_init(SysBusDevice *sbd) qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); stellaris_enet_reset(s); - register_savevm(dev, "stellaris_enet", -1, 1, - stellaris_enet_save, stellaris_enet_load, s); return 0; } @@ -428,8 +489,6 @@ static void stellaris_enet_unrealize(DeviceState *dev, Error **errp) { stellaris_enet_state *s = STELLARIS_ENET(dev); - unregister_savevm(DEVICE(s), "stellaris_enet", s); - memory_region_destroy(&s->mmio); } @@ -446,6 +505,7 @@ static void stellaris_enet_class_init(ObjectClass *klass, void *data) k->init = stellaris_enet_init; dc->unrealize = stellaris_enet_unrealize; dc->props = stellaris_enet_properties; + dc->vmsd = &vmstate_stellaris_enet; } static const TypeInfo stellaris_enet_info = { 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..aeffcb58b7 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -152,11 +152,11 @@ 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, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT64(rx_bytes, RxTxStats), VMSTATE_UINT64(tx_bytes, RxTxStats), VMSTATE_UINT64(rx, RxTxStats), diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 839d97ca86..cd952d2514 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -98,7 +98,7 @@ static unsigned int tdk_read(struct PHY *phy, unsigned int req) r |= 1; break; case 17: - /* Marvel PHY on many xilinx boards. */ + /* Marvell PHY on many xilinx boards. */ r = 0x8000; /* 1000Mb */ break; case 18: @@ -142,6 +142,9 @@ tdk_write(struct PHY *phy, unsigned int req, unsigned int data) phy->regs[regnum] = data; break; } + + /* Unconditionally clear regs[BMCR][BMCR_RESET] */ + phy->regs[0] &= ~0x8000; } static void @@ -942,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; } @@ -978,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/nvram/ds1225y.c b/hw/nvram/ds1225y.c index f9a700b01c..332598b257 100644 --- a/hw/nvram/ds1225y.c +++ b/hw/nvram/ds1225y.c @@ -95,7 +95,6 @@ static const VMStateDescription vmstate_nvram = { .name = "nvram", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = nvram_post_load, .fields = (VMStateField[]) { VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0, diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index 2eb008179a..170b10b766 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -96,8 +96,7 @@ static const VMStateDescription vmstate_macio_nvram = { .name = "macio_nvram", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size), VMSTATE_END_OF_LIST() } diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 902441f10b..56292adb03 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -687,8 +687,7 @@ static const VMStateDescription vmstate_bonito = { .name = "Bonito", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, PCIBonitoState), VMSTATE_END_OF_LIST() } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 2a9f08eb0a..22fe5eec36 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), @@ -2013,12 +2013,32 @@ static void pci_del_option_rom(PCIDevice *pdev) int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t offset, uint8_t size) { + int ret; + Error *local_err = NULL; + + ret = pci_add_capability2(pdev, cap_id, offset, size, &local_err); + if (local_err) { + assert(ret < 0); + error_report("%s", error_get_pretty(local_err)); + error_free(local_err); + } else { + /* success implies a positive offset in config space */ + assert(ret > 0); + } + return ret; +} + +int pci_add_capability2(PCIDevice *pdev, uint8_t cap_id, + uint8_t offset, uint8_t size, + Error **errp) +{ uint8_t *config; int i, overlapping_cap; if (!offset) { offset = pci_find_space(pdev, size); if (!offset) { + error_setg(errp, "out of PCI config space"); return -ENOSPC; } } else { @@ -2029,12 +2049,12 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, for (i = offset; i < offset + size; i++) { overlapping_cap = pci_find_capability_at_offset(pdev, i); if (overlapping_cap) { - fprintf(stderr, "ERROR: %s:%02x:%02x.%x " - "Attempt to add PCI capability %x at offset " - "%x overlaps existing capability %x at offset %x\n", - pci_root_bus_path(pdev), pci_bus_num(pdev->bus), - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - cap_id, offset, overlapping_cap, i); + error_setg(errp, "%s:%02x:%02x.%x " + "Attempt to add PCI capability %x at offset " + "%x overlaps existing capability %x at offset %x", + pci_root_bus_path(pdev), pci_bus_num(pdev->bus), + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + cap_id, offset, overlapping_cap, i); return -EINVAL; } } 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..597db34019 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) @@ -319,8 +319,7 @@ static const VMStateDescription vmstate_event_facility = { .name = "vmstate-event-facility", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(receive_mask, SCLPEventFacility), VMSTATE_END_OF_LIST() } diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index a3c4bd6272..1a399bd1f0 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -69,8 +69,7 @@ static const VMStateDescription vmstate_sclpquiesce = { .name = "sclpquiesce", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(event_pending, SCLPEvent), VMSTATE_END_OF_LIST() } 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/esp-pci.c b/hw/scsi/esp-pci.c index 48c8b82350..9971bbf92d 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -310,7 +310,6 @@ static const VMStateDescription vmstate_esp_pci_scsi = { .name = "pciespscsi", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, PCIESPState), VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)), diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 2d150bfe48..5ab44d860b 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -560,8 +560,7 @@ const VMStateDescription vmstate_esp = { .name ="esp", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_BUFFER(rregs, ESPState), VMSTATE_BUFFER(wregs, ESPState), VMSTATE_INT32(ti_size, ESPState), @@ -706,7 +705,6 @@ static const VMStateDescription vmstate_sysbus_esp_scsi = { .name = "sysbusespscsi", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState), VMSTATE_END_OF_LIST() 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/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index d1168c9e04..2a40f92732 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -272,8 +272,7 @@ static const VMStateDescription vmstate_milkymist_memcard = { .name = "milkymist-memcard", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(command_write_ptr, MilkymistMemcardState), VMSTATE_INT32(response_read_ptr, MilkymistMemcardState), VMSTATE_INT32(response_len, MilkymistMemcardState), diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 843e697bfe..e2951e6e95 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1197,7 +1197,7 @@ const VMStateDescription sdhci_vmstate = { .name = "sdhci", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(sdmasysad, SDHCIState), VMSTATE_UINT16(blksize, SDHCIState), VMSTATE_UINT16(blkcnt, SDHCIState), 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..61d568f36e 100644 --- a/hw/ssi/pl022.c +++ b/hw/ssi/pl022.c @@ -240,12 +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, - .fields = (VMStateField[]) { + .post_load = pl022_post_load, + .fields = (VMStateField[]) { VMSTATE_UINT32(cr0, PL022State), VMSTATE_UINT32(cr1, PL022State), VMSTATE_UINT32(bitmask, PL022State), diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 017f0221fb..1c82a93590 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -126,8 +126,7 @@ const VMStateDescription vmstate_ssi_slave = { .name = "SSISlave", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(cs, SSISlave), VMSTATE_END_OF_LIST() } diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index d44caae8ad..207f47a1c0 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -351,7 +351,6 @@ static const VMStateDescription vmstate_xilinx_spi = { .name = "xilinx_spi", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_FIFO8(tx_fifo, XilinxSPI), VMSTATE_FIFO8(rx_fifo, XilinxSPI), diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 8977243725..0910f5479a 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -704,7 +704,6 @@ static const VMStateDescription vmstate_xilinx_spips = { .name = "xilinx_spips", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .post_load = xilinx_spips_post_load, .fields = (VMStateField[]) { VMSTATE_FIFO8(tx_fifo, XilinxSPIPS), diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index d3c02ea18f..34124fe3d1 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -190,7 +190,6 @@ static const VMStateDescription vmstate_a10_pit = { .name = "a10.pit", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(irq_enable, AwA10PITState), VMSTATE_UINT32(irq_status, AwA10PITState), diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index fb0a45c889..145291016b 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -150,8 +150,7 @@ static const VMStateDescription vmstate_arm_timer = { .name = "arm_timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(control, arm_timer_state), VMSTATE_UINT32(limit, arm_timer_state), VMSTATE_INT32(int_level, arm_timer_state), @@ -271,8 +270,7 @@ static const VMStateDescription vmstate_sp804 = { .name = "sp804", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32_ARRAY(level, SP804State, 2), VMSTATE_END_OF_LIST() } diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c index 28cb328f9b..52bbbbca7f 100644 --- a/hw/timer/cadence_ttc.c +++ b/hw/timer/cadence_ttc.c @@ -443,7 +443,6 @@ static const VMStateDescription vmstate_cadence_timer = { .name = "cadence_timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = cadence_timer_pre_save, .post_load = cadence_timer_post_load, .fields = (VMStateField[]) { @@ -464,7 +463,6 @@ static const VMStateDescription vmstate_cadence_ttc = { .name = "cadence_TTC", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0, vmstate_cadence_timer, diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index 1fde22c67f..7e28e7e5f5 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -36,7 +36,6 @@ static const VMStateDescription vmstate_digic_timer = { .name = "digic.timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_PTIMER(ptimer, DigicTimerState), VMSTATE_UINT32(control, DigicTimerState), diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c index bb2f8ee8b3..ec6dbeeab0 100644 --- a/hw/timer/ds1338.c +++ b/hw/timer/ds1338.c @@ -40,7 +40,6 @@ static const VMStateDescription vmstate_ds1338 = { .name = "ds1338", .version_id = 2, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_I2C_SLAVE(parent_obj, DS1338State), VMSTATE_INT64(offset, DS1338State), diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 86f4fcd3e8..015bbaf1bd 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -264,7 +264,6 @@ static const VMStateDescription vmstate_tick_timer = { .name = "exynos4210.mct.tick_timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(cnt_run, struct tick_timer), VMSTATE_UINT32(int_run, struct tick_timer), @@ -284,7 +283,6 @@ static const VMStateDescription vmstate_lregs = { .name = "exynos4210.mct.lregs", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT), VMSTATE_UINT32(tcon, struct lregs), @@ -299,7 +297,6 @@ static const VMStateDescription vmstate_exynos4210_mct_lt = { .name = "exynos4210.mct.lt", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_INT32(id, Exynos4210MCTLT), VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0, @@ -317,7 +314,6 @@ static const VMStateDescription vmstate_gregs = { .name = "exynos4210.mct.lregs", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT64(cnt, struct gregs), VMSTATE_UINT32(cnt_wstat, struct gregs), @@ -336,7 +332,6 @@ static const VMStateDescription vmstate_exynos4210_mct_gt = { .name = "exynos4210.mct.lt", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs, struct gregs), @@ -351,7 +346,6 @@ static const VMStateDescription vmstate_exynos4210_mct_state = { .name = "exynos4210.mct", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(reg_mct_cfg, Exynos4210MCTState), VMSTATE_STRUCT_ARRAY(l_timer, Exynos4210MCTState, 2, 0, @@ -824,14 +818,14 @@ static void exynos4210_ltick_recalc_count(struct tick_timer *s) */ if (s->last_tcnto) { - to_count = s->last_tcnto * s->last_icnto; + to_count = (uint64_t)s->last_tcnto * s->last_icnto; } else { to_count = s->last_icnto; } } else { /* distance is passed, recalculate with tcnto * icnto */ if (s->icntb) { - s->distance = s->tcntb * s->icntb; + s->distance = (uint64_t)s->tcntb * s->icntb; } else { s->distance = s->tcntb; } diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 1aa8f4d07a..1c1a2b8ff6 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -120,7 +120,6 @@ static const VMStateDescription vmstate_exynos4210_pwm = { .name = "exynos4210.pwm.pwm", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(id, Exynos4210PWM), VMSTATE_UINT32(freq, Exynos4210PWM), @@ -135,7 +134,6 @@ static const VMStateDescription vmstate_exynos4210_pwm_state = { .name = "exynos4210.pwm", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(reg_tcfg, Exynos4210PWMState, 2), VMSTATE_UINT32(reg_tcon, Exynos4210PWMState), diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c index 026f81a2e3..bf2ee9f80e 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/timer/exynos4210_rtc.c @@ -118,7 +118,6 @@ static const VMStateDescription vmstate_exynos4210_rtc_state = { .name = "exynos4210.rtc", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(reg_intp, Exynos4210RTCState), VMSTATE_UINT32(reg_rtccon, Exynos4210RTCState), 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/timer/imx_epit.c b/hw/timer/imx_epit.c index 0dbe15c99b..c855eba43c 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -353,8 +353,7 @@ static const VMStateDescription vmstate_imx_timer_epit = { .name = "imx.epit", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(cr, IMXEPITState), VMSTATE_UINT32(sr, IMXEPITState), VMSTATE_UINT32(lr, IMXEPITState), diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index f2d1975e70..56ee4db991 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -146,8 +146,7 @@ static const VMStateDescription vmstate_imx_timer_gpt = { .name = "imx.gpt", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(cr, IMXGPTState), VMSTATE_UINT32(pr, IMXGPTState), VMSTATE_UINT32(sr, IMXGPTState), diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c index 8ed138cc0e..d2ab1e74b2 100644 --- a/hw/timer/lm32_timer.c +++ b/hw/timer/lm32_timer.c @@ -196,8 +196,7 @@ static const VMStateDescription vmstate_lm32_timer = { .name = "lm32-timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_PTIMER(ptimer, LM32TimerState), VMSTATE_UINT32(freq_hz, LM32TimerState), VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX), diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c index 94246e56f6..30535a4e3d 100644 --- a/hw/timer/milkymist-sysctl.c +++ b/hw/timer/milkymist-sysctl.c @@ -295,8 +295,7 @@ static const VMStateDescription vmstate_milkymist_sysctl = { .name = "milkymist-sysctl", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX), VMSTATE_PTIMER(ptimer0, MilkymistSysctlState), VMSTATE_PTIMER(ptimer1, MilkymistSysctlState), diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index 0f546c4121..130e9dc345 100644 --- a/hw/timer/pxa2xx_timer.c +++ b/hw/timer/pxa2xx_timer.c @@ -476,7 +476,6 @@ static const VMStateDescription vmstate_pxa2xx_timer0_regs = { .name = "pxa2xx_timer0", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .fields = (VMStateField[]) { VMSTATE_UINT32(value, PXA2xxTimer0), VMSTATE_END_OF_LIST(), @@ -487,7 +486,6 @@ static const VMStateDescription vmstate_pxa2xx_timer4_regs = { .name = "pxa2xx_timer4", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT(tm, PXA2xxTimer4, 1, vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), @@ -509,7 +507,6 @@ static const VMStateDescription vmstate_pxa2xx_timer_regs = { .name = "pxa2xx_timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = pxa25x_timer_post_load, .fields = (VMStateField[]) { VMSTATE_INT32(clock, PXA2xxTimerInfo), diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index e4dcceaf23..45d97e6678 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -329,8 +329,7 @@ static const VMStateDescription vmstate_timer = { .name ="timer", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT64(limit, CPUTimerState), VMSTATE_UINT32(count, CPUTimerState), VMSTATE_UINT32(counthigh, CPUTimerState), @@ -345,8 +344,7 @@ static const VMStateDescription vmstate_slavio_timer = { .name ="slavio_timer", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3, vmstate_timer, CPUTimerState), VMSTATE_END_OF_LIST() diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c index 85d59909da..7ded4ba2ad 100644 --- a/hw/timer/twl92230.c +++ b/hw/timer/twl92230.c @@ -772,8 +772,7 @@ static const VMStateDescription vmstate_menelaus_tm = { .name = "menelaus_tm", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16_HACK(tm_sec, struct tm), VMSTATE_UINT16_HACK(tm_min, struct tm), VMSTATE_UINT16_HACK(tm_hour, struct tm), @@ -811,10 +810,9 @@ static const VMStateDescription vmstate_menelaus = { .name = "menelaus", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .pre_save = menelaus_pre_save, .post_load = menelaus_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(firstbyte, MenelausState), VMSTATE_UINT8(reg, MenelausState), VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5), diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 6113b975bf..3ff1da9caf 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -169,7 +169,7 @@ timer_write(void *opaque, hwaddr addr, if (value & TCSR_TINT) value &= ~TCSR_TINT; - xt->regs[addr] = value; + xt->regs[addr] = value & 0x7ff; if (value & TCSR_ENT) timer_enable(xt); break; diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 17d460cb04..3fe4dff3bd 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -24,6 +24,7 @@ ifeq ($(CONFIG_USB_SMARTCARD),y) common-obj-y += dev-smartcard-reader.o common-obj-y += ccid-card-passthru.o common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o +ccid-card-emulated.o-cflags := -I$(SRC_PATH)/libcacard endif ifeq ($(CONFIG_POSIX),y) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index fe70429304..927a47bbff 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -49,8 +49,10 @@ static int usb_device_post_load(void *opaque, int version_id) } else { dev->attached = 1; } - if (dev->setup_index >= sizeof(dev->data_buf) || - dev->setup_len >= sizeof(dev->data_buf)) { + if (dev->setup_index < 0 || + dev->setup_len < 0 || + dev->setup_index > dev->setup_len || + dev->setup_len > sizeof(dev->data_buf)) { return -EINVAL; } return 0; @@ -61,7 +63,7 @@ const VMStateDescription vmstate_usb_device = { .version_id = 1, .minimum_version_id = 1, .post_load = usb_device_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(addr, USBDevice), VMSTATE_INT32(state, USBDevice), VMSTATE_INT32(remote_wakeup, USBDevice), diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index f36e617632..d097d937ea 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -622,7 +622,7 @@ static const VMStateDescription vmstate_usb_ptr = { .version_id = 1, .minimum_version_id = 1, .post_load = usb_ptr_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, USBHIDState), VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState), VMSTATE_END_OF_LIST() @@ -633,7 +633,7 @@ static const VMStateDescription vmstate_usb_kbd = { .name = "usb-kbd", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, USBHIDState), VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState), VMSTATE_END_OF_LIST() diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index bc03531666..749217497a 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -540,7 +540,7 @@ static const VMStateDescription vmstate_usb_hub_port = { .name = "usb-hub-port", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(wPortStatus, USBHubPort), VMSTATE_UINT16(wPortChange, USBHubPort), VMSTATE_END_OF_LIST() @@ -551,7 +551,7 @@ static const VMStateDescription vmstate_usb_hub = { .name = "usb-hub", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, USBHubState), VMSTATE_STRUCT_ARRAY(ports, USBHubState, NUM_PORTS, 0, vmstate_usb_hub_port, USBHubPort), 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/dev-storage.c b/hw/usb/dev-storage.c index 2852669d57..e919100637 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -716,7 +716,7 @@ static const VMStateDescription vmstate_usb_msd = { .name = "usb-storage", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, MSDState), VMSTATE_UINT32(mode, MSDState), VMSTATE_UINT32(scsi_len, MSDState), diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 484a9bd059..505741a783 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -108,7 +108,7 @@ static const VMStateDescription vmstate_ehci_pci = { .name = "ehci", .version_id = 2, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState), VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState), VMSTATE_END_OF_LIST() diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index fe6eea5908..19ed2c26aa 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -21,7 +21,7 @@ static const VMStateDescription vmstate_ehci_sysbus = { .name = "ehci-sysbus", .version_id = 2, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState), VMSTATE_END_OF_LIST() } diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 355bbd6bed..a3ae9f260a 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2492,7 +2492,7 @@ const VMStateDescription vmstate_ehci = { .minimum_version_id = 1, .pre_save = usb_ehci_pre_save, .post_load = usb_ehci_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { /* mmio registers */ VMSTATE_UINT32(usbcmd, EHCIState), VMSTATE_UINT32(usbsts, EHCIState), 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/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 0820244905..9b1166b2ef 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -422,8 +422,7 @@ static const VMStateDescription vmstate_uhci_port = { .name = "uhci port", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(ctrl, UHCIPort), VMSTATE_END_OF_LIST() } @@ -444,9 +443,8 @@ static const VMStateDescription vmstate_uhci = { .name = "uhci", .version_id = 3, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = uhci_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, UHCIState), VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState), VMSTATE_STRUCT_ARRAY(ports, UHCIState, NB_PORTS, 1, 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..3557c178f1 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 |