xref: /qemu/target/i386/cpu-apic.c (revision 159fb790)
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 "qapi/qmp/qdict.h"
11 #include "qapi/error.h"
12 #include "monitor/monitor.h"
13 #include "monitor/hmp-target.h"
14 #include "sysemu/hw_accel.h"
15 #include "sysemu/kvm.h"
16 #include "sysemu/xen.h"
17 #include "exec/address-spaces.h"
18 #include "hw/qdev-properties.h"
19 #include "hw/i386/apic_internal.h"
20 #include "cpu-internal.h"
21 
22 APICCommonClass *apic_get_class(Error **errp)
23 {
24     const char *apic_type = "apic";
25 
26     /* TODO: in-kernel irqchip for hvf */
27     if (kvm_enabled()) {
28         if (!kvm_irqchip_in_kernel()) {
29             error_setg(errp, "KVM does not support userspace APIC");
30             return NULL;
31         }
32         apic_type = "kvm-apic";
33     } else if (xen_enabled()) {
34         apic_type = "xen-apic";
35     } else if (whpx_apic_in_platform()) {
36         apic_type = "whpx-apic";
37     }
38 
39     return APIC_COMMON_CLASS(object_class_by_name(apic_type));
40 }
41 
42 void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
43 {
44     APICCommonState *apic;
45     APICCommonClass *apic_class = apic_get_class(errp);
46 
47     if (!apic_class) {
48         return;
49     }
50 
51     cpu->apic_state = DEVICE(object_new_with_class(OBJECT_CLASS(apic_class)));
52     object_property_add_child(OBJECT(cpu), "lapic",
53                               OBJECT(cpu->apic_state));
54     object_unref(OBJECT(cpu->apic_state));
55 
56     /* TODO: convert to link<> */
57     apic = APIC_COMMON(cpu->apic_state);
58     apic->cpu = cpu;
59     apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
60 
61     /*
62      * apic_common_set_id needs to check if the CPU has x2APIC
63      * feature in case APIC ID >= 255, so we need to set apic->cpu
64      * before setting APIC ID
65      */
66     qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
67 }
68 
69 void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
70 {
71     APICCommonState *apic;
72     static bool apic_mmio_map_once;
73 
74     if (cpu->apic_state == NULL) {
75         return;
76     }
77     qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
78 
79     /* Map APIC MMIO area */
80     apic = APIC_COMMON(cpu->apic_state);
81     if (!apic_mmio_map_once) {
82         memory_region_add_subregion_overlap(get_system_memory(),
83                                             apic->apicbase &
84                                             MSR_IA32_APICBASE_BASE,
85                                             &apic->io_memory,
86                                             0x1000);
87         apic_mmio_map_once = true;
88      }
89 }
90 
91 void hmp_info_local_apic(Monitor *mon, const QDict *qdict)
92 {
93     CPUState *cs;
94 
95     if (qdict_haskey(qdict, "apic-id")) {
96         int id = qdict_get_try_int(qdict, "apic-id", 0);
97 
98         cs = cpu_by_arch_id(id);
99         if (cs) {
100             cpu_synchronize_state(cs);
101         }
102     } else {
103         cs = mon_get_cpu(mon);
104     }
105 
106 
107     if (!cs) {
108         monitor_printf(mon, "No CPU available\n");
109         return;
110     }
111     x86_cpu_dump_local_apic_state(cs, CPU_DUMP_FPU);
112 }
113