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