aboutsummaryrefslogtreecommitdiff
path: root/drivers/kvm/kvm_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r--drivers/kvm/kvm_main.c151
1 files changed, 130 insertions, 21 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index fd1bb870545..ce7fe640f18 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -113,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,
@@ -240,7 +245,8 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
if (!dont || free->phys_mem != dont->phys_mem)
if (free->phys_mem) {
for (i = 0; i < free->npages; ++i)
- __free_page(free->phys_mem[i]);
+ if (free->phys_mem[i])
+ __free_page(free->phys_mem[i]);
vfree(free->phys_mem);
}
@@ -393,7 +399,7 @@ void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
return;
}
- if (kvm_arch_ops->is_long_mode(vcpu)) {
+ if (is_long_mode(vcpu)) {
if (!(cr4 & CR4_PAE_MASK)) {
printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
"in long mode\n");
@@ -420,7 +426,7 @@ EXPORT_SYMBOL_GPL(set_cr4);
void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
- if (kvm_arch_ops->is_long_mode(vcpu)) {
+ if (is_long_mode(vcpu)) {
if ( cr3 & CR3_L_MODE_RESEVED_BITS) {
printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
inject_gp(vcpu);
@@ -494,7 +500,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];
@@ -516,12 +522,14 @@ static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n)
if (r < 0)
goto out_free_vcpus;
- kvm_arch_ops->vcpu_load(vcpu);
+ r = kvm_mmu_create(vcpu);
+ if (r < 0)
+ goto out_free_vcpus;
- r = kvm_arch_ops->vcpu_setup(vcpu);
+ kvm_arch_ops->vcpu_load(vcpu);
+ r = kvm_mmu_setup(vcpu);
if (r >= 0)
- r = kvm_mmu_init(vcpu);
-
+ r = kvm_arch_ops->vcpu_setup(vcpu);
vcpu_put(vcpu);
if (r < 0)
@@ -1098,6 +1106,51 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
}
}
+int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
+{
+ u64 data;
+
+ switch (msr) {
+ case 0xc0010010: /* SYSCFG */
+ case 0xc0010015: /* HWCR */
+ case MSR_IA32_PLATFORM_ID:
+ case MSR_IA32_P5_MC_ADDR:
+ case MSR_IA32_P5_MC_TYPE:
+ case MSR_IA32_MC0_CTL:
+ case MSR_IA32_MCG_STATUS:
+ case MSR_IA32_MCG_CAP:
+ case MSR_IA32_MC0_MISC:
+ case MSR_IA32_MC0_MISC+4:
+ case MSR_IA32_MC0_MISC+8:
+ case MSR_IA32_MC0_MISC+12:
+ case MSR_IA32_MC0_MISC+16:
+ case MSR_IA32_UCODE_REV:
+ case MSR_IA32_PERF_STATUS:
+ /* MTRR registers */
+ case 0xfe:
+ case 0x200 ... 0x2ff:
+ data = 0;
+ break;
+ case 0xcd: /* fsb frequency */
+ data = 3;
+ break;
+ case MSR_IA32_APICBASE:
+ data = vcpu->apic_base;
+ break;
+#ifdef CONFIG_X86_64
+ case MSR_EFER:
+ data = vcpu->shadow_efer;
+ break;
+#endif
+ default:
+ printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", msr);
+ return 1;
+ }
+ *pdata = data;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_get_msr_common);
+
/*
* Reads an msr value (of 'msr_index') into 'pdata'.
* Returns 0 on success, non-0 otherwise.
@@ -1110,7 +1163,7 @@ static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
#ifdef CONFIG_X86_64
-void set_efer(struct kvm_vcpu *vcpu, u64 efer)
+static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
if (efer & EFER_RESERVED_BITS) {
printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n",
@@ -1133,10 +1186,36 @@ void set_efer(struct kvm_vcpu *vcpu, u64 efer)
vcpu->shadow_efer = efer;
}
-EXPORT_SYMBOL_GPL(set_efer);
#endif
+int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+ switch (msr) {
+#ifdef CONFIG_X86_64
+ case MSR_EFER:
+ set_efer(vcpu, data);
+ break;
+#endif
+ case MSR_IA32_MC0_STATUS:
+ printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
+ __FUNCTION__, data);
+ break;
+ case MSR_IA32_UCODE_REV:
+ case MSR_IA32_UCODE_WRITE:
+ case 0x200 ... 0x2ff: /* MTRRs */
+ break;
+ case MSR_IA32_APICBASE:
+ vcpu->apic_base = data;
+ break;
+ default:
+ printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr);
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_set_msr_common);
+
/*
* Writes msr value into into the appropriate "register".
* Returns 0 on success, non-0 otherwise.
@@ -1179,7 +1258,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);
@@ -1208,7 +1287,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);
@@ -1254,7 +1333,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);
@@ -1301,7 +1380,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)
@@ -1353,7 +1432,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)
@@ -1412,6 +1491,9 @@ 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,
@@ -1422,6 +1504,22 @@ static u32 msrs_to_save[] = {
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
@@ -1444,7 +1542,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);
@@ -1537,7 +1635,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;
@@ -1559,7 +1657,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)
@@ -1579,6 +1677,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)
@@ -1730,15 +1831,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;
}
@@ -1838,6 +1939,11 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
{
int r;
+ if (kvm_arch_ops) {
+ printk(KERN_ERR "kvm: already loaded the other module\n");
+ return -EEXIST;
+ }
+
kvm_arch_ops = ops;
if (!kvm_arch_ops->cpu_has_kvm_support()) {
@@ -1880,6 +1986,7 @@ void kvm_exit_arch(void)
unregister_reboot_notifier(&kvm_reboot_notifier);
on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
kvm_arch_ops->hardware_unsetup();
+ kvm_arch_ops = NULL;
}
static __init int kvm_init(void)
@@ -1889,6 +1996,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;