aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-02-28 13:46:53 -0500
committerAvi Kivity <avi@qumranet.com>2007-05-03 03:52:23 -0400
commit06465c5a3aa9948a7b00af49cd22ed8f235cdb0f (patch)
tree2a21941ae6f28445abbb3cc80dd3416cf2241b8d /drivers
parent46fc1477887c41c8e900f2c95485e222b9a54822 (diff)
KVM: Handle cpuid in the kernel instead of punting to userspace
KVM used to handle cpuid by letting userspace decide what values to return to the guest. We now handle cpuid completely in the kernel. We still let userspace decide which values the guest will see by having userspace set up the value table beforehand (this is necessary to allow management software to set the cpu features to the least common denominator, so that live migration can work). The motivation for the change is that kvm kernel code can be impacted by cpuid features, for example the x86 emulator. Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/kvm/kvm.h5
-rw-r--r--drivers/kvm/kvm_main.c69
-rw-r--r--drivers/kvm/svm.c4
-rw-r--r--drivers/kvm/vmx.c4
4 files changed, 78 insertions, 4 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 59cbc5b1d905..be3a0e7ecae4 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -55,6 +55,7 @@
55#define KVM_NUM_MMU_PAGES 256 55#define KVM_NUM_MMU_PAGES 256
56#define KVM_MIN_FREE_MMU_PAGES 5 56#define KVM_MIN_FREE_MMU_PAGES 5
57#define KVM_REFILL_PAGES 25 57#define KVM_REFILL_PAGES 25
58#define KVM_MAX_CPUID_ENTRIES 40
58 59
59#define FX_IMAGE_SIZE 512 60#define FX_IMAGE_SIZE 512
60#define FX_IMAGE_ALIGN 16 61#define FX_IMAGE_ALIGN 16
@@ -286,6 +287,9 @@ struct kvm_vcpu {
286 u32 ar; 287 u32 ar;
287 } tr, es, ds, fs, gs; 288 } tr, es, ds, fs, gs;
288 } rmode; 289 } rmode;
290
291 int cpuid_nent;
292 struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES];
289}; 293};
290 294
291struct kvm_memory_slot { 295struct kvm_memory_slot {
@@ -446,6 +450,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
446 450
447struct x86_emulate_ctxt; 451struct x86_emulate_ctxt;
448 452
453void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
449int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); 454int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
450int emulate_clts(struct kvm_vcpu *vcpu); 455int emulate_clts(struct kvm_vcpu *vcpu);
451int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, 456int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr,
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index ff8bcfee76e5..caec54fbf07f 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -1504,6 +1504,43 @@ void save_msrs(struct vmx_msr_entry *e, int n)
1504} 1504}
1505EXPORT_SYMBOL_GPL(save_msrs); 1505EXPORT_SYMBOL_GPL(save_msrs);
1506 1506
1507void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
1508{
1509 int i;
1510 u32 function;
1511 struct kvm_cpuid_entry *e, *best;
1512
1513 kvm_arch_ops->cache_regs(vcpu);
1514 function = vcpu->regs[VCPU_REGS_RAX];
1515 vcpu->regs[VCPU_REGS_RAX] = 0;
1516 vcpu->regs[VCPU_REGS_RBX] = 0;
1517 vcpu->regs[VCPU_REGS_RCX] = 0;
1518 vcpu->regs[VCPU_REGS_RDX] = 0;
1519 best = NULL;
1520 for (i = 0; i < vcpu->cpuid_nent; ++i) {
1521 e = &vcpu->cpuid_entries[i];
1522 if (e->function == function) {
1523 best = e;
1524 break;
1525 }
1526 /*
1527 * Both basic or both extended?
1528 */
1529 if (((e->function ^ function) & 0x80000000) == 0)
1530 if (!best || e->function > best->function)
1531 best = e;
1532 }
1533 if (best) {
1534 vcpu->regs[VCPU_REGS_RAX] = best->eax;
1535 vcpu->regs[VCPU_REGS_RBX] = best->ebx;
1536 vcpu->regs[VCPU_REGS_RCX] = best->ecx;
1537 vcpu->regs[VCPU_REGS_RDX] = best->edx;
1538 }
1539 kvm_arch_ops->decache_regs(vcpu);
1540 kvm_arch_ops->skip_emulated_instruction(vcpu);
1541}
1542EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
1543
1507static void complete_pio(struct kvm_vcpu *vcpu) 1544static void complete_pio(struct kvm_vcpu *vcpu)
1508{ 1545{
1509 struct kvm_io *io = &vcpu->run->io; 1546 struct kvm_io *io = &vcpu->run->io;
@@ -2075,6 +2112,26 @@ out:
2075 return r; 2112 return r;
2076} 2113}
2077 2114
2115static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
2116 struct kvm_cpuid *cpuid,
2117 struct kvm_cpuid_entry __user *entries)
2118{
2119 int r;
2120
2121 r = -E2BIG;
2122 if (cpuid->nent > KVM_MAX_CPUID_ENTRIES)
2123 goto out;
2124 r = -EFAULT;
2125 if (copy_from_user(&vcpu->cpuid_entries, entries,
2126 cpuid->nent * sizeof(struct kvm_cpuid_entry)))
2127 goto out;
2128 vcpu->cpuid_nent = cpuid->nent;
2129 return 0;
2130
2131out:
2132 return r;
2133}
2134
2078static long kvm_vcpu_ioctl(struct file *filp, 2135static long kvm_vcpu_ioctl(struct file *filp,
2079 unsigned int ioctl, unsigned long arg) 2136 unsigned int ioctl, unsigned long arg)
2080{ 2137{
@@ -2181,6 +2238,18 @@ static long kvm_vcpu_ioctl(struct file *filp,
2181 case KVM_SET_MSRS: 2238 case KVM_SET_MSRS:
2182 r = msr_io(vcpu, argp, do_set_msr, 0); 2239 r = msr_io(vcpu, argp, do_set_msr, 0);
2183 break; 2240 break;
2241 case KVM_SET_CPUID: {
2242 struct kvm_cpuid __user *cpuid_arg = argp;
2243 struct kvm_cpuid cpuid;
2244
2245 r = -EFAULT;
2246 if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid))
2247 goto out;
2248 r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries);
2249 if (r)
2250 goto out;
2251 break;
2252 }
2184 default: 2253 default:
2185 ; 2254 ;
2186 } 2255 }
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index c35b8c83bf3f..d4b2936479d9 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -1101,8 +1101,8 @@ static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_r
1101static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 1101static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1102{ 1102{
1103 vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; 1103 vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
1104 kvm_run->exit_reason = KVM_EXIT_CPUID; 1104 kvm_emulate_cpuid(vcpu);
1105 return 0; 1105 return 1;
1106} 1106}
1107 1107
1108static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 1108static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 4d5f40fcb651..71410a65bb90 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -1585,8 +1585,8 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1585 1585
1586static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 1586static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1587{ 1587{
1588 kvm_run->exit_reason = KVM_EXIT_CPUID; 1588 kvm_emulate_cpuid(vcpu);
1589 return 0; 1589 return 1;
1590} 1590}
1591 1591
1592static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 1592static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)