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

[Xen-devel] [PATCH 9/9] xen-access: Add support for vm_event_ng interface



Split xen-access in order to accommodate both vm_event interfaces
(legacy and NG). By default, the legacy vm_event is selected but
this can be changed by adding the '-n' flag in the command line.

Signed-off-by: Petre Pircalabu <ppircalabu@xxxxxxxxxxxxxxx>
---
 tools/tests/xen-access/Makefile      |   7 +-
 tools/tests/xen-access/vm-event-ng.c | 210 ++++++++++++++++++
 tools/tests/xen-access/vm-event.c    | 193 +++++++++++++++++
 tools/tests/xen-access/xen-access.c  | 408 +++++++++++++----------------------
 tools/tests/xen-access/xen-access.h  |  91 ++++++++
 5 files changed, 644 insertions(+), 265 deletions(-)
 create mode 100644 tools/tests/xen-access/vm-event-ng.c
 create mode 100644 tools/tests/xen-access/vm-event.c
 create mode 100644 tools/tests/xen-access/xen-access.h

diff --git a/tools/tests/xen-access/Makefile b/tools/tests/xen-access/Makefile
index 131c9f3..17760d8 100644
--- a/tools/tests/xen-access/Makefile
+++ b/tools/tests/xen-access/Makefile
@@ -7,6 +7,7 @@ CFLAGS += -DXC_WANT_COMPAT_DEVICEMODEL_API
 CFLAGS += $(CFLAGS_libxenctrl)
 CFLAGS += $(CFLAGS_libxenguest)
 CFLAGS += $(CFLAGS_libxenevtchn)
+CFLAGS += $(CFLAGS_libxenforeignmemory)
 CFLAGS += $(CFLAGS_xeninclude)
 
 TARGETS-y := xen-access
@@ -25,8 +26,10 @@ clean:
 .PHONY: distclean
 distclean: clean
 
-xen-access: xen-access.o Makefile
-       $(CC) -o $@ $< $(LDFLAGS) $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) 
$(LDLIBS_libxenevtchn)
+OBJS = xen-access.o vm-event.o vm-event-ng.o
+
+xen-access: $(OBJS) Makefile
+       $(CC) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS_libxenctrl) 
$(LDLIBS_libxenguest) $(LDLIBS_libxenevtchn) $(LDLIBS_libxenforeignmemory)
 
 install uninstall:
 
