/* * 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 "sysemu/hw_accel.h" #include "sysemu/kvm.h" #include "sysemu/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); }