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