[PATCH] KVM: API versioning
[pandora-kernel.git] / drivers / kvm / kvm_main.c
index b6b8a41..9f24f22 100644 (file)
@@ -72,18 +72,7 @@ static struct dentry *debugfs_dir;
 #define CR8_RESEVED_BITS (~0x0fULL)
 #define EFER_RESERVED_BITS 0xfffffffffffff2fe
 
-struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
-{
-       int i;
-
-       for (i = 0; i < vcpu->nmsrs; ++i)
-               if (vcpu->guest_msrs[i].index == msr)
-                       return &vcpu->guest_msrs[i];
-       return 0;
-}
-EXPORT_SYMBOL_GPL(find_msr_entry);
-
-#ifdef __x86_64__
+#ifdef CONFIG_X86_64
 // LDT or TSS descriptor in the GDT. 16 bytes.
 struct segment_descriptor_64 {
        struct segment_descriptor s;
@@ -115,7 +104,7 @@ unsigned long segment_base(u16 selector)
        }
        d = (struct segment_descriptor *)(table_base + (selector & ~7));
        v = d->base_low | ((ul)d->base_mid << 16) | ((ul)d->base_high << 24);
-#ifdef __x86_64__
+#ifdef CONFIG_X86_64
        if (d->system == 0
            && (d->type == 2 || d->type == 9 || d->type == 11))
                v |= ((ul)((struct segment_descriptor_64 *)d)->base_higher) << 32;
@@ -124,6 +113,11 @@ unsigned long segment_base(u16 selector)
 }
 EXPORT_SYMBOL_GPL(segment_base);
 
+static inline int valid_vcpu(int n)
+{
+       return likely(n >= 0 && n < KVM_MAX_VCPUS);
+}
+
 int kvm_read_guest(struct kvm_vcpu *vcpu,
                             gva_t addr,
                             unsigned long size,
@@ -216,7 +210,6 @@ static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot)
 static void vcpu_put(struct kvm_vcpu *vcpu)
 {
        kvm_arch_ops->vcpu_put(vcpu);
-       put_cpu();
        mutex_unlock(&vcpu->mutex);
 }
 
@@ -351,7 +344,7 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
        }
 
        if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
-#ifdef __x86_64__
+#ifdef CONFIG_X86_64
                if ((vcpu->shadow_efer & EFER_LME)) {
                        int cs_db, cs_l;
 
@@ -506,7 +499,7 @@ static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n)
        struct kvm_vcpu *vcpu;
 
        r = -EINVAL;
-       if (n < 0 || n >= KVM_MAX_VCPUS)
+       if (!valid_vcpu(n))
                goto out;
 
        vcpu = &kvm->vcpus[n];
@@ -1120,12 +1113,10 @@ static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
        return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
 }
 
-#ifdef __x86_64__
+#ifdef CONFIG_X86_64
 
 void set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
-       struct vmx_msr_entry *msr;
-
        if (efer & EFER_RESERVED_BITS) {
                printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n",
                       efer);
@@ -1140,16 +1131,12 @@ void set_efer(struct kvm_vcpu *vcpu, u64 efer)
                return;
        }
 
+       kvm_arch_ops->set_efer(vcpu, efer);
+
        efer &= ~EFER_LMA;
        efer |= vcpu->shadow_efer & EFER_LMA;
 
        vcpu->shadow_efer = efer;
-
-       msr = find_msr_entry(vcpu, MSR_EFER);
-
-       if (!(efer & EFER_LMA))
-           efer &= ~EFER_LME;
-       msr->data = efer;
 }
 EXPORT_SYMBOL_GPL(set_efer);
 
@@ -1197,7 +1184,7 @@ static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run)
        struct kvm_vcpu *vcpu;
        int r;
 
-       if (kvm_run->vcpu < 0 || kvm_run->vcpu >= KVM_MAX_VCPUS)
+       if (!valid_vcpu(kvm_run->vcpu))
                return -EINVAL;
 
        vcpu = vcpu_load(kvm, kvm_run->vcpu);
@@ -1226,7 +1213,7 @@ static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs)
 {
        struct kvm_vcpu *vcpu;
 
-       if (regs->vcpu < 0 || regs->vcpu >= KVM_MAX_VCPUS)
+       if (!valid_vcpu(regs->vcpu))
                return -EINVAL;
 
        vcpu = vcpu_load(kvm, regs->vcpu);
@@ -1243,7 +1230,7 @@ static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs)
        regs->rdi = vcpu->regs[VCPU_REGS_RDI];
        regs->rsp = vcpu->regs[VCPU_REGS_RSP];
        regs->rbp = vcpu->regs[VCPU_REGS_RBP];
-#ifdef __x86_64__
+#ifdef CONFIG_X86_64
        regs->r8 = vcpu->regs[VCPU_REGS_R8];
        regs->r9 = vcpu->regs[VCPU_REGS_R9];
        regs->r10 = vcpu->regs[VCPU_REGS_R10];
