All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nitin A Kamble <nitin.a.kamble@intel.com>
To: "avi@redhat.com" <avi@redhat.com>
Cc: "kvm@vger.kernel.org" <kvm@vger.kernel.org>
Subject: [userspace patch] exposing host cpuids to guest
Date: Thu, 29 Jan 2009 17:54:08 -0800	[thread overview]
Message-ID: <1233280448.28605.12.camel@mukti.sc.intel.com> (raw)
In-Reply-To: <1233277976.28605.9.camel@mukti.sc.intel.com>

[-- Attachment #1: Type: text/plain, Size: 754 bytes --]

Avi,
 Attached is the patch for kvm-userspace.git tree. With this patch
adding "-cpu host" to qemu commandline would expose the host cpuids to
the guest. Some of the cpuid data is still filtered in the kernel kvm
code. 
  Please apply or give comments for the patch.

Thanks & Regards,
Nitin


On Thu, 2009-01-29 at 17:12 -0800, Nitin A Kamble wrote:
> Avi,
>   I reworked the earlier patch for exposing the host cpuid bits to
> guests. Attached is the patch for your kvm.git tree. With this new code
> in the kernel both the old and new qemu binaries are working.
> 
>   There are also changes for the kvm-userspace.git tree. I will be
> sending out those changes too.
> 
>   Please apply or give feedback for this patch.
> 
> Thanks & Regards,
> Nitin

[-- Attachment #2: expose_host_cpuids_2_guest_kvm-userspace_patch.diff --]
[-- Type: text/x-patch, Size: 8410 bytes --]

diff --git a/libkvm/libkvm-x86.c b/libkvm/libkvm-x86.c
index dcef548..10f6614 100644
--- a/libkvm/libkvm-x86.c
+++ b/libkvm/libkvm-x86.c
@@ -379,6 +379,37 @@ int kvm_set_msrs(kvm_context_t kvm, int vcpu, struct kvm_msr_entry *msrs,
     return r;
 }
 
+/*
+ * Returns available host cpuid entries.  User must free.
+ */
+struct kvm_cpuid2 *kvm_get_host_cpuid_entries(kvm_context_t kvm)
+{
+	struct kvm_cpuid2 sizer, *cpuids;
+	int r, e;
+
+	sizer.nent = 0;
+	r = ioctl(kvm->fd, KVM_GET_SUPPORTED_CPUID, &sizer);
+	if (r != -1 && errno != EAGAIN)
+		return NULL;
+
+	cpuids = malloc(sizeof *cpuids + sizer.nent * sizeof *cpuids->entries);
+	if (!cpuids) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	cpuids->nent = sizer.nent;
+	r = ioctl(kvm->fd, KVM_GET_SUPPORTED_CPUID, cpuids);
+	if (r == -1) {
+		e = errno;
+		free(cpuids);
+		errno = e;
+		return NULL;
+	}
+	return cpuids;
+}
+
+
 static void print_seg(FILE *file, const char *name, struct kvm_segment *seg)
 {
     	fprintf(stderr,
diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h
index e79e4fd..5b7f063 100644
--- a/libkvm/libkvm.h
+++ b/libkvm/libkvm.h
@@ -27,6 +27,9 @@ typedef struct kvm_context *kvm_context_t;
 struct kvm_msr_list *kvm_get_msr_list(kvm_context_t);
 int kvm_get_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
 int kvm_set_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
+struct kvm_cpuid2 *kvm_get_host_cpuid_entries(kvm_context_t);
+void get_host_cpuid_entry(uint32_t function, uint32_t index,
+				struct kvm_cpuid_entry2 *e);
 #endif
 
 /*!
diff --git a/qemu/qemu-kvm-x86.c b/qemu/qemu-kvm-x86.c
index 01748ed..4c1c159 100644
--- a/qemu/qemu-kvm-x86.c
+++ b/qemu/qemu-kvm-x86.c
@@ -23,6 +23,7 @@
 #define MSR_IA32_TSC		0x10
 
 static struct kvm_msr_list *kvm_msr_list;
+static struct kvm_cpuid2 *kvm_host_cpuid_entries;
 extern unsigned int kvm_shadow_memory;
 static int kvm_has_msr_star;
 
@@ -57,7 +58,12 @@ int kvm_arch_qemu_create_context(void)
     for (i = 0; i < kvm_msr_list->nmsrs; ++i)
 	if (kvm_msr_list->indices[i] == MSR_STAR)
 	    kvm_has_msr_star = 1;
-	return 0;
+
+    kvm_host_cpuid_entries = kvm_get_host_cpuid_entries(kvm_context);
+    if (!kvm_host_cpuid_entries)
+	return -1;
+
+    return 0;
 }
 
 static void set_msr_entry(struct kvm_msr_entry *entry, uint32_t index,
@@ -461,13 +467,61 @@ void kvm_arch_save_regs(CPUState *env)
     }
 }
 
+void get_host_cpuid_entry(uint32_t function, uint32_t index,
+				struct kvm_cpuid_entry2 *e)
+{
+    int i;
+    struct kvm_cpuid_entry2 *entries;
+
+    memset(e, 0, (sizeof *e));
+    e->function = function;
+    e->index = index;
+
+    if (!kvm_host_cpuid_entries)
+	return;
+
+    entries = kvm_host_cpuid_entries->entries;
+
+    for (i=0; i<kvm_host_cpuid_entries->nent; i++) {
+	struct kvm_cpuid_entry2 *ent = &entries[i];
+	if (ent->function != function)
+	    continue; 
+	if ((ent->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX) && 
+						(ent->index != index))
+	    continue;
+	if ((ent->flags & KVM_CPUID_FLAG_STATEFUL_FUNC) &&
+		!(ent->flags & KVM_CPUID_FLAG_STATE_READ_NEXT))
+	    continue;
+
+	memcpy(e, ent, sizeof (*e));
+
+	if (ent->flags & KVM_CPUID_FLAG_STATEFUL_FUNC) {
+	    int j;
+	    ent->flags &= ~KVM_CPUID_FLAG_STATE_READ_NEXT;
+	    for (j=i+1; ;j=(j+1)%(kvm_host_cpuid_entries->nent)) {
+		struct kvm_cpuid_entry2 *entj = &entries[j];
+		if (entj->function == ent->function) {
+		    entj->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
+		    break;
+		}
+	    }
+	}
+	break;
+    }
+}
+
 static void do_cpuid_ent(struct kvm_cpuid_entry2 *e, uint32_t function,
-                         uint32_t count, CPUState *env)
+                         uint32_t index, CPUState *env)
 {
+    if (env->cpuid_host_cpu) {
+        get_host_cpuid_entry(function, index, e);
+	return;
+    }
+    e->function = function;
+    e->index = index;
     env->regs[R_EAX] = function;
-    env->regs[R_ECX] = count;
+    env->regs[R_ECX] = index;
     qemu_kvm_cpuid_on_env(env);
-    e->function = function;
     e->eax = env->regs[R_EAX];
     e->ebx = env->regs[R_EBX];
     e->ecx = env->regs[R_ECX];
@@ -518,6 +572,10 @@ int kvm_arch_qemu_init_env(CPUState *cenv)
 
     copy = *cenv;
 
+    if (copy.cpuid_host_cpu) 
+        if (!kvm_host_cpuid_entries)
+	   return -EINVAL;
+
 #ifdef KVM_CPUID_SIGNATURE
     /* Paravirtualization CPUIDs */
     memcpy(signature, "KVMKVMKVM\0\0\0", 12);
@@ -535,34 +593,32 @@ int kvm_arch_qemu_init_env(CPUState *cenv)
     pv_ent->eax = get_para_features(kvm_context);
 #endif
 
-    copy.regs[R_EAX] = 0;
-    qemu_kvm_cpuid_on_env(&copy);
-    limit = copy.regs[R_EAX];
+    limit = copy.cpuid_level;
 
     for (i = 0; i <= limit; ++i) {
-        if (i == 4 || i == 0xb || i == 0xd) {
+        if ( i == 2 || i == 4 || i == 0xb || i == 0xd) {
             for (j = 0; ; ++j) {
                 do_cpuid_ent(&cpuid_ent[cpuid_nent], i, j, &copy);
 
                 cpuid_ent[cpuid_nent].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
                 cpuid_ent[cpuid_nent].index = j;
-
                 cpuid_nent++;
 
-                if (i == 4 && copy.regs[R_EAX] == 0)
+                if (i == 2 && (cpuid_ent[cpuid_nent-1].eax & 0xff) == (j+1)) {
+                    break;
+		}
+                if (i == 4 && (cpuid_ent[cpuid_nent-1].eax & 0x1f) == 0)
                     break;
-                if (i == 0xb && !(copy.regs[R_ECX] & 0xff00))
+                if (i == 0xb && !(cpuid_ent[cpuid_nent-1].ecx & 0xff00))
                     break;
-                if (i == 0xd && copy.regs[R_EAX] == 0)
+                if (i == 0xd && cpuid_ent[cpuid_nent-1].eax == 0)
                     break;
             }
         } else
             do_cpuid_ent(&cpuid_ent[cpuid_nent++], i, 0, &copy);
     }
 
-    copy.regs[R_EAX] = 0x80000000;
-    qemu_kvm_cpuid_on_env(&copy);
-    limit = copy.regs[R_EAX];
+    limit = copy.cpuid_xlevel;
 
     for (i = 0x80000000; i <= limit; ++i)
 	do_cpuid_ent(&cpuid_ent[cpuid_nent++], i, 0, &copy);
diff --git a/qemu/target-i386/cpu.h b/qemu/target-i386/cpu.h
index 944e386..0a0fccf 100644
--- a/qemu/target-i386/cpu.h
+++ b/qemu/target-i386/cpu.h
@@ -628,6 +628,7 @@ typedef struct CPUX86State {
     uint32_t cpuid_ext2_features;
     uint32_t cpuid_ext3_features;
     uint32_t cpuid_apic_id;
+    uint32_t cpuid_host_cpu;
 
 #ifdef USE_KQEMU
     int kqemu_enabled;
diff --git a/qemu/target-i386/helper.c b/qemu/target-i386/helper.c
index cda0390..43de18f 100644
--- a/qemu/target-i386/helper.c
+++ b/qemu/target-i386/helper.c
@@ -119,6 +119,9 @@ typedef struct x86_def_t {
 static x86_def_t x86_defs[] = {
 #ifdef TARGET_X86_64
     {
+        .name = "host",
+    },
+    {
         .name = "qemu64",
         .level = 2,
         .vendor1 = CPUID_VENDOR_AMD_1,
@@ -372,10 +375,57 @@ void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
         (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
 }
 
+static int cpu_host_x86_register (CPUX86State *env)
+{
+    struct kvm_cpuid_entry2 e;
+    env->cpuid_host_cpu = 1;
+
+    get_host_cpuid_entry(0, 0, &e);
+    env->cpuid_level = e.eax;
+    env->cpuid_vendor1 = e.ebx;
+    env->cpuid_vendor2 = e.ecx;
+    env->cpuid_vendor3 = e.edx;
+
+    get_host_cpuid_entry(1, 0, &e);
+    env->cpuid_version = e.eax;
+    env->cpuid_features = e.edx;
+    env->cpuid_ext_features = e.ecx;
+
+    get_host_cpuid_entry(0x80000000, 0, &e);
+    env->cpuid_xlevel = e.eax;
+
+    get_host_cpuid_entry(0x80000001, 0, &e);
+    env->cpuid_ext3_features = e.ecx;
+    env->cpuid_ext2_features = e.edx;
+
+    get_host_cpuid_entry(0x80000002, 0, &e);
+    env->cpuid_model[0] = e.eax;
+    env->cpuid_model[1] = e.ebx;
+    env->cpuid_model[2] = e.ecx;
+    env->cpuid_model[3] = e.edx;
+
+    get_host_cpuid_entry(0x80000003, 0, &e);
+    env->cpuid_model[4] = e.eax;
+    env->cpuid_model[5] = e.ebx;
+    env->cpuid_model[6] = e.ecx;
+    env->cpuid_model[7] = e.edx;
+
+    get_host_cpuid_entry(0x80000004, 0, &e);
+    env->cpuid_model[8] = e.eax;
+    env->cpuid_model[9] = e.ebx;
+    env->cpuid_model[10] = e.ecx;
+    env->cpuid_model[11] = e.edx;
+
+    return 0;
+}
+
 static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
 {
     x86_def_t def1, *def = &def1;
 
+    if (0 == strcmp(cpu_model, "host")) 
+	return cpu_host_x86_register(env);
+
     if (cpu_x86_find_by_name(def, cpu_model) < 0)
         return -1;
     if (def->vendor1) {

  reply	other threads:[~2009-01-30  1:54 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-30  1:12 [kernel patch] exposing host cpuids to guest Nitin A Kamble
2009-01-30  1:54 ` Nitin A Kamble [this message]
2009-01-30 10:57   ` [userspace " Amit Shah
2009-01-30 19:40     ` Nitin A Kamble
2009-01-30 11:25 ` [kernel " Amit Shah
2009-01-30 19:36   ` Nitin A Kamble

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=1233280448.28605.12.camel@mukti.sc.intel.com \
    --to=nitin.a.kamble@intel.com \
    --cc=avi@redhat.com \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

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

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