All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vitaly Kuznetsov <vkuznets@redhat.com>
To: qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	Richard Henderson <rth@twiddle.net>,
	Eduardo Habkost <ehabkost@redhat.com>,
	Marcelo Tosatti <mtosatti@redhat.com>,
	Roman Kagan <rkagan@virtuozzo.com>
Subject: [Qemu-devel] [PATCH RFC 4/8] i386/kvm: Implement 'hv-all' pass-through mode
Date: Fri, 25 Jan 2019 12:41:51 +0100	[thread overview]
Message-ID: <20190125114155.32062-5-vkuznets@redhat.com> (raw)
In-Reply-To: <20190125114155.32062-1-vkuznets@redhat.com>

In many case we just want to give Windows guests all currently supported
Hyper-V enlightenments and that's where this new mode may come handy. We
pass through what was returned by KVM_GET_SUPPORTED_HV_CPUID.

hv_cpuid_check_and_set() is modified to also set cpu->hyperv_* flags as
we may want to check them later (and we actually do for hv_runtime,
hv_synic,...).

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
 target/i386/cpu.c |   1 +
 target/i386/cpu.h |   1 +
 target/i386/kvm.c | 133 ++++++++++++++++++++++++++++++++++++----------
 3 files changed, 107 insertions(+), 28 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 2f5412592d..b776be5223 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5771,6 +5771,7 @@ static Property x86_cpu_properties[] = {
     DEFINE_PROP_BOOL("hv-tlbflush", X86CPU, hyperv_tlbflush, false),
     DEFINE_PROP_BOOL("hv-evmcs", X86CPU, hyperv_evmcs, false),
     DEFINE_PROP_BOOL("hv-ipi", X86CPU, hyperv_ipi, false),
+    DEFINE_PROP_BOOL("hv-all", X86CPU, hyperv_all, false),
     DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true),
     DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
     DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 59656a70e6..9b5c2715cc 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1397,6 +1397,7 @@ struct X86CPU {
     bool hyperv_tlbflush;
     bool hyperv_evmcs;
     bool hyperv_ipi;
+    bool hyperv_all;
     bool check_cpuid;
     bool enforce_cpuid;
     bool expose_kvm;
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index ed55040d9e..b373b4ac06 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -647,7 +647,8 @@ static bool hyperv_enabled(X86CPU *cpu)
             cpu->hyperv_stimer ||
             cpu->hyperv_reenlightenment ||
             cpu->hyperv_tlbflush ||
-            cpu->hyperv_ipi);
+            cpu->hyperv_ipi ||
+            cpu->hyperv_all);
 }
 
 static int kvm_arch_set_tsc_khz(CPUState *cs)
@@ -995,14 +996,15 @@ static int hv_cpuid_get_fw(struct kvm_cpuid2 *cpuid, int fw, uint32_t *r)
 }
 
 static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
-                                  const char *name, bool flag)
+                                  const char *name, bool *flag)
 {
     X86CPU *cpu = X86_CPU(cs);
     CPUX86State *env = &cpu->env;
     uint32_t r, fw, bits;;
     int i, j;
+    bool present;
 
-    if (!flag) {
+    if (!*flag && !cpu->hyperv_all) {
         return 0;
     }
 
@@ -1011,6 +1013,7 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
             continue;
         }
 
+        present = true;
         for (j = 0; j < ARRAY_SIZE(kvm_hyperv_properties[i].flags); j++) {
             fw = kvm_hyperv_properties[i].flags[j].fw;
             bits = kvm_hyperv_properties[i].flags[j].bits;
@@ -1020,17 +1023,26 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
             }
 
             if (hv_cpuid_get_fw(cpuid, fw, &r) || (r & bits) != bits) {
-                fprintf(stderr,
-                        "Hyper-V %s (requested by '%s' cpu flag) "
-                        "is not supported by kernel\n",
-                        kvm_hyperv_properties[i].desc,
-                        kvm_hyperv_properties[i].name);
-                return 1;
+                if (*flag) {
+                    fprintf(stderr,
+                            "Hyper-V %s (requested by '%s' cpu flag) "
+                            "is not supported by kernel\n",
+                            kvm_hyperv_properties[i].desc,
+                            kvm_hyperv_properties[i].name);
+                    return 1;
+                } else {
+                    present = false;
+                    break;
+                }
             }
 
             env->features[fw] |= bits;
         }
 
