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