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