@@ -291,6 +291,7 @@ struct CPUState {
QTAILQ_HEAD(CPUTailQ, CPUState);
extern struct CPUTailQ cpus;
#define CPU_NEXT(cpu) QTAILQ_NEXT(cpu, node)
+#define CPU_REMOVE(cpu) QTAILQ_REMOVE(&cpus, cpu, node)
#define CPU_FOREACH(cpu) QTAILQ_FOREACH(cpu, &cpus, node)
#define CPU_FOREACH_SAFE(cpu, next_cpu) \
QTAILQ_FOREACH_SAFE(cpu, &cpus, node, next_cpu)
@@ -24,6 +24,7 @@
#include "qmp-commands.h"
#include "sysemu/arch_init.h"
#include "qemu/config-file.h"
+#include "qom/object_interfaces.h"
/*
* Aliases were a bad idea from the start. Let's keep them
@@ -49,6 +49,7 @@
#include "hw/i386/apic_internal.h"
#endif
+#include "qom/object_interfaces.h"
/* Cache topology CPUID constants: */
@@ -1550,6 +1551,7 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque,
const int64_t max = UINT32_MAX;
Error *error = NULL;
int64_t value;
+ X86CPUTopoInfo topo;
if (dev->realized) {
error_setg(errp, "Attempt to set property '%s' on '%s' after "
@@ -1569,10 +1571,24 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque,
return;
}
+ if (value > x86_cpu_apic_id_from_index(max_cpus - 1)) {
+ error_setg(errp, "CPU with APIC ID %" PRIi64
+ " is more than MAX APIC ID limits", value);
+ return;
+ }
+
+ x86_topo_ids_from_apic_id(smp_cores, smp_threads, value, &topo);
+ if (topo.smt_id >= smp_threads || topo.core_id >= smp_cores) {
+ error_setg(errp, "CPU with APIC ID %" PRIi64 " does not match "
+ "topology configuration.", value);
+ return;
+ }
+
if ((value != cpu->env.cpuid_apic_id) && cpu_exists(value)) {
error_setg(errp, "CPU with APIC ID %" PRIi64 " exists", value);
return;
}
+
cpu->env.cpuid_apic_id = value;
}
@@ -1994,12 +2010,22 @@ out:
return cpu;
}
+static void x86_cpu_cpudef_instance_init(Object *obj)
+{
+ DeviceState *dev = DEVICE(obj);
+
+ dev->hotplugged = true;
+}
+
static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data)
{
X86CPUDefinition *cpudef = data;
X86CPUClass *xcc = X86_CPU_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
xcc->cpu_def = cpudef;
+
+ dc->cannot_instantiate_with_device_add_yet = false;
}
static void x86_register_cpudef_type(X86CPUDefinition *def)
@@ -2008,6 +2034,8 @@ static void x86_register_cpudef_type(X86CPUDefinition *def)
TypeInfo ti = {
.name = typename,
.parent = TYPE_X86_CPU,
+ .instance_size = sizeof(X86CPU),
+ .instance_init = x86_cpu_cpudef_instance_init,
.class_init = x86_cpu_cpudef_class_init,
.class_data = def,
};
@@ -2544,8 +2572,17 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
return;
}
+ if (env->cpuid_apic_id > x86_cpu_apic_id_from_index(max_cpus - 1)) {
+ error_setg(errp, "CPU with APIC ID %" PRIi32
+ " is more than MAX APIC ID:%" PRIi32,
+ env->cpuid_apic_id,
+ x86_cpu_apic_id_from_index(max_cpus - 1));
+ return;
+ }
+
object_property_add_child(OBJECT(cpu), "apic",
OBJECT(cpu->apic_state), NULL);
+
qdev_prop_set_uint8(cpu->apic_state, "id", env->cpuid_apic_id);
/* TODO: convert to link<> */
apic = APIC_COMMON(cpu->apic_state);
@@ -2681,6 +2718,21 @@ uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index)
}
}
+static uint32_t get_free_apic_id(void)
+{
+ int i;
+
+ for (i = 0; i < max_cpus; i++) {
+ uint32_t id = x86_cpu_apic_id_from_index(i);
+
+ if (!cpu_exists(id)) {
+ return id;
+ }
+ }
+
+ return x86_cpu_apic_id_from_index(max_cpus);
+}
+
static void x86_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
@@ -2688,7 +2740,9 @@ static void x86_cpu_initfn(Object *obj)
X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
CPUX86State *env = &cpu->env;
static int inited;
+ uint32_t value;
+ value = get_free_apic_id();
cs->env_ptr = env;
cpu_exec_init(env);
@@ -2727,7 +2781,7 @@ static void x86_cpu_initfn(Object *obj)
NULL, NULL, (void *)cpu->filtered_features, NULL);
cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
- env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
+ env->cpuid_apic_id = value;
x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
@@ -2741,6 +2795,13 @@ static void x86_cpu_initfn(Object *obj)
}
}
+static void x86_cpu_finalizefn(Object *obj)
+{
+ CPUState *cs = CPU(obj);
+
+ CPU_REMOVE(cs);
+}
+
static int64_t x86_cpu_get_arch_id(CPUState *cs)
{
X86CPU *cpu = X86_CPU(cs);
@@ -2841,6 +2902,7 @@ static const TypeInfo x86_cpu_type_info = {
.parent = TYPE_CPU,
.instance_size = sizeof(X86CPU),
.instance_init = x86_cpu_initfn,
+ .instance_finalize = x86_cpu_finalizefn,
.abstract = true,
.class_size = sizeof(X86CPUClass),
.class_init = x86_cpu_common_class_init,
@@ -132,4 +132,22 @@ static inline apic_id_t x86_apicid_from_cpu_idx(unsigned nr_cores,
return apicid_from_topo_ids(nr_cores, nr_threads, &topo);
}
+/* Calculate CPU topology based on CPU APIC ID.
+ */
+static inline void x86_topo_ids_from_apic_id(unsigned nr_cores,
+ unsigned nr_threads,
+ apic_id_t apic_id,
+ X86CPUTopoInfo *topo)
+{
+ unsigned offset_mask;
+ topo->pkg_id = apic_id >> apicid_pkg_offset(nr_cores, nr_threads);
+
+ offset_mask = (1L << apicid_pkg_offset(nr_cores, nr_threads)) - 1;
+ topo->core_id = (apic_id & offset_mask)
+ >> apicid_core_offset(nr_cores, nr_threads);
+
+ offset_mask = (1L << apicid_core_offset(nr_cores, nr_threads)) - 1;
+ topo->smt_id = apic_id & offset_mask;
+}
+
#endif /* TARGET_I386_TOPOLOGY_H */