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

Re: [Xen-devel] [PATCH V5] vm_event: Allow subscribing to write events for specific MSR-s



On 04/26/2016 11:49 AM, Razvan Cojocaru wrote:
> Previously, subscribing to MSR write events was an all-or-none
> approach, with special cases for introspection MSR-s. This patch
> allows the vm_event consumer to specify exactly what MSR-s it is
> interested in, and as a side-effect gets rid of the
> vmx_introspection_force_enabled_msrs[] special case.
> This replaces the previously posted "xen: Filter out MSR write
> events" patch.
> 
> Signed-off-by: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx>
> 
> ---
> Changes since V4:
>  - Added arch_monitor_init_domain() and arch_monitor_cleanup_domain()
>    as suggested by Tamas Lengyel and Andrew Cooper.
>  - Factored out common MSR range code in monitor_bitmap_for_msr(),
>    as suggested by Andrew Cooper.
>  - Renamed monitor_is_msr_enabled() to monitored_msr(), as
>    suggested by Andrew Cooper.
>  - Replaced clear_bit() with __clear_bit().
>  - Now returning -EINVAL when monitor_bitmap_for_msr() returns NULL
>    (i.e. when the MSR is out of range).
>  - Since these are slightly more than minor changes, removed all
>    previous Acks.
> ---
>  tools/libxc/include/xenctrl.h      |   9 ++-
>  tools/libxc/xc_monitor.c           |   6 +-
>  xen/arch/x86/hvm/event.c           |   3 +-
>  xen/arch/x86/hvm/hvm.c             |   3 +-
>  xen/arch/x86/hvm/vmx/vmcs.c        |  26 +-------
>  xen/arch/x86/hvm/vmx/vmx.c         |  10 +---
>  xen/arch/x86/monitor.c             | 120 
> +++++++++++++++++++++++++++++++++----
>  xen/arch/x86/vm_event.c            |   9 +++
>  xen/common/vm_event.c              |   5 ++
>  xen/include/asm-arm/monitor.h      |  13 ++++
>  xen/include/asm-x86/domain.h       |   4 +-
>  xen/include/asm-x86/hvm/hvm.h      |   8 +--
>  xen/include/asm-x86/hvm/vmx/vmcs.h |   7 ---
>  xen/include/asm-x86/monitor.h      |  12 ++++
>  xen/include/public/domctl.h        |   5 +-
>  15 files changed, 173 insertions(+), 67 deletions(-)
> 
> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
> index f5a034a..3216e48 100644
> --- a/tools/libxc/include/xenctrl.h
> +++ b/tools/libxc/include/xenctrl.h
> @@ -2183,8 +2183,13 @@ int xc_monitor_get_capabilities(xc_interface *xch, 
> domid_t domain_id,
>  int xc_monitor_write_ctrlreg(xc_interface *xch, domid_t domain_id,
>                               uint16_t index, bool enable, bool sync,
>                               bool onchangeonly);
> -int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, bool enable,
> -                          bool extended_capture);
> +/*
> + * A list of MSR indices can usually be found in 
> /usr/include/asm/msr-index.h.
> + * Please consult the Intel/AMD manuals for more information on
> + * non-architectural indices.
> + */
> +int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, uint32_t msr,
> +                          bool enable);
>  int xc_monitor_singlestep(xc_interface *xch, domid_t domain_id, bool enable);
>  int xc_monitor_software_breakpoint(xc_interface *xch, domid_t domain_id,
>                                     bool enable);
> diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
> index b1705dd..78131b2 100644
> --- a/tools/libxc/xc_monitor.c
> +++ b/tools/libxc/xc_monitor.c
> @@ -86,8 +86,8 @@ int xc_monitor_write_ctrlreg(xc_interface *xch, domid_t 
> domain_id,
>      return do_domctl(xch, &domctl);
>  }
>  
> -int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, bool enable,
> -                          bool extended_capture)
> +int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, uint32_t msr,
> +                          bool enable)
>  {
>      DECLARE_DOMCTL;
>  
> @@ -96,7 +96,7 @@ int xc_monitor_mov_to_msr(xc_interface *xch, domid_t 
> domain_id, bool enable,
>      domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
>                                      : XEN_DOMCTL_MONITOR_OP_DISABLE;
>      domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR;
> -    domctl.u.monitor_op.u.mov_to_msr.extended_capture = extended_capture;
> +    domctl.u.monitor_op.u.mov_to_msr.msr = msr;
>  
>      return do_domctl(xch, &domctl);
>  }
> diff --git a/xen/arch/x86/hvm/event.c b/xen/arch/x86/hvm/event.c
> index 56c5514..8fdb6f5 100644
> --- a/xen/arch/x86/hvm/event.c
> +++ b/xen/arch/x86/hvm/event.c
> @@ -57,9 +57,8 @@ bool_t hvm_event_cr(unsigned int index, unsigned long 
> value, unsigned long old)
>  void hvm_event_msr(unsigned int msr, uint64_t value)
>  {
>      struct vcpu *curr = current;
> -    struct arch_domain *ad = &curr->domain->arch;
>  
> -    if ( ad->monitor.mov_to_msr_enabled )
> +    if ( monitored_msr(curr->domain, msr) )
>      {
>          vm_event_request_t req = {
>              .reason = VM_EVENT_REASON_MOV_TO_MSR,
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index e9d4c6b..7495820 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -3694,7 +3694,6 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t 
> msr_content,
>      bool_t mtrr;
>      unsigned int edx, index;
>      int ret = X86EMUL_OKAY;
> -    struct arch_domain *currad = &current->domain->arch;
>  
>      HVMTRACE_3D(MSR_WRITE, msr,
>                 (uint32_t)msr_content, (uint32_t)(msr_content >> 32));
> @@ -3702,7 +3701,7 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t 
> msr_content,
>      hvm_cpuid(1, NULL, NULL, NULL, &edx);
>      mtrr = !!(edx & cpufeat_mask(X86_FEATURE_MTRR));
>  
> -    if ( may_defer && unlikely(currad->monitor.mov_to_msr_enabled) )
> +    if ( may_defer && unlikely(monitored_msr(v->domain, msr)) )
>      {
>          ASSERT(v->arch.vm_event);
>  
> diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
> index 8284281..f8421e8 100644
> --- a/xen/arch/x86/hvm/vmx/vmcs.c
> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
> @@ -37,6 +37,7 @@
>  #include <asm/hvm/vmx/vvmx.h>
>  #include <asm/hvm/vmx/vmcs.h>
>  #include <asm/flushtlb.h>
> +#include <asm/monitor.h>
>  #include <asm/shadow.h>
>  #include <asm/tboot.h>
>  #include <asm/apic.h>
> @@ -108,18 +109,6 @@ u64 vmx_ept_vpid_cap __read_mostly;
>  u64 vmx_vmfunc __read_mostly;
>  bool_t vmx_virt_exception __read_mostly;
>  
> -const u32 vmx_introspection_force_enabled_msrs[] = {
> -    MSR_IA32_SYSENTER_EIP,
> -    MSR_IA32_SYSENTER_ESP,
> -    MSR_IA32_SYSENTER_CS,
> -    MSR_IA32_MC0_CTL,
> -    MSR_STAR,
> -    MSR_LSTAR
> -};
> -
> -const unsigned int vmx_introspection_force_enabled_msrs_size =
> -    ARRAY_SIZE(vmx_introspection_force_enabled_msrs);
> -
>  static DEFINE_PER_CPU_READ_MOSTLY(paddr_t, vmxon_region);
>  static DEFINE_PER_CPU(paddr_t, current_vmcs);
>  static DEFINE_PER_CPU(struct list_head, active_vmcs_list);
> @@ -810,17 +799,8 @@ void vmx_disable_intercept_for_msr(struct vcpu *v, u32 
> msr, int type)
>      if ( msr_bitmap == NULL )
>          return;
>  
> -    if ( unlikely(d->arch.monitor.mov_to_msr_enabled &&
> -                  d->arch.monitor.mov_to_msr_extended) &&
> -         vm_event_check_ring(&d->vm_event->monitor) )
> -    {
> -        unsigned int i;
> -
> -        /* Filter out MSR-s needed for memory introspection */
> -        for ( i = 0; i < vmx_introspection_force_enabled_msrs_size; i++ )
> -            if ( msr == vmx_introspection_force_enabled_msrs[i] )
> -                return;
> -    }
> +    if ( unlikely(monitored_msr(d, msr)) )
> +        return;
>  
>      /*
>       * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals
> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
> index bc4410f..9135441 100644
> --- a/xen/arch/x86/hvm/vmx/vmx.c
> +++ b/xen/arch/x86/hvm/vmx/vmx.c
> @@ -1958,16 +1958,12 @@ void vmx_hypervisor_cpuid_leaf(uint32_t sub_idx,
>          *eax |= XEN_HVM_CPUID_X2APIC_VIRT;
>  }
>  
> -static void vmx_enable_msr_exit_interception(struct domain *d)
> +static void vmx_enable_msr_interception(struct domain *d, uint32_t msr)
>  {
>      struct vcpu *v;
> -    unsigned int i;
>  
> -    /* Enable interception for MSRs needed for memory introspection. */
>      for_each_vcpu ( d, v )
> -        for ( i = 0; i < vmx_introspection_force_enabled_msrs_size; i++ )
> -            vmx_enable_intercept_for_msr(v, 
> vmx_introspection_force_enabled_msrs[i],
> -                                         MSR_TYPE_W);
> +        vmx_enable_intercept_for_msr(v, msr, MSR_TYPE_W);
>  }
>  
>  static bool_t vmx_is_singlestep_supported(void)
> @@ -2166,7 +2162,7 @@ static struct hvm_function_table __initdata 
> vmx_function_table = {
>      .handle_eoi           = vmx_handle_eoi,
>      .nhvm_hap_walk_L1_p2m = nvmx_hap_walk_L1_p2m,
>      .hypervisor_cpuid_leaf = vmx_hypervisor_cpuid_leaf,
> -    .enable_msr_exit_interception = vmx_enable_msr_exit_interception,
> +    .enable_msr_interception = vmx_enable_msr_interception,
>      .is_singlestep_supported = vmx_is_singlestep_supported,
>      .set_mode = vmx_set_mode,
>      .altp2m_vcpu_update_p2m = vmx_vcpu_update_eptp,
> diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c
> index 1fec412..df56981 100644
> --- a/xen/arch/x86/monitor.c
> +++ b/xen/arch/x86/monitor.c
> @@ -22,6 +22,99 @@
>  #include <asm/monitor.h>
>  #include <public/vm_event.h>
>  
> +int arch_monitor_init_domain(struct domain *d)
> +{
> +    d->arch.monitor_msr_bitmap = xzalloc(struct monitor_msr_bitmap);
> +
> +    if ( !d->arch.monitor_msr_bitmap )
> +        return -ENOMEM;
> +
> +    return 0;
> +}
> +
> +void arch_monitor_cleanup_domain(struct domain *d)
> +{
> +    xfree(d->arch.monitor_msr_bitmap);
> +    d->arch.monitor_msr_bitmap = NULL;
> +}
> +
> +static void *monitor_bitmap_for_msr(struct domain *d, u32 *msr)
> +{
> +    ASSERT(d->arch.monitor_msr_bitmap && msr);
> +
> +    switch ( *msr )
> +    {
> +    case 0 ... 0x1fff:
> +        BUILD_BUG_ON(ARRAY_SIZE(d->arch.monitor_msr_bitmap->low) * 8 < 
> 0x1fff);
> +        return &d->arch.monitor_msr_bitmap->low;
> +
> +    case 0x40000000 ... 0x40001fff:
> +        BUILD_BUG_ON(
> +            ARRAY_SIZE(d->arch.monitor_msr_bitmap->hypervisor) * 8 < 0x1fff);
> +        *msr &= 0x1fff;
> +        return &d->arch.monitor_msr_bitmap->hypervisor;
> +
> +    case 0xc0000000 ... 0xc0001fff:
> +        BUILD_BUG_ON(ARRAY_SIZE(d->arch.monitor_msr_bitmap->high) * 8 < 
> 0x1fff);
> +        *msr &= 0x1fff;
> +        return &d->arch.monitor_msr_bitmap->high;
> +
> +    default:
> +        return NULL;
> +    }
> +}
> +
> +static int monitor_enable_msr(struct domain *d, u32 msr)
> +{
> +    u32 *bitmap;
> +
> +    if ( !d->arch.monitor_msr_bitmap )
> +        return -ENXIO;
> +
> +    bitmap = monitor_bitmap_for_msr(d, &msr);
> +
> +    if ( !bitmap )
> +        return -EINVAL;
> +
> +    __set_bit(msr, bitmap);
> +
> +    hvm_enable_msr_interception(d, msr);
> +
> +    return 0;
> +}
> +
> +static int monitor_disable_msr(struct domain *d, u32 msr)
> +{
> +    u32 *bitmap;
> +
> +    if ( !d->arch.monitor_msr_bitmap )
> +        return -ENXIO;
> +
> +    bitmap = monitor_bitmap_for_msr(d, &msr);
> +
> +    if ( !bitmap )
> +        return -EINVAL;
> +
> +    __clear_bit(msr, bitmap);
> +
> +    return 0;
> +}
> +
> +bool_t monitored_msr(struct domain *d, u32 msr)
> +{
> +    u32 *bitmap;
> +
> +    if ( !d->arch.monitor_msr_bitmap )
> +        return 0;
> +
> +    bitmap = monitor_bitmap_for_msr(d, &msr);
> +
> +    if ( !bitmap )
> +        return 0;
> +
> +    return test_bit(msr, bitmap);
> +}
> +
>  int arch_monitor_domctl_event(struct domain *d,
>                                struct xen_domctl_monitor_op *mop)
>  {
> @@ -77,25 +170,28 @@ int arch_monitor_domctl_event(struct domain *d,
>  
>      case XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR:
>      {
> -        bool_t old_status = ad->monitor.mov_to_msr_enabled;
> +        bool_t old_status;
> +        int rc;
> +        u32 msr = mop->u.mov_to_msr.msr;
>  
> -        if ( unlikely(old_status == requested_status) )
> -            return -EEXIST;
> +        domain_pause(d);
>  
> -        if ( requested_status && mop->u.mov_to_msr.extended_capture &&
> -             !hvm_enable_msr_exit_interception(d) )
> -            return -EOPNOTSUPP;
> +        old_status = monitored_msr(d, msr);
>  
> -        domain_pause(d);
> +        if ( unlikely(old_status == requested_status) )
> +        {
> +            domain_unpause(d);
> +            return -EEXIST;
> +        }
>  
> -        if ( requested_status && mop->u.mov_to_msr.extended_capture )
> -            ad->monitor.mov_to_msr_extended = 1;
> +        if ( requested_status )
> +            rc = monitor_enable_msr(d, msr);
>          else
> -            ad->monitor.mov_to_msr_extended = 0;
> +            rc = monitor_disable_msr(d, msr);
>  
> -        ad->monitor.mov_to_msr_enabled = requested_status;
>          domain_unpause(d);
> -        break;
> +
> +        return rc;
>      }
>  
>      case XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP:
> diff --git a/xen/arch/x86/vm_event.c b/xen/arch/x86/vm_event.c
> index 5635603..22819c5 100644
> --- a/xen/arch/x86/vm_event.c
> +++ b/xen/arch/x86/vm_event.c
> @@ -20,6 +20,7 @@
>  
>  #include <xen/sched.h>
>  #include <asm/hvm/hvm.h>
> +#include <asm/monitor.h>
>  #include <asm/vm_event.h>
>  
>  /* Implicitly serialized by the domctl lock. */
> @@ -27,6 +28,11 @@ int vm_event_init_domain(struct domain *d)
>  {
>      struct vcpu *v;
>  
> +    d->arch.monitor_msr_bitmap = xzalloc(struct monitor_msr_bitmap);
> +
> +    if ( !d->arch.monitor_msr_bitmap )
> +        return -ENOMEM;
> +
>      for_each_vcpu ( d, v )
>      {
>          if ( v->arch.vm_event )
> @@ -55,6 +61,9 @@ void vm_event_cleanup_domain(struct domain *d)
>          v->arch.vm_event = NULL;
>      }
>  
> +    xfree(d->arch.monitor_msr_bitmap);
> +    d->arch.monitor_msr_bitmap = NULL;
> +
>      d->arch.mem_access_emulate_each_rep = 0;
>      memset(&d->arch.monitor, 0, sizeof(d->arch.monitor));
>      memset(&d->monitor, 0, sizeof(d->monitor));

Aside from accidentally duplicating the alloc() / free() code here, I
should have probably moved the following monitor-related memset()s in
arch_monitor_init_domain() as well. I'll do that in V6.


Thanks,
Razvan

_______________________________________________
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®.