kvm: Extract CPUID code into its own file

Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
This commit is contained in:
Pekka Enberg
2010-03-31 20:59:54 +03:00
committed by Will Deacon
parent 4837de1f00
commit a1fe6bc58d
5 changed files with 210 additions and 201 deletions
+1
View File
@@ -1,6 +1,7 @@
PROGRAM = kvm
OBJS += cpu.o
OBJS += cpuid.o
OBJS += interrupt.o
OBJS += kvm.o
OBJS += main.o
+206
View File
@@ -0,0 +1,206 @@
#include "kvm/kvm.h"
#include "kvm/util.h"
#include <sys/ioctl.h>
#include <stdlib.h>
#include <assert.h>
struct cpuid_regs {
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
};
static inline void
cpuid(struct cpuid_regs *regs)
{
asm("cpuid"
: "=a" (regs->eax),
"=b" (regs->ebx),
"=c" (regs->ecx),
"=d" (regs->edx)
: "0" (regs->eax), "2" (regs->ecx));
}
static struct kvm_cpuid2 *kvm_cpuid__new(unsigned long nent)
{
struct kvm_cpuid2 *self;
self = calloc(1, sizeof(*self) + (sizeof(struct kvm_cpuid_entry2) * nent));
if (!self)
die("out of memory");
return self;
}
static void kvm_cpuid__delete(struct kvm_cpuid2 *self)
{
free(self);
}
#define MAX_KVM_CPUID_ENTRIES 100
enum {
CPUID_GET_VENDOR_ID = 0x00,
CPUID_GET_HIGHEST_EXT_FUNCTION = 0x80000000,
};
static uint32_t cpuid_highest_ext_func(void)
{
struct cpuid_regs regs;
regs = (struct cpuid_regs) {
.eax = CPUID_GET_HIGHEST_EXT_FUNCTION,
};
cpuid(&regs);
return regs.eax;
}
static uint32_t cpuid_highest_func(void)
{
struct cpuid_regs regs;
regs = (struct cpuid_regs) {
.eax = CPUID_GET_VENDOR_ID,
};
cpuid(&regs);
return regs.eax;
}
void kvm__setup_cpuid(struct kvm *self)
{
struct kvm_cpuid2 *kvm_cpuid;
uint32_t highest_ext;
uint32_t function;
uint32_t highest;
uint32_t ndx = 0;
kvm_cpuid = kvm_cpuid__new(MAX_KVM_CPUID_ENTRIES);
highest = cpuid_highest_func();
for (function = 0; function < highest; function++) {
/*
* NOTE NOTE NOTE! Functions 0x0b and 0x0d seem to need special
* treatment as per qemu sources but we treat them as regular
* CPUID functions here because they are fairly exotic and the
* Linux kernel is not interested in them during boot up.
*/
switch (function) {
case 0x02: { /* Processor configuration descriptor */
struct cpuid_regs regs;
uint32_t times;
regs = (struct cpuid_regs) {
.eax = function,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = 0,
.flags = KVM_CPUID_FLAG_STATEFUL_FUNC | KVM_CPUID_FLAG_STATE_READ_NEXT,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
times = regs.eax & 0xff; /* AL */
while (times-- > 0) {
regs = (struct cpuid_regs) {
.eax = function,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = 0,
.flags = KVM_CPUID_FLAG_STATEFUL_FUNC,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
}
break;
}
case 0x04: {
uint32_t index;
for (index = 0; index < 2; index++) {
struct cpuid_regs regs = {
.eax = function,
.ecx = index,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = index,
.flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
}
break;
}
default: {
struct cpuid_regs regs;
regs = (struct cpuid_regs) {
.eax = function,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = 0,
.flags = 0,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
break;
}};
}
highest_ext = cpuid_highest_ext_func();
for (function = CPUID_GET_HIGHEST_EXT_FUNCTION; function < highest_ext; function++) {
struct cpuid_regs regs;
regs = (struct cpuid_regs) {
.eax = function,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = 0,
.flags = 0,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
}
assert(ndx < MAX_KVM_CPUID_ENTRIES);
kvm_cpuid->nent = ndx;
if (ioctl(self->vcpu_fd, KVM_SET_CPUID2, kvm_cpuid) < 0)
die_perror("KVM_SET_CPUID2 failed");
kvm_cpuid__delete(kvm_cpuid);
}
+1
View File
@@ -28,6 +28,7 @@ struct kvm {
};
struct kvm *kvm__init(void);
void kvm__setup_cpuid(struct kvm *self);
void kvm__enable_singlestep(struct kvm *self);
bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename, const char *kernel_cmdline);
void kvm__reset_vcpu(struct kvm *self);
-201
View File
@@ -311,209 +311,8 @@ static inline uint32_t selector_to_base(uint16_t selector)
return (uint32_t)selector * 16;
}
struct cpuid_regs {
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
};
static inline void
cpuid(struct cpuid_regs *regs)
{
asm("cpuid"
: "=a" (regs->eax),
"=b" (regs->ebx),
"=c" (regs->ecx),
"=d" (regs->edx)
: "0" (regs->eax), "2" (regs->ecx));
}
static struct kvm_cpuid2 *kvm_cpuid__new(unsigned long nent)
{
struct kvm_cpuid2 *self;
self = calloc(1, sizeof(*self) + (sizeof(struct kvm_cpuid_entry2) * nent));
if (!self)
die("out of memory");
return self;
}
static void kvm_cpuid__delete(struct kvm_cpuid2 *self)
{
free(self);
}
#define MAX_KVM_CPUID_ENTRIES 100
enum {
CPUID_GET_VENDOR_ID = 0x00,
CPUID_GET_HIGHEST_EXT_FUNCTION = 0x80000000,
};
static uint32_t cpuid_highest_ext_func(void)
{
struct cpuid_regs regs;
regs = (struct cpuid_regs) {
.eax = CPUID_GET_HIGHEST_EXT_FUNCTION,
};
cpuid(&regs);
return regs.eax;
}
static uint32_t cpuid_highest_func(void)
{
struct cpuid_regs regs;
regs = (struct cpuid_regs) {
.eax = CPUID_GET_VENDOR_ID,
};
cpuid(&regs);
return regs.eax;
}
static void setup_cpuid(struct kvm *self)
{
struct kvm_cpuid2 *kvm_cpuid;
uint32_t highest_ext;
uint32_t function;
uint32_t highest;
uint32_t ndx = 0;
kvm_cpuid = kvm_cpuid__new(MAX_KVM_CPUID_ENTRIES);
highest = cpuid_highest_func();
for (function = 0; function < highest; function++) {
/*
* NOTE NOTE NOTE! Functions 0x0b and 0x0d seem to need special
* treatment as per qemu sources but we treat them as regular
* CPUID functions here because they are fairly exotic and the
* Linux kernel is not interested in them during boot up.
*/
switch (function) {
case 0x02: { /* Processor configuration descriptor */
struct cpuid_regs regs;
uint32_t times;
regs = (struct cpuid_regs) {
.eax = function,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = 0,
.flags = KVM_CPUID_FLAG_STATEFUL_FUNC | KVM_CPUID_FLAG_STATE_READ_NEXT,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
times = regs.eax & 0xff; /* AL */
while (times-- > 0) {
regs = (struct cpuid_regs) {
.eax = function,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = 0,
.flags = KVM_CPUID_FLAG_STATEFUL_FUNC,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
}
break;
}
case 0x04: {
uint32_t index;
for (index = 0; index < 2; index++) {
struct cpuid_regs regs = {
.eax = function,
.ecx = index,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = index,
.flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
}
break;
}
default: {
struct cpuid_regs regs;
regs = (struct cpuid_regs) {
.eax = function,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = 0,
.flags = 0,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
break;
}};
}
highest_ext = cpuid_highest_ext_func();
for (function = CPUID_GET_HIGHEST_EXT_FUNCTION; function < highest_ext; function++) {
struct cpuid_regs regs;
regs = (struct cpuid_regs) {
.eax = function,
};
cpuid(&regs);
kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) {
.function = function,
.index = 0,
.flags = 0,
.eax = regs.eax,
.ebx = regs.ebx,
.ecx = regs.ecx,
.edx = regs.edx,
};
}
assert(ndx < MAX_KVM_CPUID_ENTRIES);
kvm_cpuid->nent = ndx;
if (ioctl(self->vcpu_fd, KVM_SET_CPUID2, kvm_cpuid) < 0)
die_perror("KVM_SET_CPUID2 failed");
kvm_cpuid__delete(kvm_cpuid);
}
void kvm__reset_vcpu(struct kvm *self)
{
setup_cpuid(self);
self->sregs = (struct kvm_sregs) {
.cr0 = 0x60000010ULL,
.cs = (struct kvm_segment) {
+2
View File
@@ -48,6 +48,8 @@ int main(int argc, char *argv[])
kvm = kvm__init();
kvm__setup_cpuid(kvm);
if (!kvm__load_kernel(kvm, kernel_filename, kernel_cmdline))
die("unable to load kernel %s", kernel_filename);