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 "cpu.h" |
12 | #include "hw/boards.h" |
13 | #include "qapi/error.h" |
14 | #include "qapi/qapi-commands-machine.h" |
15 | #include "qapi/qmp/qerror.h" |
16 | #include "qemu/main-loop.h" |
17 | #include "sysemu/hostmem.h" |
18 | #include "sysemu/hw_accel.h" |
19 | #include "sysemu/numa.h" |
20 | #include "sysemu/runstate.h" |
21 | #include "sysemu/sysemu.h" |
22 | |
23 | CpuInfoList *qmp_query_cpus(Error **errp) |
24 | { |
25 | MachineState *ms = MACHINE(qdev_get_machine()); |
26 | MachineClass *mc = MACHINE_GET_CLASS(ms); |
27 | CpuInfoList *head = NULL, *cur_item = NULL; |
28 | CPUState *cpu; |
29 | |
30 | CPU_FOREACH(cpu) { |
31 | CpuInfoList *info; |
32 | #if defined(TARGET_I386) |
33 | X86CPU *x86_cpu = X86_CPU(cpu); |
34 | CPUX86State *env = &x86_cpu->env; |
35 | #elif defined(TARGET_PPC) |
36 | PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu); |
37 | CPUPPCState *env = &ppc_cpu->env; |
38 | #elif defined(TARGET_SPARC) |
39 | SPARCCPU *sparc_cpu = SPARC_CPU(cpu); |
40 | CPUSPARCState *env = &sparc_cpu->env; |
41 | #elif defined(TARGET_RISCV) |
42 | RISCVCPU *riscv_cpu = RISCV_CPU(cpu); |
43 | CPURISCVState *env = &riscv_cpu->env; |
44 | #elif defined(TARGET_MIPS) |
45 | MIPSCPU *mips_cpu = MIPS_CPU(cpu); |
46 | CPUMIPSState *env = &mips_cpu->env; |
47 | #elif defined(TARGET_TRICORE) |
48 | TriCoreCPU *tricore_cpu = TRICORE_CPU(cpu); |
49 | CPUTriCoreState *env = &tricore_cpu->env; |
50 | #elif defined(TARGET_S390X) |
51 | S390CPU *s390_cpu = S390_CPU(cpu); |
52 | CPUS390XState *env = &s390_cpu->env; |
53 | #endif |
54 | |
55 | cpu_synchronize_state(cpu); |
56 | |
57 | info = g_malloc0(sizeof(*info)); |
58 | info->value = g_malloc0(sizeof(*info->value)); |
59 | info->value->CPU = cpu->cpu_index; |
60 | info->value->current = (cpu == first_cpu); |
61 | info->value->halted = cpu->halted; |
62 | info->value->qom_path = object_get_canonical_path(OBJECT(cpu)); |
63 | info->value->thread_id = cpu->thread_id; |
64 | #if defined(TARGET_I386) |
65 | info->value->arch = CPU_INFO_ARCH_X86; |
66 | info->value->u.x86.pc = env->eip + env->segs[R_CS].base; |
67 | #elif defined(TARGET_PPC) |
68 | info->value->arch = CPU_INFO_ARCH_PPC; |
69 | info->value->u.ppc.nip = env->nip; |
70 | #elif defined(TARGET_SPARC) |
71 | info->value->arch = CPU_INFO_ARCH_SPARC; |
72 | info->value->u.q_sparc.pc = env->pc; |
73 | info->value->u.q_sparc.npc = env->npc; |
74 | #elif defined(TARGET_MIPS) |
75 | info->value->arch = CPU_INFO_ARCH_MIPS; |
76 | info->value->u.q_mips.PC = env->active_tc.PC; |
77 | #elif defined(TARGET_TRICORE) |
78 | info->value->arch = CPU_INFO_ARCH_TRICORE; |
79 | info->value->u.tricore.PC = env->PC; |
80 | #elif defined(TARGET_S390X) |
81 | info->value->arch = CPU_INFO_ARCH_S390; |
82 | info->value->u.s390.cpu_state = env->cpu_state; |
83 | #elif defined(TARGET_RISCV) |
84 | info->value->arch = CPU_INFO_ARCH_RISCV; |
85 | info->value->u.riscv.pc = env->pc; |
86 | #else |
87 | info->value->arch = CPU_INFO_ARCH_OTHER; |
88 | #endif |
89 | info->value->has_props = !!mc->cpu_index_to_instance_props; |
90 | if (info->value->has_props) { |
91 | CpuInstanceProperties *props; |
92 | props = g_malloc0(sizeof(*props)); |
93 | *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index); |
94 | info->value->props = props; |
95 | } |
96 | |
97 | /* XXX: waiting for the qapi to support GSList */ |
98 | if (!cur_item) { |
99 | head = cur_item = info; |
100 | } else { |
101 | cur_item->next = info; |
102 | cur_item = info; |
103 | } |
104 | } |
105 | |
106 | return head; |
107 | } |
108 | |
109 | static CpuInfoArch sysemu_target_to_cpuinfo_arch(SysEmuTarget target) |
110 | { |
111 | /* |
112 | * The @SysEmuTarget -> @CpuInfoArch mapping below is based on the |
113 | * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script. |
114 | */ |
115 | switch (target) { |
116 | case SYS_EMU_TARGET_I386: |
117 | case SYS_EMU_TARGET_X86_64: |
118 | return CPU_INFO_ARCH_X86; |
119 | |
120 | case SYS_EMU_TARGET_PPC: |
121 | case SYS_EMU_TARGET_PPC64: |
122 | return CPU_INFO_ARCH_PPC; |
123 | |
124 | case SYS_EMU_TARGET_SPARC: |
125 | case SYS_EMU_TARGET_SPARC64: |
126 | return CPU_INFO_ARCH_SPARC; |
127 | |
128 | case SYS_EMU_TARGET_MIPS: |
129 | case SYS_EMU_TARGET_MIPSEL: |
130 | case SYS_EMU_TARGET_MIPS64: |
131 | case SYS_EMU_TARGET_MIPS64EL: |
132 | return CPU_INFO_ARCH_MIPS; |
133 | |
134 | case SYS_EMU_TARGET_TRICORE: |
135 | return CPU_INFO_ARCH_TRICORE; |
136 | |
137 | case SYS_EMU_TARGET_S390X: |
138 | return CPU_INFO_ARCH_S390; |
139 | |
140 | case SYS_EMU_TARGET_RISCV32: |
141 | case SYS_EMU_TARGET_RISCV64: |
142 | return CPU_INFO_ARCH_RISCV; |
143 | |
144 | default: |
145 | return CPU_INFO_ARCH_OTHER; |
146 | } |
147 | } |
148 | |
149 | static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu) |
150 | { |
151 | #ifdef TARGET_S390X |
152 | S390CPU *s390_cpu = S390_CPU(cpu); |
153 | CPUS390XState *env = &s390_cpu->env; |
154 | |
155 | info->cpu_state = env->cpu_state; |
156 | #else |
157 | abort(); |
158 | #endif |
159 | } |
160 | |
161 | /* |
162 | * fast means: we NEVER interrupt vCPU threads to retrieve |
163 | * information from KVM. |
164 | */ |
165 | CpuInfoFastList *qmp_query_cpus_fast(Error **errp) |
166 | { |
167 | MachineState *ms = MACHINE(qdev_get_machine()); |
168 | MachineClass *mc = MACHINE_GET_CLASS(ms); |
169 | CpuInfoFastList *head = NULL, *cur_item = NULL; |
170 | SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME, |
171 | -1, &error_abort); |
172 | CPUState *cpu; |
173 | |
174 | CPU_FOREACH(cpu) { |
175 | CpuInfoFastList *info = g_malloc0(sizeof(*info)); |
176 | info->value = g_malloc0(sizeof(*info->value)); |
177 | |
178 | info->value->cpu_index = cpu->cpu_index; |
179 | info->value->qom_path = object_get_canonical_path(OBJECT(cpu)); |
180 | info->value->thread_id = cpu->thread_id; |
181 | |
182 | info->value->has_props = !!mc->cpu_index_to_instance_props; |
183 | if (info->value->has_props) { |
184 | CpuInstanceProperties *props; |
185 | props = g_malloc0(sizeof(*props)); |
186 | *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index); |
187 | info->value->props = props; |
188 | } |
189 | |
190 | info->value->arch = sysemu_target_to_cpuinfo_arch(target); |
191 | info->value->target = target; |
192 | if (target == SYS_EMU_TARGET_S390X) { |
193 | cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu); |
194 | } |
195 | |
196 | if (!cur_item) { |
197 | head = cur_item = info; |
198 | } else { |
199 | cur_item->next = info; |
200 | cur_item = info; |
201 | } |
202 | } |
203 | |
204 | return head; |
205 | } |
206 | |
207 | MachineInfoList *qmp_query_machines(Error **errp) |
208 | { |
209 | GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); |
210 | MachineInfoList *mach_list = NULL; |
211 | |
212 | for (el = machines; el; el = el->next) { |
213 | MachineClass *mc = el->data; |
214 | MachineInfoList *entry; |
215 | MachineInfo *info; |
216 | |
217 | info = g_malloc0(sizeof(*info)); |
218 | if (mc->is_default) { |
219 | info->has_is_default = true; |
220 | info->is_default = true; |
221 | } |
222 | |
223 | if (mc->alias) { |
224 | info->has_alias = true; |
225 | info->alias = g_strdup(mc->alias); |
226 | } |
227 | |
228 | info->name = g_strdup(mc->name); |
229 | info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus; |
230 | info->hotpluggable_cpus = mc->has_hotpluggable_cpus; |
231 | info->numa_mem_supported = mc->numa_mem_supported; |
232 | info->deprecated = !!mc->deprecation_reason; |
233 | if (mc->default_cpu_type) { |
234 | info->default_cpu_type = g_strdup(mc->default_cpu_type); |
235 | info->has_default_cpu_type = true; |
236 | } |
237 | |
238 | entry = g_malloc0(sizeof(*entry)); |
239 | entry->value = info; |
240 | entry->next = mach_list; |
241 | mach_list = entry; |
242 | } |
243 | |
244 | g_slist_free(machines); |
245 | return mach_list; |
246 | } |
247 | |
248 | CurrentMachineParams *qmp_query_current_machine(Error **errp) |
249 | { |
250 | CurrentMachineParams *params = g_malloc0(sizeof(*params)); |
251 | params->wakeup_suspend_support = qemu_wakeup_suspend_enabled(); |
252 | |
253 | return params; |
254 | } |
255 | |
256 | TargetInfo *qmp_query_target(Error **errp) |
257 | { |
258 | TargetInfo *info = g_malloc0(sizeof(*info)); |
259 | |
260 | info->arch = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME, -1, |
261 | &error_abort); |
262 | |
263 | return info; |
264 | } |
265 | |
266 | HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp) |
267 | { |
268 | MachineState *ms = MACHINE(qdev_get_machine()); |
269 | MachineClass *mc = MACHINE_GET_CLASS(ms); |
270 | |
271 | if (!mc->has_hotpluggable_cpus) { |
272 | error_setg(errp, QERR_FEATURE_DISABLED, "query-hotpluggable-cpus" ); |
273 | return NULL; |
274 | } |
275 | |
276 | return machine_query_hotpluggable_cpus(ms); |
277 | } |
278 | |
279 | void qmp_cpu_add(int64_t id, Error **errp) |
280 | { |
281 | MachineClass *mc; |
282 | |
283 | mc = MACHINE_GET_CLASS(current_machine); |
284 | if (mc->hot_add_cpu) { |
285 | mc->hot_add_cpu(current_machine, id, errp); |
286 | } else { |
287 | error_setg(errp, "Not supported" ); |
288 | } |
289 | } |
290 | |
291 | void qmp_set_numa_node(NumaOptions *cmd, Error **errp) |
292 | { |
293 | if (!runstate_check(RUN_STATE_PRECONFIG)) { |
294 | error_setg(errp, "The command is permitted only in '%s' state" , |
295 | RunState_str(RUN_STATE_PRECONFIG)); |
296 | return; |
297 | } |
298 | |
299 | set_numa_options(MACHINE(qdev_get_machine()), cmd, errp); |
300 | } |
301 | |
302 | static int query_memdev(Object *obj, void *opaque) |
303 | { |
304 | MemdevList **list = opaque; |
305 | MemdevList *m = NULL; |
306 | |
307 | if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) { |
308 | m = g_malloc0(sizeof(*m)); |
309 | |
310 | m->value = g_malloc0(sizeof(*m->value)); |
311 | |
312 | m->value->id = object_get_canonical_path_component(obj); |
313 | m->value->has_id = !!m->value->id; |
314 | |
315 | m->value->size = object_property_get_uint(obj, "size" , |
316 | &error_abort); |
317 | m->value->merge = object_property_get_bool(obj, "merge" , |
318 | &error_abort); |
319 | m->value->dump = object_property_get_bool(obj, "dump" , |
320 | &error_abort); |
321 | m->value->prealloc = object_property_get_bool(obj, |
322 | "prealloc" , |
323 | &error_abort); |
324 | m->value->policy = object_property_get_enum(obj, |
325 | "policy" , |
326 | "HostMemPolicy" , |
327 | &error_abort); |
328 | object_property_get_uint16List(obj, "host-nodes" , |
329 | &m->value->host_nodes, |
330 | &error_abort); |
331 | |
332 | m->next = *list; |
333 | *list = m; |
334 | } |
335 | |
336 | return 0; |
337 | } |
338 | |
339 | MemdevList *qmp_query_memdev(Error **errp) |
340 | { |
341 | Object *obj = object_get_objects_root(); |
342 | MemdevList *list = NULL; |
343 | |
344 | object_child_foreach(obj, query_memdev, &list); |
345 | return list; |
346 | } |
347 | |