aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/ac97.c67
-rw-r--r--hw/acpi_piix4.c1
-rw-r--r--hw/apb_pci.c18
-rw-r--r--hw/es1370.c11
-rw-r--r--hw/fdc.c41
-rw-r--r--hw/ide/ahci.c4
-rw-r--r--hw/loader.c2
-rw-r--r--hw/loader.h3
-rw-r--r--hw/mips_fulong2e.c1
-rw-r--r--hw/multiboot.c12
-rw-r--r--hw/pc.c25
-rw-r--r--hw/pc_piix.c4
-rw-r--r--hw/pc_sysfw.c3
-rw-r--r--hw/pci.c1
-rw-r--r--hw/qdev-monitor.c6
-rw-r--r--hw/qdev-properties.c7
-rw-r--r--hw/qdev.c5
-rw-r--r--hw/qxl-logger.c51
-rw-r--r--hw/qxl-render.c14
-rw-r--r--hw/qxl.c153
-rw-r--r--hw/qxl.h6
-rw-r--r--hw/rtl8139.c2
-rw-r--r--hw/s390-virtio-bus.c10
-rw-r--r--hw/s390-virtio-bus.h4
-rw-r--r--hw/scsi-bus.c102
-rw-r--r--hw/scsi-defs.h1
-rw-r--r--hw/scsi-disk.c66
-rw-r--r--hw/sun4u.c56
-rw-r--r--hw/usb/hcd-ehci.c4
-rw-r--r--hw/usb/host-linux.c9
-rw-r--r--hw/vga.c7
-rw-r--r--hw/vga_int.h1
-rw-r--r--hw/virtio-balloon.c6
-rw-r--r--hw/virtio-blk.c106
-rw-r--r--hw/virtio-blk.h14
-rw-r--r--hw/virtio-net.c6
-rw-r--r--hw/virtio-pci.c13
-rw-r--r--hw/virtio-pci.h4
-rw-r--r--hw/virtio-scsi.c7
-rw-r--r--hw/virtio-serial-bus.c6
-rw-r--r--hw/virtio.h4
-rw-r--r--hw/xen_common.h2
-rw-r--r--hw/xen_disk.c42
-rw-r--r--hw/xen_platform.c5
44 files changed, 594 insertions, 318 deletions
diff --git a/hw/ac97.c b/hw/ac97.c
index 177f729d48..e791b9d3e6 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -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;
diff --git a/hw/fdc.c b/hw/fdc.c
index 756d4cefd5..30d34e3f1d 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -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);
diff --git a/hw/pc.c b/hw/pc.c
index 6691b18196..c790bcbfd7 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -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;
}
diff --git a/hw/pci.c b/hw/pci.c
index b706e6980a..c1ebdde91e 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -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)
diff --git a/hw/qdev.c b/hw/qdev.c
index 0bcde20c92..6a8f6bda2b 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -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(&copy->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;
}
diff --git a/hw/qxl.c b/hw/qxl.c
index c3540c3d50..3da3399934 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -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) {
diff --git a/hw/qxl.h b/hw/qxl.h
index cbb1e2d6d4..31029503fe 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -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 */
diff --git a/hw/vga.c b/hw/vga.c
index 5824f85d04..d784df7df4 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -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);
}
}