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