[PATCH] KVM: VMX: enable LBR virtualization

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Using vmx msr store/load mechanism and msr intercept bitmap
to implement LBR virtualization.

Signed-off-by: Jian Zhou  <jianjay.zhou@xxxxxxxxxx>
Signed-off-by: Stephen He <herongguang.he@xxxxxxxxxx>

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 2beee03..244f68c 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -887,6 +887,12 @@ struct kvm_x86_ops {
 					   gfn_t offset, unsigned long mask);
 	/* pmu operations of sub-arch */
 	const struct kvm_pmu_ops *pmu_ops;
+
+	void (*vmcs_write64)(unsigned long field, u64 value);
+	u64 (*vmcs_read64)(unsigned long field);
+
+	int (*add_atomic_switch_msr)(struct kvm_vcpu *vcpu, u32 msr, u64 guest_val, u64 host_val);
+	void (*disable_intercept_guest_msr)(struct kvm_vcpu *vcpu, u32 msr);
 };

 struct kvm_arch_async_pf {
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 06ef490..2305308 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -159,7 +159,7 @@ module_param(ple_window_max, int, S_IRUGO);

 extern const ulong vmx_return;

-#define NR_AUTOLOAD_MSRS 8
+#define NR_AUTOLOAD_MSRS 256
 #define VMCS02_POOL_SIZE 1

 struct vmcs {
@@ -1630,6 +1630,7 @@ static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
 	--m->nr;
 	m->guest[i] = m->guest[m->nr];
 	m->host[i] = m->host[m->nr];
+	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, m->nr);
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr);
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr);
 }
@@ -1645,7 +1646,7 @@ static void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
 	vm_exit_controls_setbit(vmx, exit);
 }

-static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
+static int add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 				  u64 guest_val, u64 host_val)
 {
 	unsigned i;
@@ -1660,7 +1661,7 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 					GUEST_IA32_EFER,
 					HOST_IA32_EFER,
 					guest_val, host_val);
-			return;
+			return 0;
 		}
 		break;
 	case MSR_CORE_PERF_GLOBAL_CTRL:
@@ -1671,7 +1672,7 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 					GUEST_IA32_PERF_GLOBAL_CTRL,
 					HOST_IA32_PERF_GLOBAL_CTRL,
 					guest_val, host_val);
-			return;
+			return 0;
 		}
 		break;
 	}
@@ -1683,9 +1684,10 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 	if (i == NR_AUTOLOAD_MSRS) {
 		printk_once(KERN_WARNING "Not enough msr switch entries. "
 				"Can't add msr %x\n", msr);
-		return;
+		return -ENOSPC;
 	} else if (i == m->nr) {
 		++m->nr;
+		vmcs_write32(VM_EXIT_MSR_STORE_COUNT, m->nr);
 		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr);
 		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr);
 	}
@@ -1694,6 +1696,15 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
 	m->guest[i].value = guest_val;
 	m->host[i].index = msr;
 	m->host[i].value = host_val;
+
+	return 0;
+}
+
+static int vmx_add_atomic_switch_msr(struct kvm_vcpu *vcpu, u32 msr, u64 guest_val, u64 host_val)
+{
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+	return add_atomic_switch_msr(vmx, msr, guest_val, host_val);
 }

 static void reload_tss(void)
@@ -4332,6 +4343,20 @@ static void vmx_disable_intercept_msr_write_x2apic(u32 msr)
 			msr, MSR_TYPE_W);
 }

+static void vmx_disable_intercept_guest_msr(struct kvm_vcpu *vcpu, u32 msr)
+{
+	if (irqchip_in_kernel(vcpu->kvm) && apic_x2apic_mode(vcpu->arch.apic)) {
+		vmx_disable_intercept_msr_read_x2apic(msr);
+		vmx_disable_intercept_msr_write_x2apic(msr);
+	}
+	else {
+		if (is_long_mode(vcpu))
+			vmx_disable_intercept_for_msr(msr, true);
+		else
+			vmx_disable_intercept_for_msr(msr, false);
+	}
+}
+
 static int vmx_vm_has_apicv(struct kvm *kvm)
 {
 	return enable_apicv && irqchip_in_kernel(kvm);
@@ -4654,6 +4679,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 #endif

 	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
+	vmcs_write64(VM_EXIT_MSR_STORE_ADDR, __pa(vmx->msr_autoload.guest));
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
 	vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host));
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
@@ -10409,6 +10435,12 @@ static struct kvm_x86_ops vmx_x86_ops = {
 	.enable_log_dirty_pt_masked = vmx_enable_log_dirty_pt_masked,

 	.pmu_ops = &intel_pmu_ops,
+
+	.vmcs_write64 = vmcs_write64,
+	.vmcs_read64 = vmcs_read64,
+
+	.add_atomic_switch_msr = vmx_add_atomic_switch_msr,
+	.disable_intercept_guest_msr = vmx_disable_intercept_guest_msr,
 };

 static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 92511d4..f1fcd7c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -176,6 +176,113 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {

 u64 __read_mostly host_xcr0;

+/* Netburst (P4) last-branch recording */
+#define MSR_P4_LER_FROM_LIP 		0x000001d7
+#define MSR_P4_LER_TO_LIP 		0x000001d8
+#define MSR_P4_LASTBRANCH_TOS		0x000001da
+#define MSR_P4_LASTBRANCH_0		0x000001db
+#define NUM_MSR_P4_LASTBRANCH		4
+#define MSR_P4_LASTBRANCH_0_FROM_LIP	0x00000680
+#define MSR_P4_LASTBRANCH_0_TO_LIP	0x000006c0
+#define NUM_MSR_P4_LASTBRANCH_FROM_TO	16
+
+/* Pentium M (and Core) last-branch recording */
+#define MSR_PM_LASTBRANCH_TOS		0x000001c9
+#define MSR_PM_LASTBRANCH_0		0x00000040
+#define NUM_MSR_PM_LASTBRANCH		8
+
+/* Core 2 and Atom last-branch recording */
+#define MSR_C2_LASTBRANCH_TOS		0x000001c9
+#define MSR_C2_LASTBRANCH_0_FROM_IP	0x00000040
+#define MSR_C2_LASTBRANCH_0_TO_IP	0x00000060
+#define NUM_MSR_C2_LASTBRANCH_FROM_TO	4
+#define NUM_MSR_ATOM_LASTBRANCH_FROM_TO	8
+
+struct lbr_info {
+	u32 base, count;
+} p4_lbr[] = {
+	{ MSR_LBR_SELECT,               1 },
+	{ MSR_P4_LER_FROM_LIP,          1 },
+	{ MSR_P4_LER_TO_LIP,            1 },
+	{ MSR_P4_LASTBRANCH_TOS,        1 },
+	{ MSR_P4_LASTBRANCH_0_FROM_LIP, NUM_MSR_P4_LASTBRANCH_FROM_TO },
+	{ MSR_P4_LASTBRANCH_0_TO_LIP,   NUM_MSR_P4_LASTBRANCH_FROM_TO },
+	{ 0, 0 }
+}, c2_lbr[] = {
+	{ MSR_LBR_SELECT,               1 },
+	{ MSR_IA32_LASTINTFROMIP,       1 },
+	{ MSR_IA32_LASTINTTOIP,         1 },
+	{ MSR_C2_LASTBRANCH_TOS,        1 },
+	{ MSR_C2_LASTBRANCH_0_FROM_IP,  NUM_MSR_C2_LASTBRANCH_FROM_TO },
+	{ MSR_C2_LASTBRANCH_0_TO_IP,    NUM_MSR_C2_LASTBRANCH_FROM_TO },
+	{ 0, 0 }
+}, nh_lbr[] = {
+	{ MSR_LBR_SELECT,               1 },
+	{ MSR_IA32_LASTINTFROMIP,       1 },
+	{ MSR_IA32_LASTINTTOIP,         1 },
+	{ MSR_C2_LASTBRANCH_TOS,        1 },
+	{ MSR_P4_LASTBRANCH_0_FROM_LIP, NUM_MSR_P4_LASTBRANCH_FROM_TO },
+	{ MSR_P4_LASTBRANCH_0_TO_LIP,   NUM_MSR_P4_LASTBRANCH_FROM_TO },
+	{ 0, 0 }
+}, at_lbr[] = {
+	{ MSR_LBR_SELECT,               1 },
+	{ MSR_IA32_LASTINTFROMIP,       1 },
+	{ MSR_IA32_LASTINTTOIP,         1 },
+	{ MSR_C2_LASTBRANCH_TOS,        1 },
+	{ MSR_C2_LASTBRANCH_0_FROM_IP,  NUM_MSR_ATOM_LASTBRANCH_FROM_TO },
+	{ MSR_C2_LASTBRANCH_0_TO_IP,    NUM_MSR_ATOM_LASTBRANCH_FROM_TO },
+	{ 0, 0 }
+};
+
+static const struct lbr_info *last_branch_msr_get(void)
+{
+	switch ( boot_cpu_data.x86 )
+	{
+		case 6:
+			switch ( boot_cpu_data.x86_model )
+			{
+				/* Core2 Duo */
+				case 15:
+				/* Enhanced Core */
+				case 23:
+					return c2_lbr;
+					break;
+				/* Nehalem */
+				case 26: case 30: case 31: case 46:
+				/* Westmere */
+				case 37: case 44: case 47:
+				/* Sandy Bridge */
+				case 42: case 45:
+				/* Ivy Bridge */
+				case 58: case 62:
+				/* Haswell */
+				case 60: case 63: case 69: case 70:
+				/* future */
+				case 61: case 78:
+					return nh_lbr;
+					break;
+				/* Atom */
+				case 28: case 38: case 39: case 53: case 54:
+				/* Silvermont */
+				case 55: case 74: case 77: case 90: case 93:
+					return at_lbr;
+					break;
+			}
+			break;
+		case 15:
+			switch ( boot_cpu_data.x86_model )
+			{
+				/* Pentium4/Xeon with em64t */
+				case 3: case 4: case 6:
+					return p4_lbr;
+					break;
+			}
+			break;
+	}
+
+	return NULL;
+}
+
 static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt);

 static inline void kvm_async_pf_hash_reset(struct kvm_vcpu *vcpu)
@@ -1917,6 +2024,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	bool pr = false;
 	u32 msr = msr_info->index;
 	u64 data = msr_info->data;
+	u64 supported = 0;
+	static const struct lbr_info *lbr = NULL;
+	int i = 0;
+	int value = 0;

 	switch (msr) {
 	case MSR_AMD64_NB_CFG:
@@ -1948,16 +2059,34 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		}
 		break;
 	case MSR_IA32_DEBUGCTLMSR:
-		if (!data) {
-			/* We support the non-activated case already */
-			break;
-		} else if (data & ~(DEBUGCTLMSR_LBR | DEBUGCTLMSR_BTF)) {
-			/* Values other than LBR and BTF are vendor-specific,
-			   thus reserved and should throw a #GP */
+		supported = DEBUGCTLMSR_LBR | DEBUGCTLMSR_BTF | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI;
+
+		if (data & ~supported) {
+			/* Values other than LBR, BTF and FREEZE_LBRS_ON_PMI are not supported,
+			 * thus reserved and should throw a #GP */
+			vcpu_unimpl(vcpu, "unsupported MSR_IA32_DEBUGCTLMSR wrmsr: 0x%llx\n", data);
 			return 1;
 		}
-		vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTLMSR 0x%llx, nop\n",
-			    __func__, data);
+
+		if (data & DEBUGCTLMSR_LBR) {
+			lbr = last_branch_msr_get();
+			if (lbr == NULL)
+				break;
+
+			for (; (value == 0) && lbr->count; lbr++)
+				for (i = 0; (value == 0) && (i < lbr->count); i++)
+					if ((value = kvm_x86_ops->add_atomic_switch_msr(vcpu, lbr->base + i, 0, 0)) == 0)
+						kvm_x86_ops->disable_intercept_guest_msr(vcpu, lbr->base + i);
+		}
+
+		if (value == 0) {
+			kvm_x86_ops->vmcs_write64(GUEST_IA32_DEBUGCTL, data);
+		}
+		else {
+			/* throw a #GP */
+			return 1;
+		}
+
 		break;
 	case 0x200 ... 0x2ff:
 		return kvm_mtrr_set_msr(vcpu, msr, data);
@@ -2178,9 +2307,11 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
 int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
 	switch (msr_info->index) {
+	case MSR_IA32_DEBUGCTLMSR:
+		msr_info->data = kvm_x86_ops->vmcs_read64(GUEST_IA32_DEBUGCTL);
+		break;
 	case MSR_IA32_PLATFORM_ID:
 	case MSR_IA32_EBL_CR_POWERON:
-	case MSR_IA32_DEBUGCTLMSR:
 	case MSR_IA32_LASTBRANCHFROMIP:
 	case MSR_IA32_LASTBRANCHTOIP:
 	case MSR_IA32_LASTINTFROMIP:
--
1.7.12.4


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux