diff options
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r-- | arch/x86/kvm/vmx.c | 57 |
1 files changed, 43 insertions, 14 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index b20c9e47e925..b5eae7a00aad 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -113,7 +113,8 @@ static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu); | |||
113 | 113 | ||
114 | static unsigned long *vmx_io_bitmap_a; | 114 | static unsigned long *vmx_io_bitmap_a; |
115 | static unsigned long *vmx_io_bitmap_b; | 115 | static unsigned long *vmx_io_bitmap_b; |
116 | static unsigned long *vmx_msr_bitmap; | 116 | static unsigned long *vmx_msr_bitmap_legacy; |
117 | static unsigned long *vmx_msr_bitmap_longmode; | ||
117 | 118 | ||
118 | static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS); | 119 | static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS); |
119 | static DEFINE_SPINLOCK(vmx_vpid_lock); | 120 | static DEFINE_SPINLOCK(vmx_vpid_lock); |
@@ -812,6 +813,7 @@ static void move_msr_up(struct vcpu_vmx *vmx, int from, int to) | |||
812 | static void setup_msrs(struct vcpu_vmx *vmx) | 813 | static void setup_msrs(struct vcpu_vmx *vmx) |
813 | { | 814 | { |
814 | int save_nmsrs; | 815 | int save_nmsrs; |
816 | unsigned long *msr_bitmap; | ||
815 | 817 | ||
816 | vmx_load_host_state(vmx); | 818 | vmx_load_host_state(vmx); |
817 | save_nmsrs = 0; | 819 | save_nmsrs = 0; |
@@ -847,6 +849,15 @@ static void setup_msrs(struct vcpu_vmx *vmx) | |||
847 | __find_msr_index(vmx, MSR_KERNEL_GS_BASE); | 849 | __find_msr_index(vmx, MSR_KERNEL_GS_BASE); |
848 | #endif | 850 | #endif |
849 | vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER); | 851 | vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER); |
852 | |||
853 | if (cpu_has_vmx_msr_bitmap()) { | ||
854 | if (is_long_mode(&vmx->vcpu)) | ||
855 | msr_bitmap = vmx_msr_bitmap_longmode; | ||
856 | else | ||
857 | msr_bitmap = vmx_msr_bitmap_legacy; | ||
858 | |||
859 | vmcs_write64(MSR_BITMAP, __pa(msr_bitmap)); | ||
860 | } | ||
850 | } | 861 | } |
851 | 862 | ||
852 | /* | 863 | /* |
@@ -2082,7 +2093,7 @@ static void allocate_vpid(struct vcpu_vmx *vmx) | |||
2082 | spin_unlock(&vmx_vpid_lock); | 2093 | spin_unlock(&vmx_vpid_lock); |
2083 | } | 2094 | } |
2084 | 2095 | ||
2085 | static void vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr) | 2096 | static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr) |
2086 | { | 2097 | { |
2087 | int f = sizeof(unsigned long); | 2098 | int f = sizeof(unsigned long); |
2088 | 2099 | ||
@@ -2104,6 +2115,13 @@ static void vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr) | |||
2104 | } | 2115 | } |
2105 | } | 2116 | } |
2106 | 2117 | ||
2118 | static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only) | ||
2119 | { | ||
2120 | if (!longmode_only) | ||
2121 | __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy, msr); | ||
2122 | __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode, msr); | ||
2123 | } | ||
2124 | |||
2107 | /* | 2125 | /* |
2108 | * Sets up the vmcs for emulated real mode. | 2126 | * Sets up the vmcs for emulated real mode. |
2109 | */ | 2127 | */ |
@@ -2123,7 +2141,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | |||
2123 | vmcs_write64(IO_BITMAP_B, __pa(vmx_io_bitmap_b)); | 2141 | vmcs_write64(IO_BITMAP_B, __pa(vmx_io_bitmap_b)); |
2124 | 2142 | ||
2125 | if (cpu_has_vmx_msr_bitmap()) | 2143 | if (cpu_has_vmx_msr_bitmap()) |
2126 | vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap)); | 2144 | vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy)); |
2127 | 2145 | ||
2128 | vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ | 2146 | vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ |
2129 | 2147 | ||
@@ -3705,12 +3723,18 @@ static int __init vmx_init(void) | |||
3705 | goto out; | 3723 | goto out; |
3706 | } | 3724 | } |
3707 | 3725 | ||
3708 | vmx_msr_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL); | 3726 | vmx_msr_bitmap_legacy = (unsigned long *)__get_free_page(GFP_KERNEL); |
3709 | if (!vmx_msr_bitmap) { | 3727 | if (!vmx_msr_bitmap_legacy) { |
3710 | r = -ENOMEM; | 3728 | r = -ENOMEM; |
3711 | goto out1; | 3729 | goto out1; |
3712 | } | 3730 | } |
3713 | 3731 | ||
3732 | vmx_msr_bitmap_longmode = (unsigned long *)__get_free_page(GFP_KERNEL); | ||
3733 | if (!vmx_msr_bitmap_longmode) { | ||
3734 | r = -ENOMEM; | ||
3735 | goto out2; | ||
3736 | } | ||
3737 | |||
3714 | /* | 3738 | /* |
3715 | * Allow direct access to the PC debug port (it is often used for I/O | 3739 | * Allow direct access to the PC debug port (it is often used for I/O |
3716 | * delays, but the vmexits simply slow things down). | 3740 | * delays, but the vmexits simply slow things down). |
@@ -3720,19 +3744,21 @@ static int __init vmx_init(void) | |||
3720 | 3744 | ||
3721 | memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE); | 3745 | memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE); |
3722 | 3746 | ||
3723 | memset(vmx_msr_bitmap, 0xff, PAGE_SIZE); | 3747 | memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE); |
3748 | memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE); | ||
3724 | 3749 | ||
3725 | set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ | 3750 | set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ |
3726 | 3751 | ||
3727 | r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); | 3752 | r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); |
3728 | if (r) | 3753 | if (r) |
3729 | goto out2; | 3754 | goto out3; |
3730 | 3755 | ||
3731 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_FS_BASE); | 3756 | vmx_disable_intercept_for_msr(MSR_FS_BASE, false); |
3732 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_GS_BASE); | 3757 | vmx_disable_intercept_for_msr(MSR_GS_BASE, false); |
3733 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_CS); | 3758 | vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true); |
3734 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_ESP); | 3759 | vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false); |
3735 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_EIP); | 3760 | vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false); |
3761 | vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false); | ||
3736 | 3762 | ||
3737 | if (vm_need_ept()) { | 3763 | if (vm_need_ept()) { |
3738 | bypass_guest_pf = 0; | 3764 | bypass_guest_pf = 0; |
@@ -3752,8 +3778,10 @@ static int __init vmx_init(void) | |||
3752 | 3778 | ||
3753 | return 0; | 3779 | return 0; |
3754 | 3780 | ||
3781 | out3: | ||
3782 | free_page((unsigned long)vmx_msr_bitmap_longmode); | ||
3755 | out2: | 3783 | out2: |
3756 | free_page((unsigned long)vmx_msr_bitmap); | 3784 | free_page((unsigned long)vmx_msr_bitmap_legacy); |
3757 | out1: | 3785 | out1: |
3758 | free_page((unsigned long)vmx_io_bitmap_b); | 3786 | free_page((unsigned long)vmx_io_bitmap_b); |
3759 | out: | 3787 | out: |
@@ -3763,7 +3791,8 @@ out: | |||
3763 | 3791 | ||
3764 | static void __exit vmx_exit(void) | 3792 | static void __exit vmx_exit(void) |
3765 | { | 3793 | { |
3766 | free_page((unsigned long)vmx_msr_bitmap); | 3794 | free_page((unsigned long)vmx_msr_bitmap_legacy); |
3795 | free_page((unsigned long)vmx_msr_bitmap_longmode); | ||
3767 | free_page((unsigned long)vmx_io_bitmap_b); | 3796 | free_page((unsigned long)vmx_io_bitmap_b); |
3768 | free_page((unsigned long)vmx_io_bitmap_a); | 3797 | free_page((unsigned long)vmx_io_bitmap_a); |
3769 | 3798 | ||