mirror of
https://github.com/qemu/qemu.git
synced 2024-11-26 12:23:36 +08:00
target-i386: Report hyperv feature words through qom
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> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
This commit is contained in:
parent
d6276d26bd
commit
c35bd19a5c
@ -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",
|
||||
@ -412,6 +453,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,
|
||||
|
@ -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 */
|
||||
|
@ -576,6 +576,64 @@ 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;
|
||||
}
|
||||
env->features[FEAT_HYPERV_EDX] |= HV_X64_CPU_DYNAMIC_PARTITIONING_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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Error *invtsc_mig_blocker;
|
||||
|
||||
#define KVM_MAX_CPUID_ENTRIES 100
|
||||
@ -635,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;
|
||||
r = hyperv_handle_properties(cs);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (cpu->hyperv_synic) {
|
||||
int sint;
|
||||
c->eax = env->features[FEAT_HYPERV_EAX];
|
||||
c->ebx = env->features[FEAT_HYPERV_EBX];
|
||||
c->edx = env->features[FEAT_HYPERV_EDX];
|
||||
|
||||
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 |= 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) {
|
||||
|
Loading…
Reference in New Issue
Block a user