| /* | 
 |  * QEMU x86 CPU <-> APIC | 
 |  * | 
 |  * Copyright (c) 2003-2004 Fabrice Bellard | 
 |  * | 
 |  * SPDX-License-Identifier: MIT | 
 |  */ | 
 |  | 
 | #include "qemu/osdep.h" | 
 | #include "qapi/qmp/qdict.h" | 
 | #include "qapi/error.h" | 
 | #include "monitor/monitor.h" | 
 | #include "monitor/hmp-target.h" | 
 | #include "system/hw_accel.h" | 
 | #include "system/kvm.h" | 
 | #include "system/xen.h" | 
 | #include "exec/address-spaces.h" | 
 | #include "hw/qdev-properties.h" | 
 | #include "hw/i386/apic_internal.h" | 
 | #include "cpu-internal.h" | 
 |  | 
 | APICCommonClass *apic_get_class(Error **errp) | 
 | { | 
 |     const char *apic_type = "apic"; | 
 |  | 
 |     /* TODO: in-kernel irqchip for hvf */ | 
 |     if (kvm_enabled()) { | 
 |         if (!kvm_irqchip_in_kernel()) { | 
 |             error_setg(errp, "KVM does not support userspace APIC"); | 
 |             return NULL; | 
 |         } | 
 |         apic_type = "kvm-apic"; | 
 |     } else if (xen_enabled()) { | 
 |         apic_type = "xen-apic"; | 
 |     } else if (whpx_apic_in_platform()) { | 
 |         apic_type = "whpx-apic"; | 
 |     } | 
 |  | 
 |     return APIC_COMMON_CLASS(object_class_by_name(apic_type)); | 
 | } | 
 |  | 
 | void x86_cpu_apic_create(X86CPU *cpu, Error **errp) | 
 | { | 
 |     APICCommonState *apic; | 
 |     APICCommonClass *apic_class = apic_get_class(errp); | 
 |  | 
 |     if (!apic_class) { | 
 |         return; | 
 |     } | 
 |  | 
 |     cpu->apic_state = DEVICE(object_new_with_class(OBJECT_CLASS(apic_class))); | 
 |     object_property_add_child(OBJECT(cpu), "lapic", | 
 |                               OBJECT(cpu->apic_state)); | 
 |     object_unref(OBJECT(cpu->apic_state)); | 
 |  | 
 |     /* TODO: convert to link<> */ | 
 |     apic = APIC_COMMON(cpu->apic_state); | 
 |     apic->cpu = cpu; | 
 |     apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE; | 
 |  | 
 |     /* | 
 |      * apic_common_set_id needs to check if the CPU has x2APIC | 
 |      * feature in case APIC ID >= 255, so we need to set apic->cpu | 
 |      * before setting APIC ID | 
 |      */ | 
 |     qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id); | 
 | } | 
 |  | 
 | void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) | 
 | { | 
 |     APICCommonState *apic; | 
 |     static bool apic_mmio_map_once; | 
 |  | 
 |     if (cpu->apic_state == NULL) { | 
 |         return; | 
 |     } | 
 |     qdev_realize(DEVICE(cpu->apic_state), NULL, errp); | 
 |  | 
 |     /* Map APIC MMIO area */ | 
 |     apic = APIC_COMMON(cpu->apic_state); | 
 |     if (!apic_mmio_map_once) { | 
 |         memory_region_add_subregion_overlap(get_system_memory(), | 
 |                                             apic->apicbase & | 
 |                                             MSR_IA32_APICBASE_BASE, | 
 |                                             &apic->io_memory, | 
 |                                             0x1000); | 
 |         apic_mmio_map_once = true; | 
 |      } | 
 | } | 
 |  | 
 | void hmp_info_local_apic(Monitor *mon, const QDict *qdict) | 
 | { | 
 |     CPUState *cs; | 
 |  | 
 |     if (qdict_haskey(qdict, "apic-id")) { | 
 |         int id = qdict_get_try_int(qdict, "apic-id", 0); | 
 |  | 
 |         cs = cpu_by_arch_id(id); | 
 |         if (cs) { | 
 |             cpu_synchronize_state(cs); | 
 |         } | 
 |     } else { | 
 |         cs = mon_get_cpu(mon); | 
 |     } | 
 |  | 
 |  | 
 |     if (!cs) { | 
 |         monitor_printf(mon, "No CPU available\n"); | 
 |         return; | 
 |     } | 
 |     x86_cpu_dump_local_apic_state(cs, CPU_DUMP_FPU); | 
 | } |