aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/i386/cpu.c1
-rw-r--r--target/i386/cpu.h1
-rw-r--r--target/i386/kvm.c56
-rw-r--r--target/i386/translate.c6
-rw-r--r--target/i386/whpx-all.c79
5 files changed, 127 insertions, 16 deletions
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 555ae79d29..1a6b082b6f 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -4761,6 +4761,7 @@ static Property x86_cpu_properties[] = {
DEFINE_PROP_BOOL("hv-runtime", X86CPU, hyperv_runtime, false),
DEFINE_PROP_BOOL("hv-synic", X86CPU, hyperv_synic, false),
DEFINE_PROP_BOOL("hv-stimer", X86CPU, hyperv_stimer, false),
+ DEFINE_PROP_BOOL("hv-frequencies", X86CPU, hyperv_frequencies, false),
DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true),
DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 78db1b833a..1b219fafc4 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1296,6 +1296,7 @@ struct X86CPU {
bool hyperv_runtime;
bool hyperv_synic;
bool hyperv_stimer;
+ bool hyperv_frequencies;
bool check_cpuid;
bool enforce_cpuid;
bool expose_kvm;
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index d23fff12f5..6c49954e68 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -632,11 +632,6 @@ static int hyperv_handle_properties(CPUState *cs)
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
- if (cpu->hyperv_time &&
- kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) <= 0) {
- cpu->hyperv_time = false;
- }
-
if (cpu->hyperv_relaxed_timing) {
env->features[FEAT_HYPERV_EAX] |= HV_HYPERCALL_AVAILABLE;
}
@@ -645,26 +640,61 @@ static int hyperv_handle_properties(CPUState *cs)
env->features[FEAT_HYPERV_EAX] |= HV_APIC_ACCESS_AVAILABLE;
}
if (cpu->hyperv_time) {
+ if (kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) <= 0) {
+ fprintf(stderr, "Hyper-V clocksources "
+ "(requested by 'hv-time' cpu flag) "
+ "are not supported by kernel\n");
+ return -ENOSYS;
+ }
env->features[FEAT_HYPERV_EAX] |= HV_HYPERCALL_AVAILABLE;
env->features[FEAT_HYPERV_EAX] |= HV_TIME_REF_COUNT_AVAILABLE;
env->features[FEAT_HYPERV_EAX] |= HV_REFERENCE_TSC_AVAILABLE;
-
- if (has_msr_hv_frequencies && tsc_is_stable_and_known(env)) {
- env->features[FEAT_HYPERV_EAX] |= HV_ACCESS_FREQUENCY_MSRS;
- env->features[FEAT_HYPERV_EDX] |= HV_FREQUENCY_MSRS_AVAILABLE;
+ }
+ if (cpu->hyperv_frequencies) {
+ if (!has_msr_hv_frequencies) {
+ fprintf(stderr, "Hyper-V frequency MSRs "
+ "(requested by 'hv-frequencies' cpu flag) "
+ "are not supported by kernel\n");
+ return -ENOSYS;
}
+ env->features[FEAT_HYPERV_EAX] |= HV_ACCESS_FREQUENCY_MSRS;
+ env->features[FEAT_HYPERV_EDX] |= HV_FREQUENCY_MSRS_AVAILABLE;
}
- if (cpu->hyperv_crash && has_msr_hv_crash) {
+ if (cpu->hyperv_crash) {
+ if (!has_msr_hv_crash) {
+ fprintf(stderr, "Hyper-V crash MSRs "
+ "(requested by 'hv-crash' cpu flag) "
+ "are not supported by kernel\n");
+ return -ENOSYS;
+ }
env->features[FEAT_HYPERV_EDX] |= HV_GUEST_CRASH_MSR_AVAILABLE;
}
env->features[FEAT_HYPERV_EDX] |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE;
- if (cpu->hyperv_reset && has_msr_hv_reset) {
+ if (cpu->hyperv_reset) {
+ if (!has_msr_hv_reset) {
+ fprintf(stderr, "Hyper-V reset MSR "
+ "(requested by 'hv-reset' cpu flag) "
+ "is not supported by kernel\n");
+ return -ENOSYS;
+ }
env->features[FEAT_HYPERV_EAX] |= HV_RESET_AVAILABLE;
}
- if (cpu->hyperv_vpindex && has_msr_hv_vpindex) {
+ if (cpu->hyperv_vpindex) {
+ if (!has_msr_hv_vpindex) {
+ fprintf(stderr, "Hyper-V VP_INDEX MSR "
+ "(requested by 'hv-vpindex' cpu flag) "
+ "is not supported by kernel\n");
+ return -ENOSYS;
+ }
env->features[FEAT_HYPERV_EAX] |= HV_VP_INDEX_AVAILABLE;
}
- if (cpu->hyperv_runtime && has_msr_hv_runtime) {
+ if (cpu->hyperv_runtime) {
+ if (!has_msr_hv_runtime) {
+ fprintf(stderr, "Hyper-V VP_RUNTIME MSR "
+ "(requested by 'hv-runtime' cpu flag) "
+ "is not supported by kernel\n");
+ return -ENOSYS;
+ }
env->features[FEAT_HYPERV_EAX] |= HV_VP_RUNTIME_AVAILABLE;
}
if (cpu->hyperv_synic) {
diff --git a/target/i386/translate.c b/target/i386/translate.c
index 0135415d92..c9ed8dc709 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -3802,7 +3802,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
}
ot = mo_64_32(s->dflag);
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
- tcg_gen_andc_tl(cpu_T0, cpu_regs[s->vex_v], cpu_T0);
+ tcg_gen_andc_tl(cpu_T0, cpu_T0, cpu_regs[s->vex_v]);
gen_op_mov_reg_v(ot, reg, cpu_T0);
gen_op_update1_cc();
set_cc_op(s, CC_OP_LOGICB + ot);
@@ -4563,9 +4563,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
#endif
rex_r = (~vex2 >> 4) & 8;
if (b == 0xc5) {
+ /* 2-byte VEX prefix: RVVVVlpp, implied 0f leading opcode byte */
vex3 = vex2;
- b = x86_ldub_code(env, s);
+ b = x86_ldub_code(env, s) | 0x100;
} else {
+ /* 3-byte VEX prefix: RXBmmmmm wVVVVlpp */
#ifdef TARGET_X86_64
s->rex_x = (~vex2 >> 3) & 8;
s->rex_b = (~vex2 >> 2) & 8;
diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c
index bf33d320bf..58435178a4 100644
--- a/target/i386/whpx-all.c
+++ b/target/i386/whpx-all.c
@@ -911,12 +911,62 @@ static int whpx_vcpu_run(CPUState *cpu)
ret = 1;
break;
+ case WHvRunVpExitReasonX64Cpuid: {
+ WHV_REGISTER_VALUE reg_values[5] = {0};
+ WHV_REGISTER_NAME reg_names[5];
+ UINT32 reg_count = 5;
+ UINT64 rip, rax, rcx, rdx, rbx;
+
+ rip = vcpu->exit_ctx.VpContext.Rip +
+ vcpu->exit_ctx.VpContext.InstructionLength;
+ switch (vcpu->exit_ctx.CpuidAccess.Rax) {
+ case 1:
+ rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
+ /* Advertise that we are running on a hypervisor */
+ rcx =
+ vcpu->exit_ctx.CpuidAccess.DefaultResultRcx |
+ CPUID_EXT_HYPERVISOR;
+
+ rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
+ rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
+ break;
+ default:
+ rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
+ rcx = vcpu->exit_ctx.CpuidAccess.DefaultResultRcx;
+ rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
+ rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
+ }
+
+ reg_names[0] = WHvX64RegisterRip;
+ reg_names[1] = WHvX64RegisterRax;
+ reg_names[2] = WHvX64RegisterRcx;
+ reg_names[3] = WHvX64RegisterRdx;
+ reg_names[4] = WHvX64RegisterRbx;
+
+ reg_values[0].Reg64 = rip;
+ reg_values[1].Reg64 = rax;
+ reg_values[2].Reg64 = rcx;
+ reg_values[3].Reg64 = rdx;
+ reg_values[4].Reg64 = rbx;
+
+ hr = WHvSetVirtualProcessorRegisters(whpx->partition,
+ cpu->cpu_index,
+ reg_names,
+ reg_count,
+ reg_values);
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set CpuidAccess state registers,"
+ " hr=%08lx", hr);
+ }
+ ret = 0;
+ break;
+ }
case WHvRunVpExitReasonNone:
case WHvRunVpExitReasonUnrecoverableException:
case WHvRunVpExitReasonInvalidVpRegisterValue:
case WHvRunVpExitReasonUnsupportedFeature:
case WHvRunVpExitReasonX64MsrAccess:
- case WHvRunVpExitReasonX64Cpuid:
case WHvRunVpExitReasonException:
default:
error_report("WHPX: Unexpected VP exit code %d",
@@ -1272,6 +1322,33 @@ static int whpx_accel_init(MachineState *ms)
goto error;
}
+ memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
+ prop.ExtendedVmExits.X64CpuidExit = 1;
+ hr = WHvSetPartitionProperty(whpx->partition,
+ WHvPartitionPropertyCodeExtendedVmExits,
+ &prop,
+ sizeof(WHV_PARTITION_PROPERTY));
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to enable partition extended X64CpuidExit"
+ " hr=%08lx", hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ UINT32 cpuidExitList[] = {1};
+ hr = WHvSetPartitionProperty(whpx->partition,
+ WHvPartitionPropertyCodeCpuidExitList,
+ cpuidExitList,
+ RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx",
+ hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
hr = WHvSetupPartition(whpx->partition);
if (FAILED(hr)) {
error_report("WHPX: Failed to setup partition, hr=%08lx", hr);