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