mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00

In hmp_dumpdtb(), we print a message when the command succeeds. This message is missing the trailing \n, so the HMP command prompt is printed immediately after it. We also weren't capitalizing 'DTB', or quoting the filename in the message. Fix these nits. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20250206151214.2947842-2-peter.maydell@linaro.org
436 lines
11 KiB
C
436 lines
11 KiB
C
/*
|
|
* Human Monitor Interface commands
|
|
*
|
|
* Copyright IBM, Corp. 2011
|
|
*
|
|
* Authors:
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
|
* the COPYING file in the top-level directory.
|
|
*
|
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
* GNU GPL, version 2 or (at your option) any later version.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "exec/address-spaces.h"
|
|
#include "exec/ioport.h"
|
|
#include "exec/gdbstub.h"
|
|
#include "gdbstub/enums.h"
|
|
#include "monitor/hmp.h"
|
|
#include "qemu/help_option.h"
|
|
#include "monitor/monitor-internal.h"
|
|
#include "qapi/error.h"
|
|
#include "qapi/qapi-commands-control.h"
|
|
#include "qapi/qapi-commands-machine.h"
|
|
#include "qapi/qapi-commands-misc.h"
|
|
#include "qobject/qdict.h"
|
|
#include "qemu/cutils.h"
|
|
#include "qemu/log.h"
|
|
#include "system/system.h"
|
|
|
|
bool hmp_handle_error(Monitor *mon, Error *err)
|
|
{
|
|
if (err) {
|
|
error_reportf_err(err, "Error: ");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Split @str at comma.
|
|
* A null @str defaults to "".
|
|
*/
|
|
strList *hmp_split_at_comma(const char *str)
|
|
{
|
|
char **split = g_strsplit(str ?: "", ",", -1);
|
|
strList *res = NULL;
|
|
strList **tail = &res;
|
|
int i;
|
|
|
|
for (i = 0; split[i]; i++) {
|
|
QAPI_LIST_APPEND(tail, split[i]);
|
|
}
|
|
|
|
g_free(split);
|
|
return res;
|
|
}
|
|
|
|
void hmp_info_name(Monitor *mon, const QDict *qdict)
|
|
{
|
|
NameInfo *info;
|
|
|
|
info = qmp_query_name(NULL);
|
|
if (info->name) {
|
|
monitor_printf(mon, "%s\n", info->name);
|
|
}
|
|
qapi_free_NameInfo(info);
|
|
}
|
|
|
|
void hmp_info_version(Monitor *mon, const QDict *qdict)
|
|
{
|
|
VersionInfo *info;
|
|
|
|
info = qmp_query_version(NULL);
|
|
|
|
monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
|
|
info->qemu->major, info->qemu->minor, info->qemu->micro,
|
|
info->package);
|
|
|
|
qapi_free_VersionInfo(info);
|
|
}
|
|
|
|
void hmp_quit(Monitor *mon, const QDict *qdict)
|
|
{
|
|
monitor_suspend(mon);
|
|
qmp_quit(NULL);
|
|
}
|
|
|
|
void hmp_stop(Monitor *mon, const QDict *qdict)
|
|
{
|
|
qmp_stop(NULL);
|
|
}
|
|
|
|
void hmp_sync_profile(Monitor *mon, const QDict *qdict)
|
|
{
|
|
const char *op = qdict_get_try_str(qdict, "op");
|
|
|
|
if (op == NULL) {
|
|
bool on = qsp_is_enabled();
|
|
|
|
monitor_printf(mon, "sync-profile is %s\n", on ? "on" : "off");
|
|
return;
|
|
}
|
|
if (!strcmp(op, "on")) {
|
|
qsp_enable();
|
|
} else if (!strcmp(op, "off")) {
|
|
qsp_disable();
|
|
} else if (!strcmp(op, "reset")) {
|
|
qsp_reset();
|
|
} else {
|
|
Error *err = NULL;
|
|
|
|
error_setg(&err, "invalid parameter '%s',"
|
|
" expecting 'on', 'off', or 'reset'", op);
|
|
hmp_handle_error(mon, err);
|
|
}
|
|
}
|
|
|
|
void hmp_exit_preconfig(Monitor *mon, const QDict *qdict)
|
|
{
|
|
Error *err = NULL;
|
|
|
|
qmp_x_exit_preconfig(&err);
|
|
hmp_handle_error(mon, err);
|
|
}
|
|
|
|
void hmp_cpu(Monitor *mon, const QDict *qdict)
|
|
{
|
|
int64_t cpu_index;
|
|
|
|
/* XXX: drop the monitor_set_cpu() usage when all HMP commands that
|
|
use it are converted to the QAPI */
|
|
cpu_index = qdict_get_int(qdict, "index");
|
|
if (monitor_set_cpu(mon, cpu_index) < 0) {
|
|
monitor_printf(mon, "invalid CPU index\n");
|
|
}
|
|
}
|
|
|
|
void hmp_cont(Monitor *mon, const QDict *qdict)
|
|
{
|
|
Error *err = NULL;
|
|
|
|
qmp_cont(&err);
|
|
hmp_handle_error(mon, err);
|
|
}
|
|
|
|
void hmp_change(Monitor *mon, const QDict *qdict)
|
|
{
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
const char *target = qdict_get_str(qdict, "target");
|
|
const char *arg = qdict_get_try_str(qdict, "arg");
|
|
const char *read_only = qdict_get_try_str(qdict, "read-only-mode");
|
|
bool force = qdict_get_try_bool(qdict, "force", false);
|
|
Error *err = NULL;
|
|
|
|
#ifdef CONFIG_VNC
|
|
if (strcmp(device, "vnc") == 0) {
|
|
hmp_change_vnc(mon, device, target, arg, read_only, force, &err);
|
|
} else
|
|
#endif
|
|
{
|
|
hmp_change_medium(mon, device, target, arg, read_only, force, &err);
|
|
}
|
|
|
|
hmp_handle_error(mon, err);
|
|
}
|
|
|
|
#ifdef CONFIG_POSIX
|
|
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
|
{
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
|
Error *err = NULL;
|
|
|
|
qmp_getfd(fdname, &err);
|
|
hmp_handle_error(mon, err);
|
|
}
|
|
#endif
|
|
|
|
void hmp_closefd(Monitor *mon, const QDict *qdict)
|
|
{
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
|
Error *err = NULL;
|
|
|
|
qmp_closefd(fdname, &err);
|
|
hmp_handle_error(mon, err);
|
|
}
|
|
|
|
void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
|
|
{
|
|
IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
|
|
IOThreadInfoList *info;
|
|
IOThreadInfo *value;
|
|
|
|
for (info = info_list; info; info = info->next) {
|
|
value = info->value;
|
|
monitor_printf(mon, "%s:\n", value->id);
|
|
monitor_printf(mon, " thread_id=%" PRId64 "\n", value->thread_id);
|
|
monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
|
|
monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow);
|
|
monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink);
|
|
monitor_printf(mon, " aio-max-batch=%" PRId64 "\n",
|
|
value->aio_max_batch);
|
|
}
|
|
|
|
qapi_free_IOThreadInfoList(info_list);
|
|
}
|
|
|
|
void hmp_help(Monitor *mon, const QDict *qdict)
|
|
{
|
|
hmp_help_cmd(mon, qdict_get_try_str(qdict, "name"));
|
|
}
|
|
|
|
void hmp_info_help(Monitor *mon, const QDict *qdict)
|
|
{
|
|
hmp_help_cmd(mon, "info");
|
|
}
|
|
|
|
void hmp_info_sync_profile(Monitor *mon, const QDict *qdict)
|
|
{
|
|
int64_t max = qdict_get_try_int(qdict, "max", 10);
|
|
bool mean = qdict_get_try_bool(qdict, "mean", false);
|
|
bool coalesce = !qdict_get_try_bool(qdict, "no_coalesce", false);
|
|
enum QSPSortBy sort_by;
|
|
|
|
sort_by = mean ? QSP_SORT_BY_AVG_WAIT_TIME : QSP_SORT_BY_TOTAL_WAIT_TIME;
|
|
qsp_report(max, sort_by, coalesce);
|
|
}
|
|
|
|
void hmp_info_history(Monitor *mon, const QDict *qdict)
|
|
{
|
|
MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
|
|
int i;
|
|
const char *str;
|
|
|
|
if (!hmp_mon->rs) {
|
|
return;
|
|
}
|
|
i = 0;
|
|
for(;;) {
|
|
str = readline_get_history(hmp_mon->rs, i);
|
|
if (!str) {
|
|
break;
|
|
}
|
|
monitor_printf(mon, "%d: '%s'\n", i, str);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void hmp_logfile(Monitor *mon, const QDict *qdict)
|
|
{
|
|
Error *err = NULL;
|
|
|
|
if (!qemu_set_log_filename(qdict_get_str(qdict, "filename"), &err)) {
|
|
error_report_err(err);
|
|
}
|
|
}
|
|
|
|
void hmp_log(Monitor *mon, const QDict *qdict)
|
|
{
|
|
int mask;
|
|
const char *items = qdict_get_str(qdict, "items");
|
|
Error *err = NULL;
|
|
|
|
if (!strcmp(items, "none")) {
|
|
mask = 0;
|
|
} else {
|
|
mask = qemu_str_to_log_mask(items);
|
|
if (!mask) {
|
|
hmp_help_cmd(mon, "log");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!qemu_set_log(mask, &err)) {
|
|
error_report_err(err);
|
|
}
|
|
}
|
|
|
|
void hmp_gdbserver(Monitor *mon, const QDict *qdict)
|
|
{
|
|
const char *device = qdict_get_try_str(qdict, "device");
|
|
if (!device) {
|
|
device = "tcp::" DEFAULT_GDBSTUB_PORT;
|
|
}
|
|
|
|
if (!gdbserver_start(device, &error_warn)) {
|
|
monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
|
|
device);
|
|
} else if (strcmp(device, "none") == 0) {
|
|
monitor_printf(mon, "Disabled gdbserver\n");
|
|
} else {
|
|
monitor_printf(mon, "Waiting for gdb connection on device '%s'\n",
|
|
device);
|
|
}
|
|
}
|
|
|
|
void hmp_print(Monitor *mon, const QDict *qdict)
|
|
{
|
|
int format = qdict_get_int(qdict, "format");
|
|
hwaddr val = qdict_get_int(qdict, "val");
|
|
|
|
switch(format) {
|
|
case 'o':
|
|
monitor_printf(mon, "%#" HWADDR_PRIo, val);
|
|
break;
|
|
case 'x':
|
|
monitor_printf(mon, "%#" HWADDR_PRIx, val);
|
|
break;
|
|
case 'u':
|
|
monitor_printf(mon, "%" HWADDR_PRIu, val);
|
|
break;
|
|
default:
|
|
case 'd':
|
|
monitor_printf(mon, "%" HWADDR_PRId, val);
|
|
break;
|
|
case 'c':
|
|
monitor_printc(mon, val);
|
|
break;
|
|
}
|
|
monitor_printf(mon, "\n");
|
|
}
|
|
|
|
void hmp_sum(Monitor *mon, const QDict *qdict)
|
|
{
|
|
uint32_t addr;
|
|
uint16_t sum;
|
|
uint32_t start = qdict_get_int(qdict, "start");
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
sum = 0;
|
|
for(addr = start; addr < (start + size); addr++) {
|
|
uint8_t val = address_space_ldub(&address_space_memory, addr,
|
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
|
/* BSD sum algorithm ('sum' Unix command) */
|
|
sum = (sum >> 1) | (sum << 15);
|
|
sum += val;
|
|
}
|
|
monitor_printf(mon, "%05d\n", sum);
|
|
}
|
|
|
|
void hmp_ioport_read(Monitor *mon, const QDict *qdict)
|
|
{
|
|
int size = qdict_get_int(qdict, "size");
|
|
int addr = qdict_get_int(qdict, "addr");
|
|
int has_index = qdict_haskey(qdict, "index");
|
|
uint32_t val;
|
|
int suffix;
|
|
|
|
if (has_index) {
|
|
int index = qdict_get_int(qdict, "index");
|
|
cpu_outb(addr & IOPORTS_MASK, index & 0xff);
|
|
addr++;
|
|
}
|
|
addr &= 0xffff;
|
|
|
|
switch(size) {
|
|
default:
|
|
case 1:
|
|
val = cpu_inb(addr);
|
|
suffix = 'b';
|
|
break;
|
|
case 2:
|
|
val = cpu_inw(addr);
|
|
suffix = 'w';
|
|
break;
|
|
case 4:
|
|
val = cpu_inl(addr);
|
|
suffix = 'l';
|
|
break;
|
|
}
|
|
monitor_printf(mon, "port%c[0x%04x] = 0x%0*x\n",
|
|
suffix, addr, size * 2, val);
|
|
}
|
|
|
|
void hmp_ioport_write(Monitor *mon, const QDict *qdict)
|
|
{
|
|
int size = qdict_get_int(qdict, "size");
|
|
int addr = qdict_get_int(qdict, "addr");
|
|
int val = qdict_get_int(qdict, "val");
|
|
|
|
addr &= IOPORTS_MASK;
|
|
|
|
switch (size) {
|
|
default:
|
|
case 1:
|
|
cpu_outb(addr, val);
|
|
break;
|
|
case 2:
|
|
cpu_outw(addr, val);
|
|
break;
|
|
case 4:
|
|
cpu_outl(addr, val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void hmp_boot_set(Monitor *mon, const QDict *qdict)
|
|
{
|
|
Error *local_err = NULL;
|
|
const char *bootdevice = qdict_get_str(qdict, "bootdevice");
|
|
|
|
qemu_boot_set(bootdevice, &local_err);
|
|
if (local_err) {
|
|
error_report_err(local_err);
|
|
} else {
|
|
monitor_printf(mon, "boot device list now set to %s\n", bootdevice);
|
|
}
|
|
}
|
|
|
|
void hmp_info_mtree(Monitor *mon, const QDict *qdict)
|
|
{
|
|
bool flatview = qdict_get_try_bool(qdict, "flatview", false);
|
|
bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false);
|
|
bool owner = qdict_get_try_bool(qdict, "owner", false);
|
|
bool disabled = qdict_get_try_bool(qdict, "disabled", false);
|
|
|
|
mtree_info(flatview, dispatch_tree, owner, disabled);
|
|
}
|
|
|
|
#if defined(CONFIG_FDT)
|
|
void hmp_dumpdtb(Monitor *mon, const QDict *qdict)
|
|
{
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
|
Error *local_err = NULL;
|
|
|
|
qmp_dumpdtb(filename, &local_err);
|
|
|
|
if (hmp_handle_error(mon, local_err)) {
|
|
return;
|
|
}
|
|
|
|
monitor_printf(mon, "DTB dumped to '%s'\n", filename);
|
|
}
|
|
#endif
|