domctl support for generic memory event handling.
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 17 Dec 2009 06:27:55 +0000 (06:27 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 17 Dec 2009 06:27:55 +0000 (06:27 +0000)
Signed-off-by: Patrick Colp <Patrick.Colp@citrix.com>
xen/arch/x86/domctl.c
xen/arch/x86/mm/mem_event.c
xen/include/asm-x86/mem_event.h
xen/include/public/domctl.h

index ece40141bf3767b27cf35610254cd503b1f2dfe2..d38b61e30370e22fc8f0e838af98eb9ce47c1a04 100644 (file)
@@ -30,6 +30,8 @@
 #include <asm/hypercall.h> /* for arch_do_domctl */
 #include <xsm/xsm.h>
 #include <xen/iommu.h>
+#include <asm/mem_event.h>
+#include <public/mem_event.h>
 
 #ifdef XEN_GDBSX_CONFIG                    
 #ifdef XEN_KDB_CONFIG
@@ -1299,6 +1301,22 @@ long arch_do_domctl(
     break;
 #endif /* XEN_GDBSX_CONFIG */
 
+    case XEN_DOMCTL_mem_event_op:
+    {
+        struct domain *d;
+
+        ret = -ESRCH;
+        d = rcu_lock_domain_by_id(domctl->domain);
+        if ( d != NULL )
+        {
+            ret = mem_event_domctl(d, &domctl->u.mem_event_op,
+                                   guest_handle_cast(u_domctl, void));
+            rcu_unlock_domain(d);
+            copy_to_guest(u_domctl, domctl, 1);
+        } 
+    }
+    break;
+
     default:
         ret = -ENOSYS;
         break;
index 0448bd51d9e0ee817e0a9eb7e992dfe18fc1fae1..5701bfee421191c98b9f2a25c6f2ab6acc4c06c7 100644 (file)
@@ -188,6 +188,97 @@ int mem_event_check_ring(struct domain *d)
     return ring_full;
 }
 
+int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
+                     XEN_GUEST_HANDLE(void) u_domctl)
+{
+    int rc;
+
+    if ( unlikely(d == current->domain) )
+    {
+        gdprintk(XENLOG_INFO, "Tried to do a memory paging op on itself.\n");
+        return -EINVAL;
+    }
+
+    if ( unlikely(d->is_dying) )
+    {
+        gdprintk(XENLOG_INFO, "Ignoring memory paging op on dying domain %u\n",
+                 d->domain_id);
+        return 0;
+    }
+
+    if ( unlikely(d->vcpu == NULL) || unlikely(d->vcpu[0] == NULL) )
+    {
+        MEM_EVENT_ERROR("Memory paging op on a domain (%u) with no vcpus\n",
+                         d->domain_id);
+        return -EINVAL;
+    }
+
+    /* TODO: XSM hook */
+#if 0
+    rc = xsm_mem_event_control(d, mec->op);
+    if ( rc )
+        return rc;
+#endif
+
+    if ( mec->mode == 0 )
+    {
+        switch( mec->op )
+        {
+        case XEN_DOMCTL_MEM_EVENT_OP_ENABLE:
+        {
+            struct domain *dom_mem_event = current->domain;
+            struct vcpu *v = current;
+            unsigned long ring_addr = mec->ring_addr;
+            unsigned long shared_addr = mec->shared_addr;
+            l1_pgentry_t l1e;
+            unsigned long gfn;
+            p2m_type_t p2mt;
+            mfn_t ring_mfn;
+            mfn_t shared_mfn;
+
+            /* Get MFN of ring page */
+            guest_get_eff_l1e(v, ring_addr, &l1e);
+            gfn = l1e_get_pfn(l1e);
+            ring_mfn = gfn_to_mfn(dom_mem_event, gfn, &p2mt);
+
+            rc = -EINVAL;
+            if ( unlikely(!mfn_valid(mfn_x(ring_mfn))) )
+                break;
+
+            /* Get MFN of shared page */
+            guest_get_eff_l1e(v, shared_addr, &l1e);
+            gfn = l1e_get_pfn(l1e);
+            shared_mfn = gfn_to_mfn(dom_mem_event, gfn, &p2mt);
+
+            rc = -EINVAL;
+            if ( unlikely(!mfn_valid(mfn_x(shared_mfn))) )
+                break;
+
+            rc = -EINVAL;
+            if ( mem_event_enable(d, ring_mfn, shared_mfn) != 0 )
+                break;
+
+            rc = 0;
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_EVENT_OP_DISABLE:
+        {
+            rc = mem_event_disable(d);
+        }
+        break;
+
+        default:
+            rc = -ENOSYS;
+            break;
+        }
+    }
+    else
+        rc = -ENOSYS;
+
+    return rc;
+}
+
 
 /*
  * Local variables:
index 91d6ab3a20ba652026998ddabd4a9e7e1756d601..37e3064a37ba704f3752dcf6ff7c169bf8290e35 100644 (file)
@@ -54,6 +54,9 @@ void mem_event_put_request(struct domain *d, mem_event_request_t *req);
 void mem_event_get_response(struct domain *d, mem_event_response_t *rsp);
 void mem_event_unpause_vcpus(struct domain *d);
 
+int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
+                     XEN_GUEST_HANDLE(void) u_domctl);
+
 
 #endif /* __MEM_EVENT_H__ */
 
index 88b19a4ffe1835722eadbe924447817a23791932..7a378a3519932df9bea191ace1edc2187921093b 100644 (file)
@@ -691,6 +691,31 @@ struct xen_domctl_gdbsx_domstatus {
 
 };
 
+/*
+ * Memory event operations
+ */
+
+#define XEN_DOMCTL_mem_event_op  56
+
+/* Add and remove memory handlers */
+#define XEN_DOMCTL_MEM_EVENT_OP_ENABLE     0
+#define XEN_DOMCTL_MEM_EVENT_OP_DISABLE    1
+
+struct xen_domctl_mem_event_op {
+    uint32_t       op;           /* XEN_DOMCTL_MEM_EVENT_OP_* */
+    uint32_t       mode;         /* XEN_DOMCTL_MEM_EVENT_ENABLE_* */
+
+    /* OP_ENABLE */
+    unsigned long  shared_addr;  /* IN:  Virtual address of shared page */
+    unsigned long  ring_addr;    /* IN:  Virtual address of ring page */
+
+    /* Other OPs */
+    unsigned long  gfn;          /* IN:  gfn of page being operated on */
+};
+typedef struct xen_domctl_mem_event_op xen_domctl_mem_event_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_mem_event_op_t);
+
+
 struct xen_domctl {
     uint32_t cmd;
     uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
@@ -734,6 +759,7 @@ struct xen_domctl {
         struct xen_domctl_set_target        set_target;
         struct xen_domctl_subscribe         subscribe;
         struct xen_domctl_debug_op          debug_op;
+        struct xen_domctl_mem_event_op      mem_event_op;
 #if defined(__i386__) || defined(__x86_64__)
         struct xen_domctl_cpuid             cpuid;
 #endif