apic_common_set_id() dereferences s->cpu to check for x2APIC support
when the APIC ID is >= 255. On a standalone APIC object that has not
been attached to a CPU, s->cpu is NULL, causing a segfault.
To solve this, move validation during realize().
Fixes: b5ee0468e9d2 ("apic: add support for x2APIC mode")
Signed-off-by: Marc-André Lureau <[email protected]>
---
hw/intc/apic_common.c | 23 +++++++++++++----------
target/i386/cpu-apic.c | 6 +-----
2 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index bf4abc21d7b..49c03a5bcee 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -257,6 +257,19 @@ static void apic_common_realize(DeviceState *dev, Error
**errp)
static DeviceState *vapic;
uint32_t instance_id = s->initial_apic_id;
+ if (!s->cpu) {
+ error_setg(errp, "APIC is not attached to a CPU");
+ return;
+ }
+
+ if (s->initial_apic_id >= 255 &&
+ !cpu_has_x2apic_feature(&s->cpu->env)) {
+ error_setg(errp, "APIC ID %d requires x2APIC feature in CPU",
+ s->initial_apic_id);
+ error_append_hint(errp, "Try x2apic=on in -cpu.\n");
+ return;
+ }
+
/* Normally initial APIC ID should be no more than hundreds */
assert(instance_id != VMSTATE_INSTANCE_ID_ANY);
@@ -410,7 +423,6 @@ static void apic_common_set_id(Object *obj, Visitor *v,
const char *name,
APICCommonState *s = APIC_COMMON(obj);
DeviceState *dev = DEVICE(obj);
uint32_t value;
- Error *local_err = NULL;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
@@ -421,15 +433,6 @@ static void apic_common_set_id(Object *obj, Visitor *v,
const char *name,
return;
}
- if (value >= 255 && !cpu_has_x2apic_feature(&s->cpu->env)) {
- error_setg(&local_err,
- "APIC ID %d requires x2APIC feature in CPU",
- value);
- error_append_hint(&local_err, "Try x2apic=on in -cpu.\n");
- error_propagate(errp, local_err);
- return;
- }
-
s->initial_apic_id = value;
s->id = (uint8_t)value;
}
diff --git a/target/i386/cpu-apic.c b/target/i386/cpu-apic.c
index 5599a4675c5..04b7257ad12 100644
--- a/target/i386/cpu-apic.c
+++ b/target/i386/cpu-apic.c
@@ -56,11 +56,7 @@ void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
cpu->apic_state->cpu = cpu;
cpu->apic_state->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 cpu->apic_state->cpu
- * before setting APIC ID
- */
+ /* cpu must be set before realize, which validates the APIC ID */
qdev_prop_set_uint32(DEVICE(cpu->apic_state), "id", cpu->apic_id);
}
--
2.54.0