All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] Per vcpu vm_event channels
@ 2019-05-30 14:18 ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Tamas K Lengyel, Jan Beulich,
	Roger Pau Monné

This patchset adds a new mechanism of sending synchronous vm_event
requests and handling vm_event responses without using a ring.
As each synchronous request pauses the vcpu until the corresponding
response is handled, it can be stored in a slotted memory buffer
(one per vcpu) shared between the hypervisor and the controlling domain.

The main advantages of this approach are:
- the ability to dynamicaly allocate the necessary memory used to hold
the requests/responses (the size of vm_event_request_t/vm_event_response_t
can grow unrestricted by the ring's one page limitation)
- the ring's waitqueue logic is unnecessary in this case because the
vcpu sending the request is blocked until a response is received.



Petre Pircalabu (9):
  tools/libxc: Consistent usage of xc_vm_event_* interface
  vm_event: Define VM_EVENT type
  vm_event: Make ‘local’ functions ‘static’
  vm_event: Remove "ring" suffix from vm_event_check_ring
  vm_event: Simplify vm_event interface
  vm_event: Move struct vm_event_domain to vm_event.c
  vm_event: Decouple implementation details from interface.
  vm_event: Add vm_event_ng interface
  xen-access: Add support for vm_event_ng interface

 tools/libxc/include/xenctrl.h        |  56 +---
 tools/libxc/xc_mem_paging.c          |  23 +-
 tools/libxc/xc_memshr.c              |  34 ---
 tools/libxc/xc_monitor.c             |  46 ++-
 tools/libxc/xc_private.h             |  16 +-
 tools/libxc/xc_vm_event.c            | 175 +++++++-----
 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 ++++++
 tools/xenpaging/xenpaging.c          |  42 +--
 xen/arch/arm/mem_access.c            |   2 +-
 xen/arch/x86/mm.c                    |   5 +
 xen/arch/x86/mm/mem_access.c         |   4 +-
 xen/arch/x86/mm/mem_paging.c         |   2 +-
 xen/arch/x86/mm/mem_sharing.c        |   5 +-
 xen/arch/x86/mm/p2m.c                |  11 +-
 xen/common/Makefile                  |   1 +
 xen/common/domctl.c                  |   7 +
 xen/common/mem_access.c              |   2 +-
 xen/common/monitor.c                 |   4 +-
 xen/common/vm_event.c                | 527 ++++++++++++++++++-----------------
 xen/common/vm_event_ng.c             | 449 +++++++++++++++++++++++++++++
 xen/drivers/passthrough/pci.c        |   2 +-
 xen/include/public/domctl.h          | 101 +++----
 xen/include/public/memory.h          |   2 +
 xen/include/public/vm_event.h        |  47 ++++
 xen/include/xen/sched.h              |  25 +-
 xen/include/xen/vm_event.h           |  80 +++++-
 30 files changed, 1720 insertions(+), 857 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
 create mode 100644 xen/common/vm_event_ng.c

-- 
2.7.4


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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 0/9] Per vcpu vm_event channels
@ 2019-05-30 14:18 ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Tamas K Lengyel, Jan Beulich,
	Roger Pau Monné

This patchset adds a new mechanism of sending synchronous vm_event
requests and handling vm_event responses without using a ring.
As each synchronous request pauses the vcpu until the corresponding
response is handled, it can be stored in a slotted memory buffer
(one per vcpu) shared between the hypervisor and the controlling domain.

The main advantages of this approach are:
- the ability to dynamicaly allocate the necessary memory used to hold
the requests/responses (the size of vm_event_request_t/vm_event_response_t
can grow unrestricted by the ring's one page limitation)
- the ring's waitqueue logic is unnecessary in this case because the
vcpu sending the request is blocked until a response is received.



Petre Pircalabu (9):
  tools/libxc: Consistent usage of xc_vm_event_* interface
  vm_event: Define VM_EVENT type
  vm_event: Make ‘local’ functions ‘static’
  vm_event: Remove "ring" suffix from vm_event_check_ring
  vm_event: Simplify vm_event interface
  vm_event: Move struct vm_event_domain to vm_event.c
  vm_event: Decouple implementation details from interface.
  vm_event: Add vm_event_ng interface
  xen-access: Add support for vm_event_ng interface

 tools/libxc/include/xenctrl.h        |  56 +---
 tools/libxc/xc_mem_paging.c          |  23 +-
 tools/libxc/xc_memshr.c              |  34 ---
 tools/libxc/xc_monitor.c             |  46 ++-
 tools/libxc/xc_private.h             |  16 +-
 tools/libxc/xc_vm_event.c            | 175 +++++++-----
 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 ++++++
 tools/xenpaging/xenpaging.c          |  42 +--
 xen/arch/arm/mem_access.c            |   2 +-
 xen/arch/x86/mm.c                    |   5 +
 xen/arch/x86/mm/mem_access.c         |   4 +-
 xen/arch/x86/mm/mem_paging.c         |   2 +-
 xen/arch/x86/mm/mem_sharing.c        |   5 +-
 xen/arch/x86/mm/p2m.c                |  11 +-
 xen/common/Makefile                  |   1 +
 xen/common/domctl.c                  |   7 +
 xen/common/mem_access.c              |   2 +-
 xen/common/monitor.c                 |   4 +-
 xen/common/vm_event.c                | 527 ++++++++++++++++++-----------------
 xen/common/vm_event_ng.c             | 449 +++++++++++++++++++++++++++++
 xen/drivers/passthrough/pci.c        |   2 +-
 xen/include/public/domctl.h          | 101 +++----
 xen/include/public/memory.h          |   2 +
 xen/include/public/vm_event.h        |  47 ++++
 xen/include/xen/sched.h              |  25 +-
 xen/include/xen/vm_event.h           |  80 +++++-
 30 files changed, 1720 insertions(+), 857 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
 create mode 100644 xen/common/vm_event_ng.c

-- 
2.7.4


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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 1/9] tools/libxc: Consistent usage of xc_vm_event_* interface
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel; +Cc: Petre Pircalabu, Ian Jackson, Wei Liu

Modified xc_mem_paging_enable to use directly xc_vm_event_enable and
moved the ring_page handling from client to libxc (xenpaging).

Restricted vm_event_control usage only to simplest domctls which do
not expect any return values and change xc_vm_event_enable to call do_domctl
directly.

Removed xc_memshr_ring_enable/disable and xc_memshr_domain_resume.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 tools/libxc/include/xenctrl.h | 49 +--------------------------------
 tools/libxc/xc_mem_paging.c   | 23 +++++-----------
 tools/libxc/xc_memshr.c       | 34 -----------------------
 tools/libxc/xc_monitor.c      | 31 +++++++++++++++++----
 tools/libxc/xc_private.h      |  2 +-
 tools/libxc/xc_vm_event.c     | 64 ++++++++++++++++---------------------------
 tools/xenpaging/xenpaging.c   | 42 +++-------------------------
 7 files changed, 62 insertions(+), 183 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 538007a..28fdbc0 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1949,7 +1949,7 @@ int xc_altp2m_change_gfn(xc_interface *handle, uint32_t domid,
  * Hardware-Assisted Paging (i.e. Intel EPT, AMD NPT). Moreover, AMD NPT
  * support is considered experimental.
  */
-int xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port);
+void *xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port);
 int xc_mem_paging_disable(xc_interface *xch, uint32_t domain_id);
 int xc_mem_paging_resume(xc_interface *xch, uint32_t domain_id);
 int xc_mem_paging_nominate(xc_interface *xch, uint32_t domain_id,
@@ -2082,53 +2082,6 @@ int xc_memshr_control(xc_interface *xch,
                       uint32_t domid,
                       int enable);
 
-/* Create a communication ring in which the hypervisor will place ENOMEM
- * notifications.
- *
- * ENOMEM happens when unsharing pages: a Copy-on-Write duplicate needs to be
- * allocated, and thus the out-of-memory error occurr.
- *
- * For complete examples on how to plumb a notification ring, look into
- * xenpaging or xen-access.
- *
- * On receipt of a notification, the helper should ensure there is memory
- * available to the domain before retrying.
- *
- * If a domain encounters an ENOMEM condition when sharing and this ring
- * has not been set up, the hypervisor will crash the domain.
- *
- * Fails with:
- *  EINVAL if port is NULL
- *  EINVAL if the sharing ring has already been enabled
- *  ENOSYS if no guest gfn has been specified to host the ring via an hvm param
- *  EINVAL if the gfn for the ring has not been populated
- *  ENOENT if the gfn for the ring is paged out, or cannot be unshared
- *  EINVAL if the gfn for the ring cannot be written to
- *  EINVAL if the domain is dying
- *  ENOSPC if an event channel cannot be allocated for the ring
- *  ENOMEM if memory cannot be allocated for internal data structures
- *  EINVAL or EACCESS if the request is denied by the security policy
- */
-
-int xc_memshr_ring_enable(xc_interface *xch, 
-                          uint32_t domid,
-                          uint32_t *port);
-/* Disable the ring for ENOMEM communication.
- * May fail with EINVAL if the ring was not enabled in the first place.
- */
-int xc_memshr_ring_disable(xc_interface *xch, 
-                           uint32_t domid);
-
-/*
- * Calls below return EINVAL if sharing has not been enabled for the domain
- * Calls below return EINVAL if the domain is dying
- */
-/* Once a reponse to an ENOMEM notification is prepared, the tool can
- * notify the hypervisor to re-schedule the faulting vcpu of the domain with an
- * event channel kick and/or this call. */
-int xc_memshr_domain_resume(xc_interface *xch,
-                            uint32_t domid);
-
 /* Select a page for sharing. 
  *
  * A 64 bit opaque handle will be stored in handle.  The hypervisor ensures
diff --git a/tools/libxc/xc_mem_paging.c b/tools/libxc/xc_mem_paging.c
index a067706..08468fb 100644
--- a/tools/libxc/xc_mem_paging.c
+++ b/tools/libxc/xc_mem_paging.c
@@ -37,35 +37,26 @@ static int xc_mem_paging_memop(xc_interface *xch, uint32_t domain_id,
     return do_memory_op(xch, XENMEM_paging_op, &mpo, sizeof(mpo));
 }
 
-int xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id,
-                         uint32_t *port)
+void *xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id,
+                           uint32_t *port)
 {
-    if ( !port )
-    {
-        errno = EINVAL;
-        return -1;
-    }
-
-    return xc_vm_event_control(xch, domain_id,
-                               XEN_VM_EVENT_ENABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING,
-                               port);
+    return xc_vm_event_enable(xch, domain_id,
+                              XEN_DOMCTL_VM_EVENT_OP_PAGING,
+                              port);
 }
 
 int xc_mem_paging_disable(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING,
-                               NULL);
+                               XEN_DOMCTL_VM_EVENT_OP_PAGING);
 }
 
 int xc_mem_paging_resume(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING,
-                               NULL);
+                               XEN_DOMCTL_VM_EVENT_OP_PAGING);
 }
 
 int xc_mem_paging_nominate(xc_interface *xch, uint32_t domain_id, uint64_t gfn)
diff --git a/tools/libxc/xc_memshr.c b/tools/libxc/xc_memshr.c
index d5e135e..06f613a 100644
--- a/tools/libxc/xc_memshr.c
+++ b/tools/libxc/xc_memshr.c
@@ -41,31 +41,6 @@ int xc_memshr_control(xc_interface *xch,
     return do_domctl(xch, &domctl);
 }
 
-int xc_memshr_ring_enable(xc_interface *xch, 
-                          uint32_t domid,
-                          uint32_t *port)
-{
-    if ( !port )
-    {
-        errno = EINVAL;
-        return -1;
-    }
-
-    return xc_vm_event_control(xch, domid,
-                               XEN_VM_EVENT_ENABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_SHARING,
-                               port);
-}
-
-int xc_memshr_ring_disable(xc_interface *xch, 
-                           uint32_t domid)
-{
-    return xc_vm_event_control(xch, domid,
-                               XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_SHARING,
-                               NULL);
-}
-
 static int xc_memshr_memop(xc_interface *xch, uint32_t domid,
                             xen_mem_sharing_op_t *mso)
 {
@@ -200,15 +175,6 @@ int xc_memshr_range_share(xc_interface *xch,
     return xc_memshr_memop(xch, source_domain, &mso);
 }
 
-int xc_memshr_domain_resume(xc_interface *xch,
-                            uint32_t domid)
-{
-    return xc_vm_event_control(xch, domid,
-                               XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_SHARING,
-                               NULL);
-}
-
 int xc_memshr_debug_gfn(xc_interface *xch,
                         uint32_t domid,
                         unsigned long gfn)
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index 4ac823e..d190c29 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -24,24 +24,43 @@
 
 void *xc_monitor_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port)
 {
-    return xc_vm_event_enable(xch, domain_id, HVM_PARAM_MONITOR_RING_PFN,
-                              port);
+    void *buffer;
+    int saved_errno;
+
+    /* Pause the domain for ring page setup */
+    if ( xc_domain_pause(xch, domain_id) )
+    {
+        PERROR("Unable to pause domain\n");
+        return NULL;
+    }
+
+    buffer = xc_vm_event_enable(xch, domain_id,
+                                HVM_PARAM_MONITOR_RING_PFN,
+                                port);
+    saved_errno = errno;
+    if ( xc_domain_unpause(xch, domain_id) )
+    {
+        if ( buffer )
+            saved_errno = errno;
+        PERROR("Unable to unpause domain");
+    }
+
+    errno = saved_errno;
+    return buffer;
 }
 
 int xc_monitor_disable(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_MONITOR,
-                               NULL);
+                               XEN_DOMCTL_VM_EVENT_OP_MONITOR);
 }
 
 int xc_monitor_resume(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_MONITOR,
-                               NULL);
+                               XEN_DOMCTL_VM_EVENT_OP_MONITOR);
 }
 
 int xc_monitor_get_capabilities(xc_interface *xch, uint32_t domain_id,
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index adc3b6a..663e78b 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -412,7 +412,7 @@ int xc_ffs64(uint64_t x);
  * vm_event operations. Internal use only.
  */
 int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
-                        unsigned int mode, uint32_t *port);
+                        unsigned int mode);
 /*
  * Enables vm_event and returns the mapped ring page indicated by param.
  * param can be HVM_PARAM_PAGING/ACCESS/SHARING_RING_PFN
diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
index a97c615..ea10366 100644
--- a/tools/libxc/xc_vm_event.c
+++ b/tools/libxc/xc_vm_event.c
@@ -23,20 +23,16 @@
 #include "xc_private.h"
 
 int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
-                        unsigned int mode, uint32_t *port)
+                        unsigned int mode)
 {
     DECLARE_DOMCTL;
-    int rc;
 
     domctl.cmd = XEN_DOMCTL_vm_event_op;
     domctl.domain = domain_id;
     domctl.u.vm_event_op.op = op;
     domctl.u.vm_event_op.mode = mode;
 
-    rc = do_domctl(xch, &domctl);
-    if ( !rc && port )
-        *port = domctl.u.vm_event_op.u.enable.port;
-    return rc;
+    return do_domctl(xch, &domctl);
 }
 
 void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
@@ -46,7 +42,8 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
     uint64_t pfn;
     xen_pfn_t ring_pfn, mmap_pfn;
     unsigned int op, mode;
-    int rc1, rc2, saved_errno;
+    int rc;
+    DECLARE_DOMCTL;
 
     if ( !port )
     {
@@ -54,17 +51,9 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
         return NULL;
     }
 
-    /* Pause the domain for ring page setup */
-    rc1 = xc_domain_pause(xch, domain_id);
-    if ( rc1 != 0 )
-    {
-        PERROR("Unable to pause domain\n");
-        return NULL;
-    }
-
     /* Get the pfn of the ring page */
-    rc1 = xc_hvm_param_get(xch, domain_id, param, &pfn);
-    if ( rc1 != 0 )
+    rc = xc_hvm_param_get(xch, domain_id, param, &pfn);
+    if ( rc != 0 )
     {
         PERROR("Failed to get pfn of ring page\n");
         goto out;
@@ -72,13 +61,13 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
 
     ring_pfn = pfn;
     mmap_pfn = pfn;
-    rc1 = xc_get_pfn_type_batch(xch, domain_id, 1, &mmap_pfn);
-    if ( rc1 || mmap_pfn & XEN_DOMCTL_PFINFO_XTAB )
+    rc = xc_get_pfn_type_batch(xch, domain_id, 1, &mmap_pfn);
+    if ( rc || mmap_pfn & XEN_DOMCTL_PFINFO_XTAB )
     {
         /* Page not in the physmap, try to populate it */
-        rc1 = xc_domain_populate_physmap_exact(xch, domain_id, 1, 0, 0,
+        rc = xc_domain_populate_physmap_exact(xch, domain_id, 1, 0, 0,
                                               &ring_pfn);
-        if ( rc1 != 0 )
+        if ( rc != 0 )
         {
             PERROR("Failed to populate ring pfn\n");
             goto out;
@@ -87,7 +76,7 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
 
     mmap_pfn = ring_pfn;
     ring_page = xc_map_foreign_pages(xch, domain_id, PROT_READ | PROT_WRITE,
-                                         &mmap_pfn, 1);
+                                     &mmap_pfn, 1);
     if ( !ring_page )
     {
         PERROR("Could not map the ring page\n");
@@ -117,40 +106,35 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
      */
     default:
         errno = EINVAL;
-        rc1 = -1;
+        rc = -1;
         goto out;
     }
 
-    rc1 = xc_vm_event_control(xch, domain_id, op, mode, port);
-    if ( rc1 != 0 )
+    domctl.cmd = XEN_DOMCTL_vm_event_op;
+    domctl.domain = domain_id;
+    domctl.u.vm_event_op.op = op;
+    domctl.u.vm_event_op.mode = mode;
+
+    rc = do_domctl(xch, &domctl);
+    if ( rc != 0 )
     {
         PERROR("Failed to enable vm_event\n");
         goto out;
     }
 
+    *port = domctl.u.vm_event_op.u.enable.port;
+
     /* Remove the ring_pfn from the guest's physmap */
-    rc1 = xc_domain_decrease_reservation_exact(xch, domain_id, 1, 0, &ring_pfn);
-    if ( rc1 != 0 )
+    rc = xc_domain_decrease_reservation_exact(xch, domain_id, 1, 0, &ring_pfn);
+    if ( rc != 0 )
         PERROR("Failed to remove ring page from guest physmap");
 
  out:
-    saved_errno = errno;
-
-    rc2 = xc_domain_unpause(xch, domain_id);
-    if ( rc1 != 0 || rc2 != 0 )
+    if ( rc != 0 )
     {
-        if ( rc2 != 0 )
-        {
-            if ( rc1 == 0 )
-                saved_errno = errno;
-            PERROR("Unable to unpause domain");
-        }
-
         if ( ring_page )
             xenforeignmemory_unmap(xch->fmem, ring_page, 1);
         ring_page = NULL;
-
-        errno = saved_errno;
     }
 
     return ring_page;
diff --git a/tools/xenpaging/xenpaging.c b/tools/xenpaging/xenpaging.c
index d0571ca..b4a3a5c 100644
--- a/tools/xenpaging/xenpaging.c
+++ b/tools/xenpaging/xenpaging.c
@@ -337,40 +337,11 @@ static struct xenpaging *xenpaging_init(int argc, char *argv[])
         goto err;
     }
 
-    /* Map the ring page */
-    xc_get_hvm_param(xch, paging->vm_event.domain_id, 
-                        HVM_PARAM_PAGING_RING_PFN, &ring_pfn);
-    mmap_pfn = ring_pfn;
-    paging->vm_event.ring_page = 
-        xc_map_foreign_pages(xch, paging->vm_event.domain_id,
-                             PROT_READ | PROT_WRITE, &mmap_pfn, 1);
-    if ( !paging->vm_event.ring_page )
-    {
-        /* Map failed, populate ring page */
-        rc = xc_domain_populate_physmap_exact(paging->xc_handle, 
-                                              paging->vm_event.domain_id,
-                                              1, 0, 0, &ring_pfn);
-        if ( rc != 0 )
-        {
-            PERROR("Failed to populate ring gfn\n");
-            goto err;
-        }
-
-        paging->vm_event.ring_page = 
-            xc_map_foreign_pages(xch, paging->vm_event.domain_id,
-                                 PROT_READ | PROT_WRITE,
-                                 &mmap_pfn, 1);
-        if ( !paging->vm_event.ring_page )
-        {
-            PERROR("Could not map the ring page\n");
-            goto err;
-        }
-    }
-    
     /* Initialise Xen */
-    rc = xc_mem_paging_enable(xch, paging->vm_event.domain_id,
-                             &paging->vm_event.evtchn_port);
-    if ( rc != 0 )
+    paging->vm_event.ring_page =
+            xc_mem_paging_enable(xch, paging->vm_event.domain_id,
+                                 &paging->vm_event.evtchn_port);
+    if ( paging->vm_event.ring_page == NULL )
     {
         switch ( errno ) {
             case EBUSY:
@@ -418,11 +389,6 @@ static struct xenpaging *xenpaging_init(int argc, char *argv[])
                    (vm_event_sring_t *)paging->vm_event.ring_page,
                    PAGE_SIZE);
 
-    /* Now that the ring is set, remove it from the guest's physmap */
-    if ( xc_domain_decrease_reservation_exact(xch, 
-                    paging->vm_event.domain_id, 1, 0, &ring_pfn) )
-        PERROR("Failed to remove ring from guest physmap");
-
     /* Get max_pages from guest if not provided via cmdline */
     if ( !paging->max_pages )
     {
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 1/9] tools/libxc: Consistent usage of xc_vm_event_* interface
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel; +Cc: Petre Pircalabu, Ian Jackson, Wei Liu

Modified xc_mem_paging_enable to use directly xc_vm_event_enable and
moved the ring_page handling from client to libxc (xenpaging).

Restricted vm_event_control usage only to simplest domctls which do
not expect any return values and change xc_vm_event_enable to call do_domctl
directly.

Removed xc_memshr_ring_enable/disable and xc_memshr_domain_resume.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 tools/libxc/include/xenctrl.h | 49 +--------------------------------
 tools/libxc/xc_mem_paging.c   | 23 +++++-----------
 tools/libxc/xc_memshr.c       | 34 -----------------------
 tools/libxc/xc_monitor.c      | 31 +++++++++++++++++----
 tools/libxc/xc_private.h      |  2 +-
 tools/libxc/xc_vm_event.c     | 64 ++++++++++++++++---------------------------
 tools/xenpaging/xenpaging.c   | 42 +++-------------------------
 7 files changed, 62 insertions(+), 183 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 538007a..28fdbc0 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1949,7 +1949,7 @@ int xc_altp2m_change_gfn(xc_interface *handle, uint32_t domid,
  * Hardware-Assisted Paging (i.e. Intel EPT, AMD NPT). Moreover, AMD NPT
  * support is considered experimental.
  */
-int xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port);
+void *xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port);
 int xc_mem_paging_disable(xc_interface *xch, uint32_t domain_id);
 int xc_mem_paging_resume(xc_interface *xch, uint32_t domain_id);
 int xc_mem_paging_nominate(xc_interface *xch, uint32_t domain_id,
@@ -2082,53 +2082,6 @@ int xc_memshr_control(xc_interface *xch,
                       uint32_t domid,
                       int enable);
 
-/* Create a communication ring in which the hypervisor will place ENOMEM
- * notifications.
- *
- * ENOMEM happens when unsharing pages: a Copy-on-Write duplicate needs to be
- * allocated, and thus the out-of-memory error occurr.
- *
- * For complete examples on how to plumb a notification ring, look into
- * xenpaging or xen-access.
- *
- * On receipt of a notification, the helper should ensure there is memory
- * available to the domain before retrying.
- *
- * If a domain encounters an ENOMEM condition when sharing and this ring
- * has not been set up, the hypervisor will crash the domain.
- *
- * Fails with:
- *  EINVAL if port is NULL
- *  EINVAL if the sharing ring has already been enabled
- *  ENOSYS if no guest gfn has been specified to host the ring via an hvm param
- *  EINVAL if the gfn for the ring has not been populated
- *  ENOENT if the gfn for the ring is paged out, or cannot be unshared
- *  EINVAL if the gfn for the ring cannot be written to
- *  EINVAL if the domain is dying
- *  ENOSPC if an event channel cannot be allocated for the ring
- *  ENOMEM if memory cannot be allocated for internal data structures
- *  EINVAL or EACCESS if the request is denied by the security policy
- */
-
-int xc_memshr_ring_enable(xc_interface *xch, 
-                          uint32_t domid,
-                          uint32_t *port);
-/* Disable the ring for ENOMEM communication.
- * May fail with EINVAL if the ring was not enabled in the first place.
- */
-int xc_memshr_ring_disable(xc_interface *xch, 
-                           uint32_t domid);
-
-/*
- * Calls below return EINVAL if sharing has not been enabled for the domain
- * Calls below return EINVAL if the domain is dying
- */
-/* Once a reponse to an ENOMEM notification is prepared, the tool can
- * notify the hypervisor to re-schedule the faulting vcpu of the domain with an
- * event channel kick and/or this call. */
-int xc_memshr_domain_resume(xc_interface *xch,
-                            uint32_t domid);
-
 /* Select a page for sharing. 
  *
  * A 64 bit opaque handle will be stored in handle.  The hypervisor ensures
diff --git a/tools/libxc/xc_mem_paging.c b/tools/libxc/xc_mem_paging.c
index a067706..08468fb 100644
--- a/tools/libxc/xc_mem_paging.c
+++ b/tools/libxc/xc_mem_paging.c
@@ -37,35 +37,26 @@ static int xc_mem_paging_memop(xc_interface *xch, uint32_t domain_id,
     return do_memory_op(xch, XENMEM_paging_op, &mpo, sizeof(mpo));
 }
 
-int xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id,
-                         uint32_t *port)
+void *xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id,
+                           uint32_t *port)
 {
-    if ( !port )
-    {
-        errno = EINVAL;
-        return -1;
-    }
-
-    return xc_vm_event_control(xch, domain_id,
-                               XEN_VM_EVENT_ENABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING,
-                               port);
+    return xc_vm_event_enable(xch, domain_id,
+                              XEN_DOMCTL_VM_EVENT_OP_PAGING,
+                              port);
 }
 
 int xc_mem_paging_disable(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING,
-                               NULL);
+                               XEN_DOMCTL_VM_EVENT_OP_PAGING);
 }
 
 int xc_mem_paging_resume(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING,
-                               NULL);
+                               XEN_DOMCTL_VM_EVENT_OP_PAGING);
 }
 
 int xc_mem_paging_nominate(xc_interface *xch, uint32_t domain_id, uint64_t gfn)
diff --git a/tools/libxc/xc_memshr.c b/tools/libxc/xc_memshr.c
index d5e135e..06f613a 100644
--- a/tools/libxc/xc_memshr.c
+++ b/tools/libxc/xc_memshr.c
@@ -41,31 +41,6 @@ int xc_memshr_control(xc_interface *xch,
     return do_domctl(xch, &domctl);
 }
 
-int xc_memshr_ring_enable(xc_interface *xch, 
-                          uint32_t domid,
-                          uint32_t *port)
-{
-    if ( !port )
-    {
-        errno = EINVAL;
-        return -1;
-    }
-
-    return xc_vm_event_control(xch, domid,
-                               XEN_VM_EVENT_ENABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_SHARING,
-                               port);
-}
-
-int xc_memshr_ring_disable(xc_interface *xch, 
-                           uint32_t domid)
-{
-    return xc_vm_event_control(xch, domid,
-                               XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_SHARING,
-                               NULL);
-}
-
 static int xc_memshr_memop(xc_interface *xch, uint32_t domid,
                             xen_mem_sharing_op_t *mso)
 {
@@ -200,15 +175,6 @@ int xc_memshr_range_share(xc_interface *xch,
     return xc_memshr_memop(xch, source_domain, &mso);
 }
 
-int xc_memshr_domain_resume(xc_interface *xch,
-                            uint32_t domid)
-{
-    return xc_vm_event_control(xch, domid,
-                               XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_SHARING,
-                               NULL);
-}
-
 int xc_memshr_debug_gfn(xc_interface *xch,
                         uint32_t domid,
                         unsigned long gfn)
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index 4ac823e..d190c29 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -24,24 +24,43 @@
 
 void *xc_monitor_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port)
 {
-    return xc_vm_event_enable(xch, domain_id, HVM_PARAM_MONITOR_RING_PFN,
-                              port);
+    void *buffer;
+    int saved_errno;
+
+    /* Pause the domain for ring page setup */
+    if ( xc_domain_pause(xch, domain_id) )
+    {
+        PERROR("Unable to pause domain\n");
+        return NULL;
+    }
+
+    buffer = xc_vm_event_enable(xch, domain_id,
+                                HVM_PARAM_MONITOR_RING_PFN,
+                                port);
+    saved_errno = errno;
+    if ( xc_domain_unpause(xch, domain_id) )
+    {
+        if ( buffer )
+            saved_errno = errno;
+        PERROR("Unable to unpause domain");
+    }
+
+    errno = saved_errno;
+    return buffer;
 }
 
 int xc_monitor_disable(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_MONITOR,
-                               NULL);
+                               XEN_DOMCTL_VM_EVENT_OP_MONITOR);
 }
 
 int xc_monitor_resume(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_MONITOR,
-                               NULL);
+                               XEN_DOMCTL_VM_EVENT_OP_MONITOR);
 }
 
 int xc_monitor_get_capabilities(xc_interface *xch, uint32_t domain_id,
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index adc3b6a..663e78b 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -412,7 +412,7 @@ int xc_ffs64(uint64_t x);
  * vm_event operations. Internal use only.
  */
 int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
-                        unsigned int mode, uint32_t *port);
+                        unsigned int mode);
 /*
  * Enables vm_event and returns the mapped ring page indicated by param.
  * param can be HVM_PARAM_PAGING/ACCESS/SHARING_RING_PFN
diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
index a97c615..ea10366 100644
--- a/tools/libxc/xc_vm_event.c
+++ b/tools/libxc/xc_vm_event.c
@@ -23,20 +23,16 @@
 #include "xc_private.h"
 
 int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
-                        unsigned int mode, uint32_t *port)
+                        unsigned int mode)
 {
     DECLARE_DOMCTL;
-    int rc;
 
     domctl.cmd = XEN_DOMCTL_vm_event_op;
     domctl.domain = domain_id;
     domctl.u.vm_event_op.op = op;
     domctl.u.vm_event_op.mode = mode;
 
-    rc = do_domctl(xch, &domctl);
-    if ( !rc && port )
-        *port = domctl.u.vm_event_op.u.enable.port;
-    return rc;
+    return do_domctl(xch, &domctl);
 }
 
 void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
@@ -46,7 +42,8 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
     uint64_t pfn;
     xen_pfn_t ring_pfn, mmap_pfn;
     unsigned int op, mode;
-    int rc1, rc2, saved_errno;
+    int rc;
+    DECLARE_DOMCTL;
 
     if ( !port )
     {
@@ -54,17 +51,9 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
         return NULL;
     }
 
-    /* Pause the domain for ring page setup */
-    rc1 = xc_domain_pause(xch, domain_id);
-    if ( rc1 != 0 )
-    {
-        PERROR("Unable to pause domain\n");
-        return NULL;
-    }
-
     /* Get the pfn of the ring page */
-    rc1 = xc_hvm_param_get(xch, domain_id, param, &pfn);
-    if ( rc1 != 0 )
+    rc = xc_hvm_param_get(xch, domain_id, param, &pfn);
+    if ( rc != 0 )
     {
         PERROR("Failed to get pfn of ring page\n");
         goto out;
@@ -72,13 +61,13 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
 
     ring_pfn = pfn;
     mmap_pfn = pfn;
-    rc1 = xc_get_pfn_type_batch(xch, domain_id, 1, &mmap_pfn);
-    if ( rc1 || mmap_pfn & XEN_DOMCTL_PFINFO_XTAB )
+    rc = xc_get_pfn_type_batch(xch, domain_id, 1, &mmap_pfn);
+    if ( rc || mmap_pfn & XEN_DOMCTL_PFINFO_XTAB )
     {
         /* Page not in the physmap, try to populate it */
-        rc1 = xc_domain_populate_physmap_exact(xch, domain_id, 1, 0, 0,
+        rc = xc_domain_populate_physmap_exact(xch, domain_id, 1, 0, 0,
                                               &ring_pfn);
-        if ( rc1 != 0 )
+        if ( rc != 0 )
         {
             PERROR("Failed to populate ring pfn\n");
             goto out;
@@ -87,7 +76,7 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
 
     mmap_pfn = ring_pfn;
     ring_page = xc_map_foreign_pages(xch, domain_id, PROT_READ | PROT_WRITE,
-                                         &mmap_pfn, 1);
+                                     &mmap_pfn, 1);
     if ( !ring_page )
     {
         PERROR("Could not map the ring page\n");
@@ -117,40 +106,35 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
      */
     default:
         errno = EINVAL;
-        rc1 = -1;
+        rc = -1;
         goto out;
     }
 
-    rc1 = xc_vm_event_control(xch, domain_id, op, mode, port);
-    if ( rc1 != 0 )
+    domctl.cmd = XEN_DOMCTL_vm_event_op;
+    domctl.domain = domain_id;
+    domctl.u.vm_event_op.op = op;
+    domctl.u.vm_event_op.mode = mode;
+
+    rc = do_domctl(xch, &domctl);
+    if ( rc != 0 )
     {
         PERROR("Failed to enable vm_event\n");
         goto out;
     }
 
+    *port = domctl.u.vm_event_op.u.enable.port;
+
     /* Remove the ring_pfn from the guest's physmap */
-    rc1 = xc_domain_decrease_reservation_exact(xch, domain_id, 1, 0, &ring_pfn);
-    if ( rc1 != 0 )
+    rc = xc_domain_decrease_reservation_exact(xch, domain_id, 1, 0, &ring_pfn);
+    if ( rc != 0 )
         PERROR("Failed to remove ring page from guest physmap");
 
  out:
-    saved_errno = errno;
-
-    rc2 = xc_domain_unpause(xch, domain_id);
-    if ( rc1 != 0 || rc2 != 0 )
+    if ( rc != 0 )
     {
-        if ( rc2 != 0 )
-        {
-            if ( rc1 == 0 )
-                saved_errno = errno;
-            PERROR("Unable to unpause domain");
-        }
-
         if ( ring_page )
             xenforeignmemory_unmap(xch->fmem, ring_page, 1);
         ring_page = NULL;
-
-        errno = saved_errno;
     }
 
     return ring_page;
diff --git a/tools/xenpaging/xenpaging.c b/tools/xenpaging/xenpaging.c
index d0571ca..b4a3a5c 100644
--- a/tools/xenpaging/xenpaging.c
+++ b/tools/xenpaging/xenpaging.c
@@ -337,40 +337,11 @@ static struct xenpaging *xenpaging_init(int argc, char *argv[])
         goto err;
     }
 
-    /* Map the ring page */
-    xc_get_hvm_param(xch, paging->vm_event.domain_id, 
-                        HVM_PARAM_PAGING_RING_PFN, &ring_pfn);
-    mmap_pfn = ring_pfn;
-    paging->vm_event.ring_page = 
-        xc_map_foreign_pages(xch, paging->vm_event.domain_id,
-                             PROT_READ | PROT_WRITE, &mmap_pfn, 1);
-    if ( !paging->vm_event.ring_page )
-    {
-        /* Map failed, populate ring page */
-        rc = xc_domain_populate_physmap_exact(paging->xc_handle, 
-                                              paging->vm_event.domain_id,
-                                              1, 0, 0, &ring_pfn);
-        if ( rc != 0 )
-        {
-            PERROR("Failed to populate ring gfn\n");
-            goto err;
-        }
-
-        paging->vm_event.ring_page = 
-            xc_map_foreign_pages(xch, paging->vm_event.domain_id,
-                                 PROT_READ | PROT_WRITE,
-                                 &mmap_pfn, 1);
-        if ( !paging->vm_event.ring_page )
-        {
-            PERROR("Could not map the ring page\n");
-            goto err;
-        }
-    }
-    
     /* Initialise Xen */
-    rc = xc_mem_paging_enable(xch, paging->vm_event.domain_id,
-                             &paging->vm_event.evtchn_port);
-    if ( rc != 0 )
+    paging->vm_event.ring_page =
+            xc_mem_paging_enable(xch, paging->vm_event.domain_id,
+                                 &paging->vm_event.evtchn_port);
+    if ( paging->vm_event.ring_page == NULL )
     {
         switch ( errno ) {
             case EBUSY:
@@ -418,11 +389,6 @@ static struct xenpaging *xenpaging_init(int argc, char *argv[])
                    (vm_event_sring_t *)paging->vm_event.ring_page,
                    PAGE_SIZE);
 
-    /* Now that the ring is set, remove it from the guest's physmap */
-    if ( xc_domain_decrease_reservation_exact(xch, 
-                    paging->vm_event.domain_id, 1, 0, &ring_pfn) )
-        PERROR("Failed to remove ring from guest physmap");
-
     /* Get max_pages from guest if not provided via cmdline */
     if ( !paging->max_pages )
     {
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Tamas K Lengyel, Jan Beulich

Define the type for each of the supported vm_event rings (paging,
monitor and sharing) and replace the ring param field with this type.

Replace XEN_DOMCTL_VM_EVENT_OP_ occurrences with their corresponding
XEN_VM_EVENT_TYPE_ counterpart.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 tools/libxc/include/xenctrl.h |  1 +
 tools/libxc/xc_mem_paging.c   |  6 ++--
 tools/libxc/xc_monitor.c      |  6 ++--
 tools/libxc/xc_private.h      |  8 ++---
 tools/libxc/xc_vm_event.c     | 70 ++++++++++++++++++-------------------
 xen/common/vm_event.c         | 12 +++----
 xen/include/public/domctl.h   | 81 ++++++-------------------------------------
 xen/include/public/vm_event.h | 31 +++++++++++++++++
 8 files changed, 93 insertions(+), 122 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 28fdbc0..943b933 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -46,6 +46,7 @@
 #include <xen/xsm/flask_op.h>
 #include <xen/kexec.h>
 #include <xen/platform.h>
+#include <xen/vm_event.h>
 
 #include "xentoollog.h"
 
diff --git a/tools/libxc/xc_mem_paging.c b/tools/libxc/xc_mem_paging.c
index 08468fb..37a8224 100644
--- a/tools/libxc/xc_mem_paging.c
+++ b/tools/libxc/xc_mem_paging.c
@@ -41,7 +41,7 @@ void *xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id,
                            uint32_t *port)
 {
     return xc_vm_event_enable(xch, domain_id,
-                              XEN_DOMCTL_VM_EVENT_OP_PAGING,
+                              XEN_VM_EVENT_TYPE_PAGING,
                               port);
 }
 
@@ -49,14 +49,14 @@ int xc_mem_paging_disable(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING);
+                               XEN_VM_EVENT_TYPE_PAGING);
 }
 
 int xc_mem_paging_resume(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING);
+                               XEN_VM_EVENT_TYPE_PAGING);
 }
 
 int xc_mem_paging_nominate(xc_interface *xch, uint32_t domain_id, uint64_t gfn)
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index d190c29..718fe8b 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -35,7 +35,7 @@ void *xc_monitor_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port)
     }
 
     buffer = xc_vm_event_enable(xch, domain_id,
-                                HVM_PARAM_MONITOR_RING_PFN,
+                                XEN_VM_EVENT_TYPE_MONITOR,
                                 port);
     saved_errno = errno;
     if ( xc_domain_unpause(xch, domain_id) )
@@ -53,14 +53,14 @@ int xc_monitor_disable(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_MONITOR);
+                               XEN_VM_EVENT_TYPE_MONITOR);
 }
 
 int xc_monitor_resume(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_MONITOR);
+                               XEN_VM_EVENT_TYPE_MONITOR);
 }
 
 int xc_monitor_get_capabilities(xc_interface *xch, uint32_t domain_id,
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index 663e78b..482451c 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -412,12 +412,12 @@ int xc_ffs64(uint64_t x);
  * vm_event operations. Internal use only.
  */
 int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
-                        unsigned int mode);
+                        unsigned int type);
 /*
- * Enables vm_event and returns the mapped ring page indicated by param.
- * param can be HVM_PARAM_PAGING/ACCESS/SHARING_RING_PFN
+ * Enables vm_event and returns the mapped ring page indicated by type.
+ * type can be XEN_VM_EVENT_TYPE_(PAGING/MONITOR/SHARING)
  */
-void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
+void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int type,
                          uint32_t *port);
 
 int do_dm_op(xc_interface *xch, uint32_t domid, unsigned int nr_bufs, ...);
diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
index ea10366..3b1018b 100644
--- a/tools/libxc/xc_vm_event.c
+++ b/tools/libxc/xc_vm_event.c
@@ -23,29 +23,54 @@
 #include "xc_private.h"
 
 int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
-                        unsigned int mode)
+                        unsigned int type)
 {
     DECLARE_DOMCTL;
 
     domctl.cmd = XEN_DOMCTL_vm_event_op;
     domctl.domain = domain_id;
     domctl.u.vm_event_op.op = op;
-    domctl.u.vm_event_op.mode = mode;
+    domctl.u.vm_event_op.type = type;
 
     return do_domctl(xch, &domctl);
 }
 
-void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
+static int xc_vm_event_ring_pfn_param(int type, int *param)
+{
+    if ( !param )
+        return -EINVAL;
+
+    switch ( type )
+    {
+    case XEN_VM_EVENT_TYPE_PAGING:
+        *param = HVM_PARAM_PAGING_RING_PFN;
+        break;
+
+    case XEN_VM_EVENT_TYPE_MONITOR:
+        *param = HVM_PARAM_MONITOR_RING_PFN;
+        break;
+
+    case XEN_VM_EVENT_TYPE_SHARING:
+        *param = HVM_PARAM_SHARING_RING_PFN;
+        break;
+
+    default:
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int type,
                          uint32_t *port)
 {
     void *ring_page = NULL;
     uint64_t pfn;
     xen_pfn_t ring_pfn, mmap_pfn;
-    unsigned int op, mode;
-    int rc;
+    int param, rc;
     DECLARE_DOMCTL;
 
-    if ( !port )
+    if ( !port || xc_vm_event_ring_pfn_param(type, &param) != 0 )
     {
         errno = EINVAL;
         return NULL;
@@ -83,37 +108,10 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
         goto out;
     }
 
-    switch ( param )
-    {
-    case HVM_PARAM_PAGING_RING_PFN:
-        op = XEN_VM_EVENT_ENABLE;
-        mode = XEN_DOMCTL_VM_EVENT_OP_PAGING;
-        break;
-
-    case HVM_PARAM_MONITOR_RING_PFN:
-        op = XEN_VM_EVENT_ENABLE;
-        mode = XEN_DOMCTL_VM_EVENT_OP_MONITOR;
-        break;
-
-    case HVM_PARAM_SHARING_RING_PFN:
-        op = XEN_VM_EVENT_ENABLE;
-        mode = XEN_DOMCTL_VM_EVENT_OP_SHARING;
-        break;
-
-    /*
-     * This is for the outside chance that the HVM_PARAM is valid but is invalid
-     * as far as vm_event goes.
-     */
-    default:
-        errno = EINVAL;
-        rc = -1;
-        goto out;
-    }
-
     domctl.cmd = XEN_DOMCTL_vm_event_op;
     domctl.domain = domain_id;
-    domctl.u.vm_event_op.op = op;
-    domctl.u.vm_event_op.mode = mode;
+    domctl.u.vm_event_op.op = XEN_VM_EVENT_ENABLE;
+    domctl.u.vm_event_op.type = type;
 
     rc = do_domctl(xch, &domctl);
     if ( rc != 0 )
@@ -148,7 +146,7 @@ int xc_vm_event_get_version(xc_interface *xch)
     domctl.cmd = XEN_DOMCTL_vm_event_op;
     domctl.domain = DOMID_INVALID;
     domctl.u.vm_event_op.op = XEN_VM_EVENT_GET_VERSION;
-    domctl.u.vm_event_op.mode = XEN_DOMCTL_VM_EVENT_OP_MONITOR;
+    domctl.u.vm_event_op.type = XEN_VM_EVENT_TYPE_MONITOR;
 
     rc = do_domctl(xch, &domctl);
     if ( !rc )
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 6833c21..d7c5f22 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -371,7 +371,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
     vm_event_response_t rsp;
 
     /*
-     * vm_event_resume() runs in either XEN_DOMCTL_VM_EVENT_OP_*, or
+     * vm_event_resume() runs in either XEN_VM_EVENT_* domctls, or
      * EVTCHN_send context from the introspection consumer. Both contexts
      * are guaranteed not to be the subject of vm_event responses.
      * While we could ASSERT(v != current) for each VCPU in d in the loop
@@ -597,7 +597,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
     if ( unlikely(d == NULL) )
         return -ESRCH;
 
-    rc = xsm_vm_event_control(XSM_PRIV, d, vec->mode, vec->op);
+    rc = xsm_vm_event_control(XSM_PRIV, d, vec->type, vec->op);
     if ( rc )
         return rc;
 
@@ -624,10 +624,10 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
 
     rc = -ENOSYS;
 
-    switch ( vec->mode )
+    switch ( vec->type )
     {
 #ifdef CONFIG_HAS_MEM_PAGING
-    case XEN_DOMCTL_VM_EVENT_OP_PAGING:
+    case XEN_VM_EVENT_TYPE_PAGING:
     {
         rc = -EINVAL;
 
@@ -683,7 +683,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
     break;
 #endif
 
-    case XEN_DOMCTL_VM_EVENT_OP_MONITOR:
+    case XEN_VM_EVENT_TYPE_MONITOR:
     {
         rc = -EINVAL;
 
@@ -721,7 +721,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
     break;
 
 #ifdef CONFIG_HAS_MEM_SHARING
-    case XEN_DOMCTL_VM_EVENT_OP_SHARING:
+    case XEN_VM_EVENT_TYPE_SHARING:
     {
         rc = -EINVAL;
 
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 19486d5..19281fa 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -38,7 +38,7 @@
 #include "hvm/save.h"
 #include "memory.h"
 
-#define XEN_DOMCTL_INTERFACE_VERSION 0x00000011
+#define XEN_DOMCTL_INTERFACE_VERSION 0x00000012
 
 /*
  * NB. xen_domctl.domain is an IN/OUT parameter for this operation.
@@ -769,80 +769,18 @@ struct xen_domctl_gdbsx_domstatus {
  * VM event operations
  */
 
-/* XEN_DOMCTL_vm_event_op */
-
-/*
- * There are currently three rings available for VM events:
- * sharing, monitor and paging. This hypercall allows one to
- * control these rings (enable/disable), as well as to signal
- * to the hypervisor to pull responses (resume) from the given
- * ring.
+/* XEN_DOMCTL_vm_event_op.
+ * Use for teardown/setup of helper<->hypervisor interface for paging,
+ * access and sharing.
  */
 #define XEN_VM_EVENT_ENABLE               0
 #define XEN_VM_EVENT_DISABLE              1
 #define XEN_VM_EVENT_RESUME               2
 #define XEN_VM_EVENT_GET_VERSION          3
 
-/*
- * Domain memory paging
- * Page memory in and out.
- * Domctl interface to set up and tear down the
- * pager<->hypervisor interface. Use XENMEM_paging_op*
- * to perform per-page operations.
- *
- * The XEN_VM_EVENT_PAGING_ENABLE domctl returns several
- * non-standard error codes to indicate why paging could not be enabled:
- * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
- * EMLINK - guest has iommu passthrough enabled
- * EXDEV  - guest has PoD enabled
- * EBUSY  - guest has or had paging enabled, ring buffer still active
- */
-#define XEN_DOMCTL_VM_EVENT_OP_PAGING            1
-
-/*
- * Monitor helper.
- *
- * As with paging, use the domctl for teardown/setup of the
- * helper<->hypervisor interface.
- *
- * The monitor interface can be used to register for various VM events. For
- * example, there are HVM hypercalls to set the per-page access permissions
- * of every page in a domain.  When one of these permissions--independent,
- * read, write, and execute--is violated, the VCPU is paused and a memory event
- * is sent with what happened. The memory event handler can then resume the
- * VCPU and redo the access with a XEN_VM_EVENT_RESUME option.
- *
- * See public/vm_event.h for the list of available events that can be
- * subscribed to via the monitor interface.
- *
- * The XEN_VM_EVENT_MONITOR_* domctls returns
- * non-standard error codes to indicate why access could not be enabled:
- * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
- * EBUSY  - guest has or had access enabled, ring buffer still active
- *
- */
-#define XEN_DOMCTL_VM_EVENT_OP_MONITOR           2
-
-/*
- * Sharing ENOMEM helper.
- *
- * As with paging, use the domctl for teardown/setup of the
- * helper<->hypervisor interface.
- *
- * If setup, this ring is used to communicate failed allocations
- * in the unshare path. XENMEM_sharing_op_resume is used to wake up
- * vcpus that could not unshare.
- *
- * Note that shring can be turned on (as per the domctl below)
- * *without* this ring being setup.
- */
-#define XEN_DOMCTL_VM_EVENT_OP_SHARING           3
-
-/* Use for teardown/setup of helper<->hypervisor interface for paging,
- * access and sharing.*/
 struct xen_domctl_vm_event_op {
-    uint32_t       op;           /* XEN_VM_EVENT_* */
-    uint32_t       mode;         /* XEN_DOMCTL_VM_EVENT_OP_* */
+    uint32_t        op;           /* XEN_VM_EVENT_* */
+    uint32_t        type;         /* XEN_VM_EVENT_TYPE_* */
 
     union {
         struct {
@@ -857,7 +795,10 @@ struct xen_domctl_vm_event_op {
  * Memory sharing operations
  */
 /* XEN_DOMCTL_mem_sharing_op.
- * The CONTROL sub-domctl is used for bringup/teardown. */
+ * The CONTROL sub-domctl is used for bringup/teardown.
+ * Please note that mem sharing can be turned on *without* setting-up the
+ * correspondin ring
+ */
 #define XEN_DOMCTL_MEM_SHARING_CONTROL          0
 
 struct xen_domctl_mem_sharing_op {
@@ -1004,7 +945,7 @@ struct xen_domctl_psr_cmt_op {
  * Enable/disable monitoring various VM events.
  * This domctl configures what events will be reported to helper apps
  * via the ring buffer "MONITOR". The ring has to be first enabled
- * with the domctl XEN_DOMCTL_VM_EVENT_OP_MONITOR.
+ * with XEN_VM_EVENT_ENABLE.
  *
  * GET_CAPABILITIES can be used to determine which of these features is
  * available on a given platform.
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index 959083d..c48bc21 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -36,6 +36,37 @@
 #include "io/ring.h"
 
 /*
+ * There are currently three types of VM events.
+ */
+
+/*
+ * Domain memory paging
+ *
+ * Page memory in and out.
+ */
+#define XEN_VM_EVENT_TYPE_PAGING         1
+
+/*
+ * Monitor.
+ *
+ * The monitor interface can be used to register for various VM events. For
+ * example, there are HVM hypercalls to set the per-page access permissions
+ * of every page in a domain.  When one of these permissions--independent,
+ * read, write, and execute--is violated, the VCPU is paused and a memory event
+ * is sent with what happened. The memory event handler can then resume the
+ * VCPU and redo the access with a XEN_VM_EVENT_RESUME option.
+ */
+#define XEN_VM_EVENT_TYPE_MONITOR        2
+
+/*
+ * Sharing ENOMEM.
+ *
+ * Used to communicate failed allocations in the unshare path.
+ * XENMEM_sharing_op_resume is used to wake up vcpus that could not unshare.
+ */
+#define XEN_VM_EVENT_TYPE_SHARING        3
+
+/*
  * Memory event flags
  */
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Tamas K Lengyel, Jan Beulich

Define the type for each of the supported vm_event rings (paging,
monitor and sharing) and replace the ring param field with this type.

Replace XEN_DOMCTL_VM_EVENT_OP_ occurrences with their corresponding
XEN_VM_EVENT_TYPE_ counterpart.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 tools/libxc/include/xenctrl.h |  1 +
 tools/libxc/xc_mem_paging.c   |  6 ++--
 tools/libxc/xc_monitor.c      |  6 ++--
 tools/libxc/xc_private.h      |  8 ++---
 tools/libxc/xc_vm_event.c     | 70 ++++++++++++++++++-------------------
 xen/common/vm_event.c         | 12 +++----
 xen/include/public/domctl.h   | 81 ++++++-------------------------------------
 xen/include/public/vm_event.h | 31 +++++++++++++++++
 8 files changed, 93 insertions(+), 122 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 28fdbc0..943b933 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -46,6 +46,7 @@
 #include <xen/xsm/flask_op.h>
 #include <xen/kexec.h>
 #include <xen/platform.h>
+#include <xen/vm_event.h>
 
 #include "xentoollog.h"
 
diff --git a/tools/libxc/xc_mem_paging.c b/tools/libxc/xc_mem_paging.c
index 08468fb..37a8224 100644
--- a/tools/libxc/xc_mem_paging.c
+++ b/tools/libxc/xc_mem_paging.c
@@ -41,7 +41,7 @@ void *xc_mem_paging_enable(xc_interface *xch, uint32_t domain_id,
                            uint32_t *port)
 {
     return xc_vm_event_enable(xch, domain_id,
-                              XEN_DOMCTL_VM_EVENT_OP_PAGING,
+                              XEN_VM_EVENT_TYPE_PAGING,
                               port);
 }
 
@@ -49,14 +49,14 @@ int xc_mem_paging_disable(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING);
+                               XEN_VM_EVENT_TYPE_PAGING);
 }
 
 int xc_mem_paging_resume(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_PAGING);
+                               XEN_VM_EVENT_TYPE_PAGING);
 }
 
 int xc_mem_paging_nominate(xc_interface *xch, uint32_t domain_id, uint64_t gfn)
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index d190c29..718fe8b 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -35,7 +35,7 @@ void *xc_monitor_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port)
     }
 
     buffer = xc_vm_event_enable(xch, domain_id,
-                                HVM_PARAM_MONITOR_RING_PFN,
+                                XEN_VM_EVENT_TYPE_MONITOR,
                                 port);
     saved_errno = errno;
     if ( xc_domain_unpause(xch, domain_id) )
@@ -53,14 +53,14 @@ int xc_monitor_disable(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_DISABLE,
-                               XEN_DOMCTL_VM_EVENT_OP_MONITOR);
+                               XEN_VM_EVENT_TYPE_MONITOR);
 }
 
 int xc_monitor_resume(xc_interface *xch, uint32_t domain_id)
 {
     return xc_vm_event_control(xch, domain_id,
                                XEN_VM_EVENT_RESUME,
-                               XEN_DOMCTL_VM_EVENT_OP_MONITOR);
+                               XEN_VM_EVENT_TYPE_MONITOR);
 }
 
 int xc_monitor_get_capabilities(xc_interface *xch, uint32_t domain_id,
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index 663e78b..482451c 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -412,12 +412,12 @@ int xc_ffs64(uint64_t x);
  * vm_event operations. Internal use only.
  */
 int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
-                        unsigned int mode);
+                        unsigned int type);
 /*
- * Enables vm_event and returns the mapped ring page indicated by param.
- * param can be HVM_PARAM_PAGING/ACCESS/SHARING_RING_PFN
+ * Enables vm_event and returns the mapped ring page indicated by type.
+ * type can be XEN_VM_EVENT_TYPE_(PAGING/MONITOR/SHARING)
  */
-void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
+void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int type,
                          uint32_t *port);
 
 int do_dm_op(xc_interface *xch, uint32_t domid, unsigned int nr_bufs, ...);
diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
index ea10366..3b1018b 100644
--- a/tools/libxc/xc_vm_event.c
+++ b/tools/libxc/xc_vm_event.c
@@ -23,29 +23,54 @@
 #include "xc_private.h"
 
 int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
-                        unsigned int mode)
+                        unsigned int type)
 {
     DECLARE_DOMCTL;
 
     domctl.cmd = XEN_DOMCTL_vm_event_op;
     domctl.domain = domain_id;
     domctl.u.vm_event_op.op = op;
-    domctl.u.vm_event_op.mode = mode;
+    domctl.u.vm_event_op.type = type;
 
     return do_domctl(xch, &domctl);
 }
 
-void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
+static int xc_vm_event_ring_pfn_param(int type, int *param)
+{
+    if ( !param )
+        return -EINVAL;
+
+    switch ( type )
+    {
+    case XEN_VM_EVENT_TYPE_PAGING:
+        *param = HVM_PARAM_PAGING_RING_PFN;
+        break;
+
+    case XEN_VM_EVENT_TYPE_MONITOR:
+        *param = HVM_PARAM_MONITOR_RING_PFN;
+        break;
+
+    case XEN_VM_EVENT_TYPE_SHARING:
+        *param = HVM_PARAM_SHARING_RING_PFN;
+        break;
+
+    default:
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int type,
                          uint32_t *port)
 {
     void *ring_page = NULL;
     uint64_t pfn;
     xen_pfn_t ring_pfn, mmap_pfn;
-    unsigned int op, mode;
-    int rc;
+    int param, rc;
     DECLARE_DOMCTL;
 
-    if ( !port )
+    if ( !port || xc_vm_event_ring_pfn_param(type, &param) != 0 )
     {
         errno = EINVAL;
         return NULL;
@@ -83,37 +108,10 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
         goto out;
     }
 
-    switch ( param )
-    {
-    case HVM_PARAM_PAGING_RING_PFN:
-        op = XEN_VM_EVENT_ENABLE;
-        mode = XEN_DOMCTL_VM_EVENT_OP_PAGING;
-        break;
-
-    case HVM_PARAM_MONITOR_RING_PFN:
-        op = XEN_VM_EVENT_ENABLE;
-        mode = XEN_DOMCTL_VM_EVENT_OP_MONITOR;
-        break;
-
-    case HVM_PARAM_SHARING_RING_PFN:
-        op = XEN_VM_EVENT_ENABLE;
-        mode = XEN_DOMCTL_VM_EVENT_OP_SHARING;
-        break;
-
-    /*
-     * This is for the outside chance that the HVM_PARAM is valid but is invalid
-     * as far as vm_event goes.
-     */
-    default:
-        errno = EINVAL;
-        rc = -1;
-        goto out;
-    }
-
     domctl.cmd = XEN_DOMCTL_vm_event_op;
     domctl.domain = domain_id;
-    domctl.u.vm_event_op.op = op;
-    domctl.u.vm_event_op.mode = mode;
+    domctl.u.vm_event_op.op = XEN_VM_EVENT_ENABLE;
+    domctl.u.vm_event_op.type = type;
 
     rc = do_domctl(xch, &domctl);
     if ( rc != 0 )
@@ -148,7 +146,7 @@ int xc_vm_event_get_version(xc_interface *xch)
     domctl.cmd = XEN_DOMCTL_vm_event_op;
     domctl.domain = DOMID_INVALID;
     domctl.u.vm_event_op.op = XEN_VM_EVENT_GET_VERSION;
-    domctl.u.vm_event_op.mode = XEN_DOMCTL_VM_EVENT_OP_MONITOR;
+    domctl.u.vm_event_op.type = XEN_VM_EVENT_TYPE_MONITOR;
 
     rc = do_domctl(xch, &domctl);
     if ( !rc )
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 6833c21..d7c5f22 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -371,7 +371,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
     vm_event_response_t rsp;
 
     /*
-     * vm_event_resume() runs in either XEN_DOMCTL_VM_EVENT_OP_*, or
+     * vm_event_resume() runs in either XEN_VM_EVENT_* domctls, or
      * EVTCHN_send context from the introspection consumer. Both contexts
      * are guaranteed not to be the subject of vm_event responses.
      * While we could ASSERT(v != current) for each VCPU in d in the loop
@@ -597,7 +597,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
     if ( unlikely(d == NULL) )
         return -ESRCH;
 
-    rc = xsm_vm_event_control(XSM_PRIV, d, vec->mode, vec->op);
+    rc = xsm_vm_event_control(XSM_PRIV, d, vec->type, vec->op);
     if ( rc )
         return rc;
 
@@ -624,10 +624,10 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
 
     rc = -ENOSYS;
 
-    switch ( vec->mode )
+    switch ( vec->type )
     {
 #ifdef CONFIG_HAS_MEM_PAGING
-    case XEN_DOMCTL_VM_EVENT_OP_PAGING:
+    case XEN_VM_EVENT_TYPE_PAGING:
     {
         rc = -EINVAL;
 
@@ -683,7 +683,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
     break;
 #endif
 
-    case XEN_DOMCTL_VM_EVENT_OP_MONITOR:
+    case XEN_VM_EVENT_TYPE_MONITOR:
     {
         rc = -EINVAL;
 
@@ -721,7 +721,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
     break;
 
 #ifdef CONFIG_HAS_MEM_SHARING
-    case XEN_DOMCTL_VM_EVENT_OP_SHARING:
+    case XEN_VM_EVENT_TYPE_SHARING:
     {
         rc = -EINVAL;
 
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 19486d5..19281fa 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -38,7 +38,7 @@
 #include "hvm/save.h"
 #include "memory.h"
 
-#define XEN_DOMCTL_INTERFACE_VERSION 0x00000011
+#define XEN_DOMCTL_INTERFACE_VERSION 0x00000012
 
 /*
  * NB. xen_domctl.domain is an IN/OUT parameter for this operation.
@@ -769,80 +769,18 @@ struct xen_domctl_gdbsx_domstatus {
  * VM event operations
  */
 
-/* XEN_DOMCTL_vm_event_op */
-
-/*
- * There are currently three rings available for VM events:
- * sharing, monitor and paging. This hypercall allows one to
- * control these rings (enable/disable), as well as to signal
- * to the hypervisor to pull responses (resume) from the given
- * ring.
+/* XEN_DOMCTL_vm_event_op.
+ * Use for teardown/setup of helper<->hypervisor interface for paging,
+ * access and sharing.
  */
 #define XEN_VM_EVENT_ENABLE               0
 #define XEN_VM_EVENT_DISABLE              1
 #define XEN_VM_EVENT_RESUME               2
 #define XEN_VM_EVENT_GET_VERSION          3
 
-/*
- * Domain memory paging
- * Page memory in and out.
- * Domctl interface to set up and tear down the
- * pager<->hypervisor interface. Use XENMEM_paging_op*
- * to perform per-page operations.
- *
- * The XEN_VM_EVENT_PAGING_ENABLE domctl returns several
- * non-standard error codes to indicate why paging could not be enabled:
- * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
- * EMLINK - guest has iommu passthrough enabled
- * EXDEV  - guest has PoD enabled
- * EBUSY  - guest has or had paging enabled, ring buffer still active
- */
-#define XEN_DOMCTL_VM_EVENT_OP_PAGING            1
-
-/*
- * Monitor helper.
- *
- * As with paging, use the domctl for teardown/setup of the
- * helper<->hypervisor interface.
- *
- * The monitor interface can be used to register for various VM events. For
- * example, there are HVM hypercalls to set the per-page access permissions
- * of every page in a domain.  When one of these permissions--independent,
- * read, write, and execute--is violated, the VCPU is paused and a memory event
- * is sent with what happened. The memory event handler can then resume the
- * VCPU and redo the access with a XEN_VM_EVENT_RESUME option.
- *
- * See public/vm_event.h for the list of available events that can be
- * subscribed to via the monitor interface.
- *
- * The XEN_VM_EVENT_MONITOR_* domctls returns
- * non-standard error codes to indicate why access could not be enabled:
- * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
- * EBUSY  - guest has or had access enabled, ring buffer still active
- *
- */
-#define XEN_DOMCTL_VM_EVENT_OP_MONITOR           2
-
-/*
- * Sharing ENOMEM helper.
- *
- * As with paging, use the domctl for teardown/setup of the
- * helper<->hypervisor interface.
- *
- * If setup, this ring is used to communicate failed allocations
- * in the unshare path. XENMEM_sharing_op_resume is used to wake up
- * vcpus that could not unshare.
- *
- * Note that shring can be turned on (as per the domctl below)
- * *without* this ring being setup.
- */
-#define XEN_DOMCTL_VM_EVENT_OP_SHARING           3
-
-/* Use for teardown/setup of helper<->hypervisor interface for paging,
- * access and sharing.*/
 struct xen_domctl_vm_event_op {
-    uint32_t       op;           /* XEN_VM_EVENT_* */
-    uint32_t       mode;         /* XEN_DOMCTL_VM_EVENT_OP_* */
+    uint32_t        op;           /* XEN_VM_EVENT_* */
+    uint32_t        type;         /* XEN_VM_EVENT_TYPE_* */
 
     union {
         struct {
@@ -857,7 +795,10 @@ struct xen_domctl_vm_event_op {
  * Memory sharing operations
  */
 /* XEN_DOMCTL_mem_sharing_op.
- * The CONTROL sub-domctl is used for bringup/teardown. */
+ * The CONTROL sub-domctl is used for bringup/teardown.
+ * Please note that mem sharing can be turned on *without* setting-up the
+ * correspondin ring
+ */
 #define XEN_DOMCTL_MEM_SHARING_CONTROL          0
 
 struct xen_domctl_mem_sharing_op {
@@ -1004,7 +945,7 @@ struct xen_domctl_psr_cmt_op {
  * Enable/disable monitoring various VM events.
  * This domctl configures what events will be reported to helper apps
  * via the ring buffer "MONITOR". The ring has to be first enabled
- * with the domctl XEN_DOMCTL_VM_EVENT_OP_MONITOR.
+ * with XEN_VM_EVENT_ENABLE.
  *
  * GET_CAPABILITIES can be used to determine which of these features is
  * available on a given platform.
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index 959083d..c48bc21 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -36,6 +36,37 @@
 #include "io/ring.h"
 
 /*
+ * There are currently three types of VM events.
+ */
+
+/*
+ * Domain memory paging
+ *
+ * Page memory in and out.
+ */
+#define XEN_VM_EVENT_TYPE_PAGING         1
+
+/*
+ * Monitor.
+ *
+ * The monitor interface can be used to register for various VM events. For
+ * example, there are HVM hypercalls to set the per-page access permissions
+ * of every page in a domain.  When one of these permissions--independent,
+ * read, write, and execute--is violated, the VCPU is paused and a memory event
+ * is sent with what happened. The memory event handler can then resume the
+ * VCPU and redo the access with a XEN_VM_EVENT_RESUME option.
+ */
+#define XEN_VM_EVENT_TYPE_MONITOR        2
+
+/*
+ * Sharing ENOMEM.
+ *
+ * Used to communicate failed allocations in the unshare path.
+ * XENMEM_sharing_op_resume is used to wake up vcpus that could not unshare.
+ */
+#define XEN_VM_EVENT_TYPE_SHARING        3
+
+/*
  * Memory event flags
  */
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 3/9] vm_event: Make ‘local’ functions ‘static’
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel; +Cc: Petre Pircalabu, Tamas K Lengyel, Razvan Cojocaru

vm_event_get_response, vm_event_resume, and vm_event_mark_and_pause are
used only in xen/common/vm_event.c.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/common/vm_event.c      | 6 +++---
 xen/include/xen/vm_event.h | 3 ---
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index d7c5f22..3505589 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -252,7 +252,7 @@ static inline void vm_event_release_slot(struct domain *d,
  * vm_event_mark_and_pause() tags vcpu and put it to sleep.
  * The vcpu will resume execution in vm_event_wake_blocked().
  */
-void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
+static void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
 {
     if ( !test_and_set_bit(ved->pause_flag, &v->pause_flags) )
     {
@@ -324,8 +324,8 @@ void vm_event_put_request(struct domain *d,
     notify_via_xen_event_channel(d, ved->xen_port);
 }
 
-int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
-                          vm_event_response_t *rsp)
+static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
+                                 vm_event_response_t *rsp)
 {
     vm_event_front_ring_t *front_ring;
     RING_IDX rsp_cons;
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index 53af2d5..7f6fb6d 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -64,9 +64,6 @@ void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved);
 void vm_event_put_request(struct domain *d, struct vm_event_domain *ved,
                           vm_event_request_t *req);
 
-int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
-                          vm_event_response_t *rsp);
-
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                     XEN_GUEST_HANDLE_PARAM(void) u_domctl);
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 3/9] vm_event: Make ‘local’ functions ‘static’
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel; +Cc: Petre Pircalabu, Tamas K Lengyel, Razvan Cojocaru

vm_event_get_response, vm_event_resume, and vm_event_mark_and_pause are
used only in xen/common/vm_event.c.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/common/vm_event.c      | 6 +++---
 xen/include/xen/vm_event.h | 3 ---
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index d7c5f22..3505589 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -252,7 +252,7 @@ static inline void vm_event_release_slot(struct domain *d,
  * vm_event_mark_and_pause() tags vcpu and put it to sleep.
  * The vcpu will resume execution in vm_event_wake_blocked().
  */
-void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
+static void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
 {
     if ( !test_and_set_bit(ved->pause_flag, &v->pause_flags) )
     {
@@ -324,8 +324,8 @@ void vm_event_put_request(struct domain *d,
     notify_via_xen_event_channel(d, ved->xen_port);
 }
 
-int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
-                          vm_event_response_t *rsp)
+static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
+                                 vm_event_response_t *rsp)
 {
     vm_event_front_ring_t *front_ring;
     RING_IDX rsp_cons;
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index 53af2d5..7f6fb6d 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -64,9 +64,6 @@ void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved);
 void vm_event_put_request(struct domain *d, struct vm_event_domain *ved,
                           vm_event_request_t *req);
 
-int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
-                          vm_event_response_t *rsp);
-
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                     XEN_GUEST_HANDLE_PARAM(void) u_domctl);
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 4/9] vm_event: Remove "ring" suffix from vm_event_check_ring
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Tamas K Lengyel, Wei Liu, Razvan Cojocaru,
	George Dunlap, Andrew Cooper, Julien Grall, Stefano Stabellini,
	Jan Beulich, Roger Pau Monné

Decouple implementation from interface to allow vm_event_check to be
used regardless of the vm_event underlying implementation.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/arch/arm/mem_access.c     |  2 +-
 xen/arch/x86/mm/mem_access.c  |  4 ++--
 xen/arch/x86/mm/mem_paging.c  |  2 +-
 xen/common/mem_access.c       |  2 +-
 xen/common/vm_event.c         | 24 ++++++++++++------------
 xen/drivers/passthrough/pci.c |  2 +-
 xen/include/xen/vm_event.h    |  4 ++--
 7 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/xen/arch/arm/mem_access.c b/xen/arch/arm/mem_access.c
index 3e36202..d54760b 100644
--- a/xen/arch/arm/mem_access.c
+++ b/xen/arch/arm/mem_access.c
@@ -290,7 +290,7 @@ bool p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const struct npfec npfec)
     }
 
     /* Otherwise, check if there is a vm_event monitor subscriber */
-    if ( !vm_event_check_ring(v->domain->vm_event_monitor) )
+    if ( !vm_event_check(v->domain->vm_event_monitor) )
     {
         /* No listener */
         if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index 0144f92..640352e 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -182,7 +182,7 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla,
     gfn_unlock(p2m, gfn, 0);
 
     /* Otherwise, check if there is a memory event listener, and send the message along */
-    if ( !vm_event_check_ring(d->vm_event_monitor) || !req_ptr )
+    if ( !vm_event_check(d->vm_event_monitor) || !req_ptr )
     {
         /* No listener */
         if ( p2m->access_required )
@@ -210,7 +210,7 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla,
             return true;
         }
     }
-    if ( vm_event_check_ring(d->vm_event_monitor) &&
+    if ( vm_event_check(d->vm_event_monitor) &&
          d->arch.monitor.inguest_pagefault_disabled &&
          npfec.kind != npfec_kind_with_gla ) /* don't send a mem_event */
     {
diff --git a/xen/arch/x86/mm/mem_paging.c b/xen/arch/x86/mm/mem_paging.c
index 54a94fa..dc2a59a 100644
--- a/xen/arch/x86/mm/mem_paging.c
+++ b/xen/arch/x86/mm/mem_paging.c
@@ -44,7 +44,7 @@ int mem_paging_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_paging_op_t) arg)
         goto out;
 
     rc = -ENODEV;
-    if ( unlikely(!vm_event_check_ring(d->vm_event_paging)) )
+    if ( unlikely(!vm_event_check(d->vm_event_paging)) )
         goto out;
 
     switch( mpo.op )
diff --git a/xen/common/mem_access.c b/xen/common/mem_access.c
index 010e6f8..51e4e2b 100644
--- a/xen/common/mem_access.c
+++ b/xen/common/mem_access.c
@@ -52,7 +52,7 @@ int mem_access_memop(unsigned long cmd,
         goto out;
 
     rc = -ENODEV;
-    if ( unlikely(!vm_event_check_ring(d->vm_event_monitor)) )
+    if ( unlikely(!vm_event_check(d->vm_event_monitor)) )
         goto out;
 
     switch ( mao.op )
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 3505589..1dd3e48 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -196,7 +196,7 @@ void vm_event_wake(struct domain *d, struct vm_event_domain *ved)
 
 static int vm_event_disable(struct domain *d, struct vm_event_domain **ved)
 {
-    if ( vm_event_check_ring(*ved) )
+    if ( vm_event_check(*ved) )
     {
         struct vcpu *v;
 
@@ -277,7 +277,7 @@ void vm_event_put_request(struct domain *d,
     RING_IDX req_prod;
     struct vcpu *curr = current;
 
-    if( !vm_event_check_ring(ved))
+    if( !vm_event_check(ved))
         return;
 
     if ( curr->domain != d )
@@ -380,7 +380,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
      */
     ASSERT(d != current->domain);
 
-    if ( unlikely(!vm_event_check_ring(ved)) )
+    if ( unlikely(!vm_event_check(ved)) )
          return -ENODEV;
 
     /* Pull all responses off the ring. */
@@ -452,7 +452,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
 
 void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved)
 {
-    if( !vm_event_check_ring(ved) )
+    if( !vm_event_check(ved) )
         return;
 
     vm_event_ring_lock(ved);
@@ -501,7 +501,7 @@ static int vm_event_wait_slot(struct vm_event_domain *ved)
     return rc;
 }
 
-bool vm_event_check_ring(struct vm_event_domain *ved)
+bool vm_event_check(struct vm_event_domain *ved)
 {
     return (ved && ved->ring_page);
 }
@@ -521,7 +521,7 @@ bool vm_event_check_ring(struct vm_event_domain *ved)
 int __vm_event_claim_slot(struct domain *d, struct vm_event_domain *ved,
                           bool allow_sleep)
 {
-    if ( !vm_event_check_ring(ved) )
+    if ( !vm_event_check(ved) )
         return -EOPNOTSUPP;
 
     if ( (current->domain == d) && allow_sleep )
@@ -556,7 +556,7 @@ static void mem_sharing_notification(struct vcpu *v, unsigned int port)
 void vm_event_cleanup(struct domain *d)
 {
 #ifdef CONFIG_HAS_MEM_PAGING
-    if ( vm_event_check_ring(d->vm_event_paging) )
+    if ( vm_event_check(d->vm_event_paging) )
     {
         /* Destroying the wait queue head means waking up all
          * queued vcpus. This will drain the list, allowing
@@ -569,13 +569,13 @@ void vm_event_cleanup(struct domain *d)
         (void)vm_event_disable(d, &d->vm_event_paging);
     }
 #endif
-    if ( vm_event_check_ring(d->vm_event_monitor) )
+    if ( vm_event_check(d->vm_event_monitor) )
     {
         destroy_waitqueue_head(&d->vm_event_monitor->wq);
         (void)vm_event_disable(d, &d->vm_event_monitor);
     }
 #ifdef CONFIG_HAS_MEM_SHARING
-    if ( vm_event_check_ring(d->vm_event_share) )
+    if ( vm_event_check(d->vm_event_share) )
     {
         destroy_waitqueue_head(&d->vm_event_share->wq);
         (void)vm_event_disable(d, &d->vm_event_share);
@@ -663,7 +663,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
         break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check_ring(d->vm_event_paging) )
+            if ( vm_event_check(d->vm_event_paging) )
             {
                 domain_pause(d);
                 rc = vm_event_disable(d, &d->vm_event_paging);
@@ -700,7 +700,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
             break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check_ring(d->vm_event_monitor) )
+            if ( vm_event_check(d->vm_event_monitor) )
             {
                 domain_pause(d);
                 rc = vm_event_disable(d, &d->vm_event_monitor);
@@ -745,7 +745,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
             break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check_ring(d->vm_event_share) )
+            if ( vm_event_check(d->vm_event_share) )
             {
                 domain_pause(d);
                 rc = vm_event_disable(d, &d->vm_event_share);
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index 061b201..a7d4d9e 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -1453,7 +1453,7 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
     /* Prevent device assign if mem paging or mem sharing have been 
      * enabled for this domain */
     if ( unlikely(d->arch.hvm.mem_sharing_enabled ||
-                  vm_event_check_ring(d->vm_event_paging) ||
+                  vm_event_check(d->vm_event_paging) ||
                   p2m_get_hostp2m(d)->global_logdirty) )
         return -EXDEV;
 
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index 7f6fb6d..0a05e5b 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -29,8 +29,8 @@
 /* Clean up on domain destruction */
 void vm_event_cleanup(struct domain *d);
 
-/* Returns whether a ring has been set up */
-bool vm_event_check_ring(struct vm_event_domain *ved);
+/* Returns whether the VM event domain has been set up */
+bool vm_event_check(struct vm_event_domain *ved);
 
 /* Returns 0 on success, -ENOSYS if there is no ring, -EBUSY if there is no
  * available space and the caller is a foreign domain. If the guest itself
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 4/9] vm_event: Remove "ring" suffix from vm_event_check_ring
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Tamas K Lengyel, Wei Liu, Razvan Cojocaru,
	George Dunlap, Andrew Cooper, Julien Grall, Stefano Stabellini,
	Jan Beulich, Roger Pau Monné

Decouple implementation from interface to allow vm_event_check to be
used regardless of the vm_event underlying implementation.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/arch/arm/mem_access.c     |  2 +-
 xen/arch/x86/mm/mem_access.c  |  4 ++--
 xen/arch/x86/mm/mem_paging.c  |  2 +-
 xen/common/mem_access.c       |  2 +-
 xen/common/vm_event.c         | 24 ++++++++++++------------
 xen/drivers/passthrough/pci.c |  2 +-
 xen/include/xen/vm_event.h    |  4 ++--
 7 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/xen/arch/arm/mem_access.c b/xen/arch/arm/mem_access.c
index 3e36202..d54760b 100644
--- a/xen/arch/arm/mem_access.c
+++ b/xen/arch/arm/mem_access.c
@@ -290,7 +290,7 @@ bool p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const struct npfec npfec)
     }
 
     /* Otherwise, check if there is a vm_event monitor subscriber */
-    if ( !vm_event_check_ring(v->domain->vm_event_monitor) )
+    if ( !vm_event_check(v->domain->vm_event_monitor) )
     {
         /* No listener */
         if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index 0144f92..640352e 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -182,7 +182,7 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla,
     gfn_unlock(p2m, gfn, 0);
 
     /* Otherwise, check if there is a memory event listener, and send the message along */
-    if ( !vm_event_check_ring(d->vm_event_monitor) || !req_ptr )
+    if ( !vm_event_check(d->vm_event_monitor) || !req_ptr )
     {
         /* No listener */
         if ( p2m->access_required )
@@ -210,7 +210,7 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla,
             return true;
         }
     }
-    if ( vm_event_check_ring(d->vm_event_monitor) &&
+    if ( vm_event_check(d->vm_event_monitor) &&
          d->arch.monitor.inguest_pagefault_disabled &&
          npfec.kind != npfec_kind_with_gla ) /* don't send a mem_event */
     {
diff --git a/xen/arch/x86/mm/mem_paging.c b/xen/arch/x86/mm/mem_paging.c
index 54a94fa..dc2a59a 100644
--- a/xen/arch/x86/mm/mem_paging.c
+++ b/xen/arch/x86/mm/mem_paging.c
@@ -44,7 +44,7 @@ int mem_paging_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_paging_op_t) arg)
         goto out;
 
     rc = -ENODEV;
-    if ( unlikely(!vm_event_check_ring(d->vm_event_paging)) )
+    if ( unlikely(!vm_event_check(d->vm_event_paging)) )
         goto out;
 
     switch( mpo.op )
diff --git a/xen/common/mem_access.c b/xen/common/mem_access.c
index 010e6f8..51e4e2b 100644
--- a/xen/common/mem_access.c
+++ b/xen/common/mem_access.c
@@ -52,7 +52,7 @@ int mem_access_memop(unsigned long cmd,
         goto out;
 
     rc = -ENODEV;
-    if ( unlikely(!vm_event_check_ring(d->vm_event_monitor)) )
+    if ( unlikely(!vm_event_check(d->vm_event_monitor)) )
         goto out;
 
     switch ( mao.op )
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 3505589..1dd3e48 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -196,7 +196,7 @@ void vm_event_wake(struct domain *d, struct vm_event_domain *ved)
 
 static int vm_event_disable(struct domain *d, struct vm_event_domain **ved)
 {
-    if ( vm_event_check_ring(*ved) )
+    if ( vm_event_check(*ved) )
     {
         struct vcpu *v;
 
@@ -277,7 +277,7 @@ void vm_event_put_request(struct domain *d,
     RING_IDX req_prod;
     struct vcpu *curr = current;
 
-    if( !vm_event_check_ring(ved))
+    if( !vm_event_check(ved))
         return;
 
     if ( curr->domain != d )
@@ -380,7 +380,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
      */
     ASSERT(d != current->domain);
 
-    if ( unlikely(!vm_event_check_ring(ved)) )
+    if ( unlikely(!vm_event_check(ved)) )
          return -ENODEV;
 
     /* Pull all responses off the ring. */
@@ -452,7 +452,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
 
 void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved)
 {
-    if( !vm_event_check_ring(ved) )
+    if( !vm_event_check(ved) )
         return;
 
     vm_event_ring_lock(ved);
@@ -501,7 +501,7 @@ static int vm_event_wait_slot(struct vm_event_domain *ved)
     return rc;
 }
 
-bool vm_event_check_ring(struct vm_event_domain *ved)
+bool vm_event_check(struct vm_event_domain *ved)
 {
     return (ved && ved->ring_page);
 }
@@ -521,7 +521,7 @@ bool vm_event_check_ring(struct vm_event_domain *ved)
 int __vm_event_claim_slot(struct domain *d, struct vm_event_domain *ved,
                           bool allow_sleep)
 {
-    if ( !vm_event_check_ring(ved) )
+    if ( !vm_event_check(ved) )
         return -EOPNOTSUPP;
 
     if ( (current->domain == d) && allow_sleep )
@@ -556,7 +556,7 @@ static void mem_sharing_notification(struct vcpu *v, unsigned int port)
 void vm_event_cleanup(struct domain *d)
 {
 #ifdef CONFIG_HAS_MEM_PAGING
-    if ( vm_event_check_ring(d->vm_event_paging) )
+    if ( vm_event_check(d->vm_event_paging) )
     {
         /* Destroying the wait queue head means waking up all
          * queued vcpus. This will drain the list, allowing
@@ -569,13 +569,13 @@ void vm_event_cleanup(struct domain *d)
         (void)vm_event_disable(d, &d->vm_event_paging);
     }
 #endif
-    if ( vm_event_check_ring(d->vm_event_monitor) )
+    if ( vm_event_check(d->vm_event_monitor) )
     {
         destroy_waitqueue_head(&d->vm_event_monitor->wq);
         (void)vm_event_disable(d, &d->vm_event_monitor);
     }
 #ifdef CONFIG_HAS_MEM_SHARING
-    if ( vm_event_check_ring(d->vm_event_share) )
+    if ( vm_event_check(d->vm_event_share) )
     {
         destroy_waitqueue_head(&d->vm_event_share->wq);
         (void)vm_event_disable(d, &d->vm_event_share);
@@ -663,7 +663,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
         break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check_ring(d->vm_event_paging) )
+            if ( vm_event_check(d->vm_event_paging) )
             {
                 domain_pause(d);
                 rc = vm_event_disable(d, &d->vm_event_paging);
@@ -700,7 +700,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
             break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check_ring(d->vm_event_monitor) )
+            if ( vm_event_check(d->vm_event_monitor) )
             {
                 domain_pause(d);
                 rc = vm_event_disable(d, &d->vm_event_monitor);
@@ -745,7 +745,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
             break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check_ring(d->vm_event_share) )
+            if ( vm_event_check(d->vm_event_share) )
             {
                 domain_pause(d);
                 rc = vm_event_disable(d, &d->vm_event_share);
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index 061b201..a7d4d9e 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -1453,7 +1453,7 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
     /* Prevent device assign if mem paging or mem sharing have been 
      * enabled for this domain */
     if ( unlikely(d->arch.hvm.mem_sharing_enabled ||
-                  vm_event_check_ring(d->vm_event_paging) ||
+                  vm_event_check(d->vm_event_paging) ||
                   p2m_get_hostp2m(d)->global_logdirty) )
         return -EXDEV;
 
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index 7f6fb6d..0a05e5b 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -29,8 +29,8 @@
 /* Clean up on domain destruction */
 void vm_event_cleanup(struct domain *d);
 
-/* Returns whether a ring has been set up */
-bool vm_event_check_ring(struct vm_event_domain *ved);
+/* Returns whether the VM event domain has been set up */
+bool vm_event_check(struct vm_event_domain *ved);
 
 /* Returns 0 on success, -ENOSYS if there is no ring, -EBUSY if there is no
  * available space and the caller is a foreign domain. If the guest itself
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 5/9] vm_event: Simplify vm_event interface
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Tamas K Lengyel, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Stefano Stabellini, Jan Beulich,
	Roger Pau Monné

The domain reference can be part of the vm_event_domain structure
because for every call to a vm_event interface function both the latter
and it's corresponding domain are passed as parameters.

Affected functions:
- __vm_event_claim_slot / vm_event_claim_slot / vm_event_claim_slot_nosleep
- vm_event_cancel_slot
- vm_event_put_request

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/arch/x86/mm/mem_sharing.c |  5 ++---
 xen/arch/x86/mm/p2m.c         | 11 +++++------
 xen/common/monitor.c          |  4 ++--
 xen/common/vm_event.c         | 37 ++++++++++++++++++-------------------
 xen/include/xen/sched.h       |  2 ++
 xen/include/xen/vm_event.h    | 17 +++++++----------
 6 files changed, 36 insertions(+), 40 deletions(-)

diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index f16a3f5..9d80389 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -557,8 +557,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned long gfn,
         .u.mem_sharing.p2mt = p2m_ram_shared
     };
 
-    if ( (rc = __vm_event_claim_slot(d, 
-                        d->vm_event_share, allow_sleep)) < 0 )
+    if ( (rc = __vm_event_claim_slot(d->vm_event_share, allow_sleep)) < 0 )
         return rc;
 
     if ( v->domain == d )
@@ -567,7 +566,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned long gfn,
         vm_event_vcpu_pause(v);
     }
 
-    vm_event_put_request(d, d->vm_event_share, &req);
+    vm_event_put_request(d->vm_event_share, &req);
 
     return 0;
 }
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 4c99548..625fc9b 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1652,7 +1652,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned long gfn,
      * correctness of the guest execution at this point.  If this is the only
      * page that happens to be paged-out, we'll be okay..  but it's likely the
      * guest will crash shortly anyways. */
-    int rc = vm_event_claim_slot(d, d->vm_event_paging);
+    int rc = vm_event_claim_slot(d->vm_event_paging);
     if ( rc < 0 )
         return;
 
@@ -1666,7 +1666,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned long gfn,
         /* Evict will fail now, tag this request for pager */
         req.u.mem_paging.flags |= MEM_PAGING_EVICT_FAIL;
 
-    vm_event_put_request(d, d->vm_event_paging, &req);
+    vm_event_put_request(d->vm_event_paging, &req);
 }
 
 /**
@@ -1704,8 +1704,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn_l)
     struct p2m_domain *p2m = p2m_get_hostp2m(d);
 
     /* We're paging. There should be a ring */
-    int rc = vm_event_claim_slot(d, d->vm_event_paging);
-
+    int rc = vm_event_claim_slot(d->vm_event_paging);
     if ( rc == -EOPNOTSUPP )
     {
         gdprintk(XENLOG_ERR, "Domain %hu paging gfn %lx yet no ring "
@@ -1746,7 +1745,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn_l)
     {
         /* gfn is already on its way back and vcpu is not paused */
     out_cancel:
-        vm_event_cancel_slot(d, d->vm_event_paging);
+        vm_event_cancel_slot(d->vm_event_paging);
         return;
     }
 
@@ -1754,7 +1753,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn_l)
     req.u.mem_paging.p2mt = p2mt;
     req.vcpu_id = v->vcpu_id;
 
-    vm_event_put_request(d, d->vm_event_paging, &req);
+    vm_event_put_request(d->vm_event_paging, &req);
 }
 
 /**
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index d5c9ff1..b8d33c4 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -93,7 +93,7 @@ int monitor_traps(struct vcpu *v, bool sync, vm_event_request_t *req)
     int rc;
     struct domain *d = v->domain;
 
-    rc = vm_event_claim_slot(d, d->vm_event_monitor);
+    rc = vm_event_claim_slot(d->vm_event_monitor);
     switch ( rc )
     {
     case 0:
@@ -125,7 +125,7 @@ int monitor_traps(struct vcpu *v, bool sync, vm_event_request_t *req)
     }
 
     vm_event_fill_regs(req);
-    vm_event_put_request(d, d->vm_event_monitor, req);
+    vm_event_put_request(d->vm_event_monitor, req);
 
     return rc;
 }
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 1dd3e48..3e87bbc 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -131,10 +131,11 @@ static unsigned int vm_event_ring_available(struct vm_event_domain *ved)
  * but need to be resumed where the ring is capable of processing at least
  * one event from them.
  */
-static void vm_event_wake_blocked(struct domain *d, struct vm_event_domain *ved)
+static void vm_event_wake_blocked(struct vm_event_domain *ved)
 {
     struct vcpu *v;
     unsigned int avail_req = vm_event_ring_available(ved);
+    struct domain *d = ved->d;
 
     if ( avail_req == 0 || ved->blocked == 0 )
         return;
@@ -171,7 +172,7 @@ static void vm_event_wake_blocked(struct domain *d, struct vm_event_domain *ved)
  * was unable to do so, it is queued on a wait queue.  These are woken as
  * needed, and take precedence over the blocked vCPUs.
  */
-static void vm_event_wake_queued(struct domain *d, struct vm_event_domain *ved)
+static void vm_event_wake_queued(struct vm_event_domain *ved)
 {
     unsigned int avail_req = vm_event_ring_available(ved);
 
@@ -186,12 +187,12 @@ static void vm_event_wake_queued(struct domain *d, struct vm_event_domain *ved)
  * call vm_event_wake() again, ensuring that any blocked vCPUs will get
  * unpaused once all the queued vCPUs have made it through.
  */
-void vm_event_wake(struct domain *d, struct vm_event_domain *ved)
+void vm_event_wake(struct vm_event_domain *ved)
 {
     if (!list_empty(&ved->wq.list))
-        vm_event_wake_queued(d, ved);
+        vm_event_wake_queued(ved);
     else
-        vm_event_wake_blocked(d, ved);
+        vm_event_wake_blocked(ved);
 }
 
 static int vm_event_disable(struct domain *d, struct vm_event_domain **ved)
@@ -235,17 +236,16 @@ static int vm_event_disable(struct domain *d, struct vm_event_domain **ved)
     return 0;
 }
 
-static inline void vm_event_release_slot(struct domain *d,
-                                         struct vm_event_domain *ved)
+static inline void vm_event_release_slot(struct vm_event_domain *ved)
 {
     /* Update the accounting */
-    if ( current->domain == d )
+    if ( current->domain == ved->d )
         ved->target_producers--;
     else
         ved->foreign_producers--;
 
     /* Kick any waiters */
-    vm_event_wake(d, ved);
+    vm_event_wake(ved);
 }
 
 /*
@@ -267,8 +267,7 @@ static void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
  * overly full and its continued execution would cause stalling and excessive
  * waiting.  The vCPU will be automatically unpaused when the ring clears.
  */
-void vm_event_put_request(struct domain *d,
-                          struct vm_event_domain *ved,
+void vm_event_put_request(struct vm_event_domain *ved,
                           vm_event_request_t *req)
 {
     vm_event_front_ring_t *front_ring;
@@ -276,6 +275,7 @@ void vm_event_put_request(struct domain *d,
     unsigned int avail_req;
     RING_IDX req_prod;
     struct vcpu *curr = current;
+    struct domain *d = ved->d;
 
     if( !vm_event_check(ved))
         return;
@@ -309,7 +309,7 @@ void vm_event_put_request(struct domain *d,
     RING_PUSH_REQUESTS(front_ring);
 
     /* We've actually *used* our reservation, so release the slot. */
-    vm_event_release_slot(d, ved);
+    vm_event_release_slot(ved);
 
     /* Give this vCPU a black eye if necessary, on the way out.
      * See the comments above wake_blocked() for more information
@@ -351,7 +351,7 @@ static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
 
     /* Kick any waiters -- since we've just consumed an event,
      * there may be additional space available in the ring. */
-    vm_event_wake(d, ved);
+    vm_event_wake(ved);
 
     vm_event_ring_unlock(ved);
 
@@ -450,13 +450,13 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
     return 0;
 }
 
-void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved)
+void vm_event_cancel_slot(struct vm_event_domain *ved)
 {
     if( !vm_event_check(ved) )
         return;
 
     vm_event_ring_lock(ved);
-    vm_event_release_slot(d, ved);
+    vm_event_release_slot(ved);
     vm_event_ring_unlock(ved);
 }
 
@@ -518,16 +518,15 @@ bool vm_event_check(struct vm_event_domain *ved)
  *               0: a spot has been reserved
  *
  */
-int __vm_event_claim_slot(struct domain *d, struct vm_event_domain *ved,
-                          bool allow_sleep)
+int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep)
 {
     if ( !vm_event_check(ved) )
         return -EOPNOTSUPP;
 
-    if ( (current->domain == d) && allow_sleep )
+    if ( (current->domain == ved->d) && allow_sleep )
         return vm_event_wait_slot(ved);
     else
-        return vm_event_grab_slot(ved, (current->domain != d));
+        return vm_event_grab_slot(ved, (current->domain != ved->d));
 }
 
 #ifdef CONFIG_HAS_MEM_PAGING
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 2201fac..7dee022 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -282,6 +282,8 @@ struct vcpu
 /* VM event */
 struct vm_event_domain
 {
+    /* Domain reference */
+    struct domain *d;
     /* ring lock */
     spinlock_t ring_lock;
     /* The ring has 64 entries */
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index 0a05e5b..a5c82d6 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -45,23 +45,20 @@ bool vm_event_check(struct vm_event_domain *ved);
  * cancel_slot(), both of which are guaranteed to
  * succeed.
  */
-int __vm_event_claim_slot(struct domain *d, struct vm_event_domain *ved,
-                          bool allow_sleep);
-static inline int vm_event_claim_slot(struct domain *d,
-                                      struct vm_event_domain *ved)
+int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep);
+static inline int vm_event_claim_slot(struct vm_event_domain *ved)
 {
-    return __vm_event_claim_slot(d, ved, true);
+    return __vm_event_claim_slot(ved, true);
 }
 
-static inline int vm_event_claim_slot_nosleep(struct domain *d,
-                                              struct vm_event_domain *ved)
+static inline int vm_event_claim_slot_nosleep(struct vm_event_domain *ved)
 {
-    return __vm_event_claim_slot(d, ved, false);
+    return __vm_event_claim_slot(ved, false);
 }
 
-void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved);
+void vm_event_cancel_slot(struct vm_event_domain *ved);
 
-void vm_event_put_request(struct domain *d, struct vm_event_domain *ved,
+void vm_event_put_request(struct vm_event_domain *ved,
                           vm_event_request_t *req);
 
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 5/9] vm_event: Simplify vm_event interface
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Tamas K Lengyel, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Stefano Stabellini, Jan Beulich,
	Roger Pau Monné

The domain reference can be part of the vm_event_domain structure
because for every call to a vm_event interface function both the latter
and it's corresponding domain are passed as parameters.

Affected functions:
- __vm_event_claim_slot / vm_event_claim_slot / vm_event_claim_slot_nosleep
- vm_event_cancel_slot
- vm_event_put_request

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/arch/x86/mm/mem_sharing.c |  5 ++---
 xen/arch/x86/mm/p2m.c         | 11 +++++------
 xen/common/monitor.c          |  4 ++--
 xen/common/vm_event.c         | 37 ++++++++++++++++++-------------------
 xen/include/xen/sched.h       |  2 ++
 xen/include/xen/vm_event.h    | 17 +++++++----------
 6 files changed, 36 insertions(+), 40 deletions(-)

diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index f16a3f5..9d80389 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -557,8 +557,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned long gfn,
         .u.mem_sharing.p2mt = p2m_ram_shared
     };
 
-    if ( (rc = __vm_event_claim_slot(d, 
-                        d->vm_event_share, allow_sleep)) < 0 )
+    if ( (rc = __vm_event_claim_slot(d->vm_event_share, allow_sleep)) < 0 )
         return rc;
 
     if ( v->domain == d )
@@ -567,7 +566,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned long gfn,
         vm_event_vcpu_pause(v);
     }
 
-    vm_event_put_request(d, d->vm_event_share, &req);
+    vm_event_put_request(d->vm_event_share, &req);
 
     return 0;
 }
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 4c99548..625fc9b 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1652,7 +1652,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned long gfn,
      * correctness of the guest execution at this point.  If this is the only
      * page that happens to be paged-out, we'll be okay..  but it's likely the
      * guest will crash shortly anyways. */
-    int rc = vm_event_claim_slot(d, d->vm_event_paging);
+    int rc = vm_event_claim_slot(d->vm_event_paging);
     if ( rc < 0 )
         return;
 
@@ -1666,7 +1666,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned long gfn,
         /* Evict will fail now, tag this request for pager */
         req.u.mem_paging.flags |= MEM_PAGING_EVICT_FAIL;
 
-    vm_event_put_request(d, d->vm_event_paging, &req);
+    vm_event_put_request(d->vm_event_paging, &req);
 }
 
 /**
@@ -1704,8 +1704,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn_l)
     struct p2m_domain *p2m = p2m_get_hostp2m(d);
 
     /* We're paging. There should be a ring */
-    int rc = vm_event_claim_slot(d, d->vm_event_paging);
-
+    int rc = vm_event_claim_slot(d->vm_event_paging);
     if ( rc == -EOPNOTSUPP )
     {
         gdprintk(XENLOG_ERR, "Domain %hu paging gfn %lx yet no ring "
@@ -1746,7 +1745,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn_l)
     {
         /* gfn is already on its way back and vcpu is not paused */
     out_cancel:
-        vm_event_cancel_slot(d, d->vm_event_paging);
+        vm_event_cancel_slot(d->vm_event_paging);
         return;
     }
 
@@ -1754,7 +1753,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn_l)
     req.u.mem_paging.p2mt = p2mt;
     req.vcpu_id = v->vcpu_id;
 
-    vm_event_put_request(d, d->vm_event_paging, &req);
+    vm_event_put_request(d->vm_event_paging, &req);
 }
 
 /**
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index d5c9ff1..b8d33c4 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -93,7 +93,7 @@ int monitor_traps(struct vcpu *v, bool sync, vm_event_request_t *req)
     int rc;
     struct domain *d = v->domain;
 
-    rc = vm_event_claim_slot(d, d->vm_event_monitor);
+    rc = vm_event_claim_slot(d->vm_event_monitor);
     switch ( rc )
     {
     case 0:
@@ -125,7 +125,7 @@ int monitor_traps(struct vcpu *v, bool sync, vm_event_request_t *req)
     }
 
     vm_event_fill_regs(req);
-    vm_event_put_request(d, d->vm_event_monitor, req);
+    vm_event_put_request(d->vm_event_monitor, req);
 
     return rc;
 }
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 1dd3e48..3e87bbc 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -131,10 +131,11 @@ static unsigned int vm_event_ring_available(struct vm_event_domain *ved)
  * but need to be resumed where the ring is capable of processing at least
  * one event from them.
  */
-static void vm_event_wake_blocked(struct domain *d, struct vm_event_domain *ved)
+static void vm_event_wake_blocked(struct vm_event_domain *ved)
 {
     struct vcpu *v;
     unsigned int avail_req = vm_event_ring_available(ved);
+    struct domain *d = ved->d;
 
     if ( avail_req == 0 || ved->blocked == 0 )
         return;
@@ -171,7 +172,7 @@ static void vm_event_wake_blocked(struct domain *d, struct vm_event_domain *ved)
  * was unable to do so, it is queued on a wait queue.  These are woken as
  * needed, and take precedence over the blocked vCPUs.
  */
-static void vm_event_wake_queued(struct domain *d, struct vm_event_domain *ved)
+static void vm_event_wake_queued(struct vm_event_domain *ved)
 {
     unsigned int avail_req = vm_event_ring_available(ved);
 
@@ -186,12 +187,12 @@ static void vm_event_wake_queued(struct domain *d, struct vm_event_domain *ved)
  * call vm_event_wake() again, ensuring that any blocked vCPUs will get
  * unpaused once all the queued vCPUs have made it through.
  */
-void vm_event_wake(struct domain *d, struct vm_event_domain *ved)
+void vm_event_wake(struct vm_event_domain *ved)
 {
     if (!list_empty(&ved->wq.list))
-        vm_event_wake_queued(d, ved);
+        vm_event_wake_queued(ved);
     else
-        vm_event_wake_blocked(d, ved);
+        vm_event_wake_blocked(ved);
 }
 
 static int vm_event_disable(struct domain *d, struct vm_event_domain **ved)
@@ -235,17 +236,16 @@ static int vm_event_disable(struct domain *d, struct vm_event_domain **ved)
     return 0;
 }
 
-static inline void vm_event_release_slot(struct domain *d,
-                                         struct vm_event_domain *ved)
+static inline void vm_event_release_slot(struct vm_event_domain *ved)
 {
     /* Update the accounting */
-    if ( current->domain == d )
+    if ( current->domain == ved->d )
         ved->target_producers--;
     else
         ved->foreign_producers--;
 
     /* Kick any waiters */
-    vm_event_wake(d, ved);
+    vm_event_wake(ved);
 }
 
 /*
@@ -267,8 +267,7 @@ static void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
  * overly full and its continued execution would cause stalling and excessive
  * waiting.  The vCPU will be automatically unpaused when the ring clears.
  */
-void vm_event_put_request(struct domain *d,
-                          struct vm_event_domain *ved,
+void vm_event_put_request(struct vm_event_domain *ved,
                           vm_event_request_t *req)
 {
     vm_event_front_ring_t *front_ring;
@@ -276,6 +275,7 @@ void vm_event_put_request(struct domain *d,
     unsigned int avail_req;
     RING_IDX req_prod;
     struct vcpu *curr = current;
+    struct domain *d = ved->d;
 
     if( !vm_event_check(ved))
         return;
@@ -309,7 +309,7 @@ void vm_event_put_request(struct domain *d,
     RING_PUSH_REQUESTS(front_ring);
 
     /* We've actually *used* our reservation, so release the slot. */
-    vm_event_release_slot(d, ved);
+    vm_event_release_slot(ved);
 
     /* Give this vCPU a black eye if necessary, on the way out.
      * See the comments above wake_blocked() for more information
@@ -351,7 +351,7 @@ static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
 
     /* Kick any waiters -- since we've just consumed an event,
      * there may be additional space available in the ring. */
-    vm_event_wake(d, ved);
+    vm_event_wake(ved);
 
     vm_event_ring_unlock(ved);
 
@@ -450,13 +450,13 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
     return 0;
 }
 
-void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved)
+void vm_event_cancel_slot(struct vm_event_domain *ved)
 {
     if( !vm_event_check(ved) )
         return;
 
     vm_event_ring_lock(ved);
-    vm_event_release_slot(d, ved);
+    vm_event_release_slot(ved);
     vm_event_ring_unlock(ved);
 }
 
@@ -518,16 +518,15 @@ bool vm_event_check(struct vm_event_domain *ved)
  *               0: a spot has been reserved
  *
  */
-int __vm_event_claim_slot(struct domain *d, struct vm_event_domain *ved,
-                          bool allow_sleep)
+int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep)
 {
     if ( !vm_event_check(ved) )
         return -EOPNOTSUPP;
 
-    if ( (current->domain == d) && allow_sleep )
+    if ( (current->domain == ved->d) && allow_sleep )
         return vm_event_wait_slot(ved);
     else
-        return vm_event_grab_slot(ved, (current->domain != d));
+        return vm_event_grab_slot(ved, (current->domain != ved->d));
 }
 
 #ifdef CONFIG_HAS_MEM_PAGING
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 2201fac..7dee022 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -282,6 +282,8 @@ struct vcpu
 /* VM event */
 struct vm_event_domain
 {
+    /* Domain reference */
+    struct domain *d;
     /* ring lock */
     spinlock_t ring_lock;
     /* The ring has 64 entries */
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index 0a05e5b..a5c82d6 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -45,23 +45,20 @@ bool vm_event_check(struct vm_event_domain *ved);
  * cancel_slot(), both of which are guaranteed to
  * succeed.
  */
-int __vm_event_claim_slot(struct domain *d, struct vm_event_domain *ved,
-                          bool allow_sleep);
-static inline int vm_event_claim_slot(struct domain *d,
-                                      struct vm_event_domain *ved)
+int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep);
+static inline int vm_event_claim_slot(struct vm_event_domain *ved)
 {
-    return __vm_event_claim_slot(d, ved, true);
+    return __vm_event_claim_slot(ved, true);
 }
 
-static inline int vm_event_claim_slot_nosleep(struct domain *d,
-                                              struct vm_event_domain *ved)
+static inline int vm_event_claim_slot_nosleep(struct vm_event_domain *ved)
 {
-    return __vm_event_claim_slot(d, ved, false);
+    return __vm_event_claim_slot(ved, false);
 }
 
-void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved);
+void vm_event_cancel_slot(struct vm_event_domain *ved);
 
-void vm_event_put_request(struct domain *d, struct vm_event_domain *ved,
+void vm_event_put_request(struct vm_event_domain *ved,
                           vm_event_request_t *req);
 
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 6/9] vm_event: Move struct vm_event_domain to vm_event.c
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Tamas K Lengyel, Wei Liu, Razvan Cojocaru,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Stefano Stabellini, Jan Beulich

The vm_event_domain members are not accessed outside vm_event.c so it's
better to hide de implementation details.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/common/vm_event.c   | 27 +++++++++++++++++++++++++++
 xen/include/xen/sched.h | 27 +--------------------------
 2 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 3e87bbc..02c5853 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -39,6 +39,33 @@
 #define vm_event_ring_lock(_ved)       spin_lock(&(_ved)->ring_lock)
 #define vm_event_ring_unlock(_ved)     spin_unlock(&(_ved)->ring_lock)
 
+/* VM event */
+struct vm_event_domain
+{
+    /* Domain reference */
+    struct domain *d;
+    /* ring lock */
+    spinlock_t ring_lock;
+    /* The ring has 64 entries */
+    unsigned char foreign_producers;
+    unsigned char target_producers;
+    /* shared ring page */
+    void *ring_page;
+    struct page_info *ring_pg_struct;
+    /* front-end ring */
+    vm_event_front_ring_t front_ring;
+    /* event channel port (vcpu0 only) */
+    int xen_port;
+    /* vm_event bit for vcpu->pause_flags */
+    int pause_flag;
+    /* list of vcpus waiting for room in the ring */
+    struct waitqueue_head wq;
+    /* the number of vCPUs blocked */
+    unsigned int blocked;
+    /* The last vcpu woken up */
+    unsigned int last_vcpu_wake_up;
+};
+
 static int vm_event_enable(
     struct domain *d,
     struct xen_domctl_vm_event_op *vec,
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 7dee022..207fbc4 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -279,32 +279,7 @@ struct vcpu
 #define domain_lock(d) spin_lock_recursive(&(d)->domain_lock)
 #define domain_unlock(d) spin_unlock_recursive(&(d)->domain_lock)
 
-/* VM event */
-struct vm_event_domain
-{
-    /* Domain reference */
-    struct domain *d;
-    /* ring lock */
-    spinlock_t ring_lock;
-    /* The ring has 64 entries */
-    unsigned char foreign_producers;
-    unsigned char target_producers;
-    /* shared ring page */
-    void *ring_page;
-    struct page_info *ring_pg_struct;
-    /* front-end ring */
-    vm_event_front_ring_t front_ring;
-    /* event channel port (vcpu0 only) */
-    int xen_port;
-    /* vm_event bit for vcpu->pause_flags */
-    int pause_flag;
-    /* list of vcpus waiting for room in the ring */
-    struct waitqueue_head wq;
-    /* the number of vCPUs blocked */
-    unsigned int blocked;
-    /* The last vcpu woken up */
-    unsigned int last_vcpu_wake_up;
-};
+struct vm_event_domain;
 
 struct evtchn_port_ops;
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 6/9] vm_event: Move struct vm_event_domain to vm_event.c
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Tamas K Lengyel, Wei Liu, Razvan Cojocaru,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Stefano Stabellini, Jan Beulich

The vm_event_domain members are not accessed outside vm_event.c so it's
better to hide de implementation details.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/common/vm_event.c   | 27 +++++++++++++++++++++++++++
 xen/include/xen/sched.h | 27 +--------------------------
 2 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 3e87bbc..02c5853 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -39,6 +39,33 @@
 #define vm_event_ring_lock(_ved)       spin_lock(&(_ved)->ring_lock)
 #define vm_event_ring_unlock(_ved)     spin_unlock(&(_ved)->ring_lock)
 
+/* VM event */
+struct vm_event_domain
+{
+    /* Domain reference */
+    struct domain *d;
+    /* ring lock */
+    spinlock_t ring_lock;
+    /* The ring has 64 entries */
+    unsigned char foreign_producers;
+    unsigned char target_producers;
+    /* shared ring page */
+    void *ring_page;
+    struct page_info *ring_pg_struct;
+    /* front-end ring */
+    vm_event_front_ring_t front_ring;
+    /* event channel port (vcpu0 only) */
+    int xen_port;
+    /* vm_event bit for vcpu->pause_flags */
+    int pause_flag;
+    /* list of vcpus waiting for room in the ring */
+    struct waitqueue_head wq;
+    /* the number of vCPUs blocked */
+    unsigned int blocked;
+    /* The last vcpu woken up */
+    unsigned int last_vcpu_wake_up;
+};
+
 static int vm_event_enable(
     struct domain *d,
     struct xen_domctl_vm_event_op *vec,
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 7dee022..207fbc4 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -279,32 +279,7 @@ struct vcpu
 #define domain_lock(d) spin_lock_recursive(&(d)->domain_lock)
 #define domain_unlock(d) spin_unlock_recursive(&(d)->domain_lock)
 
-/* VM event */
-struct vm_event_domain
-{
-    /* Domain reference */
-    struct domain *d;
-    /* ring lock */
-    spinlock_t ring_lock;
-    /* The ring has 64 entries */
-    unsigned char foreign_producers;
-    unsigned char target_producers;
-    /* shared ring page */
-    void *ring_page;
-    struct page_info *ring_pg_struct;
-    /* front-end ring */
-    vm_event_front_ring_t front_ring;
-    /* event channel port (vcpu0 only) */
-    int xen_port;
-    /* vm_event bit for vcpu->pause_flags */
-    int pause_flag;
-    /* list of vcpus waiting for room in the ring */
-    struct waitqueue_head wq;
-    /* the number of vCPUs blocked */
-    unsigned int blocked;
-    /* The last vcpu woken up */
-    unsigned int last_vcpu_wake_up;
-};
+struct vm_event_domain;
 
 struct evtchn_port_ops;
 
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 7/9] vm_event: Decouple implementation details from interface.
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel; +Cc: Petre Pircalabu, Tamas K Lengyel, Razvan Cojocaru

To accommodate a second implementation of the vm_event subsystem, the
current one (ring) should be decoupled from the xen/vm_event.h interface.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/common/vm_event.c      | 407 ++++++++++++++++++++++-----------------------
 xen/include/xen/vm_event.h |  56 ++++++-
 2 files changed, 252 insertions(+), 211 deletions(-)

diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 02c5853..1d85f3e 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -35,17 +35,13 @@
 #define xen_rmb()  smp_rmb()
 #define xen_wmb()  smp_wmb()
 
-#define vm_event_ring_lock_init(_ved)  spin_lock_init(&(_ved)->ring_lock)
-#define vm_event_ring_lock(_ved)       spin_lock(&(_ved)->ring_lock)
-#define vm_event_ring_unlock(_ved)     spin_unlock(&(_ved)->ring_lock)
+#define to_ring(_ved) container_of((_ved), struct vm_event_ring_domain, ved)
 
-/* VM event */
-struct vm_event_domain
+/* VM event ring implementation */
+struct vm_event_ring_domain
 {
-    /* Domain reference */
-    struct domain *d;
-    /* ring lock */
-    spinlock_t ring_lock;
+    /* VM event domain */
+    struct vm_event_domain ved;
     /* The ring has 64 entries */
     unsigned char foreign_producers;
     unsigned char target_producers;
@@ -56,8 +52,6 @@ struct vm_event_domain
     vm_event_front_ring_t front_ring;
     /* event channel port (vcpu0 only) */
     int xen_port;
-    /* vm_event bit for vcpu->pause_flags */
-    int pause_flag;
     /* list of vcpus waiting for room in the ring */
     struct waitqueue_head wq;
     /* the number of vCPUs blocked */
@@ -66,48 +60,54 @@ struct vm_event_domain
     unsigned int last_vcpu_wake_up;
 };
 
-static int vm_event_enable(
+static const struct vm_event_ops vm_event_ring_ops;
+
+static int vm_event_ring_enable(
     struct domain *d,
     struct xen_domctl_vm_event_op *vec,
-    struct vm_event_domain **ved,
+    struct vm_event_domain **_ved,
     int pause_flag,
     int param,
     xen_event_channel_notification_t notification_fn)
 {
     int rc;
     unsigned long ring_gfn = d->arch.hvm.params[param];
+    struct vm_event_ring_domain *impl;
 
-    if ( !*ved )
-        *ved = xzalloc(struct vm_event_domain);
-    if ( !*ved )
+    impl = (*_ved) ? to_ring(*_ved) :
+            xzalloc(struct vm_event_ring_domain);
+    if ( !impl )
         return -ENOMEM;
 
     /* Only one helper at a time. If the helper crashed,
      * the ring is in an undefined state and so is the guest.
      */
-    if ( (*ved)->ring_page )
-        return -EBUSY;;
+    if ( impl->ring_page )
+        return -EBUSY;
 
     /* The parameter defaults to zero, and it should be
      * set to something */
     if ( ring_gfn == 0 )
         return -EOPNOTSUPP;
 
-    vm_event_ring_lock_init(*ved);
-    vm_event_ring_lock(*ved);
+    spin_lock_init(&impl->ved.lock);
+    spin_lock(&impl->ved.lock);
 
     rc = vm_event_init_domain(d);
 
     if ( rc < 0 )
         goto err;
 
-    rc = prepare_ring_for_helper(d, ring_gfn, &(*ved)->ring_pg_struct,
-                                 &(*ved)->ring_page);
+    impl->ved.d = d;
+    impl->ved.ops = &vm_event_ring_ops;
+
+    rc = prepare_ring_for_helper(d, ring_gfn, &impl->ring_pg_struct,
+                                 &impl->ring_page);
     if ( rc < 0 )
         goto err;
 
     /* Set the number of currently blocked vCPUs to 0. */
-    (*ved)->blocked = 0;
+    impl->blocked = 0;
 
     /* Allocate event channel */
     rc = alloc_unbound_xen_event_channel(d, 0, current->domain->domain_id,
@@ -115,37 +115,37 @@ static int vm_event_enable(
     if ( rc < 0 )
         goto err;
 
-    (*ved)->xen_port = vec->u.enable.port = rc;
+    impl->xen_port = vec->u.enable.port = rc;
 
     /* Prepare ring buffer */
-    FRONT_RING_INIT(&(*ved)->front_ring,
-                    (vm_event_sring_t *)(*ved)->ring_page,
+    FRONT_RING_INIT(&impl->front_ring,
+                    (vm_event_sring_t *)impl->ring_page,
                     PAGE_SIZE);
 
     /* Save the pause flag for this particular ring. */
-    (*ved)->pause_flag = pause_flag;
+    impl->ved.pause_flag = pause_flag;
 
     /* Initialize the last-chance wait queue. */
-    init_waitqueue_head(&(*ved)->wq);
+    init_waitqueue_head(&impl->wq);
 
-    vm_event_ring_unlock(*ved);
+    spin_unlock(&impl->ved.lock);
+    *_ved = &impl->ved;
     return 0;
 
  err:
-    destroy_ring_for_helper(&(*ved)->ring_page,
-                            (*ved)->ring_pg_struct);
-    vm_event_ring_unlock(*ved);
-    xfree(*ved);
-    *ved = NULL;
+    destroy_ring_for_helper(&impl->ring_page,
+                            impl->ring_pg_struct);
+    spin_unlock(&impl->ved.lock);
+    XFREE(impl);
 
     return rc;
 }
 
-static unsigned int vm_event_ring_available(struct vm_event_domain *ved)
+static unsigned int vm_event_ring_available(struct vm_event_ring_domain *impl)
 {
-    int avail_req = RING_FREE_REQUESTS(&ved->front_ring);
-    avail_req -= ved->target_producers;
-    avail_req -= ved->foreign_producers;
+    int avail_req = RING_FREE_REQUESTS(&impl->front_ring);
+    avail_req -= impl->target_producers;
+    avail_req -= impl->foreign_producers;
 
     BUG_ON(avail_req < 0);
 
@@ -153,42 +153,42 @@ static unsigned int vm_event_ring_available(struct vm_event_domain *ved)
 }
 
 /*
- * vm_event_wake_blocked() will wakeup vcpus waiting for room in the
+ * vm_event_ring_wake_blocked() will wakeup vcpus waiting for room in the
  * ring. These vCPUs were paused on their way out after placing an event,
  * but need to be resumed where the ring is capable of processing at least
  * one event from them.
  */
-static void vm_event_wake_blocked(struct vm_event_domain *ved)
+static void vm_event_ring_wake_blocked(struct vm_event_ring_domain *impl)
 {
     struct vcpu *v;
-    unsigned int avail_req = vm_event_ring_available(ved);
-    struct domain *d = ved->d;
+    unsigned int avail_req = vm_event_ring_available(impl);
 
-    if ( avail_req == 0 || ved->blocked == 0 )
+    if ( avail_req == 0 || impl->blocked == 0 )
         return;
 
     /* We remember which vcpu last woke up to avoid scanning always linearly
      * from zero and starving higher-numbered vcpus under high load */
-    if ( d->vcpu )
+    if ( impl->ved.d->vcpu )
     {
         int i, j, k;
 
-        for (i = ved->last_vcpu_wake_up + 1, j = 0; j < d->max_vcpus; i++, j++)
+        for ( i = impl->last_vcpu_wake_up + 1, j = 0;
+              j < impl->ved.d->max_vcpus; i++, j++)
         {
-            k = i % d->max_vcpus;
-            v = d->vcpu[k];
+            k = i % impl->ved.d->max_vcpus;
+            v = impl->ved.d->vcpu[k];
             if ( !v )
                 continue;
 
-            if ( !(ved->blocked) || avail_req == 0 )
+            if ( !(impl->blocked) || avail_req == 0 )
                break;
 
-            if ( test_and_clear_bit(ved->pause_flag, &v->pause_flags) )
+            if ( test_and_clear_bit(impl->ved.pause_flag, &v->pause_flags) )
             {
                 vcpu_unpause(v);
                 avail_req--;
-                ved->blocked--;
-                ved->last_vcpu_wake_up = k;
+                impl->blocked--;
+                impl->last_vcpu_wake_up = k;
             }
         }
     }
@@ -199,92 +199,90 @@ static void vm_event_wake_blocked(struct vm_event_domain *ved)
  * was unable to do so, it is queued on a wait queue.  These are woken as
  * needed, and take precedence over the blocked vCPUs.
  */
-static void vm_event_wake_queued(struct vm_event_domain *ved)
+static void vm_event_ring_wake_queued(struct vm_event_ring_domain *impl)
 {
-    unsigned int avail_req = vm_event_ring_available(ved);
+    unsigned int avail_req = vm_event_ring_available(impl);
 
     if ( avail_req > 0 )
-        wake_up_nr(&ved->wq, avail_req);
+        wake_up_nr(&impl->wq, avail_req);
 }
 
 /*
- * vm_event_wake() will wakeup all vcpus waiting for the ring to
+ * vm_event_ring_wake() will wakeup all vcpus waiting for the ring to
  * become available.  If we have queued vCPUs, they get top priority. We
  * are guaranteed that they will go through code paths that will eventually
- * call vm_event_wake() again, ensuring that any blocked vCPUs will get
+ * call vm_event_ring_wake() again, ensuring that any blocked vCPUs will get
  * unpaused once all the queued vCPUs have made it through.
  */
-void vm_event_wake(struct vm_event_domain *ved)
+static void vm_event_ring_wake(struct vm_event_ring_domain *impl)
 {
-    if (!list_empty(&ved->wq.list))
-        vm_event_wake_queued(ved);
+    if ( !list_empty(&impl->wq.list) )
+        vm_event_ring_wake_queued(impl);
     else
-        vm_event_wake_blocked(ved);
+        vm_event_ring_wake_blocked(impl);
 }
 
-static int vm_event_disable(struct domain *d, struct vm_event_domain **ved)
+static int vm_event_ring_disable(struct vm_event_domain **_ved)
 {
-    if ( vm_event_check(*ved) )
-    {
-        struct vcpu *v;
+    struct vcpu *v;
+    struct domain *d = (*_ved)->d;
+    struct vm_event_ring_domain *impl = to_ring(*_ved);
 
-        vm_event_ring_lock(*ved);
+    spin_lock(&(*_ved)->lock);
 
-        if ( !list_empty(&(*ved)->wq.list) )
-        {
-            vm_event_ring_unlock(*ved);
-            return -EBUSY;
-        }
+    if ( !list_empty(&impl->wq.list) )
+    {
+        spin_unlock(&(*_ved)->lock);
+        return -EBUSY;
+    }
 
-        /* Free domU's event channel and leave the other one unbound */
-        free_xen_event_channel(d, (*ved)->xen_port);
+    /* Free domU's event channel and leave the other one unbound */
+    free_xen_event_channel(d, impl->xen_port);
 
-        /* Unblock all vCPUs */
-        for_each_vcpu ( d, v )
+    /* Unblock all vCPUs */
+    for_each_vcpu ( d, v )
+    {
+        if ( test_and_clear_bit((*_ved)->pause_flag, &v->pause_flags) )
         {
-            if ( test_and_clear_bit((*ved)->pause_flag, &v->pause_flags) )
-            {
-                vcpu_unpause(v);
-                (*ved)->blocked--;
-            }
+            vcpu_unpause(v);
+            impl->blocked--;
         }
+    }
 
-        destroy_ring_for_helper(&(*ved)->ring_page,
-                                (*ved)->ring_pg_struct);
-
-        vm_event_cleanup_domain(d);
+    destroy_ring_for_helper(&impl->ring_page,
+                            impl->ring_pg_struct);
 
-        vm_event_ring_unlock(*ved);
-    }
+    vm_event_cleanup_domain(d);
 
-    xfree(*ved);
-    *ved = NULL;
+    spin_unlock(&(*_ved)->lock);
 
+    XFREE(*_ved);
     return 0;
 }
 
-static inline void vm_event_release_slot(struct vm_event_domain *ved)
+static inline void vm_event_ring_release_slot(struct vm_event_ring_domain *impl)
 {
     /* Update the accounting */
-    if ( current->domain == ved->d )
-        ved->target_producers--;
+    if ( current->domain == impl->ved.d )
+        impl->target_producers--;
     else
-        ved->foreign_producers--;
+        impl->foreign_producers--;
 
     /* Kick any waiters */
-    vm_event_wake(ved);
+    vm_event_ring_wake(impl);
 }
 
 /*
- * vm_event_mark_and_pause() tags vcpu and put it to sleep.
- * The vcpu will resume execution in vm_event_wake_blocked().
+ * vm_event_ring_mark_and_pause() tags vcpu and put it to sleep.
+ * The vcpu will resume execution in vm_event_ring_wake_blocked().
  */
-static void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
+static void vm_event_ring_mark_and_pause(struct vcpu *v,
+                                         struct vm_event_ring_domain *impl)
 {
-    if ( !test_and_set_bit(ved->pause_flag, &v->pause_flags) )
+    if ( !test_and_set_bit(impl->ved.pause_flag, &v->pause_flags) )
     {
         vcpu_pause_nosync(v);
-        ved->blocked++;
+        impl->blocked++;
     }
 }
 
@@ -294,35 +292,32 @@ static void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
  * overly full and its continued execution would cause stalling and excessive
  * waiting.  The vCPU will be automatically unpaused when the ring clears.
  */
-void vm_event_put_request(struct vm_event_domain *ved,
-                          vm_event_request_t *req)
+static void vm_event_ring_put_request(struct vm_event_domain *ved,
+                                      vm_event_request_t *req)
 {
     vm_event_front_ring_t *front_ring;
     int free_req;
     unsigned int avail_req;
     RING_IDX req_prod;
     struct vcpu *curr = current;
-    struct domain *d = ved->d;
-
-    if( !vm_event_check(ved))
-        return;
+    struct vm_event_ring_domain *impl = to_ring(ved);
 
-    if ( curr->domain != d )
+    if ( curr->domain != ved->d )
     {
         req->flags |= VM_EVENT_FLAG_FOREIGN;
 #ifndef NDEBUG
         if ( !(req->flags & VM_EVENT_FLAG_VCPU_PAUSED) )
             gdprintk(XENLOG_G_WARNING, "d%dv%d was not paused.\n",
-                     d->domain_id, req->vcpu_id);
+                     ved->d->domain_id, req->vcpu_id);
 #endif
     }
 
     req->version = VM_EVENT_INTERFACE_VERSION;
 
-    vm_event_ring_lock(ved);
+    spin_lock(&impl->ved.lock);
 
     /* Due to the reservations, this step must succeed. */
-    front_ring = &ved->front_ring;
+    front_ring = &impl->front_ring;
     free_req = RING_FREE_REQUESTS(front_ring);
     ASSERT(free_req > 0);
 
@@ -336,35 +331,35 @@ void vm_event_put_request(struct vm_event_domain *ved,
     RING_PUSH_REQUESTS(front_ring);
 
     /* We've actually *used* our reservation, so release the slot. */
-    vm_event_release_slot(ved);
+    vm_event_ring_release_slot(impl);
 
     /* Give this vCPU a black eye if necessary, on the way out.
      * See the comments above wake_blocked() for more information
      * on how this mechanism works to avoid waiting. */
-    avail_req = vm_event_ring_available(ved);
-    if( curr->domain == d && avail_req < d->max_vcpus &&
+    avail_req = vm_event_ring_available(impl);
+    if( curr->domain == ved->d && avail_req < ved->d->max_vcpus &&
         !atomic_read(&curr->vm_event_pause_count) )
-        vm_event_mark_and_pause(curr, ved);
+        vm_event_ring_mark_and_pause(curr, impl);
 
-    vm_event_ring_unlock(ved);
+    spin_unlock(&impl->ved.lock);
 
-    notify_via_xen_event_channel(d, ved->xen_port);
+    notify_via_xen_event_channel(ved->d, impl->xen_port);
 }
 
-static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
-                                 vm_event_response_t *rsp)
+static int vm_event_ring_get_response(struct vm_event_ring_domain *impl,
+                                      vm_event_response_t *rsp)
 {
     vm_event_front_ring_t *front_ring;
     RING_IDX rsp_cons;
 
-    vm_event_ring_lock(ved);
+    spin_lock(&impl->ved.lock);
 
-    front_ring = &ved->front_ring;
+    front_ring = &impl->front_ring;
     rsp_cons = front_ring->rsp_cons;
 
     if ( !RING_HAS_UNCONSUMED_RESPONSES(front_ring) )
     {
-        vm_event_ring_unlock(ved);
+        spin_unlock(&impl->ved.lock);
         return 0;
     }
 
@@ -378,9 +373,9 @@ static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
 
     /* Kick any waiters -- since we've just consumed an event,
      * there may be additional space available in the ring. */
-    vm_event_wake(ved);
+    vm_event_ring_wake(impl);
 
-    vm_event_ring_unlock(ved);
+    spin_unlock(&impl->ved.lock);
 
     return 1;
 }
@@ -393,10 +388,13 @@ static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
  * Note: responses are handled the same way regardless of which ring they
  * arrive on.
  */
-static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
+static int vm_event_ring_resume(struct vm_event_ring_domain *impl)
 {
     vm_event_response_t rsp;
 
+    if ( unlikely(!impl || !vm_event_check(&impl->ved)) )
+         return -ENODEV;
+
     /*
      * vm_event_resume() runs in either XEN_VM_EVENT_* domctls, or
      * EVTCHN_send context from the introspection consumer. Both contexts
@@ -405,13 +403,10 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
      * below, this covers the case where we would need to iterate over all
      * of them more succintly.
      */
-    ASSERT(d != current->domain);
-
-    if ( unlikely(!vm_event_check(ved)) )
-         return -ENODEV;
+    ASSERT(impl->ved.d != current->domain);
 
     /* Pull all responses off the ring. */
-    while ( vm_event_get_response(d, ved, &rsp) )
+    while ( vm_event_ring_get_response(impl, &rsp) )
     {
         struct vcpu *v;
 
@@ -422,10 +417,11 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
         }
 
         /* Validate the vcpu_id in the response. */
-        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
+        if ( (rsp.vcpu_id >= impl->ved.d->max_vcpus) ||
+              !impl->ved.d->vcpu[rsp.vcpu_id] )
             continue;
 
-        v = d->vcpu[rsp.vcpu_id];
+        v = impl->ved.d->vcpu[rsp.vcpu_id];
 
         /*
          * In some cases the response type needs extra handling, so here
@@ -437,7 +433,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
         {
 #ifdef CONFIG_HAS_MEM_PAGING
             if ( rsp.reason == VM_EVENT_REASON_MEM_PAGING )
-                p2m_mem_paging_resume(d, &rsp);
+                p2m_mem_paging_resume(impl->ved.d, &rsp);
 #endif
 
             /*
@@ -457,7 +453,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
              * Check in arch-specific handler to avoid bitmask overhead when
              * not supported.
              */
-            vm_event_toggle_singlestep(d, v, &rsp);
+            vm_event_toggle_singlestep(impl->ved.d, v, &rsp);
 
             /* Check for altp2m switch */
             if ( rsp.flags & VM_EVENT_FLAG_ALTERNATE_P2M )
@@ -477,66 +473,63 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
     return 0;
 }
 
-void vm_event_cancel_slot(struct vm_event_domain *ved)
+static void vm_event_ring_cancel_slot(struct vm_event_domain *ved)
 {
-    if( !vm_event_check(ved) )
-        return;
-
-    vm_event_ring_lock(ved);
-    vm_event_release_slot(ved);
-    vm_event_ring_unlock(ved);
+    spin_lock(&ved->lock);
+    vm_event_ring_release_slot(to_ring(ved));
+    spin_unlock(&ved->lock);
 }
 
-static int vm_event_grab_slot(struct vm_event_domain *ved, int foreign)
+static int vm_event_ring_grab_slot(struct vm_event_ring_domain *impl, int foreign)
 {
     unsigned int avail_req;
 
-    if ( !ved->ring_page )
+    if ( !impl->ring_page )
         return -EOPNOTSUPP;
 
-    vm_event_ring_lock(ved);
+    spin_lock(&impl->ved.lock);
 
-    avail_req = vm_event_ring_available(ved);
+    avail_req = vm_event_ring_available(impl);
     if ( avail_req == 0 )
     {
-        vm_event_ring_unlock(ved);
+        spin_unlock(&impl->ved.lock);
         return -EBUSY;
     }
 
     if ( !foreign )
-        ved->target_producers++;
+        impl->target_producers++;
     else
-        ved->foreign_producers++;
+        impl->foreign_producers++;
 
-    vm_event_ring_unlock(ved);
+    spin_unlock(&impl->ved.lock);
 
     return 0;
 }
 
 /* Simple try_grab wrapper for use in the wait_event() macro. */
-static int vm_event_wait_try_grab(struct vm_event_domain *ved, int *rc)
+static int vm_event_ring_wait_try_grab(struct vm_event_ring_domain *impl, int *rc)
 {
-    *rc = vm_event_grab_slot(ved, 0);
+    *rc = vm_event_ring_grab_slot(impl, 0);
     return *rc;
 }
 
-/* Call vm_event_grab_slot() until the ring doesn't exist, or is available. */
-static int vm_event_wait_slot(struct vm_event_domain *ved)
+/* Call vm_event_ring_grab_slot() until the ring doesn't exist, or is available. */
+static int vm_event_ring_wait_slot(struct vm_event_ring_domain *impl)
 {
     int rc = -EBUSY;
-    wait_event(ved->wq, vm_event_wait_try_grab(ved, &rc) != -EBUSY);
+    wait_event(impl->wq, vm_event_ring_wait_try_grab(impl, &rc) != -EBUSY);
     return rc;
 }
 
-bool vm_event_check(struct vm_event_domain *ved)
+static bool vm_event_ring_check(struct vm_event_domain *ved)
 {
-    return (ved && ved->ring_page);
+    return ( to_ring(ved)->ring_page != NULL );
 }
 
 /*
  * Determines whether or not the current vCPU belongs to the target domain,
  * and calls the appropriate wait function.  If it is a guest vCPU, then we
- * use vm_event_wait_slot() to reserve a slot.  As long as there is a ring,
+ * use vm_event_ring_wait_slot() to reserve a slot.  As long as there is a ring,
  * this function will always return 0 for a guest.  For a non-guest, we check
  * for space and return -EBUSY if the ring is not available.
  *
@@ -545,36 +538,33 @@ bool vm_event_check(struct vm_event_domain *ved)
  *               0: a spot has been reserved
  *
  */
-int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep)
+static int vm_event_ring_claim_slot(struct vm_event_domain *ved, bool allow_sleep)
 {
-    if ( !vm_event_check(ved) )
-        return -EOPNOTSUPP;
-
     if ( (current->domain == ved->d) && allow_sleep )
-        return vm_event_wait_slot(ved);
+        return vm_event_ring_wait_slot(to_ring(ved));
     else
-        return vm_event_grab_slot(ved, (current->domain != ved->d));
+        return vm_event_ring_grab_slot(to_ring(ved), (current->domain != ved->d));
 }
 
 #ifdef CONFIG_HAS_MEM_PAGING
 /* Registered with Xen-bound event channel for incoming notifications. */
 static void mem_paging_notification(struct vcpu *v, unsigned int port)
 {
-    vm_event_resume(v->domain, v->domain->vm_event_paging);
+    vm_event_ring_resume(to_ring(v->domain->vm_event_paging));
 }
 #endif
 
 /* Registered with Xen-bound event channel for incoming notifications. */
 static void monitor_notification(struct vcpu *v, unsigned int port)
 {
-    vm_event_resume(v->domain, v->domain->vm_event_monitor);
+    vm_event_ring_resume(to_ring(v->domain->vm_event_monitor));
 }
 
 #ifdef CONFIG_HAS_MEM_SHARING
 /* Registered with Xen-bound event channel for incoming notifications. */
 static void mem_sharing_notification(struct vcpu *v, unsigned int port)
 {
-    vm_event_resume(v->domain, v->domain->vm_event_share);
+    vm_event_ring_resume(to_ring(v->domain->vm_event_share));
 }
 #endif
 
@@ -583,32 +573,32 @@ void vm_event_cleanup(struct domain *d)
 {
 #ifdef CONFIG_HAS_MEM_PAGING
     if ( vm_event_check(d->vm_event_paging) )
-    {
-        /* Destroying the wait queue head means waking up all
-         * queued vcpus. This will drain the list, allowing
-         * the disable routine to complete. It will also drop
-         * all domain refs the wait-queued vcpus are holding.
-         * Finally, because this code path involves previously
-         * pausing the domain (domain_kill), unpausing the
-         * vcpus causes no harm. */
-        destroy_waitqueue_head(&d->vm_event_paging->wq);
-        (void)vm_event_disable(d, &d->vm_event_paging);
-    }
+        d->vm_event_paging->ops->cleanup(&d->vm_event_paging);
 #endif
+
     if ( vm_event_check(d->vm_event_monitor) )
-    {
-        destroy_waitqueue_head(&d->vm_event_monitor->wq);
-        (void)vm_event_disable(d, &d->vm_event_monitor);
-    }
+        d->vm_event_monitor->ops->cleanup(&d->vm_event_monitor);
+
 #ifdef CONFIG_HAS_MEM_SHARING
     if ( vm_event_check(d->vm_event_share) )
-    {
-        destroy_waitqueue_head(&d->vm_event_share->wq);
-        (void)vm_event_disable(d, &d->vm_event_share);
-    }
+        d->vm_event_share->ops->cleanup(&d->vm_event_share);
 #endif
 }
 
+static void vm_event_ring_cleanup(struct vm_event_domain **_ved)
+{
+    struct vm_event_ring_domain *impl = to_ring(*_ved);
+    /* Destroying the wait queue head means waking up all
+     * queued vcpus. This will drain the list, allowing
+     * the disable routine to complete. It will also drop
+     * all domain refs the wait-queued vcpus are holding.
+     * Finally, because this code path involves previously
+     * pausing the domain (domain_kill), unpausing the
+     * vcpus causes no harm. */
+    destroy_waitqueue_head(&impl->wq);
+    (void)vm_event_ring_disable(_ved);
+}
+
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                     XEN_GUEST_HANDLE_PARAM(void) u_domctl)
 {
@@ -682,23 +672,22 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                 break;
 
             /* domain_pause() not required here, see XSA-99 */
-            rc = vm_event_enable(d, vec, &d->vm_event_paging, _VPF_mem_paging,
+            rc = vm_event_ring_enable(d, vec, &d->vm_event_paging, _VPF_mem_paging,
                                  HVM_PARAM_PAGING_RING_PFN,
                                  mem_paging_notification);
         }
         break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check(d->vm_event_paging) )
-            {
-                domain_pause(d);
-                rc = vm_event_disable(d, &d->vm_event_paging);
-                domain_unpause(d);
-            }
+            if ( !vm_event_check(d->vm_event_paging) )
+                break;
+            domain_pause(d);
+            rc = vm_event_ring_disable(&d->vm_event_paging);
+            domain_unpause(d);
             break;
 
         case XEN_VM_EVENT_RESUME:
-            rc = vm_event_resume(d, d->vm_event_paging);
+            rc = vm_event_ring_resume(to_ring(d->vm_event_paging));
             break;
 
         default:
@@ -720,23 +709,22 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
             rc = arch_monitor_init_domain(d);
             if ( rc )
                 break;
-            rc = vm_event_enable(d, vec, &d->vm_event_monitor, _VPF_mem_access,
+            rc = vm_event_ring_enable(d, vec, &d->vm_event_monitor, _VPF_mem_access,
                                  HVM_PARAM_MONITOR_RING_PFN,
                                  monitor_notification);
             break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check(d->vm_event_monitor) )
-            {
-                domain_pause(d);
-                rc = vm_event_disable(d, &d->vm_event_monitor);
-                arch_monitor_cleanup_domain(d);
-                domain_unpause(d);
-            }
+            if ( !vm_event_check(d->vm_event_monitor) )
+                break;
+            domain_pause(d);
+            rc = vm_event_ring_disable(&d->vm_event_monitor);
+            arch_monitor_cleanup_domain(d);
+            domain_unpause(d);
             break;
 
         case XEN_VM_EVENT_RESUME:
-            rc = vm_event_resume(d, d->vm_event_monitor);
+            rc = vm_event_ring_resume(to_ring(d->vm_event_monitor));
             break;
 
         default:
@@ -765,22 +753,21 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                 break;
 
             /* domain_pause() not required here, see XSA-99 */
-            rc = vm_event_enable(d, vec, &d->vm_event_share, _VPF_mem_sharing,
+            rc = vm_event_ring_enable(d, vec, &d->vm_event_share, _VPF_mem_sharing,
                                  HVM_PARAM_SHARING_RING_PFN,
                                  mem_sharing_notification);
             break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check(d->vm_event_share) )
-            {
-                domain_pause(d);
-                rc = vm_event_disable(d, &d->vm_event_share);
-                domain_unpause(d);
-            }
+            if ( !vm_event_check(d->vm_event_share) )
+                break;
+            domain_pause(d);
+            rc = vm_event_ring_disable(&d->vm_event_share);
+            domain_unpause(d);
             break;
 
         case XEN_VM_EVENT_RESUME:
-            rc = vm_event_resume(d, d->vm_event_share);
+            rc = vm_event_ring_resume(to_ring(d->vm_event_share));
             break;
 
         default:
@@ -832,6 +819,14 @@ void vm_event_vcpu_unpause(struct vcpu *v)
     vcpu_unpause(v);
 }
 
+static const struct vm_event_ops vm_event_ring_ops = {
+    .check = vm_event_ring_check,
+    .cleanup = vm_event_ring_cleanup,
+    .claim_slot = vm_event_ring_claim_slot,
+    .cancel_slot = vm_event_ring_cancel_slot,
+    .put_request = vm_event_ring_put_request
+};
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index a5c82d6..15c15e6 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -26,11 +26,38 @@
 #include <xen/sched.h>
 #include <public/vm_event.h>
 
+struct vm_event_ops
+{
+    bool (*check)(struct vm_event_domain *ved);
+    void (*cleanup)(struct vm_event_domain **_ved);
+    int (*claim_slot)(struct vm_event_domain *ved, bool allow_sleep);
+    void (*cancel_slot)(struct vm_event_domain *ved);
+    void (*put_request)(struct vm_event_domain *ved, vm_event_request_t *req);
+};
+
+struct vm_event_domain
+{
+    /* Domain reference */
+    struct domain *d;
+
+    /* vm_event_ops */
+    const struct vm_event_ops *ops;
+
+    /* vm_event domain lock */
+    spinlock_t lock;
+
+    /* vm_event bit for vcpu->pause_flags */
+    int pause_flag;
+};
+
 /* Clean up on domain destruction */
 void vm_event_cleanup(struct domain *d);
 
 /* Returns whether the VM event domain has been set up */
-bool vm_event_check(struct vm_event_domain *ved);
+static inline bool vm_event_check(struct vm_event_domain *ved)
+{
+    return (ved) && ved->ops->check(ved);
+}
 
 /* Returns 0 on success, -ENOSYS if there is no ring, -EBUSY if there is no
  * available space and the caller is a foreign domain. If the guest itself
@@ -45,7 +72,14 @@ bool vm_event_check(struct vm_event_domain *ved);
  * cancel_slot(), both of which are guaranteed to
  * succeed.
  */
-int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep);
+static inline int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep)
+{
+    if ( !vm_event_check(ved) )
+        return -EOPNOTSUPP;
+
+    return ved->ops->claim_slot(ved, allow_sleep);
+}
+
 static inline int vm_event_claim_slot(struct vm_event_domain *ved)
 {
     return __vm_event_claim_slot(ved, true);
@@ -56,10 +90,22 @@ static inline int vm_event_claim_slot_nosleep(struct vm_event_domain *ved)
     return __vm_event_claim_slot(ved, false);
 }
 
-void vm_event_cancel_slot(struct vm_event_domain *ved);
+static inline void vm_event_cancel_slot(struct vm_event_domain *ved)
+{
+    if ( !vm_event_check(ved) )
+        return;
 
-void vm_event_put_request(struct vm_event_domain *ved,
-                          vm_event_request_t *req);
+    ved->ops->cancel_slot(ved);
+}
+
+static inline void vm_event_put_request(struct vm_event_domain *ved,
+                                        vm_event_request_t *req)
+{
+    if ( !vm_event_check(ved) )
+        return;
+
+    ved->ops->put_request(ved, req);
+}
 
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                     XEN_GUEST_HANDLE_PARAM(void) u_domctl);
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 7/9] vm_event: Decouple implementation details from interface.
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel; +Cc: Petre Pircalabu, Tamas K Lengyel, Razvan Cojocaru

To accommodate a second implementation of the vm_event subsystem, the
current one (ring) should be decoupled from the xen/vm_event.h interface.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 xen/common/vm_event.c      | 407 ++++++++++++++++++++++-----------------------
 xen/include/xen/vm_event.h |  56 ++++++-
 2 files changed, 252 insertions(+), 211 deletions(-)

diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 02c5853..1d85f3e 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -35,17 +35,13 @@
 #define xen_rmb()  smp_rmb()
 #define xen_wmb()  smp_wmb()
 
-#define vm_event_ring_lock_init(_ved)  spin_lock_init(&(_ved)->ring_lock)
-#define vm_event_ring_lock(_ved)       spin_lock(&(_ved)->ring_lock)
-#define vm_event_ring_unlock(_ved)     spin_unlock(&(_ved)->ring_lock)
+#define to_ring(_ved) container_of((_ved), struct vm_event_ring_domain, ved)
 
-/* VM event */
-struct vm_event_domain
+/* VM event ring implementation */
+struct vm_event_ring_domain
 {
-    /* Domain reference */
-    struct domain *d;
-    /* ring lock */
-    spinlock_t ring_lock;
+    /* VM event domain */
+    struct vm_event_domain ved;
     /* The ring has 64 entries */
     unsigned char foreign_producers;
     unsigned char target_producers;
@@ -56,8 +52,6 @@ struct vm_event_domain
     vm_event_front_ring_t front_ring;
     /* event channel port (vcpu0 only) */
     int xen_port;
-    /* vm_event bit for vcpu->pause_flags */
-    int pause_flag;
     /* list of vcpus waiting for room in the ring */
     struct waitqueue_head wq;
     /* the number of vCPUs blocked */
@@ -66,48 +60,54 @@ struct vm_event_domain
     unsigned int last_vcpu_wake_up;
 };
 
-static int vm_event_enable(
+static const struct vm_event_ops vm_event_ring_ops;
+
+static int vm_event_ring_enable(
     struct domain *d,
     struct xen_domctl_vm_event_op *vec,
-    struct vm_event_domain **ved,
+    struct vm_event_domain **_ved,
     int pause_flag,
     int param,
     xen_event_channel_notification_t notification_fn)
 {
     int rc;
     unsigned long ring_gfn = d->arch.hvm.params[param];
+    struct vm_event_ring_domain *impl;
 
-    if ( !*ved )
-        *ved = xzalloc(struct vm_event_domain);
-    if ( !*ved )
+    impl = (*_ved) ? to_ring(*_ved) :
+            xzalloc(struct vm_event_ring_domain);
+    if ( !impl )
         return -ENOMEM;
 
     /* Only one helper at a time. If the helper crashed,
      * the ring is in an undefined state and so is the guest.
      */
-    if ( (*ved)->ring_page )
-        return -EBUSY;;
+    if ( impl->ring_page )
+        return -EBUSY;
 
     /* The parameter defaults to zero, and it should be
      * set to something */
     if ( ring_gfn == 0 )
         return -EOPNOTSUPP;
 
-    vm_event_ring_lock_init(*ved);
-    vm_event_ring_lock(*ved);
+    spin_lock_init(&impl->ved.lock);
+    spin_lock(&impl->ved.lock);
 
     rc = vm_event_init_domain(d);
 
     if ( rc < 0 )
         goto err;
 
-    rc = prepare_ring_for_helper(d, ring_gfn, &(*ved)->ring_pg_struct,
-                                 &(*ved)->ring_page);
+    impl->ved.d = d;
+    impl->ved.ops = &vm_event_ring_ops;
+
+    rc = prepare_ring_for_helper(d, ring_gfn, &impl->ring_pg_struct,
+                                 &impl->ring_page);
     if ( rc < 0 )
         goto err;
 
     /* Set the number of currently blocked vCPUs to 0. */
-    (*ved)->blocked = 0;
+    impl->blocked = 0;
 
     /* Allocate event channel */
     rc = alloc_unbound_xen_event_channel(d, 0, current->domain->domain_id,
@@ -115,37 +115,37 @@ static int vm_event_enable(
     if ( rc < 0 )
         goto err;
 
-    (*ved)->xen_port = vec->u.enable.port = rc;
+    impl->xen_port = vec->u.enable.port = rc;
 
     /* Prepare ring buffer */
-    FRONT_RING_INIT(&(*ved)->front_ring,
-                    (vm_event_sring_t *)(*ved)->ring_page,
+    FRONT_RING_INIT(&impl->front_ring,
+                    (vm_event_sring_t *)impl->ring_page,
                     PAGE_SIZE);
 
     /* Save the pause flag for this particular ring. */
-    (*ved)->pause_flag = pause_flag;
+    impl->ved.pause_flag = pause_flag;
 
     /* Initialize the last-chance wait queue. */
-    init_waitqueue_head(&(*ved)->wq);
+    init_waitqueue_head(&impl->wq);
 
-    vm_event_ring_unlock(*ved);
+    spin_unlock(&impl->ved.lock);
+    *_ved = &impl->ved;
     return 0;
 
  err:
-    destroy_ring_for_helper(&(*ved)->ring_page,
-                            (*ved)->ring_pg_struct);
-    vm_event_ring_unlock(*ved);
-    xfree(*ved);
-    *ved = NULL;
+    destroy_ring_for_helper(&impl->ring_page,
+                            impl->ring_pg_struct);
+    spin_unlock(&impl->ved.lock);
+    XFREE(impl);
 
     return rc;
 }
 
-static unsigned int vm_event_ring_available(struct vm_event_domain *ved)
+static unsigned int vm_event_ring_available(struct vm_event_ring_domain *impl)
 {
-    int avail_req = RING_FREE_REQUESTS(&ved->front_ring);
-    avail_req -= ved->target_producers;
-    avail_req -= ved->foreign_producers;
+    int avail_req = RING_FREE_REQUESTS(&impl->front_ring);
+    avail_req -= impl->target_producers;
+    avail_req -= impl->foreign_producers;
 
     BUG_ON(avail_req < 0);
 
@@ -153,42 +153,42 @@ static unsigned int vm_event_ring_available(struct vm_event_domain *ved)
 }
 
 /*
- * vm_event_wake_blocked() will wakeup vcpus waiting for room in the
+ * vm_event_ring_wake_blocked() will wakeup vcpus waiting for room in the
  * ring. These vCPUs were paused on their way out after placing an event,
  * but need to be resumed where the ring is capable of processing at least
  * one event from them.
  */
-static void vm_event_wake_blocked(struct vm_event_domain *ved)
+static void vm_event_ring_wake_blocked(struct vm_event_ring_domain *impl)
 {
     struct vcpu *v;
-    unsigned int avail_req = vm_event_ring_available(ved);
-    struct domain *d = ved->d;
+    unsigned int avail_req = vm_event_ring_available(impl);
 
-    if ( avail_req == 0 || ved->blocked == 0 )
+    if ( avail_req == 0 || impl->blocked == 0 )
         return;
 
     /* We remember which vcpu last woke up to avoid scanning always linearly
      * from zero and starving higher-numbered vcpus under high load */
-    if ( d->vcpu )
+    if ( impl->ved.d->vcpu )
     {
         int i, j, k;
 
-        for (i = ved->last_vcpu_wake_up + 1, j = 0; j < d->max_vcpus; i++, j++)
+        for ( i = impl->last_vcpu_wake_up + 1, j = 0;
+              j < impl->ved.d->max_vcpus; i++, j++)
         {
-            k = i % d->max_vcpus;
-            v = d->vcpu[k];
+            k = i % impl->ved.d->max_vcpus;
+            v = impl->ved.d->vcpu[k];
             if ( !v )
                 continue;
 
-            if ( !(ved->blocked) || avail_req == 0 )
+            if ( !(impl->blocked) || avail_req == 0 )
                break;
 
-            if ( test_and_clear_bit(ved->pause_flag, &v->pause_flags) )
+            if ( test_and_clear_bit(impl->ved.pause_flag, &v->pause_flags) )
             {
                 vcpu_unpause(v);
                 avail_req--;
-                ved->blocked--;
-                ved->last_vcpu_wake_up = k;
+                impl->blocked--;
+                impl->last_vcpu_wake_up = k;
             }
         }
     }
@@ -199,92 +199,90 @@ static void vm_event_wake_blocked(struct vm_event_domain *ved)
  * was unable to do so, it is queued on a wait queue.  These are woken as
  * needed, and take precedence over the blocked vCPUs.
  */
-static void vm_event_wake_queued(struct vm_event_domain *ved)
+static void vm_event_ring_wake_queued(struct vm_event_ring_domain *impl)
 {
-    unsigned int avail_req = vm_event_ring_available(ved);
+    unsigned int avail_req = vm_event_ring_available(impl);
 
     if ( avail_req > 0 )
-        wake_up_nr(&ved->wq, avail_req);
+        wake_up_nr(&impl->wq, avail_req);
 }
 
 /*
- * vm_event_wake() will wakeup all vcpus waiting for the ring to
+ * vm_event_ring_wake() will wakeup all vcpus waiting for the ring to
  * become available.  If we have queued vCPUs, they get top priority. We
  * are guaranteed that they will go through code paths that will eventually
- * call vm_event_wake() again, ensuring that any blocked vCPUs will get
+ * call vm_event_ring_wake() again, ensuring that any blocked vCPUs will get
  * unpaused once all the queued vCPUs have made it through.
  */
-void vm_event_wake(struct vm_event_domain *ved)
+static void vm_event_ring_wake(struct vm_event_ring_domain *impl)
 {
-    if (!list_empty(&ved->wq.list))
-        vm_event_wake_queued(ved);
+    if ( !list_empty(&impl->wq.list) )
+        vm_event_ring_wake_queued(impl);
     else
-        vm_event_wake_blocked(ved);
+        vm_event_ring_wake_blocked(impl);
 }
 
-static int vm_event_disable(struct domain *d, struct vm_event_domain **ved)
+static int vm_event_ring_disable(struct vm_event_domain **_ved)
 {
-    if ( vm_event_check(*ved) )
-    {
-        struct vcpu *v;
+    struct vcpu *v;
+    struct domain *d = (*_ved)->d;
+    struct vm_event_ring_domain *impl = to_ring(*_ved);
 
-        vm_event_ring_lock(*ved);
+    spin_lock(&(*_ved)->lock);
 
-        if ( !list_empty(&(*ved)->wq.list) )
-        {
-            vm_event_ring_unlock(*ved);
-            return -EBUSY;
-        }
+    if ( !list_empty(&impl->wq.list) )
+    {
+        spin_unlock(&(*_ved)->lock);
+        return -EBUSY;
+    }
 
-        /* Free domU's event channel and leave the other one unbound */
-        free_xen_event_channel(d, (*ved)->xen_port);
+    /* Free domU's event channel and leave the other one unbound */
+    free_xen_event_channel(d, impl->xen_port);
 
-        /* Unblock all vCPUs */
-        for_each_vcpu ( d, v )
+    /* Unblock all vCPUs */
+    for_each_vcpu ( d, v )
+    {
+        if ( test_and_clear_bit((*_ved)->pause_flag, &v->pause_flags) )
         {
-            if ( test_and_clear_bit((*ved)->pause_flag, &v->pause_flags) )
-            {
-                vcpu_unpause(v);
-                (*ved)->blocked--;
-            }
+            vcpu_unpause(v);
+            impl->blocked--;
         }
+    }
 
-        destroy_ring_for_helper(&(*ved)->ring_page,
-                                (*ved)->ring_pg_struct);
-
-        vm_event_cleanup_domain(d);
+    destroy_ring_for_helper(&impl->ring_page,
+                            impl->ring_pg_struct);
 
-        vm_event_ring_unlock(*ved);
-    }
+    vm_event_cleanup_domain(d);
 
-    xfree(*ved);
-    *ved = NULL;
+    spin_unlock(&(*_ved)->lock);
 
+    XFREE(*_ved);
     return 0;
 }
 
-static inline void vm_event_release_slot(struct vm_event_domain *ved)
+static inline void vm_event_ring_release_slot(struct vm_event_ring_domain *impl)
 {
     /* Update the accounting */
-    if ( current->domain == ved->d )
-        ved->target_producers--;
+    if ( current->domain == impl->ved.d )
+        impl->target_producers--;
     else
-        ved->foreign_producers--;
+        impl->foreign_producers--;
 
     /* Kick any waiters */
-    vm_event_wake(ved);
+    vm_event_ring_wake(impl);
 }
 
 /*
- * vm_event_mark_and_pause() tags vcpu and put it to sleep.
- * The vcpu will resume execution in vm_event_wake_blocked().
+ * vm_event_ring_mark_and_pause() tags vcpu and put it to sleep.
+ * The vcpu will resume execution in vm_event_ring_wake_blocked().
  */
-static void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
+static void vm_event_ring_mark_and_pause(struct vcpu *v,
+                                         struct vm_event_ring_domain *impl)
 {
-    if ( !test_and_set_bit(ved->pause_flag, &v->pause_flags) )
+    if ( !test_and_set_bit(impl->ved.pause_flag, &v->pause_flags) )
     {
         vcpu_pause_nosync(v);
-        ved->blocked++;
+        impl->blocked++;
     }
 }
 
@@ -294,35 +292,32 @@ static void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
  * overly full and its continued execution would cause stalling and excessive
  * waiting.  The vCPU will be automatically unpaused when the ring clears.
  */
-void vm_event_put_request(struct vm_event_domain *ved,
-                          vm_event_request_t *req)
+static void vm_event_ring_put_request(struct vm_event_domain *ved,
+                                      vm_event_request_t *req)
 {
     vm_event_front_ring_t *front_ring;
     int free_req;
     unsigned int avail_req;
     RING_IDX req_prod;
     struct vcpu *curr = current;
-    struct domain *d = ved->d;
-
-    if( !vm_event_check(ved))
-        return;
+    struct vm_event_ring_domain *impl = to_ring(ved);
 
-    if ( curr->domain != d )
+    if ( curr->domain != ved->d )
     {
         req->flags |= VM_EVENT_FLAG_FOREIGN;
 #ifndef NDEBUG
         if ( !(req->flags & VM_EVENT_FLAG_VCPU_PAUSED) )
             gdprintk(XENLOG_G_WARNING, "d%dv%d was not paused.\n",
-                     d->domain_id, req->vcpu_id);
+                     ved->d->domain_id, req->vcpu_id);
 #endif
     }
 
     req->version = VM_EVENT_INTERFACE_VERSION;
 
-    vm_event_ring_lock(ved);
+    spin_lock(&impl->ved.lock);
 
     /* Due to the reservations, this step must succeed. */
-    front_ring = &ved->front_ring;
+    front_ring = &impl->front_ring;
     free_req = RING_FREE_REQUESTS(front_ring);
     ASSERT(free_req > 0);
 
@@ -336,35 +331,35 @@ void vm_event_put_request(struct vm_event_domain *ved,
     RING_PUSH_REQUESTS(front_ring);
 
     /* We've actually *used* our reservation, so release the slot. */
-    vm_event_release_slot(ved);
+    vm_event_ring_release_slot(impl);
 
     /* Give this vCPU a black eye if necessary, on the way out.
      * See the comments above wake_blocked() for more information
      * on how this mechanism works to avoid waiting. */
-    avail_req = vm_event_ring_available(ved);
-    if( curr->domain == d && avail_req < d->max_vcpus &&
+    avail_req = vm_event_ring_available(impl);
+    if( curr->domain == ved->d && avail_req < ved->d->max_vcpus &&
         !atomic_read(&curr->vm_event_pause_count) )
-        vm_event_mark_and_pause(curr, ved);
+        vm_event_ring_mark_and_pause(curr, impl);
 
-    vm_event_ring_unlock(ved);
+    spin_unlock(&impl->ved.lock);
 
-    notify_via_xen_event_channel(d, ved->xen_port);
+    notify_via_xen_event_channel(ved->d, impl->xen_port);
 }
 
-static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
-                                 vm_event_response_t *rsp)
+static int vm_event_ring_get_response(struct vm_event_ring_domain *impl,
+                                      vm_event_response_t *rsp)
 {
     vm_event_front_ring_t *front_ring;
     RING_IDX rsp_cons;
 
-    vm_event_ring_lock(ved);
+    spin_lock(&impl->ved.lock);
 
-    front_ring = &ved->front_ring;
+    front_ring = &impl->front_ring;
     rsp_cons = front_ring->rsp_cons;
 
     if ( !RING_HAS_UNCONSUMED_RESPONSES(front_ring) )
     {
-        vm_event_ring_unlock(ved);
+        spin_unlock(&impl->ved.lock);
         return 0;
     }
 
@@ -378,9 +373,9 @@ static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
 
     /* Kick any waiters -- since we've just consumed an event,
      * there may be additional space available in the ring. */
-    vm_event_wake(ved);
+    vm_event_ring_wake(impl);
 
-    vm_event_ring_unlock(ved);
+    spin_unlock(&impl->ved.lock);
 
     return 1;
 }
@@ -393,10 +388,13 @@ static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
  * Note: responses are handled the same way regardless of which ring they
  * arrive on.
  */
-static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
+static int vm_event_ring_resume(struct vm_event_ring_domain *impl)
 {
     vm_event_response_t rsp;
 
+    if ( unlikely(!impl || !vm_event_check(&impl->ved)) )
+         return -ENODEV;
+
     /*
      * vm_event_resume() runs in either XEN_VM_EVENT_* domctls, or
      * EVTCHN_send context from the introspection consumer. Both contexts
@@ -405,13 +403,10 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
      * below, this covers the case where we would need to iterate over all
      * of them more succintly.
      */
-    ASSERT(d != current->domain);
-
-    if ( unlikely(!vm_event_check(ved)) )
-         return -ENODEV;
+    ASSERT(impl->ved.d != current->domain);
 
     /* Pull all responses off the ring. */
-    while ( vm_event_get_response(d, ved, &rsp) )
+    while ( vm_event_ring_get_response(impl, &rsp) )
     {
         struct vcpu *v;
 
@@ -422,10 +417,11 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
         }
 
         /* Validate the vcpu_id in the response. */
-        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
+        if ( (rsp.vcpu_id >= impl->ved.d->max_vcpus) ||
+              !impl->ved.d->vcpu[rsp.vcpu_id] )
             continue;
 
-        v = d->vcpu[rsp.vcpu_id];
+        v = impl->ved.d->vcpu[rsp.vcpu_id];
 
         /*
          * In some cases the response type needs extra handling, so here
@@ -437,7 +433,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
         {
 #ifdef CONFIG_HAS_MEM_PAGING
             if ( rsp.reason == VM_EVENT_REASON_MEM_PAGING )
-                p2m_mem_paging_resume(d, &rsp);
+                p2m_mem_paging_resume(impl->ved.d, &rsp);
 #endif
 
             /*
@@ -457,7 +453,7 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
              * Check in arch-specific handler to avoid bitmask overhead when
              * not supported.
              */
-            vm_event_toggle_singlestep(d, v, &rsp);
+            vm_event_toggle_singlestep(impl->ved.d, v, &rsp);
 
             /* Check for altp2m switch */
             if ( rsp.flags & VM_EVENT_FLAG_ALTERNATE_P2M )
@@ -477,66 +473,63 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
     return 0;
 }
 
-void vm_event_cancel_slot(struct vm_event_domain *ved)
+static void vm_event_ring_cancel_slot(struct vm_event_domain *ved)
 {
-    if( !vm_event_check(ved) )
-        return;
-
-    vm_event_ring_lock(ved);
-    vm_event_release_slot(ved);
-    vm_event_ring_unlock(ved);
+    spin_lock(&ved->lock);
+    vm_event_ring_release_slot(to_ring(ved));
+    spin_unlock(&ved->lock);
 }
 
-static int vm_event_grab_slot(struct vm_event_domain *ved, int foreign)
+static int vm_event_ring_grab_slot(struct vm_event_ring_domain *impl, int foreign)
 {
     unsigned int avail_req;
 
-    if ( !ved->ring_page )
+    if ( !impl->ring_page )
         return -EOPNOTSUPP;
 
-    vm_event_ring_lock(ved);
+    spin_lock(&impl->ved.lock);
 
-    avail_req = vm_event_ring_available(ved);
+    avail_req = vm_event_ring_available(impl);
     if ( avail_req == 0 )
     {
-        vm_event_ring_unlock(ved);
+        spin_unlock(&impl->ved.lock);
         return -EBUSY;
     }
 
     if ( !foreign )
-        ved->target_producers++;
+        impl->target_producers++;
     else
-        ved->foreign_producers++;
+        impl->foreign_producers++;
 
-    vm_event_ring_unlock(ved);
+    spin_unlock(&impl->ved.lock);
 
     return 0;
 }
 
 /* Simple try_grab wrapper for use in the wait_event() macro. */
-static int vm_event_wait_try_grab(struct vm_event_domain *ved, int *rc)
+static int vm_event_ring_wait_try_grab(struct vm_event_ring_domain *impl, int *rc)
 {
-    *rc = vm_event_grab_slot(ved, 0);
+    *rc = vm_event_ring_grab_slot(impl, 0);
     return *rc;
 }
 
-/* Call vm_event_grab_slot() until the ring doesn't exist, or is available. */
-static int vm_event_wait_slot(struct vm_event_domain *ved)
+/* Call vm_event_ring_grab_slot() until the ring doesn't exist, or is available. */
+static int vm_event_ring_wait_slot(struct vm_event_ring_domain *impl)
 {
     int rc = -EBUSY;
-    wait_event(ved->wq, vm_event_wait_try_grab(ved, &rc) != -EBUSY);
+    wait_event(impl->wq, vm_event_ring_wait_try_grab(impl, &rc) != -EBUSY);
     return rc;
 }
 
-bool vm_event_check(struct vm_event_domain *ved)
+static bool vm_event_ring_check(struct vm_event_domain *ved)
 {
-    return (ved && ved->ring_page);
+    return ( to_ring(ved)->ring_page != NULL );
 }
 
 /*
  * Determines whether or not the current vCPU belongs to the target domain,
  * and calls the appropriate wait function.  If it is a guest vCPU, then we
- * use vm_event_wait_slot() to reserve a slot.  As long as there is a ring,
+ * use vm_event_ring_wait_slot() to reserve a slot.  As long as there is a ring,
  * this function will always return 0 for a guest.  For a non-guest, we check
  * for space and return -EBUSY if the ring is not available.
  *
@@ -545,36 +538,33 @@ bool vm_event_check(struct vm_event_domain *ved)
  *               0: a spot has been reserved
  *
  */
-int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep)
+static int vm_event_ring_claim_slot(struct vm_event_domain *ved, bool allow_sleep)
 {
-    if ( !vm_event_check(ved) )
-        return -EOPNOTSUPP;
-
     if ( (current->domain == ved->d) && allow_sleep )
-        return vm_event_wait_slot(ved);
+        return vm_event_ring_wait_slot(to_ring(ved));
     else
-        return vm_event_grab_slot(ved, (current->domain != ved->d));
+        return vm_event_ring_grab_slot(to_ring(ved), (current->domain != ved->d));
 }
 
 #ifdef CONFIG_HAS_MEM_PAGING
 /* Registered with Xen-bound event channel for incoming notifications. */
 static void mem_paging_notification(struct vcpu *v, unsigned int port)
 {
-    vm_event_resume(v->domain, v->domain->vm_event_paging);
+    vm_event_ring_resume(to_ring(v->domain->vm_event_paging));
 }
 #endif
 
 /* Registered with Xen-bound event channel for incoming notifications. */
 static void monitor_notification(struct vcpu *v, unsigned int port)
 {
-    vm_event_resume(v->domain, v->domain->vm_event_monitor);
+    vm_event_ring_resume(to_ring(v->domain->vm_event_monitor));
 }
 
 #ifdef CONFIG_HAS_MEM_SHARING
 /* Registered with Xen-bound event channel for incoming notifications. */
 static void mem_sharing_notification(struct vcpu *v, unsigned int port)
 {
-    vm_event_resume(v->domain, v->domain->vm_event_share);
+    vm_event_ring_resume(to_ring(v->domain->vm_event_share));
 }
 #endif
 
@@ -583,32 +573,32 @@ void vm_event_cleanup(struct domain *d)
 {
 #ifdef CONFIG_HAS_MEM_PAGING
     if ( vm_event_check(d->vm_event_paging) )
-    {
-        /* Destroying the wait queue head means waking up all
-         * queued vcpus. This will drain the list, allowing
-         * the disable routine to complete. It will also drop
-         * all domain refs the wait-queued vcpus are holding.
-         * Finally, because this code path involves previously
-         * pausing the domain (domain_kill), unpausing the
-         * vcpus causes no harm. */
-        destroy_waitqueue_head(&d->vm_event_paging->wq);
-        (void)vm_event_disable(d, &d->vm_event_paging);
-    }
+        d->vm_event_paging->ops->cleanup(&d->vm_event_paging);
 #endif
+
     if ( vm_event_check(d->vm_event_monitor) )
-    {
-        destroy_waitqueue_head(&d->vm_event_monitor->wq);
-        (void)vm_event_disable(d, &d->vm_event_monitor);
-    }
+        d->vm_event_monitor->ops->cleanup(&d->vm_event_monitor);
+
 #ifdef CONFIG_HAS_MEM_SHARING
     if ( vm_event_check(d->vm_event_share) )
-    {
-        destroy_waitqueue_head(&d->vm_event_share->wq);
-        (void)vm_event_disable(d, &d->vm_event_share);
-    }
+        d->vm_event_share->ops->cleanup(&d->vm_event_share);
 #endif
 }
 
+static void vm_event_ring_cleanup(struct vm_event_domain **_ved)
+{
+    struct vm_event_ring_domain *impl = to_ring(*_ved);
+    /* Destroying the wait queue head means waking up all
+     * queued vcpus. This will drain the list, allowing
+     * the disable routine to complete. It will also drop
+     * all domain refs the wait-queued vcpus are holding.
+     * Finally, because this code path involves previously
+     * pausing the domain (domain_kill), unpausing the
+     * vcpus causes no harm. */
+    destroy_waitqueue_head(&impl->wq);
+    (void)vm_event_ring_disable(_ved);
+}
+
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                     XEN_GUEST_HANDLE_PARAM(void) u_domctl)
 {
@@ -682,23 +672,22 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                 break;
 
             /* domain_pause() not required here, see XSA-99 */
-            rc = vm_event_enable(d, vec, &d->vm_event_paging, _VPF_mem_paging,
+            rc = vm_event_ring_enable(d, vec, &d->vm_event_paging, _VPF_mem_paging,
                                  HVM_PARAM_PAGING_RING_PFN,
                                  mem_paging_notification);
         }
         break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check(d->vm_event_paging) )
-            {
-                domain_pause(d);
-                rc = vm_event_disable(d, &d->vm_event_paging);
-                domain_unpause(d);
-            }
+            if ( !vm_event_check(d->vm_event_paging) )
+                break;
+            domain_pause(d);
+            rc = vm_event_ring_disable(&d->vm_event_paging);
+            domain_unpause(d);
             break;
 
         case XEN_VM_EVENT_RESUME:
-            rc = vm_event_resume(d, d->vm_event_paging);
+            rc = vm_event_ring_resume(to_ring(d->vm_event_paging));
             break;
 
         default:
@@ -720,23 +709,22 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
             rc = arch_monitor_init_domain(d);
             if ( rc )
                 break;
-            rc = vm_event_enable(d, vec, &d->vm_event_monitor, _VPF_mem_access,
+            rc = vm_event_ring_enable(d, vec, &d->vm_event_monitor, _VPF_mem_access,
                                  HVM_PARAM_MONITOR_RING_PFN,
                                  monitor_notification);
             break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check(d->vm_event_monitor) )
-            {
-                domain_pause(d);
-                rc = vm_event_disable(d, &d->vm_event_monitor);
-                arch_monitor_cleanup_domain(d);
-                domain_unpause(d);
-            }
+            if ( !vm_event_check(d->vm_event_monitor) )
+                break;
+            domain_pause(d);
+            rc = vm_event_ring_disable(&d->vm_event_monitor);
+            arch_monitor_cleanup_domain(d);
+            domain_unpause(d);
             break;
 
         case XEN_VM_EVENT_RESUME:
-            rc = vm_event_resume(d, d->vm_event_monitor);
+            rc = vm_event_ring_resume(to_ring(d->vm_event_monitor));
             break;
 
         default:
@@ -765,22 +753,21 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                 break;
 
             /* domain_pause() not required here, see XSA-99 */
-            rc = vm_event_enable(d, vec, &d->vm_event_share, _VPF_mem_sharing,
+            rc = vm_event_ring_enable(d, vec, &d->vm_event_share, _VPF_mem_sharing,
                                  HVM_PARAM_SHARING_RING_PFN,
                                  mem_sharing_notification);
             break;
 
         case XEN_VM_EVENT_DISABLE:
-            if ( vm_event_check(d->vm_event_share) )
-            {
-                domain_pause(d);
-                rc = vm_event_disable(d, &d->vm_event_share);
-                domain_unpause(d);
-            }
+            if ( !vm_event_check(d->vm_event_share) )
+                break;
+            domain_pause(d);
+            rc = vm_event_ring_disable(&d->vm_event_share);
+            domain_unpause(d);
             break;
 
         case XEN_VM_EVENT_RESUME:
-            rc = vm_event_resume(d, d->vm_event_share);
+            rc = vm_event_ring_resume(to_ring(d->vm_event_share));
             break;
 
         default:
@@ -832,6 +819,14 @@ void vm_event_vcpu_unpause(struct vcpu *v)
     vcpu_unpause(v);
 }
 
+static const struct vm_event_ops vm_event_ring_ops = {
+    .check = vm_event_ring_check,
+    .cleanup = vm_event_ring_cleanup,
+    .claim_slot = vm_event_ring_claim_slot,
+    .cancel_slot = vm_event_ring_cancel_slot,
+    .put_request = vm_event_ring_put_request
+};
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index a5c82d6..15c15e6 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -26,11 +26,38 @@
 #include <xen/sched.h>
 #include <public/vm_event.h>
 
+struct vm_event_ops
+{
+    bool (*check)(struct vm_event_domain *ved);
+    void (*cleanup)(struct vm_event_domain **_ved);
+    int (*claim_slot)(struct vm_event_domain *ved, bool allow_sleep);
+    void (*cancel_slot)(struct vm_event_domain *ved);
+    void (*put_request)(struct vm_event_domain *ved, vm_event_request_t *req);
+};
+
+struct vm_event_domain
+{
+    /* Domain reference */
+    struct domain *d;
+
+    /* vm_event_ops */
+    const struct vm_event_ops *ops;
+
+    /* vm_event domain lock */
+    spinlock_t lock;
+
+    /* vm_event bit for vcpu->pause_flags */
+    int pause_flag;
+};
+
 /* Clean up on domain destruction */
 void vm_event_cleanup(struct domain *d);
 
 /* Returns whether the VM event domain has been set up */
-bool vm_event_check(struct vm_event_domain *ved);
+static inline bool vm_event_check(struct vm_event_domain *ved)
+{
+    return (ved) && ved->ops->check(ved);
+}
 
 /* Returns 0 on success, -ENOSYS if there is no ring, -EBUSY if there is no
  * available space and the caller is a foreign domain. If the guest itself
@@ -45,7 +72,14 @@ bool vm_event_check(struct vm_event_domain *ved);
  * cancel_slot(), both of which are guaranteed to
  * succeed.
  */
-int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep);
+static inline int __vm_event_claim_slot(struct vm_event_domain *ved, bool allow_sleep)
+{
+    if ( !vm_event_check(ved) )
+        return -EOPNOTSUPP;
+
+    return ved->ops->claim_slot(ved, allow_sleep);
+}
+
 static inline int vm_event_claim_slot(struct vm_event_domain *ved)
 {
     return __vm_event_claim_slot(ved, true);
@@ -56,10 +90,22 @@ static inline int vm_event_claim_slot_nosleep(struct vm_event_domain *ved)
     return __vm_event_claim_slot(ved, false);
 }
 
-void vm_event_cancel_slot(struct vm_event_domain *ved);
+static inline void vm_event_cancel_slot(struct vm_event_domain *ved)
+{
+    if ( !vm_event_check(ved) )
+        return;
 
-void vm_event_put_request(struct vm_event_domain *ved,
-                          vm_event_request_t *req);
+    ved->ops->cancel_slot(ved);
+}
+
+static inline void vm_event_put_request(struct vm_event_domain *ved,
+                                        vm_event_request_t *req)
+{
+    if ( !vm_event_check(ved) )
+        return;
+
+    ved->ops->put_request(ved, req);
+}
 
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                     XEN_GUEST_HANDLE_PARAM(void) u_domctl);
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 8/9] vm_event: Add vm_event_ng interface
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Tamas K Lengyel, Jan Beulich,
	Roger Pau Monné

In high throughput introspection scenarios where lots of monitor
vm_events are generated, the ring buffer can fill up before the monitor
application gets a chance to handle all the requests thus blocking
other vcpus which will have to wait for a slot to become available.

This patch adds support for a different mechanism to handle synchronous
vm_event requests / responses. As each synchronous request pauses the
vcpu until the corresponding response is handled, it can be stored in
a slotted memory buffer (one per vcpu) shared between the hypervisor and
the controlling domain.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 tools/libxc/include/xenctrl.h |   6 +
 tools/libxc/xc_monitor.c      |  15 ++
 tools/libxc/xc_private.h      |   8 +
 tools/libxc/xc_vm_event.c     |  53 +++++
 xen/arch/x86/mm.c             |   5 +
 xen/common/Makefile           |   1 +
 xen/common/domctl.c           |   7 +
 xen/common/vm_event.c         |  94 ++++-----
 xen/common/vm_event_ng.c      | 449 ++++++++++++++++++++++++++++++++++++++++++
 xen/include/public/domctl.h   |  20 ++
 xen/include/public/memory.h   |   2 +
 xen/include/public/vm_event.h |  16 ++
 xen/include/xen/vm_event.h    |  10 +
 13 files changed, 642 insertions(+), 44 deletions(-)
 create mode 100644 xen/common/vm_event_ng.c

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 943b933..c36b623 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1993,6 +1993,7 @@ int xc_get_mem_access(xc_interface *xch, uint32_t domain_id,
  * Returns the VM_EVENT_INTERFACE version.
  */
 int xc_vm_event_get_version(xc_interface *xch);
+int xc_vm_event_ng_get_version(xc_interface *xch);
 
 /***
  * Monitor control operations.
@@ -2007,6 +2008,11 @@ int xc_vm_event_get_version(xc_interface *xch);
 void *xc_monitor_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port);
 int xc_monitor_disable(xc_interface *xch, uint32_t domain_id);
 int xc_monitor_resume(xc_interface *xch, uint32_t domain_id);
+
+/* Monitor NG interface */
+int xc_monitor_ng_create(xc_interface *xch, uint32_t domain_id);
+int xc_monitor_ng_destroy(xc_interface *xch, uint32_t domain_id);
+int xc_monitor_ng_set_state(xc_interface *xch, uint32_t domain_id, bool enabled);
 /*
  * Get a bitmap of supported monitor events in the form
  * (1 << XEN_DOMCTL_MONITOR_EVENT_*).
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index 718fe8b..4c7ef2b 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -265,6 +265,21 @@ int xc_monitor_emul_unimplemented(xc_interface *xch, uint32_t domain_id,
     return do_domctl(xch, &domctl);
 }
 
+int xc_monitor_ng_create(xc_interface *xch, uint32_t domain_id)
+{
+    return xc_vm_event_ng_create(xch, domain_id, XEN_VM_EVENT_TYPE_MONITOR);
+}
+
+int xc_monitor_ng_destroy(xc_interface *xch, uint32_t domain_id)
+{
+    return xc_vm_event_ng_destroy(xch, domain_id, XEN_VM_EVENT_TYPE_MONITOR);
+}
+
+int xc_monitor_ng_set_state(xc_interface *xch, uint32_t domain_id, bool enabled)
+{
+    return xc_vm_event_ng_set_state(xch, domain_id, XEN_VM_EVENT_TYPE_MONITOR, enabled);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index 482451c..1904a1e 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -420,6 +420,14 @@ int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
 void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int type,
                          uint32_t *port);
 
+/**
+ * VM_EVENT NG operations. Internal use only.
+ */
+int xc_vm_event_ng_create(xc_interface *xch, uint32_t domain_id, int type);
+int xc_vm_event_ng_destroy(xc_interface *xch, uint32_t domain_id, int type);
+int xc_vm_event_ng_set_state(xc_interface *xch, uint32_t domain_id, int type, bool enabled);
+
+
 int do_dm_op(xc_interface *xch, uint32_t domid, unsigned int nr_bufs, ...);
 
 #endif /* __XC_PRIVATE_H__ */
diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
index 3b1018b..07243a6 100644
--- a/tools/libxc/xc_vm_event.c
+++ b/tools/libxc/xc_vm_event.c
@@ -154,6 +154,59 @@ int xc_vm_event_get_version(xc_interface *xch)
     return rc;
 }
 
+int xc_vm_event_ng_get_version(xc_interface *xch)
+{
+    DECLARE_DOMCTL;
+    int rc;
+
+    domctl.cmd = XEN_DOMCTL_vm_event_ng_op;
+    domctl.domain = DOMID_INVALID;
+    domctl.u.vm_event_op.op = XEN_VM_EVENT_NG_GET_VERSION;
+    domctl.u.vm_event_op.type = XEN_VM_EVENT_TYPE_MONITOR;
+
+    rc = do_domctl(xch, &domctl);
+    if ( !rc )
+        rc = domctl.u.vm_event_ng_op.u.version;
+    return rc;
+}
+
+int xc_vm_event_ng_create(xc_interface *xch, uint32_t domain_id, int type)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_vm_event_ng_op;
+    domctl.domain = domain_id;
+    domctl.u.vm_event_ng_op.op = XEN_VM_EVENT_NG_CREATE;
+    domctl.u.vm_event_ng_op.type = type;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_vm_event_ng_destroy(xc_interface *xch, uint32_t domain_id, int type)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_vm_event_ng_op;
+    domctl.domain = domain_id;
+    domctl.u.vm_event_ng_op.op = XEN_VM_EVENT_NG_DESTROY;
+    domctl.u.vm_event_ng_op.type = type;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_vm_event_ng_set_state(xc_interface *xch, uint32_t domain_id, int type, bool enabled)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_vm_event_ng_op;
+    domctl.domain = domain_id;
+    domctl.u.vm_event_ng_op.op = XEN_VM_EVENT_NG_SET_STATE;
+    domctl.u.vm_event_ng_op.type = type;
+    domctl.u.vm_event_ng_op.u.enabled = enabled;
+
+    return do_domctl(xch, &domctl);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 2f620d9..030b5bd 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -119,6 +119,7 @@
 #include <xen/efi.h>
 #include <xen/grant_table.h>
 #include <xen/hypercall.h>
+#include <xen/vm_event.h>
 #include <asm/paging.h>
 #include <asm/shadow.h>
 #include <asm/page.h>
@@ -4584,6 +4585,10 @@ int arch_acquire_resource(struct domain *d, unsigned int type,
     }
 #endif
 
+    case XENMEM_resource_vm_event:
+        rc = vm_event_ng_get_frames(d, id, frame, nr_frames, mfn_list);
+        break;
+
     default:
         rc = -EOPNOTSUPP;
         break;
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 33d03b8..8cb33e2 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -59,6 +59,7 @@ obj-y += trace.o
 obj-y += version.o
 obj-y += virtual_region.o
 obj-y += vm_event.o
+obj-y += vm_event_ng.o
 obj-y += vmap.o
 obj-y += vsprintf.o
 obj-y += wait.o
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index bade9a6..23f6e56 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -393,6 +393,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
     {
     case XEN_DOMCTL_test_assign_device:
     case XEN_DOMCTL_vm_event_op:
+    case XEN_DOMCTL_vm_event_ng_op:
         if ( op->domain == DOMID_INVALID )
         {
     case XEN_DOMCTL_createdomain:
@@ -1023,6 +1024,12 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
         copyback = 1;
         break;
 
+    case XEN_DOMCTL_vm_event_ng_op:
+        ret = vm_event_ng_domctl(d, &op->u.vm_event_ng_op,
+                                 guest_handle_cast(u_domctl, void));
+        copyback = 1;
+        break;
+
 #ifdef CONFIG_MEM_ACCESS
     case XEN_DOMCTL_set_access_required:
         if ( unlikely(current->domain == d) ) /* no domain_pause() */
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 1d85f3e..e94fe3c 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -380,6 +380,51 @@ static int vm_event_ring_get_response(struct vm_event_ring_domain *impl,
     return 1;
 }
 
+void vm_event_handle_response(struct domain *d, struct vcpu *v,
+                              vm_event_response_t *rsp)
+{
+    /* Check flags which apply only when the vCPU is paused */
+    if ( atomic_read(&v->vm_event_pause_count) )
+    {
+#ifdef CONFIG_HAS_MEM_PAGING
+        if ( rsp->reason == VM_EVENT_REASON_MEM_PAGING )
+            p2m_mem_paging_resume(d, rsp);
+#endif
+
+        /*
+         * Check emulation flags in the arch-specific handler only, as it
+         * has to set arch-specific flags when supported, and to avoid
+         * bitmask overhead when it isn't supported.
+         */
+        vm_event_emulate_check(v, rsp);
+
+        /*
+         * Check in arch-specific handler to avoid bitmask overhead when
+         * not supported.
+         */
+        vm_event_register_write_resume(v, rsp);
+
+        /*
+         * Check in arch-specific handler to avoid bitmask overhead when
+         * not supported.
+         */
+        vm_event_toggle_singlestep(d, v, rsp);
+
+        /* Check for altp2m switch */
+        if ( rsp->flags & VM_EVENT_FLAG_ALTERNATE_P2M )
+            p2m_altp2m_check(v, rsp->altp2m_idx);
+
+        if ( rsp->flags & VM_EVENT_FLAG_SET_REGISTERS )
+            vm_event_set_registers(v, rsp);
+
+        if ( rsp->flags & VM_EVENT_FLAG_GET_NEXT_INTERRUPT )
+            vm_event_monitor_next_interrupt(v);
+
+        if ( rsp->flags & VM_EVENT_FLAG_VCPU_PAUSED )
+            vm_event_vcpu_unpause(v);
+    }
+}
+
 /*
  * Pull all responses from the given ring and unpause the corresponding vCPU
  * if required. Based on the response type, here we can also call custom
@@ -427,47 +472,7 @@ static int vm_event_ring_resume(struct vm_event_ring_domain *impl)
          * In some cases the response type needs extra handling, so here
          * we call the appropriate handlers.
          */
-
-        /* Check flags which apply only when the vCPU is paused */
-        if ( atomic_read(&v->vm_event_pause_count) )
-        {
-#ifdef CONFIG_HAS_MEM_PAGING
-            if ( rsp.reason == VM_EVENT_REASON_MEM_PAGING )
-                p2m_mem_paging_resume(impl->ved.d, &rsp);
-#endif
-
-            /*
-             * Check emulation flags in the arch-specific handler only, as it
-             * has to set arch-specific flags when supported, and to avoid
-             * bitmask overhead when it isn't supported.
-             */
-            vm_event_emulate_check(v, &rsp);
-
-            /*
-             * Check in arch-specific handler to avoid bitmask overhead when
-             * not supported.
-             */
-            vm_event_register_write_resume(v, &rsp);
-
-            /*
-             * Check in arch-specific handler to avoid bitmask overhead when
-             * not supported.
-             */
-            vm_event_toggle_singlestep(impl->ved.d, v, &rsp);
-
-            /* Check for altp2m switch */
-            if ( rsp.flags & VM_EVENT_FLAG_ALTERNATE_P2M )
-                p2m_altp2m_check(v, rsp.altp2m_idx);
-
-            if ( rsp.flags & VM_EVENT_FLAG_SET_REGISTERS )
-                vm_event_set_registers(v, &rsp);
-
-            if ( rsp.flags & VM_EVENT_FLAG_GET_NEXT_INTERRUPT )
-                vm_event_monitor_next_interrupt(v);
-
-            if ( rsp.flags & VM_EVENT_FLAG_VCPU_PAUSED )
-                vm_event_vcpu_unpause(v);
-        }
+        vm_event_handle_response(impl->ved.d, v, &rsp);
     }
 
     return 0;
@@ -709,9 +714,10 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
             rc = arch_monitor_init_domain(d);
             if ( rc )
                 break;
-            rc = vm_event_ring_enable(d, vec, &d->vm_event_monitor, _VPF_mem_access,
-                                 HVM_PARAM_MONITOR_RING_PFN,
-                                 monitor_notification);
+            rc = vm_event_ring_enable(d, vec, &d->vm_event_monitor,
+                                      _VPF_mem_access,
+                                      HVM_PARAM_MONITOR_RING_PFN,
+                                      monitor_notification);
             break;
 
         case XEN_VM_EVENT_DISABLE:
diff --git a/xen/common/vm_event_ng.c b/xen/common/vm_event_ng.c
new file mode 100644
index 0000000..17ae33c
--- /dev/null
+++ b/xen/common/vm_event_ng.c
@@ -0,0 +1,449 @@
+/******************************************************************************
+ * vm_event_ng.c
+ *
+ * VM event support (new generation).
+ *
+ * Copyright (c) 2019, Bitdefender S.R.L.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/vm_event.h>
+#include <xen/vmap.h>
+#include <asm/monitor.h>
+#include <asm/vm_event.h>
+#include <xsm/xsm.h>
+
+#define to_channels(_ved) container_of((_ved), \
+                                        struct vm_event_channels_domain, ved)
+
+#define VM_EVENT_CHANNELS_ENABLED       1
+
+struct vm_event_channels_domain
+{
+    /* VM event domain */
+    struct vm_event_domain ved;
+    /* shared channels buffer */
+    struct vm_event_slot *slots;
+    /* the buffer size (number of frames) */
+    unsigned int nr_frames;
+    /* state */
+    bool enabled;
+    /* buffer's mnf list */
+    mfn_t mfn[0];
+};
+
+static const struct vm_event_ops vm_event_channels_ops;
+
+static int vm_event_channels_alloc_buffer(struct vm_event_channels_domain *impl)
+{
+    int i, rc = -ENOMEM;
+
+    for ( i = 0; i < impl->nr_frames; i++ )
+    {
+        struct page_info *page = alloc_domheap_page(impl->ved.d, 0);
+        if ( !page )
+            goto err;
+
+        if ( !get_page_and_type(page, impl->ved.d, PGT_writable_page) )
+        {
+            rc = -ENODATA;
+            goto err;
+        }
+
+        impl->mfn[i] = page_to_mfn(page);
+    }
+
+    impl->slots = (struct vm_event_slot *)vmap(impl->mfn, impl->nr_frames);
+    if ( !impl->slots )
+        goto err;
+
+    for ( i = 0; i < impl->nr_frames; i++ )
+        clear_page((void*)impl->slots + i * PAGE_SIZE);
+
+    return 0;
+
+err:
+    while ( --i >= 0 )
+    {
+        struct page_info *page = mfn_to_page(impl->mfn[i]);
+
+        if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
+            put_page(page);
+        put_page_and_type(page);
+    }
+
+    return rc;
+}
+
+static void vm_event_channels_free_buffer(struct vm_event_channels_domain *impl)
+{
+    int i;
+
+    ASSERT(impl);
+
+    if ( !impl->slots )
+        return;
+
+    vunmap(impl->slots);
+
+    for ( i = 0; i < impl->nr_frames; i++ )
+    {
+        struct page_info *page = mfn_to_page(impl->mfn[i]);
+
+        ASSERT(page);
+        if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
+            put_page(page);
+        put_page_and_type(page);
+    }
+}
+
+static int vm_event_channels_create(
+    struct domain *d,
+    struct xen_domctl_vm_event_ng_op *vec,
+    struct vm_event_domain **_ved,
+    int pause_flag,
+    xen_event_channel_notification_t notification_fn)
+{
+    int rc, i;
+    unsigned int nr_frames = PFN_UP(d->max_vcpus * sizeof(struct vm_event_slot));
+    struct vm_event_channels_domain *impl;
+
+    if ( *_ved )
+        return -EBUSY;
+
+    impl = _xzalloc(sizeof(struct vm_event_channels_domain) +
+                           nr_frames * sizeof(mfn_t),
+                    __alignof__(struct vm_event_channels_domain));
+    if ( unlikely(!impl) )
+        return -ENOMEM;
+
+    spin_lock_init(&impl->ved.lock);
+    spin_lock(&impl->ved.lock);
+
+    impl->nr_frames = nr_frames;
+    impl->ved.d = d;
+    impl->ved.ops = &vm_event_channels_ops;
+
+    rc = vm_event_init_domain(d);
+    if ( rc < 0 )
+        goto err;
+
+    rc = vm_event_channels_alloc_buffer(impl);
+    if ( rc )
+        goto err;
+
+    for ( i = 0; i < d->max_vcpus; i++ )
+    {
+        rc = alloc_unbound_xen_event_channel(d, i, current->domain->domain_id,
+                                             notification_fn);
+        if ( rc < 0 )
+            goto err;
+
+        impl->slots[i].port = rc;
+        impl->slots[i].state = STATE_VM_EVENT_SLOT_IDLE;
+    }
+
+    impl->enabled = false;
+
+    spin_unlock(&impl->ved.lock);
+    *_ved = &impl->ved;
+    return 0;
+
+err:
+    spin_unlock(&impl->ved.lock);
+    XFREE(impl);
+    return rc;
+}
+
+static int vm_event_channels_destroy(struct vm_event_domain **_ved)
+{
+    struct vcpu *v;
+    struct vm_event_channels_domain *impl = to_channels(*_ved);
+    int i;
+
+    spin_lock(&(*_ved)->lock);
+
+    for_each_vcpu( (*_ved)->d, v )
+    {
+        if ( atomic_read(&v->vm_event_pause_count) )
+            vm_event_vcpu_unpause(v);
+    }
+
+    for ( i = 0; i < (*_ved)->d->max_vcpus; i++ )
+        evtchn_close((*_ved)->d, impl->slots[i].port, 0);
+
+    vm_event_channels_free_buffer(impl);
+    spin_unlock(&(*_ved)->lock);
+    XFREE(*_ved);
+
+    return 0;
+}
+
+static bool vm_event_channels_check(struct vm_event_domain *ved)
+{
+    return to_channels(ved)->slots != NULL;
+}
+
+static void vm_event_channels_cleanup(struct vm_event_domain **_ved)
+{
+    vm_event_channels_destroy(_ved);
+}
+
+static int vm_event_channels_claim_slot(struct vm_event_domain *ved,
+                                        bool allow_sleep)
+{
+    return 0;
+}
+
+static void vm_event_channels_cancel_slot(struct vm_event_domain *ved)
+{
+}
+
+static void vm_event_channels_put_request(struct vm_event_domain *ved,
+                                          vm_event_request_t *req)
+{
+    struct vm_event_channels_domain *impl = to_channels(ved);
+    struct vm_event_slot *slot;
+
+    /* exit if the vm_event_domain was not specifically enabled */
+    if ( !impl->enabled )
+        return;
+
+    ASSERT( req->vcpu_id >= 0 && req->vcpu_id < ved->d->max_vcpus );
+
+    slot = &impl->slots[req->vcpu_id];
+
+    if ( current->domain != ved->d )
+    {
+        req->flags |= VM_EVENT_FLAG_FOREIGN;
+#ifndef NDEBUG
+        if ( !(req->flags & VM_EVENT_FLAG_VCPU_PAUSED) )
+            gdprintk(XENLOG_G_WARNING, "d%dv%d was not paused.\n",
+                     ved->d->domain_id, req->vcpu_id);
+#endif
+    }
+
+    req->version = VM_EVENT_INTERFACE_VERSION;
+
+    spin_lock(&impl->ved.lock);
+    if ( slot->state != STATE_VM_EVENT_SLOT_IDLE )
+    {
+        gdprintk(XENLOG_G_WARNING, "The VM event slot for d%dv%d is not IDLE.\n",
+                 impl->ved.d->domain_id, req->vcpu_id);
+        spin_unlock(&impl->ved.lock);
+        return;
+    }
+
+    slot->u.req = *req;
+    slot->state = STATE_VM_EVENT_SLOT_SUBMIT;
+    spin_unlock(&impl->ved.lock);
+    notify_via_xen_event_channel(impl->ved.d, slot->port);
+}
+
+static int vm_event_channels_get_response(struct vm_event_channels_domain *impl,
+                                          struct vcpu *v, vm_event_response_t *rsp)
+{
+    struct vm_event_slot *slot = &impl->slots[v->vcpu_id];
+
+    ASSERT( slot != NULL );
+    spin_lock(&impl->ved.lock);
+
+    if ( slot->state != STATE_VM_EVENT_SLOT_FINISH )
+    {
+        gdprintk(XENLOG_G_WARNING, "The VM event slot state for d%dv%d is invalid.\n",
+                 impl->ved.d->domain_id, v->vcpu_id);
+        spin_unlock(&impl->ved.lock);
+        return -1;
+    }
+
+    *rsp = slot->u.rsp;
+    slot->state = STATE_VM_EVENT_SLOT_IDLE;
+
+    spin_unlock(&impl->ved.lock);
+    return 0;
+}
+
+static int vm_event_channels_resume(struct vm_event_channels_domain *impl,
+                                    struct vcpu *v)
+{
+    vm_event_response_t rsp;
+
+    if ( unlikely(!impl || !vm_event_check(&impl->ved)) )
+         return -ENODEV;
+
+    ASSERT(impl->ved.d != current->domain);
+
+    if ( vm_event_channels_get_response(impl, v, &rsp) ||
+         rsp.version != VM_EVENT_INTERFACE_VERSION ||
+         rsp.vcpu_id != v->vcpu_id )
+        return -1;
+
+    vm_event_handle_response(impl->ved.d, v, &rsp);
+
+    return 0;
+}
+
+/* Registered with Xen-bound event channel for incoming notifications. */
+static void monitor_notification(struct vcpu *v, unsigned int port)
+{
+    vm_event_channels_resume(to_channels(v->domain->vm_event_monitor), v);
+}
+
+int vm_event_ng_domctl(struct domain *d, struct xen_domctl_vm_event_ng_op *vec,
+                       XEN_GUEST_HANDLE_PARAM(void) u_domctl)
+{
+    int rc;
+
+    if ( vec->op == XEN_VM_EVENT_NG_GET_VERSION )
+    {
+        vec->u.version = VM_EVENT_INTERFACE_VERSION;
+        return 0;
+    }
+
+    if ( unlikely(d == NULL) )
+        return -ESRCH;
+
+    rc = xsm_vm_event_control(XSM_PRIV, d, vec->type, vec->op);
+    if ( rc )
+        return rc;
+
+    if ( unlikely(d == current->domain) ) /* no domain_pause() */
+    {
+        gdprintk(XENLOG_INFO, "Tried to do a memory event op on itself.\n");
+        return -EINVAL;
+    }
+
+    if ( unlikely(d->is_dying) )
+    {
+        gdprintk(XENLOG_INFO, "Ignoring memory event op on dying domain %u\n",
+                 d->domain_id);
+        return 0;
+    }
+
+    if ( unlikely(d->vcpu == NULL) || unlikely(d->vcpu[0] == NULL) )
+    {
+        gdprintk(XENLOG_INFO,
+                 "Memory event op on a domain (%u) with no vcpus\n",
+                 d->domain_id);
+        return -EINVAL;
+    }
+
+    switch ( vec->type )
+    {
+    case XEN_VM_EVENT_TYPE_MONITOR:
+    {
+        rc = -EINVAL;
+
+        switch ( vec-> op)
+        {
+        case XEN_VM_EVENT_NG_CREATE:
+            /* domain_pause() not required here, see XSA-99 */
+            rc = arch_monitor_init_domain(d);
+            if ( rc )
+                break;
+            rc = vm_event_channels_create(d, vec, &d->vm_event_monitor,
+                                     _VPF_mem_access, monitor_notification);
+            break;
+
+        case XEN_VM_EVENT_NG_DESTROY:
+            if ( !vm_event_check(d->vm_event_monitor) )
+                break;
+            domain_pause(d);
+            rc = vm_event_channels_destroy(&d->vm_event_monitor);
+            arch_monitor_cleanup_domain(d);
+            domain_unpause(d);
+            break;
+
+        case XEN_VM_EVENT_NG_SET_STATE:
+            if ( !vm_event_check(d->vm_event_monitor) )
+                break;
+            domain_pause(d);
+            to_channels(d->vm_event_monitor)->enabled = !!vec->u.enabled;
+            domain_unpause(d);
+            rc = 0;
+            break;
+
+        default:
+            rc = -ENOSYS;
+        }
+        break;
+    }
+
+#ifdef CONFIG_HAS_MEM_PAGING
+    case XEN_VM_EVENT_TYPE_PAGING:
+#endif
+
+#ifdef CONFIG_HAS_MEM_SHARING
+    case XEN_VM_EVENT_TYPE_SHARING:
+#endif
+
+    default:
+        rc = -ENOSYS;
+    }
+
+    return rc;
+}
+
+int vm_event_ng_get_frames(struct domain *d, unsigned int id,
+                           unsigned long frame, unsigned int nr_frames,
+                           xen_pfn_t mfn_list[])
+{
+    struct vm_event_domain *ved;
+    int i;
+
+    switch (id )
+    {
+    case XEN_VM_EVENT_TYPE_MONITOR:
+        ved = d->vm_event_monitor;
+        break;
+
+    default:
+        return -ENOSYS;
+    }
+
+    if ( !vm_event_check(ved) )
+        return -EINVAL;
+
+    if ( frame != 0 || nr_frames != to_channels(ved)->nr_frames )
+        return -EINVAL;
+
+    spin_lock(&ved->lock);
+
+    for ( i = 0; i < to_channels(ved)->nr_frames; i++ )
+        mfn_list[i] = mfn_x(to_channels(ved)->mfn[i]);
+
+    spin_unlock(&ved->lock);
+    return 0;
+}
+
+static const struct vm_event_ops vm_event_channels_ops = {
+    .check = vm_event_channels_check,
+    .cleanup = vm_event_channels_cleanup,
+    .claim_slot = vm_event_channels_claim_slot,
+    .cancel_slot = vm_event_channels_cancel_slot,
+    .put_request = vm_event_channels_put_request
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 19281fa..ff8b680 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -792,6 +792,24 @@ struct xen_domctl_vm_event_op {
 };
 
 /*
+ * XEN_DOMCTL_vm_event_ng_op.
+ * Next Generation vm_event operations.
+ */
+#define XEN_VM_EVENT_NG_CREATE            0
+#define XEN_VM_EVENT_NG_DESTROY           1
+#define XEN_VM_EVENT_NG_SET_STATE         2
+#define XEN_VM_EVENT_NG_GET_VERSION       3
+
+struct xen_domctl_vm_event_ng_op {
+    uint32_t        op;             /* XEN_VM_EVENT_NG_* */
+    uint32_t        type;           /* XEN_VM_EVENT_TYPE_* */
+    union {
+        uint32_t version;           /* OUT: version number */
+        uint8_t  enabled;           /* IN: state */
+    } u;
+};
+
+/*
  * Memory sharing operations
  */
 /* XEN_DOMCTL_mem_sharing_op.
@@ -1142,6 +1160,7 @@ struct xen_domctl {
 /* #define XEN_DOMCTL_set_gnttab_limits          80 - Moved into XEN_DOMCTL_createdomain */
 #define XEN_DOMCTL_vuart_op                      81
 #define XEN_DOMCTL_get_cpu_policy                82
+#define XEN_DOMCTL_vm_event_ng_op                83
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1183,6 +1202,7 @@ struct xen_domctl {
         struct xen_domctl_subscribe         subscribe;
         struct xen_domctl_debug_op          debug_op;
         struct xen_domctl_vm_event_op       vm_event_op;
+        struct xen_domctl_vm_event_ng_op    vm_event_ng_op;
         struct xen_domctl_mem_sharing_op    mem_sharing_op;
 #if defined(__i386__) || defined(__x86_64__)
         struct xen_domctl_cpuid             cpuid;
diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h
index 68ddadb..2e8912e 100644
--- a/xen/include/public/memory.h
+++ b/xen/include/public/memory.h
@@ -612,6 +612,7 @@ struct xen_mem_acquire_resource {
 
 #define XENMEM_resource_ioreq_server 0
 #define XENMEM_resource_grant_table 1
+#define XENMEM_resource_vm_event 2
 
     /*
      * IN - a type-specific resource identifier, which must be zero
@@ -619,6 +620,7 @@ struct xen_mem_acquire_resource {
      *
      * type == XENMEM_resource_ioreq_server -> id == ioreq server id
      * type == XENMEM_resource_grant_table -> id defined below
+     * type == XENMEM_resource_vm_event -> id == vm_event type
      */
     uint32_t id;
 
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index c48bc21..2f2160b 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -421,6 +421,22 @@ typedef struct vm_event_st {
 
 DEFINE_RING_TYPES(vm_event, vm_event_request_t, vm_event_response_t);
 
+/* VM Event slot state */
+#define STATE_VM_EVENT_SLOT_IDLE     0 /* the slot data is invalid */
+#define STATE_VM_EVENT_SLOT_SUBMIT   1 /* a request was submitted */
+#define STATE_VM_EVENT_SLOT_FINISH   2 /* a response was issued */
+
+struct vm_event_slot
+{
+    uint32_t port;      /* evtchn for notifications to/from helper */
+    uint32_t state:4;
+    uint32_t pad:28;
+    union {
+        vm_event_request_t req;
+        vm_event_response_t rsp;
+    } u;
+};
+
 #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */
 #endif /* _XEN_PUBLIC_VM_EVENT_H */
 
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index 15c15e6..df0aafc 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -110,6 +110,13 @@ static inline void vm_event_put_request(struct vm_event_domain *ved,
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                     XEN_GUEST_HANDLE_PARAM(void) u_domctl);
 
+int vm_event_ng_domctl(struct domain *d, struct xen_domctl_vm_event_ng_op *vec,
+                       XEN_GUEST_HANDLE_PARAM(void) u_domctl);
+
+int vm_event_ng_get_frames(struct domain *d, unsigned int id,
+                           unsigned long frame, unsigned int nr_frames,
+                           xen_pfn_t mfn_list[]);
+
 void vm_event_vcpu_pause(struct vcpu *v);
 void vm_event_vcpu_unpause(struct vcpu *v);
 
@@ -118,6 +125,9 @@ void vm_event_set_registers(struct vcpu *v, vm_event_response_t *rsp);
 
 void vm_event_monitor_next_interrupt(struct vcpu *v);
 
+void vm_event_handle_response(struct domain *d, struct vcpu *v,
+                              vm_event_response_t *rsp);
+
 #endif /* __VM_EVENT_H__ */
 
 /*
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 8/9] vm_event: Add vm_event_ng interface
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Tamas K Lengyel, Jan Beulich,
	Roger Pau Monné

In high throughput introspection scenarios where lots of monitor
vm_events are generated, the ring buffer can fill up before the monitor
application gets a chance to handle all the requests thus blocking
other vcpus which will have to wait for a slot to become available.

This patch adds support for a different mechanism to handle synchronous
vm_event requests / responses. As each synchronous request pauses the
vcpu until the corresponding response is handled, it can be stored in
a slotted memory buffer (one per vcpu) shared between the hypervisor and
the controlling domain.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
---
 tools/libxc/include/xenctrl.h |   6 +
 tools/libxc/xc_monitor.c      |  15 ++
 tools/libxc/xc_private.h      |   8 +
 tools/libxc/xc_vm_event.c     |  53 +++++
 xen/arch/x86/mm.c             |   5 +
 xen/common/Makefile           |   1 +
 xen/common/domctl.c           |   7 +
 xen/common/vm_event.c         |  94 ++++-----
 xen/common/vm_event_ng.c      | 449 ++++++++++++++++++++++++++++++++++++++++++
 xen/include/public/domctl.h   |  20 ++
 xen/include/public/memory.h   |   2 +
 xen/include/public/vm_event.h |  16 ++
 xen/include/xen/vm_event.h    |  10 +
 13 files changed, 642 insertions(+), 44 deletions(-)
 create mode 100644 xen/common/vm_event_ng.c

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 943b933..c36b623 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1993,6 +1993,7 @@ int xc_get_mem_access(xc_interface *xch, uint32_t domain_id,
  * Returns the VM_EVENT_INTERFACE version.
  */
 int xc_vm_event_get_version(xc_interface *xch);
+int xc_vm_event_ng_get_version(xc_interface *xch);
 
 /***
  * Monitor control operations.
@@ -2007,6 +2008,11 @@ int xc_vm_event_get_version(xc_interface *xch);
 void *xc_monitor_enable(xc_interface *xch, uint32_t domain_id, uint32_t *port);
 int xc_monitor_disable(xc_interface *xch, uint32_t domain_id);
 int xc_monitor_resume(xc_interface *xch, uint32_t domain_id);
+
+/* Monitor NG interface */
+int xc_monitor_ng_create(xc_interface *xch, uint32_t domain_id);
+int xc_monitor_ng_destroy(xc_interface *xch, uint32_t domain_id);
+int xc_monitor_ng_set_state(xc_interface *xch, uint32_t domain_id, bool enabled);
 /*
  * Get a bitmap of supported monitor events in the form
  * (1 << XEN_DOMCTL_MONITOR_EVENT_*).
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index 718fe8b..4c7ef2b 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -265,6 +265,21 @@ int xc_monitor_emul_unimplemented(xc_interface *xch, uint32_t domain_id,
     return do_domctl(xch, &domctl);
 }
 
+int xc_monitor_ng_create(xc_interface *xch, uint32_t domain_id)
+{
+    return xc_vm_event_ng_create(xch, domain_id, XEN_VM_EVENT_TYPE_MONITOR);
+}
+
+int xc_monitor_ng_destroy(xc_interface *xch, uint32_t domain_id)
+{
+    return xc_vm_event_ng_destroy(xch, domain_id, XEN_VM_EVENT_TYPE_MONITOR);
+}
+
+int xc_monitor_ng_set_state(xc_interface *xch, uint32_t domain_id, bool enabled)
+{
+    return xc_vm_event_ng_set_state(xch, domain_id, XEN_VM_EVENT_TYPE_MONITOR, enabled);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index 482451c..1904a1e 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -420,6 +420,14 @@ int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
 void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int type,
                          uint32_t *port);
 
+/**
+ * VM_EVENT NG operations. Internal use only.
+ */
+int xc_vm_event_ng_create(xc_interface *xch, uint32_t domain_id, int type);
+int xc_vm_event_ng_destroy(xc_interface *xch, uint32_t domain_id, int type);
+int xc_vm_event_ng_set_state(xc_interface *xch, uint32_t domain_id, int type, bool enabled);
+
+
 int do_dm_op(xc_interface *xch, uint32_t domid, unsigned int nr_bufs, ...);
 
 #endif /* __XC_PRIVATE_H__ */
diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
index 3b1018b..07243a6 100644
--- a/tools/libxc/xc_vm_event.c
+++ b/tools/libxc/xc_vm_event.c
@@ -154,6 +154,59 @@ int xc_vm_event_get_version(xc_interface *xch)
     return rc;
 }
 
+int xc_vm_event_ng_get_version(xc_interface *xch)
+{
+    DECLARE_DOMCTL;
+    int rc;
+
+    domctl.cmd = XEN_DOMCTL_vm_event_ng_op;
+    domctl.domain = DOMID_INVALID;
+    domctl.u.vm_event_op.op = XEN_VM_EVENT_NG_GET_VERSION;
+    domctl.u.vm_event_op.type = XEN_VM_EVENT_TYPE_MONITOR;
+
+    rc = do_domctl(xch, &domctl);
+    if ( !rc )
+        rc = domctl.u.vm_event_ng_op.u.version;
+    return rc;
+}
+
+int xc_vm_event_ng_create(xc_interface *xch, uint32_t domain_id, int type)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_vm_event_ng_op;
+    domctl.domain = domain_id;
+    domctl.u.vm_event_ng_op.op = XEN_VM_EVENT_NG_CREATE;
+    domctl.u.vm_event_ng_op.type = type;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_vm_event_ng_destroy(xc_interface *xch, uint32_t domain_id, int type)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_vm_event_ng_op;
+    domctl.domain = domain_id;
+    domctl.u.vm_event_ng_op.op = XEN_VM_EVENT_NG_DESTROY;
+    domctl.u.vm_event_ng_op.type = type;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_vm_event_ng_set_state(xc_interface *xch, uint32_t domain_id, int type, bool enabled)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_vm_event_ng_op;
+    domctl.domain = domain_id;
+    domctl.u.vm_event_ng_op.op = XEN_VM_EVENT_NG_SET_STATE;
+    domctl.u.vm_event_ng_op.type = type;
+    domctl.u.vm_event_ng_op.u.enabled = enabled;
+
+    return do_domctl(xch, &domctl);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 2f620d9..030b5bd 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -119,6 +119,7 @@
 #include <xen/efi.h>
 #include <xen/grant_table.h>
 #include <xen/hypercall.h>
+#include <xen/vm_event.h>
 #include <asm/paging.h>
 #include <asm/shadow.h>
 #include <asm/page.h>
@@ -4584,6 +4585,10 @@ int arch_acquire_resource(struct domain *d, unsigned int type,
     }
 #endif
 
+    case XENMEM_resource_vm_event:
+        rc = vm_event_ng_get_frames(d, id, frame, nr_frames, mfn_list);
+        break;
+
     default:
         rc = -EOPNOTSUPP;
         break;
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 33d03b8..8cb33e2 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -59,6 +59,7 @@ obj-y += trace.o
 obj-y += version.o
 obj-y += virtual_region.o
 obj-y += vm_event.o
+obj-y += vm_event_ng.o
 obj-y += vmap.o
 obj-y += vsprintf.o
 obj-y += wait.o
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index bade9a6..23f6e56 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -393,6 +393,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
     {
     case XEN_DOMCTL_test_assign_device:
     case XEN_DOMCTL_vm_event_op:
+    case XEN_DOMCTL_vm_event_ng_op:
         if ( op->domain == DOMID_INVALID )
         {
     case XEN_DOMCTL_createdomain:
@@ -1023,6 +1024,12 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
         copyback = 1;
         break;
 
+    case XEN_DOMCTL_vm_event_ng_op:
+        ret = vm_event_ng_domctl(d, &op->u.vm_event_ng_op,
+                                 guest_handle_cast(u_domctl, void));
+        copyback = 1;
+        break;
+
 #ifdef CONFIG_MEM_ACCESS
     case XEN_DOMCTL_set_access_required:
         if ( unlikely(current->domain == d) ) /* no domain_pause() */
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 1d85f3e..e94fe3c 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -380,6 +380,51 @@ static int vm_event_ring_get_response(struct vm_event_ring_domain *impl,
     return 1;
 }
 
+void vm_event_handle_response(struct domain *d, struct vcpu *v,
+                              vm_event_response_t *rsp)
+{
+    /* Check flags which apply only when the vCPU is paused */
+    if ( atomic_read(&v->vm_event_pause_count) )
+    {
+#ifdef CONFIG_HAS_MEM_PAGING
+        if ( rsp->reason == VM_EVENT_REASON_MEM_PAGING )
+            p2m_mem_paging_resume(d, rsp);
+#endif
+
+        /*
+         * Check emulation flags in the arch-specific handler only, as it
+         * has to set arch-specific flags when supported, and to avoid
+         * bitmask overhead when it isn't supported.
+         */
+        vm_event_emulate_check(v, rsp);
+
+        /*
+         * Check in arch-specific handler to avoid bitmask overhead when
+         * not supported.
+         */
+        vm_event_register_write_resume(v, rsp);
+
+        /*
+         * Check in arch-specific handler to avoid bitmask overhead when
+         * not supported.
+         */
+        vm_event_toggle_singlestep(d, v, rsp);
+
+        /* Check for altp2m switch */
+        if ( rsp->flags & VM_EVENT_FLAG_ALTERNATE_P2M )
+            p2m_altp2m_check(v, rsp->altp2m_idx);
+
+        if ( rsp->flags & VM_EVENT_FLAG_SET_REGISTERS )
+            vm_event_set_registers(v, rsp);
+
+        if ( rsp->flags & VM_EVENT_FLAG_GET_NEXT_INTERRUPT )
+            vm_event_monitor_next_interrupt(v);
+
+        if ( rsp->flags & VM_EVENT_FLAG_VCPU_PAUSED )
+            vm_event_vcpu_unpause(v);
+    }
+}
+
 /*
  * Pull all responses from the given ring and unpause the corresponding vCPU
  * if required. Based on the response type, here we can also call custom
@@ -427,47 +472,7 @@ static int vm_event_ring_resume(struct vm_event_ring_domain *impl)
          * In some cases the response type needs extra handling, so here
          * we call the appropriate handlers.
          */
-
-        /* Check flags which apply only when the vCPU is paused */
-        if ( atomic_read(&v->vm_event_pause_count) )
-        {
-#ifdef CONFIG_HAS_MEM_PAGING
-            if ( rsp.reason == VM_EVENT_REASON_MEM_PAGING )
-                p2m_mem_paging_resume(impl->ved.d, &rsp);
-#endif
-
-            /*
-             * Check emulation flags in the arch-specific handler only, as it
-             * has to set arch-specific flags when supported, and to avoid
-             * bitmask overhead when it isn't supported.
-             */
-            vm_event_emulate_check(v, &rsp);
-
-            /*
-             * Check in arch-specific handler to avoid bitmask overhead when
-             * not supported.
-             */
-            vm_event_register_write_resume(v, &rsp);
-
-            /*
-             * Check in arch-specific handler to avoid bitmask overhead when
-             * not supported.
-             */
-            vm_event_toggle_singlestep(impl->ved.d, v, &rsp);
-
-            /* Check for altp2m switch */
-            if ( rsp.flags & VM_EVENT_FLAG_ALTERNATE_P2M )
-                p2m_altp2m_check(v, rsp.altp2m_idx);
-
-            if ( rsp.flags & VM_EVENT_FLAG_SET_REGISTERS )
-                vm_event_set_registers(v, &rsp);
-
-            if ( rsp.flags & VM_EVENT_FLAG_GET_NEXT_INTERRUPT )
-                vm_event_monitor_next_interrupt(v);
-
-            if ( rsp.flags & VM_EVENT_FLAG_VCPU_PAUSED )
-                vm_event_vcpu_unpause(v);
-        }
+        vm_event_handle_response(impl->ved.d, v, &rsp);
     }
 
     return 0;
@@ -709,9 +714,10 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
             rc = arch_monitor_init_domain(d);
             if ( rc )
                 break;
-            rc = vm_event_ring_enable(d, vec, &d->vm_event_monitor, _VPF_mem_access,
-                                 HVM_PARAM_MONITOR_RING_PFN,
-                                 monitor_notification);
+            rc = vm_event_ring_enable(d, vec, &d->vm_event_monitor,
+                                      _VPF_mem_access,
+                                      HVM_PARAM_MONITOR_RING_PFN,
+                                      monitor_notification);
             break;
 
         case XEN_VM_EVENT_DISABLE:
diff --git a/xen/common/vm_event_ng.c b/xen/common/vm_event_ng.c
new file mode 100644
index 0000000..17ae33c
--- /dev/null
+++ b/xen/common/vm_event_ng.c
@@ -0,0 +1,449 @@
+/******************************************************************************
+ * vm_event_ng.c
+ *
+ * VM event support (new generation).
+ *
+ * Copyright (c) 2019, Bitdefender S.R.L.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/vm_event.h>
+#include <xen/vmap.h>
+#include <asm/monitor.h>
+#include <asm/vm_event.h>
+#include <xsm/xsm.h>
+
+#define to_channels(_ved) container_of((_ved), \
+                                        struct vm_event_channels_domain, ved)
+
+#define VM_EVENT_CHANNELS_ENABLED       1
+
+struct vm_event_channels_domain
+{
+    /* VM event domain */
+    struct vm_event_domain ved;
+    /* shared channels buffer */
+    struct vm_event_slot *slots;
+    /* the buffer size (number of frames) */
+    unsigned int nr_frames;
+    /* state */
+    bool enabled;
+    /* buffer's mnf list */
+    mfn_t mfn[0];
+};
+
+static const struct vm_event_ops vm_event_channels_ops;
+
+static int vm_event_channels_alloc_buffer(struct vm_event_channels_domain *impl)
+{
+    int i, rc = -ENOMEM;
+
+    for ( i = 0; i < impl->nr_frames; i++ )
+    {
+        struct page_info *page = alloc_domheap_page(impl->ved.d, 0);
+        if ( !page )
+            goto err;
+
+        if ( !get_page_and_type(page, impl->ved.d, PGT_writable_page) )
+        {
+            rc = -ENODATA;
+            goto err;
+        }
+
+        impl->mfn[i] = page_to_mfn(page);
+    }
+
+    impl->slots = (struct vm_event_slot *)vmap(impl->mfn, impl->nr_frames);
+    if ( !impl->slots )
+        goto err;
+
+    for ( i = 0; i < impl->nr_frames; i++ )
+        clear_page((void*)impl->slots + i * PAGE_SIZE);
+
+    return 0;
+
+err:
+    while ( --i >= 0 )
+    {
+        struct page_info *page = mfn_to_page(impl->mfn[i]);
+
+        if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
+            put_page(page);
+        put_page_and_type(page);
+    }
+
+    return rc;
+}
+
+static void vm_event_channels_free_buffer(struct vm_event_channels_domain *impl)
+{
+    int i;
+
+    ASSERT(impl);
+
+    if ( !impl->slots )
+        return;
+
+    vunmap(impl->slots);
+
+    for ( i = 0; i < impl->nr_frames; i++ )
+    {
+        struct page_info *page = mfn_to_page(impl->mfn[i]);
+
+        ASSERT(page);
+        if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
+            put_page(page);
+        put_page_and_type(page);
+    }
+}
+
+static int vm_event_channels_create(
+    struct domain *d,
+    struct xen_domctl_vm_event_ng_op *vec,
+    struct vm_event_domain **_ved,
+    int pause_flag,
+    xen_event_channel_notification_t notification_fn)
+{
+    int rc, i;
+    unsigned int nr_frames = PFN_UP(d->max_vcpus * sizeof(struct vm_event_slot));
+    struct vm_event_channels_domain *impl;
+
+    if ( *_ved )
+        return -EBUSY;
+
+    impl = _xzalloc(sizeof(struct vm_event_channels_domain) +
+                           nr_frames * sizeof(mfn_t),
+                    __alignof__(struct vm_event_channels_domain));
+    if ( unlikely(!impl) )
+        return -ENOMEM;
+
+    spin_lock_init(&impl->ved.lock);
+    spin_lock(&impl->ved.lock);
+
+    impl->nr_frames = nr_frames;
+    impl->ved.d = d;
+    impl->ved.ops = &vm_event_channels_ops;
+
+    rc = vm_event_init_domain(d);
+    if ( rc < 0 )
+        goto err;
+
+    rc = vm_event_channels_alloc_buffer(impl);
+    if ( rc )
+        goto err;
+
+    for ( i = 0; i < d->max_vcpus; i++ )
+    {
+        rc = alloc_unbound_xen_event_channel(d, i, current->domain->domain_id,
+                                             notification_fn);
+        if ( rc < 0 )
+            goto err;
+
+        impl->slots[i].port = rc;
+        impl->slots[i].state = STATE_VM_EVENT_SLOT_IDLE;
+    }
+
+    impl->enabled = false;
+
+    spin_unlock(&impl->ved.lock);
+    *_ved = &impl->ved;
+    return 0;
+
+err:
+    spin_unlock(&impl->ved.lock);
+    XFREE(impl);
+    return rc;
+}
+
+static int vm_event_channels_destroy(struct vm_event_domain **_ved)
+{
+    struct vcpu *v;
+    struct vm_event_channels_domain *impl = to_channels(*_ved);
+    int i;
+
+    spin_lock(&(*_ved)->lock);
+
+    for_each_vcpu( (*_ved)->d, v )
+    {
+        if ( atomic_read(&v->vm_event_pause_count) )
+            vm_event_vcpu_unpause(v);
+    }
+
+    for ( i = 0; i < (*_ved)->d->max_vcpus; i++ )
+        evtchn_close((*_ved)->d, impl->slots[i].port, 0);
+
+    vm_event_channels_free_buffer(impl);
+    spin_unlock(&(*_ved)->lock);
+    XFREE(*_ved);
+
+    return 0;
+}
+
+static bool vm_event_channels_check(struct vm_event_domain *ved)
+{
+    return to_channels(ved)->slots != NULL;
+}
+
+static void vm_event_channels_cleanup(struct vm_event_domain **_ved)
+{
+    vm_event_channels_destroy(_ved);
+}
+
+static int vm_event_channels_claim_slot(struct vm_event_domain *ved,
+                                        bool allow_sleep)
+{
+    return 0;
+}
+
+static void vm_event_channels_cancel_slot(struct vm_event_domain *ved)
+{
+}
+
+static void vm_event_channels_put_request(struct vm_event_domain *ved,
+                                          vm_event_request_t *req)
+{
+    struct vm_event_channels_domain *impl = to_channels(ved);
+    struct vm_event_slot *slot;
+
+    /* exit if the vm_event_domain was not specifically enabled */
+    if ( !impl->enabled )
+        return;
+
+    ASSERT( req->vcpu_id >= 0 && req->vcpu_id < ved->d->max_vcpus );
+
+    slot = &impl->slots[req->vcpu_id];
+
+    if ( current->domain != ved->d )
+    {
+        req->flags |= VM_EVENT_FLAG_FOREIGN;
+#ifndef NDEBUG
+        if ( !(req->flags & VM_EVENT_FLAG_VCPU_PAUSED) )
+            gdprintk(XENLOG_G_WARNING, "d%dv%d was not paused.\n",
+                     ved->d->domain_id, req->vcpu_id);
+#endif
+    }
+
+    req->version = VM_EVENT_INTERFACE_VERSION;
+
+    spin_lock(&impl->ved.lock);
+    if ( slot->state != STATE_VM_EVENT_SLOT_IDLE )
+    {
+        gdprintk(XENLOG_G_WARNING, "The VM event slot for d%dv%d is not IDLE.\n",
+                 impl->ved.d->domain_id, req->vcpu_id);
+        spin_unlock(&impl->ved.lock);
+        return;
+    }
+
+    slot->u.req = *req;
+    slot->state = STATE_VM_EVENT_SLOT_SUBMIT;
+    spin_unlock(&impl->ved.lock);
+    notify_via_xen_event_channel(impl->ved.d, slot->port);
+}
+
+static int vm_event_channels_get_response(struct vm_event_channels_domain *impl,
+                                          struct vcpu *v, vm_event_response_t *rsp)
+{
+    struct vm_event_slot *slot = &impl->slots[v->vcpu_id];
+
+    ASSERT( slot != NULL );
+    spin_lock(&impl->ved.lock);
+
+    if ( slot->state != STATE_VM_EVENT_SLOT_FINISH )
+    {
+        gdprintk(XENLOG_G_WARNING, "The VM event slot state for d%dv%d is invalid.\n",
+                 impl->ved.d->domain_id, v->vcpu_id);
+        spin_unlock(&impl->ved.lock);
+        return -1;
+    }
+
+    *rsp = slot->u.rsp;
+    slot->state = STATE_VM_EVENT_SLOT_IDLE;
+
+    spin_unlock(&impl->ved.lock);
+    return 0;
+}
+
+static int vm_event_channels_resume(struct vm_event_channels_domain *impl,
+                                    struct vcpu *v)
+{
+    vm_event_response_t rsp;
+
+    if ( unlikely(!impl || !vm_event_check(&impl->ved)) )
+         return -ENODEV;
+
+    ASSERT(impl->ved.d != current->domain);
+
+    if ( vm_event_channels_get_response(impl, v, &rsp) ||
+         rsp.version != VM_EVENT_INTERFACE_VERSION ||
+         rsp.vcpu_id != v->vcpu_id )
+        return -1;
+
+    vm_event_handle_response(impl->ved.d, v, &rsp);
+
+    return 0;
+}
+
+/* Registered with Xen-bound event channel for incoming notifications. */
+static void monitor_notification(struct vcpu *v, unsigned int port)
+{
+    vm_event_channels_resume(to_channels(v->domain->vm_event_monitor), v);
+}
+
+int vm_event_ng_domctl(struct domain *d, struct xen_domctl_vm_event_ng_op *vec,
+                       XEN_GUEST_HANDLE_PARAM(void) u_domctl)
+{
+    int rc;
+
+    if ( vec->op == XEN_VM_EVENT_NG_GET_VERSION )
+    {
+        vec->u.version = VM_EVENT_INTERFACE_VERSION;
+        return 0;
+    }
+
+    if ( unlikely(d == NULL) )
+        return -ESRCH;
+
+    rc = xsm_vm_event_control(XSM_PRIV, d, vec->type, vec->op);
+    if ( rc )
+        return rc;
+
+    if ( unlikely(d == current->domain) ) /* no domain_pause() */
+    {
+        gdprintk(XENLOG_INFO, "Tried to do a memory event op on itself.\n");
+        return -EINVAL;
+    }
+
+    if ( unlikely(d->is_dying) )
+    {
+        gdprintk(XENLOG_INFO, "Ignoring memory event op on dying domain %u\n",
+                 d->domain_id);
+        return 0;
+    }
+
+    if ( unlikely(d->vcpu == NULL) || unlikely(d->vcpu[0] == NULL) )
+    {
+        gdprintk(XENLOG_INFO,
+                 "Memory event op on a domain (%u) with no vcpus\n",
+                 d->domain_id);
+        return -EINVAL;
+    }
+
+    switch ( vec->type )
+    {
+    case XEN_VM_EVENT_TYPE_MONITOR:
+    {
+        rc = -EINVAL;
+
+        switch ( vec-> op)
+        {
+        case XEN_VM_EVENT_NG_CREATE:
+            /* domain_pause() not required here, see XSA-99 */
+            rc = arch_monitor_init_domain(d);
+            if ( rc )
+                break;
+            rc = vm_event_channels_create(d, vec, &d->vm_event_monitor,
+                                     _VPF_mem_access, monitor_notification);
+            break;
+
+        case XEN_VM_EVENT_NG_DESTROY:
+            if ( !vm_event_check(d->vm_event_monitor) )
+                break;
+            domain_pause(d);
+            rc = vm_event_channels_destroy(&d->vm_event_monitor);
+            arch_monitor_cleanup_domain(d);
+            domain_unpause(d);
+            break;
+
+        case XEN_VM_EVENT_NG_SET_STATE:
+            if ( !vm_event_check(d->vm_event_monitor) )
+                break;
+            domain_pause(d);
+            to_channels(d->vm_event_monitor)->enabled = !!vec->u.enabled;
+            domain_unpause(d);
+            rc = 0;
+            break;
+
+        default:
+            rc = -ENOSYS;
+        }
+        break;
+    }
+
+#ifdef CONFIG_HAS_MEM_PAGING
+    case XEN_VM_EVENT_TYPE_PAGING:
+#endif
+
+#ifdef CONFIG_HAS_MEM_SHARING
+    case XEN_VM_EVENT_TYPE_SHARING:
+#endif
+
+    default:
+        rc = -ENOSYS;
+    }
+
+    return rc;
+}
+
+int vm_event_ng_get_frames(struct domain *d, unsigned int id,
+                           unsigned long frame, unsigned int nr_frames,
+                           xen_pfn_t mfn_list[])
+{
+    struct vm_event_domain *ved;
+    int i;
+
+    switch (id )
+    {
+    case XEN_VM_EVENT_TYPE_MONITOR:
+        ved = d->vm_event_monitor;
+        break;
+
+    default:
+        return -ENOSYS;
+    }
+
+    if ( !vm_event_check(ved) )
+        return -EINVAL;
+
+    if ( frame != 0 || nr_frames != to_channels(ved)->nr_frames )
+        return -EINVAL;
+
+    spin_lock(&ved->lock);
+
+    for ( i = 0; i < to_channels(ved)->nr_frames; i++ )
+        mfn_list[i] = mfn_x(to_channels(ved)->mfn[i]);
+
+    spin_unlock(&ved->lock);
+    return 0;
+}
+
+static const struct vm_event_ops vm_event_channels_ops = {
+    .check = vm_event_channels_check,
+    .cleanup = vm_event_channels_cleanup,
+    .claim_slot = vm_event_channels_claim_slot,
+    .cancel_slot = vm_event_channels_cancel_slot,
+    .put_request = vm_event_channels_put_request
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 19281fa..ff8b680 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -792,6 +792,24 @@ struct xen_domctl_vm_event_op {
 };
 
 /*
+ * XEN_DOMCTL_vm_event_ng_op.
+ * Next Generation vm_event operations.
+ */
+#define XEN_VM_EVENT_NG_CREATE            0
+#define XEN_VM_EVENT_NG_DESTROY           1
+#define XEN_VM_EVENT_NG_SET_STATE         2
+#define XEN_VM_EVENT_NG_GET_VERSION       3
+
+struct xen_domctl_vm_event_ng_op {
+    uint32_t        op;             /* XEN_VM_EVENT_NG_* */
+    uint32_t        type;           /* XEN_VM_EVENT_TYPE_* */
+    union {
+        uint32_t version;           /* OUT: version number */
+        uint8_t  enabled;           /* IN: state */
+    } u;
+};
+
+/*
  * Memory sharing operations
  */
 /* XEN_DOMCTL_mem_sharing_op.
@@ -1142,6 +1160,7 @@ struct xen_domctl {
 /* #define XEN_DOMCTL_set_gnttab_limits          80 - Moved into XEN_DOMCTL_createdomain */
 #define XEN_DOMCTL_vuart_op                      81
 #define XEN_DOMCTL_get_cpu_policy                82
+#define XEN_DOMCTL_vm_event_ng_op                83
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1183,6 +1202,7 @@ struct xen_domctl {
         struct xen_domctl_subscribe         subscribe;
         struct xen_domctl_debug_op          debug_op;
         struct xen_domctl_vm_event_op       vm_event_op;
+        struct xen_domctl_vm_event_ng_op    vm_event_ng_op;
         struct xen_domctl_mem_sharing_op    mem_sharing_op;
 #if defined(__i386__) || defined(__x86_64__)
         struct xen_domctl_cpuid             cpuid;
diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h
index 68ddadb..2e8912e 100644
--- a/xen/include/public/memory.h
+++ b/xen/include/public/memory.h
@@ -612,6 +612,7 @@ struct xen_mem_acquire_resource {
 
 #define XENMEM_resource_ioreq_server 0
 #define XENMEM_resource_grant_table 1
+#define XENMEM_resource_vm_event 2
 
     /*
      * IN - a type-specific resource identifier, which must be zero
@@ -619,6 +620,7 @@ struct xen_mem_acquire_resource {
      *
      * type == XENMEM_resource_ioreq_server -> id == ioreq server id
      * type == XENMEM_resource_grant_table -> id defined below
+     * type == XENMEM_resource_vm_event -> id == vm_event type
      */
     uint32_t id;
 
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index c48bc21..2f2160b 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -421,6 +421,22 @@ typedef struct vm_event_st {
 
 DEFINE_RING_TYPES(vm_event, vm_event_request_t, vm_event_response_t);
 
+/* VM Event slot state */
+#define STATE_VM_EVENT_SLOT_IDLE     0 /* the slot data is invalid */
+#define STATE_VM_EVENT_SLOT_SUBMIT   1 /* a request was submitted */
+#define STATE_VM_EVENT_SLOT_FINISH   2 /* a response was issued */
+
+struct vm_event_slot
+{
+    uint32_t port;      /* evtchn for notifications to/from helper */
+    uint32_t state:4;
+    uint32_t pad:28;
+    union {
+        vm_event_request_t req;
+        vm_event_response_t rsp;
+    } u;
+};
+
 #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */
 #endif /* _XEN_PUBLIC_VM_EVENT_H */
 
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index 15c15e6..df0aafc 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -110,6 +110,13 @@ static inline void vm_event_put_request(struct vm_event_domain *ved,
 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec,
                     XEN_GUEST_HANDLE_PARAM(void) u_domctl);
 
+int vm_event_ng_domctl(struct domain *d, struct xen_domctl_vm_event_ng_op *vec,
+                       XEN_GUEST_HANDLE_PARAM(void) u_domctl);
+
+int vm_event_ng_get_frames(struct domain *d, unsigned int id,
+                           unsigned long frame, unsigned int nr_frames,
+                           xen_pfn_t mfn_list[]);
+
 void vm_event_vcpu_pause(struct vcpu *v);
 void vm_event_vcpu_unpause(struct vcpu *v);
 
@@ -118,6 +125,9 @@ void vm_event_set_registers(struct vcpu *v, vm_event_response_t *rsp);
 
 void vm_event_monitor_next_interrupt(struct vcpu *v);
 
+void vm_event_handle_response(struct domain *d, struct vcpu *v,
+                              vm_event_response_t *rsp);
+
 #endif /* __VM_EVENT_H__ */
 
 /*
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 9/9] xen-access: Add support for vm_event_ng interface
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Tamas K Lengyel, Ian Jackson, Wei Liu, Razvan Cojocaru

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@bitdefender.com>
---
 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@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH 9/9] xen-access: Add support for vm_event_ng interface
@ 2019-05-30 14:18   ` Petre Pircalabu
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Pircalabu @ 2019-05-30 14:18 UTC (permalink / raw)
  To: xen-devel
  Cc: Petre Pircalabu, Tamas K Lengyel, Ian Jackson, Wei Liu, Razvan Cojocaru

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@bitdefender.com>
---
 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@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH 0/9] Per vcpu vm_event channels
@ 2019-05-30 15:27   ` Tamas K Lengyel
  0 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-05-30 15:27 UTC (permalink / raw)
  To: Petre Pircalabu
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Jan Beulich, Xen-devel,
	Roger Pau Monné

On Thu, May 30, 2019 at 7:18 AM Petre Pircalabu
<ppircalabu@bitdefender.com> wrote:
>
> This patchset adds a new mechanism of sending synchronous vm_event
> requests and handling vm_event responses without using a ring.
> As each synchronous request pauses the vcpu until the corresponding
> response is handled, it can be stored in a slotted memory buffer
> (one per vcpu) shared between the hypervisor and the controlling domain.
>
> The main advantages of this approach are:
> - the ability to dynamicaly allocate the necessary memory used to hold
> the requests/responses (the size of vm_event_request_t/vm_event_response_t
> can grow unrestricted by the ring's one page limitation)
> - the ring's waitqueue logic is unnecessary in this case because the
> vcpu sending the request is blocked until a response is received.

Hi Petre,
could you push this series as a git branch somewhere?

Thanks,
Tamas

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 0/9] Per vcpu vm_event channels
@ 2019-05-30 15:27   ` Tamas K Lengyel
  0 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-05-30 15:27 UTC (permalink / raw)
  To: Petre Pircalabu
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Jan Beulich, Xen-devel,
	Roger Pau Monné

On Thu, May 30, 2019 at 7:18 AM Petre Pircalabu
<ppircalabu@bitdefender.com> wrote:
>
> This patchset adds a new mechanism of sending synchronous vm_event
> requests and handling vm_event responses without using a ring.
> As each synchronous request pauses the vcpu until the corresponding
> response is handled, it can be stored in a slotted memory buffer
> (one per vcpu) shared between the hypervisor and the controlling domain.
>
> The main advantages of this approach are:
> - the ability to dynamicaly allocate the necessary memory used to hold
> the requests/responses (the size of vm_event_request_t/vm_event_response_t
> can grow unrestricted by the ring's one page limitation)
> - the ring's waitqueue logic is unnecessary in this case because the
> vcpu sending the request is blocked until a response is received.

Hi Petre,
could you push this series as a git branch somewhere?

Thanks,
Tamas

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 0/9] Per vcpu vm_event channels
@ 2019-05-31  7:07     ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-05-31  7:07 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Jan Beulich, Xen-devel,
	Roger Pau Monné

On Thu, 2019-05-30 at 08:27 -0700, Tamas K Lengyel wrote:
> On Thu, May 30, 2019 at 7:18 AM Petre Pircalabu
> <ppircalabu@bitdefender.com> wrote:
> > 
> > This patchset adds a new mechanism of sending synchronous vm_event
> > requests and handling vm_event responses without using a ring.
> > As each synchronous request pauses the vcpu until the corresponding
> > response is handled, it can be stored in a slotted memory buffer
> > (one per vcpu) shared between the hypervisor and the controlling
> > domain.
> > 
> > The main advantages of this approach are:
> > - the ability to dynamicaly allocate the necessary memory used to
> > hold
> > the requests/responses (the size of
> > vm_event_request_t/vm_event_response_t
> > can grow unrestricted by the ring's one page limitation)
> > - the ring's waitqueue logic is unnecessary in this case because
> > the
> > vcpu sending the request is blocked until a response is received.
> 
> Hi Petre,
> could you push this series as a git branch somewhere?
> 
> Thanks,
> Tamas

Hi Tamas,

I've pushed the changes to 
https://github.com/petrepircalabu/xen/tree/vm_event_ng/devel

Thank-you very much for your support,
Petre

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 0/9] Per vcpu vm_event channels
@ 2019-05-31  7:07     ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-05-31  7:07 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Jan Beulich, Xen-devel,
	Roger Pau Monné

On Thu, 2019-05-30 at 08:27 -0700, Tamas K Lengyel wrote:
> On Thu, May 30, 2019 at 7:18 AM Petre Pircalabu
> <ppircalabu@bitdefender.com> wrote:
> > 
> > This patchset adds a new mechanism of sending synchronous vm_event
> > requests and handling vm_event responses without using a ring.
> > As each synchronous request pauses the vcpu until the corresponding
> > response is handled, it can be stored in a slotted memory buffer
> > (one per vcpu) shared between the hypervisor and the controlling
> > domain.
> > 
> > The main advantages of this approach are:
> > - the ability to dynamicaly allocate the necessary memory used to
> > hold
> > the requests/responses (the size of
> > vm_event_request_t/vm_event_response_t
> > can grow unrestricted by the ring's one page limitation)
> > - the ring's waitqueue logic is unnecessary in this case because
> > the
> > vcpu sending the request is blocked until a response is received.
> 
> Hi Petre,
> could you push this series as a git branch somewhere?
> 
> Thanks,
> Tamas

Hi Tamas,

I've pushed the changes to 
https://github.com/petrepircalabu/xen/tree/vm_event_ng/devel

Thank-you very much for your support,
Petre

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 1/9] tools/libxc: Consistent usage of xc_vm_event_* interface
@ 2019-05-31 23:01     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:01 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel; +Cc: Ian Jackson, Wei Liu

On 30/05/2019 07:18, Petre Pircalabu wrote:
> Modified xc_mem_paging_enable to use directly xc_vm_event_enable and
> moved the ring_page handling from client to libxc (xenpaging).
>
> Restricted vm_event_control usage only to simplest domctls which do
> not expect any return values and change xc_vm_event_enable to call do_domctl
> directly.
>
> Removed xc_memshr_ring_enable/disable and xc_memshr_domain_resume.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
> ---
>  tools/libxc/include/xenctrl.h | 49 +--------------------------------
>  tools/libxc/xc_mem_paging.c   | 23 +++++-----------
>  tools/libxc/xc_memshr.c       | 34 -----------------------
>  tools/libxc/xc_monitor.c      | 31 +++++++++++++++++----
>  tools/libxc/xc_private.h      |  2 +-
>  tools/libxc/xc_vm_event.c     | 64 ++++++++++++++++---------------------------
>  tools/xenpaging/xenpaging.c   | 42 +++-------------------------

So, the diffstat here is very impressive, and judging by the delta, its
all about not opencoding the use of the HVM_PARAM interface.  Overall,
this is clearly a good thing.

However, it is quite difficult to follow exactly what is going on.

AFAICT, this wants splitting into $N patches.

One patch should refactor xc_mem_paging_enable() to use
xc_vm_event_enable(), with the associated xenpaging cleanup.

One patch should be the deletion of xc_memshr_* on its own, because
AFAICT it is an isolated change.  It also needs some justification, even
if it is "interface is unused and/or redundant with $X".

One patch (alone) should be the repositioning of the domain_pause()
calls.  This does certainly look like a vast improvement WRT error
handling in xc_vm_event_enable(), but you've definitely changed the API
(insofar as the expectation that the caller has paused the domain) goes,
and its not at all obvious that this change is safe.  It may very well
be, but you need to convince people as to why in the commit message.


I still haven't figured out what the purpose behind dropping the port
parameter from xc_vm_event_control() is.

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 1/9] tools/libxc: Consistent usage of xc_vm_event_* interface
@ 2019-05-31 23:01     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:01 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel; +Cc: Ian Jackson, Wei Liu

On 30/05/2019 07:18, Petre Pircalabu wrote:
> Modified xc_mem_paging_enable to use directly xc_vm_event_enable and
> moved the ring_page handling from client to libxc (xenpaging).
>
> Restricted vm_event_control usage only to simplest domctls which do
> not expect any return values and change xc_vm_event_enable to call do_domctl
> directly.
>
> Removed xc_memshr_ring_enable/disable and xc_memshr_domain_resume.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
> ---
>  tools/libxc/include/xenctrl.h | 49 +--------------------------------
>  tools/libxc/xc_mem_paging.c   | 23 +++++-----------
>  tools/libxc/xc_memshr.c       | 34 -----------------------
>  tools/libxc/xc_monitor.c      | 31 +++++++++++++++++----
>  tools/libxc/xc_private.h      |  2 +-
>  tools/libxc/xc_vm_event.c     | 64 ++++++++++++++++---------------------------
>  tools/xenpaging/xenpaging.c   | 42 +++-------------------------

So, the diffstat here is very impressive, and judging by the delta, its
all about not opencoding the use of the HVM_PARAM interface.  Overall,
this is clearly a good thing.

However, it is quite difficult to follow exactly what is going on.

AFAICT, this wants splitting into $N patches.

One patch should refactor xc_mem_paging_enable() to use
xc_vm_event_enable(), with the associated xenpaging cleanup.

One patch should be the deletion of xc_memshr_* on its own, because
AFAICT it is an isolated change.  It also needs some justification, even
if it is "interface is unused and/or redundant with $X".

One patch (alone) should be the repositioning of the domain_pause()
calls.  This does certainly look like a vast improvement WRT error
handling in xc_vm_event_enable(), but you've definitely changed the API
(insofar as the expectation that the caller has paused the domain) goes,
and its not at all obvious that this change is safe.  It may very well
be, but you need to convince people as to why in the commit message.


I still haven't figured out what the purpose behind dropping the port
parameter from xc_vm_event_control() is.

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-05-31 23:26     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:26 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich

On 30/05/2019 07:18, Petre Pircalabu wrote:
> diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
> index ea10366..3b1018b 100644
> --- a/tools/libxc/xc_vm_event.c
> +++ b/tools/libxc/xc_vm_event.c
> @@ -23,29 +23,54 @@
>  #include "xc_private.h"
>  
>  int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
> -                        unsigned int mode)
> +                        unsigned int type)
>  {
>      DECLARE_DOMCTL;
>  
>      domctl.cmd = XEN_DOMCTL_vm_event_op;
>      domctl.domain = domain_id;
>      domctl.u.vm_event_op.op = op;
> -    domctl.u.vm_event_op.mode = mode;
> +    domctl.u.vm_event_op.type = type;
>  
>      return do_domctl(xch, &domctl);
>  }
>  
> -void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
> +static int xc_vm_event_ring_pfn_param(int type, int *param)
> +{
> +    if ( !param )
> +        return -EINVAL;
> +
> +    switch ( type )
> +    {
> +    case XEN_VM_EVENT_TYPE_PAGING:
> +        *param = HVM_PARAM_PAGING_RING_PFN;
> +        break;
> +
> +    case XEN_VM_EVENT_TYPE_MONITOR:
> +        *param = HVM_PARAM_MONITOR_RING_PFN;
> +        break;
> +
> +    case XEN_VM_EVENT_TYPE_SHARING:
> +        *param = HVM_PARAM_SHARING_RING_PFN;
> +        break;
> +
> +    default:
> +        return -EINVAL;
> +    }
> +
> +    return 0;
> +}

This is an internal helper, so can reasonably be expected to not be
called with junk, and can do away with the param pointer.

Something like

static int xc_vm_event_ring_pfn_param(unsigned int type)
{
    switch ( type )
    {
        case XEN_VM_EVENT_TYPE_PAGING:
            return HVM_PARAM_PAGING_RING_PFN;
...
        default:
            return -EINVAL;
    }
}

will work fine because HVM_PARAM_* are all tiny unsigned integers in
practice.  It also has a more sensible API for the caller.

> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index 19486d5..19281fa 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -769,80 +769,18 @@ struct xen_domctl_gdbsx_domstatus {
>   * VM event operations
>   */
>  
> -/* XEN_DOMCTL_vm_event_op */
> -
> -/*
> - * There are currently three rings available for VM events:
> - * sharing, monitor and paging. This hypercall allows one to
> - * control these rings (enable/disable), as well as to signal
> - * to the hypervisor to pull responses (resume) from the given
> - * ring.
> +/* XEN_DOMCTL_vm_event_op.

/*
 * XEN_DOMCTL_vm_event_op.
 *

please, seeing as you're adjusting the comment.

> + * Use for teardown/setup of helper<->hypervisor interface for paging,
> + * access and sharing.
>   */
>  #define XEN_VM_EVENT_ENABLE               0
>  #define XEN_VM_EVENT_DISABLE              1
>  #define XEN_VM_EVENT_RESUME               2
>  #define XEN_VM_EVENT_GET_VERSION          3
>  
> -/*
> - * Domain memory paging
> - * Page memory in and out.
> - * Domctl interface to set up and tear down the
> - * pager<->hypervisor interface. Use XENMEM_paging_op*
> - * to perform per-page operations.
> - *
> - * The XEN_VM_EVENT_PAGING_ENABLE domctl returns several
> - * non-standard error codes to indicate why paging could not be enabled:
> - * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> - * EMLINK - guest has iommu passthrough enabled
> - * EXDEV  - guest has PoD enabled
> - * EBUSY  - guest has or had paging enabled, ring buffer still active
> - */
> -#define XEN_DOMCTL_VM_EVENT_OP_PAGING            1
> -
> -/*
> - * Monitor helper.
> - *
> - * As with paging, use the domctl for teardown/setup of the
> - * helper<->hypervisor interface.
> - *
> - * The monitor interface can be used to register for various VM events. For
> - * example, there are HVM hypercalls to set the per-page access permissions
> - * of every page in a domain.  When one of these permissions--independent,
> - * read, write, and execute--is violated, the VCPU is paused and a memory event
> - * is sent with what happened. The memory event handler can then resume the
> - * VCPU and redo the access with a XEN_VM_EVENT_RESUME option.
> - *
> - * See public/vm_event.h for the list of available events that can be
> - * subscribed to via the monitor interface.
> - *
> - * The XEN_VM_EVENT_MONITOR_* domctls returns
> - * non-standard error codes to indicate why access could not be enabled:
> - * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> - * EBUSY  - guest has or had access enabled, ring buffer still active
> - *
> - */
> -#define XEN_DOMCTL_VM_EVENT_OP_MONITOR           2
> -
> -/*
> - * Sharing ENOMEM helper.
> - *
> - * As with paging, use the domctl for teardown/setup of the
> - * helper<->hypervisor interface.
> - *
> - * If setup, this ring is used to communicate failed allocations
> - * in the unshare path. XENMEM_sharing_op_resume is used to wake up
> - * vcpus that could not unshare.
> - *
> - * Note that shring can be turned on (as per the domctl below)
> - * *without* this ring being setup.
> - */
> -#define XEN_DOMCTL_VM_EVENT_OP_SHARING           3
> -
> -/* Use for teardown/setup of helper<->hypervisor interface for paging,
> - * access and sharing.*/
>  struct xen_domctl_vm_event_op {
> -    uint32_t       op;           /* XEN_VM_EVENT_* */
> -    uint32_t       mode;         /* XEN_DOMCTL_VM_EVENT_OP_* */
> +    uint32_t        op;           /* XEN_VM_EVENT_* */
> +    uint32_t        type;         /* XEN_VM_EVENT_TYPE_* */

Why did the vertical alignment change?

>  
>      union {
>          struct {
> @@ -857,7 +795,10 @@ struct xen_domctl_vm_event_op {
>   * Memory sharing operations
>   */
>  /* XEN_DOMCTL_mem_sharing_op.
> - * The CONTROL sub-domctl is used for bringup/teardown. */
> + * The CONTROL sub-domctl is used for bringup/teardown.
> + * Please note that mem sharing can be turned on *without* setting-up the
> + * correspondin ring
> + */

As a tangent, it can? how?  (I'm entirely prepared to believe that this
is how the code currently works, but I can't see how such a setup would
plausibly work.)

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-05-31 23:26     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:26 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich

On 30/05/2019 07:18, Petre Pircalabu wrote:
> diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
> index ea10366..3b1018b 100644
> --- a/tools/libxc/xc_vm_event.c
> +++ b/tools/libxc/xc_vm_event.c
> @@ -23,29 +23,54 @@
>  #include "xc_private.h"
>  
>  int xc_vm_event_control(xc_interface *xch, uint32_t domain_id, unsigned int op,
> -                        unsigned int mode)
> +                        unsigned int type)
>  {
>      DECLARE_DOMCTL;
>  
>      domctl.cmd = XEN_DOMCTL_vm_event_op;
>      domctl.domain = domain_id;
>      domctl.u.vm_event_op.op = op;
> -    domctl.u.vm_event_op.mode = mode;
> +    domctl.u.vm_event_op.type = type;
>  
>      return do_domctl(xch, &domctl);
>  }
>  
> -void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param,
> +static int xc_vm_event_ring_pfn_param(int type, int *param)
> +{
> +    if ( !param )
> +        return -EINVAL;
> +
> +    switch ( type )
> +    {
> +    case XEN_VM_EVENT_TYPE_PAGING:
> +        *param = HVM_PARAM_PAGING_RING_PFN;
> +        break;
> +
> +    case XEN_VM_EVENT_TYPE_MONITOR:
> +        *param = HVM_PARAM_MONITOR_RING_PFN;
> +        break;
> +
> +    case XEN_VM_EVENT_TYPE_SHARING:
> +        *param = HVM_PARAM_SHARING_RING_PFN;
> +        break;
> +
> +    default:
> +        return -EINVAL;
> +    }
> +
> +    return 0;
> +}

This is an internal helper, so can reasonably be expected to not be
called with junk, and can do away with the param pointer.

Something like

static int xc_vm_event_ring_pfn_param(unsigned int type)
{
    switch ( type )
    {
        case XEN_VM_EVENT_TYPE_PAGING:
            return HVM_PARAM_PAGING_RING_PFN;
...
        default:
            return -EINVAL;
    }
}

will work fine because HVM_PARAM_* are all tiny unsigned integers in
practice.  It also has a more sensible API for the caller.

> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index 19486d5..19281fa 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -769,80 +769,18 @@ struct xen_domctl_gdbsx_domstatus {
>   * VM event operations
>   */
>  
> -/* XEN_DOMCTL_vm_event_op */
> -
> -/*
> - * There are currently three rings available for VM events:
> - * sharing, monitor and paging. This hypercall allows one to
> - * control these rings (enable/disable), as well as to signal
> - * to the hypervisor to pull responses (resume) from the given
> - * ring.
> +/* XEN_DOMCTL_vm_event_op.

/*
 * XEN_DOMCTL_vm_event_op.
 *

please, seeing as you're adjusting the comment.

> + * Use for teardown/setup of helper<->hypervisor interface for paging,
> + * access and sharing.
>   */
>  #define XEN_VM_EVENT_ENABLE               0
>  #define XEN_VM_EVENT_DISABLE              1
>  #define XEN_VM_EVENT_RESUME               2
>  #define XEN_VM_EVENT_GET_VERSION          3
>  
> -/*
> - * Domain memory paging
> - * Page memory in and out.
> - * Domctl interface to set up and tear down the
> - * pager<->hypervisor interface. Use XENMEM_paging_op*
> - * to perform per-page operations.
> - *
> - * The XEN_VM_EVENT_PAGING_ENABLE domctl returns several
> - * non-standard error codes to indicate why paging could not be enabled:
> - * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> - * EMLINK - guest has iommu passthrough enabled
> - * EXDEV  - guest has PoD enabled
> - * EBUSY  - guest has or had paging enabled, ring buffer still active
> - */
> -#define XEN_DOMCTL_VM_EVENT_OP_PAGING            1
> -
> -/*
> - * Monitor helper.
> - *
> - * As with paging, use the domctl for teardown/setup of the
> - * helper<->hypervisor interface.
> - *
> - * The monitor interface can be used to register for various VM events. For
> - * example, there are HVM hypercalls to set the per-page access permissions
> - * of every page in a domain.  When one of these permissions--independent,
> - * read, write, and execute--is violated, the VCPU is paused and a memory event
> - * is sent with what happened. The memory event handler can then resume the
> - * VCPU and redo the access with a XEN_VM_EVENT_RESUME option.
> - *
> - * See public/vm_event.h for the list of available events that can be
> - * subscribed to via the monitor interface.
> - *
> - * The XEN_VM_EVENT_MONITOR_* domctls returns
> - * non-standard error codes to indicate why access could not be enabled:
> - * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> - * EBUSY  - guest has or had access enabled, ring buffer still active
> - *
> - */
> -#define XEN_DOMCTL_VM_EVENT_OP_MONITOR           2
> -
> -/*
> - * Sharing ENOMEM helper.
> - *
> - * As with paging, use the domctl for teardown/setup of the
> - * helper<->hypervisor interface.
> - *
> - * If setup, this ring is used to communicate failed allocations
> - * in the unshare path. XENMEM_sharing_op_resume is used to wake up
> - * vcpus that could not unshare.
> - *
> - * Note that shring can be turned on (as per the domctl below)
> - * *without* this ring being setup.
> - */
> -#define XEN_DOMCTL_VM_EVENT_OP_SHARING           3
> -
> -/* Use for teardown/setup of helper<->hypervisor interface for paging,
> - * access and sharing.*/
>  struct xen_domctl_vm_event_op {
> -    uint32_t       op;           /* XEN_VM_EVENT_* */
> -    uint32_t       mode;         /* XEN_DOMCTL_VM_EVENT_OP_* */
> +    uint32_t        op;           /* XEN_VM_EVENT_* */
> +    uint32_t        type;         /* XEN_VM_EVENT_TYPE_* */

Why did the vertical alignment change?

>  
>      union {
>          struct {
> @@ -857,7 +795,10 @@ struct xen_domctl_vm_event_op {
>   * Memory sharing operations
>   */
>  /* XEN_DOMCTL_mem_sharing_op.
> - * The CONTROL sub-domctl is used for bringup/teardown. */
> + * The CONTROL sub-domctl is used for bringup/teardown.
> + * Please note that mem sharing can be turned on *without* setting-up the
> + * correspondin ring
> + */

As a tangent, it can? how?  (I'm entirely prepared to believe that this
is how the code currently works, but I can't see how such a setup would
plausibly work.)

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 3/9] vm_event: Make ‘local’ functions ‘static’
@ 2019-05-31 23:28     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:28 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel; +Cc: Tamas K Lengyel, Razvan Cojocaru

On 30/05/2019 07:18, Petre Pircalabu wrote:
> vm_event_get_response, vm_event_resume, and vm_event_mark_and_pause are
> used only in xen/common/vm_event.c.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>

Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel]  [PATCH 3/9] vm_event: Make ‘local’ functions ‘static’
@ 2019-05-31 23:28     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:28 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel; +Cc: Tamas K Lengyel, Razvan Cojocaru

On 30/05/2019 07:18, Petre Pircalabu wrote:
> vm_event_get_response, vm_event_resume, and vm_event_mark_and_pause are
> used only in xen/common/vm_event.c.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>

Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 4/9] vm_event: Remove "ring" suffix from vm_event_check_ring
@ 2019-05-31 23:32     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:32 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Tamas K Lengyel, Wei Liu, Razvan Cojocaru, George Dunlap,
	Julien Grall, Stefano Stabellini, Jan Beulich,
	Roger Pau Monné

On 30/05/2019 07:18, Petre Pircalabu wrote:
> diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
> index 3505589..1dd3e48 100644
> --- a/xen/common/vm_event.c
> +++ b/xen/common/vm_event.c
> @@ -277,7 +277,7 @@ void vm_event_put_request(struct domain *d,
>      RING_IDX req_prod;
>      struct vcpu *curr = current;
>  
> -    if( !vm_event_check_ring(ved))
> +    if( !vm_event_check(ved))

Ideally with fixing up this style error, as you're changing the line. 
This can be fixed on commit.

Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 4/9] vm_event: Remove "ring" suffix from vm_event_check_ring
@ 2019-05-31 23:32     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:32 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Tamas K Lengyel, Wei Liu, Razvan Cojocaru, George Dunlap,
	Julien Grall, Stefano Stabellini, Jan Beulich,
	Roger Pau Monné

On 30/05/2019 07:18, Petre Pircalabu wrote:
> diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
> index 3505589..1dd3e48 100644
> --- a/xen/common/vm_event.c
> +++ b/xen/common/vm_event.c
> @@ -277,7 +277,7 @@ void vm_event_put_request(struct domain *d,
>      RING_IDX req_prod;
>      struct vcpu *curr = current;
>  
> -    if( !vm_event_check_ring(ved))
> +    if( !vm_event_check(ved))

Ideally with fixing up this style error, as you're changing the line. 
This can be fixed on commit.

Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 5/9] vm_event: Simplify vm_event interface
@ 2019-05-31 23:43     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:43 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Tamas K Lengyel, Razvan Cojocaru, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Tim Deegan, Ian Jackson, Julien Grall,
	Stefano Stabellini, Jan Beulich, Roger Pau Monné

On 30/05/2019 07:18, Petre Pircalabu wrote:
> The domain reference can be part of the vm_event_domain structure
> because for every call to a vm_event interface function both the latter
> and it's corresponding domain are passed as parameters.

It can, but why is adding a backpointer helpful?

I ask because I see 5 reads of ved->d, and nothing which ever
initialises it.

This should be split into two patches.  The first which adds the
backpointer, with working initialisation, and the second which drops the
struct domain parameter from the impacted APIs.

~Andrew

> diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
> index 4c99548..625fc9b 100644
> --- a/xen/arch/x86/mm/p2m.c
> +++ b/xen/arch/x86/mm/p2m.c
> @@ -1704,8 +1704,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn_l)
>      struct p2m_domain *p2m = p2m_get_hostp2m(d);
>  
>      /* We're paging. There should be a ring */
> -    int rc = vm_event_claim_slot(d, d->vm_event_paging);
> -
> +    int rc = vm_event_claim_slot(d->vm_event_paging);

You've dropped a newline here, which should be retained.

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 5/9] vm_event: Simplify vm_event interface
@ 2019-05-31 23:43     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:43 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Tamas K Lengyel, Razvan Cojocaru, Wei Liu, Konrad Rzeszutek Wilk,
	George Dunlap, Tim Deegan, Ian Jackson, Julien Grall,
	Stefano Stabellini, Jan Beulich, Roger Pau Monné

On 30/05/2019 07:18, Petre Pircalabu wrote:
> The domain reference can be part of the vm_event_domain structure
> because for every call to a vm_event interface function both the latter
> and it's corresponding domain are passed as parameters.

It can, but why is adding a backpointer helpful?

I ask because I see 5 reads of ved->d, and nothing which ever
initialises it.

This should be split into two patches.  The first which adds the
backpointer, with working initialisation, and the second which drops the
struct domain parameter from the impacted APIs.

~Andrew

> diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
> index 4c99548..625fc9b 100644
> --- a/xen/arch/x86/mm/p2m.c
> +++ b/xen/arch/x86/mm/p2m.c
> @@ -1704,8 +1704,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn_l)
>      struct p2m_domain *p2m = p2m_get_hostp2m(d);
>  
>      /* We're paging. There should be a ring */
> -    int rc = vm_event_claim_slot(d, d->vm_event_paging);
> -
> +    int rc = vm_event_claim_slot(d->vm_event_paging);

You've dropped a newline here, which should be retained.

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 6/9] vm_event: Move struct vm_event_domain to vm_event.c
@ 2019-05-31 23:44     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:44 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Tamas K Lengyel, Wei Liu, Razvan Cojocaru, Konrad Rzeszutek Wilk,
	George Dunlap, Tim Deegan, Ian Jackson, Julien Grall,
	Stefano Stabellini, Jan Beulich

On 30/05/2019 07:18, Petre Pircalabu wrote:
> The vm_event_domain members are not accessed outside vm_event.c so it's
> better to hide de implementation details.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>

Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>

Are there any files which now no longer need to include sched.h ? 
(Probably not, but it is worth checking)

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 6/9] vm_event: Move struct vm_event_domain to vm_event.c
@ 2019-05-31 23:44     ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-05-31 23:44 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Tamas K Lengyel, Wei Liu, Razvan Cojocaru, Konrad Rzeszutek Wilk,
	George Dunlap, Tim Deegan, Ian Jackson, Julien Grall,
	Stefano Stabellini, Jan Beulich

On 30/05/2019 07:18, Petre Pircalabu wrote:
> The vm_event_domain members are not accessed outside vm_event.c so it's
> better to hide de implementation details.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>

Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>

Are there any files which now no longer need to include sched.h ? 
(Probably not, but it is worth checking)

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 5/9] vm_event: Simplify vm_event interface
@ 2019-06-01  0:06       ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-06-01  0:06 UTC (permalink / raw)
  To: xen-devel

On 31/05/2019 16:43, Andrew Cooper wrote:
> On 30/05/2019 07:18, Petre Pircalabu wrote:
>> The domain reference can be part of the vm_event_domain structure
>> because for every call to a vm_event interface function both the latter
>> and it's corresponding domain are passed as parameters.
> It can, but why is adding a backpointer helpful?
>
> I ask because I see 5 reads of ved->d, and nothing which ever
> initialises it.

P.S. I've finally found the initialisation in patch 7.

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 5/9] vm_event: Simplify vm_event interface
@ 2019-06-01  0:06       ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-06-01  0:06 UTC (permalink / raw)
  To: xen-devel

On 31/05/2019 16:43, Andrew Cooper wrote:
> On 30/05/2019 07:18, Petre Pircalabu wrote:
>> The domain reference can be part of the vm_event_domain structure
>> because for every call to a vm_event interface function both the latter
>> and it's corresponding domain are passed as parameters.
> It can, but why is adding a backpointer helpful?
>
> I ask because I see 5 reads of ved->d, and nothing which ever
> initialises it.

P.S. I've finally found the initialisation in patch 7.

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 0/9] Per vcpu vm_event channels
@ 2019-06-01  0:25   ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-06-01  0:25 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich, Roger Pau Monné

On 30/05/2019 07:18, Petre Pircalabu wrote:
> This patchset adds a new mechanism of sending synchronous vm_event
> requests and handling vm_event responses without using a ring.
> As each synchronous request pauses the vcpu until the corresponding
> response is handled, it can be stored in a slotted memory buffer
> (one per vcpu) shared between the hypervisor and the controlling domain.
>
> The main advantages of this approach are:
> - the ability to dynamicaly allocate the necessary memory used to hold
> the requests/responses (the size of vm_event_request_t/vm_event_response_t
> can grow unrestricted by the ring's one page limitation)
> - the ring's waitqueue logic is unnecessary in this case because the
> vcpu sending the request is blocked until a response is received.
>

Before I review patches 7-9 for more than stylistic things, can you
briefly describe what's next?

AFACT, this introduces a second interface between Xen and the agent,
which is limited to synchronous events only, and exclusively uses
slotted system per vcpu, with a per-vcpu event channel?

What (if any) are the future development plans, and what are the plans
for deprecating the use of the old interface?  (The answers to these
will affect my review of the new interface).

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 0/9] Per vcpu vm_event channels
@ 2019-06-01  0:25   ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-06-01  0:25 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich, Roger Pau Monné

On 30/05/2019 07:18, Petre Pircalabu wrote:
> This patchset adds a new mechanism of sending synchronous vm_event
> requests and handling vm_event responses without using a ring.
> As each synchronous request pauses the vcpu until the corresponding
> response is handled, it can be stored in a slotted memory buffer
> (one per vcpu) shared between the hypervisor and the controlling domain.
>
> The main advantages of this approach are:
> - the ability to dynamicaly allocate the necessary memory used to hold
> the requests/responses (the size of vm_event_request_t/vm_event_response_t
> can grow unrestricted by the ring's one page limitation)
> - the ring's waitqueue logic is unnecessary in this case because the
> vcpu sending the request is blocked until a response is received.
>

Before I review patches 7-9 for more than stylistic things, can you
briefly describe what's next?

AFACT, this introduces a second interface between Xen and the agent,
which is limited to synchronous events only, and exclusively uses
slotted system per vcpu, with a per-vcpu event channel?

What (if any) are the future development plans, and what are the plans
for deprecating the use of the old interface?  (The answers to these
will affect my review of the new interface).

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 3/9] vm_event: Make ‘local’ functions ‘static’
@ 2019-06-02  0:36     ` Tamas K Lengyel
  0 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-06-02  0:36 UTC (permalink / raw)
  To: Petre Pircalabu; +Cc: Xen-devel, Razvan Cojocaru

On Thu, May 30, 2019 at 8:18 AM Petre Pircalabu
<ppircalabu@bitdefender.com> wrote:
>
> vm_event_get_response, vm_event_resume, and vm_event_mark_and_pause are
> used only in xen/common/vm_event.c.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>

Acked-by: Tamas K Lengyel <tamas@tklengyel.com>

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel]  [PATCH 3/9] vm_event: Make ‘local’ functions ‘static’
@ 2019-06-02  0:36     ` Tamas K Lengyel
  0 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-06-02  0:36 UTC (permalink / raw)
  To: Petre Pircalabu; +Cc: Xen-devel, Razvan Cojocaru

On Thu, May 30, 2019 at 8:18 AM Petre Pircalabu
<ppircalabu@bitdefender.com> wrote:
>
> vm_event_get_response, vm_event_resume, and vm_event_mark_and_pause are
> used only in xen/common/vm_event.c.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>

Acked-by: Tamas K Lengyel <tamas@tklengyel.com>

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 6/9] vm_event: Move struct vm_event_domain to vm_event.c
@ 2019-06-03 11:28       ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-03 11:28 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel
  Cc: Tamas K Lengyel, Wei Liu, Razvan Cojocaru, Konrad Rzeszutek Wilk,
	George Dunlap, Tim Deegan, Ian Jackson, Julien Grall,
	Stefano Stabellini, Jan Beulich

On Fri, 2019-05-31 at 16:44 -0700, Andrew Cooper wrote:
> On 30/05/2019 07:18, Petre Pircalabu wrote:
> > The vm_event_domain members are not accessed outside vm_event.c so
> > it's
> > better to hide de implementation details.
> > 
> > Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
> 
> Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
> 
> Are there any files which now no longer need to include sched.h ? 
> (Probably not, but it is worth checking)
> 
> ________________________
> This email was scanned by Bitdefender

The "xen/sched.h header can be removed from the "xen/vm_event.h"
include list by fw declaring "struct domain" and "struct
vm_event_domain".
The vm_event clients (monitor, mem_sharing, mem_paging) need to include
"sched.h" because they need access to the "struct domain" details.

Many thanks,
Petre

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 6/9] vm_event: Move struct vm_event_domain to vm_event.c
@ 2019-06-03 11:28       ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-03 11:28 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel
  Cc: Tamas K Lengyel, Wei Liu, Razvan Cojocaru, Konrad Rzeszutek Wilk,
	George Dunlap, Tim Deegan, Ian Jackson, Julien Grall,
	Stefano Stabellini, Jan Beulich

On Fri, 2019-05-31 at 16:44 -0700, Andrew Cooper wrote:
> On 30/05/2019 07:18, Petre Pircalabu wrote:
> > The vm_event_domain members are not accessed outside vm_event.c so
> > it's
> > better to hide de implementation details.
> > 
> > Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
> 
> Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
> 
> Are there any files which now no longer need to include sched.h ? 
> (Probably not, but it is worth checking)
> 
> ________________________
> This email was scanned by Bitdefender

The "xen/sched.h header can be removed from the "xen/vm_event.h"
include list by fw declaring "struct domain" and "struct
vm_event_domain".
The vm_event clients (monitor, mem_sharing, mem_paging) need to include
"sched.h" because they need access to the "struct domain" details.

Many thanks,
Petre

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 0/9] Per vcpu vm_event channels
@ 2019-06-03 14:04     ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-03 14:04 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich, Roger Pau Monné

On Fri, 2019-05-31 at 17:25 -0700, Andrew Cooper wrote:
> On 30/05/2019 07:18, Petre Pircalabu wrote:
> > This patchset adds a new mechanism of sending synchronous vm_event
> > requests and handling vm_event responses without using a ring.
> > As each synchronous request pauses the vcpu until the corresponding
> > response is handled, it can be stored in a slotted memory buffer
> > (one per vcpu) shared between the hypervisor and the controlling
> > domain.
> > 
> > The main advantages of this approach are:
> > - the ability to dynamicaly allocate the necessary memory used to
> > hold
> > the requests/responses (the size of
> > vm_event_request_t/vm_event_response_t
> > can grow unrestricted by the ring's one page limitation)
> > - the ring's waitqueue logic is unnecessary in this case because
> > the
> > vcpu sending the request is blocked until a response is received.
> > 
> 
> Before I review patches 7-9 for more than stylistic things, can you
> briefly describe what's next?
> 
> AFACT, this introduces a second interface between Xen and the agent,
> which is limited to synchronous events only, and exclusively uses
> slotted system per vcpu, with a per-vcpu event channel?

Using a distinct interface was proposed by George in order to allow the
existing vm_event clients to run unmodified.
> 
> What (if any) are the future development plans, and what are the
> plans
> for deprecating the use of the old interface?  (The answers to these
> will affect my review of the new interface).
> 
> ~Andrew
> 
At the moment, we're only using sync vm_events, so the "one slot per
vcpu" approach suits us. Also, by allocating dynamically the
vm_event_requests/responses, we can increase their size without
suffering the performance drop incurred when using the ring
(+waitqueue).
At this moment, we don't have a schedule to deprecate the legacy (ring
based) interface, but we will adapt the new interface based on the
feedback we receive from other vm_event users. 

> ________________________
> This email was scanned by Bitdefender

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 0/9] Per vcpu vm_event channels
@ 2019-06-03 14:04     ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-03 14:04 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich, Roger Pau Monné

On Fri, 2019-05-31 at 17:25 -0700, Andrew Cooper wrote:
> On 30/05/2019 07:18, Petre Pircalabu wrote:
> > This patchset adds a new mechanism of sending synchronous vm_event
> > requests and handling vm_event responses without using a ring.
> > As each synchronous request pauses the vcpu until the corresponding
> > response is handled, it can be stored in a slotted memory buffer
> > (one per vcpu) shared between the hypervisor and the controlling
> > domain.
> > 
> > The main advantages of this approach are:
> > - the ability to dynamicaly allocate the necessary memory used to
> > hold
> > the requests/responses (the size of
> > vm_event_request_t/vm_event_response_t
> > can grow unrestricted by the ring's one page limitation)
> > - the ring's waitqueue logic is unnecessary in this case because
> > the
> > vcpu sending the request is blocked until a response is received.
> > 
> 
> Before I review patches 7-9 for more than stylistic things, can you
> briefly describe what's next?
> 
> AFACT, this introduces a second interface between Xen and the agent,
> which is limited to synchronous events only, and exclusively uses
> slotted system per vcpu, with a per-vcpu event channel?

Using a distinct interface was proposed by George in order to allow the
existing vm_event clients to run unmodified.
> 
> What (if any) are the future development plans, and what are the
> plans
> for deprecating the use of the old interface?  (The answers to these
> will affect my review of the new interface).
> 
> ~Andrew
> 
At the moment, we're only using sync vm_events, so the "one slot per
vcpu" approach suits us. Also, by allocating dynamically the
vm_event_requests/responses, we can increase their size without
suffering the performance drop incurred when using the ring
(+waitqueue).
At this moment, we don't have a schedule to deprecate the legacy (ring
based) interface, but we will adapt the new interface based on the
feedback we receive from other vm_event users. 

> ________________________
> This email was scanned by Bitdefender

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 5/9] vm_event: Simplify vm_event interface
@ 2019-06-03 15:33         ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-03 15:33 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel

On Fri, 2019-05-31 at 17:06 -0700, Andrew Cooper wrote:
> On 31/05/2019 16:43, Andrew Cooper wrote:
> > On 30/05/2019 07:18, Petre Pircalabu wrote:
> > > The domain reference can be part of the vm_event_domain structure
> > > because for every call to a vm_event interface function both the
> > > latter
> > > and it's corresponding domain are passed as parameters.
> > 
> > It can, but why is adding a backpointer helpful?
> > 
> > I ask because I see 5 reads of ved->d, and nothing which ever
> > initialises it.
> 
> P.S. I've finally found the initialisation in patch 7.
> 
> ~Andrew
> 
My mistake. I've only check if this patch compiles ok. I will fix it
and split the patch according to your suggestions.

Many thanks for noticing,
Petre

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 5/9] vm_event: Simplify vm_event interface
@ 2019-06-03 15:33         ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-03 15:33 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel

On Fri, 2019-05-31 at 17:06 -0700, Andrew Cooper wrote:
> On 31/05/2019 16:43, Andrew Cooper wrote:
> > On 30/05/2019 07:18, Petre Pircalabu wrote:
> > > The domain reference can be part of the vm_event_domain structure
> > > because for every call to a vm_event interface function both the
> > > latter
> > > and it's corresponding domain are passed as parameters.
> > 
> > It can, but why is adding a backpointer helpful?
> > 
> > I ask because I see 5 reads of ved->d, and nothing which ever
> > initialises it.
> 
> P.S. I've finally found the initialisation in patch 7.
> 
> ~Andrew
> 
My mistake. I've only check if this patch compiles ok. I will fix it
and split the patch according to your suggestions.

Many thanks for noticing,
Petre

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-06-03 15:51     ` Jan Beulich
  0 siblings, 0 replies; 67+ messages in thread
From: Jan Beulich @ 2019-06-03 15:51 UTC (permalink / raw)
  To: Petre Pircalabu
  Cc: Stefano Stabellini, WeiLiu, Razvan Cojocaru,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Tamas K Lengyel, xen-devel

>>> On 30.05.19 at 16:18, <ppircalabu@bitdefender.com> wrote:
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -38,7 +38,7 @@
>  #include "hvm/save.h"
>  #include "memory.h"
>  
> -#define XEN_DOMCTL_INTERFACE_VERSION 0x00000011
> +#define XEN_DOMCTL_INTERFACE_VERSION 0x00000012

I don't think such a bump is needed - afaict the interface remains
binary compatible.

Jan



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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-06-03 15:51     ` Jan Beulich
  0 siblings, 0 replies; 67+ messages in thread
From: Jan Beulich @ 2019-06-03 15:51 UTC (permalink / raw)
  To: Petre Pircalabu
  Cc: Stefano Stabellini, WeiLiu, Razvan Cojocaru,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Tamas K Lengyel, xen-devel

>>> On 30.05.19 at 16:18, <ppircalabu@bitdefender.com> wrote:
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -38,7 +38,7 @@
>  #include "hvm/save.h"
>  #include "memory.h"
>  
> -#define XEN_DOMCTL_INTERFACE_VERSION 0x00000011
> +#define XEN_DOMCTL_INTERFACE_VERSION 0x00000012

I don't think such a bump is needed - afaict the interface remains
binary compatible.

Jan



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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-06-03 22:22       ` Tamas K Lengyel
  0 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-06-03 22:22 UTC (permalink / raw)
  To: Andrew Cooper
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Jan Beulich, Xen-devel

> >  /* XEN_DOMCTL_mem_sharing_op.
> > - * The CONTROL sub-domctl is used for bringup/teardown. */
> > + * The CONTROL sub-domctl is used for bringup/teardown.
> > + * Please note that mem sharing can be turned on *without* setting-up the
> > + * correspondin ring
> > + */
>
> As a tangent, it can? how?  (I'm entirely prepared to believe that this
> is how the code currently works, but I can't see how such a setup would
> plausibly work.)

The vm_event ring for mem_sharing is only used to communicate
out-of-memory condition to an external listener. I think it's only
useful for logging since the listener wouldn't really be in a position
to try to "make space" for the faulting domain and it would get
destroyed after the message is sent. In any case, there isn't any
documentation for how it was intended to be used so this is just my
guess.

Tamas

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-06-03 22:22       ` Tamas K Lengyel
  0 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-06-03 22:22 UTC (permalink / raw)
  To: Andrew Cooper
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Jan Beulich, Xen-devel

> >  /* XEN_DOMCTL_mem_sharing_op.
> > - * The CONTROL sub-domctl is used for bringup/teardown. */
> > + * The CONTROL sub-domctl is used for bringup/teardown.
> > + * Please note that mem sharing can be turned on *without* setting-up the
> > + * correspondin ring
> > + */
>
> As a tangent, it can? how?  (I'm entirely prepared to believe that this
> is how the code currently works, but I can't see how such a setup would
> plausibly work.)

The vm_event ring for mem_sharing is only used to communicate
out-of-memory condition to an external listener. I think it's only
useful for logging since the listener wouldn't really be in a position
to try to "make space" for the faulting domain and it would get
destroyed after the message is sent. In any case, there isn't any
documentation for how it was intended to be used so this is just my
guess.

Tamas

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-06-03 22:26         ` Tamas K Lengyel
  0 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-06-03 22:26 UTC (permalink / raw)
  To: Andrew Cooper
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Jan Beulich, Xen-devel

On Mon, Jun 3, 2019 at 4:22 PM Tamas K Lengyel <tamas@tklengyel.com> wrote:
>
> > >  /* XEN_DOMCTL_mem_sharing_op.
> > > - * The CONTROL sub-domctl is used for bringup/teardown. */
> > > + * The CONTROL sub-domctl is used for bringup/teardown.
> > > + * Please note that mem sharing can be turned on *without* setting-up the
> > > + * correspondin ring
> > > + */
> >
> > As a tangent, it can? how?  (I'm entirely prepared to believe that this
> > is how the code currently works, but I can't see how such a setup would
> > plausibly work.)
>
> The vm_event ring for mem_sharing is only used to communicate
> out-of-memory condition to an external listener. I think it's only
> useful for logging since the listener wouldn't really be in a position
> to try to "make space" for the faulting domain and it would get
> destroyed after the message is sent. In any case, there isn't any
> documentation for how it was intended to be used so this is just my
> guess.

Actually, it seems the listener was intended to be able to try to
"make space" for the domain. How exactly is not clear but anyway, the
domain would get paused if there is a listener instead of just being
destroyed when there is an ENOMEM error while trying to deduplicate
shared pages.

Tamas

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-06-03 22:26         ` Tamas K Lengyel
  0 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-06-03 22:26 UTC (permalink / raw)
  To: Andrew Cooper
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Jan Beulich, Xen-devel

On Mon, Jun 3, 2019 at 4:22 PM Tamas K Lengyel <tamas@tklengyel.com> wrote:
>
> > >  /* XEN_DOMCTL_mem_sharing_op.
> > > - * The CONTROL sub-domctl is used for bringup/teardown. */
> > > + * The CONTROL sub-domctl is used for bringup/teardown.
> > > + * Please note that mem sharing can be turned on *without* setting-up the
> > > + * correspondin ring
> > > + */
> >
> > As a tangent, it can? how?  (I'm entirely prepared to believe that this
> > is how the code currently works, but I can't see how such a setup would
> > plausibly work.)
>
> The vm_event ring for mem_sharing is only used to communicate
> out-of-memory condition to an external listener. I think it's only
> useful for logging since the listener wouldn't really be in a position
> to try to "make space" for the faulting domain and it would get
> destroyed after the message is sent. In any case, there isn't any
> documentation for how it was intended to be used so this is just my
> guess.

Actually, it seems the listener was intended to be able to try to
"make space" for the domain. How exactly is not clear but anyway, the
domain would get paused if there is a listener instead of just being
destroyed when there is an ENOMEM error while trying to deduplicate
shared pages.

Tamas

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-06-04 10:12       ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-04 10:12 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich

On Fri, 2019-05-31 at 16:26 -0700, Andrew Cooper wrote:
> On 30/05/2019 07:18, Petre Pircalabu wrote:
> > 
> 
> This is an internal helper, so can reasonably be expected to not be
> called with junk, and can do away with the param pointer.
> 
> Something like
> 
> static int xc_vm_event_ring_pfn_param(unsigned int type)
> {
>     switch ( type )
>     {
>         case XEN_VM_EVENT_TYPE_PAGING:
>             return HVM_PARAM_PAGING_RING_PFN;
> ...
>         default:
>             return -EINVAL;
>     }
> }
> 
> will work fine because HVM_PARAM_* are all tiny unsigned integers in
> practice.  It also has a more sensible API for the caller.

I think in the end it's best just to move the helper to
xc_vm_event_enable (inline the switch) as it is not use outside it.

> 
> > index 19486d5..19281fa 100644
> > --- a/xen/include/public/domctl.h
> > +++ b/xen/include/public/domctl.h
> > @@ -769,80 +769,18 @@ struct xen_domctl_gdbsx_domstatus {
> >   * VM event operations
> >   */
> >  
> > 
> > -
> > -/* Use for teardown/setup of helper<->hypervisor interface for
> > paging,
> > - * access and sharing.*/
> >  struct xen_domctl_vm_event_op {
> > -    uint32_t       op;           /* XEN_VM_EVENT_* */
> > -    uint32_t       mode;         /* XEN_DOMCTL_VM_EVENT_OP_* */
> > +    uint32_t        op;           /* XEN_VM_EVENT_* */
> > +    uint32_t        type;         /* XEN_VM_EVENT_TYPE_* */
> 
> Why did the vertical alignment change?

The initial vertical alignment was not 4 spaces (I will revert it back
to the way it was in order to simplify the review  )
> 

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 2/9] vm_event: Define VM_EVENT type
@ 2019-06-04 10:12       ` Petre Ovidiu PIRCALABU
  0 siblings, 0 replies; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-04 10:12 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich

On Fri, 2019-05-31 at 16:26 -0700, Andrew Cooper wrote:
> On 30/05/2019 07:18, Petre Pircalabu wrote:
> > 
> 
> This is an internal helper, so can reasonably be expected to not be
> called with junk, and can do away with the param pointer.
> 
> Something like
> 
> static int xc_vm_event_ring_pfn_param(unsigned int type)
> {
>     switch ( type )
>     {
>         case XEN_VM_EVENT_TYPE_PAGING:
>             return HVM_PARAM_PAGING_RING_PFN;
> ...
>         default:
>             return -EINVAL;
>     }
> }
> 
> will work fine because HVM_PARAM_* are all tiny unsigned integers in
> practice.  It also has a more sensible API for the caller.

I think in the end it's best just to move the helper to
xc_vm_event_enable (inline the switch) as it is not use outside it.

> 
> > index 19486d5..19281fa 100644
> > --- a/xen/include/public/domctl.h
> > +++ b/xen/include/public/domctl.h
> > @@ -769,80 +769,18 @@ struct xen_domctl_gdbsx_domstatus {
> >   * VM event operations
> >   */
> >  
> > 
> > -
> > -/* Use for teardown/setup of helper<->hypervisor interface for
> > paging,
> > - * access and sharing.*/
> >  struct xen_domctl_vm_event_op {
> > -    uint32_t       op;           /* XEN_VM_EVENT_* */
> > -    uint32_t       mode;         /* XEN_DOMCTL_VM_EVENT_OP_* */
> > +    uint32_t        op;           /* XEN_VM_EVENT_* */
> > +    uint32_t        type;         /* XEN_VM_EVENT_TYPE_* */
> 
> Why did the vertical alignment change?

The initial vertical alignment was not 4 spaces (I will revert it back
to the way it was in order to simplify the review  )
> 

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 1/9] tools/libxc: Consistent usage of xc_vm_event_* interface
  2019-05-31 23:01     ` [Xen-devel] " Andrew Cooper
  (?)
@ 2019-06-04 14:23     ` Petre Ovidiu PIRCALABU
  2019-06-04 16:07       ` Andrew Cooper
  -1 siblings, 1 reply; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-04 14:23 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: Ian Jackson, Wei Liu

On Fri, 2019-05-31 at 16:01 -0700, Andrew Cooper wrote:
> On 30/05/2019 07:18, Petre Pircalabu wrote:
> > Modified xc_mem_paging_enable to use directly xc_vm_event_enable
> > and
> > moved the ring_page handling from client to libxc (xenpaging).
> > 
> > Restricted vm_event_control usage only to simplest domctls which do
> > not expect any return values and change xc_vm_event_enable to call
> > do_domctl
> > directly.
> > 
> > Removed xc_memshr_ring_enable/disable and xc_memshr_domain_resume.
> > 
> > Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
> > ---
> >  tools/libxc/include/xenctrl.h | 49 +----------------------------
> > ----
> >  tools/libxc/xc_mem_paging.c   | 23 +++++-----------
> >  tools/libxc/xc_memshr.c       | 34 -----------------------
> >  tools/libxc/xc_monitor.c      | 31 +++++++++++++++++----
> >  tools/libxc/xc_private.h      |  2 +-
> >  tools/libxc/xc_vm_event.c     | 64 ++++++++++++++++---------------
> > ------------
> >  tools/xenpaging/xenpaging.c   | 42 +++-------------------------
> 
> So, the diffstat here is very impressive, and judging by the delta,
> its
> all about not opencoding the use of the HVM_PARAM interface. 
> Overall,
> this is clearly a good thing.
> 
> However, it is quite difficult to follow exactly what is going on.
> 
> AFAICT, this wants splitting into $N patches.
> 
> One patch should refactor xc_mem_paging_enable() to use
> xc_vm_event_enable(), with the associated xenpaging cleanup.
> 
> One patch should be the deletion of xc_memshr_* on its own, because
> AFAICT it is an isolated change.  It also needs some justification,
> even
> if it is "interface is unused and/or redundant with $X".
> 
> One patch (alone) should be the repositioning of the domain_pause()
> calls.  This does certainly look like a vast improvement WRT error
> handling in xc_vm_event_enable(), but you've definitely changed the
> API
> (insofar as the expectation that the caller has paused the domain)
> goes,
> and its not at all obvious that this change is safe.  It may very
> well
> be, but you need to convince people as to why in the commit message.
> 
> 
> I still haven't figured out what the purpose behind dropping the port
> parameter from xc_vm_event_control() is.
> 
> ~Andrew

The main reason for this patch was to use an uniform calling convention
for all xc_vm_event wrappers. 
However, at this stage I think it's best to drop it altogheter as it's
not a requirement for the new vm_event interface (new domctls are used
along with their own separate wrappers).

Many thanks for your support,
Petre


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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 8/9] vm_event: Add vm_event_ng interface
  2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
  (?)
@ 2019-06-04 14:43   ` Andrew Cooper
  2019-06-05 17:01     ` Petre Ovidiu PIRCALABU
  -1 siblings, 1 reply; 67+ messages in thread
From: Andrew Cooper @ 2019-06-04 14:43 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich, Roger Pau Monné

On 30/05/2019 15:18, Petre Pircalabu wrote:
> In high throughput introspection scenarios where lots of monitor
> vm_events are generated, the ring buffer can fill up before the monitor
> application gets a chance to handle all the requests thus blocking
> other vcpus which will have to wait for a slot to become available.
>
> This patch adds support for a different mechanism to handle synchronous
> vm_event requests / responses. As each synchronous request pauses the
> vcpu until the corresponding response is handled, it can be stored in
> a slotted memory buffer (one per vcpu) shared between the hypervisor and
> the controlling domain.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>

There are a number of concerns here.

First and foremost, why is a new domctl being added?  Surely this should
just be a "type of ring access" parameter to event_enable?  Everything
else in the vm_event set of APIs should be unchanged as a result of the
interface differences.

Or am I missing something?

> diff --git a/xen/common/vm_event_ng.c b/xen/common/vm_event_ng.c
> new file mode 100644
> index 0000000..17ae33c
> --- /dev/null
> +++ b/xen/common/vm_event_ng.c
> <snip>
>
> +static int vm_event_channels_alloc_buffer(struct vm_event_channels_domain *impl)
> +{
> +    int i, rc = -ENOMEM;
> +
> +    for ( i = 0; i < impl->nr_frames; i++ )
> +    {
> +        struct page_info *page = alloc_domheap_page(impl->ved.d, 0);

This creates pages which are reference-able (in principle) by the guest,
and are bounded by d->max_pages.

Both of these are properties of the existing interface which we'd prefer
to remove.

> +        if ( !page )
> +            goto err;
> +
> +        if ( !get_page_and_type(page, impl->ved.d, PGT_writable_page) )
> +        {
> +            rc = -ENODATA;
> +            goto err;
> +        }
> +
> +        impl->mfn[i] = page_to_mfn(page);
> +    }
> +
> +    impl->slots = (struct vm_event_slot *)vmap(impl->mfn, impl->nr_frames);

You appear to have opencoded vmalloc() here.  Is there any reason not to
use that?

> +    if ( !impl->slots )
> +        goto err;
> +
> +    for ( i = 0; i < impl->nr_frames; i++ )
> +        clear_page((void*)impl->slots + i * PAGE_SIZE);
> +
> +    return 0;
> +
> +err:
> +    while ( --i >= 0 )
> +    {
> +        struct page_info *page = mfn_to_page(impl->mfn[i]);
> +
> +        if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
> +            put_page(page);
> +        put_page_and_type(page);
> +    }
> +
> +    return rc;
> +}
> +
> +static void vm_event_channels_free_buffer(struct vm_event_channels_domain *impl)
> +{
> +    int i;
> +
> +    ASSERT(impl);
> +
> +    if ( !impl->slots )
> +        return;
> +
> +    vunmap(impl->slots);
> +
> +    for ( i = 0; i < impl->nr_frames; i++ )
> +    {
> +        struct page_info *page = mfn_to_page(impl->mfn[i]);
> +
> +        ASSERT(page);

mfn_to_page() is going to explode before this ASSERT() does.

> +        if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
> +            put_page(page);
> +        put_page_and_type(page);
> +    }
> +}
> +
> +static int vm_event_channels_create(
> +    struct domain *d,
> +    struct xen_domctl_vm_event_ng_op *vec,
> +    struct vm_event_domain **_ved,
> +    int pause_flag,
> +    xen_event_channel_notification_t notification_fn)
> +{
> +    int rc, i;
> +    unsigned int nr_frames = PFN_UP(d->max_vcpus * sizeof(struct vm_event_slot));
> +    struct vm_event_channels_domain *impl;
> +
> +    if ( *_ved )
> +        return -EBUSY;
> +
> +    impl = _xzalloc(sizeof(struct vm_event_channels_domain) +
> +                           nr_frames * sizeof(mfn_t),
> +                    __alignof__(struct vm_event_channels_domain));
> +    if ( unlikely(!impl) )
> +        return -ENOMEM;
> +
> +    spin_lock_init(&impl->ved.lock);
> +    spin_lock(&impl->ved.lock);
> +
> +    impl->nr_frames = nr_frames;
> +    impl->ved.d = d;
> +    impl->ved.ops = &vm_event_channels_ops;
> +
> +    rc = vm_event_init_domain(d);
> +    if ( rc < 0 )
> +        goto err;
> +
> +    rc = vm_event_channels_alloc_buffer(impl);
> +    if ( rc )
> +        goto err;
> +
> +    for ( i = 0; i < d->max_vcpus; i++ )
> +    {
> +        rc = alloc_unbound_xen_event_channel(d, i, current->domain->domain_id,
> +                                             notification_fn);
> +        if ( rc < 0 )
> +            goto err;
> +
> +        impl->slots[i].port = rc;
> +        impl->slots[i].state = STATE_VM_EVENT_SLOT_IDLE;
> +    }
> +
> +    impl->enabled = false;
> +
> +    spin_unlock(&impl->ved.lock);
> +    *_ved = &impl->ved;
> +    return 0;
> +
> +err:
> +    spin_unlock(&impl->ved.lock);
> +    XFREE(impl);

You don't free the event channels on error.

Please write make the destructor idempotent and call it from here.

> +    return rc;
> +}
> +
> <snip>
> +int vm_event_ng_domctl(struct domain *d, struct xen_domctl_vm_event_ng_op *vec,
> +                       XEN_GUEST_HANDLE_PARAM(void) u_domctl)
> +{
> +    int rc;
> +
> +    if ( vec->op == XEN_VM_EVENT_NG_GET_VERSION )
> +    {
> +        vec->u.version = VM_EVENT_INTERFACE_VERSION;
> +        return 0;
> +    }
> +
> +    if ( unlikely(d == NULL) )
> +        return -ESRCH;
> +
> +    rc = xsm_vm_event_control(XSM_PRIV, d, vec->type, vec->op);
> +    if ( rc )
> +        return rc;
> +
> +    if ( unlikely(d == current->domain) ) /* no domain_pause() */
> +    {
> +        gdprintk(XENLOG_INFO, "Tried to do a memory event op on itself.\n");
> +        return -EINVAL;
> +    }
> +
> +    if ( unlikely(d->is_dying) )
> +    {
> +        gdprintk(XENLOG_INFO, "Ignoring memory event op on dying domain %u\n",
> +                 d->domain_id);
> +        return 0;
> +    }
> +
> +    if ( unlikely(d->vcpu == NULL) || unlikely(d->vcpu[0] == NULL) )
> +    {
> +        gdprintk(XENLOG_INFO,
> +                 "Memory event op on a domain (%u) with no vcpus\n",
> +                 d->domain_id);
> +        return -EINVAL;
> +    }
> +
> +    switch ( vec->type )
> +    {
> +    case XEN_VM_EVENT_TYPE_MONITOR:
> +    {
> +        rc = -EINVAL;
> +
> +        switch ( vec-> op)
> +        {
> +        case XEN_VM_EVENT_NG_CREATE:
> +            /* domain_pause() not required here, see XSA-99 */
> +            rc = arch_monitor_init_domain(d);
> +            if ( rc )
> +                break;
> +            rc = vm_event_channels_create(d, vec, &d->vm_event_monitor,
> +                                     _VPF_mem_access, monitor_notification);
> +            break;
> +
> +        case XEN_VM_EVENT_NG_DESTROY:
> +            if ( !vm_event_check(d->vm_event_monitor) )
> +                break;
> +            domain_pause(d);
> +            rc = vm_event_channels_destroy(&d->vm_event_monitor);
> +            arch_monitor_cleanup_domain(d);
> +            domain_unpause(d);
> +            break;
> +
> +        case XEN_VM_EVENT_NG_SET_STATE:
> +            if ( !vm_event_check(d->vm_event_monitor) )
> +                break;
> +            domain_pause(d);
> +            to_channels(d->vm_event_monitor)->enabled = !!vec->u.enabled;
> +            domain_unpause(d);
> +            rc = 0;
> +            break;
> +
> +        default:
> +            rc = -ENOSYS;
> +        }
> +        break;
> +    }
> +
> +#ifdef CONFIG_HAS_MEM_PAGING
> +    case XEN_VM_EVENT_TYPE_PAGING:
> +#endif
> +
> +#ifdef CONFIG_HAS_MEM_SHARING
> +    case XEN_VM_EVENT_TYPE_SHARING:
> +#endif

These are unnecessary, as they don't deviate from the default.

~Andrew

> +
> +    default:
> +        rc = -ENOSYS;
> +    }
> +
> +    return rc;
> +}
>


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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 9/9] xen-access: Add support for vm_event_ng interface
  2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
  (?)
@ 2019-06-04 16:04   ` Andrew Cooper
  -1 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-06-04 16:04 UTC (permalink / raw)
  To: Petre Pircalabu, xen-devel
  Cc: Tamas K Lengyel, Ian Jackson, Razvan Cojocaru, Wei Liu

On 30/05/2019 15:18, Petre Pircalabu wrote:
> +#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 )

|| info.domid != domain_id

The API is idiotic.  However... (see several below)

> +    {
> +        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));

This is C, not C++

> +    if ( !impl )
> +        return -ENOMEM;
> +
> +    impl->num_vcpus = num_vcpus;
> +
> +    impl->fmem = xenforeignmemory_open(0,0);

Spaces and NULL.

> +    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);

... one big problem with the existing vm_event interface is that it
requires domctls.

In particular, I was hoping we could take the opportunity of this new
interface to see if we could also remove the use of all unstable interfaces.

Do you happen to know offhand which non-stable hypercalls are currently
needed for introspection purposes?

> +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

Here and elsewhere, a trailing comma please.  It simplifies future diffs.

> 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
>
> +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 ) {

Style, seeing as you're moving it anyway.

> 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)

This looks like the patch wants at least splitting into two.  The first
doing cleanup/renaming/etc, and the second doing the interface
splitting.  Perhaps even a 3rd for the getopt() change.

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 1/9] tools/libxc: Consistent usage of xc_vm_event_* interface
  2019-06-04 14:23     ` Petre Ovidiu PIRCALABU
@ 2019-06-04 16:07       ` Andrew Cooper
  0 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-06-04 16:07 UTC (permalink / raw)
  To: Petre Ovidiu PIRCALABU, xen-devel; +Cc: Ian Jackson, Wei Liu

On 04/06/2019 15:23, Petre Ovidiu PIRCALABU wrote:
> On Fri, 2019-05-31 at 16:01 -0700, Andrew Cooper wrote:
>> On 30/05/2019 07:18, Petre Pircalabu wrote:
>>> Modified xc_mem_paging_enable to use directly xc_vm_event_enable
>>> and
>>> moved the ring_page handling from client to libxc (xenpaging).
>>>
>>> Restricted vm_event_control usage only to simplest domctls which do
>>> not expect any return values and change xc_vm_event_enable to call
>>> do_domctl
>>> directly.
>>>
>>> Removed xc_memshr_ring_enable/disable and xc_memshr_domain_resume.
>>>
>>> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
>>> ---
>>>  tools/libxc/include/xenctrl.h | 49 +----------------------------
>>> ----
>>>  tools/libxc/xc_mem_paging.c   | 23 +++++-----------
>>>  tools/libxc/xc_memshr.c       | 34 -----------------------
>>>  tools/libxc/xc_monitor.c      | 31 +++++++++++++++++----
>>>  tools/libxc/xc_private.h      |  2 +-
>>>  tools/libxc/xc_vm_event.c     | 64 ++++++++++++++++---------------
>>> ------------
>>>  tools/xenpaging/xenpaging.c   | 42 +++-------------------------
>> So, the diffstat here is very impressive, and judging by the delta,
>> its
>> all about not opencoding the use of the HVM_PARAM interface. 
>> Overall,
>> this is clearly a good thing.
>>
>> However, it is quite difficult to follow exactly what is going on.
>>
>> AFAICT, this wants splitting into $N patches.
>>
>> One patch should refactor xc_mem_paging_enable() to use
>> xc_vm_event_enable(), with the associated xenpaging cleanup.
>>
>> One patch should be the deletion of xc_memshr_* on its own, because
>> AFAICT it is an isolated change.  It also needs some justification,
>> even
>> if it is "interface is unused and/or redundant with $X".
>>
>> One patch (alone) should be the repositioning of the domain_pause()
>> calls.  This does certainly look like a vast improvement WRT error
>> handling in xc_vm_event_enable(), but you've definitely changed the
>> API
>> (insofar as the expectation that the caller has paused the domain)
>> goes,
>> and its not at all obvious that this change is safe.  It may very
>> well
>> be, but you need to convince people as to why in the commit message.
>>
>>
>> I still haven't figured out what the purpose behind dropping the port
>> parameter from xc_vm_event_control() is.
>>
>> ~Andrew
> The main reason for this patch was to use an uniform calling convention
> for all xc_vm_event wrappers.

The cleanup is a great, but it needs to be in finer grained patches so
it can be followed more easily.

> However, at this stage I think it's best to drop it altogheter as it's
> not a requirement for the new vm_event interface (new domctls are used
> along with their own separate wrappers).

See patch 8 for the discussion on why a new domctl probably isn't the
right course of action.

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 2/9] vm_event: Define VM_EVENT type
  2019-06-03 22:26         ` [Xen-devel] " Tamas K Lengyel
  (?)
@ 2019-06-04 16:09         ` Andrew Cooper
  -1 siblings, 0 replies; 67+ messages in thread
From: Andrew Cooper @ 2019-06-04 16:09 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: Petre Pircalabu, Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Jan Beulich, Xen-devel

On 03/06/2019 23:26, Tamas K Lengyel wrote:
> On Mon, Jun 3, 2019 at 4:22 PM Tamas K Lengyel <tamas@tklengyel.com> wrote:
>>>>  /* XEN_DOMCTL_mem_sharing_op.
>>>> - * The CONTROL sub-domctl is used for bringup/teardown. */
>>>> + * The CONTROL sub-domctl is used for bringup/teardown.
>>>> + * Please note that mem sharing can be turned on *without* setting-up the
>>>> + * correspondin ring
>>>> + */
>>> As a tangent, it can? how?  (I'm entirely prepared to believe that this
>>> is how the code currently works, but I can't see how such a setup would
>>> plausibly work.)
>> The vm_event ring for mem_sharing is only used to communicate
>> out-of-memory condition to an external listener. I think it's only
>> useful for logging since the listener wouldn't really be in a position
>> to try to "make space" for the faulting domain and it would get
>> destroyed after the message is sent. In any case, there isn't any
>> documentation for how it was intended to be used so this is just my
>> guess.
> Actually, it seems the listener was intended to be able to try to
> "make space" for the domain. How exactly is not clear but anyway, the
> domain would get paused if there is a listener instead of just being
> destroyed when there is an ENOMEM error while trying to deduplicate
> shared pages.

I can't say I'm surprised by this...

~Andrew

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 4/9] vm_event: Remove "ring" suffix from vm_event_check_ring
  2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
  (?)
  (?)
@ 2019-06-05 15:52   ` Tamas K Lengyel
  -1 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-06-05 15:52 UTC (permalink / raw)
  To: Petre Pircalabu
  Cc: Stefano Stabellini, Wei Liu, Razvan Cojocaru, George Dunlap,
	Andrew Cooper, Julien Grall, Jan Beulich, Xen-devel,
	Roger Pau Monné

On Thu, May 30, 2019 at 8:18 AM Petre Pircalabu
<ppircalabu@bitdefender.com> wrote:
>
> Decouple implementation from interface to allow vm_event_check to be
> used regardless of the vm_event underlying implementation.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>

Acked-by: Tamas K Lengyel <tamas@tklengyel.com>

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 6/9] vm_event: Move struct vm_event_domain to vm_event.c
  2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
  (?)
  (?)
@ 2019-06-05 15:53   ` Tamas K Lengyel
  -1 siblings, 0 replies; 67+ messages in thread
From: Tamas K Lengyel @ 2019-06-05 15:53 UTC (permalink / raw)
  To: Petre Pircalabu
  Cc: Stefano Stabellini, Wei Liu, Razvan Cojocaru,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Jan Beulich, Xen-devel

On Thu, May 30, 2019 at 8:18 AM Petre Pircalabu
<ppircalabu@bitdefender.com> wrote:
>
> The vm_event_domain members are not accessed outside vm_event.c so it's
> better to hide de implementation details.
>
> Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>

Acked-by: Tamas K Lengyel <tamas@tklengyel.com>

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 8/9] vm_event: Add vm_event_ng interface
  2019-06-04 14:43   ` Andrew Cooper
@ 2019-06-05 17:01     ` Petre Ovidiu PIRCALABU
  2019-06-06  8:37       ` Jan Beulich
  0 siblings, 1 reply; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-05 17:01 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel
  Cc: Stefano Stabellini, Razvan Cojocaru, Wei Liu,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, Jan Beulich, Roger Pau Monné

On Tue, 2019-06-04 at 15:43 +0100, Andrew Cooper wrote:
> On 30/05/2019 15:18, Petre Pircalabu wrote:
> > 
> > Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
> 
> There are a number of concerns here.
> 
> First and foremost, why is a new domctl being added?  Surely this
> should
> just be a "type of ring access" parameter to event_enable? 
> Everything
> else in the vm_event set of APIs should be unchanged as a result of
> the
> interface differences.
> 
> Or am I missing something?
> 
I've used different domctls in order to completely separate the new
interface from the old one.
One thing I don't really like about the old vm_event interface is that
the "create" and "start" operations are handled in the same call
(XEN_VM_EVENT_ENABLE).
These calls should separated in the new interface because the client
needs to perform its own initalization (mapping the resource and event
channel binding) between "create" and "start".

> > diff --git a/xen/common/vm_event_ng.c b/xen/common/vm_event_ng.c
> > new file mode 100644
> > index 0000000..17ae33c
> > --- /dev/null
> > +++ b/xen/common/vm_event_ng.c
> > <snip>
> > 
> > +static int vm_event_channels_alloc_buffer(struct
> > vm_event_channels_domain *impl)
> > +{
> > +    int i, rc = -ENOMEM;
> > +
> > +    for ( i = 0; i < impl->nr_frames; i++ )
> > +    {
> > +        struct page_info *page = alloc_domheap_page(impl->ved.d,
> > 0);
> 
> This creates pages which are reference-able (in principle) by the
> guest,
> and are bounded by d->max_pages.
> 
> Both of these are properties of the existing interface which we'd
> prefer
> to remove.
The allocation mechanism is similar with the one used by ioreq (the
main difference is the number of pages).
> 
> > +        if ( !page )
> > +            goto err;
> > +
> > +        if ( !get_page_and_type(page, impl->ved.d,
> > PGT_writable_page) )
> > +        {
> > +            rc = -ENODATA;
> > +            goto err;
> > +        }
> > +
> > +        impl->mfn[i] = page_to_mfn(page);
> > +    }
> > +
> > +    impl->slots = (struct vm_event_slot *)vmap(impl->mfn, impl-
> > >nr_frames);
> 
> You appear to have opencoded vmalloc() here.  Is there any reason not
> to
> use that?
> 

The problem with vmalloc is that if the pages are not assigned to a
specific domain the remapping fails in the monitor domain.
e.g.:
...
(XEN) mm.c:1015:d0v2 pg_owner d1 l1e_owner d0, but real_pg_owner d-1
(XEN) mm.c:1091:d0v7 Error getting mfn 5fbf53 (pfn ffffffffffffffff)
from L1 entry 80000005fbf53227 for l1e_owner d0, pg_owner d1

> > +err:
> > +    spin_unlock(&impl->ved.lock);
> > +    XFREE(impl);
> 
> You don't free the event channels on error.
> 
> Please write make the destructor idempotent and call it from here.
> 
> > 
> > +#ifdef CONFIG_HAS_MEM_PAGING
> > +    case XEN_VM_EVENT_TYPE_PAGING:
> > +#endif
> > +
> > +#ifdef CONFIG_HAS_MEM_SHARING
> > +    case XEN_VM_EVENT_TYPE_SHARING:
> > +#endif
> 
> These are unnecessary, as they don't deviate from the default.
> 
> ~Andrew
> 
> > 
I will correct these in the next patchset iteration.

Many thanks for your support,
Petre

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 8/9] vm_event: Add vm_event_ng interface
  2019-06-05 17:01     ` Petre Ovidiu PIRCALABU
@ 2019-06-06  8:37       ` Jan Beulich
  2019-06-06 13:48         ` Petre Ovidiu PIRCALABU
  0 siblings, 1 reply; 67+ messages in thread
From: Jan Beulich @ 2019-06-06  8:37 UTC (permalink / raw)
  To: Petre Pircalabu, Andrew Cooper
  Cc: Stefano Stabellini, WeiLiu, Razvan Cojocaru,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, xen-devel, Roger Pau Monne

>>> On 05.06.19 at 19:01, <ppircalabu@bitdefender.com> wrote:
> On Tue, 2019-06-04 at 15:43 +0100, Andrew Cooper wrote:
>> On 30/05/2019 15:18, Petre Pircalabu wrote:
>> > +static int vm_event_channels_alloc_buffer(struct
>> > vm_event_channels_domain *impl)
>> > +{
>> > +    int i, rc = -ENOMEM;
>> > +
>> > +    for ( i = 0; i < impl->nr_frames; i++ )
>> > +    {
>> > +        struct page_info *page = alloc_domheap_page(impl->ved.d,
>> > 0);
>> 
>> This creates pages which are reference-able (in principle) by the
>> guest,
>> and are bounded by d->max_pages.

Not by a HVM one, because they can't reference pages by MFN.
Or else, as Petre implies, the ioreq approach would be wrong, too.

>> Both of these are properties of the existing interface which we'd
>> prefer
>> to remove.
> The allocation mechanism is similar with the one used by ioreq (the
> main difference is the number of pages).

Question is whether here you want to use the "caller owned"
variant. I haven't thought through whether this would actually
be better, so it's merely a remark.

>> > +        if ( !page )
>> > +            goto err;
>> > +
>> > +        if ( !get_page_and_type(page, impl->ved.d,
>> > PGT_writable_page) )
>> > +        {
>> > +            rc = -ENODATA;
>> > +            goto err;
>> > +        }
>> > +
>> > +        impl->mfn[i] = page_to_mfn(page);
>> > +    }
>> > +
>> > +    impl->slots = (struct vm_event_slot *)vmap(impl->mfn, impl-
>> > >nr_frames);
>> 
>> You appear to have opencoded vmalloc() here.  Is there any reason not
>> to
>> use that?
>> 
> 
> The problem with vmalloc is that if the pages are not assigned to a
> specific domain the remapping fails in the monitor domain.
> e.g.:
> ...
> (XEN) mm.c:1015:d0v2 pg_owner d1 l1e_owner d0, but real_pg_owner d-1
> (XEN) mm.c:1091:d0v7 Error getting mfn 5fbf53 (pfn ffffffffffffffff)
> from L1 entry 80000005fbf53227 for l1e_owner d0, pg_owner d1

In which case maybe use vmalloc() and then assign_pages()?

Jan



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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 8/9] vm_event: Add vm_event_ng interface
  2019-06-06  8:37       ` Jan Beulich
@ 2019-06-06 13:48         ` Petre Ovidiu PIRCALABU
  2019-06-06 14:16           ` Jan Beulich
  0 siblings, 1 reply; 67+ messages in thread
From: Petre Ovidiu PIRCALABU @ 2019-06-06 13:48 UTC (permalink / raw)
  To: Jan Beulich, Andrew Cooper
  Cc: Stefano Stabellini, WeiLiu, Razvan Cojocaru,
	Konrad Rzeszutek Wilk, George Dunlap, Tim Deegan, Ian Jackson,
	Julien Grall, Tamas K Lengyel, xen-devel, Roger Pau Monne

On Thu, 2019-06-06 at 02:37 -0600, Jan Beulich wrote:
> > > > On 05.06.19 at 19:01, <ppircalabu@bitdefender.com> wrote:
> > 
> > On Tue, 2019-06-04 at 15:43 +0100, Andrew Cooper wrote:
> > > On 30/05/2019 15:18, Petre Pircalabu wrote:
> > > > +static int vm_event_channels_alloc_buffer(struct
> > > > vm_event_channels_domain *impl)
> > > > +{
> > > > +    int i, rc = -ENOMEM;
> > > > +
> > > > +    for ( i = 0; i < impl->nr_frames; i++ )
> > > > +    {
> > > > +        struct page_info *page = alloc_domheap_page(impl-
> > > > >ved.d,
> > > > 0);
> > > 
> > > This creates pages which are reference-able (in principle) by the
> > > guest,
> > > and are bounded by d->max_pages.
> 
> Not by a HVM one, because they can't reference pages by MFN.
> Or else, as Petre implies, the ioreq approach would be wrong, too.
> 
> > > Both of these are properties of the existing interface which we'd
> > > prefer
> > > to remove.
> > 
> > The allocation mechanism is similar with the one used by ioreq (the
> > main difference is the number of pages).
> 
> Question is whether here you want to use the "caller owned"
> variant. I haven't thought through whether this would actually
> be better, so it's merely a remark.
> 
XENMEM_rsrc_acq_caller_owned flag can only be used then the calling
domain is the hardware domain. Unfortunately for us, this is a severe
limitation as we're running the monitor client form a separate DomU.

From xen/common/memory.c :
....
/*
 * FIXME: Until foreign pages inserted into the P2M are properly
 *        reference counted, it is unsafe to allow mapping of
 *        non-caller-owned resource pages unless the caller is
 *        the hardware domain.
 */
 if ( !(xmar.flags & XENMEM_rsrc_acq_caller_owned) &&
      !is_hardware_domain(currd) )
     return -EACCES;
...
> > > > +        if ( !page )
> > > > +            goto err;
> > > > +
> > > > +        if ( !get_page_and_type(page, impl->ved.d,
> > > > PGT_writable_page) )
> > > > +        {
> > > > +            rc = -ENODATA;
> > > > +            goto err;
> > > > +        }
> > > > +
> > > > +        impl->mfn[i] = page_to_mfn(page);
> > > > +    }
> > > > +
> > > > +    impl->slots = (struct vm_event_slot *)vmap(impl->mfn,
> > > > impl-
> > > > > nr_frames);
> > > 
> > > You appear to have opencoded vmalloc() here.  Is there any reason
> > > not
> > > to
> > > use that?
> > > 
> > 
> > The problem with vmalloc is that if the pages are not assigned to a
> > specific domain the remapping fails in the monitor domain.
> > e.g.:
> > ...
> > (XEN) mm.c:1015:d0v2 pg_owner d1 l1e_owner d0, but real_pg_owner d-
> > 1
> > (XEN) mm.c:1091:d0v7 Error getting mfn 5fbf53 (pfn
> > ffffffffffffffff)
> > from L1 entry 80000005fbf53227 for l1e_owner d0, pg_owner d1
> 
> In which case maybe use vmalloc() and then assign_pages()?
> Jan
Unfortunately I wasn't able to make it work:
I replaced the buffer allocation with this code:
....
    impl->slots = vzalloc(impl->nr_frames * PAGE_SIZE);
    if ( !impl->slots )
        return -ENOMEM;

    for ( i = 0; i < impl->nr_frames; i++ )
    {
        impl->mfn[i] = vmap_to_mfn(impl->slots + i * PAGE_SIZE);
        if ( assign_pages(current->domain, mfn_to_page(impl->mfn[i]),
0, 0/*MEMF_no_refcount*/ ) )
        {
            printk("%s: assign_pages returned error\n", __func__);
        }
    }
...
And the error is similar with the one without assign_pages:
....
(XEN) mm.c:1015:d0v4 pg_owner d1 l1e_owner d0, but real_pg_owner d0
(XEN) mm.c:1091:d0v4 Error getting mfn 60deaf (pfn ffffffffffffffff)
from L1 entry 800000060deaf227 for l1e_owner d0, pg_owner d1

Am I missing something?

Many thanks,
Petre

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

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH 8/9] vm_event: Add vm_event_ng interface
  2019-06-06 13:48         ` Petre Ovidiu PIRCALABU
@ 2019-06-06 14:16           ` Jan Beulich
  0 siblings, 0 replies; 67+ messages in thread
From: Jan Beulich @ 2019-06-06 14:16 UTC (permalink / raw)
  To: Petre Pircalabu
  Cc: Stefano Stabellini, WeiLiu, Razvan Cojocaru,
	Konrad Rzeszutek Wilk, George Dunlap, Andrew Cooper, Ian Jackson,
	Tim Deegan, Julien Grall, Tamas K Lengyel, xen-devel,
	Roger Pau Monne

>>> On 06.06.19 at 15:48, <ppircalabu@bitdefender.com> wrote:
> On Thu, 2019-06-06 at 02:37 -0600, Jan Beulich wrote:
>> In which case maybe use vmalloc() and then assign_pages()?
>> Jan
> Unfortunately I wasn't able to make it work:
> I replaced the buffer allocation with this code:
> ....
>     impl->slots = vzalloc(impl->nr_frames * PAGE_SIZE);
>     if ( !impl->slots )
>         return -ENOMEM;
> 
>     for ( i = 0; i < impl->nr_frames; i++ )
>     {
>         impl->mfn[i] = vmap_to_mfn(impl->slots + i * PAGE_SIZE);
>         if ( assign_pages(current->domain, mfn_to_page(impl->mfn[i]),
> 0, 0/*MEMF_no_refcount*/ ) )

Who is current->domain at this point?

>         {
>             printk("%s: assign_pages returned error\n", __func__);
>         }
>     }
> ...
> And the error is similar with the one without assign_pages:
> ....
> (XEN) mm.c:1015:d0v4 pg_owner d1 l1e_owner d0, but real_pg_owner d0
> (XEN) mm.c:1091:d0v4 Error getting mfn 60deaf (pfn ffffffffffffffff)
> from L1 entry 800000060deaf227 for l1e_owner d0, pg_owner d1

This looks to be an attempt by Dom0 to map a page into its own
page tables which it believes to be owned by Dom1. This would
imply that current->domain above is also Dom1. I would instead
have expected this to be a Dom0-owned page, in which case you
shouldn't specify Dom1 to be the supposed owner of it in the
mapping request.

Jan



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

^ permalink raw reply	[flat|nested] 67+ messages in thread

end of thread, other threads:[~2019-06-06 14:17 UTC | newest]

Thread overview: 67+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-30 14:18 [PATCH 0/9] Per vcpu vm_event channels Petre Pircalabu
2019-05-30 14:18 ` [Xen-devel] " Petre Pircalabu
2019-05-30 14:18 ` [PATCH 1/9] tools/libxc: Consistent usage of xc_vm_event_* interface Petre Pircalabu
2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
2019-05-31 23:01   ` Andrew Cooper
2019-05-31 23:01     ` [Xen-devel] " Andrew Cooper
2019-06-04 14:23     ` Petre Ovidiu PIRCALABU
2019-06-04 16:07       ` Andrew Cooper
2019-05-30 14:18 ` [PATCH 2/9] vm_event: Define VM_EVENT type Petre Pircalabu
2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
2019-05-31 23:26   ` Andrew Cooper
2019-05-31 23:26     ` [Xen-devel] " Andrew Cooper
2019-06-03 22:22     ` Tamas K Lengyel
2019-06-03 22:22       ` [Xen-devel] " Tamas K Lengyel
2019-06-03 22:26       ` Tamas K Lengyel
2019-06-03 22:26         ` [Xen-devel] " Tamas K Lengyel
2019-06-04 16:09         ` Andrew Cooper
2019-06-04 10:12     ` Petre Ovidiu PIRCALABU
2019-06-04 10:12       ` [Xen-devel] " Petre Ovidiu PIRCALABU
2019-06-03 15:51   ` Jan Beulich
2019-06-03 15:51     ` [Xen-devel] " Jan Beulich
2019-05-30 14:18 ` [PATCH 3/9] vm_event: Make ‘local’ functions ‘static’ Petre Pircalabu
2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
2019-05-31 23:28   ` Andrew Cooper
2019-05-31 23:28     ` [Xen-devel] " Andrew Cooper
2019-06-02  0:36   ` Tamas K Lengyel
2019-06-02  0:36     ` [Xen-devel] " Tamas K Lengyel
2019-05-30 14:18 ` [PATCH 4/9] vm_event: Remove "ring" suffix from vm_event_check_ring Petre Pircalabu
2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
2019-05-31 23:32   ` Andrew Cooper
2019-05-31 23:32     ` [Xen-devel] " Andrew Cooper
2019-06-05 15:52   ` Tamas K Lengyel
2019-05-30 14:18 ` [PATCH 5/9] vm_event: Simplify vm_event interface Petre Pircalabu
2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
2019-05-31 23:43   ` Andrew Cooper
2019-05-31 23:43     ` [Xen-devel] " Andrew Cooper
2019-06-01  0:06     ` Andrew Cooper
2019-06-01  0:06       ` [Xen-devel] " Andrew Cooper
2019-06-03 15:33       ` Petre Ovidiu PIRCALABU
2019-06-03 15:33         ` [Xen-devel] " Petre Ovidiu PIRCALABU
2019-05-30 14:18 ` [PATCH 6/9] vm_event: Move struct vm_event_domain to vm_event.c Petre Pircalabu
2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
2019-05-31 23:44   ` Andrew Cooper
2019-05-31 23:44     ` [Xen-devel] " Andrew Cooper
2019-06-03 11:28     ` Petre Ovidiu PIRCALABU
2019-06-03 11:28       ` [Xen-devel] " Petre Ovidiu PIRCALABU
2019-06-05 15:53   ` Tamas K Lengyel
2019-05-30 14:18 ` [PATCH 7/9] vm_event: Decouple implementation details from interface Petre Pircalabu
2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
2019-05-30 14:18 ` [PATCH 8/9] vm_event: Add vm_event_ng interface Petre Pircalabu
2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
2019-06-04 14:43   ` Andrew Cooper
2019-06-05 17:01     ` Petre Ovidiu PIRCALABU
2019-06-06  8:37       ` Jan Beulich
2019-06-06 13:48         ` Petre Ovidiu PIRCALABU
2019-06-06 14:16           ` Jan Beulich
2019-05-30 14:18 ` [PATCH 9/9] xen-access: Add support for " Petre Pircalabu
2019-05-30 14:18   ` [Xen-devel] " Petre Pircalabu
2019-06-04 16:04   ` Andrew Cooper
2019-05-30 15:27 ` [PATCH 0/9] Per vcpu vm_event channels Tamas K Lengyel
2019-05-30 15:27   ` [Xen-devel] " Tamas K Lengyel
2019-05-31  7:07   ` Petre Ovidiu PIRCALABU
2019-05-31  7:07     ` [Xen-devel] " Petre Ovidiu PIRCALABU
2019-06-01  0:25 ` Andrew Cooper
2019-06-01  0:25   ` [Xen-devel] " Andrew Cooper
2019-06-03 14:04   ` Petre Ovidiu PIRCALABU
2019-06-03 14:04     ` [Xen-devel] " Petre Ovidiu PIRCALABU

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.