Re: [PATCH] KVM: VMX: enable LBR virtualization

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

 



ping...

> 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