|
@@ -0,0 +1,112 @@
|
|
|
+/*
|
|
|
+ * 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);
|
|
|
+}
|