aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Epstein <jepstein98@gmail.com>2011-01-07 11:54:45 +0000
committerJoe Epstein <jepstein98@gmail.com>2011-01-07 11:54:45 +0000
commit81f8af44baecf94a72d08cde1619f5af63c1b3a7 (patch)
treee4567ecb0212bfbd8ca85dd0c2cf01e601ec14c4
parentb405792883f6e2f3001328865af6960968441ad6 (diff)
downloadxen-81f8af44baecf94a72d08cde1619f5af63c1b3a7.tar.gz
xen-81f8af44baecf94a72d08cde1619f5af63c1b3a7.tar.bz2
xen-81f8af44baecf94a72d08cde1619f5af63c1b3a7.zip
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>
-rw-r--r--tools/libxc/Makefile1
-rw-r--r--tools/libxc/xc_domain.c11
-rw-r--r--tools/libxc/xc_mem_access.c42
-rw-r--r--tools/libxc/xc_misc.c60
-rw-r--r--tools/libxc/xenctrl.h28
-rw-r--r--xen/arch/ia64/vmx/vmx_hypercall.c3
-rw-r--r--xen/arch/x86/hvm/hvm.c147
-rw-r--r--xen/arch/x86/mm/mem_sharing.c2
-rw-r--r--xen/arch/x86/mm/p2m.c1
-rw-r--r--xen/include/public/hvm/hvm_op.h42
10 files changed, 335 insertions, 2 deletions
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index e042be7ea0..5a7677e996 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -28,6 +28,7 @@ CTRL_SRCS-y += xc_resume.c
CTRL_SRCS-y += xc_tmem.c
CTRL_SRCS-y += xc_mem_event.c
CTRL_SRCS-y += xc_mem_paging.c
+CTRL_SRCS-y += xc_mem_access.c
CTRL_SRCS-y += xc_memshr.c
CTRL_SRCS-y += xc_hcall_buf.c
CTRL_SRCS-y += xc_foreign_memory.c
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 2f4a990de8..98ca5ed49e 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -1442,6 +1442,17 @@ int xc_domain_debug_control(xc_interface *xc, uint32_t domid, uint32_t sop, uint
return do_domctl(xc, &domctl);
}
+int xc_domain_set_access_required(xc_interface *xch,
+ uint32_t domid,
+ unsigned int required)
+{
+ DECLARE_DOMCTL;
+
+ domctl.cmd = XEN_DOMCTL_set_access_required;
+ domctl.domain = domid;
+ domctl.u.access_required.access_required = required;
+ return do_domctl(xch, &domctl);
+}
/*
* Local variables:
diff --git a/tools/libxc/xc_mem_access.c b/tools/libxc/xc_mem_access.c
new file mode 100644
index 0000000000..b9e66bbd07
--- /dev/null
+++ b/tools/libxc/xc_mem_access.c
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * tools/libxc/xc_mem_access.c
+ *
+ * Interface to low-level memory access mode functionality
+ *
+ * Copyright (c) 2011 Virtuata, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xc_private.h"
+
+
+int xc_mem_access_resume(xc_interface *xch, domid_t domain_id, unsigned long gfn)
+{
+ return xc_mem_event_control(xch, domain_id,
+ XEN_DOMCTL_MEM_EVENT_OP_ACCESS_RESUME,
+ XEN_DOMCTL_MEM_EVENT_OP_ACCESS, NULL, NULL,
+ gfn);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c
index 47f97c55f2..f4004b1d82 100644
--- a/tools/libxc/xc_misc.c
+++ b/tools/libxc/xc_misc.c
@@ -511,6 +511,66 @@ int xc_hvm_set_mem_type(
return rc;
}
+int xc_hvm_set_mem_access(
+ xc_interface *xch, domid_t dom, hvmmem_access_t mem_access, uint64_t first_pfn, uint64_t nr)
+{
+ DECLARE_HYPERCALL;
+ DECLARE_HYPERCALL_BUFFER(struct xen_hvm_set_mem_access, arg);
+ int rc;
+
+ arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
+ if ( arg == NULL )
+ {
+ PERROR("Could not allocate memory for xc_hvm_set_mem_access hypercall");
+ return -1;
+ }
+
+ arg->domid = dom;
+ arg->hvmmem_access = mem_access;
+ arg->first_pfn = first_pfn;
+ arg->nr = nr;
+
+ hypercall.op = __HYPERVISOR_hvm_op;
+ hypercall.arg[0] = HVMOP_set_mem_access;
+ hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg);
+
+ rc = do_xen_hypercall(xch, &hypercall);
+
+ xc_hypercall_buffer_free(xch, arg);
+
+ return rc;
+}
+
+int xc_hvm_get_mem_access(
+ xc_interface *xch, domid_t dom, uint64_t pfn, hvmmem_access_t* mem_access)
+{
+ DECLARE_HYPERCALL;
+ DECLARE_HYPERCALL_BUFFER(struct xen_hvm_get_mem_access, arg);
+ int rc;
+
+ arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
+ if ( arg == NULL )
+ {
+ PERROR("Could not allocate memory for xc_hvm_get_mem_access hypercall");
+ return -1;
+ }
+
+ arg->domid = dom;
+ arg->pfn = pfn;
+
+ hypercall.op = __HYPERVISOR_hvm_op;
+ hypercall.arg[0] = HVMOP_get_mem_access;
+ hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg);
+
+ rc = do_xen_hypercall(xch, &hypercall);
+
+ if ( !rc )
+ *mem_access = arg->hvmmem_access;
+
+ xc_hypercall_buffer_free(xch, arg);
+
+ return rc;
+}
/*
* Local variables:
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 4827303b73..aec258662f 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -701,6 +701,19 @@ int xc_domain_setdebugging(xc_interface *xch,
uint32_t domid,
unsigned int enable);
+/**
+ * This function sets or clears the requirement that an access memory
+ * event listener is required on the domain.
+ *
+ * @parm xch a handle to an open hypervisor interface
+ * @parm domid the domain id to send trigger
+ * @parm enable true to require a listener
+ * return 0 on success, -1 on failure
+ */
+int xc_domain_set_access_required(xc_interface *xch,
+ uint32_t domid,
+ unsigned int required);
+
/*
* CPUPOOL MANAGEMENT FUNCTIONS
*/
@@ -1398,6 +1411,19 @@ int xc_hvm_modified_memory(
int xc_hvm_set_mem_type(
xc_interface *xch, domid_t dom, hvmmem_type_t memtype, uint64_t first_pfn, uint64_t nr);
+/*
+ * Set a range of memory to a specific access.
+ * Allowed types are HVMMEM_access_default, HVMMEM_access_n, any combination of
+ * HVM_access_ + (rwx), and HVM_access_rx2rw
+ */
+int xc_hvm_set_mem_access(
+ xc_interface *xch, domid_t dom, hvmmem_access_t memaccess, uint64_t first_pfn, uint64_t nr);
+
+/*
+ * Gets the mem access for the given page (returned in memacess on success)
+ */
+int xc_hvm_get_mem_access(
+ xc_interface *xch, domid_t dom, uint64_t pfn, hvmmem_access_t* memaccess);
/*
* LOGGING AND ERROR REPORTING
@@ -1704,6 +1730,8 @@ int xc_mem_paging_evict(xc_interface *xch, domid_t domain_id, unsigned long gfn)
int xc_mem_paging_prep(xc_interface *xch, domid_t domain_id, unsigned long gfn);
int xc_mem_paging_resume(xc_interface *xch, domid_t domain_id,
unsigned long gfn);
+int xc_mem_access_resume(xc_interface *xch, domid_t domain_id,
+ unsigned long gfn);
/**
* memshr operations
diff --git a/xen/arch/ia64/vmx/vmx_hypercall.c b/xen/arch/ia64/vmx/vmx_hypercall.c
index 451074e450..94e0850547 100644
--- a/xen/arch/ia64/vmx/vmx_hypercall.c
+++ b/xen/arch/ia64/vmx/vmx_hypercall.c
@@ -218,6 +218,9 @@ do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
}
case HVMOP_set_mem_type:
+ case HVMOP_set_mem_access:
+ case HVMOP_get_mem_access:
+
rc = -ENOSYS;
break;
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 655dbcb768..d2107db3d3 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3464,6 +3464,149 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
break;
}
+ case HVMOP_set_mem_access:
+ {
+ struct xen_hvm_set_mem_access a;
+ struct domain *d;
+ struct p2m_domain *p2m;
+ unsigned long pfn;
+
+ p2m_access_t memaccess[] = {
+ p2m_access_n,
+ p2m_access_r,
+ p2m_access_w,
+ p2m_access_rw,
+ p2m_access_x,
+ p2m_access_rx,
+ p2m_access_wx,
+ p2m_access_rwx,
+ p2m_access_rx2rw,
+ 0, /* HVMMEM_access_default -- will get set below */
+ };
+
+ if ( copy_from_guest(&a, arg, 1) )
+ return -EFAULT;
+
+ if ( current->domain->domain_id == a.domid )
+ return -EPERM;
+
+ rc = rcu_lock_target_domain_by_id(a.domid, &d);
+ if ( rc != 0 )
+ return rc;
+
+ rc = -EINVAL;
+ if ( !is_hvm_domain(d) )
+ goto param_fail5;
+
+ p2m = p2m_get_hostp2m(d);
+ memaccess[HVMMEM_access_default] = p2m->default_access;
+
+ /* If request to set default access */
+ if ( a.first_pfn == ~0ull )
+ {
+ rc = 0;
+ p2m->default_access = memaccess[a.hvmmem_access];
+ goto param_fail5;
+ }
+
+ rc = -EINVAL;
+ if ( (a.first_pfn > domain_get_maximum_gpfn(d)) ||
+ ((a.first_pfn + a.nr - 1) < a.first_pfn) ||
+ ((a.first_pfn + a.nr - 1) > domain_get_maximum_gpfn(d)) )
+ goto param_fail5;
+
+ if ( a.hvmmem_access >= ARRAY_SIZE(memaccess) )
+ goto param_fail5;
+
+ for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ )
+ {
+ p2m_type_t t;
+ mfn_t mfn;
+ int success;
+
+ mfn = gfn_to_mfn_unshare(p2m, pfn, &t, 0);
+
+ p2m_lock(p2m);
+ success = p2m->set_entry(p2m, pfn, mfn, 0, t, memaccess[a.hvmmem_access]);
+ p2m_unlock(p2m);
+ if ( !success )
+ goto param_fail5;
+ }
+
+ rc = 0;
+
+ param_fail5:
+ rcu_unlock_domain(d);
+ break;
+ }
+
+ case HVMOP_get_mem_access:
+ {
+ struct xen_hvm_get_mem_access a;
+ struct domain *d;
+ struct p2m_domain *p2m;
+ p2m_type_t t;
+ p2m_access_t ac;
+ mfn_t mfn;
+
+ /* Interface access to internal p2m accesses */
+ hvmmem_access_t memaccess[] = {
+ HVMMEM_access_n,
+ HVMMEM_access_r,
+ HVMMEM_access_w,
+ HVMMEM_access_rw,
+ HVMMEM_access_x,
+ HVMMEM_access_rx,
+ HVMMEM_access_wx,
+ HVMMEM_access_rwx,
+ HVMMEM_access_rx2rw
+ };
+
+ if ( copy_from_guest(&a, arg, 1) )
+ return -EFAULT;
+
+ if ( current->domain->domain_id == a.domid )
+ return -EPERM;
+
+ rc = rcu_lock_target_domain_by_id(a.domid, &d);
+ if ( rc != 0 )
+ return rc;
+
+ rc = -EINVAL;
+ if ( !is_hvm_domain(d) )
+ goto param_fail6;
+
+ p2m = p2m_get_hostp2m(d);
+
+ if ( a.pfn == ~0ull )
+ {
+ a.hvmmem_access = memaccess[p2m->default_access];
+ }
+ else {
+ rc = -EINVAL;
+ if ( (a.pfn > domain_get_maximum_gpfn(d)) )
+ goto param_fail6;
+
+ rc = -ESRCH;
+ mfn = p2m->get_entry(p2m, a.pfn, &t, &ac, p2m_query);
+
+ if ( mfn_x(mfn) == INVALID_MFN )
+ goto param_fail6;
+
+ rc = -ERANGE;
+ if ( ac >= ARRAY_SIZE(memaccess) )
+ goto param_fail6;
+
+ a.hvmmem_access = memaccess[ac];
+ }
+
+ rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0;
+
+ param_fail6:
+ rcu_unlock_domain(d);
+ break;
+ }
+
case HVMOP_pagetable_dying:
{
struct xen_hvm_pagetable_dying a;
@@ -3478,12 +3621,12 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
rc = -EINVAL;
if ( !is_hvm_domain(d) || !paging_mode_shadow(d) )
- goto param_fail5;
+ goto param_fail7;
rc = 0;
pagetable_dying(d, a.gpa);
- param_fail5:
+ param_fail7:
rcu_unlock_domain(d);
break;
}
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index e3d0f6cdc7..78ab1bd684 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -304,6 +304,8 @@ static struct page_info* mem_sharing_alloc_page(struct domain *d,
if(page != NULL) return page;
memset(&req, 0, sizeof(req));
+ req.type = MEM_EVENT_TYPE_SHARED;
+
if(must_succeed)
{
/* We do not support 'must_succeed' any more. External operations such
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 4abe1134ae..849c0b87eb 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -2781,6 +2781,7 @@ void p2m_mem_paging_populate(struct p2m_domain *p2m, unsigned long gfn)
return;
memset(&req, 0, sizeof(req));
+ req.type = MEM_EVENT_TYPE_PAGING;
/* Fix p2m mapping */
/* XXX: It seems inefficient to have this here, as it's only needed
diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h
index d93dd6b836..3ea1f5ce5b 100644
--- a/xen/include/public/hvm/hvm_op.h
+++ b/xen/include/public/hvm/hvm_op.h
@@ -158,4 +158,46 @@ struct xen_hvm_xentrace {
typedef struct xen_hvm_xentrace xen_hvm_xentrace_t;
DEFINE_XEN_GUEST_HANDLE(xen_hvm_xentrace_t);
+#define HVMOP_set_mem_access 12
+typedef enum {
+ HVMMEM_access_n,
+ HVMMEM_access_r,
+ HVMMEM_access_w,
+ HVMMEM_access_rw,
+ HVMMEM_access_x,
+ HVMMEM_access_rx,
+ HVMMEM_access_wx,
+ HVMMEM_access_rwx,
+ HVMMEM_access_rx2rw, /* Page starts off as read-execute, but automatically change
+ * to read-write on a write */
+ HVMMEM_access_default /* Take the domain default */
+} hvmmem_access_t;
+/* Notify that a region of memory is to have specific access types */
+struct xen_hvm_set_mem_access {
+ /* Domain to be updated. */
+ domid_t domid;
+ uint16_t pad[3]; /* align next field on 8-byte boundary */
+ /* Memory type */
+ uint64_t hvmmem_access; /* hvm_access_t */
+ /* First pfn, or ~0ull to set the default access for new pages */
+ uint64_t first_pfn;
+ /* Number of pages, ignored on setting default access */
+ uint64_t nr;
+};
+typedef struct xen_hvm_set_mem_access xen_hvm_set_mem_access_t;
+DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_mem_access_t);
+
+#define HVMOP_get_mem_access 13
+/* Get the specific access type for that region of memory */
+struct xen_hvm_get_mem_access {
+ /* Domain to be queried. */
+ domid_t domid;
+ uint16_t pad[3]; /* align next field on 8-byte boundary */
+ /* Memory type: OUT */
+ uint64_t hvmmem_access; /* hvm_access_t */
+ /* pfn, or ~0ull for default access for new pages. IN */
+ uint64_t pfn;
+};
+typedef struct xen_hvm_get_mem_access xen_hvm_get_mem_access_t;
+DEFINE_XEN_GUEST_HANDLE(xen_hvm_get_mem_access_t);
#endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */