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

Re: [Xen-devel] [PATCH v24 04/15] x86/VPMU: Interface for setting PMU mode and flags



> From: Boris Ostrovsky [mailto:boris.ostrovsky@xxxxxxxxxx]
> Sent: Wednesday, June 10, 2015 11:04 PM
> 
> Add runtime interface for setting PMU mode and flags. Three main modes are
> provided:
> * XENPMU_MODE_OFF:  PMU is not virtualized
> * XENPMU_MODE_SELF: Guests can access PMU MSRs and receive PMU interrupts.
> * XENPMU_MODE_HV: Same as XENPMU_MODE_SELF for non-proviledged guests, dom0
>   can profile itself and the hypervisor.
> 
> Note that PMU modes are different from what can be provided at Xen's boot line
> with 'vpmu' argument. An 'off' (or '0') value is equivalent to 
> XENPMU_MODE_OFF.
> Any other value, on the other hand, will cause VPMU mode to be set to
> XENPMU_MODE_SELF during boot.
> 
> For feature flags only Intel's BTS is currently supported.
> 
> Mode and flags are set via HYPERVISOR_xenpmu_op hypercall.
> 
> Signed-off-by: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
> Acked-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
> Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
> Reviewed-by: Dietmar Hahn <dietmar.hahn@xxxxxxxxxxxxxx>
> ---
>  tools/flask/policy/policy/modules/xen/xen.te |   3 +
>  xen/arch/x86/domain.c                        |   4 +-
>  xen/arch/x86/hvm/svm/vpmu.c                  |   4 +-
>  xen/arch/x86/hvm/vmx/vpmu_core2.c            |  10 +-
>  xen/arch/x86/hvm/vpmu.c                      | 159
> +++++++++++++++++++++++++--
>  xen/arch/x86/x86_64/compat/entry.S           |   4 +
>  xen/arch/x86/x86_64/entry.S                  |   4 +
>  xen/include/asm-x86/hvm/vpmu.h               |  27 +++--
>  xen/include/public/pmu.h                     |  46 ++++++++
>  xen/include/public/xen.h                     |   1 +
>  xen/include/xen/hypercall.h                  |   4 +
>  xen/include/xlat.lst                         |   1 +
>  xen/include/xsm/dummy.h                      |  15 +++
>  xen/include/xsm/xsm.h                        |   6 +
>  xen/xsm/dummy.c                              |   1 +
>  xen/xsm/flask/hooks.c                        |  18 +++
>  xen/xsm/flask/policy/access_vectors          |   2 +
>  17 files changed, 284 insertions(+), 25 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
> index d829d68..5cfb2f0 100644
> --- a/xen/arch/x86/hvm/vpmu.c
> +++ b/xen/arch/x86/hvm/vpmu.c
> @@ -246,28 +266,45 @@ void vpmu_initialise(struct vcpu *v)
> 
>      ASSERT(!vpmu->flags && !vpmu->context);
> 
> +    /*
> +     * Count active VPMUs so that we won't try to change vpmu_mode while
> +     * they are in use.
> +     */
> +    spin_lock(&vpmu_lock);
> +    vpmu_count++;
> +    spin_unlock(&vpmu_lock);
> +
>      switch ( vendor )
>      {
>      case X86_VENDOR_AMD:
> -        ret = svm_vpmu_initialise(v, opt_vpmu_enabled);
> +        ret = svm_vpmu_initialise(v);
>          break;
> 
>      case X86_VENDOR_INTEL:
> -        ret = vmx_vpmu_initialise(v, opt_vpmu_enabled);
> +        ret = vmx_vpmu_initialise(v);
>          break;
> 
>      default:
> -        if ( opt_vpmu_enabled )
> +        if ( vpmu_mode != XENPMU_MODE_OFF )
>          {
>              printk(XENLOG_G_WARNING "VPMU: Unknown CPU vendor %d. "
>                     "Disabling VPMU\n", vendor);
>              opt_vpmu_enabled = 0;
> +            vpmu_mode = XENPMU_MODE_OFF;
>          }
> -        return;
> +        return; /* Don't bother restoring vpmu_count, VPMU is off forever */

why not restoring vpmu_count here? There could be a race condition
regarding to the mode control path:

+        if ( (vpmu_count == 0) || (vpmu_mode == pmu_params.val) ||
+             ((vpmu_mode ^ pmu_params.val) ==
+              (XENPMU_MODE_SELF | XENPMU_MODE_HV)) )
+            vpmu_mode = pmu_params.val;

It's possible "vpmu_mode=pmu_params.val" happens later than
"vpmu_mode = XENPMU_MODE_OFF"... 

It might not be a big problem since opt_vpmu_enabled is 0 then, but 
then there's pointless to reset vpmu_mode further if the behavior
is not guaranteed.

>      }
> 
>      if ( ret )
>          printk(XENLOG_G_WARNING "VPMU: Initialization failed for %pv\n", v);
> +
> +    /* Intel needs to initialize VPMU ops even if VPMU is not in use */
> +    if ( ret || (vpmu_mode == XENPMU_MODE_OFF) )
> +    {
> +        spin_lock(&vpmu_lock);
> +        vpmu_count--;
> +        spin_unlock(&vpmu_lock);
> +    }
>  }
> 
>  static void vpmu_clear_last(void *arg)
> @@ -296,6 +333,10 @@ void vpmu_destroy(struct vcpu *v)
> 
>      if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->arch_vpmu_destroy )
>          vpmu->arch_vpmu_ops->arch_vpmu_destroy(v);
> +
> +    spin_lock(&vpmu_lock);
> +    vpmu_count--;
> +    spin_unlock(&vpmu_lock);
>  }
> 
>  /* Dump some vpmu informations on console. Used in keyhandler 
> dump_domains(). */
> @@ -307,6 +348,109 @@ void vpmu_dump(struct vcpu *v)
>          vpmu->arch_vpmu_ops->arch_vpmu_dump(v);
>  }
> 
> +long do_xenpmu_op(unsigned int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t)
> arg)
> +{
> +    int ret;
> +    struct xen_pmu_params pmu_params = {.val = 0};
> +
> +    if ( !opt_vpmu_enabled )
> +        return -EOPNOTSUPP;
> +
> +    ret = xsm_pmu_op(XSM_OTHER, current->domain, op);
> +    if ( ret )
> +        return ret;
> +
> +    /* Check major version when parameters are specified */
> +    switch ( op )
> +    {
> +    case XENPMU_mode_set:
> +    case XENPMU_feature_set:
> +        if ( copy_from_guest(&pmu_params, arg, 1) )
> +            return -EFAULT;
> +
> +        if ( pmu_params.version.maj != XENPMU_VER_MAJ )
> +            return -EINVAL;
> +    }
> +
> +    switch ( op )
> +    {
> +    case XENPMU_mode_set:
> +    {
> +        if ( (pmu_params.val & ~(XENPMU_MODE_SELF | XENPMU_MODE_HV)) ||
> +             (hweight64(pmu_params.val) > 1) )
> +            return -EINVAL;
> +
> +        /* 32-bit dom0 can only sample itself. */
> +        if ( is_pv_32bit_vcpu(current) && (pmu_params.val & XENPMU_MODE_HV) )
> +            return -EINVAL;
> +
> +        spin_lock(&vpmu_lock);
> +
> +        /*
> +         * We can always safely switch between XENPMU_MODE_SELF and
> +         * XENPMU_MODE_HV while other VPMUs are active.
> +         */
> +        if ( (vpmu_count == 0) || (vpmu_mode == pmu_params.val) ||
> +             ((vpmu_mode ^ pmu_params.val) ==
> +              (XENPMU_MODE_SELF | XENPMU_MODE_HV)) )
> +            vpmu_mode = pmu_params.val;
> +        else
> +        {
> +            printk(XENLOG_WARNING "VPMU: Cannot change mode while"
> +                                  " active VPMUs exist\n");
> +            ret = -EBUSY;
> +        }
> +
> +        spin_unlock(&vpmu_lock);
> +
> +        break;
> +    }
> +
> +    case XENPMU_mode_get:
> +        memset(&pmu_params, 0, sizeof(pmu_params));
> +        pmu_params.val = vpmu_mode;
> +
> +        pmu_params.version.maj = XENPMU_VER_MAJ;
> +        pmu_params.version.min = XENPMU_VER_MIN;
> +
> +        if ( copy_to_guest(arg, &pmu_params, 1) )
> +            return -EFAULT;
> +
> +        break;
> +
> +    case XENPMU_feature_set:
> +        if ( pmu_params.val & ~XENPMU_FEATURE_INTEL_BTS )
> +            return -EINVAL;
> +
> +        spin_lock(&vpmu_lock);
> +
> +        if ( vpmu_count == 0 )
> +            vpmu_features = pmu_params.val;
> +        else
> +        {
> +            printk(XENLOG_WARNING "VPMU: Cannot change features while"
> +                                  " active VPMUs exist\n");
> +            ret = -EBUSY;
> +        }

what about setting same features as existing in vpmu_features?
we should do same check as done in mode setting.

Thanks
Kevin

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.