xref: /openbmc/qemu/monitor/hmp-cmds.c (revision 2f95279a)
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 "exec/address-spaces.h"
18 #include "exec/ioport.h"
19 #include "exec/gdbstub.h"
20 #include "gdbstub/enums.h"
21 #include "monitor/hmp.h"
22 #include "qemu/help_option.h"
23 #include "monitor/monitor-internal.h"
24 #include "qapi/error.h"
25 #include "qapi/qapi-commands-control.h"
26 #include "qapi/qapi-commands-machine.h"
27 #include "qapi/qapi-commands-misc.h"
28 #include "qapi/qmp/qdict.h"
29 #include "qemu/cutils.h"
30 #include "qemu/log.h"
31 #include "sysemu/sysemu.h"
32 
33 bool hmp_handle_error(Monitor *mon, Error *err)
34 {
35     if (err) {
36         error_reportf_err(err, "Error: ");
37         return true;
38     }
39     return false;
40 }
41 
42 /*
43  * Split @str at comma.
44  * A null @str defaults to "".
45  */
46 strList *hmp_split_at_comma(const char *str)
47 {
48     char **split = g_strsplit(str ?: "", ",", -1);
49     strList *res = NULL;
50     strList **tail = &res;
51     int i;
52 
53     for (i = 0; split[i]; i++) {
54         QAPI_LIST_APPEND(tail, split[i]);
55     }
56 
57     g_free(split);
58     return res;
59 }
60 
61 void hmp_info_name(Monitor *mon, const QDict *qdict)
62 {
63     NameInfo *info;
64 
65     info = qmp_query_name(NULL);
66     if (info->name) {
67         monitor_printf(mon, "%s\n", info->name);
68     }
69     qapi_free_NameInfo(info);
70 }
71 
72 void hmp_info_version(Monitor *mon, const QDict *qdict)
73 {
74     VersionInfo *info;
75 
76     info = qmp_query_version(NULL);
77 
78     monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
79                    info->qemu->major, info->qemu->minor, info->qemu->micro,
80                    info->package);
81 
82     qapi_free_VersionInfo(info);
83 }
84 
85 void hmp_quit(Monitor *mon, const QDict *qdict)
86 {
87     monitor_suspend(mon);
88     qmp_quit(NULL);
89 }
90 
91 void hmp_stop(Monitor *mon, const QDict *qdict)
92 {
93     qmp_stop(NULL);
94 }
95 
96 void hmp_sync_profile(Monitor *mon, const QDict *qdict)
97 {
98     const char *op = qdict_get_try_str(qdict, "op");
99 
100     if (op == NULL) {
101         bool on = qsp_is_enabled();
102 
103         monitor_printf(mon, "sync-profile is %s\n", on ? "on" : "off");
104         return;
105     }
106     if (!strcmp(op, "on")) {
107         qsp_enable();
108     } else if (!strcmp(op, "off")) {
109         qsp_disable();
110     } else if (!strcmp(op, "reset")) {
111         qsp_reset();
112     } else {
113         Error *err = NULL;
114 
115         error_setg(&err, "invalid parameter '%s',"
116                    " expecting 'on', 'off', or 'reset'", op);
117         hmp_handle_error(mon, err);
118     }
119 }
120 
121 void hmp_exit_preconfig(Monitor *mon, const QDict *qdict)
122 {
123     Error *err = NULL;
124 
125     qmp_x_exit_preconfig(&err);
126     hmp_handle_error(mon, err);
127 }
128 
129 void hmp_cpu(Monitor *mon, const QDict *qdict)
130 {
131     int64_t cpu_index;
132 
133     /* XXX: drop the monitor_set_cpu() usage when all HMP commands that
134             use it are converted to the QAPI */
135     cpu_index = qdict_get_int(qdict, "index");
136     if (monitor_set_cpu(mon, cpu_index) < 0) {
137         monitor_printf(mon, "invalid CPU index\n");
138     }
139 }
140 
141 void hmp_cont(Monitor *mon, const QDict *qdict)
142 {
143     Error *err = NULL;
144 
145     qmp_cont(&err);
146     hmp_handle_error(mon, err);
147 }
148 
149 void hmp_change(Monitor *mon, const QDict *qdict)
150 {
151     const char *device = qdict_get_str(qdict, "device");
152     const char *target = qdict_get_str(qdict, "target");
153     const char *arg = qdict_get_try_str(qdict, "arg");
154     const char *read_only = qdict_get_try_str(qdict, "read-only-mode");
155     bool force = qdict_get_try_bool(qdict, "force", false);
156     Error *err = NULL;
157 
158 #ifdef CONFIG_VNC
159     if (strcmp(device, "vnc") == 0) {
160         hmp_change_vnc(mon, device, target, arg, read_only, force, &err);
161     } else
162 #endif
163     {
164         hmp_change_medium(mon, device, target, arg, read_only, force, &err);
165     }
166 
167     hmp_handle_error(mon, err);
168 }
169 
170 #ifdef CONFIG_POSIX
171 void hmp_getfd(Monitor *mon, const QDict *qdict)
172 {
173     const char *fdname = qdict_get_str(qdict, "fdname");
174     Error *err = NULL;
175 
176     qmp_getfd(fdname, &err);
177     hmp_handle_error(mon, err);
178 }
179 #endif
180 
181 void hmp_closefd(Monitor *mon, const QDict *qdict)
182 {
183     const char *fdname = qdict_get_str(qdict, "fdname");
184     Error *err = NULL;
185 
186     qmp_closefd(fdname, &err);
187     hmp_handle_error(mon, err);
188 }
189 
190 void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
191 {
192     IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
193     IOThreadInfoList *info;
194     IOThreadInfo *value;
195 
196     for (info = info_list; info; info = info->next) {
197         value = info->value;
198         monitor_printf(mon, "%s:\n", value->id);
199         monitor_printf(mon, "  thread_id=%" PRId64 "\n", value->thread_id);
200         monitor_printf(mon, "  poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
201         monitor_printf(mon, "  poll-grow=%" PRId64 "\n", value->poll_grow);
202         monitor_printf(mon, "  poll-shrink=%" PRId64 "\n", value->poll_shrink);
203         monitor_printf(mon, "  aio-max-batch=%" PRId64 "\n",
204                        value->aio_max_batch);
205     }
206 
207     qapi_free_IOThreadInfoList(info_list);
208 }
209 
210 void hmp_help(Monitor *mon, const QDict *qdict)
211 {
212     hmp_help_cmd(mon, qdict_get_try_str(qdict, "name"));
213 }
214 
215 void hmp_info_help(Monitor *mon, const QDict *qdict)
216 {
217     hmp_help_cmd(mon, "info");
218 }
219 
220 void hmp_info_sync_profile(Monitor *mon, const QDict *qdict)
221 {
222     int64_t max = qdict_get_try_int(qdict, "max", 10);
223     bool mean = qdict_get_try_bool(qdict, "mean", false);
224     bool coalesce = !qdict_get_try_bool(qdict, "no_coalesce", false);
225     enum QSPSortBy sort_by;
226 
227     sort_by = mean ? QSP_SORT_BY_AVG_WAIT_TIME : QSP_SORT_BY_TOTAL_WAIT_TIME;
228     qsp_report(max, sort_by, coalesce);
229 }
230 
231 void hmp_info_history(Monitor *mon, const QDict *qdict)
232 {
233     MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
234     int i;
235     const char *str;
236 
237     if (!hmp_mon->rs) {
238         return;
239     }
240     i = 0;
241     for(;;) {
242         str = readline_get_history(hmp_mon->rs, i);
243         if (!str) {
244             break;
245         }
246         monitor_printf(mon, "%d: '%s'\n", i, str);
247         i++;
248     }
249 }
250 
251 void hmp_logfile(Monitor *mon, const QDict *qdict)
252 {
253     Error *err = NULL;
254 
255     if (!qemu_set_log_filename(qdict_get_str(qdict, "filename"), &err)) {
256         error_report_err(err);
257     }
258 }
259 
260 void hmp_log(Monitor *mon, const QDict *qdict)
261 {
262     int mask;
263     const char *items = qdict_get_str(qdict, "items");
264     Error *err = NULL;
265 
266     if (!strcmp(items, "none")) {
267         mask = 0;
268     } else {
269         mask = qemu_str_to_log_mask(items);
270         if (!mask) {
271             hmp_help_cmd(mon, "log");
272             return;
273         }
274     }
275 
276     if (!qemu_set_log(mask, &err)) {
277         error_report_err(err);
278     }
279 }
280 
281 void hmp_gdbserver(Monitor *mon, const QDict *qdict)
282 {
283     const char *device = qdict_get_try_str(qdict, "device");
284     if (!device) {
285         device = "tcp::" DEFAULT_GDBSTUB_PORT;
286     }
287 
288     if (gdbserver_start(device) < 0) {
289         monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
290                        device);
291     } else if (strcmp(device, "none") == 0) {
292         monitor_printf(mon, "Disabled gdbserver\n");
293     } else {
294         monitor_printf(mon, "Waiting for gdb connection on device '%s'\n",
295                        device);
296     }
297 }
298 
299 void hmp_print(Monitor *mon, const QDict *qdict)
300 {
301     int format = qdict_get_int(qdict, "format");
302     hwaddr val = qdict_get_int(qdict, "val");
303 
304     switch(format) {
305     case 'o':
306         monitor_printf(mon, "%#" HWADDR_PRIo, val);
307         break;
308     case 'x':
309         monitor_printf(mon, "%#" HWADDR_PRIx, val);
310         break;
311     case 'u':
312         monitor_printf(mon, "%" HWADDR_PRIu, val);
313         break;
314     default:
315     case 'd':
316         monitor_printf(mon, "%" HWADDR_PRId, val);
317         break;
318     case 'c':
319         monitor_printc(mon, val);
320         break;
321     }
322     monitor_printf(mon, "\n");
323 }
324 
325 void hmp_sum(Monitor *mon, const QDict *qdict)
326 {
327     uint32_t addr;
328     uint16_t sum;
329     uint32_t start = qdict_get_int(qdict, "start");
330     uint32_t size = qdict_get_int(qdict, "size");
331 
332     sum = 0;
333     for(addr = start; addr < (start + size); addr++) {
334         uint8_t val = address_space_ldub(&address_space_memory, addr,
335                                          MEMTXATTRS_UNSPECIFIED, NULL);
336         /* BSD sum algorithm ('sum' Unix command) */
337         sum = (sum >> 1) | (sum << 15);
338         sum += val;
339     }
340     monitor_printf(mon, "%05d\n", sum);
341 }
342 
343 void hmp_ioport_read(Monitor *mon, const QDict *qdict)
344 {
345     int size = qdict_get_int(qdict, "size");
346     int addr = qdict_get_int(qdict, "addr");
347     int has_index = qdict_haskey(qdict, "index");
348     uint32_t val;
349     int suffix;
350 
351     if (has_index) {
352         int index = qdict_get_int(qdict, "index");
353         cpu_outb(addr & IOPORTS_MASK, index & 0xff);
354         addr++;
355     }
356     addr &= 0xffff;
357 
358     switch(size) {
359     default:
360     case 1:
361         val = cpu_inb(addr);
362         suffix = 'b';
363         break;
364     case 2:
365         val = cpu_inw(addr);
366         suffix = 'w';
367         break;
368     case 4:
369         val = cpu_inl(addr);
370         suffix = 'l';
371         break;
372     }
373     monitor_printf(mon, "port%c[0x%04x] = 0x%0*x\n",
374                    suffix, addr, size * 2, val);
375 }
376 
377 void hmp_ioport_write(Monitor *mon, const QDict *qdict)
378 {
379     int size = qdict_get_int(qdict, "size");
380     int addr = qdict_get_int(qdict, "addr");
381     int val = qdict_get_int(qdict, "val");
382 
383     addr &= IOPORTS_MASK;
384 
385     switch (size) {
386     default:
387     case 1:
388         cpu_outb(addr, val);
389         break;
390     case 2:
391         cpu_outw(addr, val);
392         break;
393     case 4:
394         cpu_outl(addr, val);
395         break;
396     }
397 }
398 
399 void hmp_boot_set(Monitor *mon, const QDict *qdict)
400 {
401     Error *local_err = NULL;
402     const char *bootdevice = qdict_get_str(qdict, "bootdevice");
403 
404     qemu_boot_set(bootdevice, &local_err);
405     if (local_err) {
406         error_report_err(local_err);
407     } else {
408         monitor_printf(mon, "boot device list now set to %s\n", bootdevice);
409     }
410 }
411 
412 void hmp_info_mtree(Monitor *mon, const QDict *qdict)
413 {
414     bool flatview = qdict_get_try_bool(qdict, "flatview", false);
415     bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false);
416     bool owner = qdict_get_try_bool(qdict, "owner", false);
417     bool disabled = qdict_get_try_bool(qdict, "disabled", false);
418 
419     mtree_info(flatview, dispatch_tree, owner, disabled);
420 }
421 
422 #if defined(CONFIG_FDT)
423 void hmp_dumpdtb(Monitor *mon, const QDict *qdict)
424 {
425     const char *filename = qdict_get_str(qdict, "filename");
426     Error *local_err = NULL;
427 
428     qmp_dumpdtb(filename, &local_err);
429 
430     if (hmp_handle_error(mon, local_err)) {
431         return;
432     }
433 
434     monitor_printf(mon, "dtb dumped to %s", filename);
435 }
436 #endif
437