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