+        if (cpu->hyperv_all && present) {
+            *flag = true;
+        }
+
         return 0;
     }
 
@@ -1038,6 +1050,43 @@ static int hv_cpuid_check_and_set(CPUState *cs, struct kvm_cpuid2 *cpuid,
     return 1;
 }
 
+static int hv_report_missing_dep(X86CPU *cpu, const char *name,
+                                 const char *dep_name)
+{
+    int i, j, nprops = sizeof(kvm_hyperv_properties);
+
+    for (i = 0; i < nprops; i++) {
+        if (!strcmp(kvm_hyperv_properties[i].name, name)) {
+            break;
+        }
+    }
+    for (j = 0; j < nprops; j++) {
+        if (!strcmp(kvm_hyperv_properties[j].name, dep_name)) {
+            break;
+        }
+    }
+
+    /*
+     * Internal error: either feature or its dependency is not in
+     * kvm_hyperv_properties!
+     */
+    if (i == nprops || j == nprops) {
+        return 1;
+    }
+
+    if (cpu->hyperv_all) {
+        fprintf(stderr, "Hyper-V %s (requested by 'hv-all' cpu flag) "
+                "requires %s (is not supported by kernel)\n",
+                kvm_hyperv_properties[i].desc, kvm_hyperv_properties[j].desc);
+    } else {
+        fprintf(stderr, "Hyper-V %s (requested by '%s' cpu flag) "
+                "requires %s ('%s')\n", kvm_hyperv_properties[i].desc,
+                name, kvm_hyperv_properties[j].desc, dep_name);
+    }
+
+    return 1;
+}
+
 /*
  * 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
@@ -1077,32 +1126,54 @@ static int hyperv_handle_properties(CPUState *cs,
         cpuid = get_supported_hv_cpuid_legacy(cs);
     }
 
+    if (cpu->hyperv_all) {
+        memcpy(cpuid_ent, &cpuid->entries[0],
+               cpuid->nent * sizeof(cpuid->entries[0]));
+
+        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->eax;
+        }
+        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_RETRY) {
+                c->ebx = cpu->hyperv_spinlock_attempts;
+            }
+        }
+        c = cpuid_find_entry(cpuid, HV_CPUID_NESTED_FEATURES, 0);
+        if (c) {
+            env->features[FEAT_HV_NESTED_EAX] = c->eax;
+        }
+    }
+
     /* Features */
     r |= hv_cpuid_check_and_set(cs, cpuid, "hv-relaxed",
-                                cpu->hyperv_relaxed_timing);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-vapic", cpu->hyperv_vapic);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-time", cpu->hyperv_time);
+                                &cpu->hyperv_relaxed_timing);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-vapic", &cpu->hyperv_vapic);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-time", &cpu->hyperv_time);
     r |= hv_cpuid_check_and_set(cs, cpuid, "hv-frequencies",
-                                cpu->hyperv_frequencies);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-crash", cpu->hyperv_crash);
+                                &cpu->hyperv_frequencies);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-crash", &cpu->hyperv_crash);
     r |= hv_cpuid_check_and_set(cs, cpuid, "hv-reenlightenment",
-                                cpu->hyperv_reenlightenment);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-reset", cpu->hyperv_reset);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-vpindex", cpu->hyperv_vpindex);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-runtime", cpu->hyperv_runtime);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-synic", cpu->hyperv_synic);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-stimer", cpu->hyperv_stimer);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-tlbflush", cpu->hyperv_tlbflush);
-    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-ipi", cpu->hyperv_ipi);
+                                &cpu->hyperv_reenlightenment);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-reset", &cpu->hyperv_reset);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-vpindex", &cpu->hyperv_vpindex);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-runtime", &cpu->hyperv_runtime);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-synic", &cpu->hyperv_synic);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-stimer", &cpu->hyperv_stimer);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-tlbflush",
+                                &cpu->hyperv_tlbflush);
+    r |= hv_cpuid_check_and_set(cs, cpuid, "hv-ipi", &cpu->hyperv_ipi);
 
     /* Dependencies */
     if (cpu->hyperv_synic && !cpu->hyperv_synic_kvm_only &&
-        !cpu->hyperv_vpindex) {
-        fprintf(stderr, "Hyper-V SynIC "
-                "(requested by 'hv-synic' cpu flag) "
-                "requires Hyper-V VP_INDEX ('hv-vpindex')\n");
-        r |= 1;
-    }
+        !cpu->hyperv_vpindex)
+        r |= hv_report_missing_dep(cpu, "hv-synic", "hv-vpindex");
 
     /* Not exposed by KVM but needed to make CPU hotplug in Windows work */
     env->features[FEAT_HYPERV_EDX] |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE;
