1 /* 2 * QMP commands related to machines and CPUs 3 * 4 * Copyright (C) 2014 Red Hat Inc 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 #include "hw/acpi/vmgenid.h" 12 #include "hw/boards.h" 13 #include "hw/intc/intc.h" 14 #include "hw/mem/memory-device.h" 15 #include "qapi/error.h" 16 #include "qapi/qapi-builtin-visit.h" 17 #include "qapi/qapi-commands-accelerator.h" 18 #include "qapi/qapi-commands-machine.h" 19 #include "qobject/qobject.h" 20 #include "qapi/qobject-input-visitor.h" 21 #include "qapi/type-helpers.h" 22 #include "qemu/uuid.h" 23 #include "qemu/target-info.h" 24 #include "qom/qom-qobject.h" 25 #include "system/hostmem.h" 26 #include "system/hw_accel.h" 27 #include "system/numa.h" 28 #include "system/runstate.h" 29 #include "system/system.h" 30 #include "hw/s390x/storage-keys.h" 31 32 /* 33 * fast means: we NEVER interrupt vCPU threads to retrieve 34 * information from KVM. 35 */ 36 CpuInfoFastList *qmp_query_cpus_fast(Error **errp) 37 { 38 MachineState *ms = MACHINE(qdev_get_machine()); 39 MachineClass *mc = MACHINE_GET_CLASS(ms); 40 CpuInfoFastList *head = NULL, **tail = &head; 41 SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), 42 -1, &error_abort); 43 CPUState *cpu; 44 45 CPU_FOREACH(cpu) { 46 CpuInfoFast *value = g_malloc0(sizeof(*value)); 47 48 value->cpu_index = cpu->cpu_index; 49 value->qom_path = object_get_canonical_path(OBJECT(cpu)); 50 value->thread_id = cpu->thread_id; 51 value->qom_type = g_strdup(object_get_typename(OBJECT(cpu))); 52 53 if (mc->cpu_index_to_instance_props) { 54 CpuInstanceProperties *props; 55 props = g_malloc0(sizeof(*props)); 56 *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index); 57 value->props = props; 58 } 59 60 value->target = target; 61 if (cpu->cc->query_cpu_fast) { 62 cpu->cc->query_cpu_fast(cpu, value); 63 } 64 65 QAPI_LIST_APPEND(tail, value); 66 } 67 68 return head; 69 } 70 71 MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props, 72 Error **errp) 73 { 74 GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); 75 MachineInfoList *mach_list = NULL; 76 77 for (el = machines; el; el = el->next) { 78 MachineClass *mc = el->data; 79 const char *default_cpu_type = machine_class_default_cpu_type(mc); 80 MachineInfo *info; 81 82 info = g_malloc0(sizeof(*info)); 83 if (mc->is_default) { 84 info->has_is_default = true; 85 info->is_default = true; 86 } 87 88 if (mc->alias) { 89 info->alias = g_strdup(mc->alias); 90 } 91 92 info->name = g_strdup(mc->name); 93 info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus; 94 info->hotpluggable_cpus = mc->has_hotpluggable_cpus; 95 info->numa_mem_supported = mc->numa_mem_supported; 96 info->deprecated = !!mc->deprecation_reason; 97 info->acpi = !!object_class_property_find(OBJECT_CLASS(mc), "acpi"); 98 if (default_cpu_type) { 99 info->default_cpu_type = g_strdup(default_cpu_type); 100 } 101 if (mc->default_ram_id) { 102 info->default_ram_id = g_strdup(mc->default_ram_id); 103 } 104 105 if (compat_props && mc->compat_props) { 106 int i; 107 info->compat_props = NULL; 108 CompatPropertyList **tail = &(info->compat_props); 109 info->has_compat_props = true; 110 111 for (i = 0; i < mc->compat_props->len; i++) { 112 GlobalProperty *mt_prop = g_ptr_array_index(mc->compat_props, 113 i); 114 CompatProperty *prop; 115 116 prop = g_malloc0(sizeof(*prop)); 117 prop->qom_type = g_strdup(mt_prop->driver); 118 prop->property = g_strdup(mt_prop->property); 119 prop->value = g_strdup(mt_prop->value); 120 121 QAPI_LIST_APPEND(tail, prop); 122 } 123 } 124 125 QAPI_LIST_PREPEND(mach_list, info); 126 } 127 128 g_slist_free(machines); 129 return mach_list; 130 } 131 132 CurrentMachineParams *qmp_query_current_machine(Error **errp) 133 { 134 CurrentMachineParams *params = g_malloc0(sizeof(*params)); 135 params->wakeup_suspend_support = qemu_wakeup_suspend_enabled(); 136 137 return params; 138 } 139 140 QemuTargetInfo *qmp_query_target(Error **errp) 141 { 142 QemuTargetInfo *info = g_malloc0(sizeof(*info)); 143 144 info->arch = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1, 145 &error_abort); 146 147 return info; 148 } 149 150 HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp) 151 { 152 MachineState *ms = MACHINE(qdev_get_machine()); 153 MachineClass *mc = MACHINE_GET_CLASS(ms); 154 155 if (!mc->has_hotpluggable_cpus) { 156 error_setg(errp, "machine does not support hot-plugging CPUs"); 157 return NULL; 158 } 159 160 return machine_query_hotpluggable_cpus(ms); 161 } 162 163 void qmp_set_numa_node(NumaOptions *cmd, Error **errp) 164 { 165 if (phase_check(PHASE_MACHINE_INITIALIZED)) { 166 error_setg(errp, "The command is permitted only before the machine has been created"); 167 return; 168 } 169 170 set_numa_options(MACHINE(qdev_get_machine()), cmd, errp); 171 } 172 173 static int query_memdev(Object *obj, void *opaque) 174 { 175 Error *err = NULL; 176 MemdevList **list = opaque; 177 Memdev *m; 178 QObject *host_nodes; 179 Visitor *v; 180 181 if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) { 182 m = g_malloc0(sizeof(*m)); 183 184 m->id = g_strdup(object_get_canonical_path_component(obj)); 185 186 m->size = object_property_get_uint(obj, "size", &error_abort); 187 m->merge = object_property_get_bool(obj, "merge", &error_abort); 188 m->dump = object_property_get_bool(obj, "dump", &error_abort); 189 m->prealloc = object_property_get_bool(obj, "prealloc", &error_abort); 190 m->share = object_property_get_bool(obj, "share", &error_abort); 191 m->reserve = object_property_get_bool(obj, "reserve", &err); 192 if (err) { 193 error_free_or_abort(&err); 194 } else { 195 m->has_reserve = true; 196 } 197 m->policy = object_property_get_enum(obj, "policy", "HostMemPolicy", 198 &error_abort); 199 host_nodes = object_property_get_qobject(obj, 200 "host-nodes", 201 &error_abort); 202 v = qobject_input_visitor_new(host_nodes); 203 visit_type_uint16List(v, NULL, &m->host_nodes, &error_abort); 204 visit_free(v); 205 qobject_unref(host_nodes); 206 207 QAPI_LIST_PREPEND(*list, m); 208 } 209 210 return 0; 211 } 212 213 MemdevList *qmp_query_memdev(Error **errp) 214 { 215 Object *obj = object_get_objects_root(); 216 MemdevList *list = NULL; 217 218 object_child_foreach(obj, query_memdev, &list); 219 return list; 220 } 221 222 HumanReadableText *qmp_x_query_numa(Error **errp) 223 { 224 g_autoptr(GString) buf = g_string_new(""); 225 int i, nb_numa_nodes; 226 NumaNodeMem *node_mem; 227 CpuInfoFastList *cpu_list, *cpu; 228 MachineState *ms = MACHINE(qdev_get_machine()); 229 230 nb_numa_nodes = ms->numa_state ? ms->numa_state->num_nodes : 0; 231 g_string_append_printf(buf, "%d nodes\n", nb_numa_nodes); 232 if (!nb_numa_nodes) { 233 goto done; 234 } 235 236 cpu_list = qmp_query_cpus_fast(&error_abort); 237 node_mem = g_new0(NumaNodeMem, nb_numa_nodes); 238 239 query_numa_node_mem(node_mem, ms); 240 for (i = 0; i < nb_numa_nodes; i++) { 241 g_string_append_printf(buf, "node %d cpus:", i); 242 for (cpu = cpu_list; cpu; cpu = cpu->next) { 243 if (cpu->value->props && cpu->value->props->has_node_id && 244 cpu->value->props->node_id == i) { 245 g_string_append_printf(buf, " %" PRIi64, cpu->value->cpu_index); 246 } 247 } 248 g_string_append_printf(buf, "\n"); 249 g_string_append_printf(buf, "node %d size: %" PRId64 " MB\n", i, 250 node_mem[i].node_mem >> 20); 251 g_string_append_printf(buf, "node %d plugged: %" PRId64 " MB\n", i, 252 node_mem[i].node_plugged_mem >> 20); 253 } 254 qapi_free_CpuInfoFastList(cpu_list); 255 g_free(node_mem); 256 257 done: 258 return human_readable_text_from_str(buf); 259 } 260 261 KvmInfo *qmp_query_kvm(Error **errp) 262 { 263 KvmInfo *info = g_malloc0(sizeof(*info)); 264 265 info->enabled = kvm_enabled(); 266 info->present = accel_find("kvm"); 267 268 return info; 269 } 270 271 UuidInfo *qmp_query_uuid(Error **errp) 272 { 273 UuidInfo *info = g_malloc0(sizeof(*info)); 274 275 info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid); 276 return info; 277 } 278 279 void qmp_system_reset(Error **errp) 280 { 281 qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET); 282 } 283 284 void qmp_system_powerdown(Error **errp) 285 { 286 qemu_system_powerdown_request(); 287 } 288 289 void qmp_system_wakeup(Error **errp) 290 { 291 if (!qemu_wakeup_suspend_enabled()) { 292 error_setg(errp, 293 "wake-up from suspend is not supported by this guest"); 294 return; 295 } 296 297 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp); 298 } 299 300 MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp) 301 { 302 return qmp_memory_device_list(); 303 } 304 305 MemoryInfo *qmp_query_memory_size_summary(Error **errp) 306 { 307 MemoryInfo *mem_info = g_new0(MemoryInfo, 1); 308 MachineState *ms = MACHINE(qdev_get_machine()); 309 310 mem_info->base_memory = ms->ram_size; 311 312 mem_info->plugged_memory = get_plugged_memory_size(); 313 mem_info->has_plugged_memory = 314 mem_info->plugged_memory != (uint64_t)-1; 315 316 return mem_info; 317 } 318 319 HumanReadableText *qmp_x_query_ramblock(Error **errp) 320 { 321 g_autoptr(GString) buf = ram_block_format(); 322 323 return human_readable_text_from_str(buf); 324 } 325 326 static int qmp_x_query_irq_foreach(Object *obj, void *opaque) 327 { 328 InterruptStatsProvider *intc; 329 InterruptStatsProviderClass *k; 330 GString *buf = opaque; 331 332 if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) { 333 intc = INTERRUPT_STATS_PROVIDER(obj); 334 k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj); 335 uint64_t *irq_counts; 336 unsigned int nb_irqs, i; 337 if (k->get_statistics && 338 k->get_statistics(intc, &irq_counts, &nb_irqs)) { 339 if (nb_irqs > 0) { 340 g_string_append_printf(buf, "IRQ statistics for %s:\n", 341 object_get_typename(obj)); 342 for (i = 0; i < nb_irqs; i++) { 343 if (irq_counts[i] > 0) { 344 g_string_append_printf(buf, "%2d: %" PRId64 "\n", i, 345 irq_counts[i]); 346 } 347 } 348 } 349 } else { 350 g_string_append_printf(buf, 351 "IRQ statistics not available for %s.\n", 352 object_get_typename(obj)); 353 } 354 } 355 356 return 0; 357 } 358 359 HumanReadableText *qmp_x_query_irq(Error **errp) 360 { 361 g_autoptr(GString) buf = g_string_new(""); 362 363 object_child_foreach_recursive(object_get_root(), 364 qmp_x_query_irq_foreach, buf); 365 366 return human_readable_text_from_str(buf); 367 } 368 369 static int qmp_x_query_intc_foreach(Object *obj, void *opaque) 370 { 371 InterruptStatsProvider *intc; 372 InterruptStatsProviderClass *k; 373 GString *buf = opaque; 374 375 if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) { 376 intc = INTERRUPT_STATS_PROVIDER(obj); 377 k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj); 378 if (k->print_info) { 379 k->print_info(intc, buf); 380 } else { 381 g_string_append_printf(buf, 382 "Interrupt controller information not available for %s.\n", 383 object_get_typename(obj)); 384 } 385 } 386 387 return 0; 388 } 389 390 HumanReadableText *qmp_x_query_interrupt_controllers(Error **errp) 391 { 392 g_autoptr(GString) buf = g_string_new(""); 393 object_child_foreach_recursive(object_get_root(), 394 qmp_x_query_intc_foreach, buf); 395 return human_readable_text_from_str(buf); 396 } 397 398 GuidInfo *qmp_query_vm_generation_id(Error **errp) 399 { 400 GuidInfo *info; 401 VmGenIdState *vms; 402 Object *obj = find_vmgenid_dev(); 403 404 if (!obj) { 405 error_setg(errp, "VM Generation ID device not found"); 406 return NULL; 407 } 408 vms = VMGENID(obj); 409 410 info = g_malloc0(sizeof(*info)); 411 info->guid = qemu_uuid_unparse_strdup(&vms->guid); 412 return info; 413 } 414 415 void qmp_dump_skeys(const char *filename, Error **errp) 416 { 417 ObjectClass *mc = object_get_class(qdev_get_machine()); 418 ObjectClass *oc = object_class_dynamic_cast(mc, TYPE_DUMP_SKEYS_INTERFACE); 419 420 if (!oc) { 421 error_setg(errp, "Storage keys information not available" 422 " for this architecture"); 423 return; 424 } 425 DUMP_SKEYS_INTERFACE_CLASS(oc)->qmp_dump_skeys(filename, errp); 426 } 427