diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | Makefile.objs | 3 | ||||
| -rw-r--r-- | Makefile.target | 9 | ||||
| -rw-r--r-- | QMP/README | 4 | ||||
| -rw-r--r-- | block.c | 4 | ||||
| -rw-r--r-- | bsd-user/main.c | 6 | ||||
| -rwxr-xr-x | configure | 51 | ||||
| -rw-r--r-- | docs/migration.txt | 56 | ||||
| -rw-r--r-- | docs/tracing.txt | 4 | ||||
| -rw-r--r-- | fsdev/qemu-fsdev.c | 9 | ||||
| -rw-r--r-- | hmp-commands.hx | 1216 | ||||
| -rw-r--r-- | hw/acpi.c | 2 | ||||
| -rw-r--r-- | hw/pci.c | 2 | ||||
| -rw-r--r-- | hw/virtio-balloon.c | 8 | ||||
| -rw-r--r-- | linux-user/m68k-sim.c | 6 | ||||
| -rw-r--r-- | linux-user/main.c | 6 | ||||
| -rw-r--r-- | monitor.c | 366 | ||||
| -rw-r--r-- | monitor.h | 2 | ||||
| -rw-r--r-- | os-win32.c | 6 | ||||
| -rw-r--r-- | pflib.c | 213 | ||||
| -rw-r--r-- | pflib.h | 20 | ||||
| -rw-r--r-- | posix-aio-compat.c | 2 | ||||
| -rw-r--r-- | qemu-config.c | 21 | ||||
| -rw-r--r-- | qemu-config.h | 1 | ||||
| -rw-r--r-- | qemu-doc.texi | 14 | ||||
| -rw-r--r-- | qemu-options.hx | 21 | ||||
| -rw-r--r-- | qemu-os-win32.h | 3 | ||||
| -rw-r--r-- | qjson.c | 55 | ||||
| -rw-r--r-- | qjson.h | 1 | ||||
| -rw-r--r-- | qmp-commands.hx (renamed from qemu-monitor.hx) | 1048 | ||||
| -rw-r--r-- | sysemu.h | 1 | ||||
| -rw-r--r-- | target-cris/op_helper.c | 4 | ||||
| -rw-r--r-- | target-ppc/helper.c | 2 | ||||
| -rw-r--r-- | target-ppc/op_helper.c | 74 | ||||
| -rw-r--r-- | trace-events | 6 | ||||
| -rwxr-xr-x | tracetool | 5 | ||||
| -rw-r--r-- | ui/qemu-spice.h | 41 | ||||
| -rw-r--r-- | ui/spice-core.c | 189 | ||||
| -rw-r--r-- | ui/spice-display.c | 412 | ||||
| -rw-r--r-- | ui/spice-display.h | 69 | ||||
| -rw-r--r-- | ui/spice-input.c | 217 | ||||
| -rw-r--r-- | ui/vnc-enc-tight.c | 2 | ||||
| -rw-r--r-- | vl.c | 53 |
44 files changed, 2955 insertions, 1286 deletions
diff --git a/.gitignore b/.gitignore index 72bff98740..a43e4d1d98 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ config-host.* config-target.* trace.h trace.c +*-timestamp *-softmmu *-darwin-user *-linux-user diff --git a/Makefile b/Makefile index 04ce07d7c4..d9971c33f3 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ clean: rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~ rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d rm -f qemu-img-cmds.h - rm -f trace.c trace.h + rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp $(MAKE) -C tests clean for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ @@ -255,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 9c13bb3539..816194a3d6 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -84,11 +84,14 @@ common-obj-y += qemu-char.o savevm.o #aio.o common-obj-y += msmouse.o ps2.o common-obj-y += qdev.o qdev-properties.o common-obj-y += block-migration.o +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 + audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o audio-obj-$(CONFIG_SDL) += sdlaudio.o audio-obj-$(CONFIG_OSS) += ossaudio.o diff --git a/Makefile.target b/Makefile.target index 4b2558a18b..c48cbcc7f3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -309,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) @@ -330,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),) diff --git a/QMP/README b/QMP/README index 948d4453d5..80503f2d7a 100644 --- a/QMP/README +++ b/QMP/README @@ -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/block.c b/block.c index ebbc376b0c..a19374dfcc 100644 --- a/block.c +++ b/block.c @@ -1983,6 +1983,8 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, BlockDriver *drv = bs->drv; BlockDriverAIOCB *ret; + trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque); + if (!drv) return NULL; if (bdrv_check_request(bs, sector_num, nb_sectors)) @@ -2007,6 +2009,8 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, BlockDriver *drv = bs->drv; BlockDriverAIOCB *ret; + trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque); + if (!drv) return NULL; if (bs->read_only) diff --git a/bsd-user/main.c b/bsd-user/main.c index aff9f13b18..6b12f8bba1 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/configure b/configure index e0d34fd29b..d30306195d 100755 --- a/configure +++ b/configure @@ -18,15 +18,18 @@ TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe" # 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() { - $cc $QEMU_CFLAGS -c -o $TMPO $TMPC > /dev/null 2> /dev/null + echo $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log + $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log 2>&1 } compile_prog() { local_cflags="$1" local_ldflags="$2" - $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags > /dev/null 2> /dev/null + echo $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log + $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1 } # check whether a command is available to this shell (may be either an @@ -327,6 +330,7 @@ user_pie="no" zero_malloc="" trace_backend="nop" trace_file="trace" +spice="" # OS specific if check_define __linux__ ; then @@ -639,6 +643,10 @@ for opt do ;; --enable-kvm) kvm="yes" ;; + --disable-spice) spice="no" + ;; + --enable-spice) spice="yes" + ;; --enable-profiler) profiler="yes" ;; --enable-cocoa) @@ -921,6 +929,8 @@ echo " --enable-vhost-net enable vhost-net acceleration support" echo " --trace-backend=B Trace backend nop simple ust" echo " --trace-file=NAME Full PATH,NAME of file to store traces" echo " Default:trace-<pid>" +echo " --disable-spice disable spice" +echo " --enable-spice enable spice" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -1319,6 +1329,7 @@ if test "$vnc_png" != "no" ; then cat > $TMPC <<EOF //#include <stdio.h> #include <png.h> +#include <stddef.h> int main(void) { png_structp png_ptr; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); @@ -1503,6 +1514,7 @@ if test "$brlapi" != "no" ; then brlapi_libs="-lbrlapi" cat > $TMPC << EOF #include <brlapi.h> +#include <stddef.h> int main( void ) { return brlapi__openConnection (NULL, NULL, NULL); } EOF if compile_prog "" "$brlapi_libs" ; then @@ -1737,6 +1749,7 @@ if test "$linux_aio" != "no" ; then cat > $TMPC <<EOF #include <libaio.h> #include <sys/eventfd.h> +#include <stddef.h> int main(void) { io_setup(0, NULL); io_set_eventfd(NULL, 0); eventfd(0, 0); return 0; } EOF if compile_prog "" "-laio" ; then @@ -1878,7 +1891,6 @@ fi utimens=no cat > $TMPC << EOF #define _ATFILE_SOURCE -#define _GNU_SOURCE #include <stddef.h> #include <fcntl.h> @@ -1896,7 +1908,6 @@ fi # check if pipe2 is there pipe2=no cat > $TMPC << EOF -#define _GNU_SOURCE #include <unistd.h> #include <fcntl.h> @@ -1914,7 +1925,6 @@ fi # check if accept4 is there accept4=no cat > $TMPC << EOF -#define _GNU_SOURCE #include <sys/socket.h> #include <stddef.h> @@ -1931,7 +1941,6 @@ fi # check if tee/splice is there. vmsplice was added same time. splice=no cat > $TMPC << EOF -#define _GNU_SOURCE #include <unistd.h> #include <fcntl.h> #include <limits.h> @@ -2075,6 +2084,29 @@ if compile_prog "" ""; then gcc_attribute_warn_unused_result=yes fi +# spice probe +if test "$spice" != "no" ; then + cat > $TMPC << EOF +#include <spice.h> +int main(void) { spice_server_new(); return 0; } +EOF + spice_cflags=$($pkgconfig --cflags spice-protocol spice-server 2>/dev/null) + spice_libs=$($pkgconfig --libs spice-protocol spice-server 2>/dev/null) + if $pkgconfig --atleast-version=0.5.3 spice-server >/dev/null 2>&1 && \ + compile_prog "$spice_cflags" "$spice_libs" ; then + spice="yes" + libs_softmmu="$libs_softmmu $spice_libs" + QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags" + else + if test "$spice" = "yes" ; then + feature_not_found "spice" + fi + spice="no" + fi +fi + +########################################## + ########################################## # check if we have fdatasync @@ -2094,6 +2126,7 @@ madvise=no cat > $TMPC << EOF #include <sys/types.h> #include <sys/mman.h> +#include <stddef.h> int main(void) { return madvise(NULL, 0, MADV_DONTNEED); } EOF if compile_prog "" "" ; then @@ -2106,6 +2139,7 @@ fi posix_madvise=no cat > $TMPC << EOF #include <sys/mman.h> +#include <stddef.h> int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); } EOF if compile_prog "" "" ; then @@ -2285,6 +2319,7 @@ echo "uuid support $uuid" echo "vhost-net support $vhost_net" echo "Trace backend $trace_backend" echo "Trace output file $trace_file-<pid>" +echo "spice support $spice" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -2540,6 +2575,10 @@ 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 +fi + # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "CONFIG_BSD=y" >> $config_host_mak diff --git a/docs/migration.txt b/docs/migration.txt index 69d53837c3..4848c1e52d 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), diff --git a/docs/tracing.txt b/docs/tracing.txt index ae01ff1378..5504850857 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -72,6 +72,10 @@ Trace events should use types as follows: * For everything else, use primitive scalar types (char, int, long) with the appropriate signedness. +Format strings should reflect the types defined in the trace event. Take +special care to use PRId64 and PRIu64 for int64_t and uint64_t types, +respectively. This ensures portability between 32- and 64-bit platforms. + === Hints for adding new trace events === 1. Trace state changes in the code. Interesting points in the code usually diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c index ad69b0ea4e..280b8f57b9 100644 --- a/fsdev/qemu-fsdev.c +++ b/fsdev/qemu-fsdev.c @@ -16,6 +16,7 @@ #include "qemu-queue.h" #include "osdep.h" #include "qemu-common.h" +#include "qemu-config.h" static QTAILQ_HEAD(FsTypeEntry_head, FsTypeListEntry) fstype_entries = QTAILQ_HEAD_INITIALIZER(fstype_entries); @@ -75,3 +76,11 @@ FsTypeEntry *get_fsdev_fsentry(char *id) } return NULL; } + +static void fsdev_register_config(void) +{ + qemu_add_opts(&qemu_fsdev_opts); + qemu_add_opts(&qemu_virtfs_opts); +} +machine_init(fsdev_register_config); + diff --git a/hmp-commands.hx b/hmp-commands.hx new file mode 100644 index 0000000000..81999aa1a9 --- /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 diff --git a/hw/acpi.c b/hw/acpi.c index 069e05fc7a..8071e7beba 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -161,7 +161,7 @@ int acpi_table_add(const char *t) /* off < length is necessary because file size can be changed under our foot */ - while(s.st_size && off < length); { + while(s.st_size && off < length) { int r; r = read(fd, p + off, s.st_size); if (r > 0) { diff --git a/hw/pci.c b/hw/pci.c index 6d0934df9a..1280d4d785 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -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) diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 1e746741ff..8adddeaa53 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; @@ -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/linux-user/m68k-sim.c b/linux-user/m68k-sim.c index 64d3b23d68..d5926eec4b 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 69d050f91b..dbba8befe7 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/monitor.c b/monitor.c index 377ab378c2..fbb678d789 100644 --- a/monitor.c +++ b/monitor.c @@ -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; @@ -328,21 +331,16 @@ static int GCC_FMT_ATTR(2, 3) monitor_fprintf(FILE *stream, 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; @@ -352,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'); @@ -634,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; } @@ -650,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) @@ -773,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); @@ -2367,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", @@ -2382,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 = "", @@ -2663,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; @@ -3369,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; } @@ -3382,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) @@ -3730,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)) { @@ -3786,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; @@ -3828,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); } @@ -4321,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; @@ -4328,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); @@ -4354,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"); @@ -4387,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; diff --git a/monitor.h b/monitor.h index 4a6cf8260a..2d36bba87f 100644 --- a/monitor.h +++ b/monitor.h @@ -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 { diff --git a/os-win32.c b/os-win32.c index dd46bf459d..3c6f50fa94 100644 --- a/os-win32.c +++ b/os-win32.c @@ -221,6 +221,12 @@ char *os_find_datadir(const char *argv0) return NULL; } +void os_set_line_buffering(void) +{ + setbuf(stdout, NULL); + setbuf(stderr, NULL); +} + /* * Parse OS specific command line options. * return 0 if option handled, -1 otherwise diff --git a/pflib.c b/pflib.c new file mode 100644 index 0000000000..1154d0c9a3 --- /dev/null +++ b/pflib.c @@ -0,0 +1,213 @@ +/* + * PixelFormat conversion library. + * + * Author: Gerd Hoffmann <kraxel@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#include "qemu-common.h" +#include "console.h" +#include "pflib.h" + +typedef struct QemuPixel QemuPixel; + +typedef void (*pf_convert)(QemuPfConv *conv, + void *dst, void *src, uint32_t cnt); +typedef void (*pf_convert_from)(PixelFormat *pf, + QemuPixel *dst, void *src, uint32_t cnt); +typedef void (*pf_convert_to)(PixelFormat *pf, + void *dst, QemuPixel *src, uint32_t cnt); + +struct QemuPfConv { + pf_convert convert; + PixelFormat src; + PixelFormat dst; + + /* for copy_generic() */ + pf_convert_from conv_from; + pf_convert_to conv_to; + QemuPixel *conv_buf; + uint32_t conv_cnt; +}; + +struct QemuPixel { + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t alpha; +}; + +/* ----------------------------------------------------------------------- */ +/* PixelFormat -> QemuPixel conversions */ + +static void conv_16_to_pixel(PixelFormat *pf, + QemuPixel *dst, void *src, uint32_t cnt) +{ + uint16_t *src16 = src; + + while (cnt > 0) { + dst->red = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits); + dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits); + dst->blue = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits); + dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits); + dst++, src16++, cnt--; + } +} + +/* assumes pf->{r,g,b,a}bits == 8 */ +static void conv_32_to_pixel_fast(PixelFormat *pf, + QemuPixel *dst, void *src, uint32_t cnt) +{ + uint32_t *src32 = src; + + while (cnt > 0) { + dst->red = (*src32 & pf->rmask) >> pf->rshift; + dst->green = (*src32 & pf->gmask) >> pf->gshift; + dst->blue = (*src32 & pf->bmask) >> pf->bshift; + dst->alpha = (*src32 & pf->amask) >> pf->ashift; + dst++, src32++, cnt--; + } +} + +static void conv_32_to_pixel_generic(PixelFormat *pf, + QemuPixel *dst, void *src, uint32_t cnt) +{ + uint32_t *src32 = src; + + while (cnt > 0) { + if (pf->rbits < 8) { + dst->red = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits); + } else { + dst->red = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8); + } + if (pf->gbits < 8) { + dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits); + } else { + dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8); + } + if (pf->bbits < 8) { + dst->blue = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits); + } else { + dst->blue = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8); + } + if (pf->abits < 8) { + dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits); + } else { + dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8); + } + dst++, src32++, cnt--; + } +} + +/* ----------------------------------------------------------------------- */ +/* QemuPixel -> PixelFormat conversions */ + +static void conv_pixel_to_16(PixelFormat *pf, + void *dst, QemuPixel *src, uint32_t cnt) +{ + uint16_t *dst16 = dst; + + while (cnt > 0) { + *dst16 = ((uint16_t)src->red >> (8 - pf->rbits)) << pf->rshift; + *dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift; + *dst16 |= ((uint16_t)src->blue >> (8 - pf->bbits)) << pf->bshift; + *dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift; + dst16++, src++, cnt--; + } +} + +static void conv_pixel_to_32(PixelFormat *pf, + void *dst, QemuPixel *src, uint32_t cnt) +{ + uint32_t *dst32 = dst; + + while (cnt > 0) { + *dst32 = ((uint32_t)src->red >> (8 - pf->rbits)) << pf->rshift; + *dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift; + *dst32 |= ((uint32_t)src->blue >> (8 - pf->bbits)) << pf->bshift; + *dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift; + dst32++, src++, cnt--; + } +} + +/* ----------------------------------------------------------------------- */ +/* PixelFormat -> PixelFormat conversions */ + +static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) +{ + uint32_t bytes = cnt * conv->src.bytes_per_pixel; + memcpy(dst, src, bytes); +} + +static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) +{ + if (conv->conv_cnt < cnt) { + conv->conv_cnt = cnt; + conv->conv_buf = qemu_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt); + } + conv->conv_from(&conv->src, conv->conv_buf, src, cnt); + conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt); +} + +/* ----------------------------------------------------------------------- */ +/* public interface */ + +QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src) +{ + QemuPfConv *conv = qemu_mallocz(sizeof(QemuPfConv)); + + conv->src = *src; + conv->dst = *dst; + + if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) { + /* formats identical, can simply copy */ + conv->convert = convert_copy; + } else { + /* generic two-step conversion: src -> QemuPixel -> dst */ + switch (conv->src.bytes_per_pixel) { + case 2: + conv->conv_from = conv_16_to_pixel; + break; + case 4: + if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) { + conv->conv_from = conv_32_to_pixel_fast; + } else { + conv->conv_from = conv_32_to_pixel_generic; + } + break; + default: + goto err; + } + switch (conv->dst.bytes_per_pixel) { + case 2: + conv->conv_to = conv_pixel_to_16; + break; + case 4: + conv->conv_to = conv_pixel_to_32; + break; + default: + goto err; + } + conv->convert = convert_generic; + } + return conv; + +err: + qemu_free(conv); + return NULL; +} + +void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) +{ + conv->convert(conv, dst, src, cnt); +} + +void qemu_pf_conv_put(QemuPfConv *conv) +{ + if (conv) { + qemu_free(conv->conv_buf); + qemu_free(conv); + } +} diff --git a/pflib.h b/pflib.h new file mode 100644 index 0000000000..b70c313acf --- /dev/null +++ b/pflib.h @@ -0,0 +1,20 @@ +#ifndef __QEMU_PFLIB_H +#define __QEMU_PFLIB_H + +/* + * PixelFormat conversion library. + * + * Author: Gerd Hoffmann <kraxel@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +typedef struct QemuPfConv QemuPfConv; + +QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src); +void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt); +void qemu_pf_conv_put(QemuPfConv *conv); + +#endif diff --git a/posix-aio-compat.c b/posix-aio-compat.c index 842f1a24aa..7b862b5400 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() diff --git a/qemu-config.c b/qemu-config.c index e3b746cc2b..32917cbda4 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 */ } }, @@ -351,6 +354,24 @@ static QemuOptsList qemu_cpudef_opts = { }, }; +QemuOptsList qemu_spice_opts = { + .name = "spice", + .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), + .desc = { + { + .name = "port", + .type = QEMU_OPT_NUMBER, + },{ + .name = "password", + .type = QEMU_OPT_STRING, + },{ + .name = "disable-ticketing", + .type = QEMU_OPT_BOOL, + }, + { /* end if list */ } + }, +}; + static QemuOptsList *vm_config_groups[32] = { &qemu_drive_opts, &qemu_chardev_opts, diff --git a/qemu-config.h b/qemu-config.h index 533a049276..20d707fa1f 100644 --- a/qemu-config.h +++ b/qemu-config.h @@ -3,6 +3,7 @@ extern QemuOptsList qemu_fsdev_opts; extern QemuOptsList qemu_virtfs_opts; +extern QemuOptsList qemu_spice_opts; QemuOptsList *qemu_find_opts(const char *group); void qemu_add_opts(QemuOptsList *list); diff --git a/qemu-doc.texi b/qemu-doc.texi index d7d760fedd..c3765293d3 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-options.hx b/qemu-options.hx index a0b5ae9bf1..718d47a2a3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -670,6 +670,27 @@ STEXI Enable SDL. ETEXI +DEF("spice", HAS_ARG, QEMU_OPTION_spice, + "-spice <args> enable spice\n", QEMU_ARCH_ALL) +STEXI +@item -spice @var{option}[,@var{option}[,...]] +@findex -spice +Enable the spice remote desktop protocol. Valid options are + +@table @option + +@item port=<nr> +Set the TCP port spice is listening on. + +@item password=<secret> +Set the password you need to authenticate. + +@item disable-ticketing +Allow client connects without authentication. + +@end table +ETEXI + DEF("portrait", 0, QEMU_OPTION_portrait, "-portrait rotate graphical output 90 deg left (only PXA LCD)\n", QEMU_ARCH_ALL) diff --git a/qemu-os-win32.h b/qemu-os-win32.h index 2ff9f45a6c..c63778d2fc 100644 --- a/qemu-os-win32.h +++ b/qemu-os-win32.h @@ -45,8 +45,7 @@ void os_host_main_loop_wait(int *timeout); static inline void os_setup_signal_handling(void) {} static inline void os_daemonize(void) {} static inline void os_setup_post(void) {} -/* Win32 doesn't support line-buffering and requires size >= 2 */ -static inline void os_set_line_buffering(void) {} +void os_set_line_buffering(void); static inline void os_set_proc_name(const char *dummy) {} #if !defined(EPROTONOSUPPORT) diff --git a/qjson.c b/qjson.c index e4ee433760..f9c8e77516 100644 --- a/qjson.c +++ b/qjson.c @@ -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; } diff --git a/qjson.h b/qjson.h index 70d0afba54..65b10ea369 100644 --- a/qjson.h +++ b/qjson.h @@ -23,5 +23,6 @@ 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 49bcd8d324..793cf1c0f9 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/sysemu.h b/sysemu.h index a1f6466ac2..b81a70ec3e 100644 --- a/sysemu.h +++ b/sysemu.h @@ -94,7 +94,6 @@ typedef enum DisplayType DT_DEFAULT, DT_CURSES, DT_SDL, - DT_VNC, DT_NOGRAPHIC, } DisplayType; diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index a60da94f30..be9eb06fd0 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -164,7 +164,9 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) D_LOG("tlb flush vaddr=%x v=%d pc=%x\n", vaddr, tlb_v, env->pc); - tlb_flush_page(env, vaddr); + if (tlb_v) { + tlb_flush_page(env, vaddr); + } } } #endif diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 3bc8a34599..edbdd80945 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; diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 3e6db85f14..45f1655cb6 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/trace-events b/trace-events index f32c83fa26..4300178f15 100644 --- a/trace-events +++ b/trace-events @@ -51,14 +51,16 @@ disable multiwrite_cb(void *mcb, int ret) "mcb %p ret %d" disable bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d" disable bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p" disable bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d" +disable bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" +disable bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" # hw/virtio-blk.c disable virtio_blk_req_complete(void *req, int status) "req %p status %d" disable virtio_blk_rw_complete(void *req, int ret) "req %p ret %d" -disable virtio_blk_handle_write(void *req, unsigned long sector, unsigned long nsectors) "req %p sector %lu nsectors %lu" +disable virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" # posix-aio-compat.c -disable paio_submit(void *acb, void *opaque, unsigned long sector_num, unsigned long nb_sectors, unsigned long type) "acb %p opaque %p sector_num %lu nb_sectors %lu type %lu" +disable paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d" # ioport.c disable cpu_in(unsigned int addr, unsigned int val) "addr %#x value %u" diff --git a/tracetool b/tracetool index 534cc709f4..701085837f 100755 --- a/tracetool +++ b/tracetool @@ -250,7 +250,7 @@ linetoh_ust() argnames=$(get_argnames "$1") cat <<EOF -DECLARE_TRACE(ust_$name, TPPROTO($args), TPARGS($argnames)); +DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames)); #define trace_$name trace_ust_$name EOF } @@ -318,8 +318,7 @@ convert() while read -r str; do # Skip comments and empty lines - str=${str%%#*} - test -z "$str" && continue + test -z "${str%%#*}" && continue # Process the line. The nop backend handles disabled lines. disable=${str%%disable *} diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h new file mode 100644 index 0000000000..063c7dc8c8 --- /dev/null +++ b/ui/qemu-spice.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_SPICE_H +#define QEMU_SPICE_H + +#ifdef CONFIG_SPICE + +#include <spice.h> + +#include "qemu-option.h" +#include "qemu-config.h" + +extern int using_spice; + +void qemu_spice_init(void); +void qemu_spice_input_init(void); +void qemu_spice_display_init(DisplayState *ds); +int qemu_spice_add_interface(SpiceBaseInstance *sin); + +#else /* CONFIG_SPICE */ + +#define using_spice 0 + +#endif /* CONFIG_SPICE */ + +#endif /* QEMU_SPICE_H */ diff --git a/ui/spice-core.c b/ui/spice-core.c new file mode 100644 index 0000000000..8b5e4a8096 --- /dev/null +++ b/ui/spice-core.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <spice.h> +#include <spice-experimental.h> + +#include "qemu-common.h" +#include "qemu-spice.h" +#include "qemu-timer.h" +#include "qemu-queue.h" +#include "monitor.h" + +/* core bits */ + +static SpiceServer *spice_server; +int using_spice = 0; + +struct SpiceTimer { + QEMUTimer *timer; + QTAILQ_ENTRY(SpiceTimer) next; +}; +static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers); + +static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque) +{ + SpiceTimer *timer; + + timer = qemu_mallocz(sizeof(*timer)); + timer->timer = qemu_new_timer(rt_clock, func, opaque); + QTAILQ_INSERT_TAIL(&timers, timer, next); + return timer; +} + +static void timer_start(SpiceTimer *timer, uint32_t ms) +{ + qemu_mod_timer(timer->timer, qemu_get_clock(rt_clock) + ms); +} + +static void timer_cancel(SpiceTimer *timer) +{ + qemu_del_timer(timer->timer); +} + +static void timer_remove(SpiceTimer *timer) +{ + qemu_del_timer(timer->timer); + qemu_free_timer(timer->timer); + QTAILQ_REMOVE(&timers, timer, next); + qemu_free(timer); +} + +struct SpiceWatch { + int fd; + int event_mask; + SpiceWatchFunc func; + void *opaque; + QTAILQ_ENTRY(SpiceWatch) next; +}; +static QTAILQ_HEAD(, SpiceWatch) watches = QTAILQ_HEAD_INITIALIZER(watches); + +static void watch_read(void *opaque) +{ + SpiceWatch *watch = opaque; + watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque); +} + +static void watch_write(void *opaque) +{ + SpiceWatch *watch = opaque; + watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque); +} + +static void watch_update_mask(SpiceWatch *watch, int event_mask) +{ + IOHandler *on_read = NULL; + IOHandler *on_write = NULL; + + watch->event_mask = event_mask; + if (watch->event_mask & SPICE_WATCH_EVENT_READ) { + on_read = watch_read; + } + if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) { + on_read = watch_write; + } + qemu_set_fd_handler(watch->fd, on_read, on_write, watch); +} + +static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque) +{ + SpiceWatch *watch; + + watch = qemu_mallocz(sizeof(*watch)); + watch->fd = fd; + watch->func = func; + watch->opaque = opaque; + QTAILQ_INSERT_TAIL(&watches, watch, next); + + watch_update_mask(watch, event_mask); + return watch; +} + +static void watch_remove(SpiceWatch *watch) +{ + watch_update_mask(watch, 0); + QTAILQ_REMOVE(&watches, watch, next); + qemu_free(watch); +} + +static SpiceCoreInterface core_interface = { + .base.type = SPICE_INTERFACE_CORE, + .base.description = "qemu core services", + .base.major_version = SPICE_INTERFACE_CORE_MAJOR, + .base.minor_version = SPICE_INTERFACE_CORE_MINOR, + + .timer_add = timer_add, + .timer_start = timer_start, + .timer_cancel = timer_cancel, + .timer_remove = timer_remove, + + .watch_add = watch_add, + .watch_update_mask = watch_update_mask, + .watch_remove = watch_remove, +}; + +/* functions for the rest of qemu */ + +void qemu_spice_init(void) +{ + QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); + const char *password; + int port; + + if (!opts) { + return; + } + port = qemu_opt_get_number(opts, "port", 0); + if (!port) { + return; + } + password = qemu_opt_get(opts, "password"); + + spice_server = spice_server_new(); + spice_server_set_port(spice_server, port); + if (password) { + spice_server_set_ticket(spice_server, password, 0, 0, 0); + } + if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) { + spice_server_set_noauth(spice_server); + } + + /* TODO: make configurable via cmdline */ + spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ); + + spice_server_init(spice_server, &core_interface); + using_spice = 1; + + qemu_spice_input_init(); +} + +int qemu_spice_add_interface(SpiceBaseInstance *sin) +{ + return spice_server_add_interface(spice_server, sin); +} + +static void spice_register_config(void) +{ + qemu_add_opts(&qemu_spice_opts); +} +machine_init(spice_register_config); + +static void spice_initialize(void) +{ + qemu_spice_init(); +} +device_init(spice_initialize); diff --git a/ui/spice-display.c b/ui/spice-display.c new file mode 100644 index 0000000000..6702dfd7ea --- /dev/null +++ b/ui/spice-display.c @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <pthread.h> + +#include "qemu-common.h" +#include "qemu-spice.h" +#include "qemu-timer.h" +#include "qemu-queue.h" +#include "monitor.h" +#include "console.h" +#include "sysemu.h" + +#include "spice-display.h" + +static int debug = 0; + +static void __attribute__((format(printf,2,3))) +dprint(int level, const char *fmt, ...) +{ + va_list args; + + if (level <= debug) { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + } +} + +int qemu_spice_rect_is_empty(const QXLRect* r) +{ + return r->top == r->bottom || r->left == r->right; +} + +void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) +{ + if (qemu_spice_rect_is_empty(r)) { + return; + } + + if (qemu_spice_rect_is_empty(dest)) { + *dest = *r; + return; + } + + dest->top = MIN(dest->top, r->top); + dest->left = MIN(dest->left, r->left); + dest->bottom = MAX(dest->bottom, r->bottom); + dest->right = MAX(dest->right, r->right); +} + +/* + * Called from spice server thread context (via interface_get_command). + * We do *not* hold the global qemu mutex here, so extra care is needed + * when calling qemu functions. Qemu interfaces used: + * - pflib (is re-entrant). + * - qemu_malloc (underlying glibc malloc is re-entrant). + */ +SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) +{ + SimpleSpiceUpdate *update; + QXLDrawable *drawable; + QXLImage *image; + QXLCommand *cmd; + uint8_t *src, *dst; + int by, bw, bh; + + if (qemu_spice_rect_is_empty(&ssd->dirty)) { + return NULL; + }; + + pthread_mutex_lock(&ssd->lock); + dprint(2, "%s: lr %d -> %d, tb -> %d -> %d\n", __FUNCTION__, + ssd->dirty.left, ssd->dirty.right, + ssd->dirty.top, ssd->dirty.bottom); + + update = qemu_mallocz(sizeof(*update)); + drawable = &update->drawable; + image = &update->image; + cmd = &update->ext.cmd; + + bw = ssd->dirty.right - ssd->dirty.left; + bh = ssd->dirty.bottom - ssd->dirty.top; + update->bitmap = qemu_malloc(bw * bh * 4); + + drawable->bbox = ssd->dirty; + drawable->clip.type = SPICE_CLIP_TYPE_NONE; + drawable->effect = QXL_EFFECT_OPAQUE; + drawable->release_info.id = (intptr_t)update; + drawable->type = QXL_DRAW_COPY; + drawable->surfaces_dest[0] = -1; + drawable->surfaces_dest[1] = -1; + drawable->surfaces_dest[2] = -1; + + drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; + drawable->u.copy.src_bitmap = (intptr_t)image; + drawable->u.copy.src_area.right = bw; + drawable->u.copy.src_area.bottom = bh; + + QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++); + image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP; + image->bitmap.flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN; + image->bitmap.stride = bw * 4; + image->descriptor.width = image->bitmap.x = bw; + image->descriptor.height = image->bitmap.y = bh; + image->bitmap.data = (intptr_t)(update->bitmap); + image->bitmap.palette = 0; + image->bitmap.format = SPICE_BITMAP_FMT_32BIT; + + if (ssd->conv == NULL) { + PixelFormat dst = qemu_default_pixelformat(32); + ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); + assert(ssd->conv); + } + + src = ds_get_data(ssd->ds) + + ssd->dirty.top * ds_get_linesize(ssd->ds) + + ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds); + dst = update->bitmap; + for (by = 0; by < bh; by++) { + qemu_pf_conv_run(ssd->conv, dst, src, bw); + src += ds_get_linesize(ssd->ds); + dst += image->bitmap.stride; + } + + cmd->type = QXL_CMD_DRAW; + cmd->data = (intptr_t)drawable; + + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + pthread_mutex_unlock(&ssd->lock); + return update; +} + +/* + * Called from spice server thread context (via interface_release_ressource) + * We do *not* hold the global qemu mutex here, so extra care is needed + * when calling qemu functions. Qemu interfaces used: + * - qemu_free (underlying glibc free is re-entrant). + */ +void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update) +{ + qemu_free(update->bitmap); + qemu_free(update); +} + +void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) +{ + QXLDevMemSlot memslot; + + dprint(1, "%s:\n", __FUNCTION__); + + memset(&memslot, 0, sizeof(memslot)); + memslot.slot_group_id = MEMSLOT_GROUP_HOST; + memslot.virt_end = ~0; + ssd->worker->add_memslot(ssd->worker, &memslot); +} + +void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) +{ + QXLDevSurfaceCreate surface; + + dprint(1, "%s: %dx%d\n", __FUNCTION__, + ds_get_width(ssd->ds), ds_get_height(ssd->ds)); + + surface.format = SPICE_SURFACE_FMT_32_xRGB; + surface.width = ds_get_width(ssd->ds); + surface.height = ds_get_height(ssd->ds); + surface.stride = -surface.width * 4; + surface.mouse_mode = true; + surface.flags = 0; + surface.type = 0; + surface.mem = (intptr_t)ssd->buf; + surface.group_id = MEMSLOT_GROUP_HOST; + ssd->worker->create_primary_surface(ssd->worker, 0, &surface); +} + +void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) +{ + dprint(1, "%s:\n", __FUNCTION__); + + ssd->worker->destroy_primary_surface(ssd->worker, 0); +} + +void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) +{ + SimpleSpiceDisplay *ssd = opaque; + + if (running) { + ssd->worker->start(ssd->worker); + } else { + ssd->worker->stop(ssd->worker); + } + ssd->running = running; +} + +/* display listener callbacks */ + +void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + int x, int y, int w, int h) +{ + QXLRect update_area; + + dprint(2, "%s: x %d y %d w %d h %d\n", __FUNCTION__, x, y, w, h); + update_area.left = x, + update_area.right = x + w; + update_area.top = y; + update_area.bottom = y + h; + + pthread_mutex_lock(&ssd->lock); + if (qemu_spice_rect_is_empty(&ssd->dirty)) { + ssd->notify++; + } + qemu_spice_rect_union(&ssd->dirty, &update_area); + pthread_mutex_unlock(&ssd->lock); +} + +void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) +{ + dprint(1, "%s:\n", __FUNCTION__); + + pthread_mutex_lock(&ssd->lock); + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + qemu_pf_conv_put(ssd->conv); + ssd->conv = NULL; + pthread_mutex_unlock(&ssd->lock); + + qemu_spice_destroy_host_primary(ssd); + qemu_spice_create_host_primary(ssd); + + pthread_mutex_lock(&ssd->lock); + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + ssd->notify++; + pthread_mutex_unlock(&ssd->lock); +} + +void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) +{ + dprint(3, "%s:\n", __FUNCTION__); + vga_hw_update(); + if (ssd->notify) { + ssd->notify = 0; + ssd->worker->wakeup(ssd->worker); + dprint(2, "%s: notify\n", __FUNCTION__); + } +} + +/* spice display interface callbacks */ + +static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) +{ + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + + dprint(1, "%s:\n", __FUNCTION__); + ssd->worker = qxl_worker; +} + +static void interface_set_compression_level(QXLInstance *sin, int level) +{ + dprint(1, "%s:\n", __FUNCTION__); + /* nothing to do */ +} + +static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) +{ + dprint(3, "%s:\n", __FUNCTION__); + /* nothing to do */ +} + +static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) +{ + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + + info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; + info->memslot_id_bits = MEMSLOT_SLOT_BITS; + info->num_memslots = NUM_MEMSLOTS; + info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; + info->internal_groupslot_id = 0; + info->qxl_ram_size = ssd->bufsize; + info->n_surfaces = NUM_SURFACES; +} + +static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) +{ + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + SimpleSpiceUpdate *update; + + dprint(3, "%s:\n", __FUNCTION__); + update = qemu_spice_create_update(ssd); + if (update == NULL) { + return false; + } + *ext = update->ext; + return true; +} + +static int interface_req_cmd_notification(QXLInstance *sin) +{ + dprint(1, "%s:\n", __FUNCTION__); + return 1; +} + +static void interface_release_resource(QXLInstance *sin, + struct QXLReleaseInfoExt ext) +{ + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + uintptr_t id; + + dprint(2, "%s:\n", __FUNCTION__); + id = ext.info->id; + qemu_spice_destroy_update(ssd, (void*)id); +} + +static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext) +{ + dprint(3, "%s:\n", __FUNCTION__); + return false; +} + +static int interface_req_cursor_notification(QXLInstance *sin) +{ + dprint(1, "%s:\n", __FUNCTION__); + return 1; +} + +static void interface_notify_update(QXLInstance *sin, uint32_t update_id) +{ + fprintf(stderr, "%s: abort()\n", __FUNCTION__); + abort(); +} + +static int interface_flush_resources(QXLInstance *sin) +{ + fprintf(stderr, "%s: abort()\n", __FUNCTION__); + abort(); + return 0; +} + +static const QXLInterface dpy_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qemu simple display", + .base.major_version = SPICE_INTERFACE_QXL_MAJOR, + .base.minor_version = SPICE_INTERFACE_QXL_MINOR, + + .attache_worker = interface_attach_worker, + .set_compression_level = interface_set_compression_level, + .set_mm_time = interface_set_mm_time, + .get_init_info = interface_get_init_info, + + /* the callbacks below are called from spice server thread context */ + .get_command = interface_get_command, + .req_cmd_notification = interface_req_cmd_notification, + .release_resource = interface_release_resource, + .get_cursor_command = interface_get_cursor_command, + .req_cursor_notification = interface_req_cursor_notification, + .notify_update = interface_notify_update, + .flush_resources = interface_flush_resources, +}; + +static SimpleSpiceDisplay sdpy; + +static void display_update(struct DisplayState *ds, int x, int y, int w, int h) +{ + qemu_spice_display_update(&sdpy, x, y, w, h); +} + +static void display_resize(struct DisplayState *ds) +{ + qemu_spice_display_resize(&sdpy); +} + +static void display_refresh(struct DisplayState *ds) +{ + qemu_spice_display_refresh(&sdpy); +} + +static DisplayChangeListener display_listener = { + .dpy_update = display_update, + .dpy_resize = display_resize, + .dpy_refresh = display_refresh, +}; + +void qemu_spice_display_init(DisplayState *ds) +{ + assert(sdpy.ds == NULL); + sdpy.ds = ds; + sdpy.bufsize = (16 * 1024 * 1024); + sdpy.buf = qemu_malloc(sdpy.bufsize); + pthread_mutex_init(&sdpy.lock, NULL); + register_displaychangelistener(ds, &display_listener); + + sdpy.qxl.base.sif = &dpy_interface.base; + qemu_spice_add_interface(&sdpy.qxl.base); + assert(sdpy.worker); + + qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy); + qemu_spice_create_host_memslot(&sdpy); + qemu_spice_create_host_primary(&sdpy); +} diff --git a/ui/spice-display.h b/ui/spice-display.h new file mode 100644 index 0000000000..e17671c12a --- /dev/null +++ b/ui/spice-display.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <spice/ipc_ring.h> +#include <spice/enums.h> +#include <spice/qxl_dev.h> + +#include "pflib.h" + +#define NUM_MEMSLOTS 8 +#define MEMSLOT_GENERATION_BITS 8 +#define MEMSLOT_SLOT_BITS 8 + +#define MEMSLOT_GROUP_HOST 0 +#define MEMSLOT_GROUP_GUEST 1 +#define NUM_MEMSLOTS_GROUPS 2 + +#define NUM_SURFACES 1024 + +typedef struct SimpleSpiceDisplay { + DisplayState *ds; + void *buf; + int bufsize; + QXLWorker *worker; + QXLInstance qxl; + uint32_t unique; + QemuPfConv *conv; + + pthread_mutex_t lock; + QXLRect dirty; + int notify; + int running; +} SimpleSpiceDisplay; + +typedef struct SimpleSpiceUpdate { + QXLDrawable drawable; + QXLImage image; + QXLCommandExt ext; + uint8_t *bitmap; +} SimpleSpiceUpdate; + +int qemu_spice_rect_is_empty(const QXLRect* r); +void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r); + +SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *sdpy); +void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update); +void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd); +void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd); +void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd); +void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason); + +void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + int x, int y, int w, int h); +void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); +void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); diff --git a/ui/spice-input.c b/ui/spice-input.c new file mode 100644 index 0000000000..37c8578a2c --- /dev/null +++ b/ui/spice-input.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdbool.h> +#include <string.h> + +#include <spice.h> +#include <spice/enums.h> + +#include "qemu-common.h" +#include "qemu-spice.h" +#include "console.h" + +/* keyboard bits */ + +typedef struct QemuSpiceKbd { + SpiceKbdInstance sin; + int ledstate; +} QemuSpiceKbd; + +static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag); +static uint8_t kbd_get_leds(SpiceKbdInstance *sin); +static void kbd_leds(void *opaque, int l); + +static const SpiceKbdInterface kbd_interface = { + .base.type = SPICE_INTERFACE_KEYBOARD, + .base.description = "qemu keyboard", + .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR, + .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR, + .push_scan_freg = kbd_push_key, + .get_leds = kbd_get_leds, +}; + +static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag) +{ + kbd_put_keycode(frag); +} + +static uint8_t kbd_get_leds(SpiceKbdInstance *sin) +{ + QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin); + return kbd->ledstate; +} + +static void kbd_leds(void *opaque, int ledstate) +{ + QemuSpiceKbd *kbd = opaque; + + kbd->ledstate = 0; + if (ledstate & QEMU_SCROLL_LOCK_LED) { + kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK; + } + if (ledstate & QEMU_NUM_LOCK_LED) { + kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK; + } + if (ledstate & QEMU_CAPS_LOCK_LED) { + kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK; + } + spice_server_kbd_leds(&kbd->sin, ledstate); +} + +/* mouse bits */ + +typedef struct QemuSpicePointer { + SpiceMouseInstance mouse; + SpiceTabletInstance tablet; + int width, height, x, y; + Notifier mouse_mode; + bool absolute; +} QemuSpicePointer; + +static int map_buttons(int spice_buttons) +{ + int qemu_buttons = 0; + + /* + * Note: SPICE_MOUSE_BUTTON_* specifies the wire protocol but this + * isn't what we get passed in via interface callbacks for the + * middle and right button ... + */ + if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_LEFT) { + qemu_buttons |= MOUSE_EVENT_LBUTTON; + } + if (spice_buttons & 0x04 /* SPICE_MOUSE_BUTTON_MASK_MIDDLE */) { + qemu_buttons |= MOUSE_EVENT_MBUTTON; + } + if (spice_buttons & 0x02 /* SPICE_MOUSE_BUTTON_MASK_RIGHT */) { + qemu_buttons |= MOUSE_EVENT_RBUTTON; + } + return qemu_buttons; +} + +static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz, + uint32_t buttons_state) +{ + kbd_mouse_event(dx, dy, dz, map_buttons(buttons_state)); +} + +static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state) +{ + kbd_mouse_event(0, 0, 0, map_buttons(buttons_state)); +} + +static const SpiceMouseInterface mouse_interface = { + .base.type = SPICE_INTERFACE_MOUSE, + .base.description = "mouse", + .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR, + .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR, + .motion = mouse_motion, + .buttons = mouse_buttons, +}; + +static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height) +{ + QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); + + if (height < 16) { + height = 16; + } + if (width < 16) { + width = 16; + } + pointer->width = width; + pointer->height = height; +} + +static void tablet_position(SpiceTabletInstance* sin, int x, int y, + uint32_t buttons_state) +{ + QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); + + pointer->x = x * 0x7FFF / (pointer->width - 1); + pointer->y = y * 0x7FFF / (pointer->height - 1); + kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state)); +} + + +static void tablet_wheel(SpiceTabletInstance* sin, int wheel, + uint32_t buttons_state) +{ + QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); + + kbd_mouse_event(pointer->x, pointer->y, wheel, map_buttons(buttons_state)); +} + +static void tablet_buttons(SpiceTabletInstance *sin, + uint32_t buttons_state) +{ + QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); + + kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state)); +} + +static const SpiceTabletInterface tablet_interface = { + .base.type = SPICE_INTERFACE_TABLET, + .base.description = "tablet", + .base.major_version = SPICE_INTERFACE_TABLET_MAJOR, + .base.minor_version = SPICE_INTERFACE_TABLET_MINOR, + .set_logical_size = tablet_set_logical_size, + .position = tablet_position, + .wheel = tablet_wheel, + .buttons = tablet_buttons, +}; + +static void mouse_mode_notifier(Notifier *notifier) +{ + QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode); + bool is_absolute = kbd_mouse_is_absolute(); + + if (pointer->absolute == is_absolute) { + return; + } + + if (is_absolute) { + qemu_spice_add_interface(&pointer->tablet.base); + } else { + spice_server_remove_interface(&pointer->tablet.base); + } + pointer->absolute = is_absolute; +} + +void qemu_spice_input_init(void) +{ + QemuSpiceKbd *kbd; + QemuSpicePointer *pointer; + + kbd = qemu_mallocz(sizeof(*kbd)); + kbd->sin.base.sif = &kbd_interface.base; + qemu_spice_add_interface(&kbd->sin.base); + qemu_add_led_event_handler(kbd_leds, kbd); + + pointer = qemu_mallocz(sizeof(*pointer)); + pointer->mouse.base.sif = &mouse_interface.base; + pointer->tablet.base.sif = &tablet_interface.base; + qemu_spice_add_interface(&pointer->mouse.base); + + pointer->absolute = false; + pointer->mouse_mode.notify = mouse_mode_notifier; + qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode); + mouse_mode_notifier(&pointer->mouse_mode); +} diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 971bced934..af45edd872 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/vl.c b/vl.c index d352d18cfe..df414ef5ac 100644 --- a/vl.c +++ b/vl.c @@ -162,6 +162,8 @@ int main(int argc, char **argv) #include "cpus.h" #include "arch_init.h" +#include "ui/qemu-spice.h" + //#define DEBUG_NET //#define DEBUG_SLIRP @@ -173,6 +175,7 @@ static const char *data_dir; const char *bios_name = NULL; enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; DisplayType display_type = DT_DEFAULT; +int display_remote = 0; const char* keyboard_layout = NULL; ram_addr_t ram_size; const char *mem_path = NULL; @@ -1562,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; @@ -1859,11 +1865,6 @@ int main(int argc, char **argv, char **envp) tb_size = 0; autostart= 1; -#ifdef CONFIG_VIRTFS - qemu_add_opts(&qemu_fsdev_opts); - qemu_add_opts(&qemu_virtfs_opts); -#endif - /* first pass of option parsing */ optind = 1; while (optind < argc) { @@ -2474,7 +2475,7 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_vnc: - display_type = DT_VNC; + display_remote++; vnc_display = optarg; break; case QEMU_OPTION_no_acpi: @@ -2617,6 +2618,18 @@ int main(int argc, char **argv, char **envp) } break; } + case QEMU_OPTION_spice: + olist = qemu_find_opts("spice"); + if (!olist) { + fprintf(stderr, "spice is not supported by this qemu build.\n"); + exit(1); + } + opts = qemu_opts_parse(olist, optarg, 0); + if (!opts) { + fprintf(stderr, "parse error: %s\n", optarg); + exit(1); + } + break; case QEMU_OPTION_writeconfig: { FILE *fp; @@ -2918,17 +2931,19 @@ int main(int argc, char **argv, char **envp) /* just use the first displaystate for the moment */ ds = get_displaystate(); - if (display_type == DT_DEFAULT) { + if (using_spice) + display_remote++; + if (display_type == DT_DEFAULT && !display_remote) { #if defined(CONFIG_SDL) || defined(CONFIG_COCOA) display_type = DT_SDL; #else - display_type = DT_VNC; vnc_display = "localhost:0,to=99"; show_vnc_port = 1; #endif } + /* init local displays */ switch (display_type) { case DT_NOGRAPHIC: break; @@ -2946,7 +2961,12 @@ int main(int argc, char **argv, char **envp) cocoa_display_init(ds, full_screen); break; #endif - case DT_VNC: + default: + break; + } + + /* init remote displays */ + if (vnc_display) { vnc_display_init(ds); if (vnc_display_open(ds, vnc_display) < 0) exit(1); @@ -2954,12 +2974,15 @@ int main(int argc, char **argv, char **envp) if (show_vnc_port) { printf("VNC server running on `%s'\n", vnc_display_local_addr(ds)); } - break; - default: - break; } - dpy_resize(ds); +#ifdef CONFIG_SPICE + if (using_spice) { + qemu_spice_display_init(ds); + } +#endif + /* display setup */ + dpy_resize(ds); dcl = ds->listeners; while (dcl != NULL) { if (dcl->dpy_refresh != NULL) { @@ -2969,12 +2992,10 @@ int main(int argc, char **argv, char **envp) } dcl = dcl->next; } - - if (display_type == DT_NOGRAPHIC || display_type == DT_VNC) { + if (ds->gui_timer == NULL) { nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL); qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock)); } - text_consoles_set_display(ds); if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) { |