diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 28 | ||||
-rw-r--r-- | Makefile.objs | 5 | ||||
-rw-r--r-- | Makefile.target | 19 | ||||
-rw-r--r-- | audio/audio.c | 3 | ||||
-rw-r--r-- | audio/audio_int.h | 1 | ||||
-rw-r--r-- | audio/spiceaudio.c | 346 | ||||
-rw-r--r-- | block.c | 21 | ||||
-rw-r--r-- | block.h | 2 | ||||
-rw-r--r-- | block/blkdebug.c | 4 | ||||
-rw-r--r-- | block/blkverify.c | 8 | ||||
-rw-r--r-- | block/cow.c | 4 | ||||
-rw-r--r-- | block/qcow.c | 4 | ||||
-rw-r--r-- | block/qcow2-cluster.c | 1 | ||||
-rw-r--r-- | block/qcow2-refcount.c | 1 | ||||
-rw-r--r-- | block/qcow2.c | 4 | ||||
-rw-r--r-- | block/raw-posix.c | 4 | ||||
-rw-r--r-- | block/raw-win32.c | 11 | ||||
-rw-r--r-- | block/raw.c | 4 | ||||
-rw-r--r-- | block/vdi.c | 4 | ||||
-rw-r--r-- | block/vmdk.c | 4 | ||||
-rw-r--r-- | block/vpc.c | 21 | ||||
-rw-r--r-- | block_int.h | 2 | ||||
-rw-r--r-- | blockdev.c | 6 | ||||
-rwxr-xr-x | configure | 21 | ||||
-rw-r--r-- | cutils.c | 88 | ||||
-rw-r--r-- | hmp-commands.hx | 5 | ||||
-rw-r--r-- | hw/acpi_piix4.c | 14 | ||||
-rw-r--r-- | hw/apic.c | 4 | ||||
-rw-r--r-- | hw/e1000.c | 5 | ||||
-rw-r--r-- | hw/hda-audio.c | 24 | ||||
-rw-r--r-- | hw/ide/core.c | 12 | ||||
-rw-r--r-- | hw/intel-hda.c | 69 | ||||
-rw-r--r-- | hw/intel-hda.h | 1 | ||||
-rw-r--r-- | hw/mips_malta.c | 2 | ||||
-rw-r--r-- | hw/multiboot.c | 6 | ||||
-rw-r--r-- | hw/pc.c | 2 | ||||
-rw-r--r-- | hw/pc.h | 3 | ||||
-rw-r--r-- | hw/pci.c | 13 | ||||
-rw-r--r-- | hw/pci.h | 10 | ||||
-rw-r--r-- | hw/pcie.c | 10 | ||||
-rw-r--r-- | hw/ppc_newworld.c | 2 | ||||
-rw-r--r-- | hw/ppc_oldworld.c | 2 | ||||
-rw-r--r-- | hw/ppc_prep.c | 2 | ||||
-rw-r--r-- | hw/scsi-disk.c | 147 | ||||
-rw-r--r-- | hw/sun4u.c | 2 | ||||
-rw-r--r-- | hw/vga-pci.c | 43 | ||||
-rw-r--r-- | hw/vga.c | 2 | ||||
-rw-r--r-- | hw/vga_int.h | 2 | ||||
-rw-r--r-- | hw/virtio-blk.c | 2 | ||||
-rw-r--r-- | hw/vmware_vga.c | 7 | ||||
-rw-r--r-- | migration.c | 4 | ||||
-rw-r--r-- | monitor.c | 47 | ||||
-rw-r--r-- | net/tap.c | 7 | ||||
-rw-r--r-- | pc-bios/vgabios-cirrus.bin | bin | 35840 -> 35840 bytes | |||
-rw-r--r-- | pc-bios/vgabios-stdvga.bin | bin | 0 -> 40448 bytes | |||
-rw-r--r-- | pc-bios/vgabios-vmware.bin | bin | 0 -> 40448 bytes | |||
-rw-r--r-- | pc-bios/vgabios.bin | bin | 38400 -> 40448 bytes | |||
-rw-r--r-- | qemu-char.c | 8 | ||||
-rw-r--r-- | qemu-common.h | 1 | ||||
m--------- | roms/vgabios | 0 | ||||
-rw-r--r-- | target-i386/cpu.h | 1 | ||||
-rw-r--r-- | target-i386/cpuid.c | 2 | ||||
-rw-r--r-- | target-i386/kvm.c | 14 | ||||
-rw-r--r-- | target-i386/machine.c | 26 | ||||
-rwxr-xr-x | tracetool | 208 | ||||
-rw-r--r-- | ui/qemu-spice.h | 1 | ||||
-rw-r--r-- | ui/spice-core.c | 1 | ||||
-rw-r--r-- | vl.c | 29 |
69 files changed, 1128 insertions, 230 deletions
diff --git a/.gitignore b/.gitignore index a43e4d1d98..3efb4ecc13 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ config-host.* config-target.* trace.h trace.c +trace-dtrace.h +trace-dtrace.dtrace *-timestamp *-softmmu *-darwin-user @@ -1,6 +1,9 @@ # Makefile for QEMU. GENERATED_HEADERS = config-host.h trace.h qemu-options.def +ifeq ($(TRACE_BACKEND),dtrace) +GENERATED_HEADERS += trace-dtrace.h +endif ifneq ($(wildcard config-host.mak),) # Put the all: rule here so that config-host.mak can contain dependencies. @@ -108,7 +111,11 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) +ifeq ($(TRACE_BACKEND),dtrace) +trace.h: trace.h-timestamp trace-dtrace.h +else trace.h: trace.h-timestamp +endif trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") @cmp -s $@ trace.h || cp $@ trace.h @@ -120,6 +127,20 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak trace.o: trace.c $(GENERATED_HEADERS) +trace-dtrace.h: trace-dtrace.dtrace + $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h") + +# Normal practice is to name DTrace probe file with a '.d' extension +# but that gets picked up by QEMU's Makefile as an external dependancy +# rule file. So we use '.dtrace' instead +trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp +trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak + $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") + @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace + +trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) + $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o") + simpletrace.o: simpletrace.c $(GENERATED_HEADERS) version.o: $(SRC_PATH)/version.rc config-host.mak @@ -157,6 +178,8 @@ clean: rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d rm -f qemu-img-cmds.h rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp + rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp + rm -f trace-dtrace.h trace-dtrace.h-timestamp $(MAKE) -C tests clean for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ @@ -178,8 +201,9 @@ ar de en-us fi fr-be hr it lv nl pl ru th \ common de-ch es fo fr-ca hu ja mk nl-be pt sl tr ifdef INSTALL_BLOBS -BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ -openbios-sparc32 openbios-sparc64 openbios-ppc \ +BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \ +vgabios-stdvga.bin vgabios-vmware.bin \ +ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \ gpxe-eepro100-80861209.rom \ gpxe-eepro100-80861229.rom \ pxe-e1000.bin \ diff --git a/Makefile.objs b/Makefile.objs index faf485ed1b..23b17cefad 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -102,6 +102,7 @@ common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display. audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o audio-obj-$(CONFIG_SDL) += sdlaudio.o audio-obj-$(CONFIG_OSS) += ossaudio.o +audio-obj-$(CONFIG_SPICE) += spiceaudio.o audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o audio-obj-$(CONFIG_ALSA) += alsaaudio.o audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o @@ -285,11 +286,15 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o ###################################################################### # trace +ifeq ($(TRACE_BACKEND),dtrace) +trace-obj-y = trace-dtrace.o +else trace-obj-y = trace.o ifeq ($(TRACE_BACKEND),simple) trace-obj-y += simpletrace.o user-obj-y += qemu-timer-common.o endif +endif vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) diff --git a/Makefile.target b/Makefile.target index 91e6e74399..a5e6410cec 100644 --- a/Makefile.target +++ b/Makefile.target @@ -40,7 +40,20 @@ kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS) config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak -all: $(PROGS) +ifdef CONFIG_SYSTEMTAP_TRACE +trace: $(QEMU_PROG).stp + +$(QEMU_PROG).stp: + $(call quiet-command,sh $(SRC_PATH)/tracetool \ + --$(TRACE_BACKEND) \ + --bindir $(bindir) \ + --target $(TARGET_ARCH) \ + -s < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp") +else +trace: +endif + +all: $(PROGS) trace # Dummy command so that make thinks it has done something @true @@ -348,6 +361,10 @@ ifneq ($(STRIP),) $(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS)) endif endif +ifdef CONFIG_SYSTEMTAP_TRACE + $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset" + $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset" +endif # Include automatically generated dependency files -include $(wildcard *.d */*.d) diff --git a/audio/audio.c b/audio/audio.c index ad51077f32..ade342e856 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -44,6 +44,9 @@ that we generate the list. */ static struct audio_driver *drvtab[] = { +#ifdef CONFIG_SPICE + &spice_audio_driver, +#endif CONFIG_AUDIO_DRIVERS &no_audio_driver, &wav_audio_driver diff --git a/audio/audio_int.h b/audio/audio_int.h index d8560b662b..d66f2c3bf6 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -209,6 +209,7 @@ extern struct audio_driver coreaudio_audio_driver; extern struct audio_driver dsound_audio_driver; extern struct audio_driver esd_audio_driver; extern struct audio_driver pa_audio_driver; +extern struct audio_driver spice_audio_driver; extern struct audio_driver winwave_audio_driver; extern struct mixeng_volume nominal_volume; diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c new file mode 100644 index 0000000000..373e4c43ed --- /dev/null +++ b/audio/spiceaudio.c @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * maintained by Gerd Hoffmann <kraxel@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw/hw.h" +#include "qemu-timer.h" +#include "ui/qemu-spice.h" + +#define AUDIO_CAP "spice" +#include "audio.h" +#include "audio_int.h" + +#define LINE_IN_SAMPLES 1024 +#define LINE_OUT_SAMPLES 1024 + +typedef struct SpiceRateCtl { + int64_t start_ticks; + int64_t bytes_sent; +} SpiceRateCtl; + +typedef struct SpiceVoiceOut { + HWVoiceOut hw; + SpicePlaybackInstance sin; + SpiceRateCtl rate; + int active; + uint32_t *frame; + uint32_t *fpos; + uint32_t fsize; +} SpiceVoiceOut; + +typedef struct SpiceVoiceIn { + HWVoiceIn hw; + SpiceRecordInstance sin; + SpiceRateCtl rate; + int active; + uint32_t samples[LINE_IN_SAMPLES]; +} SpiceVoiceIn; + +static const SpicePlaybackInterface playback_sif = { + .base.type = SPICE_INTERFACE_PLAYBACK, + .base.description = "playback", + .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR, + .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR, +}; + +static const SpiceRecordInterface record_sif = { + .base.type = SPICE_INTERFACE_RECORD, + .base.description = "record", + .base.major_version = SPICE_INTERFACE_RECORD_MAJOR, + .base.minor_version = SPICE_INTERFACE_RECORD_MINOR, +}; + +static void *spice_audio_init (void) +{ + if (!using_spice) { + return NULL; + } + return &spice_audio_init; +} + +static void spice_audio_fini (void *opaque) +{ + /* nothing */ +} + +static void rate_start (SpiceRateCtl *rate) +{ + memset (rate, 0, sizeof (*rate)); + rate->start_ticks = qemu_get_clock (vm_clock); +} + +static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate) +{ + int64_t now; + int64_t ticks; + int64_t bytes; + int64_t samples; + + now = qemu_get_clock (vm_clock); + ticks = now - rate->start_ticks; + bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ()); + samples = (bytes - rate->bytes_sent) >> info->shift; + if (samples < 0 || samples > 65536) { + fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples); + rate_start (rate); + samples = 0; + } + rate->bytes_sent += samples << info->shift; + return samples; +} + +/* playback */ + +static int line_out_init (HWVoiceOut *hw, struct audsettings *as) +{ + SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); + struct audsettings settings; + + settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ; + settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN; + settings.fmt = AUD_FMT_S16; + settings.endianness = AUDIO_HOST_ENDIANNESS; + + audio_pcm_init_info (&hw->info, &settings); + hw->samples = LINE_OUT_SAMPLES; + out->active = 0; + + out->sin.base.sif = &playback_sif.base; + qemu_spice_add_interface (&out->sin.base); + return 0; +} + +static void line_out_fini (HWVoiceOut *hw) +{ + SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); + + spice_server_remove_interface (&out->sin.base); +} + +static int line_out_run (HWVoiceOut *hw, int live) +{ + SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); + int rpos, decr; + int samples; + + if (!live) { + return 0; + } + + decr = rate_get_samples (&hw->info, &out->rate); + decr = audio_MIN (live, decr); + + samples = decr; + rpos = hw->rpos; + while (samples) { + int left_till_end_samples = hw->samples - rpos; + int len = audio_MIN (samples, left_till_end_samples); + + if (!out->frame) { + spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize); + out->fpos = out->frame; + } + if (out->frame) { + len = audio_MIN (len, out->fsize); + hw->clip (out->fpos, hw->mix_buf + rpos, len); + out->fsize -= len; + out->fpos += len; + if (out->fsize == 0) { + spice_server_playback_put_samples (&out->sin, out->frame); + out->frame = out->fpos = NULL; + } + } + rpos = (rpos + len) % hw->samples; + samples -= len; + } + hw->rpos = rpos; + return decr; +} + +static int line_out_write (SWVoiceOut *sw, void *buf, int len) +{ + return audio_pcm_sw_write (sw, buf, len); +} + +static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) +{ + SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); + + switch (cmd) { + case VOICE_ENABLE: + if (out->active) { + break; + } + out->active = 1; + rate_start (&out->rate); + spice_server_playback_start (&out->sin); + break; + case VOICE_DISABLE: + if (!out->active) { + break; + } + out->active = 0; + if (out->frame) { + memset (out->fpos, 0, out->fsize << 2); + spice_server_playback_put_samples (&out->sin, out->frame); + out->frame = out->fpos = NULL; + } + spice_server_playback_stop (&out->sin); + break; + } + return 0; +} + +/* record */ + +static int line_in_init (HWVoiceIn *hw, struct audsettings *as) +{ + SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); + struct audsettings settings; + + settings.freq = SPICE_INTERFACE_RECORD_FREQ; + settings.nchannels = SPICE_INTERFACE_RECORD_CHAN; + settings.fmt = AUD_FMT_S16; + settings.endianness = AUDIO_HOST_ENDIANNESS; + + audio_pcm_init_info (&hw->info, &settings); + hw->samples = LINE_IN_SAMPLES; + in->active = 0; + + in->sin.base.sif = &record_sif.base; + qemu_spice_add_interface (&in->sin.base); + return 0; +} + +static void line_in_fini (HWVoiceIn *hw) +{ + SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); + + spice_server_remove_interface (&in->sin.base); +} + +static int line_in_run (HWVoiceIn *hw) +{ + SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); + int num_samples; + int ready; + int len[2]; + uint64_t delta_samp; + const uint32_t *samples; + + if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) { + return 0; + } + + delta_samp = rate_get_samples (&hw->info, &in->rate); + num_samples = audio_MIN (num_samples, delta_samp); + + ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples); + samples = in->samples; + if (ready == 0) { + static const uint32_t silence[LINE_IN_SAMPLES]; + samples = silence; + ready = LINE_IN_SAMPLES; + } + + num_samples = audio_MIN (ready, num_samples); + + if (hw->wpos + num_samples > hw->samples) { + len[0] = hw->samples - hw->wpos; + len[1] = num_samples - len[0]; + } else { + len[0] = num_samples; + len[1] = 0; + } + + hw->conv (hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume); + + if (len[1]) { + hw->conv (hw->conv_buf, samples + len[0], len[1], + &nominal_volume); + } + + hw->wpos = (hw->wpos + num_samples) % hw->samples; + + return num_samples; +} + +static int line_in_read (SWVoiceIn *sw, void *buf, int size) +{ + return audio_pcm_sw_read (sw, buf, size); +} + +static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) +{ + SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); + + switch (cmd) { + case VOICE_ENABLE: + if (in->active) { + break; + } + in->active = 1; + rate_start (&in->rate); + spice_server_record_start (&in->sin); + break; + case VOICE_DISABLE: + if (!in->active) { + break; + } + in->active = 0; + spice_server_record_stop (&in->sin); + break; + } + return 0; +} + +static struct audio_option audio_options[] = { + { /* end of list */ }, +}; + +static struct audio_pcm_ops audio_callbacks = { + .init_out = line_out_init, + .fini_out = line_out_fini, + .run_out = line_out_run, + .write = line_out_write, + .ctl_out = line_out_ctl, + + .init_in = line_in_init, + .fini_in = line_in_fini, + .run_in = line_in_run, + .read = line_in_read, + .ctl_in = line_in_ctl, +}; + +struct audio_driver spice_audio_driver = { + .name = "spice", + .descr = "spice audio driver", + .options = audio_options, + .init = spice_audio_init, + .fini = spice_audio_fini, + .pcm_ops = &audio_callbacks, + .max_voices_out = 1, + .max_voices_in = 1, + .voice_size_out = sizeof (SpiceVoiceOut), + .voice_size_in = sizeof (SpiceVoiceIn), +}; + +void qemu_spice_audio_init (void) +{ + spice_audio_driver.can_be_default = 1; +} @@ -1453,14 +1453,27 @@ const char *bdrv_get_device_name(BlockDriverState *bs) return bs->device_name; } -void bdrv_flush(BlockDriverState *bs) +int bdrv_flush(BlockDriverState *bs) { if (bs->open_flags & BDRV_O_NO_FLUSH) { - return; + return 0; + } + + if (bs->drv && bs->drv->bdrv_flush) { + return bs->drv->bdrv_flush(bs); } - if (bs->drv && bs->drv->bdrv_flush) - bs->drv->bdrv_flush(bs); + /* + * Some block drivers always operate in either writethrough or unsafe mode + * and don't support bdrv_flush therefore. Usually qemu doesn't know how + * the server works (because the behaviour is hardcoded or depends on + * server-side configuration), so we can't ensure that everything is safe + * on disk. Returning an error doesn't work because that would break guests + * even if the server operates in writethrough mode. + * + * Let's hope the user knows what he's doing. + */ + return 0; } void bdrv_flush_all(void) @@ -142,7 +142,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque); /* Ensure contents are flushed to disk. */ -void bdrv_flush(BlockDriverState *bs); +int bdrv_flush(BlockDriverState *bs); void bdrv_flush_all(void); void bdrv_close_all(void); diff --git a/block/blkdebug.c b/block/blkdebug.c index 4d6ff0a368..cd9eb8006a 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -397,9 +397,9 @@ static void blkdebug_close(BlockDriverState *bs) } } -static void blkdebug_flush(BlockDriverState *bs) +static int blkdebug_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs, diff --git a/block/blkverify.c b/block/blkverify.c index b2a12fe7f5..c7522b4093 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -116,12 +116,12 @@ static void blkverify_close(BlockDriverState *bs) s->test_file = NULL; } -static void blkverify_flush(BlockDriverState *bs) +static int blkverify_flush(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; /* Only flush test file, the raw file is not important */ - bdrv_flush(s->test_file); + return bdrv_flush(s->test_file); } static int64_t blkverify_getlength(BlockDriverState *bs) @@ -300,8 +300,8 @@ static void blkverify_verify_readv(BlkverifyAIOCB *acb) { ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov); if (offset != -1) { - blkverify_err(acb, "contents mismatch in sector %lld", - acb->sector_num + (offset / BDRV_SECTOR_SIZE)); + blkverify_err(acb, "contents mismatch in sector %" PRId64, + acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE)); } } diff --git a/block/cow.c b/block/cow.c index eedcc48772..4cf543c832 100644 --- a/block/cow.c +++ b/block/cow.c @@ -282,9 +282,9 @@ exit: return ret; } -static void cow_flush(BlockDriverState *bs) +static int cow_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static QEMUOptionParameter cow_create_options[] = { diff --git a/block/qcow.c b/block/qcow.c index 816103d395..9cd547dc02 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -910,9 +910,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, return 0; } -static void qcow_flush(BlockDriverState *bs) +static int qcow_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs, diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 4f7dc59b76..b0402087cf 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -188,6 +188,7 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset, ret = bdrv_pread(bs->file, l2_offset, *l2_table, s->l2_size * sizeof(uint64_t)); if (ret < 0) { + qcow2_l2_cache_reset(bs); return ret; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 0efb6760cb..a10453c875 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -103,6 +103,7 @@ static int load_refcount_block(BlockDriverState *bs, ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache, s->cluster_size); if (ret < 0) { + s->refcount_block_cache_offset = 0; return ret; } diff --git a/block/qcow2.c b/block/qcow2.c index b816d8733f..537c479a7b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1148,9 +1148,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, return 0; } -static void qcow_flush(BlockDriverState *bs) +static int qcow_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs, diff --git a/block/raw-posix.c b/block/raw-posix.c index d0393e0c44..d0960b85c4 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -734,10 +734,10 @@ static int raw_create(const char *filename, QEMUOptionParameter *options) return result; } -static void raw_flush(BlockDriverState *bs) +static int raw_flush(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; - qemu_fdatasync(s->fd); + return qemu_fdatasync(s->fd); } diff --git a/block/raw-win32.c b/block/raw-win32.c index 503ed3959a..06c97101bb 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -147,10 +147,17 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num, return ret_count; } -static void raw_flush(BlockDriverState *bs) +static int raw_flush(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; - FlushFileBuffers(s->hfile); + int ret; + + ret = FlushFileBuffers(s->hfile); + if (ret != 0) { + return -EIO; + } + + return 0; } static void raw_close(BlockDriverState *bs) diff --git a/block/raw.c b/block/raw.c index 91087792fc..1980debc00 100644 --- a/block/raw.c +++ b/block/raw.c @@ -39,9 +39,9 @@ static void raw_close(BlockDriverState *bs) { } -static void raw_flush(BlockDriverState *bs) +static int raw_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, diff --git a/block/vdi.c b/block/vdi.c index f72633cf19..3b51e532c4 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -900,10 +900,10 @@ static void vdi_close(BlockDriverState *bs) { } -static void vdi_flush(BlockDriverState *bs) +static int vdi_flush(BlockDriverState *bs) { logout("\n"); - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } diff --git a/block/vmdk.c b/block/vmdk.c index 2d4ba421db..872aebac9b 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -823,9 +823,9 @@ static void vmdk_close(BlockDriverState *bs) qemu_free(s->l2_cache); } -static void vmdk_flush(BlockDriverState *bs) +static int vmdk_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } diff --git a/block/vpc.c b/block/vpc.c index e50509eeaa..416f48900c 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -439,6 +439,10 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num, return 0; } +static int vpc_flush(BlockDriverState *bs) +{ + return bdrv_flush(bs->file); +} /* * Calculates the number of cylinders, heads and sectors per cylinder @@ -618,14 +622,15 @@ static QEMUOptionParameter vpc_create_options[] = { }; static BlockDriver bdrv_vpc = { - .format_name = "vpc", - .instance_size = sizeof(BDRVVPCState), - .bdrv_probe = vpc_probe, - .bdrv_open = vpc_open, - .bdrv_read = vpc_read, - .bdrv_write = vpc_write, - .bdrv_close = vpc_close, - .bdrv_create = vpc_create, + .format_name = "vpc", + .instance_size = sizeof(BDRVVPCState), + .bdrv_probe = vpc_probe, + .bdrv_open = vpc_open, + .bdrv_read = vpc_read, + .bdrv_write = vpc_write, + .bdrv_flush = vpc_flush, + .bdrv_close = vpc_close, + .bdrv_create = vpc_create, .create_options = vpc_create_options, }; diff --git a/block_int.h b/block_int.h index 87e60b8597..3c3adb5c85 100644 --- a/block_int.h +++ b/block_int.h @@ -59,7 +59,7 @@ struct BlockDriver { const uint8_t *buf, int nb_sectors); void (*bdrv_close)(BlockDriverState *bs); int (*bdrv_create)(const char *filename, QEMUOptionParameter *options); - void (*bdrv_flush)(BlockDriverState *bs); + int (*bdrv_flush)(BlockDriverState *bs); int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); diff --git a/blockdev.c b/blockdev.c index ff7602be2c..6cb179a409 100644 --- a/blockdev.c +++ b/blockdev.c @@ -314,7 +314,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) on_write_error = BLOCK_ERR_STOP_ENOSPC; if ((buf = qemu_opt_get(opts, "werror")) != NULL) { if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) { - fprintf(stderr, "werror is no supported by this format\n"); + fprintf(stderr, "werror is not supported by this format\n"); return NULL; } @@ -326,8 +326,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) on_read_error = BLOCK_ERR_REPORT; if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { - if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) { - fprintf(stderr, "rerror is no supported by this format\n"); + if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) { + fprintf(stderr, "rerror is not supported by this format\n"); return NULL; } @@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build" echo " --disable-docs disable documentation build" echo " --disable-vhost-net disable vhost-net acceleration support" echo " --enable-vhost-net enable vhost-net acceleration support" -echo " --trace-backend=B Trace backend nop simple ust" +echo " --trace-backend=B Trace backend nop simple ust dtrace" echo " --trace-file=NAME Full PATH,NAME of file to store traces" echo " Default:trace-<pid>" echo " --disable-spice disable spice" @@ -2192,7 +2192,23 @@ EOF echo exit 1 fi + trace_backend_stap="no" + if has 'stap' ; then + trace_backend_stap="yes" + fi +fi + +########################################## +# For 'dtrace' backend, test if 'dtrace' command is present +if test "$trace_backend" = "dtrace"; then + if ! has 'dtrace' ; then + echo + echo "Error: dtrace command is not found in PATH $PATH" + echo + exit 1 + fi fi + ########################################## # End of CC checks # After here, no more $cc or $ld runs @@ -2633,6 +2649,9 @@ fi if test "$trace_backend" = "simple"; then trace_file="\"$trace_file-%u\"" fi +if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then + echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak +fi echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak echo "TOOLS=$tools" >> $config_host_mak @@ -23,6 +23,7 @@ */ #include "qemu-common.h" #include "host-utils.h" +#include <math.h> void pstrcpy(char *buf, int buf_size, const char *str) { @@ -283,3 +284,90 @@ int fcntl_setfl(int fd, int flag) } #endif +/* + * Convert string to bytes, allowing either B/b for bytes, K/k for KB, + * M/m for MB, G/g for GB or T/t for TB. Default without any postfix + * is MB. End pointer will be returned in *end, if not NULL. A valid + * value must be terminated by whitespace, ',' or '\0'. Return -1 on + * error. + */ +ssize_t strtosz(const char *nptr, char **end) +{ + ssize_t retval = -1; + char *endptr, c; + int mul_required = 0; + double val, mul, integral, fraction; + + errno = 0; + val = strtod(nptr, &endptr); + if (isnan(val) || endptr == nptr || errno != 0) { + goto fail; + } + integral = modf(val, &fraction); + if (integral != 0) { + mul_required = 1; + } + /* + * Any whitespace character is fine for terminating the number, + * in addition we accept ',' to handle strings where the size is + * part of a multi token argument. + */ + c = *endptr; + if (isspace(c) || c == '\0' || c == ',') { + c = 0; + } + switch (c) { + case 'B': + case 'b': + mul = 1; + if (mul_required) { + goto fail; + } + break; + case 'K': + case 'k': + mul = 1 << 10; + break; + case 0: + if (mul_required) { + goto fail; + } + case 'M': + case 'm': + mul = 1ULL << 20; + break; + case 'G': + case 'g': + mul = 1ULL << 30; + break; + case 'T': + case 't': + mul = 1ULL << 40; + break; + default: + goto fail; + } + /* + * If not terminated by whitespace, ',', or \0, increment endptr + * to point to next character, then check that we are terminated + * by an appropriate separating character, ie. whitespace, ',', or + * \0. If not, we are seeing trailing garbage, thus fail. + */ + if (c != 0) { + endptr++; + if (!isspace(*endptr) && *endptr != ',' && *endptr != 0) { + goto fail; + } + } + if ((val * mul >= ~(size_t)0) || val < 0) { + goto fail; + } + retval = val * mul; + +fail: + if (end) { + *end = endptr; + } + + return retval; +} diff --git a/hmp-commands.hx b/hmp-commands.hx index 81999aa1a9..e5585ba0e9 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -754,9 +754,10 @@ ETEXI { .name = "migrate_set_speed", - .args_type = "value:f", + .args_type = "value:o", .params = "value", - .help = "set maximum speed (in bytes) for migrations", + .help = "set maximum speed (in bytes) for migrations. " + "Defaults to MB if no size suffix is specified, ie. B/K/M/G/T", .user_print = monitor_user_noop, .mhandler.cmd_new = do_migrate_set_speed, }, diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 66c7885d62..f549089a55 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -585,7 +585,8 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val) PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val); } -static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state); +static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, + PCIHotplugState state); static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) { @@ -615,18 +616,23 @@ static void disable_device(PIIX4PMState *s, int slot) s->pci0_status.down |= (1 << slot); } -static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state) +static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, + PCIHotplugState state) { int slot = PCI_SLOT(dev->devfn); PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, DO_UPCAST(PCIDevice, qdev, qdev)); - if (!dev->qdev.hotplugged) + /* Don't send event when device is enabled during qemu machine creation: + * it is present on boot, no hotplug event is necessary. We do send an + * event when the device is disabled later. */ + if (state == PCI_COLDPLUG_ENABLED) { return 0; + } s->pci0_status.up = 0; s->pci0_status.down = 0; - if (state) { + if (state == PCI_HOTPLUG_ENABLED) { enable_device(s, slot); } else { disable_device(s, slot); @@ -437,6 +437,8 @@ static int apic_find_dest(uint8_t dest) apic = local_apics[i]; if (apic && apic->id == dest) return i; + if (!apic) + break; } return -1; @@ -472,6 +474,8 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, set_bit(deliver_bitmask, i); } } + } else { + break; } } } diff --git a/hw/e1000.c b/hw/e1000.c index 532efdc27d..677165f830 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -384,9 +384,12 @@ xmit_seg(E1000State *s) } else // UDP cpu_to_be16wu((uint16_t *)(tp->data+css+4), len); if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { + unsigned int phsum; // add pseudo-header length before checksum calculation sp = (uint16_t *)(tp->data + tp->tucso); - cpu_to_be16wu(sp, be16_to_cpup(sp) + len); + phsum = be16_to_cpup(sp) + len; + phsum = (phsum >> 16) + (phsum & 0xffff); + cpu_to_be16wu(sp, phsum); } tp->tso_frames++; } diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 103577470a..c699d6fd8b 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -808,6 +808,28 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) return 0; } +static int hda_audio_exit(HDACodecDevice *hda) +{ + HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioStream *st; + int i; + + dprint(a, 1, "%s\n", __FUNCTION__); + for (i = 0; i < ARRAY_SIZE(a->st); i++) { + st = a->st + i; + if (st->node == NULL) { + continue; + } + if (st->output) { + AUD_close_out(&a->card, st->voice.out); + } else { + AUD_close_in(&a->card, st->voice.in); + } + } + AUD_remove_card(&a->card); + return 0; +} + static int hda_audio_post_load(void *opaque, int version) { HDAAudioState *a = opaque; @@ -879,6 +901,7 @@ static HDACodecDeviceInfo hda_audio_info_output = { .qdev.vmsd = &vmstate_hda_audio, .qdev.props = hda_audio_properties, .init = hda_audio_init_output, + .exit = hda_audio_exit, .command = hda_audio_command, .stream = hda_audio_stream, }; @@ -890,6 +913,7 @@ static HDACodecDeviceInfo hda_audio_info_duplex = { .qdev.vmsd = &vmstate_hda_audio, .qdev.props = hda_audio_properties, .init = hda_audio_init_duplex, + .exit = hda_audio_exit, .command = hda_audio_command, .stream = hda_audio_stream, }; diff --git a/hw/ide/core.c b/hw/ide/core.c index bc3e91658a..484e0ca96f 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -811,10 +811,16 @@ static void ide_flush_cb(void *opaque, int ret) static void ide_flush_cache(IDEState *s) { - if (s->bs) { - bdrv_aio_flush(s->bs, ide_flush_cb, s); - } else { + BlockDriverAIOCB *acb; + + if (s->bs == NULL) { ide_flush_cb(s, 0); + return; + } + + acb = bdrv_aio_flush(s->bs, ide_flush_cb, s); + if (acb == NULL) { + ide_flush_cb(s, -EIO); } } diff --git a/hw/intel-hda.c b/hw/intel-hda.c index ccb059dc92..fe316245ad 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -19,6 +19,7 @@ #include "hw.h" #include "pci.h" +#include "msi.h" #include "qemu-timer.h" #include "audiodev.h" #include "intel-hda.h" @@ -55,15 +56,27 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base) if (dev->cad == -1) { dev->cad = bus->next_cad; } - if (dev->cad > 15) + if (dev->cad >= 15) { return -1; + } bus->next_cad = dev->cad + 1; return info->init(dev); } +static int hda_codec_dev_exit(DeviceState *qdev) +{ + HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev); + + if (dev->info->exit) { + dev->info->exit(dev); + } + return 0; +} + void hda_codec_register(HDACodecDeviceInfo *info) { info->qdev.init = hda_codec_dev_init; + info->qdev.exit = hda_codec_dev_exit; info->qdev.bus_info = &hda_codec_bus_info; qdev_register(&info->qdev); } @@ -177,6 +190,7 @@ struct IntelHDAState { /* properties */ uint32_t debug; + uint32_t msi; }; struct IntelHDAReg { @@ -235,7 +249,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d) if (d->rirb_sts & ICH6_RBSTS_OVERRUN) { sts |= (1 << 30); } - if (d->state_sts) { + if (d->state_sts & d->wake_en) { sts |= (1 << 30); } @@ -257,6 +271,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d) static void intel_hda_update_irq(IntelHDAState *d) { + int msi = d->msi && msi_enabled(&d->pci); int level; intel_hda_update_int_sts(d); @@ -265,8 +280,15 @@ static void intel_hda_update_irq(IntelHDAState *d) } else { level = 0; } - dprint(d, 2, "%s: level %d\n", __FUNCTION__, level); - qemu_set_irq(d->pci.irq[0], level); + dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__, + level, msi ? "msi" : "intx"); + if (msi) { + if (level) { + msi_notify(&d->pci, 0); + } + } else { + qemu_set_irq(d->pci.irq[0], level); + } } static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) @@ -497,6 +519,11 @@ static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32 } } +static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + intel_hda_update_irq(d); +} + static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) { intel_hda_update_irq(d); @@ -617,13 +644,15 @@ static const struct IntelHDAReg regtab[] = { [ ICH6_REG_WAKEEN ] = { .name = "WAKEEN", .size = 2, + .wmask = 0x7fff, .offset = offsetof(IntelHDAState, wake_en), + .whandler = intel_hda_set_wake_en, }, [ ICH6_REG_STATESTS ] = { .name = "STATESTS", .size = 2, - .wmask = 0x3fff, - .wclear = 0x3fff, + .wmask = 0x7fff, + .wclear = 0x7fff, .offset = offsetof(IntelHDAState, state_sts), .whandler = intel_hda_set_state_sts, }, @@ -1130,6 +1159,9 @@ static int intel_hda_init(PCIDevice *pci) intel_hda_mmio_write, d); pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY, intel_hda_map); + if (d->msi) { + msi_init(&d->pci, 0x50, 1, true, false); + } hda_codec_bus_init(&d->pci.qdev, &d->codecs, intel_hda_response, intel_hda_xfer); @@ -1137,6 +1169,28 @@ static int intel_hda_init(PCIDevice *pci) return 0; } +static int intel_hda_exit(PCIDevice *pci) +{ + IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); + + if (d->msi) { + msi_uninit(&d->pci); + } + cpu_unregister_io_memory(d->mmio_addr); + return 0; +} + +static void intel_hda_write_config(PCIDevice *pci, uint32_t addr, + uint32_t val, int len) +{ + IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); + + pci_default_write_config(pci, addr, val, len); + if (d->msi) { + msi_write_config(pci, addr, val, len); + } +} + static int intel_hda_post_load(void *opaque, int version) { IntelHDAState* d = opaque; @@ -1219,8 +1273,11 @@ static PCIDeviceInfo intel_hda_info = { .qdev.vmsd = &vmstate_intel_hda, .qdev.reset = intel_hda_reset, .init = intel_hda_init, + .exit = intel_hda_exit, + .config_write = intel_hda_write_config, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0), + DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1), DEFINE_PROP_END_OF_LIST(), } }; diff --git a/hw/intel-hda.h b/hw/intel-hda.h index ba290ec850..4e44e3894f 100644 --- a/hw/intel-hda.h +++ b/hw/intel-hda.h @@ -32,6 +32,7 @@ struct HDACodecDevice { struct HDACodecDeviceInfo { DeviceInfo qdev; int (*init)(HDACodecDevice *dev); + int (*exit)(HDACodecDevice *dev); void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data); void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running); }; diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 80260714ec..6be8aa70f9 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -977,7 +977,7 @@ void mips_malta_init (ram_addr_t ram_size, } else if (vmsvga_enabled) { pci_vmsvga_init(pci_bus); } else if (std_vga_enabled) { - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); } } diff --git a/hw/multiboot.c b/hw/multiboot.c index f9097a2f60..e710bbb948 100644 --- a/hw/multiboot.c +++ b/hw/multiboot.c @@ -171,6 +171,12 @@ int load_multiboot(void *fw_cfg, uint64_t elf_low, elf_high; int kernel_size; fclose(f); + + if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) { + fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n"); + exit(1); + } + kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, &elf_low, &elf_high, 0, ELF_MACHINE, 0); if (kernel_size < 0) { @@ -993,7 +993,7 @@ void pc_vga_init(PCIBus *pci_bus) fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); } else if (std_vga_enabled) { if (pci_bus) { - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); } else { isa_vga_init(); } @@ -154,8 +154,7 @@ enum vga_retrace_method { extern enum vga_retrace_method vga_retrace_method; int isa_vga_init(void); -int pci_vga_init(PCIBus *bus, - unsigned long vga_bios_offset, int vga_bios_size); +int pci_vga_init(PCIBus *bus); int isa_vga_mm_init(target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, int it_shift); @@ -1558,8 +1558,11 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) pci_add_option_rom(pci_dev); if (bus->hotplug) { - /* lower layer must check qdev->hotplugged */ - rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1); + /* Let buses differentiate between hotplug and when device is + * enabled during qemu machine creation. */ + rc = bus->hotplug(bus->hotplug_qdev, pci_dev, + qdev->hotplugged ? PCI_HOTPLUG_ENABLED: + PCI_COLDPLUG_ENABLED); if (rc != 0) { int r = pci_unregister_device(&pci_dev->qdev); assert(!r); @@ -1573,7 +1576,8 @@ static int pci_unplug_device(DeviceState *qdev) { PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); - return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, 0); + return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, + PCI_HOTPLUG_DISABLED); } void pci_qdev_register(PCIDeviceInfo *info) @@ -1806,8 +1810,7 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " "pci id %04x:%04x (sub %04x:%04x)\n", - indent, "", ctxt, - d->config[PCI_SECONDARY_BUS], + indent, "", ctxt, pci_bus_num(d->bus), PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), pci_get_word(d->config + PCI_VENDOR_ID), pci_get_word(d->config + PCI_DEVICE_ID), @@ -214,7 +214,15 @@ int pci_device_load(PCIDevice *s, QEMUFile *f); typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); -typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, int state); + +typedef enum { + PCI_HOTPLUG_DISABLED, + PCI_HOTPLUG_ENABLED, + PCI_COLDPLUG_ENABLED, +} PCIHotplugState; + +typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, + PCIHotplugState state); void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, int devfn_min); PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min); @@ -192,14 +192,16 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) } static int pcie_cap_slot_hotplug(DeviceState *qdev, - PCIDevice *pci_dev, int state) + PCIDevice *pci_dev, PCIHotplugState state) { PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); uint8_t *exp_cap = d->config + d->exp.exp_cap; uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); - if (!pci_dev->qdev.hotplugged) { - assert(state); /* this case only happens at machine creation. */ + /* Don't send event when device is enabled during qemu machine creation: + * it is present on boot, no hotplug event is necessary. We do send an + * event when the device is disabled later. */ + if (state == PCI_COLDPLUG_ENABLED) { pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); return 0; @@ -219,7 +221,7 @@ static int pcie_cap_slot_hotplug(DeviceState *qdev, */ assert(PCI_FUNC(pci_dev->devfn) == 0); - if (state) { + if (state == PCI_HOTPLUG_ENABLED) { pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 4369337b21..305b2d45e6 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -316,7 +316,7 @@ static void ppc_core99_init (ram_addr_t ram_size, machine_arch = ARCH_MAC99; } /* init basic PC hardware */ - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index a2f9ddf738..5efc93dc10 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -227,7 +227,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, } pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs); pci_bus = pci_grackle_init(0xfec00000, pic); - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index a6915f7e68..b1f9cc74f8 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -694,7 +694,7 @@ static void ppc_prep_init (ram_addr_t ram_size, cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); /* init basic PC hardware */ - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); // openpic = openpic_init(0x00000000, 0xF0000000, 1); // pit = pit_init(0x40, i8259[0]); rtc_init(2000, NULL); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 9628b39a21..dc719578b0 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -41,7 +41,11 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 -#define SCSI_REQ_STATUS_RETRY 0x01 +#define SCSI_REQ_STATUS_RETRY 0x01 +#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06 +#define SCSI_REQ_STATUS_RETRY_READ 0x00 +#define SCSI_REQ_STATUS_RETRY_WRITE 0x02 +#define SCSI_REQ_STATUS_RETRY_FLUSH 0x04 typedef struct SCSIDiskState SCSIDiskState; @@ -70,6 +74,9 @@ struct SCSIDiskState char *serial; }; +static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); +static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf); + static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag, uint32_t lun) { @@ -127,34 +134,30 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) static void scsi_read_complete(void * opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; + int n; r->req.aiocb = NULL; if (ret) { - DPRINTF("IO error\n"); - r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); - scsi_command_complete(r, CHECK_CONDITION, NO_SENSE); - return; + if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) { + return; + } } + DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len); + n = r->iov.iov_len / 512; + r->sector += n; + r->sector_count -= n; r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len); } -/* Read more data from scsi device into buffer. */ -static void scsi_read_data(SCSIDevice *d, uint32_t tag) + +static void scsi_read_request(SCSIDiskReq *r) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIDiskReq *r; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint32_t n; - r = scsi_find_request(s, tag); - if (!r) { - BADF("Bad read tag 0x%x\n", tag); - /* ??? This is the wrong error. */ - scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); - return; - } if (r->sector_count == (uint32_t)-1) { DPRINTF("Read buf_len=%zd\n", r->iov.iov_len); r->sector_count = 0; @@ -175,31 +178,57 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) qemu_iovec_init_external(&r->qiov, &r->iov, 1); r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n, scsi_read_complete, r); - if (r->req.aiocb == NULL) + if (r->req.aiocb == NULL) { + scsi_read_complete(r, -EIO); + } +} + +/* Read more data from scsi device into buffer. */ +static void scsi_read_data(SCSIDevice *d, uint32_t tag) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); + SCSIDiskReq *r; + + r = scsi_find_request(s, tag); + if (!r) { + BADF("Bad read tag 0x%x\n", tag); + /* ??? This is the wrong error. */ scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); - r->sector += n; - r->sector_count -= n; + return; + } + + /* No data transfer may already be in progress */ + assert(r->req.aiocb == NULL); + + scsi_read_request(r); } -static int scsi_handle_write_error(SCSIDiskReq *r, int error) +static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type) { + int is_read = (type == SCSI_REQ_STATUS_RETRY_READ); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - BlockErrorAction action = bdrv_get_on_error(s->bs, 0); + BlockErrorAction action = bdrv_get_on_error(s->bs, is_read); if (action == BLOCK_ERR_IGNORE) { - bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0); + bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read); return 0; } if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) || action == BLOCK_ERR_STOP_ANY) { - r->status |= SCSI_REQ_STATUS_RETRY; - bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0); + + type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK; + r->status |= SCSI_REQ_STATUS_RETRY | type; + + bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); vm_stop(0); } else { + if (type == SCSI_REQ_STATUS_RETRY_READ) { + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); + } scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); - bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0); + bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read); } return 1; @@ -214,8 +243,9 @@ static void scsi_write_complete(void * opaque, int ret) r->req.aiocb = NULL; if (ret) { - if (scsi_handle_write_error(r, -ret)) + if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) { return; + } } n = r->iov.iov_len / 512; @@ -244,9 +274,9 @@ static void scsi_write_request(SCSIDiskReq *r) qemu_iovec_init_external(&r->qiov, &r->iov, 1); r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n, scsi_write_complete, r); - if (r->req.aiocb == NULL) - scsi_command_complete(r, CHECK_CONDITION, - HARDWARE_ERROR); + if (r->req.aiocb == NULL) { + scsi_write_complete(r, -EIO); + } } else { /* Invoke completion routine to fetch data from host. */ scsi_write_complete(r, 0); @@ -268,8 +298,8 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) return 1; } - if (r->req.aiocb) - BADF("Data transfer already in progress\n"); + /* No data transfer may already be in progress */ + assert(r->req.aiocb == NULL); scsi_write_request(r); @@ -288,8 +318,25 @@ static void scsi_dma_restart_bh(void *opaque) QTAILQ_FOREACH(req, &s->qdev.requests, next) { r = DO_UPCAST(SCSIDiskReq, req, req); if (r->status & SCSI_REQ_STATUS_RETRY) { - r->status &= ~SCSI_REQ_STATUS_RETRY; - scsi_write_request(r); + int status = r->status; + int ret; + + r->status &= + ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK); + + switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) { + case SCSI_REQ_STATUS_RETRY_READ: + scsi_read_request(r); + break; + case SCSI_REQ_STATUS_RETRY_WRITE: + scsi_write_request(r); + break; + case SCSI_REQ_STATUS_RETRY_FLUSH: + ret = scsi_disk_emulate_command(r, r->iov.iov_base); + if (ret == 0) { + scsi_command_complete(r, GOOD, NO_SENSE); + } + } } } } @@ -747,11 +794,13 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf) return toclen; } -static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) +static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) { + SCSIRequest *req = &r->req; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); uint64_t nb_sectors; int buflen = 0; + int ret; switch (req->cmd.buf[0]) { case TEST_UNIT_READY: @@ -842,7 +891,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) buflen = 8; break; case SYNCHRONIZE_CACHE: - bdrv_flush(s->bs); + ret = bdrv_flush(s->bs); + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) { + return -1; + } + } break; case GET_CONFIGURATION: memset(outbuf, 0, 8); @@ -906,12 +960,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) return buflen; not_ready: - scsi_req_set_status(req, CHECK_CONDITION, NOT_READY); - return 0; + scsi_command_complete(r, CHECK_CONDITION, NOT_READY); + return -1; illegal_request: - scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST); - return 0; + scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST); + return -1; } /* Execute a scsi command. Returns the length of the data expected by the @@ -1019,14 +1073,12 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case REPORT_LUNS: case VERIFY: case REZERO_UNIT: - rc = scsi_disk_emulate_command(&r->req, outbuf); - if (rc > 0) { - r->iov.iov_len = rc; - } else { - scsi_req_complete(&r->req); - scsi_remove_request(r); + rc = scsi_disk_emulate_command(r, outbuf); + if (rc < 0) { return 0; } + + r->iov.iov_len = rc; break; case READ_6: case READ_10: @@ -1152,11 +1204,6 @@ static int scsi_disk_initfn(SCSIDevice *dev) return -1; } - if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) { - error_report("Device doesn't support drive option rerror"); - return -1; - } - if (!s->serial) { /* try to fall back to value set with legacy -drive serial=... */ dinfo = drive_get_by_blockdev(s->bs); diff --git a/hw/sun4u.c b/hw/sun4u.c index 45a46d673c..5292ac670f 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -767,7 +767,7 @@ static void sun4uv_init(ram_addr_t RAM_size, pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2, &pci_bus3); isa_mem_base = APB_PCI_IO_BASE; - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); // XXX Should be pci_bus3 pci_ebus_init(pci_bus, -1); diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 2315f70bca..b09789cd11 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -52,14 +52,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num, { PCIVGAState *d = (PCIVGAState *)pci_dev; VGACommonState *s = &d->vga; - if (region_num == PCI_ROM_SLOT) { - cpu_register_physical_memory(addr, s->bios_size, s->bios_offset); - } else { - cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); - s->map_addr = addr; - s->map_end = addr + s->vram_size; - vga_dirty_log_start(s); - } + + cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); + s->map_addr = addr; + s->map_end = addr + s->vram_size; + vga_dirty_log_start(s); } static void pci_vga_write_config(PCIDevice *d, @@ -95,32 +92,12 @@ static int pci_vga_initfn(PCIDevice *dev) pci_register_bar(&d->dev, 0, VGA_RAM_SIZE, PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map); - if (s->bios_size) { - unsigned int bios_total_size; - /* must be a power of two */ - bios_total_size = 1; - while (bios_total_size < s->bios_size) - bios_total_size <<= 1; - pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size, - PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map); - } - - vga_init_vbe(s); - /* ROM BIOS */ - rom_add_vga(VGABIOS_FILENAME); return 0; } -int pci_vga_init(PCIBus *bus, - unsigned long vga_bios_offset, int vga_bios_size) +int pci_vga_init(PCIBus *bus) { - PCIDevice *dev; - - dev = pci_create(bus, -1, "VGA"); - qdev_prop_set_uint32(&dev->qdev, "bios-offset", vga_bios_offset); - qdev_prop_set_uint32(&dev->qdev, "bios-size", vga_bios_size); - qdev_init_nofail(&dev->qdev); - + pci_create_simple(bus, -1, "VGA"); return 0; } @@ -130,11 +107,7 @@ static PCIDeviceInfo vga_info = { .qdev.vmsd = &vmstate_vga_pci, .init = pci_vga_initfn, .config_write = pci_vga_write_config, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("bios-offset", PCIVGAState, vga.bios_offset, 0), - DEFINE_PROP_HEX32("bios-size", PCIVGAState, vga.bios_size, 0), - DEFINE_PROP_END_OF_LIST(), - } + .romfile = "vgabios-stdvga.bin", }; static void vga_register(void) @@ -1934,8 +1934,6 @@ void vga_common_reset(VGACommonState *s) s->map_addr = 0; s->map_end = 0; s->lfb_vram_mapped = 0; - s->bios_offset = 0; - s->bios_size = 0; s->sr_index = 0; memset(s->sr, '\0', sizeof(s->sr)); s->gr_index = 0; diff --git a/hw/vga_int.h b/hw/vga_int.h index 6a46a434fe..bc1327fbf6 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -112,8 +112,6 @@ typedef struct VGACommonState { uint32_t map_addr; uint32_t map_end; uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */ - uint32_t bios_offset; - uint32_t bios_size; uint32_t latch; uint8_t sr_index; uint8_t sr[256]; diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index dbe207070e..49528a9977 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -273,7 +273,7 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb) acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req); if (!acb) { - virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); + virtio_blk_flush_complete(req, -EIO); } } diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 3d25c14da9..9337fdbfef 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -114,14 +114,12 @@ struct pci_vmsvga_state_s { # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT # define SVGA_IO_MUL 1 # define SVGA_FIFO_SIZE 0x10000 -# define SVGA_MEM_BASE 0xe0000000 # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2 #else # define SVGA_ID SVGA_ID_1 # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT # define SVGA_IO_MUL 4 # define SVGA_FIFO_SIZE 0x10000 -# define SVGA_MEM_BASE 0xe0000000 # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA #endif @@ -1219,10 +1217,6 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size) vga_init(&s->vga); vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga); - vga_init_vbe(&s->vga); - - rom_add_vga(VGABIOS_FILENAME); - vmsvga_reset(s); } @@ -1320,6 +1314,7 @@ static PCIDeviceInfo vmsvga_info = { .qdev.size = sizeof(struct pci_vmsvga_state_s), .qdev.vmsd = &vmstate_vmware_vga, .init = pci_vmsvga_initfn, + .romfile = "vgabios-vmware.bin", }; static void vmsvga_register(void) diff --git a/migration.c b/migration.c index 468d51749f..9ee8b179c0 100644 --- a/migration.c +++ b/migration.c @@ -132,10 +132,10 @@ int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data) int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data) { - double d; + int64_t d; FdMigrationState *s; - d = qdict_get_double(qdict, "value"); + d = qdict_get_int(qdict, "value"); d = MAX(0, MIN(UINT32_MAX, d)); max_throttle = d; @@ -78,10 +78,11 @@ * 'l' target long (32 or 64 bit) * 'M' just like 'l', except in user mode the value is * multiplied by 2^20 (think Mebibyte) - * 'f' double - * user mode accepts an optional G, g, M, m, K, k suffix, - * which multiplies the value by 2^30 for suffixes G and - * g, 2^20 for M and m, 2^10 for K and k + * 'o' octets (aka bytes) + * user mode accepts an optional T, t, G, g, M, m, K, k + * suffix, which multiplies the value by 2^40 for + * suffixes T and t, 2^30 for suffixes G and g, 2^20 for + * M and m, 2^10 for K and k * 'T' double * user mode accepts an optional ms, us, ns suffix, * which divides the value by 1e3, 1e6, 1e9, respectively @@ -3703,7 +3704,29 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, qdict_put(qdict, key, qint_from_int(val)); } break; - case 'f': + case 'o': + { + ssize_t val; + char *end; + + while (qemu_isspace(*p)) { + p++; + } + if (*typestr == '?') { + typestr++; + if (*p == '\0') { + break; + } + } + val = strtosz(p, &end); + if (val < 0) { + monitor_printf(mon, "invalid size\n"); + goto fail; + } + qdict_put(qdict, key, qint_from_int(val)); + p = end; + } + break; case 'T': { double val; @@ -3719,17 +3742,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, if (get_double(mon, &val, &p) < 0) { goto fail; } - if (c == 'f' && *p) { - switch (*p) { - case 'K': case 'k': - val *= 1 << 10; p++; break; - case 'M': case 'm': - val *= 1 << 20; p++; break; - case 'G': case 'g': - val *= 1 << 30; p++; break; - } - } - if (c == 'T' && p[0] && p[1] == 's') { + if (p[0] && p[1] == 's') { switch (*p) { case 'm': val /= 1e3; p += 2; break; @@ -4205,13 +4218,13 @@ static int check_client_args_type(const QDict *client_args, case 'i': case 'l': case 'M': + case 'o': if (qobject_type(client_arg) != QTYPE_QINT) { qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name, "int"); return -1; } break; - case 'f': case 'T': if (qobject_type(client_arg) != QTYPE_QINT && qobject_type(client_arg) != QTYPE_QFLOAT) { @@ -269,8 +269,11 @@ void tap_set_offload(VLANClientState *nc, int csum, int tso4, int tso6, int ecn, int ufo) { TAPState *s = DO_UPCAST(TAPState, nc, nc); + if (s->fd < 0) { + return; + } - return tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo); + tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo); } static void tap_cleanup(VLANClientState *nc) @@ -279,6 +282,7 @@ static void tap_cleanup(VLANClientState *nc) if (s->vhost_net) { vhost_net_cleanup(s->vhost_net); + s->vhost_net = NULL; } qemu_purge_queued_packets(nc); @@ -289,6 +293,7 @@ static void tap_cleanup(VLANClientState *nc) tap_read_poll(s, 0); tap_write_poll(s, 0); close(s->fd); + s->fd = -1; } static void tap_poll(VLANClientState *nc, bool enable) diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin Binary files differindex 4fa8f99f7e..424dd0c70c 100644 --- a/pc-bios/vgabios-cirrus.bin +++ b/pc-bios/vgabios-cirrus.bin diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin Binary files differnew file mode 100644 index 0000000000..5123c5fd07 --- /dev/null +++ b/pc-bios/vgabios-stdvga.bin diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin Binary files differnew file mode 100644 index 0000000000..5e8c06b228 --- /dev/null +++ b/pc-bios/vgabios-vmware.bin diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin Binary files differindex fa6f815fcf..892a2b5374 100644 --- a/pc-bios/vgabios.bin +++ b/pc-bios/vgabios.bin diff --git a/qemu-char.c b/qemu-char.c index 6d2dce7a9b..88997f9d5a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -508,9 +508,10 @@ int send_all(int fd, const void *buf, int len1) #else -static int unix_write(int fd, const uint8_t *buf, int len1) +int send_all(int fd, const void *_buf, int len1) { int ret, len; + const uint8_t *buf = _buf; len = len1; while (len > 0) { @@ -527,11 +528,6 @@ static int unix_write(int fd, const uint8_t *buf, int len1) } return len1 - len; } - -int send_all(int fd, const void *buf, int len1) -{ - return unix_write(fd, buf, len1); -} #endif /* !_WIN32 */ #ifndef _WIN32 diff --git a/qemu-common.h b/qemu-common.h index 21fc3a5308..b3957f1859 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -149,6 +149,7 @@ time_t mktimegm(struct tm *tm); int qemu_fls(int i); int qemu_fdatasync(int fd); int fcntl_setfl(int fd, int flag); +ssize_t strtosz(const char *nptr, char **end); /* path.c */ void init_paths(const char *prefix); diff --git a/roms/vgabios b/roms/vgabios -Subproject 6e62666cfc19e7fd45dd0d7c3ad62fd8d0b5f67 +Subproject 19ea12c230ded95928ecaef0db47a82231c2e48 diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2440d6536c..06e40f3e49 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -681,6 +681,7 @@ typedef struct CPUX86State { #endif uint64_t system_time_msr; uint64_t wall_clock_msr; + uint64_t async_pf_en_msr; uint64_t tsc; diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 650a7192de..165045ec42 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -73,7 +73,7 @@ static const char *ext3_feature_name[] = { }; static const char *kvm_feature_name[] = { - "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, NULL, NULL, NULL, NULL, + "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, "kvm_asyncpf", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff --git a/target-i386/kvm.c b/target-i386/kvm.c index ae0a034ab0..7dfc357e42 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -162,6 +162,9 @@ struct kvm_para_features { #ifdef KVM_CAP_PV_MMU { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP }, #endif +#ifdef KVM_CAP_ASYNC_PF + { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF }, +#endif { -1, -1 } }; @@ -838,6 +841,9 @@ static int kvm_put_msrs(CPUState *env, int level) kvm_msr_entry_set(&msrs[n++], MSR_KVM_SYSTEM_TIME, env->system_time_msr); kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr); +#ifdef KVM_CAP_ASYNC_PF + kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr); +#endif } #ifdef KVM_CAP_MCE if (env->mcg_cap) { @@ -1064,6 +1070,9 @@ static int kvm_get_msrs(CPUState *env) #endif msrs[n++].index = MSR_KVM_SYSTEM_TIME; msrs[n++].index = MSR_KVM_WALL_CLOCK; +#ifdef KVM_CAP_ASYNC_PF + msrs[n++].index = MSR_KVM_ASYNC_PF_EN; +#endif #ifdef KVM_CAP_MCE if (env->mcg_cap) { @@ -1135,6 +1144,11 @@ static int kvm_get_msrs(CPUState *env) } #endif break; +#ifdef KVM_CAP_ASYNC_PF + case MSR_KVM_ASYNC_PF_EN: + env->async_pf_en_msr = msrs[i].data; + break; +#endif } } diff --git a/target-i386/machine.c b/target-i386/machine.c index 5f8376c37b..d78eceb779 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -373,6 +373,24 @@ static int cpu_post_load(void *opaque, int version_id) return 0; } +static bool async_pf_msr_needed(void *opaque) +{ + CPUState *cpu = opaque; + + return cpu->async_pf_en_msr != 0; +} + +static const VMStateDescription vmstate_async_pf_msr = { + .name = "cpu/async_pf_msr", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64(async_pf_en_msr, CPUState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_cpu = { .name = "cpu", .version_id = CPU_SAVE_VERSION, @@ -475,6 +493,14 @@ static const VMStateDescription vmstate_cpu = { VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12), VMSTATE_END_OF_LIST() /* The above list is not sorted /wrt version numbers, watch out! */ + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_async_pf_msr, + .needed = async_pf_msr_needed, + } , { + /* empty */ + } } }; @@ -20,10 +20,18 @@ Backends: --nop Tracing disabled --simple Simple built-in backend --ust LTTng User Space Tracing backend + --dtrace DTrace/SystemTAP backend Output formats: -h Generate .h file -c Generate .c file + -d Generate .d file (DTrace only) + -s Generate .stp file (DTrace with SystemTAP only) + +Options: + --bindir [bindir] QEMU binary install location + --target [arch] QEMU target architecture + EOF exit 1 } @@ -46,8 +54,9 @@ get_args() # Get the argument name list of a trace event get_argnames() { - local nfields field name + local nfields field name sep nfields=0 + sep="$2" for field in $(get_args "$1"); do nfields=$((nfields + 1)) @@ -58,7 +67,7 @@ get_argnames() name=${field%,} test "$field" = "$name" && continue - printf "%s" "$name, " + printf "%s%s " $name $sep done # Last argument name @@ -73,7 +82,7 @@ get_argc() { local name argc argc=0 - for name in $(get_argnames "$1"); do + for name in $(get_argnames "$1", ","); do argc=$((argc + 1)) done echo $argc @@ -154,7 +163,7 @@ EOF cast_args_to_uint64_t() { local arg - for arg in $(get_argnames "$1"); do + for arg in $(get_argnames "$1", ","); do printf "%s" "(uint64_t)(uintptr_t)$arg" done } @@ -247,7 +256,7 @@ linetoh_ust() local name args argnames name=$(get_name "$1") args=$(get_args "$1") - argnames=$(get_argnames "$1") + argnames=$(get_argnames "$1", ",") cat <<EOF DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames)); @@ -274,7 +283,7 @@ linetoc_ust() local name args argnames fmt name=$(get_name "$1") args=$(get_args "$1") - argnames=$(get_argnames "$1") + argnames=$(get_argnames "$1", ",") fmt=$(get_fmt "$1") cat <<EOF @@ -306,6 +315,135 @@ EOF echo "}" } +linetoh_begin_dtrace() +{ + cat <<EOF +#include "trace-dtrace.h" +EOF +} + +linetoh_dtrace() +{ + local name args argnames state nameupper + name=$(get_name "$1") + args=$(get_args "$1") + argnames=$(get_argnames "$1", ",") + state=$(get_state "$1") + if [ "$state" = "0" ] ; then + name=${name##disable } + fi + + nameupper=`echo $name | tr '[:lower:]' '[:upper:]'` + + # Define an empty function for the trace event + cat <<EOF +static inline void trace_$name($args) { + if (QEMU_${nameupper}_ENABLED()) { + QEMU_${nameupper}($argnames); + } +} +EOF +} + +linetoh_end_dtrace() +{ + return +} + +linetoc_begin_dtrace() +{ + return +} + +linetoc_dtrace() +{ + # No need for function definitions in dtrace backend + return +} + +linetoc_end_dtrace() +{ + return +} + +linetod_begin_dtrace() +{ + cat <<EOF +provider qemu { +EOF +} + +linetod_dtrace() +{ + local name args state + name=$(get_name "$1") + args=$(get_args "$1") + state=$(get_state "$1") + if [ "$state" = "0" ] ; then + name=${name##disable } + fi + + # Define prototype for probe arguments + cat <<EOF + probe $name($args); +EOF +} + +linetod_end_dtrace() +{ + cat <<EOF +}; +EOF +} + +linetos_begin_dtrace() +{ + return +} + +linetos_dtrace() +{ + local name args arglist state + name=$(get_name "$1") + args=$(get_args "$1") + arglist=$(get_argnames "$1", "") + state=$(get_state "$1") + if [ "$state" = "0" ] ; then + name=${name##disable } + fi + + if [ "$target" = "i386" ] + then + binary="qemu" + else + binary="qemu-system-$target" + fi + + # Define prototype for probe arguments + cat <<EOF +probe qemu.system.$target.$name = process("$bindir/$binary").mark("$name") +{ +EOF + + i=1 + for arg in $arglist + do + cat <<EOF + $arg = \$arg$i; +EOF + i="$((i+1))" + done + + cat <<EOF +} +EOF +} + +linetos_end_dtrace() +{ + return +} + # Process stdin by calling begin, line, and end functions for the backend convert() { @@ -324,9 +462,10 @@ convert() disable=${str%%disable *} echo if test -z "$disable"; then - # Pass the disabled state as an arg to lineto$1_simple(). - # For all other cases, call lineto$1_nop() - if [ $backend = "simple" ]; then + # Pass the disabled state as an arg for the simple + # or DTrace backends which handle it dynamically. + # For all other backends, call lineto$1_nop() + if [ $backend = "simple" -o "$backend" = "dtrace" ]; then "$process_line" "$str" else "lineto$1_nop" "${str##disable }" @@ -360,16 +499,65 @@ tracetoc() convert c } +tracetod() +{ + if [ $backend != "dtrace" ]; then + echo "DTrace probe generator not applicable to $backend backend" + exit 1 + fi + echo "/* This file is autogenerated by tracetool, do not edit. */" + convert d +} + +tracetos() +{ + if [ $backend != "dtrace" ]; then + echo "SystemTAP tapset generator not applicable to $backend backend" + exit 1 + fi + if [ -z "$target" ]; then + echo "--target is required for SystemTAP tapset generator" + exit 1 + fi + if [ -z "$bindir" ]; then + echo "--bindir is required for SystemTAP tapset generator" + exit 1 + fi + echo "/* This file is autogenerated by tracetool, do not edit. */" + convert s +} + # Choose backend case "$1" in -"--nop" | "--simple" | "--ust") backend="${1#--}" ;; +"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;; *) usage ;; esac shift +bindir= +case "$1" in + "--bindir") + bindir=$2 + shift + shift + ;; +esac + +target= +case "$1" in + "--target") + target=$2 + shift + shift + ;; +esac + + case "$1" in "-h") tracetoh ;; "-c") tracetoc ;; +"-d") tracetod ;; +"-s") tracetos ;; "--check-backend") exit 0 ;; # used by ./configure to test for backend *) usage ;; esac diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index 063c7dc8c8..0e3ad9b8c0 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -29,6 +29,7 @@ extern int using_spice; void qemu_spice_init(void); void qemu_spice_input_init(void); +void qemu_spice_audio_init(void); void qemu_spice_display_init(DisplayState *ds); int qemu_spice_add_interface(SpiceBaseInstance *sin); diff --git a/ui/spice-core.c b/ui/spice-core.c index e97a72d3d6..d13bdc269d 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -361,6 +361,7 @@ void qemu_spice_init(void) using_spice = 1; qemu_spice_input_init(); + qemu_spice_audio_init(); qemu_free(x509_key_file); qemu_free(x509_cert_file); @@ -710,16 +710,13 @@ static void numa_add(const char *optarg) if (get_param_value(option, 128, "mem", optarg) == 0) { node_mem[nodenr] = 0; } else { - value = strtoull(option, &endptr, 0); - switch (*endptr) { - case 0: case 'M': case 'm': - value <<= 20; - break; - case 'G': case 'g': - value <<= 30; - break; + ssize_t sval; + sval = strtosz(option, NULL); + if (sval < 0) { + fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg); + exit(1); } - node_mem[nodenr] = value; + node_mem[nodenr] = sval; } if (get_param_value(option, 128, "cpus", optarg) == 0) { node_cpumask[nodenr] = 0; @@ -2139,18 +2136,10 @@ int main(int argc, char **argv, char **envp) exit(0); break; case QEMU_OPTION_m: { - uint64_t value; - char *ptr; + ssize_t value; - value = strtoul(optarg, &ptr, 10); - switch (*ptr) { - case 0: case 'M': case 'm': - value <<= 20; - break; - case 'G': case 'g': - value <<= 30; - break; - default: + value = strtosz(optarg, NULL); + if (value < 0) { fprintf(stderr, "qemu: invalid ram size: %s\n", optarg); exit(1); } |