diff options
-rw-r--r-- | drivers/kvm/Makefile | 2 | ||||
-rw-r--r-- | drivers/kvm/kvm.h | 4 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 69 | ||||
-rw-r--r-- | drivers/kvm/x86.c | 102 | ||||
-rw-r--r-- | drivers/kvm/x86.h | 16 |
5 files changed, 126 insertions, 67 deletions
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile index e5a8f4d3e973..cf18ad46e987 100644 --- a/drivers/kvm/Makefile +++ b/drivers/kvm/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for Kernel-based Virtual Machine module | 2 | # Makefile for Kernel-based Virtual Machine module |
3 | # | 3 | # |
4 | 4 | ||
5 | kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o lapic.o ioapic.o | 5 | kvm-objs := kvm_main.o x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o ioapic.o |
6 | obj-$(CONFIG_KVM) += kvm.o | 6 | obj-$(CONFIG_KVM) += kvm.o |
7 | kvm-intel-objs = vmx.o | 7 | kvm-intel-objs = vmx.o |
8 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o | 8 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o |
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 3eaed4dafec7..9c9c1d7f5b30 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -653,6 +653,10 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); | |||
653 | 653 | ||
654 | int kvm_fix_hypercall(struct kvm_vcpu *vcpu); | 654 | int kvm_fix_hypercall(struct kvm_vcpu *vcpu); |
655 | 655 | ||
656 | long kvm_arch_dev_ioctl(struct file *filp, | ||
657 | unsigned int ioctl, unsigned long arg); | ||
658 | __init void kvm_arch_init(void); | ||
659 | |||
656 | static inline void kvm_guest_enter(void) | 660 | static inline void kvm_guest_enter(void) |
657 | { | 661 | { |
658 | current->flags |= PF_VCPU; | 662 | current->flags |= PF_VCPU; |
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 22b143feb66d..ec696887b222 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -16,6 +16,7 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include "kvm.h" | 18 | #include "kvm.h" |
19 | #include "x86.h" | ||
19 | #include "x86_emulate.h" | 20 | #include "x86_emulate.h" |
20 | #include "segment_descriptor.h" | 21 | #include "segment_descriptor.h" |
21 | #include "irq.h" | 22 | #include "irq.h" |
@@ -2508,43 +2509,6 @@ void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) | |||
2508 | EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits); | 2509 | EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits); |
2509 | 2510 | ||
2510 | /* | 2511 | /* |
2511 | * List of msr numbers which we expose to userspace through KVM_GET_MSRS | ||
2512 | * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. | ||
2513 | * | ||
2514 | * This list is modified at module load time to reflect the | ||
2515 | * capabilities of the host cpu. | ||
2516 | */ | ||
2517 | static u32 msrs_to_save[] = { | ||
2518 | MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, | ||
2519 | MSR_K6_STAR, | ||
2520 | #ifdef CONFIG_X86_64 | ||
2521 | MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, | ||
2522 | #endif | ||
2523 | MSR_IA32_TIME_STAMP_COUNTER, | ||
2524 | }; | ||
2525 | |||
2526 | static unsigned num_msrs_to_save; | ||
2527 | |||
2528 | static u32 emulated_msrs[] = { | ||
2529 | MSR_IA32_MISC_ENABLE, | ||
2530 | }; | ||
2531 | |||
2532 | static __init void kvm_init_msr_list(void) | ||
2533 | { | ||
2534 | u32 dummy[2]; | ||
2535 | unsigned i, j; | ||
2536 | |||
2537 | for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) { | ||
2538 | if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0) | ||
2539 | continue; | ||
2540 | if (j < i) | ||
2541 | msrs_to_save[j] = msrs_to_save[i]; | ||
2542 | j++; | ||
2543 | } | ||
2544 | num_msrs_to_save = j; | ||
2545 | } | ||
2546 | |||
2547 | /* | ||
2548 | * Adapt set_msr() to msr_io()'s calling convention | 2512 | * Adapt set_msr() to msr_io()'s calling convention |
2549 | */ | 2513 | */ |
2550 | static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) | 2514 | static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) |
@@ -3356,33 +3320,6 @@ static long kvm_dev_ioctl(struct file *filp, | |||
3356 | goto out; | 3320 | goto out; |
3357 | r = kvm_dev_ioctl_create_vm(); | 3321 | r = kvm_dev_ioctl_create_vm(); |
3358 | break; | 3322 | break; |
3359 | case KVM_GET_MSR_INDEX_LIST: { | ||
3360 | struct kvm_msr_list __user *user_msr_list = argp; | ||
3361 | struct kvm_msr_list msr_list; | ||
3362 | unsigned n; | ||
3363 | |||
3364 | r = -EFAULT; | ||
3365 | if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list)) | ||
3366 | goto out; | ||
3367 | n = msr_list.nmsrs; | ||
3368 | msr_list.nmsrs = num_msrs_to_save + ARRAY_SIZE(emulated_msrs); | ||
3369 | if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list)) | ||
3370 | goto out; | ||
3371 | r = -E2BIG; | ||
3372 | if (n < num_msrs_to_save) | ||
3373 | goto out; | ||
3374 | r = -EFAULT; | ||
3375 | if (copy_to_user(user_msr_list->indices, &msrs_to_save, | ||
3376 | num_msrs_to_save * sizeof(u32))) | ||
3377 | goto out; | ||
3378 | if (copy_to_user(user_msr_list->indices | ||
3379 | + num_msrs_to_save * sizeof(u32), | ||
3380 | &emulated_msrs, | ||
3381 | ARRAY_SIZE(emulated_msrs) * sizeof(u32))) | ||
3382 | goto out; | ||
3383 | r = 0; | ||
3384 | break; | ||
3385 | } | ||
3386 | case KVM_CHECK_EXTENSION: { | 3323 | case KVM_CHECK_EXTENSION: { |
3387 | int ext = (long)argp; | 3324 | int ext = (long)argp; |
3388 | 3325 | ||
@@ -3406,7 +3343,7 @@ static long kvm_dev_ioctl(struct file *filp, | |||
3406 | r = 2 * PAGE_SIZE; | 3343 | r = 2 * PAGE_SIZE; |
3407 | break; | 3344 | break; |
3408 | default: | 3345 | default: |
3409 | ; | 3346 | return kvm_arch_dev_ioctl(filp, ioctl, arg); |
3410 | } | 3347 | } |
3411 | out: | 3348 | out: |
3412 | return r; | 3349 | return r; |
@@ -3770,7 +3707,7 @@ static __init int kvm_init(void) | |||
3770 | 3707 | ||
3771 | kvm_init_debug(); | 3708 | kvm_init_debug(); |
3772 | 3709 | ||
3773 | kvm_init_msr_list(); | 3710 | kvm_arch_init(); |
3774 | 3711 | ||
3775 | bad_page = alloc_page(GFP_KERNEL); | 3712 | bad_page = alloc_page(GFP_KERNEL); |
3776 | 3713 | ||
diff --git a/drivers/kvm/x86.c b/drivers/kvm/x86.c new file mode 100644 index 000000000000..437902cf178d --- /dev/null +++ b/drivers/kvm/x86.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * Kernel-based Virtual Machine driver for Linux | ||
3 | * | ||
4 | * derived from drivers/kvm/kvm_main.c | ||
5 | * | ||
6 | * Copyright (C) 2006 Qumranet, Inc. | ||
7 | * | ||
8 | * Authors: | ||
9 | * Avi Kivity <avi@qumranet.com> | ||
10 | * Yaniv Kamay <yaniv@qumranet.com> | ||
11 | * | ||
12 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
13 | * the COPYING file in the top-level directory. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include "x86.h" | ||
18 | |||
19 | #include <asm/uaccess.h> | ||
20 | |||
21 | /* | ||
22 | * List of msr numbers which we expose to userspace through KVM_GET_MSRS | ||
23 | * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. | ||
24 | * | ||
25 | * This list is modified at module load time to reflect the | ||
26 | * capabilities of the host cpu. | ||
27 | */ | ||
28 | static u32 msrs_to_save[] = { | ||
29 | MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, | ||
30 | MSR_K6_STAR, | ||
31 | #ifdef CONFIG_X86_64 | ||
32 | MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, | ||
33 | #endif | ||
34 | MSR_IA32_TIME_STAMP_COUNTER, | ||
35 | }; | ||
36 | |||
37 | static unsigned num_msrs_to_save; | ||
38 | |||
39 | static u32 emulated_msrs[] = { | ||
40 | MSR_IA32_MISC_ENABLE, | ||
41 | }; | ||
42 | |||
43 | long kvm_arch_dev_ioctl(struct file *filp, | ||
44 | unsigned int ioctl, unsigned long arg) | ||
45 | { | ||
46 | void __user *argp = (void __user *)arg; | ||
47 | long r; | ||
48 | |||
49 | switch (ioctl) { | ||
50 | case KVM_GET_MSR_INDEX_LIST: { | ||
51 | struct kvm_msr_list __user *user_msr_list = argp; | ||
52 | struct kvm_msr_list msr_list; | ||
53 | unsigned n; | ||
54 | |||
55 | r = -EFAULT; | ||
56 | if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list)) | ||
57 | goto out; | ||
58 | n = msr_list.nmsrs; | ||
59 | msr_list.nmsrs = num_msrs_to_save + ARRAY_SIZE(emulated_msrs); | ||
60 | if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list)) | ||
61 | goto out; | ||
62 | r = -E2BIG; | ||
63 | if (n < num_msrs_to_save) | ||
64 | goto out; | ||
65 | r = -EFAULT; | ||
66 | if (copy_to_user(user_msr_list->indices, &msrs_to_save, | ||
67 | num_msrs_to_save * sizeof(u32))) | ||
68 | goto out; | ||
69 | if (copy_to_user(user_msr_list->indices | ||
70 | + num_msrs_to_save * sizeof(u32), | ||
71 | &emulated_msrs, | ||
72 | ARRAY_SIZE(emulated_msrs) * sizeof(u32))) | ||
73 | goto out; | ||
74 | r = 0; | ||
75 | break; | ||
76 | } | ||
77 | default: | ||
78 | r = -EINVAL; | ||
79 | } | ||
80 | out: | ||
81 | return r; | ||
82 | } | ||
83 | |||
84 | static __init void kvm_init_msr_list(void) | ||
85 | { | ||
86 | u32 dummy[2]; | ||
87 | unsigned i, j; | ||
88 | |||
89 | for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) { | ||
90 | if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0) | ||
91 | continue; | ||
92 | if (j < i) | ||
93 | msrs_to_save[j] = msrs_to_save[i]; | ||
94 | j++; | ||
95 | } | ||
96 | num_msrs_to_save = j; | ||
97 | } | ||
98 | |||
99 | __init void kvm_arch_init(void) | ||
100 | { | ||
101 | kvm_init_msr_list(); | ||
102 | } | ||
diff --git a/drivers/kvm/x86.h b/drivers/kvm/x86.h new file mode 100644 index 000000000000..1e2f71bd805d --- /dev/null +++ b/drivers/kvm/x86.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #/* | ||
2 | * Kernel-based Virtual Machine driver for Linux | ||
3 | * | ||
4 | * This header defines architecture specific interfaces, x86 version | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
7 | * the COPYING file in the top-level directory. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #ifndef KVM_X86_H | ||
12 | #define KVM_X86_H | ||
13 | |||
14 | #include "kvm.h" | ||
15 | |||
16 | #endif | ||