ping...

> Using vmx msr store/load mechanism and msr intercept bitmap
> to implement LBR virtualization.
> 
> Signed-off-by: Jian Zhou  <jianjay.z...@huawei.com>
> Signed-off-by: Stephen He <herongguang...@huawei.com>
> 
> 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 linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to