qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
@ 2012-08-30 19:20 Don Slutz
  2012-09-05 16:48 ` Marcelo Tosatti
  2012-09-06 10:28 ` Andreas Färber
  0 siblings, 2 replies; 10+ messages in thread
From: Don Slutz @ 2012-08-30 19:20 UTC (permalink / raw)
  To: qemu-devel, kvm; +Cc: Don Slutz, Marcelo Tosatti, Avi Kivity

This is primarily done so that the guest will think it is running
under vmware when hypervisor=vmware is specified as a property of a
cpu.

Also allow this to work in accel=tcg mode.

The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
hyper_extra_b can be used to further adjust what the guest sees.

Signed-off-by: Don Slutz <Don@CloudSwitch.com>
---
 target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 target-i386/cpu.h |    9 +++
 target-i386/kvm.c |   33 ++++++++--
 3 files changed, 214 insertions(+), 6 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index f3cac49..a444b95 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -26,6 +26,7 @@
 
 #include "qemu-option.h"
 #include "qemu-config.h"
+#include "qemu-timer.h"
 
 #include "qapi/qapi-visit-core.h"
 #include "arch_init.h"
@@ -244,6 +245,15 @@ typedef struct x86_def_t {
     uint32_t xlevel2;
     /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
     uint32_t cpuid_7_0_ebx_features;
+    /* Hypervisor CPUIDs */
+    uint32_t cpuid_hv_level;
+    uint32_t cpuid_hv_vendor1;
+    uint32_t cpuid_hv_vendor2;
+    uint32_t cpuid_hv_vendor3;
+    /* VMware extra data */
+    uint32_t cpuid_hv_extra;
+    uint32_t cpuid_hv_extra_a;
+    uint32_t cpuid_hv_extra_b;
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -860,6 +870,18 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
     cpu->env.tsc_khz = value / 1000;
 }
 
+static void x86_cpuid_set_hv(x86_def_t *x86_cpu_def, uint32_t level,
+                             const char *who)
+{
+        uint32_t signature[3];
+
+        memcpy(signature, who, 12);
+        x86_cpu_def->cpuid_hv_level = level;
+        x86_cpu_def->cpuid_hv_vendor1 = signature[0];
+        x86_cpu_def->cpuid_hv_vendor2 = signature[1];
+        x86_cpu_def->cpuid_hv_vendor3 = signature[2];
+}
+
 static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 {
     unsigned int i;
@@ -867,6 +889,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 
     char *s = g_strdup(cpu_model);
     char *featurestr, *name = strtok(s, ",");
+    bool hyperv_enabled = false;
+    bool hv_enabled = false;
+    long hyper_level = -1;
+    long hyper_extra = -1;
     /* Features to be added*/
     uint32_t plus_features = 0, plus_ext_features = 0;
     uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
@@ -993,12 +1019,84 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
                 x86_cpu_def->tsc_khz = tsc_freq / 1000;
             } else if (!strcmp(featurestr, "hv_spinlocks")) {
                 char *err;
+
+                if (hv_enabled) {
+                    fprintf(stderr,
+                            "Only one of hypervisor= or hv_* can be used at one time.\n");
+                    goto error;
+                }
                 numvalue = strtoul(val, &err, 0);
                 if (!*val || *err) {
                     fprintf(stderr, "bad numerical value %s\n", val);
                     goto error;
                 }
+                hyperv_enabled = true;
                 hyperv_set_spinlock_retries(numvalue);
+            } else if (!strcmp(featurestr, "hyper_level")) {
+                char *err;
+                long longvalue = strtol(val, &err, 0);
+
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value for hyper_level=%s\n",
+                            val);
+                    goto error;
+                }
+                hyper_level = longvalue;
+            } else if (!strcmp(featurestr, "hyper_extra")) {
+                char *err;
+                long longvalue = strtol(val, &err, 0);
+
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value for hyper_extra=%s\n",
+                            val);
+                    goto error;
+                }
+                hyper_extra = longvalue;
+            } else if (!strcmp(featurestr, "hyper_extra_a")) {
+                char *err;
+
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr,
+                            "bad numerical value for hyper_extra_a=%s\n",
+                            val);
+                    goto error;
+                }
+                x86_cpu_def->cpuid_hv_extra_a = (uint32_t)numvalue;
+            } else if (!strcmp(featurestr, "hyper_extra_b")) {
+                char *err;
+
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr,
+                            "bad numerical value for hyper_extra_b=%s\n",
+                            val);
+                    goto error;
+                }
+                x86_cpu_def->cpuid_hv_extra_b = (uint32_t)numvalue;
+            } else if (!strcmp(featurestr, "hv") ||
+                       !strcmp(featurestr, "hypervisor")) {
+                if (hyperv_enabled) {
+                    fprintf(stderr,
+                            "Only one of hypervisor= or hv_* can be used at one time.\n");
+                    goto error;
+                }
+                hv_enabled = true;
+                if (!strcmp(val, "vmware")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000010, "VMwareVMware");
+                    minus_kvm_features = ~0;    /* Expected to be zero... */
+                } else if (!strcmp(val, "vmware3")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "VMwareVMware");
+                    minus_kvm_features = ~0;    /* Expected to be zero... */
+                } else if (!strcmp(val, "xen")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "XenVMMXenVMM");
+                } else if (!strcmp(val, "kvm")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0, "KVMKVMKVM\0\0\0");
+                } else {
+                    fprintf(stderr, "unknown hypervisor %s\n",
+                            val);
+                    goto error;
+                }
             } else {
                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
                 goto error;
@@ -1008,8 +1106,20 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         } else if (!strcmp(featurestr, "enforce")) {
             check_cpuid = enforce_cpuid = 1;
         } else if (!strcmp(featurestr, "hv_relaxed")) {
+            if (hv_enabled) {
+                fprintf(stderr,
+                        "Only one of hypervisor= or hv_* can be used at one time.\n");
+                goto error;
+            }
+            hyperv_enabled = true;
             hyperv_enable_relaxed_timing(true);
         } else if (!strcmp(featurestr, "hv_vapic")) {
+            if (hv_enabled) {
+                fprintf(stderr,
+                        "Only one of hypervisor= or hv_* can be used at one time.\n");
+                goto error;
+            }
+            hyperv_enabled = true;
             hyperv_enable_vapic_recommended(true);
         } else {
             fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
@@ -1017,6 +1127,34 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         }
         featurestr = strtok(NULL, ",");
     }
+#ifdef CONFIG_KVM
+    if (hyperv_enabled) {
+        x86_cpuid_set_hv(x86_cpu_def, HYPERV_CPUID_MIN, "Microsoft Hv");
+    }
+#endif
+    if (hyper_extra >= 0) {
+        x86_cpu_def->cpuid_hv_extra = 0x40000000 + hyper_extra;
+    } else if (hv_enabled && x86_cpu_def->tsc_khz) {
+        /*
+         * From http://article.gmane.org/gmane.comp.emulators.kvm.devel/22643
+         *
+         *    Leaf 0x40000010, Timing Information.
+         *
+         *    VMware has defined the first generic leaf to provide timing
+         *    information.  This leaf returns the current TSC frequency and
+         *    current Bus frequency in kHz.
+         *
+         *    # EAX: (Virtual) TSC frequency in kHz.
+         *    # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
+         *    # ECX, EDX: RESERVED (Per above, reserved fields are set to zero).
+         */
+        x86_cpu_def->cpuid_hv_extra = 0x40000010;
+        x86_cpu_def->cpuid_hv_extra_a = (uint32_t)x86_cpu_def->tsc_khz;
+        x86_cpu_def->cpuid_hv_extra_b = (uint32_t)(get_ticks_per_sec() / 1000);
+    }
+    if (hyper_level >= 0) {
+        x86_cpu_def->cpuid_hv_level = 0x40000000 + hyper_level;
+    }
     x86_cpu_def->features |= plus_features;
     x86_cpu_def->ext_features |= plus_ext_features;
     x86_cpu_def->ext2_features |= plus_ext2_features;
@@ -1192,6 +1330,13 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
     env->cpuid_ext4_features = def->ext4_features;
     env->cpuid_7_0_ebx = def->cpuid_7_0_ebx_features;
     env->cpuid_xlevel2 = def->xlevel2;
+    env->cpuid_hv_level = def->cpuid_hv_level;
+    env->cpuid_hv_vendor1 = def->cpuid_hv_vendor1;
+    env->cpuid_hv_vendor2 = def->cpuid_hv_vendor2;
+    env->cpuid_hv_vendor3 = def->cpuid_hv_vendor3;
+    env->cpuid_hv_extra = def->cpuid_hv_extra;
+    env->cpuid_hv_extra_a = def->cpuid_hv_extra_a;
+    env->cpuid_hv_extra_b = def->cpuid_hv_extra_b;
     object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
                             "tsc-frequency", &error);
     if (!kvm_enabled()) {
@@ -1390,6 +1535,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                 index =  env->cpuid_xlevel;
             }
         }
+    } else if (index & 0x40000000) {
+        if (env->cpuid_hv_level > 0) {
+            /* Handle Paravirtualization CPUIDs */
+            if (index > env->cpuid_hv_level) {
+                index = env->cpuid_hv_level;
+            }
+        } else {
+            if (index > env->cpuid_level)
+                index = env->cpuid_level;
+        }
     } else {
         if (index > env->cpuid_level)
             index = env->cpuid_level;
@@ -1528,6 +1683,29 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
             *edx = 0;
         }
         break;
