#include "hw/hw.h"
#include "monitor/qdev.h"
#include "hw/usb.h"
-#include "hw/pcmcia.h"
#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "sysemu/watchdog.h"
#include "ui/qemu-spice.h"
#include "sysemu/sysemu.h"
#include "monitor/monitor.h"
-#include "monitor/readline.h"
+#include "qemu/readline.h"
#include "ui/console.h"
+#include "ui/input.h"
#include "sysemu/blockdev.h"
#include "audio/audio.h"
#include "disas/disas.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/json-streamer.h"
#include "qapi/qmp/json-parser.h"
+#include <qom/object_interfaces.h>
#include "qemu/osdep.h"
#include "cpu.h"
#include "trace.h"
#include "trace/simple.h"
#endif
#include "exec/memory.h"
+#include "exec/cpu_ldst.h"
#include "qmp-commands.h"
#include "hmp.h"
#include "qemu/thread.h"
+#include "block/qapi.h"
+#include "qapi/qmp-event.h"
+#include "qapi-event.h"
/* for pic/irq_info */
#if defined(TARGET_SPARC)
* 'F' filename
* 'B' block device name
* 's' string (accept optional quote)
+ * 'S' it just appends the rest of the string (accept optional quote)
* 'O' option string of the form NAME=VALUE,...
* parsed according to QemuOptsList given by its name
* Example: 'device:O' uses qemu_device_opts.
* used, and mhandler of 1st level plays the role of help function.
*/
struct mon_cmd_t *sub_table;
+ void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
} mon_cmd_t;
/* file descriptors passed via SCM_RIGHTS */
* throttling is calculated globally, rather than per-Monitor
* instance.
*/
-typedef struct MonitorEventState {
- MonitorEvent event; /* Event being tracked */
- int64_t rate; /* Period over which to throttle. 0 to disable */
- int64_t last; /* Time at which event was last emitted */
+typedef struct MonitorQAPIEventState {
+ QAPIEvent event; /* Event being tracked */
+ int64_t rate; /* Minimum time (in ns) between two events */
+ int64_t last; /* QEMU_CLOCK_REALTIME value at last emission */
QEMUTimer *timer; /* Timer for handling delayed events */
QObject *data; /* Event pending delayed dispatch */
-} MonitorEventState;
+} MonitorQAPIEventState;
struct Monitor {
CharDriverState *chr;
- int mux_out;
int reset_seen;
int flags;
int suspend_cnt;
bool skip_flush;
+
+ QemuMutex out_lock;
QString *outbuf;
- guint watch;
+ guint out_watch;
+
+ /* Read under either BQL or out_lock, written with BQL+out_lock. */
+ int mux_out;
+
ReadLineState *rs;
MonitorControl *mc;
CPUState *mon_cpu;
- BlockDriverCompletionFunc *password_completion_cb;
+ BlockCompletionFunc *password_completion_cb;
void *password_opaque;
mon_cmd_t *cmd_table;
QError *error;
/* QMP checker flags */
#define QMP_ACCEPT_UNKNOWNS 1
+/* Protects mon_list, monitor_event_state. */
+static QemuMutex monitor_lock;
+
static QLIST_HEAD(mon_list, Monitor) mon_list;
static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets;
static int mon_refcount;
Monitor *cur_mon;
Monitor *default_mon;
-static void monitor_command_cb(Monitor *mon, const char *cmdline,
- void *opaque);
+static void monitor_command_cb(void *opaque, const char *cmdline,
+ void *readline_opaque);
static inline int qmp_cmd_mode(const Monitor *mon)
{
}
}
+static void monitor_flush_locked(Monitor *mon);
+
static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond,
void *opaque)
{
Monitor *mon = opaque;
- mon->watch = 0;
- monitor_flush(mon);
+ qemu_mutex_lock(&mon->out_lock);
+ mon->out_watch = 0;
+ monitor_flush_locked(mon);
+ qemu_mutex_unlock(&mon->out_lock);
return FALSE;
}
-void monitor_flush(Monitor *mon)
+/* Called with mon->out_lock held. */
+static void monitor_flush_locked(Monitor *mon)
{
int rc;
size_t len;
if (len && !mon->mux_out) {
rc = qemu_chr_fe_write(mon->chr, (const uint8_t *) buf, len);
- if (rc == len) {
- /* all flushed */
+ if ((rc < 0 && errno != EAGAIN) || (rc == len)) {
+ /* all flushed or error */
QDECREF(mon->outbuf);
mon->outbuf = qstring_new();
return;
QDECREF(mon->outbuf);
mon->outbuf = tmp;
}
- if (mon->watch == 0) {
- mon->watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT,
- monitor_unblocked, mon);
+ if (mon->out_watch == 0) {
+ mon->out_watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT|G_IO_HUP,
+ monitor_unblocked, mon);
}
}
}
+void monitor_flush(Monitor *mon)
+{
+ qemu_mutex_lock(&mon->out_lock);
+ monitor_flush_locked(mon);
+ qemu_mutex_unlock(&mon->out_lock);
+}
+
/* flush at every end of line */
static void monitor_puts(Monitor *mon, const char *str)
{
char c;
+ qemu_mutex_lock(&mon->out_lock);
for(;;) {
c = *str++;
if (c == '\0')
}
qstring_append_chr(mon->outbuf, c);
if (c == '\n') {
- monitor_flush(mon);
+ monitor_flush_locked(mon);
}
}
+ qemu_mutex_unlock(&mon->out_lock);
}
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
va_end(ap);
}
-void monitor_print_filename(Monitor *mon, const char *filename)
-{
- int i;
-
- for (i = 0; filename[i]; i++) {
- switch (filename[i]) {
- case ' ':
- case '"':
- case '\\':
- monitor_printf(mon, "\\%c", filename[i]);
- break;
- case '\t':
- monitor_printf(mon, "\\t");
- break;
- case '\r':
- monitor_printf(mon, "\\r");
- break;
- case '\n':
- monitor_printf(mon, "\\n");
- break;
- default:
- monitor_printf(mon, "%c", filename[i]);
- break;
- }
- }
-}
-
static int GCC_FMT_ATTR(2, 3) monitor_fprintf(FILE *stream,
const char *fmt, ...)
{
QDECREF(qmp);
}
-static void timestamp_put(QDict *qdict)
-{
- int err;
- QObject *obj;
- qemu_timeval tv;
-
- err = qemu_gettimeofday(&tv);
- if (err < 0)
- return;
-
- obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", "
- "'microseconds': %" PRId64 " }",
- (int64_t) tv.tv_sec, (int64_t) tv.tv_usec);
- qdict_put_obj(qdict, "timestamp", obj);
-}
-
-
-static const char *monitor_event_names[] = {
- [QEVENT_SHUTDOWN] = "SHUTDOWN",
- [QEVENT_RESET] = "RESET",
- [QEVENT_POWERDOWN] = "POWERDOWN",
- [QEVENT_STOP] = "STOP",
- [QEVENT_RESUME] = "RESUME",
- [QEVENT_VNC_CONNECTED] = "VNC_CONNECTED",
- [QEVENT_VNC_INITIALIZED] = "VNC_INITIALIZED",
- [QEVENT_VNC_DISCONNECTED] = "VNC_DISCONNECTED",
- [QEVENT_BLOCK_IO_ERROR] = "BLOCK_IO_ERROR",
- [QEVENT_RTC_CHANGE] = "RTC_CHANGE",
- [QEVENT_WATCHDOG] = "WATCHDOG",
- [QEVENT_SPICE_CONNECTED] = "SPICE_CONNECTED",
- [QEVENT_SPICE_INITIALIZED] = "SPICE_INITIALIZED",
- [QEVENT_SPICE_DISCONNECTED] = "SPICE_DISCONNECTED",
- [QEVENT_BLOCK_JOB_COMPLETED] = "BLOCK_JOB_COMPLETED",
- [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
- [QEVENT_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR",
- [QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY",
- [QEVENT_DEVICE_DELETED] = "DEVICE_DELETED",
- [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
- [QEVENT_NIC_RX_FILTER_CHANGED] = "NIC_RX_FILTER_CHANGED",
- [QEVENT_SUSPEND] = "SUSPEND",
- [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
- [QEVENT_WAKEUP] = "WAKEUP",
- [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
- [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED",
- [QEVENT_GUEST_PANICKED] = "GUEST_PANICKED",
-};
-QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
-MonitorEventState monitor_event_state[QEVENT_MAX];
-QemuMutex monitor_event_state_lock;
+static MonitorQAPIEventState monitor_qapi_event_state[QAPI_EVENT_MAX];
/*
- * Emits the event to every monitor instance
+ * Emits the event to every monitor instance, @event is only used for trace
+ * Called with monitor_lock held.
*/
-static void
-monitor_protocol_event_emit(MonitorEvent event,
- QObject *data)
+static void monitor_qapi_event_emit(QAPIEvent event, QObject *data)
{
Monitor *mon;
}
}
-
/*
* Queue a new event for emission to Monitor instances,
* applying any rate limiting if required.
*/
static void
-monitor_protocol_event_queue(MonitorEvent event,
- QObject *data)
+monitor_qapi_event_queue(QAPIEvent event, QDict *data, Error **errp)
{
- MonitorEventState *evstate;
+ MonitorQAPIEventState *evstate;
+ assert(event < QAPI_EVENT_MAX);
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
- assert(event < QEVENT_MAX);
- qemu_mutex_lock(&monitor_event_state_lock);
- evstate = &(monitor_event_state[event]);
+ evstate = &(monitor_qapi_event_state[event]);
trace_monitor_protocol_event_queue(event,
data,
evstate->rate,
now);
/* Rate limit of 0 indicates no throttling */
+ qemu_mutex_lock(&monitor_lock);
if (!evstate->rate) {
- monitor_protocol_event_emit(event, data);
+ monitor_qapi_event_emit(event, QOBJECT(data));
evstate->last = now;
} else {
int64_t delta = now - evstate->last;
int64_t then = evstate->last + evstate->rate;
timer_mod_ns(evstate->timer, then);
}
- evstate->data = data;
+ evstate->data = QOBJECT(data);
qobject_incref(evstate->data);
} else {
- monitor_protocol_event_emit(event, data);
+ monitor_qapi_event_emit(event, QOBJECT(data));
evstate->last = now;
}
}
- qemu_mutex_unlock(&monitor_event_state_lock);
+ qemu_mutex_unlock(&monitor_lock);
}
-
/*
* The callback invoked by QemuTimer when a delayed
* event is ready to be emitted
*/
-static void monitor_protocol_event_handler(void *opaque)
+static void monitor_qapi_event_handler(void *opaque)
{
- MonitorEventState *evstate = opaque;
+ MonitorQAPIEventState *evstate = opaque;
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
- qemu_mutex_lock(&monitor_event_state_lock);
-
trace_monitor_protocol_event_handler(evstate->event,
evstate->data,
evstate->last,
now);
+ qemu_mutex_lock(&monitor_lock);
if (evstate->data) {
- monitor_protocol_event_emit(evstate->event, evstate->data);
+ monitor_qapi_event_emit(evstate->event, evstate->data);
qobject_decref(evstate->data);
evstate->data = NULL;
}
evstate->last = now;
- qemu_mutex_unlock(&monitor_event_state_lock);
+ qemu_mutex_unlock(&monitor_lock);
}
-
/*
* @event: the event ID to be limited
* @rate: the rate limit in milliseconds
* milliseconds
*/
static void
-monitor_protocol_event_throttle(MonitorEvent event,
- int64_t rate)
+monitor_qapi_event_throttle(QAPIEvent event, int64_t rate)
{
- MonitorEventState *evstate;
- assert(event < QEVENT_MAX);
+ MonitorQAPIEventState *evstate;
+ assert(event < QAPI_EVENT_MAX);
- evstate = &(monitor_event_state[event]);
+ evstate = &(monitor_qapi_event_state[event]);
trace_monitor_protocol_event_throttle(event, rate);
evstate->event = event;
+ assert(rate * SCALE_MS <= INT64_MAX);
evstate->rate = rate * SCALE_MS;
- evstate->timer = timer_new(QEMU_CLOCK_REALTIME,
- SCALE_MS,
- monitor_protocol_event_handler,
- evstate);
evstate->last = 0;
evstate->data = NULL;
+ evstate->timer = timer_new(QEMU_CLOCK_REALTIME,
+ SCALE_MS,
+ monitor_qapi_event_handler,
+ evstate);
}
-
-/* Global, one-time initializer to configure the rate limiting
- * and initialize state */
-static void monitor_protocol_event_init(void)
-{
- qemu_mutex_init(&monitor_event_state_lock);
- /* Limit RTC & BALLOON events to 1 per second */
- monitor_protocol_event_throttle(QEVENT_RTC_CHANGE, 1000);
- monitor_protocol_event_throttle(QEVENT_BALLOON_CHANGE, 1000);
- monitor_protocol_event_throttle(QEVENT_WATCHDOG, 1000);
-}
-
-/**
- * monitor_protocol_event(): Generate a Monitor event
- *
- * Event-specific data can be emitted through the (optional) 'data' parameter.
- */
-void monitor_protocol_event(MonitorEvent event, QObject *data)
+static void monitor_qapi_event_init(void)
{
- QDict *qmp;
- const char *event_name;
+ /* Limit guest-triggerable events to 1 per second */
+ monitor_qapi_event_throttle(QAPI_EVENT_RTC_CHANGE, 1000);
+ monitor_qapi_event_throttle(QAPI_EVENT_WATCHDOG, 1000);
+ monitor_qapi_event_throttle(QAPI_EVENT_BALLOON_CHANGE, 1000);
+ monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_REPORT_BAD, 1000);
+ monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_FAILURE, 1000);
+ monitor_qapi_event_throttle(QAPI_EVENT_VSERPORT_CHANGE, 1000);
- assert(event < QEVENT_MAX);
-
- event_name = monitor_event_names[event];
- assert(event_name != NULL);
-
- qmp = qdict_new();
- timestamp_put(qmp);
- qdict_put(qmp, "event", qstring_from_str(event_name));
- if (data) {
- qobject_incref(data);
- qdict_put_obj(qmp, "data", data);
- }
-
- trace_monitor_protocol_event(event, event_name, qmp);
- monitor_protocol_event_queue(event, QOBJECT(qmp));
- QDECREF(qmp);
+ qmp_event_set_func_emit(monitor_qapi_event_queue);
}
static int do_qmp_capabilities(Monitor *mon, const QDict *params,
static void monitor_data_init(Monitor *mon)
{
memset(mon, 0, sizeof(Monitor));
+ qemu_mutex_init(&mon->out_lock);
mon->outbuf = qstring_new();
/* Use *mon_cmds by default. */
mon->cmd_table = mon_cmds;
static void monitor_data_destroy(Monitor *mon)
{
QDECREF(mon->outbuf);
+ qemu_mutex_destroy(&mon->out_lock);
}
char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
handle_user_command(&hmp, command_line);
cur_mon = old_mon;
+ qemu_mutex_lock(&hmp.out_lock);
if (qstring_get_length(hmp.outbuf) > 0) {
output = g_strdup(qstring_get_str(hmp.outbuf));
} else {
output = g_strdup("");
}
+ qemu_mutex_unlock(&hmp.out_lock);
out:
monitor_data_destroy(&hmp);
{
const char *tp_name = qdict_get_str(qdict, "name");
bool new_state = qdict_get_bool(qdict, "option");
+ Error *local_err = NULL;
- bool found = false;
- TraceEvent *ev = NULL;
- while ((ev = trace_event_pattern(tp_name, ev)) != NULL) {
- found = true;
- if (!trace_event_get_state_static(ev)) {
- monitor_printf(mon, "event \"%s\" is not traceable\n", tp_name);
- } else {
- trace_event_set_state_dynamic(ev, new_state);
- }
- }
- if (!trace_event_is_pattern(tp_name) && !found) {
- monitor_printf(mon, "unknown event name \"%s\"\n", tp_name);
+ qmp_trace_event_set_state(tp_name, new_state, true, true, &local_err);
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
}
}
EventInfoList *qmp_query_events(Error **errp)
{
EventInfoList *info, *ev_list = NULL;
- MonitorEvent e;
+ QAPIEvent e;
- for (e = 0 ; e < QEVENT_MAX ; e++) {
- const char *event_name = monitor_event_names[e];
+ for (e = 0 ; e < QAPI_EVENT_MAX ; e++) {
+ const char *event_name = QAPIEvent_lookup[e];
assert(event_name != NULL);
info = g_malloc0(sizeof(*info));
info->value = g_malloc0(sizeof(*info->value));
static void do_info_jit(Monitor *mon, const QDict *qdict)
{
dump_exec_info((FILE *)mon, monitor_fprintf);
+ dump_drift_info((FILE *)mon, monitor_fprintf);
}
static void do_info_history(Monitor *mon, const QDict *qdict)
static void do_trace_print_events(Monitor *mon, const QDict *qdict)
{
- trace_print_events((FILE *)mon, &monitor_fprintf);
+ TraceEventInfoList *events = qmp_trace_event_get_state("*", NULL);
+ TraceEventInfoList *elem;
+
+ for (elem = events; elem != NULL; elem = elem->next) {
+ monitor_printf(mon, "%s : state %u\n",
+ elem->value->name,
+ elem->value->state == TRACE_EVENT_STATE_ENABLED ? 1 : 0);
+ }
+ qapi_free_TraceEventInfoList(events);
}
static int client_migrate_info(Monitor *mon, const QDict *qdict,
flags = 1;
}
}
+#endif
+#ifdef TARGET_PPC
+ flags = msr_le << 16;
+ flags |= env->bfd_mach;
#endif
monitor_disas(mon, env, addr, count, is_physical, flags);
return;
sum = 0;
for(addr = start; addr < (start + size); addr++) {
- uint8_t val = ldub_phys(addr);
+ uint8_t val = ldub_phys(&address_space_memory, addr);
/* BSD sum algorithm ('sum' Unix command) */
sum = (sum >> 1) | (sum << 15);
sum += val;
static void do_mouse_move(Monitor *mon, const QDict *qdict)
{
- int dx, dy, dz;
+ int dx, dy, dz, button;
const char *dx_str = qdict_get_str(qdict, "dx_str");
const char *dy_str = qdict_get_str(qdict, "dy_str");
const char *dz_str = qdict_get_try_str(qdict, "dz_str");
+
dx = strtol(dx_str, NULL, 0);
dy = strtol(dy_str, NULL, 0);
- dz = 0;
- if (dz_str)
+ qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
+ qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
+
+ if (dz_str) {
dz = strtol(dz_str, NULL, 0);
- kbd_mouse_event(dx, dy, dz, mouse_button_state);
+ if (dz != 0) {
+ button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
+ qemu_input_queue_btn(NULL, button, true);
+ qemu_input_event_sync();
+ qemu_input_queue_btn(NULL, button, false);
+ }
+ }
+ qemu_input_event_sync();
}
static void do_mouse_button(Monitor *mon, const QDict *qdict)
{
+ static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
+ [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
+ [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
+ };
int button_state = qdict_get_int(qdict, "button_state");
+
+ if (mouse_button_state == button_state) {
+ return;
+ }
+ qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state);
+ qemu_input_event_sync();
mouse_button_state = button_state;
- kbd_mouse_event(0, 0, 0, mouse_button_state);
}
static void do_ioport_read(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
for (i = 0; i < nb_numa_nodes; i++) {
monitor_printf(mon, "node %d cpus:", i);
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
if (cpu->numa_node == i) {
monitor_printf(mon, " %d", cpu->cpu_index);
}
}
monitor_printf(mon, "\n");
monitor_printf(mon, "node %d size: %" PRId64 " MB\n", i,
- node_mem[i] >> 20);
+ numa_info[i].node_mem >> 20);
}
}
static void do_info_profile(Monitor *mon, const QDict *qdict)
{
- int64_t total;
- total = qemu_time;
- if (total == 0)
- total = 1;
monitor_printf(mon, "async time %" PRId64 " (%0.3f)\n",
dev_time, dev_time / (double)get_ticks_per_sec());
monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n",
}
if (qemu_isdigit(fdname[0])) {
+ close(fd);
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
"a name not starting with a digit");
return;
if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
monitor_fdset_cleanup(mon_fdset);
}
+ return -1;
+ } else {
+ return mon_fdset->id;
}
- return mon_fdset->id;
}
}
}
return monitor_fdset_dup_fd_find_remove(dup_fd, false);
}
-int monitor_fdset_dup_fd_remove(int dup_fd)
+void monitor_fdset_dup_fd_remove(int dup_fd)
{
- return monitor_fdset_dup_fd_find_remove(dup_fd, true);
+ monitor_fdset_dup_fd_find_remove(dup_fd, true);
}
int monitor_handle_fd_param(Monitor *mon, const char *fdname)
int fd;
Error *local_err = NULL;
- if (!qemu_isdigit(fdname[0]) && mon) {
+ fd = monitor_handle_fd_param2(mon, fdname, &local_err);
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ }
+ return fd;
+}
+
+int monitor_handle_fd_param2(Monitor *mon, const char *fdname, Error **errp)
+{
+ int fd;
+ Error *local_err = NULL;
+ if (!qemu_isdigit(fdname[0]) && mon) {
fd = monitor_get_fd(mon, fdname, &local_err);
+ } else {
+ fd = qemu_parse_fd(fdname);
if (fd == -1) {
- qerror_report_err(local_err);
- error_free(local_err);
- return -1;
+ error_setg(&local_err, "Invalid file descriptor number '%s'",
+ fdname);
}
+ }
+ if (local_err) {
+ error_propagate(errp, local_err);
+ assert(fd == -1);
} else {
- fd = qemu_parse_fd(fdname);
+ assert(fd != -1);
}
return fd;
.help = "show the current VM status (running|paused)",
.mhandler.cmd = hmp_info_status,
},
- {
- .name = "pcmcia",
- .args_type = "",
- .params = "",
- .help = "show guest PCMCIA status",
- .mhandler.cmd = pcmcia_info,
- },
{
.name = "mice",
.args_type = "",
.help = "show the TPM device",
.mhandler.cmd = hmp_info_tpm,
},
+ {
+ .name = "memdev",
+ .args_type = "",
+ .params = "",
+ .help = "show memory backends",
+ .mhandler.cmd = hmp_info_memdev,
+ },
+ {
+ .name = "memory-devices",
+ .args_type = "",
+ .params = "",
+ .help = "show memory devices",
+ .mhandler.cmd = hmp_info_memory_devices,
+ },
{
.name = NULL,
},
{ "srr0", offsetof(CPUPPCState, spr[SPR_SRR0]) },
{ "srr1", offsetof(CPUPPCState, spr[SPR_SRR1]) },
+ { "dar", offsetof(CPUPPCState, spr[SPR_DAR]) },
+ { "dsisr", offsetof(CPUPPCState, spr[SPR_DSISR]) },
+ { "cfar", offsetof(CPUPPCState, spr[SPR_CFAR]) },
{ "sprg0", offsetof(CPUPPCState, spr[SPR_SPRG0]) },
{ "sprg1", offsetof(CPUPPCState, spr[SPR_SPRG1]) },
{ "sprg2", offsetof(CPUPPCState, spr[SPR_SPRG2]) },
}
}
break;
+ case 'S':
+ {
+ /* package all remaining string */
+ int len;
+
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ if (*typestr == '?') {
+ typestr++;
+ if (*p == '\0') {
+ /* no remaining string: NULL argument */
+ break;
+ }
+ }
+ len = strlen(p);
+ if (len <= 0) {
+ monitor_printf(mon, "%s: string expected\n",
+ cmdname);
+ break;
+ }
+ qdict_put(qdict, key, qstring_from_str(p));
+ p += len;
+ }
+ break;
default:
bad_type:
monitor_printf(mon, "%s: unknown type '%c'\n", cmdname, c);
closedir(ffs);
}
-typedef struct MonitorBlockComplete {
- Monitor *mon;
- const char *input;
-} MonitorBlockComplete;
+static const char *next_arg_type(const char *typestr)
+{
+ const char *p = strchr(typestr, ':');
+ return (p != NULL ? ++p : typestr);
+}
+
+static void add_completion_option(ReadLineState *rs, const char *str,
+ const char *option)
+{
+ if (!str || !option) {
+ return;
+ }
+ if (!strncmp(option, str, strlen(str))) {
+ readline_add_completion(rs, option);
+ }
+}
-static void block_completion_it(void *opaque, BlockDriverState *bs)
+void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
- const char *name = bdrv_get_device_name(bs);
- MonitorBlockComplete *mbc = opaque;
- Monitor *mon = mbc->mon;
- const char *input = mbc->input;
+ size_t len;
+ ChardevBackendInfoList *list, *start;
+
+ if (nb_args != 2) {
+ return;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
- if (input[0] == '\0' ||
- !strncmp(name, (char *)input, strlen(input))) {
- readline_add_completion(mon->rs, name);
+ start = list = qmp_query_chardev_backends(NULL);
+ while (list) {
+ const char *chr_name = list->value->name;
+
+ if (!strncmp(chr_name, str, len)) {
+ readline_add_completion(rs, chr_name);
+ }
+ list = list->next;
}
+ qapi_free_ChardevBackendInfoList(start);
}
-static const char *next_arg_type(const char *typestr)
+void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
- const char *p = strchr(typestr, ':');
- return (p != NULL ? ++p : typestr);
+ size_t len;
+ int i;
+
+ if (nb_args != 2) {
+ return;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ for (i = 0; NetClientOptionsKind_lookup[i]; i++) {
+ add_completion_option(rs, str, NetClientOptionsKind_lookup[i]);
+ }
}
-static void monitor_find_completion(Monitor *mon,
- const char *cmdline)
+void device_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
- const char *cmdname;
- char *args[MAX_ARGS];
- int nb_args, i, len;
- const char *ptype, *str;
- const mon_cmd_t *cmd;
- MonitorBlockComplete mbs;
+ GSList *list, *elt;
+ size_t len;
- if (parse_cmdline(cmdline, &nb_args, args) < 0) {
+ if (nb_args != 2) {
return;
}
-#ifdef DEBUG_COMPLETION
- for (i = 0; i < nb_args; i++) {
- monitor_printf(mon, "arg%d = '%s'\n", i, args[i]);
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ list = elt = object_class_get_list(TYPE_DEVICE, false);
+ while (elt) {
+ const char *name;
+ DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
+ TYPE_DEVICE);
+ name = object_class_get_name(OBJECT_CLASS(dc));
+
+ if (!dc->cannot_instantiate_with_device_add_yet
+ && !strncmp(name, str, len)) {
+ readline_add_completion(rs, name);
+ }
+ elt = elt->next;
}
-#endif
+ g_slist_free(list);
+}
- /* if the line ends with a space, it means we want to complete the
- next arg */
- len = strlen(cmdline);
- if (len > 0 && qemu_isspace(cmdline[len - 1])) {
- if (nb_args >= MAX_ARGS) {
- goto cleanup;
+void object_add_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ GSList *list, *elt;
+ size_t len;
+
+ if (nb_args != 2) {
+ return;
+ }
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ list = elt = object_class_get_list(TYPE_USER_CREATABLE, false);
+ while (elt) {
+ const char *name;
+
+ name = object_class_get_name(OBJECT_CLASS(elt->data));
+ if (!strncmp(name, str, len) && strcmp(name, TYPE_USER_CREATABLE)) {
+ readline_add_completion(rs, name);
}
- args[nb_args++] = g_strdup("");
+ elt = elt->next;
+ }
+ g_slist_free(list);
+}
+
+static void peripheral_device_del_completion(ReadLineState *rs,
+ const char *str, size_t len)
+{
+ Object *peripheral;
+ GSList *list = NULL, *item;
+
+ peripheral = object_resolve_path("/machine/peripheral/", NULL);
+ if (peripheral == NULL) {
+ return;
+ }
+
+ object_child_foreach(peripheral, qdev_build_hotpluggable_device_list,
+ &list);
+
+ for (item = list; item; item = g_slist_next(item)) {
+ DeviceState *dev = item->data;
+
+ if (dev->id && !strncmp(str, dev->id, len)) {
+ readline_add_completion(rs, dev->id);
+ }
+ }
+
+ g_slist_free(list);
+}
+
+void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ size_t len;
+ ChardevInfoList *list, *start;
+
+ if (nb_args != 2) {
+ return;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+
+ start = list = qmp_query_chardev(NULL);
+ while (list) {
+ ChardevInfo *chr = list->value;
+
+ if (!strncmp(chr->label, str, len)) {
+ readline_add_completion(rs, chr->label);
+ }
+ list = list->next;
+ }
+ qapi_free_ChardevInfoList(start);
+}
+
+static void ringbuf_completion(ReadLineState *rs, const char *str)
+{
+ size_t len;
+ ChardevInfoList *list, *start;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+
+ start = list = qmp_query_chardev(NULL);
+ while (list) {
+ ChardevInfo *chr_info = list->value;
+
+ if (!strncmp(chr_info->label, str, len)) {
+ CharDriverState *chr = qemu_chr_find(chr_info->label);
+ if (chr && chr_is_ringbuf(chr)) {
+ readline_add_completion(rs, chr_info->label);
+ }
+ }
+ list = list->next;
+ }
+ qapi_free_ChardevInfoList(start);
+}
+
+void ringbuf_read_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ if (nb_args != 2) {
+ return;
+ }
+ ringbuf_completion(rs, str);
+}
+
+void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ if (nb_args != 2) {
+ return;
+ }
+ ringbuf_completion(rs, str);
+}
+
+void device_del_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ size_t len;
+
+ if (nb_args != 2) {
+ return;
+ }
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ peripheral_device_del_completion(rs, str, len);
+}
+
+void object_del_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ ObjectPropertyInfoList *list, *start;
+ size_t len;
+
+ if (nb_args != 2) {
+ return;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+
+ start = list = qmp_qom_list("/objects", NULL);
+ while (list) {
+ ObjectPropertyInfo *info = list->value;
+
+ if (!strncmp(info->type, "child<", 5)
+ && !strncmp(info->name, str, len)) {
+ readline_add_completion(rs, info->name);
+ }
+ list = list->next;
+ }
+ qapi_free_ObjectPropertyInfoList(start);
+}
+
+void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ int i;
+ char *sep;
+ size_t len;
+
+ if (nb_args != 2) {
+ return;
+ }
+ sep = strrchr(str, '-');
+ if (sep) {
+ str = sep + 1;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ for (i = 0; i < Q_KEY_CODE_MAX; i++) {
+ if (!strncmp(str, QKeyCode_lookup[i], len)) {
+ readline_add_completion(rs, QKeyCode_lookup[i]);
+ }
+ }
+}
+
+void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ size_t len;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ if (nb_args == 2) {
+ NetClientState *ncs[255];
+ int count, i;
+ count = qemu_find_net_clients_except(NULL, ncs,
+ NET_CLIENT_OPTIONS_KIND_NONE, 255);
+ for (i = 0; i < count; i++) {
+ const char *name = ncs[i]->name;
+ if (!strncmp(str, name, len)) {
+ readline_add_completion(rs, name);
+ }
+ }
+ } else if (nb_args == 3) {
+ add_completion_option(rs, str, "on");
+ add_completion_option(rs, str, "off");
+ }
+}
+
+void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ int len, count, i;
+ NetClientState *ncs[255];
+
+ if (nb_args != 2) {
+ return;
+ }
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC,
+ 255);
+ for (i = 0; i < count; i++) {
+ QemuOpts *opts;
+ const char *name = ncs[i]->name;
+ if (strncmp(str, name, len)) {
+ continue;
+ }
+ opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), name);
+ if (opts) {
+ readline_add_completion(rs, name);
+ }
+ }
+}
+
+void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ int i;
+
+ if (nb_args != 2) {
+ return;
+ }
+ readline_set_completion_index(rs, strlen(str));
+ for (i = 0; WatchdogExpirationAction_lookup[i]; i++) {
+ add_completion_option(rs, str, WatchdogExpirationAction_lookup[i]);
+ }
+}
+
+void migrate_set_capability_completion(ReadLineState *rs, int nb_args,
+ const char *str)
+{
+ size_t len;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ if (nb_args == 2) {
+ int i;
+ for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ const char *name = MigrationCapability_lookup[i];
+ if (!strncmp(str, name, len)) {
+ readline_add_completion(rs, name);
+ }
+ }
+ } else if (nb_args == 3) {
+ add_completion_option(rs, str, "on");
+ add_completion_option(rs, str, "off");
+ }
+}
+
+void host_net_add_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ int i;
+ size_t len;
+ if (nb_args != 2) {
+ return;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ for (i = 0; host_net_devices[i]; i++) {
+ if (!strncmp(host_net_devices[i], str, len)) {
+ readline_add_completion(rs, host_net_devices[i]);
+ }
+ }
+}
+
+void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ NetClientState *ncs[255];
+ int count, i, len;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ if (nb_args == 2) {
+ count = qemu_find_net_clients_except(NULL, ncs,
+ NET_CLIENT_OPTIONS_KIND_NONE, 255);
+ for (i = 0; i < count; i++) {
+ int id;
+ char name[16];
+
+ if (net_hub_id_for_client(ncs[i], &id)) {
+ continue;
+ }
+ snprintf(name, sizeof(name), "%d", id);
+ if (!strncmp(str, name, len)) {
+ readline_add_completion(rs, name);
+ }
+ }
+ return;
+ } else if (nb_args == 3) {
+ count = qemu_find_net_clients_except(NULL, ncs,
+ NET_CLIENT_OPTIONS_KIND_NIC, 255);
+ for (i = 0; i < count; i++) {
+ const char *name;
+
+ name = ncs[i]->name;
+ if (!strncmp(str, name, len)) {
+ readline_add_completion(rs, name);
+ }
+ }
+ return;
+ }
+}
+
+static void vm_completion(ReadLineState *rs, const char *str)
+{
+ size_t len;
+ BlockDriverState *bs = NULL;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ while ((bs = bdrv_next(bs))) {
+ SnapshotInfoList *snapshots, *snapshot;
+
+ if (!bdrv_can_snapshot(bs)) {
+ continue;
+ }
+ if (bdrv_query_snapshot_info_list(bs, &snapshots, NULL)) {
+ continue;
+ }
+ snapshot = snapshots;
+ while (snapshot) {
+ char *completion = snapshot->value->name;
+ if (!strncmp(str, completion, len)) {
+ readline_add_completion(rs, completion);
+ }
+ completion = snapshot->value->id;
+ if (!strncmp(str, completion, len)) {
+ readline_add_completion(rs, completion);
+ }
+ snapshot = snapshot->next;
+ }
+ qapi_free_SnapshotInfoList(snapshots);
+ }
+
+}
+
+void delvm_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ if (nb_args == 2) {
+ vm_completion(rs, str);
+ }
+}
+
+void loadvm_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ if (nb_args == 2) {
+ vm_completion(rs, str);
}
+}
+
+static void monitor_find_completion_by_table(Monitor *mon,
+ const mon_cmd_t *cmd_table,
+ char **args,
+ int nb_args)
+{
+ const char *cmdname;
+ int i;
+ const char *ptype, *str, *name;
+ const mon_cmd_t *cmd;
+ BlockDriverState *bs;
+
if (nb_args <= 1) {
/* command completion */
if (nb_args == 0)
else
cmdname = args[0];
readline_set_completion_index(mon->rs, strlen(cmdname));
- for (cmd = mon->cmd_table; cmd->name != NULL; cmd++) {
+ for (cmd = cmd_table; cmd->name != NULL; cmd++) {
cmd_completion(mon, cmdname, cmd->name);
}
} else {
/* find the command */
- for (cmd = mon->cmd_table; cmd->name != NULL; cmd++) {
+ for (cmd = cmd_table; cmd->name != NULL; cmd++) {
if (compare_cmd(args[0], cmd->name)) {
break;
}
}
if (!cmd->name) {
- goto cleanup;
+ return;
+ }
+
+ if (cmd->sub_table) {
+ /* do the job again */
+ return monitor_find_completion_by_table(mon, cmd->sub_table,
+ &args[1], nb_args - 1);
+ }
+ if (cmd->command_completion) {
+ return cmd->command_completion(mon->rs, nb_args, args[nb_args - 1]);
}
ptype = next_arg_type(cmd->args_type);
break;
case 'B':
/* block device name completion */
- mbs.mon = mon;
- mbs.input = str;
readline_set_completion_index(mon->rs, strlen(str));
- bdrv_iterate(block_completion_it, &mbs);
+ for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
+ name = bdrv_get_device_name(bs);
+ if (str[0] == '\0' ||
+ !strncmp(name, str, strlen(str))) {
+ readline_add_completion(mon->rs, name);
+ }
+ }
break;
case 's':
- /* XXX: more generic ? */
- if (!strcmp(cmd->name, "info")) {
- readline_set_completion_index(mon->rs, strlen(str));
- for(cmd = info_cmds; cmd->name != NULL; cmd++) {
- cmd_completion(mon, str, cmd->name);
- }
- } else if (!strcmp(cmd->name, "sendkey")) {
- char *sep = strrchr(str, '-');
- if (sep)
- str = sep + 1;
- readline_set_completion_index(mon->rs, strlen(str));
- for (i = 0; i < Q_KEY_CODE_MAX; i++) {
- cmd_completion(mon, str, QKeyCode_lookup[i]);
- }
- } else if (!strcmp(cmd->name, "help|?")) {
- readline_set_completion_index(mon->rs, strlen(str));
- for (cmd = mon->cmd_table; cmd->name != NULL; cmd++) {
- cmd_completion(mon, str, cmd->name);
- }
+ case 'S':
+ if (!strcmp(cmd->name, "help|?")) {
+ monitor_find_completion_by_table(mon, cmd_table,
+ &args[1], nb_args - 1);
}
break;
default:
break;
}
}
+}
+
+static void monitor_find_completion(void *opaque,
+ const char *cmdline)
+{
+ Monitor *mon = opaque;
+ char *args[MAX_ARGS];
+ int nb_args, len;
+
+ /* 1. parse the cmdline */
+ if (parse_cmdline(cmdline, &nb_args, args) < 0) {
+ return;
+ }
+#ifdef DEBUG_COMPLETION
+ {
+ int i;
+ for (i = 0; i < nb_args; i++) {
+ monitor_printf(mon, "arg%d = '%s'\n", i, args[i]);
+ }
+ }
+#endif
+
+ /* if the line ends with a space, it means we want to complete the
+ next arg */
+ len = strlen(cmdline);
+ if (len > 0 && qemu_isspace(cmdline[len - 1])) {
+ if (nb_args >= MAX_ARGS) {
+ goto cleanup;
+ }
+ args[nb_args++] = g_strdup("");
+ }
+
+ /* 2. auto complete according to args */
+ monitor_find_completion_by_table(mon, mon->cmd_table, args, nb_args);
cleanup:
free_cmdline_args(args, nb_args);
cur_mon = old_mon;
}
-static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque)
+static void monitor_command_cb(void *opaque, const char *cmdline,
+ void *readline_opaque)
{
+ Monitor *mon = opaque;
+
monitor_suspend(mon);
handle_user_command(mon, cmdline);
monitor_resume(mon);
switch (event) {
case CHR_EVENT_MUX_IN:
+ qemu_mutex_lock(&mon->out_lock);
mon->mux_out = 0;
+ qemu_mutex_unlock(&mon->out_lock);
if (mon->reset_seen) {
readline_restart(mon->rs);
monitor_resume(mon);
} else {
mon->suspend_cnt++;
}
+ qemu_mutex_lock(&mon->out_lock);
mon->mux_out = 1;
+ qemu_mutex_unlock(&mon->out_lock);
break;
case CHR_EVENT_OPENED:
monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
"information\n", QEMU_VERSION);
if (!mon->mux_out) {
+ readline_restart(mon->rs);
readline_show_prompt(mon->rs);
}
mon->reset_seen = 1;
* End:
*/
+/* These functions just adapt the readline interface in a typesafe way. We
+ * could cast function pointers but that discards compiler checks.
+ */
+static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ monitor_vprintf(opaque, fmt, ap);
+ va_end(ap);
+}
+
+static void monitor_readline_flush(void *opaque)
+{
+ monitor_flush(opaque);
+}
+
+static void __attribute__((constructor)) monitor_lock_init(void)
+{
+ qemu_mutex_init(&monitor_lock);
+}
+
void monitor_init(CharDriverState *chr, int flags)
{
static int is_first_init = 1;
Monitor *mon;
if (is_first_init) {
- monitor_protocol_event_init();
+ monitor_qapi_event_init();
sortcmdlist();
is_first_init = 0;
}
mon->chr = chr;
mon->flags = flags;
if (flags & MONITOR_USE_READLINE) {
- mon->rs = readline_init(mon, monitor_find_completion);
+ mon->rs = readline_init(monitor_readline_printf,
+ monitor_readline_flush,
+ mon,
+ monitor_find_completion);
monitor_read_command(mon, 0);
}
monitor_event, mon);
}
+ qemu_mutex_lock(&monitor_lock);
QLIST_INSERT_HEAD(&mon_list, mon, entry);
+ qemu_mutex_unlock(&monitor_lock);
+
if (!default_mon || (flags & MONITOR_IS_DEFAULT))
default_mon = mon;
}
-static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
+static void bdrv_password_cb(void *opaque, const char *password,
+ void *readline_opaque)
{
- BlockDriverState *bs = opaque;
+ Monitor *mon = opaque;
+ BlockDriverState *bs = readline_opaque;
int ret = 0;
if (bdrv_set_key(bs, password) != 0) {
}
int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
- BlockDriverCompletionFunc *completion_cb,
+ BlockCompletionFunc *completion_cb,
void *opaque)
{
int err;
}
int monitor_read_block_device_key(Monitor *mon, const char *device,
- BlockDriverCompletionFunc *completion_cb,
+ BlockCompletionFunc *completion_cb,
void *opaque)
{
BlockDriverState *bs;
{ /* end of list */ }
},
};
+
+#ifndef TARGET_I386
+void qmp_rtc_reset_reinjection(Error **errp)
+{
+ error_set(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
+}
+#endif