i386: drop FEAT_HYPERV feature leaves
Hyper-V feature leaves are weird. We have some of them in feature_word_info[] array but we don't use feature_word_info magic to enable them. Neither do we use feature_dependencies[] mechanism to validate the configuration as it doesn't allign well with Hyper-V's many-to-many dependency chains. Some of the feature leaves hold not only feature bits, but also values. E.g. FEAT_HV_NESTED_EAX contains both features and the supported Enlightened VMCS range. Hyper-V features are already represented in 'struct X86CPU' with uint64_t hyperv_features so duplicating them in env->features adds little (or zero) benefits. THe other half of Hyper-V emulation features is also stored with values in hyperv_vendor_id[], hyperv_limits[],... so env->features[] is already incomplete. Remove Hyper-V feature leaves from env->features[] completely. kvm_hyperv_properties[] is converted to using raw CPUID func/reg pairs for features, this allows us to get rid of hv_cpuid_get_fw() conversion. Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Message-Id: <20210422161130.652779-8-vkuznets@redhat.com> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
This commit is contained in:
parent
e1a66a1e27
commit
061817a7cc
@ -312,7 +312,7 @@ GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
|
||||
CPUX86State *env = &cpu->env;
|
||||
GuestPanicInformation *panic_info = NULL;
|
||||
|
||||
if (env->features[FEAT_HYPERV_EDX] & HV_GUEST_CRASH_MSR_AVAILABLE) {
|
||||
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_CRASH)) {
|
||||
panic_info = g_malloc0(sizeof(GuestPanicInformation));
|
||||
|
||||
panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V;
|
||||
|
@ -776,94 +776,6 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
||||
*/
|
||||
.no_autoenable_flags = ~0U,
|
||||
},
|
||||
/*
|
||||
* .feat_names are commented out for Hyper-V enlightenments because we
|
||||
* don't want to have two different ways for enabling them on QEMU command
|
||||
* line. Some features (e.g. "hyperv_time", "hyperv_vapic", ...) require
|
||||
* enabling several feature bits simultaneously, exposing these bits
|
||||
* individually may just confuse guests.
|
||||
*/
|
||||
[FEAT_HYPERV_EAX] = {
|
||||
.type = CPUID_FEATURE_WORD,
|
||||
.feat_names = {
|
||||
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 /* hv_msr_debug_access */, NULL /* hv_msr_reenlightenment_access */,
|
||||
NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
},
|
||||
.cpuid = { .eax = 0x40000003, .reg = R_EAX, },
|
||||
},
|
||||
[FEAT_HYPERV_EBX] = {
|
||||
.type = CPUID_FEATURE_WORD,
|
||||
.feat_names = {
|
||||
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,
|
||||
},
|
||||
.cpuid = { .eax = 0x40000003, .reg = R_EBX, },
|
||||
},
|
||||
[FEAT_HYPERV_EDX] = {
|
||||
.type = CPUID_FEATURE_WORD,
|
||||
.feat_names = {
|
||||
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,
|
||||
},
|
||||
.cpuid = { .eax = 0x40000003, .reg = R_EDX, },
|
||||
},
|
||||
[FEAT_HV_RECOMM_EAX] = {
|
||||
.type = CPUID_FEATURE_WORD,
|
||||
.feat_names = {
|
||||
NULL /* hv_recommend_pv_as_switch */,
|
||||
NULL /* hv_recommend_pv_tlbflush_local */,
|
||||
NULL /* hv_recommend_pv_tlbflush_remote */,
|
||||
NULL /* hv_recommend_msr_apic_access */,
|
||||
NULL /* hv_recommend_msr_reset */,
|
||||
NULL /* hv_recommend_relaxed_timing */,
|
||||
NULL /* hv_recommend_dma_remapping */,
|
||||
NULL /* hv_recommend_int_remapping */,
|
||||
NULL /* hv_recommend_x2apic_msrs */,
|
||||
NULL /* hv_recommend_autoeoi_deprecation */,
|
||||
NULL /* hv_recommend_pv_ipi */,
|
||||
NULL /* hv_recommend_ex_hypercalls */,
|
||||
NULL /* hv_hypervisor_is_nested */,
|
||||
NULL /* hv_recommend_int_mbec */,
|
||||
NULL /* hv_recommend_evmcs */,
|
||||
NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
},
|
||||
.cpuid = { .eax = 0x40000004, .reg = R_EAX, },
|
||||
},
|
||||
[FEAT_HV_NESTED_EAX] = {
|
||||
.type = CPUID_FEATURE_WORD,
|
||||
.cpuid = { .eax = 0x4000000A, .reg = R_EAX, },
|
||||
},
|
||||
[FEAT_SVM] = {
|
||||
.type = CPUID_FEATURE_WORD,
|
||||
.feat_names = {
|
||||
|
@ -531,11 +531,6 @@ typedef enum FeatureWord {
|
||||
FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */
|
||||
FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */
|
||||
FEAT_KVM_HINTS, /* CPUID[4000_0001].EDX */
|
||||
FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */
|
||||
FEAT_HYPERV_EBX, /* CPUID[4000_0003].EBX */
|
||||
FEAT_HYPERV_EDX, /* CPUID[4000_0003].EDX */
|
||||
FEAT_HV_RECOMM_EAX, /* CPUID[4000_0004].EAX */
|
||||
FEAT_HV_NESTED_EAX, /* CPUID[4000_000A].EAX */
|
||||
FEAT_SVM, /* CPUID[8000_000A].EDX */
|
||||
FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */
|
||||
FEAT_6_EAX, /* CPUID[6].EAX */
|
||||
|
@ -801,7 +801,8 @@ static bool tsc_is_stable_and_known(CPUX86State *env)
|
||||
static struct {
|
||||
const char *desc;
|
||||
struct {
|
||||
uint32_t fw;
|
||||
uint32_t func;
|
||||
int reg;
|
||||
uint32_t bits;
|
||||
} flags[2];
|
||||
uint64_t dependencies;
|
||||
@ -809,25 +810,25 @@ static struct {
|
||||
[HYPERV_FEAT_RELAXED] = {
|
||||
.desc = "relaxed timing (hv-relaxed)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_HYPERCALL_AVAILABLE},
|
||||
{.fw = FEAT_HV_RECOMM_EAX,
|
||||
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
|
||||
.bits = HV_RELAXED_TIMING_RECOMMENDED}
|
||||
}
|
||||
},
|
||||
[HYPERV_FEAT_VAPIC] = {
|
||||
.desc = "virtual APIC (hv-vapic)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_HYPERCALL_AVAILABLE | HV_APIC_ACCESS_AVAILABLE},
|
||||
{.fw = FEAT_HV_RECOMM_EAX,
|
||||
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
|
||||
.bits = HV_APIC_ACCESS_RECOMMENDED}
|
||||
}
|
||||
},
|
||||
[HYPERV_FEAT_TIME] = {
|
||||
.desc = "clocksources (hv-time)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_HYPERCALL_AVAILABLE | HV_TIME_REF_COUNT_AVAILABLE |
|
||||
HV_REFERENCE_TSC_AVAILABLE}
|
||||
}
|
||||
@ -835,42 +836,42 @@ static struct {
|
||||
[HYPERV_FEAT_CRASH] = {
|
||||
.desc = "crash MSRs (hv-crash)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EDX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
|
||||
.bits = HV_GUEST_CRASH_MSR_AVAILABLE}
|
||||
}
|
||||
},
|
||||
[HYPERV_FEAT_RESET] = {
|
||||
.desc = "reset MSR (hv-reset)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_RESET_AVAILABLE}
|
||||
}
|
||||
},
|
||||
[HYPERV_FEAT_VPINDEX] = {
|
||||
.desc = "VP_INDEX MSR (hv-vpindex)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_VP_INDEX_AVAILABLE}
|
||||
}
|
||||
},
|
||||
[HYPERV_FEAT_RUNTIME] = {
|
||||
.desc = "VP_RUNTIME MSR (hv-runtime)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_VP_RUNTIME_AVAILABLE}
|
||||
}
|
||||
},
|
||||
[HYPERV_FEAT_SYNIC] = {
|
||||
.desc = "synthetic interrupt controller (hv-synic)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_SYNIC_AVAILABLE}
|
||||
}
|
||||
},
|
||||
[HYPERV_FEAT_STIMER] = {
|
||||
.desc = "synthetic timers (hv-stimer)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_SYNTIMERS_AVAILABLE}
|
||||
},
|
||||
.dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_TIME)
|
||||
@ -878,23 +879,23 @@ static struct {
|
||||
[HYPERV_FEAT_FREQUENCIES] = {
|
||||
.desc = "frequency MSRs (hv-frequencies)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_ACCESS_FREQUENCY_MSRS},
|
||||
{.fw = FEAT_HYPERV_EDX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
|
||||
.bits = HV_FREQUENCY_MSRS_AVAILABLE}
|
||||
}
|
||||
},
|
||||
[HYPERV_FEAT_REENLIGHTENMENT] = {
|
||||
.desc = "reenlightenment MSRs (hv-reenlightenment)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EAX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
|
||||
.bits = HV_ACCESS_REENLIGHTENMENTS_CONTROL}
|
||||
}
|
||||
},
|
||||
[HYPERV_FEAT_TLBFLUSH] = {
|
||||
.desc = "paravirtualized TLB flush (hv-tlbflush)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HV_RECOMM_EAX,
|
||||
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
|
||||
.bits = HV_REMOTE_TLB_FLUSH_RECOMMENDED |
|
||||
HV_EX_PROCESSOR_MASKS_RECOMMENDED}
|
||||
},
|
||||
@ -903,7 +904,7 @@ static struct {
|
||||
[HYPERV_FEAT_EVMCS] = {
|
||||
.desc = "enlightened VMCS (hv-evmcs)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HV_RECOMM_EAX,
|
||||
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
|
||||
.bits = HV_ENLIGHTENED_VMCS_RECOMMENDED}
|
||||
},
|
||||
.dependencies = BIT(HYPERV_FEAT_VAPIC)
|
||||
@ -911,7 +912,7 @@ static struct {
|
||||
[HYPERV_FEAT_IPI] = {
|
||||
.desc = "paravirtualized IPI (hv-ipi)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HV_RECOMM_EAX,
|
||||
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
|
||||
.bits = HV_CLUSTER_IPI_RECOMMENDED |
|
||||
HV_EX_PROCESSOR_MASKS_RECOMMENDED}
|
||||
},
|
||||
@ -920,7 +921,7 @@ static struct {
|
||||
[HYPERV_FEAT_STIMER_DIRECT] = {
|
||||
.desc = "direct mode synthetic timers (hv-stimer-direct)",
|
||||
.flags = {
|
||||
{.fw = FEAT_HYPERV_EDX,
|
||||
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
|
||||
.bits = HV_STIMER_DIRECT_MODE_AVAILABLE}
|
||||
},
|
||||
.dependencies = BIT(HYPERV_FEAT_STIMER)
|
||||
@ -1066,48 +1067,6 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid_legacy(CPUState *cs)
|
||||
return cpuid;
|
||||
}
|
||||
|
||||
static int hv_cpuid_get_fw(struct kvm_cpuid2 *cpuid, int fw, uint32_t *r)
|
||||
{
|
||||
struct kvm_cpuid_entry2 *entry;
|
||||
uint32_t func;
|
||||
int reg;
|
||||
|
||||
switch (fw) {
|
||||
case FEAT_HYPERV_EAX:
|
||||
reg = R_EAX;
|
||||
func = HV_CPUID_FEATURES;
|
||||
break;
|
||||
case FEAT_HYPERV_EDX:
|
||||
reg = R_EDX;
|
||||
func = HV_CPUID_FEATURES;
|
||||
break;
|
||||
case FEAT_HV_RECOMM_EAX:
|
||||
reg = R_EAX;
|
||||
func = HV_CPUID_ENLIGHTMENT_INFO;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entry = cpuid_find_entry(cpuid, func, 0);
|
||||
if (!entry) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case R_EAX:
|
||||
*r = entry->eax;
|
||||
break;
|
||||
case R_EDX:
|
||||
*r = entry->edx;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t hv_cpuid_get_host(struct kvm_cpuid2 *cpuid, uint32_t func,
|
||||
int reg)
|
||||
{
|
||||
@ -1123,18 +1082,20 @@ static uint32_t hv_cpuid_get_host(struct kvm_cpuid2 *cpuid, uint32_t func,
|
||||
|
||||
static bool hyperv_feature_supported(struct kvm_cpuid2 *cpuid, int feature)
|
||||
{
|
||||
uint32_t r, fw, bits;
|
||||
int i;
|
||||
uint32_t func, bits;
|
||||
int i, reg;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(kvm_hyperv_properties[feature].flags); i++) {
|
||||
fw = kvm_hyperv_properties[feature].flags[i].fw;
|
||||
|
||||
func = kvm_hyperv_properties[feature].flags[i].func;
|
||||
reg = kvm_hyperv_properties[feature].flags[i].reg;
|
||||
bits = kvm_hyperv_properties[feature].flags[i].bits;
|
||||
|
||||
if (!fw) {
|
||||
if (!func) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hv_cpuid_get_fw(cpuid, fw, &r) || (r & bits) != bits) {
|
||||
if ((hv_cpuid_get_host(cpuid, func, reg) & bits) != bits) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1184,7 +1145,7 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t fw)
|
||||
static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
uint32_t r = 0;
|
||||
@ -1196,7 +1157,10 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t fw)
|
||||
}
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(kvm_hyperv_properties[i].flags); j++) {
|
||||
if (kvm_hyperv_properties[i].flags[j].fw != fw) {
|
||||
if (kvm_hyperv_properties[i].flags[j].func != func) {
|
||||
continue;
|
||||
}
|
||||
if (kvm_hyperv_properties[i].flags[j].reg != reg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1348,16 +1312,16 @@ static int hyperv_handle_properties(CPUState *cs,
|
||||
|
||||
c = &cpuid_ent[cpuid_i++];
|
||||
c->function = HV_CPUID_FEATURES;
|
||||
c->eax = hv_build_cpuid_leaf(cs, FEAT_HYPERV_EAX);
|
||||
c->ebx = hv_build_cpuid_leaf(cs, FEAT_HYPERV_EBX);
|
||||
c->edx = hv_build_cpuid_leaf(cs, FEAT_HYPERV_EDX);
|
||||
c->eax = hv_build_cpuid_leaf(cs, HV_CPUID_FEATURES, R_EAX);
|
||||
c->ebx = hv_build_cpuid_leaf(cs, HV_CPUID_FEATURES, R_EBX);
|
||||
c->edx = hv_build_cpuid_leaf(cs, HV_CPUID_FEATURES, R_EDX);
|
||||
|
||||
/* Not exposed by KVM but needed to make CPU hotplug in Windows work */
|
||||
c->edx |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE;
|
||||
|
||||
c = &cpuid_ent[cpuid_i++];
|
||||
c->function = HV_CPUID_ENLIGHTMENT_INFO;
|
||||
c->eax = hv_build_cpuid_leaf(cs, FEAT_HV_RECOMM_EAX);
|
||||
c->eax = hv_build_cpuid_leaf(cs, HV_CPUID_ENLIGHTMENT_INFO, R_EAX);
|
||||
c->ebx = cpu->hyperv_spinlock_attempts;
|
||||
|
||||
if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_ON) {
|
||||
|
Loading…
Reference in New Issue
Block a user