diff options
author | Avi Kivity <avi@redhat.com> | 2009-12-14 17:35:39 +0200 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-12-14 17:35:39 +0200 |
commit | d88d5dbc6b0c9ae14591e0f59d1e132c721de809 (patch) | |
tree | ddb9503c985a2064d801edac049539e98413d224 | |
parent | 5882ecd9d1de466752f4092ec5e9eddcd5dc8441 (diff) | |
parent | d5c7c9da2baea9f9e7bb5cea4479de6b92bf03a5 (diff) |
Merge branch 'stable-0.12-merge' into stable-0.12qemu-kvm-0.12.0-rc2
* stable-0.12-merge: (92 commits)
target-i386: Update CPUID feature set for TCG
s390: typo fix
s390: fix build on 32 bit host
Update Changelog and VERSION for 0.12.0-rc2
v2: properly save kvm system time msr registers
VNC: Convert do_info_vnc() to QObject
PCI: Convert pci_device_hot_add() to QObject
monitor: Convert do_info_mice() to QObject
char: Convert qemu_chr_info() to QObject
block: Convert bdrv_info_stats() to QObject
block: Convert bdrv_info() to QObject
migration: Convert do_info_migrate() to QObject
monitor: Convert do_info_kvm() to QObject
monitor: do_info_cpus(): Use QBool
monitor: Convert do_info_uuid() to QObject
monitor: Convert do_info_status() to QObject
monitor: Fix do_info_commands() output
monitor: Convert do_info_hpet() to QObject
monitor: do_info_version(): Use QDict
monitor: Fix do_info_balloon() output
...
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | Changelog | 36 | ||||
-rw-r--r-- | Makefile | 17 | ||||
-rw-r--r-- | QMP/qmp-spec.txt | 5 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | block.c | 207 | ||||
-rw-r--r-- | block.h | 7 | ||||
-rwxr-xr-x | configure | 18 | ||||
-rw-r--r-- | console.c | 10 | ||||
-rw-r--r-- | console.h | 6 | ||||
-rw-r--r-- | cpu-defs.h | 2 | ||||
-rw-r--r-- | hw/boards.h | 6 | ||||
-rw-r--r-- | hw/bt-hid.c | 4 | ||||
-rw-r--r-- | hw/cirrus_vga.c | 5 | ||||
-rw-r--r-- | hw/grackle_pci.c | 4 | ||||
-rw-r--r-- | hw/ide/cmd646.c | 4 | ||||
-rw-r--r-- | hw/ide/piix.c | 8 | ||||
-rw-r--r-- | hw/mc146818rtc.c | 17 | ||||
-rw-r--r-- | hw/msix.c | 74 | ||||
-rw-r--r-- | hw/pc.c | 2 | ||||
-rw-r--r-- | hw/pci-hotplug.c | 58 | ||||
-rw-r--r-- | hw/pci.c | 175 | ||||
-rw-r--r-- | hw/pci.h | 4 | ||||
-rw-r--r-- | hw/qdev-properties.c | 25 | ||||
-rw-r--r-- | hw/qdev.c | 2 | ||||
-rw-r--r-- | hw/qdev.h | 10 | ||||
-rw-r--r-- | hw/s390-virtio.c | 6 | ||||
-rw-r--r-- | hw/syborg_virtio.c | 12 | ||||
-rw-r--r-- | hw/unin_pci.c | 30 | ||||
-rw-r--r-- | hw/usb-bt.c | 5 | ||||
-rw-r--r-- | hw/usb-bus.c | 13 | ||||
-rw-r--r-- | hw/usb-hid.c | 14 | ||||
-rw-r--r-- | hw/usb-hub.c | 3 | ||||
-rw-r--r-- | hw/usb-msd.c | 6 | ||||
-rw-r--r-- | hw/usb-net.c | 5 | ||||
-rw-r--r-- | hw/usb-ohci.c | 5 | ||||
-rw-r--r-- | hw/usb-serial.c | 12 | ||||
-rw-r--r-- | hw/usb-uhci.c | 8 | ||||
-rw-r--r-- | hw/usb-wacom.c | 5 | ||||
-rw-r--r-- | hw/usb.h | 4 | ||||
-rw-r--r-- | hw/virtio-pci.c | 14 | ||||
-rw-r--r-- | hw/virtio.c | 11 | ||||
-rw-r--r-- | hw/virtio.h | 6 | ||||
-rw-r--r-- | hw/vmware_vga.c | 6 | ||||
-rw-r--r-- | linux-user/main.c | 1 | ||||
-rw-r--r-- | migration.c | 117 | ||||
-rw-r--r-- | migration.h | 4 | ||||
-rw-r--r-- | monitor.c | 404 | ||||
-rw-r--r-- | monitor.h | 1 | ||||
-rw-r--r-- | net.c | 5 | ||||
-rw-r--r-- | net.h | 1 | ||||
-rw-r--r--[-rwxr-xr-x] | pc-bios/openbios-ppc | bin | 295636 -> 312124 bytes | |||
-rw-r--r-- | pc-bios/openbios-sparc32 | bin | 209472 -> 217700 bytes | |||
-rw-r--r-- | pc-bios/openbios-sparc64 | bin | 1065872 -> 1065880 bytes | |||
-rw-r--r-- | qdict.c | 28 | ||||
-rw-r--r-- | qdict.h | 3 | ||||
-rw-r--r-- | qemu-char.c | 45 | ||||
-rw-r--r-- | qemu-char.h | 5 | ||||
-rw-r--r-- | qemu-config.c | 75 | ||||
-rw-r--r-- | qemu-config.h | 3 | ||||
-rw-r--r-- | qemu-malloc.c | 19 | ||||
-rw-r--r-- | qemu-monitor.hx | 20 | ||||
-rw-r--r-- | qemu-objects.h | 24 | ||||
-rw-r--r-- | qemu-option.c | 4 | ||||
-rw-r--r-- | qemu-options.hx | 22 | ||||
-rw-r--r-- | qerror.c | 85 | ||||
-rw-r--r-- | qerror.h | 57 | ||||
-rw-r--r-- | rules.mak | 3 | ||||
-rw-r--r-- | sysemu.h | 3 | ||||
-rw-r--r-- | target-i386/helper.c | 66 | ||||
-rw-r--r-- | target-i386/kvm.c | 19 | ||||
-rw-r--r-- | target-i386/machine.c | 5 | ||||
-rw-r--r-- | usb-bsd.c | 9 | ||||
-rw-r--r-- | usb-linux.c | 10 | ||||
-rw-r--r-- | vl.c | 552 | ||||
-rw-r--r-- | vnc.c | 201 |
75 files changed, 2009 insertions, 655 deletions
@@ -1,3 +1,39 @@ +version 0.12.0-rc2: + + - v2: properly save kvm system time msr registers (Glauber Costa) + - convert more monitor commands to qmp (Luiz Capitulino) + - vnc: fix capslock tracking logic. (Gerd Hoffmann) + - QemuOpts: allow larger option values. (Gerd Hoffmann) + - scsi: fix drive hotplug. (Gerd Hoffmann) + - pci: don't hw_error() when no slot is available. (Gerd Hoffmann) + - pci: don't abort() when trying to hotplug with acpi off. (Gerd Hoffmann) + - allow default devices to be implemented in config file (Gerd Hoffman) + - vc: colorize chardev title line with blue background. (Gerd Hoffmann) + - chardev: make chardevs specified in config file work. (Gerd Hoffmann) + - qdev: also match bus name for global properties (Gerd Hoffmann) + - qdev: add command line option to set global defaults for properties. (Gerd Hoffmann) + - kvm: x86: Save/restore exception_index (Jan Kiszka) + - qdev: Replace device names containing whitespace (Markus Armbruster) + - fix rtc-td-hack on host without high-res timers (Gleb Natapov) + - virtio: verify features on load (Michael S. Tsirkin) + - vmware_vga: add rom file so that it boots. (Dave Airlie) + - Do not abort on qemu_malloc(0) in production builds (Anthony Liguori) + - Fix ARM userspace strex implementation. (Paul Brook) + - qemu: delete rule target on error (Michael S. Tsirkin) + - QMP: add human-readable description to error response (Markus Armbruster) + - convert more monitor commands to QError (Markus Armbruster) + - monitor: Fix double-prompt after "change vnc passwd BLA" (Markus Armbruster) + - monitor: do_cont(): Don't ask for passwords (Luiz Capitulino) + - monitor: Introduce 'block_passwd' command (Luiz Capitulino) + - pci: interrupt disable bit support (Michael S. Tsirkin) + - pci: interrupt status bit implementation (Michael S. Tsirkin) + - pci: prepare irq code for interrupt state (Michael S. Tsirkin) + - msix: function mask support (Michael S. Tsirkin) + - msix: macro rename for function mask support (Michael S. Tsirkin) + - cpuid: Fix multicore setup on Intel (Andre Przywara) + - kvm: x86: Fix initial kvm_has_msr_star (Jan Kiszka) + - Update OpenBIOS images to r640 (Aurelien Jarno) + version 0.10.2: - fix savevm/loadvm (Anthony Liguori) @@ -94,6 +94,12 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS)) recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) ####################################################################### +# QObject +qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o +qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o +qobject-obj-y += qerror.o + +####################################################################### # block-obj-y is code used by both qemu system emulation and qemu-img block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o @@ -133,6 +139,7 @@ net-obj-y += $(addprefix net/, $(net-nested-y)) obj-y = $(block-obj-y) obj-y += $(net-obj-y) +obj-y += $(qobject-obj-y) obj-y += readline.o console.o obj-y += tcg-runtime.o host-utils.o @@ -165,8 +172,6 @@ obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o obj-y += qemu-char.o aio.o savevm.o obj-y += msmouse.o ps2.o obj-y += qdev.o qdev-properties.o -obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o json-lexer.o -obj-y += json-streamer.o json-parser.o qjson.o qerror.o obj-y += qemu-config.o block-migration.o obj-$(CONFIG_BRLAPI) += baum.o @@ -243,18 +248,18 @@ libqemu_common.a: $(obj-y) qemu-img.o: qemu-img-cmds.h -qemu-img$(EXESUF): qemu-img.o qemu-tool.o $(block-obj-y) +qemu-img$(EXESUF): qemu-img.o qemu-tool.o $(block-obj-y) $(qobject-obj-y) -qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o $(block-obj-y) +qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o $(block-obj-y) $(qobject-obj-y) -qemu-io$(EXESUF): qemu-io.o qemu-tool.o cmd.o $(block-obj-y) +qemu-io$(EXESUF): qemu-io.o qemu-tool.o cmd.o $(block-obj-y) $(qobject-obj-y) qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@") check-qint: check-qint.o qint.o qemu-malloc.o check-qstring: check-qstring.o qstring.o qemu-malloc.o -check-qdict: check-qdict.o qdict.o qint.o qstring.o qemu-malloc.o +check-qdict: check-qdict.o qdict.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt index 8429789a9..1cbd21cd4 100644 --- a/QMP/qmp-spec.txt +++ b/QMP/qmp-spec.txt @@ -102,13 +102,16 @@ completed because of an error condition. The format is: -{ "error": { "class": json-string, "data": json-value }, "id": json-value } +{ "error": { "class": json-string, "data": json-value, "desc": json-string }, + "id": json-value } Where, - The "class" member contains the error class name (eg. "ServiceUnavailable") - The "data" member contains specific error data and is defined in a per-command basis, it will be an empty json-object if the error has no data +- The "desc" member is a human-readable error message. Clients should + not attempt to parse this message. - The "id" member contains the transaction identification associated with the command execution (if issued by the Client) @@ -1 +1 @@ -0.11.50 +0.11.92 @@ -26,6 +26,7 @@ #include "monitor.h" #include "block_int.h" #include "module.h" +#include "qemu-objects.h" #ifdef CONFIG_BSD #include <sys/types.h> @@ -1139,61 +1140,203 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum); } -void bdrv_info(Monitor *mon) +static void bdrv_print_dict(QObject *obj, void *opaque) { + QDict *bs_dict; + Monitor *mon = opaque; + + bs_dict = qobject_to_qdict(obj); + + monitor_printf(mon, "%s: type=%s removable=%d", + qdict_get_str(bs_dict, "device"), + qdict_get_str(bs_dict, "type"), + qdict_get_bool(bs_dict, "removable")); + + if (qdict_get_bool(bs_dict, "removable")) { + monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked")); + } + + if (qdict_haskey(bs_dict, "inserted")) { + QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted")); + + monitor_printf(mon, " file="); + monitor_print_filename(mon, qdict_get_str(qdict, "file")); + if (qdict_haskey(qdict, "backing_file")) { + monitor_printf(mon, " backing_file="); + monitor_print_filename(mon, qdict_get_str(qdict, "backing_file")); + } + monitor_printf(mon, " ro=%d drv=%s encrypted=%d", + qdict_get_bool(qdict, "ro"), + qdict_get_str(qdict, "drv"), + qdict_get_bool(qdict, "encrypted")); + } else { + monitor_printf(mon, " [not inserted]"); + } + + monitor_printf(mon, "\n"); +} + +void bdrv_info_print(Monitor *mon, const QObject *data) +{ + qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon); +} + +/** + * bdrv_info(): Block devices information + * + * Each block device information is stored in a QDict and the + * returned QObject is a QList of all devices. + * + * The QDict contains the following: + * + * - "device": device name + * - "type": device type + * - "removable": true if the device is removable, false otherwise + * - "locked": true if the device is locked, false otherwise + * - "inserted": only present if the device is inserted, it is a QDict + * containing the following: + * - "file": device file name + * - "ro": true if read-only, false otherwise + * - "drv": driver format name + * - "backing_file": backing file name if one is used + * - "encrypted": true if encrypted, false otherwise + * + * Example: + * + * [ { "device": "ide0-hd0", "type": "hd", "removable": false, "locked": false, + * "inserted": { "file": "/tmp/foobar", "ro": false, "drv": "qcow2" } }, + * { "device": "floppy0", "type": "floppy", "removable": true, + * "locked": false } ] + */ +void bdrv_info(Monitor *mon, QObject **ret_data) +{ + QList *bs_list; BlockDriverState *bs; + bs_list = qlist_new(); + for (bs = bdrv_first; bs != NULL; bs = bs->next) { - monitor_printf(mon, "%s:", bs->device_name); - monitor_printf(mon, " type="); + QObject *bs_obj; + const char *type = "unknown"; + switch(bs->type) { case BDRV_TYPE_HD: - monitor_printf(mon, "hd"); + type = "hd"; break; case BDRV_TYPE_CDROM: - monitor_printf(mon, "cdrom"); + type = "cdrom"; break; case BDRV_TYPE_FLOPPY: - monitor_printf(mon, "floppy"); + type = "floppy"; break; } - monitor_printf(mon, " removable=%d", bs->removable); - if (bs->removable) { - monitor_printf(mon, " locked=%d", bs->locked); - } + + bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': %s, " + "'removable': %i, 'locked': %i }", + bs->device_name, type, bs->removable, + bs->locked); + assert(bs_obj != NULL); + if (bs->drv) { - monitor_printf(mon, " file="); - monitor_print_filename(mon, bs->filename); + QObject *obj; + QDict *bs_dict = qobject_to_qdict(bs_obj); + + obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, " + "'encrypted': %i }", + bs->filename, bs->read_only, + bs->drv->format_name, + bdrv_is_encrypted(bs)); + assert(obj != NULL); if (bs->backing_file[0] != '\0') { - monitor_printf(mon, " backing_file="); - monitor_print_filename(mon, bs->backing_file); + QDict *qdict = qobject_to_qdict(obj); + qdict_put(qdict, "backing_file", + qstring_from_str(bs->backing_file)); } - monitor_printf(mon, " ro=%d", bs->read_only); - monitor_printf(mon, " drv=%s", bs->drv->format_name); - monitor_printf(mon, " encrypted=%d", bdrv_is_encrypted(bs)); - } else { - monitor_printf(mon, " [not inserted]"); + + qdict_put_obj(bs_dict, "inserted", obj); } - monitor_printf(mon, "\n"); + qlist_append_obj(bs_list, bs_obj); } + + *ret_data = QOBJECT(bs_list); +} + +static void bdrv_stats_iter(QObject *data, void *opaque) +{ + QDict *qdict; + Monitor *mon = opaque; + + qdict = qobject_to_qdict(data); + monitor_printf(mon, "%s:", qdict_get_str(qdict, "device")); + + qdict = qobject_to_qdict(qdict_get(qdict, "stats")); + monitor_printf(mon, " rd_bytes=%" PRId64 + " wr_bytes=%" PRId64 + " rd_operations=%" PRId64 + " wr_operations=%" PRId64 + "\n", + qdict_get_int(qdict, "rd_bytes"), + qdict_get_int(qdict, "wr_bytes"), + qdict_get_int(qdict, "rd_operations"), + qdict_get_int(qdict, "wr_operations")); } -/* The "info blockstats" command. */ -void bdrv_info_stats(Monitor *mon) +void bdrv_stats_print(Monitor *mon, const QObject *data) { + qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon); +} + +/** + * bdrv_info_stats(): show block device statistics + * + * Each device statistic information is stored in a QDict and + * the returned QObject is a QList of all devices. + * + * The QDict contains the following: + * + * - "device": device name + * - "stats": A QDict with the statistics information, it contains: + * - "rd_bytes": bytes read + * - "wr_bytes": bytes written + * - "rd_operations": read operations + * - "wr_operations": write operations + * + * Example: + * + * [ { "device": "ide0-hd0", + * "stats": { "rd_bytes": 512, + * "wr_bytes": 0, + * "rd_operations": 1, + * "wr_operations": 0 } }, + * { "device": "ide1-cd0", + * "stats": { "rd_bytes": 0, + * "wr_bytes": 0, + * "rd_operations": 0, + * "wr_operations": 0 } } ] + */ +void bdrv_info_stats(Monitor *mon, QObject **ret_data) +{ + QObject *obj; + QList *devices; BlockDriverState *bs; + devices = qlist_new(); + for (bs = bdrv_first; bs != NULL; bs = bs->next) { - monitor_printf(mon, "%s:" - " rd_bytes=%" PRIu64 - " wr_bytes=%" PRIu64 - " rd_operations=%" PRIu64 - " wr_operations=%" PRIu64 - "\n", - bs->device_name, - bs->rd_bytes, bs->wr_bytes, - bs->rd_ops, bs->wr_ops); - } + obj = qobject_from_jsonf("{ 'device': %s, 'stats': {" + "'rd_bytes': %" PRId64 "," + "'wr_bytes': %" PRId64 "," + "'rd_operations': %" PRId64 "," + "'wr_operations': %" PRId64 + "} }", + bs->device_name, + bs->rd_bytes, bs->wr_bytes, + bs->rd_ops, bs->wr_ops); + assert(obj != NULL); + qlist_append_obj(devices, obj); + } + + *ret_data = QOBJECT(devices); } const char *bdrv_get_encrypted_filename(BlockDriverState *bs) @@ -4,6 +4,7 @@ #include "qemu-aio.h" #include "qemu-common.h" #include "qemu-option.h" +#include "qobject.h" /* block.c */ typedef struct BlockDriver BlockDriver; @@ -45,8 +46,10 @@ typedef struct QEMUSnapshotInfo { #define BDRV_SECTOR_SIZE (1 << BDRV_SECTOR_BITS) #define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1); -void bdrv_info(Monitor *mon); -void bdrv_info_stats(Monitor *mon); +void bdrv_info_print(Monitor *mon, const QObject *data); +void bdrv_info(Monitor *mon, QObject **ret_data); +void bdrv_stats_print(Monitor *mon, const QObject *data); +void bdrv_info_stats(Monitor *mon, QObject **ret_data); void bdrv_init(void); void bdrv_init_with_whitelist(void); @@ -271,6 +271,7 @@ cpu_emulation="yes" kvm_kmod="no" check_utests="no" user_pie="no" +zero_malloc="" # OS specific if check_define __linux__ ; then @@ -1930,8 +1931,9 @@ fi # Consult white-list to determine whether to enable werror # by default. Only enable by default for git builds +z_version=`cut -f3 -d. $source_path/VERSION` + if test -z "$werror" ; then - z_version=`cut -f3 -d. $source_path/VERSION` if test "$z_version" = "50" -a \ "$linux" = "yes" ; then werror="yes" @@ -1940,6 +1942,16 @@ if test -z "$werror" ; then fi fi +# Disable zero malloc errors for official releases unless explicitly told to +# enable/disable +if test -z "$zero_malloc" ; then + if test "$z_version" = "50" ; then + zero_malloc="no" + else + zero_malloc="yes" + fi +fi + if test "$werror" = "yes" ; then QEMU_CFLAGS="-Werror $QEMU_CFLAGS" fi @@ -2273,6 +2285,10 @@ fi echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak +if test "$zero_malloc" = "yes" ; then + echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak +fi + # USB host support case "$usb" in linux) @@ -1384,6 +1384,16 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpt s->t_attrib = s->t_attrib_default; text_console_resize(s); + if (chr->label) { + char msg[128]; + int len; + + s->t_attrib.bgcol = COLOR_BLUE; + len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label); + console_puts(chr, (uint8_t*)msg, len); + s->t_attrib = s->t_attrib_default; + } + qemu_chr_generic_open(chr); if (chr->init) chr->init(chr); @@ -44,7 +44,8 @@ struct MouseTransformInfo { int a[7]; }; -void do_info_mice(Monitor *mon); +void do_info_mice_print(Monitor *mon, const QObject *data); +void do_info_mice(Monitor *mon, QObject **ret_data); void do_mouse_set(Monitor *mon, const QDict *qdict); /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx @@ -322,7 +323,8 @@ void vnc_display_init(DisplayState *ds); void vnc_display_close(DisplayState *ds); int vnc_display_open(DisplayState *ds, const char *display); int vnc_display_password(DisplayState *ds, const char *password); -void do_info_vnc(Monitor *mon); +void do_info_vnc_print(Monitor *mon, const QObject *data); +void do_info_vnc(Monitor *mon, QObject **ret_data); char *vnc_display_local_addr(DisplayState *ds); /* curses.c */ diff --git a/cpu-defs.h b/cpu-defs.h index cf502e992..0e4ed1616 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -188,7 +188,7 @@ struct KVMCPUState { \ /* Core interrupt code */ \ jmp_buf jmp_env; \ - int exception_index; \ + int32_t exception_index; \ \ CPUState *next_cpu; /* next CPU sharing TB cache */ \ int cpu_index; /* CPU index (informative) */ \ diff --git a/hw/boards.h b/hw/boards.h index d8893413d..8fe0fbc8f 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -19,8 +19,12 @@ typedef struct QEMUMachine { QEMUMachineInitFunc *init; int use_scsi; int max_cpus; + int no_serial:1, + no_parallel:1, + use_virtcon:1, + no_vga:1; int is_default; - CompatProperty *compat_props; + GlobalProperty *compat_props; struct QEMUMachine *next; } QEMUMachine; diff --git a/hw/bt-hid.c b/hw/bt-hid.c index 020176eac..abdfd35e8 100644 --- a/hw/bt-hid.c +++ b/hw/bt-hid.c @@ -552,7 +552,7 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net, BT_HID_MTU, bt_hid_new_interrupt_ch); s->usbdev = dev; - s->btdev.device.lmp_name = s->usbdev->devname; + s->btdev.device.lmp_name = s->usbdev->product_desc; usb_hid_datain_cb(s->usbdev, s, bt_hid_datain); s->btdev.device.handle_destroy = bt_hid_destroy; @@ -566,6 +566,6 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net, struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net) { - USBDevice *dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Keyboard"); + USBDevice *dev = usb_create_simple(NULL /* FIXME */, "usb-kbd"); return bt_hid_init(net, dev, class_keyboard); } diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index ea9487339..3c7193b1d 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -3235,11 +3235,12 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) void pci_cirrus_vga_init(PCIBus *bus) { - pci_create_simple(bus, -1, "Cirrus VGA"); + pci_create_simple(bus, -1, "cirrus-vga"); } static PCIDeviceInfo cirrus_vga_info = { - .qdev.name = "Cirrus VGA", + .qdev.name = "cirrus-vga", + .qdev.desc = "Cirrus CLGD 54xx VGA", .qdev.size = sizeof(PCICirrusVGAState), .qdev.vmsd = &vmstate_pci_cirrus_vga, .init = pci_cirrus_vga_initfn, diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 089d1fba0..ee4fed53e 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -178,7 +178,7 @@ static PCIDeviceInfo grackle_pci_host_info = { }; static PCIDeviceInfo dec_21154_pci_host_info = { - .qdev.name = "DEC 21154", + .qdev.name = "dec-21154", .qdev.size = sizeof(PCIDevice), .init = dec_21154_pci_host_init, }; @@ -188,7 +188,7 @@ static void grackle_register_devices(void) sysbus_register_dev("grackle", sizeof(GrackleState), pci_grackle_init_device); pci_qdev_register(&grackle_pci_host_info); - sysbus_register_dev("DEC 21154", sizeof(GrackleState), + sysbus_register_dev("dec-21154", sizeof(GrackleState), pci_dec_21154_init_device); pci_qdev_register(&dec_21154_pci_host_info); } diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 3b7c60608..e1e626e2a 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -245,7 +245,7 @@ void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table, { PCIDevice *dev; - dev = pci_create(bus, -1, "CMD646 IDE"); + dev = pci_create(bus, -1, "cmd646-ide"); qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled); qdev_init_nofail(&dev->qdev); @@ -254,7 +254,7 @@ void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table, static PCIDeviceInfo cmd646_ide_info[] = { { - .qdev.name = "CMD646 IDE", + .qdev.name = "cmd646-ide", .qdev.size = sizeof(PCIIDEState), .init = pci_cmd646_ide_initfn, .qdev.props = (Property[]) { diff --git a/hw/ide/piix.c b/hw/ide/piix.c index ec93f29b5..de3648023 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -161,7 +161,7 @@ void pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) { PCIDevice *dev; - dev = pci_create_simple(bus, devfn, "PIIX3 IDE"); + dev = pci_create_simple(bus, devfn, "piix3-ide"); pci_ide_create_devs(dev, hd_table); } @@ -171,18 +171,18 @@ void pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) { PCIDevice *dev; - dev = pci_create_simple(bus, devfn, "PIIX4 IDE"); + dev = pci_create_simple(bus, devfn, "piix4-ide"); pci_ide_create_devs(dev, hd_table); } static PCIDeviceInfo piix_ide_info[] = { { - .qdev.name = "PIIX3 IDE", + .qdev.name = "piix3-ide", .qdev.size = sizeof(PCIIDEState), .qdev.no_user = 1, .init = pci_piix3_ide_initfn, },{ - .qdev.name = "PIIX4 IDE", + .qdev.name = "piix4-ide", .qdev.size = sizeof(PCIIDEState), .qdev.no_user = 1, .init = pci_piix4_ide_initfn, diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index b8c7b0c1b..e4d55c7c7 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -30,6 +30,8 @@ //#define DEBUG_CMOS +#define RTC_REINJECT_ON_ACK_COUNT 1000 + #define RTC_SECONDS 0 #define RTC_SECONDS_ALARM 1 #define RTC_MINUTES 2 @@ -76,6 +78,7 @@ struct RTCState { int64_t next_periodic_time; /* second update */ int64_t next_second_time; + uint16_t irq_reinject_on_ack_count; uint32_t irq_coalesced; uint32_t period; QEMUTimer *coalesced_timer; @@ -180,6 +183,8 @@ static void rtc_periodic_timer(void *opaque) s->cmos_data[RTC_REG_C] |= 0xc0; #ifdef TARGET_I386 if(rtc_td_hack) { + if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) + s->irq_reinject_on_ack_count = 0; apic_reset_irq_delivered(); rtc_irq_raise(s->irq); if (!apic_get_irq_delivered()) { @@ -458,6 +463,18 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; qemu_irq_lower(s->irq); +#ifdef TARGET_I386 + if(s->irq_coalesced && + s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) { + s->irq_reinject_on_ack_count++; + apic_reset_irq_delivered(); + qemu_irq_raise(s->irq); + if (apic_get_irq_delivered()) + s->irq_coalesced--; + break; + } +#endif + s->cmos_data[RTC_REG_C] = 0x00; break; default: @@ -22,6 +22,7 @@ #define PCI_MSIX_FLAGS 2 /* Table at lower 11 bits */ #define PCI_MSIX_FLAGS_QSIZE 0x7FF #define PCI_MSIX_FLAGS_ENABLE (1 << 15) +#define PCI_MSIX_FLAGS_MASKALL (1 << 14) #define PCI_MSIX_FLAGS_BIRMASK (7 << 0) /* MSI-X capability structure */ @@ -29,9 +30,10 @@ #define MSIX_PBA_OFFSET 8 #define MSIX_CAP_LENGTH 12 -/* MSI enable bit is in byte 1 in FLAGS register */ -#define MSIX_ENABLE_OFFSET (PCI_MSIX_FLAGS + 1) +/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */ +#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1) #define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) +#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) /* MSI-X table format */ #define MSIX_MSG_ADDR 0 @@ -214,22 +216,11 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries, bar_nr); pdev->msix_cap = config_offset; /* Make flags bit writeable. */ - pdev->wmask[config_offset + MSIX_ENABLE_OFFSET] |= MSIX_ENABLE_MASK; + pdev->wmask[config_offset + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK | + MSIX_MASKALL_MASK; return 0; } -/* Handle MSI-X capability config write. */ -void msix_write_config(PCIDevice *dev, uint32_t addr, - uint32_t val, int len) -{ - unsigned enable_pos = dev->msix_cap + MSIX_ENABLE_OFFSET; - if (addr + len <= enable_pos || addr > enable_pos) - return; - - if (msix_enabled(dev)) - qemu_set_irq(dev->irq[0], 0); -} - static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr) { PCIDevice *dev = opaque; @@ -270,10 +261,50 @@ static void msix_clr_pending(PCIDevice *dev, int vector) *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); } +static int msix_function_masked(PCIDevice *dev) +{ + return dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK; +} + static int msix_is_masked(PCIDevice *dev, int vector) { unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL; - return dev->msix_table_page[offset] & MSIX_VECTOR_MASK; + return msix_function_masked(dev) || + dev->msix_table_page[offset] & MSIX_VECTOR_MASK; +} + +static void msix_handle_mask_update(PCIDevice *dev, int vector) +{ + if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) { + msix_clr_pending(dev, vector); + msix_notify(dev, vector); + } +} + +/* Handle MSI-X capability config write. */ +void msix_write_config(PCIDevice *dev, uint32_t addr, + uint32_t val, int len) +{ + unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET; + int vector; + + if (addr + len <= enable_pos || addr > enable_pos) { + return; + } + + if (!msix_enabled(dev)) { + return; + } + + qemu_set_irq(dev->irq[0], 0); + + if (msix_function_masked(dev)) { + return; + } + + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { + msix_handle_mask_update(dev, vector); + } } static void msix_mmio_writel(void *opaque, target_phys_addr_t addr, @@ -287,10 +318,7 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr, if (kvm_enabled() && kvm_irqchip_in_kernel()) { kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector)); } - if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) { - msix_clr_pending(dev, vector); - msix_notify(dev, vector); - } + msix_handle_mask_update(dev, vector); } static void msix_mmio_write_unallowed(void *opaque, target_phys_addr_t addr, @@ -462,7 +490,7 @@ int msix_present(PCIDevice *dev) int msix_enabled(PCIDevice *dev) { return (dev->cap_present & QEMU_PCI_CAP_MSIX) && - (dev->config[dev->msix_cap + MSIX_ENABLE_OFFSET] & + (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_ENABLE_MASK); } @@ -505,8 +533,8 @@ void msix_reset(PCIDevice *dev) if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) return; msix_free_irq_entries(dev); - dev->config[dev->msix_cap + MSIX_ENABLE_OFFSET] &= - ~dev->wmask[dev->msix_cap + MSIX_ENABLE_OFFSET]; + dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= + ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE); msix_mask_all(dev, dev->msix_entries_nr); } @@ -1345,7 +1345,7 @@ static QEMUMachine pc_machine_v0_10 = { .desc = "Standard PC, qemu 0.10", .init = pc_init_pci, .max_cpus = 255, - .compat_props = (CompatProperty[]) { + .compat_props = (GlobalProperty[]) { { .driver = "virtio-blk-pci", .property = "class", diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index 6e4277671..ed55d5f69 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -33,6 +33,7 @@ #include "scsi.h" #include "virtio-blk.h" #include "qemu-config.h" +#include "qemu-objects.h" #include "device-assignment.h" #if defined(TARGET_I386) @@ -41,7 +42,18 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, const char *opts_str) { QemuOpts *opts; - int ret; + PCIBus *bus; + int ret, devfn; + + bus = pci_get_bus_devfn(&devfn, devaddr); + if (!bus) { + monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); + return NULL; + } + if (!((BusState*)bus)->allow_hotplug) { + monitor_printf(mon, "PCI bus doesn't support hotplug\n"); + return NULL; + } opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", NULL); if (!opts) { @@ -83,6 +95,7 @@ static int scsi_hot_add(DeviceState *adapter, DriveInfo *dinfo, int printinfo) */ dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1); scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo, dinfo->unit); + dinfo->unit = scsidev->id; if (printinfo) qemu_error("OK bus %d, unit %d\n", scsibus->busnr, scsidev->id); @@ -180,6 +193,10 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); return NULL; } + if (!((BusState*)bus)->allow_hotplug) { + monitor_printf(mon, "PCI bus doesn't support hotplug\n"); + return NULL; + } switch (type) { case IF_SCSI: @@ -231,7 +248,36 @@ static PCIDevice *qemu_pci_hot_assign_device(Monitor *mon, } #endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */ -void pci_device_hot_add(Monitor *mon, const QDict *qdict) +void pci_device_hot_add_print(Monitor *mon, const QObject *data) +{ + QDict *qdict; + + assert(qobject_type(data) == QTYPE_QDICT); + qdict = qobject_to_qdict(data); + + monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n", + (int) qdict_get_int(qdict, "domain"), + (int) qdict_get_int(qdict, "bus"), + (int) qdict_get_int(qdict, "slot"), + (int) qdict_get_int(qdict, "function")); + +} + +/** + * pci_device_hot_add(): Hot add a PCI device + * + * Return a QDict with the following device information: + * + * - "domain": domain number + * - "bus": bus number + * - "slot": slot number + * - "function": function number + * + * Example: + * + * { "domain": 0, "bus": 0, "slot": 5, "function": 0 } + */ +void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data) { PCIDevice *dev = NULL; const char *pci_addr = qdict_get_str(qdict, "pci_addr"); @@ -262,9 +308,11 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict) monitor_printf(mon, "invalid type: %s\n", type); if (dev) { - monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n", - 0, pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); + *ret_data = + qobject_from_jsonf("{ 'domain': 0, 'bus': %d, 'slot': %d, " + "'function': %d }", pci_bus_num(dev->bus), + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + assert(*ret_data != NULL); } else monitor_printf(mon, "failed to add %s\n", opts); } @@ -106,11 +106,48 @@ static int pci_bar(PCIDevice *d, int reg) return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; } +static inline int pci_irq_state(PCIDevice *d, int irq_num) +{ + return (d->irq_state >> irq_num) & 0x1; +} + +static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level) +{ + d->irq_state &= ~(0x1 << irq_num); + d->irq_state |= level << irq_num; +} + +static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) +{ + PCIBus *bus; + for (;;) { + bus = pci_dev->bus; + irq_num = bus->map_irq(pci_dev, irq_num); + if (bus->set_irq) + break; + pci_dev = bus->parent_dev; + } + bus->irq_count[irq_num] += change; + bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); +} + +/* Update interrupt status bit in config space on interrupt + * state change. */ +static void pci_update_irq_status(PCIDevice *dev) +{ + if (dev->irq_state) { + dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT; + } else { + dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; + } +} + static void pci_device_reset(PCIDevice *dev) { int r; - memset(dev->irq_state, 0, sizeof dev->irq_state); + dev->irq_state = 0; + pci_update_irq_status(dev); dev->config[PCI_COMMAND] &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); dev->config[PCI_CACHE_LINE_SIZE] = 0x0; @@ -277,6 +314,43 @@ static VMStateInfo vmstate_info_pci_config = { .put = put_pci_config_device, }; +static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) +{ + PCIDevice *s = container_of(pv, PCIDevice, config); + uint32_t irq_state[PCI_NUM_PINS]; + int i; + for (i = 0; i < PCI_NUM_PINS; ++i) { + irq_state[i] = qemu_get_be32(f); + if (irq_state[i] != 0x1 && irq_state[i] != 0) { + fprintf(stderr, "irq state %d: must be 0 or 1.\n", + irq_state[i]); + return -EINVAL; + } + } + + for (i = 0; i < PCI_NUM_PINS; ++i) { + pci_set_irq_state(s, i, irq_state[i]); + } + + return 0; +} + +static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) +{ + int i; + PCIDevice *s = container_of(pv, PCIDevice, config); + + for (i = 0; i < PCI_NUM_PINS; ++i) { + qemu_put_be32(f, pci_irq_state(s, i)); + } +} + +static VMStateInfo vmstate_info_pci_irq_state = { + .name = "pci irq state", + .get = get_pci_irq_state, + .put = put_pci_irq_state, +}; + const VMStateDescription vmstate_pci_device = { .name = "PCIDevice", .version_id = 2, @@ -287,7 +361,9 @@ const VMStateDescription vmstate_pci_device = { VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, vmstate_info_pci_config, PCI_CONFIG_SPACE_SIZE), - VMSTATE_INT32_ARRAY_V(irq_state, PCIDevice, PCI_NUM_PINS, 2), + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, + vmstate_info_pci_irq_state, + PCI_NUM_PINS * sizeof(int32_t)), VMSTATE_END_OF_LIST() } }; @@ -302,7 +378,9 @@ const VMStateDescription vmstate_pcie_device = { VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, vmstate_info_pci_config, PCIE_CONFIG_SPACE_SIZE), - VMSTATE_INT32_ARRAY_V(irq_state, PCIDevice, PCI_NUM_PINS, 2), + VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, + vmstate_info_pci_irq_state, + PCI_NUM_PINS * sizeof(int32_t)), VMSTATE_END_OF_LIST() } }; @@ -314,12 +392,23 @@ static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s) void pci_device_save(PCIDevice *s, QEMUFile *f) { + /* Clear interrupt status bit: it is implicit + * in irq_state which we are saving. + * This makes us compatible with old devices + * which never set or clear this bit. */ + s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT; vmstate_save_state(f, pci_get_vmstate(s), s); + /* Restore the interrupt status bit. */ + pci_update_irq_status(s); } int pci_device_load(PCIDevice *s, QEMUFile *f) { - return vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); + int ret; + ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); + /* Restore the interrupt status bit. */ + pci_update_irq_status(s); + return ret; } static int pci_set_default_subsystem_id(PCIDevice *pci_dev) @@ -482,7 +571,8 @@ static void pci_init_wmask(PCIDevice *dev) dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; dev->wmask[PCI_INTERRUPT_LINE] = 0xff; pci_set_word(dev->wmask + PCI_COMMAND, - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INTX_DISABLE); memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff, config_size - PCI_CONFIG_HEADER_SIZE); @@ -543,16 +633,18 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, if (!bus->devices[devfn]) goto found; } - hw_error("PCI: no devfn available for %s, all in use\n", name); + qemu_error("PCI: no devfn available for %s, all in use\n", name); + return NULL; found: ; } else if (bus->devices[devfn]) { - hw_error("PCI: devfn %d not available for %s, in use by %s\n", devfn, + qemu_error("PCI: devfn %d not available for %s, in use by %s\n", devfn, name, bus->devices[devfn]->name); + return NULL; } pci_dev->bus = bus; pci_dev->devfn = devfn; pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); - memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state)); + pci_dev->irq_state = 0; pci_config_alloc(pci_dev); header_type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION; @@ -588,6 +680,9 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, config_read, config_write, PCI_HEADER_TYPE_NORMAL); + if (pci_dev == NULL) { + hw_error("PCI: can't register device\n"); + } return pci_dev; } static target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr) @@ -902,11 +997,35 @@ static void pci_update_mappings(PCIDevice *d) } } -static uint32_t pci_read_config(PCIDevice *d, - uint32_t address, int len) +static inline int pci_irq_disabled(PCIDevice *d) +{ + return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE; +} + +/* Called after interrupt disabled field update in config space, + * assert/deassert interrupts if necessary. + * Gets original interrupt disable bit value (before update). */ +static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled) +{ + int i, disabled = pci_irq_disabled(d); + if (disabled == was_irq_disabled) + return; + for (i = 0; i < PCI_NUM_PINS; ++i) { + int state = pci_irq_state(d, i); + pci_change_irq_level(d, i, disabled ? -state : state); + } +} + +uint32_t pci_default_read_config(PCIDevice *d, + uint32_t address, int len) { uint32_t val = 0; assert(len == 1 || len == 2 || len == 4); + + if (pci_access_cap_config(d, address, len)) { + return d->cap.config_read(d, address, len); + } + len = MIN(len, pci_config_size(d) - address); memcpy(&val, d->config + address, len); return le32_to_cpu(val); @@ -933,7 +1052,7 @@ int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len) uint32_t pci_default_cap_read_config(PCIDevice *pci_dev, uint32_t address, int len) { - return pci_read_config(pci_dev, address, len); + return pci_default_read_config(pci_dev, address, len); } void pci_default_cap_write_config(PCIDevice *pci_dev, @@ -942,18 +1061,9 @@ void pci_default_cap_write_config(PCIDevice *pci_dev, pci_write_config(pci_dev, address, val, len); } -uint32_t pci_default_read_config(PCIDevice *d, - uint32_t address, int len) -{ - if (pci_access_cap_config(d, address, len)) - return d->cap.config_read(d, address, len); - - return pci_read_config(d, address, len); -} - void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) { - int i; + int i, was_irq_disabled = pci_irq_disabled(d); uint32_t config_size = pci_config_size(d); if (pci_access_cap_config(d, addr, l)) { @@ -979,6 +1089,8 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) range_covers_byte(addr, l, PCI_COMMAND)) pci_update_mappings(d); + if (range_covers_byte(addr, l, PCI_COMMAND)) + pci_update_irq_disabled(d, was_irq_disabled); } /***********************************************************/ @@ -988,28 +1100,21 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) static void pci_set_irq(void *opaque, int irq_num, int level) { PCIDevice *pci_dev = opaque; - PCIBus *bus; int change; - change = level - pci_dev->irq_state[irq_num]; + change = level - pci_irq_state(pci_dev, irq_num); if (!change) return; - pci_dev->irq_state[irq_num] = level; - #if defined(TARGET_IA64) ioapic_set_irq(pci_dev, irq_num, level); #endif - for (;;) { - bus = pci_dev->bus; - irq_num = bus->map_irq(pci_dev, irq_num); - if (bus->set_irq) - break; - pci_dev = bus->parent_dev; - } - bus->irq_count[irq_num] += change; - bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); + pci_set_irq_state(pci_dev, irq_num, level); + pci_update_irq_status(pci_dev); + if (pci_irq_disabled(pci_dev)) + return; + pci_change_irq_level(pci_dev, irq_num, change); } int pci_map_irq(PCIDevice *pci_dev, int pin) @@ -1386,6 +1491,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn, info->config_read, info->config_write, info->header_type); + if (pci_dev == NULL) + return -1; rc = info->init(pci_dev); if (rc != 0) return rc; @@ -112,7 +112,9 @@ typedef struct PCIIORegion { #define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ #define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ #define PCI_COMMAND_MASTER 0x4 /* Enable bus master */ +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ #define PCI_STATUS 0x06 /* 16 bits */ +#define PCI_STATUS_INTERRUPT 0x08 #define PCI_REVISION_ID 0x08 /* 8 bits */ #define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ #define PCI_CLASS_DEVICE 0x0a /* Device class */ @@ -245,7 +247,7 @@ struct PCIDevice { qemu_irq *irq; /* Current IRQ levels. Used internally by the generic PCI code. */ - int irq_state[PCI_NUM_PINS]; + uint8_t irq_state; /* Capability bits */ uint32_t cap_present; diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index bda669938..fb07279ba 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -593,22 +593,29 @@ void qdev_prop_set_defaults(DeviceState *dev, Property *props) } } -static CompatProperty *compat_props; +static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); -void qdev_prop_register_compat(CompatProperty *props) +void qdev_prop_register_global(GlobalProperty *prop) { - compat_props = props; + QTAILQ_INSERT_TAIL(&global_props, prop, next); } -void qdev_prop_set_compat(DeviceState *dev) +void qdev_prop_register_global_list(GlobalProperty *props) { - CompatProperty *prop; + int i; - if (!compat_props) { - return; + for (i = 0; props[i].driver != NULL; i++) { + qdev_prop_register_global(props+i); } - for (prop = compat_props; prop->driver != NULL; prop++) { - if (strcmp(dev->info->name, prop->driver) != 0) { +} + +void qdev_prop_set_globals(DeviceState *dev) +{ + GlobalProperty *prop; + + QTAILQ_FOREACH(prop, &global_props, next) { + if (strcmp(dev->info->name, prop->driver) != 0 && + strcmp(dev->info->bus_info->name, prop->driver) != 0) { continue; } if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { @@ -103,7 +103,7 @@ DeviceState *qdev_create(BusState *bus, const char *name) dev->parent_bus = bus; qdev_prop_set_defaults(dev, dev->info->props); qdev_prop_set_defaults(dev, dev->parent_bus->info->props); - qdev_prop_set_compat(dev); + qdev_prop_set_globals(dev); QLIST_INSERT_HEAD(&bus->children, dev, sibling); if (qdev_hotplug) { assert(bus->allow_hotplug); @@ -92,11 +92,12 @@ struct PropertyInfo { int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); }; -struct CompatProperty { +typedef struct GlobalProperty { const char *driver; const char *property; const char *value; -}; + QTAILQ_ENTRY(GlobalProperty) next; +} GlobalProperty; /*** Board API. This should go away once we have a machine config file. ***/ @@ -256,8 +257,9 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value); void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); void qdev_prop_set_defaults(DeviceState *dev, Property *props); -void qdev_prop_register_compat(CompatProperty *props); -void qdev_prop_set_compat(DeviceState *dev); +void qdev_prop_register_global(GlobalProperty *prop); +void qdev_prop_register_global_list(GlobalProperty *props); +void qdev_prop_set_globals(DeviceState *dev); /* This is a nasty hack to allow passing a NULL bus to qdev_create. */ extern struct BusInfo system_bus_info; diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index cc21ee6da..b56788652 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -181,7 +181,7 @@ static void s390_init(ram_addr_t ram_size, cpu_synchronize_state(env); env->psw.addr = KERN_IMAGE_START; - env->psw.mask = 0x0000000180000000UL; + env->psw.mask = 0x0000000180000000ULL; } if (initrd_filename) { @@ -243,6 +243,10 @@ static QEMUMachine s390_machine = { .alias = "s390", .desc = "VirtIO based S390 machine", .init = s390_init, + .no_serial = 1, + .no_parallel = 1, + .use_virtcon = 1, + .no_vga = 1, .max_cpus = 255, .is_default = 1, }; diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c index 6cf5a15c2..a84206a11 100644 --- a/hw/syborg_virtio.c +++ b/hw/syborg_virtio.c @@ -87,7 +87,7 @@ static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset) break; case SYBORG_VIRTIO_HOST_FEATURES: ret = vdev->get_features(vdev); - ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); + ret |= vdev->binding->get_features(s); break; case SYBORG_VIRTIO_GUEST_FEATURES: ret = vdev->features; @@ -242,8 +242,16 @@ static void syborg_virtio_update_irq(void *opaque, uint16_t vector) qemu_set_irq(proxy->irq, level != 0); } +static unsigned syborg_virtio_get_features(void *opaque) +{ + unsigned ret = 0; + ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); + return ret; +} + static VirtIOBindings syborg_virtio_bindings = { - .notify = syborg_virtio_update_irq + .notify = syborg_virtio_update_irq, + .get_features = syborg_virtio_get_features, }; static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev) diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 5b3f118fc..f07c96644 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -148,7 +148,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic) /* Use values found on a real PowerMac */ /* Uninorth main bus */ - dev = qdev_create(NULL, "Uni-north main"); + dev = qdev_create(NULL, "uni-north-main"); qdev_init_nofail(dev); s = sysbus_from_qdev(dev); d = FROM_SYSBUS(UNINState, s); @@ -157,7 +157,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic) pic, 11 << 3, 4); #if 0 - pci_create_simple(d->host_state.bus, 11 << 3, "Uni-north main"); + pci_create_simple(d->host_state.bus, 11 << 3, "uni-north-main"); #endif sysbus_mmio_map(s, 0, 0xf2800000); @@ -166,12 +166,12 @@ PCIBus *pci_pmac_init(qemu_irq *pic) /* DEC 21154 bridge */ #if 0 /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */ - pci_create_simple(d->host_state.bus, 12 << 3, "DEC 21154"); + pci_create_simple(d->host_state.bus, 12 << 3, "dec-21154"); #endif /* Uninorth AGP bus */ - pci_create_simple(d->host_state.bus, 11 << 3, "Uni-north AGP"); - dev = qdev_create(NULL, "Uni-north AGP"); + pci_create_simple(d->host_state.bus, 11 << 3, "uni-north-AGP"); + dev = qdev_create(NULL, "uni-north-AGP"); qdev_init_nofail(dev); s = sysbus_from_qdev(dev); sysbus_mmio_map(s, 0, 0xf0800000); @@ -180,8 +180,8 @@ PCIBus *pci_pmac_init(qemu_irq *pic) /* Uninorth internal bus */ #if 0 /* XXX: not needed for now */ - pci_create_simple(d->host_state.bus, 14 << 3, "Uni-north internal"); - dev = qdev_create(NULL, "Uni-north internal"); + pci_create_simple(d->host_state.bus, 14 << 3, "uni-north-internal"); + dev = qdev_create(NULL, "uni-north-internal"); qdev_init_nofail(dev); s = sysbus_from_qdev(dev); sysbus_mmio_map(s, 0, 0xf4800000); @@ -260,41 +260,41 @@ static int unin_internal_pci_host_init(PCIDevice *d) } static PCIDeviceInfo unin_main_pci_host_info = { - .qdev.name = "Uni-north main", + .qdev.name = "uni-north-main", .qdev.size = sizeof(PCIDevice), .init = unin_main_pci_host_init, }; static PCIDeviceInfo dec_21154_pci_host_info = { - .qdev.name = "DEC 21154", + .qdev.name = "dec-21154", .qdev.size = sizeof(PCIDevice), .init = dec_21154_pci_host_init, }; static PCIDeviceInfo unin_agp_pci_host_info = { - .qdev.name = "Uni-north AGP", + .qdev.name = "uni-north-AGP", .qdev.size = sizeof(PCIDevice), .init = unin_agp_pci_host_init, }; static PCIDeviceInfo unin_internal_pci_host_info = { - .qdev.name = "Uni-north internal", + .qdev.name = "uni-north-internal", .qdev.size = sizeof(PCIDevice), .init = unin_internal_pci_host_init, }; static void unin_register_devices(void) { - sysbus_register_dev("Uni-north main", sizeof(UNINState), + sysbus_register_dev("uni-north-main", sizeof(UNINState), pci_unin_main_init_device); pci_qdev_register(&unin_main_pci_host_info); - sysbus_register_dev("DEC 21154", sizeof(UNINState), + sysbus_register_dev("dec-21154", sizeof(UNINState), pci_dec_21154_init_device); pci_qdev_register(&dec_21154_pci_host_info); - sysbus_register_dev("Uni-north AGP", sizeof(UNINState), + sysbus_register_dev("uni-north-AGP", sizeof(UNINState), pci_unin_agp_init_device); pci_qdev_register(&unin_agp_pci_host_info); - sysbus_register_dev("Uni-north internal", sizeof(UNINState), + sysbus_register_dev("uni-north-internal", sizeof(UNINState), pci_unin_internal_init_device); pci_qdev_register(&unin_internal_pci_host_info); } diff --git a/hw/usb-bt.c b/hw/usb-bt.c index 18d7a98b4..56d1a6ce4 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -630,7 +630,7 @@ USBDevice *usb_bt_init(HCIInfo *hci) if (!hci) return NULL; - dev = usb_create_simple(NULL /* FIXME */, "QEMU BT dongle"); + dev = usb_create_simple(NULL /* FIXME */, "usb-bt-dongle"); s = DO_UPCAST(struct USBBtState, dev, dev); s->dev.opaque = s; @@ -645,7 +645,8 @@ USBDevice *usb_bt_init(HCIInfo *hci) } static struct USBDeviceInfo bt_info = { - .qdev.name = "QEMU BT dongle", + .product_desc = "QEMU BT dongle", + .qdev.name = "usb-bt-dongle", .qdev.size = sizeof(struct USBBtState), .init = usb_bt_initfn, .handle_packet = usb_generic_handle_packet, diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 99d185e79..54027dfc4 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -43,7 +43,7 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base); int rc; - pstrcpy(dev->devname, sizeof(dev->devname), qdev->info->name); + pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc); dev->info = info; dev->auto_attach = 1; rc = dev->info->init(dev); @@ -131,7 +131,7 @@ static void do_attach(USBDevice *dev) if (dev->attached) { fprintf(stderr, "Warning: tried to attach usb device %s twice\n", - dev->devname); + dev->product_desc); return; } dev->attached++; @@ -153,7 +153,7 @@ int usb_device_attach(USBDevice *dev) if (bus->nfree == 1) { /* Create a new hub and chain it on. */ - hub = usb_create_simple(bus, "QEMU USB Hub"); + hub = usb_create_simple(bus, "usb-hub"); } do_attach(dev); return 0; @@ -166,7 +166,7 @@ int usb_device_detach(USBDevice *dev) if (!dev->attached) { fprintf(stderr, "Warning: tried to detach unattached usb device %s\n", - dev->devname); + dev->product_desc); return -1; } dev->attached--; @@ -228,7 +228,7 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) monitor_printf(mon, "%*saddr %d.%d, speed %s, name %s%s\n", indent, "", bus->busnr, dev->addr, - usb_speed(dev->speed), dev->devname, + usb_speed(dev->speed), dev->product_desc, dev->attached ? ", attached" : ""); } @@ -249,7 +249,8 @@ void usb_info(Monitor *mon) if (!dev) continue; monitor_printf(mon, " Device %d.%d, Speed %s Mb/s, Product %s\n", - bus->busnr, dev->addr, usb_speed(dev->speed), dev->devname); + bus->busnr, dev->addr, usb_speed(dev->speed), + dev->product_desc); } } } diff --git a/hw/usb-hid.c b/hw/usb-hid.c index f4a2a481e..6abb62993 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -701,7 +701,7 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, break; case 2: /* product description */ - ret = set_usb_string(data, s->dev.devname); + ret = set_usb_string(data, s->dev.product_desc); break; case 3: /* vendor description */ @@ -880,8 +880,8 @@ void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *)) static struct USBDeviceInfo hid_info[] = { { - .qdev.name = "QEMU USB Tablet", - .qdev.alias = "usb-tablet", + .product_desc = "QEMU USB Tablet", + .qdev.name = "usb-tablet", .usbdevice_name = "tablet", .qdev.size = sizeof(USBHIDState), .init = usb_tablet_initfn, @@ -891,8 +891,8 @@ static struct USBDeviceInfo hid_info[] = { .handle_data = usb_hid_handle_data, .handle_destroy = usb_hid_handle_destroy, },{ - .qdev.name = "QEMU USB Mouse", - .qdev.alias = "usb-mouse", + .product_desc = "QEMU USB Mouse", + .qdev.name = "usb-mouse", .usbdevice_name = "mouse", .qdev.size = sizeof(USBHIDState), .init = usb_mouse_initfn, @@ -902,8 +902,8 @@ static struct USBDeviceInfo hid_info[] = { .handle_data = usb_hid_handle_data, .handle_destroy = usb_hid_handle_destroy, },{ - .qdev.name = "QEMU USB Keyboard", - .qdev.alias = "usb-kbd", + .product_desc = "QEMU USB Keyboard", + .qdev.name = "usb-kbd", .usbdevice_name = "keyboard", .qdev.size = sizeof(USBHIDState), .init = usb_keyboard_initfn, diff --git a/hw/usb-hub.c b/hw/usb-hub.c index e5a093877..acf7f6072 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -544,7 +544,8 @@ static int usb_hub_initfn(USBDevice *dev) } static struct USBDeviceInfo hub_info = { - .qdev.name = "QEMU USB Hub", + .product_desc = "QEMU USB Hub", + .qdev.name = "usb-hub", .qdev.size = sizeof(USBHubState), .init = usb_hub_initfn, .handle_packet = usb_hub_handle_packet, diff --git a/hw/usb-msd.c b/hw/usb-msd.c index bb39b625a..1fb62ad13 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -591,7 +591,7 @@ static USBDevice *usb_msd_init(const char *filename) } /* create guest device */ - dev = usb_create(NULL /* FIXME */, "QEMU USB MSD"); + dev = usb_create(NULL /* FIXME */, "usb-storage"); qdev_prop_set_drive(&dev->qdev, "drive", dinfo); if (qdev_init(&dev->qdev) < 0) return NULL; @@ -600,8 +600,8 @@ static USBDevice *usb_msd_init(const char *filename) } static struct USBDeviceInfo msd_info = { - .qdev.name = "QEMU USB MSD", - .qdev.alias = "usb-storage", + .product_desc = "QEMU USB MSD", + .qdev.name = "usb-storage", .qdev.size = sizeof(MSDState), .init = usb_msd_initfn, .handle_packet = usb_generic_handle_packet, diff --git a/hw/usb-net.c b/hw/usb-net.c index 2556e05dd..122a0d849 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1463,7 +1463,7 @@ USBDevice *usb_net_init(NICInfo *nd) USBDevice *dev; USBNetState *s; - dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Network Interface"); + dev = usb_create_simple(NULL /* FIXME */, "usb-net"); s = DO_UPCAST(USBNetState, dev, dev); memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr)); @@ -1487,7 +1487,8 @@ USBDevice *usb_net_init(NICInfo *nd) } static struct USBDeviceInfo net_info = { - .qdev.name = "QEMU USB Network Interface", + .product_desc = "QEMU USB Network Interface", + .qdev.name = "usb-net", .qdev.size = sizeof(USBNetState), .init = usb_net_initfn, .handle_packet = usb_generic_handle_packet, diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 7ab3a9861..a8a014cb1 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1736,7 +1736,7 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev) void usb_ohci_init_pci(struct PCIBus *bus, int devfn) { - pci_create_simple(bus, devfn, "OHCI USB PCI"); + pci_create_simple(bus, devfn, "pci-ohci"); } void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, @@ -1762,8 +1762,7 @@ void usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base, } static PCIDeviceInfo ohci_info = { - .qdev.name = "OHCI USB PCI", - .qdev.alias = "pci-ohci", + .qdev.name = "pci-ohci", .qdev.desc = "Apple USB Controller", .qdev.size = sizeof(OHCIPCIState), .init = usb_ohci_initfn_pci, diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 223d4c385..2775cf0f0 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -577,7 +577,7 @@ static USBDevice *usb_serial_init(const char *filename) if (!cdrv) return NULL; - dev = usb_create(NULL /* FIXME */, "QEMU USB Serial"); + dev = usb_create(NULL /* FIXME */, "usb-serial"); qdev_prop_set_chr(&dev->qdev, "chardev", cdrv); if (vendorid) qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid); @@ -597,7 +597,7 @@ static USBDevice *usb_braille_init(const char *unused) if (!cdrv) return NULL; - dev = usb_create(NULL /* FIXME */, "QEMU USB Braille"); + dev = usb_create(NULL /* FIXME */, "usb-braille"); qdev_prop_set_chr(&dev->qdev, "chardev", cdrv); qdev_init(&dev->qdev); @@ -605,8 +605,8 @@ static USBDevice *usb_braille_init(const char *unused) } static struct USBDeviceInfo serial_info = { - .qdev.name = "QEMU USB Serial", - .qdev.alias = "usb-serial", + .product_desc = "QEMU USB Serial", + .qdev.name = "usb-serial", .qdev.size = sizeof(USBSerialState), .init = usb_serial_initfn, .handle_packet = usb_generic_handle_packet, @@ -625,8 +625,8 @@ static struct USBDeviceInfo serial_info = { }; static struct USBDeviceInfo braille_info = { - .qdev.name = "QEMU USB Braille", - .qdev.alias = "usb-braille", + .product_desc = "QEMU USB Braille", + .qdev.name = "usb-braille", .qdev.size = sizeof(USBSerialState), .init = usb_serial_initfn, .handle_packet = usb_generic_handle_packet, diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index ba26a4efc..dc52737ae 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1111,12 +1111,12 @@ static int usb_uhci_piix4_initfn(PCIDevice *dev) static PCIDeviceInfo uhci_info[] = { { - .qdev.name = "PIIX3 USB-UHCI", + .qdev.name = "piix3-usb-uhci", .qdev.size = sizeof(UHCIState), .qdev.vmsd = &vmstate_uhci, .init = usb_uhci_piix3_initfn, },{ - .qdev.name = "PIIX4 USB-UHCI", + .qdev.name = "piix4-usb-uhci", .qdev.size = sizeof(UHCIState), .qdev.vmsd = &vmstate_uhci, .init = usb_uhci_piix4_initfn, @@ -1133,10 +1133,10 @@ device_init(uhci_register); void usb_uhci_piix3_init(PCIBus *bus, int devfn) { - pci_create_simple(bus, devfn, "PIIX3 USB-UHCI"); + pci_create_simple(bus, devfn, "piix3-usb-uhci"); } void usb_uhci_piix4_init(PCIBus *bus, int devfn) { - pci_create_simple(bus, devfn, "PIIX4 USB-UHCI"); + pci_create_simple(bus, devfn, "piix4-usb-uhci"); } diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index ef6137637..fe052eb75 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -409,8 +409,9 @@ static int usb_wacom_initfn(USBDevice *dev) } static struct USBDeviceInfo wacom_info = { - .qdev.name = "QEMU PenPartner Tablet", - .qdev.alias = "wacom-tablet", + .product_desc = "QEMU PenPartner Tablet", + .qdev.name = "usb-wacom-tablet", + .qdev.desc = "QEMU PenPartner Tablet", .usbdevice_name = "wacom-tablet", .qdev.size = sizeof(USBWacomState), .init = usb_wacom_initfn, @@ -132,7 +132,7 @@ struct USBDevice { int speed; uint8_t addr; - char devname[32]; + char product_desc[32]; int auto_attach; int attached; @@ -185,6 +185,8 @@ struct USBDeviceInfo { */ int (*handle_data)(USBDevice *dev, USBPacket *p); + const char *product_desc; + /* handle legacy -usbdevice command line options */ const char *usbdevice_name; USBDevice *(*usbdevice_init)(const char *params); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index d222ce03f..450013091 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -236,9 +236,7 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr) switch (addr) { case VIRTIO_PCI_HOST_FEATURES: ret = vdev->get_features(vdev); - ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); - ret |= (1 << VIRTIO_RING_F_INDIRECT_DESC); - ret |= (1 << VIRTIO_F_BAD_FEATURE); + ret |= vdev->binding->get_features(proxy); break; case VIRTIO_PCI_GUEST_FEATURES: ret = vdev->features; @@ -382,12 +380,22 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, msix_write_config(pci_dev, address, val, len); } +static unsigned virtio_pci_get_features(void *opaque) +{ + unsigned ret = 0; + ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); + ret |= (1 << VIRTIO_RING_F_INDIRECT_DESC); + ret |= (1 << VIRTIO_F_BAD_FEATURE); + return ret; +} + static const VirtIOBindings virtio_pci_bindings = { .notify = virtio_pci_notify, .save_config = virtio_pci_save_config, .load_config = virtio_pci_load_config, .save_queue = virtio_pci_save_queue, .load_queue = virtio_pci_load_queue, + .get_features = virtio_pci_get_features, }; static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev, diff --git a/hw/virtio.c b/hw/virtio.c index 1f92171f6..cecd0dc04 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -651,6 +651,9 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) int virtio_load(VirtIODevice *vdev, QEMUFile *f) { int num, i, ret; + uint32_t features; + uint32_t supported_features = vdev->get_features(vdev) | + vdev->binding->get_features(vdev->binding_opaque); if (vdev->binding->load_config) { ret = vdev->binding->load_config(vdev->binding_opaque, f); @@ -661,7 +664,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) qemu_get_8s(f, &vdev->status); qemu_get_8s(f, &vdev->isr); qemu_get_be16s(f, &vdev->queue_sel); - qemu_get_be32s(f, &vdev->features); + qemu_get_be32s(f, &features); + if (features & ~supported_features) { + fprintf(stderr, "Features 0x%x unsupported. Allowed features: 0x%x\n", + features, supported_features); + return -1; + } + vdev->features = features; vdev->config_len = qemu_get_be32(f); qemu_get_buffer(f, vdev->config, vdev->config_len); diff --git a/hw/virtio.h b/hw/virtio.h index 15ad91076..35532a6f2 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -31,6 +31,11 @@ /* We've given up on this device. */ #define VIRTIO_CONFIG_S_FAILED 0x80 +/* Some virtio feature bits (currently bits 28 through 31) are reserved for the + * transport being used (eg. virtio_ring), the rest are per-device feature bits. */ +#define VIRTIO_TRANSPORT_F_START 28 +#define VIRTIO_TRANSPORT_F_END 32 + /* We notify when the ring is completely used, even if the guest is suppressing * callbacks */ #define VIRTIO_F_NOTIFY_ON_EMPTY 24 @@ -82,6 +87,7 @@ typedef struct { void (*save_queue)(void * opaque, int n, QEMUFile *f); int (*load_config)(void * opaque, QEMUFile *f); int (*load_queue)(void * opaque, int n, QEMUFile *f); + unsigned (*get_features)(void * opaque); } VirtIOBindings; #define VIRTIO_PCI_QUEUE_MAX 16 diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 240731a1b..f3e3749e9 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "hw.h" +#include "loader.h" #include "console.h" #include "pci.h" #include "vmware_vga.h" @@ -1124,6 +1125,7 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size) cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, vga_ram_size, s->vga.vram_offset); #endif + rom_add_vga(VGABIOS_FILENAME); } static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num, @@ -1194,11 +1196,11 @@ static int pci_vmsvga_initfn(PCIDevice *dev) void pci_vmsvga_init(PCIBus *bus) { - pci_create_simple(bus, -1, "QEMUware SVGA"); + pci_create_simple(bus, -1, "vmware-svga"); } static PCIDeviceInfo vmsvga_info = { - .qdev.name = "QEMUware SVGA", + .qdev.name = "vmware-svga", .qdev.size = sizeof(struct pci_vmsvga_state_s), .qdev.vmsd = &vmstate_vmware_vga, .init = pci_vmsvga_initfn, diff --git a/linux-user/main.c b/linux-user/main.c index 5fbcda2a3..e51539eff 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -593,6 +593,7 @@ static int do_strex(CPUARMState *env) } rc = 0; fail: + env->regs[15] += 4; env->regs[(env->exclusive_info >> 4) & 0xf] = rc; done: end_exclusive(); diff --git a/migration.c b/migration.c index d6a3e2615..fda61e642 100644 --- a/migration.c +++ b/migration.c @@ -19,6 +19,7 @@ #include "block.h" #include "qemu_socket.h" #include "block-migration.h" +#include "qemu-objects.h" //#define DEBUG_MIGRATION @@ -163,37 +164,123 @@ void do_migrate_set_downtime(Monitor *mon, const QDict *qdict) max_downtime = (uint64_t)d; } -void do_info_migrate(Monitor *mon) +static void migrate_print_status(Monitor *mon, const char *name, + const QDict *status_dict) { + QDict *qdict; + + qdict = qobject_to_qdict(qdict_get(status_dict, name)); + + monitor_printf(mon, "transferred %s: %" PRIu64 " kbytes\n", name, + qdict_get_int(qdict, "transferred") >> 10); + monitor_printf(mon, "remaining %s: %" PRIu64 " kbytes\n", name, + qdict_get_int(qdict, "remaining") >> 10); + monitor_printf(mon, "total %s: %" PRIu64 " kbytes\n", name, + qdict_get_int(qdict, "total") >> 10); +} + +void do_info_migrate_print(Monitor *mon, const QObject *data) +{ + QDict *qdict; + + qdict = qobject_to_qdict(data); + + monitor_printf(mon, "Migration status: %s\n", + qdict_get_str(qdict, "status")); + + if (qdict_haskey(qdict, "ram")) { + migrate_print_status(mon, "ram", qdict); + } + + if (qdict_haskey(qdict, "disk")) { + migrate_print_status(mon, "disk", qdict); + } +} + +static void migrate_put_status(QDict *qdict, const char *name, + uint64_t trans, uint64_t rem, uint64_t total) +{ + QObject *obj; + + obj = qobject_from_jsonf("{ 'transferred': %" PRId64 ", " + "'remaining': %" PRId64 ", " + "'total': %" PRId64 " }", trans, rem, total); + assert(obj != NULL); + + qdict_put_obj(qdict, name, obj); +} + +/** + * do_info_migrate(): Migration status + * + * Return a QDict. If migration is active there will be another + * QDict with RAM migration status and if block migration is active + * another one with block migration status. + * + * The main QDict contains the following: + * + * - "status": migration status + * - "ram": only present if "status" is "active", it is a QDict with the + * following RAM information (in bytes): + * - "transferred": amount transferred + * - "remaining": amount remaining + * - "total": total + * - "disk": only present if "status" is "active" and it is a block migration, + * it is a QDict with the following disk information (in bytes): + * - "transferred": amount transferred + * - "remaining": amount remaining + * - "total": total + * + * Examples: + * + * 1. Migration is "completed": + * + * { "status": "completed" } + * + * 2. Migration is "active" and it is not a block migration: + * + * { "status": "active", + * "ram": { "transferred": 123, "remaining": 123, "total": 246 } } + * + * 3. Migration is "active" and it is a block migration: + * + * { "status": "active", + * "ram": { "total": 1057024, "remaining": 1053304, "transferred": 3720 }, + * "disk": { "total": 20971520, "remaining": 20880384, "transferred": 91136 }} + */ +void do_info_migrate(Monitor *mon, QObject **ret_data) +{ + QDict *qdict; MigrationState *s = current_migration; if (s) { - monitor_printf(mon, "Migration status: "); switch (s->get_status(s)) { case MIG_STATE_ACTIVE: - monitor_printf(mon, "active\n"); - monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n", ram_bytes_transferred() >> 10); - monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n", ram_bytes_remaining() >> 10); - monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n", ram_bytes_total() >> 10); + qdict = qdict_new(); + qdict_put(qdict, "status", qstring_from_str("active")); + + migrate_put_status(qdict, "ram", ram_bytes_transferred(), + ram_bytes_remaining(), ram_bytes_total()); + if (blk_mig_active()) { - monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n", - blk_mig_bytes_transferred() >> 10); - monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n", - blk_mig_bytes_remaining() >> 10); - monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n", - blk_mig_bytes_total() >> 10); + migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(), + blk_mig_bytes_remaining(), + blk_mig_bytes_total()); } + + *ret_data = QOBJECT(qdict); break; case MIG_STATE_COMPLETED: - monitor_printf(mon, "completed\n"); + *ret_data = qobject_from_jsonf("{ 'status': 'completed' }"); break; case MIG_STATE_ERROR: - monitor_printf(mon, "failed\n"); + *ret_data = qobject_from_jsonf("{ 'status': 'failed' }"); break; case MIG_STATE_CANCELLED: - monitor_printf(mon, "cancelled\n"); + *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }"); break; } + assert(*ret_data != NULL); } } diff --git a/migration.h b/migration.h index 3f2b3df2b..3ac208bf5 100644 --- a/migration.h +++ b/migration.h @@ -62,7 +62,9 @@ uint64_t migrate_max_downtime(void); void do_migrate_set_downtime(Monitor *mon, const QDict *qdict); -void do_info_migrate(Monitor *mon); +void do_info_migrate_print(Monitor *mon, const QObject *data); + +void do_info_migrate(Monitor *mon, QObject **ret_data); int exec_start_incoming_migration(const char *host_port); @@ -151,7 +151,10 @@ static void monitor_read_command(Monitor *mon, int show_prompt) static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, void *opaque) { - if (mon->rs) { + if (monitor_ctrl_mode(mon)) { + qemu_error_new(QERR_MISSING_PARAMETER, "password"); + return -EINVAL; + } else if (mon->rs) { readline_start(mon->rs, "Password: ", 1, readline_func, opaque); /* prompt is printed on return from the command handler */ return 0; @@ -257,24 +260,6 @@ static inline int monitor_has_error(const Monitor *mon) return mon->error != NULL; } -static void monitor_print_qobject(Monitor *mon, const QObject *data) -{ - switch (qobject_type(data)) { - case QTYPE_QSTRING: - monitor_printf(mon, "%s",qstring_get_str(qobject_to_qstring(data))); - break; - case QTYPE_QINT: - monitor_printf(mon, "%" PRId64,qint_get_int(qobject_to_qint(data))); - break; - default: - monitor_printf(mon, "ERROR: unsupported type: %d", - qobject_type(data)); - break; - } - - monitor_puts(mon, "\n"); -} - static void monitor_json_emitter(Monitor *mon, const QObject *data) { QString *json; @@ -305,6 +290,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data) } } else { /* error response */ + qdict_put(mon->error->error, "desc", qerror_human(mon->error)); qdict_put(qmp, "error", mon->error->error); QINCREF(mon->error->error); QDECREF(mon->error); @@ -503,24 +489,91 @@ help: help_cmd(mon, "info"); } +static void do_info_version_print(Monitor *mon, const QObject *data) +{ + QDict *qdict; + + qdict = qobject_to_qdict(data); + + monitor_printf(mon, "%s%s\n", qdict_get_str(qdict, "qemu"), + qdict_get_str(qdict, "package")); +} + /** * do_info_version(): Show QEMU version + * + * Return a QDict with the following information: + * + * - "qemu": QEMU's version + * - "package": package's version + * + * Example: + * + * { "qemu": "0.11.50", "package": "" } */ static void do_info_version(Monitor *mon, QObject **ret_data) { - *ret_data = QOBJECT(qstring_from_str(QEMU_VERSION QEMU_PKGVERSION)); + *ret_data = qobject_from_jsonf("{ 'qemu': %s, 'package': %s }", + QEMU_VERSION, QEMU_PKGVERSION); } -static void do_info_name(Monitor *mon) +static void do_info_name_print(Monitor *mon, const QObject *data) { - if (qemu_name) - monitor_printf(mon, "%s\n", qemu_name); + QDict *qdict; + + qdict = qobject_to_qdict(data); + if (qdict_size(qdict) == 0) { + return; + } + + monitor_printf(mon, "%s\n", qdict_get_str(qdict, "name")); +} + +/** + * do_info_name(): Show VM name + * + * Return a QDict with the following information: + * + * - "name": VM's name (optional) + * + * Example: + * + * { "name": "qemu-name" } + */ +static void do_info_name(Monitor *mon, QObject **ret_data) +{ + *ret_data = qemu_name ? qobject_from_jsonf("{'name': %s }", qemu_name) : + qobject_from_jsonf("{}"); +} + +static QObject *get_cmd_dict(const char *name) +{ + const char *p; + + /* Remove '|' from some commands */ + p = strchr(name, '|'); + if (p) { + p++; + } else { + p = name; + } + + return qobject_from_jsonf("{ 'name': %s }", p); } /** * do_info_commands(): List QMP available commands * - * Return a QList of QStrings. + * Each command is represented by a QDict, the returned QObject is a QList + * of all commands. + * + * The QDict contains: + * + * - "name": command's name + * + * Example: + * + * { [ { "name": "query-balloon" }, { "name": "system_powerdown" } ] } */ static void do_info_commands(Monitor *mon, QObject **ret_data) { @@ -531,7 +584,7 @@ static void do_info_commands(Monitor *mon, QObject **ret_data) for (cmd = mon_cmds; cmd->name != NULL; cmd++) { if (monitor_handler_ported(cmd) && !compare_cmd(cmd->name, "info")) { - qlist_append(cmd_list, qstring_from_str(cmd->name)); + qlist_append_obj(cmd_list, get_cmd_dict(cmd->name)); } } @@ -539,7 +592,7 @@ static void do_info_commands(Monitor *mon, QObject **ret_data) if (monitor_handler_ported(cmd)) { char buf[128]; snprintf(buf, sizeof(buf), "query-%s", cmd->name); - qlist_append(cmd_list, qstring_from_str(buf)); + qlist_append_obj(cmd_list, get_cmd_dict(buf)); } } @@ -547,20 +600,56 @@ static void do_info_commands(Monitor *mon, QObject **ret_data) } #if defined(TARGET_I386) -static void do_info_hpet(Monitor *mon) +static void do_info_hpet_print(Monitor *mon, const QObject *data) { monitor_printf(mon, "HPET is %s by QEMU\n", - (no_hpet) ? "disabled" : "enabled"); + qdict_get_bool(qobject_to_qdict(data), "enabled") ? + "enabled" : "disabled"); +} + +/** + * do_info_hpet(): Show HPET state + * + * Return a QDict with the following information: + * + * - "enabled": true if hpet if enabled, false otherwise + * + * Example: + * + * { "enabled": true } + */ +static void do_info_hpet(Monitor *mon, QObject **ret_data) +{ + *ret_data = qobject_from_jsonf("{ 'enabled': %i }", !no_hpet); } #endif -static void do_info_uuid(Monitor *mon) +static void do_info_uuid_print(Monitor *mon, const QObject *data) { - monitor_printf(mon, UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], + monitor_printf(mon, "%s\n", qdict_get_str(qobject_to_qdict(data), "UUID")); +} + +/** + * do_info_uuid(): Show VM UUID + * + * Return a QDict with the following information: + * + * - "UUID": Universally Unique Identifier + * + * Example: + * + * { "UUID": "550e8400-e29b-41d4-a716-446655440000" } + */ +static void do_info_uuid(Monitor *mon, QObject **ret_data) +{ + char uuid[64]; + + snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]); + *ret_data = qobject_from_jsonf("{ 'UUID': %s }", uuid); } /* get the current CPU defined by the user */ @@ -611,8 +700,9 @@ static void print_cpu_iter(QObject *obj, void *opaque) assert(qobject_type(obj) == QTYPE_QDICT); cpu = qobject_to_qdict(obj); - if (strcmp(qdict_get_str(cpu, "current"), "yes") == 0) + if (qdict_get_bool(cpu, "current")) { active = '*'; + } monitor_printf(mon, "%c CPU #%d: ", active, (int)qdict_get_int(cpu, "CPU")); @@ -632,8 +722,9 @@ static void print_cpu_iter(QObject *obj, void *opaque) (target_long) qdict_get_int(cpu, "PC")); #endif - if (strcmp(qdict_get_str(cpu, "halted"), "yes") == 0) + if (qdict_get_bool(cpu, "halted")) { monitor_printf(mon, " (halted)"); + } monitor_printf(mon, " thread_id=%" PRId64 " ", qdict_get_int(cpu, "thread_id")); @@ -653,12 +744,21 @@ static void monitor_print_cpus(Monitor *mon, const QObject *data) /** * do_info_cpus(): Show CPU information * - * Return a QList with a QDict for each CPU. + * Return a QList. Each CPU is represented by a QDict, which contains: + * + * - "cpu": CPU index + * - "current": true if this is the current CPU, false otherwise + * - "halted": true if the cpu is halted, false otherwise + * - Current program counter. The key's name depends on the architecture: + * "pc": i386/x86)64 + * "nip": PPC + * "pc" and "npc": sparc + * "PC": mips * - * For example: + * Example: * - * [ { "CPU": 0, "current": "yes", "pc": 0x..., "halted": "no" }, - * { "CPU": 1, "current": "no", "pc": 0x..., "halted": "yes" } ] + * [ { "CPU": 0, "current": true, "halted": false, "pc": 3227107138 }, + * { "CPU": 1, "current": false, "halted": true, "pc": 7108165 } ] */ static void do_info_cpus(Monitor *mon, QObject **ret_data) { @@ -671,15 +771,19 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data) mon_get_cpu(); for(env = first_cpu; env != NULL; env = env->next_cpu) { - const char *answer; - QDict *cpu = qdict_new(); + QDict *cpu; + QObject *obj; cpu_synchronize_state(env); kvm_save_mpstate(env); - qdict_put(cpu, "CPU", qint_from_int(env->cpu_index)); - answer = (env == mon->mon_cpu) ? "yes" : "no"; - qdict_put(cpu, "current", qstring_from_str(answer)); + obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }", + env->cpu_index, env == mon->mon_cpu, + env->halted); + assert(obj != NULL); + + cpu = qobject_to_qdict(obj); + #if defined(TARGET_I386) qdict_put(cpu, "pc", qint_from_int(env->eip + env->segs[R_CS].base)); #elif defined(TARGET_PPC) @@ -690,8 +794,6 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data) #elif defined(TARGET_MIPS) qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC)); #endif - answer = env->halted ? "yes" : "no"; - qdict_put(cpu, "halted", qstring_from_str(answer)); qdict_put(cpu, "thread_id", qint_from_int(env->thread_id)); qlist_append(cpu_list, cpu); @@ -774,11 +876,12 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force) if (bdrv_is_inserted(bs)) { if (!force) { if (!bdrv_is_removable(bs)) { - monitor_printf(mon, "device is not removable\n"); + qemu_error_new(QERR_DEVICE_NOT_REMOVABLE, + bdrv_get_device_name(bs)); return -1; } if (bdrv_is_locked(bs)) { - monitor_printf(mon, "device is locked\n"); + qemu_error_new(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); return -1; } } @@ -795,12 +898,28 @@ static void do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) bs = bdrv_find(filename); if (!bs) { - monitor_printf(mon, "device not found\n"); + qemu_error_new(QERR_DEVICE_NOT_FOUND, filename); return; } eject_device(mon, bs, force); } +static void do_block_set_passwd(Monitor *mon, const QDict *qdict, + QObject **ret_data) +{ + BlockDriverState *bs; + + bs = bdrv_find(qdict_get_str(qdict, "device")); + if (!bs) { + qemu_error_new(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device")); + return; + } + + if (bdrv_set_key(bs, qdict_get_str(qdict, "password")) < 0) { + qemu_error_new(QERR_INVALID_PASSWORD); + } +} + static void do_change_block(Monitor *mon, const char *device, const char *filename, const char *fmt) { @@ -809,13 +928,13 @@ static void do_change_block(Monitor *mon, const char *device, bs = bdrv_find(device); if (!bs) { - monitor_printf(mon, "device not found\n"); + qemu_error_new(QERR_DEVICE_NOT_FOUND, device); return; } if (fmt) { drv = bdrv_find_whitelisted_format(fmt); if (!drv) { - monitor_printf(mon, "invalid format %s\n", fmt); + qemu_error_new(QERR_INVALID_BLOCK_FORMAT, fmt); return; } } @@ -825,12 +944,17 @@ static void do_change_block(Monitor *mon, const char *device, monitor_read_bdrv_key_start(mon, bs, NULL, NULL); } -static void change_vnc_password_cb(Monitor *mon, const char *password, - void *opaque) +static void change_vnc_password(const char *password) { if (vnc_display_password(NULL, password) < 0) - monitor_printf(mon, "could not set VNC server password\n"); + qemu_error_new(QERR_SET_PASSWD_FAILED); +} + +static void change_vnc_password_cb(Monitor *mon, const char *password, + void *opaque) +{ + change_vnc_password(password); monitor_read_command(mon, 1); } @@ -842,17 +966,20 @@ static void do_change_vnc(Monitor *mon, const char *target, const char *arg) char password[9]; strncpy(password, arg, sizeof(password)); password[sizeof(password) - 1] = '\0'; - change_vnc_password_cb(mon, password, NULL); + change_vnc_password(password); } else { monitor_read_password(mon, change_vnc_password_cb, NULL); } } else { if (vnc_display_open(NULL, target) < 0) - monitor_printf(mon, "could not start VNC server on %s\n", target); + qemu_error_new(QERR_VNC_SERVER_FAILED, target); } } -static void do_change(Monitor *mon, const QDict *qdict) +/** + * do_change(): Change a removable medium, or VNC configuration + */ +static void do_change(Monitor *mon, const QDict *qdict, QObject **ret_data) { const char *device = qdict_get_str(qdict, "device"); const char *target = qdict_get_str(qdict, "target"); @@ -1768,16 +1895,40 @@ static void tlb_info(Monitor *mon) #endif -static void do_info_kvm(Monitor *mon) +static void do_info_kvm_print(Monitor *mon, const QObject *data) { -#if defined(USE_KVM) || defined(CONFIG_KVM) + QDict *qdict; + + qdict = qobject_to_qdict(data); + monitor_printf(mon, "kvm support: "); - if (kvm_enabled()) - monitor_printf(mon, "enabled\n"); - else - monitor_printf(mon, "disabled\n"); + if (qdict_get_bool(qdict, "present")) { + monitor_printf(mon, "%s\n", qdict_get_bool(qdict, "enabled") ? + "enabled" : "disabled"); + } else { + monitor_printf(mon, "not compiled\n"); + } +} + +/** + * do_info_kvm(): Show KVM information + * + * Return a QDict with the following information: + * + * - "enabled": true if KVM support is enabled, false otherwise + * - "present": true if QEMU has KVM support, false otherwise + * + * Example: + * + * { "enabled": true, "present": true } + */ +static void do_info_kvm(Monitor *mon, QObject **ret_data) +{ +#ifdef CONFIG_KVM + *ret_data = qobject_from_jsonf("{ 'enabled': %i, 'present': true }", + kvm_enabled()); #else - monitor_printf(mon, "kvm support: not compiled\n"); + *ret_data = qobject_from_jsonf("{ 'enabled': false, 'present': false }"); #endif } @@ -1898,16 +2049,41 @@ static void do_inject_nmi(Monitor *mon, const QDict *qdict) } #endif -static void do_info_status(Monitor *mon) +static void do_info_status_print(Monitor *mon, const QObject *data) { - if (vm_running) { - if (singlestep) { - monitor_printf(mon, "VM status: running (single step mode)\n"); - } else { - monitor_printf(mon, "VM status: running\n"); + QDict *qdict; + + qdict = qobject_to_qdict(data); + + monitor_printf(mon, "VM status: "); + if (qdict_get_bool(qdict, "running")) { + monitor_printf(mon, "running"); + if (qdict_get_bool(qdict, "singlestep")) { + monitor_printf(mon, " (single step mode)"); } - } else - monitor_printf(mon, "VM status: paused\n"); + } else { + monitor_printf(mon, "paused"); + } + + monitor_printf(mon, "\n"); +} + +/** + * do_info_status(): VM status + * + * Return a QDict with the following information: + * + * - "running": true if the VM is running, or false if it is paused + * - "singlestep": true if the VM is in single step mode, false otherwise + * + * Example: + * + * { "running": true, "singlestep": false } + */ +static void do_info_status(Monitor *mon, QObject **ret_data) +{ + *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }", + vm_running, singlestep); } /** @@ -1922,12 +2098,24 @@ static void do_balloon(Monitor *mon, const QDict *qdict, QObject **ret_data) static void monitor_print_balloon(Monitor *mon, const QObject *data) { - monitor_printf(mon, "balloon: actual=%d\n", - (int)qint_get_int(qobject_to_qint(data))); + QDict *qdict; + + qdict = qobject_to_qdict(data); + + monitor_printf(mon, "balloon: actual=%" PRId64 "\n", + qdict_get_int(qdict, "balloon") >> 20); } /** * do_info_balloon(): Balloon information + * + * Return a QDict with the following information: + * + * - "balloon": current balloon value in bytes + * + * Example: + * + * { "balloon": 1073741824 } */ static void do_info_balloon(Monitor *mon, QObject **ret_data) { @@ -1939,7 +2127,8 @@ static void do_info_balloon(Monitor *mon, QObject **ret_data) else if (actual == 0) qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon"); else - *ret_data = QOBJECT(qint_from_int((int)(actual >> 20))); + *ret_data = qobject_from_jsonf("{ 'balloon': %" PRId64 "}", + (int64_t) actual); } static qemu_acl *find_acl(Monitor *mon, const char *name) @@ -2075,19 +2264,21 @@ static void do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data) fd = qemu_chr_get_msgfd(mon->chr); if (fd == -1) { - monitor_printf(mon, "getfd: no file descriptor supplied via SCM_RIGHTS\n"); + qemu_error_new(QERR_FD_NOT_SUPPLIED); return; } if (qemu_isdigit(fdname[0])) { - monitor_printf(mon, "getfd: monitor names may not begin with a number\n"); + qemu_error_new(QERR_INVALID_PARAMETER, "fdname"); return; } fd = dup(fd); if (fd == -1) { - monitor_printf(mon, "Failed to dup() file descriptor: %s\n", - strerror(errno)); + if (errno == EMFILE) + qemu_error_new(QERR_TOO_MANY_FILES); + else + qemu_error_new(QERR_UNDEFINED_ERROR); return; } @@ -2125,8 +2316,7 @@ static void do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data) return; } - monitor_printf(mon, "Failed to find file descriptor named %s\n", - fdname); + qemu_error_new(QERR_FD_NOT_FOUND, fdname); } static void do_loadvm(Monitor *mon, const QDict *qdict) @@ -2176,7 +2366,7 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the version of QEMU", - .user_print = monitor_print_qobject, + .user_print = do_info_version_print, .mhandler.info_new = do_info_version, }, { @@ -2199,21 +2389,24 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the character devices", - .mhandler.info = qemu_chr_info, + .user_print = qemu_chr_info_print, + .mhandler.info_new = qemu_chr_info, }, { .name = "block", .args_type = "", .params = "", .help = "show the block devices", - .mhandler.info = bdrv_info, + .user_print = bdrv_info_print, + .mhandler.info_new = bdrv_info, }, { .name = "blockstats", .args_type = "", .params = "", .help = "show block device statistics", - .mhandler.info = bdrv_info_stats, + .user_print = bdrv_stats_print, + .mhandler.info_new = bdrv_info_stats, }, { .name = "registers", @@ -2280,7 +2473,8 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show state of HPET", - .mhandler.info = do_info_hpet, + .user_print = do_info_hpet_print, + .mhandler.info_new = do_info_hpet, }, #endif { @@ -2295,7 +2489,8 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show KVM information", - .mhandler.info = do_info_kvm, + .user_print = do_info_kvm_print, + .mhandler.info_new = do_info_kvm, }, { .name = "numa", @@ -2344,7 +2539,8 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the current VM status (running|paused)", - .mhandler.info = do_info_status, + .user_print = do_info_status_print, + .mhandler.info_new = do_info_status, }, { .name = "pcmcia", @@ -2358,28 +2554,32 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show which guest mouse is receiving events", - .mhandler.info = do_info_mice, + .user_print = do_info_mice_print, + .mhandler.info_new = do_info_mice, }, { .name = "vnc", .args_type = "", .params = "", .help = "show the vnc server status", - .mhandler.info = do_info_vnc, + .user_print = do_info_vnc_print, + .mhandler.info_new = do_info_vnc, }, { .name = "name", .args_type = "", .params = "", .help = "show the current VM name", - .mhandler.info = do_info_name, + .user_print = do_info_name_print, + .mhandler.info_new = do_info_name, }, { .name = "uuid", .args_type = "", .params = "", .help = "show the current VM UUID", - .mhandler.info = do_info_uuid, + .user_print = do_info_uuid_print, + .mhandler.info_new = do_info_uuid, }, #if defined(TARGET_PPC) { @@ -2404,7 +2604,8 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show migration status", - .mhandler.info = do_info_migrate, + .user_print = do_info_migrate_print, + .mhandler.info_new = do_info_migrate, }, { .name = "balloon", @@ -4040,24 +4241,6 @@ static void monitor_event(void *opaque, int event) * End: */ -const char *monitor_cmdline_parse(const char *cmdline, int *flags) -{ - const char *dev; - - if (strstart(cmdline, "control,", &dev)) { - if (strstart(dev, "vc", NULL)) { - fprintf(stderr, "qemu: control mode is for low-level interaction "); - fprintf(stderr, "cannot be used with device 'vc'\n"); - exit(1); - } - *flags &= ~MONITOR_USE_READLINE; - *flags |= MONITOR_USE_CONTROL; - return dev; - } - - return cmdline; -} - void monitor_init(CharDriverState *chr, int flags) { static int is_first_init = 1; @@ -4119,6 +4302,11 @@ void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, return; } + if (monitor_ctrl_mode(mon)) { + qemu_error_new(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs)); + return; + } + monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs), bdrv_get_encrypted_filename(bs)); @@ -24,7 +24,6 @@ typedef enum MonitorEvent { } MonitorEvent; void monitor_protocol_event(MonitorEvent event, QObject *data); -const char *monitor_cmdline_parse(const char *cmdline, int *flags); void monitor_init(CharDriverState *chr, int flags); int monitor_suspend(Monitor *mon); @@ -39,6 +39,8 @@ static QTAILQ_HEAD(, VLANState) vlans; static QTAILQ_HEAD(, VLANClientState) non_vlan_clients; +int default_net = 1; + /***********************************************************/ /* network device redirectors */ @@ -1317,7 +1319,7 @@ static int net_init_netdev(QemuOpts *opts, void *dummy) int net_init_clients(void) { - if (QTAILQ_EMPTY(&qemu_net_opts.head)) { + if (default_net) { /* if no clients, we use a default config */ qemu_opts_set(&qemu_net_opts, NULL, "type", "nic"); #ifdef CONFIG_SLIRP @@ -1353,5 +1355,6 @@ int net_client_parse(QemuOptsList *opts_list, const char *optarg) return -1; } + default_net = 0; return 0; } @@ -139,6 +139,7 @@ struct NICInfo { extern int nb_nics; extern NICInfo nd_table[MAX_NICS]; +extern int default_net; /* BT HCI info */ diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc Binary files differindex 3941c0bf5..badcb9c04 100755..100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex 2454b4a2e..596e5eed9 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex 271718123..017d68cbd 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 @@ -12,6 +12,7 @@ #include "qint.h" #include "qdict.h" +#include "qbool.h" #include "qstring.h" #include "qobject.h" #include "qemu-queue.h" @@ -189,6 +190,33 @@ int64_t qdict_get_int(const QDict *qdict, const char *key) } /** + * qdict_get_bool(): Get a bool mapped by 'key' + * + * This function assumes that 'key' exists and it stores a + * QBool object. + * + * Return bool mapped by 'key'. + */ +int qdict_get_bool(const QDict *qdict, const char *key) +{ + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QBOOL); + return qbool_get_int(qobject_to_qbool(obj)); +} + +/** + * qdict_get_qlist(): Get the QList mapped by 'key' + * + * This function assumes that 'key' exists and it stores a + * QList object. + * + * Return QList mapped by 'key'. + */ +QList *qdict_get_qlist(const QDict *qdict, const char *key) +{ + return qobject_to_qlist(qdict_get_obj(qdict, key, QTYPE_QLIST)); +} + +/** * qdict_get_str(): Get a pointer to the stored string mapped * by 'key' * @@ -2,6 +2,7 @@ #define QDICT_H #include "qobject.h" +#include "qlist.h" #include "qemu-queue.h" #include <stdint.h> @@ -37,6 +38,8 @@ void qdict_iter(const QDict *qdict, /* High level helpers */ int64_t qdict_get_int(const QDict *qdict, const char *key); +int qdict_get_bool(const QDict *qdict, const char *key); +QList *qdict_get_qlist(const QDict *qdict, const char *key); const char *qdict_get_str(const QDict *qdict, const char *key); int64_t qdict_get_try_int(const QDict *qdict, const char *key, int64_t err_value); diff --git a/qemu-char.c b/qemu-char.c index da5c15c4f..b13f8d4cf 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -32,6 +32,7 @@ #include "hw/usb.h" #include "hw/baum.h" #include "hw/msmouse.h" +#include "qemu-objects.h" #include <unistd.h> #include <fcntl.h> @@ -2231,7 +2232,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) return NULL; } -static QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) +QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { char host[65], port[33], width[8], height[8]; int pos; @@ -2469,13 +2470,51 @@ void qemu_chr_close(CharDriverState *chr) qemu_free(chr); } -void qemu_chr_info(Monitor *mon) +static void qemu_chr_qlist_iter(QObject *obj, void *opaque) { + QDict *chr_dict; + Monitor *mon = opaque; + + chr_dict = qobject_to_qdict(obj); + monitor_printf(mon, "%s: filename=%s\n", qdict_get_str(chr_dict, "label"), + qdict_get_str(chr_dict, "filename")); +} + +void qemu_chr_info_print(Monitor *mon, const QObject *ret_data) +{ + qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon); +} + +/** + * qemu_chr_info(): Character devices information + * + * Each device is represented by a QDict. The returned QObject is a QList + * of all devices. + * + * The QDict contains the following: + * + * - "label": device's label + * - "filename": device's file + * + * Example: + * + * [ { "label": "monitor", "filename", "stdio" }, + * { "label": "serial0", "filename": "vc" } ] + */ +void qemu_chr_info(Monitor *mon, QObject **ret_data) +{ + QList *chr_list; CharDriverState *chr; + chr_list = qlist_new(); + QTAILQ_FOREACH(chr, &chardevs, next) { - monitor_printf(mon, "%s: filename=%s\n", chr->label, chr->filename); + QObject *obj = qobject_from_jsonf("{ 'label': %s, 'filename': %s }", + chr->label, chr->filename); + qlist_append_obj(chr_list, obj); } + + *ret_data = QOBJECT(chr_list); } CharDriverState *qemu_chr_find(const char *name) diff --git a/qemu-char.h b/qemu-char.h index 9957db1f5..bcc07664d 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -5,6 +5,7 @@ #include "qemu-queue.h" #include "qemu-option.h" #include "qemu-config.h" +#include "qobject.h" /* character device */ @@ -69,6 +70,7 @@ struct CharDriverState { QTAILQ_ENTRY(CharDriverState) next; }; +QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename); CharDriverState *qemu_chr_open_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s)); CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s)); @@ -87,7 +89,8 @@ int qemu_chr_can_read(CharDriverState *s); void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); int qemu_chr_get_msgfd(CharDriverState *s); void qemu_chr_accept_input(CharDriverState *s); -void qemu_chr_info(Monitor *mon); +void qemu_chr_info_print(Monitor *mon, const QObject *ret_data); +void qemu_chr_info(Monitor *mon, QObject **ret_data); CharDriverState *qemu_chr_find(const char *name); extern int term_escape_char; diff --git a/qemu-config.c b/qemu-config.c index 6dd173120..2caf76c93 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -2,6 +2,7 @@ #include "qemu-option.h" #include "qemu-config.h" #include "sysemu.h" +#include "hw/qdev.h" QemuOptsList qemu_drive_opts = { .name = "drive", @@ -209,6 +210,42 @@ QemuOptsList qemu_rtc_opts = { }, }; +QemuOptsList qemu_global_opts = { + .name = "global", + .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head), + .desc = { + { + .name = "driver", + .type = QEMU_OPT_STRING, + },{ + .name = "property", + .type = QEMU_OPT_STRING, + },{ + .name = "value", + .type = QEMU_OPT_STRING, + }, + { /* end if list */ } + }, +}; + +QemuOptsList qemu_mon_opts = { + .name = "mon", + .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head), + .desc = { + { + .name = "mode", + .type = QEMU_OPT_STRING, + },{ + .name = "chardev", + .type = QEMU_OPT_STRING, + },{ + .name = "default", + .type = QEMU_OPT_BOOL, + }, + { /* end if list */ } + }, +}; + static QemuOptsList *lists[] = { &qemu_drive_opts, &qemu_chardev_opts, @@ -216,6 +253,8 @@ static QemuOptsList *lists[] = { &qemu_netdev_opts, &qemu_net_opts, &qemu_rtc_opts, + &qemu_global_opts, + &qemu_mon_opts, NULL, }; @@ -264,6 +303,42 @@ int qemu_set_option(const char *str) return 0; } +int qemu_global_option(const char *str) +{ + char driver[64], property[64]; + QemuOpts *opts; + int rc, offset; + + rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset); + if (rc < 2 || str[offset] != '=') { + qemu_error("can't parse: \"%s\"\n", str); + return -1; + } + + opts = qemu_opts_create(&qemu_global_opts, NULL, 0); + qemu_opt_set(opts, "driver", driver); + qemu_opt_set(opts, "property", property); + qemu_opt_set(opts, "value", str+offset+1); + return 0; +} + +static int qemu_add_one_global(QemuOpts *opts, void *opaque) +{ + GlobalProperty *g; + + g = qemu_mallocz(sizeof(*g)); + g->driver = qemu_opt_get(opts, "driver"); + g->property = qemu_opt_get(opts, "property"); + g->value = qemu_opt_get(opts, "value"); + qdev_prop_register_global(g); + return 0; +} + +void qemu_add_globals(void) +{ + qemu_opts_foreach(&qemu_global_opts, qemu_add_one_global, NULL, 0); +} + struct ConfigWriteData { QemuOptsList *list; FILE *fp; diff --git a/qemu-config.h b/qemu-config.h index b56485165..34dfadc5f 100644 --- a/qemu-config.h +++ b/qemu-config.h @@ -7,8 +7,11 @@ extern QemuOptsList qemu_device_opts; extern QemuOptsList qemu_netdev_opts; extern QemuOptsList qemu_net_opts; extern QemuOptsList qemu_rtc_opts; +extern QemuOptsList qemu_mon_opts; int qemu_set_option(const char *str); +int qemu_global_option(const char *str); +void qemu_add_globals(void); void qemu_config_write(FILE *fp); int qemu_config_parse(FILE *fp); diff --git a/qemu-malloc.c b/qemu-malloc.c index 295d1856e..5d9e34d69 100644 --- a/qemu-malloc.c +++ b/qemu-malloc.c @@ -42,22 +42,29 @@ void qemu_free(void *ptr) free(ptr); } +static int allow_zero_malloc(void) +{ +#if defined(CONFIG_ZERO_MALLOC) + return 1; +#else + return 0; +#endif +} + void *qemu_malloc(size_t size) { - if (!size) { + if (!size && !allow_zero_malloc()) { abort(); } - return oom_check(malloc(size)); + return oom_check(malloc(size ? size : 1)); } void *qemu_realloc(void *ptr, size_t size) { if (size) { return oom_check(realloc(ptr, size)); - } else { - if (ptr) { - return realloc(ptr, size); - } + } else if (allow_zero_malloc()) { + return oom_check(realloc(ptr, size ? size : 1)); } abort(); } diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 2b14802d7..de5b9feb4 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -147,7 +147,8 @@ ETEXI .args_type = "device:B,target:F,arg:s?", .params = "device filename [format]", .help = "change a removable medium, optional format", - .mhandler.cmd = do_change, + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_change, }, STEXI @@ -809,7 +810,8 @@ ETEXI .args_type = "pci_addr:s,type:s,opts:s?", .params = "auto|[[<domain>:]<bus>:]<slot> nic|storage|host [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]... [host=02:00.0[,name=string][,dma=none]", .help = "hot-add PCI device", - .mhandler.cmd = pci_device_hot_add, + .user_print = pci_device_hot_add_print, + .mhandler.cmd_new = pci_device_hot_add, }, #endif @@ -1048,6 +1050,20 @@ 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} +Set the encrypted device @var{device} password to @var{password} +ETEXI + + { .name = "cpu_set", .args_type = "cpu:i,state:s", .params = "cpu [online|offline]", diff --git a/qemu-objects.h b/qemu-objects.h new file mode 100644 index 000000000..e1d1e0ca7 --- /dev/null +++ b/qemu-objects.h @@ -0,0 +1,24 @@ +/* + * Include all QEMU objects. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#ifndef QEMU_OBJECTS_H +#define QEMU_OBJECTS_H + +#include "qobject.h" +#include "qint.h" +#include "qfloat.h" +#include "qbool.h" +#include "qstring.h" +#include "qdict.h" +#include "qlist.h" +#include "qjson.h" + +#endif /* QEMU_OBJECTS_H */ diff --git a/qemu-option.c b/qemu-option.c index b00910900..24392fcb4 100644 --- a/qemu-option.c +++ b/qemu-option.c @@ -705,7 +705,7 @@ int qemu_opts_print(QemuOpts *opts, void *dummy) int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname) { - char option[128], value[128]; + char option[128], value[1024]; const char *p,*pe,*pc; for (p = params; *p != '\0'; p++) { @@ -751,7 +751,7 @@ int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname) { - char value[128], *id = NULL; + char value[1024], *id = NULL; const char *p; QemuOpts *opts; diff --git a/qemu-options.hx b/qemu-options.hx index fff751b01..812d0670a 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -110,6 +110,9 @@ DEF("set", HAS_ARG, QEMU_OPTION_set, "-set group.id.arg=value\n" " set <arg> parameter for item <id> of type <group>\n" " i.e. -set drive.$id.file=/path/to/image\n") +DEF("global", HAS_ARG, QEMU_OPTION_global, + "-global driver.property=value\n" + " set a global default for a driver property\n") STEXI @item -drive @var{option}[,@var{option}[,@var{option}[,...]]] @@ -1578,14 +1581,22 @@ Use @code{-parallel none} to disable all parallel ports. ETEXI DEF("monitor", HAS_ARG, QEMU_OPTION_monitor, \ - "-monitor [control,]dev redirect the monitor to char device 'dev'\n") + "-monitor dev redirect the monitor to char device 'dev'\n") STEXI -@item -monitor [@var{control},]@var{dev} +@item -monitor @var{dev} Redirect the monitor to host device @var{dev} (same devices as the serial port). The default device is @code{vc} in graphical mode and @code{stdio} in non graphical mode. -The option @var{control} enables the QEMU Monitor Protocol. +ETEXI +DEF("qmp", HAS_ARG, QEMU_OPTION_qmp, \ + "-qmp dev like -monitor but opens in 'control' mode.\n") + +DEF("mon", HAS_ARG, QEMU_OPTION_mon, \ + "-mon chardev=[name][,mode=readline|control][,default]\n") +STEXI +@item -mon chardev=[name][,mode=readline|control][,default] +Setup monitor on chardev @var{name}. ETEXI DEF("pidfile", HAS_ARG, QEMU_OPTION_pidfile, \ @@ -1880,6 +1891,11 @@ DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \ STEXI ETEXI +DEF("nodefaults", 0, QEMU_OPTION_nodefaults, \ + "-nodefaults don't create default devices.\n") +STEXI +ETEXI + #ifndef _WIN32 DEF("chroot", HAS_ARG, QEMU_OPTION_chroot, \ "-chroot dir Chroot to dir just before starting the VM.\n") @@ -41,20 +41,56 @@ static const QType qerror_type = { */ static const QErrorStringTable qerror_table[] = { { - .error_fmt = QERR_COMMAND_NOT_FOUND, - .desc = "The command %(name) has not been found", + .error_fmt = QERR_COMMAND_NOT_FOUND, + .desc = "The command %(name) has not been found", }, { - .error_fmt = QERR_DEVICE_NOT_FOUND, - .desc = "The %(device) device has not been found", + .error_fmt = QERR_DEVICE_ENCRYPTED, + .desc = "The %(device) is encrypted", + }, + { + .error_fmt = QERR_DEVICE_LOCKED, + .desc = "Device %(device) is locked", }, { .error_fmt = QERR_DEVICE_NOT_ACTIVE, .desc = "The %(device) device has not been activated by the guest", }, { - .error_fmt = QERR_INVALID_PARAMETER_TYPE, - .desc = "Invalid parameter type, expected: %(expected)", + .error_fmt = QERR_DEVICE_NOT_FOUND, + .desc = "The %(device) device has not been found", + }, + { + .error_fmt = QERR_DEVICE_NOT_REMOVABLE, + .desc = "Device %(device) is not removable", + }, + { + .error_fmt = QERR_FD_NOT_FOUND, + .desc = "Failed to find file descriptor named %(name)", + }, + { + .error_fmt = QERR_FD_NOT_SUPPLIED, + .desc = "No file descriptor supplied via SCM_RIGHTS", + }, + { + .error_fmt = QERR_INVALID_BLOCK_FORMAT, + .desc = "Invalid block format %(name)", + }, + { + .error_fmt = QERR_INVALID_PARAMETER, + .desc = "Invalid parameter %(name)", + }, + { + .error_fmt = QERR_INVALID_PARAMETER_TYPE, + .desc = "Invalid parameter type, expected: %(expected)", + }, + { + .error_fmt = QERR_INVALID_PASSWORD, + .desc = "The entered password is invalid", + }, + { + .error_fmt = QERR_JSON_PARSING, + .desc = "Invalid JSON syntax", }, { .error_fmt = QERR_KVM_MISSING_CAP, @@ -69,12 +105,20 @@ static const QErrorStringTable qerror_table[] = { .desc = "Bad QMP input object", }, { - .error_fmt = QERR_JSON_PARSING, - .desc = "Invalid JSON synaxt", + .error_fmt = QERR_SET_PASSWD_FAILED, + .desc = "Could not set password", + }, + { + .error_fmt = QERR_TOO_MANY_FILES, + .desc = "Too many open files", + }, + { + .error_fmt = QERR_UNDEFINED_ERROR, + .desc = "An undefined error has ocurred", }, { - .error_fmt = QERR_UNDEFINED_ERROR, - .desc = "An undefined error has ocurred", + .error_fmt = QERR_VNC_SERVER_FAILED, + .desc = "Could not start VNC server on %(target)", }, {} }; @@ -239,13 +283,11 @@ static const char *append_field(QString *outstr, const QError *qerror, } /** - * qerror_print(): Print QError data + * qerror_human(): Format QError data into human-readable string. * - * This function will print the member 'desc' of the specified QError object, - * it uses qemu_error() for this, so that the output is routed to the right - * place (ie. stderr or Monitor's device). + * Formats according to member 'desc' of the specified QError object. */ -void qerror_print(const QError *qerror) +QString *qerror_human(const QError *qerror) { const char *p; QString *qstring; @@ -265,6 +307,19 @@ void qerror_print(const QError *qerror) } } + return qstring; +} + +/** + * qerror_print(): Print QError data + * + * This function will print the member 'desc' of the specified QError object, + * it uses qemu_error() for this, so that the output is routed to the right + * place (ie. stderr or Monitor's device). + */ +void qerror_print(const QError *qerror) +{ + QString *qstring = qerror_human(qerror); qemu_error("%s\n", qstring_get_str(qstring)); QDECREF(qstring); } @@ -13,6 +13,7 @@ #define QERROR_H #include "qdict.h" +#include "qstring.h" #include <stdarg.h> typedef struct QErrorStringTable { @@ -32,6 +33,7 @@ typedef struct QError { QError *qerror_new(void); QError *qerror_from_info(const char *file, int linenr, const char *func, const char *fmt, va_list *va); +QString *qerror_human(const QError *qerror); void qerror_print(const QError *qerror); QError *qobject_to_qerror(const QObject *obj); @@ -39,30 +41,63 @@ QError *qobject_to_qerror(const QObject *obj); * QError class list */ #define QERR_COMMAND_NOT_FOUND \ - "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" + "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" -#define QERR_DEVICE_NOT_FOUND \ - "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }" +#define QERR_DEVICE_ENCRYPTED \ + "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }" + +#define QERR_DEVICE_LOCKED \ + "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" #define QERR_DEVICE_NOT_ACTIVE \ - "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" + "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" + +#define QERR_DEVICE_NOT_FOUND \ + "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }" + +#define QERR_DEVICE_NOT_REMOVABLE \ + "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }" + +#define QERR_FD_NOT_FOUND \ + "{ 'class': 'FdNotFound', 'data': { 'name': %s } }" + +#define QERR_FD_NOT_SUPPLIED \ + "{ 'class': 'FdNotSupplied', 'data': {} }" + +#define QERR_INVALID_BLOCK_FORMAT \ + "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" + +#define QERR_INVALID_PARAMETER \ + "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }" #define QERR_INVALID_PARAMETER_TYPE \ - "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }" + "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }" + +#define QERR_INVALID_PASSWORD \ + "{ 'class': 'InvalidPassword', 'data': {} }" + +#define QERR_JSON_PARSING \ + "{ 'class': 'JSONParsing', 'data': {} }" #define QERR_KVM_MISSING_CAP \ - "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }" + "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }" #define QERR_MISSING_PARAMETER \ - "{ 'class': 'MissingParameter', 'data': { 'name': %s } }" + "{ 'class': 'MissingParameter', 'data': { 'name': %s } }" #define QERR_QMP_BAD_INPUT_OBJECT \ - "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" + "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" -#define QERR_JSON_PARSING \ - "{ 'class': 'JSONParsing', 'data': {} }" +#define QERR_SET_PASSWD_FAILED \ + "{ 'class': 'SetPasswdFailed', 'data': {} }" #define QERR_UNDEFINED_ERROR \ - "{ 'class': 'UndefinedError', 'data': {} }" + "{ 'class': 'UndefinedError', 'data': {} }" + +#define QERR_TOO_MANY_FILES \ + "{ 'class': 'TooManyFiles', 'data': {} }" + +#define QERR_VNC_SERVER_FAILED \ + "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" #endif /* QERROR_H */ @@ -47,3 +47,6 @@ cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \ %.h-timestamp: %.mak $(call quiet-command, sh $(SRC_PATH)/create_config < $< > $@, " GEN $*.h") @cmp $@ $*.h >/dev/null 2>&1 || cp $@ $*.h + +# will delete the target of a rule if commands exit with a nonzero exit status +.DELETE_ON_ERROR: @@ -218,7 +218,8 @@ void qemu_system_cpu_hot_add(int cpu, int state); DriveInfo *add_init_drive(const char *opts); /* pci-hotplug */ -void pci_device_hot_add(Monitor *mon, const QDict *qdict); +void pci_device_hot_add_print(Monitor *mon, const QObject *data); +void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data); void drive_hot_add(Monitor *mon, const QDict *qdict); void pci_device_hot_remove(Monitor *mon, const char *pci_addr); void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict, diff --git a/target-i386/helper.c b/target-i386/helper.c index fd32b2ee9..9a50da64d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -133,10 +133,11 @@ static x86_def_t x86_defs[] = { CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | /* this feature is needed for Solaris and isn't fully implemented */ CPUID_PSE36, - .ext_features = CPUID_EXT_SSE3, + .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT, .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, - .ext3_features = CPUID_EXT3_SVM, + .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | + CPUID_EXT3_ABM | CPUID_EXT3_SSE4A, .xlevel = 0x8000000A, .model_id = "QEMU Virtual CPU version " QEMU_VERSION, }, @@ -153,18 +154,19 @@ static x86_def_t x86_defs[] = { .features = PPRO_FEATURES | CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_PSE36, - /* Missing: CPUID_EXT_CX16, CPUID_EXT_POPCNT */ - .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR, + .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 | + CPUID_EXT_POPCNT, /* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */ .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT | CPUID_EXT2_FFXSR, - /* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC, - CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A, + /* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC, + CPUID_EXT3_CR8LEG, CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH, CPUID_EXT3_OSVW, CPUID_EXT3_IBS */ - .ext3_features = CPUID_EXT3_SVM, + .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | + CPUID_EXT3_ABM | CPUID_EXT3_SSE4A, .xlevel = 0x8000001A, .model_id = "AMD Phenom(tm) 9550 Quad-Core Processor" }, @@ -185,7 +187,7 @@ static x86_def_t x86_defs[] = { CPUID_EXT_TM2, CPUID_EXT_CX16, CPUID_EXT_XTPR, CPUID_EXT_PDCM */ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3, .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, - /* Missing: .ext3_features = CPUID_EXT3_LAHF_LM */ + .ext3_features = CPUID_EXT3_LAHF_LM, .xlevel = 0x80000008, .model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz", }, @@ -223,7 +225,7 @@ static x86_def_t x86_defs[] = { .model = 3, .stepping = 3, .features = PPRO_FEATURES, - .ext_features = CPUID_EXT_SSE3, + .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT, .xlevel = 0, .model_id = "QEMU Virtual CPU version " QEMU_VERSION, }, @@ -1645,6 +1647,24 @@ static void host_cpuid(uint32_t function, uint32_t count, #endif } +static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + *ebx = env->cpuid_vendor1; + *edx = env->cpuid_vendor2; + *ecx = env->cpuid_vendor3; + + /* sysenter isn't supported on compatibility mode on AMD, syscall + * isn't supported in compatibility mode on Intel. + * Normally we advertise the actual cpu vendor, but you can override + * this if you want to use KVM's sysenter/syscall emulation + * in compatibility mode and when doing cross vendor migration + */ + if (kvm_enabled() && env->cpuid_vendor_override) { + host_cpuid(0, 0, NULL, ebx, ecx, edx); + } +} + void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) @@ -1661,16 +1681,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, switch(index) { case 0: *eax = env->cpuid_level; - *ebx = env->cpuid_vendor1; - *edx = env->cpuid_vendor2; - *ecx = env->cpuid_vendor3; - - /* sysenter isn't supported on compatibility mode on AMD. and syscall - * isn't supported in compatibility mode on Intel. so advertise the - * actuall cpu, and say goodbye to migration between different vendors - * is you use compatibility mode. */ - if (kvm_enabled() && !env->cpuid_vendor_override) - host_cpuid(0, 0, NULL, ebx, ecx, edx); + get_cpuid_vendor(env, ebx, ecx, edx); break; case 1: *eax = env->cpuid_version; @@ -1766,11 +1777,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ecx = env->cpuid_ext3_features; *edx = env->cpuid_ext2_features; - if (env->nr_cores * env->nr_threads > 1 && - env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && - env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && - env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) { - *ecx |= 1 << 1; /* CmpLegacy bit */ + /* The Linux kernel checks for the CMPLegacy bit and + * discards multiple thread information if it is set. + * So dont set it here for Intel to make Linux guests happy. + */ + if (env->nr_cores * env->nr_threads > 1) { + uint32_t tebx, tecx, tedx; + get_cpuid_vendor(env, &tebx, &tecx, &tedx); + if (tebx != CPUID_VENDOR_INTEL_1 || + tedx != CPUID_VENDOR_INTEL_2 || + tecx != CPUID_VENDOR_INTEL_3) { + *ecx |= 1 << 1; /* CmpLegacy bit */ + } } if (kvm_enabled()) { diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 568e2117b..bb9012a3e 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -36,6 +36,9 @@ do { } while (0) #endif +#define MSR_KVM_WALL_CLOCK 0x11 +#define MSR_KVM_SYSTEM_TIME 0x12 + #ifdef KVM_CAP_EXT_CPUID static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max) @@ -245,9 +248,9 @@ static int kvm_has_msr_star(CPUState *env) * save/restore */ msr_list.nmsrs = 0; ret = kvm_ioctl(env->kvm_state, KVM_GET_MSR_INDEX_LIST, &msr_list); - if (ret < 0) + if (ret < 0 && ret != -E2BIG) { return 0; - + } /* Old kernel modules had a bug and could write beyond the provided memory. Allocate at least a safe amount of 1K. */ kvm_msr_list = qemu_mallocz(MAX(1024, sizeof(msr_list) + @@ -496,6 +499,9 @@ static int kvm_put_msrs(CPUState *env) kvm_msr_entry_set(&msrs[n++], MSR_FMASK, env->fmask); kvm_msr_entry_set(&msrs[n++], MSR_LSTAR, env->lstar); #endif + kvm_msr_entry_set(&msrs[n++], MSR_KVM_SYSTEM_TIME, env->system_time_msr); + kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr); + msr_data.info.nmsrs = n; return kvm_vcpu_ioctl(env, KVM_SET_MSRS, &msr_data); @@ -637,6 +643,9 @@ static int kvm_get_msrs(CPUState *env) msrs[n++].index = MSR_FMASK; msrs[n++].index = MSR_LSTAR; #endif + msrs[n++].index = MSR_KVM_SYSTEM_TIME; + msrs[n++].index = MSR_KVM_WALL_CLOCK; + msr_data.info.nmsrs = n; ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &msr_data); if (ret < 0) @@ -673,6 +682,12 @@ static int kvm_get_msrs(CPUState *env) case MSR_IA32_TSC: env->tsc = msrs[i].data; break; + case MSR_KVM_SYSTEM_TIME: + env->system_time_msr = msrs[i].data; + break; + case MSR_KVM_WALL_CLOCK: + env->wall_clock_msr = msrs[i].data; + break; case MSR_VM_HSAVE_PA: env->vm_hsave = msrs[i].data; break; diff --git a/target-i386/machine.c b/target-i386/machine.c index 402eddc7e..804002e66 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -465,6 +465,7 @@ static const VMStateDescription vmstate_cpu = { VMSTATE_UINT8_V(nmi_pending, CPUState, 11), VMSTATE_UINT8_V(has_error_code, CPUState, 11), VMSTATE_UINT32_V(sipi_vector, CPUState, 11), + VMSTATE_INT32_V(exception_index, CPUState, 11), /* MCE */ VMSTATE_UINT64_V(mcg_cap, CPUState, 10), VMSTATE_UINT64_V(mcg_status, CPUState, 10), @@ -473,8 +474,8 @@ static const VMStateDescription vmstate_cpu = { /* rdtscp */ VMSTATE_UINT64_V(tsc_aux, CPUState, 11), /* KVM pvclock msr */ - VMSTATE_UINT64_V(system_time_msr, CPUState, 12), - VMSTATE_UINT64_V(wall_clock_msr, CPUState, 12), + VMSTATE_UINT64_V(system_time_msr, CPUState, 11), + VMSTATE_UINT64_V(wall_clock_msr, CPUState, 11), VMSTATE_END_OF_LIST() /* The above list is not sorted /wrt version numbers, watch out! */ } @@ -361,7 +361,7 @@ USBDevice *usb_host_device_open(const char *devname) goto fail; } - d = usb_create(NULL /* FIXME */, "USB Host Device"); + d = usb_create(NULL /* FIXME */, "usb-host"); dev = DO_UPCAST(USBHostDevice, dev, d); if (dev_info.udi_speed == 1) @@ -370,10 +370,10 @@ USBDevice *usb_host_device_open(const char *devname) dev->dev.speed = USB_SPEED_FULL - 1; if (strncmp(dev_info.udi_product, "product", 7) != 0) - pstrcpy(dev->dev.devname, sizeof(dev->dev.devname), + pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc), dev_info.udi_product); else - snprintf(dev->dev.devname, sizeof(dev->dev.devname), + snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc), "host:%s", devname); pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/"); @@ -393,7 +393,8 @@ fail: } static struct USBDeviceInfo usb_host_dev_info = { - .qdev.name = "USB Host Device", + .product_desc = "USB Host Device", + .qdev.name = "usb-host", .qdev.size = sizeof(USBHostDevice), .init = usb_host_initfn, .handle_packet = usb_generic_handle_packet, diff --git a/usb-linux.c b/usb-linux.c index 285ac227a..105ce88f3 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -933,10 +933,10 @@ static int usb_host_open(USBHostDevice *dev, int bus_num, dev->dev.speed = USB_SPEED_HIGH; if (!prod_name || prod_name[0] == '\0') - snprintf(dev->dev.devname, sizeof(dev->dev.devname), + snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc), "host:%d.%d", bus_num, addr); else - pstrcpy(dev->dev.devname, sizeof(dev->dev.devname), + pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc), prod_name); /* USB devio uses 'write' flag to check for async completions */ @@ -979,8 +979,8 @@ static int usb_host_initfn(USBDevice *dev) } static struct USBDeviceInfo usb_host_dev_info = { - .qdev.name = "USB Host Device", - .qdev.alias = "usb-host", + .product_desc = "USB Host Device", + .qdev.name = "usb-host", .qdev.size = sizeof(USBHostDevice), .init = usb_host_initfn, .handle_packet = usb_host_handle_packet, @@ -1010,7 +1010,7 @@ USBDevice *usb_host_device_open(const char *devname) USBHostDevice *s; char *p; - dev = usb_create(NULL /* FIXME */, "USB Host Device"); + dev = usb_create(NULL /* FIXME */, "usb-host"); s = DO_UPCAST(USBHostDevice, dev, dev); if (strstr(devname, "auto:")) { @@ -156,6 +156,7 @@ int main(int argc, char **argv) #include "balloon.h" #include "qemu-option.h" #include "qemu-config.h" +#include "qemu-objects.h" #include "qemu-kvm.h" #include "hw/device-assignment.h" @@ -174,9 +175,6 @@ int main(int argc, char **argv) #define DEFAULT_RAM_SIZE 128 -/* Maximum number of monitor devices */ -#define MAX_MONITOR_DEVICES 10 - static const char *data_dir; const char *bios_name = NULL; /* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available @@ -196,7 +194,7 @@ int autostart; static int rtc_utc = 1; static int rtc_date_offset = -1; /* -1 means no change */ QEMUClock *rtc_clock; -int vga_interface_type = VGA_CIRRUS; +int vga_interface_type = VGA_NONE; #ifdef TARGET_SPARC int graphic_width = 1024; int graphic_height = 768; @@ -285,6 +283,41 @@ uint8_t qemu_uuid[16]; static QEMUBootSetHandler *boot_set_handler; static void *boot_set_opaque; +static int default_serial = 1; +static int default_parallel = 1; +static int default_virtcon = 1; +static int default_monitor = 1; +static int default_vga = 1; +static int default_drive = 1; + +static struct { + const char *driver; + int *flag; +} default_list[] = { + { .driver = "isa-serial", .flag = &default_serial }, + { .driver = "isa-parallel", .flag = &default_parallel }, + { .driver = "virtio-console-pci", .flag = &default_virtcon }, + { .driver = "virtio-console-s390", .flag = &default_virtcon }, + { .driver = "VGA", .flag = &default_vga }, + { .driver = "Cirrus VGA", .flag = &default_vga }, + { .driver = "QEMUware SVGA", .flag = &default_vga }, +}; + +static int default_driver_check(QemuOpts *opts, void *opaque) +{ + const char *driver = qemu_opt_get(opts, "driver"); + int i; + + if (!driver) + return 0; + for (i = 0; i < ARRAY_SIZE(default_list); i++) { + if (strcmp(default_list[i].driver, driver) != 0) + continue; + *(default_list[i].flag) = 0; + } + return 0; +} + /***********************************************************/ /* x86 ISA bus support */ @@ -472,25 +505,72 @@ int kbd_mouse_is_absolute(void) return qemu_put_mouse_event_current->qemu_put_mouse_event_absolute; } -void do_info_mice(Monitor *mon) +static void info_mice_iter(QObject *data, void *opaque) +{ + QDict *mouse; + Monitor *mon = opaque; + + mouse = qobject_to_qdict(data); + monitor_printf(mon, "%c Mouse #%" PRId64 ": %s\n", + (qdict_get_bool(mouse, "current") ? '*' : ' '), + qdict_get_int(mouse, "index"), qdict_get_str(mouse, "name")); +} + +void do_info_mice_print(Monitor *mon, const QObject *data) +{ + QList *mice_list; + + mice_list = qobject_to_qlist(data); + if (qlist_empty(mice_list)) { + monitor_printf(mon, "No mouse devices connected\n"); + return; + } + + qlist_iter(mice_list, info_mice_iter, mon); +} + +/** + * do_info_mice(): Show VM mice information + * + * Each mouse is represented by a QDict, the returned QObject is a QList of + * all mice. + * + * The mouse QDict contains the following: + * + * - "name": mouse's name + * - "index": mouse's index + * - "current": true if this mouse is receiving events, false otherwise + * + * Example: + * + * [ { "name": "QEMU Microsoft Mouse", "index": 0, "current": false }, + * { "name": "QEMU PS/2 Mouse", "index": 1, "current": true } ] + */ +void do_info_mice(Monitor *mon, QObject **ret_data) { QEMUPutMouseEntry *cursor; + QList *mice_list; int index = 0; + mice_list = qlist_new(); + if (!qemu_put_mouse_event_head) { - monitor_printf(mon, "No mouse devices connected\n"); - return; + goto out; } - monitor_printf(mon, "Mouse devices available:\n"); cursor = qemu_put_mouse_event_head; while (cursor != NULL) { - monitor_printf(mon, "%c Mouse #%d: %s\n", - (cursor == qemu_put_mouse_event_current ? '*' : ' '), - index, cursor->qemu_put_mouse_event_name); + QObject *obj; + obj = qobject_from_jsonf("{ 'name': %s, 'index': %d, 'current': %i }", + cursor->qemu_put_mouse_event_name, + index, cursor == qemu_put_mouse_event_current); + qlist_append_obj(mice_list, obj); index++; cursor = cursor->next; } + +out: + *ret_data = QOBJECT(mice_list); } void do_mouse_set(Monitor *mon, const QDict *qdict) @@ -4403,6 +4483,7 @@ static void select_vgahw (const char *p) { const char *opts; + default_vga = 0; vga_interface_type = VGA_NONE; if (strstart(p, "std", &opts)) { vga_interface_type = VGA_STD; @@ -4644,10 +4725,94 @@ static int device_init_func(QemuOpts *opts, void *opaque) return 0; } +static int chardev_init_func(QemuOpts *opts, void *opaque) +{ + CharDriverState *chr; + + chr = qemu_chr_open_opts(opts, NULL); + if (!chr) + return -1; + return 0; +} + +static int mon_init_func(QemuOpts *opts, void *opaque) +{ + CharDriverState *chr; + const char *chardev; + const char *mode; + int flags; + + mode = qemu_opt_get(opts, "mode"); + if (mode == NULL) { + mode = "readline"; + } + if (strcmp(mode, "readline") == 0) { + flags = MONITOR_USE_READLINE; + } else if (strcmp(mode, "control") == 0) { + flags = MONITOR_USE_CONTROL; + } else { + fprintf(stderr, "unknown monitor mode \"%s\"\n", mode); + exit(1); + } + + if (qemu_opt_get_bool(opts, "default", 0)) + flags |= MONITOR_IS_DEFAULT; + + chardev = qemu_opt_get(opts, "chardev"); + chr = qemu_chr_find(chardev); + if (chr == NULL) { + fprintf(stderr, "chardev \"%s\" not found\n", chardev); + exit(1); + } + + monitor_init(chr, flags); + return 0; +} + +static void monitor_parse(const char *optarg, const char *mode) +{ + static int monitor_device_index = 0; + QemuOpts *opts; + const char *p; + char label[32]; + int def = 0; + + if (strstart(optarg, "chardev:", &p)) { + snprintf(label, sizeof(label), "%s", p); + } else { + if (monitor_device_index) { + snprintf(label, sizeof(label), "monitor%d", + monitor_device_index); + } else { + snprintf(label, sizeof(label), "monitor"); + def = 1; + } + opts = qemu_chr_parse_compat(label, optarg); + if (!opts) { + fprintf(stderr, "parse error: %s\n", optarg); + exit(1); + } + } + + opts = qemu_opts_create(&qemu_mon_opts, label, 1); + if (!opts) { + fprintf(stderr, "duplicate chardev: %s\n", label); + exit(1); + } + qemu_opt_set(opts, "mode", mode); + qemu_opt_set(opts, "chardev", label); + if (def) + qemu_opt_set(opts, "default", "on"); + monitor_device_index++; +} + struct device_config { enum { - DEV_USB, /* -usbdevice */ - DEV_BT, /* -bt */ + DEV_USB, /* -usbdevice */ + DEV_BT, /* -bt */ + DEV_SERIAL, /* -serial */ + DEV_PARALLEL, /* -parallel */ + DEV_VIRTCON, /* -virtioconsole */ } type; const char *cmdline; QTAILQ_ENTRY(device_config) next; @@ -4679,6 +4844,72 @@ static int foreach_device_config(int type, int (*func)(const char *cmdline)) return 0; } +static int serial_parse(const char *devname) +{ + static int index = 0; + char label[32]; + + if (strcmp(devname, "none") == 0) + return 0; + if (index == MAX_SERIAL_PORTS) { + fprintf(stderr, "qemu: too many serial ports\n"); + exit(1); + } + snprintf(label, sizeof(label), "serial%d", index); + serial_hds[index] = qemu_chr_open(label, devname, NULL); + if (!serial_hds[index]) { + fprintf(stderr, "qemu: could not open serial device '%s': %s\n", + devname, strerror(errno)); + return -1; + } + index++; + return 0; +} + +static int parallel_parse(const char *devname) +{ + static int index = 0; + char label[32]; + + if (strcmp(devname, "none") == 0) + return 0; + if (index == MAX_PARALLEL_PORTS) { + fprintf(stderr, "qemu: too many parallel ports\n"); + exit(1); + } + snprintf(label, sizeof(label), "parallel%d", index); + parallel_hds[index] = qemu_chr_open(label, devname, NULL); + if (!parallel_hds[index]) { + fprintf(stderr, "qemu: could not open parallel device '%s': %s\n", + devname, strerror(errno)); + return -1; + } + index++; + return 0; +} + +static int virtcon_parse(const char *devname) +{ + static int index = 0; + char label[32]; + + if (strcmp(devname, "none") == 0) + return 0; + if (index == MAX_VIRTIO_CONSOLES) { + fprintf(stderr, "qemu: too many virtio consoles\n"); + exit(1); + } + snprintf(label, sizeof(label), "virtcon%d", index); + virtcon_hds[index] = qemu_chr_open(label, devname, NULL); + if (!virtcon_hds[index]) { + fprintf(stderr, "qemu: could not open virtio console '%s': %s\n", + devname, strerror(errno)); + return -1; + } + index++; + return 0; +} + int main(int argc, char **argv, char **envp) { const char *gdbstub_dev = NULL; @@ -4694,16 +4925,6 @@ int main(int argc, char **argv, char **envp) QemuOpts *hda_opts = NULL, *opts; int optind; const char *r, *optarg; - CharDriverState *monitor_hds[MAX_MONITOR_DEVICES]; - const char *monitor_devices[MAX_MONITOR_DEVICES]; - int monitor_flags[MAX_MONITOR_DEVICES]; - int monitor_device_index; - const char *serial_devices[MAX_SERIAL_PORTS]; - int serial_device_index; - const char *parallel_devices[MAX_PARALLEL_PORTS]; - int parallel_device_index; - const char *virtio_consoles[MAX_VIRTIO_CONSOLES]; - int virtio_console_index; const char *loadvm = NULL; QEMUMachine *machine; const char *cpu_model; @@ -4769,43 +4990,6 @@ int main(int argc, char **argv, char **envp) cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; -#ifdef TARGET_S390X - for(i = 0; i < MAX_SERIAL_PORTS; i++) - serial_devices[i] = NULL; - serial_device_index = 0; - - for(i = 0; i < MAX_PARALLEL_PORTS; i++) - parallel_devices[i] = NULL; - parallel_device_index = 0; - - virtio_consoles[0] = "mon:stdio"; - for(i = 1; i < MAX_VIRTIO_CONSOLES; i++) - virtio_consoles[i] = NULL; - virtio_console_index = 0; -#else - serial_devices[0] = "vc:80Cx24C"; - for(i = 1; i < MAX_SERIAL_PORTS; i++) - serial_devices[i] = NULL; - serial_device_index = 0; - - parallel_devices[0] = "vc:80Cx24C"; - for(i = 1; i < MAX_PARALLEL_PORTS; i++) - parallel_devices[i] = NULL; - parallel_device_index = 0; - - for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) - virtio_consoles[i] = NULL; - virtio_console_index = 0; -#endif - - monitor_devices[0] = "vc:80Cx24C"; - monitor_flags[0] = MONITOR_IS_DEFAULT | MONITOR_USE_READLINE; - for (i = 1; i < MAX_MONITOR_DEVICES; i++) { - monitor_devices[i] = NULL; - monitor_flags[i] = MONITOR_USE_READLINE; - } - monitor_device_index = 0; - for (i = 0; i < MAX_NODES; i++) { node_mem[i] = 0; node_cpumask[i] = 0; @@ -4911,6 +5095,10 @@ int main(int argc, char **argv, char **envp) if (qemu_set_option(optarg) != 0) exit(1); break; + case QEMU_OPTION_global: + if (qemu_global_option(optarg) != 0) + exit(1); + break; case QEMU_OPTION_mtdblock: drive_add(optarg, MTD_ALIAS); break; @@ -5221,14 +5409,20 @@ int main(int argc, char **argv, char **envp) break; } case QEMU_OPTION_monitor: - if (monitor_device_index >= MAX_MONITOR_DEVICES) { - fprintf(stderr, "qemu: too many monitor devices\n"); + monitor_parse(optarg, "readline"); + default_monitor = 0; + break; + case QEMU_OPTION_qmp: + monitor_parse(optarg, "control"); + default_monitor = 0; + break; + case QEMU_OPTION_mon: + opts = qemu_opts_parse(&qemu_mon_opts, optarg, "chardev"); + if (!opts) { + fprintf(stderr, "parse error: %s\n", optarg); exit(1); } - monitor_devices[monitor_device_index] = - monitor_cmdline_parse(optarg, - &monitor_flags[monitor_device_index]); - monitor_device_index++; + default_monitor = 0; break; case QEMU_OPTION_chardev: opts = qemu_opts_parse(&qemu_chardev_opts, optarg, "backend"); @@ -5236,17 +5430,10 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "parse error: %s\n", optarg); exit(1); } - if (qemu_chr_open_opts(opts, NULL) == NULL) { - exit(1); - } break; case QEMU_OPTION_serial: - if (serial_device_index >= MAX_SERIAL_PORTS) { - fprintf(stderr, "qemu: too many serial ports\n"); - exit(1); - } - serial_devices[serial_device_index] = optarg; - serial_device_index++; + add_device_config(DEV_SERIAL, optarg); + default_serial = 0; break; case QEMU_OPTION_watchdog: if (watchdog) { @@ -5263,20 +5450,12 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_virtiocon: - if (virtio_console_index >= MAX_VIRTIO_CONSOLES) { - fprintf(stderr, "qemu: too many virtio consoles\n"); - exit(1); - } - virtio_consoles[virtio_console_index] = optarg; - virtio_console_index++; + add_device_config(DEV_VIRTCON, optarg); + default_virtcon = 0; break; case QEMU_OPTION_parallel: - if (parallel_device_index >= MAX_PARALLEL_PORTS) { - fprintf(stderr, "qemu: too many parallel ports\n"); - exit(1); - } - parallel_devices[parallel_device_index] = optarg; - parallel_device_index++; + add_device_config(DEV_PARALLEL, optarg); + default_parallel = 0; break; case QEMU_OPTION_loadvm: loadvm = optarg; @@ -5515,6 +5694,15 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_incoming: incoming = optarg; break; + case QEMU_OPTION_nodefaults: + default_serial = 0; + default_parallel = 0; + default_virtcon = 0; + default_monitor = 0; + default_vga = 0; + default_net = 0; + default_drive = 0; + break; #ifndef _WIN32 case QEMU_OPTION_chroot: chroot_dir = optarg; @@ -5596,16 +5784,50 @@ int main(int argc, char **argv, char **envp) exit(1); } - if (display_type == DT_NOGRAPHIC) { - if (serial_device_index == 0) - serial_devices[0] = "stdio"; - if (parallel_device_index == 0) - parallel_devices[0] = "null"; - if (strncmp(monitor_devices[0], "vc", 2) == 0) { - monitor_devices[0] = "stdio"; - } + qemu_opts_foreach(&qemu_device_opts, default_driver_check, NULL, 0); + + if (machine->no_serial) { + default_serial = 0; + } + if (machine->no_parallel) { + default_parallel = 0; + } + if (!machine->use_virtcon) { + default_virtcon = 0; + } + if (machine->no_vga) { + default_vga = 0; } + if (display_type == DT_NOGRAPHIC) { + if (default_parallel) + add_device_config(DEV_PARALLEL, "null"); + if (default_serial && default_monitor) { + add_device_config(DEV_SERIAL, "mon:stdio"); + } else if (default_virtcon && default_monitor) { + add_device_config(DEV_VIRTCON, "mon:stdio"); + } else { + if (default_serial) + add_device_config(DEV_SERIAL, "stdio"); + if (default_virtcon) + add_device_config(DEV_VIRTCON, "stdio"); + if (default_monitor) + monitor_parse("stdio", "readline"); + } + } else { + if (default_serial) + add_device_config(DEV_SERIAL, "vc:80Cx24C"); + if (default_parallel) + add_device_config(DEV_PARALLEL, "vc:80Cx24C"); + if (default_monitor) + monitor_parse("vc:80Cx24C", "readline"); + } + if (default_vga) + vga_interface_type = VGA_CIRRUS; + + if (qemu_opts_foreach(&qemu_chardev_opts, chardev_init_func, NULL, 1) != 0) + exit(1); + #ifndef _WIN32 if (daemonize) { pid_t pid; @@ -5736,14 +5958,16 @@ int main(int argc, char **argv, char **envp) blk_mig_init(); - /* we always create the cdrom drive, even if no disk is there */ - drive_add(NULL, CDROM_ALIAS); + if (default_drive) { + /* we always create the cdrom drive, even if no disk is there */ + drive_add(NULL, CDROM_ALIAS); - /* we always create at least one floppy */ - drive_add(NULL, FD_ALIAS, 0); + /* we always create at least one floppy */ + drive_add(NULL, FD_ALIAS, 0); - /* we always create one sd slot, even if no card is in it */ - drive_add(NULL, SD_ALIAS); + /* we always create one sd slot, even if no card is in it */ + drive_add(NULL, SD_ALIAS); + } /* open the virtual block devices */ if (snapshot) @@ -5755,32 +5979,6 @@ int main(int argc, char **argv, char **envp) register_savevm_live("ram", 0, 3, NULL, ram_save_live, NULL, ram_load, NULL); - /* Maintain compatibility with multiple stdio monitors */ - if (!strcmp(monitor_devices[0],"stdio")) { - for (i = 0; i < MAX_SERIAL_PORTS; i++) { - const char *devname = serial_devices[i]; - if (devname && !strcmp(devname,"mon:stdio")) { - monitor_devices[0] = NULL; - break; - } else if (devname && !strcmp(devname,"stdio")) { - monitor_devices[0] = NULL; - serial_devices[i] = "mon:stdio"; - break; - } - } - for (i = 0; i < MAX_VIRTIO_CONSOLES; i++) { - const char *devname = virtio_consoles[i]; - if (devname && !strcmp(devname,"mon:stdio")) { - monitor_devices[0] = NULL; - break; - } else if (devname && !strcmp(devname,"stdio")) { - monitor_devices[0] = NULL; - virtio_consoles[i] = "mon:stdio"; - break; - } - } - } - if (nb_numa_nodes > 0) { int i; @@ -5823,65 +6021,12 @@ int main(int argc, char **argv, char **envp) } } - for (i = 0; i < MAX_MONITOR_DEVICES; i++) { - const char *devname = monitor_devices[i]; - if (devname && strcmp(devname, "none")) { - char label[32]; - if (i == 0) { - snprintf(label, sizeof(label), "monitor"); - } else { - snprintf(label, sizeof(label), "monitor%d", i); - } - monitor_hds[i] = qemu_chr_open(label, devname, NULL); - if (!monitor_hds[i]) { - fprintf(stderr, "qemu: could not open monitor device '%s'\n", - devname); - exit(1); - } - } - } - - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - const char *devname = serial_devices[i]; - if (devname && strcmp(devname, "none")) { - char label[32]; - snprintf(label, sizeof(label), "serial%d", i); - serial_hds[i] = qemu_chr_open(label, devname, NULL); - if (!serial_hds[i]) { - fprintf(stderr, "qemu: could not open serial device '%s': %s\n", - devname, strerror(errno)); - exit(1); - } - } - } - - for(i = 0; i < MAX_PARALLEL_PORTS; i++) { - const char *devname = parallel_devices[i]; - if (devname && strcmp(devname, "none")) { - char label[32]; - snprintf(label, sizeof(label), "parallel%d", i); - parallel_hds[i] = qemu_chr_open(label, devname, NULL); - if (!parallel_hds[i]) { - fprintf(stderr, "qemu: could not open parallel device '%s': %s\n", - devname, strerror(errno)); - exit(1); - } - } - } - - for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { - const char *devname = virtio_consoles[i]; - if (devname && strcmp(devname, "none")) { - char label[32]; - snprintf(label, sizeof(label), "virtcon%d", i); - virtcon_hds[i] = qemu_chr_open(label, devname, NULL); - if (!virtcon_hds[i]) { - fprintf(stderr, "qemu: could not open virtio console '%s': %s\n", - devname, strerror(errno)); - exit(1); - } - } - } + if (foreach_device_config(DEV_SERIAL, serial_parse) < 0) + exit(1); + if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0) + exit(1); + if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0) + exit(1); module_call_init(MODULE_INIT_DEVICE); @@ -5892,8 +6037,10 @@ int main(int argc, char **argv, char **envp) } if (machine->compat_props) { - qdev_prop_register_compat(machine->compat_props); + qdev_prop_register_global_list(machine->compat_props); } + qemu_add_globals(); + machine->init(ram_size, boot_devices, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); @@ -5986,35 +6133,8 @@ int main(int argc, char **argv, char **envp) text_consoles_set_display(display_state); - for (i = 0; i < MAX_MONITOR_DEVICES; i++) { - if (monitor_devices[i] && monitor_hds[i]) { - monitor_init(monitor_hds[i], monitor_flags[i]); - } - } - - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - const char *devname = serial_devices[i]; - if (devname && strcmp(devname, "none")) { - if (strstart(devname, "vc", 0)) - qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i); - } - } - - for(i = 0; i < MAX_PARALLEL_PORTS; i++) { - const char *devname = parallel_devices[i]; - if (devname && strcmp(devname, "none")) { - if (strstart(devname, "vc", 0)) - qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i); - } - } - - for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { - const char *devname = virtio_consoles[i]; - if (virtcon_hds[i] && devname) { - if (strstart(devname, "vc", 0)) - qemu_chr_printf(virtcon_hds[i], "virtio console%d\r\n", i); - } - } + if (qemu_opts_foreach(&qemu_mon_opts, mon_init_func, NULL, 1) != 0) + exit(1); if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) { fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n", @@ -29,6 +29,7 @@ #include "qemu_socket.h" #include "qemu-timer.h" #include "acl.h" +#include "qemu-objects.h" #define VNC_REFRESH_INTERVAL_BASE 30 #define VNC_REFRESH_INTERVAL_INC 50 @@ -99,6 +100,54 @@ char *vnc_socket_remote_addr(const char *format, int fd) { return addr_to_string(format, &sa, salen); } +static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa, + socklen_t salen) +{ + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + int err; + + if ((err = getnameinfo((struct sockaddr *)sa, salen, + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { + VNC_DEBUG("Cannot resolve address %d: %s\n", + err, gai_strerror(err)); + return -1; + } + + qdict_put(qdict, "host", qstring_from_str(host)); + qdict_put(qdict, "service", qstring_from_str(serv)); + + return 0; +} + +static int vnc_qdict_local_addr(QDict *qdict, int fd) +{ + struct sockaddr_storage sa; + socklen_t salen; + + salen = sizeof(sa); + if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) { + return -1; + } + + return put_addr_qdict(qdict, &sa, salen); +} + +static int vnc_qdict_remote_addr(QDict *qdict, int fd) +{ + struct sockaddr_storage sa; + socklen_t salen; + + salen = sizeof(sa); + if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) { + return -1; + } + + return put_addr_qdict(qdict, &sa, salen); +} + static const char *vnc_auth_name(VncDisplay *vd) { switch (vd->auth) { case VNC_AUTH_INVALID: @@ -150,58 +199,140 @@ static const char *vnc_auth_name(VncDisplay *vd) { return "unknown"; } -static void do_info_vnc_client(Monitor *mon, VncState *client) +static QDict *do_info_vnc_client(Monitor *mon, VncState *client) { - char *clientAddr = - vnc_socket_remote_addr(" address: %s:%s\n", - client->csock); - if (!clientAddr) - return; + QDict *qdict; - monitor_printf(mon, "Client:\n"); - monitor_printf(mon, "%s", clientAddr); - free(clientAddr); + qdict = qdict_new(); + if (vnc_qdict_remote_addr(qdict, client->csock) < 0) { + QDECREF(qdict); + return NULL; + } #ifdef CONFIG_VNC_TLS if (client->tls.session && - client->tls.dname) - monitor_printf(mon, " x509 dname: %s\n", client->tls.dname); - else - monitor_printf(mon, " x509 dname: none\n"); + client->tls.dname) { + qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname)); + } #endif #ifdef CONFIG_VNC_SASL if (client->sasl.conn && - client->sasl.username) - monitor_printf(mon, " username: %s\n", client->sasl.username); - else - monitor_printf(mon, " username: none\n"); + client->sasl.username) { + qdict_put(qdict, "username", qstring_from_str(client->sasl.username)); + } #endif + + return qdict; } -void do_info_vnc(Monitor *mon) +static void info_vnc_iter(QObject *obj, void *opaque) { - if (vnc_display == NULL || vnc_display->display == NULL) { + QDict *client; + Monitor *mon = opaque; + + client = qobject_to_qdict(obj); + monitor_printf(mon, "Client:\n"); + monitor_printf(mon, " address: %s:%s\n", + qdict_get_str(client, "host"), + qdict_get_str(client, "service")); + +#ifdef CONFIG_VNC_TLS + monitor_printf(mon, " x509_dname: %s\n", + qdict_haskey(client, "x509_dname") ? + qdict_get_str(client, "x509_dname") : "none"); +#endif +#ifdef CONFIG_VNC_SASL + monitor_printf(mon, " username: %s\n", + qdict_haskey(client, "username") ? + qdict_get_str(client, "username") : "none"); +#endif +} + +void do_info_vnc_print(Monitor *mon, const QObject *data) +{ + QDict *server; + QList *clients; + + server = qobject_to_qdict(data); + if (strcmp(qdict_get_str(server, "status"), "disabled") == 0) { monitor_printf(mon, "Server: disabled\n"); - } else { - char *serverAddr = vnc_socket_local_addr(" address: %s:%s\n", - vnc_display->lsock); + return; + } - if (!serverAddr) - return; + monitor_printf(mon, "Server:\n"); + monitor_printf(mon, " address: %s:%s\n", + qdict_get_str(server, "host"), + qdict_get_str(server, "service")); + monitor_printf(mon, " auth: %s\n", + qdict_haskey(server, "auth") ? qdict_get_str(server, "auth") : "none"); - monitor_printf(mon, "Server:\n"); - monitor_printf(mon, "%s", serverAddr); - free(serverAddr); - monitor_printf(mon, " auth: %s\n", vnc_auth_name(vnc_display)); + clients = qdict_get_qlist(server, "clients"); + if (qlist_empty(clients)) { + monitor_printf(mon, "Client: none\n"); + } else { + qlist_iter(clients, info_vnc_iter, mon); + } +} +/** + * do_info_vnc(): Show VNC server information + * + * Return a QDict with server information. Connected clients are returned + * as a QList of QDicts. + * + * The main QDict contains the following: + * + * - "status": "disabled" or "enabled" + * - "host": server's IP address + * - "service": server's port number + * - "auth": authentication method (optional) + * - "clients": a QList of all connected clients + * + * Clients are described by a QDict, with the following information: + * + * - "host": client's IP address + * - "service": client's port number + * - "x509_dname": TLS dname (optional) + * - "username": SASL username (optional) + * + * Example: + * + * { "status": "enabled", "host": "0.0.0.0", "service": "50402", "auth": "vnc", + * "clients": [ { "host": "127.0.0.1", "service": "50401" } ] } + */ +void do_info_vnc(Monitor *mon, QObject **ret_data) +{ + if (vnc_display == NULL || vnc_display->display == NULL) { + *ret_data = qobject_from_jsonf("{ 'status': 'disabled' }"); + } else { + QDict *qdict; + QList *clist; + + clist = qlist_new(); if (vnc_display->clients) { VncState *client = vnc_display->clients; while (client) { - do_info_vnc_client(mon, client); + qdict = do_info_vnc_client(mon, client); + if (qdict) + qlist_append(clist, qdict); client = client->next; } - } else { - monitor_printf(mon, "Client: none\n"); + } + + *ret_data = qobject_from_jsonf("{ 'status': 'enabled', 'clients': %p }", + QOBJECT(clist)); + assert(*ret_data != NULL); + + qdict = qobject_to_qdict(*ret_data); + + if (vnc_display->auth != VNC_AUTH_NONE) { + qdict_put(qdict, "auth", + qstring_from_str(vnc_auth_name(vnc_display))); + } + + if (vnc_qdict_local_addr(qdict, vnc_display->lsock) < 0) { + qobject_decref(*ret_data); + *ret_data = NULL; } } } @@ -1506,11 +1637,13 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) static void key_event(VncState *vs, int down, uint32_t sym) { int keycode; + int lsym = sym; - if (sym >= 'A' && sym <= 'Z' && is_graphic_console()) - sym = sym - 'A' + 'a'; + if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) { + lsym = lsym - 'A' + 'a'; + } - keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF); + keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF); do_key_event(vs, down, keycode, sym); } |