@@ -1272,7 +1259,7 @@ static int kvm_dev_ioctl_set_regs(struct kvm *kvm, struct kvm_regs *regs)
 {
        struct kvm_vcpu *vcpu;
 
-       if (regs->vcpu < 0 || regs->vcpu >= KVM_MAX_VCPUS)
+       if (!valid_vcpu(regs->vcpu))
                return -EINVAL;
 
        vcpu = vcpu_load(kvm, regs->vcpu);
@@ -1287,7 +1274,7 @@ static int kvm_dev_ioctl_set_regs(struct kvm *kvm, struct kvm_regs *regs)
        vcpu->regs[VCPU_REGS_RDI] = regs->rdi;
        vcpu->regs[VCPU_REGS_RSP] = regs->rsp;
        vcpu->regs[VCPU_REGS_RBP] = regs->rbp;
-#ifdef __x86_64__
+#ifdef CONFIG_X86_64
        vcpu->regs[VCPU_REGS_R8] = regs->r8;
        vcpu->regs[VCPU_REGS_R9] = regs->r9;
        vcpu->regs[VCPU_REGS_R10] = regs->r10;
@@ -1319,7 +1306,7 @@ static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
        struct kvm_vcpu *vcpu;
        struct descriptor_table dt;
 
-       if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS)
+       if (!valid_vcpu(sregs->vcpu))
                return -EINVAL;
        vcpu = vcpu_load(kvm, sregs->vcpu);
        if (!vcpu)
@@ -1371,7 +1358,7 @@ static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
        int i;
        struct descriptor_table dt;
 
-       if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS)
+       if (!valid_vcpu(sregs->vcpu))
                return -EINVAL;
        vcpu = vcpu_load(kvm, sregs->vcpu);
        if (!vcpu)
@@ -1401,7 +1388,7 @@ static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
        vcpu->cr8 = sregs->cr8;
 
        mmu_reset_needed |= vcpu->shadow_efer != sregs->efer;
-#ifdef __x86_64__
+#ifdef CONFIG_X86_64
        kvm_arch_ops->set_efer(vcpu, sregs->efer);
 #endif
        vcpu->apic_base = sregs->apic_base;
@@ -1430,16 +1417,35 @@ static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
 /*
  * List of msr numbers which we expose to userspace through KVM_GET_MSRS
  * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST.
+ *
+ * This list is modified at module load time to reflect the
+ * capabilities of the host cpu.
  */
 static u32 msrs_to_save[] = {
        MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
        MSR_K6_STAR,
-#ifdef __x86_64__
+#ifdef CONFIG_X86_64
        MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
 #endif
        MSR_IA32_TIME_STAMP_COUNTER,
 };
 
+static unsigned num_msrs_to_save;
+
+static __init void kvm_init_msr_list(void)
+{
+       u32 dummy[2];
+       unsigned i, j;
+
+       for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) {
+               if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0)
+                       continue;
+               if (j < i)
+                       msrs_to_save[j] = msrs_to_save[i];
+               j++;
+       }
+       num_msrs_to_save = j;
+}
 
 /*
  * Adapt set_msr() to msr_io()'s calling convention
@@ -1462,7 +1468,7 @@ static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs,
        struct kvm_vcpu *vcpu;
        int i;
 
-       if (msrs->vcpu < 0 || msrs->vcpu >= KVM_MAX_VCPUS)
+       if (!valid_vcpu(msrs->vcpu))
                return -EINVAL;
 
        vcpu = vcpu_load(kvm, msrs->vcpu);
@@ -1555,7 +1561,7 @@ static int kvm_dev_ioctl_interrupt(struct kvm *kvm, struct kvm_interrupt *irq)
 {
        struct kvm_vcpu *vcpu;
 
-       if (irq->vcpu < 0 || irq->vcpu >= KVM_MAX_VCPUS)
+       if (!valid_vcpu(irq->vcpu))
                return -EINVAL;
        if (irq->irq < 0 || irq->irq >= 256)
                return -EINVAL;
@@ -1577,7 +1583,7 @@ static int kvm_dev_ioctl_debug_guest(struct kvm *kvm,
        struct kvm_vcpu *vcpu;
        int r;
 
-       if (dbg->vcpu < 0 || dbg->vcpu >= KVM_MAX_VCPUS)
+       if (!valid_vcpu(dbg->vcpu))
                return -EINVAL;
        vcpu = vcpu_load(kvm, dbg->vcpu);
        if (!vcpu)
@@ -1597,6 +1603,9 @@ static long kvm_dev_ioctl(struct file *filp,
        int r = -EINVAL;
 
        switch (ioctl) {
+       case KVM_GET_API_VERSION:
+               r = KVM_API_VERSION;
+               break;
        case KVM_CREATE_VCPU: {
                r = kvm_dev_ioctl_create_vcpu(kvm, arg);
                if (r)
@@ -1748,15 +1757,15 @@ static long kvm_dev_ioctl(struct file *filp,
                if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list))
                        goto out;
                n = msr_list.nmsrs;
-               msr_list.nmsrs = ARRAY_SIZE(msrs_to_save);
+               msr_list.nmsrs = num_msrs_to_save;
                if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list))
                        goto out;
                r = -E2BIG;
-               if (n < ARRAY_SIZE(msrs_to_save))
+               if (n < num_msrs_to_save)
                        goto out;
                r = -EFAULT;
                if (copy_to_user(user_msr_list->indices, &msrs_to_save,
-                                sizeof msrs_to_save))
+                                num_msrs_to_save * sizeof(u32)))
                        goto out;
                r = 0;
        }
@@ -1907,6 +1916,8 @@ static __init int kvm_init(void)
 
        kvm_init_debug();
 
+       kvm_init_msr_list();
+
        if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) {
                r = -ENOMEM;
                goto out;