diff options
91 files changed, 3062 insertions, 1519 deletions
@@ -43,9 +43,11 @@ config-all-devices.mak: $(SUBDIR_DEVICES_MAK) %/config-devices.mak: default-configs/%.mak $(call quiet-command,cat $< > $@.tmp, " GEN $@") @if test -f $@; then \ - if cmp -s $@.old $@ || cmp -s $@ $@.tmp; then \ - mv $@.tmp $@; \ - cp -p $@ $@.old; \ + if cmp -s $@.old $@; then \ + if ! cmp -s $@ $@.tmp; then \ + mv $@.tmp $@; \ + cp -p $@ $@.old; \ + fi; \ else \ if test -f $@.old; then \ echo "WARNING: $@ (user modified) out of date.";\ @@ -80,9 +82,9 @@ include $(SRC_PATH)/Makefile.objs endif $(common-obj-y): $(GENERATED_HEADERS) -$(filter %-softmmu,$(SUBDIR_RULES)): $(common-obj-y) subdir-libdis +$(filter %-softmmu,$(SUBDIR_RULES)): $(trace-obj-y) $(common-obj-y) subdir-libdis -$(filter %-user,$(SUBDIR_RULES)): $(GENERATED_HEADERS) subdir-libdis-user subdir-libuser +$(filter %-user,$(SUBDIR_RULES)): $(GENERATED_HEADERS) $(trace-obj-y) subdir-libdis-user subdir-libuser ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) romsubdir-%: @@ -104,26 +106,34 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) -trace.h: $(SRC_PATH)/trace-events config-host.mak - $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN $@") +trace.h: trace.h-timestamp +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 -trace.c: $(SRC_PATH)/trace-events config-host.mak - $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN $@") +trace.c: trace.c-timestamp +trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak + $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c") + @cmp -s $@ trace.c || cp $@ trace.c trace.o: trace.c $(GENERATED_HEADERS) simpletrace.o: simpletrace.c $(GENERATED_HEADERS) +version.o: $(SRC_PATH)/version.rc config-host.mak + $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@") + +version-obj-$(CONFIG_WIN32) += version.o ###################################################################### qemu-img.o: qemu-img-cmds.h qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS) -qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) +qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) -qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) +qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) -qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) +qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@") @@ -245,10 +255,10 @@ TEXIFLAG=$(if $(V),,--quiet) qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@") -qemu-monitor.texi: $(SRC_PATH)/qemu-monitor.hx +qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@") -QMP/qmp-commands.txt: $(SRC_PATH)/qemu-monitor.hx +QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx $(call quiet-command,sh $(SRC_PATH)/hxtool -q < $< > $@," GEN $@") qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx diff --git a/Makefile.objs b/Makefile.objs index a3113d8..816194a 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -14,7 +14,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o -block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o +block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o block-nested-$(CONFIG_WIN32) += raw-win32.o block-nested-$(CONFIG_POSIX) += raw-posix.o block-nested-$(CONFIG_CURL) += curl.o @@ -31,6 +31,7 @@ net-nested-$(CONFIG_WIN32) += tap-win32.o net-nested-$(CONFIG_BSD) += tap-bsd.o net-nested-$(CONFIG_SOLARIS) += tap-solaris.o net-nested-$(CONFIG_AIX) += tap-aix.o +net-nested-$(CONFIG_HAIKU) += tap-haiku.o net-nested-$(CONFIG_SLIRP) += slirp.o net-nested-$(CONFIG_VDE) += vde.o net-obj-y += $(addprefix net/, $(net-nested-y)) @@ -87,6 +88,7 @@ common-obj-y += pflib.o common-obj-$(CONFIG_BRLAPI) += baum.o common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o +common-obj-$(CONFIG_WIN32) += version.o common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o diff --git a/Makefile.target b/Makefile.target index a4e80b1..c48cbcc 100644 --- a/Makefile.target +++ b/Makefile.target @@ -31,7 +31,9 @@ endif PROGS=$(QEMU_PROG) +ifndef CONFIG_HAIKU LIBS+=-lm +endif kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS) @@ -217,9 +219,17 @@ obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-ppc-y += ppc440.o ppc440_bamboo.o # PowerPC E500 boards obj-ppc-y += ppce500_mpc8544ds.o +# PowerPC 440 Xilinx ML507 reference board. +obj-ppc-y += virtex_ml507.o obj-ppc-$(CONFIG_KVM) += kvm_ppc.o obj-ppc-$(CONFIG_FDT) += device_tree.o +# Xilinx PPC peripherals +obj-ppc-y += xilinx_intc.o +obj-ppc-y += xilinx_timer.o +obj-ppc-y += xilinx_uartlite.o +obj-ppc-y += xilinx_ethlite.o + obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o obj-mips-y += vga.o i8259.o @@ -299,7 +309,7 @@ obj-alpha-y = alpha_palcode.o main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) -monitor.o: qemu-monitor.h +monitor.o: hmp-commands.h qmp-commands.h $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) @@ -320,13 +330,16 @@ $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/feature_to_c.sh $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") -qemu-monitor.h: $(SRC_PATH)/qemu-monitor.hx +hmp-commands.h: $(SRC_PATH)/hmp-commands.hx + $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") + +qmp-commands.h: $(SRC_PATH)/qmp-commands.hx $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") clean: rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o rm -f *.d */*.d tcg/*.o ide/*.o - rm -f qemu-monitor.h gdbstub-xml.c + rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c install: all ifneq ($(PROGS),) @@ -82,10 +82,10 @@ doing any code change. This is so because: 2. Review can improve your interface. Letting that happen before you implement it can save you work. -* The qmp-commands.txt file is generated from the qemu-monitor.hx one, which +* The qmp-commands.txt file is generated from the qmp-commands.hx one, which is the file that should be edited. Homepage -------- -http://www.linux-kvm.org/page/MonitorProtocol +http://wiki.qemu.org/QMP diff --git a/arch_init.c b/arch_init.c index e468c0c..a910033 100644 --- a/arch_init.c +++ b/arch_init.c @@ -396,7 +396,7 @@ int ram_load(QEMUFile *f, void *opaque, int version_id) #ifndef _WIN32 if (ch == 0 && (!kvm_enabled() || kvm_has_sync_mmu())) { - madvise(host, TARGET_PAGE_SIZE, MADV_DONTNEED); + qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED); } #endif } else if (flags & RAM_SAVE_FLAG_PAGE) { diff --git a/audio/audio.h b/audio/audio.h index 454ade2..a70fda9 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -86,12 +86,8 @@ typedef struct QEMUAudioTimeStamp { uint64_t old_ts; } QEMUAudioTimeStamp; -void AUD_vlog (const char *cap, const char *fmt, va_list ap); -void AUD_log (const char *cap, const char *fmt, ...) -#ifdef __GNUC__ - __attribute__ ((__format__ (__printf__, 2, 3))) -#endif - ; +void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0); +void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3); void AUD_help (void); void AUD_register_card (const char *name, QEMUSoundCard *card); diff --git a/audio/audio_int.h b/audio/audio_int.h index 06e313f..d8560b6 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -236,14 +236,6 @@ static inline int audio_ring_dist (int dst, int src, int len) return (dst >= src) ? (dst - src) : (len - src + dst); } -#if defined __GNUC__ -#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2))) -#define GCC_FMT_ATTR(n, m) __attribute__ ((__format__ (__printf__, n, m))) -#else -#define GCC_ATTR /**/ -#define GCC_FMT_ATTR(n, m) -#endif - static void GCC_ATTR dolog (const char *fmt, ...) { va_list ap; diff --git a/audio/audio_template.h b/audio/audio_template.h index 2f5224b..fd4469e 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -108,11 +108,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) { int samples; -#ifdef DAC - samples = sw->hw->samples; -#else samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; -#endif sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample)); if (!sw->buf) { diff --git a/audio/paaudio.c b/audio/paaudio.c index 9118ece..ff71dac 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -110,8 +110,8 @@ static void *qpa_thread_out (void *arg) return NULL; } + pa->live = 0; pa->rpos = rpos; - pa->live -= decr; pa->decr += decr; } diff --git a/block/blkverify.c b/block/blkverify.c new file mode 100644 index 0000000..8083464 --- /dev/null +++ b/block/blkverify.c @@ -0,0 +1,382 @@ +/* + * Block protocol for block driver correctness testing + * + * Copyright (C) 2010 IBM, Corp. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <stdarg.h> +#include "qemu_socket.h" /* for EINPROGRESS on Windows */ +#include "block_int.h" + +typedef struct { + BlockDriverState *test_file; +} BDRVBlkverifyState; + +typedef struct BlkverifyAIOCB BlkverifyAIOCB; +struct BlkverifyAIOCB { + BlockDriverAIOCB common; + QEMUBH *bh; + + /* Request metadata */ + bool is_write; + int64_t sector_num; + int nb_sectors; + + int ret; /* first completed request's result */ + unsigned int done; /* completion counter */ + bool *finished; /* completion signal for cancel */ + + QEMUIOVector *qiov; /* user I/O vector */ + QEMUIOVector raw_qiov; /* cloned I/O vector for raw file */ + void *buf; /* buffer for raw file I/O */ + + void (*verify)(BlkverifyAIOCB *acb); +}; + +static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb) +{ + BlkverifyAIOCB *acb = (BlkverifyAIOCB *)blockacb; + bool finished = false; + + /* Wait until request completes, invokes its callback, and frees itself */ + acb->finished = &finished; + while (!finished) { + qemu_aio_wait(); + } +} + +static AIOPool blkverify_aio_pool = { + .aiocb_size = sizeof(BlkverifyAIOCB), + .cancel = blkverify_aio_cancel, +}; + +static void blkverify_err(BlkverifyAIOCB *acb, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ", + acb->is_write ? "write" : "read", acb->sector_num, + acb->nb_sectors); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + +/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */ +static int blkverify_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVBlkverifyState *s = bs->opaque; + int ret; + char *raw, *c; + + /* Parse the blkverify: prefix */ + if (strncmp(filename, "blkverify:", strlen("blkverify:"))) { + return -EINVAL; + } + filename += strlen("blkverify:"); + + /* Parse the raw image filename */ + c = strchr(filename, ':'); + if (c == NULL) { + return -EINVAL; + } + + raw = strdup(filename); + raw[c - filename] = '\0'; + ret = bdrv_file_open(&bs->file, raw, flags); + free(raw); + if (ret < 0) { + return ret; + } + filename = c + 1; + + /* Open the test file */ + s->test_file = bdrv_new(""); + ret = bdrv_open(s->test_file, filename, flags, NULL); + if (ret < 0) { + bdrv_delete(s->test_file); + s->test_file = NULL; + return ret; + } + + return 0; +} + +static void blkverify_close(BlockDriverState *bs) +{ + BDRVBlkverifyState *s = bs->opaque; + + bdrv_delete(s->test_file); + s->test_file = NULL; +} + +static void blkverify_flush(BlockDriverState *bs) +{ + BDRVBlkverifyState *s = bs->opaque; + + /* Only flush test file, the raw file is not important */ + bdrv_flush(s->test_file); +} + +static int64_t blkverify_getlength(BlockDriverState *bs) +{ + BDRVBlkverifyState *s = bs->opaque; + + return bdrv_getlength(s->test_file); +} + +/** + * Check that I/O vector contents are identical + * + * @a: I/O vector + * @b: I/O vector + * @ret: Offset to first mismatching byte or -1 if match + */ +static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b) +{ + int i; + ssize_t offset = 0; + + assert(a->niov == b->niov); + for (i = 0; i < a->niov; i++) { + size_t len = 0; + uint8_t *p = (uint8_t *)a->iov[i].iov_base; + uint8_t *q = (uint8_t *)b->iov[i].iov_base; + + assert(a->iov[i].iov_len == b->iov[i].iov_len); + while (len < a->iov[i].iov_len && *p++ == *q++) { + len++; + } + + offset += len; + + if (len != a->iov[i].iov_len) { + return offset; + } + } + return -1; +} + +typedef struct { + int src_index; + struct iovec *src_iov; + void *dest_base; +} IOVectorSortElem; + +static int sortelem_cmp_src_base(const void *a, const void *b) +{ + const IOVectorSortElem *elem_a = a; + const IOVectorSortElem *elem_b = b; + + /* Don't overflow */ + if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) { + return -1; + } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) { + return 1; + } else { + return 0; + } +} + +static int sortelem_cmp_src_index(const void *a, const void *b) +{ + const IOVectorSortElem *elem_a = a; + const IOVectorSortElem *elem_b = b; + + return elem_a->src_index - elem_b->src_index; +} + +/** + * Copy contents of I/O vector + * + * The relative relationships of overlapping iovecs are preserved. This is + * necessary to ensure identical semantics in the cloned I/O vector. + */ +static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, + void *buf) +{ + IOVectorSortElem sortelems[src->niov]; + void *last_end; + int i; + + /* Sort by source iovecs by base address */ + for (i = 0; i < src->niov; i++) { + sortelems[i].src_index = i; + sortelems[i].src_iov = &src->iov[i]; + } + qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base); + + /* Allocate buffer space taking into account overlapping iovecs */ + last_end = NULL; + for (i = 0; i < src->niov; i++) { + struct iovec *cur = sortelems[i].src_iov; + ptrdiff_t rewind = 0; + + /* Detect overlap */ + if (last_end && last_end > cur->iov_base) { + rewind = last_end - cur->iov_base; + } + + sortelems[i].dest_base = buf - rewind; + buf += cur->iov_len - MIN(rewind, cur->iov_len); + last_end = MAX(cur->iov_base + cur->iov_len, last_end); + } + + /* Sort by source iovec index and build destination iovec */ + qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index); + for (i = 0; i < src->niov; i++) { + qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len); + } +} + +static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, + int64_t sector_num, QEMUIOVector *qiov, + int nb_sectors, + BlockDriverCompletionFunc *cb, + void *opaque) +{ + BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque); + + acb->bh = NULL; + acb->is_write = is_write; + acb->sector_num = sector_num; + acb->nb_sectors = nb_sectors; + acb->ret = -EINPROGRESS; + acb->done = 0; + acb->qiov = qiov; + acb->buf = NULL; + acb->verify = NULL; + acb->finished = NULL; + return acb; +} + +static void blkverify_aio_bh(void *opaque) +{ + BlkverifyAIOCB *acb = opaque; + + qemu_bh_delete(acb->bh); + if (acb->buf) { + qemu_iovec_destroy(&acb->raw_qiov); + qemu_vfree(acb->buf); + } + acb->common.cb(acb->common.opaque, acb->ret); + if (acb->finished) { + *acb->finished = true; + } + qemu_aio_release(acb); +} + +static void blkverify_aio_cb(void *opaque, int ret) +{ + BlkverifyAIOCB *acb = opaque; + + switch (++acb->done) { + case 1: + acb->ret = ret; + break; + + case 2: + if (acb->ret != ret) { + blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret); + } + + if (acb->verify) { + acb->verify(acb); + } + + acb->bh = qemu_bh_new(blkverify_aio_bh, acb); + qemu_bh_schedule(acb->bh); + break; + } +} + +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 %ld", + acb->sector_num + (offset / BDRV_SECTOR_SIZE)); + } +} + +static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + BDRVBlkverifyState *s = bs->opaque; + BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov, + nb_sectors, cb, opaque); + + acb->verify = blkverify_verify_readv; + acb->buf = qemu_blockalign(bs->file, qiov->size); + qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov); + blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf); + + if (!bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors, + blkverify_aio_cb, acb)) { + blkverify_aio_cb(acb, -EIO); + } + if (!bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors, + blkverify_aio_cb, acb)) { + blkverify_aio_cb(acb, -EIO); + } + return &acb->common; +} + +static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + BDRVBlkverifyState *s = bs->opaque; + BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov, + nb_sectors, cb, opaque); + + if (!bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors, + blkverify_aio_cb, acb)) { + blkverify_aio_cb(acb, -EIO); + } + if (!bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, + blkverify_aio_cb, acb)) { + blkverify_aio_cb(acb, -EIO); + } + return &acb->common; +} + +static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, + void *opaque) +{ + BDRVBlkverifyState *s = bs->opaque; + + /* Only flush test file, the raw file is not important */ + return bdrv_aio_flush(s->test_file, cb, opaque); +} + +static BlockDriver bdrv_blkverify = { + .format_name = "blkverify", + .protocol_name = "blkverify", + + .instance_size = sizeof(BDRVBlkverifyState), + + .bdrv_getlength = blkverify_getlength, + + .bdrv_file_open = blkverify_open, + .bdrv_close = blkverify_close, + .bdrv_flush = blkverify_flush, + + .bdrv_aio_readv = blkverify_aio_readv, + .bdrv_aio_writev = blkverify_aio_writev, + .bdrv_aio_flush = blkverify_aio_flush, +}; + +static void bdrv_blkverify_init(void) +{ + bdrv_register(&bdrv_blkverify); +} + +block_init(bdrv_blkverify_init); diff --git a/block/nbd.c b/block/nbd.c index 5e9d6cb..c8dc763 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -95,8 +95,6 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags) if (r == p) { goto out; } - } else if (name == NULL) { - goto out; } sock = tcp_socket_outgoing(hostname, port); diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index f562b16..fb4224a 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -60,6 +60,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size) qemu_free(new_l1_table); return new_l1_table_offset; } + bdrv_flush(bs->file); BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE); for(i = 0; i < s->l1_size; i++) @@ -243,6 +244,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table) if (l2_offset < 0) { return l2_offset; } + bdrv_flush(bs->file); /* allocate a new entry in the l2 cache */ @@ -348,6 +350,8 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, BDRVQcowState *s = bs->opaque; int ret, index_in_cluster, n, n1; uint64_t cluster_offset; + struct iovec iov; + QEMUIOVector qiov; while (nb_sectors > 0) { n = nb_sectors; @@ -362,7 +366,11 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, if (!cluster_offset) { if (bs->backing_hd) { /* read from the base image */ - n1 = qcow2_backing_read1(bs->backing_hd, sector_num, buf, n); + iov.iov_base = buf; + iov.iov_len = n * 512; + qemu_iovec_init_external(&qiov, &iov, 1); + + n1 = qcow2_backing_read1(bs->backing_hd, &qiov, sector_num, n); if (n1 > 0) { BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING); ret = bdrv_read(bs->backing_hd, sector_num, buf, n1); @@ -413,7 +421,7 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect, &s->aes_encrypt_key); } BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE); - ret = bdrv_write_sync(bs->file, (cluster_offset >> 9) + n_start, + ret = bdrv_write(bs->file, (cluster_offset >> 9) + n_start, s->cluster_data, n); if (ret < 0) return ret; @@ -712,6 +720,13 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) (i << s->cluster_bits)) | QCOW_OFLAG_COPIED); } + /* + * Before we update the L2 table to actually point to the new cluster, we + * need to be sure that the refcounts have been increased and COW was + * handled. + */ + bdrv_flush(bs->file); + ret = write_l2_entries(bs, l2_table, l2_offset, l2_index, m->nb_clusters); if (ret < 0) { qcow2_l2_cache_reset(bs); diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 4c19e7e..7082601 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -261,6 +261,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) goto fail_block; } + bdrv_flush(bs->file); + /* Initialize the new refcount block only after updating its refcount, * update_refcount uses the refcount cache itself */ memset(s->refcount_block_cache, 0, s->cluster_size); @@ -444,7 +446,7 @@ static int write_refcount_block_entries(BlockDriverState *bs, size = (last_index - first_index) << REFCOUNT_SHIFT; BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART); - ret = bdrv_pwrite_sync(bs->file, + ret = bdrv_pwrite(bs->file, refcount_block_offset + (first_index << REFCOUNT_SHIFT), &s->refcount_block_cache[first_index], size); if (ret < 0) { @@ -573,6 +575,8 @@ static int update_cluster_refcount(BlockDriverState *bs, return ret; } + bdrv_flush(bs->file); + return get_refcount(bs, cluster_index); } @@ -624,6 +628,7 @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size) if (ret < 0) { return ret; } + return offset; } @@ -671,6 +676,8 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) goto redo; } } + + bdrv_flush(bs->file); return offset; } @@ -801,6 +808,10 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, if (ret < 0) { goto fail; } + + /* TODO Flushing once for the whole function should + * be enough */ + bdrv_flush(bs->file); } /* compressed clusters are never modified */ refcount = 2; diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 6228612..bbfcaaa 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -138,6 +138,7 @@ static int qcow_write_snapshots(BlockDriverState *bs) snapshots_size = offset; snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size); + bdrv_flush(bs->file); offset = snapshots_offset; if (offset < 0) { return offset; @@ -271,6 +272,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) if (l1_table_offset < 0) { goto fail; } + bdrv_flush(bs->file); sn->l1_table_offset = l1_table_offset; sn->l1_size = s->l1_size; diff --git a/block/qcow2.c b/block/qcow2.c index a53014d..ee3481b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -311,8 +311,8 @@ static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, } /* handle reading after the end of the backing file */ -int qcow2_backing_read1(BlockDriverState *bs, - int64_t sector_num, uint8_t *buf, int nb_sectors) +int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, + int64_t sector_num, int nb_sectors) { int n1; if ((sector_num + nb_sectors) <= bs->total_sectors) @@ -321,7 +321,9 @@ int qcow2_backing_read1(BlockDriverState *bs, n1 = 0; else n1 = bs->total_sectors - sector_num; - memset(buf + n1 * 512, 0, 512 * (nb_sectors - n1)); + + qemu_iovec_memset(qiov, 0, 512 * (nb_sectors - n1)); + return n1; } @@ -329,14 +331,12 @@ typedef struct QCowAIOCB { BlockDriverAIOCB common; int64_t sector_num; QEMUIOVector *qiov; - uint8_t *buf; - void *orig_buf; int remaining_sectors; int cur_nr_sectors; /* number of sectors in current iteration */ + uint64_t bytes_done; uint64_t cluster_offset; uint8_t *cluster_data; BlockDriverAIOCB *hd_aiocb; - struct iovec hd_iov; QEMUIOVector hd_qiov; QEMUBH *bh; QCowL2Meta l2meta; @@ -397,15 +397,19 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* nothing to do */ } else { if (s->crypt_method) { - qcow2_encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, - acb->cur_nr_sectors, 0, - &s->aes_decrypt_key); + qcow2_encrypt_sectors(s, acb->sector_num, acb->cluster_data, + acb->cluster_data, acb->cur_nr_sectors, 0, &s->aes_decrypt_key); + qemu_iovec_reset(&acb->hd_qiov); + qemu_iovec_copy(&acb->hd_qiov, acb->qiov, acb->bytes_done, + acb->cur_nr_sectors * 512); + qemu_iovec_from_buffer(&acb->hd_qiov, acb->cluster_data, + 512 * acb->cur_nr_sectors); } } acb->remaining_sectors -= acb->cur_nr_sectors; acb->sector_num += acb->cur_nr_sectors; - acb->buf += acb->cur_nr_sectors * 512; + acb->bytes_done += acb->cur_nr_sectors * 512; if (acb->remaining_sectors == 0) { /* request completed */ @@ -415,6 +419,11 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* prepare next AIO request */ acb->cur_nr_sectors = acb->remaining_sectors; + if (s->crypt_method) { + acb->cur_nr_sectors = MIN(acb->cur_nr_sectors, + QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors); + } + ret = qcow2_get_cluster_offset(bs, acb->sector_num << 9, &acb->cur_nr_sectors, &acb->cluster_offset); if (ret < 0) { @@ -423,15 +432,17 @@ static void qcow_aio_read_cb(void *opaque, int ret) index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); + qemu_iovec_reset(&acb->hd_qiov); + qemu_iovec_copy(&acb->hd_qiov, acb->qiov, acb->bytes_done, + acb->cur_nr_sectors * 512); + if (!acb->cluster_offset) { + if (bs->backing_hd) { /* read from the base image */ - n1 = qcow2_backing_read1(bs->backing_hd, acb->sector_num, - acb->buf, acb->cur_nr_sectors); + n1 = qcow2_backing_read1(bs->backing_hd, &acb->hd_qiov, + acb->sector_num, acb->cur_nr_sectors); if (n1 > 0) { - acb->hd_iov.iov_base = (void *)acb->buf; - acb->hd_iov.iov_len = acb->cur_nr_sectors * 512; - qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num, &acb->hd_qiov, acb->cur_nr_sectors, @@ -445,7 +456,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) } } else { /* Note: in this case, no need to wait */ - memset(acb->buf, 0, 512 * acb->cur_nr_sectors); + qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors); ret = qcow_schedule_bh(qcow_aio_read_bh, acb); if (ret < 0) goto done; @@ -454,8 +465,11 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* add AIO support for compressed blocks ? */ if (qcow2_decompress_cluster(bs, acb->cluster_offset) < 0) goto done; - memcpy(acb->buf, s->cluster_cache + index_in_cluster * 512, - 512 * acb->cur_nr_sectors); + + qemu_iovec_from_buffer(&acb->hd_qiov, + s->cluster_cache + index_in_cluster * 512, + 512 * acb->cur_nr_sectors); + ret = qcow_schedule_bh(qcow_aio_read_bh, acb); if (ret < 0) goto done; @@ -465,9 +479,23 @@ static void qcow_aio_read_cb(void *opaque, int ret) goto done; } - acb->hd_iov.iov_base = (void *)acb->buf; - acb->hd_iov.iov_len = acb->cur_nr_sectors * 512; - qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); + if (s->crypt_method) { + /* + * For encrypted images, read everything into a temporary + * contiguous buffer on which the AES functions can work. + */ + if (!acb->cluster_data) { + acb->cluster_data = + qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); + } + + assert(acb->cur_nr_sectors <= + QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors); + qemu_iovec_reset(&acb->hd_qiov); + qemu_iovec_add(&acb->hd_qiov, acb->cluster_data, + 512 * acb->cur_nr_sectors); + } + BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); acb->hd_aiocb = bdrv_aio_readv(bs->file, (acb->cluster_offset >> 9) + index_in_cluster, @@ -481,11 +509,8 @@ static void qcow_aio_read_cb(void *opaque, int ret) return; done: - if (acb->qiov->niov > 1) { - qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size); - qemu_vfree(acb->orig_buf); - } acb->common.cb(acb->common.opaque, ret); + qemu_iovec_destroy(&acb->hd_qiov); qemu_aio_release(acb); } @@ -501,13 +526,10 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs, acb->hd_aiocb = NULL; acb->sector_num = sector_num; acb->qiov = qiov; - if (qiov->niov > 1) { - acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size); - if (is_write) - qemu_iovec_to_buffer(qiov, acb->buf); - } else { - acb->buf = (uint8_t *)qiov->iov->iov_base; - } + + qemu_iovec_init(&acb->hd_qiov, qiov->niov); + + acb->bytes_done = 0; acb->remaining_sectors = nb_sectors; acb->cur_nr_sectors = 0; acb->cluster_offset = 0; @@ -557,7 +579,6 @@ static void qcow_aio_write_cb(void *opaque, int ret) BlockDriverState *bs = acb->common.bs; BDRVQcowState *s = bs->opaque; int index_in_cluster; - const uint8_t *src_buf; int n_end; acb->hd_aiocb = NULL; @@ -573,7 +594,7 @@ static void qcow_aio_write_cb(void *opaque, int ret) acb->remaining_sectors -= acb->cur_nr_sectors; acb->sector_num += acb->cur_nr_sectors; - acb->buf += acb->cur_nr_sectors * 512; + acb->bytes_done += acb->cur_nr_sectors * 512; if (acb->remaining_sectors == 0) { /* request completed */ @@ -604,20 +625,27 @@ static void qcow_aio_write_cb(void *opaque, int ret) assert((acb->cluster_offset & 511) == 0); + qemu_iovec_reset(&acb->hd_qiov); + qemu_iovec_copy(&acb->hd_qiov, acb->qiov, acb->bytes_done, + acb->cur_nr_sectors * 512); + if (s->crypt_method) { if (!acb->cluster_data) { acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); } - qcow2_encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, - acb->cur_nr_sectors, 1, &s->aes_encrypt_key); - src_buf = acb->cluster_data; - } else { - src_buf = acb->buf; + + assert(acb->hd_qiov.size <= QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); + qemu_iovec_to_buffer(&acb->hd_qiov, acb->cluster_data); + + qcow2_encrypt_sectors(s, acb->sector_num, acb->cluster_data, + acb->cluster_data, acb->cur_nr_sectors, 1, &s->aes_encrypt_key); + + qemu_iovec_reset(&acb->hd_qiov); + qemu_iovec_add(&acb->hd_qiov, acb->cluster_data, + acb->cur_nr_sectors * 512); } - acb->hd_iov.iov_base = (void *)src_buf; - acb->hd_iov.iov_len = acb->cur_nr_sectors * 512; - qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); + BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); acb->hd_aiocb = bdrv_aio_writev(bs->file, (acb->cluster_offset >> 9) + index_in_cluster, @@ -635,9 +663,8 @@ fail: QLIST_REMOVE(&acb->l2meta, next_in_flight); } done: - if (acb->qiov->niov > 1) - qemu_vfree(acb->orig_buf); acb->common.cb(acb->common.opaque, ret); + qemu_iovec_destroy(&acb->hd_qiov); qemu_aio_release(acb); } diff --git a/block/qcow2.h b/block/qcow2.h index 3ff162e..356a34a 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -166,8 +166,8 @@ static inline int64_t align_offset(int64_t offset, int n) // FIXME Need qcow2_ prefix to global functions /* qcow2.c functions */ -int qcow2_backing_read1(BlockDriverState *bs, - int64_t sector_num, uint8_t *buf, int nb_sectors); +int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, + int64_t sector_num, int nb_sectors); /* qcow2-refcount.c functions */ int qcow2_refcount_init(BlockDriverState *bs); diff --git a/block/raw-posix.c b/block/raw-posix.c index 813372a..a5cbb7e 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -97,12 +97,12 @@ #define FTYPE_CD 1 #define FTYPE_FD 2 -#define ALIGNED_BUFFER_SIZE (32 * 512) - /* if the FD is not accessed during that time (in ms), we try to reopen it to see if the disk has been changed */ #define FD_OPEN_TIMEOUT 1000 +#define MAX_BLOCKSIZE 4096 + typedef struct BDRVRawState { int fd; int type; @@ -118,7 +118,8 @@ typedef struct BDRVRawState { int use_aio; void *aio_ctx; #endif - uint8_t* aligned_buf; + uint8_t *aligned_buf; + unsigned aligned_buf_size; } BDRVRawState; static int fd_open(BlockDriverState *bs); @@ -161,7 +162,12 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, s->aligned_buf = NULL; if ((bdrv_flags & BDRV_O_NOCACHE)) { - s->aligned_buf = qemu_blockalign(bs, ALIGNED_BUFFER_SIZE); + /* + * Allocate a buffer for read/modify/write cycles. Chose the size + * pessimistically as we don't know the block size yet. + */ + s->aligned_buf_size = 32 * MAX_BLOCKSIZE; + s->aligned_buf = qemu_memalign(MAX_BLOCKSIZE, s->aligned_buf_size); if (s->aligned_buf == NULL) { goto out_close; } @@ -278,8 +284,9 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset, } /* - * offset and count are in bytes, but must be multiples of 512 for files - * opened with O_DIRECT. buf must be aligned to 512 bytes then. + * offset and count are in bytes, but must be multiples of the sector size + * for files opened with O_DIRECT. buf must be aligned to sector size bytes + * then. * * This function may be called without alignment if the caller ensures * that O_DIRECT is not in effect. @@ -316,24 +323,25 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, uint8_t *buf, int count) { BDRVRawState *s = bs->opaque; + unsigned sector_mask = bs->buffer_alignment - 1; int size, ret, shift, sum; sum = 0; if (s->aligned_buf != NULL) { - if (offset & 0x1ff) { - /* align offset on a 512 bytes boundary */ + if (offset & sector_mask) { + /* align offset on a sector size bytes boundary */ - shift = offset & 0x1ff; - size = (shift + count + 0x1ff) & ~0x1ff; - if (size > ALIGNED_BUFFER_SIZE) - size = ALIGNED_BUFFER_SIZE; + shift = offset & sector_mask; + size = (shift + count + sector_mask) & ~sector_mask; + if (size > s->aligned_buf_size) + size = s->aligned_buf_size; ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, size); if (ret < 0) return ret; - size = 512 - shift; + size = bs->buffer_alignment - shift; if (size > count) size = count; memcpy(buf, s->aligned_buf + shift, size); @@ -346,15 +354,15 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, if (count == 0) return sum; } - if (count & 0x1ff || (uintptr_t) buf & 0x1ff) { + if (count & sector_mask || (uintptr_t) buf & sector_mask) { /* read on aligned buffer */ while (count) { - size = (count + 0x1ff) & ~0x1ff; - if (size > ALIGNED_BUFFER_SIZE) - size = ALIGNED_BUFFER_SIZE; + size = (count + sector_mask) & ~sector_mask; + if (size > s->aligned_buf_size) + size = s->aligned_buf_size; ret = raw_pread_aligned(bs, offset, s->aligned_buf, size); if (ret < 0) { @@ -404,25 +412,28 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, const uint8_t *buf, int count) { BDRVRawState *s = bs->opaque; + unsigned sector_mask = bs->buffer_alignment - 1; int size, ret, shift, sum; sum = 0; if (s->aligned_buf != NULL) { - if (offset & 0x1ff) { - /* align offset on a 512 bytes boundary */ - shift = offset & 0x1ff; - ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, 512); + if (offset & sector_mask) { + /* align offset on a sector size bytes boundary */ + shift = offset & sector_mask; + ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, + bs->buffer_alignment); if (ret < 0) return ret; - size = 512 - shift; + size = bs->buffer_alignment - shift; if (size > count) size = count; memcpy(s->aligned_buf + shift, buf, size); - ret = raw_pwrite_aligned(bs, offset - shift, s->aligned_buf, 512); + ret = raw_pwrite_aligned(bs, offset - shift, s->aligned_buf, + bs->buffer_alignment); if (ret < 0) return ret; @@ -434,12 +445,12 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, if (count == 0) return sum; } - if (count & 0x1ff || (uintptr_t) buf & 0x1ff) { + if (count & sector_mask || (uintptr_t) buf & sector_mask) { - while ((size = (count & ~0x1ff)) != 0) { + while ((size = (count & ~sector_mask)) != 0) { - if (size > ALIGNED_BUFFER_SIZE) - size = ALIGNED_BUFFER_SIZE; + if (size > s->aligned_buf_size) + size = s->aligned_buf_size; memcpy(s->aligned_buf, buf, size); @@ -452,14 +463,16 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, count -= ret; sum += ret; } - /* here, count < 512 because (count & ~0x1ff) == 0 */ + /* here, count < 512 because (count & ~sector_mask) == 0 */ if (count) { - ret = raw_pread_aligned(bs, offset, s->aligned_buf, 512); + ret = raw_pread_aligned(bs, offset, s->aligned_buf, + bs->buffer_alignment); if (ret < 0) return ret; memcpy(s->aligned_buf, buf, count); - ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, 512); + ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, + bs->buffer_alignment); if (ret < 0) return ret; if (count < ret) @@ -487,12 +500,12 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num, /* * Check if all memory in this vector is sector aligned. */ -static int qiov_is_aligned(QEMUIOVector *qiov) +static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) { int i; for (i = 0; i < qiov->niov; i++) { - if ((uintptr_t) qiov->iov[i].iov_base % BDRV_SECTOR_SIZE) { + if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) { return 0; } } @@ -515,7 +528,7 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs, * driver that it needs to copy the buffer. */ if (s->aligned_buf) { - if (!qiov_is_aligned(qiov)) { + if (!qiov_is_aligned(bs, qiov)) { type |= QEMU_AIO_MISALIGNED; #ifdef CONFIG_LINUX_AIO } else if (s->use_aio) { diff --git a/block/vvfat.c b/block/vvfat.c index 365332a..26dd474 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2282,7 +2282,6 @@ static void check1(BDRVVVFATState* s) fprintf(stderr, "deleted\n"); continue; } - assert(mapping->dir_index >= 0); assert(mapping->dir_index < s->directory.next); direntry_t* direntry = array_get(&(s->directory), mapping->dir_index); assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0); @@ -2665,6 +2664,11 @@ static int vvfat_write(BlockDriverState *bs, int64_t sector_num, DLOG(checkpoint()); + /* Check if we're operating in read-only mode */ + if (s->qcow == NULL) { + return -EACCES; + } + vvfat_close_current_file(s); /* @@ -2763,12 +2767,12 @@ static int vvfat_is_allocated(BlockDriverState *bs, static int write_target_commit(BlockDriverState *bs, int64_t sector_num, const uint8_t* buffer, int nb_sectors) { - BDRVVVFATState* s = bs->opaque; + BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque); return try_commit(s); } static void write_target_close(BlockDriverState *bs) { - BDRVVVFATState* s = bs->opaque; + BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque); bdrv_delete(s->qcow); free(s->qcow_filename); } @@ -2783,6 +2787,7 @@ static int enable_write_target(BDRVVVFATState *s) { BlockDriver *bdrv_qcow; QEMUOptionParameter *options; + int ret; int size = sector2cluster(s, s->sector_count); s->used_clusters = calloc(size, 1); @@ -2798,11 +2803,16 @@ static int enable_write_target(BDRVVVFATState *s) if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0) return -1; + s->qcow = bdrv_new(""); - if (s->qcow == NULL || - bdrv_open(s->qcow, s->qcow_filename, BDRV_O_RDWR, bdrv_qcow) < 0) - { - return -1; + if (s->qcow == NULL) { + return -1; + } + + ret = bdrv_open(s->qcow, s->qcow_filename, + BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow); + if (ret < 0) { + return ret; } #ifndef _WIN32 @@ -2811,7 +2821,8 @@ static int enable_write_target(BDRVVVFATState *s) s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1); s->bs->backing_hd->drv = &vvfat_write_target; - s->bs->backing_hd->opaque = s; + s->bs->backing_hd->opaque = qemu_malloc(sizeof(void*)); + *(void**)s->bs->backing_hd->opaque = s; return 0; } @@ -34,14 +34,13 @@ struct DriveInfo { #define MAX_IDE_DEVS 2 #define MAX_SCSI_DEVS 7 -extern DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); -extern int drive_get_max_bus(BlockInterfaceType type); -extern void drive_uninit(DriveInfo *dinfo); -extern DriveInfo *drive_get_by_blockdev(BlockDriverState *bs); - -extern QemuOpts *drive_add(const char *file, const char *fmt, ...); -extern DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi, - int *fatal_error); +DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); +int drive_get_max_bus(BlockInterfaceType type); +void drive_uninit(DriveInfo *dinfo); +DriveInfo *drive_get_by_blockdev(BlockDriverState *bs); + +QemuOpts *drive_add(const char *file, const char *fmt, ...) GCC_FMT_ATTR(2, 3); +DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi, int *fatal_error); /* device-hotplug */ diff --git a/bsd-user/main.c b/bsd-user/main.c index aff9f13..6b12f8b 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -795,6 +795,12 @@ int main(int argc, char **argv) r = argv[optind++]; if (envlist_setenv(envlist, r) != 0) usage(); + } else if (!strcmp(r, "ignore-environment")) { + envlist_free(envlist); + if ((envlist = envlist_create()) == NULL) { + (void) fprintf(stderr, "Unable to allocate envlist\n"); + exit(1); + } } else if (!strcmp(r, "U")) { r = argv[optind++]; if (envlist_unsetenv(envlist, r) != 0) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 554ff8b..9763616 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -139,7 +139,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6); -void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); +void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2); extern THREAD CPUState *thread_env; void cpu_loop(CPUState *env); char *target_strerror(int err); @@ -15,7 +15,9 @@ TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c" TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o" TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe" -trap "rm -f $TMPC $TMPO $TMPE ; exit" EXIT INT QUIT TERM +# NB: do not call "exit" in the trap handler; this is buggy with some shells; +# see <1285349658-3122-1-git-send-email-loic.minier@linaro.org> +trap "rm -f $TMPC $TMPO $TMPE" EXIT INT QUIT TERM rm -f config.log compile_object() { @@ -84,6 +86,7 @@ install="install" objcopy="objcopy" ld="ld" strip="strip" +windres="windres" helper_cflags="" libs_softmmu="" libs_tools="" @@ -130,6 +133,7 @@ ar="${cross_prefix}${ar}" objcopy="${cross_prefix}${objcopy}" ld="${cross_prefix}${ld}" strip="${cross_prefix}${strip}" +windres="${cross_prefix}${windres}" # default flags for all hosts QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS" @@ -318,6 +322,7 @@ io_thread="no" mixemu="no" kerneldir="" aix="no" +haiku="no" blobs="yes" pkgversion="" check_utests="no" @@ -336,6 +341,8 @@ elif check_define __OpenBSD__ ; then targetos='OpenBSD' elif check_define __sun__ ; then targetos='SunOS' +elif check_define __HAIKU__ ; then + targetos='Haiku' else targetos=`uname -s` fi @@ -451,6 +458,11 @@ AIX) aix="yes" make="gmake" ;; +Haiku) + haiku="yes" + QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS $QEMU_CFLAGS" + LIBS="-lposix_error_mapper -lnetwork $LIBS" +;; *) audio_drv_list="oss" audio_possible_drivers="oss alsa sdl esd pa" @@ -1708,13 +1720,17 @@ cat > $TMPC << EOF #include <pthread.h> int main(void) { pthread_create(0,0,0,0); return 0; } EOF -for pthread_lib in $PTHREADLIBS_LIST; do - if compile_prog "" "$pthread_lib" ; then - pthread=yes - LIBS="$pthread_lib $LIBS" - break - fi -done +if compile_prog "" "" ; then + pthread=yes +else + for pthread_lib in $PTHREADLIBS_LIST; do + if compile_prog "" "$pthread_lib" ; then + pthread=yes + LIBS="$pthread_lib $LIBS" + break + fi + done +fi if test "$mingw32" != yes -a "$pthread" = no; then echo @@ -2036,7 +2052,7 @@ elif compile_prog "" "-lrt" ; then fi if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \ - "$aix" != "yes" ; then + "$aix" != "yes" -a "$haiku" != "yes" ; then libs_softmmu="-lutil $libs_softmmu" fi @@ -2105,6 +2121,31 @@ if compile_prog "" "" ; then fi ########################################## +# check if we have madvise + +madvise=no +cat > $TMPC << EOF +#include <sys/types.h> +#include <sys/mman.h> +int main(void) { return madvise(NULL, 0, MADV_DONTNEED); } +EOF +if compile_prog "" "" ; then + madvise=yes +fi + +########################################## +# check if we have posix_madvise + +posix_madvise=no +cat > $TMPC << EOF +#include <sys/mman.h> +int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); } +EOF +if compile_prog "" "" ; then + posix_madvise=yes +fi + +########################################## # check if trace backend exists sh "$source_path/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null @@ -2271,6 +2312,8 @@ echo "KVM support $kvm" echo "fdt support $fdt" echo "preadv support $preadv" echo "fdatasync $fdatasync" +echo "madvise $madvise" +echo "posix_madvise $posix_madvise" echo "uuid support $uuid" echo "vhost-net support $vhost_net" echo "Trace backend $trace_backend" @@ -2324,6 +2367,15 @@ fi echo "HOST_LONG_BITS=$hostlongbits" >> $config_host_mak if test "$mingw32" = "yes" ; then echo "CONFIG_WIN32=y" >> $config_host_mak + rc_version=`cat $source_path/VERSION` + version_major=${rc_version%%.*} + rc_version=${rc_version#*.} + version_minor=${rc_version%%.*} + rc_version=${rc_version#*.} + version_subminor=${rc_version%%.*} + version_micro=0 + echo "CONFIG_FILEVERSION=$version_major,$version_minor,$version_subminor,$version_micro" >> $config_host_mak + echo "CONFIG_PRODUCTVERSION=$version_major,$version_minor,$version_subminor,$version_micro" >> $config_host_mak else echo "CONFIG_POSIX=y" >> $config_host_mak fi @@ -2347,6 +2399,9 @@ if test "$solaris" = "yes" ; then echo "CONFIG_NEEDS_LIBSUNMATH=y" >> $config_host_mak fi fi +if test "$haiku" = "yes" ; then + echo "CONFIG_HAIKU=y" >> $config_host_mak +fi if test "$static" = "yes" ; then echo "CONFIG_STATIC=y" >> $config_host_mak fi @@ -2512,6 +2567,12 @@ fi if test "$fdatasync" = "yes" ; then echo "CONFIG_FDATASYNC=y" >> $config_host_mak fi +if test "$madvise" = "yes" ; then + echo "CONFIG_MADVISE=y" >> $config_host_mak +fi +if test "$posix_madvise" = "yes" ; then + echo "CONFIG_POSIX_MADVISE=y" >> $config_host_mak +fi if test "$spice" = "yes" ; then echo "CONFIG_SPICE=y" >> $config_host_mak @@ -2568,6 +2629,7 @@ fi echo "AR=$ar" >> $config_host_mak echo "OBJCOPY=$objcopy" >> $config_host_mak echo "LD=$ld" >> $config_host_mak +echo "WINDRES=$windres" >> $config_host_mak echo "CFLAGS=$CFLAGS" >> $config_host_mak echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak echo "HELPER_CFLAGS=$helper_cflags" >> $config_host_mak @@ -1060,8 +1060,10 @@ void console_select(unsigned int index) if (index >= MAX_CONSOLES) return; - active_console->g_width = ds_get_width(active_console->ds); - active_console->g_height = ds_get_height(active_console->ds); + if (active_console) { + active_console->g_width = ds_get_width(active_console->ds); + active_console->g_height = ds_get_height(active_console->ds); + } s = consoles[index]; if (s) { DisplayState *ds = s->ds; @@ -168,30 +168,50 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len) } /* - * Copies iovecs from src to the end dst until src is completely copied or the - * total size of the copied iovec reaches size. The size of the last copied - * iovec is changed in order to fit the specified total size if it isn't a - * perfect fit already. + * Copies iovecs from src to the end of dst. It starts copying after skipping + * the given number of bytes in src and copies until src is completely copied + * or the total size of the copied iovec reaches size.The size of the last + * copied iovec is changed in order to fit the specified total size if it isn't + * a perfect fit already. */ -void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size) +void qemu_iovec_copy(QEMUIOVector *dst, QEMUIOVector *src, uint64_t skip, + size_t size) { int i; size_t done; + void *iov_base; + uint64_t iov_len; assert(dst->nalloc != -1); done = 0; for (i = 0; (i < src->niov) && (done != size); i++) { - if (done + src->iov[i].iov_len > size) { - qemu_iovec_add(dst, src->iov[i].iov_base, size - done); + if (skip >= src->iov[i].iov_len) { + /* Skip the whole iov */ + skip -= src->iov[i].iov_len; + continue; + } else { + /* Skip only part (or nothing) of the iov */ + iov_base = (uint8_t*) src->iov[i].iov_base + skip; + iov_len = src->iov[i].iov_len - skip; + skip = 0; + } + + if (done + iov_len > size) { + qemu_iovec_add(dst, iov_base, size - done); break; } else { - qemu_iovec_add(dst, src->iov[i].iov_base, src->iov[i].iov_len); + qemu_iovec_add(dst, iov_base, iov_len); } - done += src->iov[i].iov_len; + done += iov_len; } } +void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size) +{ + qemu_iovec_copy(dst, src, 0, size); +} + void qemu_iovec_destroy(QEMUIOVector *qiov) { assert(qiov->nalloc != -1); @@ -234,6 +254,18 @@ void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count) } } +void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count) +{ + size_t n; + int i; + + for (i = 0; i < qiov->niov && count; ++i) { + n = MIN(count, qiov->iov[i].iov_len); + memset(qiov->iov[i].iov_base, c, n); + count -= n; + } +} + #ifndef _WIN32 /* Sets a specific flag */ int fcntl_setfl(int fd, int flag) diff --git a/darwin-user/qemu.h b/darwin-user/qemu.h index 462bbda..0c5081b 100644 --- a/darwin-user/qemu.h +++ b/darwin-user/qemu.h @@ -99,7 +99,7 @@ int do_sigaction(int sig, const struct sigaction *act, struct sigaction *oact); int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss); -void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); +void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2); void qerror(const char *fmt, ...); void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags); diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index c026bbb..940f4bf 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -32,4 +32,6 @@ CONFIG_IDE_MACIO=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y CONFIG_VIRTIO_PCI=y +CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y +CONFIG_PTIMER=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index 0101a28..e1bc6b8 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -32,4 +32,6 @@ CONFIG_IDE_MACIO=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y CONFIG_VIRTIO_PCI=y +CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y +CONFIG_PTIMER=y diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index 8ba9ac1..8f1cc09 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -32,4 +32,6 @@ CONFIG_IDE_MACIO=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y CONFIG_VIRTIO_PCI=y +CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y +CONFIG_PTIMER=y @@ -349,7 +349,8 @@ monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, return 0; } -static int monitor_fprintf(FILE *stream, const char *fmt, ...) +static int GCC_FMT_ATTR(2, 3) +monitor_fprintf(FILE *stream, const char *fmt, ...) { va_list ap; va_start(ap, fmt); diff --git a/docs/blkverify.txt b/docs/blkverify.txt new file mode 100644 index 0000000..d556dc4 --- /dev/null +++ b/docs/blkverify.txt @@ -0,0 +1,69 @@ += Block driver correctness testing with blkverify = + +== Introduction == + +This document describes how to use the blkverify protocol to test that a block +driver is operating correctly. + +It is difficult to test and debug block drivers against real guests. Often +processes inside the guest will crash because corrupt sectors were read as part +of the executable. Other times obscure errors are raised by a program inside +the guest. These issues are extremely hard to trace back to bugs in the block +driver. + +Blkverify solves this problem by catching data corruption inside QEMU the first +time bad data is read and reporting the disk sector that is corrupted. + +== How it works == + +The blkverify protocol has two child block devices, the "test" device and the +"raw" device. Read/write operations are mirrored to both devices so their +state should always be in sync. + +The "raw" device is a raw image, a flat file, that has identical starting +contents to the "test" image. The idea is that the "raw" device will handle +read/write operations correctly and not corrupt data. It can be used as a +reference for comparison against the "test" device. + +After a mirrored read operation completes, blkverify will compare the data and +raise an error if it is not identical. This makes it possible to catch the +first instance where corrupt data is read. + +== Example == + +Imagine raw.img has 0xcd repeated throughout its first sector: + + $ ./qemu-io -c 'read -v 0 512' raw.img + 00000000: cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ................ + 00000010: cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ................ + [...] + 000001e0: cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ................ + 000001f0: cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ................ + read 512/512 bytes at offset 0 + 512.000000 bytes, 1 ops; 0.0000 sec (97.656 MiB/sec and 200000.0000 ops/sec) + +And test.img is corrupt, its first sector is zeroed when it shouldn't be: + + $ ./qemu-io -c 'read -v 0 512' test.img + 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + [...] + 000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 000001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + read 512/512 bytes at offset 0 + 512.000000 bytes, 1 ops; 0.0000 sec (81.380 MiB/sec and 166666.6667 ops/sec) + +This error is caught by blkverify: + + $ ./qemu-io -c 'read 0 512' blkverify:a.img:b.img + blkverify: read sector_num=0 nb_sectors=4 contents mismatch in sector 0 + +A more realistic scenario is verifying the installation of a guest OS: + + $ ./qemu-img create raw.img 16G + $ ./qemu-img create -f qcow2 test.qcow2 16G + $ x86_64-softmmu/qemu-system-x86_64 -cdrom debian.iso \ + -drive file=blkverify:raw.img:test.qcow2 + +If the installation is aborted when blkverify detects corruption, use qemu-io +to explore the contents of the disk image at the sector in question. diff --git a/docs/migration.txt b/docs/migration.txt index 69d5383..4848c1e 100644 --- a/docs/migration.txt +++ b/docs/migration.txt @@ -1,21 +1,21 @@ = Migration = QEMU has code to load/save the state of the guest that it is running. -This are two complementary operations. Saving the state just does +These are two complementary operations. Saving the state just does that, saves the state for each device that the guest is running. Restoring a guest is just the opposite operation: we need to load the state of each device. -For this to work, QEMU has to be launch with the same arguments the +For this to work, QEMU has to be launched with the same arguments the two times. I.e. it can only restore the state in one guest that has the same devices that the one it was saved (this last requirement can -be relaxed a bit, but for now we can consider that configuration have +be relaxed a bit, but for now we can consider that configuration has to be exactly the same). Once that we are able to save/restore a guest, a new functionality is requested: migration. This means that QEMU is able to start in one -machine and being "migrated" to other machine. I.e. being moved to -other machine. +machine and being "migrated" to another machine. I.e. being moved to +another machine. Next was the "live migration" functionality. This is important because some guests run with a lot of state (specially RAM), and it @@ -24,7 +24,7 @@ migration allows the guest to continue running while the state is transferred. Only while the last part of the state is transferred has the guest to be stopped. Typically the time that the guest is unresponsive during live migration is the low hundred of milliseconds -(notice that this depends on lot of things). +(notice that this depends on a lot of things). === Types of migration === @@ -35,9 +35,9 @@ to do migration: - unix migration: do the migration using unix sockets - exec migration: do the migration using the stdin/stdout through a process. - fd migration: do the migration using an file descriptor that is - passed to QEMU. QEMU don't cares how this file descriptor is opened. + passed to QEMU. QEMU doesn't care how this file descriptor is opened. -All this four migration protocols use the same infrastructure to +All these four migration protocols use the same infrastructure to save/restore state devices. This infrastructure is shared with the savevm/loadvm functionality. @@ -49,21 +49,21 @@ This is used for RAM and block devices. It is not yet ported to vmstate. === What is the common infrastructure === QEMU uses a QEMUFile abstraction to be able to do migration. Any type -of migration that what to use QEMU infrastructure has to create a +of migration that wants to use QEMU infrastructure has to create a QEMUFile with: QEMUFile *qemu_fopen_ops(void *opaque, - QEMUFilePutBufferFunc *put_buffer, + QEMUFilePutBufferFunc *put_buffer, QEMUFileGetBufferFunc *get_buffer, QEMUFileCloseFunc *close, QEMUFileRateLimit *rate_limit, QEMUFileSetRateLimit *set_rate_limit, - QEMUFileGetRateLimit *get_rate_limit); + QEMUFileGetRateLimit *get_rate_limit); The functions have the following functionality: This function writes a chunk of data to a file at the given position. -The pos argument can be ignored if the file is only being used for +The pos argument can be ignored if the file is only used for streaming. The handler should try to write all of the data it can. typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf, @@ -76,18 +76,18 @@ bytes actually read should be returned. typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, int64_t pos, int size); -Close a file and return an error code +Close a file and return an error code. typedef int (QEMUFileCloseFunc)(void *opaque); -Called to determine if the file has exceeded it's bandwidth allocation. The +Called to determine if the file has exceeded its bandwidth allocation. The bandwidth capping is a soft limit, not a hard limit. typedef int (QEMUFileRateLimit)(void *opaque); Called to change the current bandwidth allocation. This function must return the new actual bandwidth. It should be new_rate if everything goes OK, and -the old rate otherwise +the old rate otherwise. typedef size_t (QEMUFileSetRateLimit)(void *opaque, size_t new_rate); typedef size_t (QEMUFileGetRateLimit)(void *opaque); @@ -111,8 +111,8 @@ version. When we migrate a device, we save/load the state as a series of fields. Some times, due to bugs or new functionality, we need to change the state to store more/different information. We use the version to identify each time that we do a change. Each version is -associated with a series of fields saved. The save_state always save -the state as the newer version. But load_state some times is able to +associated with a series of fields saved. The save_state always saves +the state as the newer version. But load_state sometimes is able to load state from an older version. === Legacy way === @@ -135,14 +135,14 @@ typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); The important functions for the device state format are the save_state and load_state. Notice that load_state receives a version_id -parameter to know what state format is receiving. save_state don't -have a version_id parameter because it uses always the latest version. +parameter to know what state format is receiving. save_state doesn't +have a version_id parameter because it always uses the latest version. === VMState === The legacy way of saving/loading state of the device had the problem -that we have to maintain in sync two functions. If we did one change -in one of them and not on the other, we got a failed migration. +that we have to maintain two functions in sync. If we did one change +in one of them and not in the other, we would get a failed migration. VMState changed the way that state is saved/loaded. Instead of using a function to save the state and another to load it, it was changed to @@ -173,7 +173,7 @@ We registered this with: vmstate_register(NULL, 0, &vmstate_kbd, s); -Note: talk about how vmstate <-> qdev interact, and what the instance id's mean. +Note: talk about how vmstate <-> qdev interact, and what the instance ids mean. You can search for VMSTATE_* macros for lots of types used in QEMU in hw/hw.h. @@ -182,7 +182,7 @@ hw/hw.h. You can see that there are several version fields: -- version_id: the maximum version_id supported by VMState for that device +- version_id: the maximum version_id supported by VMState for that device. - minimum_version_id: the minimum version_id that VMState is able to understand for that device. - minimum_version_id_old: For devices that were not able to port to vmstate, we can @@ -195,7 +195,7 @@ deprecated and will be removed when no more users are left. === Massaging functions === -Some times, it is not enough to be able to save the state directly +Sometimes, it is not enough to be able to save the state directly from one structure, we need to fill the correct values there. One example is when we are using kvm. Before saving the cpu state, we need to ask kvm to copy to QEMU the state that it is using. And the @@ -227,14 +227,14 @@ makes very complicated to fix bugs in stable branches. If we need to add anything to the state to fix a bug, we have to disable migration to older versions that don't have that bug-fix (i.e. a new field). -But some time, that bug-fix is only needed sometimes, not always. For +But sometimes, that bug-fix is only needed sometimes, not always. For instance, if the device is in the middle of a DMA operation, it is using a specific functionality, .... It is impossible to create a way to make migration from any version to -any other version to work. But we can do better that only allowing +any other version to work. But we can do better than only allowing migration from older versions no newer ones. For that fields that are -only needed sometimes, we add the idea of subsections. a subsection +only needed sometimes, we add the idea of subsections. A subsection is "like" a device vmstate, but with a particularity, it has a Boolean function that tells if that values are needed to be sent or not. If this functions returns false, the subsection is not sent. @@ -266,7 +266,7 @@ const VMStateDescription vmstate_ide_drive_pio_state = { .fields = (VMStateField []) { VMSTATE_INT32(req_nb_sectors, IDEState), VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1, - vmstate_info_uint8, uint8_t), + vmstate_info_uint8, uint8_t), VMSTATE_INT32(cur_io_buffer_offset, IDEState), VMSTATE_INT32(cur_io_buffer_len, IDEState), VMSTATE_UINT8(end_transfer_fn_idx, IDEState), @@ -2173,8 +2173,9 @@ void tlb_set_page(CPUState *env, target_ulong vaddr, pd = p->phys_offset; } #if defined(DEBUG_TLB) - printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n", - vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd); + printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx + " prot=%x idx=%d pd=0x%08lx\n", + vaddr, paddr, prot, mmu_idx, pd); #endif address = vaddr; @@ -2841,9 +2842,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name, new_block->host = file_ram_alloc(new_block, size, mem_path); if (!new_block->host) { new_block->host = qemu_vmalloc(size); -#ifdef MADV_MERGEABLE - madvise(new_block->host, size, MADV_MERGEABLE); -#endif + qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE); } #else fprintf(stderr, "-mem-path option unsupported\n"); @@ -2858,9 +2857,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name, #else new_block->host = qemu_vmalloc(size); #endif -#ifdef MADV_MERGEABLE - madvise(new_block->host, size, MADV_MERGEABLE); -#endif + qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE); } } diff --git a/hmp-commands.hx b/hmp-commands.hx new file mode 100644 index 0000000..81999aa --- /dev/null +++ b/hmp-commands.hx @@ -0,0 +1,1216 @@ +HXCOMM Use DEFHEADING() to define headings in both help text and texi +HXCOMM Text between STEXI and ETEXI are copied to texi version and +HXCOMM discarded from C version +HXCOMM DEF(command, args, callback, arg_string, help) is used to construct +HXCOMM monitor commands +HXCOMM HXCOMM can be used for comments, discarded from both texi and C + +STEXI +@table @option +ETEXI + + { + .name = "help|?", + .args_type = "name:s?", + .params = "[cmd]", + .help = "show the help", + .mhandler.cmd = do_help_cmd, + }, + +STEXI +@item help or ? [@var{cmd}] +@findex help +Show the help for all commands or just for command @var{cmd}. +ETEXI + + { + .name = "commit", + .args_type = "device:B", + .params = "device|all", + .help = "commit changes to the disk images (if -snapshot is used) or backing files", + .mhandler.cmd = do_commit, + }, + +STEXI +@item commit +@findex commit +Commit changes to the disk images (if -snapshot is used) or backing files. +ETEXI + + { + .name = "q|quit", + .args_type = "", + .params = "", + .help = "quit the emulator", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_quit, + }, + +STEXI +@item q or quit +@findex quit +Quit the emulator. +ETEXI + + { + .name = "eject", + .args_type = "force:-f,device:B", + .params = "[-f] device", + .help = "eject a removable medium (use -f to force it)", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_eject, + }, + +STEXI +@item eject [-f] @var{device} +@findex eject +Eject a removable medium (use -f to force it). +ETEXI + + { + .name = "change", + .args_type = "device:B,target:F,arg:s?", + .params = "device filename [format]", + .help = "change a removable medium, optional format", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_change, + }, + +STEXI +@item change @var{device} @var{setting} +@findex change + +Change the configuration of a device. + +@table @option +@item change @var{diskdevice} @var{filename} [@var{format}] +Change the medium for a removable disk device to point to @var{filename}. eg + +@example +(qemu) change ide1-cd0 /path/to/some.iso +@end example + +@var{format} is optional. + +@item change vnc @var{display},@var{options} +Change the configuration of the VNC server. The valid syntax for @var{display} +and @var{options} are described at @ref{sec_invocation}. eg + +@example +(qemu) change vnc localhost:1 +@end example + +@item change vnc password [@var{password}] + +Change the password associated with the VNC server. If the new password is not +supplied, the monitor will prompt for it to be entered. VNC passwords are only +significant up to 8 letters. eg + +@example +(qemu) change vnc password +Password: ******** +@end example + +@end table +ETEXI + + { + .name = "screendump", + .args_type = "filename:F", + .params = "filename", + .help = "save screen into PPM image 'filename'", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_screen_dump, + }, + +STEXI +@item screendump @var{filename} +@findex screendump +Save screen into PPM image @var{filename}. +ETEXI + + { + .name = "logfile", + .args_type = "filename:F", + .params = "filename", + .help = "output logs to 'filename'", + .mhandler.cmd = do_logfile, + }, + +STEXI +@item logfile @var{filename} +@findex logfile +Output logs to @var{filename}. +ETEXI + +#ifdef CONFIG_SIMPLE_TRACE + { + .name = "trace-event", + .args_type = "name:s,option:b", + .params = "name on|off", + .help = "changes status of a specific trace event", + .mhandler.cmd = do_change_trace_event_state, + }, + +STEXI +@item trace-event +@findex trace-event +changes status of a trace event +ETEXI + + { + .name = "trace-file", + .args_type = "op:s?,arg:F?", + .params = "on|off|flush|set [arg]", + .help = "open, close, or flush trace file, or set a new file name", + .mhandler.cmd = do_trace_file, + }, + +STEXI +@item trace-file on|off|flush +@findex trace-file +Open, close, or flush the trace file. If no argument is given, the status of the trace file is displayed. +ETEXI +#endif + + { + .name = "log", + .args_type = "items:s", + .params = "item1[,...]", + .help = "activate logging of the specified items to '/tmp/qemu.log'", + .mhandler.cmd = do_log, + }, + +STEXI +@item log @var{item1}[,...] +@findex log +Activate logging of the specified items to @file{/tmp/qemu.log}. +ETEXI + + { + .name = "savevm", + .args_type = "name:s?", + .params = "[tag|id]", + .help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created", + .mhandler.cmd = do_savevm, + }, + +STEXI +@item savevm [@var{tag}|@var{id}] +@findex savevm +Create a snapshot of the whole virtual machine. If @var{tag} is +provided, it is used as human readable identifier. If there is already +a snapshot with the same tag or ID, it is replaced. More info at +@ref{vm_snapshots}. +ETEXI + + { + .name = "loadvm", + .args_type = "name:s", + .params = "tag|id", + .help = "restore a VM snapshot from its tag or id", + .mhandler.cmd = do_loadvm, + }, + +STEXI +@item loadvm @var{tag}|@var{id} +@findex loadvm +Set the whole virtual machine to the snapshot identified by the tag +@var{tag} or the unique snapshot ID @var{id}. +ETEXI + + { + .name = "delvm", + .args_type = "name:s", + .params = "tag|id", + .help = "delete a VM snapshot from its tag or id", + .mhandler.cmd = do_delvm, + }, + +STEXI +@item delvm @var{tag}|@var{id} +@findex delvm +Delete the snapshot identified by @var{tag} or @var{id}. +ETEXI + + { + .name = "singlestep", + .args_type = "option:s?", + .params = "[on|off]", + .help = "run emulation in singlestep mode or switch to normal mode", + .mhandler.cmd = do_singlestep, + }, + +STEXI +@item singlestep [off] +@findex singlestep +Run the emulation in single step mode. +If called with option off, the emulation returns to normal mode. +ETEXI + + { + .name = "stop", + .args_type = "", + .params = "", + .help = "stop emulation", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_stop, + }, + +STEXI +@item stop +@findex stop +Stop emulation. +ETEXI + + { + .name = "c|cont", + .args_type = "", + .params = "", + .help = "resume emulation", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_cont, + }, + +STEXI +@item c or cont +@findex cont +Resume emulation. +ETEXI + + { + .name = "gdbserver", + .args_type = "device:s?", + .params = "[device]", + .help = "start gdbserver on given device (default 'tcp::1234'), stop with 'none'", + .mhandler.cmd = do_gdbserver, + }, + +STEXI +@item gdbserver [@var{port}] +@findex gdbserver +Start gdbserver session (default @var{port}=1234) +ETEXI + + { + .name = "x", + .args_type = "fmt:/,addr:l", + .params = "/fmt addr", + .help = "virtual memory dump starting at 'addr'", + .mhandler.cmd = do_memory_dump, + }, + +STEXI +@item x/fmt @var{addr} +@findex x +Virtual memory dump starting at @var{addr}. +ETEXI + + { + .name = "xp", + .args_type = "fmt:/,addr:l", + .params = "/fmt addr", + .help = "physical memory dump starting at 'addr'", + .mhandler.cmd = do_physical_memory_dump, + }, + +STEXI +@item xp /@var{fmt} @var{addr} +@findex xp +Physical memory dump starting at @var{addr}. + +@var{fmt} is a format which tells the command how to format the +data. Its syntax is: @option{/@{count@}@{format@}@{size@}} + +@table @var +@item count +is the number of items to be dumped. + +@item format +can be x (hex), d (signed decimal), u (unsigned decimal), o (octal), +c (char) or i (asm instruction). + +@item size +can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits). On x86, +@code{h} or @code{w} can be specified with the @code{i} format to +respectively select 16 or 32 bit code instruction size. + +@end table + +Examples: +@itemize +@item +Dump 10 instructions at the current instruction pointer: +@example +(qemu) x/10i $eip +0x90107063: ret +0x90107064: sti +0x90107065: lea 0x0(%esi,1),%esi +0x90107069: lea 0x0(%edi,1),%edi +0x90107070: ret +0x90107071: jmp 0x90107080 +0x90107073: nop +0x90107074: nop +0x90107075: nop +0x90107076: nop +@end example + +@item +Dump 80 16 bit values at the start of the video memory. +@smallexample +(qemu) xp/80hx 0xb8000 +0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42 +0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41 +0x000b8020: 0x0b42 0x0b69 0x0b6f 0x0b73 0x0b20 0x0b63 0x0b75 0x0b72 +0x000b8030: 0x0b72 0x0b65 0x0b6e 0x0b74 0x0b2d 0x0b63 0x0b76 0x0b73 +0x000b8040: 0x0b20 0x0b30 0x0b35 0x0b20 0x0b4e 0x0b6f 0x0b76 0x0b20 +0x000b8050: 0x0b32 0x0b30 0x0b30 0x0b33 0x0720 0x0720 0x0720 0x0720 +0x000b8060: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 +0x000b8070: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 +0x000b8080: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 +0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 +@end smallexample +@end itemize +ETEXI + + { + .name = "p|print", + .args_type = "fmt:/,val:l", + .params = "/fmt expr", + .help = "print expression value (use $reg for CPU register access)", + .mhandler.cmd = do_print, + }, + +STEXI +@item p or print/@var{fmt} @var{expr} +@findex print + +Print expression value. Only the @var{format} part of @var{fmt} is +used. +ETEXI + + { + .name = "i", + .args_type = "fmt:/,addr:i,index:i.", + .params = "/fmt addr", + .help = "I/O port read", + .mhandler.cmd = do_ioport_read, + }, + +STEXI +Read I/O port. +ETEXI + + { + .name = "o", + .args_type = "fmt:/,addr:i,val:i", + .params = "/fmt addr value", + .help = "I/O port write", + .mhandler.cmd = do_ioport_write, + }, + +STEXI +Write to I/O port. +ETEXI + + { + .name = "sendkey", + .args_type = "string:s,hold_time:i?", + .params = "keys [hold_ms]", + .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", + .mhandler.cmd = do_sendkey, + }, + +STEXI +@item sendkey @var{keys} +@findex sendkey + +Send @var{keys} to the emulator. @var{keys} could be the name of the +key or @code{#} followed by the raw value in either decimal or hexadecimal +format. Use @code{-} to press several keys simultaneously. Example: +@example +sendkey ctrl-alt-f1 +@end example + +This command is useful to send keys that your graphical user interface +intercepts at low level, such as @code{ctrl-alt-f1} in X Window. +ETEXI + + { + .name = "system_reset", + .args_type = "", + .params = "", + .help = "reset the system", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_system_reset, + }, + +STEXI +@item system_reset +@findex system_reset + +Reset the system. +ETEXI + + { + .name = "system_powerdown", + .args_type = "", + .params = "", + .help = "send system power down event", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_system_powerdown, + }, + +STEXI +@item system_powerdown +@findex system_powerdown + +Power down the system (if supported). +ETEXI + + { + .name = "sum", + .args_type = "start:i,size:i", + .params = "addr size", + .help = "compute the checksum of a memory region", + .mhandler.cmd = do_sum, + }, + +STEXI +@item sum @var{addr} @var{size} +@findex sum + +Compute the checksum of a memory region. +ETEXI + + { + .name = "usb_add", + .args_type = "devname:s", + .params = "device", + .help = "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')", + .mhandler.cmd = do_usb_add, + }, + +STEXI +@item usb_add @var{devname} +@findex usb_add + +Add the USB device @var{devname}. For details of available devices see +@ref{usb_devices} +ETEXI + + { + .name = "usb_del", + .args_type = "devname:s", + .params = "device", + .help = "remove USB device 'bus.addr'", + .mhandler.cmd = do_usb_del, + }, + +STEXI +@item usb_del @var{devname} +@findex usb_del + +Remove the USB device @var{devname} from the QEMU virtual USB +hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor +command @code{info usb} to see the devices you can remove. +ETEXI + + { + .name = "device_add", + .args_type = "device:O", + .params = "driver[,prop=value][,...]", + .help = "add device, like -device on the command line", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_device_add, + }, + +STEXI +@item device_add @var{config} +@findex device_add + +Add device. +ETEXI + + { + .name = "device_del", + .args_type = "id:s", + .params = "device", + .help = "remove device", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_device_del, + }, + +STEXI +@item device_del @var{id} +@findex device_del + +Remove device @var{id}. +ETEXI + + { + .name = "cpu", + .args_type = "index:i", + .params = "index", + .help = "set the default CPU", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_cpu_set, + }, + +STEXI +@item cpu @var{index} +@findex cpu +Set the default CPU. +ETEXI + + { + .name = "mouse_move", + .args_type = "dx_str:s,dy_str:s,dz_str:s?", + .params = "dx dy [dz]", + .help = "send mouse move events", + .mhandler.cmd = do_mouse_move, + }, + +STEXI +@item mouse_move @var{dx} @var{dy} [@var{dz}] +@findex mouse_move +Move the active mouse to the specified coordinates @var{dx} @var{dy} +with optional scroll axis @var{dz}. +ETEXI + + { + .name = "mouse_button", + .args_type = "button_state:i", + .params = "state", + .help = "change mouse button state (1=L, 2=M, 4=R)", + .mhandler.cmd = do_mouse_button, + }, + +STEXI +@item mouse_button @var{val} +@findex mouse_button +Change the active mouse button state @var{val} (1=L, 2=M, 4=R). +ETEXI + + { + .name = "mouse_set", + .args_type = "index:i", + .params = "index", + .help = "set which mouse device receives events", + .mhandler.cmd = do_mouse_set, + }, + +STEXI +@item mouse_set @var{index} +@findex mouse_set +Set which mouse device receives events at given @var{index}, index +can be obtained with +@example +info mice +@end example +ETEXI + +#ifdef HAS_AUDIO + { + .name = "wavcapture", + .args_type = "path:F,freq:i?,bits:i?,nchannels:i?", + .params = "path [frequency [bits [channels]]]", + .help = "capture audio to a wave file (default frequency=44100 bits=16 channels=2)", + .mhandler.cmd = do_wav_capture, + }, +#endif +STEXI +@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]] +@findex wavcapture +Capture audio into @var{filename}. Using sample rate @var{frequency} +bits per sample @var{bits} and number of channels @var{channels}. + +Defaults: +@itemize @minus +@item Sample rate = 44100 Hz - CD quality +@item Bits = 16 +@item Number of channels = 2 - Stereo +@end itemize +ETEXI + +#ifdef HAS_AUDIO + { + .name = "stopcapture", + .args_type = "n:i", + .params = "capture index", + .help = "stop capture", + .mhandler.cmd = do_stop_capture, + }, +#endif +STEXI +@item stopcapture @var{index} +@findex stopcapture +Stop capture with a given @var{index}, index can be obtained with +@example +info capture +@end example +ETEXI + + { + .name = "memsave", + .args_type = "val:l,size:i,filename:s", + .params = "addr size file", + .help = "save to disk virtual memory dump starting at 'addr' of size 'size'", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_memory_save, + }, + +STEXI +@item memsave @var{addr} @var{size} @var{file} +@findex memsave +save to disk virtual memory dump starting at @var{addr} of size @var{size}. +ETEXI + + { + .name = "pmemsave", + .args_type = "val:l,size:i,filename:s", + .params = "addr size file", + .help = "save to disk physical memory dump starting at 'addr' of size 'size'", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_physical_memory_save, + }, + +STEXI +@item pmemsave @var{addr} @var{size} @var{file} +@findex pmemsave +save to disk physical memory dump starting at @var{addr} of size @var{size}. +ETEXI + + { + .name = "boot_set", + .args_type = "bootdevice:s", + .params = "bootdevice", + .help = "define new values for the boot device list", + .mhandler.cmd = do_boot_set, + }, + +STEXI +@item boot_set @var{bootdevicelist} +@findex boot_set + +Define new values for the boot device list. Those values will override +the values specified on the command line through the @code{-boot} option. + +The values that can be specified here depend on the machine type, but are +the same that can be specified in the @code{-boot} command line option. +ETEXI + +#if defined(TARGET_I386) + { + .name = "nmi", + .args_type = "cpu_index:i", + .params = "cpu", + .help = "inject an NMI on the given CPU", + .mhandler.cmd = do_inject_nmi, + }, +#endif +STEXI +@item nmi @var{cpu} +@findex nmi +Inject an NMI on the given CPU (x86 only). +ETEXI + + { + .name = "migrate", + .args_type = "detach:-d,blk:-b,inc:-i,uri:s", + .params = "[-d] [-b] [-i] uri", + .help = "migrate to URI (using -d to not wait for completion)" + "\n\t\t\t -b for migration without shared storage with" + " full copy of disk\n\t\t\t -i for migration without " + "shared storage with incremental copy of disk " + "(base image shared between src and destination)", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_migrate, + }, + + +STEXI +@item migrate [-d] [-b] [-i] @var{uri} +@findex migrate +Migrate to @var{uri} (using -d to not wait for completion). + -b for migration with full copy of disk + -i for migration with incremental copy of disk (base image is shared) +ETEXI + + { + .name = "migrate_cancel", + .args_type = "", + .params = "", + .help = "cancel the current VM migration", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_migrate_cancel, + }, + +STEXI +@item migrate_cancel +@findex migrate_cancel +Cancel the current VM migration. +ETEXI + + { + .name = "migrate_set_speed", + .args_type = "value:f", + .params = "value", + .help = "set maximum speed (in bytes) for migrations", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_migrate_set_speed, + }, + +STEXI +@item migrate_set_speed @var{value} +@findex migrate_set_speed +Set maximum speed to @var{value} (in bytes) for migrations. +ETEXI + + { + .name = "migrate_set_downtime", + .args_type = "value:T", + .params = "value", + .help = "set maximum tolerated downtime (in seconds) for migrations", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_migrate_set_downtime, + }, + +STEXI +@item migrate_set_downtime @var{second} +@findex migrate_set_downtime +Set maximum tolerated downtime (in seconds) for migration. +ETEXI + +#if defined(TARGET_I386) + { + .name = "drive_add", + .args_type = "pci_addr:s,opts:s", + .params = "[[<domain>:]<bus>:]<slot>\n" + "[file=file][,if=type][,bus=n]\n" + "[,unit=m][,media=d][index=i]\n" + "[,cyls=c,heads=h,secs=s[,trans=t]]\n" + "[snapshot=on|off][,cache=on|off]", + .help = "add drive to PCI storage controller", + .mhandler.cmd = drive_hot_add, + }, +#endif + +STEXI +@item drive_add +@findex drive_add +Add drive to PCI storage controller. +ETEXI + +#if defined(TARGET_I386) + { + .name = "pci_add", + .args_type = "pci_addr:s,type:s,opts:s?", + .params = "auto|[[<domain>:]<bus>:]<slot> nic|storage [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...", + .help = "hot-add PCI device", + .mhandler.cmd = pci_device_hot_add, + }, +#endif + +STEXI +@item pci_add +@findex pci_add +Hot-add PCI device. +ETEXI + +#if defined(TARGET_I386) + { + .name = "pci_del", + .args_type = "pci_addr:s", + .params = "[[<domain>:]<bus>:]<slot>", + .help = "hot remove PCI device", + .mhandler.cmd = do_pci_device_hot_remove, + }, +#endif + +STEXI +@item pci_del +@findex pci_del +Hot remove PCI device. +ETEXI + + { + .name = "host_net_add", + .args_type = "device:s,opts:s?", + .params = "tap|user|socket|vde|dump [options]", + .help = "add host VLAN client", + .mhandler.cmd = net_host_device_add, + }, + +STEXI +@item host_net_add +@findex host_net_add +Add host VLAN client. +ETEXI + + { + .name = "host_net_remove", + .args_type = "vlan_id:i,device:s", + .params = "vlan_id name", + .help = "remove host VLAN client", + .mhandler.cmd = net_host_device_remove, + }, + +STEXI +@item host_net_remove +@findex host_net_remove +Remove host VLAN client. +ETEXI + + { + .name = "netdev_add", + .args_type = "netdev:O", + .params = "[user|tap|socket],id=str[,prop=value][,...]", + .help = "add host network device", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_netdev_add, + }, + +STEXI +@item netdev_add +@findex netdev_add +Add host network device. +ETEXI + + { + .name = "netdev_del", + .args_type = "id:s", + .params = "id", + .help = "remove host network device", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_netdev_del, + }, + +STEXI +@item netdev_del +@findex netdev_del +Remove host network device. +ETEXI + +#ifdef CONFIG_SLIRP + { + .name = "hostfwd_add", + .args_type = "arg1:s,arg2:s?,arg3:s?", + .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport", + .help = "redirect TCP or UDP connections from host to guest (requires -net user)", + .mhandler.cmd = net_slirp_hostfwd_add, + }, +#endif +STEXI +@item hostfwd_add +@findex hostfwd_add +Redirect TCP or UDP connections from host to guest (requires -net user). +ETEXI + +#ifdef CONFIG_SLIRP + { + .name = "hostfwd_remove", + .args_type = "arg1:s,arg2:s?,arg3:s?", + .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport", + .help = "remove host-to-guest TCP or UDP redirection", + .mhandler.cmd = net_slirp_hostfwd_remove, + }, + +#endif +STEXI +@item hostfwd_remove +@findex hostfwd_remove +Remove host-to-guest TCP or UDP redirection. +ETEXI + + { + .name = "balloon", + .args_type = "value:M", + .params = "target", + .help = "request VM to change its memory allocation (in MB)", + .user_print = monitor_user_noop, + .mhandler.cmd_async = do_balloon, + .flags = MONITOR_CMD_ASYNC, + }, + +STEXI +@item balloon @var{value} +@findex balloon +Request VM to change its memory allocation to @var{value} (in MB). +ETEXI + + { + .name = "set_link", + .args_type = "name:s,up:b", + .params = "name on|off", + .help = "change the link status of a network adapter", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_set_link, + }, + +STEXI +@item set_link @var{name} [on|off] +@findex set_link +Switch link @var{name} on (i.e. up) or off (i.e. down). +ETEXI + + { + .name = "watchdog_action", + .args_type = "action:s", + .params = "[reset|shutdown|poweroff|pause|debug|none]", + .help = "change watchdog action", + .mhandler.cmd = do_watchdog_action, + }, + +STEXI +@item watchdog_action +@findex watchdog_action +Change watchdog action. +ETEXI + + { + .name = "acl_show", + .args_type = "aclname:s", + .params = "aclname", + .help = "list rules in the access control list", + .mhandler.cmd = do_acl_show, + }, + +STEXI +@item acl_show @var{aclname} +@findex acl_show +List all the matching rules in the access control list, and the default +policy. There are currently two named access control lists, +@var{vnc.x509dname} and @var{vnc.username} matching on the x509 client +certificate distinguished name, and SASL username respectively. +ETEXI + + { + .name = "acl_policy", + .args_type = "aclname:s,policy:s", + .params = "aclname allow|deny", + .help = "set default access control list policy", + .mhandler.cmd = do_acl_policy, + }, + +STEXI +@item acl_policy @var{aclname} @code{allow|deny} +@findex acl_policy +Set the default access control list policy, used in the event that +none of the explicit rules match. The default policy at startup is +always @code{deny}. +ETEXI + + { + .name = "acl_add", + .args_type = "aclname:s,match:s,policy:s,index:i?", + .params = "aclname match allow|deny [index]", + .help = "add a match rule to the access control list", + .mhandler.cmd = do_acl_add, + }, + +STEXI +@item acl_add @var{aclname} @var{match} @code{allow|deny} [@var{index}] +@findex acl_add +Add a match rule to the access control list, allowing or denying access. +The match will normally be an exact username or x509 distinguished name, +but can optionally include wildcard globs. eg @code{*@@EXAMPLE.COM} to +allow all users in the @code{EXAMPLE.COM} kerberos realm. The match will +normally be appended to the end of the ACL, but can be inserted +earlier in the list if the optional @var{index} parameter is supplied. +ETEXI + + { + .name = "acl_remove", + .args_type = "aclname:s,match:s", + .params = "aclname match", + .help = "remove a match rule from the access control list", + .mhandler.cmd = do_acl_remove, + }, + +STEXI +@item acl_remove @var{aclname} @var{match} +@findex acl_remove +Remove the specified match rule from the access control list. +ETEXI + + { + .name = "acl_reset", + .args_type = "aclname:s", + .params = "aclname", + .help = "reset the access control list", + .mhandler.cmd = do_acl_reset, + }, + +STEXI +@item acl_reset @var{aclname} +@findex acl_reset +Remove all matches from the access control list, and set the default +policy back to @code{deny}. +ETEXI + +#if defined(TARGET_I386) + + { + .name = "mce", + .args_type = "cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l", + .params = "cpu bank status mcgstatus addr misc", + .help = "inject a MCE on the given CPU", + .mhandler.cmd = do_inject_mce, + }, + +#endif +STEXI +@item mce @var{cpu} @var{bank} @var{status} @var{mcgstatus} @var{addr} @var{misc} +@findex mce (x86) +Inject an MCE on the given CPU (x86 only). +ETEXI + + { + .name = "getfd", + .args_type = "fdname:s", + .params = "getfd name", + .help = "receive a file descriptor via SCM rights and assign it a name", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_getfd, + }, + +STEXI +@item getfd @var{fdname} +@findex getfd +If a file descriptor is passed alongside this command using the SCM_RIGHTS +mechanism on unix sockets, it is stored using the name @var{fdname} for +later use by other monitor commands. +ETEXI + + { + .name = "closefd", + .args_type = "fdname:s", + .params = "closefd name", + .help = "close a file descriptor previously passed via SCM rights", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_closefd, + }, + +STEXI +@item closefd @var{fdname} +@findex closefd +Close the file descriptor previously assigned to @var{fdname} using the +@code{getfd} command. This is only needed if the file descriptor was never +used by another monitor command. +ETEXI + + { + .name = "block_passwd", + .args_type = "device:B,password:s", + .params = "block_passwd device password", + .help = "set the password of encrypted block devices", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_block_set_passwd, + }, + +STEXI +@item block_passwd @var{device} @var{password} +@findex block_passwd +Set the encrypted device @var{device} password to @var{password} +ETEXI + + { + .name = "info", + .args_type = "item:s?", + .params = "[subcommand]", + .help = "show various information about the system state", + .mhandler.cmd = do_info, + }, + +STEXI +@item info @var{subcommand} +@findex info +Show various information about the system state. + +@table @option +@item info version +show the version of QEMU +@item info network +show the various VLANs and the associated devices +@item info chardev +show the character devices +@item info block +show the block devices +@item info blockstats +show block device statistics +@item info registers +show the cpu registers +@item info cpus +show infos for each CPU +@item info history +show the command line history +@item info irq +show the interrupts statistics (if available) +@item info pic +show i8259 (PIC) state +@item info pci +show emulated PCI device info +@item info tlb +show virtual to physical memory mappings (i386 only) +@item info mem +show the active virtual memory mappings (i386 only) +@item info jit +show dynamic compiler info +@item info kvm +show KVM information +@item info numa +show NUMA information +@item info kvm +show KVM information +@item info usb +show USB devices plugged on the virtual USB hub +@item info usbhost +show all USB host devices +@item info profile +show profiling information +@item info capture +show information about active capturing +@item info snapshots +show list of VM snapshots +@item info status +show the current VM status (running|paused) +@item info pcmcia +show guest PCMCIA status +@item info mice +show which guest mouse is receiving events +@item info vnc +show the vnc server status +@item info name +show the current VM name +@item info uuid +show the current VM UUID +@item info cpustats +show CPU statistics +@item info usernet +show user network stack connection states +@item info migrate +show migration status +@item info balloon +show balloon information +@item info qtree +show device tree +@item info qdm +show qdev device model list +@item info roms +show roms +@end table +ETEXI + +#ifdef CONFIG_SIMPLE_TRACE +STEXI +@item info trace +show contents of trace buffer +@item info trace-events +show available trace events and their state +ETEXI +#endif + +STEXI +@end table +ETEXI @@ -1342,8 +1342,9 @@ unsigned char OPLRead(FM_OPL *OPL,int a) { if(OPL->keyboardhandler_r) return OPL->keyboardhandler_r(OPL->keyboard_param); - else + else { LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); + } } return 0; #if 0 @@ -1355,8 +1356,9 @@ unsigned char OPLRead(FM_OPL *OPL,int a) { if(OPL->porthandler_r) return OPL->porthandler_r(OPL->port_param); - else + else { LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); + } } return 0; case 0x1a: /* PCM-DATA */ diff --git a/hw/ide/core.c b/hw/ide/core.c index 1e466d1..06b6e14 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2645,6 +2645,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, if (bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM) { s->drive_kind = IDE_CD; bdrv_set_change_cb(bs, cdrom_change_cb, s); + bs->buffer_alignment = 2048; } else { if (!bdrv_is_inserted(s->bs)) { error_report("Device needs media, but drive is empty"); @@ -2679,7 +2680,8 @@ static void ide_init1(IDEBus *bus, int unit) s->bus = bus; s->unit = unit; s->drive_serial = drive_serial++; - s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4); + /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */ + s->io_buffer = qemu_memalign(2048, IDE_DMA_BUF_SECTORS*512 + 4); s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4; s->smart_selftest_data = qemu_blockalign(s->bs, 512); s->sector_write_timer = qemu_new_timer(vm_clock, diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index ac82067..df80ef6 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -76,7 +76,8 @@ static struct _loaderparams { const char *initrd_filename; } loaderparams; -static void prom_set(uint32_t* prom_buf, int index, const char *string, ...) +static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, + const char *string, ...) { va_list ap; int32_t table_addr; @@ -141,13 +142,13 @@ static int64_t load_kernel (CPUState *env) prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE); prom_buf = qemu_malloc(prom_size); - prom_set(prom_buf, index++, loaderparams.kernel_filename); + prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename); if (initrd_size > 0) { - prom_set(prom_buf, index++, "rd_start=0x" PRIx64 " rd_size=%li %s", + prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s", cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, loaderparams.kernel_cmdline); } else { - prom_set(prom_buf, index++, loaderparams.kernel_cmdline); + prom_set(prom_buf, index++, "%s", loaderparams.kernel_cmdline); } /* Setup minimum environment variables */ diff --git a/hw/mips_malta.c b/hw/mips_malta.c index ec95cd8..09690894 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -654,7 +654,8 @@ static void write_bootloader (CPUState *env, uint8_t *base, } -static void prom_set(uint32_t* prom_buf, int index, const char *string, ...) +static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, + const char *string, ...) { va_list ap; int32_t table_addr; @@ -728,13 +729,13 @@ static int64_t load_kernel (void) prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE); prom_buf = qemu_malloc(prom_size); - prom_set(prom_buf, prom_index++, loaderparams.kernel_filename); + prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename); if (initrd_size > 0) { prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s", cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, loaderparams.kernel_cmdline); } else { - prom_set(prom_buf, prom_index++, loaderparams.kernel_cmdline); + prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline); } prom_set(prom_buf, prom_index++, "memsize"); diff --git a/hw/mipsnet.c b/hw/mipsnet.c index a95b3ce..c5e54ff 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -81,7 +81,7 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; #ifdef DEBUG_MIPSNET_RECEIVE - printf("mipsnet: receiving len=%d\n", size); + printf("mipsnet: receiving len=%zu\n", size); #endif if (!mipsnet_can_receive(nc)) return -1; @@ -604,7 +604,7 @@ static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) } /* - * multifuction bit is interpreted in two ways as follows. + * multifunction bit is interpreted in two ways as follows. * - all functions must set the bit to 1. * Example: Intel X53 * - function 0 must set the bit, but the rest function (> 0) @@ -769,6 +769,9 @@ struct ppcemb_timer_t { struct QEMUTimer *fit_timer; uint64_t wdt_next; /* Tick for next WDT interrupt */ struct QEMUTimer *wdt_timer; + + /* 405 have the PIT, 440 have a DECR. */ + unsigned int decr_excp; }; /* Fixed interval timer */ @@ -851,7 +854,7 @@ static void cpu_4xx_pit_cb (void *opaque) ppcemb_timer = tb_env->opaque; env->spr[SPR_40x_TSR] |= 1 << 27; if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) - ppc_set_irq(env, PPC_INTERRUPT_PIT, 1); + ppc_set_irq(env, ppcemb_timer->decr_excp, 1); start_stop_pit(env, tb_env, 1); LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " " "%016" PRIx64 "\n", __func__, @@ -948,10 +951,15 @@ target_ulong load_40x_pit (CPUState *env) void store_booke_tsr (CPUState *env, target_ulong val) { + ppc_tb_t *tb_env = env->tb_env; + ppcemb_timer_t *ppcemb_timer; + + ppcemb_timer = tb_env->opaque; + LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val); env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000); if (val & 0x80000000) - ppc_set_irq(env, PPC_INTERRUPT_PIT, 0); + ppc_set_irq(env, ppcemb_timer->decr_excp, 0); } void store_booke_tcr (CPUState *env, target_ulong val) @@ -977,7 +985,8 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq) /* XXX: we should also update all timers */ } -clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) +clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq, + unsigned int decr_excp) { ppc_tb_t *tb_env; ppcemb_timer_t *ppcemb_timer; @@ -996,6 +1005,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env); ppcemb_timer->wdt_timer = qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env); + ppcemb_timer->decr_excp = decr_excp; } return &ppc_emb_set_tb_clk; @@ -19,7 +19,9 @@ int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn), int (*dcr_write_error)(int dcrn)); int ppc_dcr_register (CPUState *env, int dcrn, void *opaque, dcr_read_cb drc_read, dcr_write_cb dcr_write); -clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq); +clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq, + unsigned int decr_excp); + /* Embedded PowerPC reset */ void ppc40x_core_reset (CPUState *env); void ppc40x_chip_reset (CPUState *env); diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 7f698b8..5f581fe 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -56,7 +56,7 @@ CPUState *ppc4xx_init (const char *cpu_model, cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ cpu_clk->opaque = env; /* Set time-base frequency to sysclk */ - tb_clk->cb = ppc_emb_timers_init(env, sysclk); + tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_PIT); tb_clk->opaque = env; ppc_dcr_init(env, NULL, NULL); /* Register qemu callbacks */ diff --git a/hw/rc4030.c b/hw/rc4030.c index 2231373..abbc3eb 100644 --- a/hw/rc4030.c +++ b/hw/rc4030.c @@ -749,7 +749,10 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri printf("rc4030 dma: Copying %d bytes %s host %p\n", len, is_write ? "from" : "to", buf); for (i = 0; i < len; i += 16) { - int n = min(16, len - i); + int n = 16; + if (n > len - i) { + n = len - i; + } for (j = 0; j < n; j++) printf("%02x ", buf[i + j]); while (j++ < 16) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 7aa0bcd..5a3fd4b 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -208,6 +208,8 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd) case SEEK_6: case WRITE_FILEMARKS: case SPACE: + case RESERVE: + case RELEASE: case ERASE: case ALLOW_MEDIUM_REMOVAL: case VERIFY: @@ -319,7 +321,6 @@ static void scsi_req_xfer_mode(SCSIRequest *req) case WRITE_BUFFER: case FORMAT_UNIT: case REASSIGN_BLOCKS: - case RESERVE: case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 1446ca6..9628b39 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -70,14 +70,15 @@ struct SCSIDiskState char *serial; }; -static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) +static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag, + uint32_t lun) { SCSIRequest *req; SCSIDiskReq *r; - req = scsi_req_alloc(sizeof(SCSIDiskReq), d, tag, lun); + req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun); r = DO_UPCAST(SCSIDiskReq, req, req); - r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE); + r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE); return r; } @@ -939,7 +940,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } /* ??? Tags are not unique for different luns. We only implement a single lun, so this should not matter. */ - r = scsi_new_request(d, tag, lun); + r = scsi_new_request(s, tag, lun); outbuf = (uint8_t *)r->iov.iov_base; is_write = 0; DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); @@ -1177,6 +1178,7 @@ static int scsi_disk_initfn(SCSIDevice *dev) s->qdev.blocksize = s->qdev.conf.logical_block_size; } s->cluster_size = s->qdev.blocksize / 512; + s->bs->buffer_alignment = s->qdev.blocksize; s->qdev.type = TYPE_DISK; qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s); diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 9538027..7212091 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -455,15 +455,31 @@ static int get_stream_blocksize(BlockDriverState *bdrv) return (buf[9] << 16) | (buf[10] << 8) | buf[11]; } -static void scsi_destroy(SCSIDevice *d) +static void scsi_generic_purge_requests(SCSIGenericState *s) { - SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); SCSIGenericReq *r; while (!QTAILQ_EMPTY(&s->qdev.requests)) { r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests)); + if (r->req.aiocb) { + bdrv_aio_cancel(r->req.aiocb); + } scsi_remove_request(r); } +} + +static void scsi_generic_reset(DeviceState *dev) +{ + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev); + + scsi_generic_purge_requests(s); +} + +static void scsi_destroy(SCSIDevice *d) +{ + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); + + scsi_generic_purge_requests(s); blockdev_mark_auto_del(s->qdev.conf.bs); } @@ -537,6 +553,7 @@ static SCSIDeviceInfo scsi_generic_info = { .qdev.name = "scsi-generic", .qdev.desc = "pass through generic scsi device (/dev/sg*)", .qdev.size = sizeof(SCSIGenericState), + .qdev.reset = scsi_generic_reset, .init = scsi_generic_initfn, .destroy = scsi_destroy, .send_command = scsi_send_command, @@ -31,6 +31,7 @@ #include "hw.h" #include "block.h" +#include "block_int.h" #include "sd.h" //#define DEBUG_SD 1 @@ -440,7 +441,7 @@ SDState *sd_init(BlockDriverState *bs, int is_spi) SDState *sd; sd = (SDState *) qemu_mallocz(sizeof(SDState)); - sd->buf = qemu_memalign(512, 512); + sd->buf = qemu_blockalign(bs, 512); sd->spi = is_spi; sd->enable = 1; sd_reset(sd, bs); diff --git a/hw/sysbus.c b/hw/sysbus.c index 1f7f138..d817721 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -82,7 +82,8 @@ void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target) } } -void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc) +void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, + ram_addr_t iofunc) { int n; diff --git a/hw/sysbus.h b/hw/sysbus.h index 1a8f289..5980901 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -21,7 +21,7 @@ struct SysBusDevice { target_phys_addr_t addr; target_phys_addr_t size; mmio_mapfunc cb; - int iofunc; + ram_addr_t iofunc; } mmio[QDEV_MAX_MMIO]; }; @@ -39,7 +39,8 @@ typedef struct { void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init); void sysbus_register_withprop(SysBusDeviceInfo *info); void *sysbus_new(void); -void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc); +void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, + ram_addr_t iofunc); void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size, mmio_mapfunc cb); void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p); diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c new file mode 100644 index 0000000..c5bbeda --- /dev/null +++ b/hw/virtex_ml507.c @@ -0,0 +1,279 @@ +/* + * Model of Xilinx Virtex5 ML507 PPC-440 refdesign. + * + * Copyright (c) 2010 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "hw.h" +#include "pc.h" +#include "net.h" +#include "flash.h" +#include "sysemu.h" +#include "devices.h" +#include "boards.h" +#include "device_tree.h" +#include "loader.h" +#include "elf.h" +#include "qemu-log.h" + +#include "ppc.h" +#include "ppc4xx.h" +#include "ppc440.h" +#include "ppc405.h" + +#include "blockdev.h" +#include "xilinx.h" + +#define EPAPR_MAGIC (0x45504150) +#define FLASH_SIZE (16 * 1024 * 1024) + +static struct boot_info +{ + uint32_t bootstrap_pc; + uint32_t cmdline; + uint32_t fdt; + uint32_t ima_size; + void *vfdt; +} boot_info; + +/* Create reset TLB entries for BookE, spanning the 32bit addr space. */ +static void mmubooke_create_initial_mapping(CPUState *env, + target_ulong va, + target_phys_addr_t pa) +{ + ppcemb_tlb_t *tlb = &env->tlb[0].tlbe; + + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0x80000000 */ + tlb->EPN = va & TARGET_PAGE_MASK; + tlb->RPN = pa & TARGET_PAGE_MASK; + tlb->PID = 0; + + tlb = &env->tlb[1].tlbe; + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0xffffffff */ + tlb->EPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->RPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->PID = 0; +} + +static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size, + int do_init, + const char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk) +{ + CPUState *env; + qemu_irq *pic; + qemu_irq *irqs; + + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to initialize CPU!\n"); + exit(1); + } + + cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ + cpu_clk->opaque = env; + /* Set time-base frequency to sysclk */ + tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_DECR); + tb_clk->opaque = env; + + ppc_dcr_init(env, NULL, NULL); + + /* interrupt controller */ + irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); + irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; + irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; + pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); + return env; +} + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + struct boot_info *bi = env->load_info; + + cpu_reset(env); + /* Linux Kernel Parameters (passing device tree): + * r3: pointer to the fdt + * r4: 0 + * r5: 0 + * r6: epapr magic + * r7: size of IMA in bytes + * r8: 0 + * r9: 0 + */ + env->gpr[1] = (16<<20) - 8; + /* Provide a device-tree. */ + env->gpr[3] = bi->fdt; + env->nip = bi->bootstrap_pc; + + /* Create a mapping for the kernel. */ + mmubooke_create_initial_mapping(env, 0, 0); + env->gpr[6] = tswap32(EPAPR_MAGIC); + env->gpr[7] = bi->ima_size; +} + +#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb" +static int xilinx_load_device_tree(target_phys_addr_t addr, + uint32_t ramsize, + target_phys_addr_t initrd_base, + target_phys_addr_t initrd_size, + const char *kernel_cmdline) +{ + char *path; + int fdt_size; +#ifdef CONFIG_FDT + void *fdt; + int r; + + /* Try the local "ppc.dtb" override. */ + fdt = load_device_tree("ppc.dtb", &fdt_size); + if (!fdt) { + path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); + if (path) { + fdt = load_device_tree(path, &fdt_size); + qemu_free(path); + } + if (!fdt) { + return 0; + } + } + + r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); + if (r < 0) + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + cpu_physical_memory_write (addr, (void *)fdt, fdt_size); +#else + /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob + to the kernel. */ + fdt_size = load_image_targphys("ppc.dtb", addr, 0x10000); + if (fdt_size < 0) { + path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); + if (path) { + fdt_size = load_image_targphys(path, addr, 0x10000); + qemu_free(path); + } + } + + if (kernel_cmdline) { + fprintf(stderr, + "Warning: missing libfdt, cannot pass cmdline to kernel!\n"); + } +#endif + return fdt_size; +} + +static void virtex_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + DeviceState *dev; + CPUState *env; + target_phys_addr_t ram_base = 0; + DriveInfo *dinfo; + ram_addr_t phys_ram; + ram_addr_t phys_flash; + qemu_irq irq[32], *cpu_irq; + clk_setup_t clk_setup[7]; + int kernel_size; + int i; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "440-Xilinx"; + } + + memset(clk_setup, 0, sizeof(clk_setup)); + env = ppc440_init_xilinx(&ram_size, 1, cpu_model, &clk_setup[0], + &clk_setup[1], 400000000); + qemu_register_reset(main_cpu_reset, env); + + phys_ram = qemu_ram_alloc(NULL, "ram", ram_size); + cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM); + + phys_flash = qemu_ram_alloc(NULL, "virtex.flash", FLASH_SIZE); + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi01_register(0xfc000000, phys_flash, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + FLASH_SIZE >> 16, + 1, 0x89, 0x18, 0x0000, 0x0, 1); + + cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT]; + dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(dev, i); + } + + serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0], 1, 0); + + /* 2 timers at irq 2 @ 62 Mhz. */ + xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000); + + if (kernel_filename) { + uint64_t entry, low, high; + uint32_t base32; + target_phys_addr_t boot_offset; + + /* Boots a kernel elf binary. */ + kernel_size = load_elf(kernel_filename, NULL, NULL, + &entry, &low, &high, 1, ELF_MACHINE, 0); + base32 = entry; + boot_info.bootstrap_pc = entry & 0x00ffffff; + + if (kernel_size < 0) { + boot_offset = 0x1200000; + /* If we failed loading ELF's try a raw image. */ + kernel_size = load_image_targphys(kernel_filename, + boot_offset, + ram_size); + boot_info.bootstrap_pc = boot_offset; + high = boot_info.bootstrap_pc + kernel_size + 8192; + } + + boot_info.ima_size = kernel_size; + + /* Provide a device-tree. */ + boot_info.fdt = high + (8192 * 2); + boot_info.fdt &= ~8191; + xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline); + } + env->load_info = &boot_info; +} + +static QEMUMachine virtex_machine = { + .name = "virtex-ml507", + .desc = "Xilinx Virtex ML507 reference design", + .init = virtex_init, +}; + +static void virtex_machine_init(void) +{ + qemu_register_machine(&virtex_machine); +} + +machine_init(virtex_machine_init); diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c index 32fa3bc..3b2d49c 100644 --- a/hw/virtio-9p.c +++ b/hw/virtio-9p.c @@ -333,7 +333,8 @@ static int number_to_string(void *arg, char type) return ret; } -static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap) +static int GCC_FMT_ATTR(2, 0) +v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap) { va_list ap2; char *iter = (char *)fmt; @@ -387,7 +388,8 @@ alloc_print: return vsprintf(*strp, fmt, ap); } -static void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...) +static void GCC_FMT_ATTR(2, 3) +v9fs_string_sprintf(V9fsString *str, const char *fmt, ...) { va_list ap; int err; @@ -1034,8 +1036,8 @@ static int stat_to_v9stat(V9fsState *s, V9fsString *name, S_ISCHR(stbuf->st_mode) ? 'c' : 'b', major(stbuf->st_rdev), minor(stbuf->st_rdev)); } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) { - v9fs_string_sprintf(&v9stat->extension, "%s %u", - "HARDLINKCOUNT", stbuf->st_nlink); + v9fs_string_sprintf(&v9stat->extension, "%s %lu", + "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink); } str = strrchr(name->data, '/'); diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 9fe3886..8adddea 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -29,6 +29,10 @@ #include <sys/mman.h> #endif +/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */ +#define ENABLE_GUEST_STATS 0 + + typedef struct VirtIOBalloon { VirtIODevice vdev; @@ -51,8 +55,8 @@ static void balloon_page(void *addr, int deflate) { #if defined(__linux__) if (!kvm_enabled() || kvm_has_sync_mmu()) - madvise(addr, TARGET_PAGE_SIZE, - deflate ? MADV_WILLNEED : MADV_DONTNEED); + qemu_madvise(addr, TARGET_PAGE_SIZE, + deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED); #endif } @@ -83,12 +87,14 @@ static QObject *get_stats_qobject(VirtIOBalloon *dev) VIRTIO_BALLOON_PFN_SHIFT); stat_put(dict, "actual", actual); +#if ENABLE_GUEST_STATS stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]); stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]); stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]); stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]); stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]); stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]); +#endif return QOBJECT(dict); } @@ -214,7 +220,7 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target, } dev->stats_callback = cb; dev->stats_opaque_callback_data = cb_data; - if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) { + if (ENABLE_GUEST_STATS && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) { virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset); virtio_notify(&dev->vdev, dev->svq); } else { diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index bd6bbe6..a1df26d 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -540,6 +540,7 @@ 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_removable(s->bs, 0); + s->bs->buffer_alignment = conf->logical_block_size; return &s->vdev; } diff --git a/hw/xen_backend.h b/hw/xen_backend.h index 292126d..1b428e3 100644 --- a/hw/xen_backend.h +++ b/hw/xen_backend.h @@ -84,7 +84,7 @@ int xen_be_bind_evtchn(struct XenDevice *xendev); void xen_be_unbind_evtchn(struct XenDevice *xendev); int xen_be_send_notify(struct XenDevice *xendev); void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); + GCC_FMT_ATTR(3, 4); /* actual backend drivers */ extern struct XenDevOps xen_console_ops; /* xen_console.c */ diff --git a/json-parser.c b/json-parser.c index 70b9b6f..6c06ef9 100644 --- a/json-parser.c +++ b/json-parser.c @@ -91,7 +91,8 @@ static int token_is_escape(QObject *obj, const char *value) /** * Error handler */ -static void parse_error(JSONParserContext *ctxt, QObject *token, const char *msg, ...) +static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt, + QObject *token, const char *msg, ...) { va_list ap; va_start(ap, msg); @@ -1031,18 +1031,14 @@ int kvm_has_xcrs(void) void kvm_setup_guest_memory(void *start, size_t size) { if (!kvm_has_sync_mmu()) { -#ifdef MADV_DONTFORK - int ret = madvise(start, size, MADV_DONTFORK); + int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK); if (ret) { - perror("madvice"); + perror("qemu_madvise"); + fprintf(stderr, + "Need MADV_DONTFORK in absence of synchronous KVM MMU\n"); exit(1); } -#else - fprintf(stderr, - "Need MADV_DONTFORK in absence of synchronous KVM MMU\n"); - exit(1); -#endif } } diff --git a/linux-user/m68k-sim.c b/linux-user/m68k-sim.c index 64d3b23..d5926ee 100644 --- a/linux-user/m68k-sim.c +++ b/linux-user/m68k-sim.c @@ -38,7 +38,7 @@ #define SYS_ISATTY 29 #define SYS_LSEEK 199 -struct m86k_sim_stat { +struct m68k_sim_stat { uint16_t sim_st_dev; uint16_t sim_st_ino; uint32_t sim_st_mode; @@ -138,10 +138,10 @@ void do_m68k_simcall(CPUM68KState *env, int nr) { struct stat s; int rc; - struct m86k_sim_stat *p; + struct m68k_sim_stat *p; rc = check_err(env, fstat(ARG(0), &s)); if (rc == 0) { - p = (struct m86k_sim_stat *)(unsigned long)ARG(1); + p = (struct m68k_sim_stat *)(unsigned long)ARG(1); p->sim_st_dev = tswap16(s.st_dev); p->sim_st_ino = tswap16(s.st_ino); p->sim_st_mode = tswap32(s.st_mode); diff --git a/linux-user/main.c b/linux-user/main.c index 69d050f..dbba8be 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2790,6 +2790,12 @@ int main(int argc, char **argv, char **envp) r = argv[optind++]; if (envlist_setenv(envlist, r) != 0) usage(); + } else if (!strcmp(r, "ignore-environment")) { + envlist_free(envlist); + if ((envlist = envlist_create()) == NULL) { + (void) fprintf(stderr, "Unable to allocate envlist\n"); + exit(1); + } } else if (!strcmp(r, "U")) { r = argv[optind++]; if (envlist_unsetenv(envlist, r) != 0) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 794fe49..708021e 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -186,7 +186,7 @@ void syscall_init(void); abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6); -void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); +void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2); extern THREAD CPUState *thread_env; void cpu_loop(CPUState *env); char *target_strerror(int err); @@ -189,6 +189,9 @@ static QLIST_HEAD(mon_list, Monitor) mon_list; static const mon_cmd_t mon_cmds[]; static const mon_cmd_t info_cmds[]; +static const mon_cmd_t qmp_cmds[]; +static const mon_cmd_t qmp_query_cmds[]; + Monitor *cur_mon; Monitor *default_mon; @@ -316,7 +319,8 @@ void monitor_print_filename(Monitor *mon, const char *filename) } } -static int monitor_fprintf(FILE *stream, const char *fmt, ...) +static int GCC_FMT_ATTR(2, 3) monitor_fprintf(FILE *stream, + const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -327,21 +331,16 @@ static int monitor_fprintf(FILE *stream, const char *fmt, ...) static void monitor_user_noop(Monitor *mon, const QObject *data) { } -static inline int monitor_handler_ported(const mon_cmd_t *cmd) +static inline int handler_is_qobject(const mon_cmd_t *cmd) { return cmd->user_print != NULL; } -static inline bool monitor_handler_is_async(const mon_cmd_t *cmd) +static inline bool handler_is_async(const mon_cmd_t *cmd) { return cmd->flags & MONITOR_CMD_ASYNC; } -static inline bool monitor_cmd_user_only(const mon_cmd_t *cmd) -{ - return (cmd->flags & MONITOR_CMD_USER_ONLY); -} - static inline int monitor_has_error(const Monitor *mon) { return mon->error != NULL; @@ -351,7 +350,10 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data) { QString *json; - json = qobject_to_json(data); + if (mon->flags & MONITOR_USE_PRETTY) + json = qobject_to_json_pretty(data); + else + json = qobject_to_json(data); assert(json != NULL); qstring_append_chr(json, '\n'); @@ -633,13 +635,12 @@ static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd) } } -static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data) +static void do_info(Monitor *mon, const QDict *qdict) { const mon_cmd_t *cmd; const char *item = qdict_get_try_str(qdict, "item"); if (!item) { - assert(monitor_ctrl_mode(mon) == 0); goto help; } @@ -649,56 +650,27 @@ static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data) } if (cmd->name == NULL) { - if (monitor_ctrl_mode(mon)) { - qerror_report(QERR_COMMAND_NOT_FOUND, item); - return -1; - } goto help; } - if (monitor_ctrl_mode(mon) && monitor_cmd_user_only(cmd)) { - qerror_report(QERR_COMMAND_NOT_FOUND, item); - return -1; - } + if (handler_is_async(cmd)) { + user_async_info_handler(mon, cmd); + } else if (handler_is_qobject(cmd)) { + QObject *info_data = NULL; - if (monitor_handler_is_async(cmd)) { - if (monitor_ctrl_mode(mon)) { - qmp_async_info_handler(mon, cmd); - } else { - user_async_info_handler(mon, cmd); - } - /* - * Indicate that this command is asynchronous and will not return any - * data (not even empty). Instead, the data will be returned via a - * completion callback. - */ - *ret_data = qobject_from_jsonf("{ '__mon_async': 'return' }"); - } else if (monitor_handler_ported(cmd)) { - cmd->mhandler.info_new(mon, ret_data); - - if (!monitor_ctrl_mode(mon)) { - /* - * User Protocol function is called here, Monitor Protocol is - * handled by monitor_call_handler() - */ - if (*ret_data) - cmd->user_print(mon, *ret_data); + cmd->mhandler.info_new(mon, &info_data); + if (info_data) { + cmd->user_print(mon, info_data); + qobject_decref(info_data); } } else { - if (monitor_ctrl_mode(mon)) { - /* handler not converted yet */ - qerror_report(QERR_COMMAND_NOT_FOUND, item); - return -1; - } else { - cmd->mhandler.info(mon); - } + cmd->mhandler.info(mon); } - return 0; + return; help: help_cmd(mon, "info"); - return 0; } static void do_info_version_print(Monitor *mon, const QObject *data) @@ -772,19 +744,14 @@ static void do_info_commands(Monitor *mon, QObject **ret_data) cmd_list = qlist_new(); - for (cmd = mon_cmds; cmd->name != NULL; cmd++) { - if (monitor_handler_ported(cmd) && !monitor_cmd_user_only(cmd) && - !compare_cmd(cmd->name, "info")) { - qlist_append_obj(cmd_list, get_cmd_dict(cmd->name)); - } + for (cmd = qmp_cmds; cmd->name != NULL; cmd++) { + qlist_append_obj(cmd_list, get_cmd_dict(cmd->name)); } - for (cmd = info_cmds; cmd->name != NULL; cmd++) { - if (monitor_handler_ported(cmd) && !monitor_cmd_user_only(cmd)) { - char buf[128]; - snprintf(buf, sizeof(buf), "query-%s", cmd->name); - qlist_append_obj(cmd_list, get_cmd_dict(buf)); - } + for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) { + char buf[128]; + snprintf(buf, sizeof(buf), "query-%s", cmd->name); + qlist_append_obj(cmd_list, get_cmd_dict(buf)); } *ret_data = QOBJECT(cmd_list); @@ -2366,11 +2333,11 @@ int monitor_get_fd(Monitor *mon, const char *fdname) } static const mon_cmd_t mon_cmds[] = { -#include "qemu-monitor.h" +#include "hmp-commands.h" { NULL, NULL, }, }; -/* Please update qemu-monitor.hx when adding or changing commands */ +/* Please update hmp-commands.hx when adding or changing commands */ static const mon_cmd_t info_cmds[] = { { .name = "version", @@ -2381,14 +2348,6 @@ static const mon_cmd_t info_cmds[] = { .mhandler.info_new = do_info_version, }, { - .name = "commands", - .args_type = "", - .params = "", - .help = "list QMP available commands", - .user_print = monitor_user_noop, - .mhandler.info_new = do_info_commands, - }, - { .name = "network", .args_type = "", .params = "", @@ -2662,6 +2621,136 @@ static const mon_cmd_t info_cmds[] = { }, }; +static const mon_cmd_t qmp_cmds[] = { +#include "qmp-commands.h" + { /* NULL */ }, +}; + +static const mon_cmd_t qmp_query_cmds[] = { + { + .name = "version", + .args_type = "", + .params = "", + .help = "show the version of QEMU", + .user_print = do_info_version_print, + .mhandler.info_new = do_info_version, + }, + { + .name = "commands", + .args_type = "", + .params = "", + .help = "list QMP available commands", + .user_print = monitor_user_noop, + .mhandler.info_new = do_info_commands, + }, + { + .name = "chardev", + .args_type = "", + .params = "", + .help = "show the character devices", + .user_print = qemu_chr_info_print, + .mhandler.info_new = qemu_chr_info, + }, + { + .name = "block", + .args_type = "", + .params = "", + .help = "show the block devices", + .user_print = bdrv_info_print, + .mhandler.info_new = bdrv_info, + }, + { + .name = "blockstats", + .args_type = "", + .params = "", + .help = "show block device statistics", + .user_print = bdrv_stats_print, + .mhandler.info_new = bdrv_info_stats, + }, + { + .name = "cpus", + .args_type = "", + .params = "", + .help = "show infos for each CPU", + .user_print = monitor_print_cpus, + .mhandler.info_new = do_info_cpus, + }, + { + .name = "pci", + .args_type = "", + .params = "", + .help = "show PCI info", + .user_print = do_pci_info_print, + .mhandler.info_new = do_pci_info, + }, + { + .name = "kvm", + .args_type = "", + .params = "", + .help = "show KVM information", + .user_print = do_info_kvm_print, + .mhandler.info_new = do_info_kvm, + }, + { + .name = "status", + .args_type = "", + .params = "", + .help = "show the current VM status (running|paused)", + .user_print = do_info_status_print, + .mhandler.info_new = do_info_status, + }, + { + .name = "mice", + .args_type = "", + .params = "", + .help = "show which guest mouse is receiving events", + .user_print = do_info_mice_print, + .mhandler.info_new = do_info_mice, + }, + { + .name = "vnc", + .args_type = "", + .params = "", + .help = "show the vnc server status", + .user_print = do_info_vnc_print, + .mhandler.info_new = do_info_vnc, + }, + { + .name = "name", + .args_type = "", + .params = "", + .help = "show the current VM name", + .user_print = do_info_name_print, + .mhandler.info_new = do_info_name, + }, + { + .name = "uuid", + .args_type = "", + .params = "", + .help = "show the current VM UUID", + .user_print = do_info_uuid_print, + .mhandler.info_new = do_info_uuid, + }, + { + .name = "migrate", + .args_type = "", + .params = "", + .help = "show migration status", + .user_print = do_info_migrate_print, + .mhandler.info_new = do_info_migrate, + }, + { + .name = "balloon", + .args_type = "", + .params = "", + .help = "show balloon information", + .user_print = monitor_print_balloon, + .mhandler.info_async = do_info_balloon, + .flags = MONITOR_CMD_ASYNC, + }, + { /* NULL */ }, +}; + /*******************************************************************/ static const char *pch; @@ -3368,11 +3457,12 @@ static int is_valid_option(const char *c, const char *typestr) return (typestr != NULL); } -static const mon_cmd_t *monitor_find_command(const char *cmdname) +static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table, + const char *cmdname) { const mon_cmd_t *cmd; - for (cmd = mon_cmds; cmd->name != NULL; cmd++) { + for (cmd = disp_table; cmd->name != NULL; cmd++) { if (compare_cmd(cmdname, cmd->name)) { return cmd; } @@ -3381,6 +3471,21 @@ static const mon_cmd_t *monitor_find_command(const char *cmdname) return NULL; } +static const mon_cmd_t *monitor_find_command(const char *cmdname) +{ + return search_dispatch_table(mon_cmds, cmdname); +} + +static const mon_cmd_t *qmp_find_query_cmd(const char *info_item) +{ + return search_dispatch_table(qmp_query_cmds, info_item); +} + +static const mon_cmd_t *qmp_find_cmd(const char *cmdname) +{ + return search_dispatch_table(qmp_cmds, cmdname); +} + static const mon_cmd_t *monitor_parse_command(Monitor *mon, const char *cmdline, QDict *qdict) @@ -3729,15 +3834,6 @@ void monitor_set_error(Monitor *mon, QError *qerror) } } -static int is_async_return(const QObject *data) -{ - if (data && qobject_type(data) == QTYPE_QDICT) { - return qdict_haskey(qobject_to_qdict(data), "__mon_async"); - } - - return 0; -} - static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret) { if (monitor_ctrl_mode(mon)) { @@ -3785,37 +3881,6 @@ static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret) } } -static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd, - const QDict *params) -{ - int ret; - QObject *data = NULL; - - mon_print_count_init(mon); - - ret = cmd->mhandler.cmd_new(mon, params, &data); - handler_audit(mon, cmd, ret); - - if (is_async_return(data)) { - /* - * Asynchronous commands have no initial return data but they can - * generate errors. Data is returned via the async completion handler. - */ - if (monitor_ctrl_mode(mon) && monitor_has_error(mon)) { - monitor_protocol_emitter(mon, NULL); - } - } else if (monitor_ctrl_mode(mon)) { - /* Monitor Protocol */ - monitor_protocol_emitter(mon, data); - } else { - /* User Protocol */ - if (data) - cmd->user_print(mon, data); - } - - qobject_decref(data); -} - static void handle_user_command(Monitor *mon, const char *cmdline) { QDict *qdict; @@ -3827,10 +3892,18 @@ static void handle_user_command(Monitor *mon, const char *cmdline) if (!cmd) goto out; - if (monitor_handler_is_async(cmd)) { + if (handler_is_async(cmd)) { user_async_cmd_handler(mon, cmd, qdict); - } else if (monitor_handler_ported(cmd)) { - monitor_call_handler(mon, cmd, qdict); + } else if (handler_is_qobject(cmd)) { + QObject *data = NULL; + + /* XXX: ignores the error code */ + cmd->mhandler.cmd_new(mon, qdict, &data); + assert(!monitor_has_error(mon)); + if (data) { + cmd->user_print(mon, data); + qobject_decref(data); + } } else { cmd->mhandler.cmd(mon, qdict); } @@ -4320,6 +4393,38 @@ static QDict *qmp_check_input_obj(QObject *input_obj) return input_dict; } +static void qmp_call_query_cmd(Monitor *mon, const mon_cmd_t *cmd) +{ + QObject *ret_data = NULL; + + if (handler_is_async(cmd)) { + qmp_async_info_handler(mon, cmd); + if (monitor_has_error(mon)) { + monitor_protocol_emitter(mon, NULL); + } + } else { + cmd->mhandler.info_new(mon, &ret_data); + if (ret_data) { + monitor_protocol_emitter(mon, ret_data); + qobject_decref(ret_data); + } + } +} + +static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd, + const QDict *params) +{ + int ret; + QObject *data = NULL; + + mon_print_count_init(mon); + + ret = cmd->mhandler.cmd_new(mon, params, &data); + handler_audit(mon, cmd, ret); + monitor_protocol_emitter(mon, data); + qobject_decref(data); +} + static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) { int err; @@ -4327,8 +4432,9 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) QDict *input, *args; const mon_cmd_t *cmd; Monitor *mon = cur_mon; - const char *cmd_name, *info_item; + const char *cmd_name, *query_cmd; + query_cmd = NULL; args = input = NULL; obj = json_parser_parse(tokens, NULL); @@ -4353,24 +4459,15 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) goto err_out; } - /* - * XXX: We need this special case until we get info handlers - * converted into 'query-' commands - */ - if (compare_cmd(cmd_name, "info")) { + if (strstart(cmd_name, "query-", &query_cmd)) { + cmd = qmp_find_query_cmd(query_cmd); + } else { + cmd = qmp_find_cmd(cmd_name); + } + + if (!cmd) { qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_out; - } else if (strstart(cmd_name, "query-", &info_item)) { - cmd = monitor_find_command("info"); - qdict_put_obj(input, "arguments", - qobject_from_jsonf("{ 'item': %s }", info_item)); - } else { - cmd = monitor_find_command(cmd_name); - if (!cmd || !monitor_handler_ported(cmd) - || monitor_cmd_user_only(cmd)) { - qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); - goto err_out; - } } obj = qdict_get(input, "arguments"); @@ -4386,14 +4483,16 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) goto err_out; } - if (monitor_handler_is_async(cmd)) { + if (query_cmd) { + qmp_call_query_cmd(mon, cmd); + } else if (handler_is_async(cmd)) { err = qmp_async_cmd_handler(mon, cmd, args); if (err) { /* emit the error response */ goto err_out; } } else { - monitor_call_handler(mon, cmd, args); + qmp_call_cmd(mon, cmd, args); } goto out; @@ -14,10 +14,10 @@ extern Monitor *default_mon; #define MONITOR_IS_DEFAULT 0x01 #define MONITOR_USE_READLINE 0x02 #define MONITOR_USE_CONTROL 0x04 +#define MONITOR_USE_PRETTY 0x08 /* flags for monitor commands */ #define MONITOR_CMD_ASYNC 0x0001 -#define MONITOR_CMD_USER_ONLY 0x0002 /* QMP events */ typedef enum MonitorEvent { @@ -49,9 +49,9 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, int monitor_get_fd(Monitor *mon, const char *fdname); -void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap); -void monitor_printf(Monitor *mon, const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); +void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) + GCC_FMT_ATTR(2, 0); +void monitor_printf(Monitor *mon, const char *fmt, ...) GCC_FMT_ATTR(2, 3); void monitor_print_filename(Monitor *mon, const char *filename); void monitor_flush(Monitor *mon); @@ -23,7 +23,7 @@ #ifndef _WIN32 #include <sys/ioctl.h> #endif -#ifdef __sun__ +#if defined(__sun__) || defined(__HAIKU__) #include <sys/ioccom.h> #endif #include <ctype.h> @@ -49,6 +49,7 @@ /* This is all part of the "official" NBD API */ +#define NBD_REPLY_SIZE (4 + 4 + 8) #define NBD_REQUEST_MAGIC 0x25609513 #define NBD_REPLY_MAGIC 0x67446698 @@ -588,7 +589,7 @@ static int nbd_receive_request(int csock, struct nbd_request *request) int nbd_receive_reply(int csock, struct nbd_reply *reply) { - uint8_t buf[4 + 4 + 8]; + uint8_t buf[NBD_REPLY_SIZE]; uint32_t magic; memset(buf, 0xAA, sizeof(buf)); @@ -655,9 +656,9 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, if (nbd_receive_request(csock, &request) == -1) return -1; - if (request.len > data_size) { + if (request.len + NBD_REPLY_SIZE > data_size) { LOG("len (%u) is larger than max len (%u)", - request.len, data_size); + request.len + NBD_REPLY_SIZE, data_size); errno = EINVAL; return -1; } @@ -687,7 +688,8 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, case NBD_CMD_READ: TRACE("Request type is READ"); - if (bdrv_read(bs, (request.from + dev_offset) / 512, data, + if (bdrv_read(bs, (request.from + dev_offset) / 512, + data + NBD_REPLY_SIZE, request.len / 512) == -1) { LOG("reading from file failed"); errno = EINVAL; @@ -697,12 +699,21 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, TRACE("Read %u byte(s)", request.len); - if (nbd_send_reply(csock, &reply) == -1) - return -1; + /* Reply + [ 0 .. 3] magic (NBD_REPLY_MAGIC) + [ 4 .. 7] error (0 == no error) + [ 7 .. 15] handle + */ + + cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC); + cpu_to_be32w((uint32_t*)(data + 4), reply.error); + cpu_to_be64w((uint64_t*)(data + 8), reply.handle); TRACE("Sending data to client"); - if (write_sync(csock, data, request.len) != request.len) { + if (write_sync(csock, data, + request.len + NBD_REPLY_SIZE) != + request.len + NBD_REPLY_SIZE) { LOG("writing to socket failed"); errno = EINVAL; return -1; diff --git a/net/tap-bsd.c b/net/tap-bsd.c index 3513075..efccfe0 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -37,10 +37,6 @@ #include <util.h> #endif -#if defined(__OpenBSD__) -#include <util.h> -#endif - int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required) { int fd; diff --git a/net/tap-haiku.c b/net/tap-haiku.c new file mode 100644 index 0000000..91dda8e --- /dev/null +++ b/net/tap-haiku.c @@ -0,0 +1,61 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "net/tap.h" +#include <stdio.h> + +int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required) +{ + fprintf(stderr, "no tap on Haiku\n"); + return -1; +} + +int tap_set_sndbuf(int fd, QemuOpts *opts) +{ + return 0; +} + +int tap_probe_vnet_hdr(int fd) +{ + return 0; +} + +int tap_probe_has_ufo(int fd) +{ + return 0; +} + +int tap_probe_vnet_hdr_len(int fd, int len) +{ + return 0; +} + +void tap_fd_set_vnet_hdr_len(int fd, int len) +{ +} + +void tap_fd_set_offload(int fd, int csum, int tso4, + int tso6, int ecn, int ufo) +{ +} @@ -32,9 +32,16 @@ /* Needed early for CONFIG_BSD etc. */ #include "config-host.h" +#if defined(CONFIG_MADVISE) || defined(CONFIG_POSIX_MADVISE) +#include <sys/mman.h> +#endif + #ifdef CONFIG_SOLARIS #include <sys/types.h> #include <sys/statvfs.h> +/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for + discussion about Solaris header problems */ +extern int madvise(caddr_t, size_t, int); #endif #ifdef CONFIG_EVENTFD @@ -139,6 +146,22 @@ void qemu_vfree(void *ptr) #endif +int qemu_madvise(void *addr, size_t len, int advice) +{ + if (advice == QEMU_MADV_INVALID) { + errno = EINVAL; + return -1; + } +#if defined(CONFIG_MADVISE) + return madvise(addr, len, advice); +#elif defined(CONFIG_POSIX_MADVISE) + return posix_madvise(addr, len, advice); +#else + errno = EINVAL; + return -1; +#endif +} + int qemu_create_pidfile(const char *filename) { char buffer[128]; @@ -90,6 +90,41 @@ void *qemu_memalign(size_t alignment, size_t size); void *qemu_vmalloc(size_t size); void qemu_vfree(void *ptr); +#define QEMU_MADV_INVALID -1 + +#if defined(CONFIG_MADVISE) + +#define QEMU_MADV_WILLNEED MADV_WILLNEED +#define QEMU_MADV_DONTNEED MADV_DONTNEED +#ifdef MADV_DONTFORK +#define QEMU_MADV_DONTFORK MADV_DONTFORK +#else +#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID +#endif +#ifdef MADV_MERGEABLE +#define QEMU_MADV_MERGEABLE MADV_MERGEABLE +#else +#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID +#endif + +#elif defined(CONFIG_POSIX_MADVISE) + +#define QEMU_MADV_WILLNEED POSIX_MADV_WILLNEED +#define QEMU_MADV_DONTNEED POSIX_MADV_DONTNEED +#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID +#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID + +#else /* no-op */ + +#define QEMU_MADV_WILLNEED QEMU_MADV_INVALID +#define QEMU_MADV_DONTNEED QEMU_MADV_INVALID +#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID +#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID + +#endif + +int qemu_madvise(void *addr, size_t len, int advice); + int qemu_create_pidfile(const char *filename); #ifdef _WIN32 diff --git a/posix-aio-compat.c b/posix-aio-compat.c index 10f1f03..7b862b5 100644 --- a/posix-aio-compat.c +++ b/posix-aio-compat.c @@ -128,7 +128,7 @@ static ssize_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb) /* * This looks weird, but the aio code only consideres a request - * successfull if it has written the number full number of bytes. + * successful if it has written the number full number of bytes. * * Now we overload aio_nbytes as aio_ioctl_cmd for the ioctl command, * so in fact we return the ioctl command here to make posix_aio_read() @@ -270,7 +270,7 @@ static ssize_t handle_aiocb_rw(struct qemu_paiocb *aiocb) * Ok, we have to do it the hard way, copy all segments into * a single aligned buffer. */ - buf = qemu_memalign(512, aiocb->aio_nbytes); + buf = qemu_blockalign(aiocb->common.bs, aiocb->aio_nbytes); if (aiocb->aio_type & QEMU_AIO_WRITE) { char *p = buf; int i; diff --git a/qemu-char.h b/qemu-char.h index 6ea01ba..18ad12b 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -76,7 +76,8 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s)); CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s)); void qemu_chr_close(CharDriverState *chr); -void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); +void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) + GCC_FMT_ATTR(2, 3); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); void qemu_chr_send_event(CharDriverState *s, int event); void qemu_chr_add_handlers(CharDriverState *s, diff --git a/qemu-common.h b/qemu-common.h index dfd3dc0..81aafa0 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -70,6 +70,22 @@ struct iovec { #include <sys/uio.h> #endif +#if defined __GNUC__ +# if (__GNUC__ < 4) || \ + defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 4) + /* gcc versions before 4.4.x don't support gnu_printf, so use printf. */ +# define GCC_ATTR __attribute__((__unused__, format(printf, 1, 2))) +# define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m))) +# else + /* Use gnu_printf when supported (qemu uses standard format strings). */ +# define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2))) +# define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m))) +# endif +#else +#define GCC_ATTR /**/ +#define GCC_FMT_ATTR(n, m) +#endif + #ifdef _WIN32 #define fsync _commit #define lseek _lseeki64 @@ -180,8 +196,7 @@ int qemu_pipe(int pipefd[2]); /* Error handling. */ -void QEMU_NORETURN hw_error(const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); +void QEMU_NORETURN hw_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2); /* IO callbacks. */ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); @@ -278,11 +293,14 @@ typedef struct QEMUIOVector { void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint); void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov); void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len); +void qemu_iovec_copy(QEMUIOVector *dst, QEMUIOVector *src, uint64_t skip, + size_t size); void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size); void qemu_iovec_destroy(QEMUIOVector *qiov); void qemu_iovec_reset(QEMUIOVector *qiov); void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf); void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count); +void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count); struct Monitor; typedef struct Monitor Monitor; diff --git a/qemu-config.c b/qemu-config.c index 5c6ae63..32917cb 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -283,6 +283,9 @@ static QemuOptsList qemu_mon_opts = { },{ .name = "default", .type = QEMU_OPT_BOOL, + },{ + .name = "pretty", + .type = QEMU_OPT_BOOL, }, { /* end of list */ } }, diff --git a/qemu-doc.texi b/qemu-doc.texi index d7d760f..c376529 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2186,6 +2186,13 @@ Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) Set the x86 stack size in bytes (default=524288) @item -cpu model Select CPU model (-cpu ? for list and additional feature selection) +@item -ignore-environment +Start with an empty environment. Without this option, +the inital environment is a copy of the caller's environment. +@item -E @var{var}=@var{value} +Set environment @var{var} to @var{value}. +@item -U @var{var} +Remove @var{var} from the environment. @item -B offset Offset guest address by the specified number of bytes. This is useful when the address region required by guest applications is reserved on the host. @@ -2409,6 +2416,13 @@ Print the help Set the library root path (default=/) @item -s size Set the stack size in bytes (default=524288) +@item -ignore-environment +Start with an empty environment. Without this option, +the inital environment is a copy of the caller's environment. +@item -E @var{var}=@var{value} +Set environment @var{var} to @var{value}. +@item -U @var{var} +Remove @var{var} from the environment. @item -bsd type Set the type of the emulated BSD Operating system. Valid values are FreeBSD, NetBSD and OpenBSD (default). diff --git a/qemu-error.h b/qemu-error.h index a45609f..4d5c537 100644 --- a/qemu-error.h +++ b/qemu-error.h @@ -30,12 +30,11 @@ void loc_set_none(void); void loc_set_cmdline(char **argv, int idx, int cnt); void loc_set_file(const char *fname, int lno); -void error_vprintf(const char *fmt, va_list ap); -void error_printf(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); -void error_printf_unless_qmp(const char *fmt, ...) - __attribute__ ((format(printf, 1, 2))); +void error_vprintf(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0); +void error_printf(const char *fmt, ...) GCC_FMT_ATTR(1, 2); +void error_printf_unless_qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2); void error_print_loc(void); void error_set_progname(const char *argv0); -void error_report(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); +void error_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2); #endif @@ -39,7 +39,7 @@ typedef struct img_cmd_t { /* Default to cache=writeback as data integrity is not important for qemu-tcg. */ #define BDRV_O_FLAGS BDRV_O_CACHE_WB -static void error(const char *fmt, ...) +static void GCC_FMT_ATTR(1, 2) error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -61,7 +61,7 @@ static void *qemu_io_alloc(size_t len, int pattern) if (misalign) len += MISALIGN_OFFSET; - buf = qemu_memalign(512, len); + buf = qemu_blockalign(bs, len); memset(buf, pattern, len); if (misalign) buf += MISALIGN_OFFSET; @@ -44,7 +44,7 @@ static void usage(const char *name) "Usage: %s [OPTIONS] FILE\n" "QEMU Disk Network Block Device Server\n" "\n" -" -p, --port=PORT port to listen on (default `1024')\n" +" -p, --port=PORT port to listen on (default `%d')\n" " -o, --offset=OFFSET offset into the image\n" " -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n" " -k, --socket=PATH path to the unix socket\n" @@ -62,7 +62,7 @@ static void usage(const char *name) " -V, --version output version information and exit\n" "\n" "Report bugs to <anthony@codemonkey.ws>\n" - , name, "DEVICE"); + , name, NBD_DEFAULT_PORT, "DEVICE"); } static void version(const char *name) @@ -188,7 +188,7 @@ int main(int argc, char **argv) bool readonly = false; bool disconnect = false; const char *bindto = "0.0.0.0"; - int port = 1024; + int port = NBD_DEFAULT_PORT; struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); off_t fd_size; @@ -446,7 +446,7 @@ int main(int argc, char **argv) max_fd = sharing_fds[0]; nb_fds++; - data = qemu_memalign(512, NBD_BUFFER_SIZE); + data = qemu_blockalign(bs, NBD_BUFFER_SIZE); if (data == NULL) errx(EXIT_FAILURE, "Cannot allocate data buffer"); diff --git a/qemu_socket.h b/qemu_socket.h index 164ae3e..897a8ae 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -17,6 +17,7 @@ int inet_aton(const char *cp, struct in_addr *ia); #else +#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> @@ -218,7 +218,8 @@ QError *qerror_new(void) return qerr; } -static void qerror_abort(const QError *qerr, const char *fmt, ...) +static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr, + const char *fmt, ...) { va_list ap; @@ -233,7 +234,8 @@ static void qerror_abort(const QError *qerr, const char *fmt, ...) abort(); } -static void qerror_set_data(QError *qerr, const char *fmt, va_list *va) +static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr, + const char *fmt, va_list *va) { QObject *obj; @@ -34,12 +34,11 @@ typedef struct QError { QError *qerror_new(void); QError *qerror_from_info(const char *file, int linenr, const char *func, - const char *fmt, va_list *va); + const char *fmt, va_list *va) GCC_FMT_ATTR(4, 0); QString *qerror_human(const QError *qerror); void qerror_print(QError *qerror); void qerror_report_internal(const char *file, int linenr, const char *func, - const char *fmt, ...) - __attribute__ ((format(printf, 4, 5))); + const char *fmt, ...) GCC_FMT_ATTR(4, 5); #define qerror_report(fmt, ...) \ qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__) QError *qobject_to_qerror(const QObject *obj); @@ -72,43 +72,57 @@ QObject *qobject_from_jsonf(const char *string, ...) typedef struct ToJsonIterState { + int indent; + int pretty; int count; QString *str; } ToJsonIterState; -static void to_json(const QObject *obj, QString *str); +static void to_json(const QObject *obj, QString *str, int pretty, int indent); static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) { ToJsonIterState *s = opaque; QString *qkey; + int j; - if (s->count) { + if (s->count) qstring_append(s->str, ", "); + + if (s->pretty) { + qstring_append(s->str, "\n"); + for (j = 0 ; j < s->indent ; j++) + qstring_append(s->str, " "); } qkey = qstring_from_str(key); - to_json(QOBJECT(qkey), s->str); + to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); QDECREF(qkey); qstring_append(s->str, ": "); - to_json(obj, s->str); + to_json(obj, s->str, s->pretty, s->indent); s->count++; } static void to_json_list_iter(QObject *obj, void *opaque) { ToJsonIterState *s = opaque; + int j; - if (s->count) { + if (s->count) qstring_append(s->str, ", "); + + if (s->pretty) { + qstring_append(s->str, "\n"); + for (j = 0 ; j < s->indent ; j++) + qstring_append(s->str, " "); } - to_json(obj, s->str); + to_json(obj, s->str, s->pretty, s->indent); s->count++; } -static void to_json(const QObject *obj, QString *str) +static void to_json(const QObject *obj, QString *str, int pretty, int indent) { switch (qobject_type(obj)) { case QTYPE_QINT: { @@ -193,8 +207,16 @@ static void to_json(const QObject *obj, QString *str) s.count = 0; s.str = str; + s.indent = indent + 1; + s.pretty = pretty; qstring_append(str, "{"); qdict_iter(val, to_json_dict_iter, &s); + if (pretty) { + int j; + qstring_append(str, "\n"); + for (j = 0 ; j < indent ; j++) + qstring_append(str, " "); + } qstring_append(str, "}"); break; } @@ -204,8 +226,16 @@ static void to_json(const QObject *obj, QString *str) s.count = 0; s.str = str; + s.indent = indent + 1; + s.pretty = pretty; qstring_append(str, "["); qlist_iter(val, (void *)to_json_list_iter, &s); + if (pretty) { + int j; + qstring_append(str, "\n"); + for (j = 0 ; j < indent ; j++) + qstring_append(str, " "); + } qstring_append(str, "]"); break; } @@ -249,7 +279,16 @@ QString *qobject_to_json(const QObject *obj) { QString *str = qstring_new(); - to_json(obj, str); + to_json(obj, str, 0, 0); + + return str; +} + +QString *qobject_to_json_pretty(const QObject *obj) +{ + QString *str = qstring_new(); + + to_json(obj, str, 1, 0); return str; } @@ -18,11 +18,11 @@ #include "qobject.h" #include "qstring.h" -QObject *qobject_from_json(const char *string); -QObject *qobject_from_jsonf(const char *string, ...) - __attribute__((__format__ (__printf__, 1, 2))); -QObject *qobject_from_jsonv(const char *string, va_list *ap); +QObject *qobject_from_json(const char *string) GCC_FMT_ATTR(1, 0); +QObject *qobject_from_jsonf(const char *string, ...) GCC_FMT_ATTR(1, 2); +QObject *qobject_from_jsonv(const char *string, va_list *ap) GCC_FMT_ATTR(1, 0); QString *qobject_to_json(const QObject *obj); +QString *qobject_to_json_pretty(const QObject *obj); #endif /* QJSON_H */ diff --git a/qemu-monitor.hx b/qmp-commands.hx index 49bcd8d..793cf1c 100644 --- a/qemu-monitor.hx +++ b/qmp-commands.hx @@ -1,11 +1,6 @@ -HXCOMM Use DEFHEADING() to define headings in both help text and texi -HXCOMM Text between STEXI and ETEXI are copied to texi version and -HXCOMM discarded from C version +HXCOMM QMP dispatch table and documentation HXCOMM Text between SQMP and EQMP is copied to the QMP documention file and HXCOMM does not show up in the other formats. -HXCOMM DEF(command, args, callback, arg_string, help) is used to construct -HXCOMM monitor commands -HXCOMM HXCOMM can be used for comments, discarded from both texi and C SQMP QMP Supported Commands @@ -65,40 +60,8 @@ refer to the QMP specification for more details on error responses. EQMP -STEXI -@table @option -ETEXI - - { - .name = "help|?", - .args_type = "name:s?", - .params = "[cmd]", - .help = "show the help", - .mhandler.cmd = do_help_cmd, - }, - -STEXI -@item help or ? [@var{cmd}] -@findex help -Show the help for all commands or just for command @var{cmd}. -ETEXI - - { - .name = "commit", - .args_type = "device:B", - .params = "device|all", - .help = "commit changes to the disk images (if -snapshot is used) or backing files", - .mhandler.cmd = do_commit, - }, - -STEXI -@item commit -@findex commit -Commit changes to the disk images (if -snapshot is used) or backing files. -ETEXI - { - .name = "q|quit", + .name = "quit", .args_type = "", .params = "", .help = "quit the emulator", @@ -106,11 +69,6 @@ ETEXI .mhandler.cmd_new = do_quit, }, -STEXI -@item q or quit -@findex quit -Quit the emulator. -ETEXI SQMP quit ---- @@ -135,11 +93,6 @@ EQMP .mhandler.cmd_new = do_eject, }, -STEXI -@item eject [-f] @var{device} -@findex eject -Eject a removable medium (use -f to force it). -ETEXI SQMP eject ----- @@ -169,43 +122,6 @@ EQMP .mhandler.cmd_new = do_change, }, -STEXI -@item change @var{device} @var{setting} -@findex change - -Change the configuration of a device. - -@table @option -@item change @var{diskdevice} @var{filename} [@var{format}] -Change the medium for a removable disk device to point to @var{filename}. eg - -@example -(qemu) change ide1-cd0 /path/to/some.iso -@end example - -@var{format} is optional. - -@item change vnc @var{display},@var{options} -Change the configuration of the VNC server. The valid syntax for @var{display} -and @var{options} are described at @ref{sec_invocation}. eg - -@example -(qemu) change vnc localhost:1 -@end example - -@item change vnc password [@var{password}] - -Change the password associated with the VNC server. If the new password is not -supplied, the monitor will prompt for it to be entered. VNC passwords are only -significant up to 8 letters. eg - -@example -(qemu) change vnc password -Password: ******** -@end example - -@end table -ETEXI SQMP change ------ @@ -245,11 +161,6 @@ EQMP .mhandler.cmd_new = do_screen_dump, }, -STEXI -@item screendump @var{filename} -@findex screendump -Save screen into PPM image @var{filename}. -ETEXI SQMP screendump ---------- @@ -268,125 +179,6 @@ Example: EQMP { - .name = "logfile", - .args_type = "filename:F", - .params = "filename", - .help = "output logs to 'filename'", - .mhandler.cmd = do_logfile, - }, - -STEXI -@item logfile @var{filename} -@findex logfile -Output logs to @var{filename}. -ETEXI - -#ifdef CONFIG_SIMPLE_TRACE - { - .name = "trace-event", - .args_type = "name:s,option:b", - .params = "name on|off", - .help = "changes status of a specific trace event", - .mhandler.cmd = do_change_trace_event_state, - }, - -STEXI -@item trace-event -@findex trace-event -changes status of a trace event -ETEXI - - { - .name = "trace-file", - .args_type = "op:s?,arg:F?", - .params = "on|off|flush|set [arg]", - .help = "open, close, or flush trace file, or set a new file name", - .mhandler.cmd = do_trace_file, - }, - -STEXI -@item trace-file on|off|flush -@findex trace-file -Open, close, or flush the trace file. If no argument is given, the status of the trace file is displayed. -ETEXI -#endif - - { - .name = "log", - .args_type = "items:s", - .params = "item1[,...]", - .help = "activate logging of the specified items to '/tmp/qemu.log'", - .mhandler.cmd = do_log, - }, - -STEXI -@item log @var{item1}[,...] -@findex log -Activate logging of the specified items to @file{/tmp/qemu.log}. -ETEXI - - { - .name = "savevm", - .args_type = "name:s?", - .params = "[tag|id]", - .help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created", - .mhandler.cmd = do_savevm, - }, - -STEXI -@item savevm [@var{tag}|@var{id}] -@findex savevm -Create a snapshot of the whole virtual machine. If @var{tag} is -provided, it is used as human readable identifier. If there is already -a snapshot with the same tag or ID, it is replaced. More info at -@ref{vm_snapshots}. -ETEXI - - { - .name = "loadvm", - .args_type = "name:s", - .params = "tag|id", - .help = "restore a VM snapshot from its tag or id", - .mhandler.cmd = do_loadvm, - }, - -STEXI -@item loadvm @var{tag}|@var{id} -@findex loadvm -Set the whole virtual machine to the snapshot identified by the tag -@var{tag} or the unique snapshot ID @var{id}. -ETEXI - - { - .name = "delvm", - .args_type = "name:s", - .params = "tag|id", - .help = "delete a VM snapshot from its tag or id", - .mhandler.cmd = do_delvm, - }, - -STEXI -@item delvm @var{tag}|@var{id} -@findex delvm -Delete the snapshot identified by @var{tag} or @var{id}. -ETEXI - - { - .name = "singlestep", - .args_type = "option:s?", - .params = "[on|off]", - .help = "run emulation in singlestep mode or switch to normal mode", - .mhandler.cmd = do_singlestep, - }, - -STEXI -@item singlestep [off] -@findex singlestep -Run the emulation in single step mode. -If called with option off, the emulation returns to normal mode. -ETEXI - - { .name = "stop", .args_type = "", .params = "", @@ -395,11 +187,6 @@ ETEXI .mhandler.cmd_new = do_stop, }, -STEXI -@item stop -@findex stop -Stop emulation. -ETEXI SQMP stop ---- @@ -416,7 +203,7 @@ Example: EQMP { - .name = "c|cont", + .name = "cont", .args_type = "", .params = "", .help = "resume emulation", @@ -424,11 +211,6 @@ EQMP .mhandler.cmd_new = do_cont, }, -STEXI -@item c or cont -@findex cont -Resume emulation. -ETEXI SQMP cont ---- @@ -445,164 +227,6 @@ Example: EQMP { - .name = "gdbserver", - .args_type = "device:s?", - .params = "[device]", - .help = "start gdbserver on given device (default 'tcp::1234'), stop with 'none'", - .mhandler.cmd = do_gdbserver, - }, - -STEXI -@item gdbserver [@var{port}] -@findex gdbserver -Start gdbserver session (default @var{port}=1234) -ETEXI - - { - .name = "x", - .args_type = "fmt:/,addr:l", - .params = "/fmt addr", - .help = "virtual memory dump starting at 'addr'", - .mhandler.cmd = do_memory_dump, - }, - -STEXI -@item x/fmt @var{addr} -@findex x -Virtual memory dump starting at @var{addr}. -ETEXI - - { - .name = "xp", - .args_type = "fmt:/,addr:l", - .params = "/fmt addr", - .help = "physical memory dump starting at 'addr'", - .mhandler.cmd = do_physical_memory_dump, - }, - -STEXI -@item xp /@var{fmt} @var{addr} -@findex xp -Physical memory dump starting at @var{addr}. - -@var{fmt} is a format which tells the command how to format the -data. Its syntax is: @option{/@{count@}@{format@}@{size@}} - -@table @var -@item count -is the number of items to be dumped. - -@item format -can be x (hex), d (signed decimal), u (unsigned decimal), o (octal), -c (char) or i (asm instruction). - -@item size -can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits). On x86, -@code{h} or @code{w} can be specified with the @code{i} format to -respectively select 16 or 32 bit code instruction size. - -@end table - -Examples: -@itemize -@item -Dump 10 instructions at the current instruction pointer: -@example -(qemu) x/10i $eip -0x90107063: ret -0x90107064: sti -0x90107065: lea 0x0(%esi,1),%esi -0x90107069: lea 0x0(%edi,1),%edi -0x90107070: ret -0x90107071: jmp 0x90107080 -0x90107073: nop -0x90107074: nop -0x90107075: nop -0x90107076: nop -@end example - -@item -Dump 80 16 bit values at the start of the video memory. -@smallexample -(qemu) xp/80hx 0xb8000 -0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42 -0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41 -0x000b8020: 0x0b42 0x0b69 0x0b6f 0x0b73 0x0b20 0x0b63 0x0b75 0x0b72 -0x000b8030: 0x0b72 0x0b65 0x0b6e 0x0b74 0x0b2d 0x0b63 0x0b76 0x0b73 -0x000b8040: 0x0b20 0x0b30 0x0b35 0x0b20 0x0b4e 0x0b6f 0x0b76 0x0b20 -0x000b8050: 0x0b32 0x0b30 0x0b30 0x0b33 0x0720 0x0720 0x0720 0x0720 -0x000b8060: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 -0x000b8070: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 -0x000b8080: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 -0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 -@end smallexample -@end itemize -ETEXI - - { - .name = "p|print", - .args_type = "fmt:/,val:l", - .params = "/fmt expr", - .help = "print expression value (use $reg for CPU register access)", - .mhandler.cmd = do_print, - }, - -STEXI -@item p or print/@var{fmt} @var{expr} -@findex print - -Print expression value. Only the @var{format} part of @var{fmt} is -used. -ETEXI - - { - .name = "i", - .args_type = "fmt:/,addr:i,index:i.", - .params = "/fmt addr", - .help = "I/O port read", - .mhandler.cmd = do_ioport_read, - }, - -STEXI -Read I/O port. -ETEXI - - { - .name = "o", - .args_type = "fmt:/,addr:i,val:i", - .params = "/fmt addr value", - .help = "I/O port write", - .mhandler.cmd = do_ioport_write, - }, - -STEXI -Write to I/O port. -ETEXI - - { - .name = "sendkey", - .args_type = "string:s,hold_time:i?", - .params = "keys [hold_ms]", - .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", - .mhandler.cmd = do_sendkey, - }, - -STEXI -@item sendkey @var{keys} -@findex sendkey - -Send @var{keys} to the emulator. @var{keys} could be the name of the -key or @code{#} followed by the raw value in either decimal or hexadecimal -format. Use @code{-} to press several keys simultaneously. Example: -@example -sendkey ctrl-alt-f1 -@end example - -This command is useful to send keys that your graphical user interface -intercepts at low level, such as @code{ctrl-alt-f1} in X Window. -ETEXI - - { .name = "system_reset", .args_type = "", .params = "", @@ -611,12 +235,6 @@ ETEXI .mhandler.cmd_new = do_system_reset, }, -STEXI -@item system_reset -@findex system_reset - -Reset the system. -ETEXI SQMP system_reset ------------ @@ -641,12 +259,6 @@ EQMP .mhandler.cmd_new = do_system_powerdown, }, -STEXI -@item system_powerdown -@findex system_powerdown - -Power down the system (if supported). -ETEXI SQMP system_powerdown ---------------- @@ -663,54 +275,6 @@ Example: EQMP { - .name = "sum", - .args_type = "start:i,size:i", - .params = "addr size", - .help = "compute the checksum of a memory region", - .mhandler.cmd = do_sum, - }, - -STEXI -@item sum @var{addr} @var{size} -@findex sum - -Compute the checksum of a memory region. -ETEXI - - { - .name = "usb_add", - .args_type = "devname:s", - .params = "device", - .help = "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')", - .mhandler.cmd = do_usb_add, - }, - -STEXI -@item usb_add @var{devname} -@findex usb_add - -Add the USB device @var{devname}. For details of available devices see -@ref{usb_devices} -ETEXI - - { - .name = "usb_del", - .args_type = "devname:s", - .params = "device", - .help = "remove USB device 'bus.addr'", - .mhandler.cmd = do_usb_del, - }, - -STEXI -@item usb_del @var{devname} -@findex usb_del - -Remove the USB device @var{devname} from the QEMU virtual USB -hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor -command @code{info usb} to see the devices you can remove. -ETEXI - - { .name = "device_add", .args_type = "device:O", .params = "driver[,prop=value][,...]", @@ -719,12 +283,6 @@ ETEXI .mhandler.cmd_new = do_device_add, }, -STEXI -@item device_add @var{config} -@findex device_add - -Add device. -ETEXI SQMP device_add ---------- @@ -762,12 +320,6 @@ EQMP .mhandler.cmd_new = do_device_del, }, -STEXI -@item device_del @var{id} -@findex device_del - -Remove device @var{id}. -ETEXI SQMP device_del ---------- @@ -794,11 +346,6 @@ EQMP .mhandler.cmd_new = do_cpu_set, }, -STEXI -@item cpu @var{index} -@findex cpu -Set the default CPU. -ETEXI SQMP cpu --- @@ -819,94 +366,6 @@ Note: CPUs' indexes are obtained with the 'query-cpus' command. EQMP { - .name = "mouse_move", - .args_type = "dx_str:s,dy_str:s,dz_str:s?", - .params = "dx dy [dz]", - .help = "send mouse move events", - .mhandler.cmd = do_mouse_move, - }, - -STEXI -@item mouse_move @var{dx} @var{dy} [@var{dz}] -@findex mouse_move -Move the active mouse to the specified coordinates @var{dx} @var{dy} -with optional scroll axis @var{dz}. -ETEXI - - { - .name = "mouse_button", - .args_type = "button_state:i", - .params = "state", - .help = "change mouse button state (1=L, 2=M, 4=R)", - .mhandler.cmd = do_mouse_button, - }, - -STEXI -@item mouse_button @var{val} -@findex mouse_button -Change the active mouse button state @var{val} (1=L, 2=M, 4=R). -ETEXI - - { - .name = "mouse_set", - .args_type = "index:i", - .params = "index", - .help = "set which mouse device receives events", - .mhandler.cmd = do_mouse_set, - }, - -STEXI -@item mouse_set @var{index} -@findex mouse_set -Set which mouse device receives events at given @var{index}, index -can be obtained with -@example -info mice -@end example -ETEXI - -#ifdef HAS_AUDIO - { - .name = "wavcapture", - .args_type = "path:F,freq:i?,bits:i?,nchannels:i?", - .params = "path [frequency [bits [channels]]]", - .help = "capture audio to a wave file (default frequency=44100 bits=16 channels=2)", - .mhandler.cmd = do_wav_capture, - }, -#endif -STEXI -@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]] -@findex wavcapture -Capture audio into @var{filename}. Using sample rate @var{frequency} -bits per sample @var{bits} and number of channels @var{channels}. - -Defaults: -@itemize @minus -@item Sample rate = 44100 Hz - CD quality -@item Bits = 16 -@item Number of channels = 2 - Stereo -@end itemize -ETEXI - -#ifdef HAS_AUDIO - { - .name = "stopcapture", - .args_type = "n:i", - .params = "capture index", - .help = "stop capture", - .mhandler.cmd = do_stop_capture, - }, -#endif -STEXI -@item stopcapture @var{index} -@findex stopcapture -Stop capture with a given @var{index}, index can be obtained with -@example -info capture -@end example -ETEXI - - { .name = "memsave", .args_type = "val:l,size:i,filename:s", .params = "addr size file", @@ -915,11 +374,6 @@ ETEXI .mhandler.cmd_new = do_memory_save, }, -STEXI -@item memsave @var{addr} @var{size} @var{file} -@findex memsave -save to disk virtual memory dump starting at @var{addr} of size @var{size}. -ETEXI SQMP memsave ------- @@ -953,11 +407,6 @@ EQMP .mhandler.cmd_new = do_physical_memory_save, }, -STEXI -@item pmemsave @var{addr} @var{size} @var{file} -@findex pmemsave -save to disk physical memory dump starting at @var{addr} of size @var{size}. -ETEXI SQMP pmemsave -------- @@ -981,40 +430,6 @@ Example: EQMP { - .name = "boot_set", - .args_type = "bootdevice:s", - .params = "bootdevice", - .help = "define new values for the boot device list", - .mhandler.cmd = do_boot_set, - }, - -STEXI -@item boot_set @var{bootdevicelist} -@findex boot_set - -Define new values for the boot device list. Those values will override -the values specified on the command line through the @code{-boot} option. - -The values that can be specified here depend on the machine type, but are -the same that can be specified in the @code{-boot} command line option. -ETEXI - -#if defined(TARGET_I386) - { - .name = "nmi", - .args_type = "cpu_index:i", - .params = "cpu", - .help = "inject an NMI on the given CPU", - .mhandler.cmd = do_inject_nmi, - }, -#endif -STEXI -@item nmi @var{cpu} -@findex nmi -Inject an NMI on the given CPU (x86 only). -ETEXI - - { .name = "migrate", .args_type = "detach:-d,blk:-b,inc:-i,uri:s", .params = "[-d] [-b] [-i] uri", @@ -1027,14 +442,6 @@ ETEXI .mhandler.cmd_new = do_migrate, }, - -STEXI -@item migrate [-d] [-b] [-i] @var{uri} -@findex migrate -Migrate to @var{uri} (using -d to not wait for completion). - -b for migration with full copy of disk - -i for migration with incremental copy of disk (base image is shared) -ETEXI SQMP migrate ------- @@ -1071,11 +478,6 @@ EQMP .mhandler.cmd_new = do_migrate_cancel, }, -STEXI -@item migrate_cancel -@findex migrate_cancel -Cancel the current VM migration. -ETEXI SQMP migrate_cancel -------------- @@ -1100,11 +502,6 @@ EQMP .mhandler.cmd_new = do_migrate_set_speed, }, -STEXI -@item migrate_set_speed @var{value} -@findex migrate_set_speed -Set maximum speed to @var{value} (in bytes) for migrations. -ETEXI SQMP migrate_set_speed ----------------- @@ -1131,11 +528,6 @@ EQMP .mhandler.cmd_new = do_migrate_set_downtime, }, -STEXI -@item migrate_set_downtime @var{second} -@findex migrate_set_downtime -Set maximum tolerated downtime (in seconds) for migration. -ETEXI SQMP migrate_set_downtime -------------------- @@ -1153,86 +545,6 @@ Example: EQMP -#if defined(TARGET_I386) - { - .name = "drive_add", - .args_type = "pci_addr:s,opts:s", - .params = "[[<domain>:]<bus>:]<slot>\n" - "[file=file][,if=type][,bus=n]\n" - "[,unit=m][,media=d][index=i]\n" - "[,cyls=c,heads=h,secs=s[,trans=t]]\n" - "[snapshot=on|off][,cache=on|off]", - .help = "add drive to PCI storage controller", - .mhandler.cmd = drive_hot_add, - }, -#endif - -STEXI -@item drive_add -@findex drive_add -Add drive to PCI storage controller. -ETEXI - -#if defined(TARGET_I386) - { - .name = "pci_add", - .args_type = "pci_addr:s,type:s,opts:s?", - .params = "auto|[[<domain>:]<bus>:]<slot> nic|storage [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...", - .help = "hot-add PCI device", - .mhandler.cmd = pci_device_hot_add, - }, -#endif - -STEXI -@item pci_add -@findex pci_add -Hot-add PCI device. -ETEXI - -#if defined(TARGET_I386) - { - .name = "pci_del", - .args_type = "pci_addr:s", - .params = "[[<domain>:]<bus>:]<slot>", - .help = "hot remove PCI device", - .mhandler.cmd = do_pci_device_hot_remove, - }, -#endif - -STEXI -@item pci_del -@findex pci_del -Hot remove PCI device. -ETEXI - - { - .name = "host_net_add", - .args_type = "device:s,opts:s?", - .params = "tap|user|socket|vde|dump [options]", - .help = "add host VLAN client", - .mhandler.cmd = net_host_device_add, - }, - -STEXI -@item host_net_add -@findex host_net_add -Add host VLAN client. -ETEXI - - { - .name = "host_net_remove", - .args_type = "vlan_id:i,device:s", - .params = "vlan_id name", - .help = "remove host VLAN client", - .mhandler.cmd = net_host_device_remove, - }, - -STEXI -@item host_net_remove -@findex host_net_remove -Remove host VLAN client. -ETEXI - { .name = "netdev_add", .args_type = "netdev:O", @@ -1242,11 +554,6 @@ ETEXI .mhandler.cmd_new = do_netdev_add, }, -STEXI -@item netdev_add -@findex netdev_add -Add host network device. -ETEXI SQMP netdev_add ---------- @@ -1279,11 +586,6 @@ EQMP .mhandler.cmd_new = do_netdev_del, }, -STEXI -@item netdev_del -@findex netdev_del -Remove host network device. -ETEXI SQMP netdev_del ---------- @@ -1301,37 +603,6 @@ Example: EQMP -#ifdef CONFIG_SLIRP - { - .name = "hostfwd_add", - .args_type = "arg1:s,arg2:s?,arg3:s?", - .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport", - .help = "redirect TCP or UDP connections from host to guest (requires -net user)", - .mhandler.cmd = net_slirp_hostfwd_add, - }, -#endif -STEXI -@item hostfwd_add -@findex hostfwd_add -Redirect TCP or UDP connections from host to guest (requires -net user). -ETEXI - -#ifdef CONFIG_SLIRP - { - .name = "hostfwd_remove", - .args_type = "arg1:s,arg2:s?,arg3:s?", - .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport", - .help = "remove host-to-guest TCP or UDP redirection", - .mhandler.cmd = net_slirp_hostfwd_remove, - }, - -#endif -STEXI -@item hostfwd_remove -@findex hostfwd_remove -Remove host-to-guest TCP or UDP redirection. -ETEXI - { .name = "balloon", .args_type = "value:M", @@ -1342,11 +613,6 @@ ETEXI .flags = MONITOR_CMD_ASYNC, }, -STEXI -@item balloon @var{value} -@findex balloon -Request VM to change its memory allocation to @var{value} (in MB). -ETEXI SQMP balloon ------- @@ -1373,11 +639,6 @@ EQMP .mhandler.cmd_new = do_set_link, }, -STEXI -@item set_link @var{name} [on|off] -@findex set_link -Switch link @var{name} on (i.e. up) or off (i.e. down). -ETEXI SQMP set_link -------- @@ -1397,118 +658,6 @@ Example: EQMP { - .name = "watchdog_action", - .args_type = "action:s", - .params = "[reset|shutdown|poweroff|pause|debug|none]", - .help = "change watchdog action", - .mhandler.cmd = do_watchdog_action, - }, - -STEXI -@item watchdog_action -@findex watchdog_action -Change watchdog action. -ETEXI - - { - .name = "acl_show", - .args_type = "aclname:s", - .params = "aclname", - .help = "list rules in the access control list", - .mhandler.cmd = do_acl_show, - }, - -STEXI -@item acl_show @var{aclname} -@findex acl_show -List all the matching rules in the access control list, and the default -policy. There are currently two named access control lists, -@var{vnc.x509dname} and @var{vnc.username} matching on the x509 client -certificate distinguished name, and SASL username respectively. -ETEXI - - { - .name = "acl_policy", - .args_type = "aclname:s,policy:s", - .params = "aclname allow|deny", - .help = "set default access control list policy", - .mhandler.cmd = do_acl_policy, - }, - -STEXI -@item acl_policy @var{aclname} @code{allow|deny} -@findex acl_policy -Set the default access control list policy, used in the event that -none of the explicit rules match. The default policy at startup is -always @code{deny}. -ETEXI - - { - .name = "acl_add", - .args_type = "aclname:s,match:s,policy:s,index:i?", - .params = "aclname match allow|deny [index]", - .help = "add a match rule to the access control list", - .mhandler.cmd = do_acl_add, - }, - -STEXI -@item acl_add @var{aclname} @var{match} @code{allow|deny} [@var{index}] -@findex acl_add -Add a match rule to the access control list, allowing or denying access. -The match will normally be an exact username or x509 distinguished name, -but can optionally include wildcard globs. eg @code{*@@EXAMPLE.COM} to -allow all users in the @code{EXAMPLE.COM} kerberos realm. The match will -normally be appended to the end of the ACL, but can be inserted -earlier in the list if the optional @var{index} parameter is supplied. -ETEXI - - { - .name = "acl_remove", - .args_type = "aclname:s,match:s", - .params = "aclname match", - .help = "remove a match rule from the access control list", - .mhandler.cmd = do_acl_remove, - }, - -STEXI -@item acl_remove @var{aclname} @var{match} -@findex acl_remove -Remove the specified match rule from the access control list. -ETEXI - - { - .name = "acl_reset", - .args_type = "aclname:s", - .params = "aclname", - .help = "reset the access control list", - .mhandler.cmd = do_acl_reset, - }, - -STEXI -@item acl_reset @var{aclname} -@findex acl_reset -Remove all matches from the access control list, and set the default -policy back to @code{deny}. -ETEXI - -#if defined(TARGET_I386) - - { - .name = "mce", - .args_type = "cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l", - .params = "cpu bank status mcgstatus addr misc", - .help = "inject a MCE on the given CPU", - .mhandler.cmd = do_inject_mce, - }, - -#endif -STEXI -@item mce @var{cpu} @var{bank} @var{status} @var{mcgstatus} @var{addr} @var{misc} -@findex mce (x86) -Inject an MCE on the given CPU (x86 only). -ETEXI - - { .name = "getfd", .args_type = "fdname:s", .params = "getfd name", @@ -1517,13 +666,6 @@ ETEXI .mhandler.cmd_new = do_getfd, }, -STEXI -@item getfd @var{fdname} -@findex getfd -If a file descriptor is passed alongside this command using the SCM_RIGHTS -mechanism on unix sockets, it is stored using the name @var{fdname} for -later use by other monitor commands. -ETEXI SQMP getfd ----- @@ -1550,13 +692,6 @@ EQMP .mhandler.cmd_new = do_closefd, }, -STEXI -@item closefd @var{fdname} -@findex closefd -Close the file descriptor previously assigned to @var{fdname} using the -@code{getfd} command. This is only needed if the file descriptor was never -used by another monitor command. -ETEXI SQMP closefd ------- @@ -1583,11 +718,6 @@ EQMP .mhandler.cmd_new = do_block_set_passwd, }, -STEXI -@item block_passwd @var{device} @var{password} -@findex block_passwd -Set the encrypted device @var{device} password to @var{password} -ETEXI SQMP block_passwd ------------ @@ -1616,11 +746,6 @@ EQMP .mhandler.cmd_new = do_qmp_capabilities, }, -STEXI -@item qmp_capabilities -@findex qmp_capabilities -Enable the specified QMP capabilities -ETEXI SQMP qmp_capabilities ---------------- @@ -1636,37 +761,15 @@ Example: Note: This command must be issued before issuing any other command. -EQMP - - -HXCOMM Keep the 'info' command at the end! -HXCOMM This is required for the QMP documentation layout. - -SQMP - 3. Query Commands ================= -EQMP +HXCOMM Each query command below is inside a SQMP/EQMP section, do NOT change +HXCOMM this! We will possibly move query commands definitions inside those +HXCOMM sections, just like regular commands. - { - .name = "info", - .args_type = "item:s?", - .params = "[subcommand]", - .help = "show various information about the system state", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_info, - }, - -STEXI -@item info @var{subcommand} -@findex info -Show various information about the system state. +EQMP -@table @option -@item info version -show the version of QEMU -ETEXI SQMP query-version ------------- @@ -1697,10 +800,6 @@ Example: EQMP -STEXI -@item info commands -list QMP available commands -ETEXI SQMP query-commands -------------- @@ -1732,15 +831,6 @@ Note: This example has been shortened as the real response is too long. EQMP -STEXI -@item info network -show the various VLANs and the associated devices -ETEXI - -STEXI -@item info chardev -show the character devices -ETEXI SQMP query-chardev ------------- @@ -1771,10 +861,6 @@ Example: EQMP -STEXI -@item info block -show the block devices -ETEXI SQMP query-block ----------- @@ -1844,10 +930,6 @@ Example: EQMP -STEXI -@item info blockstats -show block device statistics -ETEXI SQMP query-blockstats ---------------- @@ -1931,12 +1013,6 @@ Example: EQMP -STEXI -@item info registers -show the cpu registers -@item info cpus -show infos for each CPU -ETEXI SQMP query-cpus ---------- @@ -1976,19 +1052,6 @@ Example: EQMP -STEXI -@item info history -show the command line history -@item info irq -show the interrupts statistics (if available) -@item info pic -show i8259 (PIC) state -ETEXI - -STEXI -@item info pci -show emulated PCI device info -ETEXI SQMP query-pci --------- @@ -2200,26 +1263,6 @@ Note: This example has been shortened as the real response is too long. EQMP -STEXI -@item info tlb -show virtual to physical memory mappings (i386 only) -@item info mem -show the active virtual memory mappings (i386 only) -ETEXI - -STEXI -@item info jit -show dynamic compiler info -@item info kvm -show KVM information -@item info numa -show NUMA information -ETEXI - -STEXI -@item info kvm -show KVM information -ETEXI SQMP query-kvm --------- @@ -2238,23 +1281,6 @@ Example: EQMP -STEXI -@item info usb -show USB devices plugged on the virtual USB hub -@item info usbhost -show all USB host devices -@item info profile -show profiling information -@item info capture -show information about active capturing -@item info snapshots -show list of VM snapshots -ETEXI - -STEXI -@item info status -show the current VM status (running|paused) -ETEXI SQMP query-status ------------ @@ -2272,15 +1298,6 @@ Example: EQMP -STEXI -@item info pcmcia -show guest PCMCIA status -ETEXI - -STEXI -@item info mice -show which guest mouse is receiving events -ETEXI SQMP query-mice ---------- @@ -2319,10 +1336,6 @@ Example: EQMP -STEXI -@item info vnc -show the vnc server status -ETEXI SQMP query-vnc --------- @@ -2380,10 +1393,6 @@ Example: EQMP -STEXI -@item info name -show the current VM name -ETEXI SQMP query-name ---------- @@ -2401,10 +1410,6 @@ Example: EQMP -STEXI -@item info uuid -show the current VM UUID -ETEXI SQMP query-uuid ---------- @@ -2422,17 +1427,6 @@ Example: EQMP -STEXI -@item info cpustats -show CPU statistics -@item info usernet -show user network stack connection states -ETEXI - -STEXI -@item info migrate -show migration status -ETEXI SQMP query-migrate ------------- @@ -2510,10 +1504,6 @@ Examples: EQMP -STEXI -@item info balloon -show balloon information -ETEXI SQMP query-balloon ------------- @@ -2549,27 +1539,3 @@ Example: EQMP -STEXI -@item info qtree -show device tree -@item info qdm -show qdev device model list -@item info roms -show roms -@end table -ETEXI - -#ifdef CONFIG_SIMPLE_TRACE -STEXI -@item info trace -show contents of trace buffer -@item info trace-events -show available trace events and their state -ETEXI -#endif - -HXCOMM DO NOT add new commands after 'info', move your addition before it! - -STEXI -@end table -ETEXI diff --git a/slirp/slirp.h b/slirp/slirp.h index 3a5d592..462292d 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -24,7 +24,9 @@ typedef char *caddr_t; #else # define ioctlsocket ioctl # define closesocket(s) close(s) -# define O_BINARY 0 +# if !defined(__HAIKU__) +# define O_BINARY 0 +# endif #endif #include <sys/types.h> @@ -261,7 +263,7 @@ void if_start(struct ttys *); long gethostid(void); #endif -void lprint(const char *, ...); +void lprint(const char *, ...) GCC_FMT_ATTR(1, 2); #ifndef _WIN32 #include <netdb.h> diff --git a/target-cris/translate.c b/target-cris/translate.c index 45c7682..8361369 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3409,7 +3409,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { log_target_disas(pc_start, dc->pc - pc_start, dc->env->pregs[PR_VR]); - qemu_log("\nisize=%d osize=%zd\n", + qemu_log("\nisize=%d osize=%td\n", dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); } #endif diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 6c305d4..38149bb 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1516,7 +1516,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, #if DISAS_GNU log_target_disas(pc_start, dc->pc - pc_start, 0); #endif - qemu_log("\nisize=%d osize=%zd\n", + qemu_log("\nisize=%d osize=%td\n", dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); } #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 9c8d774..bf81941 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -453,6 +453,9 @@ struct ppc_slb_t { #endif #endif +/* Exception state register bits definition */ +#define ESR_ST 23 /* Exception was caused by a store type access. */ + enum { POWERPC_FLAG_NONE = 0x00000000, /* Flag for MSR bit 25 signification (VRE/SPE) */ @@ -699,6 +702,10 @@ struct CPUPPCState { /* temporary hack to handle OSI calls (only used if non NULL) */ int (*osi_call)(struct CPUPPCState *env); + +#if !defined(CONFIG_USER_ONLY) + void *load_info; /* Holds boot loading state. */ +#endif }; #if !defined(CONFIG_USER_ONLY) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index f865d7a..edbdd80 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1172,9 +1172,7 @@ static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, case 0x1: check_perms: /* Check from TLB entry */ - /* XXX: there is a problem here or in the TLB fill code... */ ctx->prot = tlb->prot; - ctx->prot |= PAGE_EXEC; ret = check_prot(ctx->prot, rw, access_type); if (ret == -2) env->spr[SPR_40x_ESR] = 0; @@ -1325,8 +1323,15 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, #endif if ((access_type == ACCESS_CODE && msr_ir == 0) || (access_type != ACCESS_CODE && msr_dr == 0)) { - /* No address translation */ - ret = check_physical(env, ctx, eaddr, rw); + if (env->mmu_model == POWERPC_MMU_BOOKE) { + /* The BookE MMU always performs address translation. The + IS and DS bits only affect the address space. */ + ret = mmubooke_get_physical_address(env, ctx, eaddr, + rw, access_type); + } else { + /* No address translation. */ + ret = check_physical(env, ctx, eaddr, rw); + } } else { ret = -1; switch (env->mmu_model) { @@ -1444,8 +1449,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->error_code = 0x40000000; break; case POWERPC_MMU_BOOKE: - /* XXX: TODO */ - cpu_abort(env, "BookE MMU model is not implemented\n"); + env->exception_index = POWERPC_EXCP_ITLB; + env->error_code = 0; + env->spr[SPR_BOOKE_DEAR] = address; return -1; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ @@ -1471,6 +1477,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, break; case -3: /* No execute protection violation */ + if (env->mmu_model == POWERPC_MMU_BOOKE) { + env->spr[SPR_BOOKE_ESR] = 0x00000000; + } env->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x10000000; break; @@ -1556,8 +1565,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, cpu_abort(env, "MPC8xx MMU model is not implemented\n"); break; case POWERPC_MMU_BOOKE: - /* XXX: TODO */ - cpu_abort(env, "BookE MMU model is not implemented\n"); + env->exception_index = POWERPC_EXCP_DTLB; + env->error_code = 0; + env->spr[SPR_BOOKE_DEAR] = address; + env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0; return -1; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ @@ -1582,6 +1593,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, if (rw) { env->spr[SPR_40x_ESR] |= 0x00800000; } + } else if (env->mmu_model == POWERPC_MMU_BOOKE) { + env->spr[SPR_BOOKE_DEAR] = address; + env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0; } else { env->spr[SPR_DAR] = address; if (rw == 1) { @@ -1848,8 +1862,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) cpu_abort(env, "MPC8xx MMU model is not implemented\n"); break; case POWERPC_MMU_BOOKE: - /* XXX: TODO */ - cpu_abort(env, "BookE MMU model is not implemented\n"); + tlb_flush(env, 1); break; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ @@ -2607,6 +2620,13 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp) /* Reset exception state */ env->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; + + if (env->mmu_model == POWERPC_MMU_BOOKE) { + /* XXX: The BookE changes address space when switching modes, + we should probably implement that as different MMU indexes, + but for the moment we do it the slow way and flush all. */ + tlb_flush(env, 1); + } } void do_interrupt (CPUState *env) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 3e6db85..45f1655 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -3929,37 +3929,56 @@ static inline int booke_page_size_to_tlb(target_ulong page_size) } /* Helpers for 4xx TLB management */ -target_ulong helper_4xx_tlbre_lo (target_ulong entry) +#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */ + +#define PPC4XX_TLBHI_V 0x00000040 +#define PPC4XX_TLBHI_E 0x00000020 +#define PPC4XX_TLBHI_SIZE_MIN 0 +#define PPC4XX_TLBHI_SIZE_MAX 7 +#define PPC4XX_TLBHI_SIZE_DEFAULT 1 +#define PPC4XX_TLBHI_SIZE_SHIFT 7 +#define PPC4XX_TLBHI_SIZE_MASK 0x00000007 + +#define PPC4XX_TLBLO_EX 0x00000200 +#define PPC4XX_TLBLO_WR 0x00000100 +#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF +#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00 + +target_ulong helper_4xx_tlbre_hi (target_ulong entry) { ppcemb_tlb_t *tlb; target_ulong ret; int size; - entry &= 0x3F; + entry &= PPC4XX_TLB_ENTRY_MASK; tlb = &env->tlb[entry].tlbe; ret = tlb->EPN; - if (tlb->prot & PAGE_VALID) - ret |= 0x400; + if (tlb->prot & PAGE_VALID) { + ret |= PPC4XX_TLBHI_V; + } size = booke_page_size_to_tlb(tlb->size); - if (size < 0 || size > 0x7) - size = 1; - ret |= size << 7; + if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) { + size = PPC4XX_TLBHI_SIZE_DEFAULT; + } + ret |= size << PPC4XX_TLBHI_SIZE_SHIFT; env->spr[SPR_40x_PID] = tlb->PID; return ret; } -target_ulong helper_4xx_tlbre_hi (target_ulong entry) +target_ulong helper_4xx_tlbre_lo (target_ulong entry) { ppcemb_tlb_t *tlb; target_ulong ret; - entry &= 0x3F; + entry &= PPC4XX_TLB_ENTRY_MASK; tlb = &env->tlb[entry].tlbe; ret = tlb->RPN; - if (tlb->prot & PAGE_EXEC) - ret |= 0x200; - if (tlb->prot & PAGE_WRITE) - ret |= 0x100; + if (tlb->prot & PAGE_EXEC) { + ret |= PPC4XX_TLBLO_EX; + } + if (tlb->prot & PAGE_WRITE) { + ret |= PPC4XX_TLBLO_WR; + } return ret; } @@ -3970,30 +3989,32 @@ void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val) LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry, val); - entry &= 0x3F; + entry &= PPC4XX_TLB_ENTRY_MASK; tlb = &env->tlb[entry].tlbe; /* Invalidate previous TLB (if it's valid) */ if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end " TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { tlb_flush_page(env, page); + } } - tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7); + tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT) + & PPC4XX_TLBHI_SIZE_MASK); /* We cannot handle TLB size < TARGET_PAGE_SIZE. * If this ever occurs, one should use the ppcemb target instead * of the ppc or ppc64 one */ - if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) { + if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) { cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u " "are not supported (%d)\n", tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7)); } tlb->EPN = val & ~(tlb->size - 1); - if (val & 0x40) { + if (val & PPC4XX_TLBHI_V) { tlb->prot |= PAGE_VALID; - if (val & 0x20) { + if (val & PPC4XX_TLBHI_E) { /* XXX: TO BE FIXED */ cpu_abort(env, "Little-endian TLB entries are not supported by now\n"); @@ -4014,8 +4035,9 @@ void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val) end = tlb->EPN + tlb->size; LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end " TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { tlb_flush_page(env, page); + } } } @@ -4025,15 +4047,17 @@ void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val) LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry, val); - entry &= 0x3F; + entry &= PPC4XX_TLB_ENTRY_MASK; tlb = &env->tlb[entry].tlbe; - tlb->attr = val & 0xFF; - tlb->RPN = val & 0xFFFFFC00; + tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK; + tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK; tlb->prot = PAGE_READ; - if (val & 0x200) + if (val & PPC4XX_TLBLO_EX) { tlb->prot |= PAGE_EXEC; - if (val & 0x100) + } + if (val & PPC4XX_TLBLO_WR) { tlb->prot |= PAGE_WRITE; + } LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, (int)entry, tlb->RPN, tlb->EPN, tlb->size, diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2bd8b00..05ffe95 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3596,7 +3596,6 @@ static void init_proc_440x4 (CPUPPCState *env) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) #define check_pow_440x5 check_pow_nocheck -__attribute__ (( unused )) static void init_proc_440x5 (CPUPPCState *env) { /* Time base */ @@ -3656,7 +3655,7 @@ static void init_proc_440x5 (CPUPPCState *env) init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; - /* XXX: TODO: allocate internal IRQ controller */ + ppc40x_irq_init(env); } /* PowerPC 460 (guessed) */ @@ -6536,6 +6535,7 @@ enum { #if 0 CPU_POWERPC_440A4 = xxx, #endif + CPU_POWERPC_440_XILINX = 0x7ff21910, #if 0 CPU_POWERPC_440A5 = xxx, #endif @@ -7464,6 +7464,8 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 440 A4 */ POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4), #endif + /* PowerPC 440 Xilinx 5 */ + POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5), #if defined (TODO) /* PowerPC 440 A5 */ POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5), diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 971bced..af45edd 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -641,7 +641,7 @@ DEFINE_GRADIENT_FILTER_FUNCTION(32) /* * Check if a rectangle is all of the same color. If needSameColor is * set to non-zero, then also check that its color equals to the - * *colorPtr value. The result is 1 if the test is successfull, and in + * *colorPtr value. The result is 1 if the test is successful, and in * that case new color will be stored in *colorPtr. */ diff --git a/version.rc b/version.rc new file mode 100644 index 0000000..82e10ec --- /dev/null +++ b/version.rc @@ -0,0 +1,28 @@ +#include <winver.h> +#include "config-host.h" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION CONFIG_FILEVERSION +PRODUCTVERSION CONFIG_PRODUCTVERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +FILESUBTYPE VFT2_UNKNOWN +{ + BLOCK "StringFileInfo" + { + BLOCK "040904E4" + { + VALUE "CompanyName", "http://www.qemu.org" + VALUE "FileDescription", "QEMU machine emulators and tools" + VALUE "FileVersion", QEMU_VERSION + VALUE "LegalCopyright", "Copyright various authors. Released under the GNU General Public License." + VALUE "LegalTrademarks", "QEMU is a trademark of Fabrice Bellard." + VALUE "ProductName", "QEMU" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 1252 + } +} @@ -80,9 +80,6 @@ #include <net/if.h> #include <syslog.h> #include <stropts.h> -/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for - discussion about Solaris header problems */ -extern int madvise(caddr_t, size_t, int); #endif #endif #endif @@ -1568,6 +1565,9 @@ static int mon_init_func(QemuOpts *opts, void *opaque) exit(1); } + if (qemu_opt_get_bool(opts, "pretty", 0)) + flags |= MONITOR_USE_PRETTY; + if (qemu_opt_get_bool(opts, "default", 0)) flags |= MONITOR_IS_DEFAULT; |