diff mbox series

[1/4] hw/i386: Factorize CPU routine

Message ID 20190628115349.60293-2-slp@redhat.com
State New
Headers show
Series Introduce the microvm machine type | expand

Commit Message

Sergio Lopez June 28, 2019, 11:53 a.m. UTC
This is a combination of the following commits from
NEMU (https://github.com/intel/nemu):

===============================================
commit b6472ce5ce5108c7aacb0dfa3d74b3eb8f98ae85
Author: Samuel Ortiz <sameo@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 <sameo@linux.intel.com>

commit f29f3c294a889ad659dc8808728e8441e23a675c
Author: Samuel Ortiz <sameo@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 <sameo@linux.intel.com>
===============================================

Signed-off-by: Sergio Lopez <slp@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

Comments

Eduardo Habkost June 28, 2019, 8:03 p.m. UTC | #1
On Fri, Jun 28, 2019 at 01:53:46PM +0200, Sergio Lopez wrote:
[...]
>  /* Enables contiguous-apic-ID mode, for compatibility */
> -static bool compat_apic_id_mode;
> +bool compat_apic_id_mode;

We can get rid of this global variable, see the patch I have just
sent:

  [PATCH] pc: Move compat_apic_id_mode variable to PCMachineClass
Sergio Lopez June 28, 2019, 9:44 p.m. UTC | #2
Eduardo Habkost <ehabkost@redhat.com> writes:

> On Fri, Jun 28, 2019 at 01:53:46PM +0200, Sergio Lopez wrote:
> [...]
>>  /* Enables contiguous-apic-ID mode, for compatibility */
>> -static bool compat_apic_id_mode;
>> +bool compat_apic_id_mode;
>
> We can get rid of this global variable, see the patch I have just
> sent:
>
>   [PATCH] pc: Move compat_apic_id_mode variable to PCMachineClass

Nice. I'll adapt the v2 of the patchset to assume this has been
committed.

Thanks!
Sergio.
Michael S. Tsirkin July 1, 2019, 9:25 a.m. UTC | #3
On Fri, Jun 28, 2019 at 11:44:07PM +0200, Sergio Lopez wrote:
> 
> Eduardo Habkost <ehabkost@redhat.com> writes:
> 
> > On Fri, Jun 28, 2019 at 01:53:46PM +0200, Sergio Lopez wrote:
> > [...]
> >>  /* Enables contiguous-apic-ID mode, for compatibility */
> >> -static bool compat_apic_id_mode;
> >> +bool compat_apic_id_mode;
> >
> > We can get rid of this global variable, see the patch I have just
> > sent:
> >
> >   [PATCH] pc: Move compat_apic_id_mode variable to PCMachineClass
> 
> Nice. I'll adapt the v2 of the patchset to assume this has been
> committed.
> 
> Thanks!
> Sergio.


or include it for completeness.
diff mbox series

Patch

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