debuggers.hg

changeset 22716:76e07538870e

mem_access: HVMOPs for setting mem access

* Creates HVMOPs for setting and getting memory access. The hypercalls
can set individual pages or the default access for new/refreshed
pages.

* Added functions to libxc to access these hypercalls.

Signed-off-by: Joe Epstein <jepstein98@gmail.com>
Reviewed-by: Ian Campbell <ian.campbell@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Keir Fraser <keir@xen.org>
Acked-by: Tim Deegan <Tim.Deegan@citrix.com>
author Joe Epstein <jepstein98@gmail.com>
date Fri Jan 07 11:54:45 2011 +0000 (2011-01-07)
parents 8af5bab1bf43
children d9dca2bfe6b2
files tools/libxc/Makefile tools/libxc/xc_domain.c tools/libxc/xc_mem_access.c tools/libxc/xc_misc.c tools/libxc/xenctrl.h xen/arch/ia64/vmx/vmx_hypercall.c xen/arch/x86/hvm/hvm.c xen/arch/x86/mm/mem_sharing.c xen/arch/x86/mm/p2m.c xen/include/public/hvm/hvm_op.h
line diff
     1.1 --- a/tools/libxc/Makefile	Fri Jan 07 11:54:42 2011 +0000
     1.2 +++ b/tools/libxc/Makefile	Fri Jan 07 11:54:45 2011 +0000
     1.3 @@ -28,6 +28,7 @@ CTRL_SRCS-y       += xc_resume.c
     1.4  CTRL_SRCS-y       += xc_tmem.c
     1.5  CTRL_SRCS-y       += xc_mem_event.c
     1.6  CTRL_SRCS-y       += xc_mem_paging.c
     1.7 +CTRL_SRCS-y       += xc_mem_access.c
     1.8  CTRL_SRCS-y       += xc_memshr.c
     1.9  CTRL_SRCS-y       += xc_hcall_buf.c
    1.10  CTRL_SRCS-y       += xc_foreign_memory.c
     2.1 --- a/tools/libxc/xc_domain.c	Fri Jan 07 11:54:42 2011 +0000
     2.2 +++ b/tools/libxc/xc_domain.c	Fri Jan 07 11:54:45 2011 +0000
     2.3 @@ -1442,6 +1442,17 @@ int xc_domain_debug_control(xc_interface
     2.4      return do_domctl(xc, &domctl);
     2.5  }
     2.6  
     2.7 +int xc_domain_set_access_required(xc_interface *xch,
     2.8 +                                  uint32_t domid,
     2.9 +                                  unsigned int required)
    2.10 +{
    2.11 +    DECLARE_DOMCTL;
    2.12 +
    2.13 +    domctl.cmd = XEN_DOMCTL_set_access_required;
    2.14 +    domctl.domain = domid;
    2.15 +    domctl.u.access_required.access_required = required;
    2.16 +    return do_domctl(xch, &domctl);
    2.17 +}
    2.18  
    2.19  /*
    2.20   * Local variables:
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/libxc/xc_mem_access.c	Fri Jan 07 11:54:45 2011 +0000
     3.3 @@ -0,0 +1,42 @@
     3.4 +/******************************************************************************
     3.5 + *
     3.6 + * tools/libxc/xc_mem_access.c
     3.7 + *
     3.8 + * Interface to low-level memory access mode functionality
     3.9 + *
    3.10 + * Copyright (c) 2011 Virtuata, Inc.
    3.11 + *
    3.12 + * This library is free software; you can redistribute it and/or
    3.13 + * modify it under the terms of the GNU Lesser General Public
    3.14 + * License as published by the Free Software Foundation; either
    3.15 + * version 2.1 of the License, or (at your option) any later version.
    3.16 + *
    3.17 + * This library is distributed in the hope that it will be useful,
    3.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    3.20 + * Lesser General Public License for more details.
    3.21 + *
    3.22 + * You should have received a copy of the GNU Lesser General Public
    3.23 + * License along with this library; if not, write to the Free Software
    3.24 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    3.25 + */
    3.26 +
    3.27 +#include "xc_private.h"
    3.28 +
    3.29 +
    3.30 +int xc_mem_access_resume(xc_interface *xch, domid_t domain_id, unsigned long gfn)
    3.31 +{
    3.32 +    return xc_mem_event_control(xch, domain_id,
    3.33 +                                XEN_DOMCTL_MEM_EVENT_OP_ACCESS_RESUME,
    3.34 +                                XEN_DOMCTL_MEM_EVENT_OP_ACCESS, NULL, NULL,
    3.35 +                                gfn);
    3.36 +}
    3.37 +
    3.38 +/*
    3.39 + * Local variables:
    3.40 + * mode: C
    3.41 + * c-set-style: "BSD"
    3.42 + * c-basic-offset: 4
    3.43 + * indent-tabs-mode: nil
    3.44 + * End: 
    3.45 + */
     4.1 --- a/tools/libxc/xc_misc.c	Fri Jan 07 11:54:42 2011 +0000
     4.2 +++ b/tools/libxc/xc_misc.c	Fri Jan 07 11:54:45 2011 +0000
     4.3 @@ -511,6 +511,66 @@ int xc_hvm_set_mem_type(
     4.4      return rc;
     4.5  }
     4.6  
     4.7 +int xc_hvm_set_mem_access(
     4.8 +    xc_interface *xch, domid_t dom, hvmmem_access_t mem_access, uint64_t first_pfn, uint64_t nr)
     4.9 +{
    4.10 +    DECLARE_HYPERCALL;
    4.11 +    DECLARE_HYPERCALL_BUFFER(struct xen_hvm_set_mem_access, arg);
    4.12 +    int rc;
    4.13 +
    4.14 +    arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
    4.15 +    if ( arg == NULL )
    4.16 +    {
    4.17 +        PERROR("Could not allocate memory for xc_hvm_set_mem_access hypercall");
    4.18 +        return -1;
    4.19 +    }
    4.20 +
    4.21 +    arg->domid         = dom;
    4.22 +    arg->hvmmem_access = mem_access;
    4.23 +    arg->first_pfn     = first_pfn;
    4.24 +    arg->nr            = nr;
    4.25 +
    4.26 +    hypercall.op     = __HYPERVISOR_hvm_op;
    4.27 +    hypercall.arg[0] = HVMOP_set_mem_access;
    4.28 +    hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg);
    4.29 +
    4.30 +    rc = do_xen_hypercall(xch, &hypercall);
    4.31 +
    4.32 +    xc_hypercall_buffer_free(xch, arg);
    4.33 +
    4.34 +    return rc;
    4.35 +}
    4.36 +
    4.37 +int xc_hvm_get_mem_access(
    4.38 +    xc_interface *xch, domid_t dom, uint64_t pfn, hvmmem_access_t* mem_access)
    4.39 +{
    4.40 +    DECLARE_HYPERCALL;
    4.41 +    DECLARE_HYPERCALL_BUFFER(struct xen_hvm_get_mem_access, arg);
    4.42 +    int rc;
    4.43 +
    4.44 +    arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
    4.45 +    if ( arg == NULL )
    4.46 +    {
    4.47 +        PERROR("Could not allocate memory for xc_hvm_get_mem_access hypercall");
    4.48 +        return -1;
    4.49 +    }
    4.50 +
    4.51 +    arg->domid       = dom;
    4.52 +    arg->pfn         = pfn;
    4.53 +
    4.54 +    hypercall.op     = __HYPERVISOR_hvm_op;
    4.55 +    hypercall.arg[0] = HVMOP_get_mem_access;
    4.56 +    hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg);
    4.57 +
    4.58 +    rc = do_xen_hypercall(xch, &hypercall);
    4.59 +
    4.60 +    if ( !rc )
    4.61 +        *mem_access = arg->hvmmem_access;
    4.62 +
    4.63 +    xc_hypercall_buffer_free(xch, arg);
    4.64 +
    4.65 +    return rc;
    4.66 +}
    4.67  
    4.68  /*
    4.69   * Local variables:
     5.1 --- a/tools/libxc/xenctrl.h	Fri Jan 07 11:54:42 2011 +0000
     5.2 +++ b/tools/libxc/xenctrl.h	Fri Jan 07 11:54:45 2011 +0000
     5.3 @@ -701,6 +701,19 @@ int xc_domain_setdebugging(xc_interface 
     5.4                             uint32_t domid,
     5.5                             unsigned int enable);
     5.6  
     5.7 +/**
     5.8 + * This function sets or clears the requirement that an access memory
     5.9 + * event listener is required on the domain.
    5.10 + *
    5.11 + * @parm xch a handle to an open hypervisor interface
    5.12 + * @parm domid the domain id to send trigger
    5.13 + * @parm enable true to require a listener
    5.14 + * return 0 on success, -1 on failure
    5.15 + */
    5.16 +int xc_domain_set_access_required(xc_interface *xch,
    5.17 +				  uint32_t domid,
    5.18 +				  unsigned int required);
    5.19 +
    5.20  /*
    5.21   * CPUPOOL MANAGEMENT FUNCTIONS
    5.22   */
    5.23 @@ -1398,6 +1411,19 @@ int xc_hvm_modified_memory(
    5.24  int xc_hvm_set_mem_type(
    5.25      xc_interface *xch, domid_t dom, hvmmem_type_t memtype, uint64_t first_pfn, uint64_t nr);
    5.26  
    5.27 +/*
    5.28 + * Set a range of memory to a specific access.
    5.29 + * Allowed types are HVMMEM_access_default, HVMMEM_access_n, any combination of 
    5.30 + * HVM_access_ + (rwx), and HVM_access_rx2rw
    5.31 + */
    5.32 +int xc_hvm_set_mem_access(
    5.33 +    xc_interface *xch, domid_t dom, hvmmem_access_t memaccess, uint64_t first_pfn, uint64_t nr);
    5.34 +
    5.35 +/*
    5.36 + * Gets the mem access for the given page (returned in memacess on success)
    5.37 + */
    5.38 +int xc_hvm_get_mem_access(
    5.39 +    xc_interface *xch, domid_t dom, uint64_t pfn, hvmmem_access_t* memaccess);
    5.40  
    5.41  /*
    5.42   *  LOGGING AND ERROR REPORTING
    5.43 @@ -1704,6 +1730,8 @@ int xc_mem_paging_evict(xc_interface *xc
    5.44  int xc_mem_paging_prep(xc_interface *xch, domid_t domain_id, unsigned long gfn);
    5.45  int xc_mem_paging_resume(xc_interface *xch, domid_t domain_id,
    5.46                           unsigned long gfn);
    5.47 +int xc_mem_access_resume(xc_interface *xch, domid_t domain_id,
    5.48 +                         unsigned long gfn);
    5.49  
    5.50  /**
    5.51   * memshr operations
     6.1 --- a/xen/arch/ia64/vmx/vmx_hypercall.c	Fri Jan 07 11:54:42 2011 +0000
     6.2 +++ b/xen/arch/ia64/vmx/vmx_hypercall.c	Fri Jan 07 11:54:45 2011 +0000
     6.3 @@ -218,6 +218,9 @@ do_hvm_op(unsigned long op, XEN_GUEST_HA
     6.4      }
     6.5  
     6.6      case HVMOP_set_mem_type:
     6.7 +    case HVMOP_set_mem_access:
     6.8 +    case HVMOP_get_mem_access:
     6.9 +
    6.10          rc = -ENOSYS;
    6.11          break;
    6.12  
     7.1 --- a/xen/arch/x86/hvm/hvm.c	Fri Jan 07 11:54:42 2011 +0000
     7.2 +++ b/xen/arch/x86/hvm/hvm.c	Fri Jan 07 11:54:45 2011 +0000
     7.3 @@ -3464,6 +3464,149 @@ long do_hvm_op(unsigned long op, XEN_GUE
     7.4          break;
     7.5      }
     7.6  
     7.7 +    case HVMOP_set_mem_access:
     7.8 +    {
     7.9 +        struct xen_hvm_set_mem_access a;
    7.10 +        struct domain *d;
    7.11 +        struct p2m_domain *p2m;
    7.12 +        unsigned long pfn;
    7.13 +        
    7.14 +        p2m_access_t memaccess[] = {
    7.15 +            p2m_access_n,
    7.16 +            p2m_access_r,
    7.17 +            p2m_access_w,
    7.18 +            p2m_access_rw,
    7.19 +            p2m_access_x,
    7.20 +            p2m_access_rx,
    7.21 +            p2m_access_wx,
    7.22 +            p2m_access_rwx,
    7.23 +            p2m_access_rx2rw,
    7.24 +            0,  /* HVMMEM_access_default -- will get set below */
    7.25 +        };
    7.26 +
    7.27 +        if ( copy_from_guest(&a, arg, 1) )
    7.28 +            return -EFAULT;
    7.29 +
    7.30 +        if ( current->domain->domain_id == a.domid )
    7.31 +            return -EPERM;
    7.32 +
    7.33 +        rc = rcu_lock_target_domain_by_id(a.domid, &d);
    7.34 +        if ( rc != 0 )
    7.35 +            return rc;
    7.36 +
    7.37 +        rc = -EINVAL;
    7.38 +        if ( !is_hvm_domain(d) )
    7.39 +            goto param_fail5;
    7.40 +
    7.41 +        p2m = p2m_get_hostp2m(d);
    7.42 +        memaccess[HVMMEM_access_default] = p2m->default_access;
    7.43 +
    7.44 +        /* If request to set default access */
    7.45 +        if ( a.first_pfn == ~0ull ) 
    7.46 +        {
    7.47 +            rc = 0;
    7.48 +            p2m->default_access = memaccess[a.hvmmem_access];
    7.49 +            goto param_fail5;
    7.50 +        }
    7.51 +
    7.52 +        rc = -EINVAL;
    7.53 +        if ( (a.first_pfn > domain_get_maximum_gpfn(d)) ||
    7.54 +             ((a.first_pfn + a.nr - 1) < a.first_pfn) ||
    7.55 +             ((a.first_pfn + a.nr - 1) > domain_get_maximum_gpfn(d)) )
    7.56 +            goto param_fail5;
    7.57 +            
    7.58 +        if ( a.hvmmem_access >= ARRAY_SIZE(memaccess) )
    7.59 +            goto param_fail5;
    7.60 +
    7.61 +        for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ )
    7.62 +        {
    7.63 +            p2m_type_t t;
    7.64 +            mfn_t mfn;
    7.65 +            int success;
    7.66 +
    7.67 +            mfn = gfn_to_mfn_unshare(p2m, pfn, &t, 0);
    7.68 +
    7.69 +            p2m_lock(p2m);
    7.70 +            success = p2m->set_entry(p2m, pfn, mfn, 0, t, memaccess[a.hvmmem_access]);
    7.71 +            p2m_unlock(p2m);
    7.72 +            if ( !success )
    7.73 +                goto param_fail5;
    7.74 +        }
    7.75 +
    7.76 +        rc = 0;
    7.77 +
    7.78 +    param_fail5:
    7.79 +        rcu_unlock_domain(d);
    7.80 +        break;
    7.81 +    }
    7.82 +
    7.83 +    case HVMOP_get_mem_access:
    7.84 +    {
    7.85 +        struct xen_hvm_get_mem_access a;
    7.86 +        struct domain *d;
    7.87 +        struct p2m_domain *p2m;
    7.88 +        p2m_type_t t;
    7.89 +        p2m_access_t ac;
    7.90 +        mfn_t mfn;
    7.91 +
    7.92 +        /* Interface access to internal p2m accesses */
    7.93 +        hvmmem_access_t memaccess[] = {
    7.94 +            HVMMEM_access_n,
    7.95 +            HVMMEM_access_r,
    7.96 +            HVMMEM_access_w,
    7.97 +            HVMMEM_access_rw,
    7.98 +            HVMMEM_access_x,
    7.99 +            HVMMEM_access_rx,
   7.100 +            HVMMEM_access_wx,
   7.101 +            HVMMEM_access_rwx,
   7.102 +            HVMMEM_access_rx2rw
   7.103 +        };
   7.104 +
   7.105 +        if ( copy_from_guest(&a, arg, 1) )
   7.106 +            return -EFAULT;
   7.107 +
   7.108 +        if ( current->domain->domain_id == a.domid )
   7.109 +            return -EPERM;
   7.110 +
   7.111 +        rc = rcu_lock_target_domain_by_id(a.domid, &d);
   7.112 +        if ( rc != 0 )
   7.113 +            return rc;
   7.114 +
   7.115 +        rc = -EINVAL;
   7.116 +        if ( !is_hvm_domain(d) )
   7.117 +            goto param_fail6;
   7.118 +
   7.119 +        p2m = p2m_get_hostp2m(d);
   7.120 +        
   7.121 +        if ( a.pfn == ~0ull ) 
   7.122 +        {
   7.123 +            a.hvmmem_access = memaccess[p2m->default_access];
   7.124 +        }
   7.125 +        else {
   7.126 +            rc = -EINVAL;
   7.127 +            if ( (a.pfn > domain_get_maximum_gpfn(d)) )
   7.128 +                goto param_fail6;
   7.129 +
   7.130 +            rc = -ESRCH;
   7.131 +            mfn = p2m->get_entry(p2m, a.pfn, &t, &ac, p2m_query);
   7.132 +
   7.133 +            if ( mfn_x(mfn) == INVALID_MFN )
   7.134 +                goto param_fail6;
   7.135 +            
   7.136 +            rc = -ERANGE;
   7.137 +            if ( ac >= ARRAY_SIZE(memaccess) )
   7.138 +                goto param_fail6;
   7.139 +        
   7.140 +            a.hvmmem_access = memaccess[ac];
   7.141 +        }
   7.142 +
   7.143 +        rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0;
   7.144 +
   7.145 +    param_fail6:
   7.146 +        rcu_unlock_domain(d);
   7.147 +        break;
   7.148 +    }
   7.149 +
   7.150      case HVMOP_pagetable_dying:
   7.151      {
   7.152          struct xen_hvm_pagetable_dying a;
   7.153 @@ -3478,12 +3621,12 @@ long do_hvm_op(unsigned long op, XEN_GUE
   7.154  
   7.155          rc = -EINVAL;
   7.156          if ( !is_hvm_domain(d) || !paging_mode_shadow(d) )
   7.157 -            goto param_fail5;
   7.158 +            goto param_fail7;
   7.159  
   7.160          rc = 0;
   7.161          pagetable_dying(d, a.gpa);
   7.162  
   7.163 -    param_fail5:
   7.164 +    param_fail7:
   7.165          rcu_unlock_domain(d);
   7.166          break;
   7.167      }
     8.1 --- a/xen/arch/x86/mm/mem_sharing.c	Fri Jan 07 11:54:42 2011 +0000
     8.2 +++ b/xen/arch/x86/mm/mem_sharing.c	Fri Jan 07 11:54:45 2011 +0000
     8.3 @@ -304,6 +304,8 @@ static struct page_info* mem_sharing_all
     8.4      if(page != NULL) return page;
     8.5  
     8.6      memset(&req, 0, sizeof(req));
     8.7 +    req.type = MEM_EVENT_TYPE_SHARED;
     8.8 +
     8.9      if(must_succeed) 
    8.10      {
    8.11          /* We do not support 'must_succeed' any more. External operations such
     9.1 --- a/xen/arch/x86/mm/p2m.c	Fri Jan 07 11:54:42 2011 +0000
     9.2 +++ b/xen/arch/x86/mm/p2m.c	Fri Jan 07 11:54:45 2011 +0000
     9.3 @@ -2781,6 +2781,7 @@ void p2m_mem_paging_populate(struct p2m_
     9.4          return;
     9.5  
     9.6      memset(&req, 0, sizeof(req));
     9.7 +    req.type = MEM_EVENT_TYPE_PAGING;
     9.8  
     9.9      /* Fix p2m mapping */
    9.10      /* XXX: It seems inefficient to have this here, as it's only needed
    10.1 --- a/xen/include/public/hvm/hvm_op.h	Fri Jan 07 11:54:42 2011 +0000
    10.2 +++ b/xen/include/public/hvm/hvm_op.h	Fri Jan 07 11:54:45 2011 +0000
    10.3 @@ -158,4 +158,46 @@ struct xen_hvm_xentrace {
    10.4  typedef struct xen_hvm_xentrace xen_hvm_xentrace_t;
    10.5  DEFINE_XEN_GUEST_HANDLE(xen_hvm_xentrace_t);
    10.6  
    10.7 +#define HVMOP_set_mem_access        12
    10.8 +typedef enum {
    10.9 +    HVMMEM_access_n,
   10.10 +    HVMMEM_access_r,
   10.11 +    HVMMEM_access_w,
   10.12 +    HVMMEM_access_rw,
   10.13 +    HVMMEM_access_x,
   10.14 +    HVMMEM_access_rx,
   10.15 +    HVMMEM_access_wx,
   10.16 +    HVMMEM_access_rwx,
   10.17 +    HVMMEM_access_rx2rw,       /* Page starts off as read-execute, but automatically change
   10.18 +				* to read-write on a write */
   10.19 +    HVMMEM_access_default      /* Take the domain default */
   10.20 +} hvmmem_access_t;
   10.21 +/* Notify that a region of memory is to have specific access types */
   10.22 +struct xen_hvm_set_mem_access {
   10.23 +    /* Domain to be updated. */
   10.24 +    domid_t domid;
   10.25 +    uint16_t pad[3]; /* align next field on 8-byte boundary */
   10.26 +    /* Memory type */
   10.27 +    uint64_t hvmmem_access; /* hvm_access_t */
   10.28 +    /* First pfn, or ~0ull to set the default access for new pages */
   10.29 +    uint64_t first_pfn;
   10.30 +    /* Number of pages, ignored on setting default access */
   10.31 +    uint64_t nr;
   10.32 +};
   10.33 +typedef struct xen_hvm_set_mem_access xen_hvm_set_mem_access_t;
   10.34 +DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_mem_access_t);
   10.35 +
   10.36 +#define HVMOP_get_mem_access        13
   10.37 +/* Get the specific access type for that region of memory */
   10.38 +struct xen_hvm_get_mem_access {
   10.39 +    /* Domain to be queried. */
   10.40 +    domid_t domid;
   10.41 +    uint16_t pad[3]; /* align next field on 8-byte boundary */
   10.42 +    /* Memory type: OUT */
   10.43 +    uint64_t hvmmem_access; /* hvm_access_t */
   10.44 +    /* pfn, or ~0ull for default access for new pages.  IN */
   10.45 +    uint64_t pfn;
   10.46 +};
   10.47 +typedef struct xen_hvm_get_mem_access xen_hvm_get_mem_access_t;
   10.48 +DEFINE_XEN_GUEST_HANDLE(xen_hvm_get_mem_access_t);
   10.49  #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */