From ec1c753c90e22777a035dcf55aaf0e2571c35046 Mon Sep 17 00:00:00 2001
From: Sheng Yang <sheng.yang@intel.com>
Date: Wed, 1 Aug 2007 16:11:54 +0800
Subject: [PATCH 2/2] Add MSR Bitmap support for VMX

Add MSR Bitmap support for VMX so that some execution of RDMSR or WRMSR
won't cause a VM exit.

Signed-off-by: Sheng Yang <sheng.yang@intel.com>
Signed-off-by: Qing He <qing.he@intel.com>
---
 drivers/kvm/vmx.c |   44 +++++++++++++++++++++++++++++++++++++++++++-
 drivers/kvm/vmx.h |    3 +++
 2 files changed, 46 insertions(+), 1 deletions(-)

diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 3b901fe..bebe0d4 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -71,6 +71,7 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
 
 static struct page *vmx_io_bitmap_a;
 static struct page *vmx_io_bitmap_b;
+static struct page *vmx_msr_bitmap;
 
 #define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE)
 
@@ -867,7 +868,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
 	      CPU_BASED_USE_IO_BITMAPS |
 	      CPU_BASED_MOV_DR_EXITING |
 	      CPU_BASED_USE_TSC_OFFSETING;
-	opt = 0;
+	opt = CPU_BASED_USE_MSR_BITMAPS;
 	if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
 				&_cpu_based_exec_control) < 0)
 		return -EIO;
@@ -1426,6 +1427,10 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 	vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a));
 	vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b));
 
+	/* MSR bitmap */
+	if (cpu_has_vmx_msr_bitmap)
+		vmcs_write64(MSR_BITMAP, page_to_phys(vmx_msr_bitmap));
+
 	guest_write_tsc(0);
 
 	vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
@@ -2424,6 +2429,19 @@ static void __init vmx_check_processor_compat(void *rtn)
 	}
 }
 
+static void __init disable_intercept_for_msr(u32 msr, void *msr_bitmap_va)
+{
+	/* See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). */
+	if (msr <= 0x1fff) { /* read and write bitmaps for low MSRs */
+		__clear_bit(msr, msr_bitmap_va + 0x000);
+		__clear_bit(msr, msr_bitmap_va + 0x800);
+	} else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+		msr &= 0x1fff; /* read and write bitmaps for high MSRs */
+		__clear_bit(msr, msr_bitmap_va + 0x400);
+		__clear_bit(msr, msr_bitmap_va + 0xc00);
+	}
+}
+
 static struct kvm_arch_ops vmx_arch_ops = {
 	.cpu_has_kvm_support = cpu_has_kvm_support,
 	.disabled_by_bios = vmx_disabled_by_bios,
@@ -2505,6 +2523,28 @@ static int __init vmx_init(void)
 	if (r)
 		goto out1;
 
+	if (cpu_has_vmx_msr_bitmap) {
+		vmx_msr_bitmap = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+		if (!vmx_msr_bitmap) {
+			r = -ENOMEM;
+			goto out1;
+		}
+
+		printk(KERN_INFO "kvm: Enable MSR bitmap support.\n");
+
+		va = kmap(vmx_msr_bitmap);
+		memset(va, 0xff, PAGE_SIZE);
+
+		disable_intercept_for_msr(MSR_FS_BASE, va);
+		disable_intercept_for_msr(MSR_GS_BASE, va);
+
+		disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, va);
+		disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, va);
+		disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, va);
+
+		kunmap(vmx_msr_bitmap);
+	}
+
 	return 0;
 
 out1:
@@ -2516,6 +2556,8 @@ out:
 
 static void __exit vmx_exit(void)
 {
+	if (cpu_has_vmx_msr_bitmap)
+		__free_page(vmx_msr_bitmap);
 	__free_page(vmx_io_bitmap_b);
 	__free_page(vmx_io_bitmap_a);
 
diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
index 7e4dc12..b61c7f3 100644
--- a/drivers/kvm/vmx.h
+++ b/drivers/kvm/vmx.h
@@ -309,4 +309,7 @@ enum vmcs_field {
 #define MSR_IA32_FEATURE_CONTROL_LOCKED         0x1
 #define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED  0x4
 
+#define cpu_has_vmx_msr_bitmap \
+	(vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS)
+
 #endif
-- 
1.5.2

