master
c 109 lines 2.86 KB
Raw
1 /*
2 * QEMU x86 CPU <-> APIC
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 *
6 * SPDX-License-Identifier: MIT
7 */
8
9 #include "qemu/osdep.h"
10 #include "qobject/qdict.h"
11 #include "qapi/error.h"
12 #include "monitor/monitor.h"
13 #include "monitor/hmp.h"
14 #include "system/hw_accel.h"
15 #include "system/kvm.h"
16 #include "system/xen.h"
17 #include "system/mshv.h"
18 #include "system/address-spaces.h"
19 #include "hw/core/qdev-properties.h"
20 #include "hw/i386/apic_internal.h"
21 #include "cpu-internal.h"
22
23 APICCommonClass *apic_get_class(Error **errp)
24 {
25 const char *apic_type = "apic";
26
27 /* TODO: in-kernel irqchip for hvf */
28 if (kvm_enabled()) {
29 if (!kvm_irqchip_in_kernel()) {
30 error_setg(errp, "KVM does not support userspace APIC");
31 return NULL;
32 }
33 apic_type = "kvm-apic";
34 } else if (xen_enabled()) {
35 apic_type = "xen-apic";
36 } else if (whpx_irqchip_in_kernel()) {
37 apic_type = "whpx-apic";
38 } else if (mshv_enabled()) {
39 apic_type = "mshv-apic";
40 }
41
42 return APIC_COMMON_CLASS(object_class_by_name(apic_type));
43 }
44
45 void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
46 {
47 APICCommonClass *apic_class = apic_get_class(errp);
48
49 if (!apic_class) {
50 return;
51 }
52
53 cpu->apic_state = APIC_COMMON(object_new_with_class(OBJECT_CLASS(apic_class)));
54 object_property_add_child(OBJECT(cpu), "lapic",
55 OBJECT(cpu->apic_state));
56 object_unref(OBJECT(cpu->apic_state));
57
58 /* TODO: convert to link<> */
59 cpu->apic_state->cpu = cpu;
60 cpu->apic_state->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
61
62 /* cpu must be set before realize, which validates the APIC ID */
63 qdev_prop_set_uint32(DEVICE(cpu->apic_state), "id", cpu->apic_id);
64 }
65
66 void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
67 {
68 static bool apic_mmio_map_once;
69
70 if (cpu->apic_state == NULL) {
71 return;
72 }
73 qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
74
75 /* Map APIC MMIO area */
76 if (!apic_mmio_map_once) {
77 memory_region_add_subregion_overlap(get_system_memory(),
78 cpu->apic_state->apicbase &
79 MSR_IA32_APICBASE_BASE,
80 &cpu->apic_state->io_memory,
81 0x1000);
82 apic_mmio_map_once = true;
83 }
84 }
85
86 #ifdef CONFIG_HMP
87 void hmp_info_local_apic(MonitorHMP *hmp, const QDict *qdict)
88 {
89 CPUState *cs;
90
91 if (qdict_haskey(qdict, "apic-id")) {
92 int id = qdict_get_try_int(qdict, "apic-id", 0);
93
94 cs = cpu_by_arch_id(id);
95 if (cs) {
96 cpu_synchronize_state(cs);
97 }
98 } else {
99 cs = monitor_hmp_get_cpu(hmp);
100 }
101
102
103 if (!cs) {
104 monitor_hmp_printf(hmp, "No CPU available\n");
105 return;
106 }
107 x86_cpu_dump_local_apic_state(cs, CPU_DUMP_FPU);
108 }
109 #endif