+    case 0x40000000:
+        *eax = env->cpuid_hv_level;
+        *ebx = env->cpuid_hv_vendor1;
+        *ecx = env->cpuid_hv_vendor2;
+        *edx = env->cpuid_hv_vendor3;
+        break;
+    case 0x40000001:
+        *eax = env->cpuid_kvm_features;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    case 0x40000002 ... 0x400000FF:
+        if (index == env->cpuid_hv_extra) {
+            *eax = env->cpuid_hv_extra_a;
+            *ebx = env->cpuid_hv_extra_b;
+        } else {
+            *eax = 0;
+            *ebx = 0;
+        }
+        *ecx = 0;
+        *edx = 0;
+        break;
     case 0x80000000:
         *eax = env->cpuid_xlevel;
         *ebx = env->cpuid_vendor1;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 0677502..dc2039a 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -746,6 +746,15 @@ typedef struct CPUX86State {
     uint32_t cpuid_ext4_features;
     /* Flags from CPUID[EAX=7,ECX=0].EBX */
     uint32_t cpuid_7_0_ebx;
+    /* Paravirtualization CPUIDs */
+    uint32_t cpuid_hv_level;
+    uint32_t cpuid_hv_vendor1;
+    uint32_t cpuid_hv_vendor2;
+    uint32_t cpuid_hv_vendor3;
+    /* VMware extra data */
+    uint32_t cpuid_hv_extra;
+    uint32_t cpuid_hv_extra_a;
+    uint32_t cpuid_hv_extra_b;
 
     /* MTRRs */
     uint64_t mtrr_fixed[11];
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ffc294e..d01a5f8 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -389,16 +389,18 @@ int kvm_arch_init_vcpu(CPUX86State *env)
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_SIGNATURE;
-    if (!hyperv_enabled()) {
+    if (env->cpuid_hv_level == 0) {
         memcpy(signature, "KVMKVMKVM\0\0\0", 12);
         c->eax = 0;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
     } else {
-        memcpy(signature, "Microsoft Hv", 12);
-        c->eax = HYPERV_CPUID_MIN;
+        c->eax = env->cpuid_hv_level;
+        c->ebx = env->cpuid_hv_vendor1;
+        c->ecx = env->cpuid_hv_vendor2;
+        c->edx = env->cpuid_hv_vendor3;
     }
-    c->ebx = signature[0];
-    c->ecx = signature[1];
-    c->edx = signature[2];
 
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
@@ -452,6 +454,25 @@ int kvm_arch_init_vcpu(CPUX86State *env)
         c->ebx = signature[0];
         c->ecx = signature[1];
         c->edx = signature[2];
+    } else if (env->cpuid_hv_level > 0) {
+        for (i = KVM_CPUID_FEATURES + 1; i <= env->cpuid_hv_level; i++) {
+            c = &cpuid_data.entries[cpuid_i++];
+            memset(c, 0, sizeof(*c));
+            c->function = i;
+            if (i == env->cpuid_hv_extra) {
+                c->eax = env->cpuid_hv_extra_a;
+                c->ebx = env->cpuid_hv_extra_b;
+            }
+        }
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = KVM_CPUID_SIGNATURE_NEXT;
+        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+        c->eax = 0;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
     }
 
     has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
@ 2012-08-30 20:36 Don Slutz
  0 siblings, 0 replies; 10+ messages in thread
From: Don Slutz @ 2012-08-30 20:36 UTC (permalink / raw)
  To: qemu-devel, kvm; +Cc: Don Slutz, Marcelo Tosatti, Avi Kivity

This is primarily done so that the guest will think it is running
under vmware when hypervisor=vmware is specified as a property of a
cpu.

Also allow this to work in accel=tcg mode.

The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
hyper_extra_b can be used to further adjust what the guest sees.

Signed-off-by: Don Slutz <Don@CloudSwitch.com>
---
 target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 target-i386/cpu.h |    9 +++
 target-i386/kvm.c |   33 ++++++++--
 3 files changed, 214 insertions(+), 6 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index f3cac49..a444b95 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -26,6 +26,7 @@
 
 #include "qemu-option.h"
 #include "qemu-config.h"
+#include "qemu-timer.h"
 
 #include "qapi/qapi-visit-core.h"
 #include "arch_init.h"
@@ -244,6 +245,15 @@ typedef struct x86_def_t {
     uint32_t xlevel2;
     /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
     uint32_t cpuid_7_0_ebx_features;
+    /* Hypervisor CPUIDs */
+    uint32_t cpuid_hv_level;
+    uint32_t cpuid_hv_vendor1;
+    uint32_t cpuid_hv_vendor2;
+    uint32_t cpuid_hv_vendor3;
+    /* VMware extra data */
+    uint32_t cpuid_hv_extra;
+    uint32_t cpuid_hv_extra_a;
+    uint32_t cpuid_hv_extra_b;
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -860,6 +870,18 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
     cpu->env.tsc_khz = value / 1000;
 }
 
+static void x86_cpuid_set_hv(x86_def_t *x86_cpu_def, uint32_t level,
+                             const char *who)
+{
+        uint32_t signature[3];
+
+        memcpy(signature, who, 12);
+        x86_cpu_def->cpuid_hv_level = level;
+        x86_cpu_def->cpuid_hv_vendor1 = signature[0];
+        x86_cpu_def->cpuid_hv_vendor2 = signature[1];
+        x86_cpu_def->cpuid_hv_vendor3 = signature[2];
+}
+
 static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 {
     unsigned int i;
@@ -867,6 +889,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 
     char *s = g_strdup(cpu_model);
     char *featurestr, *name = strtok(s, ",");
+    bool hyperv_enabled = false;
+    bool hv_enabled = false;
+    long hyper_level = -1;
+    long hyper_extra = -1;
     /* Features to be added*/
     uint32_t plus_features = 0, plus_ext_features = 0;
     uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
@@ -993,12 +1019,84 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
                 x86_cpu_def->tsc_khz = tsc_freq / 1000;
             } else if (!strcmp(featurestr, "hv_spinlocks")) {
                 char *err;
+
+                if (hv_enabled) {
+                    fprintf(stderr,
+                            "Only one of hypervisor= or hv_* can be used at one time.\n");
+                    goto error;
+                }
                 numvalue = strtoul(val, &err, 0);
                 if (!*val || *err) {
                     fprintf(stderr, "bad numerical value %s\n", val);
                     goto error;
                 }
+                hyperv_enabled = true;
                 hyperv_set_spinlock_retries(numvalue);
+            } else if (!strcmp(featurestr, "hyper_level")) {
+                char *err;
+                long longvalue = strtol(val, &err, 0);
+
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value for hyper_level=%s\n",
+                            val);
+                    goto error;
+                }
+                hyper_level = longvalue;
+            } else if (!strcmp(featurestr, "hyper_extra")) {
+                char *err;
+                long longvalue = strtol(val, &err, 0);
+
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value for hyper_extra=%s\n",
+                            val);
+                    goto error;
+                }
+                hyper_extra = longvalue;
+            } else if (!strcmp(featurestr, "hyper_extra_a")) {
+                char *err;
+
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr,
+                            "bad numerical value for hyper_extra_a=%s\n",
+                            val);
+                    goto error;
+                }
+                x86_cpu_def->cpuid_hv_extra_a = (uint32_t)numvalue;
+            } else if (!strcmp(featurestr, "hyper_extra_b")) {
+                char *err;
+
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr,
+                            "bad numerical value for hyper_extra_b=%s\n",
+                            val);
+                    goto error;
+                }
+                x86_cpu_def->cpuid_hv_extra_b = (uint32_t)numvalue;
+            } else if (!strcmp(featurestr, "hv") ||
+                       !strcmp(featurestr, "hypervisor")) {
+                if (hyperv_enabled) {
+                    fprintf(stderr,
+                            "Only one of hypervisor= or hv_* can be used at one time.\n");
+                    goto error;
+                }
+                hv_enabled = true;
+                if (!strcmp(val, "vmware")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000010, "VMwareVMware");
+                    minus_kvm_features = ~0;    /* Expected to be zero... */
+                } else if (!strcmp(val, "vmware3")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "VMwareVMware");
+                    minus_kvm_features = ~0;    /* Expected to be zero... */
+                } else if (!strcmp(val, "xen")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "XenVMMXenVMM");
+                } else if (!strcmp(val, "kvm")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0, "KVMKVMKVM\0\0\0");
+                } else {
+                    fprintf(stderr, "unknown hypervisor %s\n",
+                            val);
+                    goto error;
+                }
             } else {
                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
                 goto error;
@@ -1008,8 +1106,20 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         } else if (!strcmp(featurestr, "enforce")) {
             check_cpuid = enforce_cpuid = 1;
         } else if (!strcmp(featurestr, "hv_relaxed")) {
+            if (hv_enabled) {
+                fprintf(stderr,
+                        "Only one of hypervisor= or hv_* can be used at one time.\n");
+                goto error;
+            }
+            hyperv_enabled = true;
             hyperv_enable_relaxed_timing(true);
         } else if (!strcmp(featurestr, "hv_vapic")) {
+            if (hv_enabled) {
+                fprintf(stderr,
+                        "Only one of hypervisor= or hv_* can be used at one time.\n");
+                goto error;
+            }
+            hyperv_enabled = true;
             hyperv_enable_vapic_recommended(true);
         } else {
             fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
@@ -1017,6 +1127,34 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         }
         featurestr = strtok(NULL, ",");
     }
+#ifdef CONFIG_KVM
+    if (hyperv_enabled) {
+        x86_cpuid_set_hv(x86_cpu_def, HYPERV_CPUID_MIN, "Microsoft Hv");
+    }
+#endif
+    if (hyper_extra >= 0) {
+        x86_cpu_def->cpuid_hv_extra = 0x40000000 + hyper_extra;
+    } else if (hv_enabled && x86_cpu_def->tsc_khz) {
+        /*
+         * From http://article.gmane.org/gmane.comp.emulators.kvm.devel/22643
+         *
+         *    Leaf 0x40000010, Timing Information.
+         *
+         *    VMware has defined the first generic leaf to provide timing
+         *    information.  This leaf returns the current TSC frequency and
+         *    current Bus frequency in kHz.
+         *
+         *    # EAX: (Virtual) TSC frequency in kHz.
+         *    # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
+         *    # ECX, EDX: RESERVED (Per above, reserved fields are set to zero).
+         */
+        x86_cpu_def->cpuid_hv_extra = 0x40000010;
+        x86_cpu_def->cpuid_hv_extra_a = (uint32_t)x86_cpu_def->tsc_khz;
+        x86_cpu_def->cpuid_hv_extra_b = (uint32_t)(get_ticks_per_sec() / 1000);
+    }
+    if (hyper_level >= 0) {
+        x86_cpu_def->cpuid_hv_level = 0x40000000 + hyper_level;
+    }
     x86_cpu_def->features |= plus_features;
     x86_cpu_def->ext_features |= plus_ext_features;
     x86_cpu_def->ext2_features |= plus_ext2_features;
@@ -1192,6 +1330,13 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
     env->cpuid_ext4_features = def->ext4_features;
     env->cpuid_7_0_ebx = def->cpuid_7_0_ebx_features;
     env->cpuid_xlevel2 = def->xlevel2;
+    env->cpuid_hv_level = def->cpuid_hv_level;
+    env->cpuid_hv_vendor1 = def->cpuid_hv_vendor1;
+    env->cpuid_hv_vendor2 = def->cpuid_hv_vendor2;
+    env->cpuid_hv_vendor3 = def->cpuid_hv_vendor3;
+    env->cpuid_hv_extra = def->cpuid_hv_extra;
+    env->cpuid_hv_extra_a = def->cpuid_hv_extra_a;
+    env->cpuid_hv_extra_b = def->cpuid_hv_extra_b;
     object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
                             "tsc-frequency", &error);
     if (!kvm_enabled()) {
@@ -1390,6 +1535,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                 index =  env->cpuid_xlevel;
             }
         }
+    } else if (index & 0x40000000) {
+        if (env->cpuid_hv_level > 0) {
+            /* Handle Paravirtualization CPUIDs */
+            if (index > env->cpuid_hv_level) {
+                index = env->cpuid_hv_level;
+            }
+        } else {
+            if (index > env->cpuid_level)
+                index = env->cpuid_level;
+        }
     } else {
         if (index > env->cpuid_level)
             index = env->cpuid_level;
@@ -1528,6 +1683,29 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
             *edx = 0;
         }
         break;
