aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/kvm_main.c
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/kvm/kvm_main.c
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/kvm/kvm_main.c')
-rw-r--r--drivers/kvm/kvm_main.c69
1 files changed, 69 insertions, 0 deletions
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 }