diff --git a/tools/tests/xen-access/vm-event-ng.c 
b/tools/tests/xen-access/vm-event-ng.c
new file mode 100644
index 0000000..9177cfc
--- /dev/null
+++ b/tools/tests/xen-access/vm-event-ng.c
@@ -0,0 +1,210 @@
+/*
+ * vm-event-ng.c
+ *
+ * Copyright (c) 2019 Bitdefender S.R.L.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <xenforeignmemory.h>
+#include "xen-access.h"
+
+#ifndef PFN_UP
+#define PFN_UP(x)     (((x) + XC_PAGE_SIZE-1) >> XC_PAGE_SHIFT)
+#endif /* PFN_UP */
+
+typedef struct vm_event_channels
+{
+    vm_event_t vme;
+    int num_vcpus;
+    xenforeignmemory_handle *fmem;
+    xenforeignmemory_resource_handle *fres;
+    struct vm_event_slot *slots;
+    int ports[0];
+} vm_event_channels_t;
+
+#define to_channels(_vme) container_of((_vme), vm_event_channels_t, vme)
+
+static int vm_event_channels_init(xc_interface *xch, xenevtchn_handle *xce,
+                                  domid_t domain_id, vm_event_ops_t *ops,
+                                  vm_event_t **vm_event)
+{
+    vm_event_channels_t *impl = NULL;
+    int rc, i, num_vcpus;
+    xc_dominfo_t info;
+    unsigned long nr_frames;
+
+    /* Get the numbers of vcpus */
+    rc = xc_domain_getinfo(xch, domain_id, 1, &info);
+    if ( rc != 1 )
+    {
+        ERROR("xc_domain_getinfo failed. rc = %d\n", rc);
+        return rc;
+    }
+
+    num_vcpus = info.max_vcpu_id + 1;
+
+    impl = (vm_event_channels_t *)calloc(1, sizeof(vm_event_channels_t) +
+                                            num_vcpus * sizeof(int));
+    if ( !impl )
+        return -ENOMEM;
+
+    impl->num_vcpus = num_vcpus;
+
+    impl->fmem = xenforeignmemory_open(0,0);
+    if ( !impl->fmem )
+    {
+        rc = -errno;
+        goto err;
+    }
+
+    rc = xc_monitor_ng_create(xch, domain_id);
+    if ( rc )
+    {
+        ERROR("Failed to enable monitor");
+        goto err;
+    }
+
+    nr_frames = PFN_UP(num_vcpus * sizeof(struct vm_event_slot));
+
+    impl->fres = xenforeignmemory_map_resource(impl->fmem, domain_id,
+                                               XENMEM_resource_vm_event,
+                                               XEN_VM_EVENT_TYPE_MONITOR, 0,
+                                               nr_frames, (void*)&impl->slots,
+                                               PROT_READ | PROT_WRITE, 0);
+    if ( !impl->fres )
+    {
+        ERROR("Failed to map vm_event resource");
+        rc = -errno;
+        goto err;
+    }
+
+    for ( i = 0; i < impl->num_vcpus; i++)
+    {
+        rc = xenevtchn_bind_interdomain(xce, domain_id, impl->slots[i].port);
+        if (  rc < 0 )
+        {
+            ERROR("Failed to bind vm_event_slot port for vcpu %d", i);
+            rc = -errno;
+            goto err;
+        }
+
+        impl->ports[i] = rc;
+    }
+
+    rc = xc_monitor_ng_set_state(xch, domain_id, true);
+    if (  rc < 0 )
+    {
+        ERROR("Failed to start monitor rc = %d", rc);
+        goto err;
+    }
+
+
+    *vm_event = (vm_event_t*) impl;
+    return 0;
+
+err:
+    xc_monitor_ng_destroy(xch, domain_id);
+    xenforeignmemory_unmap_resource(impl->fmem, impl->fres);
+    xenforeignmemory_close(impl->fmem);
+    free(impl);
+    return rc;
+}
+
+static int vcpu_id_by_port(vm_event_channels_t *impl, int port, int *vcpu_id)
+{
+    int i;
+
+    for ( i = 0; i < impl->num_vcpus; i++ )
+    {
+        if ( port == impl->ports[i] )
+        {
+            *vcpu_id = i;
+            return 0;
+        }
+    }
+
+    return -EINVAL;
+}
+
+static int vm_event_channels_teardown(vm_event_t *vm_event)
+{
+    vm_event_channels_t *impl = to_channels(vm_event);
+
+    xc_monitor_ng_destroy(impl->vme.xch, impl->vme.domain_id);
+    xenforeignmemory_unmap_resource(impl->fmem, impl->fres);
+    xenforeignmemory_close(impl->fmem);
+
+    return 0;
+}
+
+static bool vm_event_channels_get_request(vm_event_t *vm_event, 
vm_event_request_t *req, int *port)
+{
+    int vcpu_id;
+    vm_event_channels_t *impl = to_channels(vm_event);
+
+    if ( vcpu_id_by_port(impl, *port, &vcpu_id) != 0 )
+        return false;
+
+    if ( impl->slots[vcpu_id].state != STATE_VM_EVENT_SLOT_SUBMIT )
+        return false;
+
+    memcpy(req, &impl->slots[vcpu_id].u.req, sizeof(*req));
+
+    return true;
+}
+
+static void vm_event_channels_put_response(vm_event_t *vm_event, 
vm_event_response_t *rsp, int port)
+{
+    int vcpu_id;
+    vm_event_channels_t *impl = to_channels(vm_event);
+
+    if ( vcpu_id_by_port(impl, port, &vcpu_id) != 0 )
+        return;
+
+    memcpy(&impl->slots[vcpu_id].u.rsp, rsp, sizeof(*rsp));
+    impl->slots[vcpu_id].state = STATE_VM_EVENT_SLOT_FINISH;
+}
+
+static int vm_event_channels_notify_port(vm_event_t *vm_event, int port)
+{
+    return xenevtchn_notify(vm_event->xce, port);
+}
+
+vm_event_ops_t channel_ops = {
+    .get_request = vm_event_channels_get_request,
+    .put_response = vm_event_channels_put_response,
+    .notify_port = vm_event_channels_notify_port,
+    .init = vm_event_channels_init,
+    .teardown = vm_event_channels_teardown
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+- */
diff --git a/tools/tests/xen-access/vm-event.c 
b/tools/tests/xen-access/vm-event.c
new file mode 100644
index 0000000..ffd5476
--- /dev/null
+++ b/tools/tests/xen-access/vm-event.c
@@ -0,0 +1,193 @@
+/*
+ * vm-event.c
+ *
+ * Copyright (c) 2019 Bitdefender S.R.L.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include "xen-access.h"
+
+typedef struct vm_event_ring {
+    vm_event_t vme;
+    int port;
+    vm_event_back_ring_t back_ring;
+    uint32_t evtchn_port;
+    void *ring_page;
+} vm_event_ring_t;
+
+#define to_ring(_vme) container_of((_vme), vm_event_ring_t, vme)
+
+static int vm_event_ring_init(xc_interface *xch, xenevtchn_handle *xce,
+                              domid_t domain_id, vm_event_ops_t *ops,
+                              vm_event_t **vm_event)
+{
+    vm_event_ring_t *impl;
+    int rc;
+
+    impl = (vm_event_ring_t*) calloc (1, sizeof(vm_event_ring_t));
+    if ( !impl )
+        return -ENOMEM;
+
+    /* Enable mem_access */
+    impl->ring_page = xc_monitor_enable(xch, domain_id, &impl->evtchn_port);
+    if ( impl->ring_page == NULL )
+    {
+        switch ( errno ) {
+            case EBUSY:
+                ERROR("xenaccess is (or was) active on this domain");
+                break;
+            case ENODEV:
+                ERROR("EPT not supported for this guest");
+                break;
+            default:
+                perror("Error enabling mem_access");
+                break;
+        }
+        rc = -errno;
+        goto err;
+    }
+
+    /* Bind event notification */
+    rc = xenevtchn_bind_interdomain(xce, domain_id, impl->evtchn_port);
+    if ( rc < 0 )
+    {
+        ERROR("Failed to bind event channel");
+        munmap(impl->ring_page, XC_PAGE_SIZE);
+        xc_monitor_disable(xch, domain_id);
+        goto err;
+    }
+
+    impl->port = rc;
+
+    /* Initialise ring */
+    SHARED_RING_INIT((vm_event_sring_t *)impl->ring_page);
+    BACK_RING_INIT(&impl->back_ring, (vm_event_sring_t *)impl->ring_page,
+                   XC_PAGE_SIZE);
+
+    *vm_event = (vm_event_t*) impl;
+    return 0;
+
+err:
+    free(impl);
+    return rc;
+}
+
+static int vm_event_ring_teardown(vm_event_t *vm_event)
+{
+    vm_event_ring_t *impl = to_ring(vm_event);
+    int rc;
+
+    if ( impl->ring_page )
+        munmap(impl->ring_page, XC_PAGE_SIZE);
+
+    /* Tear down domain xenaccess in Xen */
+    rc = xc_monitor_disable(vm_event->xch, vm_event->domain_id);
+    if ( rc != 0 )
+    {
+        ERROR("Error tearing down domain xenaccess in xen");
+        return rc;
+    }
+
+    /* Unbind VIRQ */
+    rc = xenevtchn_unbind(vm_event->xce, impl->port);
+    if ( rc != 0 )
+    {
+        ERROR("Error unbinding event port");
+        return rc;
+    }
+
+    return 0;
+}
+
+/*
+ * Note that this function is not thread safe.
+ */
+static bool vm_event_ring_get_request(vm_event_t *vm_event, vm_event_request_t 
*req, int *port)
+{
+    vm_event_back_ring_t *back_ring;
+    RING_IDX req_cons;
+    vm_event_ring_t *impl = to_ring(vm_event);
+
+    if ( !RING_HAS_UNCONSUMED_REQUESTS(&impl->back_ring) )
+        return false;
+
+    back_ring = &impl->back_ring;
+    req_cons = back_ring->req_cons;
+
+    /* Copy request */
+    memcpy(req, RING_GET_REQUEST(back_ring, req_cons), sizeof(*req));
+    req_cons++;
+
+    /* Update ring */
+    back_ring->req_cons = req_cons;
+    back_ring->sring->req_event = req_cons + 1;
+
+    *port = impl->port;
+
+    return true;
+}
+
+/*
+ * Note that this function is not thread safe.
+ */
+static void vm_event_ring_put_response(vm_event_t *vm_event, 
vm_event_response_t *rsp, int port)
+{
+    vm_event_back_ring_t *back_ring;
+    RING_IDX rsp_prod;
+    vm_event_ring_t *impl = to_ring(vm_event);
+
+    back_ring = &impl->back_ring;
+    rsp_prod = back_ring->rsp_prod_pvt;
+
+    /* Copy response */
+    memcpy(RING_GET_RESPONSE(back_ring, rsp_prod), rsp, sizeof(*rsp));
+    rsp_prod++;
+
+    /* Update ring */
+    back_ring->rsp_prod_pvt = rsp_prod;
+    RING_PUSH_RESPONSES(back_ring);
+}
+
+static int vm_event_ring_notify_port(vm_event_t *vm_event, int port)
+{
+    return xenevtchn_notify(vm_event->xce, port);
+}
+
+vm_event_ops_t ring_ops = {
+    .get_request = vm_event_ring_get_request,
+    .put_response = vm_event_ring_put_response,
+    .notify_port = vm_event_ring_notify_port,
+    .init = vm_event_ring_init,
+    .teardown = vm_event_ring_teardown
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/tests/xen-access/xen-access.c 
b/tools/tests/xen-access/xen-access.c
index 6aaee16..267d163 100644
--- a/tools/tests/xen-access/xen-access.c
+++ b/tools/tests/xen-access/xen-access.c
@@ -35,12 +35,8 @@
 #include <time.h>
 #include <signal.h>
 #include <unistd.h>
-#include <sys/mman.h>
 #include <poll.h>
-
-#include <xenctrl.h>
-#include <xenevtchn.h>
-#include <xen/vm_event.h>
+#include <getopt.h>
 
 #include <xen-tools/libs.h>
 
@@ -51,9 +47,7 @@
 #define START_PFN 0ULL
 #endif
 
-#define DPRINTF(a, b...) fprintf(stderr, a, ## b)
-#define ERROR(a, b...) fprintf(stderr, a "\n", ## b)
-#define PERROR(a, b...) fprintf(stderr, a ": %s\n", ## b, strerror(errno))
+#include "xen-access.h"
 
 /* From xen/include/asm-x86/processor.h */
 #define X86_TRAP_DEBUG  1
@@ -62,32 +56,14 @@
 /* From xen/include/asm-x86/x86-defns.h */
 #define X86_CR4_PGE        0x00000080 /* enable global pages */
 
-typedef struct vm_event {
-    domid_t domain_id;
-    xenevtchn_handle *xce_handle;
-    int port;
-    vm_event_back_ring_t back_ring;
-    uint32_t evtchn_port;
-    void *ring_page;
-} vm_event_t;
-
-typedef struct xenaccess {
-    xc_interface *xc_handle;
-
-    xen_pfn_t max_gpfn;
-
-    vm_event_t vm_event;
-} xenaccess_t;
-
 static int interrupted;
-bool evtchn_bind = 0, evtchn_open = 0, mem_access_enable = 0;
 
 static void close_handler(int sig)
 {
     interrupted = sig;
 }
 
-int xc_wait_for_event_or_timeout(xc_interface *xch, xenevtchn_handle *xce, 
unsigned long ms)
+static int xc_wait_for_event_or_timeout(xc_interface *xch, xenevtchn_handle 
*xce, unsigned long ms)
 {
     struct pollfd fd = { .fd = xenevtchn_fd(xce), .events = POLLIN | POLLERR };
     int port;
@@ -128,160 +104,86 @@ int xc_wait_for_event_or_timeout(xc_interface *xch, 
xenevtchn_handle *xce, unsig
     return -errno;
 }
 
-int xenaccess_teardown(xc_interface *xch, xenaccess_t *xenaccess)
+static int vm_event_teardown(vm_event_t *vm_event)
 {
     int rc;
 
-    if ( xenaccess == NULL )
+    if ( vm_event == NULL )
         return 0;
 
-    /* Tear down domain xenaccess in Xen */
-    if ( xenaccess->vm_event.ring_page )
-        munmap(xenaccess->vm_event.ring_page, XC_PAGE_SIZE);
-
-    if ( mem_access_enable )
-    {
-        rc = xc_monitor_disable(xenaccess->xc_handle,
-                                xenaccess->vm_event.domain_id);
-        if ( rc != 0 )
-        {
-            ERROR("Error tearing down domain xenaccess in xen");
-            return rc;
-        }
-    }
-
-    /* Unbind VIRQ */
-    if ( evtchn_bind )
-    {
-        rc = xenevtchn_unbind(xenaccess->vm_event.xce_handle,
-                              xenaccess->vm_event.port);
-        if ( rc != 0 )
-        {
-            ERROR("Error unbinding event port");
-            return rc;
-        }
-    }
+    rc = vm_event->ops->teardown(vm_event);
+    if ( rc != 0 )
+        return rc;
 
     /* Close event channel */
-    if ( evtchn_open )
+    rc = xenevtchn_close(vm_event->xce);
+    if ( rc != 0 )
     {
-        rc = xenevtchn_close(xenaccess->vm_event.xce_handle);
-        if ( rc != 0 )
-        {
-            ERROR("Error closing event channel");
-            return rc;
-        }
+        ERROR("Error closing event channel");
+        return rc;
     }
 
     /* Close connection to Xen */
-    rc = xc_interface_close(xenaccess->xc_handle);
+    rc = xc_interface_close(vm_event->xch);
     if ( rc != 0 )
     {
         ERROR("Error closing connection to xen");
         return rc;
     }
-    xenaccess->xc_handle = NULL;
-
-    free(xenaccess);
 
     return 0;
 }
 
-xenaccess_t *xenaccess_init(xc_interface **xch_r, domid_t domain_id)
+static vm_event_t *vm_event_init(domid_t domain_id, vm_event_ops_t *ops)
 {
-    xenaccess_t *xenaccess = 0;
+    vm_event_t *vm_event;
     xc_interface *xch;
+    xenevtchn_handle *xce;
+    xen_pfn_t max_gpfn;
     int rc;
 
+    if ( !ops )
+        return NULL;
+
     xch = xc_interface_open(NULL, NULL, 0);
     if ( !xch )
-        goto err_iface;
+        goto err;
 
     DPRINTF("xenaccess init\n");
-    *xch_r = xch;
-
-    /* Allocate memory */
-    xenaccess = malloc(sizeof(xenaccess_t));
-    memset(xenaccess, 0, sizeof(xenaccess_t));
-
-    /* Open connection to xen */
-    xenaccess->xc_handle = xch;
-
-    /* Set domain id */
-    xenaccess->vm_event.domain_id = domain_id;
-
-    /* Enable mem_access */
-    xenaccess->vm_event.ring_page =
-            xc_monitor_enable(xenaccess->xc_handle,
-                              xenaccess->vm_event.domain_id,
-                              &xenaccess->vm_event.evtchn_port);
-    if ( xenaccess->vm_event.ring_page == NULL )
-    {
-        switch ( errno ) {
-            case EBUSY:
-                ERROR("xenaccess is (or was) active on this domain");
-                break;
-            case ENODEV:
-                ERROR("EPT not supported for this guest");
-                break;
-            default:
-                perror("Error enabling mem_access");
-                break;
-        }
-        goto err;
-    }
-    mem_access_enable = 1;
 
     /* Open event channel */
-    xenaccess->vm_event.xce_handle = xenevtchn_open(NULL, 0);
-    if ( xenaccess->vm_event.xce_handle == NULL )
+    xce = xenevtchn_open(NULL, 0);
+    if ( !xce )
     {
         ERROR("Failed to open event channel");
         goto err;
     }
-    evtchn_open = 1;
-
-    /* Bind event notification */
-    rc = xenevtchn_bind_interdomain(xenaccess->vm_event.xce_handle,
-                                    xenaccess->vm_event.domain_id,
-                                    xenaccess->vm_event.evtchn_port);
-    if ( rc < 0 )
-    {
-        ERROR("Failed to bind event channel");
-        goto err;
-    }
-    evtchn_bind = 1;
-    xenaccess->vm_event.port = rc;
-
-    /* Initialise ring */
-    SHARED_RING_INIT((vm_event_sring_t *)xenaccess->vm_event.ring_page);
-    BACK_RING_INIT(&xenaccess->vm_event.back_ring,
-                   (vm_event_sring_t *)xenaccess->vm_event.ring_page,
-                   XC_PAGE_SIZE);
 
     /* Get max_gpfn */
-    rc = xc_domain_maximum_gpfn(xenaccess->xc_handle,
-                                xenaccess->vm_event.domain_id,
-                                &xenaccess->max_gpfn);
-
+    rc = xc_domain_maximum_gpfn(xch, domain_id, &max_gpfn);
     if ( rc )
     {
         ERROR("Failed to get max gpfn");
         goto err;
     }
+    DPRINTF("max_gpfn = %"PRI_xen_pfn"\n", max_gpfn);
+
+    rc = ops->init(xch, xce, domain_id, ops, &vm_event);
+    if ( rc < 0 )
+        goto err;
 
-    DPRINTF("max_gpfn = %"PRI_xen_pfn"\n", xenaccess->max_gpfn);
+    vm_event->xch = xch;
+    vm_event->xce = xce;
+    vm_event->domain_id = domain_id;
+    vm_event->ops = ops;
+    vm_event->max_gpfn = max_gpfn;
 
-    return xenaccess;
+    return vm_event;
 
  err:
-    rc = xenaccess_teardown(xch, xenaccess);
-    if ( rc )
-    {
-        ERROR("Failed to teardown xenaccess structure!\n");
-    }
+    xenevtchn_close(xce);
+    xc_interface_close(xch);
 
- err_iface:
     return NULL;
 }
 
@@ -299,26 +201,6 @@ int control_singlestep(
 }
 
 /*
- * Note that this function is not thread safe.
- */
-static void get_request(vm_event_t *vm_event, vm_event_request_t *req)
-{
-    vm_event_back_ring_t *back_ring;
-    RING_IDX req_cons;
-
-    back_ring = &vm_event->back_ring;
-    req_cons = back_ring->req_cons;
-
-    /* Copy request */
-    memcpy(req, RING_GET_REQUEST(back_ring, req_cons), sizeof(*req));
-    req_cons++;
-
-    /* Update ring */
-    back_ring->req_cons = req_cons;
-    back_ring->sring->req_event = req_cons + 1;
-}
-
-/*
  * X86 control register names
  */
 static const char* get_x86_ctrl_reg_name(uint32_t index)
@@ -336,29 +218,9 @@ static const char* get_x86_ctrl_reg_name(uint32_t index)
     return names[index];
 }
 
-/*
- * Note that this function is not thread safe.
- */
-static void put_response(vm_event_t *vm_event, vm_event_response_t *rsp)
-{
-    vm_event_back_ring_t *back_ring;
-    RING_IDX rsp_prod;
-
-    back_ring = &vm_event->back_ring;
-    rsp_prod = back_ring->rsp_prod_pvt;
-
-    /* Copy response */
-    memcpy(RING_GET_RESPONSE(back_ring, rsp_prod), rsp, sizeof(*rsp));
-    rsp_prod++;
-
-    /* Update ring */
-    back_ring->rsp_prod_pvt = rsp_prod;
-    RING_PUSH_RESPONSES(back_ring);
-}
-
 void usage(char* progname)
 {
-    fprintf(stderr, "Usage: %s [-m] <domain_id> write|exec", progname);
+    fprintf(stderr, "Usage: %s [-m] [-n] <domain_id> write|exec", progname);
 #if defined(__i386__) || defined(__x86_64__)
             fprintf(stderr, 
"|breakpoint|altp2m_write|altp2m_exec|debug|cpuid|desc_access|write_ctrlreg_cr4|altp2m_write_no_gpt");
 #elif defined(__arm__) || defined(__aarch64__)
@@ -368,19 +230,22 @@ void usage(char* progname)
             "\n"
             "Logs first page writes, execs, or breakpoint traps that occur on 
the domain.\n"
             "\n"
-            "-m requires this program to run, or else the domain may pause\n");
+            "-m requires this program to run, or else the domain may pause\n"
+           "-n uses the per-vcpu channels vm_event interface\n");
 }
 
