@@ -1145,16 +1145,12 @@ static bool hyperv_feature_supported(CPUState *cs, int feature)
return true;
}
-static int hv_cpuid_check_and_set(CPUState *cs, int feature, Error **errp)
+/* Checks that all feature dependencies are enabled */
+static bool hv_feature_check_deps(X86CPU *cpu, int feature, Error **errp)
{
- X86CPU *cpu = X86_CPU(cs);
uint64_t deps;
int dep_feat;
- if (!hyperv_feat_enabled(cpu, feature) && !cpu->hyperv_passthrough) {
- return 0;
- }
-
deps = kvm_hyperv_properties[feature].dependencies;
while (deps) {
dep_feat = ctz64(deps);
@@ -1162,26 +1158,12 @@ static int hv_cpuid_check_and_set(CPUState *cs, int feature, Error **errp)
error_setg(errp, "Hyper-V %s requires Hyper-V %s",
kvm_hyperv_properties[feature].desc,
kvm_hyperv_properties[dep_feat].desc);
- return 1;
+ return false;
}
deps &= ~(1ull << dep_feat);
}
- if (!hyperv_feature_supported(cs, feature)) {
- if (hyperv_feat_enabled(cpu, feature)) {
- error_setg(errp, "Hyper-V %s is not supported by kernel",
- kvm_hyperv_properties[feature].desc);
- return 1;
- } else {
- return 0;
- }
- }
-
- if (cpu->hyperv_passthrough) {
- cpu->hyperv_features |= BIT(feature);
- }
-
- return 0;
+ return true;
}
static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg)
@@ -1220,6 +1202,8 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg)
bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp)
{
CPUState *cs = CPU(cpu);
+ Error *local_err = NULL;
+ int feat;
if (!hyperv_enabled(cpu))
return true;
@@ -1275,53 +1259,37 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp)
cpu->hyperv_spinlock_attempts =
hv_cpuid_get_host(cs, HV_CPUID_ENLIGHTMENT_INFO, R_EBX);
- }
- /* Features */
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RELAXED, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VAPIC, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TIME, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_CRASH, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RESET, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VPINDEX, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RUNTIME, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_SYNIC, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_FREQUENCIES, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_REENLIGHTENMENT, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TLBFLUSH, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_EVMCS, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_IPI, errp)) {
- return false;
- }
- if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER_DIRECT, errp)) {
- return false;
+ /*
+ * Mark feature as enabled in 'cpu->hyperv_features' as
+ * hv_build_cpuid_leaf() uses this info to build guest CPUIDs.
+ */
+ for (feat = 0; feat < ARRAY_SIZE(kvm_hyperv_properties); feat++) {
+ if (hyperv_feature_supported(cs, feat)) {
+ cpu->hyperv_features |= BIT(feat);
+ }
+ }
+ } else {
+ /* Check features availability and dependencies */
+ for (feat = 0; feat < ARRAY_SIZE(kvm_hyperv_properties); feat++) {
+ /* If the feature was not requested skip it. */
+ if (!hyperv_feat_enabled(cpu, feat)) {
+ continue;
+ }
+
+ /* Check if the feature is supported by KVM */
+ if (!hyperv_feature_supported(cs, feat)) {
+ error_setg(errp, "Hyper-V %s is not supported by kernel",
+ kvm_hyperv_properties[feat].desc);
+ return false;
+ }
+
+ /* Check dependencies */
+ if (!hv_feature_check_deps(cpu, feat, &local_err)) {
+ error_propagate(errp, local_err);
+ return false;
+ }
+ }
}
/* Additional dependencies not covered by kvm_hyperv_properties[] */