2 * Copyright (c) 2003-2004 Fabrice Bellard
3 * Copyright (c) 2019 Red Hat, Inc.
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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
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"
34 #include "hw/acpi/aml-build.h"
35 #include "hw/i386/x86.h"
36 #include "hw/i386/topology.h"
39 #include "kvm/kvm_i386.h"
42 void init_topo_info(X86CPUTopoInfo
*topo_info
,
43 const X86MachineState
*x86ms
)
45 MachineState
*ms
= MACHINE(x86ms
);
47 topo_info
->dies_per_pkg
= ms
->smp
.dies
;
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
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
;
60 * Calculates initial APIC ID for a specific CPU index
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.
67 uint32_t x86_cpu_apic_id_from_index(X86MachineState
*x86ms
,
68 unsigned int cpu_index
)
70 X86CPUTopoInfo topo_info
;
72 init_topo_info(&topo_info
, x86ms
);
74 return x86_apicid_from_cpu_idx(&topo_info
, cpu_index
);
77 static CpuInstanceProperties
78 x86_cpu_index_to_props(MachineState
*ms
, unsigned cpu_index
)
80 MachineClass
*mc
= MACHINE_GET_CLASS(ms
);
81 const CPUArchIdList
*possible_cpus
= mc
->possible_cpu_arch_ids(ms
);
83 assert(cpu_index
< possible_cpus
->len
);
84 return possible_cpus
->cpus
[cpu_index
].props
;
87 static int64_t x86_get_default_cpu_node_id(const MachineState
*ms
, int idx
)
89 X86CPUTopoIDs topo_ids
;
90 X86MachineState
*x86ms
= X86_MACHINE(ms
);
91 X86CPUTopoInfo topo_info
;
93 init_topo_info(&topo_info
, x86ms
);
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
;
101 static const CPUArchIdList
*x86_possible_cpu_arch_ids(MachineState
*ms
)
103 X86MachineState
*x86ms
= X86_MACHINE(ms
);
104 unsigned int max_cpus
= ms
->smp
.max_cpus
;
105 X86CPUTopoInfo topo_info
;
108 if (ms
->possible_cpus
) {
110 * make sure that max_cpus hasn't changed since the first use, i.e.
111 * -smp hasn't been parsed after it
113 assert(ms
->possible_cpus
->len
== max_cpus
);
114 return ms
->possible_cpus
;
117 ms
->possible_cpus
= g_malloc0(sizeof(CPUArchIdList
) +
118 sizeof(CPUArchId
) * max_cpus
);
119 ms
->possible_cpus
->len
= max_cpus
;
121 init_topo_info(&topo_info
, x86ms
);
123 for (i
= 0; i
< ms
->possible_cpus
->len
; i
++) {
124 X86CPUTopoIDs topo_ids
;
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
;
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
;
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
;
147 return ms
->possible_cpus
;
150 static void x86_nmi(NMIState
*n
, int cpu_index
, Error
**errp
)
152 /* cpu index isn't used */
156 X86CPU
*cpu
= X86_CPU(cs
);
158 if (cpu_is_apic_enabled(cpu
->apic_state
)) {
159 apic_deliver_nmi(cpu
->apic_state
);
161 cpu_interrupt(cs
, CPU_INTERRUPT_NMI
);
166 bool x86_machine_is_smm_enabled(const X86MachineState
*x86ms
)
168 bool smm_available
= false;
170 if (x86ms
->smm
== ON_OFF_AUTO_OFF
) {
174 if (tcg_enabled() || qtest_enabled()) {
175 smm_available
= true;
176 } else if (kvm_enabled()) {
177 smm_available
= kvm_has_smm();
184 if (x86ms
->smm
== ON_OFF_AUTO_ON
) {
185 error_report("System Management Mode not supported by this hypervisor.");
191 static void x86_machine_get_smm(Object
*obj
, Visitor
*v
, const char *name
,
192 void *opaque
, Error
**errp
)
194 X86MachineState
*x86ms
= X86_MACHINE(obj
);
195 OnOffAuto smm
= x86ms
->smm
;
197 visit_type_OnOffAuto(v
, name
, &smm
, errp
);
200 static void x86_machine_set_smm(Object
*obj
, Visitor
*v
, const char *name
,
201 void *opaque
, Error
**errp
)
203 X86MachineState
*x86ms
= X86_MACHINE(obj
);
205 visit_type_OnOffAuto(v
, name
, &x86ms
->smm
, errp
);
208 bool x86_machine_is_acpi_enabled(const X86MachineState
*x86ms
)
210 if (x86ms
->acpi
== ON_OFF_AUTO_OFF
) {
216 static void x86_machine_get_acpi(Object
*obj
, Visitor
*v
, const char *name
,
217 void *opaque
, Error
**errp
)
219 X86MachineState
*x86ms
= X86_MACHINE(obj
);
220 OnOffAuto acpi
= x86ms
->acpi
;
222 visit_type_OnOffAuto(v
, name
, &acpi
, errp
);
225 static void x86_machine_set_acpi(Object
*obj
, Visitor
*v
, const char *name
,
226 void *opaque
, Error
**errp
)
228 X86MachineState
*x86ms
= X86_MACHINE(obj
);
230 visit_type_OnOffAuto(v
, name
, &x86ms
->acpi
, errp
);
233 static void x86_machine_get_pit(Object
*obj
, Visitor
*v
, const char *name
,
234 void *opaque
, Error
**errp
)
236 X86MachineState
*x86ms
= X86_MACHINE(obj
);
237 OnOffAuto pit
= x86ms
->pit
;
239 visit_type_OnOffAuto(v
, name
, &pit
, errp
);
242 static void x86_machine_set_pit(Object
*obj
, Visitor
*v
, const char *name
,
243 void *opaque
, Error
**errp
)
245 X86MachineState
*x86ms
= X86_MACHINE(obj
);;
247 visit_type_OnOffAuto(v
, name
, &x86ms
->pit
, errp
);
250 static void x86_machine_get_pic(Object
*obj
, Visitor
*v
, const char *name
,
251 void *opaque
, Error
**errp
)
253 X86MachineState
*x86ms
= X86_MACHINE(obj
);
254 OnOffAuto pic
= x86ms
->pic
;
256 visit_type_OnOffAuto(v
, name
, &pic
, errp
);
259 static void x86_machine_set_pic(Object
*obj
, Visitor
*v
, const char *name
,
260 void *opaque
, Error
**errp
)
262 X86MachineState
*x86ms
= X86_MACHINE(obj
);
264 visit_type_OnOffAuto(v
, name
, &x86ms
->pic
, errp
);
267 static char *x86_machine_get_oem_id(Object
*obj
, Error
**errp
)
269 X86MachineState
*x86ms
= X86_MACHINE(obj
);
271 return g_strdup(x86ms
->oem_id
);
274 static void x86_machine_set_oem_id(Object
*obj
, const char *value
, Error
**errp
)
276 X86MachineState
*x86ms
= X86_MACHINE(obj
);
277 size_t len
= strlen(value
);
281 "User specified "X86_MACHINE_OEM_ID
" value is bigger than "
286 strncpy(x86ms
->oem_id
, value
, 6);
289 static char *x86_machine_get_oem_table_id(Object
*obj
, Error
**errp
)
291 X86MachineState
*x86ms
= X86_MACHINE(obj
);
293 return g_strdup(x86ms
->oem_table_id
);
296 static void x86_machine_set_oem_table_id(Object
*obj
, const char *value
,
299 X86MachineState
*x86ms
= X86_MACHINE(obj
);
300 size_t len
= strlen(value
);
304 "User specified "X86_MACHINE_OEM_TABLE_ID
305 " value is bigger than "
309 strncpy(x86ms
->oem_table_id
, value
, 8);
312 static void x86_machine_get_bus_lock_ratelimit(Object
*obj
, Visitor
*v
,
313 const char *name
, void *opaque
, Error
**errp
)
315 X86MachineState
*x86ms
= X86_MACHINE(obj
);
316 uint64_t bus_lock_ratelimit
= x86ms
->bus_lock_ratelimit
;
318 visit_type_uint64(v
, name
, &bus_lock_ratelimit
, errp
);
321 static void x86_machine_set_bus_lock_ratelimit(Object
*obj
, Visitor
*v
,
322 const char *name
, void *opaque
, Error
**errp
)
324 X86MachineState
*x86ms
= X86_MACHINE(obj
);
326 visit_type_uint64(v
, name
, &x86ms
->bus_lock_ratelimit
, errp
);
329 static void machine_get_sgx_epc(Object
*obj
, Visitor
*v
, const char *name
,
330 void *opaque
, Error
**errp
)
332 X86MachineState
*x86ms
= X86_MACHINE(obj
);
333 SgxEPCList
*list
= x86ms
->sgx_epc_list
;
335 visit_type_SgxEPCList(v
, name
, &list
, errp
);
338 static void machine_set_sgx_epc(Object
*obj
, Visitor
*v
, const char *name
,
339 void *opaque
, Error
**errp
)
341 X86MachineState
*x86ms
= X86_MACHINE(obj
);
344 list
= x86ms
->sgx_epc_list
;
345 visit_type_SgxEPCList(v
, name
, &x86ms
->sgx_epc_list
, errp
);
347 qapi_free_SgxEPCList(list
);
350 static int x86_kvm_type(MachineState
*ms
, const char *vm_type
)
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.
356 assert(vm_type
== NULL
);
357 return kvm_enabled() ? kvm_get_vm_type(ms
) : 0;
360 static void x86_machine_initfn(Object
*obj
)
362 X86MachineState
*x86ms
= X86_MACHINE(obj
);
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
;
375 static void x86_machine_class_init(ObjectClass
*oc
, void *data
)
377 MachineClass
*mc
= MACHINE_CLASS(oc
);
378 X86MachineClass
*x86mc
= X86_MACHINE_CLASS(oc
);
379 NMIClass
*nc
= NMI_CLASS(oc
);
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
;
389 object_class_property_add(oc
, X86_MACHINE_SMM
, "OnOffAuto",
390 x86_machine_get_smm
, x86_machine_set_smm
,
392 object_class_property_set_description(oc
, X86_MACHINE_SMM
,
395 object_class_property_add(oc
, X86_MACHINE_ACPI
, "OnOffAuto",
396 x86_machine_get_acpi
, x86_machine_set_acpi
,
398 object_class_property_set_description(oc
, X86_MACHINE_ACPI
,
401 object_class_property_add(oc
, X86_MACHINE_PIT
, "OnOffAuto",
405 object_class_property_set_description(oc
, X86_MACHINE_PIT
,
408 object_class_property_add(oc
, X86_MACHINE_PIC
, "OnOffAuto",
412 object_class_property_set_description(oc
, X86_MACHINE_PIC
,
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");
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");
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");
438 object_class_property_add(oc
, "sgx-epc", "SgxEPC",
439 machine_get_sgx_epc
, machine_set_sgx_epc
,
441 object_class_property_set_description(oc
, "sgx-epc",
445 static const TypeInfo x86_machine_info
= {
446 .name
= TYPE_X86_MACHINE
,
447 .parent
= TYPE_MACHINE
,
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
[]) {
459 static void x86_machine_register_types(void)
461 type_register_static(&x86_machine_info
);
464 type_init(x86_machine_register_types
)