xref: /openbmc/qemu/monitor/hmp-cmds.c (revision fa1cea9d)
1 /*
2  * Human Monitor Interface commands
3  *
4  * Copyright IBM, Corp. 2011
5  *
6  * Authors:
7  *  Anthony Liguori   <aliguori@us.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  *
12  * Contributions after 2012-01-13 are licensed under the terms of the
13  * GNU GPL, version 2 or (at your option) any later version.
14  */
15 
16 #include "qemu/osdep.h"
17 #include "monitor/hmp.h"
18 #include "qemu/help_option.h"
19 #include "monitor/monitor.h"
20 #include "qapi/error.h"
21 #include "qapi/qapi-commands-control.h"
22 #include "qapi/qapi-commands-misc.h"
23 #include "qapi/qapi-commands-run-state.h"
24 #include "qapi/qapi-commands-stats.h"
25 #include "qapi/qapi-commands-tpm.h"
26 #include "qapi/qmp/qdict.h"
27 #include "qapi/qmp/qerror.h"
28 #include "qemu/cutils.h"
29 #include "hw/core/cpu.h"
30 #include "hw/intc/intc.h"
31 
32 bool hmp_handle_error(Monitor *mon, Error *err)
33 {
34     if (err) {
35         error_reportf_err(err, "Error: ");
36         return true;
37     }
38     return false;
39 }
40 
41 /*
42  * Split @str at comma.
43  * A null @str defaults to "".
44  */
45 strList *hmp_split_at_comma(const char *str)
46 {
47     char **split = g_strsplit(str ?: "", ",", -1);
48     strList *res = NULL;
49     strList **tail = &res;
50     int i;
51 
52     for (i = 0; split[i]; i++) {
53         QAPI_LIST_APPEND(tail, split[i]);
54     }
55 
56     g_free(split);
57     return res;
58 }
59 
60 void hmp_info_name(Monitor *mon, const QDict *qdict)
61 {
62     NameInfo *info;
63 
64     info = qmp_query_name(NULL);
65     if (info->name) {
66         monitor_printf(mon, "%s\n", info->name);
67     }
68     qapi_free_NameInfo(info);
69 }
70 
71 void hmp_info_version(Monitor *mon, const QDict *qdict)
72 {
73     VersionInfo *info;
74 
75     info = qmp_query_version(NULL);
76 
77     monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
78                    info->qemu->major, info->qemu->minor, info->qemu->micro,
79                    info->package);
80 
81     qapi_free_VersionInfo(info);
82 }
83 
84 void hmp_info_status(Monitor *mon, const QDict *qdict)
85 {
86     StatusInfo *info;
87 
88     info = qmp_query_status(NULL);
89 
90     monitor_printf(mon, "VM status: %s%s",
91                    info->running ? "running" : "paused",
92                    info->singlestep ? " (single step mode)" : "");
93 
94     if (!info->running && info->status != RUN_STATE_PAUSED) {
95         monitor_printf(mon, " (%s)", RunState_str(info->status));
96     }
97 
98     monitor_printf(mon, "\n");
99 
100     qapi_free_StatusInfo(info);
101 }
102 
103 static int hmp_info_pic_foreach(Object *obj, void *opaque)
104 {
105     InterruptStatsProvider *intc;
106     InterruptStatsProviderClass *k;
107     Monitor *mon = opaque;
108 
109     if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
110         intc = INTERRUPT_STATS_PROVIDER(obj);
111         k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
112         if (k->print_info) {
113             k->print_info(intc, mon);
114         } else {
115             monitor_printf(mon, "Interrupt controller information not available for %s.\n",
116                            object_get_typename(obj));
117         }
118     }
119 
120     return 0;
121 }
122 
123 void hmp_info_pic(Monitor *mon, const QDict *qdict)
124 {
125     object_child_foreach_recursive(object_get_root(),
126                                    hmp_info_pic_foreach, mon);
127 }
128 
129 void hmp_info_tpm(Monitor *mon, const QDict *qdict)
130 {
131 #ifdef CONFIG_TPM
132     TPMInfoList *info_list, *info;
133     Error *err = NULL;
134     unsigned int c = 0;
135     TPMPassthroughOptions *tpo;
136     TPMEmulatorOptions *teo;
137 
138     info_list = qmp_query_tpm(&err);
139     if (err) {
140         monitor_printf(mon, "TPM device not supported\n");
141         error_free(err);
142         return;
143     }
144 
145     if (info_list) {
146         monitor_printf(mon, "TPM device:\n");
147     }
148 
149     for (info = info_list; info; info = info->next) {
150         TPMInfo *ti = info->value;
151         monitor_printf(mon, " tpm%d: model=%s\n",
152                        c, TpmModel_str(ti->model));
153 
154         monitor_printf(mon, "  \\ %s: type=%s",
155                        ti->id, TpmType_str(ti->options->type));
156 
157         switch (ti->options->type) {
158         case TPM_TYPE_PASSTHROUGH:
159             tpo = ti->options->u.passthrough.data;
160             monitor_printf(mon, "%s%s%s%s",
161                            tpo->path ? ",path=" : "",
162                            tpo->path ?: "",
163                            tpo->cancel_path ? ",cancel-path=" : "",
164                            tpo->cancel_path ?: "");
165             break;
166         case TPM_TYPE_EMULATOR:
167             teo = ti->options->u.emulator.data;
168             monitor_printf(mon, ",chardev=%s", teo->chardev);
169             break;
170         case TPM_TYPE__MAX:
171             break;
172         }
173         monitor_printf(mon, "\n");
174         c++;
175     }
176     qapi_free_TPMInfoList(info_list);
177 #else
178     monitor_printf(mon, "TPM device not supported\n");
179 #endif /* CONFIG_TPM */
180 }
181 
182 void hmp_quit(Monitor *mon, const QDict *qdict)
183 {
184     monitor_suspend(mon);
185     qmp_quit(NULL);
186 }
187 
188 void hmp_stop(Monitor *mon, const QDict *qdict)
189 {
190     qmp_stop(NULL);
191 }
192 
193 void hmp_sync_profile(Monitor *mon, const QDict *qdict)
194 {
195     const char *op = qdict_get_try_str(qdict, "op");
196 
197     if (op == NULL) {
198         bool on = qsp_is_enabled();
199 
200         monitor_printf(mon, "sync-profile is %s\n", on ? "on" : "off");
201         return;
202     }
203     if (!strcmp(op, "on")) {
204         qsp_enable();
205     } else if (!strcmp(op, "off")) {
206         qsp_disable();
207     } else if (!strcmp(op, "reset")) {
208         qsp_reset();
209     } else {
210         Error *err = NULL;
211 
212         error_setg(&err, QERR_INVALID_PARAMETER, op);
213         hmp_handle_error(mon, err);
214     }
215 }
216 
217 void hmp_exit_preconfig(Monitor *mon, const QDict *qdict)
218 {
219     Error *err = NULL;
220 
221     qmp_x_exit_preconfig(&err);
222     hmp_handle_error(mon, err);
223 }
224 
225 void hmp_cpu(Monitor *mon, const QDict *qdict)
226 {
227     int64_t cpu_index;
228 
229     /* XXX: drop the monitor_set_cpu() usage when all HMP commands that
230             use it are converted to the QAPI */
231     cpu_index = qdict_get_int(qdict, "index");
232     if (monitor_set_cpu(mon, cpu_index) < 0) {
233         monitor_printf(mon, "invalid CPU index\n");
234     }
235 }
236 
237 void hmp_cont(Monitor *mon, const QDict *qdict)
238 {
239     Error *err = NULL;
240 
241     qmp_cont(&err);
242     hmp_handle_error(mon, err);
243 }
244 
245 void hmp_change(Monitor *mon, const QDict *qdict)
246 {
247     const char *device = qdict_get_str(qdict, "device");
248     const char *target = qdict_get_str(qdict, "target");
249     const char *arg = qdict_get_try_str(qdict, "arg");
250     const char *read_only = qdict_get_try_str(qdict, "read-only-mode");
251     bool force = qdict_get_try_bool(qdict, "force", false);
252     Error *err = NULL;
253 
254 #ifdef CONFIG_VNC
255     if (strcmp(device, "vnc") == 0) {
256         hmp_change_vnc(mon, device, target, arg, read_only, force, &err);
257     } else
258 #endif
259     {
260         hmp_change_medium(mon, device, target, arg, read_only, force, &err);
261     }
262 
263     hmp_handle_error(mon, err);
264 }
265 
266 void hmp_getfd(Monitor *mon, const QDict *qdict)
267 {
268     const char *fdname = qdict_get_str(qdict, "fdname");
269     Error *err = NULL;
270 
271     qmp_getfd(fdname, &err);
272     hmp_handle_error(mon, err);
273 }
274 
275 void hmp_closefd(Monitor *mon, const QDict *qdict)
276 {
277     const char *fdname = qdict_get_str(qdict, "fdname");
278     Error *err = NULL;
279 
280     qmp_closefd(fdname, &err);
281     hmp_handle_error(mon, err);
282 }
283 
284 void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
285 {
286     IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
287     IOThreadInfoList *info;
288     IOThreadInfo *value;
289 
290     for (info = info_list; info; info = info->next) {
291         value = info->value;
292         monitor_printf(mon, "%s:\n", value->id);
293         monitor_printf(mon, "  thread_id=%" PRId64 "\n", value->thread_id);
294         monitor_printf(mon, "  poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
295         monitor_printf(mon, "  poll-grow=%" PRId64 "\n", value->poll_grow);
296         monitor_printf(mon, "  poll-shrink=%" PRId64 "\n", value->poll_shrink);
297         monitor_printf(mon, "  aio-max-batch=%" PRId64 "\n",
298                        value->aio_max_batch);
299     }
300 
301     qapi_free_IOThreadInfoList(info_list);
302 }
303 
304 static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value)
305 {
306     const char *unit = NULL;
307     monitor_printf(mon, "    %s (%s%s", value->name, StatsType_str(value->type),
308                    value->has_unit || value->exponent ? ", " : "");
309 
310     if (value->has_unit) {
311         if (value->unit == STATS_UNIT_SECONDS) {
312             unit = "s";
313         } else if (value->unit == STATS_UNIT_BYTES) {
314             unit = "B";
315         }
316     }
317 
318     if (unit && value->base == 10 &&
319         value->exponent >= -18 && value->exponent <= 18 &&
320         value->exponent % 3 == 0) {
321         monitor_puts(mon, si_prefix(value->exponent));
322     } else if (unit && value->base == 2 &&
323                value->exponent >= 0 && value->exponent <= 60 &&
324                value->exponent % 10 == 0) {
325 
326         monitor_puts(mon, iec_binary_prefix(value->exponent));
327     } else if (value->exponent) {
328         /* Use exponential notation and write the unit's English name */
329         monitor_printf(mon, "* %d^%d%s",
330                        value->base, value->exponent,
331                        value->has_unit ? " " : "");
332         unit = NULL;
333     }
334 
335     if (value->has_unit) {
336         monitor_puts(mon, unit ? unit : StatsUnit_str(value->unit));
337     }
338 
339     /* Print bucket size for linear histograms */
340     if (value->type == STATS_TYPE_LINEAR_HISTOGRAM && value->has_bucket_size) {
341         monitor_printf(mon, ", bucket size=%d", value->bucket_size);
342     }
343     monitor_printf(mon, ")");
344 }
345 
346 static StatsSchemaValueList *find_schema_value_list(
347     StatsSchemaList *list, StatsProvider provider,
348     StatsTarget target)
349 {
350     StatsSchemaList *node;
351 
352     for (node = list; node; node = node->next) {
353         if (node->value->provider == provider &&
354             node->value->target == target) {
355             return node->value->stats;
356         }
357     }
358     return NULL;
359 }
360 
361 static void print_stats_results(Monitor *mon, StatsTarget target,
362                                 bool show_provider,
363                                 StatsResult *result,
364                                 StatsSchemaList *schema)
365 {
366     /* Find provider schema */
367     StatsSchemaValueList *schema_value_list =
368         find_schema_value_list(schema, result->provider, target);
369     StatsList *stats_list;
370 
371     if (!schema_value_list) {
372         monitor_printf(mon, "failed to find schema list for %s\n",
373                        StatsProvider_str(result->provider));
374         return;
375     }
376 
377     if (show_provider) {
378         monitor_printf(mon, "provider: %s\n",
379                        StatsProvider_str(result->provider));
380     }
381 
382     for (stats_list = result->stats; stats_list;
383              stats_list = stats_list->next,
384              schema_value_list = schema_value_list->next) {
385 
386         Stats *stats = stats_list->value;
387         StatsValue *stats_value = stats->value;
388         StatsSchemaValue *schema_value = schema_value_list->value;
389 
390         /* Find schema entry */
391         while (!g_str_equal(stats->name, schema_value->name)) {
392             if (!schema_value_list->next) {
393                 monitor_printf(mon, "failed to find schema entry for %s\n",
394                                stats->name);
395                 return;
396             }
397             schema_value_list = schema_value_list->next;
398             schema_value = schema_value_list->value;
399         }
400 
401         print_stats_schema_value(mon, schema_value);
402 
403         if (stats_value->type == QTYPE_QNUM) {
404             monitor_printf(mon, ": %" PRId64 "\n", stats_value->u.scalar);
405         } else if (stats_value->type == QTYPE_QBOOL) {
406             monitor_printf(mon, ": %s\n", stats_value->u.boolean ? "yes" : "no");
407         } else if (stats_value->type == QTYPE_QLIST) {
408             uint64List *list;
409             int i;
410 
411             monitor_printf(mon, ": ");
412             for (list = stats_value->u.list, i = 1;
413                  list;
414                  list = list->next, i++) {
415                 monitor_printf(mon, "[%d]=%" PRId64 " ", i, list->value);
416             }
417             monitor_printf(mon, "\n");
418         }
419     }
420 }
421 
422 /* Create the StatsFilter that is needed for an "info stats" invocation.  */
423 static StatsFilter *stats_filter(StatsTarget target, const char *names,
424                                  int cpu_index, StatsProvider provider)
425 {
426     StatsFilter *filter = g_malloc0(sizeof(*filter));
427     StatsProvider provider_idx;
428     StatsRequestList *request_list = NULL;
429 
430     filter->target = target;
431     switch (target) {
432     case STATS_TARGET_VM:
433         break;
434     case STATS_TARGET_VCPU:
435     {
436         strList *vcpu_list = NULL;
437         CPUState *cpu = qemu_get_cpu(cpu_index);
438         char *canonical_path = object_get_canonical_path(OBJECT(cpu));
439 
440         QAPI_LIST_PREPEND(vcpu_list, canonical_path);
441         filter->u.vcpu.has_vcpus = true;
442         filter->u.vcpu.vcpus = vcpu_list;
443         break;
444     }
445     default:
446         break;
447     }
448 
449     if (!names && provider == STATS_PROVIDER__MAX) {
450         return filter;
451     }
452 
453     /*
454      * "info stats" can only query either one or all the providers.  Querying
455      * by name, but not by provider, requires the creation of one filter per
456      * provider.
457      */
458     for (provider_idx = 0; provider_idx < STATS_PROVIDER__MAX; provider_idx++) {
459         if (provider == STATS_PROVIDER__MAX || provider == provider_idx) {
460             StatsRequest *request = g_new0(StatsRequest, 1);
461             request->provider = provider_idx;
462             if (names && !g_str_equal(names, "*")) {
463                 request->has_names = true;
464                 request->names = hmp_split_at_comma(names);
465             }
466             QAPI_LIST_PREPEND(request_list, request);
467         }
468     }
469 
470     filter->has_providers = true;
471     filter->providers = request_list;
472     return filter;
473 }
474 
475 void hmp_info_stats(Monitor *mon, const QDict *qdict)
476 {
477     const char *target_str = qdict_get_str(qdict, "target");
478     const char *provider_str = qdict_get_try_str(qdict, "provider");
479     const char *names = qdict_get_try_str(qdict, "names");
480 
481     StatsProvider provider = STATS_PROVIDER__MAX;
482     StatsTarget target;
483     Error *err = NULL;
484     g_autoptr(StatsSchemaList) schema = NULL;
485     g_autoptr(StatsResultList) stats = NULL;
486     g_autoptr(StatsFilter) filter = NULL;
487     StatsResultList *entry;
488 
489     target = qapi_enum_parse(&StatsTarget_lookup, target_str, -1, &err);
490     if (err) {
491         monitor_printf(mon, "invalid stats target %s\n", target_str);
492         goto exit_no_print;
493     }
494     if (provider_str) {
495         provider = qapi_enum_parse(&StatsProvider_lookup, provider_str, -1, &err);
496         if (err) {
497             monitor_printf(mon, "invalid stats provider %s\n", provider_str);
498             goto exit_no_print;
499         }
500     }
501 
502     schema = qmp_query_stats_schemas(provider_str ? true : false,
503                                      provider, &err);
504     if (err) {
505         goto exit;
506     }
507 
508     switch (target) {
509     case STATS_TARGET_VM:
510         filter = stats_filter(target, names, -1, provider);
511         break;
512     case STATS_TARGET_VCPU: {}
513         int cpu_index = monitor_get_cpu_index(mon);
514         filter = stats_filter(target, names, cpu_index, provider);
515         break;
516     default:
517         abort();
518     }
519 
520     stats = qmp_query_stats(filter, &err);
521     if (err) {
522         goto exit;
523     }
524     for (entry = stats; entry; entry = entry->next) {
525         print_stats_results(mon, target, provider_str == NULL, entry->value, schema);
526     }
527 
528 exit:
529     if (err) {
530         monitor_printf(mon, "%s\n", error_get_pretty(err));
531     }
532 exit_no_print:
533     error_free(err);
534 }
535