Message ID | 1466765376-25722-1-git-send-email-den@openvz.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 06/24/2016 01:49 PM, Denis V. Lunev wrote: > From: Evgeny Yakovlev <eyakovlev@virtuozzo.com> > > This change adds hyperv feature words report through qom rpc. > > When VM is configured with hyperv features enabled > libvirt will check that required feature words are set > in cpuid leaf 40000003 through qom request. > > Currently qemu does not report hyperv feature words > which prevents windows guests from starting with libvirt. > > To avoid conflicting with current hyperv properties all added feature > words cannot be set directly with -cpu +feature yet. > > Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com> > Signed-off-by: Denis V. Lunev <den@openvz.org> > CC: Paolo Bonzini <pbonzini@redhat.com> > CC: Richard Henderson <rth@twiddle.net> > CC: Eduardo Habkost <ehabkost@redhat.com> > CC: Marcelo Tosatti <mtosatti@redhat.com> > --- > Changes from v2: > - removed all hyperv feature_names so that we don't have two ways of > setting CPUID bits > > Changes from v1: > - renamed hyperv features so they don't conflict with hyperv properties > - refactored kvm_arch_init_vcpu to process hyperv props into feature words > > target-i386/cpu.c | 53 +++++++++++++++++++++++++ > target-i386/cpu.h | 3 ++ > target-i386/kvm.c | 114 +++++++++++++++++++++++++++++++----------------------- > 3 files changed, 122 insertions(+), 48 deletions(-) > > diff --git a/target-i386/cpu.c b/target-i386/cpu.c > index 3bd3cfc..d07da78 100644 > --- a/target-i386/cpu.c > +++ b/target-i386/cpu.c > @@ -245,6 +245,47 @@ static const char *kvm_feature_name[] = { > NULL, NULL, NULL, NULL, > }; > > +static const char *hyperv_priv_feature_name[] = { > + NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */, > + NULL /* hv_msr_synic_access */, NULL /* hv_msr_stimer_access */, > + NULL /* hv_msr_apic_access */, NULL /* hv_msr_hypercall_access */, > + NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */, > + NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */, > + NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access */, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > +}; > + > +static const char *hyperv_ident_feature_name[] = { > + NULL /* hv_create_partitions */, NULL /* hv_access_partition_id */, > + NULL /* hv_access_memory_pool */, NULL /* hv_adjust_message_buffers */, > + NULL /* hv_post_messages */, NULL /* hv_signal_events */, > + NULL /* hv_create_port */, NULL /* hv_connect_port */, > + NULL /* hv_access_stats */, NULL, NULL, NULL /* hv_debugging */, > + NULL /* hv_cpu_power_management */, NULL /* hv_configure_profiler */, > + NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > +}; > + > +static const char *hyperv_misc_feature_name[] = { > + NULL /* hv_mwait */, NULL /* hv_guest_debugging */, > + NULL /* hv_perf_monitor */, NULL /* hv_cpu_dynamic_part */, > + NULL /* hv_hypercall_params_xmm */, NULL /* hv_guest_idle_state */, > + NULL, NULL, > + NULL, NULL, NULL /* hv_guest_crash_msr */, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > +}; > + > static const char *svm_feature_name[] = { > "npt", "lbrv", "svm_lock", "nrip_save", > "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists", > @@ -411,6 +452,18 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { > .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX, > .tcg_features = TCG_KVM_FEATURES, > }, > + [FEAT_HYPERV_EAX] = { > + .feat_names = hyperv_priv_feature_name, > + .cpuid_eax = 0x40000003, .cpuid_reg = R_EAX, > + }, > + [FEAT_HYPERV_EBX] = { > + .feat_names = hyperv_ident_feature_name, > + .cpuid_eax = 0x40000003, .cpuid_reg = R_EBX, > + }, > + [FEAT_HYPERV_EDX] = { > + .feat_names = hyperv_misc_feature_name, > + .cpuid_eax = 0x40000003, .cpuid_reg = R_EDX, > + }, > [FEAT_SVM] = { > .feat_names = svm_feature_name, > .cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX, > diff --git a/target-i386/cpu.h b/target-i386/cpu.h > index d9ab884..4496c8b 100644 > --- a/target-i386/cpu.h > +++ b/target-i386/cpu.h > @@ -440,6 +440,9 @@ typedef enum FeatureWord { > FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */ > FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ > FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ > + FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */ > + FEAT_HYPERV_EBX, /* CPUID[4000_0003].EBX */ > + FEAT_HYPERV_EDX, /* CPUID[4000_0003].EDX */ > FEAT_SVM, /* CPUID[8000_000A].EDX */ > FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */ > FEAT_6_EAX, /* CPUID[6].EAX */ > diff --git a/target-i386/kvm.c b/target-i386/kvm.c > index f3698f1..f44e3c7 100644 > --- a/target-i386/kvm.c > +++ b/target-i386/kvm.c > @@ -574,6 +574,66 @@ static int kvm_arch_set_tsc_khz(CPUState *cs) > return 0; > } > > +static int hyperv_handle_properties(CPUState *cs) > +{ > + X86CPU *cpu = X86_CPU(cs); > + CPUX86State *env = &cpu->env; > + > + if (cpu->hyperv_relaxed_timing) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; > + } > + if (cpu->hyperv_vapic) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; > + env->features[FEAT_HYPERV_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) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; > + env->features[FEAT_HYPERV_EAX] |= 0x200; > + has_msr_hv_tsc = true; > + } > + if (cpu->hyperv_crash && has_msr_hv_crash) { > + env->features[FEAT_HYPERV_EDX] |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; > + } > + if (cpu->hyperv_reset && has_msr_hv_reset) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_RESET_AVAILABLE; > + } > + if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_INDEX_AVAILABLE; > + } > + if (cpu->hyperv_runtime && has_msr_hv_runtime) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; > + } > + if (cpu->hyperv_synic) { > + int sint; > + > + if (!has_msr_hv_synic || > + kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { > + fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); > + return -ENOSYS; > + } > + > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNIC_AVAILABLE; > + env->msr_hv_synic_version = HV_SYNIC_VERSION_1; > + for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { > + env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; > + } > + } > + if (cpu->hyperv_stimer) { > + if (!has_msr_hv_stimer) { > + fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); > + return -ENOSYS; > + } > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNTIMER_AVAILABLE; > + } > + if (MACHINE_GET_CLASS(current_machine)->hot_add_cpu != NULL) { > + env->features[FEAT_HYPERV_EDX] |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; > + } > + return 0; > +} > + > static Error *invtsc_mig_blocker; > > #define KVM_MAX_CPUID_ENTRIES 100 > @@ -633,56 +693,14 @@ int kvm_arch_init_vcpu(CPUState *cs) > > c = &cpuid_data.entries[cpuid_i++]; > c->function = HYPERV_CPUID_FEATURES; > - if (cpu->hyperv_relaxed_timing) { > - c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; > - } > - 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; > - } > - if (cpu->hyperv_crash && has_msr_hv_crash) { > - c->edx |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; > - } > - c->edx |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; > - if (cpu->hyperv_reset && has_msr_hv_reset) { > - c->eax |= HV_X64_MSR_RESET_AVAILABLE; > - } > - if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { > - c->eax |= HV_X64_MSR_VP_INDEX_AVAILABLE; > - } > - if (cpu->hyperv_runtime && has_msr_hv_runtime) { > - c->eax |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; > + r = hyperv_handle_properties(cs); > + if (r) { > + return r; > } > - if (cpu->hyperv_synic) { > - int sint; > - > - if (!has_msr_hv_synic || > - kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { > - fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); > - return -ENOSYS; > - } > + c->eax = env->features[FEAT_HYPERV_EAX]; > + c->ebx = env->features[FEAT_HYPERV_EBX]; > + c->edx = env->features[FEAT_HYPERV_EDX]; > > - c->eax |= HV_X64_MSR_SYNIC_AVAILABLE; > - env->msr_hv_synic_version = HV_SYNIC_VERSION_1; > - for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { > - env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; > - } > - } > - if (cpu->hyperv_stimer) { > - if (!has_msr_hv_stimer) { > - fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); > - return -ENOSYS; > - } > - c->eax |= HV_X64_MSR_SYNTIMER_AVAILABLE; > - } > c = &cpuid_data.entries[cpuid_i++]; > c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; > if (cpu->hyperv_relaxed_timing) { ping
On 06/24/2016 01:49 PM, Denis V. Lunev wrote: > From: Evgeny Yakovlev <eyakovlev@virtuozzo.com> > > This change adds hyperv feature words report through qom rpc. > > When VM is configured with hyperv features enabled > libvirt will check that required feature words are set > in cpuid leaf 40000003 through qom request. > > Currently qemu does not report hyperv feature words > which prevents windows guests from starting with libvirt. > > To avoid conflicting with current hyperv properties all added feature > words cannot be set directly with -cpu +feature yet. > > Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com> > Signed-off-by: Denis V. Lunev <den@openvz.org> > CC: Paolo Bonzini <pbonzini@redhat.com> > CC: Richard Henderson <rth@twiddle.net> > CC: Eduardo Habkost <ehabkost@redhat.com> > CC: Marcelo Tosatti <mtosatti@redhat.com> > --- > Changes from v2: > - removed all hyperv feature_names so that we don't have two ways of > setting CPUID bits > > Changes from v1: > - renamed hyperv features so they don't conflict with hyperv properties > - refactored kvm_arch_init_vcpu to process hyperv props into feature words > > target-i386/cpu.c | 53 +++++++++++++++++++++++++ > target-i386/cpu.h | 3 ++ > target-i386/kvm.c | 114 +++++++++++++++++++++++++++++++----------------------- > 3 files changed, 122 insertions(+), 48 deletions(-) > > diff --git a/target-i386/cpu.c b/target-i386/cpu.c > index 3bd3cfc..d07da78 100644 > --- a/target-i386/cpu.c > +++ b/target-i386/cpu.c > @@ -245,6 +245,47 @@ static const char *kvm_feature_name[] = { > NULL, NULL, NULL, NULL, > }; > > +static const char *hyperv_priv_feature_name[] = { > + NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */, > + NULL /* hv_msr_synic_access */, NULL /* hv_msr_stimer_access */, > + NULL /* hv_msr_apic_access */, NULL /* hv_msr_hypercall_access */, > + NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */, > + NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */, > + NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access */, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > +}; > + > +static const char *hyperv_ident_feature_name[] = { > + NULL /* hv_create_partitions */, NULL /* hv_access_partition_id */, > + NULL /* hv_access_memory_pool */, NULL /* hv_adjust_message_buffers */, > + NULL /* hv_post_messages */, NULL /* hv_signal_events */, > + NULL /* hv_create_port */, NULL /* hv_connect_port */, > + NULL /* hv_access_stats */, NULL, NULL, NULL /* hv_debugging */, > + NULL /* hv_cpu_power_management */, NULL /* hv_configure_profiler */, > + NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > +}; > + > +static const char *hyperv_misc_feature_name[] = { > + NULL /* hv_mwait */, NULL /* hv_guest_debugging */, > + NULL /* hv_perf_monitor */, NULL /* hv_cpu_dynamic_part */, > + NULL /* hv_hypercall_params_xmm */, NULL /* hv_guest_idle_state */, > + NULL, NULL, > + NULL, NULL, NULL /* hv_guest_crash_msr */, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > +}; > + > static const char *svm_feature_name[] = { > "npt", "lbrv", "svm_lock", "nrip_save", > "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists", > @@ -411,6 +452,18 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { > .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX, > .tcg_features = TCG_KVM_FEATURES, > }, > + [FEAT_HYPERV_EAX] = { > + .feat_names = hyperv_priv_feature_name, > + .cpuid_eax = 0x40000003, .cpuid_reg = R_EAX, > + }, > + [FEAT_HYPERV_EBX] = { > + .feat_names = hyperv_ident_feature_name, > + .cpuid_eax = 0x40000003, .cpuid_reg = R_EBX, > + }, > + [FEAT_HYPERV_EDX] = { > + .feat_names = hyperv_misc_feature_name, > + .cpuid_eax = 0x40000003, .cpuid_reg = R_EDX, > + }, > [FEAT_SVM] = { > .feat_names = svm_feature_name, > .cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX, > diff --git a/target-i386/cpu.h b/target-i386/cpu.h > index d9ab884..4496c8b 100644 > --- a/target-i386/cpu.h > +++ b/target-i386/cpu.h > @@ -440,6 +440,9 @@ typedef enum FeatureWord { > FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */ > FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ > FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ > + FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */ > + FEAT_HYPERV_EBX, /* CPUID[4000_0003].EBX */ > + FEAT_HYPERV_EDX, /* CPUID[4000_0003].EDX */ > FEAT_SVM, /* CPUID[8000_000A].EDX */ > FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */ > FEAT_6_EAX, /* CPUID[6].EAX */ > diff --git a/target-i386/kvm.c b/target-i386/kvm.c > index f3698f1..f44e3c7 100644 > --- a/target-i386/kvm.c > +++ b/target-i386/kvm.c > @@ -574,6 +574,66 @@ static int kvm_arch_set_tsc_khz(CPUState *cs) > return 0; > } > > +static int hyperv_handle_properties(CPUState *cs) > +{ > + X86CPU *cpu = X86_CPU(cs); > + CPUX86State *env = &cpu->env; > + > + if (cpu->hyperv_relaxed_timing) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; > + } > + if (cpu->hyperv_vapic) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; > + env->features[FEAT_HYPERV_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) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; > + env->features[FEAT_HYPERV_EAX] |= 0x200; > + has_msr_hv_tsc = true; > + } > + if (cpu->hyperv_crash && has_msr_hv_crash) { > + env->features[FEAT_HYPERV_EDX] |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; > + } > + if (cpu->hyperv_reset && has_msr_hv_reset) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_RESET_AVAILABLE; > + } > + if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_INDEX_AVAILABLE; > + } > + if (cpu->hyperv_runtime && has_msr_hv_runtime) { > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; > + } > + if (cpu->hyperv_synic) { > + int sint; > + > + if (!has_msr_hv_synic || > + kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { > + fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); > + return -ENOSYS; > + } > + > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNIC_AVAILABLE; > + env->msr_hv_synic_version = HV_SYNIC_VERSION_1; > + for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { > + env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; > + } > + } > + if (cpu->hyperv_stimer) { > + if (!has_msr_hv_stimer) { > + fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); > + return -ENOSYS; > + } > + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNTIMER_AVAILABLE; > + } > + if (MACHINE_GET_CLASS(current_machine)->hot_add_cpu != NULL) { > + env->features[FEAT_HYPERV_EDX] |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; > + } > + return 0; > +} > + > static Error *invtsc_mig_blocker; > > #define KVM_MAX_CPUID_ENTRIES 100 > @@ -633,56 +693,14 @@ int kvm_arch_init_vcpu(CPUState *cs) > > c = &cpuid_data.entries[cpuid_i++]; > c->function = HYPERV_CPUID_FEATURES; > - if (cpu->hyperv_relaxed_timing) { > - c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; > - } > - 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; > - } > - if (cpu->hyperv_crash && has_msr_hv_crash) { > - c->edx |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; > - } > - c->edx |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; > - if (cpu->hyperv_reset && has_msr_hv_reset) { > - c->eax |= HV_X64_MSR_RESET_AVAILABLE; > - } > - if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { > - c->eax |= HV_X64_MSR_VP_INDEX_AVAILABLE; > - } > - if (cpu->hyperv_runtime && has_msr_hv_runtime) { > - c->eax |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; > + r = hyperv_handle_properties(cs); > + if (r) { > + return r; > } > - if (cpu->hyperv_synic) { > - int sint; > - > - if (!has_msr_hv_synic || > - kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { > - fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); > - return -ENOSYS; > - } > + c->eax = env->features[FEAT_HYPERV_EAX]; > + c->ebx = env->features[FEAT_HYPERV_EBX]; > + c->edx = env->features[FEAT_HYPERV_EDX]; > > - c->eax |= HV_X64_MSR_SYNIC_AVAILABLE; > - env->msr_hv_synic_version = HV_SYNIC_VERSION_1; > - for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { > - env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; > - } > - } > - if (cpu->hyperv_stimer) { > - if (!has_msr_hv_stimer) { > - fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); > - return -ENOSYS; > - } > - c->eax |= HV_X64_MSR_SYNTIMER_AVAILABLE; > - } > c = &cpuid_data.entries[cpuid_i++]; > c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; > if (cpu->hyperv_relaxed_timing) { ping v2
Hi, Sorry for taking so long to review it. The patch in general looks good, except for: On Fri, Jun 24, 2016 at 01:49:36PM +0300, Denis V. Lunev wrote: [...] > + if (MACHINE_GET_CLASS(current_machine)->hot_add_cpu != NULL) { > + env->features[FEAT_HYPERV_EDX] |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; > + } [...] > +} > + [...] > - c->edx |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; If you want to change the rules for setting HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE, please do it in a separate patch.
diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 3bd3cfc..d07da78 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -245,6 +245,47 @@ static const char *kvm_feature_name[] = { NULL, NULL, NULL, NULL, }; +static const char *hyperv_priv_feature_name[] = { + NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */, + NULL /* hv_msr_synic_access */, NULL /* hv_msr_stimer_access */, + NULL /* hv_msr_apic_access */, NULL /* hv_msr_hypercall_access */, + NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */, + NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */, + NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access */, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + +static const char *hyperv_ident_feature_name[] = { + NULL /* hv_create_partitions */, NULL /* hv_access_partition_id */, + NULL /* hv_access_memory_pool */, NULL /* hv_adjust_message_buffers */, + NULL /* hv_post_messages */, NULL /* hv_signal_events */, + NULL /* hv_create_port */, NULL /* hv_connect_port */, + NULL /* hv_access_stats */, NULL, NULL, NULL /* hv_debugging */, + NULL /* hv_cpu_power_management */, NULL /* hv_configure_profiler */, + NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + +static const char *hyperv_misc_feature_name[] = { + NULL /* hv_mwait */, NULL /* hv_guest_debugging */, + NULL /* hv_perf_monitor */, NULL /* hv_cpu_dynamic_part */, + NULL /* hv_hypercall_params_xmm */, NULL /* hv_guest_idle_state */, + NULL, NULL, + NULL, NULL, NULL /* hv_guest_crash_msr */, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + static const char *svm_feature_name[] = { "npt", "lbrv", "svm_lock", "nrip_save", "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists", @@ -411,6 +452,18 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX, .tcg_features = TCG_KVM_FEATURES, }, + [FEAT_HYPERV_EAX] = { + .feat_names = hyperv_priv_feature_name, + .cpuid_eax = 0x40000003, .cpuid_reg = R_EAX, + }, + [FEAT_HYPERV_EBX] = { + .feat_names = hyperv_ident_feature_name, + .cpuid_eax = 0x40000003, .cpuid_reg = R_EBX, + }, + [FEAT_HYPERV_EDX] = { + .feat_names = hyperv_misc_feature_name, + .cpuid_eax = 0x40000003, .cpuid_reg = R_EDX, + }, [FEAT_SVM] = { .feat_names = svm_feature_name, .cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index d9ab884..4496c8b 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -440,6 +440,9 @@ typedef enum FeatureWord { FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */ FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ + FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */ + FEAT_HYPERV_EBX, /* CPUID[4000_0003].EBX */ + FEAT_HYPERV_EDX, /* CPUID[4000_0003].EDX */ FEAT_SVM, /* CPUID[8000_000A].EDX */ FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */ FEAT_6_EAX, /* CPUID[6].EAX */ diff --git a/target-i386/kvm.c b/target-i386/kvm.c index f3698f1..f44e3c7 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -574,6 +574,66 @@ static int kvm_arch_set_tsc_khz(CPUState *cs) return 0; } +static int hyperv_handle_properties(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + if (cpu->hyperv_relaxed_timing) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; + } + if (cpu->hyperv_vapic) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; + env->features[FEAT_HYPERV_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) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= 0x200; + has_msr_hv_tsc = true; + } + if (cpu->hyperv_crash && has_msr_hv_crash) { + env->features[FEAT_HYPERV_EDX] |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; + } + if (cpu->hyperv_reset && has_msr_hv_reset) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_RESET_AVAILABLE; + } + if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_INDEX_AVAILABLE; + } + if (cpu->hyperv_runtime && has_msr_hv_runtime) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; + } + if (cpu->hyperv_synic) { + int sint; + + if (!has_msr_hv_synic || + kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { + fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); + return -ENOSYS; + } + + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNIC_AVAILABLE; + env->msr_hv_synic_version = HV_SYNIC_VERSION_1; + for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { + env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; + } + } + if (cpu->hyperv_stimer) { + if (!has_msr_hv_stimer) { + fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); + return -ENOSYS; + } + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNTIMER_AVAILABLE; + } + if (MACHINE_GET_CLASS(current_machine)->hot_add_cpu != NULL) { + env->features[FEAT_HYPERV_EDX] |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; + } + return 0; +} + static Error *invtsc_mig_blocker; #define KVM_MAX_CPUID_ENTRIES 100 @@ -633,56 +693,14 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_FEATURES; - if (cpu->hyperv_relaxed_timing) { - c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; - } - 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; - } - if (cpu->hyperv_crash && has_msr_hv_crash) { - c->edx |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; - } - c->edx |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; - if (cpu->hyperv_reset && has_msr_hv_reset) { - c->eax |= HV_X64_MSR_RESET_AVAILABLE; - } - if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { - c->eax |= HV_X64_MSR_VP_INDEX_AVAILABLE; - } - if (cpu->hyperv_runtime && has_msr_hv_runtime) { - c->eax |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; + r = hyperv_handle_properties(cs); + if (r) { + return r; } - if (cpu->hyperv_synic) { - int sint; - - if (!has_msr_hv_synic || - kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { - fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); - return -ENOSYS; - } + c->eax = env->features[FEAT_HYPERV_EAX]; + c->ebx = env->features[FEAT_HYPERV_EBX]; + c->edx = env->features[FEAT_HYPERV_EDX]; - c->eax |= HV_X64_MSR_SYNIC_AVAILABLE; - env->msr_hv_synic_version = HV_SYNIC_VERSION_1; - for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { - env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; - } - } - if (cpu->hyperv_stimer) { - if (!has_msr_hv_stimer) { - fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); - return -ENOSYS; - } - c->eax |= HV_X64_MSR_SYNTIMER_AVAILABLE; - } c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) {