#ifdef TARGET_X86_64
WHvX64RegisterKernelGsBase,
#endif
- WHvX64RegisterApicBase,
/* WHvX64RegisterPat, */
WHvX64RegisterSysenterCs,
WHvX64RegisterSysenterEip,
r86 = !(env->cr[0] & CR0_PE_MASK);
vcpu->tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
- vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state);
idx = 0;
vcxt.values[idx++].Reg64 = env->kernelgsbase;
#endif
- assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
- vcxt.values[idx++].Reg64 = vcpu->apic_base;
-
/* WHvX64RegisterPat - Skipped */
assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
error_report("WHPX: Failed to set virtual processor context, hr=%08lx",
hr);
}
+
+ if (level >= WHPX_LEVEL_FULL_STATE) {
+ WHV_REGISTER_VALUE apic_base = {};
+ apic_base.Reg64 = cpu_get_apic_base(X86_CPU(cpu)->apic_state);
+ whpx_set_reg(cpu, WHvX64RegisterApicBase, apic_base);
+ }
}
static int whpx_get_tsc(CPUState *cpu)
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
struct whpx_register_set vcxt;
- uint64_t tpr, apic_base;
+ uint64_t tpr;
HRESULT hr;
int idx;
int idx_next;
env->kernelgsbase = vcxt.values[idx++].Reg64;
#endif
- assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
- apic_base = vcxt.values[idx++].Reg64;
- if (apic_base != vcpu->apic_base) {
- vcpu->apic_base = apic_base;
- cpu_set_apic_base(x86_cpu->apic_state, vcpu->apic_base);
- }
-
/* WHvX64RegisterPat - Skipped */
assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
val = X86_CPU(cpu)->env.apic_bus_freq;
}
- if (!whpx_irqchip_in_kernel() &&
- vcpu->exit_ctx.MsrAccess.MsrNumber == MSR_IA32_APICBASE) {
+ if (vcpu->exit_ctx.MsrAccess.MsrNumber == MSR_IA32_APICBASE) {
is_known_msr = 1;
if (!vcpu->exit_ctx.MsrAccess.AccessInfo.IsWrite) {
/* Read path unreachable on Hyper-V */
} else {
reg_values[2].Reg32 &= ~CPUID_EXT_X2APIC;
}
+
+ /* CPUID[1:EDX].APIC is dynamic */
+ if (env->features[FEAT_1_EDX] & CPUID_APIC) {
+ reg_values[3].Reg32 |= CPUID_APIC;
+ } else {
+ reg_values[3].Reg32 &= ~CPUID_APIC;
+ }
}
/* Dynamic depending on XCR0 and XSS, so query DefaultResult */
memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
prop.X64MsrExitBitmap.UnhandledMsrs = 1;
- if (!whpx_irqchip_in_kernel()) {
- prop.X64MsrExitBitmap.ApicBaseMsrWrite = 1;
- }
+ prop.X64MsrExitBitmap.ApicBaseMsrWrite = 1;
hr = whp_dispatch.WHvSetPartitionProperty(
whpx->partition,
apic_next_timer(s, s->initial_count_load_time);
}
-static int whpx_apic_set_base(APICCommonState *s, uint64_t val)
+static int apic_set_base_check(APICCommonState *s, uint64_t val)
{
- s->apicbase = 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 & MSR_IA32_APICBASE_BASE) |
+ (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
+ if (!(val & MSR_IA32_APICBASE_ENABLE)) {
+ s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
+ cpu_clear_apic_feature(&s->cpu->env);
+ }
+
+ /* 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;
+ }
+
return 0;
}
static const MemoryRegionOps whpx_apic_io_ops = {
.read = whpx_apic_mem_read,
.write = whpx_apic_mem_write,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
.endianness = DEVICE_LITTLE_ENDIAN,
};
k->realize = whpx_apic_realize;
k->reset = whpx_apic_reset;
- k->set_base = whpx_apic_set_base;
+ k->set_base = apic_set_base;
k->set_tpr = whpx_apic_set_tpr;
k->get_tpr = whpx_apic_get_tpr;
k->post_load = whpx_apic_post_load;