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