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