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