This is a combination of the following commits from NEMU (https://github.com/intel/nemu):
=============================================== commit b6472ce5ce5108c7aacb0dfa3d74b3eb8f98ae85 Author: Samuel Ortiz <sa...@linux.intel.com> Date: Fri Mar 22 10:28:31 2019 +0800 hw: i386: Factorize CPU routines A few routines are now shared between pc_* and virt, including the CPU init one. We factorize those routines into an i386 specific file that is now used by all x86 machines. Signed-off-by: Samuel Ortiz <sa...@linux.intel.com> commit f29f3c294a889ad659dc8808728e8441e23a675c Author: Samuel Ortiz <sa...@linux.intel.com> Date: Mon Oct 8 15:37:17 2018 +0200 hw: i386: Remove the pc header dependency from the cpu code It's only a matter of moving the compat APIC boolean to the correct header file (apic.h). Signed-off-by: Samuel Ortiz <sa...@linux.intel.com> =============================================== Signed-off-by: Sergio Lopez <s...@redhat.com> --- hw/i386/Makefile.objs | 1 + hw/i386/cpu.c | 174 +++++++++++++++++++++++++++++++++ hw/i386/pc.c | 151 ++-------------------------- hw/i386/pc_piix.c | 3 +- hw/i386/pc_q35.c | 3 +- include/hw/i386/apic.h | 1 + include/hw/i386/cpu-internal.h | 32 ++++++ 7 files changed, 218 insertions(+), 147 deletions(-) create mode 100644 hw/i386/cpu.c create mode 100644 include/hw/i386/cpu-internal.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 5d9c9efd5f..102f2b35fc 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,5 +1,6 @@ obj-$(CONFIG_KVM) += kvm/ obj-y += multiboot.o +obj-y += cpu.o obj-y += pc.o obj-$(CONFIG_I440FX) += pc_piix.o obj-$(CONFIG_Q35) += pc_q35.o diff --git a/hw/i386/cpu.c b/hw/i386/cpu.c new file mode 100644 index 0000000000..e13ae61535 --- /dev/null +++ b/hw/i386/cpu.c @@ -0,0 +1,174 @@ +/* + * + * Copyright (c) 2018 Intel Corportation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" + +#include "sysemu/cpus.h" +#include "sysemu/qtest.h" +#include "sysemu/numa.h" +#include "sysemu/sysemu.h" + +#include "hw/i386/cpu-internal.h" +#include "hw/i386/apic.h" +#include "hw/i386/topology.h" + +#include "hw/acpi/pc-hotplug.h" + +static void cpu_new(const char *typename, int64_t apic_id, Error **errp) +{ + Object *cpu = NULL; + Error *local_err = NULL; + + cpu = object_new(typename); + + object_property_set_uint(cpu, apic_id, "apic-id", &local_err); + object_property_set_bool(cpu, true, "realized", &local_err); + + object_unref(cpu); + error_propagate(errp, local_err); +} + +/* Calculates initial APIC ID for a specific CPU index + * + * Currently we need to be able to calculate the APIC ID from the CPU index + * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have + * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of + * all CPUs up to max_cpus. + */ +uint32_t cpu_apicid_from_index(unsigned int cpu_index, bool compat) +{ + uint32_t correct_id; + static bool warned; + + correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index); + if (compat) { + if (cpu_index != correct_id && !warned && !qtest_enabled()) { + error_report("APIC IDs set in compatibility mode, " + "CPU topology won't match the configuration"); + warned = true; + } + return cpu_index; + } else { + return correct_id; + } +} + +CpuInstanceProperties cpu_index_to_props(MachineState *ms, unsigned cpu_index) +{ + MachineClass *mc = MACHINE_GET_CLASS(ms); + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); + + assert(cpu_index < possible_cpus->len); + return possible_cpus->cpus[cpu_index].props; +} + + +int64_t cpu_get_default_cpu_node_id(const MachineState *ms, int idx) +{ + X86CPUTopoInfo topo; + + assert(idx < ms->possible_cpus->len); + x86_topo_ids_from_apicid(ms->possible_cpus->cpus[idx].arch_id, + smp_cores, smp_threads, &topo); + return topo.pkg_id % nb_numa_nodes; +} + +const CPUArchIdList *cpu_possible_cpu_arch_ids(MachineState *ms) +{ + int i; + + if (ms->possible_cpus) { + /* + * make sure that max_cpus hasn't changed since the first use, i.e. + * -smp hasn't been parsed after it + */ + assert(ms->possible_cpus->len == max_cpus); + return ms->possible_cpus; + } + + ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + + sizeof(CPUArchId) * max_cpus); + ms->possible_cpus->len = max_cpus; + for (i = 0; i < ms->possible_cpus->len; i++) { + X86CPUTopoInfo topo; + + ms->possible_cpus->cpus[i].type = ms->cpu_type; + ms->possible_cpus->cpus[i].vcpus_count = 1; + ms->possible_cpus->cpus[i].arch_id = cpu_apicid_from_index(i, compat_apic_id_mode); + x86_topo_ids_from_apicid(ms->possible_cpus->cpus[i].arch_id, + smp_cores, smp_threads, &topo); + ms->possible_cpus->cpus[i].props.has_socket_id = true; + ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id; + ms->possible_cpus->cpus[i].props.has_core_id = true; + ms->possible_cpus->cpus[i].props.core_id = topo.core_id; + ms->possible_cpus->cpus[i].props.has_thread_id = true; + ms->possible_cpus->cpus[i].props.thread_id = topo.smt_id; + } + return ms->possible_cpus; +} + + +void cpu_hot_add(const int64_t id, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + int64_t apic_id = cpu_apicid_from_index(id, compat_apic_id_mode); + Error *local_err = NULL; + + if (id < 0) { + error_setg(errp, "Invalid CPU id: %" PRIi64, id); + return; + } + + if (apic_id >= ACPI_CPU_HOTPLUG_ID_LIMIT) { + error_setg(errp, "Unable to add CPU: %" PRIi64 + ", resulting APIC ID (%" PRIi64 ") is too large", + id, apic_id); + return; + } + + cpu_new(ms->cpu_type, apic_id, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } +} + +uint32_t cpus_init(MachineState *ms, bool compat) +{ + int i; + uint32_t apic_id_limit; + const CPUArchIdList *possible_cpus; + MachineClass *mc = MACHINE_GET_CLASS(ms); + + /* Calculates the limit to CPU APIC ID values + * + * Limit for the APIC ID value, so that all + * CPU APIC IDs are < ms->apic_id_limit. + * + * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init(). + */ + apic_id_limit = cpu_apicid_from_index(max_cpus - 1, compat) + 1; + possible_cpus = mc->possible_cpu_arch_ids(ms); + for (i = 0; i < smp_cpus; i++) { + cpu_new(possible_cpus->cpus[i].type, possible_cpus->cpus[i].arch_id, + &error_fatal); + } + + return apic_id_limit; +} diff --git a/hw/i386/pc.c b/hw/i386/pc.c index e96360b47a..07d67a5031 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -26,6 +26,7 @@ #include "qemu/units.h" #include "hw/hw.h" #include "hw/i386/pc.h" +#include "hw/i386/cpu-internal.h" #include "hw/char/serial.h" #include "hw/char/parallel.h" #include "hw/i386/apic.h" @@ -914,38 +915,13 @@ bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *length) } /* Enables contiguous-apic-ID mode, for compatibility */ -static bool compat_apic_id_mode; +bool compat_apic_id_mode; void enable_compat_apic_id_mode(void) { compat_apic_id_mode = true; } -/* Calculates initial APIC ID for a specific CPU index - * - * Currently we need to be able to calculate the APIC ID from the CPU index - * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have - * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of - * all CPUs up to max_cpus. - */ -static uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index) -{ - uint32_t correct_id; - static bool warned; - - correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index); - if (compat_apic_id_mode) { - if (cpu_index != correct_id && !warned && !qtest_enabled()) { - error_report("APIC IDs set in compatibility mode, " - "CPU topology won't match the configuration"); - warned = true; - } - return cpu_index; - } else { - return correct_id; - } -} - static void pc_build_smbios(PCMachineState *pcms) { uint8_t *smbios_tables, *smbios_anchor; @@ -1516,67 +1492,6 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static void pc_new_cpu(const char *typename, int64_t apic_id, Error **errp) -{ - Object *cpu = NULL; - Error *local_err = NULL; - - cpu = object_new(typename); - - object_property_set_uint(cpu, apic_id, "apic-id", &local_err); - object_property_set_bool(cpu, true, "realized", &local_err); - - object_unref(cpu); - error_propagate(errp, local_err); -} - -void pc_hot_add_cpu(const int64_t id, Error **errp) -{ - MachineState *ms = MACHINE(qdev_get_machine()); - int64_t apic_id = x86_cpu_apic_id_from_index(id); - Error *local_err = NULL; - - if (id < 0) { - error_setg(errp, "Invalid CPU id: %" PRIi64, id); - return; - } - - if (apic_id >= ACPI_CPU_HOTPLUG_ID_LIMIT) { - error_setg(errp, "Unable to add CPU: %" PRIi64 - ", resulting APIC ID (%" PRIi64 ") is too large", - id, apic_id); - return; - } - - pc_new_cpu(ms->cpu_type, apic_id, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -} - -void pc_cpus_init(PCMachineState *pcms) -{ - int i; - const CPUArchIdList *possible_cpus; - MachineState *ms = MACHINE(pcms); - MachineClass *mc = MACHINE_GET_CLASS(pcms); - - /* Calculates the limit to CPU APIC ID values - * - * Limit for the APIC ID value, so that all - * CPU APIC IDs are < pcms->apic_id_limit. - * - * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init(). - */ - pcms->apic_id_limit = x86_cpu_apic_id_from_index(max_cpus - 1) + 1; - possible_cpus = mc->possible_cpu_arch_ids(ms); - for (i = 0; i < smp_cpus; i++) { - pc_new_cpu(possible_cpus->cpus[i].type, possible_cpus->cpus[i].arch_id, - &error_fatal); - } -} - static void pc_build_feature_control_file(PCMachineState *pcms) { MachineState *ms = MACHINE(pcms); @@ -2638,60 +2553,6 @@ static void pc_machine_reset(void) } } -static CpuInstanceProperties -pc_cpu_index_to_props(MachineState *ms, unsigned cpu_index) -{ - MachineClass *mc = MACHINE_GET_CLASS(ms); - const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); - - assert(cpu_index < possible_cpus->len); - return possible_cpus->cpus[cpu_index].props; -} - -static int64_t pc_get_default_cpu_node_id(const MachineState *ms, int idx) -{ - X86CPUTopoInfo topo; - - assert(idx < ms->possible_cpus->len); - x86_topo_ids_from_apicid(ms->possible_cpus->cpus[idx].arch_id, - smp_cores, smp_threads, &topo); - return topo.pkg_id % nb_numa_nodes; -} - -static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms) -{ - int i; - - if (ms->possible_cpus) { - /* - * make sure that max_cpus hasn't changed since the first use, i.e. - * -smp hasn't been parsed after it - */ - assert(ms->possible_cpus->len == max_cpus); - return ms->possible_cpus; - } - - ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + - sizeof(CPUArchId) * max_cpus); - ms->possible_cpus->len = max_cpus; - for (i = 0; i < ms->possible_cpus->len; i++) { - X86CPUTopoInfo topo; - - ms->possible_cpus->cpus[i].type = ms->cpu_type; - ms->possible_cpus->cpus[i].vcpus_count = 1; - ms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(i); - x86_topo_ids_from_apicid(ms->possible_cpus->cpus[i].arch_id, - smp_cores, smp_threads, &topo); - ms->possible_cpus->cpus[i].props.has_socket_id = true; - ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id; - ms->possible_cpus->cpus[i].props.has_core_id = true; - ms->possible_cpus->cpus[i].props.core_id = topo.core_id; - ms->possible_cpus->cpus[i].props.has_thread_id = true; - ms->possible_cpus->cpus[i].props.thread_id = topo.smt_id; - } - return ms->possible_cpus; -} - static void x86_nmi(NMIState *n, int cpu_index, Error **errp) { /* cpu index isn't used */ @@ -2732,13 +2593,13 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) pcmc->pvh_enabled = true; assert(!mc->get_hotplug_handler); mc->get_hotplug_handler = pc_get_hotplug_handler; - mc->cpu_index_to_instance_props = pc_cpu_index_to_props; - mc->get_default_cpu_node_id = pc_get_default_cpu_node_id; - mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids; + mc->cpu_index_to_instance_props = cpu_index_to_props; + mc->get_default_cpu_node_id = cpu_get_default_cpu_node_id; + mc->possible_cpu_arch_ids = cpu_possible_cpu_arch_ids; mc->auto_enable_numa_with_memhp = true; mc->has_hotpluggable_cpus = true; mc->default_boot_order = "cad"; - mc->hot_add_cpu = pc_hot_add_cpu; + mc->hot_add_cpu = cpu_hot_add; mc->block_default_type = IF_IDE; mc->max_cpus = 255; mc->reset = pc_machine_reset; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index c07c4a5b38..1e240004dd 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -28,6 +28,7 @@ #include "hw/hw.h" #include "hw/loader.h" #include "hw/i386/pc.h" +#include "hw/i386/cpu-internal.h" #include "hw/i386/apic.h" #include "hw/display/ramfb.h" #include "hw/firmware/smbios.h" @@ -150,7 +151,7 @@ static void pc_init1(MachineState *machine, } } - pc_cpus_init(pcms); + pcms->apic_id_limit = cpus_init(machine, compat_apic_id_mode); if (kvm_enabled() && pcmc->kvmclock_enabled) { kvmclock_create(); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 57232aed6b..308cd04a13 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -43,6 +43,7 @@ #include "hw/pci-host/q35.h" #include "exec/address-spaces.h" #include "hw/i386/pc.h" +#include "hw/i386/cpu-internal.h" #include "hw/i386/ich9.h" #include "hw/i386/amd_iommu.h" #include "hw/i386/intel_iommu.h" @@ -180,7 +181,7 @@ static void pc_q35_init(MachineState *machine) xen_hvm_init(pcms, &ram_memory); } - pc_cpus_init(pcms); + pcms->apic_id_limit = cpus_init(machine, compat_apic_id_mode); kvmclock_create(); diff --git a/include/hw/i386/apic.h b/include/hw/i386/apic.h index da1d2fe155..f72be753b8 100644 --- a/include/hw/i386/apic.h +++ b/include/hw/i386/apic.h @@ -23,5 +23,6 @@ int apic_get_highest_priority_irr(DeviceState *dev); /* pc.c */ DeviceState *cpu_get_current_apic(void); +extern bool compat_apic_id_mode; #endif diff --git a/include/hw/i386/cpu-internal.h b/include/hw/i386/cpu-internal.h new file mode 100644 index 0000000000..48a5253aa9 --- /dev/null +++ b/include/hw/i386/cpu-internal.h @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 2018 Intel Corportation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_I386_CPU_H +#define QEMU_I386_CPU_H + +#include "hw/boards.h" + +uint32_t cpu_apicid_from_index(unsigned int cpu_index, bool compat); + +CpuInstanceProperties cpu_index_to_props(MachineState *ms, unsigned cpu_index); +int64_t cpu_get_default_cpu_node_id(const MachineState *ms, int idx); +const CPUArchIdList *cpu_possible_cpu_arch_ids(MachineState *ms); + +void cpu_hot_add(const int64_t id, Error **errp); +uint32_t cpus_init(MachineState *ms, bool compat); + +#endif -- 2.21.0