Message ID | 1346354435-21685-1-git-send-email-Don@CloudSwitch.com |
---|---|
State | New |
Headers | show |
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
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
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. >
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
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
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
This depends on: http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg01400.html As far as I know it is #4. It depends on (1) and (2) and (3). Changes from v1 to v2: 1) Added 1/4 from http://lists.gnu.org/archive/html/qemu-devel/2012-08/msg05153.html Because Fred is changing jobs and so will not be pushing to get this in. It needed to be rebased, And I needed it to complete the testing of this change. 2) Added 2/4 because of the re-work I needed a way to clear all KVM bits, 3) The rework of v1. Make it fit into the object model re-work of cpu.c for x86. 4) Added 3/4 -- The split out of the code that is not needed for accel=kvm. Don Slutz (4): target-i386: Allow tsc-frequency to be larger then 2.147G target-i386: Add missing kvm bits. target-i386: Allow changing of Hypervisor CPUIDs. target-i386: Add Hypervisor CPUIDs in accel=tcg mode. target-i386/cpu.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/cpu.h | 21 +++++ target-i386/kvm.c | 33 ++++++-- 3 files changed, 304 insertions(+), 11 deletions(-)
Also known as Paravirtualization CPUIDs. This is primarily done so that the guest will think it is running under vmware when hypervisor-vendor=vmware is specified as a property of a cpu. This depends on: http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg01400.html As far as I know it is #4. It depends on (1) and (2) and (3). This change is based on: Microsoft Hypervisor CPUID Leaves: http://msdn.microsoft.com/en-us/library/windows/hardware/ff542428%28v=vs.85%29.aspx Linux kernel change starts with: http://fixunix.com/kernel/538707-use-cpuid-communicate-hypervisor.html Also: http://lkml.indiana.edu/hypermail/linux/kernel/1205.0/00100.html VMware documention on CPUIDs (Mechanisms to determine if software is running in a VMware virtual machine): http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 Changes from v1 to v2: 1) Added 1/4 from http://lists.gnu.org/archive/html/qemu-devel/2012-08/msg05153.html Because Fred is changing jobs and so will not be pushing to get this in. It needed to be rebased, And I needed it to complete the testing of this change. 2) Added 2/4 because of the re-work I needed a way to clear all KVM bits, 3) The rework of v1. Make it fit into the object model re-work of cpu.c for x86. 4) Added 3/4 -- The split out of the code that is not needed for accel=kvm. Changes from v2 to v3: Marcelo Tosatti: Its one big patch, better split in logically correlated patches (with better changelog). This would help reviewers. So split 3 and 4 into 3 to 17. More info in change log. No code change. Don Slutz (17): target-i386: Allow tsc-frequency to be larger then 2.147G target-i386: Add missing kvm bits. target-i386: Add Hypervisor level. target-i386: Add cpu object access routines for Hypervisor level. target-i386: Add x86_set_hyperv. target-i386: Use Hypervisor level in -machine pc,accel=kvm. target-i386: Use Hypervisor level in -machine pc,accel=tcg. target-i386: Add Hypervisor vendor. target-i386: Add cpu object access routines for Hypervisor vendor. target-i386: Use Hypervisor vendor in -machine pc,accel=kvm. target-i386: Use Hypervisor vendor in -machine pc,accel=tcg. target-i386: Add some known names to Hypervisor vendor. target-i386: Add optional Hypervisor leaf extra. target-i386: Add cpu object access routines for Hypervisor leaf extra. target-i386: Add setting of Hypervisor leaf extra for known vmare4. target-i386: Use Hypervisor leaf extra in -machine pc,accel=kvm. target-i386: Use Hypervisor leaf extra in -machine pc,accel=tcg. target-i386/cpu.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/cpu.h | 21 +++++ target-i386/kvm.c | 33 ++++++-- 3 files changed, 304 insertions(+), 11 deletions(-)
*** BLURB HERE *** Don Slutz (17): target-i386: Allow tsc-frequency to be larger then 2.147G target-i386: Add missing kvm bits. target-i386: Add Hypervisor level. target-i386: Add cpu object access routines for Hypervisor level. target-i386: Add x86_set_hyperv. target-i386: Use Hypervisor level in -machine pc,accel=kvm. target-i386: Use Hypervisor level in -machine pc,accel=tcg. target-i386: Add Hypervisor vendor. target-i386: Add cpu object access routines for Hypervisor vendor. target-i386: Use Hypervisor vendor in -machine pc,accel=kvm. target-i386: Use Hypervisor vendor in -machine pc,accel=tcg. target-i386: Add some known names to Hypervisor vendor. target-i386: Add optional Hypervisor leaf extra. target-i386: Add cpu object access routines for Hypervisor leaf extra. target-i386: Add setting of Hypervisor leaf extra for known vmare4. target-i386: Use Hypervisor leaf extra in -machine pc,accel=kvm. target-i386: Use Hypervisor leaf extra in -machine pc,accel=tcg. target-i386/cpu.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/cpu.h | 21 +++++ target-i386/kvm.c | 33 ++++++-- 3 files changed, 304 insertions(+), 11 deletions(-)
Also known as Paravirtualization CPUIDs. This is primarily done so that the guest will think it is running under vmware when hypervisor-vendor=vmware is specified as a property of a cpu. This depends on: http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg01400.html As far as I know it is #4. It depends on (1) and (2) and (3). This change is based on: Microsoft Hypervisor CPUID Leaves: http://msdn.microsoft.com/en-us/library/windows/hardware/ff542428%28v=vs.85%29.aspx Linux kernel change starts with: http://fixunix.com/kernel/538707-use-cpuid-communicate-hypervisor.html Also: http://lkml.indiana.edu/hypermail/linux/kernel/1205.0/00100.html VMware documention on CPUIDs (Mechanisms to determine if software is running in a VMware virtual machine): http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 Changes from v1 to v2: 1) Added 1/4 from http://lists.gnu.org/archive/html/qemu-devel/2012-08/msg05153.html Because Fred is changing jobs and so will not be pushing to get this in. It needed to be rebased, And I needed it to complete the testing of this change. 2) Added 2/4 because of the re-work I needed a way to clear all KVM bits, 3) The rework of v1. Make it fit into the object model re-work of cpu.c for x86. 4) Added 3/4 -- The split out of the code that is not needed for accel=kvm. Changes from v2 to v3: Marcelo Tosatti: Its one big patch, better split in logically correlated patches (with better changelog). This would help reviewers. So split 3 and 4 into 3 to 17. More info in change log. No code change. Don Slutz (17): target-i386: Allow tsc-frequency to be larger then 2.147G target-i386: Add missing kvm bits. target-i386: Add Hypervisor level. target-i386: Add cpu object access routines for Hypervisor level. target-i386: Add x86_set_hyperv. target-i386: Use Hypervisor level in -machine pc,accel=kvm. target-i386: Use Hypervisor level in -machine pc,accel=tcg. target-i386: Add Hypervisor vendor. target-i386: Add cpu object access routines for Hypervisor vendor. target-i386: Use Hypervisor vendor in -machine pc,accel=kvm. target-i386: Use Hypervisor vendor in -machine pc,accel=tcg. target-i386: Add some known names to Hypervisor vendor. target-i386: Add optional Hypervisor leaf extra. target-i386: Add cpu object access routines for Hypervisor leaf extra. target-i386: Add setting of Hypervisor leaf extra for known vmare4. target-i386: Use Hypervisor leaf extra in -machine pc,accel=kvm. target-i386: Use Hypervisor leaf extra in -machine pc,accel=tcg. target-i386/cpu.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/cpu.h | 21 +++++ target-i386/kvm.c | 33 ++++++-- 3 files changed, 304 insertions(+), 11 deletions(-)
forgot to delete the backup versions. :( -Don On 09/17/12 09:39, Don Slutz wrote: > *** BLURB HERE *** > > Don Slutz (17): > target-i386: Allow tsc-frequency to be larger then 2.147G > target-i386: Add missing kvm bits. > target-i386: Add Hypervisor level. > target-i386: Add cpu object access routines for Hypervisor level. > target-i386: Add x86_set_hyperv. > target-i386: Use Hypervisor level in -machine pc,accel=kvm. > target-i386: Use Hypervisor level in -machine pc,accel=tcg. > target-i386: Add Hypervisor vendor. > target-i386: Add cpu object access routines for Hypervisor vendor. > target-i386: Use Hypervisor vendor in -machine pc,accel=kvm. > target-i386: Use Hypervisor vendor in -machine pc,accel=tcg. > target-i386: Add some known names to Hypervisor vendor. > target-i386: Add optional Hypervisor leaf extra. > target-i386: Add cpu object access routines for Hypervisor leaf > extra. > target-i386: Add setting of Hypervisor leaf extra for known vmare4. > target-i386: Use Hypervisor leaf extra in -machine pc,accel=kvm. > target-i386: Use Hypervisor leaf extra in -machine pc,accel=tcg. > > target-i386/cpu.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++- > target-i386/cpu.h | 21 +++++ > target-i386/kvm.c | 33 ++++++-- > 3 files changed, 304 insertions(+), 11 deletions(-) >
On 09/17/12 09:49, Don Slutz wrote: > forgot to delete the backup versions. :( > -Don > On 09/17/12 09:39, Don Slutz wrote: Here is the planned cover letter: From 7c0a80d8e870da981786b7235d3a968024c89abb Mon Sep 17 00:00:00 2001 In-Reply-To: <1346354435-21685-1-git-send-email-Don@CloudSwitch.com> References: <1346354435-21685-1-git-send-email-Don@CloudSwitch.com> From: Don Slutz <Don@CloudSwitch.com> Date: Mon, 17 Sep 2012 09:23:29 -0400 Subject: [PATCH v3 00/17] Allow changing of Hypervisor CPUIDs. Also known as Paravirtualization CPUIDs. This is primarily done so that the guest will think it is running under vmware when hypervisor-vendor=vmware is specified as a property of a cpu. This depends on: http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg01400.html As far as I know it is #4. It depends on (1) and (2) and (3). This change is based on: Microsoft Hypervisor CPUID Leaves: http://msdn.microsoft.com/en-us/library/windows/hardware/ff542428%28v=vs.85%29.aspx Linux kernel change starts with: http://fixunix.com/kernel/538707-use-cpuid-communicate-hypervisor.html Also: http://lkml.indiana.edu/hypermail/linux/kernel/1205.0/00100.html VMware documention on CPUIDs (Mechanisms to determine if software is running in a VMware virtual machine): http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 Changes from v1 to v2: 1) Added 1/4 from http://lists.gnu.org/archive/html/qemu-devel/2012-08/msg05153.html Because Fred is changing jobs and so will not be pushing to get this in. It needed to be rebased, And I needed it to complete the testing of this change. 2) Added 2/4 because of the re-work I needed a way to clear all KVM bits, 3) The rework of v1. Make it fit into the object model re-work of cpu.c for x86. 4) Added 3/4 -- The split out of the code that is not needed for accel=kvm. Changes from v2 to v3: Marcelo Tosatti: Its one big patch, better split in logically correlated patches (with better changelog). This would help reviewers. So split 3 and 4 into 3 to 17. More info in change log. No code change. Don Slutz (17): target-i386: Allow tsc-frequency to be larger then 2.147G target-i386: Add missing kvm bits. target-i386: Add Hypervisor level. target-i386: Add cpu object access routines for Hypervisor level. target-i386: Add x86_set_hyperv. target-i386: Use Hypervisor level in -machine pc,accel=kvm. target-i386: Use Hypervisor level in -machine pc,accel=tcg. target-i386: Add Hypervisor vendor. target-i386: Add cpu object access routines for Hypervisor vendor. target-i386: Use Hypervisor vendor in -machine pc,accel=kvm. target-i386: Use Hypervisor vendor in -machine pc,accel=tcg. target-i386: Add some known names to Hypervisor vendor. target-i386: Add optional Hypervisor leaf extra. target-i386: Add cpu object access routines for Hypervisor leaf extra. target-i386: Add setting of Hypervisor leaf extra for known vmare4. target-i386: Use Hypervisor leaf extra in -machine pc,accel=kvm. target-i386: Use Hypervisor leaf extra in -machine pc,accel=tcg. target-i386/cpu.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/cpu.h | 21 +++++ target-i386/kvm.c | 33 ++++++-- 3 files changed, 304 insertions(+), 11 deletions(-)
Resend with new id so the backup files are not included. Also known as Paravirtualization CPUIDs. This is primarily done so that the guest will think it is running under vmware when hypervisor-vendor=vmware is specified as a property of a cpu. This depends on: http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg01400.html As far as I know it is #4. It depends on (1) and (2) and (3). This change is based on: Microsoft Hypervisor CPUID Leaves: http://msdn.microsoft.com/en-us/library/windows/hardware/ff542428%28v=vs.85%29.aspx Linux kernel change starts with: http://fixunix.com/kernel/538707-use-cpuid-communicate-hypervisor.html Also: http://lkml.indiana.edu/hypermail/linux/kernel/1205.0/00100.html VMware documention on CPUIDs (Mechanisms to determine if software is running in a VMware virtual machine): http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 Changes from v1 to v2: 1) Added 1/4 from http://lists.gnu.org/archive/html/qemu-devel/2012-08/msg05153.html Because Fred is changing jobs and so will not be pushing to get this in. It needed to be rebased, And I needed it to complete the testing of this change. 2) Added 2/4 because of the re-work I needed a way to clear all KVM bits, 3) The rework of v1. Make it fit into the object model re-work of cpu.c for x86. 4) Added 3/4 -- The split out of the code that is not needed for accel=kvm. Changes from v2 to v3: Marcelo Tosatti: Its one big patch, better split in logically correlated patches (with better changelog). This would help reviewers. So split 3 and 4 into 3 to 17. More info in change log. No code change. Don Slutz (17): target-i386: Allow tsc-frequency to be larger then 2.147G target-i386: Add missing kvm bits. target-i386: Add Hypervisor level. target-i386: Add cpu object access routines for Hypervisor level. target-i386: Add x86_set_hyperv. target-i386: Use Hypervisor level in -machine pc,accel=kvm. target-i386: Use Hypervisor level in -machine pc,accel=tcg. target-i386: Add Hypervisor vendor. target-i386: Add cpu object access routines for Hypervisor vendor. target-i386: Use Hypervisor vendor in -machine pc,accel=kvm. target-i386: Use Hypervisor vendor in -machine pc,accel=tcg. target-i386: Add some known names to Hypervisor vendor. target-i386: Add optional Hypervisor leaf extra. target-i386: Add cpu object access routines for Hypervisor leaf extra. target-i386: Add setting of Hypervisor leaf extra for known vmare4. target-i386: Use Hypervisor leaf extra in -machine pc,accel=kvm. target-i386: Use Hypervisor leaf extra in -machine pc,accel=tcg. target-i386/cpu.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/cpu.h | 21 +++++ target-i386/kvm.c | 33 ++++++-- 3 files changed, 304 insertions(+), 11 deletions(-)
On Mon, Sep 17, 2012 at 10:00:50AM -0400, Don Slutz wrote: > Resend with new id so the backup files are not included. > > Also known as Paravirtualization CPUIDs. > > This is primarily done so that the guest will think it is running > under vmware when hypervisor-vendor=vmware is specified as a > property of a cpu. > > > This depends on: > > http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg01400.html > > As far as I know it is #4. It depends on (1) and (2) and (3). Correct. I have removed v2 and added this version to my cpu-queue[1] branch. [1] https://github.com/ehabkost/qemu/commits/cpu-queue My branch is now based on Andreas's qom-cpu branch from https://github.com/afaerber/qemu-cpu/commits/qom-cpu > > This change is based on: > > Microsoft Hypervisor CPUID Leaves: > http://msdn.microsoft.com/en-us/library/windows/hardware/ff542428%28v=vs.85%29.aspx > > Linux kernel change starts with: > http://fixunix.com/kernel/538707-use-cpuid-communicate-hypervisor.html > Also: > http://lkml.indiana.edu/hypermail/linux/kernel/1205.0/00100.html > > VMware documention on CPUIDs (Mechanisms to determine if software is > running in a VMware virtual machine): > http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 > > Changes from v1 to v2: > > 1) Added 1/4 from http://lists.gnu.org/archive/html/qemu-devel/2012-08/msg05153.html > > Because Fred is changing jobs and so will not be pushing to get > this in. It needed to be rebased, And I needed it to complete the > testing of this change. > > 2) Added 2/4 because of the re-work I needed a way to clear all KVM bits, > > 3) The rework of v1. Make it fit into the object model re-work of cpu.c for x86. > > 4) Added 3/4 -- The split out of the code that is not needed for accel=kvm. > > Changes from v2 to v3: > > Marcelo Tosatti: > Its one big patch, better split in logically correlated patches > (with better changelog). This would help reviewers. > > So split 3 and 4 into 3 to 17. More info in change log. > No code change. > > Don Slutz (17): > target-i386: Allow tsc-frequency to be larger then 2.147G > target-i386: Add missing kvm bits. > target-i386: Add Hypervisor level. > target-i386: Add cpu object access routines for Hypervisor level. > target-i386: Add x86_set_hyperv. > target-i386: Use Hypervisor level in -machine pc,accel=kvm. > target-i386: Use Hypervisor level in -machine pc,accel=tcg. > target-i386: Add Hypervisor vendor. > target-i386: Add cpu object access routines for Hypervisor vendor. > target-i386: Use Hypervisor vendor in -machine pc,accel=kvm. > target-i386: Use Hypervisor vendor in -machine pc,accel=tcg. > target-i386: Add some known names to Hypervisor vendor. > target-i386: Add optional Hypervisor leaf extra. > target-i386: Add cpu object access routines for Hypervisor leaf > extra. > target-i386: Add setting of Hypervisor leaf extra for known vmare4. > target-i386: Use Hypervisor leaf extra in -machine pc,accel=kvm. > target-i386: Use Hypervisor leaf extra in -machine pc,accel=tcg. > > target-i386/cpu.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++- > target-i386/cpu.h | 21 +++++ > target-i386/kvm.c | 33 ++++++-- > 3 files changed, 304 insertions(+), 11 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);
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(-)