xref: /openbmc/qemu/hw/i386/x86.c (revision 0fd05c8d)
1 /*
2  * Copyright (c) 2003-2004 Fabrice Bellard
3  * Copyright (c) 2019 Red Hat, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21  * THE SOFTWARE.
22  */
23 #include "qemu/osdep.h"
24 #include "qemu/error-report.h"
25 #include "qemu/units.h"
26 #include "qapi/error.h"
27 #include "qapi/qapi-visit-common.h"
28 #include "qapi/qapi-visit-machine.h"
29 #include "qapi/visitor.h"
30 #include "sysemu/qtest.h"
31 #include "sysemu/numa.h"
32 #include "trace.h"
33 
34 #include "hw/acpi/aml-build.h"
35 #include "hw/i386/x86.h"
36 #include "hw/i386/topology.h"
37 
38 #include "hw/nmi.h"
39 #include "kvm/kvm_i386.h"
40 
41 
42 void init_topo_info(X86CPUTopoInfo *topo_info,
43                     const X86MachineState *x86ms)
44 {
45     MachineState *ms = MACHINE(x86ms);
46 
47     topo_info->dies_per_pkg = ms->smp.dies;
48     /*
49      * Though smp.modules means the number of modules in one cluster,
50      * i386 doesn't support cluster level so that the smp.clusters
51      * always defaults to 1, therefore using smp.modules directly is
52      * fine here.
53      */
54     topo_info->modules_per_die = ms->smp.modules;
55     topo_info->cores_per_module = ms->smp.cores;
56     topo_info->threads_per_core = ms->smp.threads;
57 }
58 
59 /*
60  * Calculates initial APIC ID for a specific CPU index
61  *
62  * Currently we need to be able to calculate the APIC ID from the CPU index
63  * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have
64  * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of
65  * all CPUs up to max_cpus.
66  */
67 uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms,
68                                     unsigned int cpu_index)
69 {
70     X86CPUTopoInfo topo_info;
71 
72     init_topo_info(&topo_info, x86ms);
73 
74     return x86_apicid_from_cpu_idx(&topo_info, cpu_index);
75 }
76 
77 static CpuInstanceProperties
78 x86_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
79 {
80     MachineClass *mc = MACHINE_GET_CLASS(ms);
81     const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
82 
83     assert(cpu_index < possible_cpus->len);
84     return possible_cpus->cpus[cpu_index].props;
85 }
86 
87 static int64_t x86_get_default_cpu_node_id(const MachineState *ms, int idx)
88 {
89    X86CPUTopoIDs topo_ids;
90    X86MachineState *x86ms = X86_MACHINE(ms);
91    X86CPUTopoInfo topo_info;
92 
93    init_topo_info(&topo_info, x86ms);
94 
95    assert(idx < ms->possible_cpus->len);
96    x86_topo_ids_from_apicid(ms->possible_cpus->cpus[idx].arch_id,
97                             &topo_info, &topo_ids);
98    return topo_ids.pkg_id % ms->numa_state->num_nodes;
99 }
100 
101 static const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms)
102 {
103     X86MachineState *x86ms = X86_MACHINE(ms);
104     unsigned int max_cpus = ms->smp.max_cpus;
105     X86CPUTopoInfo topo_info;
106     int i;
107 
108     if (ms->possible_cpus) {
109         /*
110          * make sure that max_cpus hasn't changed since the first use, i.e.
111          * -smp hasn't been parsed after it
112          */
113         assert(ms->possible_cpus->len == max_cpus);
114         return ms->possible_cpus;
115     }
116 
117     ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
118                                   sizeof(CPUArchId) * max_cpus);
119     ms->possible_cpus->len = max_cpus;
120 
121     init_topo_info(&topo_info, x86ms);
122 
123     for (i = 0; i < ms->possible_cpus->len; i++) {
124         X86CPUTopoIDs topo_ids;
125 
126         ms->possible_cpus->cpus[i].type = ms->cpu_type;
127         ms->possible_cpus->cpus[i].vcpus_count = 1;
128         ms->possible_cpus->cpus[i].arch_id =
129             x86_cpu_apic_id_from_index(x86ms, i);
130         x86_topo_ids_from_apicid(ms->possible_cpus->cpus[i].arch_id,
131                                  &topo_info, &topo_ids);
132         ms->possible_cpus->cpus[i].props.has_socket_id = true;
133         ms->possible_cpus->cpus[i].props.socket_id = topo_ids.pkg_id;
134         if (ms->smp.dies > 1) {
135             ms->possible_cpus->cpus[i].props.has_die_id = true;
136             ms->possible_cpus->cpus[i].props.die_id = topo_ids.die_id;
137         }
138         if (ms->smp.modules > 1) {
139             ms->possible_cpus->cpus[i].props.has_module_id = true;
140             ms->possible_cpus->cpus[i].props.module_id = topo_ids.module_id;
141         }
142         ms->possible_cpus->cpus[i].props.has_core_id = true;
143         ms->possible_cpus->cpus[i].props.core_id = topo_ids.core_id;
144         ms->possible_cpus->cpus[i].props.has_thread_id = true;
145         ms->possible_cpus->cpus[i].props.thread_id = topo_ids.smt_id;
146     }
147     return ms->possible_cpus;
148 }
149 
150 static void x86_nmi(NMIState *n, int cpu_index, Error **errp)
151 {
152     /* cpu index isn't used */
153     CPUState *cs;
154 
155     CPU_FOREACH(cs) {
156         X86CPU *cpu = X86_CPU(cs);
157 
158         if (cpu_is_apic_enabled(cpu->apic_state)) {
159             apic_deliver_nmi(cpu->apic_state);
160         } else {
161             cpu_interrupt(cs, CPU_INTERRUPT_NMI);
162         }
163     }
164 }
165 
166 bool x86_machine_is_smm_enabled(const X86MachineState *x86ms)
167 {
168     bool smm_available = false;
169 
170     if (x86ms->smm == ON_OFF_AUTO_OFF) {
171         return false;
172     }
173 
174     if (tcg_enabled() || qtest_enabled()) {
175         smm_available = true;
176     } else if (kvm_enabled()) {
177         smm_available = kvm_has_smm();
178     }
179 
180     if (smm_available) {
181         return true;
182     }
183 
184     if (x86ms->smm == ON_OFF_AUTO_ON) {
185         error_report("System Management Mode not supported by this hypervisor.");
186         exit(1);
187     }
188     return false;
189 }
190 
191 static void x86_machine_get_smm(Object *obj, Visitor *v, const char *name,
192                                void *opaque, Error **errp)
193 {
194     X86MachineState *x86ms = X86_MACHINE(obj);
195     OnOffAuto smm = x86ms->smm;
196 
197     visit_type_OnOffAuto(v, name, &smm, errp);
198 }
199 
200 static void x86_machine_set_smm(Object *obj, Visitor *v, const char *name,
201                                void *opaque, Error **errp)
202 {
203     X86MachineState *x86ms = X86_MACHINE(obj);
204 
205     visit_type_OnOffAuto(v, name, &x86ms->smm, errp);
206 }
207 
208 bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms)
209 {
210     if (x86ms->acpi == ON_OFF_AUTO_OFF) {
211         return false;
212     }
213     return true;
214 }
215 
216 static void x86_machine_get_acpi(Object *obj, Visitor *v, const char *name,
217                                  void *opaque, Error **errp)
218 {
219     X86MachineState *x86ms = X86_MACHINE(obj);
220     OnOffAuto acpi = x86ms->acpi;
221 
222     visit_type_OnOffAuto(v, name, &acpi, errp);
223 }
224 
225 static void x86_machine_set_acpi(Object *obj, Visitor *v, const char *name,
226                                  void *opaque, Error **errp)
227 {
228     X86MachineState *x86ms = X86_MACHINE(obj);
229 
230     visit_type_OnOffAuto(v, name, &x86ms->acpi, errp);
231 }
232 
233 static void x86_machine_get_pit(Object *obj, Visitor *v, const char *name,
234                                     void *opaque, Error **errp)
235 {
236     X86MachineState *x86ms = X86_MACHINE(obj);
237     OnOffAuto pit = x86ms->pit;
238 
239     visit_type_OnOffAuto(v, name, &pit, errp);
240 }
241 
242 static void x86_machine_set_pit(Object *obj, Visitor *v, const char *name,
243                                     void *opaque, Error **errp)
244 {
245     X86MachineState *x86ms = X86_MACHINE(obj);;
246 
247     visit_type_OnOffAuto(v, name, &x86ms->pit, errp);
248 }
249 
250 static void x86_machine_get_pic(Object *obj, Visitor *v, const char *name,
251                                 void *opaque, Error **errp)
252 {
253     X86MachineState *x86ms = X86_MACHINE(obj);
254     OnOffAuto pic = x86ms->pic;
255 
256     visit_type_OnOffAuto(v, name, &pic, errp);
257 }
258 
259 static void x86_machine_set_pic(Object *obj, Visitor *v, const char *name,
260                                 void *opaque, Error **errp)
261 {
262     X86MachineState *x86ms = X86_MACHINE(obj);
263 
264     visit_type_OnOffAuto(v, name, &x86ms->pic, errp);
265 }
266 
267 static char *x86_machine_get_oem_id(Object *obj, Error **errp)
268 {
269     X86MachineState *x86ms = X86_MACHINE(obj);
270 
271     return g_strdup(x86ms->oem_id);
272 }
273 
274 static void x86_machine_set_oem_id(Object *obj, const char *value, Error **errp)
275 {
276     X86MachineState *x86ms = X86_MACHINE(obj);
277     size_t len = strlen(value);
278 
279     if (len > 6) {
280         error_setg(errp,
281                    "User specified "X86_MACHINE_OEM_ID" value is bigger than "
282                    "6 bytes in size");
283         return;
284     }
285 
286     strncpy(x86ms->oem_id, value, 6);
287 }
288 
289 static char *x86_machine_get_oem_table_id(Object *obj, Error **errp)
290 {
291     X86MachineState *x86ms = X86_MACHINE(obj);
292 
293     return g_strdup(x86ms->oem_table_id);
294 }
295 
296 static void x86_machine_set_oem_table_id(Object *obj, const char *value,
297                                          Error **errp)
298 {
299     X86MachineState *x86ms = X86_MACHINE(obj);
300     size_t len = strlen(value);
301 
302     if (len > 8) {
303         error_setg(errp,
304                    "User specified "X86_MACHINE_OEM_TABLE_ID
305                    " value is bigger than "
306                    "8 bytes in size");
307         return;
308     }
309     strncpy(x86ms->oem_table_id, value, 8);
310 }
311 
312 static void x86_machine_get_bus_lock_ratelimit(Object *obj, Visitor *v,
313                                 const char *name, void *opaque, Error **errp)
314 {
315     X86MachineState *x86ms = X86_MACHINE(obj);
316     uint64_t bus_lock_ratelimit = x86ms->bus_lock_ratelimit;
317 
318     visit_type_uint64(v, name, &bus_lock_ratelimit, errp);
319 }
320 
321 static void x86_machine_set_bus_lock_ratelimit(Object *obj, Visitor *v,
322                                const char *name, void *opaque, Error **errp)
323 {
324     X86MachineState *x86ms = X86_MACHINE(obj);
325 
326     visit_type_uint64(v, name, &x86ms->bus_lock_ratelimit, errp);
327 }
328 
329 static void machine_get_sgx_epc(Object *obj, Visitor *v, const char *name,
330                                 void *opaque, Error **errp)
331 {
332     X86MachineState *x86ms = X86_MACHINE(obj);
333     SgxEPCList *list = x86ms->sgx_epc_list;
334 
335     visit_type_SgxEPCList(v, name, &list, errp);
336 }
337 
338 static void machine_set_sgx_epc(Object *obj, Visitor *v, const char *name,
339                                 void *opaque, Error **errp)
340 {
341     X86MachineState *x86ms = X86_MACHINE(obj);
342     SgxEPCList *list;
343 
344     list = x86ms->sgx_epc_list;
345     visit_type_SgxEPCList(v, name, &x86ms->sgx_epc_list, errp);
346 
347     qapi_free_SgxEPCList(list);
348 }
349 
350 static int x86_kvm_type(MachineState *ms, const char *vm_type)
351 {
352     /*
353      * No x86 machine has a kvm-type property.  If one is added that has
354      * it, it should call kvm_get_vm_type() directly or not use it at all.
355      */
356     assert(vm_type == NULL);
357     return kvm_enabled() ? kvm_get_vm_type(ms) : 0;
358 }
359 
360 static void x86_machine_initfn(Object *obj)
361 {
362     X86MachineState *x86ms = X86_MACHINE(obj);
363 
364     x86ms->smm = ON_OFF_AUTO_AUTO;
365     x86ms->acpi = ON_OFF_AUTO_AUTO;
366     x86ms->pit = ON_OFF_AUTO_AUTO;
367     x86ms->pic = ON_OFF_AUTO_AUTO;
368     x86ms->pci_irq_mask = ACPI_BUILD_PCI_IRQS;
369     x86ms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
370     x86ms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
371     x86ms->bus_lock_ratelimit = 0;
372     x86ms->above_4g_mem_start = 4 * GiB;
373 }
374 
375 static void x86_machine_class_init(ObjectClass *oc, void *data)
376 {
377     MachineClass *mc = MACHINE_CLASS(oc);
378     X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
379     NMIClass *nc = NMI_CLASS(oc);
380 
381     mc->cpu_index_to_instance_props = x86_cpu_index_to_props;
382     mc->get_default_cpu_node_id = x86_get_default_cpu_node_id;
383     mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids;
384     mc->kvm_type = x86_kvm_type;
385     x86mc->save_tsc_khz = true;
386     x86mc->fwcfg_dma_enabled = true;
387     nc->nmi_monitor_handler = x86_nmi;
388 
389     object_class_property_add(oc, X86_MACHINE_SMM, "OnOffAuto",
390         x86_machine_get_smm, x86_machine_set_smm,
391         NULL, NULL);
392     object_class_property_set_description(oc, X86_MACHINE_SMM,
393         "Enable SMM");
394 
395     object_class_property_add(oc, X86_MACHINE_ACPI, "OnOffAuto",
396         x86_machine_get_acpi, x86_machine_set_acpi,
397         NULL, NULL);
398     object_class_property_set_description(oc, X86_MACHINE_ACPI,
399         "Enable ACPI");
400 
401     object_class_property_add(oc, X86_MACHINE_PIT, "OnOffAuto",
402                               x86_machine_get_pit,
403                               x86_machine_set_pit,
404                               NULL, NULL);
405     object_class_property_set_description(oc, X86_MACHINE_PIT,
406         "Enable i8254 PIT");
407 
408     object_class_property_add(oc, X86_MACHINE_PIC, "OnOffAuto",
409                               x86_machine_get_pic,
410                               x86_machine_set_pic,
411                               NULL, NULL);
412     object_class_property_set_description(oc, X86_MACHINE_PIC,
413         "Enable i8259 PIC");
414 
415     object_class_property_add_str(oc, X86_MACHINE_OEM_ID,
416                                   x86_machine_get_oem_id,
417                                   x86_machine_set_oem_id);
418     object_class_property_set_description(oc, X86_MACHINE_OEM_ID,
419                                           "Override the default value of field OEMID "
420                                           "in ACPI table header."
421                                           "The string may be up to 6 bytes in size");
422 
423 
424     object_class_property_add_str(oc, X86_MACHINE_OEM_TABLE_ID,
425                                   x86_machine_get_oem_table_id,
426                                   x86_machine_set_oem_table_id);
427     object_class_property_set_description(oc, X86_MACHINE_OEM_TABLE_ID,
428                                           "Override the default value of field OEM Table ID "
429                                           "in ACPI table header."
430                                           "The string may be up to 8 bytes in size");
431 
432     object_class_property_add(oc, X86_MACHINE_BUS_LOCK_RATELIMIT, "uint64_t",
433                                 x86_machine_get_bus_lock_ratelimit,
434                                 x86_machine_set_bus_lock_ratelimit, NULL, NULL);
435     object_class_property_set_description(oc, X86_MACHINE_BUS_LOCK_RATELIMIT,
436             "Set the ratelimit for the bus locks acquired in VMs");
437 
438     object_class_property_add(oc, "sgx-epc", "SgxEPC",
439         machine_get_sgx_epc, machine_set_sgx_epc,
440         NULL, NULL);
441     object_class_property_set_description(oc, "sgx-epc",
442         "SGX EPC device");
443 }
444 
445 static const TypeInfo x86_machine_info = {
446     .name = TYPE_X86_MACHINE,
447     .parent = TYPE_MACHINE,
448     .abstract = true,
449     .instance_size = sizeof(X86MachineState),
450     .instance_init = x86_machine_initfn,
451     .class_size = sizeof(X86MachineClass),
452     .class_init = x86_machine_class_init,
453     .interfaces = (InterfaceInfo[]) {
454          { TYPE_NMI },
455          { }
456     },
457 };
458 
459 static void x86_machine_register_types(void)
460 {
461     type_register_static(&x86_machine_info);
462 }
463 
464 type_init(x86_machine_register_types)
465