+extern vm_event_ops_t ring_ops;
+extern vm_event_ops_t channel_ops;
+
 int main(int argc, char *argv[])
 {
     struct sigaction act;
     domid_t domain_id;
-    xenaccess_t *xenaccess;
+    vm_event_t *vm_event;
     vm_event_request_t req;
     vm_event_response_t rsp;
     int rc = -1;
     int rc1;
-    xc_interface *xch;
     xenmem_access_t default_access = XENMEM_access_rwx;
     xenmem_access_t after_first_access = XENMEM_access_rwx;
     int memaccess = 0;
@@ -395,106 +260,122 @@ int main(int argc, char *argv[])
     int write_ctrlreg_cr4 = 0;
     int altp2m_write_no_gpt = 0;
     uint16_t altp2m_view_id = 0;
+    int new_interface = 0;
 
     char* progname = argv[0];
-    argv++;
-    argc--;
+    char* command;
+    int c;
+    int option_index;
+    struct option long_options[] =
+    {
+        { "mem-access-listener", no_argument, 0, 'm' },
+        { "new-interface", no_argument, 0, 'n' }
+    };
 
-    if ( argc == 3 && argv[0][0] == '-' )
+    while(1)
     {
-        if ( !strcmp(argv[0], "-m") )
-            required = 1;
-        else
+        c = getopt_long(argc, argv, "mn", long_options, &option_index);
+        if ( c == -1 )
+            break;
+
+        switch (c)
         {
-            usage(progname);
-            return -1;
+            case 'm':
+                required = 1;
+                break;
+
+            case 'n':
+                new_interface = 1;
+                break;
+
+            default:
+                usage(progname);
+                return -1;
         }
-        argv++;
-        argc--;
     }
 
-    if ( argc != 2 )
+    if ( argc - optind != 2 )
     {
         usage(progname);
         return -1;
     }
 
-    domain_id = atoi(argv[0]);
-    argv++;
-    argc--;
+    domain_id = atoi(argv[optind++]);
+    command = argv[optind];
 
-    if ( !strcmp(argv[0], "write") )
+    if ( !strcmp(command, "write") )
     {
         default_access = XENMEM_access_rx;
         after_first_access = XENMEM_access_rwx;
         memaccess = 1;
     }
-    else if ( !strcmp(argv[0], "exec") )
+    else if ( !strcmp(command, "exec") )
     {
         default_access = XENMEM_access_rw;
         after_first_access = XENMEM_access_rwx;
         memaccess = 1;
     }
 #if defined(__i386__) || defined(__x86_64__)
-    else if ( !strcmp(argv[0], "breakpoint") )
+    else if ( !strcmp(command, "breakpoint") )
     {
         breakpoint = 1;
     }
-    else if ( !strcmp(argv[0], "altp2m_write") )
+    else if ( !strcmp(command, "altp2m_write") )
     {
         default_access = XENMEM_access_rx;
         altp2m = 1;
         memaccess = 1;
     }
-    else if ( !strcmp(argv[0], "altp2m_exec") )
+    else if ( !strcmp(command, "altp2m_exec") )
     {
         default_access = XENMEM_access_rw;
         altp2m = 1;
         memaccess = 1;
     }
-    else if ( !strcmp(argv[0], "altp2m_write_no_gpt") )
+    else if ( !strcmp(command, "altp2m_write_no_gpt") )
     {
         default_access = XENMEM_access_rw;
         altp2m_write_no_gpt = 1;
         memaccess = 1;
         altp2m = 1;
     }
-    else if ( !strcmp(argv[0], "debug") )
+    else if ( !strcmp(command, "debug") )
     {
         debug = 1;
     }
-    else if ( !strcmp(argv[0], "cpuid") )
+    else if ( !strcmp(command, "cpuid") )
     {
         cpuid = 1;
     }
-    else if ( !strcmp(argv[0], "desc_access") )
+    else if ( !strcmp(command, "desc_access") )
     {
         desc_access = 1;
     }
-    else if ( !strcmp(argv[0], "write_ctrlreg_cr4") )
+    else if ( !strcmp(command, "write_ctrlreg_cr4") )
     {
         write_ctrlreg_cr4 = 1;
     }
 #elif defined(__arm__) || defined(__aarch64__)
-    else if ( !strcmp(argv[0], "privcall") )
+    else if ( !strcmp(command, "privcall") )
     {
         privcall = 1;
     }
 #endif
     else
     {
-        usage(argv[0]);
+        usage(command);
         return -1;
     }
 
-    xenaccess = xenaccess_init(&xch, domain_id);
-    if ( xenaccess == NULL )
+    vm_event = vm_event_init(domain_id,
+                             (new_interface) ? &channel_ops : &ring_ops);
+    if ( vm_event == NULL )
     {
-        ERROR("Error initialising xenaccess");
+        ERROR("Error initialising vm_event");
         return 1;
     }
 
-    DPRINTF("starting %s %u\n", argv[0], domain_id);
+    DPRINTF("starting %s %u\n", command, domain_id);
 
     /* ensure that if we get a signal, we'll do cleanup, then exit */
     act.sa_handler = close_handler;
@@ -506,7 +387,7 @@ int main(int argc, char *argv[])
     sigaction(SIGALRM, &act, NULL);
 
     /* Set whether the access listener is required */
-    rc = xc_domain_set_access_required(xch, domain_id, required);
+    rc = xc_domain_set_access_required(vm_event->xch, domain_id, required);
     if ( rc < 0 )
     {
         ERROR("Error %d setting mem_access listener required\n", rc);
@@ -521,13 +402,13 @@ int main(int argc, char *argv[])
 
         if( altp2m_write_no_gpt )
         {
-            rc = xc_monitor_inguest_pagefault(xch, domain_id, 1);
+            rc = xc_monitor_inguest_pagefault(vm_event->xch, domain_id, 1);
             if ( rc < 0 )
             {
                 ERROR("Error %d setting inguest pagefault\n", rc);
                 goto exit;
             }
-            rc = xc_monitor_emul_unimplemented(xch, domain_id, 1);
+            rc = xc_monitor_emul_unimplemented(vm_event->xch, domain_id, 1);
             if ( rc < 0 )
             {
                 ERROR("Error %d failed to enable emul unimplemented\n", rc);
@@ -535,14 +416,15 @@ int main(int argc, char *argv[])
             }
         }
 
-        rc = xc_altp2m_set_domain_state( xch, domain_id, 1 );
+        rc = xc_altp2m_set_domain_state( vm_event->xch, domain_id, 1 );
         if ( rc < 0 )
         {
             ERROR("Error %d enabling altp2m on domain!\n", rc);
             goto exit;
         }
 
-        rc = xc_altp2m_create_view( xch, domain_id, default_access, 
&altp2m_view_id );
+        rc = xc_altp2m_create_view( vm_event->xch, domain_id, default_access,
+                                    &altp2m_view_id );
         if ( rc < 0 )
         {
             ERROR("Error %d creating altp2m view!\n", rc);
@@ -552,24 +434,24 @@ int main(int argc, char *argv[])
         DPRINTF("altp2m view created with id %u\n", altp2m_view_id);
         DPRINTF("Setting altp2m mem_access permissions.. ");
 
-        for(; gfn < xenaccess->max_gpfn; ++gfn)
+        for(; gfn < vm_event->max_gpfn; ++gfn)
         {
-            rc = xc_altp2m_set_mem_access( xch, domain_id, altp2m_view_id, gfn,
-                                           default_access);
+            rc = xc_altp2m_set_mem_access( vm_event->xch, domain_id,
+                                           altp2m_view_id, gfn, 
default_access);
             if ( !rc )
                 perm_set++;
         }
 
         DPRINTF("done! Permissions set on %lu pages.\n", perm_set);
 
-        rc = xc_altp2m_switch_to_view( xch, domain_id, altp2m_view_id );
+        rc = xc_altp2m_switch_to_view( vm_event->xch, domain_id, 
altp2m_view_id );
         if ( rc < 0 )
         {
             ERROR("Error %d switching to altp2m view!\n", rc);
             goto exit;
         }
 
-        rc = xc_monitor_singlestep( xch, domain_id, 1 );
+        rc = xc_monitor_singlestep( vm_event->xch, domain_id, 1 );
         if ( rc < 0 )
         {
             ERROR("Error %d failed to enable singlestep monitoring!\n", rc);
@@ -580,15 +462,15 @@ int main(int argc, char *argv[])
     if ( memaccess && !altp2m )
     {
         /* Set the default access type and convert all pages to it */
-        rc = xc_set_mem_access(xch, domain_id, default_access, ~0ull, 0);
+        rc = xc_set_mem_access(vm_event->xch, domain_id, default_access, 
~0ull, 0);
         if ( rc < 0 )
         {
             ERROR("Error %d setting default mem access type\n", rc);
             goto exit;
         }
 
-        rc = xc_set_mem_access(xch, domain_id, default_access, START_PFN,
-                               (xenaccess->max_gpfn - START_PFN) );
+        rc = xc_set_mem_access(vm_event->xch, domain_id, default_access, 
START_PFN,
+                               (vm_event->max_gpfn - START_PFN) );
 
         if ( rc < 0 )
         {
@@ -600,7 +482,7 @@ int main(int argc, char *argv[])
 
     if ( breakpoint )
     {
-        rc = xc_monitor_software_breakpoint(xch, domain_id, 1);
+        rc = xc_monitor_software_breakpoint(vm_event->xch, domain_id, 1);
         if ( rc < 0 )
         {
             ERROR("Error %d setting breakpoint trapping with vm_event\n", rc);
@@ -610,7 +492,7 @@ int main(int argc, char *argv[])
 
     if ( debug )
     {
-        rc = xc_monitor_debug_exceptions(xch, domain_id, 1, 1);
+        rc = xc_monitor_debug_exceptions(vm_event->xch, domain_id, 1, 1);
         if ( rc < 0 )
         {
             ERROR("Error %d setting debug exception listener with vm_event\n", 
rc);
@@ -620,7 +502,7 @@ int main(int argc, char *argv[])
 
     if ( cpuid )
     {
-        rc = xc_monitor_cpuid(xch, domain_id, 1);
+        rc = xc_monitor_cpuid(vm_event->xch, domain_id, 1);
         if ( rc < 0 )
         {
             ERROR("Error %d setting cpuid listener with vm_event\n", rc);
@@ -630,7 +512,7 @@ int main(int argc, char *argv[])
 
     if ( desc_access )
     {
-        rc = xc_monitor_descriptor_access(xch, domain_id, 1);
+        rc = xc_monitor_descriptor_access(vm_event->xch, domain_id, 1);
         if ( rc < 0 )
         {
             ERROR("Error %d setting descriptor access listener with 
vm_event\n", rc);
@@ -640,7 +522,7 @@ int main(int argc, char *argv[])
 
     if ( privcall )
     {
-        rc = xc_monitor_privileged_call(xch, domain_id, 1);
+        rc = xc_monitor_privileged_call(vm_event->xch, domain_id, 1);
         if ( rc < 0 )
         {
             ERROR("Error %d setting privileged call trapping with vm_event\n", 
rc);
@@ -651,7 +533,7 @@ int main(int argc, char *argv[])
     if ( write_ctrlreg_cr4 )
     {
         /* Mask the CR4.PGE bit so no events will be generated for global TLB 
flushes. */
-        rc = xc_monitor_write_ctrlreg(xch, domain_id, VM_EVENT_X86_CR4, 1, 1,
+        rc = xc_monitor_write_ctrlreg(vm_event->xch, domain_id, 
VM_EVENT_X86_CR4, 1, 1,
                                       X86_CR4_PGE, 1);
         if ( rc < 0 )
         {
@@ -663,41 +545,43 @@ int main(int argc, char *argv[])
     /* Wait for access */
     for (;;)
     {
+        int port = 0;
+
         if ( interrupted )
         {
             /* Unregister for every event */
             DPRINTF("xenaccess shutting down on signal %d\n", interrupted);
 
             if ( breakpoint )
-                rc = xc_monitor_software_breakpoint(xch, domain_id, 0);
+                rc = xc_monitor_software_breakpoint(vm_event->xch, domain_id, 
0);
             if ( debug )
-                rc = xc_monitor_debug_exceptions(xch, domain_id, 0, 0);
+                rc = xc_monitor_debug_exceptions(vm_event->xch, domain_id, 0, 
0);
             if ( cpuid )
-                rc = xc_monitor_cpuid(xch, domain_id, 0);
+                rc = xc_monitor_cpuid(vm_event->xch, domain_id, 0);
             if ( desc_access )
-                rc = xc_monitor_descriptor_access(xch, domain_id, 0);
+                rc = xc_monitor_descriptor_access(vm_event->xch, domain_id, 0);
             if ( write_ctrlreg_cr4 )
-                rc = xc_monitor_write_ctrlreg(xch, domain_id, 
VM_EVENT_X86_CR4, 0, 0, 0, 0);
+                rc = xc_monitor_write_ctrlreg(vm_event->xch, domain_id, 
VM_EVENT_X86_CR4, 0, 0, 0, 0);
 
             if ( privcall )
-                rc = xc_monitor_privileged_call(xch, domain_id, 0);
+                rc = xc_monitor_privileged_call(vm_event->xch, domain_id, 0);
 
             if ( altp2m )
             {
-                rc = xc_altp2m_switch_to_view( xch, domain_id, 0 );
-                rc = xc_altp2m_destroy_view(xch, domain_id, altp2m_view_id);
-                rc = xc_altp2m_set_domain_state(xch, domain_id, 0);
-                rc = xc_monitor_singlestep(xch, domain_id, 0);
+                rc = xc_altp2m_switch_to_view( vm_event->xch, domain_id, 0 );
+                rc = xc_altp2m_destroy_view(vm_event->xch, domain_id, 
altp2m_view_id);
+                rc = xc_altp2m_set_domain_state(vm_event->xch, domain_id, 0);
+                rc = xc_monitor_singlestep(vm_event->xch, domain_id, 0);
             } else {
-                rc = xc_set_mem_access(xch, domain_id, XENMEM_access_rwx, 
~0ull, 0);
-                rc = xc_set_mem_access(xch, domain_id, XENMEM_access_rwx, 
START_PFN,
-                                       (xenaccess->max_gpfn - START_PFN) );
+                rc = xc_set_mem_access(vm_event->xch, domain_id, 
XENMEM_access_rwx, ~0ull, 0);
+                rc = xc_set_mem_access(vm_event->xch, domain_id, 
XENMEM_access_rwx, START_PFN,
+                                       (vm_event->max_gpfn - START_PFN) );
             }
 
             shutting_down = 1;
         }
 
-        rc = xc_wait_for_event_or_timeout(xch, xenaccess->vm_event.xce_handle, 
100);
+        rc = xc_wait_for_event_or_timeout(vm_event->xch, vm_event->xce, 100);
         if ( rc < -1 )
         {
             ERROR("Error getting event");
@@ -709,10 +593,10 @@ int main(int argc, char *argv[])
             DPRINTF("Got event from Xen\n");
         }
 
-        while ( RING_HAS_UNCONSUMED_REQUESTS(&xenaccess->vm_event.back_ring) )
-        {
-            get_request(&xenaccess->vm_event, &req);
+        port = rc;
 
+        while ( vm_event->ops->get_request(vm_event, &req, &port) )
+        {
             if ( req.version != VM_EVENT_INTERFACE_VERSION )
             {
                 ERROR("Error: vm_event interface version mismatch!\n");
@@ -735,7 +619,7 @@ int main(int argc, char *argv[])
                      * At shutdown we have already reset all the permissions 
so really no use getting it again.
                      */
                     xenmem_access_t access;
-                    rc = xc_get_mem_access(xch, domain_id, 
req.u.mem_access.gfn, &access);
+                    rc = xc_get_mem_access(vm_event->xch, domain_id, 
req.u.mem_access.gfn, &access);
                     if (rc < 0)
                     {
                         ERROR("Error %d getting mem_access event\n", rc);
@@ -768,7 +652,7 @@ int main(int argc, char *argv[])
                 }
                 else if ( default_access != after_first_access )
                 {
-                    rc = xc_set_mem_access(xch, domain_id, after_first_access,
+                    rc = xc_set_mem_access(vm_event->xch, domain_id, 
after_first_access,
                                            req.u.mem_access.gfn, 1);
                     if (rc < 0)
                     {
@@ -788,7 +672,7 @@ int main(int argc, char *argv[])
                        req.vcpu_id);
 
                 /* Reinject */
-                rc = xc_hvm_inject_trap(xch, domain_id, req.vcpu_id,
+                rc = xc_hvm_inject_trap(vm_event->xch, domain_id, req.vcpu_id,
                                         X86_TRAP_INT3,
                                         req.u.software_breakpoint.type, -1,
                                         req.u.software_breakpoint.insn_length, 
0);
@@ -833,7 +717,7 @@ int main(int argc, char *argv[])
                        req.u.debug_exception.insn_length);
 
                 /* Reinject */
-                rc = xc_hvm_inject_trap(xch, domain_id, req.vcpu_id,
+                rc = xc_hvm_inject_trap(vm_event->xch, domain_id, req.vcpu_id,
                                         X86_TRAP_DEBUG,
                                         req.u.debug_exception.type, -1,
                                         req.u.debug_exception.insn_length,
@@ -896,17 +780,15 @@ int main(int argc, char *argv[])
             }
 
             /* Put the response on the ring */
-            put_response(&xenaccess->vm_event, &rsp);
-        }
-
-        /* Tell Xen page is ready */
-        rc = xenevtchn_notify(xenaccess->vm_event.xce_handle,
-                              xenaccess->vm_event.port);
+            put_response(vm_event, &rsp, port);
 
-        if ( rc != 0 )
-        {
-            ERROR("Error resuming page");
-            interrupted = -1;
+            /* Tell Xen page is ready */
+            rc = notify_port(vm_event, port);
+            if ( rc != 0 )
+            {
+                ERROR("Error resuming page");
+                interrupted = -1;
+            }
         }
 
         if ( shutting_down )
@@ -919,13 +801,13 @@ exit:
     {
         uint32_t vcpu_id;
         for ( vcpu_id = 0; vcpu_id<XEN_LEGACY_MAX_VCPUS; vcpu_id++)
-            rc = control_singlestep(xch, domain_id, vcpu_id, 0);
+            rc = control_singlestep(vm_event->xch, domain_id, vcpu_id, 0);
     }
 
-    /* Tear down domain xenaccess */
-    rc1 = xenaccess_teardown(xch, xenaccess);
+    /* Tear down domain */
+    rc1 = vm_event_teardown(vm_event);
     if ( rc1 != 0 )
-        ERROR("Error tearing down xenaccess");
+        ERROR("Error tearing down vm_event");
 
     if ( rc == 0 )
         rc = rc1;
diff --git a/tools/tests/xen-access/xen-access.h 
b/tools/tests/xen-access/xen-access.h
new file mode 100644
index 0000000..9fc640c
--- /dev/null
+++ b/tools/tests/xen-access/xen-access.h
@@ -0,0 +1,91 @@
+/*
+ * xen-access.h
+ *
+ * Copyright (c) 2019 Bitdefender S.R.L.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef XEN_ACCESS_H
+#define XEN_ACCESS_H
+
+#include <xenctrl.h>
+#include <xenevtchn.h>
+#include <xen/vm_event.h>
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+                const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+                (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif /* container_of */
+
+#define DPRINTF(a, b...) fprintf(stderr, a, ## b)
+#define ERROR(a, b...) fprintf(stderr, a "\n", ## b)
+#define PERROR(a, b...) fprintf(stderr, a ": %s\n", ## b, strerror(errno))
+
+struct vm_event_ops;
+
+typedef struct vm_event {
+    xc_interface *xch;
+    domid_t domain_id;
+    xenevtchn_handle *xce;
+    xen_pfn_t max_gpfn;
+    struct vm_event_ops *ops;
+} vm_event_t;
+
+typedef struct vm_event_ops {
+    int (*init)(xc_interface *, xenevtchn_handle *, domid_t,
+                struct vm_event_ops *, vm_event_t **);
+    int (*teardown)(vm_event_t *);
+    bool (*get_request)(vm_event_t *, vm_event_request_t *, int *);
+    void (*put_response)(vm_event_t *, vm_event_response_t *, int);
+    int (*notify_port)(vm_event_t *, int port);
+} vm_event_ops_t;
+
+static inline bool get_request(vm_event_t *vm_event, vm_event_request_t *req,
+                               int *port)
+{
+    return ( vm_event ) ? vm_event->ops->get_request(vm_event, req, port) :
+                          false;
+}
+
+static inline void put_response(vm_event_t *vm_event, vm_event_response_t 
*rsp, int port)
+{
+    if (  vm_event )
+        vm_event->ops->put_response(vm_event, rsp, port);
+}
+
+static inline int notify_port(vm_event_t *vm_event, int port)
+{
+    if ( !vm_event )
+        return -EINVAL;
+
+    return vm_event->ops->notify_port(vm_event, port);
+}
+
+#endif /* XEN_ACCESS_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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