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