diff options
Diffstat (limited to 'hw')
44 files changed, 594 insertions, 318 deletions
@@ -54,6 +54,8 @@ enum { AC97_6Ch_Vol_C_LFE_Mute = 0x36, AC97_6Ch_Vol_L_R_Surround_Mute = 0x38, AC97_Vendor_Reserved = 0x58, + AC97_Sigmatel_Analog = 0x6c, /* We emulate a Sigmatel codec */ + AC97_Sigmatel_Dac2Invert = 0x6e, /* We emulate a Sigmatel codec */ AC97_Vendor_ID1 = 0x7c, AC97_Vendor_ID2 = 0x7e }; @@ -342,7 +344,7 @@ static uint16_t mixer_load (AC97LinkState *s, uint32_t i) uint16_t val = 0xffff; if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_store: index %d out of bounds %zd\n", + dolog ("mixer_load: index %d out of bounds %zd\n", i, sizeof (s->mixer_data)); } else { @@ -456,8 +458,7 @@ static void update_combined_volume_out (AC97LinkState *s) get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, &mute, &lvol, &rvol); - /* FIXME: should be 1f according to spec */ - get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, + get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, &pmute, &plvol, &prvol); mute = mute | pmute; @@ -480,11 +481,22 @@ static void update_volume_in (AC97LinkState *s) static void set_volume (AC97LinkState *s, int index, uint32_t val) { - mixer_store (s, index, val); - if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) { + switch (index) { + case AC97_Master_Volume_Mute: + val &= 0xbf3f; + mixer_store (s, index, val); + update_combined_volume_out (s); + break; + case AC97_PCM_Out_Volume_Mute: + val &= 0x9f1f; + mixer_store (s, index, val); update_combined_volume_out (s); - } else if (index == AC97_Record_Gain_Mute) { + break; + case AC97_Record_Gain_Mute: + val &= 0x8f0f; + mixer_store (s, index, val); update_volume_in (s); + break; } } @@ -503,14 +515,17 @@ static void mixer_reset (AC97LinkState *s) memset (s->mixer_data, 0, sizeof (s->mixer_data)); memset (active, 0, sizeof (active)); mixer_store (s, AC97_Reset , 0x0000); /* 6940 */ - mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000); + mixer_store (s, AC97_Headphone_Volume_Mute , 0x0000); + mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000); + mixer_store (s, AC97_Master_Tone_RL, 0x0000); mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000); - - mixer_store (s, AC97_Phone_Volume_Mute , 0x8008); - mixer_store (s, AC97_Mic_Volume_Mute , 0x8008); - mixer_store (s, AC97_CD_Volume_Mute , 0x8808); - mixer_store (s, AC97_Aux_Volume_Mute , 0x8808); - mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x8000); + mixer_store (s, AC97_Phone_Volume_Mute , 0x0000); + mixer_store (s, AC97_Mic_Volume_Mute , 0x0000); + mixer_store (s, AC97_Line_In_Volume_Mute , 0x0000); + mixer_store (s, AC97_CD_Volume_Mute , 0x0000); + mixer_store (s, AC97_Video_Volume_Mute , 0x0000); + mixer_store (s, AC97_Aux_Volume_Mute , 0x0000); + mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x0000); mixer_store (s, AC97_General_Purpose , 0x0000); mixer_store (s, AC97_3D_Control , 0x0000); mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f); @@ -532,7 +547,7 @@ static void mixer_reset (AC97LinkState *s) record_select (s, 0); set_volume (s, AC97_Master_Volume_Mute, 0x8000); set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); - set_volume (s, AC97_Line_In_Volume_Mute, 0x8808); + set_volume (s, AC97_Record_Gain_Mute, 0x8808); reset_voices (s, active); } @@ -588,14 +603,13 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) mixer_reset (s); break; case AC97_Powerdown_Ctrl_Stat: - val &= ~0xf; + val &= ~0x800f; val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; case AC97_PCM_Out_Volume_Mute: case AC97_Master_Volume_Mute: case AC97_Record_Gain_Mute: - case AC97_Line_In_Volume_Mute: set_volume (s, index, val); break; case AC97_Record_Select: @@ -657,6 +671,23 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val); } break; + case AC97_Headphone_Volume_Mute: + case AC97_Master_Volume_Mono_Mute: + case AC97_Master_Tone_RL: + case AC97_PC_BEEP_Volume_Mute: + case AC97_Phone_Volume_Mute: + case AC97_Mic_Volume_Mute: + case AC97_Line_In_Volume_Mute: + case AC97_CD_Volume_Mute: + case AC97_Video_Volume_Mute: + case AC97_Aux_Volume_Mute: + case AC97_Record_Gain_Mic_Mute: + case AC97_General_Purpose: + case AC97_3D_Control: + case AC97_Sigmatel_Analog: + case AC97_Sigmatel_Dac2Invert: + /* None of the features in these regs are emulated, so they are RO */ + break; default: dolog ("U nam writew %#x <- %#x\n", addr, val); mixer_store (s, index, val); @@ -1158,8 +1189,8 @@ static int ac97_post_load (void *opaque, int version_id) mixer_load (s, AC97_Master_Volume_Mute)); set_volume (s, AC97_PCM_Out_Volume_Mute, mixer_load (s, AC97_PCM_Out_Volume_Mute)); - set_volume (s, AC97_Line_In_Volume_Mute, - mixer_load (s, AC97_Line_In_Volume_Mute)); + set_volume (s, AC97_Record_Gain_Mute, + mixer_load (s, AC97_Record_Gain_Mute)); active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 585da4e3eb..0345490ee0 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -299,6 +299,7 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots) if (pc->no_hotplug) { slot_free = false; } else { + object_unparent(OBJECT(dev)); qdev_free(qdev); } } diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 7e28808ec4..c28411a460 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -85,6 +85,8 @@ typedef struct APBState { unsigned int nr_resets; } APBState; +static void pci_apb_set_irq(void *opaque, int irq_num, int level); + static void apb_config_writel (void *opaque, target_phys_addr_t addr, uint64_t val, unsigned size) { @@ -113,6 +115,16 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr, s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK; } break; + case 0x1400 ... 0x143f: /* PCI interrupt clear */ + if (addr & 4) { + pci_apb_set_irq(s, (addr & 0x3f) >> 3, 0); + } + break; + case 0x1800 ... 0x1860: /* OBIO interrupt clear */ + if (addr & 4) { + pci_apb_set_irq(s, 0x20 | ((addr & 0xff) >> 3), 0); + } + break; case 0x2000 ... 0x202f: /* PCI control */ s->pci_control[(addr & 0x3f) >> 2] = val; break; @@ -404,6 +416,9 @@ static void pci_pbm_reset(DeviceState *d) for (i = 0; i < 8; i++) { s->pci_irq_map[i] &= PBM_PCI_IMR_MASK; } + for (i = 0; i < 32; i++) { + s->obio_irq_map[i] &= PBM_PCI_IMR_MASK; + } if (s->nr_resets++ == 0) { /* Power on reset */ @@ -426,6 +441,9 @@ static int pci_pbm_init_device(SysBusDevice *dev) for (i = 0; i < 8; i++) { s->pci_irq_map[i] = (0x1f << 6) | (i << 2); } + for (i = 0; i < 32; i++) { + s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i; + } s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC); /* apb_config */ diff --git a/hw/es1370.c b/hw/es1370.c index f19cef31a6..573f747362 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -410,7 +410,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) if ((old_fmt != new_fmt) || (old_freq != new_freq)) { d->shift = (new_fmt & 1) + (new_fmt >> 1); - ldebug ("channel %d, freq = %d, nchannels %d, fmt %d, shift %d\n", + ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n", i, new_freq, 1 << (new_fmt & 1), @@ -578,7 +578,7 @@ IO_WRITE_PROTO (es1370_writel) d++; case ES1370_REG_DAC1_SCOUNT: d->scount = (val & 0xffff) | (d->scount & ~0xffff); - ldebug ("chan %d CURR_SAMP_CT %d, SAMP_CT %d\n", + ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n", d - &s->chan[0], val >> 16, (val & 0xffff)); break; @@ -588,7 +588,7 @@ IO_WRITE_PROTO (es1370_writel) d++; case ES1370_REG_DAC1_FRAMEADR: d->frame_addr = val; - ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val); + ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val); break; case ES1370_REG_PHANTOM_FRAMECNT: @@ -605,7 +605,7 @@ IO_WRITE_PROTO (es1370_writel) case ES1370_REG_DAC1_FRAMECNT: d->frame_cnt = val; d->leftover = 0; - ldebug ("chan %d frame count %d, buffer size %d\n", + ldebug ("chan %td frame count %d, buffer size %d\n", d - &s->chan[0], val >> 16, val & 0xffff); break; @@ -745,9 +745,10 @@ IO_READ_PROTO (es1370_readl) { uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2; uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2; - if (curr > size) + if (curr > size) { dolog ("read framecnt curr %d, size %d %d\n", curr, size, curr > size); + } } #endif break; @@ -179,12 +179,14 @@ static void fd_revalidate(FDrive *drv) FDriveRate rate; FLOPPY_DPRINTF("revalidate\n"); - if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) { + if (drv->bs != NULL) { ro = bdrv_is_read_only(drv->bs); bdrv_get_floppy_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect, drv->drive, &drive, &rate); - if (nb_heads != 0 && max_track != 0 && last_sect != 0) { - FLOPPY_DPRINTF("User defined disk (%d %d %d)", + if (!bdrv_is_inserted(drv->bs)) { + FLOPPY_DPRINTF("No disk in drive\n"); + } else if (nb_heads != 0 && max_track != 0 && last_sect != 0) { + FLOPPY_DPRINTF("User defined disk (%d %d %d)\n", nb_heads - 1, max_track, last_sect); } else { FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads, @@ -201,7 +203,7 @@ static void fd_revalidate(FDrive *drv) drv->drive = drive; drv->media_rate = rate; } else { - FLOPPY_DPRINTF("No disk in drive\n"); + FLOPPY_DPRINTF("No drive connected\n"); drv->last_sect = 0; drv->max_track = 0; drv->flags &= ~FDISK_DBL_SIDES; @@ -705,6 +707,15 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0) qemu_set_irq(fdctrl->irq, 1); fdctrl->sra |= FD_SRA_INTPEND; } + if (status0 & FD_SR0_SEEK) { + FDrive *cur_drv; + /* A seek clears the disk change line (if a disk is inserted) */ + cur_drv = get_cur_drv(fdctrl); + if (cur_drv->bs != NULL && bdrv_is_inserted(cur_drv->bs)) { + cur_drv->media_changed = 0; + } + } + fdctrl->reset_sensei = 0; fdctrl->status0 = status0; FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0); @@ -936,23 +947,7 @@ static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value) static int fdctrl_media_changed(FDrive *drv) { - int ret; - - if (!drv->bs) - return 0; - if (drv->media_changed) { - drv->media_changed = 0; - ret = 1; - } else { - ret = bdrv_media_changed(drv->bs); - if (ret < 0) { - ret = 0; /* we don't know, assume no */ - } - } - if (ret) { - fd_revalidate(drv); - } - return ret; + return drv->media_changed; } /* Digital input register : 0x07 (read-only) */ @@ -1856,6 +1851,7 @@ static void fdctrl_change_cb(void *opaque, bool load) FDrive *drive = opaque; drive->media_changed = 1; + fd_revalidate(drive); } static const BlockDevOps fdctrl_block_ops = { @@ -1884,9 +1880,8 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl) } fd_init(drive); - fd_revalidate(drive); + fdctrl_change_cb(drive, 0); if (drive->bs) { - drive->media_changed = 1; bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive); } } diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index a883a920be..2d7d03d772 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -462,7 +462,7 @@ static void ahci_check_cmd_bh(void *opaque) static void ahci_init_d2h(AHCIDevice *ad) { - uint8_t init_fis[0x20]; + uint8_t init_fis[20]; IDEState *ide_state = &ad->port.ifs[0]; memset(init_fis, 0, sizeof(init_fis)); @@ -619,7 +619,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) d2h_fis[11] = cmd_fis[11]; d2h_fis[12] = cmd_fis[12]; d2h_fis[13] = cmd_fis[13]; - for (i = 14; i < 0x20; i++) { + for (i = 14; i < 20; i++) { d2h_fis[i] = 0; } diff --git a/hw/loader.c b/hw/loader.c index 415cdce534..7d64113e7f 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -103,7 +103,7 @@ ssize_t read_targphys(const char *name, /* return the size or -1 if error */ int load_image_targphys(const char *filename, - target_phys_addr_t addr, int max_sz) + target_phys_addr_t addr, uint64_t max_sz) { int size; diff --git a/hw/loader.h b/hw/loader.h index fbcaba9f0c..6da291e31f 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -4,7 +4,8 @@ /* loader.c */ int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); /* deprecated */ -int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz); +int load_image_targphys(const char *filename, target_phys_addr_t, + uint64_t max_sz); int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int big_endian, int elf_machine, diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 37dc711e08..1a8df10429 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -284,7 +284,6 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, exit(1); } - register_savevm(NULL, "cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); /* fulong 2e has 256M ram. */ diff --git a/hw/multiboot.c b/hw/multiboot.c index b4484a3262..b1e04c5718 100644 --- a/hw/multiboot.c +++ b/hw/multiboot.c @@ -202,10 +202,16 @@ int load_multiboot(void *fw_cfg, uint32_t mh_bss_end_addr = ldl_p(header+i+24); mh_load_addr = ldl_p(header+i+16); uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr); - uint32_t mb_load_size = mh_load_end_addr - mh_load_addr; - + uint32_t mb_load_size = 0; mh_entry_addr = ldl_p(header+i+28); - mb_kernel_size = mh_bss_end_addr - mh_load_addr; + + if (mh_load_end_addr) { + mb_kernel_size = mh_bss_end_addr - mh_load_addr; + mb_load_size = mh_load_end_addr - mh_load_addr; + } else { + mb_kernel_size = kernel_file_size - mb_kernel_text_offset; + mb_load_size = mb_kernel_size; + } /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE. uint32_t mh_mode_type = ldl_p(header+i+32); @@ -47,6 +47,7 @@ #include "ui/qemu-spice.h" #include "memory.h" #include "exec-memory.h" +#include "arch_init.h" /* output Bochs bios info messages */ //#define DEBUG_BIOS @@ -382,7 +383,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, if (floppy) { fdc_get_bs(fd, floppy); for (i = 0; i < 2; i++) { - if (fd[i] && bdrv_is_inserted(fd[i])) { + if (fd[i]) { bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track, &last_sect, FDRIVE_DRV_NONE, &fd_type[i], &rate); @@ -1088,7 +1089,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, qemu_irq pit_alt_irq = NULL; qemu_irq rtc_irq = NULL; qemu_irq *a20_line; - ISADevice *i8042, *port92, *vmmouse, *pit; + ISADevice *i8042, *port92, *vmmouse, *pit = NULL; qemu_irq *cpu_exit_irq; register_ioport_write(0x80, 1, 1, ioport80_write, NULL); @@ -1117,16 +1118,18 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, qemu_register_boot_set(pc_boot_set, *rtc_state); - if (kvm_irqchip_in_kernel()) { - pit = kvm_pit_init(isa_bus, 0x40); - } else { - pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq); - } - if (hpet) { - /* connect PIT to output control line of the HPET */ - qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0)); + if (!xen_enabled()) { + if (kvm_irqchip_in_kernel()) { + pit = kvm_pit_init(isa_bus, 0x40); + } else { + pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq); + } + if (hpet) { + /* connect PIT to output control line of the HPET */ + qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0)); + } + pcspk_init(isa_bus, pit); } - pcspk_init(isa_bus, pit); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 044dfcb377..f49b0aaf89 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -518,6 +518,10 @@ static QEMUMachine pc_machine_v0_12 = { .driver = "virtio-blk-pci",\ .property = "vectors",\ .value = stringify(0),\ + },{\ + .driver = "PCI",\ + .property = "rombar",\ + .value = stringify(0),\ } static QEMUMachine pc_machine_v0_11 = { diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index fafdf9b1c1..f0d7c21b5c 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -85,6 +85,9 @@ static void pc_fw_add_pflash_drv(void) filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); opts = drive_add(IF_PFLASH, -1, filename, "readonly=on"); + + g_free(filename); + if (opts == NULL) { return; } @@ -1527,7 +1527,6 @@ static int pci_unplug_device(DeviceState *qdev) qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev))); return -1; } - object_unparent(OBJECT(dev)); return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, PCI_HOTPLUG_DISABLED); } diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index dc4e4e1b84..eed781d2f0 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -158,7 +158,7 @@ int qdev_device_help(QemuOpts *opts) * for removal. This conditional should be removed along with * it. */ - if (!prop->info->parse) { + if (!prop->info->set) { continue; /* no way to set it, don't show */ } error_printf("%s.%s=%s\n", driver, prop->name, @@ -166,7 +166,7 @@ int qdev_device_help(QemuOpts *opts) } if (info->bus_info) { for (prop = info->bus_info->props; prop && prop->name; prop++) { - if (!prop->info->parse) { + if (!prop->info->set) { continue; /* no way to set it, don't show */ } error_printf("%s.%s=%s\n", driver, prop->name, @@ -493,7 +493,7 @@ static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { value = object_property_get_str(OBJECT(dev), legacy_name, &err); } else { - value = object_property_get_str(OBJECT(dev), props->name, &err); + value = object_property_print(OBJECT(dev), props->name, &err); } g_free(legacy_name); diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 98dd06aeba..b7b5597c62 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -753,10 +753,12 @@ static void set_mac(Object *obj, Visitor *v, void *opaque, } mac->a[i] = strtol(str+pos, &p, 16); } + g_free(str); return; inval: error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); } PropertyInfo qdev_prop_macaddr = { @@ -825,7 +827,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, uint32_t *ptr = qdev_get_prop_ptr(dev, prop); unsigned int slot, fn, n; Error *local_err = NULL; - char *str = (char *)""; + char *str; if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); @@ -834,6 +836,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, visit_type_str(v, &str, name, &local_err); if (local_err) { + error_free(local_err); return set_int32(obj, v, opaque, name, errp); } @@ -847,10 +850,12 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, goto invalid; } *ptr = slot << 3 | fn; + g_free(str); return; invalid: error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); } static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) @@ -576,9 +576,12 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop, { gchar *name, *type; - if (!prop->info->print && !prop->info->parse) { + /* Register pointer properties as legacy properties */ + if (!prop->info->print && !prop->info->parse && + (prop->info->set || prop->info->get)) { return; } + name = g_strdup_printf("legacy-%s", prop->name); type = g_strdup_printf("legacy<%s>", prop->info->legacy_name ?: prop->info->name); diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c index 367aad19f4..fe2878c836 100644 --- a/hw/qxl-logger.c +++ b/hw/qxl-logger.c @@ -100,12 +100,15 @@ static const char *qxl_v2n(const char *n[], size_t l, int v) } #define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value) -static void qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) +static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) { QXLImage *image; QXLImageDescriptor *desc; image = qxl_phys2virt(qxl, addr, group_id); + if (!image) { + return 1; + } desc = &image->descriptor; fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d", desc->id, desc->type, desc->flags, desc->width, desc->height); @@ -120,6 +123,7 @@ static void qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) break; } fprintf(stderr, ")"); + return 0; } static void qxl_log_rect(QXLRect *rect) @@ -130,17 +134,24 @@ static void qxl_log_rect(QXLRect *rect) rect->left, rect->top); } -static void qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy, int group_id) +static int qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy, + int group_id) { + int ret; + fprintf(stderr, " src %" PRIx64, copy->src_bitmap); - qxl_log_image(qxl, copy->src_bitmap, group_id); + ret = qxl_log_image(qxl, copy->src_bitmap, group_id); + if (ret != 0) { + return ret; + } fprintf(stderr, " area"); qxl_log_rect(©->src_area); fprintf(stderr, " rop %d", copy->rop_descriptor); + return 0; } -static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id) +static int qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id) { fprintf(stderr, ": surface_id %d type %s effect %s", draw->surface_id, @@ -148,13 +159,14 @@ static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id) qxl_name(qxl_draw_effect, draw->effect)); switch (draw->type) { case QXL_DRAW_COPY: - qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); + return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); break; } + return 0; } -static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw, - int group_id) +static int qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw, + int group_id) { fprintf(stderr, ": type %s effect %s", qxl_name(qxl_draw_type, draw->type), @@ -166,9 +178,10 @@ static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw, } switch (draw->type) { case QXL_DRAW_COPY: - qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); + return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); break; } + return 0; } static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd) @@ -189,7 +202,7 @@ static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd) } } -void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) +int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) { QXLCursor *cursor; @@ -203,6 +216,9 @@ void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) cmd->u.set.visible ? "yes" : "no", cmd->u.set.shape); cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id); + if (!cursor) { + return 1; + } fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d" " unique 0x%" PRIx64 " data-size %d", qxl_name(spice_cursor_type, cursor->header.type), @@ -214,15 +230,17 @@ void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y); break; } + return 0; } -void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) +int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) { bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT; void *data; + int ret; if (!qxl->cmdlog) { - return; + return 0; } fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_get_clock_ns(vm_clock), qxl->id, ring); @@ -231,12 +249,18 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) compat ? "(compat)" : ""); data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + if (!data) { + return 1; + } switch (ext->cmd.type) { case QXL_CMD_DRAW: if (!compat) { - qxl_log_cmd_draw(qxl, data, ext->group_id); + ret = qxl_log_cmd_draw(qxl, data, ext->group_id); } else { - qxl_log_cmd_draw_compat(qxl, data, ext->group_id); + ret = qxl_log_cmd_draw_compat(qxl, data, ext->group_id); + } + if (ret) { + return ret; } break; case QXL_CMD_SURFACE: @@ -247,4 +271,5 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) break; } fprintf(stderr, "\n"); + return 0; } diff --git a/hw/qxl-render.c b/hw/qxl-render.c index f7f1bfda04..e2e3fe2d37 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -228,14 +228,18 @@ fail: /* called from spice server thread context only */ -void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) +int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) { QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); QXLCursor *cursor; QEMUCursor *c; + if (!cmd) { + return 1; + } + if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) { - return; + return 0; } if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) { @@ -246,9 +250,12 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) switch (cmd->type) { case QXL_CURSOR_SET: cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id); + if (!cursor) { + return 1; + } if (cursor->chunk.data_size != cursor->data_size) { fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__); - return; + return 1; } c = qxl_cursor(qxl, cursor); if (c == NULL) { @@ -270,4 +277,5 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) qemu_mutex_unlock(&qxl->ssd.lock); break; } + return 0; } @@ -27,28 +27,42 @@ #include "qxl.h" +/* + * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as + * such can be changed by the guest, so to avoid a guest trigerrable + * abort we just set qxl_guest_bug and set the return to NULL. Still + * it may happen as a result of emulator bug as well. + */ #undef SPICE_RING_PROD_ITEM -#define SPICE_RING_PROD_ITEM(r, ret) { \ +#define SPICE_RING_PROD_ITEM(qxl, r, ret) { \ typeof(r) start = r; \ typeof(r) end = r + 1; \ uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \ typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \ if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ - abort(); \ + qxl_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch " \ + "! %p <= %p < %p", (uint8_t *)start, \ + (uint8_t *)m_item, (uint8_t *)end); \ + ret = NULL; \ + } else { \ + ret = &m_item->el; \ } \ - ret = &m_item->el; \ } #undef SPICE_RING_CONS_ITEM -#define SPICE_RING_CONS_ITEM(r, ret) { \ +#define SPICE_RING_CONS_ITEM(qxl, r, ret) { \ typeof(r) start = r; \ typeof(r) end = r + 1; \ uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r); \ typeof(&(r)->items[cons]) m_item = &(r)->items[cons]; \ if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ - abort(); \ + qxl_guest_bug(qxl, "SPICE_RING_CONS_ITEM indices mismatch " \ + "! %p <= %p < %p", (uint8_t *)start, \ + (uint8_t *)m_item, (uint8_t *)end); \ + ret = NULL; \ + } else { \ + ret = &m_item->el; \ } \ - ret = &m_item->el; \ } #undef ALIGN @@ -343,7 +357,8 @@ static void init_qxl_ram(PCIQXLDevice *d) SPICE_RING_INIT(&d->ram->cmd_ring); SPICE_RING_INIT(&d->ram->cursor_ring); SPICE_RING_INIT(&d->ram->release_ring); - SPICE_RING_PROD_ITEM(&d->ram->release_ring, item); + SPICE_RING_PROD_ITEM(d, &d->ram->release_ring, item); + assert(item); *item = 0; qxl_ring_set_dirty(d); } @@ -383,14 +398,22 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl) * keep track of some command state, for savevm/loadvm. * called from spice server thread context only */ -static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) +static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) { switch (le32_to_cpu(ext->cmd.type)) { case QXL_CMD_SURFACE: { QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + + if (!cmd) { + return 1; + } uint32_t id = le32_to_cpu(cmd->surface_id); - PANIC_ON(id >= NUM_SURFACES); + + if (id >= NUM_SURFACES) { + qxl_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id, NUM_SURFACES); + return 1; + } qemu_mutex_lock(&qxl->track_lock); if (cmd->type == QXL_SURFACE_CMD_CREATE) { qxl->guest_surfaces.cmds[id] = ext->cmd.data; @@ -408,6 +431,10 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) case QXL_CMD_CURSOR: { QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + + if (!cmd) { + return 1; + } if (cmd->type == QXL_CURSOR_SET) { qemu_mutex_lock(&qxl->track_lock); qxl->guest_cursor = ext->cmd.data; @@ -416,6 +443,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) break; } } + return 0; } /* spice display interface callbacks */ @@ -546,8 +574,10 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) if (SPICE_RING_IS_EMPTY(ring)) { return false; } - trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); - SPICE_RING_CONS_ITEM(ring, cmd); + SPICE_RING_CONS_ITEM(qxl, ring, cmd); + if (!cmd) { + return false; + } ext->cmd = *cmd; ext->group_id = MEMSLOT_GROUP_GUEST; ext->flags = qxl->cmdflags; @@ -559,6 +589,7 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) qxl->guest_primary.commands++; qxl_track_command(qxl, ext); qxl_log_command(qxl, "cmd", ext); + trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); return true; default: return false; @@ -617,7 +648,10 @@ static inline void qxl_push_free_res(PCIQXLDevice *d, int flush) if (notify) { qxl_send_events(d, QXL_INTERRUPT_DISPLAY); } - SPICE_RING_PROD_ITEM(ring, item); + SPICE_RING_PROD_ITEM(d, ring, item); + if (!item) { + return; + } *item = 0; d->num_free_res = 0; d->last_release = NULL; @@ -643,7 +677,10 @@ static void interface_release_resource(QXLInstance *sin, * pci bar 0, $command.release_info */ ring = &qxl->ram->release_ring; - SPICE_RING_PROD_ITEM(ring, item); + SPICE_RING_PROD_ITEM(qxl, ring, item); + if (!item) { + return; + } if (*item == 0) { /* stick head into the ring */ id = ext.info->id; @@ -682,7 +719,10 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * if (SPICE_RING_IS_EMPTY(ring)) { return false; } - SPICE_RING_CONS_ITEM(ring, cmd); + SPICE_RING_CONS_ITEM(qxl, ring, cmd); + if (!cmd) { + return false; + } ext->cmd = *cmd; ext->group_id = MEMSLOT_GROUP_GUEST; ext->flags = qxl->cmdflags; @@ -728,8 +768,13 @@ static int interface_req_cursor_notification(QXLInstance *sin) /* called from spice server thread context */ static void interface_notify_update(QXLInstance *sin, uint32_t update_id) { - fprintf(stderr, "%s: abort()\n", __FUNCTION__); - abort(); + /* + * Called by spice-server as a result of a QXL_CMD_UPDATE which is not in + * use by xf86-video-qxl and is defined out in the qxl windows driver. + * Probably was at some earlier version that is prior to git start (2009), + * and is still guest trigerrable. + */ + fprintf(stderr, "%s: deprecated\n", __func__); } /* called from spice server thread context only */ @@ -764,8 +809,8 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) } if (cookie && current_async != cookie->io) { fprintf(stderr, - "qxl: %s: error: current_async = %d != %" PRId64 " = cookie->io\n", - __func__, current_async, cookie->io); + "qxl: %s: error: current_async = %d != %" + PRId64 " = cookie->io\n", __func__, current_async, cookie->io); } switch (current_async) { case QXL_IO_MEMSLOT_ADD_ASYNC: @@ -993,8 +1038,8 @@ static const MemoryRegionPortio qxl_vga_portio_list[] = { PORTIO_END_OF_LIST(), }; -static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, - qxl_async_io async) +static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + qxl_async_io async) { static const int regions[] = { QXL_RAM_RANGE_INDEX, @@ -1015,8 +1060,16 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end); - PANIC_ON(slot_id >= NUM_MEMSLOTS); - PANIC_ON(guest_start > guest_end); + if (slot_id >= NUM_MEMSLOTS) { + qxl_guest_bug(d, "%s: slot_id >= NUM_MEMSLOTS %d >= %d", __func__, + slot_id, NUM_MEMSLOTS); + return 1; + } + if (guest_start > guest_end) { + qxl_guest_bug(d, "%s: guest_start > guest_end 0x%" PRIx64 + " > 0x%" PRIx64, __func__, guest_start, guest_end); + return 1; + } for (i = 0; i < ARRAY_SIZE(regions); i++) { pci_region = regions[i]; @@ -1037,7 +1090,10 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, /* passed */ break; } - PANIC_ON(i == ARRAY_SIZE(regions)); /* finished loop without match */ + if (i == ARRAY_SIZE(regions)) { + qxl_guest_bug(d, "%s: finished loop without match", __func__); + return 1; + } switch (pci_region) { case QXL_RAM_RANGE_INDEX: @@ -1049,7 +1105,8 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, break; default: /* should not happen */ - abort(); + qxl_guest_bug(d, "%s: pci_region = %d", __func__, pci_region); + return 1; } memslot.slot_id = slot_id; @@ -1065,6 +1122,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; d->guest_slots[slot_id].delta = delta; d->guest_slots[slot_id].active = 1; + return 0; } static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) @@ -1097,15 +1155,28 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) case MEMSLOT_GROUP_HOST: return (void *)(intptr_t)offset; case MEMSLOT_GROUP_GUEST: - PANIC_ON(slot >= NUM_MEMSLOTS); - PANIC_ON(!qxl->guest_slots[slot].active); - PANIC_ON(offset < qxl->guest_slots[slot].delta); + if (slot >= NUM_MEMSLOTS) { + qxl_guest_bug(qxl, "slot too large %d >= %d", slot, NUM_MEMSLOTS); + return NULL; + } + if (!qxl->guest_slots[slot].active) { + qxl_guest_bug(qxl, "inactive slot %d\n", slot); + return NULL; + } + if (offset < qxl->guest_slots[slot].delta) { + qxl_guest_bug(qxl, "slot %d offset %"PRIu64" < delta %"PRIu64"\n", + slot, offset, qxl->guest_slots[slot].delta); + return NULL; + } offset -= qxl->guest_slots[slot].delta; - PANIC_ON(offset > qxl->guest_slots[slot].size) + if (offset > qxl->guest_slots[slot].size) { + qxl_guest_bug(qxl, "slot %d offset %"PRIu64" > size %"PRIu64"\n", + slot, offset, qxl->guest_slots[slot].size); + return NULL; + } return qxl->guest_slots[slot].ptr + offset; - default: - PANIC_ON(1); } + return NULL; } static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl) @@ -1120,7 +1191,10 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, QXLDevSurfaceCreate surface; QXLSurfaceCreate *sc = &qxl->guest_primary.surface; - assert(qxl->mode != QXL_MODE_NATIVE); + if (qxl->mode == QXL_MODE_NATIVE) { + qxl_guest_bug(qxl, "%s: nop since already in QXL_MODE_NATIVE", + __func__); + } qxl_exit_vga_mode(qxl); surface.format = le32_to_cpu(sc->format); @@ -1192,7 +1266,7 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) } d->guest_slots[0].slot = slot; - qxl_add_memslot(d, 0, devmem, QXL_SYNC); + assert(qxl_add_memslot(d, 0, devmem, QXL_SYNC) == 0); d->guest_primary.surface = surface; qxl_create_guest_primary(d, 0, QXL_SYNC); @@ -1393,8 +1467,7 @@ async_common: qxl_spice_destroy_surfaces(d, async); break; default: - fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); - abort(); + qxl_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port); } return; cancel_async: @@ -1450,7 +1523,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) qxl_update_irq(d); } else { if (write(d->pipe[1], d, 1) != 1) { - dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__); + dprint(d, 1, "%s: write to pipe failed\n", __func__); } } } @@ -1555,10 +1628,12 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], MEMSLOT_GROUP_GUEST); + assert(cmd); assert(cmd->type == QXL_SURFACE_CMD_CREATE); surface_offset = (intptr_t)qxl_phys2virt(qxl, cmd->u.surface_create.data, MEMSLOT_GROUP_GUEST); + assert(surface_offset); surface_offset -= vram_start; surface_size = cmd->u.surface_create.height * abs(cmd->u.surface_create.stride); @@ -1671,13 +1746,16 @@ static int qxl_init_common(PCIQXLDevice *qxl) switch (qxl->revision) { case 1: /* spice 0.4 -- qxl-1 */ pci_device_rev = QXL_REVISION_STABLE_V04; + io_size = 8; break; case 2: /* spice 0.6 -- qxl-2 */ pci_device_rev = QXL_REVISION_STABLE_V06; + io_size = 16; break; case 3: /* qxl-3 */ default: pci_device_rev = QXL_DEFAULT_REVISION; + io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); break; } @@ -1695,11 +1773,6 @@ static int qxl_init_common(PCIQXLDevice *qxl) memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar, 0, qxl->vram32_size); - io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); - if (qxl->revision == 1) { - io_size = 8; - } - memory_region_init_io(&qxl->io_bar, &qxl_io_ops, qxl, "qxl-ioports", io_size); if (qxl->id == 0) { @@ -142,12 +142,12 @@ void qxl_spice_reset_image_cache(PCIQXLDevice *qxl); void qxl_spice_reset_cursor(PCIQXLDevice *qxl); /* qxl-logger.c */ -void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); -void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); +int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); +int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); /* qxl-render.c */ void qxl_render_resize(PCIQXLDevice *qxl); void qxl_render_update(PCIQXLDevice *qxl); -void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); +int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie); void qxl_render_update_area_bh(void *opaque); diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 4d0f5ba518..eb22d04fad 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -2500,7 +2500,7 @@ static uint32_t rtl8139_TxStatus_TxAddr_read(RTL8139State *s, uint32_t regs[], case 1: /* fall through */ case 2: /* fall through */ case 4: - ret = (regs[reg] >> offset * 8) & ((1 << (size * 8)) - 1); + ret = (regs[reg] >> offset * 8) & (((uint64_t)1 << (size * 8)) - 1); DPRINTF("TxStatus/TxAddr[%d] read addr=0x%x size=0x%x val=0x%08x\n", reg, addr, size, ret); break; diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 63ccd5c35a..1d38a8f5c5 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -163,8 +163,7 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev) { VirtIODevice *vdev; - vdev = virtio_blk_init((DeviceState *)dev, &dev->block, - &dev->block_serial); + vdev = virtio_blk_init((DeviceState *)dev, &dev->blk); if (!vdev) { return -1; } @@ -400,8 +399,11 @@ static TypeInfo s390_virtio_net = { }; static Property s390_virtio_blk_properties[] = { - DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block), - DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial), + DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, blk.conf), + DEFINE_PROP_STRING("serial", VirtIOS390Device, blk.serial), +#ifdef __linux__ + DEFINE_PROP_BIT("scsi", VirtIOS390Device, blk.scsi, 0, true), +#endif DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 49e6c462df..4b99d02298 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "virtio-blk.h" #include "virtio-net.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -64,8 +65,7 @@ struct VirtIOS390Device { ram_addr_t feat_offs; uint8_t feat_len; VirtIODevice *vdev; - BlockConf block; - char *block_serial; + VirtIOBlkConf blk; NICConf nic; uint32_t host_features; virtio_serial_conf serial; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index dbdb99ce35..f10f3ec25c 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -239,6 +239,18 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus) return res; } +static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf) +{ + scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD)); + scsi_req_complete(req, CHECK_CONDITION); + return 0; +} + +static const struct SCSIReqOps reqops_invalid_field = { + .size = sizeof(SCSIRequest), + .send_command = scsi_invalid_field +}; + /* SCSIReqOps implementation for invalid commands. */ static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf) @@ -355,10 +367,6 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r) if (r->req.cmd.buf[1] & 0x1) { /* Vital product data */ uint8_t page_code = r->req.cmd.buf[2]; - if (r->req.cmd.xfer < 4) { - return false; - } - r->buf[r->len++] = page_code ; /* this page */ r->buf[r->len++] = 0x00; @@ -386,10 +394,6 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r) } /* PAGE CODE == 0 */ - if (r->req.cmd.xfer < 5) { - return false; - } - r->len = MIN(r->req.cmd.xfer, 36); memset(r->buf, 0, r->len); if (r->req.lun != 0) { @@ -423,9 +427,6 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) } break; case REQUEST_SENSE: - if (req->cmd.xfer < 4) { - goto illegal_request; - } r->len = scsi_device_get_sense(r->req.dev, r->buf, MIN(req->cmd.xfer, sizeof r->buf), (req->cmd.buf[1] & 1) == 0); @@ -517,23 +518,25 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, cmd.lba); } - if ((d->unit_attention.key == UNIT_ATTENTION || - bus->unit_attention.key == UNIT_ATTENTION) && - (buf[0] != INQUIRY && - buf[0] != REPORT_LUNS && - buf[0] != GET_CONFIGURATION && - buf[0] != GET_EVENT_STATUS_NOTIFICATION && - - /* - * If we already have a pending unit attention condition, - * report this one before triggering another one. - */ - !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) { + if (cmd.xfer > INT32_MAX) { + req = scsi_req_alloc(&reqops_invalid_field, d, tag, lun, hba_private); + } else if ((d->unit_attention.key == UNIT_ATTENTION || + bus->unit_attention.key == UNIT_ATTENTION) && + (buf[0] != INQUIRY && + buf[0] != REPORT_LUNS && + buf[0] != GET_CONFIGURATION && + buf[0] != GET_EVENT_STATUS_NOTIFICATION && + + /* + * If we already have a pending unit attention condition, + * report this one before triggering another one. + */ + !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) { req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun, hba_private); } else if (lun != d->lun || - buf[0] == REPORT_LUNS || - (buf[0] == REQUEST_SENSE && (d->sense_len || cmd.xfer < 4))) { + buf[0] == REPORT_LUNS || + (buf[0] == REQUEST_SENSE && d->sense_len)) { req = scsi_req_alloc(&reqops_target_command, d, tag, lun, hba_private); } else { @@ -646,7 +649,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense) trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag, sense.key, sense.asc, sense.ascq); memset(req->sense, 0, 18); - req->sense[0] = 0xf0; + req->sense[0] = 0x70; req->sense[2] = sense.key; req->sense[7] = 10; req->sense[12] = sense.asc; @@ -721,10 +724,6 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case 0: cmd->xfer = buf[4]; cmd->len = 6; - /* length 0 means 256 blocks */ - if (cmd->xfer == 0) { - cmd->xfer = 256; - } break; case 1: case 2: @@ -777,7 +776,8 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case MODE_SENSE: break; case WRITE_SAME_10: - cmd->xfer = 1; + case WRITE_SAME_16: + cmd->xfer = dev->blocksize; break; case READ_CAPACITY_10: cmd->xfer = 8; @@ -793,18 +793,26 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) cmd->xfer = buf[9] | (buf[8] << 8); } break; + case WRITE_6: + /* length 0 means 256 blocks */ + if (cmd->xfer == 0) { + cmd->xfer = 256; + } case WRITE_10: case WRITE_VERIFY_10: - case WRITE_6: case WRITE_12: case WRITE_VERIFY_12: case WRITE_16: case WRITE_VERIFY_16: cmd->xfer *= dev->blocksize; break; - case READ_10: case READ_6: case READ_REVERSE: + /* length 0 means 256 blocks */ + if (cmd->xfer == 0) { + cmd->xfer = 256; + } + case READ_10: case RECOVER_BUFFERED_DATA: case READ_12: case READ_16: @@ -872,6 +880,16 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu cmd->xfer *= dev->blocksize; } break; + case READ_16: + case READ_REVERSE_16: + case VERIFY_16: + case WRITE_16: + cmd->len = 16; + cmd->xfer = buf[14] | (buf[13] << 8) | (buf[12] << 16); + if (buf[1] & 0x01) { /* fixed */ + cmd->xfer *= dev->blocksize; + } + break; case REWIND: case START_STOP: cmd->len = 6; @@ -895,6 +913,10 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu static void scsi_cmd_xfer_mode(SCSICommand *cmd) { + if (!cmd->xfer) { + cmd->mode = SCSI_XFER_NONE; + return; + } switch (cmd->buf[0]) { case WRITE_6: case WRITE_10: @@ -920,6 +942,8 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) case UPDATE_BLOCK: case WRITE_LONG_10: case WRITE_SAME_10: + case WRITE_SAME_16: + case UNMAP: case SEARCH_HIGH_12: case SEARCH_EQUAL_12: case SEARCH_LOW_12: @@ -929,14 +953,11 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) case SEND_DVD_STRUCTURE: case PERSISTENT_RESERVE_OUT: case MAINTENANCE_OUT: + case ATA_PASSTHROUGH: cmd->mode = SCSI_XFER_TO_DEV; break; default: - if (cmd->xfer) - cmd->mode = SCSI_XFER_FROM_DEV; - else { - cmd->mode = SCSI_XFER_NONE; - } + cmd->mode = SCSI_XFER_FROM_DEV; break; } } @@ -1127,7 +1148,7 @@ int scsi_build_sense(uint8_t *in_buf, int in_len, memset(buf, 0, len); if (fixed) { /* Return fixed format sense buffer */ - buf[0] = 0xf0; + buf[0] = 0x70; buf[2] = sense.key; buf[7] = 10; buf[12] = sense.asc; @@ -1270,6 +1291,7 @@ SCSIRequest *scsi_req_ref(SCSIRequest *req) void scsi_req_unref(SCSIRequest *req) { + assert(req->refcount > 0); if (--req->refcount == 0) { if (req->ops->free_req) { req->ops->free_req(req); @@ -1539,7 +1561,7 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) return 0; } -const VMStateInfo vmstate_info_scsi_requests = { +static const VMStateInfo vmstate_info_scsi_requests = { .name = "scsi-requests", .get = get_scsi_requests, .put = put_scsi_requests, diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index ca24192d53..219c84dfb1 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -92,6 +92,7 @@ #define PERSISTENT_RESERVE_OUT 0x5f #define VARLENGTH_CDB 0x7f #define WRITE_FILEMARKS_16 0x80 +#define READ_REVERSE_16 0x81 #define ALLOW_OVERWRITE 0x82 #define EXTENDED_COPY 0x83 #define ATA_PASSTHROUGH 0x85 diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index a029ab6e84..045c764d9b 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -28,9 +28,6 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do {} while(0) #endif -#define BADF(fmt, ...) \ -do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) - #include "qemu-common.h" #include "qemu-error.h" #include "scsi.h" @@ -61,10 +58,13 @@ typedef struct SCSIDiskReq { BlockAcctCookie acct; } SCSIDiskReq; +#define SCSI_DISK_F_REMOVABLE 0 +#define SCSI_DISK_F_DPOFUA 1 + struct SCSIDiskState { SCSIDevice qdev; - uint32_t removable; + uint32_t features; bool media_changed; bool media_event; bool eject_request; @@ -296,6 +296,13 @@ static void scsi_do_read(void *opaque, int ret) } } + if (r->req.io_canceled) { + return; + } + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + if (r->req.sg) { dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ); r->req.resid -= r->req.sg->size; @@ -505,20 +512,9 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); int buflen = 0; - if (req->cmd.buf[1] & 0x2) { - /* Command support data - optional, not implemented */ - BADF("optional INQUIRY command support request not implemented\n"); - return -1; - } - if (req->cmd.buf[1] & 0x1) { /* Vital product data */ uint8_t page_code = req->cmd.buf[2]; - if (req->cmd.xfer < 4) { - BADF("Error: Inquiry (EVPD[%02X]) buffer size %zd is " - "less than 4\n", page_code, req->cmd.xfer); - return -1; - } outbuf[buflen++] = s->qdev.type & 0x1f; outbuf[buflen++] = page_code ; // this page @@ -633,8 +629,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) break; } default: - BADF("Error: unsupported Inquiry (EVPD[%02X]) " - "buffer size %zd\n", page_code, req->cmd.xfer); return -1; } /* done with EVPD */ @@ -643,18 +637,10 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) /* Standard INQUIRY data */ if (req->cmd.buf[2] != 0) { - BADF("Error: Inquiry (STANDARD) page or code " - "is non-zero [%02X]\n", req->cmd.buf[2]); return -1; } /* PAGE CODE == 0 */ - if (req->cmd.xfer < 5) { - BADF("Error: Inquiry (STANDARD) buffer size %zd " - "is less than 5\n", req->cmd.xfer); - return -1; - } - buflen = req->cmd.xfer; if (buflen > SCSI_MAX_INQUIRY_LEN) { buflen = SCSI_MAX_INQUIRY_LEN; @@ -662,7 +648,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) memset(outbuf, 0, buflen); outbuf[0] = s->qdev.type & 0x1f; - outbuf[1] = s->removable ? 0x80 : 0; + outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0; if (s->qdev.type == TYPE_ROM) { memcpy(&outbuf[16], "QEMU CD-ROM ", 16); } else { @@ -1094,7 +1080,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) p = outbuf; if (s->qdev.type == TYPE_DISK) { - dev_specific_param = 0x10; /* DPOFUA */ + dev_specific_param = s->features & (1 << SCSI_DISK_F_DPOFUA) ? 0x10 : 0; if (bdrv_is_read_only(s->qdev.conf.bs)) { dev_specific_param |= 0x80; /* Readonly. */ } @@ -1559,8 +1545,11 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) } break; case WRITE_SAME_10: + len = lduw_be_p(&buf[7]); + goto write_same; case WRITE_SAME_16: - len = r->req.cmd.xfer / s->qdev.blocksize; + len = ldl_be_p(&buf[10]) & 0xffffffffULL; + write_same: DPRINTF("WRITE SAME() (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); @@ -1700,7 +1689,8 @@ static int scsi_initfn(SCSIDevice *dev) return -1; } - if (!s->removable && !bdrv_is_inserted(s->qdev.conf.bs)) { + if (!(s->features & (1 << SCSI_DISK_F_REMOVABLE)) && + !bdrv_is_inserted(s->qdev.conf.bs)) { error_report("Device needs media, but drive is empty"); return -1; } @@ -1722,7 +1712,7 @@ static int scsi_initfn(SCSIDevice *dev) return -1; } - if (s->removable) { + if (s->features & (1 << SCSI_DISK_F_REMOVABLE)) { bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s); } bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize); @@ -1745,7 +1735,7 @@ static int scsi_cd_initfn(SCSIDevice *dev) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); s->qdev.blocksize = 2048; s->qdev.type = TYPE_ROM; - s->removable = true; + s->features |= 1 << SCSI_DISK_F_REMOVABLE; return scsi_initfn(&s->qdev); } @@ -1818,7 +1808,9 @@ static int get_device_type(SCSIDiskState *s) return -1; } s->qdev.type = buf[0]; - s->removable = (buf[1] & 0x80) != 0; + if (buf[1] & 0x80) { + s->features |= 1 << SCSI_DISK_F_REMOVABLE; + } return 0; } @@ -1918,7 +1910,10 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, static Property scsi_hd_properties[] = { DEFINE_SCSI_DISK_PROPERTIES(), - DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), + DEFINE_PROP_BIT("removable", SCSIDiskState, features, + SCSI_DISK_F_REMOVABLE, false), + DEFINE_PROP_BIT("dpofua", SCSIDiskState, features, + SCSI_DISK_F_DPOFUA, false), DEFINE_PROP_END_OF_LIST(), }; @@ -2020,7 +2015,10 @@ static TypeInfo scsi_block_info = { static Property scsi_disk_properties[] = { DEFINE_SCSI_DISK_PROPERTIES(), - DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), + DEFINE_PROP_BIT("removable", SCSIDiskState, features, + SCSI_DISK_F_REMOVABLE, false), + DEFINE_PROP_BIT("dpofua", SCSIDiskState, features, + SCSI_DISK_F_DPOFUA, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/sun4u.c b/hw/sun4u.c index fe3313890d..517bdb818d 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -67,7 +67,6 @@ #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 -#define INITRD_LOAD_ADDR 0x00300000 #define PROM_SIZE_MAX (4 * 1024 * 1024) #define PROM_VADDR 0x000ffd00000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL @@ -181,14 +180,18 @@ static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size, return 0; } -static unsigned long sun4u_load_kernel(const char *kernel_filename, - const char *initrd_filename, - ram_addr_t RAM_size, long *initrd_size) + +static uint64_t sun4u_load_kernel(const char *kernel_filename, + const char *initrd_filename, + ram_addr_t RAM_size, uint64_t *initrd_size, + uint64_t *initrd_addr, uint64_t *kernel_addr, + uint64_t *kernel_entry) { int linux_boot; unsigned int i; long kernel_size; uint8_t *ptr; + uint64_t kernel_top; linux_boot = (kernel_filename != NULL); @@ -201,29 +204,34 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename, #else bswap_needed = 0; #endif - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - NULL, NULL, 1, ELF_MACHINE, 0); - if (kernel_size < 0) + kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry, + kernel_addr, &kernel_top, 1, ELF_MACHINE, 0); + if (kernel_size < 0) { + *kernel_addr = KERNEL_LOAD_ADDR; + *kernel_entry = KERNEL_LOAD_ADDR; kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR, RAM_size - KERNEL_LOAD_ADDR, bswap_needed, TARGET_PAGE_SIZE); - if (kernel_size < 0) + } + if (kernel_size < 0) { kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, RAM_size - KERNEL_LOAD_ADDR); + } if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } - - /* load initrd */ + /* load initrd above kernel */ *initrd_size = 0; if (initrd_filename) { + *initrd_addr = TARGET_PAGE_ALIGN(kernel_top); + *initrd_size = load_image_targphys(initrd_filename, - INITRD_LOAD_ADDR, - RAM_size - INITRD_LOAD_ADDR); - if (*initrd_size < 0) { + *initrd_addr, + RAM_size - *initrd_addr); + if ((int)*initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); @@ -231,9 +239,9 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename, } if (*initrd_size > 0) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - ptr = rom_ptr(KERNEL_LOAD_ADDR + i); + ptr = rom_ptr(*kernel_addr + i); if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */ - stl_p(ptr + 24, INITRD_LOAD_ADDR + KERNEL_LOAD_ADDR - 0x4000); + stl_p(ptr + 24, *initrd_addr + *kernel_addr); stl_p(ptr + 28, *initrd_size); break; } @@ -788,7 +796,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, CPUSPARCState *env; M48t59State *nvram; unsigned int i; - long initrd_size, kernel_size; + uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; PCIBus *pci_bus, *pci_bus2, *pci_bus3; ISABus *isa_bus; qemu_irq *ivec_irqs, *pbm_irqs; @@ -845,13 +853,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem, nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59); initrd_size = 0; + initrd_addr = 0; kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename, - ram_size, &initrd_size); + ram_size, &initrd_size, &initrd_addr, + &kernel_addr, &kernel_entry); sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices, - KERNEL_LOAD_ADDR, kernel_size, + kernel_addr, kernel_size, kernel_cmdline, - INITRD_LOAD_ADDR, initrd_size, + initrd_addr, initrd_size, /* XXX: need an option to load a NVRAM image */ 0, graphic_width, graphic_height, graphic_depth, @@ -861,8 +871,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry); + fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); @@ -872,8 +882,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, } else { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); } - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); + fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); + fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width); diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 4ff4d40a8c..e759c996ce 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1091,8 +1091,8 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) break; case USBSTS: - val &= USBSTS_RO_MASK; // bits 6 thru 31 are RO - ehci_clear_usbsts(s, val); // bits 0 thru 5 are R/WC + val &= USBSTS_RO_MASK; // bits 6 through 31 are RO + ehci_clear_usbsts(s, val); // bits 0 through 5 are R/WC val = s->usbsts; ehci_set_interrupt(s, 0); break; diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 048f8ffa8b..a95b0eda55 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1058,6 +1058,15 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, ret = usb_host_set_interface(s, index, value); trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); return ret; + + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == 0) { /* clear halt */ + int pid = (index & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; + ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index); + clear_halt(s, pid, index & 0x0f); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0); + return 0; + } } /* The rest are asynchronous */ @@ -2357,10 +2357,15 @@ void vga_init(VGACommonState *s, MemoryRegion *address_space, void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory) { #ifdef CONFIG_BOCHS_VBE + /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region, + * so use an alias to avoid double-mapping the same region. + */ + memory_region_init_alias(&s->vram_vbe, "vram.vbe", + &s->vram, 0, memory_region_size(&s->vram)); /* XXX: use optimized standard vga accesses */ memory_region_add_subregion(system_memory, VBE_DISPI_LFB_PHYSICAL_ADDRESS, - &s->vram); + &s->vram_vbe); s->vbe_mapped = 1; #endif } diff --git a/hw/vga_int.h b/hw/vga_int.h index 7685b2b167..d244d8ff99 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -105,6 +105,7 @@ typedef struct VGACommonState { MemoryRegion *legacy_address_space; uint8_t *vram_ptr; MemoryRegion vram; + MemoryRegion vram_vbe; uint32_t vram_size; uint32_t latch; MemoryRegion *chain4_alias; diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index ce9d2c9759..075ed87e37 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -211,11 +211,15 @@ static void virtio_balloon_save(QEMUFile *f, void *opaque) static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBalloon *s = opaque; + int ret; if (version_id != 1) return -EINVAL; - virtio_load(&s->vdev, f); + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } s->num_pages = qemu_get_be32(f); s->actual = qemu_get_be32(f); diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 49990f8efe..fe0774617b 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -29,7 +29,7 @@ typedef struct VirtIOBlock void *rq; QEMUBH *bh; BlockConf *conf; - char *serial; + VirtIOBlkConf *blk; unsigned short sector_mask; DeviceState *qdev; } VirtIOBlock; @@ -145,19 +145,13 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) return req; } -#ifdef __linux__ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) { - struct sg_io_hdr hdr; +#ifdef __linux__ int ret; - int status; int i; - - if ((req->dev->vdev.guest_features & (1 << VIRTIO_BLK_F_SCSI)) == 0) { - virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); - g_free(req); - return; - } +#endif + int status = VIRTIO_BLK_S_OK; /* * We require at least one output segment each for the virtio_blk_outhdr @@ -173,20 +167,26 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) } /* - * No support for bidirection commands yet. + * The scsi inhdr is placed in the second-to-last input segment, just + * before the regular inhdr. */ - if (req->elem.out_num > 2 && req->elem.in_num > 3) { - virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); - g_free(req); - return; + req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; + + if (!req->dev->blk->scsi) { + status = VIRTIO_BLK_S_UNSUPP; + goto fail; } /* - * The scsi inhdr is placed in the second-to-last input segment, just - * before the regular inhdr. + * No support for bidirection commands yet. */ - req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; + if (req->elem.out_num > 2 && req->elem.in_num > 3) { + status = VIRTIO_BLK_S_UNSUPP; + goto fail; + } +#ifdef __linux__ + struct sg_io_hdr hdr; memset(&hdr, 0, sizeof(struct sg_io_hdr)); hdr.interface_id = 'S'; hdr.cmd_len = req->elem.out_sg[1].iov_len; @@ -230,12 +230,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr); if (ret) { status = VIRTIO_BLK_S_UNSUPP; - hdr.status = ret; - hdr.resid = hdr.dxfer_len; - } else if (hdr.status) { - status = VIRTIO_BLK_S_IOERR; - } else { - status = VIRTIO_BLK_S_OK; + goto fail; } /* @@ -258,14 +253,16 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) virtio_blk_req_complete(req, status); g_free(req); -} #else -static void virtio_blk_handle_scsi(VirtIOBlockReq *req) -{ - virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); + abort(); +#endif + +fail: + /* Just put anything nonzero so that the ioctl fails in the guest. */ + stl_p(&req->scsi->errors, 255); + virtio_blk_req_complete(req, status); g_free(req); } -#endif /* __linux__ */ typedef struct MultiReqBuffer { BlockRequest blkreq[32]; @@ -394,7 +391,7 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, * terminated by '\0' only when shorter than buffer. */ strncpy(req->elem.in_sg[0].iov_base, - s->serial ? s->serial : "", + s->blk->serial ? s->blk->serial : "", MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES)); virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); g_free(req); @@ -494,7 +491,22 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size); stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size); blkcfg.heads = heads; - blkcfg.sectors = secs & ~s->sector_mask; + /* + * We must ensure that the block device capacity is a multiple of + * the logical block size. If that is not the case, lets use + * sector_mask to adopt the geometry to have a correct picture. + * For those devices where the capacity is ok for the given geometry + * we dont touch the sector value of the geometry, since some devices + * (like s390 dasd) need a specific value. Here the capacity is already + * cyls*heads*secs*blk_size and the sector value is not block size + * divided by 512 - instead it is the amount of blk_size blocks + * per track (cylinder). + */ + if (bdrv_getlength(s->bs) / heads / secs % blk_size) { + blkcfg.sectors = secs & ~s->sector_mask; + } else { + blkcfg.sectors = secs; + } blkcfg.size_max = 0; blkcfg.physical_block_exp = get_physical_block_exp(s->conf); blkcfg.alignment_offset = 0; @@ -509,6 +521,7 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) features |= (1 << VIRTIO_BLK_F_GEOMETRY); features |= (1 << VIRTIO_BLK_F_TOPOLOGY); features |= (1 << VIRTIO_BLK_F_BLK_SIZE); + features |= (1 << VIRTIO_BLK_F_SCSI); if (bdrv_enable_write_cache(s->bs)) features |= (1 << VIRTIO_BLK_F_WCACHE); @@ -537,11 +550,16 @@ static void virtio_blk_save(QEMUFile *f, void *opaque) static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBlock *s = opaque; + int ret; if (version_id != 2) return -EINVAL; - virtio_load(&s->vdev, f); + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } + while (qemu_get_sbyte(f)) { VirtIOBlockReq *req = virtio_blk_alloc_request(s); qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem)); @@ -568,28 +586,27 @@ static const BlockDevOps virtio_block_ops = { .resize_cb = virtio_blk_resize, }; -VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, - char **serial) +VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk) { VirtIOBlock *s; int cylinders, heads, secs; static int virtio_blk_id; DriveInfo *dinfo; - if (!conf->bs) { + if (!blk->conf.bs) { error_report("drive property not set"); return NULL; } - if (!bdrv_is_inserted(conf->bs)) { + if (!bdrv_is_inserted(blk->conf.bs)) { error_report("Device needs media, but drive is empty"); return NULL; } - if (!*serial) { + if (!blk->serial) { /* try to fall back to value set with legacy -drive serial=... */ - dinfo = drive_get_by_blockdev(conf->bs); + dinfo = drive_get_by_blockdev(blk->conf.bs); if (*dinfo->serial) { - *serial = strdup(dinfo->serial); + blk->serial = strdup(dinfo->serial); } } @@ -600,9 +617,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, s->vdev.get_config = virtio_blk_update_config; s->vdev.get_features = virtio_blk_get_features; s->vdev.reset = virtio_blk_reset; - s->bs = conf->bs; - s->conf = conf; - s->serial = *serial; + s->bs = blk->conf.bs; + s->conf = &blk->conf; + s->blk = blk; s->rq = NULL; s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1; bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); @@ -614,10 +631,10 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); - bdrv_set_buffer_alignment(s->bs, conf->logical_block_size); + bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size); bdrv_iostatus_enable(s->bs); - add_boot_device_path(conf->bootindex, dev, "/disk@0,0"); + add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0"); return &s->vdev; } @@ -626,5 +643,6 @@ void virtio_blk_exit(VirtIODevice *vdev) { VirtIOBlock *s = to_virtio_blk(vdev); unregister_savevm(s->qdev, "virtio-blk", s); + blockdev_mark_auto_del(s->bs); virtio_cleanup(vdev); } diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index 244dce45aa..d7850012bd 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -97,12 +97,14 @@ struct virtio_scsi_inhdr uint32_t residual; }; -#ifdef __linux__ -#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ - DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \ - DEFINE_PROP_BIT("scsi", _state, _field, VIRTIO_BLK_F_SCSI, true) -#else +struct VirtIOBlkConf +{ + BlockConf conf; + char *serial; + uint32_t scsi; +}; + #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) -#endif + #endif diff --git a/hw/virtio-net.c b/hw/virtio-net.c index bc5e3a83d1..3f190d417e 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -891,11 +891,15 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; int i; + int ret; if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) return -EINVAL; - virtio_load(&n->vdev, f); + ret = virtio_load(&n->vdev, f); + if (ret) { + return ret; + } qemu_get_buffer(f, n->mac, ETH_ALEN); n->tx_waiting = qemu_get_be32(f); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 01f5b92b1c..d08c1590d2 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -492,7 +492,7 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) virtio_config_writel(proxy->vdev, addr, val); } -const MemoryRegionPortio virtio_portio[] = { +static const MemoryRegionPortio virtio_portio[] = { { 0, 0x10000, 1, .write = virtio_pci_config_writeb, }, { 0, 0x10000, 2, .write = virtio_pci_config_writew, }, { 0, 0x10000, 4, .write = virtio_pci_config_writel, }, @@ -823,8 +823,7 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev) proxy->class_code != PCI_CLASS_STORAGE_OTHER) proxy->class_code = PCI_CLASS_STORAGE_SCSI; - vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block, - &proxy->block_serial); + vdev = virtio_blk_init(&pci_dev->qdev, &proxy->blk); if (!vdev) { return -1; } @@ -852,7 +851,6 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev) virtio_pci_stop_ioeventfd(proxy); virtio_blk_exit(proxy->vdev); - blockdev_mark_auto_del(proxy->block.bs); return virtio_exit_pci(pci_dev); } @@ -940,8 +938,11 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev) static Property virtio_blk_properties[] = { DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block), - DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial), + DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf), + DEFINE_PROP_STRING("serial", VirtIOPCIProxy, blk.serial), +#ifdef __linux__ + DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true), +#endif DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index 8d28d4b789..91b791ba9d 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -15,6 +15,7 @@ #ifndef QEMU_VIRTIO_PCI_H #define QEMU_VIRTIO_PCI_H +#include "virtio-blk.h" #include "virtio-net.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -37,8 +38,7 @@ typedef struct { uint32_t flags; uint32_t class_code; uint32_t nvectors; - BlockConf block; - char *block_serial; + VirtIOBlkConf blk; NICConf nic; uint32_t host_features; #ifdef CONFIG_LINUX diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index e8328f4652..5e39ce93c4 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -564,7 +564,12 @@ static void virtio_scsi_save(QEMUFile *f, void *opaque) static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) { VirtIOSCSI *s = opaque; - virtio_load(&s->vdev, f); + int ret; + + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } return 0; } diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index ffbdfc2de1..72287d10ce 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -637,13 +637,17 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) VirtIOSerialPort *port; uint32_t max_nr_ports, nr_active_ports, ports_map; unsigned int i; + int ret; if (version_id > 3) { return -EINVAL; } /* The virtio device */ - virtio_load(&s->vdev, f); + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } if (version_id < 2) { return 0; diff --git a/hw/virtio.h b/hw/virtio.h index 0aef7d1bc0..85aabe53d8 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -191,8 +191,8 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, void *opaque); /* Base devices. */ -VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, - char **serial); +typedef struct VirtIOBlkConf VirtIOBlkConf; +VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk); struct virtio_net_conf; VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, struct virtio_net_conf *net); diff --git a/hw/xen_common.h b/hw/xen_common.h index 7043c14cae..fe7f227f92 100644 --- a/hw/xen_common.h +++ b/hw/xen_common.h @@ -148,6 +148,6 @@ static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom, } #endif -void destroy_hvm_domain(void); +void destroy_hvm_domain(bool reboot); #endif /* QEMU_HW_XEN_COMMON_H */ diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 22dbd10303..07594bc0c8 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -48,7 +48,6 @@ /* ------------------------------------------------------------- */ -static int syncwrite = 0; static int batch_maps = 0; static int max_requests = 32; @@ -67,6 +66,7 @@ struct ioreq { QEMUIOVector v; int presync; int postsync; + uint8_t mapped; /* grant mapping */ uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST]; @@ -154,7 +154,7 @@ static void ioreq_finish(struct ioreq *ioreq) blkdev->requests_finished++; } -static void ioreq_release(struct ioreq *ioreq) +static void ioreq_release(struct ioreq *ioreq, bool finish) { struct XenBlkDev *blkdev = ioreq->blkdev; @@ -162,7 +162,11 @@ static void ioreq_release(struct ioreq *ioreq) memset(ioreq, 0, sizeof(*ioreq)); ioreq->blkdev = blkdev; QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list); - blkdev->requests_finished--; + if (finish) { + blkdev->requests_finished--; + } else { + blkdev->requests_inflight--; + } } /* @@ -189,15 +193,10 @@ static int ioreq_parse(struct ioreq *ioreq) ioreq->presync = 1; return 0; } - if (!syncwrite) { - ioreq->presync = ioreq->postsync = 1; - } + ioreq->presync = ioreq->postsync = 1; /* fall through */ case BLKIF_OP_WRITE: ioreq->prot = PROT_READ; /* from memory */ - if (syncwrite) { - ioreq->postsync = 1; - } break; default: xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n", @@ -248,7 +247,7 @@ static void ioreq_unmap(struct ioreq *ioreq) XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev; int i; - if (ioreq->v.niov == 0) { + if (ioreq->v.niov == 0 || ioreq->mapped == 0) { return; } if (batch_maps) { @@ -274,6 +273,7 @@ static void ioreq_unmap(struct ioreq *ioreq) ioreq->page[i] = NULL; } } + ioreq->mapped = 0; } static int ioreq_map(struct ioreq *ioreq) @@ -281,7 +281,7 @@ static int ioreq_map(struct ioreq *ioreq) XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev; int i; - if (ioreq->v.niov == 0) { + if (ioreq->v.niov == 0 || ioreq->mapped == 1) { return 0; } if (batch_maps) { @@ -313,9 +313,12 @@ static int ioreq_map(struct ioreq *ioreq) ioreq->blkdev->cnt_map++; } } + ioreq->mapped = 1; return 0; } +static int ioreq_runio_qemu_aio(struct ioreq *ioreq); + static void qemu_aio_complete(void *opaque, int ret) { struct ioreq *ioreq = opaque; @@ -327,11 +330,19 @@ static void qemu_aio_complete(void *opaque, int ret) } ioreq->aio_inflight--; + if (ioreq->presync) { + ioreq->presync = 0; + ioreq_runio_qemu_aio(ioreq); + return; + } if (ioreq->aio_inflight > 0) { return; } if (ioreq->postsync) { - bdrv_flush(ioreq->blkdev->bs); + ioreq->postsync = 0; + ioreq->aio_inflight++; + bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq); + return; } ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; @@ -351,7 +362,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) ioreq->aio_inflight++; if (ioreq->presync) { - bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */ + bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq); + return 0; } switch (ioreq->req.operation) { @@ -449,7 +461,7 @@ static void blk_send_response_all(struct XenBlkDev *blkdev) while (!QLIST_EMPTY(&blkdev->finished)) { ioreq = QLIST_FIRST(&blkdev->finished); send_notify += blk_send_response_one(ioreq); - ioreq_release(ioreq); + ioreq_release(ioreq, true); } if (send_notify) { xen_be_send_notify(&blkdev->xendev); @@ -505,7 +517,7 @@ static void blk_handle_requests(struct XenBlkDev *blkdev) if (blk_send_response_one(ioreq)) { xen_be_send_notify(&blkdev->xendev); } - ioreq_release(ioreq); + ioreq_release(ioreq, false); continue; } diff --git a/hw/xen_platform.c b/hw/xen_platform.c index a9c52a6e36..0214f370b2 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -87,7 +87,10 @@ static void unplug_nic(PCIBus *b, PCIDevice *d) { if (pci_get_word(d->config + PCI_CLASS_DEVICE) == PCI_CLASS_NETWORK_ETHERNET) { - qdev_unplug(&(d->qdev), NULL); + /* Until qdev_free includes a call to object_unparent, we call it here + */ + object_unparent(&d->qdev.parent_obj); + qdev_free(&d->qdev); } } |