* [PATCH v5 01/17] i386: keep hyperv_vendor string up-to-date
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 02/17] i386: invert hyperv_spinlock_attempts setting logic with hv_passthrough Vitaly Kuznetsov
` (15 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
When cpu->hyperv_vendor is not set manually we default to "Microsoft Hv"
and in 'hv_passthrough' mode we get the information from the host. This
information is stored in cpu->hyperv_vendor_id[] array but we don't update
cpu->hyperv_vendor string so e.g. QMP's query-cpu-model-expansion output
is incorrect.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/cpu.c | 19 +++++++++----------
target/i386/kvm/kvm.c | 5 +++++
2 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 6a53446e6a56..ee094877d7a1 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6653,17 +6653,16 @@ static void x86_cpu_hyperv_realize(X86CPU *cpu)
/* Hyper-V vendor id */
if (!cpu->hyperv_vendor) {
- memcpy(cpu->hyperv_vendor_id, "Microsoft Hv", 12);
- } else {
- len = strlen(cpu->hyperv_vendor);
-
- if (len > 12) {
- warn_report("hv-vendor-id truncated to 12 characters");
- len = 12;
- }
- memset(cpu->hyperv_vendor_id, 0, 12);
- memcpy(cpu->hyperv_vendor_id, cpu->hyperv_vendor, len);
+ object_property_set_str(OBJECT(cpu), "hv-vendor-id", "Microsoft Hv",
+ &error_abort);
+ }
+ len = strlen(cpu->hyperv_vendor);
+ if (len > 12) {
+ warn_report("hv-vendor-id truncated to 12 characters");
+ len = 12;
}
+ memset(cpu->hyperv_vendor_id, 0, 12);
+ memcpy(cpu->hyperv_vendor_id, cpu->hyperv_vendor, len);
/* 'Hv#1' interface identification*/
cpu->hyperv_interface_id[0] = 0x31237648;
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 0b5755e42b87..8e9ae7522582 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1215,6 +1215,11 @@ static int hyperv_handle_properties(CPUState *cs,
cpu->hyperv_vendor_id[0] = c->ebx;
cpu->hyperv_vendor_id[1] = c->ecx;
cpu->hyperv_vendor_id[2] = c->edx;
+ cpu->hyperv_vendor = g_realloc(cpu->hyperv_vendor,
+ sizeof(cpu->hyperv_vendor_id) + 1);
+ memcpy(cpu->hyperv_vendor, cpu->hyperv_vendor_id,
+ sizeof(cpu->hyperv_vendor_id));
+ cpu->hyperv_vendor[sizeof(cpu->hyperv_vendor_id)] = 0;
}
c = cpuid_find_entry(cpuid, HV_CPUID_INTERFACE, 0);
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 02/17] i386: invert hyperv_spinlock_attempts setting logic with hv_passthrough
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 01/17] i386: keep hyperv_vendor string up-to-date Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 03/17] i386: always fill Hyper-V CPUID feature leaves from X86CPU data Vitaly Kuznetsov
` (14 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
There is no need to have this special case: like all other Hyper-V
enlightenments we can just use kernel's supplied value in hv_passthrough
mode.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 8e9ae7522582..3c1202333d9d 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1256,11 +1256,7 @@ static int hyperv_handle_properties(CPUState *cs,
c = cpuid_find_entry(cpuid, HV_CPUID_ENLIGHTMENT_INFO, 0);
if (c) {
env->features[FEAT_HV_RECOMM_EAX] = c->eax;
-
- /* hv-spinlocks may have been overriden */
- if (cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_NOTIFY) {
- c->ebx = cpu->hyperv_spinlock_attempts;
- }
+ cpu->hyperv_spinlock_attempts = c->ebx;
}
c = cpuid_find_entry(cpuid, HV_CPUID_NESTED_FEATURES, 0);
if (c) {
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 03/17] i386: always fill Hyper-V CPUID feature leaves from X86CPU data
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 01/17] i386: keep hyperv_vendor string up-to-date Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 02/17] i386: invert hyperv_spinlock_attempts setting logic with hv_passthrough Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 04/17] i386: stop using env->features[] for filling Hyper-V CPUIDs Vitaly Kuznetsov
` (13 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
We have all the required data in X86CPU already and as we are about to
split hyperv_handle_properties() into hyperv_expand_features()/
hyperv_fill_cpuids() we can remove the blind copy. The functional change
is that QEMU won't pass CPUID leaves it doesn't currently know about
to the guest but arguably this is a good change.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 3c1202333d9d..1b1934362a89 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1207,9 +1207,6 @@ static int hyperv_handle_properties(CPUState *cs,
}
if (cpu->hyperv_passthrough) {
- memcpy(cpuid_ent, &cpuid->entries[0],
- cpuid->nent * sizeof(cpuid->entries[0]));
-
c = cpuid_find_entry(cpuid, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, 0);
if (c) {
cpu->hyperv_vendor_id[0] = c->ebx;
@@ -1309,12 +1306,6 @@ static int hyperv_handle_properties(CPUState *cs,
goto free;
}
- if (cpu->hyperv_passthrough) {
- /* We already copied all feature words from KVM as is */
- r = cpuid->nent;
- goto free;
- }
-
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
c->eax = hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) ?
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 04/17] i386: stop using env->features[] for filling Hyper-V CPUIDs
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (2 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 03/17] i386: always fill Hyper-V CPUID feature leaves from X86CPU data Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 05/17] i386: introduce hyperv_feature_supported() Vitaly Kuznetsov
` (12 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
As a preparatory patch to dropping Hyper-V CPUID leaves from
feature_word_info[] stop using env->features[] as a temporary
storage of Hyper-V CPUIDs, just build Hyper-V CPUID leaves directly
from kvm_hyperv_properties[] data.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/cpu.h | 1 +
target/i386/kvm/kvm.c | 80 +++++++++++++++++++++++--------------------
2 files changed, 43 insertions(+), 38 deletions(-)
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 8be39cfb62e5..118454d24b8f 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1683,6 +1683,7 @@ struct X86CPU {
uint32_t hyperv_interface_id[4];
uint32_t hyperv_version_id[4];
uint32_t hyperv_limits[3];
+ uint32_t hyperv_nested[4];
bool check_cpuid;
bool enforce_cpuid;
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 1b1934362a89..dc372ed213ff 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1111,7 +1111,6 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
int feature)
{
X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
uint32_t r, fw, bits;
uint64_t deps;
int i, dep_feat;
@@ -1151,8 +1150,6 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
return 0;
}
}
-
- env->features[fw] |= bits;
}
if (cpu->hyperv_passthrough) {
@@ -1162,6 +1159,29 @@ 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)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ uint32_t r = 0;
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(kvm_hyperv_properties); i++) {
+ if (!hyperv_feat_enabled(cpu, i)) {
+ continue;
+ }
+
+ for (j = 0; j < ARRAY_SIZE(kvm_hyperv_properties[i].flags); j++) {
+ if (kvm_hyperv_properties[i].flags[j].fw != fw) {
+ continue;
+ }
+
+ r |= kvm_hyperv_properties[i].flags[j].bits;
+ }
+ }
+
+ return r;
+}
+
/*
* Fill in Hyper-V CPUIDs. Returns the number of entries filled in cpuid_ent in
* case of success, errno < 0 in case of failure and 0 when no Hyper-V
@@ -1171,9 +1191,8 @@ static int hyperv_handle_properties(CPUState *cs,
struct kvm_cpuid_entry2 *cpuid_ent)
{
X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
struct kvm_cpuid2 *cpuid;
- struct kvm_cpuid_entry2 *c;
+ struct kvm_cpuid_entry2 *c, *c2;
uint32_t cpuid_i = 0;
int r;
@@ -1194,9 +1213,7 @@ static int hyperv_handle_properties(CPUState *cs,
}
if (!r) {
- env->features[FEAT_HV_RECOMM_EAX] |=
- HV_ENLIGHTENED_VMCS_RECOMMENDED;
- env->features[FEAT_HV_NESTED_EAX] = evmcs_version;
+ cpu->hyperv_nested[0] = evmcs_version;
}
}
@@ -1235,13 +1252,6 @@ static int hyperv_handle_properties(CPUState *cs,
cpu->hyperv_version_id[3] = c->edx;
}
- c = cpuid_find_entry(cpuid, HV_CPUID_FEATURES, 0);
- if (c) {
- env->features[FEAT_HYPERV_EAX] = c->eax;
- env->features[FEAT_HYPERV_EBX] = c->ebx;
- env->features[FEAT_HYPERV_EDX] = c->edx;
- }
-
c = cpuid_find_entry(cpuid, HV_CPUID_IMPLEMENT_LIMITS, 0);
if (c) {
cpu->hv_max_vps = c->eax;
@@ -1252,23 +1262,8 @@ static int hyperv_handle_properties(CPUState *cs,
c = cpuid_find_entry(cpuid, HV_CPUID_ENLIGHTMENT_INFO, 0);
if (c) {
- env->features[FEAT_HV_RECOMM_EAX] = c->eax;
cpu->hyperv_spinlock_attempts = c->ebx;
}
- c = cpuid_find_entry(cpuid, HV_CPUID_NESTED_FEATURES, 0);
- if (c) {
- env->features[FEAT_HV_NESTED_EAX] = c->eax;
- }
- }
-
- if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_ON) {
- env->features[FEAT_HV_RECOMM_EAX] |= HV_NO_NONARCH_CORESHARING;
- } else if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_AUTO) {
- c = cpuid_find_entry(cpuid, HV_CPUID_ENLIGHTMENT_INFO, 0);
- if (c) {
- env->features[FEAT_HV_RECOMM_EAX] |=
- c->eax & HV_NO_NONARCH_CORESHARING;
- }
}
/* Features */
@@ -1298,9 +1293,6 @@ static int hyperv_handle_properties(CPUState *cs,
r |= 1;
}
- /* Not exposed by KVM but needed to make CPU hotplug in Windows work */
- env->features[FEAT_HYPERV_EDX] |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE;
-
if (r) {
r = -ENOSYS;
goto free;
@@ -1330,15 +1322,27 @@ static int hyperv_handle_properties(CPUState *cs,
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_FEATURES;
- c->eax = env->features[FEAT_HYPERV_EAX];
- c->ebx = env->features[FEAT_HYPERV_EBX];
- c->edx = env->features[FEAT_HYPERV_EDX];
+ 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);
+
+ /* 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 = env->features[FEAT_HV_RECOMM_EAX];
+ c->eax = hv_build_cpuid_leaf(cs, FEAT_HV_RECOMM_EAX);
c->ebx = cpu->hyperv_spinlock_attempts;
+ if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_ON) {
+ c->eax |= HV_NO_NONARCH_CORESHARING;
+ } else if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_AUTO) {
+ c2 = cpuid_find_entry(cpuid, HV_CPUID_ENLIGHTMENT_INFO, 0);
+ if (c2) {
+ c->eax |= c2->eax & HV_NO_NONARCH_CORESHARING;
+ }
+ }
+
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_IMPLEMENT_LIMITS;
c->eax = cpu->hv_max_vps;
@@ -1358,7 +1362,7 @@ static int hyperv_handle_properties(CPUState *cs,
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_NESTED_FEATURES;
- c->eax = env->features[FEAT_HV_NESTED_EAX];
+ c->eax = cpu->hyperv_nested[0];
}
r = cpuid_i;
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 05/17] i386: introduce hyperv_feature_supported()
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (3 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 04/17] i386: stop using env->features[] for filling Hyper-V CPUIDs Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 06/17] i386: introduce hv_cpuid_get_host() Vitaly Kuznetsov
` (11 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
Clean up hv_cpuid_check_and_set() by separating hyperv_feature_supported()
off it. No functional change intended.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 49 ++++++++++++++++++++++++++-----------------
1 file changed, 30 insertions(+), 19 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index dc372ed213ff..bbc76a7475cd 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1107,13 +1107,33 @@ static int hv_cpuid_get_fw(struct kvm_cpuid2 *cpuid, int fw, uint32_t *r)
return 0;
}
+static bool hyperv_feature_supported(struct kvm_cpuid2 *cpuid, int feature)
+{
+ uint32_t r, fw, bits;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kvm_hyperv_properties[feature].flags); i++) {
+ fw = kvm_hyperv_properties[feature].flags[i].fw;
+ bits = kvm_hyperv_properties[feature].flags[i].bits;
+
+ if (!fw) {
+ continue;
+ }
+
+ if (hv_cpuid_get_fw(cpuid, fw, &r) || (r & bits) != bits) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
int feature)
{
X86CPU *cpu = X86_CPU(cs);
- uint32_t r, fw, bits;
uint64_t deps;
- int i, dep_feat;
+ int dep_feat;
if (!hyperv_feat_enabled(cpu, feature) && !cpu->hyperv_passthrough) {
return 0;
@@ -1132,23 +1152,14 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
deps &= ~(1ull << dep_feat);
}
- for (i = 0; i < ARRAY_SIZE(kvm_hyperv_properties[feature].flags); i++) {
- fw = kvm_hyperv_properties[feature].flags[i].fw;
- bits = kvm_hyperv_properties[feature].flags[i].bits;
-
- if (!fw) {
- continue;
- }
-
- if (hv_cpuid_get_fw(cpuid, fw, &r) || (r & bits) != bits) {
- if (hyperv_feat_enabled(cpu, feature)) {
- fprintf(stderr,
- "Hyper-V %s is not supported by kernel\n",
- kvm_hyperv_properties[feature].desc);
- return 1;
- } else {
- return 0;
- }
+ if (!hyperv_feature_supported(cpuid, feature)) {
+ if (hyperv_feat_enabled(cpu, feature)) {
+ fprintf(stderr,
+ "Hyper-V %s is not supported by kernel\n",
+ kvm_hyperv_properties[feature].desc);
+ return 1;
+ } else {
+ return 0;
}
}
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 06/17] i386: introduce hv_cpuid_get_host()
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (4 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 05/17] i386: introduce hyperv_feature_supported() Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 07/17] i386: drop FEAT_HYPERV feature leaves Vitaly Kuznetsov
` (10 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
As a preparation to implementing hv_cpuid_cache intro introduce
hv_cpuid_get_host(). No functional change intended.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 102 +++++++++++++++++++++++-------------------
1 file changed, 57 insertions(+), 45 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index bbc76a7475cd..9835c3809723 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1107,6 +1107,19 @@ static int hv_cpuid_get_fw(struct kvm_cpuid2 *cpuid, int fw, uint32_t *r)
return 0;
}
+static uint32_t hv_cpuid_get_host(struct kvm_cpuid2 *cpuid, uint32_t func,
+ int reg)
+{
+ struct kvm_cpuid_entry2 *entry;
+
+ entry = cpuid_find_entry(cpuid, func, 0);
+ if (!entry) {
+ return 0;
+ }
+
+ return cpuid_entry_get_reg(entry, reg);
+}
+
static bool hyperv_feature_supported(struct kvm_cpuid2 *cpuid, int feature)
{
uint32_t r, fw, bits;
@@ -1203,7 +1216,7 @@ static int hyperv_handle_properties(CPUState *cs,
{
X86CPU *cpu = X86_CPU(cs);
struct kvm_cpuid2 *cpuid;
- struct kvm_cpuid_entry2 *c, *c2;
+ struct kvm_cpuid_entry2 *c;
uint32_t cpuid_i = 0;
int r;
@@ -1235,46 +1248,47 @@ static int hyperv_handle_properties(CPUState *cs,
}
if (cpu->hyperv_passthrough) {
- c = cpuid_find_entry(cpuid, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, 0);
- if (c) {
- cpu->hyperv_vendor_id[0] = c->ebx;
- cpu->hyperv_vendor_id[1] = c->ecx;
- cpu->hyperv_vendor_id[2] = c->edx;
- cpu->hyperv_vendor = g_realloc(cpu->hyperv_vendor,
- sizeof(cpu->hyperv_vendor_id) + 1);
- memcpy(cpu->hyperv_vendor, cpu->hyperv_vendor_id,
- sizeof(cpu->hyperv_vendor_id));
- cpu->hyperv_vendor[sizeof(cpu->hyperv_vendor_id)] = 0;
- }
-
- c = cpuid_find_entry(cpuid, HV_CPUID_INTERFACE, 0);
- if (c) {
- cpu->hyperv_interface_id[0] = c->eax;
- cpu->hyperv_interface_id[1] = c->ebx;
- cpu->hyperv_interface_id[2] = c->ecx;
- cpu->hyperv_interface_id[3] = c->edx;
- }
-
- c = cpuid_find_entry(cpuid, HV_CPUID_VERSION, 0);
- if (c) {
- cpu->hyperv_version_id[0] = c->eax;
- cpu->hyperv_version_id[1] = c->ebx;
- cpu->hyperv_version_id[2] = c->ecx;
- cpu->hyperv_version_id[3] = c->edx;
- }
-
- c = cpuid_find_entry(cpuid, HV_CPUID_IMPLEMENT_LIMITS, 0);
- if (c) {
- cpu->hv_max_vps = c->eax;
- cpu->hyperv_limits[0] = c->ebx;
- cpu->hyperv_limits[1] = c->ecx;
- cpu->hyperv_limits[2] = c->edx;
- }
-
- c = cpuid_find_entry(cpuid, HV_CPUID_ENLIGHTMENT_INFO, 0);
- if (c) {
- cpu->hyperv_spinlock_attempts = c->ebx;
- }
+ cpu->hyperv_vendor_id[0] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EBX);
+ cpu->hyperv_vendor_id[1] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_ECX);
+ cpu->hyperv_vendor_id[2] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EDX);
+ cpu->hyperv_vendor = g_realloc(cpu->hyperv_vendor,
+ sizeof(cpu->hyperv_vendor_id) + 1);
+ memcpy(cpu->hyperv_vendor, cpu->hyperv_vendor_id,
+ sizeof(cpu->hyperv_vendor_id));
+ cpu->hyperv_vendor[sizeof(cpu->hyperv_vendor_id)] = 0;
+
+ cpu->hyperv_interface_id[0] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_INTERFACE, R_EAX);
+ cpu->hyperv_interface_id[1] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_INTERFACE, R_EBX);
+ cpu->hyperv_interface_id[2] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_INTERFACE, R_ECX);
+ cpu->hyperv_interface_id[3] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_INTERFACE, R_EDX);
+
+ cpu->hyperv_version_id[0] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_VERSION, R_EAX);
+ cpu->hyperv_version_id[1] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_VERSION, R_EBX);
+ cpu->hyperv_version_id[2] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_VERSION, R_ECX);
+ cpu->hyperv_version_id[3] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_VERSION, R_EDX);
+
+ cpu->hv_max_vps = hv_cpuid_get_host(cpuid, HV_CPUID_IMPLEMENT_LIMITS,
+ R_EAX);
+ cpu->hyperv_limits[0] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_IMPLEMENT_LIMITS, R_EBX);
+ cpu->hyperv_limits[1] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_IMPLEMENT_LIMITS, R_ECX);
+ cpu->hyperv_limits[2] =
+ hv_cpuid_get_host(cpuid, HV_CPUID_IMPLEMENT_LIMITS, R_EDX);
+
+ cpu->hyperv_spinlock_attempts =
+ hv_cpuid_get_host(cpuid, HV_CPUID_ENLIGHTMENT_INFO, R_EBX);
}
/* Features */
@@ -1348,10 +1362,8 @@ static int hyperv_handle_properties(CPUState *cs,
if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_ON) {
c->eax |= HV_NO_NONARCH_CORESHARING;
} else if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_AUTO) {
- c2 = cpuid_find_entry(cpuid, HV_CPUID_ENLIGHTMENT_INFO, 0);
- if (c2) {
- c->eax |= c2->eax & HV_NO_NONARCH_CORESHARING;
- }
+ c->eax |= hv_cpuid_get_host(cpuid, HV_CPUID_ENLIGHTMENT_INFO, R_EAX) &
+ HV_NO_NONARCH_CORESHARING;
}
c = &cpuid_ent[cpuid_i++];
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 07/17] i386: drop FEAT_HYPERV feature leaves
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (5 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 06/17] i386: introduce hv_cpuid_get_host() Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 08/17] i386: introduce hv_cpuid_cache Vitaly Kuznetsov
` (9 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
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>
---
target/i386/cpu.c | 90 +----------------------------------
target/i386/cpu.h | 5 --
target/i386/kvm/kvm.c | 108 ++++++++++++++----------------------------
3 files changed, 37 insertions(+), 166 deletions(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ee094877d7a1..e943d42569db 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -832,94 +832,6 @@ static 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 = {
@@ -7057,7 +6969,7 @@ static 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;
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 118454d24b8f..265e552746e7 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -519,11 +519,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 */
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 9835c3809723..a65f2ccc1052 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -800,7 +800,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;
@@ -808,25 +809,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}
}
@@ -834,42 +835,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)
@@ -877,23 +878,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}
},
@@ -902,7 +903,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)
@@ -910,7 +911,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}
},
@@ -919,7 +920,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)
@@ -1065,48 +1066,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)
{
@@ -1122,18 +1081,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;
}
}
@@ -1183,7 +1144,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;
@@ -1195,7 +1156,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;
}
@@ -1347,16 +1311,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) {
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 08/17] i386: introduce hv_cpuid_cache
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (6 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 07/17] i386: drop FEAT_HYPERV feature leaves Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 09/17] i386: split hyperv_handle_properties() into hyperv_expand_features()/hyperv_fill_cpuids() Vitaly Kuznetsov
` (8 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
Just like with cpuid_cache, it makes no sense to call
KVM_GET_SUPPORTED_HV_CPUID more than once and instead of (ab)using
env->features[] and/or trying to keep all the code in one place, it is
better to introduce persistent hv_cpuid_cache and hv_cpuid_get_host()
accessor to it.
Note, hv_cpuid_get_fw() is converted to using hv_cpuid_get_host()
just to be removed later with Hyper-V specific feature words.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 109 ++++++++++++++++++++++--------------------
1 file changed, 56 insertions(+), 53 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index a65f2ccc1052..043d4c84d2d2 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -128,6 +128,7 @@ static int has_exception_payload;
static bool has_msr_mcg_ext_ctl;
static struct kvm_cpuid2 *cpuid_cache;
+static struct kvm_cpuid2 *hv_cpuid_cache;
static struct kvm_msr_list *kvm_feature_msrs;
int kvm_has_pit_state2(void)
@@ -1066,10 +1067,25 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid_legacy(CPUState *cs)
return cpuid;
}
-static uint32_t hv_cpuid_get_host(struct kvm_cpuid2 *cpuid, uint32_t func,
- int reg)
+static uint32_t hv_cpuid_get_host(CPUState *cs, uint32_t func, int reg)
{
struct kvm_cpuid_entry2 *entry;
+ struct kvm_cpuid2 *cpuid;
+
+ if (hv_cpuid_cache) {
+ cpuid = hv_cpuid_cache;
+ } else {
+ if (kvm_check_extension(kvm_state, KVM_CAP_HYPERV_CPUID) > 0) {
+ cpuid = get_supported_hv_cpuid(cs);
+ } else {
+ cpuid = get_supported_hv_cpuid_legacy(cs);
+ }
+ hv_cpuid_cache = cpuid;
+ }
+
+ if (!cpuid) {
+ return 0;
+ }
entry = cpuid_find_entry(cpuid, func, 0);
if (!entry) {
@@ -1079,7 +1095,7 @@ static uint32_t hv_cpuid_get_host(struct kvm_cpuid2 *cpuid, uint32_t func,
return cpuid_entry_get_reg(entry, reg);
}
-static bool hyperv_feature_supported(struct kvm_cpuid2 *cpuid, int feature)
+static bool hyperv_feature_supported(CPUState *cs, int feature)
{
uint32_t func, bits;
int i, reg;
@@ -1094,7 +1110,7 @@ static bool hyperv_feature_supported(struct kvm_cpuid2 *cpuid, int feature)
continue;
}
- if ((hv_cpuid_get_host(cpuid, func, reg) & bits) != bits) {
+ if ((hv_cpuid_get_host(cs, func, reg) & bits) != bits) {
return false;
}
}
@@ -1102,8 +1118,7 @@ static bool hyperv_feature_supported(struct kvm_cpuid2 *cpuid, int feature)
return true;
}
-static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
- int feature)
+static int hv_cpuid_check_and_set(CPUState *cs, int feature)
{
X86CPU *cpu = X86_CPU(cs);
uint64_t deps;
@@ -1126,7 +1141,7 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
deps &= ~(1ull << dep_feat);
}
- if (!hyperv_feature_supported(cpuid, feature)) {
+ if (!hyperv_feature_supported(cs, feature)) {
if (hyperv_feat_enabled(cpu, feature)) {
fprintf(stderr,
"Hyper-V %s is not supported by kernel\n",
@@ -1179,7 +1194,6 @@ static int hyperv_handle_properties(CPUState *cs,
struct kvm_cpuid_entry2 *cpuid_ent)
{
X86CPU *cpu = X86_CPU(cs);
- struct kvm_cpuid2 *cpuid;
struct kvm_cpuid_entry2 *c;
uint32_t cpuid_i = 0;
int r;
@@ -1205,19 +1219,13 @@ static int hyperv_handle_properties(CPUState *cs,
}
}
- if (kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_CPUID) > 0) {
- cpuid = get_supported_hv_cpuid(cs);
- } else {
- cpuid = get_supported_hv_cpuid_legacy(cs);
- }
-
if (cpu->hyperv_passthrough) {
cpu->hyperv_vendor_id[0] =
- hv_cpuid_get_host(cpuid, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EBX);
+ hv_cpuid_get_host(cs, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EBX);
cpu->hyperv_vendor_id[1] =
- hv_cpuid_get_host(cpuid, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_ECX);
+ hv_cpuid_get_host(cs, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_ECX);
cpu->hyperv_vendor_id[2] =
- hv_cpuid_get_host(cpuid, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EDX);
+ hv_cpuid_get_host(cs, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EDX);
cpu->hyperv_vendor = g_realloc(cpu->hyperv_vendor,
sizeof(cpu->hyperv_vendor_id) + 1);
memcpy(cpu->hyperv_vendor, cpu->hyperv_vendor_id,
@@ -1225,52 +1233,52 @@ static int hyperv_handle_properties(CPUState *cs,
cpu->hyperv_vendor[sizeof(cpu->hyperv_vendor_id)] = 0;
cpu->hyperv_interface_id[0] =
- hv_cpuid_get_host(cpuid, HV_CPUID_INTERFACE, R_EAX);
+ hv_cpuid_get_host(cs, HV_CPUID_INTERFACE, R_EAX);
cpu->hyperv_interface_id[1] =
- hv_cpuid_get_host(cpuid, HV_CPUID_INTERFACE, R_EBX);
+ hv_cpuid_get_host(cs, HV_CPUID_INTERFACE, R_EBX);
cpu->hyperv_interface_id[2] =
- hv_cpuid_get_host(cpuid, HV_CPUID_INTERFACE, R_ECX);
+ hv_cpuid_get_host(cs, HV_CPUID_INTERFACE, R_ECX);
cpu->hyperv_interface_id[3] =
- hv_cpuid_get_host(cpuid, HV_CPUID_INTERFACE, R_EDX);
+ hv_cpuid_get_host(cs, HV_CPUID_INTERFACE, R_EDX);
cpu->hyperv_version_id[0] =
- hv_cpuid_get_host(cpuid, HV_CPUID_VERSION, R_EAX);
+ hv_cpuid_get_host(cs, HV_CPUID_VERSION, R_EAX);
cpu->hyperv_version_id[1] =
- hv_cpuid_get_host(cpuid, HV_CPUID_VERSION, R_EBX);
+ hv_cpuid_get_host(cs, HV_CPUID_VERSION, R_EBX);
cpu->hyperv_version_id[2] =
- hv_cpuid_get_host(cpuid, HV_CPUID_VERSION, R_ECX);
+ hv_cpuid_get_host(cs, HV_CPUID_VERSION, R_ECX);
cpu->hyperv_version_id[3] =
- hv_cpuid_get_host(cpuid, HV_CPUID_VERSION, R_EDX);
+ hv_cpuid_get_host(cs, HV_CPUID_VERSION, R_EDX);
- cpu->hv_max_vps = hv_cpuid_get_host(cpuid, HV_CPUID_IMPLEMENT_LIMITS,
+ cpu->hv_max_vps = hv_cpuid_get_host(cs, HV_CPUID_IMPLEMENT_LIMITS,
R_EAX);
cpu->hyperv_limits[0] =
- hv_cpuid_get_host(cpuid, HV_CPUID_IMPLEMENT_LIMITS, R_EBX);
+ hv_cpuid_get_host(cs, HV_CPUID_IMPLEMENT_LIMITS, R_EBX);
cpu->hyperv_limits[1] =
- hv_cpuid_get_host(cpuid, HV_CPUID_IMPLEMENT_LIMITS, R_ECX);
+ hv_cpuid_get_host(cs, HV_CPUID_IMPLEMENT_LIMITS, R_ECX);
cpu->hyperv_limits[2] =
- hv_cpuid_get_host(cpuid, HV_CPUID_IMPLEMENT_LIMITS, R_EDX);
+ hv_cpuid_get_host(cs, HV_CPUID_IMPLEMENT_LIMITS, R_EDX);
cpu->hyperv_spinlock_attempts =
- hv_cpuid_get_host(cpuid, HV_CPUID_ENLIGHTMENT_INFO, R_EBX);
+ hv_cpuid_get_host(cs, HV_CPUID_ENLIGHTMENT_INFO, R_EBX);
}
/* Features */
- r = hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_RELAXED);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_VAPIC);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_TIME);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_CRASH);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_RESET);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_VPINDEX);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_RUNTIME);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_SYNIC);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_STIMER);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_FREQUENCIES);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_REENLIGHTENMENT);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_TLBFLUSH);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_EVMCS);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_IPI);
- r |= hv_cpuid_check_and_set(cs, cpuid, HYPERV_FEAT_STIMER_DIRECT);
+ r = hv_cpuid_check_and_set(cs, HYPERV_FEAT_RELAXED);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_VAPIC);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_TIME);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_CRASH);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_RESET);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_VPINDEX);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_RUNTIME);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_SYNIC);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_FREQUENCIES);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_REENLIGHTENMENT);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_TLBFLUSH);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_EVMCS);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_IPI);
+ r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER_DIRECT);
/* Additional dependencies not covered by kvm_hyperv_properties[] */
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC) &&
@@ -1283,8 +1291,7 @@ static int hyperv_handle_properties(CPUState *cs,
}
if (r) {
- r = -ENOSYS;
- goto free;
+ return -ENOSYS;
}
c = &cpuid_ent[cpuid_i++];
@@ -1326,7 +1333,7 @@ static int hyperv_handle_properties(CPUState *cs,
if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_ON) {
c->eax |= HV_NO_NONARCH_CORESHARING;
} else if (cpu->hyperv_no_nonarch_cs == ON_OFF_AUTO_AUTO) {
- c->eax |= hv_cpuid_get_host(cpuid, HV_CPUID_ENLIGHTMENT_INFO, R_EAX) &
+ c->eax |= hv_cpuid_get_host(cs, HV_CPUID_ENLIGHTMENT_INFO, R_EAX) &
HV_NO_NONARCH_CORESHARING;
}
@@ -1351,12 +1358,8 @@ static int hyperv_handle_properties(CPUState *cs,
c->function = HV_CPUID_NESTED_FEATURES;
c->eax = cpu->hyperv_nested[0];
}
- r = cpuid_i;
-free:
- g_free(cpuid);
-
- return r;
+ return cpuid_i;
}
static Error *hv_passthrough_mig_blocker;
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 09/17] i386: split hyperv_handle_properties() into hyperv_expand_features()/hyperv_fill_cpuids()
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (7 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 08/17] i386: introduce hv_cpuid_cache Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 10/17] i386: move eVMCS enablement to hyperv_init_vcpu() Vitaly Kuznetsov
` (7 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
The intention is to call hyperv_expand_features() early, before vCPUs
are created and use the acquired data later when we set guest visible
CPUID data.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 043d4c84d2d2..ab828df397e8 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1186,16 +1186,15 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg)
}
/*
- * Fill in Hyper-V CPUIDs. Returns the number of entries filled in cpuid_ent in
- * case of success, errno < 0 in case of failure and 0 when no Hyper-V
- * extentions are enabled.
+ * Expand Hyper-V CPU features. In partucular, check that all the requested
+ * features are supported by the host and the sanity of the configuration
+ * (that all the required dependencies are included). Also, this takes care
+ * of 'hv_passthrough' mode and fills the environment with all supported
+ * Hyper-V features.
*/
-static int hyperv_handle_properties(CPUState *cs,
- struct kvm_cpuid_entry2 *cpuid_ent)
+static int hyperv_expand_features(CPUState *cs)
{
X86CPU *cpu = X86_CPU(cs);
- struct kvm_cpuid_entry2 *c;
- uint32_t cpuid_i = 0;
int r;
if (!hyperv_enabled(cpu))
@@ -1294,6 +1293,19 @@ static int hyperv_handle_properties(CPUState *cs,
return -ENOSYS;
}
+ return 0;
+}
+
+/*
+ * Fill in Hyper-V CPUIDs. Returns the number of entries filled in cpuid_ent.
+ */
+static int hyperv_fill_cpuids(CPUState *cs,
+ struct kvm_cpuid_entry2 *cpuid_ent)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ struct kvm_cpuid_entry2 *c;
+ uint32_t cpuid_i = 0;
+
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
c->eax = hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) ?
@@ -1501,11 +1513,13 @@ int kvm_arch_init_vcpu(CPUState *cs)
env->apic_bus_freq = KVM_APIC_BUS_FREQUENCY;
/* Paravirtualization CPUIDs */
- r = hyperv_handle_properties(cs, cpuid_data.entries);
+ r = hyperv_expand_features(cs);
if (r < 0) {
return r;
- } else if (r > 0) {
- cpuid_i = r;
+ }
+
+ if (hyperv_enabled(cpu)) {
+ cpuid_i = hyperv_fill_cpuids(cs, cpuid_data.entries);
kvm_base = KVM_CPUID_SIGNATURE_NEXT;
has_msr_hv_hypercall = true;
}
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 10/17] i386: move eVMCS enablement to hyperv_init_vcpu()
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (8 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 09/17] i386: split hyperv_handle_properties() into hyperv_expand_features()/hyperv_fill_cpuids() Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 11/17] i386: switch hyperv_expand_features() to using error_setg() Vitaly Kuznetsov
` (6 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
hyperv_expand_features() will be called before we create vCPU so
evmcs enablement should go away. hyperv_init_vcpu() looks like the
right place.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 60 ++++++++++++++++++++++++++-----------------
1 file changed, 37 insertions(+), 23 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index ab828df397e8..34820c3ef29a 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -962,6 +962,7 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs)
{
struct kvm_cpuid2 *cpuid;
int max = 7; /* 0x40000000..0x40000005, 0x4000000A */
+ int i;
/*
* When the buffer is too small, KVM_GET_SUPPORTED_HV_CPUID fails with
@@ -971,6 +972,22 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs)
while ((cpuid = try_get_hv_cpuid(cs, max)) == NULL) {
max++;
}
+
+ /*
+ * KVM_GET_SUPPORTED_HV_CPUID does not set EVMCS CPUID bit before
+ * KVM_CAP_HYPERV_ENLIGHTENED_VMCS is enabled but we want to get the
+ * information early, just check for the capability and set the bit
+ * manually.
+ */
+ if (kvm_check_extension(cs->kvm_state,
+ KVM_CAP_HYPERV_ENLIGHTENED_VMCS) > 0) {
+ for (i = 0; i < cpuid->nent; i++) {
+ if (cpuid->entries[i].function == HV_CPUID_ENLIGHTMENT_INFO) {
+ cpuid->entries[i].eax |= HV_ENLIGHTENED_VMCS_RECOMMENDED;
+ }
+ }
+ }
+
return cpuid;
}
@@ -1200,24 +1217,6 @@ static int hyperv_expand_features(CPUState *cs)
if (!hyperv_enabled(cpu))
return 0;
- if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) ||
- cpu->hyperv_passthrough) {
- uint16_t evmcs_version;
-
- r = kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, 0,
- (uintptr_t)&evmcs_version);
-
- if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) && r) {
- fprintf(stderr, "Hyper-V %s is not supported by kernel\n",
- kvm_hyperv_properties[HYPERV_FEAT_EVMCS].desc);
- return -ENOSYS;
- }
-
- if (!r) {
- cpu->hyperv_nested[0] = evmcs_version;
- }
- }
-
if (cpu->hyperv_passthrough) {
cpu->hyperv_vendor_id[0] =
hv_cpuid_get_host(cs, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EBX);
@@ -1455,6 +1454,21 @@ static int hyperv_init_vcpu(X86CPU *cpu)
}
}
+ if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) {
+ uint16_t evmcs_version;
+
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, 0,
+ (uintptr_t)&evmcs_version);
+
+ if (ret < 0) {
+ fprintf(stderr, "Hyper-V %s is not supported by kernel\n",
+ kvm_hyperv_properties[HYPERV_FEAT_EVMCS].desc);
+ return ret;
+ }
+
+ cpu->hyperv_nested[0] = evmcs_version;
+ }
+
return 0;
}
@@ -1519,6 +1533,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
}
if (hyperv_enabled(cpu)) {
+ r = hyperv_init_vcpu(cpu);
+ if (r) {
+ return r;
+ }
+
cpuid_i = hyperv_fill_cpuids(cs, cpuid_data.entries);
kvm_base = KVM_CPUID_SIGNATURE_NEXT;
has_msr_hv_hypercall = true;
@@ -1868,11 +1887,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
kvm_init_msrs(cpu);
- r = hyperv_init_vcpu(cpu);
- if (r) {
- goto fail;
- }
-
return 0;
fail:
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 11/17] i386: switch hyperv_expand_features() to using error_setg()
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (9 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 10/17] i386: move eVMCS enablement to hyperv_init_vcpu() Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 12/17] i386: adjust the expected KVM_GET_SUPPORTED_HV_CPUID array size Vitaly Kuznetsov
` (5 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
Use standard error_setg() mechanism in hyperv_expand_features().
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 101 +++++++++++++++++++++++++-----------------
1 file changed, 61 insertions(+), 40 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 34820c3ef29a..5cdceb6e34c4 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1135,7 +1135,7 @@ static bool hyperv_feature_supported(CPUState *cs, int feature)
return true;
}
-static int hv_cpuid_check_and_set(CPUState *cs, int feature)
+static int hv_cpuid_check_and_set(CPUState *cs, int feature, Error **errp)
{
X86CPU *cpu = X86_CPU(cs);
uint64_t deps;
@@ -1149,20 +1149,18 @@ static int hv_cpuid_check_and_set(CPUState *cs, int feature)
while (deps) {
dep_feat = ctz64(deps);
if (!(hyperv_feat_enabled(cpu, dep_feat))) {
- fprintf(stderr,
- "Hyper-V %s requires Hyper-V %s\n",
- kvm_hyperv_properties[feature].desc,
- kvm_hyperv_properties[dep_feat].desc);
- return 1;
+ error_setg(errp, "Hyper-V %s requires Hyper-V %s",
+ kvm_hyperv_properties[feature].desc,
+ kvm_hyperv_properties[dep_feat].desc);
+ return 1;
}
deps &= ~(1ull << dep_feat);
}
if (!hyperv_feature_supported(cs, feature)) {
if (hyperv_feat_enabled(cpu, feature)) {
- fprintf(stderr,
- "Hyper-V %s is not supported by kernel\n",
- kvm_hyperv_properties[feature].desc);
+ error_setg(errp, "Hyper-V %s is not supported by kernel",
+ kvm_hyperv_properties[feature].desc);
return 1;
} else {
return 0;
@@ -1209,13 +1207,12 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg)
* of 'hv_passthrough' mode and fills the environment with all supported
* Hyper-V features.
*/
-static int hyperv_expand_features(CPUState *cs)
+static void hyperv_expand_features(CPUState *cs, Error **errp)
{
X86CPU *cpu = X86_CPU(cs);
- int r;
if (!hyperv_enabled(cpu))
- return 0;
+ return;
if (cpu->hyperv_passthrough) {
cpu->hyperv_vendor_id[0] =
@@ -1262,37 +1259,60 @@ static int hyperv_expand_features(CPUState *cs)
}
/* Features */
- r = hv_cpuid_check_and_set(cs, HYPERV_FEAT_RELAXED);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_VAPIC);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_TIME);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_CRASH);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_RESET);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_VPINDEX);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_RUNTIME);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_SYNIC);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_FREQUENCIES);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_REENLIGHTENMENT);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_TLBFLUSH);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_EVMCS);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_IPI);
- r |= hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER_DIRECT);
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RELAXED, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VAPIC, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TIME, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_CRASH, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RESET, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_VPINDEX, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_RUNTIME, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_SYNIC, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_FREQUENCIES, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_REENLIGHTENMENT, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_TLBFLUSH, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_EVMCS, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_IPI, errp)) {
+ return;
+ }
+ if (hv_cpuid_check_and_set(cs, HYPERV_FEAT_STIMER_DIRECT, errp)) {
+ return;
+ }
/* Additional dependencies not covered by kvm_hyperv_properties[] */
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC) &&
!cpu->hyperv_synic_kvm_only &&
!hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX)) {
- fprintf(stderr, "Hyper-V %s requires Hyper-V %s\n",
- kvm_hyperv_properties[HYPERV_FEAT_SYNIC].desc,
- kvm_hyperv_properties[HYPERV_FEAT_VPINDEX].desc);
- r |= 1;
- }
-
- if (r) {
- return -ENOSYS;
+ error_setg(errp, "Hyper-V %s requires Hyper-V %s",
+ kvm_hyperv_properties[HYPERV_FEAT_SYNIC].desc,
+ kvm_hyperv_properties[HYPERV_FEAT_VPINDEX].desc);
}
-
- return 0;
}
/*
@@ -1527,9 +1547,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
env->apic_bus_freq = KVM_APIC_BUS_FREQUENCY;
/* Paravirtualization CPUIDs */
- r = hyperv_expand_features(cs);
- if (r < 0) {
- return r;
+ hyperv_expand_features(cs, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return -ENOSYS;
}
if (hyperv_enabled(cpu)) {
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 12/17] i386: adjust the expected KVM_GET_SUPPORTED_HV_CPUID array size
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (10 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 11/17] i386: switch hyperv_expand_features() to using error_setg() Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:50 ` [PATCH v5 13/17] i386: prefer system KVM_GET_SUPPORTED_HV_CPUID ioctl over vCPU's one Vitaly Kuznetsov
` (4 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
SYNDBG leaves were recently (Linux-5.8) added to KVM but we haven't
updated the expected size of KVM_GET_SUPPORTED_HV_CPUID output in
KVM so we now make serveral tries before succeeding. Update the
default.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 5cdceb6e34c4..4d301da7375e 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -961,7 +961,8 @@ static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max)
static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs)
{
struct kvm_cpuid2 *cpuid;
- int max = 7; /* 0x40000000..0x40000005, 0x4000000A */
+ /* 0x40000000..0x40000005, 0x4000000A, 0x40000080..0x40000080 leaves */
+ int max = 10;
int i;
/*
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 13/17] i386: prefer system KVM_GET_SUPPORTED_HV_CPUID ioctl over vCPU's one
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (11 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 12/17] i386: adjust the expected KVM_GET_SUPPORTED_HV_CPUID array size Vitaly Kuznetsov
@ 2021-03-01 13:50 ` Vitaly Kuznetsov
2021-03-01 13:51 ` [PATCH v5 14/17] i386: use global kvm_state in hyperv_enabled() check Vitaly Kuznetsov
` (3 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
KVM_GET_SUPPORTED_HV_CPUID was made a system wide ioctl which can be called
prior to creating vCPUs and we are going to use that to expand Hyper-V cpu
features early. Use it when it is supported by KVM.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 4d301da7375e..264f879cd257 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -928,7 +928,8 @@ static struct {
},
};
-static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max)
+static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max,
+ bool do_sys_ioctl)
{
struct kvm_cpuid2 *cpuid;
int r, size;
@@ -937,7 +938,11 @@ static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max)
cpuid = g_malloc0(size);
cpuid->nent = max;
- r = kvm_vcpu_ioctl(cs, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
+ if (do_sys_ioctl) {
+ r = kvm_ioctl(kvm_state, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
+ } else {
+ r = kvm_vcpu_ioctl(cs, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
+ }
if (r == 0 && cpuid->nent >= max) {
r = -E2BIG;
}
@@ -964,13 +969,17 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs)
/* 0x40000000..0x40000005, 0x4000000A, 0x40000080..0x40000080 leaves */
int max = 10;
int i;
+ bool do_sys_ioctl;
+
+ do_sys_ioctl =
+ kvm_check_extension(kvm_state, KVM_CAP_SYS_HYPERV_CPUID) > 0;
/*
* When the buffer is too small, KVM_GET_SUPPORTED_HV_CPUID fails with
* -E2BIG, however, it doesn't report back the right size. Keep increasing
* it and re-trying until we succeed.
*/
- while ((cpuid = try_get_hv_cpuid(cs, max)) == NULL) {
+ while ((cpuid = try_get_hv_cpuid(cs, max, do_sys_ioctl)) == NULL) {
max++;
}
@@ -980,7 +989,7 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs)
* information early, just check for the capability and set the bit
* manually.
*/
- if (kvm_check_extension(cs->kvm_state,
+ if (!do_sys_ioctl && kvm_check_extension(cs->kvm_state,
KVM_CAP_HYPERV_ENLIGHTENED_VMCS) > 0) {
for (i = 0; i < cpuid->nent; i++) {
if (cpuid->entries[i].function == HV_CPUID_ENLIGHTMENT_INFO) {
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 14/17] i386: use global kvm_state in hyperv_enabled() check
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (12 preceding siblings ...)
2021-03-01 13:50 ` [PATCH v5 13/17] i386: prefer system KVM_GET_SUPPORTED_HV_CPUID ioctl over vCPU's one Vitaly Kuznetsov
@ 2021-03-01 13:51 ` Vitaly Kuznetsov
2021-03-01 13:51 ` [PATCH v5 15/17] i386: expand Hyper-V features during CPU feature expansion time Vitaly Kuznetsov
` (2 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
There is no need to use vCPU-specific kvm state in hyperv_enabled() check
and we need to do that when feature expansion happens early, before vCPU
specific KVM state is created.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/kvm/kvm.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 264f879cd257..3fa6570215b6 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -715,8 +715,7 @@ unsigned long kvm_arch_vcpu_id(CPUState *cs)
static bool hyperv_enabled(X86CPU *cpu)
{
- CPUState *cs = CPU(cpu);
- return kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV) > 0 &&
+ return kvm_check_extension(kvm_state, KVM_CAP_HYPERV) > 0 &&
((cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_NOTIFY) ||
cpu->hyperv_features || cpu->hyperv_passthrough);
}
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 15/17] i386: expand Hyper-V features during CPU feature expansion time
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (13 preceding siblings ...)
2021-03-01 13:51 ` [PATCH v5 14/17] i386: use global kvm_state in hyperv_enabled() check Vitaly Kuznetsov
@ 2021-03-01 13:51 ` Vitaly Kuznetsov
2021-03-01 13:51 ` [PATCH v5 16/17] i386: provide simple 'hv-default=on' option Vitaly Kuznetsov
2021-03-01 13:51 ` [PATCH v5 17/17] qtest/hyperv: Introduce a simple hyper-v test Vitaly Kuznetsov
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
To make Hyper-V features appear in e.g. QMP query-cpu-model-expansion we
need to expand and set the corresponding CPUID leaves early. Modify
x86_cpu_get_supported_feature_word() to call newly intoduced Hyper-V
specific kvm_hv_get_supported_cpuid() instead of
kvm_arch_get_supported_cpuid(). We can't use kvm_arch_get_supported_cpuid()
as Hyper-V specific CPUID leaves intersect with KVM's.
Note, early expansion will only happen when KVM supports system wide
KVM_GET_SUPPORTED_HV_CPUID ioctl (KVM_CAP_SYS_HYPERV_CPUID).
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
target/i386/cpu.c | 4 ++++
target/i386/kvm/kvm-stub.c | 5 +++++
target/i386/kvm/kvm.c | 15 ++++++++++++---
target/i386/kvm/kvm_i386.h | 1 +
4 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index e943d42569db..dd639dd06784 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6502,6 +6502,10 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
if (env->cpuid_xlevel2 == UINT32_MAX) {
env->cpuid_xlevel2 = env->cpuid_min_xlevel2;
}
+
+ if (kvm_enabled()) {
+ kvm_hyperv_expand_features(cpu, errp);
+ }
}
/*
diff --git a/target/i386/kvm/kvm-stub.c b/target/i386/kvm/kvm-stub.c
index 92f49121b8fa..7f175faa3abd 100644
--- a/target/i386/kvm/kvm-stub.c
+++ b/target/i386/kvm/kvm-stub.c
@@ -39,3 +39,8 @@ bool kvm_hv_vpindex_settable(void)
{
return false;
}
+
+void kvm_hyperv_expand_features(X86CPU *cpu, Error **errp)
+{
+ return;
+}
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 3fa6570215b6..f865057a81dd 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1216,13 +1216,22 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg)
* of 'hv_passthrough' mode and fills the environment with all supported
* Hyper-V features.
*/
-static void hyperv_expand_features(CPUState *cs, Error **errp)
+void kvm_hyperv_expand_features(X86CPU *cpu, Error **errp)
{
- X86CPU *cpu = X86_CPU(cs);
+ CPUState *cs = CPU(cpu);
if (!hyperv_enabled(cpu))
return;
+ /*
+ * When kvm_hyperv_expand_features is called at CPU feature expansion
+ * time per-CPU kvm_state is not available yet so we can only proceed
+ * when KVM_CAP_SYS_HYPERV_CPUID is supported.
+ */
+ if (!cs->kvm_state &&
+ !kvm_check_extension(kvm_state, KVM_CAP_SYS_HYPERV_CPUID))
+ return;
+
if (cpu->hyperv_passthrough) {
cpu->hyperv_vendor_id[0] =
hv_cpuid_get_host(cs, HV_CPUID_VENDOR_AND_MAX_FUNCTIONS, R_EBX);
@@ -1556,7 +1565,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
env->apic_bus_freq = KVM_APIC_BUS_FREQUENCY;
/* Paravirtualization CPUIDs */
- hyperv_expand_features(cs, &local_err);
+ kvm_hyperv_expand_features(cpu, &local_err);
if (local_err) {
error_report_err(local_err);
return -ENOSYS;
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index dc725083891c..f1176491051d 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -47,6 +47,7 @@ bool kvm_has_x2apic_api(void);
bool kvm_has_waitpkg(void);
bool kvm_hv_vpindex_settable(void);
+void kvm_hyperv_expand_features(X86CPU *cpu, Error **errp);
uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address);
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 16/17] i386: provide simple 'hv-default=on' option
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (14 preceding siblings ...)
2021-03-01 13:51 ` [PATCH v5 15/17] i386: expand Hyper-V features during CPU feature expansion time Vitaly Kuznetsov
@ 2021-03-01 13:51 ` Vitaly Kuznetsov
2021-03-01 13:51 ` [PATCH v5 17/17] qtest/hyperv: Introduce a simple hyper-v test Vitaly Kuznetsov
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
Enabling Hyper-V emulation for a Windows VM is a tiring experience as it
requires listing all currently supported enlightenments ("hv-*" CPU
features) explicitly. We do have 'hv-passthrough' mode enabling
everything but it can't be used in production as it prevents migration.
Introduce a simple 'hv-default=on' CPU flag enabling all currently supported
Hyper-V enlightenments. Later, when new enlightenments get implemented,
compat_props mechanism will be used to disable them for legacy machine types,
this will keep 'hv-default=on' configurations migratable.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
docs/hyperv.txt | 18 ++++++++++++++---
target/i386/cpu.c | 50 +++++++++++++++++++++++++++++++++++++++++++++--
target/i386/cpu.h | 3 +++
3 files changed, 66 insertions(+), 5 deletions(-)
diff --git a/docs/hyperv.txt b/docs/hyperv.txt
index 5df00da54fc4..0a15cf026017 100644
--- a/docs/hyperv.txt
+++ b/docs/hyperv.txt
@@ -17,10 +17,22 @@ compatible hypervisor and use Hyper-V specific features.
2. Setup
=========
-No Hyper-V enlightenments are enabled by default by either KVM or QEMU. In
-QEMU, individual enlightenments can be enabled through CPU flags, e.g:
+The default set of currently supported Hyper-V enlightenments (consisting of all
+currently supported enlightenments except for 'hv-evmcs' which can only be
+enabled on VMX enabled guests) can be enabled by specifying 'hv-default=on' CPU
+flag:
- qemu-system-x86_64 --enable-kvm --cpu host,hv_relaxed,hv_vpindex,hv_time, ...
+ qemu-system-x86_64 --enable-kvm --cpu host,hv-default ...
+
+Alternatively, it is possible to do fine-grained enablement through CPU flags,
+e.g:
+
+ qemu-system-x86_64 --enable-kvm --cpu host,hv-relaxed,hv-vpindex,hv-time ...
+
+It is also possible to disable individual enlightenments from the default list,
+this can be used for debugging purposes:
+
+ qemu-system-x86_64 --enable-kvm --cpu host,hv-default=on,hv-evmcs=off ...
Sometimes there are dependencies between enlightenments, QEMU is supposed to
check that the supplied configuration is sane.
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index dd639dd06784..14f566cfde57 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -4658,6 +4658,25 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, const char *name,
cpu->env.tsc_khz = cpu->env.user_tsc_khz = value / 1000;
}
+static bool x86_hv_default_get(Object *obj, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+
+ return cpu->hyperv_default;
+}
+
+static void x86_hv_default_set(Object *obj, bool value, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+
+ cpu->hyperv_default = value;
+
+ /* hv-default overrides everything with the default set */
+ if (value) {
+ cpu->hyperv_features = cpu->hyperv_default_features;
+ }
+}
+
/* Generic getter for "feature-words" and "filtered-features" properties */
static void x86_cpu_get_feature_words(Object *obj, Visitor *v,
const char *name, void *opaque,
@@ -6563,10 +6582,16 @@ static void x86_cpu_filter_features(X86CPU *cpu, bool verbose)
}
}
-static void x86_cpu_hyperv_realize(X86CPU *cpu)
+static void x86_cpu_hyperv_realize(X86CPU *cpu, Error **errp)
{
size_t len;
+ if (cpu->hyperv_passthrough && cpu->hyperv_default) {
+ error_setg(errp,
+ "'hv-default' and 'hv-paththrough' are mutually exclusive");
+ return;
+ }
+
/* Hyper-V vendor id */
if (!cpu->hyperv_vendor) {
object_property_set_str(OBJECT(cpu), "hv-vendor-id", "Microsoft Hv",
@@ -6768,7 +6793,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
}
/* Process Hyper-V enlightenments */
- x86_cpu_hyperv_realize(cpu);
+ x86_cpu_hyperv_realize(cpu, &local_err);
+ if (local_err) {
+ goto out;
+ }
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
@@ -7063,6 +7091,20 @@ static void x86_cpu_initfn(Object *obj)
if (xcc->model) {
x86_cpu_load_model(cpu, xcc->model);
}
+
+ /*
+ * Hyper-V features enabled with 'hv-default=on'
+ * TODO: add 'HYPERV_FEAT_EVMCS' to the list. Enlightened VMCS can only
+ * be enabled for VMX enabled guests but here it can't be checked.
+ */
+ cpu->hyperv_default_features = BIT(HYPERV_FEAT_RELAXED) |
+ BIT(HYPERV_FEAT_VAPIC) | BIT(HYPERV_FEAT_TIME) |
+ BIT(HYPERV_FEAT_CRASH) | BIT(HYPERV_FEAT_RESET) |
+ BIT(HYPERV_FEAT_VPINDEX) | BIT(HYPERV_FEAT_RUNTIME) |
+ BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_STIMER) |
+ BIT(HYPERV_FEAT_FREQUENCIES) | BIT(HYPERV_FEAT_REENLIGHTENMENT) |
+ BIT(HYPERV_FEAT_TLBFLUSH) | BIT(HYPERV_FEAT_IPI) |
+ BIT(HYPERV_FEAT_STIMER_DIRECT);
}
static int64_t x86_cpu_get_arch_id(CPUState *cs)
@@ -7389,6 +7431,10 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
x86_cpu_get_crash_info_qom, NULL, NULL, NULL);
#endif
+ object_class_property_add_bool(oc, "hv-default",
+ x86_hv_default_get,
+ x86_hv_default_set);
+
for (w = 0; w < FEATURE_WORDS; w++) {
int bitnr;
for (bitnr = 0; bitnr < 64; bitnr++) {
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 265e552746e7..f014f1a89f89 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1673,6 +1673,9 @@ struct X86CPU {
bool hyperv_synic_kvm_only;
uint64_t hyperv_features;
bool hyperv_passthrough;
+ /* 'hv-default' enablement */
+ uint64_t hyperv_default_features;
+ bool hyperv_default;
OnOffAuto hyperv_no_nonarch_cs;
uint32_t hyperv_vendor_id[3];
uint32_t hyperv_interface_id[4];
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 17/17] qtest/hyperv: Introduce a simple hyper-v test
2021-03-01 13:50 [PATCH v5 00/17] i386: KVM: expand Hyper-V features early and provide simple 'hv-default=on' option Vitaly Kuznetsov
` (15 preceding siblings ...)
2021-03-01 13:51 ` [PATCH v5 16/17] i386: provide simple 'hv-default=on' option Vitaly Kuznetsov
@ 2021-03-01 13:51 ` Vitaly Kuznetsov
16 siblings, 0 replies; 18+ messages in thread
From: Vitaly Kuznetsov @ 2021-03-01 13:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Marcelo Tosatti, Eduardo Habkost, Igor Mammedov
For the beginning, just test 'hv-default', 'hv-passthrough' and a couple
of custom Hyper-V enlightenments configurations through QMP. Later, it
would be great to complement this by checking CPUID values from within the
guest.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
MAINTAINERS | 1 +
tests/qtest/hyperv-test.c | 270 ++++++++++++++++++++++++++++++++++++++
tests/qtest/meson.build | 3 +-
3 files changed, 273 insertions(+), 1 deletion(-)
create mode 100644 tests/qtest/hyperv-test.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 9b2aa18e1fe3..9c4152588f3e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1517,6 +1517,7 @@ F: hw/isa/apm.c
F: include/hw/isa/apm.h
F: tests/test-x86-cpuid.c
F: tests/qtest/test-x86-cpuid-compat.c
+F: tests/qtest/hyperv-test.c
PC Chipset
M: Michael S. Tsirkin <mst@redhat.com>
diff --git a/tests/qtest/hyperv-test.c b/tests/qtest/hyperv-test.c
new file mode 100644
index 000000000000..707fce80c5a0
--- /dev/null
+++ b/tests/qtest/hyperv-test.c
@@ -0,0 +1,270 @@
+/*
+ * Hyper-V emulation CPU feature test cases
+ *
+ * Copyright (c) 2021 Red Hat Inc.
+ * Authors:
+ * Vitaly Kuznetsov <vkuznets@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <linux/kvm.h>
+#include <sys/ioctl.h>
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "libqos/libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
+
+#define MACHINE_KVM "-machine pc-q35-5.2 -accel kvm "
+#define QUERY_HEAD "{ 'execute': 'query-cpu-model-expansion', " \
+ " 'arguments': { 'type': 'full', "
+#define QUERY_TAIL "}}"
+
+static bool kvm_enabled(QTestState *qts)
+{
+ QDict *resp, *qdict;
+ bool enabled;
+
+ resp = qtest_qmp(qts, "{ 'execute': 'query-kvm' }");
+ g_assert(qdict_haskey(resp, "return"));
+ qdict = qdict_get_qdict(resp, "return");
+ g_assert(qdict_haskey(qdict, "enabled"));
+ enabled = qdict_get_bool(qdict, "enabled");
+ qobject_unref(resp);
+
+ return enabled;
+}
+
+static bool kvm_has_sys_hyperv_cpuid(void)
+{
+ int fd = open("/dev/kvm", O_RDWR);
+ int ret;
+
+ g_assert(fd > 0);
+
+ ret = ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_SYS_HYPERV_CPUID);
+
+ close(fd);
+
+ return ret > 0;
+}
+
+static QDict *do_query_no_props(QTestState *qts, const char *cpu_type)
+{
+ return qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s }"
+ QUERY_TAIL, cpu_type);
+}
+
+static bool resp_has_props(QDict *resp)
+{
+ QDict *qdict;
+
+ g_assert(resp);
+
+ if (!qdict_haskey(resp, "return")) {
+ return false;
+ }
+ qdict = qdict_get_qdict(resp, "return");
+
+ if (!qdict_haskey(qdict, "model")) {
+ return false;
+ }
+ qdict = qdict_get_qdict(qdict, "model");
+
+ return qdict_haskey(qdict, "props");
+}
+
+static QDict *resp_get_props(QDict *resp)
+{
+ QDict *qdict;
+
+ g_assert(resp);
+ g_assert(resp_has_props(resp));
+
+ qdict = qdict_get_qdict(resp, "return");
+ qdict = qdict_get_qdict(qdict, "model");
+ qdict = qdict_get_qdict(qdict, "props");
+
+ return qdict;
+}
+
+static bool resp_get_feature(QDict *resp, const char *feature)
+{
+ QDict *props;
+
+ g_assert(resp);
+ g_assert(resp_has_props(resp));
+ props = resp_get_props(resp);
+ g_assert(qdict_get(props, feature));
+ return qdict_get_bool(props, feature);
+}
+
+#define assert_has_feature(qts, cpu_type, feature) \
+({ \
+ QDict *_resp = do_query_no_props(qts, cpu_type); \
+ g_assert(_resp); \
+ g_assert(resp_has_props(_resp)); \
+ g_assert(qdict_get(resp_get_props(_resp), feature)); \
+ qobject_unref(_resp); \
+})
+
+#define resp_assert_feature(resp, feature, expected_value) \
+({ \
+ QDict *_props; \
+ \
+ g_assert(_resp); \
+ g_assert(resp_has_props(_resp)); \
+ _props = resp_get_props(_resp); \
+ g_assert(qdict_get(_props, feature)); \
+ g_assert(qdict_get_bool(_props, feature) == (expected_value)); \
+})
+
+#define assert_feature(qts, cpu_type, feature, expected_value) \
+({ \
+ QDict *_resp; \
+ \
+ _resp = do_query_no_props(qts, cpu_type); \
+ g_assert(_resp); \
+ resp_assert_feature(_resp, feature, expected_value); \
+ qobject_unref(_resp); \
+})
+
+#define assert_has_feature_enabled(qts, cpu_type, feature) \
+ assert_feature(qts, cpu_type, feature, true)
+
+#define assert_has_feature_disabled(qts, cpu_type, feature) \
+ assert_feature(qts, cpu_type, feature, false)
+
+static void test_assert_hyperv_all_but_evmcs(QTestState *qts)
+{
+ assert_has_feature_enabled(qts, "host", "hv-relaxed");
+ assert_has_feature_enabled(qts, "host", "hv-vapic");
+ assert_has_feature_enabled(qts, "host", "hv-vpindex");
+ assert_has_feature_enabled(qts, "host", "hv-runtime");
+ assert_has_feature_enabled(qts, "host", "hv-crash");
+ assert_has_feature_enabled(qts, "host", "hv-time");
+ assert_has_feature_enabled(qts, "host", "hv-synic");
+ assert_has_feature_enabled(qts, "host", "hv-stimer");
+ assert_has_feature_enabled(qts, "host", "hv-tlbflush");
+ assert_has_feature_enabled(qts, "host", "hv-ipi");
+ assert_has_feature_enabled(qts, "host", "hv-reset");
+ assert_has_feature_enabled(qts, "host", "hv-frequencies");
+ assert_has_feature_enabled(qts, "host", "hv-reenlightenment");
+ assert_has_feature_enabled(qts, "host", "hv-stimer-direct");
+}
+
+static void test_query_cpu_hv_all_but_evmcs(const void *data)
+{
+ QTestState *qts;
+
+ qts = qtest_init(MACHINE_KVM "-cpu host,hv-relaxed,hv-vapic,hv-vpindex,"
+ "hv-runtime,hv-crash,hv-time,hv-synic,hv-stimer,"
+ "hv-tlbflush,hv-ipi,hv-reset,hv-frequencies,"
+ "hv-reenlightenment,hv-stimer-direct");
+
+ test_assert_hyperv_all_but_evmcs(qts);
+
+ qtest_quit(qts);
+}
+
+static void test_query_cpu_hv_default(const void *data)
+{
+ QTestState *qts;
+
+ qts = qtest_init(MACHINE_KVM "-cpu host,hv-default");
+
+ test_assert_hyperv_all_but_evmcs(qts);
+
+ qtest_quit(qts);
+}
+
+static void test_query_cpu_hv_default_minus(const void *data)
+{
+ QTestState *qts;
+
+ qts = qtest_init(MACHINE_KVM "-cpu host,hv-default,hv_ipi=off");
+
+ assert_has_feature_enabled(qts, "host", "hv-tlbflush");
+ assert_has_feature_disabled(qts, "host", "hv-ipi");
+
+ qtest_quit(qts);
+}
+
+static void test_query_cpu_hv_custom(const void *data)
+{
+ QTestState *qts;
+
+ qts = qtest_init(MACHINE_KVM "-cpu host,hv-vpindex");
+
+ assert_has_feature_enabled(qts, "host", "hv-vpindex");
+ assert_has_feature_disabled(qts, "host", "hv-synic");
+
+ qtest_quit(qts);
+}
+
+static void test_query_cpu_hv_passthrough(const void *data)
+{
+ QTestState *qts;
+ QDict *resp;
+
+ qts = qtest_init(MACHINE_KVM "-cpu host,hv-passthrough");
+ if (!kvm_enabled(qts)) {
+ qtest_quit(qts);
+ return;
+ }
+
+ test_assert_hyperv_all_but_evmcs(qts);
+
+ resp = do_query_no_props(qts, "host");
+ if (resp_get_feature(resp, "vmx")) {
+ assert_has_feature_enabled(qts, "host", "hv-evmcs");
+ } else {
+ assert_has_feature_disabled(qts, "host", "hv-evmcs");
+ }
+
+ qtest_quit(qts);
+}
+
+static void test_query_cpu_hv_evmcs_novmx_default(const void *data)
+{
+ QTestState *qts;
+
+ qts = qtest_init(MACHINE_KVM "-cpu host,-vmx,hv-default");
+ if (!kvm_enabled(qts)) {
+ qtest_quit(qts);
+ return;
+ }
+
+ assert_has_feature_disabled(qts, "host", "vmx");
+ assert_has_feature_disabled(qts, "host", "hv-evmcs");
+
+ qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+ const char *arch = qtest_get_arch();
+
+ g_test_init(&argc, &argv, NULL);
+
+ if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) {
+ qtest_add_data_func("/hyperv/hv-all-but-evmcs",
+ NULL, test_query_cpu_hv_all_but_evmcs);
+ qtest_add_data_func("/hyperv/hv-default",
+ NULL, test_query_cpu_hv_default);
+ qtest_add_data_func("/hyperv/hv-default-minus",
+ NULL, test_query_cpu_hv_default_minus);
+ qtest_add_data_func("/hyperv/hv-custom",
+ NULL, test_query_cpu_hv_custom);
+ if (kvm_has_sys_hyperv_cpuid()) {
+ qtest_add_data_func("/hyperv/hv-passthrough",
+ NULL, test_query_cpu_hv_passthrough);
+ qtest_add_data_func("/hyperv/hv-evmcs-novmx-default", NULL,
+ test_query_cpu_hv_evmcs_novmx_default);
+ }
+ }
+
+ return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index ba6ecaed3256..c65f2098defc 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -65,7 +65,8 @@ qtests_i386 = \
'vmgenid-test',
'migration-test',
'test-x86-cpuid-compat',
- 'numa-test']
+ 'numa-test',
+ 'hyperv-test']
dbus_daemon = find_program('dbus-daemon', required: false)
if dbus_daemon.found() and config_host.has_key('GDBUS_CODEGEN')
--
2.29.2
^ permalink raw reply related [flat|nested] 18+ messages in thread