+    case 0x40000000:
+        *eax = env->cpuid_hv_level;
+        *ebx = env->cpuid_hv_vendor1;
+        *ecx = env->cpuid_hv_vendor2;
+        *edx = env->cpuid_hv_vendor3;
+        break;
+    case 0x40000001:
+        *eax = env->cpuid_kvm_features;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    case 0x40000002 ... 0x400000FF:
+        if (index == env->cpuid_hv_extra) {
+            *eax = env->cpuid_hv_extra_a;
+            *ebx = env->cpuid_hv_extra_b;
+        } else {
+            *eax = 0;
+            *ebx = 0;
+        }
+        *ecx = 0;
+        *edx = 0;
+        break;
     case 0x80000000:
         *eax = env->cpuid_xlevel;
         *ebx = env->cpuid_vendor1;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 0677502..dc2039a 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -746,6 +746,15 @@ typedef struct CPUX86State {
     uint32_t cpuid_ext4_features;
     /* Flags from CPUID[EAX=7,ECX=0].EBX */
     uint32_t cpuid_7_0_ebx;
+    /* Paravirtualization CPUIDs */
+    uint32_t cpuid_hv_level;
+    uint32_t cpuid_hv_vendor1;
+    uint32_t cpuid_hv_vendor2;
+    uint32_t cpuid_hv_vendor3;
+    /* VMware extra data */
+    uint32_t cpuid_hv_extra;
+    uint32_t cpuid_hv_extra_a;
+    uint32_t cpuid_hv_extra_b;
 
     /* MTRRs */
     uint64_t mtrr_fixed[11];
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ffc294e..d01a5f8 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -389,16 +389,18 @@ int kvm_arch_init_vcpu(CPUX86State *env)
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_SIGNATURE;
-    if (!hyperv_enabled()) {
+    if (env->cpuid_hv_level == 0) {
         memcpy(signature, "KVMKVMKVM\0\0\0", 12);
         c->eax = 0;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
     } else {
-        memcpy(signature, "Microsoft Hv", 12);
-        c->eax = HYPERV_CPUID_MIN;
+        c->eax = env->cpuid_hv_level;
+        c->ebx = env->cpuid_hv_vendor1;
+        c->ecx = env->cpuid_hv_vendor2;
+        c->edx = env->cpuid_hv_vendor3;
     }
-    c->ebx = signature[0];
-    c->ecx = signature[1];
-    c->edx = signature[2];
 
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
@@ -452,6 +454,25 @@ int kvm_arch_init_vcpu(CPUX86State *env)
         c->ebx = signature[0];
         c->ecx = signature[1];
         c->edx = signature[2];
+    } else if (env->cpuid_hv_level > 0) {
+        for (i = KVM_CPUID_FEATURES + 1; i <= env->cpuid_hv_level; i++) {
+            c = &cpuid_data.entries[cpuid_i++];
+            memset(c, 0, sizeof(*c));
+            c->function = i;
+            if (i == env->cpuid_hv_extra) {
+                c->eax = env->cpuid_hv_extra_a;
+                c->ebx = env->cpuid_hv_extra_b;
+            }
+        }
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = KVM_CPUID_SIGNATURE_NEXT;
+        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+        c->eax = 0;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
     }
 
     has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
@ 2012-08-30 20:56 Don Slutz
  0 siblings, 0 replies; 10+ messages in thread
From: Don Slutz @ 2012-08-30 20:56 UTC (permalink / raw)
  To: qemu-devel, kvm; +Cc: Don Slutz, Marcelo Tosatti, Avi Kivity

This is primarily done so that the guest will think it is running
under vmware when hypervisor=vmware is specified as a property of a
cpu.

Also allow this to work in accel=tcg mode.

The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
hyper_extra_b can be used to further adjust what the guest sees.

Signed-off-by: Don Slutz <Don@CloudSwitch.com>
---
 target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 target-i386/cpu.h |    9 +++
 target-i386/kvm.c |   33 ++++++++--
 3 files changed, 214 insertions(+), 6 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index f3cac49..9e82b76 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -26,6 +26,7 @@
 
 #include "qemu-option.h"
 #include "qemu-config.h"
+#include "qemu-timer.h"
 
 #include "qapi/qapi-visit-core.h"
 #include "arch_init.h"
@@ -244,6 +245,15 @@ typedef struct x86_def_t {
     uint32_t xlevel2;
     /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
     uint32_t cpuid_7_0_ebx_features;
+    /* Hypervisor CPUIDs */
+    uint32_t cpuid_hv_level;
+    uint32_t cpuid_hv_vendor1;
+    uint32_t cpuid_hv_vendor2;
+    uint32_t cpuid_hv_vendor3;
+    /* VMware extra data */
+    uint32_t cpuid_hv_extra;
+    uint32_t cpuid_hv_extra_a;
+    uint32_t cpuid_hv_extra_b;
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -860,6 +870,18 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
     cpu->env.tsc_khz = value / 1000;
 }
 
+static void x86_cpuid_set_hv(x86_def_t *x86_cpu_def, uint32_t level,
+                             const char *who)
+{
+        uint32_t signature[3];
+
+        memcpy(signature, who, 12);
+        x86_cpu_def->cpuid_hv_level = level;
+        x86_cpu_def->cpuid_hv_vendor1 = signature[0];
+        x86_cpu_def->cpuid_hv_vendor2 = signature[1];
+        x86_cpu_def->cpuid_hv_vendor3 = signature[2];
+}
+
 static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 {
     unsigned int i;
@@ -867,6 +889,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 
     char *s = g_strdup(cpu_model);
     char *featurestr, *name = strtok(s, ",");
+    bool hyperv_enabled = false;
+    bool hv_enabled = false;
+    long hyper_level = -1;
+    long hyper_extra = -1;
     /* Features to be added*/
     uint32_t plus_features = 0, plus_ext_features = 0;
     uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
@@ -993,12 +1019,84 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
                 x86_cpu_def->tsc_khz = tsc_freq / 1000;
             } else if (!strcmp(featurestr, "hv_spinlocks")) {
                 char *err;
+
+                if (hv_enabled) {
+                    fprintf(stderr,
+                            "Only one of hypervisor= or hv_* can be used at one time.\n");
+                    goto error;
+                }
                 numvalue = strtoul(val, &err, 0);
                 if (!*val || *err) {
                     fprintf(stderr, "bad numerical value %s\n", val);
                     goto error;
                 }
+                hyperv_enabled = true;
                 hyperv_set_spinlock_retries(numvalue);
+            } else if (!strcmp(featurestr, "hyper_level")) {
+                char *err;
+                long longvalue = strtol(val, &err, 0);
+
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value for hyper_level=%s\n",
+                            val);
+                    goto error;
+                }
+                hyper_level = longvalue;
+            } else if (!strcmp(featurestr, "hyper_extra")) {
+                char *err;
+                long longvalue = strtol(val, &err, 0);
+
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value for hyper_extra=%s\n",
+                            val);
+                    goto error;
+                }
+                hyper_extra = longvalue;
+            } else if (!strcmp(featurestr, "hyper_extra_a")) {
+                char *err;
+
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr,
+                            "bad numerical value for hyper_extra_a=%s\n",
+                            val);
+                    goto error;
+                }
+                x86_cpu_def->cpuid_hv_extra_a = (uint32_t)numvalue;
+            } else if (!strcmp(featurestr, "hyper_extra_b")) {
+                char *err;
+
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr,
+                            "bad numerical value for hyper_extra_b=%s\n",
+                            val);
+                    goto error;
+                }
+                x86_cpu_def->cpuid_hv_extra_b = (uint32_t)numvalue;
+            } else if (!strcmp(featurestr, "hv") ||
+                       !strcmp(featurestr, "hypervisor")) {
+                if (hyperv_enabled) {
+                    fprintf(stderr,
+                            "Only one of hypervisor= or hv_* can be used at one time.\n");
+                    goto error;
+                }
+                hv_enabled = true;
+                if (!strcmp(val, "vmware")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000010, "VMwareVMware");
+                    minus_kvm_features = ~0;    /* Expected to be zero... */
+                } else if (!strcmp(val, "vmware3")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "VMwareVMware");
+                    minus_kvm_features = ~0;    /* Expected to be zero... */
+                } else if (!strcmp(val, "xen")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "XenVMMXenVMM");
+                } else if (!strcmp(val, "kvm")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0, "KVMKVMKVM\0\0\0");
+                } else {
+                    fprintf(stderr, "unknown hypervisor %s\n",
+                            val);
+                    goto error;
+                }
             } else {
                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
                 goto error;
@@ -1008,8 +1106,20 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         } else if (!strcmp(featurestr, "enforce")) {
             check_cpuid = enforce_cpuid = 1;
         } else if (!strcmp(featurestr, "hv_relaxed")) {
+            if (hv_enabled) {
+                fprintf(stderr,
+                        "Only one of hypervisor= or hv_* can be used at one time.\n");
+                goto error;
+            }
+            hyperv_enabled = true;
             hyperv_enable_relaxed_timing(true);
         } else if (!strcmp(featurestr, "hv_vapic")) {
+            if (hv_enabled) {
+                fprintf(stderr,
+                        "Only one of hypervisor= or hv_* can be used at one time.\n");
+                goto error;
+            }
+            hyperv_enabled = true;
             hyperv_enable_vapic_recommended(true);
         } else {
             fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
@@ -1017,6 +1127,34 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         }
         featurestr = strtok(NULL, ",");
     }
+#ifdef CONFIG_KVM
+    if (hyperv_enabled) {
+        x86_cpuid_set_hv(x86_cpu_def, HYPERV_CPUID_MIN, "Microsoft Hv");
+    }
+#endif
+    if (hyper_extra >= 0) {
+        x86_cpu_def->cpuid_hv_extra = 0x40000000 + hyper_extra;
+    } else if (hv_enabled && x86_cpu_def->tsc_khz) {
+        /*
+         * From article.gmane.org/gmane.comp.emulators.kvm.devel/22643
+         *
+         *    Leaf 0x40000010, Timing Information.
+         *
+         *    VMware has defined the first generic leaf to provide timing
+         *    information.  This leaf returns the current TSC frequency and
+         *    current Bus frequency in kHz.
+         *
+         *    # EAX: (Virtual) TSC frequency in kHz.
+         *    # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
+         *    # ECX, EDX: RESERVED (Per above, reserved fields are set to zero).
+         */
+        x86_cpu_def->cpuid_hv_extra = 0x40000010;
+        x86_cpu_def->cpuid_hv_extra_a = (uint32_t)x86_cpu_def->tsc_khz;
+        x86_cpu_def->cpuid_hv_extra_b = (uint32_t)(get_ticks_per_sec() / 1000);
+    }
+    if (hyper_level >= 0) {
+        x86_cpu_def->cpuid_hv_level = 0x40000000 + hyper_level;
+    }
     x86_cpu_def->features |= plus_features;
     x86_cpu_def->ext_features |= plus_ext_features;
     x86_cpu_def->ext2_features |= plus_ext2_features;
@@ -1192,6 +1330,13 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
     env->cpuid_ext4_features = def->ext4_features;
     env->cpuid_7_0_ebx = def->cpuid_7_0_ebx_features;
     env->cpuid_xlevel2 = def->xlevel2;
+    env->cpuid_hv_level = def->cpuid_hv_level;
+    env->cpuid_hv_vendor1 = def->cpuid_hv_vendor1;
+    env->cpuid_hv_vendor2 = def->cpuid_hv_vendor2;
+    env->cpuid_hv_vendor3 = def->cpuid_hv_vendor3;
+    env->cpuid_hv_extra = def->cpuid_hv_extra;
+    env->cpuid_hv_extra_a = def->cpuid_hv_extra_a;
+    env->cpuid_hv_extra_b = def->cpuid_hv_extra_b;
     object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
                             "tsc-frequency", &error);
     if (!kvm_enabled()) {
@@ -1390,6 +1535,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                 index =  env->cpuid_xlevel;
             }
         }
+    } else if (index & 0x40000000) {
+        if (env->cpuid_hv_level > 0) {
+            /* Handle Paravirtualization CPUIDs */
+            if (index > env->cpuid_hv_level) {
+                index = env->cpuid_hv_level;
+            }
+        } else {
+            if (index > env->cpuid_level)
+                index = env->cpuid_level;
+        }
     } else {
         if (index > env->cpuid_level)
             index = env->cpuid_level;
@@ -1528,6 +1683,29 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
             *edx = 0;
         }
         break;
