xref: /openbmc/qemu/hw/i386/x86.c (revision 3568adc995b3906b5cc134753a829363f08bf6e1)
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         ms->possible_cpus->cpus[i].props.has_core_id = true;
139         ms->possible_cpus->cpus[i].props.core_id = topo_ids.core_id;
140         ms->possible_cpus->cpus[i].props.has_thread_id = true;
141         ms->possible_cpus->cpus[i].props.thread_id = topo_ids.smt_id;
142     }
143     return ms->possible_cpus;
144 }
145 
146 static void x86_nmi(NMIState *n, int cpu_index, Error **errp)
147 {
148     /* cpu index isn't used */
149     CPUState *cs;
150 
151     CPU_FOREACH(cs) {
152         X86CPU *cpu = X86_CPU(cs);
153 
154         if (cpu_is_apic_enabled(cpu->apic_state)) {
155             apic_deliver_nmi(cpu->apic_state);
156         } else {
157             cpu_interrupt(cs, CPU_INTERRUPT_NMI);
158         }
159     }
160 }
161 
162 bool x86_machine_is_smm_enabled(const X86MachineState *x86ms)
163 {
164     bool smm_available = false;
165 
166     if (x86ms->smm == ON_OFF_AUTO_OFF) {
167         return false;
168     }
169 
170     if (tcg_enabled() || qtest_enabled()) {
171         smm_available = true;
172     } else if (kvm_enabled()) {
173         smm_available = kvm_has_smm();
174     }
175 
176     if (smm_available) {
177         return true;
178     }
179 
180     if (x86ms->smm == ON_OFF_AUTO_ON) {
181         error_report("System Management Mode not supported by this hypervisor.");
182         exit(1);
183     }
184     return false;
185 }
186 
187 static void x86_machine_get_smm(Object *obj, Visitor *v, const char *name,
188                                void *opaque, Error **errp)
189 {
190     X86MachineState *x86ms = X86_MACHINE(obj);
191     OnOffAuto smm = x86ms->smm;
192 
193     visit_type_OnOffAuto(v, name, &smm, errp);
194 }
195 
196 static void x86_machine_set_smm(Object *obj, Visitor *v, const char *name,
197                                void *opaque, Error **errp)
198 {
199     X86MachineState *x86ms = X86_MACHINE(obj);
200 
201     visit_type_OnOffAuto(v, name, &x86ms->smm, errp);
202 }
203 
204 bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms)
205 {
206     if (x86ms->acpi == ON_OFF_AUTO_OFF) {
207         return false;
208     }
209     return true;
210 }
211 
212 static void x86_machine_get_acpi(Object *obj, Visitor *v, const char *name,
213                                  void *opaque, Error **errp)
214 {
215     X86MachineState *x86ms = X86_MACHINE(obj);
216     OnOffAuto acpi = x86ms->acpi;
217 
218     visit_type_OnOffAuto(v, name, &acpi, errp);
219 }
220 
221 static void x86_machine_set_acpi(Object *obj, Visitor *v, const char *name,
222                                  void *opaque, Error **errp)
223 {
224     X86MachineState *x86ms = X86_MACHINE(obj);
225 
226     visit_type_OnOffAuto(v, name, &x86ms->acpi, errp);
227 }
228 
229 static void x86_machine_get_pit(Object *obj, Visitor *v, const char *name,
230                                     void *opaque, Error **errp)
231 {
232     X86MachineState *x86ms = X86_MACHINE(obj);
233     OnOffAuto pit = x86ms->pit;
234 
235     visit_type_OnOffAuto(v, name, &pit, errp);
236 }
237 
238 static void x86_machine_set_pit(Object *obj, Visitor *v, const char *name,
239                                     void *opaque, Error **errp)
240 {
241     X86MachineState *x86ms = X86_MACHINE(obj);;
242 
243     visit_type_OnOffAuto(v, name, &x86ms->pit, errp);
244 }
245 
246 static void x86_machine_get_pic(Object *obj, Visitor *v, const char *name,
247                                 void *opaque, Error **errp)
248 {
249     X86MachineState *x86ms = X86_MACHINE(obj);
250     OnOffAuto pic = x86ms->pic;
251 
252     visit_type_OnOffAuto(v, name, &pic, errp);
253 }
254 
255 static void x86_machine_set_pic(Object *obj, Visitor *v, const char *name,
256                                 void *opaque, Error **errp)
257 {
258     X86MachineState *x86ms = X86_MACHINE(obj);
259 
260     visit_type_OnOffAuto(v, name, &x86ms->pic, errp);
261 }
262 
263 static char *x86_machine_get_oem_id(Object *obj, Error **errp)
264 {
265     X86MachineState *x86ms = X86_MACHINE(obj);
266 
267     return g_strdup(x86ms->oem_id);
268 }
269 
270 static void x86_machine_set_oem_id(Object *obj, const char *value, Error **errp)
271 {
272     X86MachineState *x86ms = X86_MACHINE(obj);
273     size_t len = strlen(value);
274 
275     if (len > 6) {
276         error_setg(errp,
277                    "User specified "X86_MACHINE_OEM_ID" value is bigger than "
278                    "6 bytes in size");
279         return;
280     }
281 
282     strncpy(x86ms->oem_id, value, 6);
283 }
284 
285 static char *x86_machine_get_oem_table_id(Object *obj, Error **errp)
286 {
287     X86MachineState *x86ms = X86_MACHINE(obj);
288 
289     return g_strdup(x86ms->oem_table_id);
290 }
291 
292 static void x86_machine_set_oem_table_id(Object *obj, const char *value,
293                                          Error **errp)
294 {
295     X86MachineState *x86ms = X86_MACHINE(obj);
296     size_t len = strlen(value);
297 
298     if (len > 8) {
299         error_setg(errp,
300                    "User specified "X86_MACHINE_OEM_TABLE_ID
301                    " value is bigger than "
302                    "8 bytes in size");
303         return;
304     }
305     strncpy(x86ms->oem_table_id, value, 8);
306 }
307 
308 static void x86_machine_get_bus_lock_ratelimit(Object *obj, Visitor *v,
309                                 const char *name, void *opaque, Error **errp)
310 {
311     X86MachineState *x86ms = X86_MACHINE(obj);
312     uint64_t bus_lock_ratelimit = x86ms->bus_lock_ratelimit;
313 
314     visit_type_uint64(v, name, &bus_lock_ratelimit, errp);
315 }
316 
317 static void x86_machine_set_bus_lock_ratelimit(Object *obj, Visitor *v,
318                                const char *name, void *opaque, Error **errp)
319 {
320     X86MachineState *x86ms = X86_MACHINE(obj);
321 
322     visit_type_uint64(v, name, &x86ms->bus_lock_ratelimit, errp);
323 }
324 
325 static void machine_get_sgx_epc(Object *obj, Visitor *v, const char *name,
326                                 void *opaque, Error **errp)
327 {
328     X86MachineState *x86ms = X86_MACHINE(obj);
329     SgxEPCList *list = x86ms->sgx_epc_list;
330 
331     visit_type_SgxEPCList(v, name, &list, errp);
332 }
333 
334 static void machine_set_sgx_epc(Object *obj, Visitor *v, const char *name,
335                                 void *opaque, Error **errp)
336 {
337     X86MachineState *x86ms = X86_MACHINE(obj);
338     SgxEPCList *list;
339 
340     list = x86ms->sgx_epc_list;
341     visit_type_SgxEPCList(v, name, &x86ms->sgx_epc_list, errp);
342 
343     qapi_free_SgxEPCList(list);
344 }
345 
346 static int x86_kvm_type(MachineState *ms, const char *vm_type)
347 {
348     /*
349      * No x86 machine has a kvm-type property.  If one is added that has
350      * it, it should call kvm_get_vm_type() directly or not use it at all.
351      */
352     assert(vm_type == NULL);
353     return kvm_enabled() ? kvm_get_vm_type(ms) : 0;
354 }
355 
356 static void x86_machine_initfn(Object *obj)
357 {
358     X86MachineState *x86ms = X86_MACHINE(obj);
359 
360     x86ms->smm = ON_OFF_AUTO_AUTO;
361     x86ms->acpi = ON_OFF_AUTO_AUTO;
362     x86ms->pit = ON_OFF_AUTO_AUTO;
363     x86ms->pic = ON_OFF_AUTO_AUTO;
364     x86ms->pci_irq_mask = ACPI_BUILD_PCI_IRQS;
365     x86ms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
366     x86ms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
367     x86ms->bus_lock_ratelimit = 0;
368     x86ms->above_4g_mem_start = 4 * GiB;
369 }
370 
371 static void x86_machine_class_init(ObjectClass *oc, void *data)
372 {
373     MachineClass *mc = MACHINE_CLASS(oc);
374     X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
375     NMIClass *nc = NMI_CLASS(oc);
376 
377     mc->cpu_index_to_instance_props = x86_cpu_index_to_props;
378     mc->get_default_cpu_node_id = x86_get_default_cpu_node_id;
379     mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids;
380     mc->kvm_type = x86_kvm_type;
381     x86mc->save_tsc_khz = true;
382     x86mc->fwcfg_dma_enabled = true;
383     nc->nmi_monitor_handler = x86_nmi;
384 
385     object_class_property_add(oc, X86_MACHINE_SMM, "OnOffAuto",
386         x86_machine_get_smm, x86_machine_set_smm,
387         NULL, NULL);
388     object_class_property_set_description(oc, X86_MACHINE_SMM,
389         "Enable SMM");
390 
391     object_class_property_add(oc, X86_MACHINE_ACPI, "OnOffAuto",
392         x86_machine_get_acpi, x86_machine_set_acpi,
393         NULL, NULL);
394     object_class_property_set_description(oc, X86_MACHINE_ACPI,
395         "Enable ACPI");
396 
397     object_class_property_add(oc, X86_MACHINE_PIT, "OnOffAuto",
398                               x86_machine_get_pit,
399                               x86_machine_set_pit,
400                               NULL, NULL);
401     object_class_property_set_description(oc, X86_MACHINE_PIT,
402         "Enable i8254 PIT");
403 
404     object_class_property_add(oc, X86_MACHINE_PIC, "OnOffAuto",
405                               x86_machine_get_pic,
406                               x86_machine_set_pic,
407                               NULL, NULL);
408     object_class_property_set_description(oc, X86_MACHINE_PIC,
409         "Enable i8259 PIC");
410 
411     object_class_property_add_str(oc, X86_MACHINE_OEM_ID,
412                                   x86_machine_get_oem_id,
413                                   x86_machine_set_oem_id);
414     object_class_property_set_description(oc, X86_MACHINE_OEM_ID,
415                                           "Override the default value of field OEMID "
416                                           "in ACPI table header."
417                                           "The string may be up to 6 bytes in size");
418 
419 
420     object_class_property_add_str(oc, X86_MACHINE_OEM_TABLE_ID,
421                                   x86_machine_get_oem_table_id,
422                                   x86_machine_set_oem_table_id);
423     object_class_property_set_description(oc, X86_MACHINE_OEM_TABLE_ID,
424                                           "Override the default value of field OEM Table ID "
425                                           "in ACPI table header."
426                                           "The string may be up to 8 bytes in size");
427 
428     object_class_property_add(oc, X86_MACHINE_BUS_LOCK_RATELIMIT, "uint64_t",
429                                 x86_machine_get_bus_lock_ratelimit,
430                                 x86_machine_set_bus_lock_ratelimit, NULL, NULL);
431     object_class_property_set_description(oc, X86_MACHINE_BUS_LOCK_RATELIMIT,
432             "Set the ratelimit for the bus locks acquired in VMs");
433 
434     object_class_property_add(oc, "sgx-epc", "SgxEPC",
435         machine_get_sgx_epc, machine_set_sgx_epc,
436         NULL, NULL);
437     object_class_property_set_description(oc, "sgx-epc",
438         "SGX EPC device");
439 }
440 
441 static const TypeInfo x86_machine_info = {
442     .name = TYPE_X86_MACHINE,
443     .parent = TYPE_MACHINE,
444     .abstract = true,
445     .instance_size = sizeof(X86MachineState),
446     .instance_init = x86_machine_initfn,
447     .class_size = sizeof(X86MachineClass),
448     .class_init = x86_machine_class_init,
449     .interfaces = (InterfaceInfo[]) {
450          { TYPE_NMI },
451          { }
452     },
453 };
454 
455 static void x86_machine_register_types(void)
456 {
457     type_register_static(&x86_machine_info);
458 }
459 
460 type_init(x86_machine_register_types)
461