Merge remote-tracking branch 'qmp/queue/qmp' into staging
Conflicts: ui/spice-core.c
This commit is contained in:
commit
96b3d73f5a
72
balloon.c
72
balloon.c
@ -25,12 +25,11 @@
|
||||
*/
|
||||
|
||||
#include "monitor.h"
|
||||
#include "qjson.h"
|
||||
#include "qint.h"
|
||||
#include "cpu-common.h"
|
||||
#include "kvm.h"
|
||||
#include "balloon.h"
|
||||
#include "trace.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
static QEMUBalloonEvent *balloon_event_fn;
|
||||
static QEMUBalloonStatus *balloon_stat_fn;
|
||||
@ -72,76 +71,33 @@ static int qemu_balloon(ram_addr_t target)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
|
||||
static int qemu_balloon_status(BalloonInfo *info)
|
||||
{
|
||||
if (!balloon_stat_fn) {
|
||||
return 0;
|
||||
}
|
||||
balloon_stat_fn(balloon_opaque, cb, opaque);
|
||||
balloon_stat_fn(balloon_opaque, info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
|
||||
BalloonInfo *qmp_query_balloon(Error **errp)
|
||||
{
|
||||
Monitor *mon = opaque;
|
||||
|
||||
if (strcmp(key, "actual")) {
|
||||
monitor_printf(mon, ",%s=%" PRId64, key,
|
||||
qint_get_int(qobject_to_qint(obj)));
|
||||
}
|
||||
}
|
||||
|
||||
void monitor_print_balloon(Monitor *mon, const QObject *data)
|
||||
{
|
||||
QDict *qdict;
|
||||
|
||||
qdict = qobject_to_qdict(data);
|
||||
if (!qdict_haskey(qdict, "actual")) {
|
||||
return;
|
||||
}
|
||||
monitor_printf(mon, "balloon: actual=%" PRId64,
|
||||
qdict_get_int(qdict, "actual") >> 20);
|
||||
qdict_iter(qdict, print_balloon_stat, mon);
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* do_info_balloon(): Balloon information
|
||||
*
|
||||
* Make an asynchronous request for balloon info. When the request completes
|
||||
* a QDict will be returned according to the following specification:
|
||||
*
|
||||
* - "actual": current balloon value in bytes
|
||||
* The following fields may or may not be present:
|
||||
* - "mem_swapped_in": Amount of memory swapped in (bytes)
|
||||
* - "mem_swapped_out": Amount of memory swapped out (bytes)
|
||||
* - "major_page_faults": Number of major faults
|
||||
* - "minor_page_faults": Number of minor faults
|
||||
* - "free_mem": Total amount of free and unused memory (bytes)
|
||||
* - "total_mem": Total amount of available memory (bytes)
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0,
|
||||
* "major_page_faults": 142, "minor_page_faults": 239245,
|
||||
* "free_mem": 1014185984, "total_mem": 1044668416 }
|
||||
*/
|
||||
int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
|
||||
{
|
||||
int ret;
|
||||
BalloonInfo *info;
|
||||
|
||||
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
||||
qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
|
||||
return -1;
|
||||
error_set(errp, QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = qemu_balloon_status(cb, opaque);
|
||||
if (!ret) {
|
||||
qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
|
||||
return -1;
|
||||
info = g_malloc0(sizeof(*info));
|
||||
|
||||
if (qemu_balloon_status(info) == 0) {
|
||||
error_set(errp, QERR_DEVICE_NOT_ACTIVE, "balloon");
|
||||
qapi_free_BalloonInfo(info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,17 +15,15 @@
|
||||
#define _QEMU_BALLOON_H
|
||||
|
||||
#include "monitor.h"
|
||||
#include "qapi-types.h"
|
||||
|
||||
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
|
||||
typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
|
||||
void *cb_data);
|
||||
typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
|
||||
|
||||
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
|
||||
QEMUBalloonStatus *stat_func, void *opaque);
|
||||
void qemu_remove_balloon_handler(void *opaque);
|
||||
|
||||
void monitor_print_balloon(Monitor *mon, const QObject *data);
|
||||
int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
|
||||
int do_balloon(Monitor *mon, const QDict *params,
|
||||
MonitorCompletion cb, void *opaque);
|
||||
|
||||
|
236
block.c
236
block.c
@ -27,8 +27,9 @@
|
||||
#include "monitor.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include "qemu-objects.h"
|
||||
#include "qjson.h"
|
||||
#include "qemu-coroutine.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
#ifdef CONFIG_BSD
|
||||
#include <sys/types.h>
|
||||
@ -1824,195 +1825,105 @@ void bdrv_mon_event(const BlockDriverState *bdrv,
|
||||
qobject_decref(data);
|
||||
}
|
||||
|
||||
static void bdrv_print_dict(QObject *obj, void *opaque)
|
||||
BlockInfoList *qmp_query_block(Error **errp)
|
||||
{
|
||||
QDict *bs_dict;
|
||||
Monitor *mon = opaque;
|
||||
|
||||
bs_dict = qobject_to_qdict(obj);
|
||||
|
||||
monitor_printf(mon, "%s: removable=%d",
|
||||
qdict_get_str(bs_dict, "device"),
|
||||
qdict_get_bool(bs_dict, "removable"));
|
||||
|
||||
if (qdict_get_bool(bs_dict, "removable")) {
|
||||
monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
|
||||
monitor_printf(mon, " tray-open=%d",
|
||||
qdict_get_bool(bs_dict, "tray-open"));
|
||||
}
|
||||
|
||||
if (qdict_haskey(bs_dict, "io-status")) {
|
||||
monitor_printf(mon, " io-status=%s", qdict_get_str(bs_dict, "io-status"));
|
||||
}
|
||||
|
||||
if (qdict_haskey(bs_dict, "inserted")) {
|
||||
QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
|
||||
|
||||
monitor_printf(mon, " file=");
|
||||
monitor_print_filename(mon, qdict_get_str(qdict, "file"));
|
||||
if (qdict_haskey(qdict, "backing_file")) {
|
||||
monitor_printf(mon, " backing_file=");
|
||||
monitor_print_filename(mon, qdict_get_str(qdict, "backing_file"));
|
||||
}
|
||||
monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
|
||||
qdict_get_bool(qdict, "ro"),
|
||||
qdict_get_str(qdict, "drv"),
|
||||
qdict_get_bool(qdict, "encrypted"));
|
||||
} else {
|
||||
monitor_printf(mon, " [not inserted]");
|
||||
}
|
||||
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
void bdrv_info_print(Monitor *mon, const QObject *data)
|
||||
{
|
||||
qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
|
||||
}
|
||||
|
||||
static const char *const io_status_name[BDRV_IOS_MAX] = {
|
||||
[BDRV_IOS_OK] = "ok",
|
||||
[BDRV_IOS_FAILED] = "failed",
|
||||
[BDRV_IOS_ENOSPC] = "nospace",
|
||||
};
|
||||
|
||||
void bdrv_info(Monitor *mon, QObject **ret_data)
|
||||
{
|
||||
QList *bs_list;
|
||||
BlockInfoList *head = NULL, *cur_item = NULL;
|
||||
BlockDriverState *bs;
|
||||
|
||||
bs_list = qlist_new();
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
||||
QObject *bs_obj;
|
||||
QDict *bs_dict;
|
||||
BlockInfoList *info = g_malloc0(sizeof(*info));
|
||||
|
||||
bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
|
||||
"'removable': %i, 'locked': %i }",
|
||||
bs->device_name,
|
||||
bdrv_dev_has_removable_media(bs),
|
||||
bdrv_dev_is_medium_locked(bs));
|
||||
bs_dict = qobject_to_qdict(bs_obj);
|
||||
info->value = g_malloc0(sizeof(*info->value));
|
||||
info->value->device = g_strdup(bs->device_name);
|
||||
info->value->type = g_strdup("unknown");
|
||||
info->value->locked = bdrv_dev_is_medium_locked(bs);
|
||||
info->value->removable = bdrv_dev_has_removable_media(bs);
|
||||
|
||||
if (bdrv_dev_has_removable_media(bs)) {
|
||||
qdict_put(bs_dict, "tray-open",
|
||||
qbool_from_int(bdrv_dev_is_tray_open(bs)));
|
||||
info->value->has_tray_open = true;
|
||||
info->value->tray_open = bdrv_dev_is_tray_open(bs);
|
||||
}
|
||||
|
||||
if (bdrv_iostatus_is_enabled(bs)) {
|
||||
qdict_put(bs_dict, "io-status",
|
||||
qstring_from_str(io_status_name[bs->iostatus]));
|
||||
info->value->has_io_status = true;
|
||||
info->value->io_status = bs->iostatus;
|
||||
}
|
||||
|
||||
if (bs->drv) {
|
||||
QObject *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));
|
||||
if (bs->backing_file[0] != '\0') {
|
||||
QDict *qdict = qobject_to_qdict(obj);
|
||||
qdict_put(qdict, "backing_file",
|
||||
qstring_from_str(bs->backing_file));
|
||||
info->value->has_inserted = true;
|
||||
info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
|
||||
info->value->inserted->file = g_strdup(bs->filename);
|
||||
info->value->inserted->ro = bs->read_only;
|
||||
info->value->inserted->drv = g_strdup(bs->drv->format_name);
|
||||
info->value->inserted->encrypted = bs->encrypted;
|
||||
if (bs->backing_file[0]) {
|
||||
info->value->inserted->has_backing_file = true;
|
||||
info->value->inserted->backing_file = g_strdup(bs->backing_file);
|
||||
}
|
||||
|
||||
qdict_put_obj(bs_dict, "inserted", obj);
|
||||
}
|
||||
qlist_append_obj(bs_list, bs_obj);
|
||||
|
||||
/* XXX: waiting for the qapi to support GSList */
|
||||
if (!cur_item) {
|
||||
head = cur_item = info;
|
||||
} else {
|
||||
cur_item->next = info;
|
||||
cur_item = info;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_data = QOBJECT(bs_list);
|
||||
return head;
|
||||
}
|
||||
|
||||
static void bdrv_stats_iter(QObject *data, void *opaque)
|
||||
/* Consider exposing this as a full fledged QMP command */
|
||||
static BlockStats *qmp_query_blockstat(const BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
QDict *qdict;
|
||||
Monitor *mon = opaque;
|
||||
BlockStats *s;
|
||||
|
||||
qdict = qobject_to_qdict(data);
|
||||
monitor_printf(mon, "%s:", qdict_get_str(qdict, "device"));
|
||||
s = g_malloc0(sizeof(*s));
|
||||
|
||||
qdict = qobject_to_qdict(qdict_get(qdict, "stats"));
|
||||
monitor_printf(mon, " rd_bytes=%" PRId64
|
||||
" wr_bytes=%" PRId64
|
||||
" rd_operations=%" PRId64
|
||||
" wr_operations=%" PRId64
|
||||
" flush_operations=%" PRId64
|
||||
" wr_total_time_ns=%" PRId64
|
||||
" rd_total_time_ns=%" PRId64
|
||||
" flush_total_time_ns=%" 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"),
|
||||
qdict_get_int(qdict, "flush_operations"),
|
||||
qdict_get_int(qdict, "wr_total_time_ns"),
|
||||
qdict_get_int(qdict, "rd_total_time_ns"),
|
||||
qdict_get_int(qdict, "flush_total_time_ns"));
|
||||
}
|
||||
|
||||
void bdrv_stats_print(Monitor *mon, const QObject *data)
|
||||
{
|
||||
qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
|
||||
}
|
||||
|
||||
static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
|
||||
{
|
||||
QObject *res;
|
||||
QDict *dict;
|
||||
|
||||
res = qobject_from_jsonf("{ 'stats': {"
|
||||
"'rd_bytes': %" PRId64 ","
|
||||
"'wr_bytes': %" PRId64 ","
|
||||
"'rd_operations': %" PRId64 ","
|
||||
"'wr_operations': %" PRId64 ","
|
||||
"'wr_highest_offset': %" PRId64 ","
|
||||
"'flush_operations': %" PRId64 ","
|
||||
"'wr_total_time_ns': %" PRId64 ","
|
||||
"'rd_total_time_ns': %" PRId64 ","
|
||||
"'flush_total_time_ns': %" PRId64
|
||||
"} }",
|
||||
bs->nr_bytes[BDRV_ACCT_READ],
|
||||
bs->nr_bytes[BDRV_ACCT_WRITE],
|
||||
bs->nr_ops[BDRV_ACCT_READ],
|
||||
bs->nr_ops[BDRV_ACCT_WRITE],
|
||||
bs->wr_highest_sector *
|
||||
(uint64_t)BDRV_SECTOR_SIZE,
|
||||
bs->nr_ops[BDRV_ACCT_FLUSH],
|
||||
bs->total_time_ns[BDRV_ACCT_WRITE],
|
||||
bs->total_time_ns[BDRV_ACCT_READ],
|
||||
bs->total_time_ns[BDRV_ACCT_FLUSH]);
|
||||
dict = qobject_to_qdict(res);
|
||||
|
||||
if (*bs->device_name) {
|
||||
qdict_put(dict, "device", qstring_from_str(bs->device_name));
|
||||
if (bs->device_name[0]) {
|
||||
s->has_device = true;
|
||||
s->device = g_strdup(bs->device_name);
|
||||
}
|
||||
|
||||
s->stats = g_malloc0(sizeof(*s->stats));
|
||||
s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ];
|
||||
s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE];
|
||||
s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ];
|
||||
s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE];
|
||||
s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE;
|
||||
s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH];
|
||||
s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE];
|
||||
s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ];
|
||||
s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH];
|
||||
|
||||
if (bs->file) {
|
||||
QObject *parent = bdrv_info_stats_bs(bs->file);
|
||||
qdict_put_obj(dict, "parent", parent);
|
||||
s->has_parent = true;
|
||||
s->parent = qmp_query_blockstat(bs->file, NULL);
|
||||
}
|
||||
|
||||
return res;
|
||||
return s;
|
||||
}
|
||||
|
||||
void bdrv_info_stats(Monitor *mon, QObject **ret_data)
|
||||
BlockStatsList *qmp_query_blockstats(Error **errp)
|
||||
{
|
||||
QObject *obj;
|
||||
QList *devices;
|
||||
BlockStatsList *head = NULL, *cur_item = NULL;
|
||||
BlockDriverState *bs;
|
||||
|
||||
devices = qlist_new();
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
||||
obj = bdrv_info_stats_bs(bs);
|
||||
qlist_append_obj(devices, obj);
|
||||
BlockStatsList *info = g_malloc0(sizeof(*info));
|
||||
info->value = qmp_query_blockstat(bs, NULL);
|
||||
|
||||
/* XXX: waiting for the qapi to support GSList */
|
||||
if (!cur_item) {
|
||||
head = cur_item = info;
|
||||
} else {
|
||||
cur_item->next = info;
|
||||
cur_item = info;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_data = QOBJECT(devices);
|
||||
return head;
|
||||
}
|
||||
|
||||
const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
|
||||
@ -3139,14 +3050,15 @@ int bdrv_in_use(BlockDriverState *bs)
|
||||
|
||||
void bdrv_iostatus_enable(BlockDriverState *bs)
|
||||
{
|
||||
bs->iostatus = BDRV_IOS_OK;
|
||||
bs->iostatus_enabled = true;
|
||||
bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
|
||||
}
|
||||
|
||||
/* The I/O status is only enabled if the drive explicitly
|
||||
* enables it _and_ the VM is configured to stop on errors */
|
||||
bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
|
||||
{
|
||||
return (bs->iostatus != BDRV_IOS_INVAL &&
|
||||
return (bs->iostatus_enabled &&
|
||||
(bs->on_write_error == BLOCK_ERR_STOP_ENOSPC ||
|
||||
bs->on_write_error == BLOCK_ERR_STOP_ANY ||
|
||||
bs->on_read_error == BLOCK_ERR_STOP_ANY));
|
||||
@ -3154,13 +3066,13 @@ bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
|
||||
|
||||
void bdrv_iostatus_disable(BlockDriverState *bs)
|
||||
{
|
||||
bs->iostatus = BDRV_IOS_INVAL;
|
||||
bs->iostatus_enabled = false;
|
||||
}
|
||||
|
||||
void bdrv_iostatus_reset(BlockDriverState *bs)
|
||||
{
|
||||
if (bdrv_iostatus_is_enabled(bs)) {
|
||||
bs->iostatus = BDRV_IOS_OK;
|
||||
bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3169,9 +3081,11 @@ void bdrv_iostatus_reset(BlockDriverState *bs)
|
||||
possible to implement this without device models being involved */
|
||||
void bdrv_iostatus_set_err(BlockDriverState *bs, int error)
|
||||
{
|
||||
if (bdrv_iostatus_is_enabled(bs) && bs->iostatus == BDRV_IOS_OK) {
|
||||
if (bdrv_iostatus_is_enabled(bs) &&
|
||||
bs->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
|
||||
assert(error >= 0);
|
||||
bs->iostatus = error == ENOSPC ? BDRV_IOS_ENOSPC : BDRV_IOS_FAILED;
|
||||
bs->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
|
||||
BLOCK_DEVICE_IO_STATUS_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
|
5
block.h
5
block.h
@ -77,11 +77,6 @@ typedef enum {
|
||||
BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
|
||||
} BlockMonEventAction;
|
||||
|
||||
typedef enum {
|
||||
BDRV_IOS_INVAL, BDRV_IOS_OK, BDRV_IOS_FAILED, BDRV_IOS_ENOSPC,
|
||||
BDRV_IOS_MAX
|
||||
} BlockIOStatus;
|
||||
|
||||
void bdrv_iostatus_enable(BlockDriverState *bs);
|
||||
void bdrv_iostatus_reset(BlockDriverState *bs);
|
||||
void bdrv_iostatus_disable(BlockDriverState *bs);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-coroutine.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "qapi-types.h"
|
||||
|
||||
#define BLOCK_FLAG_ENCRYPT 1
|
||||
#define BLOCK_FLAG_COMPAT6 4
|
||||
@ -202,7 +203,8 @@ struct BlockDriverState {
|
||||
drivers. They are not used by the block driver */
|
||||
int cyls, heads, secs, translation;
|
||||
BlockErrorAction on_read_error, on_write_error;
|
||||
BlockIOStatus iostatus;
|
||||
bool iostatus_enabled;
|
||||
BlockDeviceIoStatus iostatus;
|
||||
char device_name[32];
|
||||
unsigned long *dirty_bitmap;
|
||||
int64_t dirty_count;
|
||||
|
@ -383,8 +383,6 @@ char *vnc_display_local_addr(DisplayState *ds);
|
||||
#ifdef CONFIG_VNC
|
||||
int vnc_display_password(DisplayState *ds, const char *password);
|
||||
int vnc_display_pw_expire(DisplayState *ds, time_t expires);
|
||||
void do_info_vnc_print(Monitor *mon, const QObject *data);
|
||||
void do_info_vnc(Monitor *mon, QObject **ret_data);
|
||||
#else
|
||||
static inline int vnc_display_password(DisplayState *ds, const char *password)
|
||||
{
|
||||
@ -396,13 +394,6 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
|
||||
qerror_report(QERR_FEATURE_DISABLED, "vnc");
|
||||
return -ENODEV;
|
||||
};
|
||||
static inline void do_info_vnc(Monitor *mon, QObject **ret_data)
|
||||
{
|
||||
};
|
||||
static inline void do_info_vnc_print(Monitor *mon, const QObject *data)
|
||||
{
|
||||
monitor_printf(mon, "VNC support disabled\n");
|
||||
};
|
||||
#endif
|
||||
|
||||
/* curses.c */
|
||||
|
45
cpus.c
45
cpus.c
@ -30,6 +30,7 @@
|
||||
#include "gdbstub.h"
|
||||
#include "dma.h"
|
||||
#include "kvm.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
#include "qemu-thread.h"
|
||||
#include "cpus.h"
|
||||
@ -1094,3 +1095,47 @@ void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
|
||||
cpu_list(f, cpu_fprintf); /* deprecated */
|
||||
#endif
|
||||
}
|
||||
|
||||
CpuInfoList *qmp_query_cpus(Error **errp)
|
||||
{
|
||||
CpuInfoList *head = NULL, *cur_item = NULL;
|
||||
CPUState *env;
|
||||
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
CpuInfoList *info;
|
||||
|
||||
cpu_synchronize_state(env);
|
||||
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->value = g_malloc0(sizeof(*info->value));
|
||||
info->value->CPU = env->cpu_index;
|
||||
info->value->current = (env == first_cpu);
|
||||
info->value->halted = env->halted;
|
||||
info->value->thread_id = env->thread_id;
|
||||
#if defined(TARGET_I386)
|
||||
info->value->has_pc = true;
|
||||
info->value->pc = env->eip + env->segs[R_CS].base;
|
||||
#elif defined(TARGET_PPC)
|
||||
info->value->has_nip = true;
|
||||
info->value->nip = env->nip;
|
||||
#elif defined(TARGET_SPARC)
|
||||
info->value->has_pc = true;
|
||||
info->value->pc = env->pc;
|
||||
info->value->has_npc = true;
|
||||
info->value->npc = env->npc;
|
||||
#elif defined(TARGET_MIPS)
|
||||
info->value->has_PC = true;
|
||||
info->value->PC = env->active_tc.PC;
|
||||
#endif
|
||||
|
||||
/* XXX: waiting for the qapi to support GSList */
|
||||
if (!cur_item) {
|
||||
head = cur_item = info;
|
||||
} else {
|
||||
cur_item->next = info;
|
||||
cur_item = info;
|
||||
}
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
3
error.c
3
error.c
@ -12,8 +12,9 @@
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "error.h"
|
||||
#include "qjson.h"
|
||||
#include "qdict.h"
|
||||
#include "error_int.h"
|
||||
#include "qemu-objects.h"
|
||||
#include "qerror.h"
|
||||
|
||||
struct Error
|
||||
|
@ -587,8 +587,7 @@ ETEXI
|
||||
.args_type = "index:i",
|
||||
.params = "index",
|
||||
.help = "set the default CPU",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = do_cpu_set,
|
||||
.mhandler.cmd = hmp_cpu,
|
||||
},
|
||||
|
||||
STEXI
|
||||
|
407
hmp.c
407
hmp.c
@ -94,6 +94,401 @@ void hmp_info_chardev(Monitor *mon)
|
||||
qapi_free_ChardevInfoList(char_info);
|
||||
}
|
||||
|
||||
void hmp_info_mice(Monitor *mon)
|
||||
{
|
||||
MouseInfoList *mice_list, *mouse;
|
||||
|
||||
mice_list = qmp_query_mice(NULL);
|
||||
if (!mice_list) {
|
||||
monitor_printf(mon, "No mouse devices connected\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (mouse = mice_list; mouse; mouse = mouse->next) {
|
||||
monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
|
||||
mouse->value->current ? '*' : ' ',
|
||||
mouse->value->index, mouse->value->name,
|
||||
mouse->value->absolute ? " (absolute)" : "");
|
||||
}
|
||||
|
||||
qapi_free_MouseInfoList(mice_list);
|
||||
}
|
||||
|
||||
void hmp_info_migrate(Monitor *mon)
|
||||
{
|
||||
MigrationInfo *info;
|
||||
|
||||
info = qmp_query_migrate(NULL);
|
||||
|
||||
if (info->has_status) {
|
||||
monitor_printf(mon, "Migration status: %s\n", info->status);
|
||||
}
|
||||
|
||||
if (info->has_ram) {
|
||||
monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n",
|
||||
info->ram->transferred >> 10);
|
||||
monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n",
|
||||
info->ram->remaining >> 10);
|
||||
monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n",
|
||||
info->ram->total >> 10);
|
||||
}
|
||||
|
||||
if (info->has_disk) {
|
||||
monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n",
|
||||
info->disk->transferred >> 10);
|
||||
monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n",
|
||||
info->disk->remaining >> 10);
|
||||
monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n",
|
||||
info->disk->total >> 10);
|
||||
}
|
||||
|
||||
qapi_free_MigrationInfo(info);
|
||||
}
|
||||
|
||||
void hmp_info_cpus(Monitor *mon)
|
||||
{
|
||||
CpuInfoList *cpu_list, *cpu;
|
||||
|
||||
cpu_list = qmp_query_cpus(NULL);
|
||||
|
||||
for (cpu = cpu_list; cpu; cpu = cpu->next) {
|
||||
int active = ' ';
|
||||
|
||||
if (cpu->value->CPU == monitor_get_cpu_index()) {
|
||||
active = '*';
|
||||
}
|
||||
|
||||
monitor_printf(mon, "%c CPU #%" PRId64 ": ", active, cpu->value->CPU);
|
||||
|
||||
if (cpu->value->has_pc) {
|
||||
monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc);
|
||||
}
|
||||
if (cpu->value->has_nip) {
|
||||
monitor_printf(mon, "nip=0x%016" PRIx64, cpu->value->nip);
|
||||
}
|
||||
if (cpu->value->has_npc) {
|
||||
monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc);
|
||||
monitor_printf(mon, "npc=0x%016" PRIx64, cpu->value->npc);
|
||||
}
|
||||
if (cpu->value->has_PC) {
|
||||
monitor_printf(mon, "PC=0x%016" PRIx64, cpu->value->PC);
|
||||
}
|
||||
|
||||
if (cpu->value->halted) {
|
||||
monitor_printf(mon, " (halted)");
|
||||
}
|
||||
|
||||
monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
|
||||
}
|
||||
|
||||
qapi_free_CpuInfoList(cpu_list);
|
||||
}
|
||||
|
||||
void hmp_info_block(Monitor *mon)
|
||||
{
|
||||
BlockInfoList *block_list, *info;
|
||||
|
||||
block_list = qmp_query_block(NULL);
|
||||
|
||||
for (info = block_list; info; info = info->next) {
|
||||
monitor_printf(mon, "%s: removable=%d",
|
||||
info->value->device, info->value->removable);
|
||||
|
||||
if (info->value->removable) {
|
||||
monitor_printf(mon, " locked=%d", info->value->locked);
|
||||
monitor_printf(mon, " tray-open=%d", info->value->tray_open);
|
||||
}
|
||||
|
||||
if (info->value->has_io_status) {
|
||||
monitor_printf(mon, " io-status=%s",
|
||||
BlockDeviceIoStatus_lookup[info->value->io_status]);
|
||||
}
|
||||
|
||||
if (info->value->has_inserted) {
|
||||
monitor_printf(mon, " file=");
|
||||
monitor_print_filename(mon, info->value->inserted->file);
|
||||
|
||||
if (info->value->inserted->has_backing_file) {
|
||||
monitor_printf(mon, " backing_file=");
|
||||
monitor_print_filename(mon, info->value->inserted->backing_file);
|
||||
}
|
||||
monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
|
||||
info->value->inserted->ro,
|
||||
info->value->inserted->drv,
|
||||
info->value->inserted->encrypted);
|
||||
} else {
|
||||
monitor_printf(mon, " [not inserted]");
|
||||
}
|
||||
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
qapi_free_BlockInfoList(block_list);
|
||||
}
|
||||
|
||||
void hmp_info_blockstats(Monitor *mon)
|
||||
{
|
||||
BlockStatsList *stats_list, *stats;
|
||||
|
||||
stats_list = qmp_query_blockstats(NULL);
|
||||
|
||||
for (stats = stats_list; stats; stats = stats->next) {
|
||||
if (!stats->value->has_device) {
|
||||
continue;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "%s:", stats->value->device);
|
||||
monitor_printf(mon, " rd_bytes=%" PRId64
|
||||
" wr_bytes=%" PRId64
|
||||
" rd_operations=%" PRId64
|
||||
" wr_operations=%" PRId64
|
||||
" flush_operations=%" PRId64
|
||||
" wr_total_time_ns=%" PRId64
|
||||
" rd_total_time_ns=%" PRId64
|
||||
" flush_total_time_ns=%" PRId64
|
||||
"\n",
|
||||
stats->value->stats->rd_bytes,
|
||||
stats->value->stats->wr_bytes,
|
||||
stats->value->stats->rd_operations,
|
||||
stats->value->stats->wr_operations,
|
||||
stats->value->stats->flush_operations,
|
||||
stats->value->stats->wr_total_time_ns,
|
||||
stats->value->stats->rd_total_time_ns,
|
||||
stats->value->stats->flush_total_time_ns);
|
||||
}
|
||||
|
||||
qapi_free_BlockStatsList(stats_list);
|
||||
}
|
||||
|
||||
void hmp_info_vnc(Monitor *mon)
|
||||
{
|
||||
VncInfo *info;
|
||||
Error *err = NULL;
|
||||
VncClientInfoList *client;
|
||||
|
||||
info = qmp_query_vnc(&err);
|
||||
if (err) {
|
||||
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
||||
error_free(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info->enabled) {
|
||||
monitor_printf(mon, "Server: disabled\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "Server:\n");
|
||||
if (info->has_host && info->has_service) {
|
||||
monitor_printf(mon, " address: %s:%s\n", info->host, info->service);
|
||||
}
|
||||
if (info->has_auth) {
|
||||
monitor_printf(mon, " auth: %s\n", info->auth);
|
||||
}
|
||||
|
||||
if (!info->has_clients || info->clients == NULL) {
|
||||
monitor_printf(mon, "Client: none\n");
|
||||
} else {
|
||||
for (client = info->clients; client; client = client->next) {
|
||||
monitor_printf(mon, "Client:\n");
|
||||
monitor_printf(mon, " address: %s:%s\n",
|
||||
client->value->host, client->value->service);
|
||||
monitor_printf(mon, " x509_dname: %s\n",
|
||||
client->value->x509_dname ?
|
||||
client->value->x509_dname : "none");
|
||||
monitor_printf(mon, " username: %s\n",
|
||||
client->value->has_sasl_username ?
|
||||
client->value->sasl_username : "none");
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
qapi_free_VncInfo(info);
|
||||
}
|
||||
|
||||
void hmp_info_spice(Monitor *mon)
|
||||
{
|
||||
SpiceChannelList *chan;
|
||||
SpiceInfo *info;
|
||||
|
||||
info = qmp_query_spice(NULL);
|
||||
|
||||
if (!info->enabled) {
|
||||
monitor_printf(mon, "Server: disabled\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "Server:\n");
|
||||
if (info->has_port) {
|
||||
monitor_printf(mon, " address: %s:%" PRId64 "\n",
|
||||
info->host, info->port);
|
||||
}
|
||||
if (info->has_tls_port) {
|
||||
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
|
||||
info->host, info->tls_port);
|
||||
}
|
||||
monitor_printf(mon, " auth: %s\n", info->auth);
|
||||
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
||||
|
||||
if (!info->has_channels || info->channels == NULL) {
|
||||
monitor_printf(mon, "Channels: none\n");
|
||||
} else {
|
||||
for (chan = info->channels; chan; chan = chan->next) {
|
||||
monitor_printf(mon, "Channel:\n");
|
||||
monitor_printf(mon, " address: %s:%s%s\n",
|
||||
chan->value->host, chan->value->port,
|
||||
chan->value->tls ? " [tls]" : "");
|
||||
monitor_printf(mon, " session: %" PRId64 "\n",
|
||||
chan->value->connection_id);
|
||||
monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n",
|
||||
chan->value->channel_type, chan->value->channel_id);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
qapi_free_SpiceInfo(info);
|
||||
}
|
||||
|
||||
void hmp_info_balloon(Monitor *mon)
|
||||
{
|
||||
BalloonInfo *info;
|
||||
Error *err = NULL;
|
||||
|
||||
info = qmp_query_balloon(&err);
|
||||
if (err) {
|
||||
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
||||
error_free(err);
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
|
||||
if (info->has_mem_swapped_in) {
|
||||
monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
|
||||
}
|
||||
if (info->has_mem_swapped_out) {
|
||||
monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
|
||||
}
|
||||
if (info->has_major_page_faults) {
|
||||
monitor_printf(mon, " major_page_faults=%" PRId64,
|
||||
info->major_page_faults);
|
||||
}
|
||||
if (info->has_minor_page_faults) {
|
||||
monitor_printf(mon, " minor_page_faults=%" PRId64,
|
||||
info->minor_page_faults);
|
||||
}
|
||||
if (info->has_free_mem) {
|
||||
monitor_printf(mon, " free_mem=%" PRId64, info->free_mem);
|
||||
}
|
||||
if (info->has_total_mem) {
|
||||
monitor_printf(mon, " total_mem=%" PRId64, info->total_mem);
|
||||
}
|
||||
|
||||
monitor_printf(mon, "\n");
|
||||
|
||||
qapi_free_BalloonInfo(info);
|
||||
}
|
||||
|
||||
static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
|
||||
{
|
||||
PciMemoryRegionList *region;
|
||||
|
||||
monitor_printf(mon, " Bus %2" PRId64 ", ", dev->bus);
|
||||
monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
|
||||
dev->slot, dev->function);
|
||||
monitor_printf(mon, " ");
|
||||
|
||||
if (dev->class_info.has_desc) {
|
||||
monitor_printf(mon, "%s", dev->class_info.desc);
|
||||
} else {
|
||||
monitor_printf(mon, "Class %04" PRId64, dev->class_info.class);
|
||||
}
|
||||
|
||||
monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
|
||||
dev->id.vendor, dev->id.device);
|
||||
|
||||
if (dev->has_irq) {
|
||||
monitor_printf(mon, " IRQ %" PRId64 ".\n", dev->irq);
|
||||
}
|
||||
|
||||
if (dev->has_pci_bridge) {
|
||||
monitor_printf(mon, " BUS %" PRId64 ".\n",
|
||||
dev->pci_bridge->bus.number);
|
||||
monitor_printf(mon, " secondary bus %" PRId64 ".\n",
|
||||
dev->pci_bridge->bus.secondary);
|
||||
monitor_printf(mon, " subordinate bus %" PRId64 ".\n",
|
||||
dev->pci_bridge->bus.subordinate);
|
||||
|
||||
monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
|
||||
dev->pci_bridge->bus.io_range->base,
|
||||
dev->pci_bridge->bus.io_range->limit);
|
||||
|
||||
monitor_printf(mon,
|
||||
" memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
||||
dev->pci_bridge->bus.memory_range->base,
|
||||
dev->pci_bridge->bus.memory_range->limit);
|
||||
|
||||
monitor_printf(mon, " prefetchable memory range "
|
||||
"[0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
||||
dev->pci_bridge->bus.prefetchable_range->base,
|
||||
dev->pci_bridge->bus.prefetchable_range->limit);
|
||||
}
|
||||
|
||||
for (region = dev->regions; region; region = region->next) {
|
||||
uint64_t addr, size;
|
||||
|
||||
addr = region->value->address;
|
||||
size = region->value->size;
|
||||
|
||||
monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar);
|
||||
|
||||
if (!strcmp(region->value->type, "io")) {
|
||||
monitor_printf(mon, "I/O at 0x%04" PRIx64
|
||||
" [0x%04" PRIx64 "].\n",
|
||||
addr, addr + size - 1);
|
||||
} else {
|
||||
monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
|
||||
" [0x%08" PRIx64 "].\n",
|
||||
region->value->mem_type_64 ? 64 : 32,
|
||||
region->value->prefetch ? " prefetchable" : "",
|
||||
addr, addr + size - 1);
|
||||
}
|
||||
}
|
||||
|
||||
monitor_printf(mon, " id \"%s\"\n", dev->qdev_id);
|
||||
|
||||
if (dev->has_pci_bridge) {
|
||||
if (dev->pci_bridge->has_devices) {
|
||||
PciDeviceInfoList *cdev;
|
||||
for (cdev = dev->pci_bridge->devices; cdev; cdev = cdev->next) {
|
||||
hmp_info_pci_device(mon, cdev->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hmp_info_pci(Monitor *mon)
|
||||
{
|
||||
PciInfoList *info;
|
||||
Error *err = NULL;
|
||||
|
||||
info = qmp_query_pci(&err);
|
||||
if (err) {
|
||||
monitor_printf(mon, "PCI devices not supported\n");
|
||||
error_free(err);
|
||||
return;
|
||||
}
|
||||
|
||||
for (; info; info = info->next) {
|
||||
PciDeviceInfoList *dev;
|
||||
|
||||
for (dev = info->value->devices; dev; dev = dev->next) {
|
||||
hmp_info_pci_device(mon, dev->value);
|
||||
}
|
||||
}
|
||||
|
||||
qapi_free_PciInfoList(info);
|
||||
}
|
||||
|
||||
void hmp_quit(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
monitor_suspend(mon);
|
||||
@ -114,3 +509,15 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
qmp_system_powerdown(NULL);
|
||||
}
|
||||
|
||||
void hmp_cpu(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
int64_t cpu_index;
|
||||
|
||||
/* XXX: drop the monitor_set_cpu() usage when all HMP commands that
|
||||
use it are converted to the QAPI */
|
||||
cpu_index = qdict_get_int(qdict, "index");
|
||||
if (monitor_set_cpu(cpu_index) < 0) {
|
||||
monitor_printf(mon, "invalid CPU index\n");
|
||||
}
|
||||
}
|
||||
|
10
hmp.h
10
hmp.h
@ -23,9 +23,19 @@ void hmp_info_kvm(Monitor *mon);
|
||||
void hmp_info_status(Monitor *mon);
|
||||
void hmp_info_uuid(Monitor *mon);
|
||||
void hmp_info_chardev(Monitor *mon);
|
||||
void hmp_info_mice(Monitor *mon);
|
||||
void hmp_info_migrate(Monitor *mon);
|
||||
void hmp_info_cpus(Monitor *mon);
|
||||
void hmp_info_block(Monitor *mon);
|
||||
void hmp_info_blockstats(Monitor *mon);
|
||||
void hmp_info_vnc(Monitor *mon);
|
||||
void hmp_info_spice(Monitor *mon);
|
||||
void hmp_info_balloon(Monitor *mon);
|
||||
void hmp_info_pci(Monitor *mon);
|
||||
void hmp_quit(Monitor *mon, const QDict *qdict);
|
||||
void hmp_stop(Monitor *mon, const QDict *qdict);
|
||||
void hmp_system_reset(Monitor *mon, const QDict *qdict);
|
||||
void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
|
||||
void hmp_cpu(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif
|
||||
|
@ -21,22 +21,19 @@
|
||||
#include "sysemu.h"
|
||||
#include "monitor.h"
|
||||
#include "pci.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
PciInfoList *qmp_query_pci(Error **errp)
|
||||
{
|
||||
error_set(errp, QERR_UNSUPPORTED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pci_error_message(Monitor *mon)
|
||||
{
|
||||
monitor_printf(mon, "PCI devices not supported\n");
|
||||
}
|
||||
|
||||
void do_pci_info(Monitor *mon, QObject **ret_data)
|
||||
{
|
||||
pci_error_message(mon);
|
||||
}
|
||||
|
||||
void do_pci_info_print(Monitor *mon, const QObject *data)
|
||||
{
|
||||
pci_error_message(mon);
|
||||
}
|
||||
|
||||
int do_pcie_aer_inejct_error(Monitor *mon,
|
||||
const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
|
334
hw/pci.c
334
hw/pci.c
@ -29,8 +29,8 @@
|
||||
#include "net.h"
|
||||
#include "sysemu.h"
|
||||
#include "loader.h"
|
||||
#include "qemu-objects.h"
|
||||
#include "range.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
//#define DEBUG_PCI
|
||||
#ifdef DEBUG_PCI
|
||||
@ -1164,276 +1164,194 @@ void pci_for_each_device(PCIBus *bus, int bus_num,
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_device_print(Monitor *mon, QDict *device)
|
||||
static const pci_class_desc *get_class_desc(int class)
|
||||
{
|
||||
QDict *qdict;
|
||||
QListEntry *entry;
|
||||
uint64_t addr, size;
|
||||
|
||||
monitor_printf(mon, " Bus %2" PRId64 ", ", qdict_get_int(device, "bus"));
|
||||
monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
|
||||
qdict_get_int(device, "slot"),
|
||||
qdict_get_int(device, "function"));
|
||||
monitor_printf(mon, " ");
|
||||
|
||||
qdict = qdict_get_qdict(device, "class_info");
|
||||
if (qdict_haskey(qdict, "desc")) {
|
||||
monitor_printf(mon, "%s", qdict_get_str(qdict, "desc"));
|
||||
} else {
|
||||
monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));
|
||||
}
|
||||
|
||||
qdict = qdict_get_qdict(device, "id");
|
||||
monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
|
||||
qdict_get_int(qdict, "device"),
|
||||
qdict_get_int(qdict, "vendor"));
|
||||
|
||||
if (qdict_haskey(device, "irq")) {
|
||||
monitor_printf(mon, " IRQ %" PRId64 ".\n",
|
||||
qdict_get_int(device, "irq"));
|
||||
}
|
||||
|
||||
if (qdict_haskey(device, "pci_bridge")) {
|
||||
QDict *info;
|
||||
|
||||
qdict = qdict_get_qdict(device, "pci_bridge");
|
||||
|
||||
info = qdict_get_qdict(qdict, "bus");
|
||||
monitor_printf(mon, " BUS %" PRId64 ".\n",
|
||||
qdict_get_int(info, "number"));
|
||||
monitor_printf(mon, " secondary bus %" PRId64 ".\n",
|
||||
qdict_get_int(info, "secondary"));
|
||||
monitor_printf(mon, " subordinate bus %" PRId64 ".\n",
|
||||
qdict_get_int(info, "subordinate"));
|
||||
|
||||
info = qdict_get_qdict(qdict, "io_range");
|
||||
monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
|
||||
qdict_get_int(info, "base"),
|
||||
qdict_get_int(info, "limit"));
|
||||
|
||||
info = qdict_get_qdict(qdict, "memory_range");
|
||||
monitor_printf(mon,
|
||||
" memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
||||
qdict_get_int(info, "base"),
|
||||
qdict_get_int(info, "limit"));
|
||||
|
||||
info = qdict_get_qdict(qdict, "prefetchable_range");
|
||||
monitor_printf(mon, " prefetchable memory range "
|
||||
"[0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
||||
qdict_get_int(info, "base"),
|
||||
qdict_get_int(info, "limit"));
|
||||
}
|
||||
|
||||
QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) {
|
||||
qdict = qobject_to_qdict(qlist_entry_obj(entry));
|
||||
monitor_printf(mon, " BAR%d: ", (int) qdict_get_int(qdict, "bar"));
|
||||
|
||||
addr = qdict_get_int(qdict, "address");
|
||||
size = qdict_get_int(qdict, "size");
|
||||
|
||||
if (!strcmp(qdict_get_str(qdict, "type"), "io")) {
|
||||
monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
|
||||
" [0x%04"FMT_PCIBUS"].\n",
|
||||
addr, addr + size - 1);
|
||||
} else {
|
||||
monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS
|
||||
" [0x%08"FMT_PCIBUS"].\n",
|
||||
qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,
|
||||
qdict_get_bool(qdict, "prefetch") ?
|
||||
" prefetchable" : "", addr, addr + size - 1);
|
||||
}
|
||||
}
|
||||
|
||||
monitor_printf(mon, " id \"%s\"\n", qdict_get_str(device, "qdev_id"));
|
||||
|
||||
if (qdict_haskey(device, "pci_bridge")) {
|
||||
qdict = qdict_get_qdict(device, "pci_bridge");
|
||||
if (qdict_haskey(qdict, "devices")) {
|
||||
QListEntry *dev;
|
||||
QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
|
||||
pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void do_pci_info_print(Monitor *mon, const QObject *data)
|
||||
{
|
||||
QListEntry *bus, *dev;
|
||||
|
||||
QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) {
|
||||
QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus));
|
||||
QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
|
||||
pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QObject *pci_get_dev_class(const PCIDevice *dev)
|
||||
{
|
||||
int class;
|
||||
const pci_class_desc *desc;
|
||||
|
||||
class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
|
||||
desc = pci_class_descriptions;
|
||||
while (desc->desc && class != desc->class)
|
||||
while (desc->desc && class != desc->class) {
|
||||
desc++;
|
||||
|
||||
if (desc->desc) {
|
||||
return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",
|
||||
desc->desc, class);
|
||||
} else {
|
||||
return qobject_from_jsonf("{ 'class': %d }", class);
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
static QObject *pci_get_dev_id(const PCIDevice *dev)
|
||||
{
|
||||
return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",
|
||||
pci_get_word(dev->config + PCI_VENDOR_ID),
|
||||
pci_get_word(dev->config + PCI_DEVICE_ID));
|
||||
}
|
||||
static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
|
||||
|
||||
static QObject *pci_get_regions_list(const PCIDevice *dev)
|
||||
static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
|
||||
{
|
||||
PciMemoryRegionList *head = NULL, *cur_item = NULL;
|
||||
int i;
|
||||
QList *regions_list;
|
||||
|
||||
regions_list = qlist_new();
|
||||
|
||||
for (i = 0; i < PCI_NUM_REGIONS; i++) {
|
||||
QObject *obj;
|
||||
const PCIIORegion *r = &dev->io_regions[i];
|
||||
PciMemoryRegionList *region;
|
||||
|
||||
if (!r->size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
|
||||
"'address': %" PRId64 ", "
|
||||
"'size': %" PRId64 " }",
|
||||
i, r->addr, r->size);
|
||||
} else {
|
||||
int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
|
||||
region = g_malloc0(sizeof(*region));
|
||||
region->value = g_malloc0(sizeof(*region->value));
|
||||
|
||||
obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "
|
||||
"'mem_type_64': %i, 'prefetch': %i, "
|
||||
"'address': %" PRId64 ", "
|
||||
"'size': %" PRId64 " }",
|
||||
i, mem_type_64,
|
||||
r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,
|
||||
r->addr, r->size);
|
||||
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
region->value->type = g_strdup("io");
|
||||
} else {
|
||||
region->value->type = g_strdup("memory");
|
||||
region->value->has_prefetch = true;
|
||||
region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||
region->value->has_mem_type_64 = true;
|
||||
region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
|
||||
}
|
||||
|
||||
qlist_append_obj(regions_list, obj);
|
||||
region->value->bar = i;
|
||||
region->value->address = r->addr;
|
||||
region->value->size = r->size;
|
||||
|
||||
/* XXX: waiting for the qapi to support GSList */
|
||||
if (!cur_item) {
|
||||
head = cur_item = region;
|
||||
} else {
|
||||
cur_item->next = region;
|
||||
cur_item = region;
|
||||
}
|
||||
}
|
||||
|
||||
return QOBJECT(regions_list);
|
||||
return head;
|
||||
}
|
||||
|
||||
static QObject *pci_get_devices_list(PCIBus *bus, int bus_num);
|
||||
|
||||
static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num)
|
||||
static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
|
||||
int bus_num)
|
||||
{
|
||||
uint8_t type;
|
||||
QObject *obj;
|
||||
PciBridgeInfo *info;
|
||||
|
||||
obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d," "'class_info': %p, 'id': %p, 'regions': %p,"
|
||||
" 'qdev_id': %s }",
|
||||
bus_num,
|
||||
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
|
||||
pci_get_dev_class(dev), pci_get_dev_id(dev),
|
||||
pci_get_regions_list(dev),
|
||||
dev->qdev.id ? dev->qdev.id : "");
|
||||
info = g_malloc0(sizeof(*info));
|
||||
|
||||
info->bus.number = dev->config[PCI_PRIMARY_BUS];
|
||||
info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
|
||||
info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
|
||||
|
||||
info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
|
||||
info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
||||
info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
||||
|
||||
info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
|
||||
info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
||||
info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
||||
|
||||
info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range));
|
||||
info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||
info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||
|
||||
if (dev->config[PCI_SECONDARY_BUS] != 0) {
|
||||
PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
|
||||
if (child_bus) {
|
||||
info->has_devices = true;
|
||||
info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
|
||||
int bus_num)
|
||||
{
|
||||
const pci_class_desc *desc;
|
||||
PciDeviceInfo *info;
|
||||
uint8_t type;
|
||||
int class;
|
||||
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->bus = bus_num;
|
||||
info->slot = PCI_SLOT(dev->devfn);
|
||||
info->function = PCI_FUNC(dev->devfn);
|
||||
|
||||
class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
|
||||
info->class_info.class = class;
|
||||
desc = get_class_desc(class);
|
||||
if (desc->desc) {
|
||||
info->class_info.has_desc = true;
|
||||
info->class_info.desc = g_strdup(desc->desc);
|
||||
}
|
||||
|
||||
info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
|
||||
info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
|
||||
info->regions = qmp_query_pci_regions(dev);
|
||||
info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
|
||||
|
||||
if (dev->config[PCI_INTERRUPT_PIN] != 0) {
|
||||
QDict *qdict = qobject_to_qdict(obj);
|
||||
qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));
|
||||
info->has_irq = true;
|
||||
info->irq = dev->config[PCI_INTERRUPT_LINE];
|
||||
}
|
||||
|
||||
type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
|
||||
if (type == PCI_HEADER_TYPE_BRIDGE) {
|
||||
QDict *qdict;
|
||||
QObject *pci_bridge;
|
||||
|
||||
pci_bridge = qobject_from_jsonf("{ 'bus': "
|
||||
"{ 'number': %d, 'secondary': %d, 'subordinate': %d }, "
|
||||
"'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
|
||||
"'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
|
||||
"'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }",
|
||||
dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS],
|
||||
dev->config[PCI_SUBORDINATE_BUS],
|
||||
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO),
|
||||
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO),
|
||||
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
|
||||
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
|
||||
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
|
||||
PCI_BASE_ADDRESS_MEM_PREFETCH),
|
||||
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
|
||||
PCI_BASE_ADDRESS_MEM_PREFETCH));
|
||||
|
||||
if (dev->config[PCI_SECONDARY_BUS] != 0) {
|
||||
PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
|
||||
|
||||
if (child_bus) {
|
||||
qdict = qobject_to_qdict(pci_bridge);
|
||||
qdict_put_obj(qdict, "devices",
|
||||
pci_get_devices_list(child_bus,
|
||||
dev->config[PCI_SECONDARY_BUS]));
|
||||
}
|
||||
}
|
||||
qdict = qobject_to_qdict(obj);
|
||||
qdict_put_obj(qdict, "pci_bridge", pci_bridge);
|
||||
info->has_pci_bridge = true;
|
||||
info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
|
||||
}
|
||||
|
||||
return obj;
|
||||
return info;
|
||||
}
|
||||
|
||||
static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)
|
||||
static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
|
||||
{
|
||||
int devfn;
|
||||
PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
|
||||
PCIDevice *dev;
|
||||
QList *dev_list;
|
||||
|
||||
dev_list = qlist_new();
|
||||
int devfn;
|
||||
|
||||
for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
|
||||
dev = bus->devices[devfn];
|
||||
if (dev) {
|
||||
qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus, bus_num));
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->value = qmp_query_pci_device(dev, bus, bus_num);
|
||||
|
||||
/* XXX: waiting for the qapi to support GSList */
|
||||
if (!cur_item) {
|
||||
head = cur_item = info;
|
||||
} else {
|
||||
cur_item->next = info;
|
||||
cur_item = info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QOBJECT(dev_list);
|
||||
return head;
|
||||
}
|
||||
|
||||
static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)
|
||||
static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
|
||||
{
|
||||
PciInfo *info = NULL;
|
||||
|
||||
bus = pci_find_bus(bus, bus_num);
|
||||
if (bus) {
|
||||
return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
|
||||
bus_num, pci_get_devices_list(bus, bus_num));
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->bus = bus_num;
|
||||
info->devices = qmp_query_pci_devices(bus, bus_num);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return info;
|
||||
}
|
||||
|
||||
void do_pci_info(Monitor *mon, QObject **ret_data)
|
||||
PciInfoList *qmp_query_pci(Error **errp)
|
||||
{
|
||||
QList *bus_list;
|
||||
PciInfoList *info, *head = NULL, *cur_item = NULL;
|
||||
struct PCIHostBus *host;
|
||||
|
||||
bus_list = qlist_new();
|
||||
|
||||
QLIST_FOREACH(host, &host_buses, next) {
|
||||
QObject *obj = pci_get_bus_dict(host->bus, 0);
|
||||
if (obj) {
|
||||
qlist_append_obj(bus_list, obj);
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->value = qmp_query_pci_bus(host->bus, 0);
|
||||
|
||||
/* XXX: waiting for the qapi to support GSList */
|
||||
if (!cur_item) {
|
||||
head = cur_item = info;
|
||||
} else {
|
||||
cur_item->next = info;
|
||||
cur_item = info;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_data = QOBJECT(bus_list);
|
||||
return head;
|
||||
}
|
||||
|
||||
static const char * const pci_nic_models[] = {
|
||||
|
4
hw/pci.h
4
hw/pci.h
@ -2,7 +2,6 @@
|
||||
#define QEMU_PCI_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qobject.h"
|
||||
|
||||
#include "qdev.h"
|
||||
#include "memory.h"
|
||||
@ -271,9 +270,6 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
|
||||
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
|
||||
unsigned *slotp);
|
||||
|
||||
void do_pci_info_print(Monitor *mon, const QObject *data);
|
||||
void do_pci_info(Monitor *mon, QObject **ret_data);
|
||||
|
||||
void pci_device_deassert_intx(PCIDevice *dev);
|
||||
|
||||
static inline void
|
||||
|
@ -18,22 +18,14 @@
|
||||
#include "virtio.h"
|
||||
#include "pc.h"
|
||||
#include "cpu.h"
|
||||
#include "monitor.h"
|
||||
#include "balloon.h"
|
||||
#include "virtio-balloon.h"
|
||||
#include "kvm.h"
|
||||
#include "qlist.h"
|
||||
#include "qint.h"
|
||||
#include "qstring.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */
|
||||
#define ENABLE_GUEST_STATS 0
|
||||
|
||||
|
||||
typedef struct VirtIOBalloon
|
||||
{
|
||||
VirtIODevice vdev;
|
||||
@ -43,8 +35,6 @@ typedef struct VirtIOBalloon
|
||||
uint64_t stats[VIRTIO_BALLOON_S_NR];
|
||||
VirtQueueElement stats_vq_elem;
|
||||
size_t stats_vq_offset;
|
||||
MonitorCompletion *stats_callback;
|
||||
void *stats_opaque_callback_data;
|
||||
DeviceState *qdev;
|
||||
} VirtIOBalloon;
|
||||
|
||||
@ -76,31 +66,6 @@ static inline void reset_stats(VirtIOBalloon *dev)
|
||||
for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
|
||||
}
|
||||
|
||||
static void stat_put(QDict *dict, const char *label, uint64_t val)
|
||||
{
|
||||
if (val != -1)
|
||||
qdict_put(dict, label, qint_from_int(val));
|
||||
}
|
||||
|
||||
static QObject *get_stats_qobject(VirtIOBalloon *dev)
|
||||
{
|
||||
QDict *dict = qdict_new();
|
||||
uint64_t actual = ram_size - ((uint64_t) dev->actual <<
|
||||
VIRTIO_BALLOON_PFN_SHIFT);
|
||||
|
||||
stat_put(dict, "actual", actual);
|
||||
#if ENABLE_GUEST_STATS
|
||||
stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]);
|
||||
stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
|
||||
stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]);
|
||||
stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]);
|
||||
stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
|
||||
stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
|
||||
#endif
|
||||
|
||||
return QOBJECT(dict);
|
||||
}
|
||||
|
||||
static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
VirtIOBalloon *s = to_virtio_balloon(vdev);
|
||||
@ -131,20 +96,6 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
}
|
||||
}
|
||||
|
||||
static void complete_stats_request(VirtIOBalloon *vb)
|
||||
{
|
||||
QObject *stats;
|
||||
|
||||
if (!vb->stats_opaque_callback_data)
|
||||
return;
|
||||
|
||||
stats = get_stats_qobject(vb);
|
||||
vb->stats_callback(vb->stats_opaque_callback_data, stats);
|
||||
qobject_decref(stats);
|
||||
vb->stats_opaque_callback_data = NULL;
|
||||
vb->stats_callback = NULL;
|
||||
}
|
||||
|
||||
static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
|
||||
@ -172,8 +123,6 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
|
||||
s->stats[tag] = val;
|
||||
}
|
||||
s->stats_vq_offset = offset;
|
||||
|
||||
complete_stats_request(s);
|
||||
}
|
||||
|
||||
static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
|
||||
@ -202,32 +151,33 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
|
||||
return f;
|
||||
}
|
||||
|
||||
static void virtio_balloon_stat(void *opaque, MonitorCompletion cb,
|
||||
void *cb_data)
|
||||
static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
|
||||
{
|
||||
VirtIOBalloon *dev = opaque;
|
||||
|
||||
/* For now, only allow one request at a time. This restriction can be
|
||||
* removed later by queueing callback and data pairs.
|
||||
#if 0
|
||||
/* Disable guest-provided stats for now. For more details please check:
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=623903
|
||||
*
|
||||
* If you do enable it (which is probably not going to happen as we
|
||||
* need a new command for it), remember that you also need to fill the
|
||||
* appropriate members of the BalloonInfo structure so that the stats
|
||||
* are returned to the client.
|
||||
*/
|
||||
if (dev->stats_callback != NULL) {
|
||||
return;
|
||||
}
|
||||
dev->stats_callback = cb;
|
||||
dev->stats_opaque_callback_data = cb_data;
|
||||
|
||||
if (ENABLE_GUEST_STATS
|
||||
&& (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
|
||||
if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
|
||||
virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
|
||||
virtio_notify(&dev->vdev, dev->svq);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Stats are not supported. Clear out any stale values that might
|
||||
* have been set by a more featureful guest kernel.
|
||||
*/
|
||||
reset_stats(dev);
|
||||
complete_stats_request(dev);
|
||||
|
||||
info->actual = ram_size - ((uint64_t) dev->actual <<
|
||||
VIRTIO_BALLOON_PFN_SHIFT);
|
||||
}
|
||||
|
||||
static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
|
||||
|
66
input.c
66
input.c
@ -26,7 +26,8 @@
|
||||
#include "net.h"
|
||||
#include "monitor.h"
|
||||
#include "console.h"
|
||||
#include "qjson.h"
|
||||
#include "error.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
static QEMUPutKBDEvent *qemu_put_kbd_event;
|
||||
static void *qemu_put_kbd_event_opaque;
|
||||
@ -211,60 +212,27 @@ int kbd_mouse_has_absolute(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void info_mice_iter(QObject *data, void *opaque)
|
||||
{
|
||||
QDict *mouse;
|
||||
Monitor *mon = opaque;
|
||||
|
||||
mouse = qobject_to_qdict(data);
|
||||
monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
|
||||
(qdict_get_bool(mouse, "current") ? '*' : ' '),
|
||||
qdict_get_int(mouse, "index"), qdict_get_str(mouse, "name"),
|
||||
qdict_get_bool(mouse, "absolute") ? " (absolute)" : "");
|
||||
}
|
||||
|
||||
void do_info_mice_print(Monitor *mon, const QObject *data)
|
||||
{
|
||||
QList *mice_list;
|
||||
|
||||
mice_list = qobject_to_qlist(data);
|
||||
if (qlist_empty(mice_list)) {
|
||||
monitor_printf(mon, "No mouse devices connected\n");
|
||||
return;
|
||||
}
|
||||
|
||||
qlist_iter(mice_list, info_mice_iter, mon);
|
||||
}
|
||||
|
||||
void do_info_mice(Monitor *mon, QObject **ret_data)
|
||||
MouseInfoList *qmp_query_mice(Error **errp)
|
||||
{
|
||||
MouseInfoList *mice_list = NULL;
|
||||
QEMUPutMouseEntry *cursor;
|
||||
QList *mice_list;
|
||||
int current;
|
||||
|
||||
mice_list = qlist_new();
|
||||
|
||||
if (QTAILQ_EMPTY(&mouse_handlers)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
current = QTAILQ_FIRST(&mouse_handlers)->index;
|
||||
bool current = true;
|
||||
|
||||
QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
|
||||
QObject *obj;
|
||||
obj = qobject_from_jsonf("{ 'name': %s,"
|
||||
" 'index': %d,"
|
||||
" 'current': %i,"
|
||||
" 'absolute': %i }",
|
||||
cursor->qemu_put_mouse_event_name,
|
||||
cursor->index,
|
||||
cursor->index == current,
|
||||
!!cursor->qemu_put_mouse_event_absolute);
|
||||
qlist_append_obj(mice_list, obj);
|
||||
MouseInfoList *info = g_malloc0(sizeof(*info));
|
||||
info->value = g_malloc0(sizeof(*info->value));
|
||||
info->value->name = g_strdup(cursor->qemu_put_mouse_event_name);
|
||||
info->value->index = cursor->index;
|
||||
info->value->absolute = !!cursor->qemu_put_mouse_event_absolute;
|
||||
info->value->current = current;
|
||||
|
||||
current = false;
|
||||
|
||||
info->next = mice_list;
|
||||
mice_list = info;
|
||||
}
|
||||
|
||||
out:
|
||||
*ret_data = QOBJECT(mice_list);
|
||||
return mice_list;
|
||||
}
|
||||
|
||||
void do_mouse_set(Monitor *mon, const QDict *qdict)
|
||||
|
82
migration.c
82
migration.c
@ -19,7 +19,7 @@
|
||||
#include "block.h"
|
||||
#include "qemu_socket.h"
|
||||
#include "block-migration.h"
|
||||
#include "qemu-objects.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
//#define DEBUG_MIGRATION
|
||||
|
||||
@ -107,53 +107,9 @@ uint64_t migrate_max_downtime(void)
|
||||
return max_downtime;
|
||||
}
|
||||
|
||||
static void migrate_print_status(Monitor *mon, const char *name,
|
||||
const QDict *status_dict)
|
||||
MigrationInfo *qmp_query_migrate(Error **errp)
|
||||
{
|
||||
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);
|
||||
qdict_put_obj(qdict, name, obj);
|
||||
}
|
||||
|
||||
void do_info_migrate(Monitor *mon, QObject **ret_data)
|
||||
{
|
||||
QDict *qdict;
|
||||
MigrationInfo *info = g_malloc0(sizeof(*info));
|
||||
MigrationState *s = migrate_get_current();
|
||||
|
||||
switch (s->state) {
|
||||
@ -161,30 +117,38 @@ void do_info_migrate(Monitor *mon, QObject **ret_data)
|
||||
/* no migration has happened ever */
|
||||
break;
|
||||
case MIG_STATE_ACTIVE:
|
||||
qdict = qdict_new();
|
||||
qdict_put(qdict, "status", qstring_from_str("active"));
|
||||
info->has_status = true;
|
||||
info->status = g_strdup("active");
|
||||
|
||||
migrate_put_status(qdict, "ram", ram_bytes_transferred(),
|
||||
ram_bytes_remaining(), ram_bytes_total());
|
||||
info->has_ram = true;
|
||||
info->ram = g_malloc0(sizeof(*info->ram));
|
||||
info->ram->transferred = ram_bytes_transferred();
|
||||
info->ram->remaining = ram_bytes_remaining();
|
||||
info->ram->total = ram_bytes_total();
|
||||
|
||||
if (blk_mig_active()) {
|
||||
migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
|
||||
blk_mig_bytes_remaining(),
|
||||
blk_mig_bytes_total());
|
||||
info->has_disk = true;
|
||||
info->disk = g_malloc0(sizeof(*info->disk));
|
||||
info->disk->transferred = blk_mig_bytes_transferred();
|
||||
info->disk->remaining = blk_mig_bytes_remaining();
|
||||
info->disk->total = blk_mig_bytes_total();
|
||||
}
|
||||
|
||||
*ret_data = QOBJECT(qdict);
|
||||
break;
|
||||
case MIG_STATE_COMPLETED:
|
||||
*ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
|
||||
info->has_status = true;
|
||||
info->status = g_strdup("completed");
|
||||
break;
|
||||
case MIG_STATE_ERROR:
|
||||
*ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
|
||||
info->has_status = true;
|
||||
info->status = g_strdup("failed");
|
||||
break;
|
||||
case MIG_STATE_CANCELLED:
|
||||
*ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
|
||||
info->has_status = true;
|
||||
info->status = g_strdup("cancelled");
|
||||
break;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/* shared migration helpers */
|
||||
|
313
monitor.c
313
monitor.c
@ -123,8 +123,6 @@ typedef struct mon_cmd_t {
|
||||
void (*user_print)(Monitor *mon, const QObject *data);
|
||||
union {
|
||||
void (*info)(Monitor *mon);
|
||||
void (*info_new)(Monitor *mon, QObject **ret_data);
|
||||
int (*info_async)(Monitor *mon, MonitorCompletion *cb, void *opaque);
|
||||
void (*cmd)(Monitor *mon, const QDict *qdict);
|
||||
int (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
|
||||
int (*cmd_async)(Monitor *mon, const QDict *params,
|
||||
@ -205,7 +203,6 @@ static const mon_cmd_t mon_cmds[];
|
||||
static const mon_cmd_t info_cmds[];
|
||||
|
||||
static const mon_cmd_t qmp_cmds[];
|
||||
static const mon_cmd_t qmp_query_cmds[];
|
||||
|
||||
Monitor *cur_mon;
|
||||
Monitor *default_mon;
|
||||
@ -514,7 +511,6 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mon_set_cpu(int cpu_index);
|
||||
static void handle_user_command(Monitor *mon, const char *cmdline);
|
||||
|
||||
static int do_hmp_passthrough(Monitor *mon, const QDict *params,
|
||||
@ -532,7 +528,7 @@ static int do_hmp_passthrough(Monitor *mon, const QDict *params,
|
||||
cur_mon = &hmp;
|
||||
|
||||
if (qdict_haskey(params, "cpu-index")) {
|
||||
ret = mon_set_cpu(qdict_get_int(params, "cpu-index"));
|
||||
ret = monitor_set_cpu(qdict_get_int(params, "cpu-index"));
|
||||
if (ret < 0) {
|
||||
cur_mon = old_mon;
|
||||
qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number");
|
||||
@ -664,11 +660,6 @@ static int qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
|
||||
return cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
|
||||
}
|
||||
|
||||
static void qmp_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
|
||||
{
|
||||
cmd->mhandler.info_async(mon, qmp_monitor_complete, mon);
|
||||
}
|
||||
|
||||
static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
|
||||
const QDict *params)
|
||||
{
|
||||
@ -686,21 +677,6 @@ static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
MonitorCompletionData *cb_data = g_malloc(sizeof(*cb_data));
|
||||
cb_data->mon = mon;
|
||||
cb_data->user_print = cmd->user_print;
|
||||
monitor_suspend(mon);
|
||||
ret = cmd->mhandler.info_async(mon, user_monitor_complete, cb_data);
|
||||
if (ret < 0) {
|
||||
monitor_resume(mon);
|
||||
g_free(cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_info(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const mon_cmd_t *cmd;
|
||||
@ -719,52 +695,23 @@ static void do_info(Monitor *mon, const QDict *qdict)
|
||||
goto help;
|
||||
}
|
||||
|
||||
if (handler_is_async(cmd)) {
|
||||
user_async_info_handler(mon, cmd);
|
||||
} else if (handler_is_qobject(cmd)) {
|
||||
QObject *info_data = NULL;
|
||||
|
||||
cmd->mhandler.info_new(mon, &info_data);
|
||||
if (info_data) {
|
||||
cmd->user_print(mon, info_data);
|
||||
qobject_decref(info_data);
|
||||
}
|
||||
} else {
|
||||
cmd->mhandler.info(mon);
|
||||
}
|
||||
|
||||
cmd->mhandler.info(mon);
|
||||
return;
|
||||
|
||||
help:
|
||||
help_cmd(mon, "info");
|
||||
}
|
||||
|
||||
static CommandInfoList *alloc_cmd_entry(const char *cmd_name)
|
||||
{
|
||||
CommandInfoList *info;
|
||||
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->value = g_malloc0(sizeof(*info->value));
|
||||
info->value->name = g_strdup(cmd_name);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
CommandInfoList *qmp_query_commands(Error **errp)
|
||||
{
|
||||
CommandInfoList *info, *cmd_list = NULL;
|
||||
const mon_cmd_t *cmd;
|
||||
|
||||
for (cmd = qmp_cmds; cmd->name != NULL; cmd++) {
|
||||
info = alloc_cmd_entry(cmd->name);
|
||||
info->next = cmd_list;
|
||||
cmd_list = info;
|
||||
}
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->value = g_malloc0(sizeof(*info->value));
|
||||
info->value->name = g_strdup(cmd->name);
|
||||
|
||||
for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) {
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "query-%s", cmd->name);
|
||||
info = alloc_cmd_entry(buf);
|
||||
info->next = cmd_list;
|
||||
cmd_list = info;
|
||||
}
|
||||
@ -772,8 +719,8 @@ CommandInfoList *qmp_query_commands(Error **errp)
|
||||
return cmd_list;
|
||||
}
|
||||
|
||||
/* get the current CPU defined by the user */
|
||||
static int mon_set_cpu(int cpu_index)
|
||||
/* set the current CPU defined by the user */
|
||||
int monitor_set_cpu(int cpu_index)
|
||||
{
|
||||
CPUState *env;
|
||||
|
||||
@ -789,12 +736,17 @@ static int mon_set_cpu(int cpu_index)
|
||||
static CPUState *mon_get_cpu(void)
|
||||
{
|
||||
if (!cur_mon->mon_cpu) {
|
||||
mon_set_cpu(0);
|
||||
monitor_set_cpu(0);
|
||||
}
|
||||
cpu_synchronize_state(cur_mon->mon_cpu);
|
||||
return cur_mon->mon_cpu;
|
||||
}
|
||||
|
||||
int monitor_get_cpu_index(void)
|
||||
{
|
||||
return mon_get_cpu()->cpu_index;
|
||||
}
|
||||
|
||||
static void do_info_registers(Monitor *mon)
|
||||
{
|
||||
CPUState *env;
|
||||
@ -808,107 +760,6 @@ static void do_info_registers(Monitor *mon)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print_cpu_iter(QObject *obj, void *opaque)
|
||||
{
|
||||
QDict *cpu;
|
||||
int active = ' ';
|
||||
Monitor *mon = opaque;
|
||||
|
||||
assert(qobject_type(obj) == QTYPE_QDICT);
|
||||
cpu = qobject_to_qdict(obj);
|
||||
|
||||
if (qdict_get_bool(cpu, "current")) {
|
||||
active = '*';
|
||||
}
|
||||
|
||||
monitor_printf(mon, "%c CPU #%d: ", active, (int)qdict_get_int(cpu, "CPU"));
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
|
||||
(target_ulong) qdict_get_int(cpu, "pc"));
|
||||
#elif defined(TARGET_PPC)
|
||||
monitor_printf(mon, "nip=0x" TARGET_FMT_lx,
|
||||
(target_long) qdict_get_int(cpu, "nip"));
|
||||
#elif defined(TARGET_SPARC)
|
||||
monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
|
||||
(target_long) qdict_get_int(cpu, "pc"));
|
||||
monitor_printf(mon, "npc=0x" TARGET_FMT_lx,
|
||||
(target_long) qdict_get_int(cpu, "npc"));
|
||||
#elif defined(TARGET_MIPS)
|
||||
monitor_printf(mon, "PC=0x" TARGET_FMT_lx,
|
||||
(target_long) qdict_get_int(cpu, "PC"));
|
||||
#endif
|
||||
|
||||
if (qdict_get_bool(cpu, "halted")) {
|
||||
monitor_printf(mon, " (halted)");
|
||||
}
|
||||
|
||||
monitor_printf(mon, " thread_id=%" PRId64 " ",
|
||||
qdict_get_int(cpu, "thread_id"));
|
||||
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
static void monitor_print_cpus(Monitor *mon, const QObject *data)
|
||||
{
|
||||
QList *cpu_list;
|
||||
|
||||
assert(qobject_type(data) == QTYPE_QLIST);
|
||||
cpu_list = qobject_to_qlist(data);
|
||||
qlist_iter(cpu_list, print_cpu_iter, mon);
|
||||
}
|
||||
|
||||
static void do_info_cpus(Monitor *mon, QObject **ret_data)
|
||||
{
|
||||
CPUState *env;
|
||||
QList *cpu_list;
|
||||
|
||||
cpu_list = qlist_new();
|
||||
|
||||
/* just to set the default cpu if not already done */
|
||||
mon_get_cpu();
|
||||
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
QDict *cpu;
|
||||
QObject *obj;
|
||||
|
||||
cpu_synchronize_state(env);
|
||||
|
||||
obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }",
|
||||
env->cpu_index, env == mon->mon_cpu,
|
||||
env->halted);
|
||||
|
||||
cpu = qobject_to_qdict(obj);
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
qdict_put(cpu, "pc", qint_from_int(env->eip + env->segs[R_CS].base));
|
||||
#elif defined(TARGET_PPC)
|
||||
qdict_put(cpu, "nip", qint_from_int(env->nip));
|
||||
#elif defined(TARGET_SPARC)
|
||||
qdict_put(cpu, "pc", qint_from_int(env->pc));
|
||||
qdict_put(cpu, "npc", qint_from_int(env->npc));
|
||||
#elif defined(TARGET_MIPS)
|
||||
qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
|
||||
#endif
|
||||
qdict_put(cpu, "thread_id", qint_from_int(env->thread_id));
|
||||
|
||||
qlist_append(cpu_list, cpu);
|
||||
}
|
||||
|
||||
*ret_data = QOBJECT(cpu_list);
|
||||
}
|
||||
|
||||
static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
int index = qdict_get_int(qdict, "index");
|
||||
if (mon_set_cpu(index) < 0) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_VALUE, "index",
|
||||
"a CPU number");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_info_jit(Monitor *mon)
|
||||
{
|
||||
dump_exec_info((FILE *)mon, monitor_fprintf);
|
||||
@ -2773,16 +2624,14 @@ static const mon_cmd_t info_cmds[] = {
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the block devices",
|
||||
.user_print = bdrv_info_print,
|
||||
.mhandler.info_new = bdrv_info,
|
||||
.mhandler.info = hmp_info_block,
|
||||
},
|
||||
{
|
||||
.name = "blockstats",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show block device statistics",
|
||||
.user_print = bdrv_stats_print,
|
||||
.mhandler.info_new = bdrv_info_stats,
|
||||
.mhandler.info = hmp_info_blockstats,
|
||||
},
|
||||
{
|
||||
.name = "registers",
|
||||
@ -2796,8 +2645,7 @@ static const mon_cmd_t info_cmds[] = {
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show infos for each CPU",
|
||||
.user_print = monitor_print_cpus,
|
||||
.mhandler.info_new = do_info_cpus,
|
||||
.mhandler.info = hmp_info_cpus,
|
||||
},
|
||||
{
|
||||
.name = "history",
|
||||
@ -2840,8 +2688,7 @@ static const mon_cmd_t info_cmds[] = {
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show PCI info",
|
||||
.user_print = do_pci_info_print,
|
||||
.mhandler.info_new = do_pci_info,
|
||||
.mhandler.info = hmp_info_pci,
|
||||
},
|
||||
#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
|
||||
defined(TARGET_PPC)
|
||||
@ -2944,16 +2791,14 @@ static const mon_cmd_t info_cmds[] = {
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show which guest mouse is receiving events",
|
||||
.user_print = do_info_mice_print,
|
||||
.mhandler.info_new = do_info_mice,
|
||||
.mhandler.info = hmp_info_mice,
|
||||
},
|
||||
{
|
||||
.name = "vnc",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the vnc server status",
|
||||
.user_print = do_info_vnc_print,
|
||||
.mhandler.info_new = do_info_vnc,
|
||||
.mhandler.info = hmp_info_vnc,
|
||||
},
|
||||
#if defined(CONFIG_SPICE)
|
||||
{
|
||||
@ -2961,8 +2806,7 @@ static const mon_cmd_t info_cmds[] = {
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the spice server status",
|
||||
.user_print = do_info_spice_print,
|
||||
.mhandler.info_new = do_info_spice,
|
||||
.mhandler.info = hmp_info_spice,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
@ -3002,17 +2846,14 @@ static const mon_cmd_t info_cmds[] = {
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show migration status",
|
||||
.user_print = do_info_migrate_print,
|
||||
.mhandler.info_new = do_info_migrate,
|
||||
.mhandler.info = hmp_info_migrate,
|
||||
},
|
||||
{
|
||||
.name = "balloon",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show balloon information",
|
||||
.user_print = monitor_print_balloon,
|
||||
.mhandler.info_async = do_info_balloon,
|
||||
.flags = MONITOR_CMD_ASYNC,
|
||||
.mhandler.info = hmp_info_balloon,
|
||||
},
|
||||
{
|
||||
.name = "qtree",
|
||||
@ -3061,85 +2902,6 @@ static const mon_cmd_t qmp_cmds[] = {
|
||||
{ /* NULL */ },
|
||||
};
|
||||
|
||||
static const mon_cmd_t qmp_query_cmds[] = {
|
||||
{
|
||||
.name = "block",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the block devices",
|
||||
.user_print = bdrv_info_print,
|
||||
.mhandler.info_new = bdrv_info,
|
||||
},
|
||||
{
|
||||
.name = "blockstats",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show block device statistics",
|
||||
.user_print = bdrv_stats_print,
|
||||
.mhandler.info_new = bdrv_info_stats,
|
||||
},
|
||||
{
|
||||
.name = "cpus",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show infos for each CPU",
|
||||
.user_print = monitor_print_cpus,
|
||||
.mhandler.info_new = do_info_cpus,
|
||||
},
|
||||
{
|
||||
.name = "pci",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show PCI info",
|
||||
.user_print = do_pci_info_print,
|
||||
.mhandler.info_new = do_pci_info,
|
||||
},
|
||||
{
|
||||
.name = "mice",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show which guest mouse is receiving events",
|
||||
.user_print = do_info_mice_print,
|
||||
.mhandler.info_new = do_info_mice,
|
||||
},
|
||||
{
|
||||
.name = "vnc",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the vnc server status",
|
||||
.user_print = do_info_vnc_print,
|
||||
.mhandler.info_new = do_info_vnc,
|
||||
},
|
||||
#if defined(CONFIG_SPICE)
|
||||
{
|
||||
.name = "spice",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the spice server status",
|
||||
.user_print = do_info_spice_print,
|
||||
.mhandler.info_new = do_info_spice,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.name = "migrate",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show migration status",
|
||||
.user_print = do_info_migrate_print,
|
||||
.mhandler.info_new = do_info_migrate,
|
||||
},
|
||||
{
|
||||
.name = "balloon",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show balloon information",
|
||||
.user_print = monitor_print_balloon,
|
||||
.mhandler.info_async = do_info_balloon,
|
||||
.flags = MONITOR_CMD_ASYNC,
|
||||
},
|
||||
{ /* NULL */ },
|
||||
};
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
static const char *pch;
|
||||
@ -3934,11 +3696,6 @@ static const mon_cmd_t *monitor_find_command(const char *cmdname)
|
||||
return search_dispatch_table(mon_cmds, cmdname);
|
||||
}
|
||||
|
||||
static const mon_cmd_t *qmp_find_query_cmd(const char *info_item)
|
||||
{
|
||||
return search_dispatch_table(qmp_query_cmds, info_item);
|
||||
}
|
||||
|
||||
static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
|
||||
{
|
||||
return search_dispatch_table(qmp_cmds, cmdname);
|
||||
@ -4862,22 +4619,6 @@ static QDict *qmp_check_input_obj(QObject *input_obj)
|
||||
return input_dict;
|
||||
}
|
||||
|
||||
static void qmp_call_query_cmd(Monitor *mon, const mon_cmd_t *cmd)
|
||||
{
|
||||
QObject *ret_data = NULL;
|
||||
|
||||
if (handler_is_async(cmd)) {
|
||||
qmp_async_info_handler(mon, cmd);
|
||||
if (monitor_has_error(mon)) {
|
||||
monitor_protocol_emitter(mon, NULL);
|
||||
}
|
||||
} else {
|
||||
cmd->mhandler.info_new(mon, &ret_data);
|
||||
monitor_protocol_emitter(mon, ret_data);
|
||||
qobject_decref(ret_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd,
|
||||
const QDict *params)
|
||||
{
|
||||
@ -4898,10 +4639,9 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
||||
QObject *obj;
|
||||
QDict *input, *args;
|
||||
const mon_cmd_t *cmd;
|
||||
const char *cmd_name;
|
||||
Monitor *mon = cur_mon;
|
||||
const char *cmd_name, *query_cmd;
|
||||
|
||||
query_cmd = NULL;
|
||||
args = input = NULL;
|
||||
|
||||
obj = json_parser_parse(tokens, NULL);
|
||||
@ -4928,9 +4668,6 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
||||
}
|
||||
|
||||
cmd = qmp_find_cmd(cmd_name);
|
||||
if (!cmd && strstart(cmd_name, "query-", &query_cmd)) {
|
||||
cmd = qmp_find_query_cmd(query_cmd);
|
||||
}
|
||||
if (!cmd) {
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
|
||||
goto err_out;
|
||||
@ -4949,9 +4686,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (query_cmd) {
|
||||
qmp_call_query_cmd(mon, cmd);
|
||||
} else if (handler_is_async(cmd)) {
|
||||
if (handler_is_async(cmd)) {
|
||||
err = qmp_async_cmd_handler(mon, cmd, args);
|
||||
if (err) {
|
||||
/* emit the error response */
|
||||
|
@ -57,6 +57,8 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
|
||||
void monitor_printf(Monitor *mon, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
|
||||
void monitor_print_filename(Monitor *mon, const char *filename);
|
||||
void monitor_flush(Monitor *mon);
|
||||
int monitor_set_cpu(int cpu_index);
|
||||
int monitor_get_cpu_index(void);
|
||||
|
||||
typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
|
||||
|
||||
|
616
qapi-schema.json
616
qapi-schema.json
@ -225,6 +225,611 @@
|
||||
##
|
||||
{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
|
||||
|
||||
##
|
||||
# @MigrationStats
|
||||
#
|
||||
# Detailed migration status.
|
||||
#
|
||||
# @transferred: amount of bytes already transferred to the target VM
|
||||
#
|
||||
# @remaining: amount of bytes remaining to be transferred to the target VM
|
||||
#
|
||||
# @total: total amount of bytes involved in the migration process
|
||||
#
|
||||
# Since: 0.14.0.
|
||||
##
|
||||
{ 'type': 'MigrationStats',
|
||||
'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' } }
|
||||
|
||||
##
|
||||
# @MigrationInfo
|
||||
#
|
||||
# Information about current migration process.
|
||||
#
|
||||
# @status: #optional string describing the current migration status.
|
||||
# As of 0.14.0 this can be 'active', 'completed', 'failed' or
|
||||
# 'cancelled'. If this field is not returned, no migration process
|
||||
# has been initiated
|
||||
#
|
||||
# @ram: #optional @MigrationStats containing detailed migration status,
|
||||
# only returned if status is 'active'
|
||||
#
|
||||
# @disk: #optional @MigrationStats containing detailed disk migration
|
||||
# status, only returned if status is 'active' and it is a block
|
||||
# migration
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'MigrationInfo',
|
||||
'data': {'*status': 'str', '*ram': 'MigrationStats',
|
||||
'*disk': 'MigrationStats'} }
|
||||
|
||||
##
|
||||
# @query-migrate
|
||||
#
|
||||
# Returns information about current migration process.
|
||||
#
|
||||
# Returns: @MigrationInfo
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'query-migrate', 'returns': 'MigrationInfo' }
|
||||
|
||||
##
|
||||
# @MouseInfo:
|
||||
#
|
||||
# Information about a mouse device.
|
||||
#
|
||||
# @name: the name of the mouse device
|
||||
#
|
||||
# @index: the index of the mouse device
|
||||
#
|
||||
# @current: true if this device is currently receiving mouse events
|
||||
#
|
||||
# @absolute: true if this device supports absolute coordinates as input
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'MouseInfo',
|
||||
'data': {'name': 'str', 'index': 'int', 'current': 'bool',
|
||||
'absolute': 'bool'} }
|
||||
|
||||
##
|
||||
# @query-mice:
|
||||
#
|
||||
# Returns information about each active mouse device
|
||||
#
|
||||
# Returns: a list of @MouseInfo for each device
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'query-mice', 'returns': ['MouseInfo'] }
|
||||
|
||||
##
|
||||
# @CpuInfo:
|
||||
#
|
||||
# Information about a virtual CPU
|
||||
#
|
||||
# @CPU: the index of the virtual CPU
|
||||
#
|
||||
# @current: this only exists for backwards compatible and should be ignored
|
||||
#
|
||||
# @halted: true if the virtual CPU is in the halt state. Halt usually refers
|
||||
# to a processor specific low power mode.
|
||||
#
|
||||
# @pc: #optional If the target is i386 or x86_64, this is the 64-bit instruction
|
||||
# pointer.
|
||||
# If the target is Sparc, this is the PC component of the
|
||||
# instruction pointer.
|
||||
#
|
||||
# @nip: #optional If the target is PPC, the instruction pointer
|
||||
#
|
||||
# @npc: #optional If the target is Sparc, the NPC component of the instruction
|
||||
# pointer
|
||||
#
|
||||
# @PC: #optional If the target is MIPS, the instruction pointer
|
||||
#
|
||||
# @thread_id: ID of the underlying host thread
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Notes: @halted is a transient state that changes frequently. By the time the
|
||||
# data is sent to the client, the guest may no longer be halted.
|
||||
##
|
||||
{ 'type': 'CpuInfo',
|
||||
'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', '*pc': 'int',
|
||||
'*nip': 'int', '*npc': 'int', '*PC': 'int', 'thread_id': 'int'} }
|
||||
|
||||
##
|
||||
# @query-cpus:
|
||||
#
|
||||
# Returns a list of information about each virtual CPU.
|
||||
#
|
||||
# Returns: a list of @CpuInfo for each virtual CPU
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'query-cpus', 'returns': ['CpuInfo'] }
|
||||
|
||||
##
|
||||
# @BlockDeviceInfo:
|
||||
#
|
||||
# Information about the backing device for a block device.
|
||||
#
|
||||
# @file: the filename of the backing device
|
||||
#
|
||||
# @ro: true if the backing device was open read-only
|
||||
#
|
||||
# @drv: the name of the block format used to open the backing device. As of
|
||||
# 0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg',
|
||||
# 'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
|
||||
# 'host_floppy', 'http', 'https', 'nbd', 'parallels', 'qcow',
|
||||
# 'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat'
|
||||
#
|
||||
# @backing_file: #optional the name of the backing file (for copy-on-write)
|
||||
#
|
||||
# @encrypted: true if the backing device is encrypted
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Notes: This interface is only found in @BlockInfo.
|
||||
##
|
||||
{ 'type': 'BlockDeviceInfo',
|
||||
'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
|
||||
'*backing_file': 'str', 'encrypted': 'bool' } }
|
||||
|
||||
##
|
||||
# @BlockDeviceIoStatus:
|
||||
#
|
||||
# An enumeration of block device I/O status.
|
||||
#
|
||||
# @ok: The last I/O operation has succeeded
|
||||
#
|
||||
# @failed: The last I/O operation has failed
|
||||
#
|
||||
# @nospace: The last I/O operation has failed due to a no-space condition
|
||||
#
|
||||
# Since: 1.0
|
||||
##
|
||||
{ 'enum': 'BlockDeviceIoStatus', 'data': [ 'ok', 'failed', 'nospace' ] }
|
||||
|
||||
##
|
||||
# @BlockInfo:
|
||||
#
|
||||
# Block device information. This structure describes a virtual device and
|
||||
# the backing device associated with it.
|
||||
#
|
||||
# @device: The device name associated with the virtual device.
|
||||
#
|
||||
# @type: This field is returned only for compatibility reasons, it should
|
||||
# not be used (always returns 'unknown')
|
||||
#
|
||||
# @removable: True if the device supports removable media.
|
||||
#
|
||||
# @locked: True if the guest has locked this device from having its media
|
||||
# removed
|
||||
#
|
||||
# @tray_open: #optional True if the device has a tray and it is open
|
||||
# (only present if removable is true)
|
||||
#
|
||||
# @io-status: #optional @BlockDeviceIoStatus. Only present if the device
|
||||
# supports it and the VM is configured to stop on errors
|
||||
#
|
||||
# @inserted: #optional @BlockDeviceInfo describing the device if media is
|
||||
# present
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'BlockInfo',
|
||||
'data': {'device': 'str', 'type': 'str', 'removable': 'bool',
|
||||
'locked': 'bool', '*inserted': 'BlockDeviceInfo',
|
||||
'*tray_open': 'bool', '*io-status': 'BlockDeviceIoStatus'} }
|
||||
|
||||
##
|
||||
# @query-block:
|
||||
#
|
||||
# Get a list of BlockInfo for all virtual block devices.
|
||||
#
|
||||
# Returns: a list of @BlockInfo describing each virtual block device
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'query-block', 'returns': ['BlockInfo'] }
|
||||
|
||||
##
|
||||
# @BlockDeviceStats:
|
||||
#
|
||||
# Statistics of a virtual block device or a block backing device.
|
||||
#
|
||||
# @rd_bytes: The number of bytes read by the device.
|
||||
#
|
||||
# @wr_bytes: The number of bytes written by the device.
|
||||
#
|
||||
# @rd_operations: The number of read operations performed by the device.
|
||||
#
|
||||
# @wr_operations: The number of write operations performed by the device.
|
||||
#
|
||||
# @flush_operations: The number of cache flush operations performed by the
|
||||
# device (since 0.15.0)
|
||||
#
|
||||
# @flush_total_time_ns: Total time spend on cache flushes in nano-seconds
|
||||
# (since 0.15.0).
|
||||
#
|
||||
# @wr_total_time_ns: Total time spend on writes in nano-seconds (since 0.15.0).
|
||||
#
|
||||
# @rd_total_time_ns: Total_time_spend on reads in nano-seconds (since 0.15.0).
|
||||
#
|
||||
# @wr_highest_offset: The offset after the greatest byte written to the
|
||||
# device. The intended use of this information is for
|
||||
# growable sparse files (like qcow2) that are used on top
|
||||
# of a physical device.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'BlockDeviceStats',
|
||||
'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'rd_operations': 'int',
|
||||
'wr_operations': 'int', 'flush_operations': 'int',
|
||||
'flush_total_time_ns': 'int', 'wr_total_time_ns': 'int',
|
||||
'rd_total_time_ns': 'int', 'wr_highest_offset': 'int' } }
|
||||
|
||||
##
|
||||
# @BlockStats:
|
||||
#
|
||||
# Statistics of a virtual block device or a block backing device.
|
||||
#
|
||||
# @device: #optional If the stats are for a virtual block device, the name
|
||||
# corresponding to the virtual block device.
|
||||
#
|
||||
# @stats: A @BlockDeviceStats for the device.
|
||||
#
|
||||
# @parent: #optional This may point to the backing block device if this is a
|
||||
# a virtual block device. If it's a backing block, this will point
|
||||
# to the backing file is one is present.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'BlockStats',
|
||||
'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
|
||||
'*parent': 'BlockStats'} }
|
||||
|
||||
##
|
||||
# @query-blockstats:
|
||||
#
|
||||
# Query the @BlockStats for all virtual block devices.
|
||||
#
|
||||
# Returns: A list of @BlockStats for each virtual block devices.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'query-blockstats', 'returns': ['BlockStats'] }
|
||||
|
||||
##
|
||||
# @VncClientInfo:
|
||||
#
|
||||
# Information about a connected VNC client.
|
||||
#
|
||||
# @host: The host name of the client. QEMU tries to resolve this to a DNS name
|
||||
# when possible.
|
||||
#
|
||||
# @family: 'ipv6' if the client is connected via IPv6 and TCP
|
||||
# 'ipv4' if the client is connected via IPv4 and TCP
|
||||
# 'unix' if the client is connected via a unix domain socket
|
||||
# 'unknown' otherwise
|
||||
#
|
||||
# @service: The service name of the client's port. This may depends on the
|
||||
# host system's service database so symbolic names should not be
|
||||
# relied on.
|
||||
#
|
||||
# @x509_dname: #optional If x509 authentication is in use, the Distinguished
|
||||
# Name of the client.
|
||||
#
|
||||
# @sasl_username: #optional If SASL authentication is in use, the SASL username
|
||||
# used for authentication.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'VncClientInfo',
|
||||
'data': {'host': 'str', 'family': 'str', 'service': 'str',
|
||||
'*x509_dname': 'str', '*sasl_username': 'str'} }
|
||||
|
||||
##
|
||||
# @VncInfo:
|
||||
#
|
||||
# Information about the VNC session.
|
||||
#
|
||||
# @enabled: true if the VNC server is enabled, false otherwise
|
||||
#
|
||||
# @host: #optional The hostname the VNC server is bound to. This depends on
|
||||
# the name resolution on the host and may be an IP address.
|
||||
#
|
||||
# @family: #optional 'ipv6' if the host is listening for IPv6 connections
|
||||
# 'ipv4' if the host is listening for IPv4 connections
|
||||
# 'unix' if the host is listening on a unix domain socket
|
||||
# 'unknown' otherwise
|
||||
#
|
||||
# @service: #optional The service name of the server's port. This may depends
|
||||
# on the host system's service database so symbolic names should not
|
||||
# be relied on.
|
||||
#
|
||||
# @auth: #optional the current authentication type used by the server
|
||||
# 'none' if no authentication is being used
|
||||
# 'vnc' if VNC authentication is being used
|
||||
# 'vencrypt+plain' if VEncrypt is used with plain text authentication
|
||||
# 'vencrypt+tls+none' if VEncrypt is used with TLS and no authentication
|
||||
# 'vencrypt+tls+vnc' if VEncrypt is used with TLS and VNC authentication
|
||||
# 'vencrypt+tls+plain' if VEncrypt is used with TLS and plain text auth
|
||||
# 'vencrypt+x509+none' if VEncrypt is used with x509 and no auth
|
||||
# 'vencrypt+x509+vnc' if VEncrypt is used with x509 and VNC auth
|
||||
# 'vencrypt+x509+plain' if VEncrypt is used with x509 and plain text auth
|
||||
# 'vencrypt+tls+sasl' if VEncrypt is used with TLS and SASL auth
|
||||
# 'vencrypt+x509+sasl' if VEncrypt is used with x509 and SASL auth
|
||||
#
|
||||
# @clients: a list of @VncClientInfo of all currently connected clients
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'VncInfo',
|
||||
'data': {'enabled': 'bool', '*host': 'str', '*family': 'str',
|
||||
'*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
|
||||
|
||||
##
|
||||
# @query-vnc:
|
||||
#
|
||||
# Returns information about the current VNC server
|
||||
#
|
||||
# Returns: @VncInfo
|
||||
# If VNC support is not compiled in, FeatureDisabled
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'query-vnc', 'returns': 'VncInfo' }
|
||||
|
||||
##
|
||||
# @SpiceChannel
|
||||
#
|
||||
# Information about a SPICE client channel.
|
||||
#
|
||||
# @host: The host name of the client. QEMU tries to resolve this to a DNS name
|
||||
# when possible.
|
||||
#
|
||||
# @family: 'ipv6' if the client is connected via IPv6 and TCP
|
||||
# 'ipv4' if the client is connected via IPv4 and TCP
|
||||
# 'unix' if the client is connected via a unix domain socket
|
||||
# 'unknown' otherwise
|
||||
#
|
||||
# @port: The client's port number.
|
||||
#
|
||||
# @connection-id: SPICE connection id number. All channels with the same id
|
||||
# belong to the same SPICE session.
|
||||
#
|
||||
# @connection-type: SPICE channel type number. "1" is the main control channel,
|
||||
# filter for this one if you want track spice sessions only
|
||||
#
|
||||
# @channel-id: SPICE channel ID number. Usually "0", might be different needed
|
||||
# when multiple channels of the same type exist, such as multiple
|
||||
# display channels in a multihead setup
|
||||
#
|
||||
# @tls: true if the channel is encrypted, false otherwise.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'SpiceChannel',
|
||||
'data': {'host': 'str', 'family': 'str', 'port': 'str',
|
||||
'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
|
||||
'tls': 'bool'} }
|
||||
|
||||
##
|
||||
# @SpiceInfo
|
||||
#
|
||||
# Information about the SPICE session.
|
||||
#
|
||||
# @enabled: true if the SPICE server is enabled, false otherwise
|
||||
#
|
||||
# @host: #optional The hostname the SPICE server is bound to. This depends on
|
||||
# the name resolution on the host and may be an IP address.
|
||||
#
|
||||
# @port: #optional The SPICE server's port number.
|
||||
#
|
||||
# @compiled-version: #optional SPICE server version.
|
||||
#
|
||||
# @tls-port: #optional The SPICE server's TLS port number.
|
||||
#
|
||||
# @auth: #optional the current authentication type used by the server
|
||||
# 'none' if no authentication is being used
|
||||
# 'spice' (TODO: describe)
|
||||
#
|
||||
# @channels: a list of @SpiceChannel for each active spice channel
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'SpiceInfo',
|
||||
'data': {'enabled': 'bool', '*host': 'str', '*port': 'int',
|
||||
'*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
|
||||
'*channels': ['SpiceChannel']} }
|
||||
|
||||
##
|
||||
# @query-spice
|
||||
#
|
||||
# Returns information about the current SPICE server
|
||||
#
|
||||
# Returns: @SpiceInfo
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'query-spice', 'returns': 'SpiceInfo' }
|
||||
|
||||
##
|
||||
# @BalloonInfo:
|
||||
#
|
||||
# Information about the guest balloon device.
|
||||
#
|
||||
# @actual: the number of bytes the balloon currently contains
|
||||
#
|
||||
# @mem_swapped_in: #optional number of pages swapped in within the guest
|
||||
#
|
||||
# @mem_swapped_out: #optional number of pages swapped out within the guest
|
||||
#
|
||||
# @major_page_faults: #optional number of major page faults within the guest
|
||||
#
|
||||
# @minor_page_faults: #optional number of minor page faults within the guest
|
||||
#
|
||||
# @free_mem: #optional amount of memory (in bytes) free in the guest
|
||||
#
|
||||
# @total_mem: #optional amount of memory (in bytes) visible to the guest
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Notes: all current versions of QEMU do not fill out optional information in
|
||||
# this structure.
|
||||
##
|
||||
{ 'type': 'BalloonInfo',
|
||||
'data': {'actual': 'int', '*mem_swapped_in': 'int',
|
||||
'*mem_swapped_out': 'int', '*major_page_faults': 'int',
|
||||
'*minor_page_faults': 'int', '*free_mem': 'int',
|
||||
'*total_mem': 'int'} }
|
||||
|
||||
##
|
||||
# @query-balloon:
|
||||
#
|
||||
# Return information about the balloon device.
|
||||
#
|
||||
# Returns: @BalloonInfo on success
|
||||
# If the balloon driver is enabled but not functional because the KVM
|
||||
# kernel module cannot support it, KvmMissingCap
|
||||
# If no balloon device is present, DeviceNotActive
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
|
||||
|
||||
##
|
||||
# @PciMemoryRange:
|
||||
#
|
||||
# A PCI device memory region
|
||||
#
|
||||
# @base: the starting address (guest physical)
|
||||
#
|
||||
# @limit: the ending address (guest physical)
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
|
||||
|
||||
##
|
||||
# @PciMemoryRegion
|
||||
#
|
||||
# Information about a PCI device I/O region.
|
||||
#
|
||||
# @bar: the index of the Base Address Register for this region
|
||||
#
|
||||
# @type: 'io' if the region is a PIO region
|
||||
# 'memory' if the region is a MMIO region
|
||||
#
|
||||
# @prefetch: #optional if @type is 'memory', true if the memory is prefetchable
|
||||
#
|
||||
# @mem_type_64: #optional if @type is 'memory', true if the BAR is 64-bit
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'PciMemoryRegion',
|
||||
'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
|
||||
'*prefetch': 'bool', '*mem_type_64': 'bool' } }
|
||||
|
||||
##
|
||||
# @PciBridgeInfo:
|
||||
#
|
||||
# Information about a PCI Bridge device
|
||||
#
|
||||
# @bus.number: primary bus interface number. This should be the number of the
|
||||
# bus the device resides on.
|
||||
#
|
||||
# @bus.secondary: secondary bus interface number. This is the number of the
|
||||
# main bus for the bridge
|
||||
#
|
||||
# @bus.subordinate: This is the highest number bus that resides below the
|
||||
# bridge.
|
||||
#
|
||||
# @bus.io_range: The PIO range for all devices on this bridge
|
||||
#
|
||||
# @bus.memory_range: The MMIO range for all devices on this bridge
|
||||
#
|
||||
# @bus.prefetchable_range: The range of prefetchable MMIO for all devices on
|
||||
# this bridge
|
||||
#
|
||||
# @devices: a list of @PciDeviceInfo for each device on this bridge
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'PciBridgeInfo',
|
||||
'data': {'bus': { 'number': 'int', 'secondary': 'int', 'subordinate': 'int',
|
||||
'io_range': 'PciMemoryRange',
|
||||
'memory_range': 'PciMemoryRange',
|
||||
'prefetchable_range': 'PciMemoryRange' },
|
||||
'*devices': ['PciDeviceInfo']} }
|
||||
|
||||
##
|
||||
# @PciDeviceInfo:
|
||||
#
|
||||
# Information about a PCI device
|
||||
#
|
||||
# @bus: the bus number of the device
|
||||
#
|
||||
# @slot: the slot the device is located in
|
||||
#
|
||||
# @function: the function of the slot used by the device
|
||||
#
|
||||
# @class_info.desc: #optional a string description of the device's class
|
||||
#
|
||||
# @class_info.class: the class code of the device
|
||||
#
|
||||
# @id.device: the PCI device id
|
||||
#
|
||||
# @id.vendor: the PCI vendor id
|
||||
#
|
||||
# @irq: #optional if an IRQ is assigned to the device, the IRQ number
|
||||
#
|
||||
# @qdev_id: the device name of the PCI device
|
||||
#
|
||||
# @pci_bridge: if the device is a PCI bridge, the bridge information
|
||||
#
|
||||
# @regions: a list of the PCI I/O regions associated with the device
|
||||
#
|
||||
# Notes: the contents of @class_info.desc are not stable and should only be
|
||||
# treated as informational.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'PciDeviceInfo',
|
||||
'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
|
||||
'class_info': {'*desc': 'str', 'class': 'int'},
|
||||
'id': {'device': 'int', 'vendor': 'int'},
|
||||
'*irq': 'int', 'qdev_id': 'str', '*pci_bridge': 'PciBridgeInfo',
|
||||
'regions': ['PciMemoryRegion']} }
|
||||
|
||||
##
|
||||
# @PciInfo:
|
||||
#
|
||||
# Information about a PCI bus
|
||||
#
|
||||
# @bus: the bus index
|
||||
#
|
||||
# @devices: a list of devices on this bus
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
|
||||
|
||||
##
|
||||
# @query-pci:
|
||||
#
|
||||
# Return information about the PCI bus topology of the guest.
|
||||
#
|
||||
# Returns: a list of @PciInfo for each PCI bus
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'query-pci', 'returns': ['PciInfo'] }
|
||||
|
||||
##
|
||||
# @quit:
|
||||
#
|
||||
@ -271,3 +876,14 @@
|
||||
# prompting the user in some way.
|
||||
##
|
||||
{ 'command': 'system_powerdown' }
|
||||
|
||||
##
|
||||
# @cpu:
|
||||
#
|
||||
# This command is a nop that is only provided for the purposes of compatibility.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Notes: Do not use this command.
|
||||
##
|
||||
{ 'command': 'cpu', 'data': {'index': 'int'} }
|
||||
|
4
qerror.c
4
qerror.c
@ -116,6 +116,10 @@ static const QErrorStringTable qerror_table[] = {
|
||||
.error_fmt = QERR_FD_NOT_SUPPLIED,
|
||||
.desc = "No file descriptor supplied via SCM_RIGHTS",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_FEATURE_DISABLED,
|
||||
.desc = "The feature '%(name)' is not enabled",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_INVALID_BLOCK_FORMAT,
|
||||
.desc = "Invalid block format '%(name)'",
|
||||
|
@ -331,10 +331,7 @@ EQMP
|
||||
{
|
||||
.name = "cpu",
|
||||
.args_type = "index:i",
|
||||
.params = "index",
|
||||
.help = "set the default CPU",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = do_cpu_set,
|
||||
.mhandler.cmd_new = qmp_marshal_input_cpu,
|
||||
},
|
||||
|
||||
SQMP
|
||||
@ -1202,6 +1199,12 @@ Example:
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "query-block",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_block,
|
||||
},
|
||||
|
||||
SQMP
|
||||
query-blockstats
|
||||
----------------
|
||||
@ -1309,6 +1312,12 @@ Example:
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "query-blockstats",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_blockstats,
|
||||
},
|
||||
|
||||
SQMP
|
||||
query-cpus
|
||||
----------
|
||||
@ -1351,6 +1360,12 @@ Example:
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "query-cpus",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_cpus,
|
||||
},
|
||||
|
||||
SQMP
|
||||
query-pci
|
||||
---------
|
||||
@ -1562,6 +1577,12 @@ Note: This example has been shortened as the real response is too long.
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "query-pci",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_pci,
|
||||
},
|
||||
|
||||
SQMP
|
||||
query-kvm
|
||||
---------
|
||||
@ -1664,6 +1685,12 @@ Example:
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "query-mice",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_mice,
|
||||
},
|
||||
|
||||
SQMP
|
||||
query-vnc
|
||||
---------
|
||||
@ -1721,6 +1748,12 @@ Example:
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "query-vnc",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_vnc,
|
||||
},
|
||||
|
||||
SQMP
|
||||
query-spice
|
||||
-----------
|
||||
@ -1791,6 +1824,14 @@ Example:
|
||||
|
||||
EQMP
|
||||
|
||||
#if defined(CONFIG_SPICE)
|
||||
{
|
||||
.name = "query-spice",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_spice,
|
||||
},
|
||||
#endif
|
||||
|
||||
SQMP
|
||||
query-name
|
||||
----------
|
||||
@ -1914,6 +1955,12 @@ Examples:
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "query-migrate",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_migrate,
|
||||
},
|
||||
|
||||
SQMP
|
||||
query-balloon
|
||||
-------------
|
||||
@ -1949,3 +1996,8 @@ Example:
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "query-balloon",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_balloon,
|
||||
},
|
||||
|
27
qmp.c
27
qmp.c
@ -90,3 +90,30 @@ void qmp_system_powerdown(Error **erp)
|
||||
{
|
||||
qemu_system_powerdown_request();
|
||||
}
|
||||
|
||||
void qmp_cpu(int64_t index, Error **errp)
|
||||
{
|
||||
/* Just do nothing */
|
||||
}
|
||||
|
||||
#ifndef CONFIG_VNC
|
||||
/* If VNC support is enabled, the "true" query-vnc command is
|
||||
defined in the VNC subsystem */
|
||||
VncInfo *qmp_query_vnc(Error **errp)
|
||||
{
|
||||
error_set(errp, QERR_FEATURE_DISABLED, "vnc");
|
||||
return NULL;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SPICE
|
||||
/* If SPICE support is enabled, the "true" query-spice command is
|
||||
defined in the SPICE subsystem. Also note that we use a small
|
||||
trick to maintain query-spice's original behavior, which is not
|
||||
to be available in the namespace if SPICE is not compiled in */
|
||||
SpiceInfo *qmp_query_spice(Error **errp)
|
||||
{
|
||||
error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice");
|
||||
return NULL;
|
||||
};
|
||||
#endif
|
||||
|
@ -62,7 +62,9 @@ def gen_sync_call(name, args, ret_type, indent=0):
|
||||
name=c_var(name), args=arglist, retval=retval).rstrip()
|
||||
if ret_type:
|
||||
ret += "\n" + mcgen(''''
|
||||
%(marshal_output_call)s
|
||||
if (!error_is_set(errp)) {
|
||||
%(marshal_output_call)s
|
||||
}
|
||||
''',
|
||||
marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
|
||||
pop_indent(indent)
|
||||
|
143
ui/spice-core.c
143
ui/spice-core.c
@ -27,6 +27,7 @@
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-x509.h"
|
||||
#include "qemu_socket.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qint.h"
|
||||
#include "qbool.h"
|
||||
#include "qstring.h"
|
||||
@ -194,22 +195,6 @@ static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info)
|
||||
qdict_put(dict, "tls", qbool_from_int(tls));
|
||||
}
|
||||
|
||||
static QList *channel_list_get(void)
|
||||
{
|
||||
ChannelList *item;
|
||||
QList *list;
|
||||
QDict *dict;
|
||||
|
||||
list = qlist_new();
|
||||
QTAILQ_FOREACH(item, &channel_list, link) {
|
||||
dict = qdict_new();
|
||||
add_addr_info(dict, &item->info->paddr, item->info->plen);
|
||||
add_channel_info(dict, item->info);
|
||||
qlist_append(list, dict);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static void channel_event(int event, SpiceChannelEventInfo *info)
|
||||
{
|
||||
static const int qevent[] = {
|
||||
@ -383,98 +368,90 @@ static const char *wan_compression_names[] = {
|
||||
|
||||
/* functions for the rest of qemu */
|
||||
|
||||
static void info_spice_iter(QObject *obj, void *opaque)
|
||||
static SpiceChannelList *qmp_query_spice_channels(void)
|
||||
{
|
||||
QDict *client;
|
||||
Monitor *mon = opaque;
|
||||
SpiceChannelList *cur_item = NULL, *head = NULL;
|
||||
ChannelList *item;
|
||||
|
||||
client = qobject_to_qdict(obj);
|
||||
monitor_printf(mon, "Channel:\n");
|
||||
monitor_printf(mon, " address: %s:%s%s\n",
|
||||
qdict_get_str(client, "host"),
|
||||
qdict_get_str(client, "port"),
|
||||
qdict_get_bool(client, "tls") ? " [tls]" : "");
|
||||
monitor_printf(mon, " session: %" PRId64 "\n",
|
||||
qdict_get_int(client, "connection-id"));
|
||||
monitor_printf(mon, " channel: %d:%d\n",
|
||||
(int)qdict_get_int(client, "channel-type"),
|
||||
(int)qdict_get_int(client, "channel-id"));
|
||||
QTAILQ_FOREACH(item, &channel_list, link) {
|
||||
SpiceChannelList *chan;
|
||||
char host[NI_MAXHOST], port[NI_MAXSERV];
|
||||
|
||||
chan = g_malloc0(sizeof(*chan));
|
||||
chan->value = g_malloc0(sizeof(*chan->value));
|
||||
|
||||
getnameinfo(&item->info->paddr, item->info->plen,
|
||||
host, sizeof(host), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
chan->value->host = g_strdup(host);
|
||||
chan->value->port = g_strdup(port);
|
||||
chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family));
|
||||
|
||||
chan->value->connection_id = item->info->connection_id;
|
||||
chan->value->channel_type = item->info->type;
|
||||
chan->value->channel_id = item->info->id;
|
||||
chan->value->tls = item->info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS;
|
||||
|
||||
/* XXX: waiting for the qapi to support GSList */
|
||||
if (!cur_item) {
|
||||
head = cur_item = chan;
|
||||
} else {
|
||||
cur_item->next = chan;
|
||||
cur_item = chan;
|
||||
}
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
void do_info_spice_print(Monitor *mon, const QObject *data)
|
||||
{
|
||||
QDict *server;
|
||||
QList *channels;
|
||||
const char *host;
|
||||
int port;
|
||||
|
||||
server = qobject_to_qdict(data);
|
||||
if (qdict_get_bool(server, "enabled") == 0) {
|
||||
monitor_printf(mon, "Server: disabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "Server:\n");
|
||||
host = qdict_get_str(server, "host");
|
||||
port = qdict_get_try_int(server, "port", -1);
|
||||
if (port != -1) {
|
||||
monitor_printf(mon, " address: %s:%d\n", host, port);
|
||||
}
|
||||
port = qdict_get_try_int(server, "tls-port", -1);
|
||||
if (port != -1) {
|
||||
monitor_printf(mon, " address: %s:%d [tls]\n", host, port);
|
||||
}
|
||||
monitor_printf(mon, " auth: %s\n", qdict_get_str(server, "auth"));
|
||||
monitor_printf(mon, " compiled: %s\n",
|
||||
qdict_get_str(server, "compiled-version"));
|
||||
|
||||
channels = qdict_get_qlist(server, "channels");
|
||||
if (qlist_empty(channels)) {
|
||||
monitor_printf(mon, "Channels: none\n");
|
||||
} else {
|
||||
qlist_iter(channels, info_spice_iter, mon);
|
||||
}
|
||||
}
|
||||
|
||||
void do_info_spice(Monitor *mon, QObject **ret_data)
|
||||
SpiceInfo *qmp_query_spice(Error **errp)
|
||||
{
|
||||
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
|
||||
QDict *server;
|
||||
QList *clist;
|
||||
const char *addr;
|
||||
int port, tls_port;
|
||||
const char *addr;
|
||||
SpiceInfo *info;
|
||||
char version_string[20]; /* 12 = |255.255.255\0| is the max */
|
||||
|
||||
info = g_malloc0(sizeof(*info));
|
||||
|
||||
if (!spice_server || !opts) {
|
||||
*ret_data = qobject_from_jsonf("{ 'enabled': false }");
|
||||
return;
|
||||
info->enabled = false;
|
||||
return info;
|
||||
}
|
||||
|
||||
info->enabled = true;
|
||||
|
||||
addr = qemu_opt_get(opts, "addr");
|
||||
port = qemu_opt_get_number(opts, "port", 0);
|
||||
tls_port = qemu_opt_get_number(opts, "tls-port", 0);
|
||||
clist = channel_list_get();
|
||||
|
||||
server = qdict_new();
|
||||
qdict_put(server, "enabled", qbool_from_int(true));
|
||||
qdict_put(server, "auth", qstring_from_str(auth));
|
||||
qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0"));
|
||||
info->has_auth = true;
|
||||
info->auth = g_strdup(auth);
|
||||
|
||||
info->has_host = true;
|
||||
info->host = g_strdup(addr ? addr : "0.0.0.0");
|
||||
|
||||
info->has_compiled_version = true;
|
||||
snprintf(version_string, sizeof(version_string), "%d.%d.%d",
|
||||
(SPICE_SERVER_VERSION & 0xff0000) >> 16,
|
||||
(SPICE_SERVER_VERSION & 0xff00) >> 8,
|
||||
SPICE_SERVER_VERSION & 0xff);
|
||||
qdict_put(server, "compiled-version", qstring_from_str(version_string));
|
||||
info->compiled_version = g_strdup(version_string);
|
||||
|
||||
if (port) {
|
||||
qdict_put(server, "port", qint_from_int(port));
|
||||
info->has_port = true;
|
||||
info->port = port;
|
||||
}
|
||||
if (tls_port) {
|
||||
qdict_put(server, "tls-port", qint_from_int(tls_port));
|
||||
}
|
||||
if (clist) {
|
||||
qdict_put(server, "channels", clist);
|
||||
info->has_tls_port = true;
|
||||
info->tls_port = tls_port;
|
||||
}
|
||||
|
||||
*ret_data = QOBJECT(server);
|
||||
/* for compatibility with the original command */
|
||||
info->has_channels = true;
|
||||
info->channels = qmp_query_spice_channels();
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void migration_state_notifier(Notifier *notifier, void *data)
|
||||
|
137
ui/vnc.c
137
ui/vnc.c
@ -31,6 +31,7 @@
|
||||
#include "qemu-timer.h"
|
||||
#include "acl.h"
|
||||
#include "qemu-objects.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
#define VNC_REFRESH_INTERVAL_BASE 30
|
||||
#define VNC_REFRESH_INTERVAL_INC 50
|
||||
@ -274,80 +275,110 @@ static void vnc_qmp_event(VncState *vs, MonitorEvent event)
|
||||
qobject_decref(data);
|
||||
}
|
||||
|
||||
static void info_vnc_iter(QObject *obj, void *opaque)
|
||||
static VncClientInfo *qmp_query_vnc_client(const VncState *client)
|
||||
{
|
||||
QDict *client;
|
||||
Monitor *mon = opaque;
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t salen = sizeof(sa);
|
||||
char host[NI_MAXHOST];
|
||||
char serv[NI_MAXSERV];
|
||||
VncClientInfo *info;
|
||||
|
||||
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"));
|
||||
if (getpeername(client->csock, (struct sockaddr *)&sa, &salen) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (getnameinfo((struct sockaddr *)&sa, salen,
|
||||
host, sizeof(host),
|
||||
serv, sizeof(serv),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->host = g_strdup(host);
|
||||
info->service = g_strdup(serv);
|
||||
info->family = g_strdup(inet_strfamily(sa.ss_family));
|
||||
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
monitor_printf(mon, " x509_dname: %s\n",
|
||||
qdict_haskey(client, "x509_dname") ?
|
||||
qdict_get_str(client, "x509_dname") : "none");
|
||||
if (client->tls.session && client->tls.dname) {
|
||||
info->has_x509_dname = true;
|
||||
info->x509_dname = g_strdup(client->tls.dname);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_VNC_SASL
|
||||
monitor_printf(mon, " username: %s\n",
|
||||
qdict_haskey(client, "sasl_username") ?
|
||||
qdict_get_str(client, "sasl_username") : "none");
|
||||
if (client->sasl.conn && client->sasl.username) {
|
||||
info->has_sasl_username = true;
|
||||
info->sasl_username = g_strdup(client->sasl.username);
|
||||
}
|
||||
#endif
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void do_info_vnc_print(Monitor *mon, const QObject *data)
|
||||
VncInfo *qmp_query_vnc(Error **errp)
|
||||
{
|
||||
QDict *server;
|
||||
QList *clients;
|
||||
VncInfo *info = g_malloc0(sizeof(*info));
|
||||
|
||||
server = qobject_to_qdict(data);
|
||||
if (qdict_get_bool(server, "enabled") == 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_get_str(server, "auth"));
|
||||
|
||||
clients = qdict_get_qlist(server, "clients");
|
||||
if (qlist_empty(clients)) {
|
||||
monitor_printf(mon, "Client: none\n");
|
||||
} else {
|
||||
qlist_iter(clients, info_vnc_iter, mon);
|
||||
}
|
||||
}
|
||||
|
||||
void do_info_vnc(Monitor *mon, QObject **ret_data)
|
||||
{
|
||||
if (vnc_display == NULL || vnc_display->display == NULL) {
|
||||
*ret_data = qobject_from_jsonf("{ 'enabled': false }");
|
||||
info->enabled = false;
|
||||
} else {
|
||||
QList *clist;
|
||||
VncClientInfoList *cur_item = NULL;
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t salen = sizeof(sa);
|
||||
char host[NI_MAXHOST];
|
||||
char serv[NI_MAXSERV];
|
||||
VncState *client;
|
||||
|
||||
clist = qlist_new();
|
||||
info->enabled = true;
|
||||
|
||||
/* for compatibility with the original command */
|
||||
info->has_clients = true;
|
||||
|
||||
QTAILQ_FOREACH(client, &vnc_display->clients, next) {
|
||||
if (client->info) {
|
||||
/* incref so that it's not freed by upper layers */
|
||||
qobject_incref(client->info);
|
||||
qlist_append_obj(clist, client->info);
|
||||
VncClientInfoList *cinfo = g_malloc0(sizeof(*info));
|
||||
cinfo->value = qmp_query_vnc_client(client);
|
||||
|
||||
/* XXX: waiting for the qapi to support GSList */
|
||||
if (!cur_item) {
|
||||
info->clients = cur_item = cinfo;
|
||||
} else {
|
||||
cur_item->next = cinfo;
|
||||
cur_item = cinfo;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_data = qobject_from_jsonf("{ 'enabled': true, 'clients': %p }",
|
||||
QOBJECT(clist));
|
||||
assert(*ret_data != NULL);
|
||||
|
||||
if (vnc_server_info_put(qobject_to_qdict(*ret_data)) < 0) {
|
||||
qobject_decref(*ret_data);
|
||||
*ret_data = NULL;
|
||||
if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa,
|
||||
&salen) == -1) {
|
||||
error_set(errp, QERR_UNDEFINED_ERROR);
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (getnameinfo((struct sockaddr *)&sa, salen,
|
||||
host, sizeof(host),
|
||||
serv, sizeof(serv),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
|
||||
error_set(errp, QERR_UNDEFINED_ERROR);
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
info->has_host = true;
|
||||
info->host = g_strdup(host);
|
||||
|
||||
info->has_service = true;
|
||||
info->service = g_strdup(serv);
|
||||
|
||||
info->has_family = true;
|
||||
info->family = g_strdup(inet_strfamily(sa.ss_family));
|
||||
|
||||
info->has_auth = true;
|
||||
info->auth = g_strdup(vnc_auth_name(vnc_display));
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
out_error:
|
||||
qapi_free_VncInfo(info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* TODO
|
||||
|
2
vl.c
2
vl.c
@ -143,9 +143,9 @@ int main(int argc, char **argv)
|
||||
#include "audio/audio.h"
|
||||
#include "migration.h"
|
||||
#include "kvm.h"
|
||||
#include "qjson.h"
|
||||
#include "qemu-option.h"
|
||||
#include "qemu-config.h"
|
||||
#include "qemu-objects.h"
|
||||
#include "qemu-options.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "main-loop.h"
|
||||
|
Loading…
Reference in New Issue
Block a user