+    case 0x40000000:
+        *eax = env->cpuid_hv_level;
+        *ebx = env->cpuid_hv_vendor1;
+        *ecx = env->cpuid_hv_vendor2;
+        *edx = env->cpuid_hv_vendor3;
+        break;
+    case 0x40000001:
+        *eax = env->cpuid_kvm_features;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    case 0x40000002 ... 0x400000FF:
+        if (index == env->cpuid_hv_extra) {
+            *eax = env->cpuid_hv_extra_a;
+            *ebx = env->cpuid_hv_extra_b;
+        } else {
+            *eax = 0;
+            *ebx = 0;
+        }
+        *ecx = 0;
+        *edx = 0;
+        break;
     case 0x80000000:
         *eax = env->cpuid_xlevel;
         *ebx = env->cpuid_vendor1;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 0677502..dc2039a 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -746,6 +746,15 @@ typedef struct CPUX86State {
     uint32_t cpuid_ext4_features;
     /* Flags from CPUID[EAX=7,ECX=0].EBX */
     uint32_t cpuid_7_0_ebx;
+    /* Paravirtualization CPUIDs */
+    uint32_t cpuid_hv_level;
+    uint32_t cpuid_hv_vendor1;
+    uint32_t cpuid_hv_vendor2;
+    uint32_t cpuid_hv_vendor3;
+    /* VMware extra data */
+    uint32_t cpuid_hv_extra;
+    uint32_t cpuid_hv_extra_a;
+    uint32_t cpuid_hv_extra_b;
 
     /* MTRRs */
     uint64_t mtrr_fixed[11];
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ffc294e..d01a5f8 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -389,16 +389,18 @@ int kvm_arch_init_vcpu(CPUX86State *env)
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_SIGNATURE;
-    if (!hyperv_enabled()) {
+    if (env->cpuid_hv_level == 0) {
         memcpy(signature, "KVMKVMKVM\0\0\0", 12);
         c->eax = 0;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
     } else {
-        memcpy(signature, "Microsoft Hv", 12);
-        c->eax = HYPERV_CPUID_MIN;
+        c->eax = env->cpuid_hv_level;
+        c->ebx = env->cpuid_hv_vendor1;
+        c->ecx = env->cpuid_hv_vendor2;
+        c->edx = env->cpuid_hv_vendor3;
     }
-    c->ebx = signature[0];
-    c->ecx = signature[1];
-    c->edx = signature[2];
 
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
@@ -452,6 +454,25 @@ int kvm_arch_init_vcpu(CPUX86State *env)
         c->ebx = signature[0];
         c->ecx = signature[1];
         c->edx = signature[2];
+    } else if (env->cpuid_hv_level > 0) {
+        for (i = KVM_CPUID_FEATURES + 1; i <= env->cpuid_hv_level; i++) {
+            c = &cpuid_data.entries[cpuid_i++];
+            memset(c, 0, sizeof(*c));
+            c->function = i;
+            if (i == env->cpuid_hv_extra) {
+                c->eax = env->cpuid_hv_extra_a;
+                c->ebx = env->cpuid_hv_extra_b;
+            }
+        }
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = KVM_CPUID_SIGNATURE_NEXT;
+        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+        c->eax = 0;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
     }
 
     has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
@ 2012-08-30 21:07 Don Slutz
  0 siblings, 0 replies; 10+ messages in thread
From: Don Slutz @ 2012-08-30 21:07 UTC (permalink / raw)
  To: qemu-devel, kvm; +Cc: Don Slutz, Marcelo Tosatti, Avi Kivity

This is primarily done so that the guest will think it is running
under vmware when hypervisor=vmware is specified as a property of a
cpu.

Also allow this to work in accel=tcg mode.

The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
hyper_extra_b can be used to further adjust what the guest sees.

Signed-off-by: Don Slutz <Don@CloudSwitch.com>
---
 target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 target-i386/cpu.h |    9 +++
 target-i386/kvm.c |   33 ++++++++--
 3 files changed, 214 insertions(+), 6 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index f3cac49..9e82b76 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -26,6 +26,7 @@
 
 #include "qemu-option.h"
 #include "qemu-config.h"
+#include "qemu-timer.h"
 
 #include "qapi/qapi-visit-core.h"
 #include "arch_init.h"
@@ -244,6 +245,15 @@ typedef struct x86_def_t {
     uint32_t xlevel2;
     /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
     uint32_t cpuid_7_0_ebx_features;
+    /* Hypervisor CPUIDs */
+    uint32_t cpuid_hv_level;
+    uint32_t cpuid_hv_vendor1;
+    uint32_t cpuid_hv_vendor2;
+    uint32_t cpuid_hv_vendor3;
+    /* VMware extra data */
+    uint32_t cpuid_hv_extra;
+    uint32_t cpuid_hv_extra_a;
+    uint32_t cpuid_hv_extra_b;
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -860,6 +870,18 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
     cpu->env.tsc_khz = value / 1000;
 }
 
+static void x86_cpuid_set_hv(x86_def_t *x86_cpu_def, uint32_t level,
+                             const char *who)
+{
+        uint32_t signature[3];
+
+        memcpy(signature, who, 12);
+        x86_cpu_def->cpuid_hv_level = level;
+        x86_cpu_def->cpuid_hv_vendor1 = signature[0];
+        x86_cpu_def->cpuid_hv_vendor2 = signature[1];
+        x86_cpu_def->cpuid_hv_vendor3 = signature[2];
+}
+
 static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 {
     unsigned int i;
@@ -867,6 +889,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 
     char *s = g_strdup(cpu_model);
     char *featurestr, *name = strtok(s, ",");
+    bool hyperv_enabled = false;
+    bool hv_enabled = false;
+    long hyper_level = -1;
+    long hyper_extra = -1;
     /* Features to be added*/
     uint32_t plus_features = 0, plus_ext_features = 0;
     uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
@@ -993,12 +1019,84 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
                 x86_cpu_def->tsc_khz = tsc_freq / 1000;
             } else if (!strcmp(featurestr, "hv_spinlocks")) {
                 char *err;
+
+                if (hv_enabled) {
+                    fprintf(stderr,
+                            "Only one of hypervisor= or hv_* can be used at one time.\n");
+                    goto error;
+                }
                 numvalue = strtoul(val, &err, 0);
                 if (!*val || *err) {
                     fprintf(stderr, "bad numerical value %s\n", val);
                     goto error;
                 }
+                hyperv_enabled = true;
                 hyperv_set_spinlock_retries(numvalue);
+            } else if (!strcmp(featurestr, "hyper_level")) {
+                char *err;
+                long longvalue = strtol(val, &err, 0);
+
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value for hyper_level=%s\n",
+                            val);
+                    goto error;
+                }
+                hyper_level = longvalue;
+            } else if (!strcmp(featurestr, "hyper_extra")) {
+                char *err;
+                long longvalue = strtol(val, &err, 0);
+
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value for hyper_extra=%s\n",
+                            val);
+                    goto error;
+                }
+                hyper_extra = longvalue;
+            } else if (!strcmp(featurestr, "hyper_extra_a")) {
+                char *err;
+
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr,
+                            "bad numerical value for hyper_extra_a=%s\n",
+                            val);
+                    goto error;
+                }
+                x86_cpu_def->cpuid_hv_extra_a = (uint32_t)numvalue;
+            } else if (!strcmp(featurestr, "hyper_extra_b")) {
+                char *err;
+
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr,
+                            "bad numerical value for hyper_extra_b=%s\n",
+                            val);
+                    goto error;
+                }
+                x86_cpu_def->cpuid_hv_extra_b = (uint32_t)numvalue;
+            } else if (!strcmp(featurestr, "hv") ||
+                       !strcmp(featurestr, "hypervisor")) {
+                if (hyperv_enabled) {
+                    fprintf(stderr,
+                            "Only one of hypervisor= or hv_* can be used at one time.\n");
+                    goto error;
+                }
+                hv_enabled = true;
+                if (!strcmp(val, "vmware")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000010, "VMwareVMware");
+                    minus_kvm_features = ~0;    /* Expected to be zero... */
+                } else if (!strcmp(val, "vmware3")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "VMwareVMware");
+                    minus_kvm_features = ~0;    /* Expected to be zero... */
+                } else if (!strcmp(val, "xen")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "XenVMMXenVMM");
+                } else if (!strcmp(val, "kvm")) {
+                    x86_cpuid_set_hv(x86_cpu_def, 0, "KVMKVMKVM\0\0\0");
+                } else {
+                    fprintf(stderr, "unknown hypervisor %s\n",
+                            val);
+                    goto error;
+                }
             } else {
                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
                 goto error;
@@ -1008,8 +1106,20 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         } else if (!strcmp(featurestr, "enforce")) {
             check_cpuid = enforce_cpuid = 1;
         } else if (!strcmp(featurestr, "hv_relaxed")) {
+            if (hv_enabled) {
+                fprintf(stderr,
+                        "Only one of hypervisor= or hv_* can be used at one time.\n");
+                goto error;
+            }
+            hyperv_enabled = true;
             hyperv_enable_relaxed_timing(true);
         } else if (!strcmp(featurestr, "hv_vapic")) {
+            if (hv_enabled) {
+                fprintf(stderr,
+                        "Only one of hypervisor= or hv_* can be used at one time.\n");
+                goto error;
+            }
+            hyperv_enabled = true;
             hyperv_enable_vapic_recommended(true);
         } else {
             fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
@@ -1017,6 +1127,34 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         }
         featurestr = strtok(NULL, ",");
     }
+#ifdef CONFIG_KVM
+    if (hyperv_enabled) {
+        x86_cpuid_set_hv(x86_cpu_def, HYPERV_CPUID_MIN, "Microsoft Hv");
+    }
+#endif
+    if (hyper_extra >= 0) {
+        x86_cpu_def->cpuid_hv_extra = 0x40000000 + hyper_extra;
+    } else if (hv_enabled && x86_cpu_def->tsc_khz) {
+        /*
+         * From article.gmane.org/gmane.comp.emulators.kvm.devel/22643
+         *
+         *    Leaf 0x40000010, Timing Information.
+         *
+         *    VMware has defined the first generic leaf to provide timing
+         *    information.  This leaf returns the current TSC frequency and
+         *    current Bus frequency in kHz.
+         *
+         *    # EAX: (Virtual) TSC frequency in kHz.
+         *    # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
+         *    # ECX, EDX: RESERVED (Per above, reserved fields are set to zero).
+         */
+        x86_cpu_def->cpuid_hv_extra = 0x40000010;
+        x86_cpu_def->cpuid_hv_extra_a = (uint32_t)x86_cpu_def->tsc_khz;
+        x86_cpu_def->cpuid_hv_extra_b = (uint32_t)(get_ticks_per_sec() / 1000);
+    }
+    if (hyper_level >= 0) {
+        x86_cpu_def->cpuid_hv_level = 0x40000000 + hyper_level;
+    }
     x86_cpu_def->features |= plus_features;
     x86_cpu_def->ext_features |= plus_ext_features;
     x86_cpu_def->ext2_features |= plus_ext2_features;
@@ -1192,6 +1330,13 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
     env->cpuid_ext4_features = def->ext4_features;
     env->cpuid_7_0_ebx = def->cpuid_7_0_ebx_features;
     env->cpuid_xlevel2 = def->xlevel2;
+    env->cpuid_hv_level = def->cpuid_hv_level;
+    env->cpuid_hv_vendor1 = def->cpuid_hv_vendor1;
+    env->cpuid_hv_vendor2 = def->cpuid_hv_vendor2;
+    env->cpuid_hv_vendor3 = def->cpuid_hv_vendor3;
+    env->cpuid_hv_extra = def->cpuid_hv_extra;
+    env->cpuid_hv_extra_a = def->cpuid_hv_extra_a;
+    env->cpuid_hv_extra_b = def->cpuid_hv_extra_b;
     object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
                             "tsc-frequency", &error);
     if (!kvm_enabled()) {
@@ -1390,6 +1535,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                 index =  env->cpuid_xlevel;
             }
         }
