aboutsummaryrefslogtreecommitdiff
path: root/target-i386/kvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-i386/kvm.c')
-rw-r--r--target-i386/kvm.c109
1 files changed, 78 insertions, 31 deletions
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 0a21c3085d..e555040a97 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -72,6 +72,9 @@ static bool has_msr_misc_enable;
static bool has_msr_bndcfgs;
static bool has_msr_kvm_steal_time;
static int lm_capable_kernel;
+static bool has_msr_hv_hypercall;
+static bool has_msr_hv_vapic;
+static bool has_msr_hv_tsc;
static bool has_msr_architectural_pmu;
static uint32_t num_architectural_pmu_counters;
@@ -437,8 +440,11 @@ static bool hyperv_hypercall_available(X86CPU *cpu)
static bool hyperv_enabled(X86CPU *cpu)
{
- return hyperv_hypercall_available(cpu) ||
- cpu->hyperv_relaxed_timing;
+ CPUState *cs = CPU(cpu);
+ return kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV) > 0 &&
+ (hyperv_hypercall_available(cpu) ||
+ cpu->hyperv_time ||
+ cpu->hyperv_relaxed_timing);
}
#define KVM_MAX_CPUID_ENTRIES 100
@@ -455,6 +461,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
uint32_t unused;
struct kvm_cpuid_entry2 *c;
uint32_t signature[3];
+ int kvm_base = KVM_CPUID_SIGNATURE;
int r;
memset(&cpuid_data, 0, sizeof(cpuid_data));
@@ -462,26 +469,22 @@ int kvm_arch_init_vcpu(CPUState *cs)
cpuid_i = 0;
/* Paravirtualization CPUIDs */
- c = &cpuid_data.entries[cpuid_i++];
- c->function = KVM_CPUID_SIGNATURE;
- if (!hyperv_enabled(cpu)) {
- memcpy(signature, "KVMKVMKVM\0\0\0", 12);
- c->eax = 0;
- } else {
+ if (hyperv_enabled(cpu)) {
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
memcpy(signature, "Microsoft Hv", 12);
c->eax = HYPERV_CPUID_MIN;
- }
- c->ebx = signature[0];
- c->ecx = signature[1];
- c->edx = signature[2];
-
- c = &cpuid_data.entries[cpuid_i++];
- c->function = KVM_CPUID_FEATURES;
- c->eax = env->features[FEAT_KVM];
+ c->ebx = signature[0];
+ c->ecx = signature[1];
+ c->edx = signature[2];
- if (hyperv_enabled(cpu)) {
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = HYPERV_CPUID_INTERFACE;
memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
c->eax = signature[0];
+ c->ebx = 0;
+ c->ecx = 0;
+ c->edx = 0;
c = &cpuid_data.entries[cpuid_i++];
c->function = HYPERV_CPUID_VERSION;
@@ -496,14 +499,21 @@ int kvm_arch_init_vcpu(CPUState *cs)
if (cpu->hyperv_vapic) {
c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
+ has_msr_hv_vapic = true;
+ }
+ if (cpu->hyperv_time &&
+ kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) {
+ c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+ c->eax |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
+ c->eax |= 0x200;
+ has_msr_hv_tsc = true;
}
-
c = &cpuid_data.entries[cpuid_i++];
c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
if (cpu->hyperv_relaxed_timing) {
c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED;
}
- if (cpu->hyperv_vapic) {
+ if (has_msr_hv_vapic) {
c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED;
}
c->ebx = cpu->hyperv_spinlock_attempts;
@@ -513,15 +523,22 @@ int kvm_arch_init_vcpu(CPUState *cs)
c->eax = 0x40;
c->ebx = 0x40;
- c = &cpuid_data.entries[cpuid_i++];
- c->function = KVM_CPUID_SIGNATURE_NEXT;
- memcpy(signature, "KVMKVMKVM\0\0\0", 12);
- c->eax = 0;
- c->ebx = signature[0];
- c->ecx = signature[1];
- c->edx = signature[2];
+ kvm_base = KVM_CPUID_SIGNATURE_NEXT;
+ has_msr_hv_hypercall = true;
}
+ memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = KVM_CPUID_SIGNATURE | kvm_base;
+ c->eax = 0;
+ c->ebx = signature[0];
+ c->ecx = signature[1];
+ c->edx = signature[2];
+
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = KVM_CPUID_FEATURES | kvm_base;
+ c->eax = env->features[FEAT_KVM];
+
has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI);
@@ -1220,12 +1237,19 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_GLOBAL_CTRL,
env->msr_global_ctrl);
}
- if (hyperv_hypercall_available(cpu)) {
- kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
- kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
+ if (has_msr_hv_hypercall) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID,
+ env->msr_hv_guest_os_id);
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL,
+ env->msr_hv_hypercall);
}
- if (cpu->hyperv_vapic) {
- kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0);
+ if (has_msr_hv_vapic) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE,
+ env->msr_hv_vapic);
+ }
+ if (has_msr_hv_tsc) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_REFERENCE_TSC,
+ env->msr_hv_tsc);
}
/* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
@@ -1511,6 +1535,17 @@ static int kvm_get_msrs(X86CPU *cpu)
}
}
+ if (has_msr_hv_hypercall) {
+ msrs[n++].index = HV_X64_MSR_HYPERCALL;
+ msrs[n++].index = HV_X64_MSR_GUEST_OS_ID;
+ }
+ if (has_msr_hv_vapic) {
+ msrs[n++].index = HV_X64_MSR_APIC_ASSIST_PAGE;
+ }
+ if (has_msr_hv_tsc) {
+ msrs[n++].index = HV_X64_MSR_REFERENCE_TSC;
+ }
+
msr_data.info.nmsrs = n;
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
if (ret < 0) {
@@ -1618,6 +1653,18 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL0 + MAX_GP_COUNTERS - 1:
env->msr_gp_evtsel[index - MSR_P6_EVNTSEL0] = msrs[i].data;
break;
+ case HV_X64_MSR_HYPERCALL:
+ env->msr_hv_hypercall = msrs[i].data;
+ break;
+ case HV_X64_MSR_GUEST_OS_ID:
+ env->msr_hv_guest_os_id = msrs[i].data;
+ break;
+ case HV_X64_MSR_APIC_ASSIST_PAGE:
+ env->msr_hv_vapic = msrs[i].data;
+ break;
+ case HV_X64_MSR_REFERENCE_TSC:
+ env->msr_hv_tsc = msrs[i].data;
+ break;
}
}