|
@@ -308,8 +308,49 @@ bool is_x2apic_mode(DeviceState *dev)
|
|
return s->apicbase & MSR_IA32_APICBASE_EXTD;
|
|
return s->apicbase & MSR_IA32_APICBASE_EXTD;
|
|
}
|
|
}
|
|
|
|
|
|
-static void apic_set_base(APICCommonState *s, uint64_t val)
|
|
|
|
|
|
+static int apic_set_base_check(APICCommonState *s, uint64_t val)
|
|
{
|
|
{
|
|
|
|
+ /* Enable x2apic when x2apic is not supported by CPU */
|
|
|
|
+ if (!cpu_has_x2apic_feature(&s->cpu->env) &&
|
|
|
|
+ val & MSR_IA32_APICBASE_EXTD) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Transition into invalid state
|
|
|
|
+ * (s->apicbase & MSR_IA32_APICBASE_ENABLE == 0) &&
|
|
|
|
+ * (s->apicbase & MSR_IA32_APICBASE_EXTD) == 1
|
|
|
|
+ */
|
|
|
|
+ if (!(val & MSR_IA32_APICBASE_ENABLE) &&
|
|
|
|
+ (val & MSR_IA32_APICBASE_EXTD)) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Invalid transition from disabled mode to x2APIC */
|
|
|
|
+ if (!(s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
|
|
|
|
+ !(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
|
|
|
|
+ (val & MSR_IA32_APICBASE_ENABLE) &&
|
|
|
|
+ (val & MSR_IA32_APICBASE_EXTD)) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Invalid transition from x2APIC to xAPIC */
|
|
|
|
+ if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
|
|
|
|
+ (s->apicbase & MSR_IA32_APICBASE_EXTD) &&
|
|
|
|
+ (val & MSR_IA32_APICBASE_ENABLE) &&
|
|
|
|
+ !(val & MSR_IA32_APICBASE_EXTD)) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int apic_set_base(APICCommonState *s, uint64_t val)
|
|
|
|
+{
|
|
|
|
+ if (apic_set_base_check(s, val) < 0) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
s->apicbase = (val & 0xfffff000) |
|
|
s->apicbase = (val & 0xfffff000) |
|
|
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
|
|
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
|
|
/* if disabled, cannot be enabled again */
|
|
/* if disabled, cannot be enabled again */
|
|
@@ -318,6 +359,25 @@ static void apic_set_base(APICCommonState *s, uint64_t val)
|
|
cpu_clear_apic_feature(&s->cpu->env);
|
|
cpu_clear_apic_feature(&s->cpu->env);
|
|
s->spurious_vec &= ~APIC_SV_ENABLE;
|
|
s->spurious_vec &= ~APIC_SV_ENABLE;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* Transition from disabled mode to xAPIC */
|
|
|
|
+ if (!(s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
|
|
|
|
+ (val & MSR_IA32_APICBASE_ENABLE)) {
|
|
|
|
+ s->apicbase |= MSR_IA32_APICBASE_ENABLE;
|
|
|
|
+ cpu_set_apic_feature(&s->cpu->env);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Transition from xAPIC to x2APIC */
|
|
|
|
+ if (cpu_has_x2apic_feature(&s->cpu->env) &&
|
|
|
|
+ !(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
|
|
|
|
+ (val & MSR_IA32_APICBASE_EXTD)) {
|
|
|
|
+ s->apicbase |= MSR_IA32_APICBASE_EXTD;
|
|
|
|
+
|
|
|
|
+ s->log_dest = ((s->initial_apic_id & 0xffff0) << 16) |
|
|
|
|
+ (1 << (s->initial_apic_id & 0xf));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void apic_set_tpr(APICCommonState *s, uint8_t val)
|
|
static void apic_set_tpr(APICCommonState *s, uint8_t val)
|