+    } else if (index & 0x40000000) {
+        if (env->cpuid_hv_level > 0) {
+            /* Handle Paravirtualization CPUIDs */
+            if (index > env->cpuid_hv_level) {
+                index = env->cpuid_hv_level;
+            }
+        } else {
+            if (index > env->cpuid_level)
+                index = env->cpuid_level;
+        }
     } else {
         if (index > env->cpuid_level)
             index = env->cpuid_level;
@@ -1528,6 +1683,29 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
             *edx = 0;
         }
         break;
+    case 0x40000000:
+        *eax = env->cpuid_hv_level;
+        *ebx = env->cpuid_hv_vendor1;
+        *ecx = env->cpuid_hv_vendor2;
+        *edx = env->cpuid_hv_vendor3;
+        break;
+    case 0x40000001:
+        *eax = env->cpuid_kvm_features;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        break;
+    case 0x40000002 ... 0x400000FF:
+        if (index == env->cpuid_hv_extra) {
+            *eax = env->cpuid_hv_extra_a;
+            *ebx = env->cpuid_hv_extra_b;
+        } else {
+            *eax = 0;
+            *ebx = 0;
+        }
+        *ecx = 0;
+        *edx = 0;
+        break;
     case 0x80000000:
         *eax = env->cpuid_xlevel;
         *ebx = env->cpuid_vendor1;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 0677502..dc2039a 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -746,6 +746,15 @@ typedef struct CPUX86State {
     uint32_t cpuid_ext4_features;
     /* Flags from CPUID[EAX=7,ECX=0].EBX */
     uint32_t cpuid_7_0_ebx;
+    /* Paravirtualization CPUIDs */
+    uint32_t cpuid_hv_level;
+    uint32_t cpuid_hv_vendor1;
+    uint32_t cpuid_hv_vendor2;
+    uint32_t cpuid_hv_vendor3;
+    /* VMware extra data */
+    uint32_t cpuid_hv_extra;
+    uint32_t cpuid_hv_extra_a;
+    uint32_t cpuid_hv_extra_b;
 
     /* MTRRs */
     uint64_t mtrr_fixed[11];
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ffc294e..d01a5f8 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -389,16 +389,18 @@ int kvm_arch_init_vcpu(CPUX86State *env)
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_SIGNATURE;
-    if (!hyperv_enabled()) {
+    if (env->cpuid_hv_level == 0) {
         memcpy(signature, "KVMKVMKVM\0\0\0", 12);
         c->eax = 0;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
     } else {
-        memcpy(signature, "Microsoft Hv", 12);
-        c->eax = HYPERV_CPUID_MIN;
+        c->eax = env->cpuid_hv_level;
+        c->ebx = env->cpuid_hv_vendor1;
+        c->ecx = env->cpuid_hv_vendor2;
+        c->edx = env->cpuid_hv_vendor3;
     }
-    c->ebx = signature[0];
-    c->ecx = signature[1];
-    c->edx = signature[2];
 
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
@@ -452,6 +454,25 @@ int kvm_arch_init_vcpu(CPUX86State *env)
         c->ebx = signature[0];
         c->ecx = signature[1];
         c->edx = signature[2];
+    } else if (env->cpuid_hv_level > 0) {
+        for (i = KVM_CPUID_FEATURES + 1; i <= env->cpuid_hv_level; i++) {
+            c = &cpuid_data.entries[cpuid_i++];
+            memset(c, 0, sizeof(*c));
+            c->function = i;
+            if (i == env->cpuid_hv_extra) {
+                c->eax = env->cpuid_hv_extra_a;
+                c->ebx = env->cpuid_hv_extra_b;
+            }
+        }
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = KVM_CPUID_SIGNATURE_NEXT;
+        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+        c->eax = 0;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
     }
 
     has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
  2012-08-30 19:20 Don Slutz
@ 2012-09-05 16:48 ` Marcelo Tosatti
  2012-09-11 13:57   ` Don Slutz
  2012-09-06 10:28 ` Andreas Färber
  1 sibling, 1 reply; 10+ messages in thread
From: Marcelo Tosatti @ 2012-09-05 16:48 UTC (permalink / raw)
  To: Don Slutz; +Cc: Don Slutz, qemu-devel, kvm, Avi Kivity

On Thu, Aug 30, 2012 at 03:20:35PM -0400, Don Slutz wrote:
> This is primarily done so that the guest will think it is running
> under vmware when hypervisor=vmware is specified as a property of a
> cpu.
> 
> Also allow this to work in accel=tcg mode.
> 
> The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
> hyper_extra_b can be used to further adjust what the guest sees.
> 
> Signed-off-by: Don Slutz <Don@CloudSwitch.com>

For what purpose? 

Is the VMWare interface documented somewhere?

> ---
>  target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  target-i386/cpu.h |    9 +++
>  target-i386/kvm.c |   33 ++++++++--
>  3 files changed, 214 insertions(+), 6 deletions(-)
> 
> diff --git a/target-i386/cpu.c b/target-i386/cpu.c
> index f3cac49..a444b95 100644
> --- a/target-i386/cpu.c
> +++ b/target-i386/cpu.c
> @@ -26,6 +26,7 @@
>  
>  #include "qemu-option.h"
>  #include "qemu-config.h"
> +#include "qemu-timer.h"
>  
>  #include "qapi/qapi-visit-core.h"
>  #include "arch_init.h"
> @@ -244,6 +245,15 @@ typedef struct x86_def_t {
>      uint32_t xlevel2;
>      /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
>      uint32_t cpuid_7_0_ebx_features;
> +    /* Hypervisor CPUIDs */
> +    uint32_t cpuid_hv_level;
> +    uint32_t cpuid_hv_vendor1;
> +    uint32_t cpuid_hv_vendor2;
> +    uint32_t cpuid_hv_vendor3;
> +    /* VMware extra data */
> +    uint32_t cpuid_hv_extra;
> +    uint32_t cpuid_hv_extra_a;
> +    uint32_t cpuid_hv_extra_b;
>  } x86_def_t;
>  
>  #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
> @@ -860,6 +870,18 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
>      cpu->env.tsc_khz = value / 1000;
>  }
>  
> +static void x86_cpuid_set_hv(x86_def_t *x86_cpu_def, uint32_t level,
> +                             const char *who)
> +{
> +        uint32_t signature[3];
> +
> +        memcpy(signature, who, 12);
> +        x86_cpu_def->cpuid_hv_level = level;
> +        x86_cpu_def->cpuid_hv_vendor1 = signature[0];
> +        x86_cpu_def->cpuid_hv_vendor2 = signature[1];
> +        x86_cpu_def->cpuid_hv_vendor3 = signature[2];
> +}
> +
>  static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>  {
>      unsigned int i;
> @@ -867,6 +889,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>  
>      char *s = g_strdup(cpu_model);
>      char *featurestr, *name = strtok(s, ",");
> +    bool hyperv_enabled = false;
> +    bool hv_enabled = false;
> +    long hyper_level = -1;
> +    long hyper_extra = -1;
>      /* Features to be added*/
>      uint32_t plus_features = 0, plus_ext_features = 0;
>      uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
> @@ -993,12 +1019,84 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>                  x86_cpu_def->tsc_khz = tsc_freq / 1000;
>              } else if (!strcmp(featurestr, "hv_spinlocks")) {
>                  char *err;
> +
> +                if (hv_enabled) {
> +                    fprintf(stderr,
> +                            "Only one of hypervisor= or hv_* can be used at one time.\n");
> +                    goto error;
> +                }
>                  numvalue = strtoul(val, &err, 0);
>                  if (!*val || *err) {
>                      fprintf(stderr, "bad numerical value %s\n", val);
>                      goto error;
>                  }
> +                hyperv_enabled = true;
>                  hyperv_set_spinlock_retries(numvalue);
> +            } else if (!strcmp(featurestr, "hyper_level")) {
> +                char *err;
> +                long longvalue = strtol(val, &err, 0);
> +
> +                if (!*val || *err) {
> +                    fprintf(stderr, "bad numerical value for hyper_level=%s\n",
> +                            val);
> +                    goto error;
> +                }
> +                hyper_level = longvalue;
> +            } else if (!strcmp(featurestr, "hyper_extra")) {
> +                char *err;
> +                long longvalue = strtol(val, &err, 0);
> +
> +                if (!*val || *err) {
> +                    fprintf(stderr, "bad numerical value for hyper_extra=%s\n",
> +                            val);
> +                    goto error;
> +                }
> +                hyper_extra = longvalue;
> +            } else if (!strcmp(featurestr, "hyper_extra_a")) {
> +                char *err;
> +
> +                numvalue = strtoul(val, &err, 0);
> +                if (!*val || *err) {
> +                    fprintf(stderr,
> +                            "bad numerical value for hyper_extra_a=%s\n",
> +                            val);
> +                    goto error;
> +                }
> +                x86_cpu_def->cpuid_hv_extra_a = (uint32_t)numvalue;
> +            } else if (!strcmp(featurestr, "hyper_extra_b")) {
> +                char *err;
> +
> +                numvalue = strtoul(val, &err, 0);
> +                if (!*val || *err) {
> +                    fprintf(stderr,
> +                            "bad numerical value for hyper_extra_b=%s\n",
> +                            val);
> +                    goto error;
> +                }
> +                x86_cpu_def->cpuid_hv_extra_b = (uint32_t)numvalue;
> +            } else if (!strcmp(featurestr, "hv") ||
> +                       !strcmp(featurestr, "hypervisor")) {
> +                if (hyperv_enabled) {
> +                    fprintf(stderr,
> +                            "Only one of hypervisor= or hv_* can be used at one time.\n");
> +                    goto error;
> +                }
> +                hv_enabled = true;
> +                if (!strcmp(val, "vmware")) {
> +                    x86_cpuid_set_hv(x86_cpu_def, 0x40000010, "VMwareVMware");
> +                    minus_kvm_features = ~0;    /* Expected to be zero... */
> +                } else if (!strcmp(val, "vmware3")) {
> +                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "VMwareVMware");
> +                    minus_kvm_features = ~0;    /* Expected to be zero... */
> +                } else if (!strcmp(val, "xen")) {
> +                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "XenVMMXenVMM");
> +                } else if (!strcmp(val, "kvm")) {
> +                    x86_cpuid_set_hv(x86_cpu_def, 0, "KVMKVMKVM\0\0\0");
> +                } else {
> +                    fprintf(stderr, "unknown hypervisor %s\n",
> +                            val);
> +                    goto error;
> +                }
>              } else {
>                  fprintf(stderr, "unrecognized feature %s\n", featurestr);
>                  goto error;
> @@ -1008,8 +1106,20 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>          } else if (!strcmp(featurestr, "enforce")) {
>              check_cpuid = enforce_cpuid = 1;
>          } else if (!strcmp(featurestr, "hv_relaxed")) {
> +            if (hv_enabled) {
> +                fprintf(stderr,
> +                        "Only one of hypervisor= or hv_* can be used at one time.\n");
> +                goto error;
> +            }
> +            hyperv_enabled = true;
>              hyperv_enable_relaxed_timing(true);
>          } else if (!strcmp(featurestr, "hv_vapic")) {
> +            if (hv_enabled) {
> +                fprintf(stderr,
> +                        "Only one of hypervisor= or hv_* can be used at one time.\n");
> +                goto error;
> +            }
> +            hyperv_enabled = true;
>              hyperv_enable_vapic_recommended(true);
>          } else {
>              fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
> @@ -1017,6 +1127,34 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>          }
>          featurestr = strtok(NULL, ",");
>      }
> +#ifdef CONFIG_KVM
> +    if (hyperv_enabled) {
> +        x86_cpuid_set_hv(x86_cpu_def, HYPERV_CPUID_MIN, "Microsoft Hv");
> +    }
> +#endif
> +    if (hyper_extra >= 0) {
> +        x86_cpu_def->cpuid_hv_extra = 0x40000000 + hyper_extra;
> +    } else if (hv_enabled && x86_cpu_def->tsc_khz) {
> +        /*
> +         * From http://article.gmane.org/gmane.comp.emulators.kvm.devel/22643
> +         *
> +         *    Leaf 0x40000010, Timing Information.
> +         *
> +         *    VMware has defined the first generic leaf to provide timing
> +         *    information.  This leaf returns the current TSC frequency and
> +         *    current Bus frequency in kHz.
> +         *
> +         *    # EAX: (Virtual) TSC frequency in kHz.
> +         *    # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
> +         *    # ECX, EDX: RESERVED (Per above, reserved fields are set to zero).
> +         */
> +        x86_cpu_def->cpuid_hv_extra = 0x40000010;
> +        x86_cpu_def->cpuid_hv_extra_a = (uint32_t)x86_cpu_def->tsc_khz;
> +        x86_cpu_def->cpuid_hv_extra_b = (uint32_t)(get_ticks_per_sec() / 1000);
> +    }
> +    if (hyper_level >= 0) {
> +        x86_cpu_def->cpuid_hv_level = 0x40000000 + hyper_level;
> +    }
>      x86_cpu_def->features |= plus_features;
>      x86_cpu_def->ext_features |= plus_ext_features;
>      x86_cpu_def->ext2_features |= plus_ext2_features;
> @@ -1192,6 +1330,13 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
>      env->cpuid_ext4_features = def->ext4_features;
>      env->cpuid_7_0_ebx = def->cpuid_7_0_ebx_features;
>      env->cpuid_xlevel2 = def->xlevel2;
> +    env->cpuid_hv_level = def->cpuid_hv_level;
> +    env->cpuid_hv_vendor1 = def->cpuid_hv_vendor1;
> +    env->cpuid_hv_vendor2 = def->cpuid_hv_vendor2;
> +    env->cpuid_hv_vendor3 = def->cpuid_hv_vendor3;
> +    env->cpuid_hv_extra = def->cpuid_hv_extra;
> +    env->cpuid_hv_extra_a = def->cpuid_hv_extra_a;
> +    env->cpuid_hv_extra_b = def->cpuid_hv_extra_b;
>      object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
>                              "tsc-frequency", &error);
>      if (!kvm_enabled()) {
> @@ -1390,6 +1535,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
>                  index =  env->cpuid_xlevel;
>              }
>          }
> +    } else if (index & 0x40000000) {
> +        if (env->cpuid_hv_level > 0) {
> +            /* Handle Paravirtualization CPUIDs */
> +            if (index > env->cpuid_hv_level) {
> +                index = env->cpuid_hv_level;
> +            }
> +        } else {
> +            if (index > env->cpuid_level)
> +                index = env->cpuid_level;
> +        }
>      } else {
>          if (index > env->cpuid_level)
>              index = env->cpuid_level;
> @@ -1528,6 +1683,29 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
>              *edx = 0;
>          }
>          break;
> +    case 0x40000000:
> +        *eax = env->cpuid_hv_level;
> +        *ebx = env->cpuid_hv_vendor1;
> +        *ecx = env->cpuid_hv_vendor2;
> +        *edx = env->cpuid_hv_vendor3;
> +        break;
> +    case 0x40000001:
> +        *eax = env->cpuid_kvm_features;
> +        *ebx = 0;
> +        *ecx = 0;
> +        *edx = 0;
> +        break;
> +    case 0x40000002 ... 0x400000FF:
> +        if (index == env->cpuid_hv_extra) {
> +            *eax = env->cpuid_hv_extra_a;
> +            *ebx = env->cpuid_hv_extra_b;
> +        } else {
> +            *eax = 0;
> +            *ebx = 0;
> +        }
> +        *ecx = 0;
> +        *edx = 0;
> +        break;
>      case 0x80000000:
>          *eax = env->cpuid_xlevel;
>          *ebx = env->cpuid_vendor1;
> diff --git a/target-i386/cpu.h b/target-i386/cpu.h
> index 0677502..dc2039a 100644
> --- a/target-i386/cpu.h
> +++ b/target-i386/cpu.h
> @@ -746,6 +746,15 @@ typedef struct CPUX86State {
>      uint32_t cpuid_ext4_features;
>      /* Flags from CPUID[EAX=7,ECX=0].EBX */
>      uint32_t cpuid_7_0_ebx;
> +    /* Paravirtualization CPUIDs */
> +    uint32_t cpuid_hv_level;
> +    uint32_t cpuid_hv_vendor1;
> +    uint32_t cpuid_hv_vendor2;
> +    uint32_t cpuid_hv_vendor3;
> +    /* VMware extra data */
> +    uint32_t cpuid_hv_extra;
> +    uint32_t cpuid_hv_extra_a;
> +    uint32_t cpuid_hv_extra_b;
>  
>      /* MTRRs */
>      uint64_t mtrr_fixed[11];
> diff --git a/target-i386/kvm.c b/target-i386/kvm.c
> index ffc294e..d01a5f8 100644
> --- a/target-i386/kvm.c
> +++ b/target-i386/kvm.c
> @@ -389,16 +389,18 @@ int kvm_arch_init_vcpu(CPUX86State *env)
>      c = &cpuid_data.entries[cpuid_i++];
>      memset(c, 0, sizeof(*c));
>      c->function = KVM_CPUID_SIGNATURE;
> -    if (!hyperv_enabled()) {
> +    if (env->cpuid_hv_level == 0) {
>          memcpy(signature, "KVMKVMKVM\0\0\0", 12);
>          c->eax = 0;
> +        c->ebx = signature[0];
> +        c->ecx = signature[1];
> +        c->edx = signature[2];
>      } else {
> -        memcpy(signature, "Microsoft Hv", 12);
> -        c->eax = HYPERV_CPUID_MIN;
> +        c->eax = env->cpuid_hv_level;
> +        c->ebx = env->cpuid_hv_vendor1;
> +        c->ecx = env->cpuid_hv_vendor2;
> +        c->edx = env->cpuid_hv_vendor3;
>      }
> -    c->ebx = signature[0];
> -    c->ecx = signature[1];
> -    c->edx = signature[2];
>  
>      c = &cpuid_data.entries[cpuid_i++];
>      memset(c, 0, sizeof(*c));
> @@ -452,6 +454,25 @@ int kvm_arch_init_vcpu(CPUX86State *env)
>          c->ebx = signature[0];
>          c->ecx = signature[1];
>          c->edx = signature[2];
> +    } else if (env->cpuid_hv_level > 0) {
> +        for (i = KVM_CPUID_FEATURES + 1; i <= env->cpuid_hv_level; i++) {
> +            c = &cpuid_data.entries[cpuid_i++];
> +            memset(c, 0, sizeof(*c));
> +            c->function = i;
> +            if (i == env->cpuid_hv_extra) {
> +                c->eax = env->cpuid_hv_extra_a;
> +                c->ebx = env->cpuid_hv_extra_b;
> +            }
> +        }
> +
> +        c = &cpuid_data.entries[cpuid_i++];
> +        memset(c, 0, sizeof(*c));
> +        c->function = KVM_CPUID_SIGNATURE_NEXT;
> +        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
> +        c->eax = 0;
> +        c->ebx = signature[0];
> +        c->ecx = signature[1];
> +        c->edx = signature[2];
>      }
>  
>      has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
> -- 
> 1.7.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
  2012-08-30 19:20 Don Slutz
  2012-09-05 16:48 ` Marcelo Tosatti
@ 2012-09-06 10:28 ` Andreas Färber
  2012-09-06 18:40   ` Eduardo Habkost
  1 sibling, 1 reply; 10+ messages in thread
From: Andreas Färber @ 2012-09-06 10:28 UTC (permalink / raw)
  To: Don Slutz
  Cc: Eduardo Habkost, kvm, Don Slutz, Marcelo Tosatti, qemu-devel,
	Avi Kivity, Igor Mammedov

Am 30.08.2012 21:20, schrieb Don Slutz:
> This is primarily done so that the guest will think it is running
> under vmware when hypervisor=vmware is specified as a property of a
> cpu.
> 
> Also allow this to work in accel=tcg mode.
> 
> The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
> hyper_extra_b can be used to further adjust what the guest sees.
> 
> Signed-off-by: Don Slutz <Don@CloudSwitch.com>
> ---
>  target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  target-i386/cpu.h |    9 +++
>  target-i386/kvm.c |   33 ++++++++--
>  3 files changed, 214 insertions(+), 6 deletions(-)

Please don't add new CPU command line options without matching QOM
properties. There are patch series in the works that convert the CPU
definitions to QOM subclasses, the parameters then need to be set on the
X86CPU object instance.

Note that the convention for QOM properties is
descriptive-name-with-dashes rather than shortened_abbrev_with_underscore.

Regards,
Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
  2012-09-06 10:28 ` Andreas Färber
@ 2012-09-06 18:40   ` Eduardo Habkost
  2012-09-06 19:00     ` Don Slutz
  0 siblings, 1 reply; 10+ messages in thread
From: Eduardo Habkost @ 2012-09-06 18:40 UTC (permalink / raw)
  To: Andreas Färber
  Cc: kvm, Don Slutz, Marcelo Tosatti, Don Slutz, qemu-devel,
	Avi Kivity, Igor Mammedov

On Thu, Sep 06, 2012 at 12:28:05PM +0200, Andreas Färber wrote:
> Am 30.08.2012 21:20, schrieb Don Slutz:
> > This is primarily done so that the guest will think it is running
> > under vmware when hypervisor=vmware is specified as a property of a
> > cpu.
> > 
> > Also allow this to work in accel=tcg mode.
> > 
> > The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
> > hyper_extra_b can be used to further adjust what the guest sees.
> > 
> > Signed-off-by: Don Slutz <Don@CloudSwitch.com>
> > ---
> >  target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  target-i386/cpu.h |    9 +++
> >  target-i386/kvm.c |   33 ++++++++--
> >  3 files changed, 214 insertions(+), 6 deletions(-)
> 
> Please don't add new CPU command line options without matching QOM
> properties. There are patch series in the works that convert the CPU
> definitions to QOM subclasses, the parameters then need to be set on the
> X86CPU object instance.

It seems to be a good idea to wait for the CPU properties series from
Igor to be applied, before implementing this. It should make the new
code much simpler.

> 
> Note that the convention for QOM properties is
> descriptive-name-with-dashes rather than shortened_abbrev_with_underscore.
> 

-- 
Eduardo

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
  2012-09-06 18:40   ` Eduardo Habkost
@ 2012-09-06 19:00     ` Don Slutz
  2012-09-06 19:36       ` Eduardo Habkost
  0 siblings, 1 reply; 10+ messages in thread
From: Don Slutz @ 2012-09-06 19:00 UTC (permalink / raw)
  To: Eduardo Habkost
  Cc: kvm, Marcelo Tosatti, qemu-devel, Don Slutz, Avi Kivity,
	Igor Mammedov, Andreas Färber

On 09/06/12 14:40, Eduardo Habkost wrote:
> On Thu, Sep 06, 2012 at 12:28:05PM +0200, Andreas Färber wrote:
>> Am 30.08.2012 21:20, schrieb Don Slutz:
>>> This is primarily done so that the guest will think it is running
>>> under vmware when hypervisor=vmware is specified as a property of a
>>> cpu.
>>>
>>> Also allow this to work in accel=tcg mode.
>>>
>>> The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
>>> hyper_extra_b can be used to further adjust what the guest sees.
>>>
>>> Signed-off-by: Don Slutz <Don@CloudSwitch.com>
>>> ---
>>>   target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   target-i386/cpu.h |    9 +++
>>>   target-i386/kvm.c |   33 ++++++++--
>>>   3 files changed, 214 insertions(+), 6 deletions(-)
>> Please don't add new CPU command line options without matching QOM
>> properties. There are patch series in the works that convert the CPU
>> definitions to QOM subclasses, the parameters then need to be set on the
>> X86CPU object instance.
I found:
http://lists.gnu.org/archive/html/qemu-devel/2012-08/msg00587.html

Is this the right set?
> It seems to be a good idea to wait for the CPU properties series from
> Igor to be applied, before implementing this. It should make the new
> code much simpler.
So Igor has a patch set that does a similar change like above.  I so far 
have not found it on QEMU-DEVEL.  Please provide a pointer to this patch 
set.
>
>> Note that the convention for QOM properties is
>> descriptive-name-with-dashes rather than shortened_abbrev_with_underscore.
>>
I will be re-working this change, and wait (for v2) until master has 
changed to the new way.
    -Don

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
  2012-09-06 19:00     ` Don Slutz
@ 2012-09-06 19:36       ` Eduardo Habkost
  0 siblings, 0 replies; 10+ messages in thread
From: Eduardo Habkost @ 2012-09-06 19:36 UTC (permalink / raw)
  To: Don Slutz
  Cc: kvm, Marcelo Tosatti, qemu-devel, Don Slutz, Avi Kivity,
	Igor Mammedov, Andreas Färber

On Thu, Sep 06, 2012 at 03:00:47PM -0400, Don Slutz wrote:
> On 09/06/12 14:40, Eduardo Habkost wrote:
> >On Thu, Sep 06, 2012 at 12:28:05PM +0200, Andreas Färber wrote:
> >>Am 30.08.2012 21:20, schrieb Don Slutz:
> >>>This is primarily done so that the guest will think it is running
> >>>under vmware when hypervisor=vmware is specified as a property of a
> >>>cpu.
> >>>
> >>>Also allow this to work in accel=tcg mode.
> >>>
> >>>The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
> >>>hyper_extra_b can be used to further adjust what the guest sees.
> >>>
> >>>Signed-off-by: Don Slutz <Don@CloudSwitch.com>
> >>>---
> >>>  target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> >>>  target-i386/cpu.h |    9 +++
> >>>  target-i386/kvm.c |   33 ++++++++--
> >>>  3 files changed, 214 insertions(+), 6 deletions(-)
> >>Please don't add new CPU command line options without matching QOM
> >>properties. There are patch series in the works that convert the CPU
> >>definitions to QOM subclasses, the parameters then need to be set on the
> >>X86CPU object instance.
> I found:
> http://lists.gnu.org/archive/html/qemu-devel/2012-08/msg00587.html
> 
> Is this the right set?

Yes. But note that there are lots of work in progress in the list (and
work that we haven't submitted to the list yet). You don't necessarily
need to wait for the above to be applied, probably you can just rebase
on top of the "CPU properties" work (that affects your patch more
directly). See below.


> >It seems to be a good idea to wait for the CPU properties series from
> >Igor to be applied, before implementing this. It should make the new
> >code much simpler.
> So Igor has a patch set that does a similar change like above.  I so
> far have not found it on QEMU-DEVEL.  Please provide a pointer to
> this patch set.

I was talking specifically about the "CPU properties" series, at:
http://article.gmane.org/gmane.comp.emulators.qemu/165728

The "CPU model classes" series (URL you sent above) is an additional
series to be applied on top of the "CPU properties" series. But the "CPU
model classes" work probably don't impact your patch, so you can simply
be ready to rebase/resend your patch after Igor sends a new version of
the CPU properties series.

Note that the URLs above are old versions of the work in progress. You
may find newer versions at my github tree[1] or at Igor's tree[2].

Basically once we introduce CPU properties, you'll just need to define
the new properties on X86CPU, without the need to change the CPU model
string parsing code. It should make your patch simpler.


[1] An experimental rebase of Igor's CPU properties series (Igor's
    latest version may look different):
    https://github.com/ehabkost/qemu-hacks/tree/work/cpu-properties-igor-rebase-v4.3-2012-08-31
    CPU model classes:
    (may look different when I submit to qemu-devel again):
    https://github.com/ehabkost/qemu-hacks/tree/work/cpu-model-classes-v2.8-2012-08-31
    Lots of work in progress, including multiple branches/series:
    (may look very different when I submit to qemu-devel):
    https://github.com/ehabkost/qemu-hacks/tree/work/cpuid-refactor-v0.22-2012-08-31
[2] Igor's work in progress branch:
    https://github.com/imammedo/qemu/tree/x86-cpu-properties.WIP


> >
> >>Note that the convention for QOM properties is
> >>descriptive-name-with-dashes rather than shortened_abbrev_with_underscore.
> >>
> I will be re-working this change, and wait (for v2) until master has
> changed to the new way.
>    -Don

-- 
Eduardo

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs.
  2012-09-05 16:48 ` Marcelo Tosatti
@ 2012-09-11 13:57   ` Don Slutz
  0 siblings, 0 replies; 10+ messages in thread
From: Don Slutz @ 2012-09-11 13:57 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: Avi Kivity, Don Slutz, kvm, qemu-devel

On 09/05/12 12:48, Marcelo Tosatti wrote:
> On Thu, Aug 30, 2012 at 03:20:35PM -0400, Don Slutz wrote:
>> This is primarily done so that the guest will think it is running
>> under vmware when hypervisor=vmware is specified as a property of a
>> cpu.
>>
>> Also allow this to work in accel=tcg mode.
>>
>> The new cpu properties hyper_level, hyper_extra, hyper_extra_a, and
>> hyper_extra_b can be used to further adjust what the guest sees.
>>
>> Signed-off-by: Don Slutz <Don@CloudSwitch.com>
> For what purpose?
To be able to run bits copied from a ESX(i) server with limited changes 
to the bits.
>
> Is the VMWare interface documented somewhere?
Not that I know of.  All of this change is taken from the Linux source 
(2.6.18-194.32.1.el5 or later) that checks for running on a VMware 
hypervisor.
>
>> ---
>>   target-i386/cpu.c |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   target-i386/cpu.h |    9 +++
>>   target-i386/kvm.c |   33 ++++++++--
>>   3 files changed, 214 insertions(+), 6 deletions(-)
>>
>> diff --git a/target-i386/cpu.c b/target-i386/cpu.c
>> index f3cac49..a444b95 100644
>> --- a/target-i386/cpu.c
>> +++ b/target-i386/cpu.c
>> @@ -26,6 +26,7 @@
>>   
>>   #include "qemu-option.h"
>>   #include "qemu-config.h"
>> +#include "qemu-timer.h"
>>   
>>   #include "qapi/qapi-visit-core.h"
>>   #include "arch_init.h"
>> @@ -244,6 +245,15 @@ typedef struct x86_def_t {
>>       uint32_t xlevel2;
>>       /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
>>       uint32_t cpuid_7_0_ebx_features;
>> +    /* Hypervisor CPUIDs */
>> +    uint32_t cpuid_hv_level;
>> +    uint32_t cpuid_hv_vendor1;
>> +    uint32_t cpuid_hv_vendor2;
>> +    uint32_t cpuid_hv_vendor3;
>> +    /* VMware extra data */
>> +    uint32_t cpuid_hv_extra;
>> +    uint32_t cpuid_hv_extra_a;
>> +    uint32_t cpuid_hv_extra_b;
>>   } x86_def_t;
>>   
>>   #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
>> @@ -860,6 +870,18 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
>>       cpu->env.tsc_khz = value / 1000;
>>   }
>>   
>> +static void x86_cpuid_set_hv(x86_def_t *x86_cpu_def, uint32_t level,
>> +                             const char *who)
>> +{
>> +        uint32_t signature[3];
>> +
>> +        memcpy(signature, who, 12);
>> +        x86_cpu_def->cpuid_hv_level = level;
>> +        x86_cpu_def->cpuid_hv_vendor1 = signature[0];
>> +        x86_cpu_def->cpuid_hv_vendor2 = signature[1];
>> +        x86_cpu_def->cpuid_hv_vendor3 = signature[2];
>> +}
>> +
>>   static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>>   {
>>       unsigned int i;
>> @@ -867,6 +889,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>>   
>>       char *s = g_strdup(cpu_model);
>>       char *featurestr, *name = strtok(s, ",");
>> +    bool hyperv_enabled = false;
>> +    bool hv_enabled = false;
>> +    long hyper_level = -1;
>> +    long hyper_extra = -1;
>>       /* Features to be added*/
>>       uint32_t plus_features = 0, plus_ext_features = 0;
>>       uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
>> @@ -993,12 +1019,84 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>>                   x86_cpu_def->tsc_khz = tsc_freq / 1000;
>>               } else if (!strcmp(featurestr, "hv_spinlocks")) {
>>                   char *err;
>> +
>> +                if (hv_enabled) {
>> +                    fprintf(stderr,
>> +                            "Only one of hypervisor= or hv_* can be used at one time.\n");
>> +                    goto error;
>> +                }
>>                   numvalue = strtoul(val, &err, 0);
>>                   if (!*val || *err) {
>>                       fprintf(stderr, "bad numerical value %s\n", val);
>>                       goto error;
>>                   }
>> +                hyperv_enabled = true;
>>                   hyperv_set_spinlock_retries(numvalue);
>> +            } else if (!strcmp(featurestr, "hyper_level")) {
>> +                char *err;
>> +                long longvalue = strtol(val, &err, 0);
>> +
>> +                if (!*val || *err) {
>> +                    fprintf(stderr, "bad numerical value for hyper_level=%s\n",
>> +                            val);
>> +                    goto error;
>> +                }
>> +                hyper_level = longvalue;
>> +            } else if (!strcmp(featurestr, "hyper_extra")) {
>> +                char *err;
>> +                long longvalue = strtol(val, &err, 0);
>> +
>> +                if (!*val || *err) {
>> +                    fprintf(stderr, "bad numerical value for hyper_extra=%s\n",
>> +                            val);
>> +                    goto error;
>> +                }
>> +                hyper_extra = longvalue;
>> +            } else if (!strcmp(featurestr, "hyper_extra_a")) {
>> +                char *err;
>> +
>> +                numvalue = strtoul(val, &err, 0);
>> +                if (!*val || *err) {
>> +                    fprintf(stderr,
>> +                            "bad numerical value for hyper_extra_a=%s\n",
>> +                            val);
>> +                    goto error;
>> +                }
>> +                x86_cpu_def->cpuid_hv_extra_a = (uint32_t)numvalue;
>> +            } else if (!strcmp(featurestr, "hyper_extra_b")) {
>> +                char *err;
>> +
>> +                numvalue = strtoul(val, &err, 0);
>> +                if (!*val || *err) {
>> +                    fprintf(stderr,
>> +                            "bad numerical value for hyper_extra_b=%s\n",
>> +                            val);
>> +                    goto error;
>> +                }
>> +                x86_cpu_def->cpuid_hv_extra_b = (uint32_t)numvalue;
>> +            } else if (!strcmp(featurestr, "hv") ||
>> +                       !strcmp(featurestr, "hypervisor")) {
>> +                if (hyperv_enabled) {
>> +                    fprintf(stderr,
>> +                            "Only one of hypervisor= or hv_* can be used at one time.\n");
>> +                    goto error;
>> +                }
>> +                hv_enabled = true;
>> +                if (!strcmp(val, "vmware")) {
>> +                    x86_cpuid_set_hv(x86_cpu_def, 0x40000010, "VMwareVMware");
>> +                    minus_kvm_features = ~0;    /* Expected to be zero... */
>> +                } else if (!strcmp(val, "vmware3")) {
>> +                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "VMwareVMware");
>> +                    minus_kvm_features = ~0;    /* Expected to be zero... */
>> +                } else if (!strcmp(val, "xen")) {
>> +                    x86_cpuid_set_hv(x86_cpu_def, 0x40000002, "XenVMMXenVMM");
>> +                } else if (!strcmp(val, "kvm")) {
>> +                    x86_cpuid_set_hv(x86_cpu_def, 0, "KVMKVMKVM\0\0\0");
>> +                } else {
>> +                    fprintf(stderr, "unknown hypervisor %s\n",
>> +                            val);
>> +                    goto error;
>> +                }
>>               } else {
>>                   fprintf(stderr, "unrecognized feature %s\n", featurestr);
>>                   goto error;
>> @@ -1008,8 +1106,20 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>>           } else if (!strcmp(featurestr, "enforce")) {
>>               check_cpuid = enforce_cpuid = 1;
>>           } else if (!strcmp(featurestr, "hv_relaxed")) {
>> +            if (hv_enabled) {
>> +                fprintf(stderr,
>> +                        "Only one of hypervisor= or hv_* can be used at one time.\n");
>> +                goto error;
>> +            }
>> +            hyperv_enabled = true;
>>               hyperv_enable_relaxed_timing(true);
>>           } else if (!strcmp(featurestr, "hv_vapic")) {
>> +            if (hv_enabled) {
>> +                fprintf(stderr,
>> +                        "Only one of hypervisor= or hv_* can be used at one time.\n");
>> +                goto error;
>> +            }
>> +            hyperv_enabled = true;
>>               hyperv_enable_vapic_recommended(true);
>>           } else {
>>               fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
>> @@ -1017,6 +1127,34 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
>>           }
>>           featurestr = strtok(NULL, ",");
>>       }
>> +#ifdef CONFIG_KVM
>> +    if (hyperv_enabled) {
>> +        x86_cpuid_set_hv(x86_cpu_def, HYPERV_CPUID_MIN, "Microsoft Hv");
>> +    }
>> +#endif
>> +    if (hyper_extra >= 0) {
>> +        x86_cpu_def->cpuid_hv_extra = 0x40000000 + hyper_extra;
>> +    } else if (hv_enabled && x86_cpu_def->tsc_khz) {
>> +        /*
>> +         * From http://article.gmane.org/gmane.comp.emulators.kvm.devel/22643
>> +         *
>> +         *    Leaf 0x40000010, Timing Information.
>> +         *
>> +         *    VMware has defined the first generic leaf to provide timing
>> +         *    information.  This leaf returns the current TSC frequency and
>> +         *    current Bus frequency in kHz.
>> +         *
>> +         *    # EAX: (Virtual) TSC frequency in kHz.
>> +         *    # EBX: (Virtual) Bus (local apic timer) frequency in kHz.
>> +         *    # ECX, EDX: RESERVED (Per above, reserved fields are set to zero).
>> +         */
>> +        x86_cpu_def->cpuid_hv_extra = 0x40000010;
>> +        x86_cpu_def->cpuid_hv_extra_a = (uint32_t)x86_cpu_def->tsc_khz;
>> +        x86_cpu_def->cpuid_hv_extra_b = (uint32_t)(get_ticks_per_sec() / 1000);
>> +    }
>> +    if (hyper_level >= 0) {
>> +        x86_cpu_def->cpuid_hv_level = 0x40000000 + hyper_level;
>> +    }
>>       x86_cpu_def->features |= plus_features;
>>       x86_cpu_def->ext_features |= plus_ext_features;
>>       x86_cpu_def->ext2_features |= plus_ext2_features;
>> @@ -1192,6 +1330,13 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
>>       env->cpuid_ext4_features = def->ext4_features;
>>       env->cpuid_7_0_ebx = def->cpuid_7_0_ebx_features;
>>       env->cpuid_xlevel2 = def->xlevel2;
>> +    env->cpuid_hv_level = def->cpuid_hv_level;
>> +    env->cpuid_hv_vendor1 = def->cpuid_hv_vendor1;
>> +    env->cpuid_hv_vendor2 = def->cpuid_hv_vendor2;
>> +    env->cpuid_hv_vendor3 = def->cpuid_hv_vendor3;
>> +    env->cpuid_hv_extra = def->cpuid_hv_extra;
>> +    env->cpuid_hv_extra_a = def->cpuid_hv_extra_a;
>> +    env->cpuid_hv_extra_b = def->cpuid_hv_extra_b;
>>       object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
>>                               "tsc-frequency", &error);
>>       if (!kvm_enabled()) {
>> @@ -1390,6 +1535,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
>>                   index =  env->cpuid_xlevel;
>>               }
>>           }
>> +    } else if (index & 0x40000000) {
>> +        if (env->cpuid_hv_level > 0) {
>> +            /* Handle Paravirtualization CPUIDs */
>> +            if (index > env->cpuid_hv_level) {
>> +                index = env->cpuid_hv_level;
>> +            }
>> +        } else {
>> +            if (index > env->cpuid_level)
>> +                index = env->cpuid_level;
>> +        }
>>       } else {
>>           if (index > env->cpuid_level)
>>               index = env->cpuid_level;
>> @@ -1528,6 +1683,29 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
>>               *edx = 0;
>>           }
>>           break;
>> +    case 0x40000000:
>> +        *eax = env->cpuid_hv_level;
>> +        *ebx = env->cpuid_hv_vendor1;
>> +        *ecx = env->cpuid_hv_vendor2;
>> +        *edx = env->cpuid_hv_vendor3;
>> +        break;
>> +    case 0x40000001:
>> +        *eax = env->cpuid_kvm_features;
>> +        *ebx = 0;
>> +        *ecx = 0;
>> +        *edx = 0;
>> +        break;
>> +    case 0x40000002 ... 0x400000FF:
>> +        if (index == env->cpuid_hv_extra) {
>> +            *eax = env->cpuid_hv_extra_a;
>> +            *ebx = env->cpuid_hv_extra_b;
>> +        } else {
>> +            *eax = 0;
>> +            *ebx = 0;
>> +        }
>> +        *ecx = 0;
>> +        *edx = 0;
>> +        break;
>>       case 0x80000000:
>>           *eax = env->cpuid_xlevel;
>>           *ebx = env->cpuid_vendor1;
>> diff --git a/target-i386/cpu.h b/target-i386/cpu.h
>> index 0677502..dc2039a 100644
>> --- a/target-i386/cpu.h
>> +++ b/target-i386/cpu.h
>> @@ -746,6 +746,15 @@ typedef struct CPUX86State {
>>       uint32_t cpuid_ext4_features;
>>       /* Flags from CPUID[EAX=7,ECX=0].EBX */
>>       uint32_t cpuid_7_0_ebx;
>> +    /* Paravirtualization CPUIDs */
>> +    uint32_t cpuid_hv_level;
>> +    uint32_t cpuid_hv_vendor1;
>> +    uint32_t cpuid_hv_vendor2;
>> +    uint32_t cpuid_hv_vendor3;
>> +    /* VMware extra data */
>> +    uint32_t cpuid_hv_extra;
>> +    uint32_t cpuid_hv_extra_a;
>> +    uint32_t cpuid_hv_extra_b;
>>   
>>       /* MTRRs */
>>       uint64_t mtrr_fixed[11];
>> diff --git a/target-i386/kvm.c b/target-i386/kvm.c
>> index ffc294e..d01a5f8 100644
>> --- a/target-i386/kvm.c
>> +++ b/target-i386/kvm.c
>> @@ -389,16 +389,18 @@ int kvm_arch_init_vcpu(CPUX86State *env)
>>       c = &cpuid_data.entries[cpuid_i++];
>>       memset(c, 0, sizeof(*c));
>>       c->function = KVM_CPUID_SIGNATURE;
>> -    if (!hyperv_enabled()) {
>> +    if (env->cpuid_hv_level == 0) {
>>           memcpy(signature, "KVMKVMKVM\0\0\0", 12);
>>           c->eax = 0;
>> +        c->ebx = signature[0];
>> +        c->ecx = signature[1];
>> +        c->edx = signature[2];
>>       } else {
>> -        memcpy(signature, "Microsoft Hv", 12);
>> -        c->eax = HYPERV_CPUID_MIN;
>> +        c->eax = env->cpuid_hv_level;
>> +        c->ebx = env->cpuid_hv_vendor1;
>> +        c->ecx = env->cpuid_hv_vendor2;
>> +        c->edx = env->cpuid_hv_vendor3;
>>       }
>> -    c->ebx = signature[0];
>> -    c->ecx = signature[1];
>> -    c->edx = signature[2];
>>   
>>       c = &cpuid_data.entries[cpuid_i++];
>>       memset(c, 0, sizeof(*c));
>> @@ -452,6 +454,25 @@ int kvm_arch_init_vcpu(CPUX86State *env)
>>           c->ebx = signature[0];
>>           c->ecx = signature[1];
>>           c->edx = signature[2];
>> +    } else if (env->cpuid_hv_level > 0) {
>> +        for (i = KVM_CPUID_FEATURES + 1; i <= env->cpuid_hv_level; i++) {
>> +            c = &cpuid_data.entries[cpuid_i++];
>> +            memset(c, 0, sizeof(*c));
>> +            c->function = i;
>> +            if (i == env->cpuid_hv_extra) {
>> +                c->eax = env->cpuid_hv_extra_a;
>> +                c->ebx = env->cpuid_hv_extra_b;
>> +            }
>> +        }
>> +
>> +        c = &cpuid_data.entries[cpuid_i++];
>> +        memset(c, 0, sizeof(*c));
>> +        c->function = KVM_CPUID_SIGNATURE_NEXT;
>> +        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
>> +        c->eax = 0;
>> +        c->ebx = signature[0];
>> +        c->ecx = signature[1];
>> +        c->edx = signature[2];
>>       }
>>   
>>       has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
>> -- 
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe kvm" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
v2 is on it way now that QEMU 1.3 is open.
     -Don

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-09-11 13:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-30 20:36 [Qemu-devel] [PATCH] target-i386: Allow changing of Hypervisor CPUIDs Don Slutz
  -- strict thread matches above, loose matches on Subject: below --
2012-08-30 21:07 Don Slutz
2012-08-30 20:56 Don Slutz
2012-08-30 19:20 Don Slutz
2012-09-05 16:48 ` Marcelo Tosatti
2012-09-11 13:57   ` Don Slutz
2012-09-06 10:28 ` Andreas Färber
2012-09-06 18:40   ` Eduardo Habkost
2012-09-06 19:00     ` Don Slutz
2012-09-06 19:36       ` Eduardo Habkost

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).