Compare commits
89 Commits
v8.0.0
...
v0.12.0-rc
Author | SHA1 | Date | |
---|---|---|---|
|
a68fc29ceb | ||
|
0014803d23 | ||
|
5118f7b47c | ||
|
1c1d7bda2c | ||
|
bdae662c94 | ||
|
0108d4e323 | ||
|
4305793bad | ||
|
d2d51eeff0 | ||
|
3be42b28c1 | ||
|
ee70ef8771 | ||
|
5f9fe0f8d0 | ||
|
7589acc9e8 | ||
|
94f539bdac | ||
|
e637fd2386 | ||
|
6e785bee32 | ||
|
f883e4f7b8 | ||
|
5daa7bb7a4 | ||
|
b0a84d0525 | ||
|
f1f84ba223 | ||
|
db830f26cb | ||
|
61a606dade | ||
|
2d95575edb | ||
|
d707483ce3 | ||
|
e2deb622c2 | ||
|
6e792a557e | ||
|
ea2138cf90 | ||
|
992f3cb78e | ||
|
828b2ff676 | ||
|
a231a8272c | ||
|
f2604b35dc | ||
|
fc05630f1f | ||
|
ad960ddbce | ||
|
239a69680c | ||
|
f4f1df70f2 | ||
|
782e9e6554 | ||
|
64de0113f1 | ||
|
84db615abc | ||
|
7c6a56cc63 | ||
|
a20600b917 | ||
|
4986fd4111 | ||
|
96639424e2 | ||
|
6ac733bf09 | ||
|
25d82d3311 | ||
|
f9800fe5a0 | ||
|
542d991b4c | ||
|
d1d6963eba | ||
|
7058b807cd | ||
|
f49d2561cb | ||
|
a63e5f1971 | ||
|
ebbc8a3d8e | ||
|
08b2d3ba9a | ||
|
72fbd9f97c | ||
|
5b6d0419d9 | ||
|
9df9eeeb18 | ||
|
5b6321a237 | ||
|
5e0c455842 | ||
|
4d687b13cf | ||
|
d7b8193716 | ||
|
2e51813417 | ||
|
90f445e1c9 | ||
|
143d288cba | ||
|
13a2ccc46f | ||
|
ea2b7d7079 | ||
|
0b52786ce1 | ||
|
e36469149a | ||
|
e5fc266be5 | ||
|
3e4cd634cc | ||
|
06976f82e7 | ||
|
fe7c6c90a8 | ||
|
960a4b537a | ||
|
c756b1e762 | ||
|
06921ec84f | ||
|
8cb1cec656 | ||
|
a46657d185 | ||
|
28acf422cb | ||
|
a7d5da8857 | ||
|
931a548be3 | ||
|
bcddbd0f6a | ||
|
b3dfdb5a3b | ||
|
6ccc51fd20 | ||
|
0ea5709a32 | ||
|
67a2698dac | ||
|
eea4acfa5c | ||
|
c99d32efe6 | ||
|
9fa7591beb | ||
|
066263f377 | ||
|
20c1a35211 | ||
|
ea6112b165 | ||
|
e222100afe |
36
Changelog
36
Changelog
@@ -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)
|
||||
|
17
Makefile
17
Makefile
@@ -81,6 +81,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
|
||||
|
||||
@@ -120,6 +126,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
|
||||
@@ -152,8 +159,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
|
||||
@@ -230,18 +235,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
|
||||
|
@@ -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)
|
||||
|
||||
|
233
block.c
233
block.c
@@ -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)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
QDict *bs_dict;
|
||||
Monitor *mon = opaque;
|
||||
|
||||
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
|
||||
monitor_printf(mon, "%s:", bs->device_name);
|
||||
monitor_printf(mon, " type=");
|
||||
switch(bs->type) {
|
||||
case BDRV_TYPE_HD:
|
||||
monitor_printf(mon, "hd");
|
||||
break;
|
||||
case BDRV_TYPE_CDROM:
|
||||
monitor_printf(mon, "cdrom");
|
||||
break;
|
||||
case BDRV_TYPE_FLOPPY:
|
||||
monitor_printf(mon, "floppy");
|
||||
break;
|
||||
}
|
||||
monitor_printf(mon, " removable=%d", bs->removable);
|
||||
if (bs->removable) {
|
||||
monitor_printf(mon, " locked=%d", bs->locked);
|
||||
}
|
||||
if (bs->drv) {
|
||||
monitor_printf(mon, " file=");
|
||||
monitor_print_filename(mon, bs->filename);
|
||||
if (bs->backing_file[0] != '\0') {
|
||||
monitor_printf(mon, " backing_file=");
|
||||
monitor_print_filename(mon, 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]");
|
||||
}
|
||||
monitor_printf(mon, "\n");
|
||||
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");
|
||||
}
|
||||
|
||||
/* The "info blockstats" command. */
|
||||
void bdrv_info_stats(Monitor *mon)
|
||||
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:"
|
||||
" 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);
|
||||
QObject *bs_obj;
|
||||
const char *type = "unknown";
|
||||
|
||||
switch(bs->type) {
|
||||
case BDRV_TYPE_HD:
|
||||
type = "hd";
|
||||
break;
|
||||
case BDRV_TYPE_CDROM:
|
||||
type = "cdrom";
|
||||
break;
|
||||
case BDRV_TYPE_FLOPPY:
|
||||
type = "floppy";
|
||||
break;
|
||||
}
|
||||
|
||||
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) {
|
||||
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') {
|
||||
QDict *qdict = qobject_to_qdict(obj);
|
||||
qdict_put(qdict, "backing_file",
|
||||
qstring_from_str(bs->backing_file));
|
||||
}
|
||||
|
||||
qdict_put_obj(bs_dict, "inserted", obj);
|
||||
}
|
||||
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"));
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
|
7
block.h
7
block.h
@@ -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);
|
||||
|
18
configure
vendored
18
configure
vendored
@@ -256,6 +256,7 @@ blobs="yes"
|
||||
pkgversion=""
|
||||
check_utests="no"
|
||||
user_pie="no"
|
||||
zero_malloc=""
|
||||
|
||||
# OS specific
|
||||
if check_define __linux__ ; then
|
||||
@@ -1792,8 +1793,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"
|
||||
@@ -1802,6 +1804,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
|
||||
@@ -2109,6 +2121,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)
|
||||
|
10
console.c
10
console.c
@@ -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 */
|
||||
|
@@ -179,7 +179,7 @@ typedef struct CPUWatchpoint {
|
||||
\
|
||||
/* 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) */ \
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -3217,11 +3217,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,
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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[]) {
|
||||
|
@@ -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,
|
||||
|
@@ -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:
|
||||
|
74
hw/msix.c
74
hw/msix.c
@@ -20,6 +20,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 */
|
||||
@@ -27,9 +28,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
|
||||
@@ -101,22 +103,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;
|
||||
@@ -157,10 +148,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,
|
||||
@@ -170,10 +201,7 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
|
||||
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
|
||||
int vector = offset / MSIX_ENTRY_SIZE;
|
||||
pci_set_long(dev->msix_table_page + offset, val);
|
||||
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,
|
||||
@@ -327,7 +355,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);
|
||||
}
|
||||
|
||||
@@ -363,8 +391,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);
|
||||
}
|
||||
|
2
hw/pc.c
2
hw/pc.c
@@ -1298,7 +1298,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",
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include "scsi.h"
|
||||
#include "virtio-blk.h"
|
||||
#include "qemu-config.h"
|
||||
#include "qemu-objects.h"
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
|
||||
@@ -40,7 +41,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) {
|
||||
@@ -82,6 +94,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);
|
||||
@@ -179,6 +192,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:
|
||||
@@ -212,7 +229,36 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
|
||||
return dev;
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -239,9 +285,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);
|
||||
}
|
||||
|
155
hw/pci.c
155
hw/pci.c
@@ -103,11 +103,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;
|
||||
@@ -274,6 +311,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,
|
||||
@@ -284,7 +358,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()
|
||||
}
|
||||
};
|
||||
@@ -299,7 +375,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()
|
||||
}
|
||||
};
|
||||
@@ -311,12 +389,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)
|
||||
@@ -429,7 +518,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);
|
||||
@@ -490,16 +580,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;
|
||||
@@ -535,6 +627,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)
|
||||
@@ -849,6 +944,25 @@ static void pci_update_mappings(PCIDevice *d)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -861,7 +975,7 @@ uint32_t pci_default_read_config(PCIDevice *d,
|
||||
|
||||
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);
|
||||
|
||||
for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
|
||||
@@ -873,6 +987,9 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
|
||||
ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
|
||||
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);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
@@ -882,23 +999,17 @@ 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;
|
||||
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);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
@@ -1270,6 +1381,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;
|
||||
|
4
hw/pci.h
4
hw/pci.h
@@ -101,7 +101,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 */
|
||||
@@ -220,7 +222,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;
|
||||
|
@@ -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);
|
||||
|
10
hw/qdev.h
10
hw/qdev.h
@@ -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;
|
||||
|
@@ -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,
|
||||
};
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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,
|
||||
|
13
hw/usb-bus.c
13
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
14
hw/usb-hid.c
14
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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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");
|
||||
}
|
||||
|
@@ -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,
|
||||
|
4
hw/usb.h
4
hw/usb.h
@@ -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);
|
||||
|
@@ -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,
|
||||
|
11
hw/virtio.c
11
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);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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();
|
||||
|
117
migration.c
117
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
403
monitor.c
403
monitor.c
@@ -148,7 +148,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;
|
||||
@@ -254,24 +257,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;
|
||||
@@ -302,6 +287,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);
|
||||
@@ -500,24 +486,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)
|
||||
{
|
||||
@@ -528,7 +581,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,7 +589,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,20 +597,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 */
|
||||
@@ -607,8 +696,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"));
|
||||
|
||||
@@ -628,8 +718,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, "\n");
|
||||
}
|
||||
@@ -646,12 +737,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:
|
||||
*
|
||||
* For example:
|
||||
* - "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
|
||||
*
|
||||
* [ { "CPU": 0, "current": "yes", "pc": 0x..., "halted": "no" },
|
||||
* { "CPU": 1, "current": "no", "pc": 0x..., "halted": "yes" } ]
|
||||
* Example:
|
||||
*
|
||||
* [ { "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)
|
||||
{
|
||||
@@ -664,14 +764,17 @@ 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);
|
||||
|
||||
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));
|
||||
@@ -683,8 +786,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));
|
||||
|
||||
qlist_append(cpu_list, cpu);
|
||||
}
|
||||
@@ -745,11 +846,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;
|
||||
}
|
||||
}
|
||||
@@ -766,12 +868,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)
|
||||
{
|
||||
@@ -780,13 +898,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;
|
||||
}
|
||||
}
|
||||
@@ -796,12 +914,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(const char *password)
|
||||
{
|
||||
if (vnc_display_password(NULL, password) < 0)
|
||||
qemu_error_new(QERR_SET_PASSWD_FAILED);
|
||||
|
||||
}
|
||||
|
||||
static void change_vnc_password_cb(Monitor *mon, const char *password,
|
||||
void *opaque)
|
||||
{
|
||||
if (vnc_display_password(NULL, password) < 0)
|
||||
monitor_printf(mon, "could not set VNC server password\n");
|
||||
|
||||
change_vnc_password(password);
|
||||
monitor_read_command(mon, 1);
|
||||
}
|
||||
|
||||
@@ -813,17 +936,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");
|
||||
@@ -1739,16 +1865,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)
|
||||
{
|
||||
QDict *qdict;
|
||||
|
||||
qdict = qobject_to_qdict(data);
|
||||
|
||||
monitor_printf(mon, "kvm support: ");
|
||||
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
|
||||
monitor_printf(mon, "kvm support: ");
|
||||
if (kvm_enabled())
|
||||
monitor_printf(mon, "enabled\n");
|
||||
else
|
||||
monitor_printf(mon, "disabled\n");
|
||||
*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
|
||||
}
|
||||
|
||||
@@ -1866,16 +2016,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1890,12 +2065,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)
|
||||
{
|
||||
@@ -1907,7 +2094,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)
|
||||
@@ -2043,19 +2231,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;
|
||||
}
|
||||
|
||||
@@ -2093,8 +2283,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)
|
||||
@@ -2144,7 +2333,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,
|
||||
},
|
||||
{
|
||||
@@ -2167,21 +2356,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",
|
||||
@@ -2248,7 +2440,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
|
||||
{
|
||||
@@ -2263,7 +2456,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",
|
||||
@@ -2312,7 +2506,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",
|
||||
@@ -2326,28 +2521,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)
|
||||
{
|
||||
@@ -2372,7 +2571,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",
|
||||
@@ -4008,24 +4208,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;
|
||||
@@ -4087,6 +4269,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);
|
||||
|
5
net.c
5
net.c
@@ -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;
|
||||
}
|
||||
|
1
net.h
1
net.h
@@ -139,6 +139,7 @@ struct NICInfo {
|
||||
|
||||
extern int nb_nics;
|
||||
extern NICInfo nd_table[MAX_NICS];
|
||||
extern int default_net;
|
||||
|
||||
/* BT HCI info */
|
||||
|
||||
|
BIN
pc-bios/openbios-ppc
Executable file → Normal file
BIN
pc-bios/openbios-ppc
Executable file → Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
28
qdict.c
28
qdict.c
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "qint.h"
|
||||
#include "qdict.h"
|
||||
#include "qbool.h"
|
||||
#include "qstring.h"
|
||||
#include "qobject.h"
|
||||
#include "qemu-queue.h"
|
||||
@@ -188,6 +189,33 @@ int64_t qdict_get_int(const QDict *qdict, const char *key)
|
||||
return qint_get_int(qobject_to_qint(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'
|
||||
|
3
qdict.h
3
qdict.h
@@ -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);
|
||||
|
45
qemu-char.c
45
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)
|
||||
|
@@ -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;
|
||||
|
@@ -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",
|
||||
@@ -205,6 +206,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,
|
||||
@@ -212,6 +249,8 @@ static QemuOptsList *lists[] = {
|
||||
&qemu_netdev_opts,
|
||||
&qemu_net_opts,
|
||||
&qemu_rtc_opts,
|
||||
&qemu_global_opts,
|
||||
&qemu_mon_opts,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -260,6 +299,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;
|
||||
|
@@ -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);
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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 [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...",
|
||||
.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
|
||||
|
||||
@@ -1045,6 +1047,20 @@ STEXI
|
||||
Close the file descriptor previously assigned to @var{fdname} using the
|
||||
@code{getfd} command. This is only needed if the file descriptor was never
|
||||
used by another monitor command.
|
||||
ETEXI
|
||||
|
||||
{
|
||||
.name = "block_passwd",
|
||||
.args_type = "device:B,password:s",
|
||||
.params = "block_passwd device password",
|
||||
.help = "set the password of encrypted block devices",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = do_block_set_passwd,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@item block_passwd @var{device} @var{password}
|
||||
Set the encrypted device @var{device} password to @var{password}
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
|
24
qemu-objects.h
Normal file
24
qemu-objects.h
Normal file
@@ -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 */
|
@@ -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;
|
||||
|
||||
|
@@ -109,6 +109,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}[,...]]]
|
||||
|
||||
@@ -1577,14 +1580,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, \
|
||||
@@ -1879,6 +1890,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")
|
||||
|
85
qerror.c
85
qerror.c
@@ -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_UNDEFINED_ERROR,
|
||||
.desc = "An undefined error has ocurred",
|
||||
.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_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);
|
||||
}
|
||||
|
65
qerror.h
65
qerror.h
@@ -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_KVM_MISSING_CAP \
|
||||
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
|
||||
|
||||
#define QERR_MISSING_PARAMETER \
|
||||
"{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
|
||||
|
||||
#define QERR_QMP_BAD_INPUT_OBJECT \
|
||||
"{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
|
||||
#define QERR_INVALID_PASSWORD \
|
||||
"{ 'class': 'InvalidPassword', 'data': {} }"
|
||||
|
||||
#define QERR_JSON_PARSING \
|
||||
"{ 'class': 'JSONParsing', 'data': {} }"
|
||||
"{ 'class': 'JSONParsing', 'data': {} }"
|
||||
|
||||
#define QERR_KVM_MISSING_CAP \
|
||||
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
|
||||
|
||||
#define QERR_MISSING_PARAMETER \
|
||||
"{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
|
||||
|
||||
#define QERR_QMP_BAD_INPUT_OBJECT \
|
||||
"{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
|
||||
|
||||
#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:
|
||||
|
3
sysemu.h
3
sysemu.h
@@ -212,7 +212,8 @@ extern DriveInfo *drive_init(QemuOpts *arg, void *machine, int *fatal_error);
|
||||
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,
|
||||
|
@@ -651,6 +651,8 @@ typedef struct CPUX86State {
|
||||
target_ulong fmask;
|
||||
target_ulong kernelgsbase;
|
||||
#endif
|
||||
uint64_t system_time_msr;
|
||||
uint64_t wall_clock_msr;
|
||||
|
||||
uint64_t tsc;
|
||||
|
||||
|
@@ -1638,6 +1638,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)
|
||||
@@ -1654,16 +1672,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;
|
||||
@@ -1759,11 +1768,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()) {
|
||||
|
@@ -35,6 +35,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)
|
||||
@@ -244,9 +247,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) +
|
||||
@@ -494,6 +497,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);
|
||||
@@ -634,6 +640,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)
|
||||
@@ -670,6 +679,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -453,6 +453,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),
|
||||
@@ -460,6 +461,9 @@ static const VMStateDescription vmstate_cpu = {
|
||||
VMSTATE_UINT64_ARRAY_V(mce_banks, CPUState, MCE_BANKS_DEF *4, 10),
|
||||
/* rdtscp */
|
||||
VMSTATE_UINT64_V(tsc_aux, CPUState, 11),
|
||||
/* KVM pvclock msr */
|
||||
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,
|
||||
|
10
usb-linux.c
10
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:")) {
|
||||
|
554
vl.c
554
vl.c
@@ -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 "disas.h"
|
||||
|
||||
@@ -172,9 +173,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
|
||||
@@ -193,7 +191,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;
|
||||
@@ -271,6 +269,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 */
|
||||
|
||||
@@ -458,25 +491,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)
|
||||
{
|
||||
QEMUPutMouseEntry *cursor;
|
||||
int index = 0;
|
||||
QDict *mouse;
|
||||
Monitor *mon = opaque;
|
||||
|
||||
if (!qemu_put_mouse_event_head) {
|
||||
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;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "Mouse devices available:\n");
|
||||
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) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -4345,6 +4425,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;
|
||||
@@ -4586,10 +4667,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;
|
||||
@@ -4621,6 +4786,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;
|
||||
@@ -4636,16 +4867,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;
|
||||
@@ -4711,43 +4932,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;
|
||||
@@ -4851,6 +5035,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;
|
||||
@@ -5161,14 +5349,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");
|
||||
@@ -5176,17 +5370,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) {
|
||||
@@ -5203,20 +5390,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;
|
||||
@@ -5409,6 +5588,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;
|
||||
@@ -5487,15 +5675,49 @@ 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) {
|
||||
@@ -5623,14 +5845,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)
|
||||
@@ -5642,32 +5866,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;
|
||||
|
||||
@@ -5710,65 +5908,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);
|
||||
|
||||
@@ -5779,8 +5924,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);
|
||||
|
||||
@@ -5873,35 +6020,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",
|
||||
|
203
vnc.c
203
vnc.c
@@ -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;
|
||||
}
|
||||
|
||||
static void info_vnc_iter(QObject *obj, void *opaque)
|
||||
{
|
||||
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(Monitor *mon)
|
||||
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");
|
||||
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");
|
||||
|
||||
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) {
|
||||
monitor_printf(mon, "Server: disabled\n");
|
||||
*ret_data = qobject_from_jsonf("{ 'status': 'disabled' }");
|
||||
} else {
|
||||
char *serverAddr = vnc_socket_local_addr(" address: %s:%s\n",
|
||||
vnc_display->lsock);
|
||||
|
||||
if (!serverAddr)
|
||||
return;
|
||||
|
||||
monitor_printf(mon, "Server:\n");
|
||||
monitor_printf(mon, "%s", serverAddr);
|
||||
free(serverAddr);
|
||||
monitor_printf(mon, " auth: %s\n", vnc_auth_name(vnc_display));
|
||||
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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user