X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/9f0355b590ac523d0c4e67c416c3f9cf7af3d574..2f5732e9648fcddc8759a8fd25c0b41a38352be6:/monitor.c?ds=sidebyside diff --git a/monitor.c b/monitor.c index 593679a17a..799131bd01 100644 --- a/monitor.c +++ b/monitor.c @@ -66,9 +66,13 @@ #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) @@ -177,23 +181,28 @@ typedef struct MonitorControl { * 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; @@ -208,6 +217,9 @@ struct Monitor { /* 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; @@ -266,17 +278,22 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, } } +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; @@ -303,18 +320,26 @@ void monitor_flush(Monitor *mon) 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, + 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') @@ -324,9 +349,10 @@ static void monitor_puts(Monitor *mon, const char *str) } 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) @@ -437,65 +463,14 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data) 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", - [QEVENT_BLOCK_IMAGE_CORRUPTED] = "BLOCK_IMAGE_CORRUPTED", - [QEVENT_QUORUM_FAILURE] = "QUORUM_FAILURE", - [QEVENT_QUORUM_REPORT_BAD] = "QUORUM_REPORT_BAD", -}; -QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) - -static MonitorEventState monitor_event_state[QEVENT_MAX]; +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; @@ -507,20 +482,18 @@ monitor_protocol_event_emit(MonitorEvent event, } } - /* * 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); - evstate = &(monitor_event_state[event]); + evstate = &(monitor_qapi_event_state[event]); trace_monitor_protocol_event_queue(event, data, evstate->rate, @@ -528,8 +501,9 @@ monitor_protocol_event_queue(MonitorEvent event, 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; @@ -545,39 +519,39 @@ monitor_protocol_event_queue(MonitorEvent event, 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_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); - 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_lock); } - /* * @event: the event ID to be limited * @rate: the rate limit in milliseconds @@ -587,65 +561,36 @@ static void monitor_protocol_event_handler(void *opaque) * 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) +static void monitor_qapi_event_init(void) { - /* 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); - /* limit the rate of quorum events to avoid hammering the management */ - monitor_protocol_event_throttle(QEVENT_QUORUM_REPORT_BAD, 1000); - monitor_protocol_event_throttle(QEVENT_QUORUM_FAILURE, 1000); -} + /* 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); -/** - * 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) -{ - QDict *qmp; - const char *event_name; - - 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, @@ -664,6 +609,7 @@ static void handle_user_command(Monitor *mon, const char *cmdline); 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; @@ -672,6 +618,7 @@ static void monitor_data_init(Monitor *mon) 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, @@ -699,11 +646,13 @@ 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); @@ -1042,10 +991,10 @@ CommandInfoList *qmp_query_commands(Error **errp) 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)); @@ -1282,6 +1231,10 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize, 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; @@ -2005,7 +1958,7 @@ static void do_info_numa(Monitor *mon, const QDict *qdict) } monitor_printf(mon, "\n"); monitor_printf(mon, "node %d size: %" PRId64 " MB\n", i, - node_mem[i] >> 20); + numa_info[i].node_mem >> 20); } } @@ -2957,6 +2910,13 @@ static mon_cmd_t info_cmds[] = { .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 = NULL, }, @@ -4411,6 +4371,45 @@ void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str) 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; @@ -4519,6 +4518,142 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str) } } +void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str) +{ + if (nb_args != 2) { + return; + } + readline_set_completion_index(rs, strlen(str)); + add_completion_option(rs, str, "reset"); + add_completion_option(rs, str, "shutdown"); + add_completion_option(rs, str, "poweroff"); + add_completion_option(rs, str, "pause"); + add_completion_option(rs, str, "debug"); + add_completion_option(rs, str, "none"); +} + +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, @@ -5077,7 +5212,9 @@ static void monitor_event(void *opaque, int event) 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); @@ -5097,7 +5234,9 @@ static void monitor_event(void *opaque, int event) } 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: @@ -5162,13 +5301,18 @@ 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; } @@ -5199,7 +5343,10 @@ void monitor_init(CharDriverState *chr, int flags) 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; } @@ -5294,3 +5441,10 @@ QemuOptsList qemu_mon_opts = { { /* end of list */ } }, }; + +#ifndef TARGET_I386 +void qmp_rtc_reset_reinjection(Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection"); +} +#endif