@@ -1112,6 +1183,12 @@ static int hyperv_handle_properties(CPUState *cs,
         goto free;
     }
 
+    if (cpu->hyperv_all) {
+        /* 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;
     if (!cpu->hyperv_vendor_id) {
-- 
2.20.1

  parent reply	other threads:[~2019-01-25 11:42 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-25 11:41 [Qemu-devel] [PATCH RFC 0/8] i386/kvm/hyper-v: refactor and implement 'hv-stimer-direct' and 'hv-all' enlightenments Vitaly Kuznetsov
2019-01-25 11:41 ` [Qemu-devel] [PATCH RFC 1/8] Update linux headers (5.0-rc2) Vitaly Kuznetsov
2019-01-25 11:41 ` [Qemu-devel] [PATCH RFC 2/8] i386/kvm: add support for KVM_GET_SUPPORTED_HV_CPUID Vitaly Kuznetsov
2019-01-25 11:41 ` [Qemu-devel] [PATCH RFC 3/8] i386/kvm: move Hyper-V CPUID filling to hyperv_handle_properties() Vitaly Kuznetsov
2019-01-25 11:41 ` Vitaly Kuznetsov [this message]
2019-01-25 12:47   ` [Qemu-devel] [PATCH RFC 4/8] i386/kvm: Implement 'hv-all' pass-through mode Roman Kagan
2019-01-25 13:46     ` Vitaly Kuznetsov
2019-01-28 11:30       ` Roman Kagan
2019-01-28 13:54         ` Vitaly Kuznetsov
2019-01-28 18:22           ` Dr. David Alan Gilbert
2019-01-28 19:10             ` Eduardo Habkost
2019-01-29 15:25               ` Vitaly Kuznetsov
2019-01-29 15:20             ` Vitaly Kuznetsov
2019-01-29 15:28               ` Dr. David Alan Gilbert
2019-01-29 15:43             ` Daniel P. Berrangé
2019-01-25 11:41 ` [Qemu-devel] [PATCH RFC 5/8] i386/kvm: hv-evmcs requires hv-vapic Vitaly Kuznetsov
2019-01-25 11:41 ` [Qemu-devel] [PATCH RFC 6/8] i386/kvm: hv-stimer requires hv-time and hv-synic Vitaly Kuznetsov
2019-01-25 11:41 ` [Qemu-devel] [PATCH RFC 7/8] i386/kvm: hv-tlbflush/ipi require hv-vpindex Vitaly Kuznetsov
2019-01-25 11:41 ` [Qemu-devel] [PATCH RFC 8/8] i386/kvm: add support for Direct Mode for Hyper-V synthetic timers Vitaly Kuznetsov
2019-01-31 18:09 ` [Qemu-devel] [PATCH RFC 0/8] i386/kvm/hyper-v: refactor and implement 'hv-stimer-direct' and 'hv-all' enlightenments no-reply
2019-02-02 13:39   ` Vitaly Kuznetsov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190125114155.32062-5-vkuznets@redhat.com \
    --to=vkuznets@redhat.com \
    --cc=ehabkost@redhat.com \
    --cc=mtosatti@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rkagan@virtuozzo.com \
    --cc=rth@twiddle.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.