All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM
@ 2014-09-23 13:14 Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 01/19] xen: Relocate mem_access and mem_event into common Tamas K Lengyel
                   ` (18 more replies)
  0 siblings, 19 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

The ARM virtualization extension provides 2-stage paging, a similar mechanisms
to Intel's EPT, which can be used to trace the memory accesses performed by
the guest systems. This series moves the mem_access and mem_event codebase
into Xen common, performs some code cleanup and architecture specific division
of components, then sets up the necessary infrastructure in the ARM code
to deliver the event on R/W/X traps. Finally, we turn on the compilation of
mem_access and mem_event on ARM and perform the necessary changes to the tools side.

This version of the series is based on staging and has been fully tested on both
an Arndale board and on Intel hardware.

This PATCH series is also available at:
https://github.com/tklengyel/xen/tree/arm_memaccess8

Julien Grall (1):
  xen/arm: Implement domain_get_maximum_gpfn

Tamas K Lengyel (18):
  xen: Relocate mem_access and mem_event into common.
  xen: Relocate struct npfec definition into common
  xen: Relocate p2m_access_t into common and swap the order
  xen: Relocate p2m_mem_access_resume to mem_access common
  xen: Relocate set_access_required domctl into common
  xen: Relocate mem_event_op domctl and access_op memop into common.
  x86/p2m: Typo fix for spelling ambiguous
  xen/mem_event: Clean out superfluous white-spaces
  xen/mem_event: Relax error condition on debug builds
  xen/mem_event: Abstract architecture specific sanity checks
  xen/mem_access: Abstract architecture specific sanity check
  xen/arm: p2m changes for mem_access support
  xen/arm: Add p2m_set_permission and p2m_shatter_page helpers.
  xen/arm: Data abort exception (R/W) mem_events.
  xen/arm: Instruction prefetch abort (X) mem_event handling
  xen/arm: Enable the compilation of mem_access and mem_event on ARM.
  tools/libxc: Allocate magic page for mem access on ARM
  tools/tests: Enable xen-access on ARM

 MAINTAINERS                         |   6 +
 config/arm32.mk                     |   1 +
 config/arm64.mk                     |   1 +
 config/x86_32.mk                    |   4 +
 config/x86_64.mk                    |   4 +
 tools/libxc/xc_dom_arm.c            |   6 +-
 tools/tests/xen-access/Makefile     |   9 +-
 tools/tests/xen-access/xen-access.c |  79 ++--
 xen/Rules.mk                        |   3 +
 xen/arch/arm/mm.c                   |   2 +-
 xen/arch/arm/p2m.c                  | 549 +++++++++++++++++++++++----
 xen/arch/arm/traps.c                |  58 ++-
 xen/arch/x86/domctl.c               |  24 +-
 xen/arch/x86/hvm/hvm.c              |  63 +---
 xen/arch/x86/hvm/vmx/vmcs.c         |   8 +-
 xen/arch/x86/mm/Makefile            |   2 -
 xen/arch/x86/mm/hap/nested_ept.c    |   6 +-
 xen/arch/x86/mm/hap/nested_hap.c    |   8 +-
 xen/arch/x86/mm/mem_access.c        | 133 -------
 xen/arch/x86/mm/mem_event.c         | 716 -----------------------------------
 xen/arch/x86/mm/mem_paging.c        |   2 +-
 xen/arch/x86/mm/mem_sharing.c       |   4 +-
 xen/arch/x86/mm/p2m-pod.c           |   8 +-
 xen/arch/x86/mm/p2m-pt.c            |  10 +-
 xen/arch/x86/mm/p2m.c               | 145 ++++---
 xen/arch/x86/x86_64/compat/mm.c     |   8 +-
 xen/arch/x86/x86_64/mm.c            |   8 +-
 xen/common/Makefile                 |   2 +
 xen/common/compat/memory.c          |   5 +
 xen/common/domain.c                 |   1 +
 xen/common/domctl.c                 |  22 ++
 xen/common/mem_access.c             | 159 ++++++++
 xen/common/mem_event.c              | 735 ++++++++++++++++++++++++++++++++++++
 xen/common/memory.c                 |  72 +++-
 xen/include/asm-arm/domain.h        |   1 +
 xen/include/asm-arm/mm.h            |   1 -
 xen/include/asm-arm/p2m.h           | 109 ++++--
 xen/include/asm-arm/processor.h     |  13 +-
 xen/include/asm-x86/hvm/hvm.h       |   8 +-
 xen/include/asm-x86/mem_access.h    |  39 --
 xen/include/asm-x86/mem_event.h     |  82 ----
 xen/include/asm-x86/mm.h            |  23 --
 xen/include/asm-x86/p2m.h           |  52 ++-
 xen/include/xen/mem_access.h        |  65 ++++
 xen/include/xen/mem_event.h         | 143 +++++++
 xen/include/xen/mm.h                |  27 ++
 xen/include/xen/p2m-common.h        |  29 ++
 xen/include/xsm/dummy.h             |  26 +-
 xen/include/xsm/xsm.h               |  29 +-
 xen/xsm/dummy.c                     |   7 +-
 xen/xsm/flask/hooks.c               |  33 +-
 51 files changed, 2154 insertions(+), 1396 deletions(-)
 delete mode 100644 xen/arch/x86/mm/mem_access.c
 delete mode 100644 xen/arch/x86/mm/mem_event.c
 create mode 100644 xen/common/mem_access.c
 create mode 100644 xen/common/mem_event.c
 delete mode 100644 xen/include/asm-x86/mem_access.h
 delete mode 100644 xen/include/asm-x86/mem_event.h
 create mode 100644 xen/include/xen/mem_access.h
 create mode 100644 xen/include/xen/mem_event.h

-- 
2.1.0

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

* [PATCH for-4.5 v8 01/19] xen: Relocate mem_access and mem_event into common.
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 02/19] xen: Relocate struct npfec definition " Tamas K Lengyel
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

In preparation to add support for ARM LPAE mem_event, relocate mem_access,
mem_event and auxiliary functions into common Xen code.
This patch makes no functional changes to the X86 side, for ARM mem_event
and mem_access functions are just defined as placeholder stubs, and are
actually enabled later in the series.

Edits that are only header path adjustments:
   xen/arch/x86/domctl.c
   xen/arch/x86/mm/hap/nested_ept.c
   xen/arch/x86/mm/hap/nested_hap.c
   xen/arch/x86/mm/mem_paging.c
   xen/arch/x86/mm/mem_sharing.c
   xen/arch/x86/mm/p2m-pod.c
   xen/arch/x86/mm/p2m-pt.c
   xen/arch/x86/mm/p2m.c
   xen/arch/x86/x86_64/compat/mm.c
   xen/arch/x86/x86_64/mm.c

Makefile adjustments for new/removed code:
   xen/common/Makefile
   xen/arch/x86/mm/Makefile

Relocated prepare_ring_for_helper and destroy_ring_for_helper functions:
   xen/include/xen/mm.h
   xen/common/memory.c
   xen/include/asm-x86/hvm/hvm.h
   xen/arch/x86/hvm/hvm.c

Code movement of mem_event and mem_access:
    xen/arch/x86/mm/mem_access.c -> xen/common/mem_access.c
    xen/arch/x86/mm/mem_event.c -> xen/common/mem_event.c
    xen/include/asm-x86/mem_access.h -> xen/include/xen/mem_access.h
    xen/include/asm-x86/mem_event.h -> xen/include/xen/mem_event.h

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Tim Deegan <tim@xen.org>
---
v8: Define HAS_MEM_ACCESS/PAGING/SHARING in config/x86_*.mk
    and wrap required parts in mem_event into ifdefs accordingly.

v5: Make <xen/mem-event.h> include <xen/sched.h> by default.
    Style fix with grouping of #includes.

v4: Make <xen/mem_access.h> include <public/memory.h> by default.

v3: Replace asm/domain.h with xen/sched.h in mem_event.c to better
    accomodate for the new code location.
    Replace #ifdef CONFIG_X86 wrappers with HAS_MEM_ACCESS flags.

v2: Update MAINTAINERS.
    More descriptive commit message to aid in the review process.
---
 MAINTAINERS                      |   6 +
 config/x86_32.mk                 |   4 +
 config/x86_64.mk                 |   4 +
 xen/Rules.mk                     |   3 +
 xen/arch/x86/domctl.c            |   2 +-
 xen/arch/x86/hvm/hvm.c           |  63 +---
 xen/arch/x86/hvm/vmx/vmcs.c      |   8 +-
 xen/arch/x86/mm/Makefile         |   2 -
 xen/arch/x86/mm/hap/nested_ept.c |   6 +-
 xen/arch/x86/mm/hap/nested_hap.c |   6 +-
 xen/arch/x86/mm/mem_access.c     | 133 -------
 xen/arch/x86/mm/mem_event.c      | 716 -------------------------------------
 xen/arch/x86/mm/mem_paging.c     |   2 +-
 xen/arch/x86/mm/mem_sharing.c    |   4 +-
 xen/arch/x86/mm/p2m-pod.c        |   8 +-
 xen/arch/x86/mm/p2m-pt.c         |  10 +-
 xen/arch/x86/mm/p2m.c            |   8 +-
 xen/arch/x86/x86_64/compat/mm.c  |   4 +-
 xen/arch/x86/x86_64/mm.c         |   4 +-
 xen/common/Makefile              |   2 +
 xen/common/domain.c              |   1 +
 xen/common/mem_access.c          | 133 +++++++
 xen/common/mem_event.c           | 739 +++++++++++++++++++++++++++++++++++++++
 xen/common/memory.c              |  63 ++++
 xen/include/asm-arm/mm.h         |   1 -
 xen/include/asm-x86/hvm/hvm.h    |   6 -
 xen/include/asm-x86/mem_access.h |  39 ---
 xen/include/asm-x86/mem_event.h  |  82 -----
 xen/include/asm-x86/mm.h         |   2 -
 xen/include/xen/mem_access.h     |  60 ++++
 xen/include/xen/mem_event.h      | 143 ++++++++
 xen/include/xen/mm.h             |   6 +
 32 files changed, 1198 insertions(+), 1072 deletions(-)
 delete mode 100644 xen/arch/x86/mm/mem_access.c
 delete mode 100644 xen/arch/x86/mm/mem_event.c
 create mode 100644 xen/common/mem_access.c
 create mode 100644 xen/common/mem_event.c
 delete mode 100644 xen/include/asm-x86/mem_access.h
 delete mode 100644 xen/include/asm-x86/mem_event.h
 create mode 100644 xen/include/xen/mem_access.h
 create mode 100644 xen/include/xen/mem_event.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 266e47b..f659180 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -337,6 +337,12 @@ F:	xen/arch/x86/mm/mem_sharing.c
 F:	xen/arch/x86/mm/mem_paging.c
 F:	tools/memshr
 
+MEMORY EVENT AND ACCESS
+M:	Tim Deegan <tim@xen.org>
+S:	Supported
+F:	xen/common/mem_event.c
+F:	xen/common/mem_access.c
+
 XENTRACE
 M:	George Dunlap <george.dunlap@eu.citrix.com>
 S:	Supported
diff --git a/config/x86_32.mk b/config/x86_32.mk
index 7f76b25..123f1b7 100644
--- a/config/x86_32.mk
+++ b/config/x86_32.mk
@@ -6,6 +6,10 @@ CONFIG_HVM := y
 CONFIG_MIGRATE := y
 CONFIG_XCUTILS := y
 
+HAS_MEM_ACCESS := y
+HAS_MEM_PAGING := y
+HAS_MEM_SHARING := y
+
 CFLAGS += -m32 -march=i686
 
 # Use only if calling $(LD) directly.
diff --git a/config/x86_64.mk b/config/x86_64.mk
index 11104bd..ff0b474 100644
--- a/config/x86_64.mk
+++ b/config/x86_64.mk
@@ -7,6 +7,10 @@ CONFIG_HVM := y
 CONFIG_MIGRATE := y
 CONFIG_XCUTILS := y
 
+HAS_MEM_ACCESS := y
+HAS_MEM_PAGING := y
+HAS_MEM_SHARING := y
+
 CONFIG_XEN_INSTALL_SUFFIX := .gz
 
 CFLAGS += -m64
diff --git a/xen/Rules.mk b/xen/Rules.mk
index e2f9e36..a97405c 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -57,6 +57,9 @@ CFLAGS-$(HAS_ACPI)      += -DHAS_ACPI
 CFLAGS-$(HAS_GDBSX)     += -DHAS_GDBSX
 CFLAGS-$(HAS_PASSTHROUGH) += -DHAS_PASSTHROUGH
 CFLAGS-$(HAS_DEVICE_TREE) += -DHAS_DEVICE_TREE
+CFLAGS-$(HAS_MEM_ACCESS)  += -DHAS_MEM_ACCESS
+CFLAGS-$(HAS_MEM_PAGING)  += -DHAS_MEM_PAGING
+CFLAGS-$(HAS_MEM_SHARING) += -DHAS_MEM_SHARING
 CFLAGS-$(HAS_PCI)       += -DHAS_PCI
 CFLAGS-$(HAS_IOPORTS)   += -DHAS_IOPORTS
 CFLAGS-$(HAS_PDX)       += -DHAS_PDX
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 7a5de43..26a3ea1 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -30,7 +30,7 @@
 #include <xen/hypercall.h> /* for arch_do_domctl */
 #include <xsm/xsm.h>
 #include <xen/iommu.h>
-#include <asm/mem_event.h>
+#include <xen/mem_event.h>
 #include <public/mem_event.h>
 #include <asm/mem_sharing.h>
 #include <asm/xstate.h>
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index bb45593..dd4a06a 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -35,6 +35,9 @@
 #include <xen/paging.h>
 #include <xen/cpu.h>
 #include <xen/wait.h>
+#include <xen/mem_event.h>
+#include <xen/mem_access.h>
+#include <xen/rangeset.h>
 #include <asm/shadow.h>
 #include <asm/hap.h>
 #include <asm/current.h>
@@ -63,10 +66,7 @@
 #include <public/hvm/ioreq.h>
 #include <public/version.h>
 #include <public/memory.h>
-#include <asm/mem_event.h>
-#include <asm/mem_access.h>
 #include <public/mem_event.h>
-#include <xen/rangeset.h>
 #include <public/arch-x86/cpuid.h>
 
 bool_t __read_mostly hvm_enabled;
@@ -484,19 +484,6 @@ static void hvm_free_ioreq_gmfn(struct domain *d, unsigned long gmfn)
     clear_bit(i, &d->arch.hvm_domain.ioreq_gmfn.mask);
 }
 
-void destroy_ring_for_helper(
-    void **_va, struct page_info *page)
-{
-    void *va = *_va;
-
-    if ( va != NULL )
-    {
-        unmap_domain_page_global(va);
-        put_page_and_type(page);
-        *_va = NULL;
-    }
-}
-
 static void hvm_unmap_ioreq_page(struct hvm_ioreq_server *s, bool_t buf)
 {
     struct hvm_ioreq_page *iorp = buf ? &s->bufioreq : &s->ioreq;
@@ -504,50 +491,6 @@ static void hvm_unmap_ioreq_page(struct hvm_ioreq_server *s, bool_t buf)
     destroy_ring_for_helper(&iorp->va, iorp->page);
 }
 
-int prepare_ring_for_helper(
-    struct domain *d, unsigned long gmfn, struct page_info **_page,
-    void **_va)
-{
-    struct page_info *page;
-    p2m_type_t p2mt;
-    void *va;
-
-    page = get_page_from_gfn(d, gmfn, &p2mt, P2M_UNSHARE);
-    if ( p2m_is_paging(p2mt) )
-    {
-        if ( page )
-            put_page(page);
-        p2m_mem_paging_populate(d, gmfn);
-        return -ENOENT;
-    }
-    if ( p2m_is_shared(p2mt) )
-    {
-        if ( page )
-            put_page(page);
-        return -ENOENT;
-    }
-    if ( !page )
-        return -EINVAL;
-
-    if ( !get_page_type(page, PGT_writable_page) )
-    {
-        put_page(page);
-        return -EINVAL;
-    }
-
-    va = __map_domain_page_global(page);
-    if ( va == NULL )
-    {
-        put_page_and_type(page);
-        return -ENOMEM;
-    }
-
-    *_va = va;
-    *_page = page;
-
-    return 0;
-}
-
 static int hvm_map_ioreq_page(
     struct hvm_ioreq_server *s, bool_t buf, unsigned long gmfn)
 {
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index fc1f882..9d8033e 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -22,6 +22,10 @@
 #include <xen/lib.h>
 #include <xen/errno.h>
 #include <xen/domain_page.h>
+#include <xen/event.h>
+#include <xen/kernel.h>
+#include <xen/keyhandler.h>
+#include <xen/mem_event.h>
 #include <asm/current.h>
 #include <asm/cpufeature.h>
 #include <asm/processor.h>
@@ -34,12 +38,8 @@
 #include <asm/hvm/vmx/vvmx.h>
 #include <asm/hvm/vmx/vmcs.h>
 #include <asm/flushtlb.h>
-#include <xen/event.h>
-#include <xen/kernel.h>
-#include <xen/keyhandler.h>
 #include <asm/shadow.h>
 #include <asm/tboot.h>
-#include <asm/mem_event.h>
 
 static bool_t __read_mostly opt_vpid_enabled = 1;
 boolean_param("vpid", opt_vpid_enabled);
diff --git a/xen/arch/x86/mm/Makefile b/xen/arch/x86/mm/Makefile
index 73dcdf4..ed4b1f8 100644
--- a/xen/arch/x86/mm/Makefile
+++ b/xen/arch/x86/mm/Makefile
@@ -6,10 +6,8 @@ obj-y += p2m.o p2m-pt.o p2m-ept.o p2m-pod.o
 obj-y += guest_walk_2.o
 obj-y += guest_walk_3.o
 obj-$(x86_64) += guest_walk_4.o
-obj-$(x86_64) += mem_event.o
 obj-$(x86_64) += mem_paging.o
 obj-$(x86_64) += mem_sharing.o
-obj-$(x86_64) += mem_access.o
 
 guest_walk_%.o: guest_walk.c Makefile
 	$(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@
diff --git a/xen/arch/x86/mm/hap/nested_ept.c b/xen/arch/x86/mm/hap/nested_ept.c
index 0d044bc..cbbc4e9 100644
--- a/xen/arch/x86/mm/hap/nested_ept.c
+++ b/xen/arch/x86/mm/hap/nested_ept.c
@@ -17,14 +17,14 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+#include <xen/mem_event.h>
+#include <xen/event.h>
+#include <public/mem_event.h>
 #include <asm/domain.h>
 #include <asm/page.h>
 #include <asm/paging.h>
 #include <asm/p2m.h>
-#include <asm/mem_event.h>
-#include <public/mem_event.h>
 #include <asm/mem_sharing.h>
-#include <xen/event.h>
 #include <asm/hap.h>
 #include <asm/hvm/support.h>
 
diff --git a/xen/arch/x86/mm/hap/nested_hap.c b/xen/arch/x86/mm/hap/nested_hap.c
index 137a87c..a4bb835 100644
--- a/xen/arch/x86/mm/hap/nested_hap.c
+++ b/xen/arch/x86/mm/hap/nested_hap.c
@@ -19,14 +19,14 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <xen/mem_event.h>
+#include <xen/event.h>
+#include <public/mem_event.h>
 #include <asm/domain.h>
 #include <asm/page.h>
 #include <asm/paging.h>
 #include <asm/p2m.h>
-#include <asm/mem_event.h>
-#include <public/mem_event.h>
 #include <asm/mem_sharing.h>
-#include <xen/event.h>
 #include <asm/hap.h>
 #include <asm/hvm/support.h>
 
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
deleted file mode 100644
index e8465a5..0000000
--- a/xen/arch/x86/mm/mem_access.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/******************************************************************************
- * arch/x86/mm/mem_access.c
- *
- * Memory access support.
- *
- * Copyright (c) 2011 Virtuata, Inc.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include <xen/sched.h>
-#include <xen/guest_access.h>
-#include <xen/hypercall.h>
-#include <asm/p2m.h>
-#include <asm/mem_event.h>
-#include <xsm/xsm.h>
-
-
-int mem_access_memop(unsigned long cmd,
-                     XEN_GUEST_HANDLE_PARAM(xen_mem_access_op_t) arg)
-{
-    long rc;
-    xen_mem_access_op_t mao;
-    struct domain *d;
-
-    if ( copy_from_guest(&mao, arg, 1) )
-        return -EFAULT;
-
-    rc = rcu_lock_live_remote_domain_by_id(mao.domid, &d);
-    if ( rc )
-        return rc;
-
-    rc = -EINVAL;
-    if ( !is_hvm_domain(d) )
-        goto out;
-
-    rc = xsm_mem_event_op(XSM_DM_PRIV, d, XENMEM_access_op);
-    if ( rc )
-        goto out;
-
-    rc = -ENODEV;
-    if ( unlikely(!d->mem_event->access.ring_page) )
-        goto out;
-
-    switch ( mao.op )
-    {
-    case XENMEM_access_op_resume:
-        p2m_mem_access_resume(d);
-        rc = 0;
-        break;
-
-    case XENMEM_access_op_set_access:
-    {
-        unsigned long start_iter = cmd & ~MEMOP_CMD_MASK;
-
-        rc = -EINVAL;
-        if ( (mao.pfn != ~0ull) &&
-             (mao.nr < start_iter ||
-              ((mao.pfn + mao.nr - 1) < mao.pfn) ||
-              ((mao.pfn + mao.nr - 1) > domain_get_maximum_gpfn(d))) )
-            break;
-
-        rc = p2m_set_mem_access(d, mao.pfn, mao.nr, start_iter,
-                                MEMOP_CMD_MASK, mao.access);
-        if ( rc > 0 )
-        {
-            ASSERT(!(rc & MEMOP_CMD_MASK));
-            rc = hypercall_create_continuation(__HYPERVISOR_memory_op, "lh",
-                                               XENMEM_access_op | rc, arg);
-        }
-        break;
-    }
-
-    case XENMEM_access_op_get_access:
-    {
-        xenmem_access_t access;
-
-        rc = -EINVAL;
-        if ( (mao.pfn > domain_get_maximum_gpfn(d)) && mao.pfn != ~0ull )
-            break;
-
-        rc = p2m_get_mem_access(d, mao.pfn, &access);
-        if ( rc != 0 )
-            break;
-
-        mao.access = access;
-        rc = __copy_field_to_guest(arg, &mao, access) ? -EFAULT : 0;
-
-        break;
-    }
-
-    default:
-        rc = -ENOSYS;
-        break;
-    }
-
- out:
-    rcu_unlock_domain(d);
-    return rc;
-}
-
-int mem_access_send_req(struct domain *d, mem_event_request_t *req)
-{
-    int rc = mem_event_claim_slot(d, &d->mem_event->access);
-    if ( rc < 0 )
-        return rc;
-
-    mem_event_put_request(d, &d->mem_event->access, req);
-
-    return 0;
-} 
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/xen/arch/x86/mm/mem_event.c b/xen/arch/x86/mm/mem_event.c
deleted file mode 100644
index fdd5ff6..0000000
--- a/xen/arch/x86/mm/mem_event.c
+++ /dev/null
@@ -1,716 +0,0 @@
-/******************************************************************************
- * arch/x86/mm/mem_event.c
- *
- * Memory event support.
- *
- * Copyright (c) 2009 Citrix Systems, Inc. (Patrick Colp)
- *
- * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include <asm/domain.h>
-#include <xen/event.h>
-#include <xen/wait.h>
-#include <asm/p2m.h>
-#include <asm/mem_event.h>
-#include <asm/mem_paging.h>
-#include <asm/mem_access.h>
-#include <asm/mem_sharing.h>
-#include <xsm/xsm.h>
-
-/* for public/io/ring.h macros */
-#define xen_mb()   mb()
-#define xen_rmb()  rmb()
-#define xen_wmb()  wmb()
-
-#define mem_event_ring_lock_init(_med)  spin_lock_init(&(_med)->ring_lock)
-#define mem_event_ring_lock(_med)       spin_lock(&(_med)->ring_lock)
-#define mem_event_ring_unlock(_med)     spin_unlock(&(_med)->ring_lock)
-
-static int mem_event_enable(
-    struct domain *d,
-    xen_domctl_mem_event_op_t *mec,
-    struct mem_event_domain *med,
-    int pause_flag,
-    int param,
-    xen_event_channel_notification_t notification_fn)
-{
-    int rc;
-    unsigned long ring_gfn = d->arch.hvm_domain.params[param];
-
-    /* Only one helper at a time. If the helper crashed,
-     * the ring is in an undefined state and so is the guest.
-     */
-    if ( med->ring_page )
-        return -EBUSY;
-
-    /* The parameter defaults to zero, and it should be 
-     * set to something */
-    if ( ring_gfn == 0 )
-        return -ENOSYS;
-
-    mem_event_ring_lock_init(med);
-    mem_event_ring_lock(med);
-
-    rc = prepare_ring_for_helper(d, ring_gfn, &med->ring_pg_struct, 
-                                    &med->ring_page);
-    if ( rc < 0 )
-        goto err;
-
-    /* Set the number of currently blocked vCPUs to 0. */
-    med->blocked = 0;
-
-    /* Allocate event channel */
-    rc = alloc_unbound_xen_event_channel(d->vcpu[0],
-                                         current->domain->domain_id,
-                                         notification_fn);
-    if ( rc < 0 )
-        goto err;
-
-    med->xen_port = mec->port = rc;
-
-    /* Prepare ring buffer */
-    FRONT_RING_INIT(&med->front_ring,
-                    (mem_event_sring_t *)med->ring_page,
-                    PAGE_SIZE);
-
-    /* Save the pause flag for this particular ring. */
-    med->pause_flag = pause_flag;
-
-    /* Initialize the last-chance wait queue. */
-    init_waitqueue_head(&med->wq);
-
-    mem_event_ring_unlock(med);
-    return 0;
-
- err:
-    destroy_ring_for_helper(&med->ring_page, 
-                            med->ring_pg_struct);
-    mem_event_ring_unlock(med);
-
-    return rc;
-}
-
-static unsigned int mem_event_ring_available(struct mem_event_domain *med)
-{
-    int avail_req = RING_FREE_REQUESTS(&med->front_ring);
-    avail_req -= med->target_producers;
-    avail_req -= med->foreign_producers;
-
-    BUG_ON(avail_req < 0);
-
-    return avail_req;
-}
-
-/*
- * mem_event_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 mem_event_wake_blocked(struct domain *d, struct mem_event_domain *med)
-{
-    struct vcpu *v;
-    int online = d->max_vcpus;
-    unsigned int avail_req = mem_event_ring_available(med);
-
-    if ( avail_req == 0 || med->blocked == 0 )
-        return;
-
-    /*
-     * We ensure that we only have vCPUs online if there are enough free slots
-     * for their memory events to be processed.  This will ensure that no
-     * memory events are lost (due to the fact that certain types of events
-     * cannot be replayed, we need to ensure that there is space in the ring
-     * for when they are hit).
-     * See comment below in mem_event_put_request().
-     */
-    for_each_vcpu ( d, v )
-        if ( test_bit(med->pause_flag, &v->pause_flags) )
-            online--;
-
-    ASSERT(online == (d->max_vcpus - med->blocked));
-
-    /* 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 )
-    {
-        int i, j, k;
-
-        for (i = med->last_vcpu_wake_up + 1, j = 0; j < d->max_vcpus; i++, j++)
-        {
-            k = i % d->max_vcpus;
-            v = d->vcpu[k];
-            if ( !v )
-                continue;
-
-            if ( !(med->blocked) || online >= avail_req )
-               break;
-
-            if ( test_and_clear_bit(med->pause_flag, &v->pause_flags) )
-            {
-                vcpu_unpause(v);
-                online++;
-                med->blocked--;
-                med->last_vcpu_wake_up = k;
-            }
-        }
-    }
-}
-
-/*
- * In the event that a vCPU attempted to place an event in the ring and
- * 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 mem_event_wake_queued(struct domain *d, struct mem_event_domain *med)
-{
-    unsigned int avail_req = mem_event_ring_available(med);
-
-    if ( avail_req > 0 )
-        wake_up_nr(&med->wq, avail_req);
-}
-
-/*
- * mem_event_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 mem_event_wake() again, ensuring that any blocked vCPUs will get
- * unpaused once all the queued vCPUs have made it through.
- */
-void mem_event_wake(struct domain *d, struct mem_event_domain *med)
-{
-    if (!list_empty(&med->wq.list))
-        mem_event_wake_queued(d, med);
-    else
-        mem_event_wake_blocked(d, med);
-}
-
-static int mem_event_disable(struct domain *d, struct mem_event_domain *med)
-{
-    if ( med->ring_page )
-    {
-        struct vcpu *v;
-
-        mem_event_ring_lock(med);
-
-        if ( !list_empty(&med->wq.list) )
-        {
-            mem_event_ring_unlock(med);
-            return -EBUSY;
-        }
-
-        /* Free domU's event channel and leave the other one unbound */
-        free_xen_event_channel(d->vcpu[0], med->xen_port);
-
-        /* Unblock all vCPUs */
-        for_each_vcpu ( d, v )
-        {
-            if ( test_and_clear_bit(med->pause_flag, &v->pause_flags) )
-            {
-                vcpu_unpause(v);
-                med->blocked--;
-            }
-        }
-
-        destroy_ring_for_helper(&med->ring_page, 
-                                med->ring_pg_struct);
-        mem_event_ring_unlock(med);
-    }
-
-    return 0;
-}
-
-static inline void mem_event_release_slot(struct domain *d,
-                                          struct mem_event_domain *med)
-{
-    /* Update the accounting */
-    if ( current->domain == d )
-        med->target_producers--;
-    else
-        med->foreign_producers--;
-
-    /* Kick any waiters */
-    mem_event_wake(d, med);
-}
-
-/*
- * mem_event_mark_and_pause() tags vcpu and put it to sleep.
- * The vcpu will resume execution in mem_event_wake_waiters().
- */
-void mem_event_mark_and_pause(struct vcpu *v, struct mem_event_domain *med)
-{
-    if ( !test_and_set_bit(med->pause_flag, &v->pause_flags) )
-    {
-        vcpu_pause_nosync(v);
-        med->blocked++;
-    }
-}
-
-/*
- * This must be preceded by a call to claim_slot(), and is guaranteed to
- * succeed.  As a side-effect however, the vCPU may be paused if the ring is
- * overly full and its continued execution would cause stalling and excessive
- * waiting.  The vCPU will be automatically unpaused when the ring clears.
- */
-void mem_event_put_request(struct domain *d,
-                           struct mem_event_domain *med,
-                           mem_event_request_t *req)
-{
-    mem_event_front_ring_t *front_ring;
-    int free_req;
-    unsigned int avail_req;
-    RING_IDX req_prod;
-
-    if ( current->domain != d )
-    {
-        req->flags |= MEM_EVENT_FLAG_FOREIGN;
-        ASSERT( !(req->flags & MEM_EVENT_FLAG_VCPU_PAUSED) );
-    }
-
-    mem_event_ring_lock(med);
-
-    /* Due to the reservations, this step must succeed. */
-    front_ring = &med->front_ring;
-    free_req = RING_FREE_REQUESTS(front_ring);
-    ASSERT(free_req > 0);
-
-    /* Copy request */
-    req_prod = front_ring->req_prod_pvt;
-    memcpy(RING_GET_REQUEST(front_ring, req_prod), req, sizeof(*req));
-    req_prod++;
-
-    /* Update ring */
-    front_ring->req_prod_pvt = req_prod;
-    RING_PUSH_REQUESTS(front_ring);
-
-    /* We've actually *used* our reservation, so release the slot. */
-    mem_event_release_slot(d, med);
-
-    /* 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 = mem_event_ring_available(med);
-    if( current->domain == d && avail_req < d->max_vcpus )
-        mem_event_mark_and_pause(current, med);
-
-    mem_event_ring_unlock(med);
-
-    notify_via_xen_event_channel(d, med->xen_port);
-}
-
-int mem_event_get_response(struct domain *d, struct mem_event_domain *med, mem_event_response_t *rsp)
-{
-    mem_event_front_ring_t *front_ring;
-    RING_IDX rsp_cons;
-
-    mem_event_ring_lock(med);
-
-    front_ring = &med->front_ring;
-    rsp_cons = front_ring->rsp_cons;
-
-    if ( !RING_HAS_UNCONSUMED_RESPONSES(front_ring) )
-    {
-        mem_event_ring_unlock(med);
-        return 0;
-    }
-
-    /* Copy response */
-    memcpy(rsp, RING_GET_RESPONSE(front_ring, rsp_cons), sizeof(*rsp));
-    rsp_cons++;
-
-    /* Update ring */
-    front_ring->rsp_cons = rsp_cons;
-    front_ring->sring->rsp_event = rsp_cons + 1;
-
-    /* Kick any waiters -- since we've just consumed an event,
-     * there may be additional space available in the ring. */
-    mem_event_wake(d, med);
-
-    mem_event_ring_unlock(med);
-
-    return 1;
-}
-
-void mem_event_cancel_slot(struct domain *d, struct mem_event_domain *med)
-{
-    mem_event_ring_lock(med);
-    mem_event_release_slot(d, med);
-    mem_event_ring_unlock(med);
-}
-
-static int mem_event_grab_slot(struct mem_event_domain *med, int foreign)
-{
-    unsigned int avail_req;
-
-    if ( !med->ring_page )
-        return -ENOSYS;
-
-    mem_event_ring_lock(med);
-
-    avail_req = mem_event_ring_available(med);
-    if ( avail_req == 0 )
-    {
-        mem_event_ring_unlock(med);
-        return -EBUSY;
-    }
-
-    if ( !foreign )
-        med->target_producers++;
-    else
-        med->foreign_producers++;
-
-    mem_event_ring_unlock(med);
-
-    return 0;
-}
-
-/* Simple try_grab wrapper for use in the wait_event() macro. */
-static int mem_event_wait_try_grab(struct mem_event_domain *med, int *rc)
-{
-    *rc = mem_event_grab_slot(med, 0);
-    return *rc;
-}
-
-/* Call mem_event_grab_slot() until the ring doesn't exist, or is available. */
-static int mem_event_wait_slot(struct mem_event_domain *med)
-{
-    int rc = -EBUSY;
-    wait_event(med->wq, mem_event_wait_try_grab(med, &rc) != -EBUSY);
-    return rc;
-}
-
-bool_t mem_event_check_ring(struct mem_event_domain *med)
-{
-    return (med->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 mem_event_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.
- *
- * Return codes: -ENOSYS: the ring is not yet configured
- *               -EBUSY: the ring is busy
- *               0: a spot has been reserved
- *
- */
-int __mem_event_claim_slot(struct domain *d, struct mem_event_domain *med,
-                            bool_t allow_sleep)
-{
-    if ( (current->domain == d) && allow_sleep )
-        return mem_event_wait_slot(med);
-    else
-        return mem_event_grab_slot(med, (current->domain != d));
-}
-
-/* Registered with Xen-bound event channel for incoming notifications. */
-static void mem_paging_notification(struct vcpu *v, unsigned int port)
-{
-    if ( likely(v->domain->mem_event->paging.ring_page != NULL) )
-        p2m_mem_paging_resume(v->domain);
-}
-
-/* Registered with Xen-bound event channel for incoming notifications. */
-static void mem_access_notification(struct vcpu *v, unsigned int port)
-{
-    if ( likely(v->domain->mem_event->access.ring_page != NULL) )
-        p2m_mem_access_resume(v->domain);
-}
-
-/* Registered with Xen-bound event channel for incoming notifications. */
-static void mem_sharing_notification(struct vcpu *v, unsigned int port)
-{
-    if ( likely(v->domain->mem_event->share.ring_page != NULL) )
-        mem_sharing_sharing_resume(v->domain);
-}
-
-int do_mem_event_op(int op, uint32_t domain, void *arg)
-{
-    int ret;
-    struct domain *d;
-
-    ret = rcu_lock_live_remote_domain_by_id(domain, &d);
-    if ( ret )
-        return ret;
-
-    ret = xsm_mem_event_op(XSM_DM_PRIV, d, op);
-    if ( ret )
-        goto out;
-
-    switch (op)
-    {
-        case XENMEM_paging_op:
-            ret = mem_paging_memop(d, (xen_mem_event_op_t *) arg);
-            break;
-        case XENMEM_sharing_op:
-            ret = mem_sharing_memop(d, (xen_mem_sharing_op_t *) arg);
-            break;
-        default:
-            ret = -ENOSYS;
-    }
-
- out:
-    rcu_unlock_domain(d);
-    return ret;
-}
-
-/* Clean up on domain destruction */
-void mem_event_cleanup(struct domain *d)
-{
-    if ( d->mem_event->paging.ring_page ) {
-        /* 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->mem_event->paging.wq);
-        (void)mem_event_disable(d, &d->mem_event->paging);
-    }
-    if ( d->mem_event->access.ring_page ) {
-        destroy_waitqueue_head(&d->mem_event->access.wq);
-        (void)mem_event_disable(d, &d->mem_event->access);
-    }
-    if ( d->mem_event->share.ring_page ) {
-        destroy_waitqueue_head(&d->mem_event->share.wq);
-        (void)mem_event_disable(d, &d->mem_event->share);
-    }
-}
-
-int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
-                     XEN_GUEST_HANDLE_PARAM(void) u_domctl)
-{
-    int rc;
-
-    rc = xsm_mem_event_control(XSM_PRIV, d, mec->mode, mec->op);
-    if ( rc )
-        return rc;
-
-    if ( unlikely(d == current->domain) )
-    {
-        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;
-    }
-
-    rc = -ENOSYS;
-
-    switch ( mec->mode )
-    {
-    case XEN_DOMCTL_MEM_EVENT_OP_PAGING:
-    {
-        struct mem_event_domain *med = &d->mem_event->paging;
-        rc = -EINVAL;
-
-        switch( mec->op )
-        {
-        case XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE:
-        {
-            struct p2m_domain *p2m = p2m_get_hostp2m(d);
-
-            rc = -EOPNOTSUPP;
-            /* pvh fixme: p2m_is_foreign types need addressing */
-            if ( is_pvh_vcpu(current) || is_pvh_domain(hardware_domain) )
-                break;
-
-            rc = -ENODEV;
-            /* Only HAP is supported */
-            if ( !hap_enabled(d) )
-                break;
-
-            /* No paging if iommu is used */
-            rc = -EMLINK;
-            if ( unlikely(need_iommu(d)) )
-                break;
-
-            rc = -EXDEV;
-            /* Disallow paging in a PoD guest */
-            if ( p2m->pod.entry_count )
-                break;
-
-            rc = mem_event_enable(d, mec, med, _VPF_mem_paging, 
-                                    HVM_PARAM_PAGING_RING_PFN,
-                                    mem_paging_notification);
-        }
-        break;
-
-        case XEN_DOMCTL_MEM_EVENT_OP_PAGING_DISABLE:
-        {
-            if ( med->ring_page )
-                rc = mem_event_disable(d, med);
-        }
-        break;
-
-        default:
-            rc = -ENOSYS;
-            break;
-        }
-    }
-    break;
-
-    case XEN_DOMCTL_MEM_EVENT_OP_ACCESS: 
-    {
-        struct mem_event_domain *med = &d->mem_event->access;
-        rc = -EINVAL;
-
-        switch( mec->op )
-        {
-        case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE:
-        case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION:
-        {
-            rc = -ENODEV;
-            /* Only HAP is supported */
-            if ( !hap_enabled(d) )
-                break;
-
-            /* Currently only EPT is supported */
-            if ( !cpu_has_vmx )
-                break;
-
-            rc = mem_event_enable(d, mec, med, _VPF_mem_access, 
-                                    HVM_PARAM_ACCESS_RING_PFN,
-                                    mem_access_notification);
-
-            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
-                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
-            {
-                d->arch.hvm_domain.introspection_enabled = 1;
-                hvm_funcs.enable_msr_exit_interception(d);
-            }
-        }
-        break;
-
-        case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_DISABLE:
-        {
-            if ( med->ring_page )
-            {
-                rc = mem_event_disable(d, med);
-                d->arch.hvm_domain.introspection_enabled = 0;
-            }
-        }
-        break;
-
-        default:
-            rc = -ENOSYS;
-            break;
-        }
-    }
-    break;
-
-    case XEN_DOMCTL_MEM_EVENT_OP_SHARING: 
-    {
-        struct mem_event_domain *med = &d->mem_event->share;
-        rc = -EINVAL;
-
-        switch( mec->op )
-        {
-        case XEN_DOMCTL_MEM_EVENT_OP_SHARING_ENABLE:
-        {
-            rc = -EOPNOTSUPP;
-            /* pvh fixme: p2m_is_foreign types need addressing */
-            if ( is_pvh_vcpu(current) || is_pvh_domain(hardware_domain) )
-                break;
-
-            rc = -ENODEV;
-            /* Only HAP is supported */
-            if ( !hap_enabled(d) )
-                break;
-
-            rc = mem_event_enable(d, mec, med, _VPF_mem_sharing, 
-                                    HVM_PARAM_SHARING_RING_PFN,
-                                    mem_sharing_notification);
-        }
-        break;
-
-        case XEN_DOMCTL_MEM_EVENT_OP_SHARING_DISABLE:
-        {
-            if ( med->ring_page )
-                rc = mem_event_disable(d, med);
-        }
-        break;
-
-        default:
-            rc = -ENOSYS;
-            break;
-        }
-    }
-    break;
-
-    default:
-        rc = -ENOSYS;
-    }
-
-    return rc;
-}
-
-void mem_event_vcpu_pause(struct vcpu *v)
-{
-    ASSERT(v == current);
-
-    atomic_inc(&v->mem_event_pause_count);
-    vcpu_pause_nosync(v);
-}
-
-void mem_event_vcpu_unpause(struct vcpu *v)
-{
-    int old, new, prev = v->mem_event_pause_count.counter;
-
-    /* All unpause requests as a result of toolstack responses.  Prevent
-     * underflow of the vcpu pause count. */
-    do
-    {
-        old = prev;
-        new = old - 1;
-
-        if ( new < 0 )
-        {
-            printk(XENLOG_G_WARNING
-                   "%pv mem_event: Too many unpause attempts\n", v);
-            return;
-        }
-
-        prev = cmpxchg(&v->mem_event_pause_count.counter, old, new);
-    } while ( prev != old );
-
-    vcpu_unpause(v);
-}
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/xen/arch/x86/mm/mem_paging.c b/xen/arch/x86/mm/mem_paging.c
index 235776d..65f6a3d 100644
--- a/xen/arch/x86/mm/mem_paging.c
+++ b/xen/arch/x86/mm/mem_paging.c
@@ -22,7 +22,7 @@
 
 
 #include <asm/p2m.h>
-#include <asm/mem_event.h>
+#include <xen/mem_event.h>
 
 
 int mem_paging_memop(struct domain *d, xen_mem_event_op_t *mec)
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index 79188b9..7c0fc7d 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -27,12 +27,12 @@
 #include <xen/mm.h>
 #include <xen/grant_table.h>
 #include <xen/sched.h>
+#include <xen/rcupdate.h>
+#include <xen/mem_event.h>
 #include <asm/page.h>
 #include <asm/string.h>
 #include <asm/p2m.h>
-#include <asm/mem_event.h>
 #include <asm/atomic.h>
-#include <xen/rcupdate.h>
 #include <asm/event.h>
 #include <xsm/xsm.h>
 
diff --git a/xen/arch/x86/mm/p2m-pod.c b/xen/arch/x86/mm/p2m-pod.c
index bd4c7c8..43f507c 100644
--- a/xen/arch/x86/mm/p2m-pod.c
+++ b/xen/arch/x86/mm/p2m-pod.c
@@ -20,16 +20,16 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <xen/iommu.h>
+#include <xen/mem_event.h>
+#include <xen/event.h>
+#include <public/mem_event.h>
 #include <asm/domain.h>
 #include <asm/page.h>
 #include <asm/paging.h>
 #include <asm/p2m.h>
 #include <asm/hvm/vmx/vmx.h> /* ept_p2m_init() */
-#include <xen/iommu.h>
-#include <asm/mem_event.h>
-#include <public/mem_event.h>
 #include <asm/mem_sharing.h>
-#include <xen/event.h>
 #include <asm/hvm/nestedhvm.h>
 #include <asm/hvm/svm/amd-iommu-proto.h>
 
diff --git a/xen/arch/x86/mm/p2m-pt.c b/xen/arch/x86/mm/p2m-pt.c
index 085ab6f..e48b63a 100644
--- a/xen/arch/x86/mm/p2m-pt.c
+++ b/xen/arch/x86/mm/p2m-pt.c
@@ -25,16 +25,16 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <xen/iommu.h>
+#include <xen/mem_event.h>
+#include <xen/event.h>
+#include <xen/trace.h>
+#include <public/mem_event.h>
 #include <asm/domain.h>
 #include <asm/page.h>
 #include <asm/paging.h>
 #include <asm/p2m.h>
-#include <xen/iommu.h>
-#include <asm/mem_event.h>
-#include <public/mem_event.h>
 #include <asm/mem_sharing.h>
-#include <xen/event.h>
-#include <xen/trace.h>
 #include <asm/hvm/nestedhvm.h>
 #include <asm/hvm/svm/amd-iommu-proto.h>
 
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 54859c8..31d0d9e 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -24,16 +24,16 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <xen/iommu.h>
+#include <xen/mem_event.h>
+#include <xen/event.h>
+#include <public/mem_event.h>
 #include <asm/domain.h>
 #include <asm/page.h>
 #include <asm/paging.h>
 #include <asm/p2m.h>
 #include <asm/hvm/vmx/vmx.h> /* ept_p2m_init() */
-#include <xen/iommu.h>
-#include <asm/mem_event.h>
-#include <public/mem_event.h>
 #include <asm/mem_sharing.h>
-#include <xen/event.h>
 #include <asm/hvm/nestedhvm.h>
 #include <asm/hvm/svm/amd-iommu-proto.h>
 #include <xsm/xsm.h>
diff --git a/xen/arch/x86/x86_64/compat/mm.c b/xen/arch/x86/x86_64/compat/mm.c
index 69c6195..c079702 100644
--- a/xen/arch/x86/x86_64/compat/mm.c
+++ b/xen/arch/x86/x86_64/compat/mm.c
@@ -1,10 +1,10 @@
 #include <xen/event.h>
+#include <xen/mem_event.h>
+#include <xen/mem_access.h>
 #include <xen/multicall.h>
 #include <compat/memory.h>
 #include <compat/xen.h>
-#include <asm/mem_event.h>
 #include <asm/mem_sharing.h>
-#include <asm/mem_access.h>
 
 int compat_set_gdt(XEN_GUEST_HANDLE_PARAM(uint) frame_list, unsigned int entries)
 {
diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c
index 09817fc..cce1406 100644
--- a/xen/arch/x86/x86_64/mm.c
+++ b/xen/arch/x86/x86_64/mm.c
@@ -26,6 +26,8 @@
 #include <xen/nodemask.h>
 #include <xen/guest_access.h>
 #include <xen/hypercall.h>
+#include <xen/mem_event.h>
+#include <xen/mem_access.h>
 #include <asm/current.h>
 #include <asm/asm_defns.h>
 #include <asm/page.h>
@@ -35,9 +37,7 @@
 #include <asm/msr.h>
 #include <asm/setup.h>
 #include <asm/numa.h>
-#include <asm/mem_event.h>
 #include <asm/mem_sharing.h>
-#include <asm/mem_access.h>
 #include <public/memory.h>
 
 unsigned int __read_mostly m2p_compat_vstart = __HYPERVISOR_COMPAT_VIRT_START;
diff --git a/xen/common/Makefile b/xen/common/Makefile
index f7d10f0..9167104 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -52,6 +52,8 @@ obj-y += radix-tree.o
 obj-y += rbtree.o
 obj-y += lzo.o
 obj-$(HAS_PDX) += pdx.o
+obj-$(HAS_MEM_ACCESS) += mem_access.o
+obj-$(HAS_MEM_ACCESS) += mem_event.o
 
 obj-bin-$(CONFIG_X86) += $(foreach n,decompress bunzip2 unxz unlzma unlzo unlz4 earlycpio,$(n).init.o)
 
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 62514b0..134bed6 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -15,6 +15,7 @@
 #include <xen/domain.h>
 #include <xen/mm.h>
 #include <xen/event.h>
+#include <xen/mem_event.h>
 #include <xen/time.h>
 #include <xen/console.h>
 #include <xen/softirq.h>
diff --git a/xen/common/mem_access.c b/xen/common/mem_access.c
new file mode 100644
index 0000000..9a8c1a9
--- /dev/null
+++ b/xen/common/mem_access.c
@@ -0,0 +1,133 @@
+/******************************************************************************
+ * mem_access.c
+ *
+ * Memory access support.
+ *
+ * Copyright (c) 2011 Virtuata, Inc.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <xen/sched.h>
+#include <xen/guest_access.h>
+#include <xen/hypercall.h>
+#include <xen/mem_event.h>
+#include <public/memory.h>
+#include <asm/p2m.h>
+#include <xsm/xsm.h>
+
+int mem_access_memop(unsigned long cmd,
+                     XEN_GUEST_HANDLE_PARAM(xen_mem_access_op_t) arg)
+{
+    long rc;
+    xen_mem_access_op_t mao;
+    struct domain *d;
+
+    if ( copy_from_guest(&mao, arg, 1) )
+        return -EFAULT;
+
+    rc = rcu_lock_live_remote_domain_by_id(mao.domid, &d);
+    if ( rc )
+        return rc;
+
+    rc = -EINVAL;
+    if ( !is_hvm_domain(d) )
+        goto out;
+
+    rc = xsm_mem_event_op(XSM_DM_PRIV, d, XENMEM_access_op);
+    if ( rc )
+        goto out;
+
+    rc = -ENODEV;
+    if ( unlikely(!d->mem_event->access.ring_page) )
+        goto out;
+
+    switch ( mao.op )
+    {
+    case XENMEM_access_op_resume:
+        p2m_mem_access_resume(d);
+        rc = 0;
+        break;
+
+    case XENMEM_access_op_set_access:
+    {
+        unsigned long start_iter = cmd & ~MEMOP_CMD_MASK;
+
+        rc = -EINVAL;
+        if ( (mao.pfn != ~0ull) &&
+             (mao.nr < start_iter ||
+              ((mao.pfn + mao.nr - 1) < mao.pfn) ||
+              ((mao.pfn + mao.nr - 1) > domain_get_maximum_gpfn(d))) )
+            break;
+
+        rc = p2m_set_mem_access(d, mao.pfn, mao.nr, start_iter,
+                                MEMOP_CMD_MASK, mao.access);
+        if ( rc > 0 )
+        {
+            ASSERT(!(rc & MEMOP_CMD_MASK));
+            rc = hypercall_create_continuation(__HYPERVISOR_memory_op, "lh",
+                                               XENMEM_access_op | rc, arg);
+        }
+        break;
+    }
+
+    case XENMEM_access_op_get_access:
+    {
+        xenmem_access_t access;
+
+        rc = -EINVAL;
+        if ( (mao.pfn > domain_get_maximum_gpfn(d)) && mao.pfn != ~0ull )
+            break;
+
+        rc = p2m_get_mem_access(d, mao.pfn, &access);
+        if ( rc != 0 )
+            break;
+
+        mao.access = access;
+        rc = __copy_field_to_guest(arg, &mao, access) ? -EFAULT : 0;
+
+        break;
+    }
+
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
+ out:
+    rcu_unlock_domain(d);
+    return rc;
+}
+
+int mem_access_send_req(struct domain *d, mem_event_request_t *req)
+{
+    int rc = mem_event_claim_slot(d, &d->mem_event->access);
+    if ( rc < 0 )
+        return rc;
+
+    mem_event_put_request(d, &d->mem_event->access, req);
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/mem_event.c b/xen/common/mem_event.c
new file mode 100644
index 0000000..7cc99b3
--- /dev/null
+++ b/xen/common/mem_event.c
@@ -0,0 +1,739 @@
+/******************************************************************************
+ * mem_event.c
+ *
+ * Memory event support.
+ *
+ * Copyright (c) 2009 Citrix Systems, Inc. (Patrick Colp)
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/wait.h>
+#include <xen/mem_event.h>
+#include <xen/mem_access.h>
+#include <asm/p2m.h>
+
+#ifdef HAS_MEM_PAGING
+#include <asm/mem_paging.h>
+#endif
+
+#ifdef HAS_MEM_SHARING
+#include <asm/mem_sharing.h>
+#endif
+
+#include <xsm/xsm.h>
+
+/* for public/io/ring.h macros */
+#define xen_mb()   mb()
+#define xen_rmb()  rmb()
+#define xen_wmb()  wmb()
+
+#define mem_event_ring_lock_init(_med)  spin_lock_init(&(_med)->ring_lock)
+#define mem_event_ring_lock(_med)       spin_lock(&(_med)->ring_lock)
+#define mem_event_ring_unlock(_med)     spin_unlock(&(_med)->ring_lock)
+
+static int mem_event_enable(
+    struct domain *d,
+    xen_domctl_mem_event_op_t *mec,
+    struct mem_event_domain *med,
+    int pause_flag,
+    int param,
+    xen_event_channel_notification_t notification_fn)
+{
+    int rc;
+    unsigned long ring_gfn = d->arch.hvm_domain.params[param];
+
+    /* Only one helper at a time. If the helper crashed,
+     * the ring is in an undefined state and so is the guest.
+     */
+    if ( med->ring_page )
+        return -EBUSY;
+
+    /* The parameter defaults to zero, and it should be 
+     * set to something */
+    if ( ring_gfn == 0 )
+        return -ENOSYS;
+
+    mem_event_ring_lock_init(med);
+    mem_event_ring_lock(med);
+
+    rc = prepare_ring_for_helper(d, ring_gfn, &med->ring_pg_struct, 
+                                    &med->ring_page);
+    if ( rc < 0 )
+        goto err;
+
+    /* Set the number of currently blocked vCPUs to 0. */
+    med->blocked = 0;
+
+    /* Allocate event channel */
+    rc = alloc_unbound_xen_event_channel(d->vcpu[0],
+                                         current->domain->domain_id,
+                                         notification_fn);
+    if ( rc < 0 )
+        goto err;
+
+    med->xen_port = mec->port = rc;
+
+    /* Prepare ring buffer */
+    FRONT_RING_INIT(&med->front_ring,
+                    (mem_event_sring_t *)med->ring_page,
+                    PAGE_SIZE);
+
+    /* Save the pause flag for this particular ring. */
+    med->pause_flag = pause_flag;
+
+    /* Initialize the last-chance wait queue. */
+    init_waitqueue_head(&med->wq);
+
+    mem_event_ring_unlock(med);
+    return 0;
+
+ err:
+    destroy_ring_for_helper(&med->ring_page, 
+                            med->ring_pg_struct);
+    mem_event_ring_unlock(med);
+
+    return rc;
+}
+
+static unsigned int mem_event_ring_available(struct mem_event_domain *med)
+{
+    int avail_req = RING_FREE_REQUESTS(&med->front_ring);
+    avail_req -= med->target_producers;
+    avail_req -= med->foreign_producers;
+
+    BUG_ON(avail_req < 0);
+
+    return avail_req;
+}
+
+/*
+ * mem_event_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 mem_event_wake_blocked(struct domain *d, struct mem_event_domain *med)
+{
+    struct vcpu *v;
+    int online = d->max_vcpus;
+    unsigned int avail_req = mem_event_ring_available(med);
+
+    if ( avail_req == 0 || med->blocked == 0 )
+        return;
+
+    /*
+     * We ensure that we only have vCPUs online if there are enough free slots
+     * for their memory events to be processed.  This will ensure that no
+     * memory events are lost (due to the fact that certain types of events
+     * cannot be replayed, we need to ensure that there is space in the ring
+     * for when they are hit).
+     * See comment below in mem_event_put_request().
+     */
+    for_each_vcpu ( d, v )
+        if ( test_bit(med->pause_flag, &v->pause_flags) )
+            online--;
+
+    ASSERT(online == (d->max_vcpus - med->blocked));
+
+    /* 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 )
+    {
+        int i, j, k;
+
+        for (i = med->last_vcpu_wake_up + 1, j = 0; j < d->max_vcpus; i++, j++)
+        {
+            k = i % d->max_vcpus;
+            v = d->vcpu[k];
+            if ( !v )
+                continue;
+
+            if ( !(med->blocked) || online >= avail_req )
+               break;
+
+            if ( test_and_clear_bit(med->pause_flag, &v->pause_flags) )
+            {
+                vcpu_unpause(v);
+                online++;
+                med->blocked--;
+                med->last_vcpu_wake_up = k;
+            }
+        }
+    }
+}
+
+/*
+ * In the event that a vCPU attempted to place an event in the ring and
+ * 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 mem_event_wake_queued(struct domain *d, struct mem_event_domain *med)
+{
+    unsigned int avail_req = mem_event_ring_available(med);
+
+    if ( avail_req > 0 )
+        wake_up_nr(&med->wq, avail_req);
+}
+
+/*
+ * mem_event_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 mem_event_wake() again, ensuring that any blocked vCPUs will get
+ * unpaused once all the queued vCPUs have made it through.
+ */
+void mem_event_wake(struct domain *d, struct mem_event_domain *med)
+{
+    if (!list_empty(&med->wq.list))
+        mem_event_wake_queued(d, med);
+    else
+        mem_event_wake_blocked(d, med);
+}
+
+static int mem_event_disable(struct domain *d, struct mem_event_domain *med)
+{
+    if ( med->ring_page )
+    {
+        struct vcpu *v;
+
+        mem_event_ring_lock(med);
+
+        if ( !list_empty(&med->wq.list) )
+        {
+            mem_event_ring_unlock(med);
+            return -EBUSY;
+        }
+
+        /* Free domU's event channel and leave the other one unbound */
+        free_xen_event_channel(d->vcpu[0], med->xen_port);
+
+        /* Unblock all vCPUs */
+        for_each_vcpu ( d, v )
+        {
+            if ( test_and_clear_bit(med->pause_flag, &v->pause_flags) )
+            {
+                vcpu_unpause(v);
+                med->blocked--;
+            }
+        }
+
+        destroy_ring_for_helper(&med->ring_page, 
+                                med->ring_pg_struct);
+        mem_event_ring_unlock(med);
+    }
+
+    return 0;
+}
+
+static inline void mem_event_release_slot(struct domain *d,
+                                          struct mem_event_domain *med)
+{
+    /* Update the accounting */
+    if ( current->domain == d )
+        med->target_producers--;
+    else
+        med->foreign_producers--;
+
+    /* Kick any waiters */
+    mem_event_wake(d, med);
+}
+
+/*
+ * mem_event_mark_and_pause() tags vcpu and put it to sleep.
+ * The vcpu will resume execution in mem_event_wake_waiters().
+ */
+void mem_event_mark_and_pause(struct vcpu *v, struct mem_event_domain *med)
+{
+    if ( !test_and_set_bit(med->pause_flag, &v->pause_flags) )
+    {
+        vcpu_pause_nosync(v);
+        med->blocked++;
+    }
+}
+
+/*
+ * This must be preceded by a call to claim_slot(), and is guaranteed to
+ * succeed.  As a side-effect however, the vCPU may be paused if the ring is
+ * overly full and its continued execution would cause stalling and excessive
+ * waiting.  The vCPU will be automatically unpaused when the ring clears.
+ */
+void mem_event_put_request(struct domain *d,
+                           struct mem_event_domain *med,
+                           mem_event_request_t *req)
+{
+    mem_event_front_ring_t *front_ring;
+    int free_req;
+    unsigned int avail_req;
+    RING_IDX req_prod;
+
+    if ( current->domain != d )
+    {
+        req->flags |= MEM_EVENT_FLAG_FOREIGN;
+        ASSERT( !(req->flags & MEM_EVENT_FLAG_VCPU_PAUSED) );
+    }
+
+    mem_event_ring_lock(med);
+
+    /* Due to the reservations, this step must succeed. */
+    front_ring = &med->front_ring;
+    free_req = RING_FREE_REQUESTS(front_ring);
+    ASSERT(free_req > 0);
+
+    /* Copy request */
+    req_prod = front_ring->req_prod_pvt;
+    memcpy(RING_GET_REQUEST(front_ring, req_prod), req, sizeof(*req));
+    req_prod++;
+
+    /* Update ring */
+    front_ring->req_prod_pvt = req_prod;
+    RING_PUSH_REQUESTS(front_ring);
+
+    /* We've actually *used* our reservation, so release the slot. */
+    mem_event_release_slot(d, med);
+
+    /* 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 = mem_event_ring_available(med);
+    if( current->domain == d && avail_req < d->max_vcpus )
+        mem_event_mark_and_pause(current, med);
+
+    mem_event_ring_unlock(med);
+
+    notify_via_xen_event_channel(d, med->xen_port);
+}
+
+int mem_event_get_response(struct domain *d, struct mem_event_domain *med, mem_event_response_t *rsp)
+{
+    mem_event_front_ring_t *front_ring;
+    RING_IDX rsp_cons;
+
+    mem_event_ring_lock(med);
+
+    front_ring = &med->front_ring;
+    rsp_cons = front_ring->rsp_cons;
+
+    if ( !RING_HAS_UNCONSUMED_RESPONSES(front_ring) )
+    {
+        mem_event_ring_unlock(med);
+        return 0;
+    }
+
+    /* Copy response */
+    memcpy(rsp, RING_GET_RESPONSE(front_ring, rsp_cons), sizeof(*rsp));
+    rsp_cons++;
+
+    /* Update ring */
+    front_ring->rsp_cons = rsp_cons;
+    front_ring->sring->rsp_event = rsp_cons + 1;
+
+    /* Kick any waiters -- since we've just consumed an event,
+     * there may be additional space available in the ring. */
+    mem_event_wake(d, med);
+
+    mem_event_ring_unlock(med);
+
+    return 1;
+}
+
+void mem_event_cancel_slot(struct domain *d, struct mem_event_domain *med)
+{
+    mem_event_ring_lock(med);
+    mem_event_release_slot(d, med);
+    mem_event_ring_unlock(med);
+}
+
+static int mem_event_grab_slot(struct mem_event_domain *med, int foreign)
+{
+    unsigned int avail_req;
+
+    if ( !med->ring_page )
+        return -ENOSYS;
+
+    mem_event_ring_lock(med);
+
+    avail_req = mem_event_ring_available(med);
+    if ( avail_req == 0 )
+    {
+        mem_event_ring_unlock(med);
+        return -EBUSY;
+    }
+
+    if ( !foreign )
+        med->target_producers++;
+    else
+        med->foreign_producers++;
+
+    mem_event_ring_unlock(med);
+
+    return 0;
+}
+
+/* Simple try_grab wrapper for use in the wait_event() macro. */
+static int mem_event_wait_try_grab(struct mem_event_domain *med, int *rc)
+{
+    *rc = mem_event_grab_slot(med, 0);
+    return *rc;
+}
+
+/* Call mem_event_grab_slot() until the ring doesn't exist, or is available. */
+static int mem_event_wait_slot(struct mem_event_domain *med)
+{
+    int rc = -EBUSY;
+    wait_event(med->wq, mem_event_wait_try_grab(med, &rc) != -EBUSY);
+    return rc;
+}
+
+bool_t mem_event_check_ring(struct mem_event_domain *med)
+{
+    return (med->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 mem_event_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.
+ *
+ * Return codes: -ENOSYS: the ring is not yet configured
+ *               -EBUSY: the ring is busy
+ *               0: a spot has been reserved
+ *
+ */
+int __mem_event_claim_slot(struct domain *d, struct mem_event_domain *med,
+                            bool_t allow_sleep)
+{
+    if ( (current->domain == d) && allow_sleep )
+        return mem_event_wait_slot(med);
+    else
+        return mem_event_grab_slot(med, (current->domain != d));
+}
+
+#ifdef HAS_MEM_PAGING
+/* Registered with Xen-bound event channel for incoming notifications. */
+static void mem_paging_notification(struct vcpu *v, unsigned int port)
+{
+    if ( likely(v->domain->mem_event->paging.ring_page != NULL) )
+        p2m_mem_paging_resume(v->domain);
+}
+#endif
+
+/* Registered with Xen-bound event channel for incoming notifications. */
+static void mem_access_notification(struct vcpu *v, unsigned int port)
+{
+    if ( likely(v->domain->mem_event->access.ring_page != NULL) )
+        p2m_mem_access_resume(v->domain);
+}
+
+#ifdef HAS_MEM_SHARING
+/* Registered with Xen-bound event channel for incoming notifications. */
+static void mem_sharing_notification(struct vcpu *v, unsigned int port)
+{
+    if ( likely(v->domain->mem_event->share.ring_page != NULL) )
+        mem_sharing_sharing_resume(v->domain);
+}
+#endif
+
+int do_mem_event_op(int op, uint32_t domain, void *arg)
+{
+    int ret;
+    struct domain *d;
+
+    ret = rcu_lock_live_remote_domain_by_id(domain, &d);
+    if ( ret )
+        return ret;
+
+    ret = xsm_mem_event_op(XSM_DM_PRIV, d, op);
+    if ( ret )
+        goto out;
+
+    switch (op)
+    {
+#ifdef HAS_MEM_PAGING
+        case XENMEM_paging_op:
+            ret = mem_paging_memop(d, (xen_mem_event_op_t *) arg);
+            break;
+#endif
+#ifdef HAS_MEM_SHARING
+        case XENMEM_sharing_op:
+            ret = mem_sharing_memop(d, (xen_mem_sharing_op_t *) arg);
+            break;
+#endif
+        default:
+            ret = -ENOSYS;
+    }
+
+ out:
+    rcu_unlock_domain(d);
+    return ret;
+}
+
+/* Clean up on domain destruction */
+void mem_event_cleanup(struct domain *d)
+{
+#ifdef HAS_MEM_PAGING
+    if ( d->mem_event->paging.ring_page ) {
+        /* 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->mem_event->paging.wq);
+        (void)mem_event_disable(d, &d->mem_event->paging);
+    }
+#endif
+    if ( d->mem_event->access.ring_page ) {
+        destroy_waitqueue_head(&d->mem_event->access.wq);
+        (void)mem_event_disable(d, &d->mem_event->access);
+    }
+#ifdef HAS_MEM_SHARING
+    if ( d->mem_event->share.ring_page ) {
+        destroy_waitqueue_head(&d->mem_event->share.wq);
+        (void)mem_event_disable(d, &d->mem_event->share);
+    }
+#endif
+}
+
+int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
+                     XEN_GUEST_HANDLE_PARAM(void) u_domctl)
+{
+    int rc;
+
+    rc = xsm_mem_event_control(XSM_PRIV, d, mec->mode, mec->op);
+    if ( rc )
+        return rc;
+
+    if ( unlikely(d == current->domain) )
+    {
+        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;
+    }
+
+    rc = -ENOSYS;
+
+    switch ( mec->mode )
+    {
+#ifdef HAS_MEM_PAGING
+    case XEN_DOMCTL_MEM_EVENT_OP_PAGING:
+    {
+        struct mem_event_domain *med = &d->mem_event->paging;
+        rc = -EINVAL;
+
+        switch( mec->op )
+        {
+        case XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE:
+        {
+            struct p2m_domain *p2m = p2m_get_hostp2m(d);
+
+            rc = -EOPNOTSUPP;
+            /* pvh fixme: p2m_is_foreign types need addressing */
+            if ( is_pvh_vcpu(current) || is_pvh_domain(hardware_domain) )
+                break;
+
+            rc = -ENODEV;
+            /* Only HAP is supported */
+            if ( !hap_enabled(d) )
+                break;
+
+            /* No paging if iommu is used */
+            rc = -EMLINK;
+            if ( unlikely(need_iommu(d)) )
+                break;
+
+            rc = -EXDEV;
+            /* Disallow paging in a PoD guest */
+            if ( p2m->pod.entry_count )
+                break;
+
+            rc = mem_event_enable(d, mec, med, _VPF_mem_paging, 
+                                    HVM_PARAM_PAGING_RING_PFN,
+                                    mem_paging_notification);
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_EVENT_OP_PAGING_DISABLE:
+        {
+            if ( med->ring_page )
+                rc = mem_event_disable(d, med);
+        }
+        break;
+
+        default:
+            rc = -ENOSYS;
+            break;
+        }
+    }
+    break;
+#endif
+
+    case XEN_DOMCTL_MEM_EVENT_OP_ACCESS: 
+    {
+        struct mem_event_domain *med = &d->mem_event->access;
+        rc = -EINVAL;
+
+        switch( mec->op )
+        {
+        case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE:
+        case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION:
+        {
+            rc = -ENODEV;
+            /* Only HAP is supported */
+            if ( !hap_enabled(d) )
+                break;
+
+            /* Currently only EPT is supported */
+            if ( !cpu_has_vmx )
+                break;
+
+            rc = mem_event_enable(d, mec, med, _VPF_mem_access, 
+                                    HVM_PARAM_ACCESS_RING_PFN,
+                                    mem_access_notification);
+
+            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
+                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
+            {
+                d->arch.hvm_domain.introspection_enabled = 1;
+                hvm_funcs.enable_msr_exit_interception(d);
+            }
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_DISABLE:
+        {
+            if ( med->ring_page )
+            {
+                rc = mem_event_disable(d, med);
+                d->arch.hvm_domain.introspection_enabled = 0;
+            }
+        }
+        break;
+
+        default:
+            rc = -ENOSYS;
+            break;
+        }
+    }
+    break;
+
+#ifdef HAS_MEM_SHARING
+    case XEN_DOMCTL_MEM_EVENT_OP_SHARING: 
+    {
+        struct mem_event_domain *med = &d->mem_event->share;
+        rc = -EINVAL;
+
+        switch( mec->op )
+        {
+        case XEN_DOMCTL_MEM_EVENT_OP_SHARING_ENABLE:
+        {
+            rc = -EOPNOTSUPP;
+            /* pvh fixme: p2m_is_foreign types need addressing */
+            if ( is_pvh_vcpu(current) || is_pvh_domain(hardware_domain) )
+                break;
+
+            rc = -ENODEV;
+            /* Only HAP is supported */
+            if ( !hap_enabled(d) )
+                break;
+
+            rc = mem_event_enable(d, mec, med, _VPF_mem_sharing, 
+                                    HVM_PARAM_SHARING_RING_PFN,
+                                    mem_sharing_notification);
+        }
+        break;
+
+        case XEN_DOMCTL_MEM_EVENT_OP_SHARING_DISABLE:
+        {
+            if ( med->ring_page )
+                rc = mem_event_disable(d, med);
+        }
+        break;
+
+        default:
+            rc = -ENOSYS;
+            break;
+        }
+    }
+    break;
+#endif
+
+    default:
+        rc = -ENOSYS;
+    }
+
+    return rc;
+}
+
+void mem_event_vcpu_pause(struct vcpu *v)
+{
+    ASSERT(v == current);
+
+    atomic_inc(&v->mem_event_pause_count);
+    vcpu_pause_nosync(v);
+}
+
+void mem_event_vcpu_unpause(struct vcpu *v)
+{
+    int old, new, prev = v->mem_event_pause_count.counter;
+
+    /* All unpause requests as a result of toolstack responses.  Prevent
+     * underflow of the vcpu pause count. */
+    do
+    {
+        old = prev;
+        new = old - 1;
+
+        if ( new < 0 )
+        {
+            printk(XENLOG_G_WARNING
+                   "%pv mem_event: Too many unpause attempts\n", v);
+            return;
+        }
+
+        prev = cmpxchg(&v->mem_event_pause_count.counter, old, new);
+    } while ( prev != old );
+
+    vcpu_unpause(v);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 2e3225d..bad50cb 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -1104,6 +1104,69 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
     return rc;
 }
 
+void destroy_ring_for_helper(
+    void **_va, struct page_info *page)
+{
+    void *va = *_va;
+
+    if ( va != NULL )
+    {
+        unmap_domain_page_global(va);
+        put_page_and_type(page);
+        *_va = NULL;
+    }
+}
+
+int prepare_ring_for_helper(
+    struct domain *d, unsigned long gmfn, struct page_info **_page,
+    void **_va)
+{
+    struct page_info *page;
+    p2m_type_t p2mt;
+    void *va;
+
+    page = get_page_from_gfn(d, gmfn, &p2mt, P2M_UNSHARE);
+
+#ifdef HAS_MEM_PAGING
+    if ( p2m_is_paging(p2mt) )
+    {
+        if ( page )
+            put_page(page);
+        p2m_mem_paging_populate(d, gmfn);
+        return -ENOENT;
+    }
+#endif
+#ifdef HAS_MEM_SHARING
+    if ( p2m_is_shared(p2mt) )
+    {
+        if ( page )
+            put_page(page);
+        return -ENOENT;
+    }
+#endif
+
+    if ( !page )
+        return -EINVAL;
+
+    if ( !get_page_type(page, PGT_writable_page) )
+    {
+        put_page(page);
+        return -EINVAL;
+    }
+
+    va = __map_domain_page_global(page);
+    if ( va == NULL )
+    {
+        put_page_and_type(page);
+        return -ENOMEM;
+    }
+
+    *_va = va;
+    *_page = page;
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/mm.h b/xen/include/asm-arm/mm.h
index 33ac4b4..1e4711c 100644
--- a/xen/include/asm-arm/mm.h
+++ b/xen/include/asm-arm/mm.h
@@ -300,7 +300,6 @@ struct page_info *get_page_from_gva(struct domain *d, vaddr_t va,
     })
 
 static inline void put_gfn(struct domain *d, unsigned long gfn) {}
-static inline void mem_event_cleanup(struct domain *d) {}
 static inline int relinquish_shared_pages(struct domain *d)
 {
     return 0;
diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
index 121d053..405f1f0 100644
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -228,12 +228,6 @@ int hvm_vcpu_cacheattr_init(struct vcpu *v);
 void hvm_vcpu_cacheattr_destroy(struct vcpu *v);
 void hvm_vcpu_reset_state(struct vcpu *v, uint16_t cs, uint16_t ip);
 
-/* Prepare/destroy a ring for a dom0 helper. Helper with talk
- * with Xen on behalf of this hvm domain. */
-int prepare_ring_for_helper(struct domain *d, unsigned long gmfn, 
-                            struct page_info **_page, void **_va);
-void destroy_ring_for_helper(void **_va, struct page_info *page);
-
 bool_t hvm_send_assist_req(ioreq_t *p);
 void hvm_broadcast_assist_req(ioreq_t *p);
 
diff --git a/xen/include/asm-x86/mem_access.h b/xen/include/asm-x86/mem_access.h
deleted file mode 100644
index 5c7c5fd..0000000
--- a/xen/include/asm-x86/mem_access.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/******************************************************************************
- * include/asm-x86/mem_access.h
- *
- * Memory access support.
- *
- * Copyright (c) 2011 Virtuata, Inc.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef _XEN_ASM_MEM_ACCESS_H
-#define _XEN_ASM_MEM_ACCESS_H
-
-int mem_access_memop(unsigned long cmd,
-                     XEN_GUEST_HANDLE_PARAM(xen_mem_access_op_t) arg);
-int mem_access_send_req(struct domain *d, mem_event_request_t *req);
-
-#endif /* _XEN_ASM_MEM_ACCESS_H */
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/xen/include/asm-x86/mem_event.h b/xen/include/asm-x86/mem_event.h
deleted file mode 100644
index ed4481a..0000000
--- a/xen/include/asm-x86/mem_event.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/******************************************************************************
- * include/asm-x86/mem_event.h
- *
- * Common interface for memory event support.
- *
- * Copyright (c) 2009 Citrix Systems, Inc. (Patrick Colp)
- *
- * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#ifndef __MEM_EVENT_H__
-#define __MEM_EVENT_H__
-
-/* Returns whether a ring has been set up */
-bool_t mem_event_check_ring(struct mem_event_domain *med);
-
-/* 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
- * is the caller, -EBUSY is avoided by sleeping on a wait queue to ensure
- * that the ring does not lose future events. 
- *
- * However, the allow_sleep flag can be set to false in cases in which it is ok
- * to lose future events, and thus -EBUSY can be returned to guest vcpus
- * (handle with care!). 
- *
- * In general, you must follow a claim_slot() call with either put_request() or
- * cancel_slot(), both of which are guaranteed to
- * succeed. 
- */
-int __mem_event_claim_slot(struct domain *d, struct mem_event_domain *med,
-                            bool_t allow_sleep);
-static inline int mem_event_claim_slot(struct domain *d, 
-                                        struct mem_event_domain *med)
-{
-    return __mem_event_claim_slot(d, med, 1);
-}
-
-static inline int mem_event_claim_slot_nosleep(struct domain *d,
-                                        struct mem_event_domain *med)
-{
-    return __mem_event_claim_slot(d, med, 0);
-}
-
-void mem_event_cancel_slot(struct domain *d, struct mem_event_domain *med);
-
-void mem_event_put_request(struct domain *d, struct mem_event_domain *med,
-                            mem_event_request_t *req);
-
-int mem_event_get_response(struct domain *d, struct mem_event_domain *med,
-                           mem_event_response_t *rsp);
-
-int do_mem_event_op(int op, uint32_t domain, void *arg);
-int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
-                     XEN_GUEST_HANDLE_PARAM(void) u_domctl);
-
-void mem_event_vcpu_pause(struct vcpu *v);
-void mem_event_vcpu_unpause(struct vcpu *v);
-
-#endif /* __MEM_EVENT_H__ */
-
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index 746bcf1..aae63ee 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -609,8 +609,6 @@ unsigned int domain_clamp_alloc_bitsize(struct domain *d, unsigned int bits);
 
 unsigned long domain_get_maximum_gpfn(struct domain *d);
 
-void mem_event_cleanup(struct domain *d);
-
 extern struct domain *dom_xen, *dom_io, *dom_cow;	/* for vmcoreinfo */
 
 /* Definition of an mm lock: spinlock with extra fields for debugging */
diff --git a/xen/include/xen/mem_access.h b/xen/include/xen/mem_access.h
new file mode 100644
index 0000000..19d1a2d
--- /dev/null
+++ b/xen/include/xen/mem_access.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * mem_access.h
+ *
+ * Memory access support.
+ *
+ * Copyright (c) 2011 Virtuata, Inc.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _XEN_ASM_MEM_ACCESS_H
+#define _XEN_ASM_MEM_ACCESS_H
+
+#include <public/memory.h>
+
+#ifdef HAS_MEM_ACCESS
+
+int mem_access_memop(unsigned long cmd,
+                     XEN_GUEST_HANDLE_PARAM(xen_mem_access_op_t) arg);
+int mem_access_send_req(struct domain *d, mem_event_request_t *req);
+
+#else
+
+static inline
+int mem_access_memop(unsigned long cmd,
+                     XEN_GUEST_HANDLE_PARAM(xen_mem_access_op_t) arg)
+{
+    return -ENOSYS;
+}
+
+static inline
+int mem_access_send_req(struct domain *d, mem_event_request_t *req)
+{
+    return -ENOSYS;
+}
+
+#endif /* HAS_MEM_ACCESS */
+
+#endif /* _XEN_ASM_MEM_ACCESS_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/xen/mem_event.h b/xen/include/xen/mem_event.h
new file mode 100644
index 0000000..8612b26
--- /dev/null
+++ b/xen/include/xen/mem_event.h
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * mem_event.h
+ *
+ * Common interface for memory event support.
+ *
+ * Copyright (c) 2009 Citrix Systems, Inc. (Patrick Colp)
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef __MEM_EVENT_H__
+#define __MEM_EVENT_H__
+
+#include <xen/sched.h>
+
+#ifdef HAS_MEM_ACCESS
+
+/* Clean up on domain destruction */
+void mem_event_cleanup(struct domain *d);
+
+/* Returns whether a ring has been set up */
+bool_t mem_event_check_ring(struct mem_event_domain *med);
+
+/* 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
+ * is the caller, -EBUSY is avoided by sleeping on a wait queue to ensure
+ * that the ring does not lose future events. 
+ *
+ * However, the allow_sleep flag can be set to false in cases in which it is ok
+ * to lose future events, and thus -EBUSY can be returned to guest vcpus
+ * (handle with care!). 
+ *
+ * In general, you must follow a claim_slot() call with either put_request() or
+ * cancel_slot(), both of which are guaranteed to
+ * succeed. 
+ */
+int __mem_event_claim_slot(struct domain *d, struct mem_event_domain *med,
+                            bool_t allow_sleep);
+static inline int mem_event_claim_slot(struct domain *d, 
+                                        struct mem_event_domain *med)
+{
+    return __mem_event_claim_slot(d, med, 1);
+}
+
+static inline int mem_event_claim_slot_nosleep(struct domain *d,
+                                        struct mem_event_domain *med)
+{
+    return __mem_event_claim_slot(d, med, 0);
+}
+
+void mem_event_cancel_slot(struct domain *d, struct mem_event_domain *med);
+
+void mem_event_put_request(struct domain *d, struct mem_event_domain *med,
+                            mem_event_request_t *req);
+
+int mem_event_get_response(struct domain *d, struct mem_event_domain *med,
+                           mem_event_response_t *rsp);
+
+int do_mem_event_op(int op, uint32_t domain, void *arg);
+int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
+                     XEN_GUEST_HANDLE_PARAM(void) u_domctl);
+
+void mem_event_vcpu_pause(struct vcpu *v);
+void mem_event_vcpu_unpause(struct vcpu *v);
+
+#else
+
+static inline void mem_event_cleanup(struct domain *d) {}
+
+static inline bool_t mem_event_check_ring(struct mem_event_domain *med)
+{
+    return 0;
+}
+
+static inline int mem_event_claim_slot(struct domain *d,
+                                        struct mem_event_domain *med)
+{
+    return -ENOSYS;
+}
+
+static inline int mem_event_claim_slot_nosleep(struct domain *d,
+                                        struct mem_event_domain *med)
+{
+    return -ENOSYS;
+}
+
+static inline
+void mem_event_cancel_slot(struct domain *d, struct mem_event_domain *med)
+{}
+
+static inline
+void mem_event_put_request(struct domain *d, struct mem_event_domain *med,
+                            mem_event_request_t *req)
+{}
+
+static inline
+int mem_event_get_response(struct domain *d, struct mem_event_domain *med,
+                           mem_event_response_t *rsp)
+{
+    return -ENOSYS;
+}
+
+static inline int do_mem_event_op(int op, uint32_t domain, void *arg)
+{
+    return -ENOSYS;
+}
+
+static inline
+int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
+                     XEN_GUEST_HANDLE_PARAM(void) u_domctl)
+{
+    return -ENOSYS;
+}
+
+static inline void mem_event_vcpu_pause(struct vcpu *v) {}
+static inline void mem_event_vcpu_unpause(struct vcpu *v) {}
+
+#endif /* HAS_MEM_ACCESS */
+
+#endif /* __MEM_EVENT_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
index b183189..7c0efc7 100644
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -371,4 +371,10 @@ int guest_remove_page(struct domain *d, unsigned long gmfn);
 /* TRUE if the whole page at @mfn is of the requested RAM type(s) above. */
 int page_is_ram_type(unsigned long mfn, unsigned long mem_type);
 
+/* Prepare/destroy a ring for a dom0 helper. Helper with talk
+ * with Xen on behalf of this domain. */
+int prepare_ring_for_helper(struct domain *d, unsigned long gmfn,
+                            struct page_info **_page, void **_va);
+void destroy_ring_for_helper(void **_va, struct page_info *page);
+
 #endif /* __XEN_MM_H__ */
-- 
2.1.0

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

* [PATCH for-4.5 v8 02/19] xen: Relocate struct npfec definition into common
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 01/19] xen: Relocate mem_access and mem_event into common Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 03/19] xen: Relocate p2m_access_t into common and swap the order Tamas K Lengyel
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Nested page fault exception code definitions can be reused on ARM as well.

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Tim Deegan <tim@xen.org>
---
 xen/include/asm-x86/hvm/hvm.h |  2 +-
 xen/include/asm-x86/mm.h      | 21 ---------------------
 xen/include/xen/mm.h          | 21 +++++++++++++++++++++
 3 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
index 405f1f0..1a9bfd4 100644
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -27,7 +27,7 @@
 #include <public/domctl.h>
 #include <public/hvm/save.h>
 #include <public/hvm/ioreq.h>
-#include <asm/mm.h>
+#include <xen/mm.h>
 
 /* Interrupt acknowledgement sources. */
 enum hvm_intsrc {
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index aae63ee..dca298f 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -549,27 +549,6 @@ void audit_domains(void);
 
 #endif
 
-/*
- * Extra fault info types which are used to further describe
- * the source of an access violation.
- */
-typedef enum {
-    npfec_kind_unknown, /* must be first */
-    npfec_kind_in_gpt,  /* violation in guest page table */
-    npfec_kind_with_gla /* violation with guest linear address */
-} npfec_kind_t;
-
-/*
- * Nested page fault exception codes.
- */
-struct npfec {
-    unsigned int read_access:1;
-    unsigned int write_access:1;
-    unsigned int insn_fetch:1;
-    unsigned int gla_valid:1;
-    unsigned int kind:2;  /* npfec_kind_t */
-};
-
 int new_guest_cr3(unsigned long pfn);
 void make_cr3(struct vcpu *v, unsigned long mfn);
 void update_cr3(struct vcpu *v);
diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
index 7c0efc7..74a65a6 100644
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -88,6 +88,27 @@ int assign_pages(
 /* Dump info to serial console */
 void arch_dump_shared_mem_info(void);
 
+/*
+ * Extra fault info types which are used to further describe
+ * the source of an access violation.
+ */
+typedef enum {
+    npfec_kind_unknown, /* must be first */
+    npfec_kind_in_gpt,  /* violation in guest page table */
+    npfec_kind_with_gla /* violation with guest linear address */
+} npfec_kind_t;
+
+/*
+ * Nested page fault exception codes.
+ */
+struct npfec {
+    unsigned int read_access:1;
+    unsigned int write_access:1;
+    unsigned int insn_fetch:1;
+    unsigned int gla_valid:1;
+    unsigned int kind:2;  /* npfec_kind_t */
+};
+
 /* memflags: */
 #define _MEMF_no_refcount 0
 #define  MEMF_no_refcount (1U<<_MEMF_no_refcount)
-- 
2.1.0

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

* [PATCH for-4.5 v8 03/19] xen: Relocate p2m_access_t into common and swap the order
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 01/19] xen: Relocate mem_access and mem_event into common Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 02/19] xen: Relocate struct npfec definition " Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common Tamas K Lengyel
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

We swap the order of the enum of types n ... rwx, as to have rwx at 0, which is
the default setting when mem_access is not in use. This has performance benefits for
non-memaccess paths, as now comparison is to 0 when checking if memaccess is in use,
which is often faster.

We fix one location in nested_hap where the order of the enum made a difference.

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Tim Deegan <tim@xen.org>
---
 xen/arch/x86/mm/hap/nested_hap.c |  2 +-
 xen/include/asm-x86/p2m.h        | 28 ----------------------------
 xen/include/xen/p2m-common.h     | 29 +++++++++++++++++++++++++++++
 3 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/xen/arch/x86/mm/hap/nested_hap.c b/xen/arch/x86/mm/hap/nested_hap.c
index a4bb835..9c1ec11 100644
--- a/xen/arch/x86/mm/hap/nested_hap.c
+++ b/xen/arch/x86/mm/hap/nested_hap.c
@@ -264,7 +264,7 @@ nestedhvm_hap_nested_page_fault(struct vcpu *v, paddr_t *L2_gpa,
 
     switch ( p2ma_10 )
     {
-    case p2m_access_n ... p2m_access_rwx:
+    case p2m_access_rwx ... p2m_access_n:
         break;
     case p2m_access_rx2rw:
         p2ma_10 = p2m_access_rx;
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index bae669e..a2a6289 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -74,34 +74,6 @@ typedef enum {
     p2m_map_foreign  = 14,        /* ram pages from foreign domain */
 } p2m_type_t;
 
-/*
- * Additional access types, which are used to further restrict
- * the permissions given my the p2m_type_t memory type.  Violations
- * caused by p2m_access_t restrictions are sent to the mem_event
- * interface.
- *
- * The access permissions are soft state: when any ambigious change of page
- * type or use occurs, or when pages are flushed, swapped, or at any other
- * convenient type, the access permissions can get reset to the p2m_domain
- * default.
- */
-typedef enum {
-    p2m_access_n     = 0, /* No access permissions allowed */
-    p2m_access_r     = 1,
-    p2m_access_w     = 2, 
-    p2m_access_rw    = 3,
-    p2m_access_x     = 4, 
-    p2m_access_rx    = 5,
-    p2m_access_wx    = 6, 
-    p2m_access_rwx   = 7,
-    p2m_access_rx2rw = 8, /* Special: page goes from RX to RW on write */
-    p2m_access_n2rwx = 9, /* Special: page goes from N to RWX on access, *
-                           * generates an event but does not pause the
-                           * vcpu */
-
-    /* NOTE: Assumed to be only 4 bits right now */
-} p2m_access_t;
-
 /* Modifiers to the query */
 typedef unsigned int p2m_query_t;
 #define P2M_ALLOC    (1u<<0)   /* Populate PoD and paged-out entries */
diff --git a/xen/include/xen/p2m-common.h b/xen/include/xen/p2m-common.h
index 9f1b771..787fc43 100644
--- a/xen/include/xen/p2m-common.h
+++ b/xen/include/xen/p2m-common.h
@@ -1,6 +1,35 @@
 #ifndef _XEN_P2M_COMMON_H
 #define _XEN_P2M_COMMON_H
 
+/*
+ * Additional access types, which are used to further restrict
+ * the permissions given my the p2m_type_t memory type.  Violations
+ * caused by p2m_access_t restrictions are sent to the mem_event
+ * interface.
+ *
+ * The access permissions are soft state: when any ambiguous change of page
+ * type or use occurs, or when pages are flushed, swapped, or at any other
+ * convenient type, the access permissions can get reset to the p2m_domain
+ * default.
+ */
+typedef enum {
+    p2m_access_rwx   = 0, /* The default access type when not used. */
+    p2m_access_wx    = 1,
+    p2m_access_rx    = 2,
+    p2m_access_x     = 3,
+    p2m_access_rw    = 4,
+    p2m_access_w     = 5,
+    p2m_access_r     = 6,
+    p2m_access_n     = 7, /* No access allowed. */
+
+    p2m_access_rx2rw = 8, /* Special: page goes from RX to RW on write */
+    p2m_access_n2rwx = 9, /* Special: page goes from N to RWX on access, *
+                           * generates an event but does not pause the
+                           * vcpu */
+
+    /* NOTE: Assumed to be only 4 bits right now on x86. */
+} p2m_access_t;
+
 /* Map MMIO regions in the p2m: start_gfn and nr describe the range in
  *  * the guest physical address space to map, starting from the machine
  *   * frame number mfn. */
-- 
2.1.0

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

* [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (2 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 03/19] xen: Relocate p2m_access_t into common and swap the order Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:28   ` Jan Beulich
  2014-09-23 13:14 ` [PATCH for-4.5 v8 05/19] xen: Relocate set_access_required domctl into common Tamas K Lengyel
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Relocate p2m_mem_access_resume to common and abstract the new
p2m_mem_event_emulate_check into the p2m layer to.

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Tim Deegan <tim@xen.org>
---
v8: Abstract p2m_mem_event_emulate_check.
v6: Keep the comment describing the function.
v5: Style fix.
---
 xen/arch/x86/mm/p2m.c        | 128 ++++++++++++++++++-------------------------
 xen/common/mem_access.c      |  28 +++++++++-
 xen/common/mem_event.c       |   2 +-
 xen/include/asm-arm/p2m.h    |   7 +++
 xen/include/asm-x86/p2m.h    |   7 ++-
 xen/include/xen/mem_access.h |   5 ++
 6 files changed, 99 insertions(+), 78 deletions(-)

diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 31d0d9e..92b20bc 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1382,6 +1382,60 @@ static void p2m_mem_event_fill_regs(mem_event_request_t *req)
     req->x86_regs.cs_arbytes = seg.attr.bytes;
 }
 
+void p2m_mem_event_emulate_check(struct domain *d, const mem_event_response_t *rsp)
+{
+    /* Mark vcpu for skipping one instruction upon rescheduling. */
+    if ( rsp->flags & MEM_EVENT_FLAG_EMULATE )
+    {
+        struct vcpu *v = current;
+        xenmem_access_t access;
+        bool_t violation = 1;
+
+        if ( p2m_get_mem_access(d, rsp->gfn, &access) == 0 )
+        {
+            switch ( access )
+            {
+            case XENMEM_access_n:
+            case XENMEM_access_n2rwx:
+            default:
+                violation = rsp->access_r || rsp->access_w || rsp->access_x;
+                break;
+
+            case XENMEM_access_r:
+                violation = rsp->access_w || rsp->access_x;
+                break;
+
+            case XENMEM_access_w:
+                violation = rsp->access_r || rsp->access_x;
+                break;
+
+            case XENMEM_access_x:
+                violation = rsp->access_r || rsp->access_w;
+                break;
+
+            case XENMEM_access_rx:
+            case XENMEM_access_rx2rw:
+                violation = rsp->access_w;
+                break;
+
+            case XENMEM_access_wx:
+                violation = rsp->access_r;
+                break;
+
+            case XENMEM_access_rw:
+                violation = rsp->access_x;
+                break;
+
+            case XENMEM_access_rwx:
+                violation = 0;
+                break;
+            }
+        }
+
+        v->arch.mem_event.emulate_flags = violation ? rsp->flags : 0;
+    }
+}
+
 bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
                             struct npfec npfec,
                             mem_event_request_t **req_ptr)
@@ -1509,80 +1563,6 @@ bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
     return (p2ma == p2m_access_n2rwx);
 }
 
-void p2m_mem_access_resume(struct domain *d)
-{
-    mem_event_response_t rsp;
-
-    /* Pull all responses off the ring */
-    while( mem_event_get_response(d, &d->mem_event->access, &rsp) )
-    {
-        struct vcpu *v;
-
-        if ( rsp.flags & MEM_EVENT_FLAG_DUMMY )
-            continue;
-
-        /* Validate the vcpu_id in the response. */
-        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
-            continue;
-
-        v = d->vcpu[rsp.vcpu_id];
-
-        /* Mark vcpu for skipping one instruction upon rescheduling. */
-        if ( rsp.flags & MEM_EVENT_FLAG_EMULATE )
-        {
-            xenmem_access_t access;
-            bool_t violation = 1;
-
-            if ( p2m_get_mem_access(d, rsp.gfn, &access) == 0 )
-            {
-                switch ( access )
-                {
-                case XENMEM_access_n:
-                case XENMEM_access_n2rwx:
-                default:
-                    violation = rsp.access_r || rsp.access_w || rsp.access_x;
-                    break;
-
-                case XENMEM_access_r:
-                    violation = rsp.access_w || rsp.access_x;
-                    break;
-
-                case XENMEM_access_w:
-                    violation = rsp.access_r || rsp.access_x;
-                    break;
-
-                case XENMEM_access_x:
-                    violation = rsp.access_r || rsp.access_w;
-                    break;
-
-                case XENMEM_access_rx:
-                case XENMEM_access_rx2rw:
-                    violation = rsp.access_w;
-                    break;
-
-                case XENMEM_access_wx:
-                    violation = rsp.access_r;
-                    break;
-
-                case XENMEM_access_rw:
-                    violation = rsp.access_x;
-                    break;
-
-                case XENMEM_access_rwx:
-                    violation = 0;
-                    break;
-                }
-            }
-
-            v->arch.mem_event.emulate_flags = violation ? rsp.flags : 0;
-        }
-
-        /* Unpause domain */
-        if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED )
-            mem_event_vcpu_unpause(v);
-    }
-}
-
 /* Set access type for a region of pfns.
  * If start_pfn == -1ul, sets the default access type */
 long p2m_set_mem_access(struct domain *d, unsigned long pfn, uint32_t nr,
diff --git a/xen/common/mem_access.c b/xen/common/mem_access.c
index 9a8c1a9..42423c1 100644
--- a/xen/common/mem_access.c
+++ b/xen/common/mem_access.c
@@ -29,6 +29,32 @@
 #include <asm/p2m.h>
 #include <xsm/xsm.h>
 
+void mem_access_resume(struct domain *d)
+{
+    mem_event_response_t rsp;
+
+    /* Pull all responses off the ring. */
+    while ( mem_event_get_response(d, &d->mem_event->access, &rsp) )
+    {
+        struct vcpu *v;
+
+        if ( rsp.flags & MEM_EVENT_FLAG_DUMMY )
+            continue;
+
+        /* Validate the vcpu_id in the response. */
+        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
+            continue;
+
+        v = d->vcpu[rsp.vcpu_id];
+
+        p2m_mem_event_emulate_check(d, &rsp);
+
+        /* Unpause domain. */
+        if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED )
+            mem_event_vcpu_unpause(v);
+    }
+}
+
 int mem_access_memop(unsigned long cmd,
                      XEN_GUEST_HANDLE_PARAM(xen_mem_access_op_t) arg)
 {
@@ -58,7 +84,7 @@ int mem_access_memop(unsigned long cmd,
     switch ( mao.op )
     {
     case XENMEM_access_op_resume:
-        p2m_mem_access_resume(d);
+        mem_access_resume(d);
         rc = 0;
         break;
 
diff --git a/xen/common/mem_event.c b/xen/common/mem_event.c
index 7cc99b3..9f1a1b0 100644
--- a/xen/common/mem_event.c
+++ b/xen/common/mem_event.c
@@ -439,7 +439,7 @@ static void mem_paging_notification(struct vcpu *v, unsigned int port)
 static void mem_access_notification(struct vcpu *v, unsigned int port)
 {
     if ( likely(v->domain->mem_event->access.ring_page != NULL) )
-        p2m_mem_access_resume(v->domain);
+        mem_access_resume(v->domain);
 }
 
 #ifdef HAS_MEM_SHARING
diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
index faf14d3..b64dd9a 100644
--- a/xen/include/asm-arm/p2m.h
+++ b/xen/include/asm-arm/p2m.h
@@ -66,6 +66,13 @@ typedef enum {
     p2m_max_real_type,  /* Types after this won't be store in the p2m */
 } p2m_type_t;
 
+static inline
+void p2m_mem_event_emulate_check(struct domain *d,
+                                 const mem_event_response_t *rsp)
+{
+    /* Not supported on ARM. */
+};
+
 #define p2m_is_foreign(_t)  ((_t) == p2m_map_foreign)
 #define p2m_is_ram(_t)      ((_t) == p2m_ram_rw || (_t) == p2m_ram_ro)
 
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index a2a6289..2513c6f 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -573,8 +573,6 @@ void p2m_mem_paging_resume(struct domain *d);
 bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
                             struct npfec npfec,
                             mem_event_request_t **req_ptr);
-/* Resumes the running of the VCPU, restarting the last instruction */
-void p2m_mem_access_resume(struct domain *d);
 
 /* Set access type for a region of pfns.
  * If start_pfn == -1ul, sets the default access type */
@@ -586,6 +584,11 @@ long p2m_set_mem_access(struct domain *d, unsigned long start_pfn, uint32_t nr,
 int p2m_get_mem_access(struct domain *d, unsigned long pfn,
                        xenmem_access_t *access);
 
+/* Check for emulation and mark vcpu for skipping one instruction
+ * upon rescheduling if required. */
+void p2m_mem_event_emulate_check(struct domain *d,
+                                 const mem_event_response_t *rsp);
+
 /* 
  * Internal functions, only called by other p2m code
  */
diff --git a/xen/include/xen/mem_access.h b/xen/include/xen/mem_access.h
index 19d1a2d..6ceb2a4 100644
--- a/xen/include/xen/mem_access.h
+++ b/xen/include/xen/mem_access.h
@@ -31,6 +31,9 @@ int mem_access_memop(unsigned long cmd,
                      XEN_GUEST_HANDLE_PARAM(xen_mem_access_op_t) arg);
 int mem_access_send_req(struct domain *d, mem_event_request_t *req);
 
+/* Resumes the running of the VCPU, restarting the last instruction */
+void mem_access_resume(struct domain *d);
+
 #else
 
 static inline
@@ -46,6 +49,8 @@ int mem_access_send_req(struct domain *d, mem_event_request_t *req)
     return -ENOSYS;
 }
 
+static inline void mem_access_resume(struct domain *d) {}
+
 #endif /* HAS_MEM_ACCESS */
 
 #endif /* _XEN_ASM_MEM_ACCESS_H */
-- 
2.1.0

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

* [PATCH for-4.5 v8 05/19] xen: Relocate set_access_required domctl into common
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (3 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-24 14:18   ` Julien Grall
  2014-09-23 13:14 ` [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop " Tamas K Lengyel
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Tim Deegan <tim@xen.org>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
v8: Remove superfluous paranthesis in macro get_hostp2m.
---
 xen/arch/x86/domctl.c     | 14 --------------
 xen/common/domctl.c       | 15 +++++++++++++++
 xen/include/asm-arm/p2m.h |  7 +++++++
 3 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 26a3ea1..8731e7f 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1163,20 +1163,6 @@ long arch_do_domctl(
     break;
 #endif /* P2M_AUDIT */
 
-    case XEN_DOMCTL_set_access_required:
-    {
-        struct p2m_domain* p2m;
-        
-        ret = -EPERM;
-        if ( current->domain == d )
-            break;
-
-        ret = 0;
-        p2m = p2m_get_hostp2m(d);
-        p2m->access_required = domctl->u.access_required.access_required;
-    }
-    break;
-
     case XEN_DOMCTL_set_broken_page_p2m:
     {
         p2m_type_t pt;
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 1ad0729..329e535 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -27,6 +27,7 @@
 #include <asm/current.h>
 #include <asm/irq.h>
 #include <asm/page.h>
+#include <asm/p2m.h>
 #include <public/domctl.h>
 #include <xsm/xsm.h>
 
@@ -1116,6 +1117,20 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
     }
     break;
 
+    case XEN_DOMCTL_set_access_required:
+    {
+        struct p2m_domain* p2m;
+
+        ret = -EPERM;
+        if ( current->domain == d )
+            break;
+
+        ret = 0;
+        p2m = p2m_get_hostp2m(d);
+        p2m->access_required = op->u.access_required.access_required;
+    }
+    break;
+
     case XEN_DOMCTL_set_virq_handler:
     {
         uint32_t virq = op->u.set_virq_handler.virq;
diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
index b64dd9a..12fe808 100644
--- a/xen/include/asm-arm/p2m.h
+++ b/xen/include/asm-arm/p2m.h
@@ -44,6 +44,10 @@ struct p2m_domain {
          * at each p2m tree level. */
         unsigned long shattered[4];
     } stats;
+
+    /* If true, and an access fault comes in and there is no mem_event listener,
+     * pause domain. Otherwise, remove access restrictions. */
+    bool_t access_required;
 };
 
 /* List of possible type for each page in the p2m entry.
@@ -208,6 +212,9 @@ int arch_grant_map_page_identity(struct domain *d, unsigned long frame,
                                  bool_t writeable);
 int arch_grant_unmap_page_identity(struct domain *d, unsigned long frame);
 
+/* get host p2m table */
+#define p2m_get_hostp2m(d) (&(d)->arch.p2m)
+
 #endif /* _XEN_P2M_H */
 
 /*
-- 
2.1.0

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

* [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop into common.
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (4 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 05/19] xen: Relocate set_access_required domctl into common Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:32   ` Jan Beulich
  2014-09-23 13:14 ` [PATCH for-4.5 v8 07/19] x86/p2m: Typo fix for spelling ambiguous Tamas K Lengyel
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Tim Deegan <tim@xen.org>
---
v8: Move the new enable_msr_exit_interception test into the p2m layer.
v6: Grouping style fix of #includes in common/memory.c.
v5: Move memop compat into common as well.
    Position domctl in switch relative to the domctl #.
v4: Don't remove memop handling from x86_64/compat and style fixes.
---
 xen/arch/x86/domctl.c           | 8 --------
 xen/arch/x86/mm/p2m.c           | 9 +++++++++
 xen/arch/x86/x86_64/compat/mm.c | 4 ----
 xen/arch/x86/x86_64/mm.c        | 4 ----
 xen/common/compat/memory.c      | 5 +++++
 xen/common/domctl.c             | 7 +++++++
 xen/common/mem_event.c          | 9 +++------
 xen/common/memory.c             | 9 +++++++--
 xen/include/asm-arm/p2m.h       | 5 +++++
 xen/include/asm-x86/p2m.h       | 3 +++
 10 files changed, 39 insertions(+), 24 deletions(-)

diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 8731e7f..ec77555 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1131,14 +1131,6 @@ long arch_do_domctl(
     }
     break;
 
-    case XEN_DOMCTL_mem_event_op:
-    {
-        ret = mem_event_domctl(d, &domctl->u.mem_event_op,
-                              guest_handle_cast(u_domctl, void));
-        copyback = 1;
-    }
-    break;
-
     case XEN_DOMCTL_mem_sharing_op:
     {
         ret = mem_sharing_domctl(d, &domctl->u.mem_sharing_op);
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 92b20bc..b46284d 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1436,6 +1436,15 @@ void p2m_mem_event_emulate_check(struct domain *d, const mem_event_response_t *r
     }
 }
 
+void p2m_enable_msr_exit_interception(struct domain *d)
+{
+    if ( hvm_funcs.enable_msr_exit_interception )
+    {
+        d->arch.hvm_domain.introspection_enabled = 1;
+        hvm_funcs.enable_msr_exit_interception(d);
+    }
+}
+
 bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
                             struct npfec npfec,
                             mem_event_request_t **req_ptr)
diff --git a/xen/arch/x86/x86_64/compat/mm.c b/xen/arch/x86/x86_64/compat/mm.c
index c079702..54f25b7 100644
--- a/xen/arch/x86/x86_64/compat/mm.c
+++ b/xen/arch/x86/x86_64/compat/mm.c
@@ -198,10 +198,6 @@ int compat_arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
         break;
     }
 
-    case XENMEM_access_op:
-        rc = mem_access_memop(cmd, guest_handle_cast(arg, xen_mem_access_op_t));
-        break;
-
     case XENMEM_sharing_op:
     {
         xen_mem_sharing_op_t mso;
diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c
index cce1406..8e5a1a1 100644
--- a/xen/arch/x86/x86_64/mm.c
+++ b/xen/arch/x86/x86_64/mm.c
@@ -995,10 +995,6 @@ long subarch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
         break;
     }
 
-    case XENMEM_access_op:
-        rc = mem_access_memop(cmd, guest_handle_cast(arg, xen_mem_access_op_t));
-        break;
-
     case XENMEM_sharing_op:
     {
         xen_mem_sharing_op_t mso;
diff --git a/xen/common/compat/memory.c b/xen/common/compat/memory.c
index 25dc016..43d02bc 100644
--- a/xen/common/compat/memory.c
+++ b/xen/common/compat/memory.c
@@ -4,6 +4,7 @@
 #include <xen/guest_access.h>
 #include <xen/sched.h>
 #include <xen/event.h>
+#include <xen/mem_access.h>
 #include <asm/current.h>
 #include <compat/memory.h>
 
@@ -381,6 +382,10 @@ int compat_memory_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) compat)
             break;
         }
 
+        case XENMEM_access_op:
+            rc = mem_access_memop(cmd, guest_handle_cast(compat, xen_mem_access_op_t));
+            break;
+
         case XENMEM_add_to_physmap_batch:
             start_extent = end_extent;
             break;
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 329e535..fd8dd44 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -24,6 +24,7 @@
 #include <xen/bitmap.h>
 #include <xen/paging.h>
 #include <xen/hypercall.h>
+#include <xen/mem_event.h>
 #include <asm/current.h>
 #include <asm/irq.h>
 #include <asm/page.h>
@@ -1111,6 +1112,12 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
     }
     break;
 
+    case XEN_DOMCTL_mem_event_op:
+        ret = mem_event_domctl(d, &op->u.mem_event_op,
+                               guest_handle_cast(u_domctl, void));
+        copyback = 1;
+        break;
+
     case XEN_DOMCTL_disable_migrate:
     {
         d->disable_migrate = op->u.disable_migrate.disable;
diff --git a/xen/common/mem_event.c b/xen/common/mem_event.c
index 9f1a1b0..aa39f7b 100644
--- a/xen/common/mem_event.c
+++ b/xen/common/mem_event.c
@@ -623,12 +623,9 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
                                     HVM_PARAM_ACCESS_RING_PFN,
                                     mem_access_notification);
 
-            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
-                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
-            {
-                d->arch.hvm_domain.introspection_enabled = 1;
-                hvm_funcs.enable_msr_exit_interception(d);
-            }
+            if ( !rc && mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE )
+                p2m_enable_msr_exit_interception(d);
+
         }
         break;
 
diff --git a/xen/common/memory.c b/xen/common/memory.c
index bad50cb..cc36e39 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -21,13 +21,14 @@
 #include <xen/errno.h>
 #include <xen/tmem.h>
 #include <xen/tmem_xen.h>
+#include <xen/numa.h>
+#include <xen/mem_access.h>
+#include <xen/trace.h>
 #include <asm/current.h>
 #include <asm/hardirq.h>
 #include <asm/p2m.h>
-#include <xen/numa.h>
 #include <public/memory.h>
 #include <xsm/xsm.h>
-#include <xen/trace.h>
 
 struct memop_args {
     /* INPUT */
@@ -939,6 +940,10 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
         break;
     }
 
+    case XENMEM_access_op:
+        rc = mem_access_memop(cmd, guest_handle_cast(arg, xen_mem_access_op_t));
+        break;
+
     case XENMEM_claim_pages:
         if ( copy_from_guest(&reservation, arg, 1) )
             return -EFAULT;
diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
index 12fe808..27225c4 100644
--- a/xen/include/asm-arm/p2m.h
+++ b/xen/include/asm-arm/p2m.h
@@ -77,6 +77,11 @@ void p2m_mem_event_emulate_check(struct domain *d,
     /* Not supported on ARM. */
 };
 
+void p2m_enable_msr_exit_interception(struct domain *d)
+{
+    /* Not supported on ARM. */
+}
+
 #define p2m_is_foreign(_t)  ((_t) == p2m_map_foreign)
 #define p2m_is_ram(_t)      ((_t) == p2m_ram_rw || (_t) == p2m_ram_ro)
 
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index 2513c6f..68e871b 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -589,6 +589,9 @@ int p2m_get_mem_access(struct domain *d, unsigned long pfn,
 void p2m_mem_event_emulate_check(struct domain *d,
                                  const mem_event_response_t *rsp);
 
+/* Enable MSR exit interception. */
+void p2m_enable_msr_exit_interception(struct domain *d);
+
 /* 
  * Internal functions, only called by other p2m code
  */
-- 
2.1.0

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

* [PATCH for-4.5 v8 07/19] x86/p2m: Typo fix for spelling ambiguous
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (5 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop " Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 08/19] xen/mem_event: Clean out superfluous white-spaces Tamas K Lengyel
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Tim Deegan <tim@xen.org>
---
 xen/include/asm-x86/p2m.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index 68e871b..e201f1e 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -234,7 +234,7 @@ struct p2m_domain {
     long               (*audit_p2m)(struct p2m_domain *p2m);
 
     /* Default P2M access type for each page in the the domain: new pages,
-     * swapped in pages, cleared pages, and pages that are ambiquously
+     * swapped in pages, cleared pages, and pages that are ambiguously
      * retyped get this access type.  See definition of p2m_access_t. */
     p2m_access_t default_access;
 
-- 
2.1.0

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

* [PATCH for-4.5 v8 08/19] xen/mem_event: Clean out superfluous white-spaces
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (6 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 07/19] x86/p2m: Typo fix for spelling ambiguous Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 09/19] xen/mem_event: Relax error condition on debug builds Tamas K Lengyel
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Tim Deegan <tim@xen.org>
---
v2: Clean the mem_event header as well.
---
 xen/common/mem_event.c      | 20 ++++++++++----------
 xen/include/xen/mem_event.h |  8 ++++----
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/xen/common/mem_event.c b/xen/common/mem_event.c
index aa39f7b..638b4e3 100644
--- a/xen/common/mem_event.c
+++ b/xen/common/mem_event.c
@@ -64,7 +64,7 @@ static int mem_event_enable(
     if ( med->ring_page )
         return -EBUSY;
 
-    /* The parameter defaults to zero, and it should be 
+    /* The parameter defaults to zero, and it should be
      * set to something */
     if ( ring_gfn == 0 )
         return -ENOSYS;
@@ -72,7 +72,7 @@ static int mem_event_enable(
     mem_event_ring_lock_init(med);
     mem_event_ring_lock(med);
 
-    rc = prepare_ring_for_helper(d, ring_gfn, &med->ring_pg_struct, 
+    rc = prepare_ring_for_helper(d, ring_gfn, &med->ring_pg_struct,
                                     &med->ring_page);
     if ( rc < 0 )
         goto err;
@@ -104,7 +104,7 @@ static int mem_event_enable(
     return 0;
 
  err:
-    destroy_ring_for_helper(&med->ring_page, 
+    destroy_ring_for_helper(&med->ring_page,
                             med->ring_pg_struct);
     mem_event_ring_unlock(med);
 
@@ -233,7 +233,7 @@ static int mem_event_disable(struct domain *d, struct mem_event_domain *med)
             }
         }
 
-        destroy_ring_for_helper(&med->ring_page, 
+        destroy_ring_for_helper(&med->ring_page,
                                 med->ring_pg_struct);
         mem_event_ring_unlock(med);
     }
@@ -495,7 +495,7 @@ void mem_event_cleanup(struct domain *d)
          * 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 
+         * pausing the domain (domain_kill), unpausing the
          * vcpus causes no harm. */
         destroy_waitqueue_head(&d->mem_event->paging.wq);
         (void)mem_event_disable(d, &d->mem_event->paging);
@@ -579,7 +579,7 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
             if ( p2m->pod.entry_count )
                 break;
 
-            rc = mem_event_enable(d, mec, med, _VPF_mem_paging, 
+            rc = mem_event_enable(d, mec, med, _VPF_mem_paging,
                                     HVM_PARAM_PAGING_RING_PFN,
                                     mem_paging_notification);
         }
@@ -600,7 +600,7 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
     break;
 #endif
 
-    case XEN_DOMCTL_MEM_EVENT_OP_ACCESS: 
+    case XEN_DOMCTL_MEM_EVENT_OP_ACCESS:
     {
         struct mem_event_domain *med = &d->mem_event->access;
         rc = -EINVAL;
@@ -619,7 +619,7 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
             if ( !cpu_has_vmx )
                 break;
 
-            rc = mem_event_enable(d, mec, med, _VPF_mem_access, 
+            rc = mem_event_enable(d, mec, med, _VPF_mem_access,
                                     HVM_PARAM_ACCESS_RING_PFN,
                                     mem_access_notification);
 
@@ -647,7 +647,7 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
     break;
 
 #ifdef HAS_MEM_SHARING
-    case XEN_DOMCTL_MEM_EVENT_OP_SHARING: 
+    case XEN_DOMCTL_MEM_EVENT_OP_SHARING:
     {
         struct mem_event_domain *med = &d->mem_event->share;
         rc = -EINVAL;
@@ -666,7 +666,7 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
             if ( !hap_enabled(d) )
                 break;
 
-            rc = mem_event_enable(d, mec, med, _VPF_mem_sharing, 
+            rc = mem_event_enable(d, mec, med, _VPF_mem_sharing,
                                     HVM_PARAM_SHARING_RING_PFN,
                                     mem_sharing_notification);
         }
diff --git a/xen/include/xen/mem_event.h b/xen/include/xen/mem_event.h
index 8612b26..4f3ad8e 100644
--- a/xen/include/xen/mem_event.h
+++ b/xen/include/xen/mem_event.h
@@ -37,19 +37,19 @@ bool_t mem_event_check_ring(struct mem_event_domain *med);
 /* 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
  * is the caller, -EBUSY is avoided by sleeping on a wait queue to ensure
- * that the ring does not lose future events. 
+ * that the ring does not lose future events.
  *
  * However, the allow_sleep flag can be set to false in cases in which it is ok
  * to lose future events, and thus -EBUSY can be returned to guest vcpus
- * (handle with care!). 
+ * (handle with care!).
  *
  * In general, you must follow a claim_slot() call with either put_request() or
  * cancel_slot(), both of which are guaranteed to
- * succeed. 
+ * succeed.
  */
 int __mem_event_claim_slot(struct domain *d, struct mem_event_domain *med,
                             bool_t allow_sleep);
-static inline int mem_event_claim_slot(struct domain *d, 
+static inline int mem_event_claim_slot(struct domain *d,
                                         struct mem_event_domain *med)
 {
     return __mem_event_claim_slot(d, med, 1);
-- 
2.1.0

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

* [PATCH for-4.5 v8 09/19] xen/mem_event: Relax error condition on debug builds
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (7 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 08/19] xen/mem_event: Clean out superfluous white-spaces Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 10/19] xen/mem_event: Abstract architecture specific sanity checks Tamas K Lengyel
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

A faulty tool stack can brick a debug hypervisor. Unpleasant while dev/test.

Suggested-by: Andres Lagar Cavilla <andres@lagarcavilla.org>
Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Tim Deegan <tim@xen.org>
---
v5: Make printout greppable.
v4: Add domain_id to the printout.
v3: Switch to gdprintk and print the vCPU id as well.
---
 xen/common/mem_event.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/xen/common/mem_event.c b/xen/common/mem_event.c
index 638b4e3..c04a685 100644
--- a/xen/common/mem_event.c
+++ b/xen/common/mem_event.c
@@ -285,7 +285,11 @@ void mem_event_put_request(struct domain *d,
     if ( current->domain != d )
     {
         req->flags |= MEM_EVENT_FLAG_FOREIGN;
-        ASSERT( !(req->flags & MEM_EVENT_FLAG_VCPU_PAUSED) );
+#ifndef NDEBUG
+        if ( !(req->flags & MEM_EVENT_FLAG_VCPU_PAUSED) )
+            gdprintk(XENLOG_G_WARNING, "d%dv%d was not paused.\n",
+                     d->domain_id, req->vcpu_id);
+#endif
     }
 
     mem_event_ring_lock(med);
-- 
2.1.0

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

* [PATCH for-4.5 v8 10/19] xen/mem_event: Abstract architecture specific sanity checks
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (8 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 09/19] xen/mem_event: Relax error condition on debug builds Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 11/19] xen/mem_access: Abstract architecture specific sanity check Tamas K Lengyel
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Move architecture specific sanity checks into its own function
which is called when enabling mem_event.

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Tim Deegan <tim@xen.org>
---
v5: Style fix.
v4: Style fix.
v2: Move sanity check function into architecture specific p2m.h
---
 xen/common/mem_event.c    | 7 +------
 xen/include/asm-x86/p2m.h | 6 ++++++
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/xen/common/mem_event.c b/xen/common/mem_event.c
index c04a685..82ebfd1 100644
--- a/xen/common/mem_event.c
+++ b/xen/common/mem_event.c
@@ -615,12 +615,7 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
         case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION:
         {
             rc = -ENODEV;
-            /* Only HAP is supported */
-            if ( !hap_enabled(d) )
-                break;
-
-            /* Currently only EPT is supported */
-            if ( !cpu_has_vmx )
+            if ( !p2m_mem_event_sanity_check(d) )
                 break;
 
             rc = mem_event_enable(d, mec, med, _VPF_mem_access,
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index e201f1e..484538b 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -592,6 +592,12 @@ void p2m_mem_event_emulate_check(struct domain *d,
 /* Enable MSR exit interception. */
 void p2m_enable_msr_exit_interception(struct domain *d);
 
+/* Sanity check for mem_event hardware support */
+static inline bool_t p2m_mem_event_sanity_check(struct domain *d)
+{
+    return hap_enabled(d) && cpu_has_vmx;
+}
+
 /* 
  * Internal functions, only called by other p2m code
  */
-- 
2.1.0

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

* [PATCH for-4.5 v8 11/19] xen/mem_access: Abstract architecture specific sanity check
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (9 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 10/19] xen/mem_event: Abstract architecture specific sanity checks Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support Tamas K Lengyel
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Tim Deegan <tim@xen.org>
---
v5: Style fix.
v4: Style fix.
v2: Move sanity check function into architecture specific p2m.h
---
 xen/common/mem_access.c   | 2 +-
 xen/include/asm-x86/p2m.h | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/xen/common/mem_access.c b/xen/common/mem_access.c
index 42423c1..b9081e6 100644
--- a/xen/common/mem_access.c
+++ b/xen/common/mem_access.c
@@ -70,7 +70,7 @@ int mem_access_memop(unsigned long cmd,
         return rc;
 
     rc = -EINVAL;
-    if ( !is_hvm_domain(d) )
+    if ( !p2m_mem_access_sanity_check(d) )
         goto out;
 
     rc = xsm_mem_event_op(XSM_DM_PRIV, d, XENMEM_access_op);
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index 484538b..13df43d 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -598,6 +598,12 @@ static inline bool_t p2m_mem_event_sanity_check(struct domain *d)
     return hap_enabled(d) && cpu_has_vmx;
 }
 
+/* Sanity check for mem_access hardware support */
+static inline bool_t p2m_mem_access_sanity_check(struct domain *d)
+{
+    return is_hvm_domain(d);
+}
+
 /* 
  * Internal functions, only called by other p2m code
  */
-- 
2.1.0

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

* [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (10 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 11/19] xen/mem_access: Abstract architecture specific sanity check Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-24 14:40   ` Ian Campbell
  2014-09-24 14:43   ` Julien Grall
  2014-09-23 13:14 ` [PATCH for-4.5 v8 13/19] xen/arm: Implement domain_get_maximum_gpfn Tamas K Lengyel
                   ` (6 subsequent siblings)
  18 siblings, 2 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Add p2m_access_t to struct page_info and add necessary changes for
page table construction routines to pass the default access information.
We store the p2m_access_t info in page_info as the PTE lacks enough
software programmable bits.

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
---
v8: - Drop lock inputs as common mem_access_check is postponed.
    - Resurrect the radix tree with an extra boolean access_in_use flag
      to indicate if the tree is empty to avoid lookups.
v7: - Remove radix tree init/destroy and move p2m_access_t store to page_info.
    - Add p2m_gpfn_lock/unlock functions.
    - Add bool_t lock input to p2m_lookup and apply_p2m_changes so the caller
      can specify if locking should be performed. This is needed in order to
      support mem_access_check from common.
v6: - Move mem_event header include to first patch that needs it.
v5: - #include grouping style-fix.
v4: - Move p2m_get_hostp2m definition here.
---
 xen/arch/arm/p2m.c           | 49 +++++++++++++++++++---------
 xen/include/asm-arm/domain.h |  1 +
 xen/include/asm-arm/p2m.h    | 77 ++++++++++++++++++++++++++++++--------------
 3 files changed, 86 insertions(+), 41 deletions(-)

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 4dccf7b..760d064 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -228,7 +228,7 @@ int p2m_pod_decrease_reservation(struct domain *d,
 }
 
 static lpae_t mfn_to_p2m_entry(unsigned long mfn, unsigned int mattr,
-                               p2m_type_t t)
+                               p2m_type_t t, p2m_access_t a)
 {
     paddr_t pa = ((paddr_t) mfn) << PAGE_SHIFT;
     /* sh, xn and write bit will be defined in the following switches
@@ -346,7 +346,7 @@ static int p2m_create_table(struct domain *d, lpae_t *entry,
          for ( i=0 ; i < LPAE_ENTRIES; i++ )
          {
              pte = mfn_to_p2m_entry(base_pfn + (i<<(level_shift-LPAE_SHIFT)),
-                                    MATTR_MEM, t);
+                                    MATTR_MEM, t, p2m->default_access);
 
              /*
               * First and second level super pages set p2m.table = 0, but
@@ -366,7 +366,8 @@ static int p2m_create_table(struct domain *d, lpae_t *entry,
 
     unmap_domain_page(p);
 
-    pte = mfn_to_p2m_entry(page_to_mfn(page), MATTR_MEM, p2m_invalid);
+    pte = mfn_to_p2m_entry(page_to_mfn(page), MATTR_MEM, p2m_invalid,
+                           p2m->default_access);
 
     p2m_write_pte(entry, pte, flush_cache);
 
@@ -469,7 +470,8 @@ static int apply_one_level(struct domain *d,
                            paddr_t *maddr,
                            bool_t *flush,
                            int mattr,
-                           p2m_type_t t)
+                           p2m_type_t t,
+                           p2m_access_t a)
 {
     const paddr_t level_size = level_sizes[level];
     const paddr_t level_mask = level_masks[level];
@@ -498,7 +500,7 @@ static int apply_one_level(struct domain *d,
             page = alloc_domheap_pages(d, level_shift - PAGE_SHIFT, 0);
             if ( page )
             {
-                pte = mfn_to_p2m_entry(page_to_mfn(page), mattr, t);
+                pte = mfn_to_p2m_entry(page_to_mfn(page), mattr, t, a);
                 if ( level < 3 )
                     pte.p2m.table = 0;
                 p2m_write_pte(entry, pte, flush_cache);
@@ -533,7 +535,7 @@ static int apply_one_level(struct domain *d,
              (level == 3 || !p2m_table(orig_pte)) )
         {
             /* New mapping is superpage aligned, make it */
-            pte = mfn_to_p2m_entry(*maddr >> PAGE_SHIFT, mattr, t);
+            pte = mfn_to_p2m_entry(*maddr >> PAGE_SHIFT, mattr, t, a);
             if ( level < 3 )
                 pte.p2m.table = 0; /* Superpage entry */
 
@@ -712,7 +714,9 @@ static int apply_p2m_changes(struct domain *d,
                      paddr_t end_gpaddr,
                      paddr_t maddr,
                      int mattr,
-                     p2m_type_t t)
+                     uint32_t mask,
+                     p2m_type_t t,
+                     p2m_access_t a)
 {
     int rc, ret;
     struct p2m_domain *p2m = &d->arch.p2m;
@@ -805,7 +809,7 @@ static int apply_p2m_changes(struct domain *d,
                                   level, flush_pt, op,
                                   start_gpaddr, end_gpaddr,
                                   &addr, &maddr, &flush,
-                                  mattr, t);
+                                  mattr, t, a);
             if ( ret < 0 ) { rc = ret ; goto out; }
             count += ret;
             /* L3 had better have done something! We cannot descend any further */
@@ -863,7 +867,7 @@ out:
          */
         apply_p2m_changes(d, REMOVE,
                           start_gpaddr, addr + level_sizes[level], orig_maddr,
-                          mattr, p2m_invalid);
+                          mattr, 0, p2m_invalid, d->arch.p2m.default_access);
     }
 
     for ( level = P2M_ROOT_LEVEL; level < 4; level ++ )
@@ -882,7 +886,8 @@ int p2m_populate_ram(struct domain *d,
                      paddr_t end)
 {
     return apply_p2m_changes(d, ALLOCATE, start, end,
-                             0, MATTR_MEM, p2m_ram_rw);
+                             0, MATTR_MEM, 0, p2m_ram_rw,
+                             d->arch.p2m.default_access);
 }
 
 int map_mmio_regions(struct domain *d,
@@ -894,7 +899,8 @@ int map_mmio_regions(struct domain *d,
                              pfn_to_paddr(start_gfn),
                              pfn_to_paddr(start_gfn + nr),
                              pfn_to_paddr(mfn),
-                             MATTR_DEV, p2m_mmio_direct);
+                             MATTR_DEV, 0, p2m_mmio_direct,
+                             d->arch.p2m.default_access);
 }
 
 int unmap_mmio_regions(struct domain *d,
@@ -906,7 +912,8 @@ int unmap_mmio_regions(struct domain *d,
                              pfn_to_paddr(start_gfn),
                              pfn_to_paddr(start_gfn + nr),
                              pfn_to_paddr(mfn),
-                             MATTR_DEV, p2m_invalid);
+                             MATTR_DEV, 0, p2m_invalid,
+                             d->arch.p2m.default_access);
 }
 
 int guest_physmap_add_entry(struct domain *d,
@@ -918,7 +925,8 @@ int guest_physmap_add_entry(struct domain *d,
     return apply_p2m_changes(d, INSERT,
                              pfn_to_paddr(gpfn),
                              pfn_to_paddr(gpfn + (1 << page_order)),
-                             pfn_to_paddr(mfn), MATTR_MEM, t);
+                             pfn_to_paddr(mfn), MATTR_MEM, 0, t,
+                             d->arch.p2m.default_access);
 }
 
 void guest_physmap_remove_page(struct domain *d,
@@ -928,7 +936,8 @@ void guest_physmap_remove_page(struct domain *d,
     apply_p2m_changes(d, REMOVE,
                       pfn_to_paddr(gpfn),
                       pfn_to_paddr(gpfn + (1<<page_order)),
-                      pfn_to_paddr(mfn), MATTR_MEM, p2m_invalid);
+                      pfn_to_paddr(mfn), MATTR_MEM, 0, p2m_invalid,
+                      d->arch.p2m.default_access);
 }
 
 int arch_grant_map_page_identity(struct domain *d, unsigned long frame,
@@ -1058,6 +1067,8 @@ void p2m_teardown(struct domain *d)
 
     p2m_free_vmid(d);
 
+    radix_tree_destroy(&p2m->mem_access_settings, NULL);
+
     spin_unlock(&p2m->lock);
 }
 
@@ -1083,6 +1094,10 @@ int p2m_init(struct domain *d)
     p2m->max_mapped_gfn = 0;
     p2m->lowest_mapped_gfn = ULONG_MAX;
 
+    p2m->default_access = p2m_access_rwx;
+    p2m->access_in_use = false;
+    radix_tree_init(&p2m->mem_access_settings);
+
 err:
     spin_unlock(&p2m->lock);
 
@@ -1097,7 +1112,8 @@ int relinquish_p2m_mapping(struct domain *d)
                               pfn_to_paddr(p2m->lowest_mapped_gfn),
                               pfn_to_paddr(p2m->max_mapped_gfn),
                               pfn_to_paddr(INVALID_MFN),
-                              MATTR_MEM, p2m_invalid);
+                              MATTR_MEM, 0, p2m_invalid,
+                              d->arch.p2m.default_access);
 }
 
 int p2m_cache_flush(struct domain *d, xen_pfn_t start_mfn, xen_pfn_t end_mfn)
@@ -1111,7 +1127,8 @@ int p2m_cache_flush(struct domain *d, xen_pfn_t start_mfn, xen_pfn_t end_mfn)
                              pfn_to_paddr(start_mfn),
                              pfn_to_paddr(end_mfn),
                              pfn_to_paddr(INVALID_MFN),
-                             MATTR_MEM, p2m_invalid);
+                             MATTR_MEM, 0, p2m_invalid,
+                             d->arch.p2m.default_access);
 }
 
 unsigned long gmfn_to_mfn(struct domain *d, unsigned long gpfn)
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 787e93c..3d69152 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -17,6 +17,7 @@ struct hvm_domain
 {
     uint64_t              params[HVM_NR_PARAMS];
     struct hvm_iommu      iommu;
+    bool_t                introspection_enabled;
 }  __cacheline_aligned;
 
 #ifdef CONFIG_ARM_64
diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
index 27225c4..dba0df5 100644
--- a/xen/include/asm-arm/p2m.h
+++ b/xen/include/asm-arm/p2m.h
@@ -2,6 +2,8 @@
 #define _XEN_P2M_H
 
 #include <xen/mm.h>
+#include <xen/radix-tree.h>
+#include <public/mem_event.h> /* for mem_event_response_t */
 
 #include <xen/p2m-common.h>
 
@@ -11,6 +13,31 @@ struct domain;
 
 extern void memory_type_changed(struct domain *);
 
+/* List of possible type for each page in the p2m entry.
+ * The number of available bit per page in the pte for this purpose is 4 bits.
+ * So it's possible to only have 16 fields. If we run out of value in the
+ * future, it's possible to use higher value for pseudo-type and don't store
+ * them in the p2m entry.
+ */
+typedef enum {
+    p2m_invalid = 0,    /* Nothing mapped here */
+    p2m_ram_rw,         /* Normal read/write guest RAM */
+    p2m_ram_ro,         /* Read-only; writes are silently dropped */
+    p2m_mmio_direct,    /* Read/write mapping of genuine MMIO area */
+    p2m_map_foreign,    /* Ram pages from foreign domain */
+    p2m_grant_map_rw,   /* Read/write grant mapping */
+    p2m_grant_map_ro,   /* Read-only grant mapping */
+    /* The types below are only used to decide the page attribute in the P2M */
+    p2m_iommu_map_rw,   /* Read/write iommu mapping */
+    p2m_iommu_map_ro,   /* Read-only iommu mapping */
+    p2m_max_real_type,  /* Types after this won't be store in the p2m */
+} p2m_type_t;
+
+/* Look up a GFN and take a reference count on the backing page. */
+typedef unsigned int p2m_query_t;
+#define P2M_ALLOC    (1u<<0)   /* Populate PoD and paged-out entries */
+#define P2M_UNSHARE  (1u<<1)   /* Break CoW sharing */
+
 /* Per-p2m-table state */
 struct p2m_domain {
     /* Lock that protects updates to the p2m */
@@ -48,27 +75,20 @@ struct p2m_domain {
     /* If true, and an access fault comes in and there is no mem_event listener,
      * pause domain. Otherwise, remove access restrictions. */
     bool_t access_required;
-};
 
-/* List of possible type for each page in the p2m entry.
- * The number of available bit per page in the pte for this purpose is 4 bits.
- * So it's possible to only have 16 fields. If we run out of value in the
- * future, it's possible to use higher value for pseudo-type and don't store
- * them in the p2m entry.
- */
-typedef enum {
-    p2m_invalid = 0,    /* Nothing mapped here */
-    p2m_ram_rw,         /* Normal read/write guest RAM */
-    p2m_ram_ro,         /* Read-only; writes are silently dropped */
-    p2m_mmio_direct,    /* Read/write mapping of genuine MMIO area */
-    p2m_map_foreign,    /* Ram pages from foreign domain */
-    p2m_grant_map_rw,   /* Read/write grant mapping */
-    p2m_grant_map_ro,   /* Read-only grant mapping */
-    /* The types below are only used to decide the page attribute in the P2M */
-    p2m_iommu_map_rw,   /* Read/write iommu mapping */
-    p2m_iommu_map_ro,   /* Read-only iommu mapping */
-    p2m_max_real_type,  /* Types after this won't be store in the p2m */
-} p2m_type_t;
+    /* Defines if mem_access is in use for the domain to avoid uneccessary radix
+     * lookups. */
+    bool_t access_in_use;
+
+    /* Default P2M access type for each page in the the domain: new pages,
+     * swapped in pages, cleared pages, and pages that are ambiguously
+     * retyped get this access type. See definition of p2m_access_t. */
+    p2m_access_t default_access;
+
+    /* Radix tree to store the p2m_access_t settings as the pte's don't have
+     * enough available bits to store this information. */
+    struct radix_tree_root mem_access_settings;
+};
 
 static inline
 void p2m_mem_event_emulate_check(struct domain *d,
@@ -77,6 +97,7 @@ void p2m_mem_event_emulate_check(struct domain *d,
     /* Not supported on ARM. */
 };
 
+static inline
 void p2m_enable_msr_exit_interception(struct domain *d)
 {
     /* Not supported on ARM. */
@@ -157,11 +178,6 @@ p2m_pod_decrease_reservation(struct domain *d,
                              xen_pfn_t gpfn,
                              unsigned int order);
 
-/* Look up a GFN and take a reference count on the backing page. */
-typedef unsigned int p2m_query_t;
-#define P2M_ALLOC    (1u<<0)   /* Populate PoD and paged-out entries */
-#define P2M_UNSHARE  (1u<<1)   /* Break CoW sharing */
-
 static inline struct page_info *get_page_from_gfn(
     struct domain *d, unsigned long gfn, p2m_type_t *t, p2m_query_t q)
 {
@@ -220,6 +236,17 @@ int arch_grant_unmap_page_identity(struct domain *d, unsigned long frame);
 /* get host p2m table */
 #define p2m_get_hostp2m(d) (&(d)->arch.p2m)
 
+/* mem_event and mem_access are supported on any ARM guest */
+static inline bool_t p2m_mem_access_sanity_check(struct domain *d)
+{
+    return 1;
+}
+
+static inline bool_t p2m_mem_event_sanity_check(struct domain *d)
+{
+    return 1;
+}
+
 #endif /* _XEN_P2M_H */
 
 /*
-- 
2.1.0

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

* [PATCH for-4.5 v8 13/19] xen/arm: Implement domain_get_maximum_gpfn
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (11 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 14/19] xen/arm: Add p2m_set_permission and p2m_shatter_page helpers Tamas K Lengyel
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra

From: Julien Grall <julien.grall@linaro.org>

The function domain_get_maximum_gpfn is returning the maximum gpfn ever
mapped in the guest. We can use d->arch.p2m.max_mapped_gfn for this purpose.

We use this in xenaccess as to avoid the user attempting to set page
permissions on pages which don't exist for the domain, as a non-arch specific
sanity check.

Signed-off-by: Julien Grall <julien.grall@linaro.org>
---
 xen/arch/arm/mm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index c5b48ef..439cb01 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -971,7 +971,7 @@ int page_is_ram_type(unsigned long mfn, unsigned long mem_type)
 
 unsigned long domain_get_maximum_gpfn(struct domain *d)
 {
-    return -ENOSYS;
+    return d->arch.p2m.max_mapped_gfn;
 }
 
 void share_xen_page_with_guest(struct page_info *page,
-- 
2.1.0

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

* [PATCH for-4.5 v8 14/19] xen/arm: Add p2m_set_permission and p2m_shatter_page helpers.
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (12 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 13/19] xen/arm: Implement domain_get_maximum_gpfn Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-24 14:48   ` Julien Grall
  2014-09-23 13:14 ` [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events Tamas K Lengyel
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
---
v8: Determine level_shift in p2m_shatter_page instead of passing as argument.
---
 xen/arch/arm/p2m.c | 136 ++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 93 insertions(+), 43 deletions(-)

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 760d064..1fb531d 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -227,6 +227,76 @@ int p2m_pod_decrease_reservation(struct domain *d,
     return -ENOSYS;
 }
 
+static void p2m_set_permission(lpae_t *e, p2m_type_t t, p2m_access_t a)
+{
+    /* First apply type permissions */
+    switch ( t )
+    {
+    case p2m_ram_rw:
+        e->p2m.xn = 0;
+        e->p2m.write = 1;
+        break;
+
+    case p2m_ram_ro:
+        e->p2m.xn = 0;
+        e->p2m.write = 0;
+        break;
+
+    case p2m_iommu_map_rw:
+    case p2m_map_foreign:
+    case p2m_grant_map_rw:
+    case p2m_mmio_direct:
+        e->p2m.xn = 1;
+        e->p2m.write = 1;
+        break;
+
+    case p2m_iommu_map_ro:
+    case p2m_grant_map_ro:
+    case p2m_invalid:
+        e->p2m.xn = 1;
+        e->p2m.write = 0;
+        break;
+
+    case p2m_max_real_type:
+        BUG();
+        break;
+    }
+
+    /* Then restrict with access permissions */
+    switch ( a )
+    {
+    case p2m_access_rwx:
+        break;
+    case p2m_access_wx:
+        e->p2m.read = 0;
+        break;
+    case p2m_access_rw:
+        e->p2m.xn = 1;
+        break;
+    case p2m_access_w:
+        e->p2m.read = 0;
+        e->p2m.xn = 1;
+        break;
+    case p2m_access_rx:
+    case p2m_access_rx2rw:
+        e->p2m.write = 0;
+        break;
+    case p2m_access_x:
+        e->p2m.write = 0;
+        e->p2m.read = 0;
+        break;
+    case p2m_access_r:
+        e->p2m.write = 0;
+        e->p2m.xn = 1;
+        break;
+    case p2m_access_n:
+    case p2m_access_n2rwx:
+        e->p2m.read = e->p2m.write = 0;
+        e->p2m.xn = 1;
+        break;
+    }
+}
+
 static lpae_t mfn_to_p2m_entry(unsigned long mfn, unsigned int mattr,
                                p2m_type_t t, p2m_access_t a)
 {
@@ -258,37 +328,7 @@ static lpae_t mfn_to_p2m_entry(unsigned long mfn, unsigned int mattr,
         break;
     }
 
-    switch (t)
-    {
-    case p2m_ram_rw:
-        e.p2m.xn = 0;
-        e.p2m.write = 1;
-        break;
-
-    case p2m_ram_ro:
-        e.p2m.xn = 0;
-        e.p2m.write = 0;
-        break;
-
-    case p2m_iommu_map_rw:
-    case p2m_map_foreign:
-    case p2m_grant_map_rw:
-    case p2m_mmio_direct:
-        e.p2m.xn = 1;
-        e.p2m.write = 1;
-        break;
-
-    case p2m_iommu_map_ro:
-    case p2m_grant_map_ro:
-    case p2m_invalid:
-        e.p2m.xn = 1;
-        e.p2m.write = 0;
-        break;
-
-    case p2m_max_real_type:
-        BUG();
-        break;
-    }
+    p2m_set_permission(&e, t, a);
 
     ASSERT(!(pa & ~PAGE_MASK));
     ASSERT(!(pa & ~PADDR_MASK));
@@ -452,6 +492,26 @@ static const paddr_t level_masks[] =
 static const paddr_t level_shifts[] =
     { ZEROETH_SHIFT, FIRST_SHIFT, SECOND_SHIFT, THIRD_SHIFT };
 
+static int p2m_shatter_page(struct domain *d,
+                            lpae_t *entry,
+                            unsigned int level,
+                            bool_t flush_cache)
+{
+    const paddr_t level_shift = level_shifts[level];
+    int rc = p2m_create_table(d, entry,
+                              level_shift - PAGE_SHIFT, flush_cache);
+
+    if ( !rc )
+    {
+        struct p2m_domain *p2m = &d->arch.p2m;
+        p2m->stats.shattered[level]++;
+        p2m->stats.mappings[level]--;
+        p2m->stats.mappings[level+1] += LPAE_ENTRIES;
+    }
+
+    return rc;
+}
+
 /*
  * 0   == (P2M_ONE_DESCEND) continue to descend the tree
  * +ve == (P2M_ONE_PROGRESS_*) handled at this level, continue, flush,
@@ -584,14 +644,9 @@ static int apply_one_level(struct domain *d,
             if ( p2m_mapping(orig_pte) )
             {
                 *flush = true;
-                rc = p2m_create_table(d, entry,
-                                      level_shift - PAGE_SHIFT, flush_cache);
+                rc = p2m_shatter_page(d, entry, level, flush_cache);
                 if ( rc < 0 )
                     return rc;
-
-                p2m->stats.shattered[level]++;
-                p2m->stats.mappings[level]--;
-                p2m->stats.mappings[level+1] += LPAE_ENTRIES;
             } /* else: an existing table mapping -> descend */
 
             BUG_ON(!p2m_table(*entry));
@@ -626,15 +681,10 @@ static int apply_one_level(struct domain *d,
                  * and descend.
                  */
                 *flush = true;
-                rc = p2m_create_table(d, entry,
-                                      level_shift - PAGE_SHIFT, flush_cache);
+                rc = p2m_shatter_page(d, entry, level, flush_cache);
                 if ( rc < 0 )
                     return rc;
 
-                p2m->stats.shattered[level]++;
-                p2m->stats.mappings[level]--;
-                p2m->stats.mappings[level+1] += LPAE_ENTRIES;
-
                 return P2M_ONE_DESCEND;
             }
         }
-- 
2.1.0

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

* [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (13 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 14/19] xen/arm: Add p2m_set_permission and p2m_shatter_page helpers Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-24 15:02   ` Ian Campbell
  2014-09-24 15:35   ` Julien Grall
  2014-09-23 13:14 ` [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling Tamas K Lengyel
                   ` (3 subsequent siblings)
  18 siblings, 2 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

This patch enables to store, set, check and deliver LPAE R/W mem_events.
As the LPAE PTE's lack enough available software programmable bits,
we store the permissions in a Radix tree. A custom boolean, access_in_use,
specifies if the tree is in use to avoid uneccessary lookups on an empty tree.

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
---
v8: - Revert to arch specific p2m_mem_access_check.
    - Retire dabt_dfsc enum and use FSC_FLT defines.
    - Revert to Radix tree approach and use access_in_use flag to
      indicate if the tree is in use or not to avoid uneccessary lookups.
v7: - Removed p2m_shatter_page and p2m_set_permission into separate
      patch.
    - Replace Radix tree settings store with extended struct page_info
      approach. This way the trap handlers can use the MMU directly to
      locate the permission store instead of having to do a tree-lookup.
    - Add p2m_get_entry/set_entry compat functions which are required by
      the common mem_access_check function.
    - Typo fixes.
v6: - Add helper function p2m_shatter_page.
    - Only allocate 4k pages when mem_access is in use.
    - If no setting was found in radix tree but PTE exists,
      return rwx as permission.
    - Move the inclusion of various headers into this patch.
    - Make npfec a const.
v5: - Move p2m_set_entry's logic into apply_one_level via
      a new p2m_op, MEMACCESS.
v4: - Add p2m_mem_access_radix_set function to be called
      when inserting new PTE's and when updating existing entries.
    - Switch p2m_mem_access_check to return bool_t.
    - Use new struct npfec to pass violation info.
v3: - Add new function for updating the PTE entries, p2m_set_entry.
    - Use the new struct npfec to pass violation information.
    - Implement n2rwx, rx2rw and listener required routines.
v2: - Patch been split to ease the review process.
    - Add definitions of data abort data fetch status codes (enum dabt_dfsc)
      and only call p2m_mem_access_check for traps caused by permission violations.
    - Only call p2m_write_pte in p2m_lookup if the PTE permission actually changed.
    - Properly save settings in the Radix tree and pause the VCPU with
      mem_event_vcpu_pause.
---
 xen/arch/arm/p2m.c        | 364 +++++++++++++++++++++++++++++++++++++++++++++-
 xen/arch/arm/traps.c      |  27 +++-
 xen/include/asm-arm/p2m.h |  15 ++
 3 files changed, 398 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 1fb531d..b63390f 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -5,6 +5,9 @@
 #include <xen/errno.h>
 #include <xen/domain_page.h>
 #include <xen/bitops.h>
+#include <xen/mem_event.h>
+#include <xen/mem_access.h>
+#include <public/mem_event.h>
 #include <asm/flushtlb.h>
 #include <asm/gic.h>
 #include <asm/event.h>
@@ -414,12 +417,40 @@ static int p2m_create_table(struct domain *d, lpae_t *entry,
     return 0;
 }
 
+static long p2m_mem_access_radix_set(struct p2m_domain *p2m, unsigned long pfn,
+                                     p2m_access_t a)
+{
+    long rc;
+    if ( p2m_access_rwx == a )
+    {
+        if ( p2m->access_in_use )
+            radix_tree_delete(&p2m->mem_access_settings, pfn);
+
+        return 0;
+    }
+
+    rc = radix_tree_insert(&p2m->mem_access_settings, pfn,
+                           radix_tree_int_to_ptr(a));
+    if ( -EEXIST == rc )
+    {
+        /* If a setting existed already, change it to the new one */
+        radix_tree_replace_slot(
+            radix_tree_lookup_slot(
+                &p2m->mem_access_settings, pfn),
+            radix_tree_int_to_ptr(a));
+        rc = 0;
+    }
+
+    return rc;
+}
+
 enum p2m_operation {
     INSERT,
     ALLOCATE,
     REMOVE,
     RELINQUISH,
     CACHEFLUSH,
+    MEMACCESS,
 };
 
 /* Put any references on the single 4K page referenced by pte.  TODO:
@@ -553,13 +584,22 @@ static int apply_one_level(struct domain *d,
         if ( p2m_valid(orig_pte) )
             return P2M_ONE_DESCEND;
 
-        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size) )
+        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size) &&
+           /* We only create superpages when mem_access is not in use. */
+             (level == 3 || (level < 3 && !p2m->access_in_use)) )
         {
             struct page_info *page;
 
             page = alloc_domheap_pages(d, level_shift - PAGE_SHIFT, 0);
             if ( page )
             {
+                rc = p2m_mem_access_radix_set(p2m, paddr_to_pfn(*addr), a);
+                if ( rc < 0 )
+                {
+                    free_domheap_page(page);
+                    return rc;
+                }
+
                 pte = mfn_to_p2m_entry(page_to_mfn(page), mattr, t, a);
                 if ( level < 3 )
                     pte.p2m.table = 0;
@@ -580,8 +620,8 @@ static int apply_one_level(struct domain *d,
         /*
          * If we get here then we failed to allocate a sufficiently
          * large contiguous region for this level (which can't be
-         * L3). Create a page table and continue to descend so we try
-         * smaller allocations.
+         * L3) or mem_access is in use. Create a page table and
+         * continue to descend so we try smaller allocations.
          */
         rc = p2m_create_table(d, entry, 0, flush_cache);
         if ( rc < 0 )
@@ -591,9 +631,14 @@ static int apply_one_level(struct domain *d,
 
     case INSERT:
         if ( is_mapping_aligned(*addr, end_gpaddr, *maddr, level_size) &&
-           /* We do not handle replacing an existing table with a superpage */
-             (level == 3 || !p2m_table(orig_pte)) )
+           /* We do not handle replacing an existing table with a superpage
+            * or when mem_access is in use. */
+             (level == 3 || (!p2m_table(orig_pte) && !p2m->access_in_use)) )
         {
+            rc = p2m_mem_access_radix_set(p2m, paddr_to_pfn(*addr), a);
+            if ( rc < 0 )
+                return rc;
+
             /* New mapping is superpage aligned, make it */
             pte = mfn_to_p2m_entry(*maddr >> PAGE_SHIFT, mattr, t, a);
             if ( level < 3 )
@@ -709,6 +754,7 @@ static int apply_one_level(struct domain *d,
 
         memset(&pte, 0x00, sizeof(pte));
         p2m_write_pte(entry, pte, flush_cache);
+        p2m_mem_access_radix_set(p2m, paddr_to_pfn(*addr), p2m_access_rwx);
 
         *addr += level_size;
         *maddr += level_size;
@@ -753,6 +799,49 @@ static int apply_one_level(struct domain *d,
             *addr += PAGE_SIZE;
             return P2M_ONE_PROGRESS_NOP;
         }
+
+    case MEMACCESS:
+        if ( level < 3 )
+        {
+            if ( !p2m_valid(orig_pte) )
+            {
+                *addr += level_size;
+                return P2M_ONE_PROGRESS_NOP;
+            }
+
+            /* Shatter large pages as we descend */
+            if ( p2m_mapping(orig_pte) )
+            {
+                rc = p2m_shatter_page(d, entry, level, flush_cache);
+
+                if ( rc < 0 )
+                    return rc;
+            } /* else: an existing table mapping -> descend */
+
+            return P2M_ONE_DESCEND;
+        }
+        else
+        {
+            pte = orig_pte;
+
+            if ( !p2m_table(pte) )
+                pte.bits = 0;
+
+            if ( p2m_valid(pte) )
+            {
+                ASSERT(pte.p2m.type != p2m_invalid);
+
+                rc = p2m_mem_access_radix_set(p2m, paddr_to_pfn(*addr), a);
+                if ( rc < 0 )
+                    return rc;
+
+                p2m_set_permission(&pte, pte.p2m.type, a);
+                p2m_write_pte(entry, pte, flush_cache);
+            }
+
+            *addr += level_size;
+            return P2M_ONE_PROGRESS;
+        }
     }
 
     BUG(); /* Should never get here */
@@ -776,6 +865,8 @@ static int apply_p2m_changes(struct domain *d,
     unsigned int cur_root_table = ~0;
     unsigned int cur_offset[4] = { ~0, };
     unsigned int count = 0;
+    unsigned long start_gpfn = paddr_to_pfn(start_gpaddr),
+                  end_gpfn = paddr_to_pfn(end_gpaddr);
     bool_t flush = false;
     bool_t flush_pt;
 
@@ -821,6 +912,21 @@ static int apply_p2m_changes(struct domain *d,
             count = 0;
         }
 
+        /*
+         * Preempt setting mem_access permissions as required by XSA-89,
+         * if it's not the last iteration.
+         */
+        if ( op == MEMACCESS && count )
+        {
+            int progress = paddr_to_pfn(addr) - start_gpfn + 1;
+            if ( (end_gpfn-start_gpfn) > progress && !(progress & mask)
+                 && hypercall_preempt_check() )
+            {
+                rc = progress;
+                goto out;
+            }
+        }
+
         if ( P2M_ROOT_PAGES > 1 )
         {
             int i;
@@ -1283,6 +1389,254 @@ void __init setup_virt_paging(void)
     smp_call_function(setup_virt_paging_one, (void *)val, 1);
 }
 
+bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const struct npfec npfec)
+{
+    int rc;
+    bool_t violation;
+    xenmem_access_t xma;
+    mem_event_request_t *req;
+    struct vcpu *v = current;
+    struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
+
+    /* Mem_access is not in use. */
+    if ( !p2m->access_in_use )
+        return true;
+
+    rc = p2m_get_mem_access(v->domain, paddr_to_pfn(gpa), &xma);
+    if ( rc )
+        return true;
+
+    /* Now check for mem_access violation. */
+    switch ( xma )
+    {
+    case XENMEM_access_rwx:
+        violation = false;
+        break;
+    case XENMEM_access_rw:
+        violation = npfec.insn_fetch;
+        break;
+    case XENMEM_access_wx:
+        violation = npfec.read_access;
+        break;
+    case XENMEM_access_rx:
+        violation = npfec.write_access;
+        break;
+    case XENMEM_access_x:
+        violation = npfec.read_access || npfec.write_access;
+        break;
+    case XENMEM_access_w:
+        violation = npfec.read_access || npfec.insn_fetch;
+        break;
+    case XENMEM_access_r:
+        violation = npfec.write_access || npfec.insn_fetch;
+        break;
+    default:
+    case XENMEM_access_n:
+        violation = true;
+        break;
+    }
+
+    if ( !violation )
+        return true;
+
+    /* First, handle rx2rw and n2rwx conversion automatically. */
+    if ( npfec.write_access && xma == XENMEM_access_rx2rw )
+    {
+        rc = p2m_set_mem_access(v->domain, paddr_to_pfn(gpa), 1,
+                                0, ~0, XENMEM_access_rw);
+        return false;
+    }
+    else if ( xma == XENMEM_access_n2rwx )
+    {
+        rc = p2m_set_mem_access(v->domain, paddr_to_pfn(gpa), 1,
+                                0, ~0, XENMEM_access_rwx);
+    }
+
+    /* Otherwise, check if there is a memory event listener, and send the message along */
+    if ( !mem_event_check_ring( &v->domain->mem_event->access ) )
+    {
+        /* No listener */
+        if ( p2m->access_required )
+        {
+            gdprintk(XENLOG_INFO, "Memory access permissions failure, "
+                                  "no mem_event listener VCPU %d, dom %d\n",
+                                  v->vcpu_id, v->domain->domain_id);
+            domain_crash(v->domain);
+        }
+        else
+        {
+            /* n2rwx was already handled */
+            if ( xma != XENMEM_access_n2rwx)
+            {
+                /* A listener is not required, so clear the access
+                 * restrictions. */
+                rc = p2m_set_mem_access(v->domain, paddr_to_pfn(gpa), 1,
+                                        0, ~0, XENMEM_access_rwx);
+            }
+        }
+
+        /* No need to reinject */
+        return false;
+    }
+
+    req = xzalloc(mem_event_request_t);
+    if ( req )
+    {
+        req->reason = MEM_EVENT_REASON_VIOLATION;
+        if ( xma != XENMEM_access_n2rwx )
+            req->flags |= MEM_EVENT_FLAG_VCPU_PAUSED;
+        req->gfn = gpa >> PAGE_SHIFT;
+        req->offset =  gpa & ((1 << PAGE_SHIFT) - 1);
+        req->gla = gla;
+        req->gla_valid = npfec.gla_valid;
+        req->access_r = npfec.read_access;
+        req->access_w = npfec.write_access;
+        req->access_x = npfec.insn_fetch;
+        if ( npfec_kind_in_gpt == npfec.kind )
+            req->fault_in_gpt = 1;
+        if ( npfec_kind_with_gla == npfec.kind )
+            req->fault_with_gla = 1;
+        req->vcpu_id = v->vcpu_id;
+
+        mem_access_send_req(v->domain, req);
+        xfree(req);
+    }
+
+    /* Pause the current VCPU */
+    if ( xma != XENMEM_access_n2rwx )
+        mem_event_vcpu_pause(v);
+
+    return false;
+}
+
+/* Set access type for a region of pfns.
+ * If start_pfn == -1ul, sets the default access type */
+long p2m_set_mem_access(struct domain *d, unsigned long pfn, uint32_t nr,
+                        uint32_t start, uint32_t mask, xenmem_access_t access)
+{
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    p2m_access_t a;
+    long rc = 0;
+
+    static const p2m_access_t memaccess[] = {
+#define ACCESS(ac) [XENMEM_access_##ac] = p2m_access_##ac
+        ACCESS(n),
+        ACCESS(r),
+        ACCESS(w),
+        ACCESS(rw),
+        ACCESS(x),
+        ACCESS(rx),
+        ACCESS(wx),
+        ACCESS(rwx),
+        ACCESS(rx2rw),
+        ACCESS(n2rwx),
+#undef ACCESS
+    };
+
+    switch ( access )
+    {
+    case 0 ... ARRAY_SIZE(memaccess) - 1:
+        a = memaccess[access];
+        break;
+    case XENMEM_access_default:
+        a = p2m->default_access;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    /*
+     * Flip access_in_use to true when a permission is set, as to prevent
+     * allocating or inserting super-pages.
+     */
+    p2m->access_in_use = true;
+
+    /* If request to set default access. */
+    if ( pfn == ~0ul )
+    {
+        p2m->default_access = a;
+        return 0;
+    }
+
+    rc = apply_p2m_changes(d, MEMACCESS,
+                           pfn_to_paddr(pfn+start), pfn_to_paddr(pfn+nr),
+                           0, MATTR_MEM, mask, 0, a);
+
+    if ( rc < 0 )
+        return rc;
+    else if ( rc > 0 )
+        return start+rc;
+
+    flush_tlb_domain(d);
+    return 0;
+}
+
+int p2m_get_mem_access(struct domain *d, unsigned long gpfn,
+                       xenmem_access_t *access)
+{
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    void *i;
+    unsigned int index;
+
+    static const xenmem_access_t memaccess[] = {
+#define ACCESS(ac) [p2m_access_##ac] = XENMEM_access_##ac
+            ACCESS(n),
+            ACCESS(r),
+            ACCESS(w),
+            ACCESS(rw),
+            ACCESS(x),
+            ACCESS(rx),
+            ACCESS(wx),
+            ACCESS(rwx),
+            ACCESS(rx2rw),
+            ACCESS(n2rwx),
+#undef ACCESS
+    };
+
+    /* If no setting was ever set, just return rwx. */
+    if ( !p2m->access_in_use )
+    {
+        *access = XENMEM_access_rwx;
+        return 0;
+    }
+
+    /* If request to get default access */
+    if ( gpfn == ~0ull )
+    {
+        *access = memaccess[p2m->default_access];
+        return 0;
+    }
+
+    spin_lock(&p2m->lock);
+    i = radix_tree_lookup(&p2m->mem_access_settings, gpfn);
+    spin_unlock(&p2m->lock);
+
+    if ( !i )
+    {
+        /*
+         * No setting was found in the Radix tree. Check if the
+         * entry exists in the page-tables.
+         */
+        paddr_t maddr = p2m_lookup(d, gpfn << PAGE_SHIFT, NULL);
+        if ( INVALID_PADDR == maddr )
+            return -ESRCH;
+
+        /* If entry exists then its rwx. */
+        *access = XENMEM_access_rwx;
+    }
+    else
+    {
+        /* Seting was found in the Radix tree. */
+        index = radix_tree_ptr_to_int(i);
+        if ( index >= ARRAY_SIZE(memaccess) )
+            return -ERANGE;
+
+        *access = memaccess[index];
+    }
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 25fa8a0..695a33b 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -30,6 +30,7 @@
 #include <xen/hypercall.h>
 #include <xen/softirq.h>
 #include <xen/domain_page.h>
+#include <xen/mem_access.h>
 #include <public/sched.h>
 #include <public/xen.h>
 #include <asm/event.h>
@@ -1867,11 +1868,31 @@ static void do_trap_data_abort_guest(struct cpu_user_regs *regs,
     info.gva = READ_SYSREG64(FAR_EL2);
 #endif
 
-    if (dabt.s1ptw)
+    rc = gva_to_ipa(info.gva, &info.gpa);
+    if ( -EFAULT == rc )
         goto bad_data_abort;
 
-    rc = gva_to_ipa(info.gva, &info.gpa);
-    if ( rc == -EFAULT )
+    switch ( dabt.dfsc & 0x3f )
+    {
+    case FSC_FLT_PERM ... FSC_FLT_PERM + 3:
+    {
+        const struct npfec npfec = {
+            .read_access = 1,
+            .write_access = dabt.write,
+            .gla_valid = 1,
+            .kind = dabt.s1ptw ? npfec_kind_in_gpt : npfec_kind_with_gla
+        };
+
+        rc = p2m_mem_access_check(info.gpa, info.gva, npfec);
+
+        /* Trap was triggered by mem_access, work here is done */
+        if ( !rc )
+            return;
+    }
+    break;
+    }
+
+    if ( dabt.s1ptw )
         goto bad_data_abort;
 
     /* XXX: Decode the instruction if ISS is not valid */
diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
index dba0df5..09006fc 100644
--- a/xen/include/asm-arm/p2m.h
+++ b/xen/include/asm-arm/p2m.h
@@ -4,6 +4,7 @@
 #include <xen/mm.h>
 #include <xen/radix-tree.h>
 #include <public/mem_event.h> /* for mem_event_response_t */
+#include <public/memory.h>
 
 #include <xen/p2m-common.h>
 
@@ -247,6 +248,20 @@ static inline bool_t p2m_mem_event_sanity_check(struct domain *d)
     return 1;
 }
 
+/* Send mem event based on the access. Boolean return value indicates if trap
+ * needs to be injected into guest. */
+bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const struct npfec npfec);
+
+/* Set access type for a region of pfns.
+ * If start_pfn == -1ul, sets the default access type */
+long p2m_set_mem_access(struct domain *d, unsigned long start_pfn, uint32_t nr,
+                        uint32_t start, uint32_t mask, xenmem_access_t access);
+
+/* Get access type for a pfn
+ * If pfn == -1ul, gets the default access type */
+int p2m_get_mem_access(struct domain *d, unsigned long pfn,
+                       xenmem_access_t *access);
+
 #endif /* _XEN_P2M_H */
 
 /*
-- 
2.1.0

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

* [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (14 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-24 15:05   ` Ian Campbell
  2014-09-24 15:41   ` Julien Grall
  2014-09-23 13:14 ` [PATCH for-4.5 v8 17/19] xen/arm: Enable the compilation of mem_access and mem_event on ARM Tamas K Lengyel
                   ` (2 subsequent siblings)
  18 siblings, 2 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Add missing structure definition for iabt and update the trap handling
mechanism to only inject the exception if the mem_access checker
decides to do so.

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
---
v8: - Revert to arch specific p2m_mem_access_check.
    - Retire iabt_fsc enum and use FSC_FLT instead.
    - Complete the struct definition of hsr_iabt.
v7: - Use the new common mem_access_check.
v6: - Make npfec a const.
v4: - Don't mark instruction fetch violation as read violation.
    - Use new struct npfec to pass violation info.
v2: - Add definition for instruction abort instruction fetch status codes
       (enum iabt_ifsc) and only call p2m_mem_access_check for traps triggered
       for permission violations.
---
 xen/arch/arm/traps.c            | 31 +++++++++++++++++++++++++++++--
 xen/include/asm-arm/processor.h | 13 ++++++++++++-
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 695a33b..3d645b3 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1844,8 +1844,35 @@ done:
 static void do_trap_instr_abort_guest(struct cpu_user_regs *regs,
                                       union hsr hsr)
 {
-    register_t addr = READ_SYSREG(FAR_EL2);
-    inject_iabt_exception(regs, addr, hsr.len);
+    struct hsr_iabt iabt = hsr.iabt;
+    int rc;
+    paddr_t gpa;
+    register_t gva = READ_SYSREG(FAR_EL2);
+
+    rc = gva_to_ipa(gva, &gpa);
+    if ( -EFAULT == rc )
+        return;
+
+    switch ( iabt.ifsc & 0x3f )
+    {
+    case FSC_FLT_PERM ... FSC_FLT_PERM + 3:
+    {
+        const struct npfec npfec = {
+            .insn_fetch = 1,
+            .gla_valid = 1,
+            .kind = iabt.s1ptw ? npfec_kind_in_gpt : npfec_kind_with_gla
+        };
+
+        rc = p2m_mem_access_check(gpa, gva, npfec);
+
+        /* Trap was triggered by mem_access, work here is done */
+        if ( !rc )
+            return;
+    }
+    break;
+    }
+
+    inject_iabt_exception(regs, gva, hsr.len);
 }
 
 static void do_trap_data_abort_guest(struct cpu_user_regs *regs,
diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
index 07a421c..46e408a 100644
--- a/xen/include/asm-arm/processor.h
+++ b/xen/include/asm-arm/processor.h
@@ -432,10 +432,21 @@ union hsr {
     } sysreg; /* HSR_EC_SYSREG */
 #endif
 
+    struct hsr_iabt {
+        unsigned long ifsc:6;  /* Instruction fault status code */
+        unsigned long res0:1;
+        unsigned long s1ptw:1; /* Fault during a stage 1 translation table walk */
+        unsigned long res1:1;
+        unsigned long eat:1;   /* External abort type */
+        unsigned long res2:15;
+        unsigned long len:1;   /* Instruction length */
+        unsigned long ec:6;    /* Exception Class */
+    } iabt; /* HSR_EC_INSTR_ABORT_* */
+
     struct hsr_dabt {
         unsigned long dfsc:6;  /* Data Fault Status Code */
         unsigned long write:1; /* Write / not Read */
-        unsigned long s1ptw:1; /* */
+        unsigned long s1ptw:1; /* Fault during a stage 1 translation table walk */
         unsigned long cache:1; /* Cache Maintenance */
         unsigned long eat:1;   /* External Abort Type */
 #ifdef CONFIG_ARM_32
-- 
2.1.0

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

* [PATCH for-4.5 v8 17/19] xen/arm: Enable the compilation of mem_access and mem_event on ARM.
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (15 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-24 15:08   ` Ian Campbell
  2014-09-24 15:42   ` Julien Grall
  2014-09-23 13:14 ` [PATCH for-4.5 v8 18/19] tools/libxc: Allocate magic page for mem access " Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 19/19] tools/tests: Enable xen-access " Tamas K Lengyel
  18 siblings, 2 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

This patch sets up the infrastructure to support mem_access and mem_event
on ARM and turns on compilation. We define the required XSM functions.

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
---
v8: All MEM_* flags have been converted to HAS_* and moved into config/*.mk

v3: Wrap mem_event related functions in XSM into #ifdef HAS_MEM_ACCESS
       blocks.
    Update XSM hooks in flask to properly wire it up on ARM.

v2: Add CONFIG_MEM_PAGING and CONFIG_MEM_SHARING definitions and
       use them instead of CONFIG_X86.
    Split domctl copy-back and p2m type definitions into separate
       patches and move this patch to the end of the series.
---
 config/arm32.mk         |  1 +
 config/arm64.mk         |  1 +
 xen/include/xsm/dummy.h | 26 ++++++++++++++------------
 xen/include/xsm/xsm.h   | 29 +++++++++++++++++------------
 xen/xsm/dummy.c         |  7 +++++--
 xen/xsm/flask/hooks.c   | 33 ++++++++++++++++++++-------------
 6 files changed, 58 insertions(+), 39 deletions(-)

diff --git a/config/arm32.mk b/config/arm32.mk
index aa79d22..4a7c259 100644
--- a/config/arm32.mk
+++ b/config/arm32.mk
@@ -13,6 +13,7 @@ HAS_PL011 := y
 HAS_EXYNOS4210 := y
 HAS_OMAP := y
 HAS_NS16550 := y
+HAS_MEM_ACCESS := y
 
 # Use only if calling $(LD) directly.
 LDFLAGS_DIRECT += -EL
diff --git a/config/arm64.mk b/config/arm64.mk
index 15b57a4..ea6558d 100644
--- a/config/arm64.mk
+++ b/config/arm64.mk
@@ -8,6 +8,7 @@ CFLAGS += #-marm -march= -mcpu= etc
 
 HAS_PL011 := y
 HAS_NS16550 := y
+HAS_MEM_ACCESS := y
 
 # Use only if calling $(LD) directly.
 LDFLAGS_DIRECT += -EL
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index df55e70..f20e89c 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -513,6 +513,20 @@ static XSM_INLINE int xsm_hvm_param_nested(XSM_DEFAULT_ARG struct domain *d)
     return xsm_default_action(action, current->domain, d);
 }
 
+#ifdef HAS_MEM_ACCESS
+static XSM_INLINE int xsm_mem_event_control(XSM_DEFAULT_ARG struct domain *d, int mode, int op)
+{
+    XSM_ASSERT_ACTION(XSM_PRIV);
+    return xsm_default_action(action, current->domain, d);
+}
+
+static XSM_INLINE int xsm_mem_event_op(XSM_DEFAULT_ARG struct domain *d, int op)
+{
+    XSM_ASSERT_ACTION(XSM_DM_PRIV);
+    return xsm_default_action(action, current->domain, d);
+}
+#endif
+
 #ifdef CONFIG_X86
 static XSM_INLINE int xsm_do_mca(XSM_DEFAULT_VOID)
 {
@@ -556,18 +570,6 @@ static XSM_INLINE int xsm_hvm_ioreq_server(XSM_DEFAULT_ARG struct domain *d, int
     return xsm_default_action(action, current->domain, d);
 }
 
-static XSM_INLINE int xsm_mem_event_control(XSM_DEFAULT_ARG struct domain *d, int mode, int op)
-{
-    XSM_ASSERT_ACTION(XSM_PRIV);
-    return xsm_default_action(action, current->domain, d);
-}
-
-static XSM_INLINE int xsm_mem_event_op(XSM_DEFAULT_ARG struct domain *d, int op)
-{
-    XSM_ASSERT_ACTION(XSM_DM_PRIV);
-    return xsm_default_action(action, current->domain, d);
-}
-
 static XSM_INLINE int xsm_mem_sharing_op(XSM_DEFAULT_ARG struct domain *d, struct domain *cd, int op)
 {
     XSM_ASSERT_ACTION(XSM_DM_PRIV);
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index 6c1c079..4ce089f 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -141,6 +141,11 @@ struct xsm_operations {
     int (*hvm_param_nested) (struct domain *d);
     int (*get_vnumainfo) (struct domain *d);
 
+#ifdef HAS_MEM_ACCESS
+    int (*mem_event_control) (struct domain *d, int mode, int op);
+    int (*mem_event_op) (struct domain *d, int op);
+#endif
+
 #ifdef CONFIG_X86
     int (*do_mca) (void);
     int (*shadow_control) (struct domain *d, uint32_t op);
@@ -149,8 +154,6 @@ struct xsm_operations {
     int (*hvm_set_pci_link_route) (struct domain *d);
     int (*hvm_inject_msi) (struct domain *d);
     int (*hvm_ioreq_server) (struct domain *d, int op);
-    int (*mem_event_control) (struct domain *d, int mode, int op);
-    int (*mem_event_op) (struct domain *d, int op);
     int (*mem_sharing_op) (struct domain *d, struct domain *cd, int op);
     int (*apic) (struct domain *d, int cmd);
     int (*memtype) (uint32_t access);
@@ -540,6 +543,18 @@ static inline int xsm_get_vnumainfo (xsm_default_t def, struct domain *d)
     return xsm_ops->get_vnumainfo(d);
 }
 
+#ifdef HAS_MEM_ACCESS
+static inline int xsm_mem_event_control (xsm_default_t def, struct domain *d, int mode, int op)
+{
+    return xsm_ops->mem_event_control(d, mode, op);
+}
+
+static inline int xsm_mem_event_op (xsm_default_t def, struct domain *d, int op)
+{
+    return xsm_ops->mem_event_op(d, op);
+}
+#endif
+
 #ifdef CONFIG_X86
 static inline int xsm_do_mca(xsm_default_t def)
 {
@@ -576,16 +591,6 @@ static inline int xsm_hvm_ioreq_server (xsm_default_t def, struct domain *d, int
     return xsm_ops->hvm_ioreq_server(d, op);
 }
 
-static inline int xsm_mem_event_control (xsm_default_t def, struct domain *d, int mode, int op)
-{
-    return xsm_ops->mem_event_control(d, mode, op);
-}
-
-static inline int xsm_mem_event_op (xsm_default_t def, struct domain *d, int op)
-{
-    return xsm_ops->mem_event_op(d, op);
-}
-
 static inline int xsm_mem_sharing_op (xsm_default_t def, struct domain *d, struct domain *cd, int op)
 {
     return xsm_ops->mem_sharing_op(d, cd, op);
diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c
index 0826a8b..8eb3050 100644
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -118,6 +118,11 @@ void xsm_fixup_ops (struct xsm_operations *ops)
     set_to_dummy_if_null(ops, remove_from_physmap);
     set_to_dummy_if_null(ops, map_gmfn_foreign);
 
+#ifdef HAS_MEM_ACCESS
+    set_to_dummy_if_null(ops, mem_event_control);
+    set_to_dummy_if_null(ops, mem_event_op);
+#endif
+
 #ifdef CONFIG_X86
     set_to_dummy_if_null(ops, do_mca);
     set_to_dummy_if_null(ops, shadow_control);
@@ -126,8 +131,6 @@ void xsm_fixup_ops (struct xsm_operations *ops)
     set_to_dummy_if_null(ops, hvm_set_pci_link_route);
     set_to_dummy_if_null(ops, hvm_inject_msi);
     set_to_dummy_if_null(ops, hvm_ioreq_server);
-    set_to_dummy_if_null(ops, mem_event_control);
-    set_to_dummy_if_null(ops, mem_event_op);
     set_to_dummy_if_null(ops, mem_sharing_op);
     set_to_dummy_if_null(ops, apic);
     set_to_dummy_if_null(ops, platform_op);
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index df05566..8de5e49 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -577,6 +577,9 @@ static int flask_domctl(struct domain *d, int cmd)
     case XEN_DOMCTL_iomem_permission:
     case XEN_DOMCTL_memory_mapping:
     case XEN_DOMCTL_set_target:
+#ifdef HAS_MEM_ACCESS
+    case XEN_DOMCTL_mem_event_op:
+#endif
 #ifdef CONFIG_X86
     /* These have individual XSM hooks (arch/x86/domctl.c) */
     case XEN_DOMCTL_shadow_op:
@@ -584,7 +587,6 @@ static int flask_domctl(struct domain *d, int cmd)
     case XEN_DOMCTL_bind_pt_irq:
     case XEN_DOMCTL_unbind_pt_irq:
     case XEN_DOMCTL_ioport_mapping:
-    case XEN_DOMCTL_mem_event_op:
     /* These have individual XSM hooks (drivers/passthrough/iommu.c) */
     case XEN_DOMCTL_get_device_group:
     case XEN_DOMCTL_test_assign_device:
@@ -1189,6 +1191,18 @@ static int flask_deassign_device(struct domain *d, uint32_t machine_bdf)
 }
 #endif /* HAS_PASSTHROUGH && HAS_PCI */
 
+#ifdef HAS_MEM_ACCESS
+static int flask_mem_event_control(struct domain *d, int mode, int op)
+{
+    return current_has_perm(d, SECCLASS_HVM, HVM__MEM_EVENT);
+}
+
+static int flask_mem_event_op(struct domain *d, int op)
+{
+    return current_has_perm(d, SECCLASS_HVM, HVM__MEM_EVENT);
+}
+#endif /* HAS_MEM_ACCESS */
+
 #ifdef CONFIG_X86
 static int flask_do_mca(void)
 {
@@ -1299,16 +1313,6 @@ static int flask_hvm_ioreq_server(struct domain *d, int op)
     return current_has_perm(d, SECCLASS_HVM, HVM__HVMCTL);
 }
 
-static int flask_mem_event_control(struct domain *d, int mode, int op)
-{
-    return current_has_perm(d, SECCLASS_HVM, HVM__MEM_EVENT);
-}
-
-static int flask_mem_event_op(struct domain *d, int op)
-{
-    return current_has_perm(d, SECCLASS_HVM, HVM__MEM_EVENT);
-}
-
 static int flask_mem_sharing_op(struct domain *d, struct domain *cd, int op)
 {
     int rc = current_has_perm(cd, SECCLASS_HVM, HVM__MEM_SHARING);
@@ -1577,6 +1581,11 @@ static struct xsm_operations flask_ops = {
     .deassign_device = flask_deassign_device,
 #endif
 
+#ifdef HAS_MEM_ACCESS
+    .mem_event_control = flask_mem_event_control,
+    .mem_event_op = flask_mem_event_op,
+#endif
+
 #ifdef CONFIG_X86
     .do_mca = flask_do_mca,
     .shadow_control = flask_shadow_control,
@@ -1585,8 +1594,6 @@ static struct xsm_operations flask_ops = {
     .hvm_set_pci_link_route = flask_hvm_set_pci_link_route,
     .hvm_inject_msi = flask_hvm_inject_msi,
     .hvm_ioreq_server = flask_hvm_ioreq_server,
-    .mem_event_control = flask_mem_event_control,
-    .mem_event_op = flask_mem_event_op,
     .mem_sharing_op = flask_mem_sharing_op,
     .apic = flask_apic,
     .platform_op = flask_platform_op,
-- 
2.1.0

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

* [PATCH for-4.5 v8 18/19] tools/libxc: Allocate magic page for mem access on ARM
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (16 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 17/19] xen/arm: Enable the compilation of mem_access and mem_event on ARM Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-23 13:14 ` [PATCH for-4.5 v8 19/19] tools/tests: Enable xen-access " Tamas K Lengyel
  18 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
Reviewed-by: Julien Grall <julien.grall@linaro.org>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 tools/libxc/xc_dom_arm.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/tools/libxc/xc_dom_arm.c b/tools/libxc/xc_dom_arm.c
index 9b31b1f..13e881e 100644
--- a/tools/libxc/xc_dom_arm.c
+++ b/tools/libxc/xc_dom_arm.c
@@ -26,9 +26,10 @@
 #include "xg_private.h"
 #include "xc_dom.h"
 
-#define NR_MAGIC_PAGES 2
+#define NR_MAGIC_PAGES 3
 #define CONSOLE_PFN_OFFSET 0
 #define XENSTORE_PFN_OFFSET 1
+#define MEMACCESS_PFN_OFFSET 2
 
 #define LPAE_SHIFT 9
 
@@ -87,10 +88,13 @@ static int alloc_magic_pages(struct xc_dom_image *dom)
 
     xc_clear_domain_page(dom->xch, dom->guest_domid, dom->console_pfn);
     xc_clear_domain_page(dom->xch, dom->guest_domid, dom->xenstore_pfn);
+    xc_clear_domain_page(dom->xch, dom->guest_domid, base + MEMACCESS_PFN_OFFSET);
     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_CONSOLE_PFN,
             dom->console_pfn);
     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_STORE_PFN,
             dom->xenstore_pfn);
+    xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_ACCESS_RING_PFN,
+            base + MEMACCESS_PFN_OFFSET);
     /* allocated by toolstack */
     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_CONSOLE_EVTCHN,
             dom->console_evtchn);
-- 
2.1.0

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

* [PATCH for-4.5 v8 19/19] tools/tests: Enable xen-access on ARM
  2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
                   ` (17 preceding siblings ...)
  2014-09-23 13:14 ` [PATCH for-4.5 v8 18/19] tools/libxc: Allocate magic page for mem access " Tamas K Lengyel
@ 2014-09-23 13:14 ` Tamas K Lengyel
  2014-09-24 15:12   ` Ian Campbell
  18 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 13:14 UTC (permalink / raw)
  To: xen-devel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, stefano.stabellini,
	andres, jbeulich, dgdegra, Tamas K Lengyel

Define the ARM specific test_and_set_bit functions and switch
to use maximum gpfn as the limit to setting permissions. Also,
move HAS_MEM_ACCESS definition into config.

Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
---
v6: - Just use xc_domain_maximum_gpfn to get max_gpfn.
v5: - Use the new information returned by getdomaininfo, max_gpfn, to
      set access permissions. On ARM this will include the potential
      memory hole as well which the hypervisor just loops over.
v4: - Take into account multiple guest ram banks on ARM.
    - Move HAS_MEM_ACCESS definition into config/*.mk and only compile
      xen-access when it is defined.
    - Pass CONFIG_X86/CONFIG_ARM flags during compilation in xen-access
      Makefile.
---
 tools/tests/xen-access/Makefile     |  9 ++++-
 tools/tests/xen-access/xen-access.c | 79 ++++++++++++++++++++++++-------------
 2 files changed, 59 insertions(+), 29 deletions(-)

diff --git a/tools/tests/xen-access/Makefile b/tools/tests/xen-access/Makefile
index 65eef99..5056972 100644
--- a/tools/tests/xen-access/Makefile
+++ b/tools/tests/xen-access/Makefile
@@ -7,8 +7,13 @@ CFLAGS += $(CFLAGS_libxenctrl)
 CFLAGS += $(CFLAGS_libxenguest)
 CFLAGS += $(CFLAGS_xeninclude)
 
-TARGETS-y := 
-TARGETS-$(CONFIG_X86) += xen-access
+CFLAGS-y :=
+CFLAGS-$(CONFIG_X86) := -DCONFIG_X86
+CFLAGS-$(CONFIG_ARM) := -DCONFIG_ARM
+CFLAGS += $(CFLAGS-y)
+
+TARGETS-y :=
+TARGETS-$(HAS_MEM_ACCESS) := xen-access
 TARGETS := $(TARGETS-y)
 
 .PHONY: all
diff --git a/tools/tests/xen-access/xen-access.c b/tools/tests/xen-access/xen-access.c
index 6cb382d..40a7143 100644
--- a/tools/tests/xen-access/xen-access.c
+++ b/tools/tests/xen-access/xen-access.c
@@ -41,22 +41,16 @@
 #include <xenctrl.h>
 #include <xen/mem_event.h>
 
-#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))
-
-/* Spinlock and mem event definitions */
-
-#define SPIN_LOCK_UNLOCKED 0
+#ifdef CONFIG_X86
 
+#define START_PFN 0ULL
 #define ADDR (*(volatile long *) addr)
+
 /**
  * test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and cannot be reordered.
- * It also implies a memory barrier.
  */
 static inline int test_and_set_bit(int nr, volatile void *addr)
 {
@@ -69,6 +63,43 @@ static inline int test_and_set_bit(int nr, volatile void *addr)
     return oldbit;
 }
 
+#elif CONFIG_ARM
+
+#include <xen/arch-arm.h>
+
+#define PAGE_SHIFT              12
+#define START_PFN               (GUEST_RAM0_BASE >> PAGE_SHIFT)
+#define BITS_PER_WORD           32
+#define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_WORD))
+#define BIT_WORD(nr)            ((nr) / BITS_PER_WORD)
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ */
+static inline int test_and_set_bit(int nr, volatile void *addr)
+{
+        unsigned int mask = BIT_MASK(nr);
+        volatile unsigned int *p =
+                ((volatile unsigned int *)addr) + BIT_WORD(nr);
+        unsigned int old = *p;
+
+        *p = old | mask;
+        return (old & mask) != 0;
+}
+
+#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))
+
+/* Spinlock and mem event definitions */
+
+#define SPIN_LOCK_UNLOCKED 0
+
 typedef int spinlock_t;
 
 static inline void spin_lock(spinlock_t *lock)
@@ -108,7 +139,7 @@ typedef struct mem_event {
 typedef struct xenaccess {
     xc_interface *xc_handle;
 
-    xc_domaininfo_t    *domain_info;
+    int max_gpfn;
 
     mem_event_t mem_event;
 } xenaccess_t;
@@ -212,7 +243,6 @@ int xenaccess_teardown(xc_interface *xch, xenaccess_t *xenaccess)
     }
     xenaccess->xc_handle = NULL;
 
-    free(xenaccess->domain_info);
     free(xenaccess);
 
     return 0;
@@ -293,23 +323,17 @@ xenaccess_t *xenaccess_init(xc_interface **xch_r, domid_t domain_id)
                    (mem_event_sring_t *)xenaccess->mem_event.ring_page,
                    XC_PAGE_SIZE);
 
-    /* Get domaininfo */
-    xenaccess->domain_info = malloc(sizeof(xc_domaininfo_t));
-    if ( xenaccess->domain_info == NULL )
-    {
-        ERROR("Error allocating memory for domain info");
-        goto err;
-    }
+    /* Get max_gpfn */
+    xenaccess->max_gpfn = xc_domain_maximum_gpfn(xenaccess->xc_handle,
+                                                 xenaccess->mem_event.domain_id);
 
-    rc = xc_domain_getinfolist(xenaccess->xc_handle, domain_id, 1,
-                               xenaccess->domain_info);
-    if ( rc != 1 )
+    if ( xenaccess->max_gpfn < 0 )
     {
-        ERROR("Error getting domain info");
+        ERROR("Failed to get max gpfn");
         goto err;
     }
 
-    DPRINTF("max_pages = %"PRIx64"\n", xenaccess->domain_info->max_pages);
+    DPRINTF("max_gpfn = %"PRIx32"\n", xenaccess->max_gpfn);
 
     return xenaccess;
 
@@ -492,8 +516,9 @@ int main(int argc, char *argv[])
         goto exit;
     }
 
-    rc = xc_set_mem_access(xch, domain_id, default_access, 0,
-                           xenaccess->domain_info->max_pages);
+    rc = xc_set_mem_access(xch, domain_id, default_access, START_PFN,
+                           (xenaccess->max_gpfn - START_PFN) );
+
     if ( rc < 0 )
     {
         ERROR("Error %d setting all memory to access type %d\n", rc,
@@ -520,8 +545,8 @@ int main(int argc, char *argv[])
 
             /* Unregister for every event */
             rc = xc_set_mem_access(xch, domain_id, XENMEM_access_rwx, ~0ull, 0);
-            rc = xc_set_mem_access(xch, domain_id, XENMEM_access_rwx, 0,
-                                   xenaccess->domain_info->max_pages);
+            rc = xc_set_mem_access(xch, domain_id, XENMEM_access_rwx, START_PFN,
+                                   (xenaccess->max_gpfn - START_PFN) );
             rc = xc_hvm_param_set(xch, domain_id, HVM_PARAM_MEMORY_EVENT_INT3, HVMPME_mode_disabled);
 
             shutting_down = 1;
-- 
2.1.0

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

* Re: [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common
  2014-09-23 13:14 ` [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common Tamas K Lengyel
@ 2014-09-23 13:28   ` Jan Beulich
  2014-09-23 14:04     ` Tamas K Lengyel
  0 siblings, 1 reply; 58+ messages in thread
From: Jan Beulich @ 2014-09-23 13:28 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, xen-devel,
	stefano.stabellini, andres, dgdegra

>>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
> Relocate p2m_mem_access_resume to common and abstract the new
> p2m_mem_event_emulate_check into the p2m layer to.
> 
> Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
> Acked-by: Tim Deegan <tim@xen.org>
> ---
> v8: Abstract p2m_mem_event_emulate_check.

This is a pretty big change compared to the size of this patch, so
retaining the ack wasn't really appropriate. That's even more so
because you didn't even retain previous behavior:

> +void p2m_mem_event_emulate_check(struct domain *d, const mem_event_response_t *rsp)
> +{
> +    /* Mark vcpu for skipping one instruction upon rescheduling. */
> +    if ( rsp->flags & MEM_EVENT_FLAG_EMULATE )
> +    {
> +        struct vcpu *v = current;

Compare this with ...

> -void p2m_mem_access_resume(struct domain *d)
> -{
> -    mem_event_response_t rsp;
> -
> -    /* Pull all responses off the ring */
> -    while( mem_event_get_response(d, &d->mem_event->access, &rsp) )
> -    {
> -        struct vcpu *v;
> -
> -        if ( rsp.flags & MEM_EVENT_FLAG_DUMMY )
> -            continue;
> -
> -        /* Validate the vcpu_id in the response. */
> -        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
> -            continue;
> -
> -        v = d->vcpu[rsp.vcpu_id];

... the original code. I.e. you should pass v instead of d into
p2m_mem_event_emulate_check().

Jan

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

* Re: [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop into common.
  2014-09-23 13:14 ` [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop " Tamas K Lengyel
@ 2014-09-23 13:32   ` Jan Beulich
  2014-09-23 14:00     ` Razvan Cojocaru
  0 siblings, 1 reply; 58+ messages in thread
From: Jan Beulich @ 2014-09-23 13:32 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, xen-devel,
	stefano.stabellini, andres, dgdegra

>>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
> Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
> Acked-by: Jan Beulich <jbeulich@suse.com>
> Acked-by: Tim Deegan <tim@xen.org>
> ---
> v8: Move the new enable_msr_exit_interception test into the p2m layer.

Again invalidating earlier acks imo.

> --- a/xen/common/mem_event.c
> +++ b/xen/common/mem_event.c
> @@ -623,12 +623,9 @@ int mem_event_domctl(struct domain *d, 
> xen_domctl_mem_event_op_t *mec,
>                                      HVM_PARAM_ACCESS_RING_PFN,
>                                      mem_access_notification);
>  
> -            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
> -                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
> -            {
> -                d->arch.hvm_domain.introspection_enabled = 1;
> -                hvm_funcs.enable_msr_exit_interception(d);
> -            }
> +            if ( !rc && mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE )
> +                p2m_enable_msr_exit_interception(d);

The name is clearly not suitable for an abstraction - there's certainly
not going to be MSRs on each and every CPU architecture. Maybe
consult with Razvan on an agreeable more suitable name.

Jan

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

* Re: [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop into common.
  2014-09-23 13:32   ` Jan Beulich
@ 2014-09-23 14:00     ` Razvan Cojocaru
  2014-09-23 14:07       ` Jan Beulich
  2014-09-23 14:08       ` Tamas K Lengyel
  0 siblings, 2 replies; 58+ messages in thread
From: Razvan Cojocaru @ 2014-09-23 14:00 UTC (permalink / raw)
  To: Jan Beulich, Tamas K Lengyel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, xen-devel,
	stefano.stabellini, andres, dgdegra

On 09/23/2014 04:32 PM, Jan Beulich wrote:
>>>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
>> --- a/xen/common/mem_event.c
>> +++ b/xen/common/mem_event.c
>> @@ -623,12 +623,9 @@ int mem_event_domctl(struct domain *d, 
>> xen_domctl_mem_event_op_t *mec,
>>                                      HVM_PARAM_ACCESS_RING_PFN,
>>                                      mem_access_notification);
>>  
>> -            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
>> -                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
>> -            {
>> -                d->arch.hvm_domain.introspection_enabled = 1;
>> -                hvm_funcs.enable_msr_exit_interception(d);
>> -            }
>> +            if ( !rc && mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE )
>> +                p2m_enable_msr_exit_interception(d);
> 
> The name is clearly not suitable for an abstraction - there's certainly
> not going to be MSRs on each and every CPU architecture. Maybe
> consult with Razvan on an agreeable more suitable name.

P2m_set_up_introspection() perhaps? With the MSR HVM code where
applicable, nothing (or something else) where not? Would this be too
generic?


Regards,
Razvan Cojocaru

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

* Re: [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common
  2014-09-23 13:28   ` Jan Beulich
@ 2014-09-23 14:04     ` Tamas K Lengyel
  2014-09-23 14:08       ` Jan Beulich
  0 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 14:04 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Ian Campbell, Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Daniel De Graaf,
	Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 2030 bytes --]

On Tue, Sep 23, 2014 at 3:28 PM, Jan Beulich <JBeulich@suse.com> wrote:

> >>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
> > Relocate p2m_mem_access_resume to common and abstract the new
> > p2m_mem_event_emulate_check into the p2m layer to.
> >
> > Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
> > Acked-by: Tim Deegan <tim@xen.org>
> > ---
> > v8: Abstract p2m_mem_event_emulate_check.
>
> This is a pretty big change compared to the size of this patch, so
> retaining the ack wasn't really appropriate. That's even more so
> because you didn't even retain previous behavior:
>

I was debating about it and I had it as a separate patch first. If
required, should be no problem and I can resend the series before the
feature freeze.


>
> > +void p2m_mem_event_emulate_check(struct domain *d, const
> mem_event_response_t *rsp)
> > +{
> > +    /* Mark vcpu for skipping one instruction upon rescheduling. */
> > +    if ( rsp->flags & MEM_EVENT_FLAG_EMULATE )
> > +    {
> > +        struct vcpu *v = current;
>
> Compare this with ...
>
> > -void p2m_mem_access_resume(struct domain *d)
> > -{
> > -    mem_event_response_t rsp;
> > -
> > -    /* Pull all responses off the ring */
> > -    while( mem_event_get_response(d, &d->mem_event->access, &rsp) )
> > -    {
> > -        struct vcpu *v;
> > -
> > -        if ( rsp.flags & MEM_EVENT_FLAG_DUMMY )
> > -            continue;
> > -
> > -        /* Validate the vcpu_id in the response. */
> > -        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
> > -            continue;
> > -
> > -        v = d->vcpu[rsp.vcpu_id];
>
> ... the original code. I.e. you should pass v instead of d into
> p2m_mem_event_emulate_check().
>

Ah good point, but I think passing d is better (as it is also required
further down), I just have to make v = d->vcpu[rsp.vcpu_id] instead of
current.

Tamas


>
> Jan
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
>

[-- Attachment #1.2: Type: text/html, Size: 3416 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop into common.
  2014-09-23 14:00     ` Razvan Cojocaru
@ 2014-09-23 14:07       ` Jan Beulich
  2014-09-23 14:13         ` Tamas K Lengyel
  2014-09-23 14:19         ` Razvan Cojocaru
  2014-09-23 14:08       ` Tamas K Lengyel
  1 sibling, 2 replies; 58+ messages in thread
From: Jan Beulich @ 2014-09-23 14:07 UTC (permalink / raw)
  To: Razvan Cojocaru, Tamas K Lengyel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, xen-devel,
	stefano.stabellini, andres, dgdegra

>>> On 23.09.14 at 16:00, <rcojocaru@bitdefender.com> wrote:
> On 09/23/2014 04:32 PM, Jan Beulich wrote:
>>>>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
>>> --- a/xen/common/mem_event.c
>>> +++ b/xen/common/mem_event.c
>>> @@ -623,12 +623,9 @@ int mem_event_domctl(struct domain *d, 
>>> xen_domctl_mem_event_op_t *mec,
>>>                                      HVM_PARAM_ACCESS_RING_PFN,
>>>                                      mem_access_notification);
>>>  
>>> -            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
>>> -                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
>>> -            {
>>> -                d->arch.hvm_domain.introspection_enabled = 1;
>>> -                hvm_funcs.enable_msr_exit_interception(d);
>>> -            }
>>> +            if ( !rc && mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE )
>>> +                p2m_enable_msr_exit_interception(d);
>> 
>> The name is clearly not suitable for an abstraction - there's certainly
>> not going to be MSRs on each and every CPU architecture. Maybe
>> consult with Razvan on an agreeable more suitable name.
> 
> P2m_set_up_introspection() perhaps? With the MSR HVM code where
> applicable, nothing (or something else) where not? Would this be too
> generic?

I'd be fine with that name provided the != above gets converted
to a == XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION.

Jan

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

* Re: [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop into common.
  2014-09-23 14:00     ` Razvan Cojocaru
  2014-09-23 14:07       ` Jan Beulich
@ 2014-09-23 14:08       ` Tamas K Lengyel
  1 sibling, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 14:08 UTC (permalink / raw)
  To: Razvan Cojocaru
  Cc: Ian Campbell, Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 1694 bytes --]

On Tue, Sep 23, 2014 at 4:00 PM, Razvan Cojocaru <rcojocaru@bitdefender.com>
wrote:

> On 09/23/2014 04:32 PM, Jan Beulich wrote:
> >>>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
> >> --- a/xen/common/mem_event.c
> >> +++ b/xen/common/mem_event.c
> >> @@ -623,12 +623,9 @@ int mem_event_domctl(struct domain *d,
> >> xen_domctl_mem_event_op_t *mec,
> >>                                      HVM_PARAM_ACCESS_RING_PFN,
> >>                                      mem_access_notification);
> >>
> >> -            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
> >> -                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
> >> -            {
> >> -                d->arch.hvm_domain.introspection_enabled = 1;
> >> -                hvm_funcs.enable_msr_exit_interception(d);
> >> -            }
> >> +            if ( !rc && mec->op !=
> XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE )
> >> +                p2m_enable_msr_exit_interception(d);
> >
> > The name is clearly not suitable for an abstraction - there's certainly
> > not going to be MSRs on each and every CPU architecture. Maybe
> > consult with Razvan on an agreeable more suitable name.
>
> P2m_set_up_introspection() perhaps? With the MSR HVM code where
> applicable, nothing (or something else) where not? Would this be too
> generic?
>
>
Yes, I think its too generic of a name (which IMHO applies to the boolean
on the hvm_domain as well, introspection_enabled). I don't know what would
be an adequate name for this really.

Tamas


>
> Regards,
> Razvan Cojocaru
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
>

[-- Attachment #1.2: Type: text/html, Size: 2664 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common
  2014-09-23 14:04     ` Tamas K Lengyel
@ 2014-09-23 14:08       ` Jan Beulich
  2014-09-23 14:15         ` Tamas K Lengyel
  0 siblings, 1 reply; 58+ messages in thread
From: Jan Beulich @ 2014-09-23 14:08 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: Ian Campbell, Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Daniel De Graaf,
	Tamas K Lengyel

>>> On 23.09.14 at 16:04, <tamas.lengyel@zentific.com> wrote:
> On Tue, Sep 23, 2014 at 3:28 PM, Jan Beulich <JBeulich@suse.com> wrote:
>> >>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
>> > +void p2m_mem_event_emulate_check(struct domain *d, const mem_event_response_t *rsp)
>> > +{
>> > +    /* Mark vcpu for skipping one instruction upon rescheduling. */
>> > +    if ( rsp->flags & MEM_EVENT_FLAG_EMULATE )
>> > +    {
>> > +        struct vcpu *v = current;
>>
>> Compare this with ...
>>
>> > -void p2m_mem_access_resume(struct domain *d)
>> > -{
>> > -    mem_event_response_t rsp;
>> > -
>> > -    /* Pull all responses off the ring */
>> > -    while( mem_event_get_response(d, &d->mem_event->access, &rsp) )
>> > -    {
>> > -        struct vcpu *v;
>> > -
>> > -        if ( rsp.flags & MEM_EVENT_FLAG_DUMMY )
>> > -            continue;
>> > -
>> > -        /* Validate the vcpu_id in the response. */
>> > -        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
>> > -            continue;
>> > -
>> > -        v = d->vcpu[rsp.vcpu_id];
>>
>> ... the original code. I.e. you should pass v instead of d into
>> p2m_mem_event_emulate_check().
>>
> 
> Ah good point, but I think passing d is better (as it is also required
> further down), I just have to make v = d->vcpu[rsp.vcpu_id] instead of
> current.

No - d can simply be had from v->domain.

Jan

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

* Re: [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop into common.
  2014-09-23 14:07       ` Jan Beulich
@ 2014-09-23 14:13         ` Tamas K Lengyel
  2014-09-23 14:23           ` Razvan Cojocaru
  2014-09-23 14:19         ` Razvan Cojocaru
  1 sibling, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 14:13 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Ian Campbell, Razvan Cojocaru, Tim Deegan, Julien Grall,
	Ian Jackson, xen-devel, Stefano Stabellini, Andres Lagar-Cavilla,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 1933 bytes --]

On Tue, Sep 23, 2014 at 4:07 PM, Jan Beulich <JBeulich@suse.com> wrote:

> >>> On 23.09.14 at 16:00, <rcojocaru@bitdefender.com> wrote:
> > On 09/23/2014 04:32 PM, Jan Beulich wrote:
> >>>>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
> >>> --- a/xen/common/mem_event.c
> >>> +++ b/xen/common/mem_event.c
> >>> @@ -623,12 +623,9 @@ int mem_event_domctl(struct domain *d,
> >>> xen_domctl_mem_event_op_t *mec,
> >>>                                      HVM_PARAM_ACCESS_RING_PFN,
> >>>                                      mem_access_notification);
> >>>
> >>> -            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
> >>> -                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
> >>> -            {
> >>> -                d->arch.hvm_domain.introspection_enabled = 1;
> >>> -                hvm_funcs.enable_msr_exit_interception(d);
> >>> -            }
> >>> +            if ( !rc && mec->op !=
> XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE )
> >>> +                p2m_enable_msr_exit_interception(d);
> >>
> >> The name is clearly not suitable for an abstraction - there's certainly
> >> not going to be MSRs on each and every CPU architecture. Maybe
> >> consult with Razvan on an agreeable more suitable name.
> >
> > P2m_set_up_introspection() perhaps? With the MSR HVM code where
> > applicable, nothing (or something else) where not? Would this be too
> > generic?
>
> I'd be fine with that name provided the != above gets converted
> to a == XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION.
>
> Jan
>

My problem with this name is that introspection is really way too generic
of a term. You can certainly do all sorts of introspection without having
this feature or using this feature.. Ultimately its just a name so if this
becomes Xen's terminology to mean this particular feature I'm fine with it
but that's going to be confusing when other people talk about
'introspection'.

Tamas

[-- Attachment #1.2: Type: text/html, Size: 2834 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common
  2014-09-23 14:08       ` Jan Beulich
@ 2014-09-23 14:15         ` Tamas K Lengyel
  2014-09-23 15:02           ` Jan Beulich
  0 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 14:15 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Ian Campbell, Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Daniel De Graaf,
	Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 1646 bytes --]

On Tue, Sep 23, 2014 at 4:08 PM, Jan Beulich <JBeulich@suse.com> wrote:

> >>> On 23.09.14 at 16:04, <tamas.lengyel@zentific.com> wrote:
> > On Tue, Sep 23, 2014 at 3:28 PM, Jan Beulich <JBeulich@suse.com> wrote:
> >> >>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
> >> > +void p2m_mem_event_emulate_check(struct domain *d, const
> mem_event_response_t *rsp)
> >> > +{
> >> > +    /* Mark vcpu for skipping one instruction upon rescheduling. */
> >> > +    if ( rsp->flags & MEM_EVENT_FLAG_EMULATE )
> >> > +    {
> >> > +        struct vcpu *v = current;
> >>
> >> Compare this with ...
> >>
> >> > -void p2m_mem_access_resume(struct domain *d)
> >> > -{
> >> > -    mem_event_response_t rsp;
> >> > -
> >> > -    /* Pull all responses off the ring */
> >> > -    while( mem_event_get_response(d, &d->mem_event->access, &rsp) )
> >> > -    {
> >> > -        struct vcpu *v;
> >> > -
> >> > -        if ( rsp.flags & MEM_EVENT_FLAG_DUMMY )
> >> > -            continue;
> >> > -
> >> > -        /* Validate the vcpu_id in the response. */
> >> > -        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
> >> > -            continue;
> >> > -
> >> > -        v = d->vcpu[rsp.vcpu_id];
> >>
> >> ... the original code. I.e. you should pass v instead of d into
> >> p2m_mem_event_emulate_check().
> >>
> >
> > Ah good point, but I think passing d is better (as it is also required
> > further down), I just have to make v = d->vcpu[rsp.vcpu_id] instead of
> > current.
>
> No - d can simply be had from v->domain.
>
> Jan
>

Ack. Would you still prefer splitting the abstraction from this patch into
a separate one?

Tamas

[-- Attachment #1.2: Type: text/html, Size: 2691 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop into common.
  2014-09-23 14:07       ` Jan Beulich
  2014-09-23 14:13         ` Tamas K Lengyel
@ 2014-09-23 14:19         ` Razvan Cojocaru
  1 sibling, 0 replies; 58+ messages in thread
From: Razvan Cojocaru @ 2014-09-23 14:19 UTC (permalink / raw)
  To: Jan Beulich, Tamas K Lengyel
  Cc: ian.campbell, tim, julien.grall, ian.jackson, xen-devel,
	stefano.stabellini, andres, dgdegra

On 09/23/2014 05:07 PM, Jan Beulich wrote:
>>>> On 23.09.14 at 16:00, <rcojocaru@bitdefender.com> wrote:
>> On 09/23/2014 04:32 PM, Jan Beulich wrote:
>>>>>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
>>>> --- a/xen/common/mem_event.c
>>>> +++ b/xen/common/mem_event.c
>>>> @@ -623,12 +623,9 @@ int mem_event_domctl(struct domain *d, 
>>>> xen_domctl_mem_event_op_t *mec,
>>>>                                      HVM_PARAM_ACCESS_RING_PFN,
>>>>                                      mem_access_notification);
>>>>  
>>>> -            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
>>>> -                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
>>>> -            {
>>>> -                d->arch.hvm_domain.introspection_enabled = 1;
>>>> -                hvm_funcs.enable_msr_exit_interception(d);
>>>> -            }
>>>> +            if ( !rc && mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE )
>>>> +                p2m_enable_msr_exit_interception(d);
>>>
>>> The name is clearly not suitable for an abstraction - there's certainly
>>> not going to be MSRs on each and every CPU architecture. Maybe
>>> consult with Razvan on an agreeable more suitable name.
>>
>> P2m_set_up_introspection() perhaps? With the MSR HVM code where
>> applicable, nothing (or something else) where not? Would this be too
>> generic?
> 
> I'd be fine with that name provided the != above gets converted
> to a == XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION.

No problem here (should Tamas choose to go in that direction).


Regards,
Razvan Cojocaru

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

* Re: [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop into common.
  2014-09-23 14:13         ` Tamas K Lengyel
@ 2014-09-23 14:23           ` Razvan Cojocaru
  2014-09-23 14:28             ` Tamas K Lengyel
  0 siblings, 1 reply; 58+ messages in thread
From: Razvan Cojocaru @ 2014-09-23 14:23 UTC (permalink / raw)
  To: Tamas K Lengyel, Jan Beulich
  Cc: Ian Campbell, Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Daniel De Graaf,
	Tamas K Lengyel

On 09/23/2014 05:13 PM, Tamas K Lengyel wrote:
> 
> 
> On Tue, Sep 23, 2014 at 4:07 PM, Jan Beulich <JBeulich@suse.com
> <mailto:JBeulich@suse.com>> wrote:
> 
>     >>> On 23.09.14 at 16:00, <rcojocaru@bitdefender.com <mailto:rcojocaru@bitdefender.com>> wrote:
>     > On 09/23/2014 04:32 PM, Jan Beulich wrote:
>     >>>>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de <mailto:tklengyel@sec.in.tum.de>> wrote:
>     >>> --- a/xen/common/mem_event.c
>     >>> +++ b/xen/common/mem_event.c
>     >>> @@ -623,12 +623,9 @@ int mem_event_domctl(struct domain *d,
>     >>> xen_domctl_mem_event_op_t *mec,
>     >>>                                      HVM_PARAM_ACCESS_RING_PFN,
>     >>>                                      mem_access_notification);
>     >>>
>     >>> -            if ( mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
>     >>> -                 rc == 0 && hvm_funcs.enable_msr_exit_interception )
>     >>> -            {
>     >>> -                d->arch.hvm_domain.introspection_enabled = 1;
>     >>> -                hvm_funcs.enable_msr_exit_interception(d);
>     >>> -            }
>     >>> +            if ( !rc && mec->op != XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE )
>     >>> +                p2m_enable_msr_exit_interception(d);
>     >>
>     >> The name is clearly not suitable for an abstraction - there's certainly
>     >> not going to be MSRs on each and every CPU architecture. Maybe
>     >> consult with Razvan on an agreeable more suitable name.
>     >
>     > P2m_set_up_introspection() perhaps? With the MSR HVM code where
>     > applicable, nothing (or something else) where not? Would this be too
>     > generic?
> 
>     I'd be fine with that name provided the != above gets converted
>     to a == XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION.
> 
>     Jan
> 
> 
> My problem with this name is that introspection is really way too
> generic of a term. You can certainly do all sorts of introspection
> without having this feature or using this feature.. Ultimately its just
> a name so if this becomes Xen's terminology to mean this particular
> feature I'm fine with it but that's going to be confusing when other
> people talk about 'introspection'.

"Introspection" in general, yes, is a bit generic. However, the
"MEM_EVENT_OP_ACCESS" part of
XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION, and the "p2m_" part
of "p2m_set_up_introspection()" would, I think, narrow it down a bit more.

But it is, of course, ultimately up to you (and the Xen maintainers). It
was merely a suggestion.


Regards,
Razvan Cojocaru

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

* Re: [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop into common.
  2014-09-23 14:23           ` Razvan Cojocaru
@ 2014-09-23 14:28             ` Tamas K Lengyel
  0 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-23 14:28 UTC (permalink / raw)
  To: Razvan Cojocaru
  Cc: Ian Campbell, Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 3083 bytes --]

On Tue, Sep 23, 2014 at 4:23 PM, Razvan Cojocaru <rcojocaru@bitdefender.com>
wrote:

> On 09/23/2014 05:13 PM, Tamas K Lengyel wrote:
> >
> >
> > On Tue, Sep 23, 2014 at 4:07 PM, Jan Beulich <JBeulich@suse.com
> > <mailto:JBeulich@suse.com>> wrote:
> >
> >     >>> On 23.09.14 at 16:00, <rcojocaru@bitdefender.com <mailto:
> rcojocaru@bitdefender.com>> wrote:
> >     > On 09/23/2014 04:32 PM, Jan Beulich wrote:
> >     >>>>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de <mailto:
> tklengyel@sec.in.tum.de>> wrote:
> >     >>> --- a/xen/common/mem_event.c
> >     >>> +++ b/xen/common/mem_event.c
> >     >>> @@ -623,12 +623,9 @@ int mem_event_domctl(struct domain *d,
> >     >>> xen_domctl_mem_event_op_t *mec,
> >     >>>                                      HVM_PARAM_ACCESS_RING_PFN,
> >     >>>                                      mem_access_notification);
> >     >>>
> >     >>> -            if ( mec->op !=
> XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE &&
> >     >>> -                 rc == 0 &&
> hvm_funcs.enable_msr_exit_interception )
> >     >>> -            {
> >     >>> -                d->arch.hvm_domain.introspection_enabled = 1;
> >     >>> -                hvm_funcs.enable_msr_exit_interception(d);
> >     >>> -            }
> >     >>> +            if ( !rc && mec->op !=
> XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE )
> >     >>> +                p2m_enable_msr_exit_interception(d);
> >     >>
> >     >> The name is clearly not suitable for an abstraction - there's
> certainly
> >     >> not going to be MSRs on each and every CPU architecture. Maybe
> >     >> consult with Razvan on an agreeable more suitable name.
> >     >
> >     > P2m_set_up_introspection() perhaps? With the MSR HVM code where
> >     > applicable, nothing (or something else) where not? Would this be
> too
> >     > generic?
> >
> >     I'd be fine with that name provided the != above gets converted
> >     to a == XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION.
> >
> >     Jan
> >
> >
> > My problem with this name is that introspection is really way too
> > generic of a term. You can certainly do all sorts of introspection
> > without having this feature or using this feature.. Ultimately its just
> > a name so if this becomes Xen's terminology to mean this particular
> > feature I'm fine with it but that's going to be confusing when other
> > people talk about 'introspection'.
>
> "Introspection" in general, yes, is a bit generic. However, the
> "MEM_EVENT_OP_ACCESS" part of
> XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE_INTROSPECTION, and the "p2m_" part
> of "p2m_set_up_introspection()" would, I think, narrow it down a bit more.
>
> But it is, of course, ultimately up to you (and the Xen maintainers). It
> was merely a suggestion.
>
>
> Regards,
> Razvan Cojocaru
>

Thanks, I guess we can keep that name for the function with a comment
saying this is used to enable additional arch-specific introspection
options, such as MSR interception on x86. Maybe there will be more in the
future which could be put in here beside what it is used for at the moment.

Tamas

[-- Attachment #1.2: Type: text/html, Size: 4426 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common
  2014-09-23 14:15         ` Tamas K Lengyel
@ 2014-09-23 15:02           ` Jan Beulich
  0 siblings, 0 replies; 58+ messages in thread
From: Jan Beulich @ 2014-09-23 15:02 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: Ian Campbell, Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Daniel De Graaf,
	Tamas K Lengyel

>>> On 23.09.14 at 16:15, <tamas.lengyel@zentific.com> wrote:
> On Tue, Sep 23, 2014 at 4:08 PM, Jan Beulich <JBeulich@suse.com> wrote:
> 
>> >>> On 23.09.14 at 16:04, <tamas.lengyel@zentific.com> wrote:
>> > On Tue, Sep 23, 2014 at 3:28 PM, Jan Beulich <JBeulich@suse.com> wrote:
>> >> >>> On 23.09.14 at 15:14, <tklengyel@sec.in.tum.de> wrote:
>> >> > +void p2m_mem_event_emulate_check(struct domain *d, const
>> mem_event_response_t *rsp)
>> >> > +{
>> >> > +    /* Mark vcpu for skipping one instruction upon rescheduling. */
>> >> > +    if ( rsp->flags & MEM_EVENT_FLAG_EMULATE )
>> >> > +    {
>> >> > +        struct vcpu *v = current;
>> >>
>> >> Compare this with ...
>> >>
>> >> > -void p2m_mem_access_resume(struct domain *d)
>> >> > -{
>> >> > -    mem_event_response_t rsp;
>> >> > -
>> >> > -    /* Pull all responses off the ring */
>> >> > -    while( mem_event_get_response(d, &d->mem_event->access, &rsp) )
>> >> > -    {
>> >> > -        struct vcpu *v;
>> >> > -
>> >> > -        if ( rsp.flags & MEM_EVENT_FLAG_DUMMY )
>> >> > -            continue;
>> >> > -
>> >> > -        /* Validate the vcpu_id in the response. */
>> >> > -        if ( (rsp.vcpu_id >= d->max_vcpus) || !d->vcpu[rsp.vcpu_id] )
>> >> > -            continue;
>> >> > -
>> >> > -        v = d->vcpu[rsp.vcpu_id];
>> >>
>> >> ... the original code. I.e. you should pass v instead of d into
>> >> p2m_mem_event_emulate_check().
>> >>
>> >
>> > Ah good point, but I think passing d is better (as it is also required
>> > further down), I just have to make v = d->vcpu[rsp.vcpu_id] instead of
>> > current.
>>
>> No - d can simply be had from v->domain.
> 
> Ack. Would you still prefer splitting the abstraction from this patch into
> a separate one?

I don't think there's a need.

Jan

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

* Re: [PATCH for-4.5 v8 05/19] xen: Relocate set_access_required domctl into common
  2014-09-23 13:14 ` [PATCH for-4.5 v8 05/19] xen: Relocate set_access_required domctl into common Tamas K Lengyel
@ 2014-09-24 14:18   ` Julien Grall
  2014-09-24 15:05     ` Tamas K Lengyel
  0 siblings, 1 reply; 58+ messages in thread
From: Julien Grall @ 2014-09-24 14:18 UTC (permalink / raw)
  To: Tamas K Lengyel, xen-devel
  Cc: ian.campbell, tim, ian.jackson, stefano.stabellini, andres,
	jbeulich, dgdegra

Hi Tamas,

On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> @@ -1116,6 +1117,20 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
>      }
>      break;
>  
> +    case XEN_DOMCTL_set_access_required:
> +    {
> +        struct p2m_domain* p2m;
> +
> +        ret = -EPERM;
> +        if ( current->domain == d )
> +            break;
> +
> +        ret = 0;
> +        p2m = p2m_get_hostp2m(d);
> +        p2m->access_required = op->u.access_required.access_required;
> +    }
> +    break;
> +

IHMO this DOMCTL should only exist when mem access is supported/compiled
for the specific architecture. (i.e when HAS_MEM_ACCESS is defined).

Regards,

-- 
Julien Grall

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

* Re: [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support
  2014-09-23 13:14 ` [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support Tamas K Lengyel
@ 2014-09-24 14:40   ` Ian Campbell
  2014-09-24 16:58     ` Tamas K Lengyel
  2014-09-24 14:43   ` Julien Grall
  1 sibling, 1 reply; 58+ messages in thread
From: Ian Campbell @ 2014-09-24 14:40 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: tim, julien.grall, ian.jackson, xen-devel, stefano.stabellini,
	andres, jbeulich, dgdegra

On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
> Add p2m_access_t to struct page_info and add necessary changes for
> page table construction routines to pass the default access information.
> We store the p2m_access_t info in page_info as the PTE lacks enough
> software programmable bits.

The last bit of this is now out of date.

> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index 787e93c..3d69152 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -17,6 +17,7 @@ struct hvm_domain
>  {
>      uint64_t              params[HVM_NR_PARAMS];
>      struct hvm_iommu      iommu;
> +    bool_t                introspection_enabled;

I've not found the user of this yet, but is it not somewhat redundant
with p2m->access_in_use?

>  }  __cacheline_aligned;
>  
>  #ifdef CONFIG_ARM_64
> diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
> index 27225c4..dba0df5 100644
> --- a/xen/include/asm-arm/p2m.h
> +++ b/xen/include/asm-arm/p2m.h

> +/* Look up a GFN and take a reference count on the backing page. */
> +typedef unsigned int p2m_query_t;
> +#define P2M_ALLOC    (1u<<0)   /* Populate PoD and paged-out entries */
> +#define P2M_UNSHARE  (1u<<1)   /* Break CoW sharing */

Are the a result of something going wrong in a rebase? The comment here
refers to get_page_from_gfn which you've left behind, so it is out of
context now.

I don't think your other changes here require any of this to move, do
they?

> +    /* Defines if mem_access is in use for the domain to avoid uneccessary radix

"unnecessary"

> +     * lookups. */
> +    bool_t access_in_use;

> @@ -77,6 +97,7 @@ void p2m_mem_event_emulate_check(struct domain *d,
>      /* Not supported on ARM. */
>  };
>  
> +static inline
>  void p2m_enable_msr_exit_interception(struct domain *d)

I think this must belong in a previous patch which added this fn?

Ian.

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

* Re: [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support
  2014-09-23 13:14 ` [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support Tamas K Lengyel
  2014-09-24 14:40   ` Ian Campbell
@ 2014-09-24 14:43   ` Julien Grall
  2014-09-24 16:48     ` Tamas K Lengyel
  1 sibling, 1 reply; 58+ messages in thread
From: Julien Grall @ 2014-09-24 14:43 UTC (permalink / raw)
  To: Tamas K Lengyel, xen-devel
  Cc: ian.campbell, tim, ian.jackson, stefano.stabellini, andres,
	jbeulich, dgdegra

On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> +/* List of possible type for each page in the p2m entry.
> + * The number of available bit per page in the pte for this purpose is 4 bits.
> + * So it's possible to only have 16 fields. If we run out of value in the
> + * future, it's possible to use higher value for pseudo-type and don't store
> + * them in the p2m entry.
> + */
> +typedef enum {
> +    p2m_invalid = 0,    /* Nothing mapped here */
> +    p2m_ram_rw,         /* Normal read/write guest RAM */
> +    p2m_ram_ro,         /* Read-only; writes are silently dropped */
> +    p2m_mmio_direct,    /* Read/write mapping of genuine MMIO area */
> +    p2m_map_foreign,    /* Ram pages from foreign domain */
> +    p2m_grant_map_rw,   /* Read/write grant mapping */
> +    p2m_grant_map_ro,   /* Read-only grant mapping */
> +    /* The types below are only used to decide the page attribute in the P2M */
> +    p2m_iommu_map_rw,   /* Read/write iommu mapping */
> +    p2m_iommu_map_ro,   /* Read-only iommu mapping */
> +    p2m_max_real_type,  /* Types after this won't be store in the p2m */
> +} p2m_type_t;

In the context of this patch, this clearly looks a spurious change.

As said on a previous version, moving this enum only for style is not a
good reason. It makes more difficult to use git-blame.

Please avoid to move this enum.

> +
> +/* Look up a GFN and take a reference count on the backing page. */
> +typedef unsigned int p2m_query_t;
> +#define P2M_ALLOC    (1u<<0)   /* Populate PoD and paged-out entries */
> +#define P2M_UNSHARE  (1u<<1)   /* Break CoW sharing */
> +
>  /* Per-p2m-table state */
>  struct p2m_domain {
>      /* Lock that protects updates to the p2m */
> @@ -48,27 +75,20 @@ struct p2m_domain {
>      /* If true, and an access fault comes in and there is no mem_event listener,
>       * pause domain. Otherwise, remove access restrictions. */
>      bool_t access_required;
> -};
>  
> -/* List of possible type for each page in the p2m entry.
> - * The number of available bit per page in the pte for this purpose is 4 bits.
> - * So it's possible to only have 16 fields. If we run out of value in the
> - * future, it's possible to use higher value for pseudo-type and don't store
> - * them in the p2m entry.
> - */
> -typedef enum {
> -    p2m_invalid = 0,    /* Nothing mapped here */
> -    p2m_ram_rw,         /* Normal read/write guest RAM */
> -    p2m_ram_ro,         /* Read-only; writes are silently dropped */
> -    p2m_mmio_direct,    /* Read/write mapping of genuine MMIO area */
> -    p2m_map_foreign,    /* Ram pages from foreign domain */
> -    p2m_grant_map_rw,   /* Read/write grant mapping */
> -    p2m_grant_map_ro,   /* Read-only grant mapping */
> -    /* The types below are only used to decide the page attribute in the P2M */
> -    p2m_iommu_map_rw,   /* Read/write iommu mapping */
> -    p2m_iommu_map_ro,   /* Read-only iommu mapping */
> -    p2m_max_real_type,  /* Types after this won't be store in the p2m */
> -} p2m_type_t;
> +    /* Defines if mem_access is in use for the domain to avoid uneccessary radix

unecessary

> +     * lookups. */
> +    bool_t access_in_use;

Actually, you are using this boolean for more than avoid lookup to the
radix. I would drop the end of the sentence i.e: "to avoid uneccessary
radix lookups".

I gave a look to the radix tree lookups functions. Even if it's not
obvious, those functions have nearly the same cost as checking a boolean
when the radix tree is empty.

It might be interesting to see if we can avoid some if
(p2m->access_in_use) check in the p2m code.

Regards,


-- 
Julien Grall

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

* Re: [PATCH for-4.5 v8 14/19] xen/arm: Add p2m_set_permission and p2m_shatter_page helpers.
  2014-09-23 13:14 ` [PATCH for-4.5 v8 14/19] xen/arm: Add p2m_set_permission and p2m_shatter_page helpers Tamas K Lengyel
@ 2014-09-24 14:48   ` Julien Grall
  0 siblings, 0 replies; 58+ messages in thread
From: Julien Grall @ 2014-09-24 14:48 UTC (permalink / raw)
  To: Tamas K Lengyel, xen-devel
  Cc: ian.campbell, tim, ian.jackson, stefano.stabellini, andres,
	jbeulich, dgdegra

Hello Tamas,

On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
> Acked-by: Ian Campbell <ian.campbell@citrix.com>
Reviewed-by: Julien Grall <julien.grall@linaro.org>

Regards,

-- 
Julien Grall

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

* Re: [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-23 13:14 ` [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events Tamas K Lengyel
@ 2014-09-24 15:02   ` Ian Campbell
  2014-09-24 16:17     ` Tamas K Lengyel
  2014-09-24 15:35   ` Julien Grall
  1 sibling, 1 reply; 58+ messages in thread
From: Ian Campbell @ 2014-09-24 15:02 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: tim, julien.grall, ian.jackson, xen-devel, stefano.stabellini,
	andres, jbeulich, dgdegra

On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
> This patch enables to store, set, check and deliver LPAE R/W mem_events.
> As the LPAE PTE's lack enough available software programmable bits,
> we store the permissions in a Radix tree. A custom boolean, access_in_use,
> specifies if the tree is in use to avoid uneccessary lookups on an empty tree.

"unnecessary".

> @@ -414,12 +417,40 @@ static int p2m_create_table(struct domain *d, lpae_t *entry,
>      return 0;
>  }
>  
> +static long p2m_mem_access_radix_set(struct p2m_domain *p2m, unsigned long pfn,
> +                                     p2m_access_t a)
> +{
> +    long rc;
> +    if ( p2m_access_rwx == a )

I think I mentioned this before, but please write your conditionals the
more conventional way around.

> +    {
> +        if ( p2m->access_in_use )
> +            radix_tree_delete(&p2m->mem_access_settings, pfn);
> +
> +        return 0;
> +    }
> +
> +    rc = radix_tree_insert(&p2m->mem_access_settings, pfn,
> +                           radix_tree_int_to_ptr(a));
> +    if ( -EEXIST == rc )
> +    {
> +        /* If a setting existed already, change it to the new one */
> +        radix_tree_replace_slot(
> +            radix_tree_lookup_slot(
> +                &p2m->mem_access_settings, pfn),
> +            radix_tree_int_to_ptr(a));

What a shame that the API doesn't allow you to do an insert or replace
in one go!

> @@ -591,9 +631,14 @@ static int apply_one_level(struct domain *d,
>  
>      case INSERT:
>          if ( is_mapping_aligned(*addr, end_gpaddr, *maddr, level_size) &&
> -           /* We do not handle replacing an existing table with a superpage */
> -             (level == 3 || !p2m_table(orig_pte)) )
> +           /* We do not handle replacing an existing table with a superpage
> +            * or when mem_access is in use. */
> +             (level == 3 || (!p2m_table(orig_pte) && !p2m->access_in_use)) )
>          {
> +            rc = p2m_mem_access_radix_set(p2m, paddr_to_pfn(*addr), a);
> +            if ( rc < 0 )
> +                return rc;

I expect the answer is yes, but just to check: It is desirable to be
able to insert with a specific non-defualt access perms, as opposed to
INSERT with defaults then MEMACCESS?

> @@ -753,6 +799,49 @@ static int apply_one_level(struct domain *d,
>              *addr += PAGE_SIZE;
>              return P2M_ONE_PROGRESS_NOP;
>          }
> +
> +    case MEMACCESS:
> +        if ( level < 3 )
> +        {
> +            if ( !p2m_valid(orig_pte) )
> +            {
> +                *addr += level_size;
> +                return P2M_ONE_PROGRESS_NOP;
> +            }
> +
> +            /* Shatter large pages as we descend */
> +            if ( p2m_mapping(orig_pte) )
> +            {
> +                rc = p2m_shatter_page(d, entry, level, flush_cache);
> +
> +                if ( rc < 0 )
> +                    return rc;

I don't know if that matter for this specific sub op but what is
supposed to happen on error? Should partial work be undone?

> @@ -776,6 +865,8 @@ static int apply_p2m_changes(struct domain *d,
>      unsigned int cur_root_table = ~0;
>      unsigned int cur_offset[4] = { ~0, };
>      unsigned int count = 0;
> +    unsigned long start_gpfn = paddr_to_pfn(start_gpaddr),
> +                  end_gpfn = paddr_to_pfn(end_gpaddr);

You don't need to update end_gpaddr up, do you?

>      bool_t flush = false;
>      bool_t flush_pt;
>  
> @@ -821,6 +912,21 @@ static int apply_p2m_changes(struct domain *d,
>              count = 0;
>          }
>  
> +        /*
> +         * Preempt setting mem_access permissions as required by XSA-89,
> +         * if it's not the last iteration.
> +         */
> +        if ( op == MEMACCESS && count )
> +        {
> +            int progress = paddr_to_pfn(addr) - start_gpfn + 1;
> +            if ( (end_gpfn-start_gpfn) > progress && !(progress & mask)

This differs from the x86 equivalent in that it is not "++progress".
Doesn't that mean that we can fail to make any progress at all?

> +int p2m_get_mem_access(struct domain *d, unsigned long gpfn,
> +                       xenmem_access_t *access)
> +{
> +    struct p2m_domain *p2m = p2m_get_hostp2m(d);
> +    void *i;
> +    unsigned int index;
> +
> +    static const xenmem_access_t memaccess[] = {
> +#define ACCESS(ac) [p2m_access_##ac] = XENMEM_access_##ac
> +            ACCESS(n),
> +            ACCESS(r),
> +            ACCESS(w),
> +            ACCESS(rw),
> +            ACCESS(x),
> +            ACCESS(rx),
> +            ACCESS(wx),
> +            ACCESS(rwx),
> +            ACCESS(rx2rw),
> +            ACCESS(n2rwx),
> +#undef ACCESS

Unlike x86 I think you have pretty much complete freedom to define
p2m_access_*? Why not just make them 1:1?

(one for a future cleanup if you prefer)

> +        /* Seting was found in the Radix tree. */

"Setting"

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

* Re: [PATCH for-4.5 v8 05/19] xen: Relocate set_access_required domctl into common
  2014-09-24 14:18   ` Julien Grall
@ 2014-09-24 15:05     ` Tamas K Lengyel
  0 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 15:05 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Tim Deegan, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 1019 bytes --]

On Wed, Sep 24, 2014 at 4:18 PM, Julien Grall <julien.grall@linaro.org>
wrote:

> Hi Tamas,
>
> On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> > @@ -1116,6 +1117,20 @@ long
> do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
> >      }
> >      break;
> >
> > +    case XEN_DOMCTL_set_access_required:
> > +    {
> > +        struct p2m_domain* p2m;
> > +
> > +        ret = -EPERM;
> > +        if ( current->domain == d )
> > +            break;
> > +
> > +        ret = 0;
> > +        p2m = p2m_get_hostp2m(d);
> > +        p2m->access_required = op->u.access_required.access_required;
> > +    }
> > +    break;
> > +
>
> IHMO this DOMCTL should only exist when mem access is supported/compiled
> for the specific architecture. (i.e when HAS_MEM_ACCESS is defined).
>
> Regards,
>
> --
> Julien Grall


Ack, it certainly wouldn't hurt although technically right now it is
supported on both architectures that Xen supports. I can see it being
beneficial going forward in case another arch is added.

Tamas

[-- Attachment #1.2: Type: text/html, Size: 1590 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling
  2014-09-23 13:14 ` [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling Tamas K Lengyel
@ 2014-09-24 15:05   ` Ian Campbell
  2014-09-24 17:04     ` Tamas K Lengyel
  2014-09-24 15:41   ` Julien Grall
  1 sibling, 1 reply; 58+ messages in thread
From: Ian Campbell @ 2014-09-24 15:05 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: tim, julien.grall, ian.jackson, xen-devel, stefano.stabellini,
	andres, jbeulich, dgdegra

On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
> Add missing structure definition for iabt and update the trap handling
> mechanism to only inject the exception if the mem_access checker
> decides to do so.
> 
> Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>

Acked-by: Ian Campbell <ian.campbell@citrix.com>

> +        const struct npfec npfec = {
> +            .insn_fetch = 1,
> +            .gla_valid = 1,
> +            .kind = iabt.s1ptw ? npfec_kind_in_gpt : npfec_kind_with_gla

The references to "gla" here are just because the interface has been
refactored out of x86 into common code, right?

(if not and this is in fact an arm specific thing then please rename)

Ian.

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

* Re: [PATCH for-4.5 v8 17/19] xen/arm: Enable the compilation of mem_access and mem_event on ARM.
  2014-09-23 13:14 ` [PATCH for-4.5 v8 17/19] xen/arm: Enable the compilation of mem_access and mem_event on ARM Tamas K Lengyel
@ 2014-09-24 15:08   ` Ian Campbell
  2014-09-24 15:42   ` Julien Grall
  1 sibling, 0 replies; 58+ messages in thread
From: Ian Campbell @ 2014-09-24 15:08 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: tim, julien.grall, ian.jackson, xen-devel, stefano.stabellini,
	andres, jbeulich, dgdegra

On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
> This patch sets up the infrastructure to support mem_access and mem_event
> on ARM and turns on compilation. We define the required XSM functions.
> 
> Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
> Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>

Acked-by: Ian Campbell <ian.campbell@citrix.com>

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

* Re: [PATCH for-4.5 v8 19/19] tools/tests: Enable xen-access on ARM
  2014-09-23 13:14 ` [PATCH for-4.5 v8 19/19] tools/tests: Enable xen-access " Tamas K Lengyel
@ 2014-09-24 15:12   ` Ian Campbell
  2014-09-24 16:05     ` Tamas K Lengyel
  0 siblings, 1 reply; 58+ messages in thread
From: Ian Campbell @ 2014-09-24 15:12 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: tim, julien.grall, ian.jackson, xen-devel, stefano.stabellini,
	andres, jbeulich, dgdegra

On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
> Define the ARM specific test_and_set_bit functions and switch
> to use maximum gpfn as the limit to setting permissions. Also,
> move HAS_MEM_ACCESS definition into config.

Please could you mention the removal of the x86 comment about atomicity
here, since the reasoning for its correctness will be of interest to
future code archaeologists.

> -    rc = xc_set_mem_access(xch, domain_id, default_access, 0,
> -                           xenaccess->domain_info->max_pages);
> +    rc = xc_set_mem_access(xch, domain_id, default_access, START_PFN,
> +                           (xenaccess->max_gpfn - START_PFN) );

So the reason why info->max_pages is no use any more is because ARM
starts at non-zero and has multiple banks?

I suppose that's fair enough.

Ian.

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

* Re: [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-23 13:14 ` [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events Tamas K Lengyel
  2014-09-24 15:02   ` Ian Campbell
@ 2014-09-24 15:35   ` Julien Grall
  2014-09-24 16:27     ` Tamas K Lengyel
  1 sibling, 1 reply; 58+ messages in thread
From: Julien Grall @ 2014-09-24 15:35 UTC (permalink / raw)
  To: Tamas K Lengyel, xen-devel
  Cc: ian.campbell, tim, ian.jackson, stefano.stabellini, andres,
	jbeulich, dgdegra

Hello Tamas,

On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> This patch enables to store, set, check and deliver LPAE R/W mem_events.
> As the LPAE PTE's lack enough available software programmable bits,
> we store the permissions in a Radix tree. A custom boolean, access_in_use,
> specifies if the tree is in use to avoid uneccessary lookups on an empty tree.

unecessary

[..]

> +static long p2m_mem_access_radix_set(struct p2m_domain *p2m, unsigned long pfn,

Shouldn't "int" enough for the return type?

> +                                     p2m_access_t a)
> +{
> +    long rc;

NIT: missing new line here.

[..]

>  /* Put any references on the single 4K page referenced by pte.  TODO:
> @@ -553,13 +584,22 @@ static int apply_one_level(struct domain *d,
>          if ( p2m_valid(orig_pte) )
>              return P2M_ONE_DESCEND;
>  
> -        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size) )
> +        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size) &&
> +           /* We only create superpages when mem_access is not in use. */
> +             (level == 3 || (level < 3 && !p2m->access_in_use)) )

Can't this check be moved in is_mapping_aligned? You have nearly the
same few lines below.

[..]

> +    case MEMACCESS:
> +        if ( level < 3 )
> +        {
> +            if ( !p2m_valid(orig_pte) )
> +            {
> +                *addr += level_size;
> +                return P2M_ONE_PROGRESS_NOP;
> +            }
> +
> +            /* Shatter large pages as we descend */
> +            if ( p2m_mapping(orig_pte) )
> +            {
> +                rc = p2m_shatter_page(d, entry, level, flush_cache);
> +
> +                if ( rc < 0 )
> +                    return rc;
> +            } /* else: an existing table mapping -> descend */
> +
> +            return P2M_ONE_DESCEND;
> +        }
> +        else
> +        {
> +            pte = orig_pte;
> +
> +            if ( !p2m_table(pte) )
> +                pte.bits = 0;
> +
> +            if ( p2m_valid(pte) )
> +            {
> +                ASSERT(pte.p2m.type != p2m_invalid);

Why the ASSERT? I don't see why we wouldn't want to set permission for
this type of page.

[..]

> @@ -821,6 +912,21 @@ static int apply_p2m_changes(struct domain *d,
>              count = 0;
>          }
>  
> +        /*
> +         * Preempt setting mem_access permissions as required by XSA-89,
> +         * if it's not the last iteration.
> +         */
> +        if ( op == MEMACCESS && count )
> +        {
> +            int progress = paddr_to_pfn(addr) - start_gpfn + 1;

uint32_t?


NIT: Missing blank line.

> +            if ( (end_gpfn-start_gpfn) > progress && !(progress & mask)

NIT: (end_gpfn - start_gpfn)

Also you are comparing with an "int" with an "unsigned long". I'm not
sure what could happen in the compiler (implicit cast, sign extension...)

> +                 && hypercall_preempt_check() )
> +            {
> +                rc = progress;
> +                goto out;

Jumping directly to the label "out" will skip flushing the TLB for the
domain. While it wasn't critical until now, partial redo during
insertion/allocation or hypercall preemption only for relinquish, the
guest may use the wrong permission because the TLB hasn't been flushed.

At the same time, it looks like you never request to flush for the
MEMACCESS operation (see *flush = true). Does memaccess does a TLB flush
somewhere else?

[..]

> +bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const struct npfec npfec)
> +{
> +    int rc;
> +    bool_t violation;
> +    xenmem_access_t xma;
> +    mem_event_request_t *req;
> +    struct vcpu *v = current;
> +    struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
> +
> +    /* Mem_access is not in use. */
> +    if ( !p2m->access_in_use )
> +        return true;

AFAIU, it's not possible to call this function when mem access is not in
use. I would turn this check into an ASSERT.


[..]

> +    if ( !violation )
> +        return true;
> +
> +    /* First, handle rx2rw and n2rwx conversion automatically. */
> +    if ( npfec.write_access && xma == XENMEM_access_rx2rw )
> +    {
> +        rc = p2m_set_mem_access(v->domain, paddr_to_pfn(gpa), 1,
> +                                0, ~0, XENMEM_access_rw);
> +        return false;
> +    }
> +    else if ( xma == XENMEM_access_n2rwx )
> +    {
> +        rc = p2m_set_mem_access(v->domain, paddr_to_pfn(gpa), 1,
> +                                0, ~0, XENMEM_access_rwx);
> +    }
> +
> +    /* Otherwise, check if there is a memory event listener, and send the message along */
> +    if ( !mem_event_check_ring( &v->domain->mem_event->access ) )

NIT: if ( !mem_event_check_ring(&v->domain->mem_event->access) )

> +    {
> +        /* No listener */
> +        if ( p2m->access_required )
> +        {
> +            gdprintk(XENLOG_INFO, "Memory access permissions failure, "
> +                                  "no mem_event listener VCPU %d, dom %d\n",
> +                                  v->vcpu_id, v->domain->domain_id);
> +            domain_crash(v->domain);
> +        }
> +        else
> +        {
> +            /* n2rwx was already handled */
> +            if ( xma != XENMEM_access_n2rwx)

NIT: if ( ... )

[..]

> +/* Set access type for a region of pfns.
> + * If start_pfn == -1ul, sets the default access type */
> +long p2m_set_mem_access(struct domain *d, unsigned long pfn, uint32_t nr,
> +                        uint32_t start, uint32_t mask, xenmem_access_t access)
> +{

[..]

> +    rc = apply_p2m_changes(d, MEMACCESS,
> +                           pfn_to_paddr(pfn+start), pfn_to_paddr(pfn+nr),
> +                           0, MATTR_MEM, mask, 0, a);
> +
> +    if ( rc < 0 )
> +        return rc;
> +    else if ( rc > 0 )
> +        return start+rc;

start + rc

> +
> +    flush_tlb_domain(d);

NIT: Missing blank line.

Regards,


-- 
Julien Grall

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

* Re: [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling
  2014-09-23 13:14 ` [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling Tamas K Lengyel
  2014-09-24 15:05   ` Ian Campbell
@ 2014-09-24 15:41   ` Julien Grall
  2014-09-24 17:08     ` Tamas K Lengyel
  1 sibling, 1 reply; 58+ messages in thread
From: Julien Grall @ 2014-09-24 15:41 UTC (permalink / raw)
  To: Tamas K Lengyel, xen-devel
  Cc: ian.campbell, tim, ian.jackson, stefano.stabellini, andres,
	jbeulich, dgdegra

Hello Tamas,

On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> +        unsigned long s1ptw:1; /* Fault during a stage 1 translation table walk */

[..]

> +        unsigned long s1ptw:1; /* Fault during a stage 1 translation table walk */

The description is confusing, it gives the impression that this bit is
used to know if the fault has occurred a stage 1 translation table walk
or not. I would say: "Stage 2 fault during a stage 1 translation table
walk".

Regards,

-- 
Julien Grall

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

* Re: [PATCH for-4.5 v8 17/19] xen/arm: Enable the compilation of mem_access and mem_event on ARM.
  2014-09-23 13:14 ` [PATCH for-4.5 v8 17/19] xen/arm: Enable the compilation of mem_access and mem_event on ARM Tamas K Lengyel
  2014-09-24 15:08   ` Ian Campbell
@ 2014-09-24 15:42   ` Julien Grall
  1 sibling, 0 replies; 58+ messages in thread
From: Julien Grall @ 2014-09-24 15:42 UTC (permalink / raw)
  To: Tamas K Lengyel, xen-devel
  Cc: ian.campbell, tim, ian.jackson, stefano.stabellini, andres,
	jbeulich, dgdegra

Hello Tamas,

On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> This patch sets up the infrastructure to support mem_access and mem_event
> on ARM and turns on compilation. We define the required XSM functions.
> 
> Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
> Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Reviewed-by: Julien Grall <julien.grall@linaro.org>

Regards,

-- 
Julien Grall

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

* Re: [PATCH for-4.5 v8 19/19] tools/tests: Enable xen-access on ARM
  2014-09-24 15:12   ` Ian Campbell
@ 2014-09-24 16:05     ` Tamas K Lengyel
  0 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 16:05 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 1401 bytes --]

On Wed, Sep 24, 2014 at 5:12 PM, Ian Campbell <Ian.Campbell@citrix.com>
wrote:

> On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
> > Define the ARM specific test_and_set_bit functions and switch
> > to use maximum gpfn as the limit to setting permissions. Also,
> > move HAS_MEM_ACCESS definition into config.
>
> Please could you mention the removal of the x86 comment about atomicity
> here, since the reasoning for its correctness will be of interest to
> future code archaeologists.
>

Ack. I'm still hoping we can figure out if its the code or the comments
that's wrong. I tend to think its the comment as it smells like a
copy-paste.


>
> > -    rc = xc_set_mem_access(xch, domain_id, default_access, 0,
> > -                           xenaccess->domain_info->max_pages);
> > +    rc = xc_set_mem_access(xch, domain_id, default_access, START_PFN,
> > +                           (xenaccess->max_gpfn - START_PFN) );
>
> So the reason why info->max_pages is no use any more is because ARM
> starts at non-zero and has multiple banks?
>
> I suppose that's fair enough.
>
> Ian.
>

Yeap. It's not a problem to start at 0, this is just a bit of optimization
from the user's side that I would consider best-practice. The user could
also include some logic to skip the hole in-between the banks (if there are
multiple banks), but that I felt is too much complexity to include here.

Tamas

[-- Attachment #1.2: Type: text/html, Size: 2102 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-24 15:02   ` Ian Campbell
@ 2014-09-24 16:17     ` Tamas K Lengyel
  0 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 16:17 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 6119 bytes --]

On Wed, Sep 24, 2014 at 5:02 PM, Ian Campbell <Ian.Campbell@citrix.com>
wrote:

> On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
> > This patch enables to store, set, check and deliver LPAE R/W mem_events.
> > As the LPAE PTE's lack enough available software programmable bits,
> > we store the permissions in a Radix tree. A custom boolean,
> access_in_use,
> > specifies if the tree is in use to avoid uneccessary lookups on an empty
> tree.
>
> "unnecessary".
>

Ack.


>
> > @@ -414,12 +417,40 @@ static int p2m_create_table(struct domain *d,
> lpae_t *entry,
> >      return 0;
> >  }
> >
> > +static long p2m_mem_access_radix_set(struct p2m_domain *p2m, unsigned
> long pfn,
> > +                                     p2m_access_t a)
> > +{
> > +    long rc;
> > +    if ( p2m_access_rwx == a )
>
> I think I mentioned this before, but please write your conditionals the
> more conventional way around.
>

I guess my argument for this style was too much tin-foil-hat so Ack.


>
> > +    {
> > +        if ( p2m->access_in_use )
> > +            radix_tree_delete(&p2m->mem_access_settings, pfn);
> > +
> > +        return 0;
> > +    }
> > +
> > +    rc = radix_tree_insert(&p2m->mem_access_settings, pfn,
> > +                           radix_tree_int_to_ptr(a));
> > +    if ( -EEXIST == rc )
> > +    {
> > +        /* If a setting existed already, change it to the new one */
> > +        radix_tree_replace_slot(
> > +            radix_tree_lookup_slot(
> > +                &p2m->mem_access_settings, pfn),
> > +            radix_tree_int_to_ptr(a));
>
> What a shame that the API doesn't allow you to do an insert or replace
> in one go!
>

Could be extended I guess in the future.


>
> > @@ -591,9 +631,14 @@ static int apply_one_level(struct domain *d,
> >
> >      case INSERT:
> >          if ( is_mapping_aligned(*addr, end_gpaddr, *maddr, level_size)
> &&
> > -           /* We do not handle replacing an existing table with a
> superpage */
> > -             (level == 3 || !p2m_table(orig_pte)) )
> > +           /* We do not handle replacing an existing table with a
> superpage
> > +            * or when mem_access is in use. */
> > +             (level == 3 || (!p2m_table(orig_pte) &&
> !p2m->access_in_use)) )
> >          {
> > +            rc = p2m_mem_access_radix_set(p2m, paddr_to_pfn(*addr), a);
> > +            if ( rc < 0 )
> > +                return rc;
>
> I expect the answer is yes, but just to check: It is desirable to be
> able to insert with a specific non-defualt access perms, as opposed to
> INSERT with defaults then MEMACCESS?
>

I would say yes for performance reasons. No need to go through the pages
once for INSERT then once for MEMACCESS.


>
> > @@ -753,6 +799,49 @@ static int apply_one_level(struct domain *d,
> >              *addr += PAGE_SIZE;
> >              return P2M_ONE_PROGRESS_NOP;
> >          }
> > +
> > +    case MEMACCESS:
> > +        if ( level < 3 )
> > +        {
> > +            if ( !p2m_valid(orig_pte) )
> > +            {
> > +                *addr += level_size;
> > +                return P2M_ONE_PROGRESS_NOP;
> > +            }
> > +
> > +            /* Shatter large pages as we descend */
> > +            if ( p2m_mapping(orig_pte) )
> > +            {
> > +                rc = p2m_shatter_page(d, entry, level, flush_cache);
> > +
> > +                if ( rc < 0 )
> > +                    return rc;
>
> I don't know if that matter for this specific sub op but what is
> supposed to happen on error? Should partial work be undone?
>

IMHO if a page cannot be shattered something must be pretty screwed already
(Xen running out of memory?) in which case un-doing the already shattered
pages is the least of our concern..


>
> > @@ -776,6 +865,8 @@ static int apply_p2m_changes(struct domain *d,
> >      unsigned int cur_root_table = ~0;
> >      unsigned int cur_offset[4] = { ~0, };
> >      unsigned int count = 0;
> > +    unsigned long start_gpfn = paddr_to_pfn(start_gpaddr),
> > +                  end_gpfn = paddr_to_pfn(end_gpaddr);
>
> You don't need to update end_gpaddr up, do you?
>

No, these two values are provided by the user and we only keep track of the
progress made in updating the PTEs that fall in-range.


>
> >      bool_t flush = false;
> >      bool_t flush_pt;
> >
> > @@ -821,6 +912,21 @@ static int apply_p2m_changes(struct domain *d,
> >              count = 0;
> >          }
> >
> > +        /*
> > +         * Preempt setting mem_access permissions as required by XSA-89,
> > +         * if it's not the last iteration.
> > +         */
> > +        if ( op == MEMACCESS && count )
> > +        {
> > +            int progress = paddr_to_pfn(addr) - start_gpfn + 1;
> > +            if ( (end_gpfn-start_gpfn) > progress && !(progress & mask)
>
> This differs from the x86 equivalent in that it is not "++progress".
> Doesn't that mean that we can fail to make any progress at all?
>

It is technically ++progress, just the style is different. Note the +1 when
declaring progress. Furthermore, the && count ensures that at least one
iteration is always done when calling with MEMACCESS.


>
> > +int p2m_get_mem_access(struct domain *d, unsigned long gpfn,
> > +                       xenmem_access_t *access)
> > +{
> > +    struct p2m_domain *p2m = p2m_get_hostp2m(d);
> > +    void *i;
> > +    unsigned int index;
> > +
> > +    static const xenmem_access_t memaccess[] = {
> > +#define ACCESS(ac) [p2m_access_##ac] = XENMEM_access_##ac
> > +            ACCESS(n),
> > +            ACCESS(r),
> > +            ACCESS(w),
> > +            ACCESS(rw),
> > +            ACCESS(x),
> > +            ACCESS(rx),
> > +            ACCESS(wx),
> > +            ACCESS(rwx),
> > +            ACCESS(rx2rw),
> > +            ACCESS(n2rwx),
> > +#undef ACCESS
>
> Unlike x86 I think you have pretty much complete freedom to define
> p2m_access_*? Why not just make them 1:1?
>
> (one for a future cleanup if you prefer)
>

I moved p2m_access_t into common in this version of the series..


>
> > +        /* Seting was found in the Radix tree. */
>
> "Setting"
>

Ack.

Thanks,
Tamas

[-- Attachment #1.2: Type: text/html, Size: 8743 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-24 15:35   ` Julien Grall
@ 2014-09-24 16:27     ` Tamas K Lengyel
  2014-09-24 16:51       ` Julien Grall
  0 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 16:27 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Tim Deegan, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 7264 bytes --]

On Wed, Sep 24, 2014 at 5:35 PM, Julien Grall <julien.grall@linaro.org>
wrote:

> Hello Tamas,
>
> On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> > This patch enables to store, set, check and deliver LPAE R/W mem_events.
> > As the LPAE PTE's lack enough available software programmable bits,
> > we store the permissions in a Radix tree. A custom boolean,
> access_in_use,
> > specifies if the tree is in use to avoid uneccessary lookups on an empty
> tree.
>
> unecessary
>

Ack.


> [..]
>
> > +static long p2m_mem_access_radix_set(struct p2m_domain *p2m, unsigned
> long pfn,
>
> Shouldn't "int" enough for the return type?
>
> > +                                     p2m_access_t a)
> > +{
> > +    long rc;
>
> NIT: missing new line here.
>

Ack.


>
> [..]
>
> >  /* Put any references on the single 4K page referenced by pte.  TODO:
> > @@ -553,13 +584,22 @@ static int apply_one_level(struct domain *d,
> >          if ( p2m_valid(orig_pte) )
> >              return P2M_ONE_DESCEND;
> >
> > -        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size) )
> > +        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size) &&
> > +           /* We only create superpages when mem_access is not in use.
> */
> > +             (level == 3 || (level < 3 && !p2m->access_in_use)) )
>
> Can't this check be moved in is_mapping_aligned? You have nearly the
> same few lines below.
>

Unfortunately not, I already checked and it is used in REMOVE as well in
which case we would need an exception.. and that wasn't very straight
forward.


>
> [..]
>
> > +    case MEMACCESS:
> > +        if ( level < 3 )
> > +        {
> > +            if ( !p2m_valid(orig_pte) )
> > +            {
> > +                *addr += level_size;
> > +                return P2M_ONE_PROGRESS_NOP;
> > +            }
> > +
> > +            /* Shatter large pages as we descend */
> > +            if ( p2m_mapping(orig_pte) )
> > +            {
> > +                rc = p2m_shatter_page(d, entry, level, flush_cache);
> > +
> > +                if ( rc < 0 )
> > +                    return rc;
> > +            } /* else: an existing table mapping -> descend */
> > +
> > +            return P2M_ONE_DESCEND;
> > +        }
> > +        else
> > +        {
> > +            pte = orig_pte;
> > +
> > +            if ( !p2m_table(pte) )
> > +                pte.bits = 0;
> > +
> > +            if ( p2m_valid(pte) )
> > +            {
> > +                ASSERT(pte.p2m.type != p2m_invalid);
>
> Why the ASSERT? I don't see why we wouldn't want to set permission for
> this type of page.
>

Not sure, this I copied from p2m_lookup. Can it even happen that something
passes p2m_valid() but have a type of p2m_invalid? I think that just
signals that something is very wrong.


>
> [..]
>
> > @@ -821,6 +912,21 @@ static int apply_p2m_changes(struct domain *d,
> >              count = 0;
> >          }
> >
> > +        /*
> > +         * Preempt setting mem_access permissions as required by XSA-89,
> > +         * if it's not the last iteration.
> > +         */
> > +        if ( op == MEMACCESS && count )
> > +        {
> > +            int progress = paddr_to_pfn(addr) - start_gpfn + 1;
>
> uint32_t?
>

Ack.


>
>
> NIT: Missing blank line.
>
> > +            if ( (end_gpfn-start_gpfn) > progress && !(progress & mask)
>
> NIT: (end_gpfn - start_gpfn)
>
> Also you are comparing with an "int" with an "unsigned long". I'm not
> sure what could happen in the compiler (implicit cast, sign extension...)
>

Yea, converting to uint32_t is the way to go.


>
> > +                 && hypercall_preempt_check() )
> > +            {
> > +                rc = progress;
> > +                goto out;
>
> Jumping directly to the label "out" will skip flushing the TLB for the
> domain. While it wasn't critical until now, partial redo during
> insertion/allocation or hypercall preemption only for relinquish, the
> guest may use the wrong permission because the TLB hasn't been flushed.
>
> At the same time, it looks like you never request to flush for the
> MEMACCESS operation (see *flush = true). Does memaccess does a TLB flush
> somewhere else?
>

Yes, at the end of p2m_set_mem_access once all PTEs are updated
successfully. I guess we could flush the TLB as we are progressing as well,
it wouldn't hurt.


>
> [..]
>
> > +bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const struct
> npfec npfec)
> > +{
> > +    int rc;
> > +    bool_t violation;
> > +    xenmem_access_t xma;
> > +    mem_event_request_t *req;
> > +    struct vcpu *v = current;
> > +    struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
> > +
> > +    /* Mem_access is not in use. */
> > +    if ( !p2m->access_in_use )
> > +        return true;
>
> AFAIU, it's not possible to call this function when mem access is not in
> use. I would turn this check into an ASSERT.
>

It is possible to call this function when mem_access is not in use and it
is called every time there is a permission fault in the second stage
translation. This check here just makes sure the function returns as fast
as possible when not in use.


>
>
> [..]
>
> > +    if ( !violation )
> > +        return true;
> > +
> > +    /* First, handle rx2rw and n2rwx conversion automatically. */
> > +    if ( npfec.write_access && xma == XENMEM_access_rx2rw )
> > +    {
> > +        rc = p2m_set_mem_access(v->domain, paddr_to_pfn(gpa), 1,
> > +                                0, ~0, XENMEM_access_rw);
> > +        return false;
> > +    }
> > +    else if ( xma == XENMEM_access_n2rwx )
> > +    {
> > +        rc = p2m_set_mem_access(v->domain, paddr_to_pfn(gpa), 1,
> > +                                0, ~0, XENMEM_access_rwx);
> > +    }
> > +
> > +    /* Otherwise, check if there is a memory event listener, and send
> the message along */
> > +    if ( !mem_event_check_ring( &v->domain->mem_event->access ) )
>
> NIT: if ( !mem_event_check_ring(&v->domain->mem_event->access) )
>

Ack.


>
> > +    {
> > +        /* No listener */
> > +        if ( p2m->access_required )
> > +        {
> > +            gdprintk(XENLOG_INFO, "Memory access permissions failure, "
> > +                                  "no mem_event listener VCPU %d, dom
> %d\n",
> > +                                  v->vcpu_id, v->domain->domain_id);
> > +            domain_crash(v->domain);
> > +        }
> > +        else
> > +        {
> > +            /* n2rwx was already handled */
> > +            if ( xma != XENMEM_access_n2rwx)
>
> NIT: if ( ... )
>

Ack.


>
> [..]
>
> > +/* Set access type for a region of pfns.
> > + * If start_pfn == -1ul, sets the default access type */
> > +long p2m_set_mem_access(struct domain *d, unsigned long pfn, uint32_t
> nr,
> > +                        uint32_t start, uint32_t mask, xenmem_access_t
> access)
> > +{
>
> [..]
>
> > +    rc = apply_p2m_changes(d, MEMACCESS,
> > +                           pfn_to_paddr(pfn+start),
> pfn_to_paddr(pfn+nr),
> > +                           0, MATTR_MEM, mask, 0, a);
> > +
> > +    if ( rc < 0 )
> > +        return rc;
> > +    else if ( rc > 0 )
> > +        return start+rc;
>
> start + rc
>

Ack.


>
> > +
> > +    flush_tlb_domain(d);
>
> NIT: Missing blank line.
>
>
Ack.


> Regards,
>
>
> --
> Julien Grall
>
>
Thanks!
Tamas

[-- Attachment #1.2: Type: text/html, Size: 11249 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support
  2014-09-24 14:43   ` Julien Grall
@ 2014-09-24 16:48     ` Tamas K Lengyel
  0 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 16:48 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Tim Deegan, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 4220 bytes --]

On Wed, Sep 24, 2014 at 4:43 PM, Julien Grall <julien.grall@linaro.org>
wrote:

> On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> > +/* List of possible type for each page in the p2m entry.
> > + * The number of available bit per page in the pte for this purpose is
> 4 bits.
> > + * So it's possible to only have 16 fields. If we run out of value in
> the
> > + * future, it's possible to use higher value for pseudo-type and don't
> store
> > + * them in the p2m entry.
> > + */
> > +typedef enum {
> > +    p2m_invalid = 0,    /* Nothing mapped here */
> > +    p2m_ram_rw,         /* Normal read/write guest RAM */
> > +    p2m_ram_ro,         /* Read-only; writes are silently dropped */
> > +    p2m_mmio_direct,    /* Read/write mapping of genuine MMIO area */
> > +    p2m_map_foreign,    /* Ram pages from foreign domain */
> > +    p2m_grant_map_rw,   /* Read/write grant mapping */
> > +    p2m_grant_map_ro,   /* Read-only grant mapping */
> > +    /* The types below are only used to decide the page attribute in
> the P2M */
> > +    p2m_iommu_map_rw,   /* Read/write iommu mapping */
> > +    p2m_iommu_map_ro,   /* Read-only iommu mapping */
> > +    p2m_max_real_type,  /* Types after this won't be store in the p2m */
> > +} p2m_type_t;
>
> In the context of this patch, this clearly looks a spurious change.
>
> As said on a previous version, moving this enum only for style is not a
> good reason. It makes more difficult to use git-blame.
>
> Please avoid to move this enum.
>

Ack, forgot to move it back after I abstracted p2m_access_t into p2m-common.


>
> > +
> > +/* Look up a GFN and take a reference count on the backing page. */
> > +typedef unsigned int p2m_query_t;
> > +#define P2M_ALLOC    (1u<<0)   /* Populate PoD and paged-out entries */
> > +#define P2M_UNSHARE  (1u<<1)   /* Break CoW sharing */
> > +
> >  /* Per-p2m-table state */
> >  struct p2m_domain {
> >      /* Lock that protects updates to the p2m */
> > @@ -48,27 +75,20 @@ struct p2m_domain {
> >      /* If true, and an access fault comes in and there is no mem_event
> listener,
> >       * pause domain. Otherwise, remove access restrictions. */
> >      bool_t access_required;
> > -};
> >
> > -/* List of possible type for each page in the p2m entry.
> > - * The number of available bit per page in the pte for this purpose is
> 4 bits.
> > - * So it's possible to only have 16 fields. If we run out of value in
> the
> > - * future, it's possible to use higher value for pseudo-type and don't
> store
> > - * them in the p2m entry.
> > - */
> > -typedef enum {
> > -    p2m_invalid = 0,    /* Nothing mapped here */
> > -    p2m_ram_rw,         /* Normal read/write guest RAM */
> > -    p2m_ram_ro,         /* Read-only; writes are silently dropped */
> > -    p2m_mmio_direct,    /* Read/write mapping of genuine MMIO area */
> > -    p2m_map_foreign,    /* Ram pages from foreign domain */
> > -    p2m_grant_map_rw,   /* Read/write grant mapping */
> > -    p2m_grant_map_ro,   /* Read-only grant mapping */
> > -    /* The types below are only used to decide the page attribute in
> the P2M */
> > -    p2m_iommu_map_rw,   /* Read/write iommu mapping */
> > -    p2m_iommu_map_ro,   /* Read-only iommu mapping */
> > -    p2m_max_real_type,  /* Types after this won't be store in the p2m */
> > -} p2m_type_t;
> > +    /* Defines if mem_access is in use for the domain to avoid
> uneccessary radix
>
> unecessary
>

Ack.


>
> > +     * lookups. */
> > +    bool_t access_in_use;
>
> Actually, you are using this boolean for more than avoid lookup to the
> radix. I would drop the end of the sentence i.e: "to avoid uneccessary
> radix lookups".
>
> I gave a look to the radix tree lookups functions. Even if it's not
> obvious, those functions have nearly the same cost as checking a boolean
> when the radix tree is empty.
>

Thanks for looking into it, that was my initial assumption as well.
However, as the radix tree API lacks an is_empty() check, it is still
somewhat nice to have this separate boolean for the checks in
ALLOCATE/INSERT.


>
> It might be interesting to see if we can avoid some if
> (p2m->access_in_use) check in the p2m code.
>
> Regards,
>
>
> --
> Julien Grall
>
>
Thanks!
Tamas

[-- Attachment #1.2: Type: text/html, Size: 5668 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-24 16:27     ` Tamas K Lengyel
@ 2014-09-24 16:51       ` Julien Grall
  2014-09-24 17:13         ` Tamas K Lengyel
  0 siblings, 1 reply; 58+ messages in thread
From: Julien Grall @ 2014-09-24 16:51 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: Ian Campbell, Tim Deegan, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel

Hello Tamas,

On 09/24/2014 05:27 PM, Tamas K Lengyel wrote:
>     >  /* Put any references on the single 4K page referenced by pte.  TODO:
>     > @@ -553,13 +584,22 @@ static int apply_one_level(struct domain *d,
>     >          if ( p2m_valid(orig_pte) )
>     >              return P2M_ONE_DESCEND;
>     >
>     > -        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size) )
>     > +        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size) &&
>     > +           /* We only create superpages when mem_access is not in use. */
>     > +             (level == 3 || (level < 3 && !p2m->access_in_use)) )
> 
>     Can't this check be moved in is_mapping_aligned? You have nearly the
>     same few lines below.
> 
> 
> Unfortunately not, I already checked and it is used in REMOVE as well in
> which case we would need an exception.. and that wasn't very straight
> forward.

Ok.

> 
>     [..]
> 
>     > +    case MEMACCESS:
>     > +        if ( level < 3 )
>     > +        {
>     > +            if ( !p2m_valid(orig_pte) )
>     > +            {
>     > +                *addr += level_size;
>     > +                return P2M_ONE_PROGRESS_NOP;
>     > +            }
>     > +
>     > +            /* Shatter large pages as we descend */
>     > +            if ( p2m_mapping(orig_pte) )
>     > +            {
>     > +                rc = p2m_shatter_page(d, entry, level, flush_cache);
>     > +
>     > +                if ( rc < 0 )
>     > +                    return rc;
>     > +            } /* else: an existing table mapping -> descend */
>     > +
>     > +            return P2M_ONE_DESCEND;
>     > +        }
>     > +        else
>     > +        {
>     > +            pte = orig_pte;
>     > +
>     > +            if ( !p2m_table(pte) )
>     > +                pte.bits = 0;
>     > +
>     > +            if ( p2m_valid(pte) )
>     > +            {
>     > +                ASSERT(pte.p2m.type != p2m_invalid);
> 
>     Why the ASSERT? I don't see why we wouldn't want to set permission for
>     this type of page.
> 
> 
> Not sure, this I copied from p2m_lookup. Can it even happen that
> something passes p2m_valid() but have a type of p2m_invalid? I think
> that just signals that something is very wrong.

The ASSERT has been added in p2m_lookup, because p2m_invalid means the
MFN is wrong. Hence, p2m_invalid is only used for page table.

In your case, you don't need to use the MFN. So, IHMO, this ASSERT is
not necessary.

> 
>     > +                 && hypercall_preempt_check() )
>     > +            {
>     > +                rc = progress;
>     > +                goto out;
> 
>     Jumping directly to the label "out" will skip flushing the TLB for the
>     domain. While it wasn't critical until now, partial redo during
>     insertion/allocation or hypercall preemption only for relinquish, the
>     guest may use the wrong permission because the TLB hasn't been flushed.
> 
>     At the same time, it looks like you never request to flush for the
>     MEMACCESS operation (see *flush = true). Does memaccess does a TLB flush
>     somewhere else?
> 
> 
> Yes, at the end of p2m_set_mem_access once all PTEs are updated
> successfully. I guess we could flush the TLB as we are progressing as
> well, it wouldn't hurt.

We should flush the TLB as we are progressing because the guest may
technically continue to run...

>     [..]
> 
>     > +bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const struct npfec npfec)
>     > +{
>     > +    int rc;
>     > +    bool_t violation;
>     > +    xenmem_access_t xma;
>     > +    mem_event_request_t *req;
>     > +    struct vcpu *v = current;
>     > +    struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
>     > +
>     > +    /* Mem_access is not in use. */
>     > +    if ( !p2m->access_in_use )
>     > +        return true;
> 
>     AFAIU, it's not possible to call this function when mem access is not in
>     use. I would turn this check into an ASSERT.
> 
> 
> It is possible to call this function when mem_access is not in use and
> it is called every time there is a permission fault in the second stage
> translation. This check here just makes sure the function returns as
> fast as possible when not in use.

Oh right, sorry for the noise.

This case made me also think about another possible issue. Permission
are checked in raw_copy_{from,to}_guest_helper during virtual address
translation to a physical address.

As you modified the attribute in the P2M, the copy may failed because of
the lake of permission.

Regards,

-- 
Julien Grall

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

* Re: [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support
  2014-09-24 14:40   ` Ian Campbell
@ 2014-09-24 16:58     ` Tamas K Lengyel
  2014-09-24 17:14       ` Razvan Cojocaru
  0 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 16:58 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 2505 bytes --]

On Wed, Sep 24, 2014 at 4:40 PM, Ian Campbell <Ian.Campbell@citrix.com>
wrote:

> On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
> > Add p2m_access_t to struct page_info and add necessary changes for
> > page table construction routines to pass the default access information.
> > We store the p2m_access_t info in page_info as the PTE lacks enough
> > software programmable bits.
>
> The last bit of this is now out of date.
>

Ack.


>
> > diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> > index 787e93c..3d69152 100644
> > --- a/xen/include/asm-arm/domain.h
> > +++ b/xen/include/asm-arm/domain.h
> > @@ -17,6 +17,7 @@ struct hvm_domain
> >  {
> >      uint64_t              params[HVM_NR_PARAMS];
> >      struct hvm_iommu      iommu;
> > +    bool_t                introspection_enabled;
>
> I've not found the user of this yet, but is it not somewhat redundant
> with p2m->access_in_use?
>

It's used by mem_event memop for XEN_DOMCTL_MEM_EVENT_OP_ACCESS_DISABLE. I
just added this one field to the hvm_domain for compat reasons instead of
abstracting setting that value to 0 and adding an empty inline for ARM.
This looked like less trouble.


>
> >  }  __cacheline_aligned;
> >
> >  #ifdef CONFIG_ARM_64
> > diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
> > index 27225c4..dba0df5 100644
> > --- a/xen/include/asm-arm/p2m.h
> > +++ b/xen/include/asm-arm/p2m.h
>
> > +/* Look up a GFN and take a reference count on the backing page. */
> > +typedef unsigned int p2m_query_t;
> > +#define P2M_ALLOC    (1u<<0)   /* Populate PoD and paged-out entries */
> > +#define P2M_UNSHARE  (1u<<1)   /* Break CoW sharing */
>
> Are the a result of something going wrong in a rebase? The comment here
> refers to get_page_from_gfn which you've left behind, so it is out of
> context now.
>
> I don't think your other changes here require any of this to move, do
> they?
>

Ack, these are just artifacts from the previous iteration.


>
> > +    /* Defines if mem_access is in use for the domain to avoid
> uneccessary radix
>
> "unnecessary"
>

Ack.


>
> > +     * lookups. */
> > +    bool_t access_in_use;
>
> > @@ -77,6 +97,7 @@ void p2m_mem_event_emulate_check(struct domain *d,
> >      /* Not supported on ARM. */
> >  };
> >
> > +static inline
> >  void p2m_enable_msr_exit_interception(struct domain *d)
>
> I think this must belong in a previous patch which added this fn?
>
> Ian.
>

Yes and has been since renamed and fixed.

Thanks!
Tamas

[-- Attachment #1.2: Type: text/html, Size: 4078 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling
  2014-09-24 15:05   ` Ian Campbell
@ 2014-09-24 17:04     ` Tamas K Lengyel
  0 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 17:04 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 1079 bytes --]

On Wed, Sep 24, 2014 at 5:05 PM, Ian Campbell <Ian.Campbell@citrix.com>
wrote:

> On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
> > Add missing structure definition for iabt and update the trap handling
> > mechanism to only inject the exception if the mem_access checker
> > decides to do so.
> >
> > Signed-off-by: Tamas K Lengyel <tklengyel@sec.in.tum.de>
>
> Acked-by: Ian Campbell <ian.campbell@citrix.com>
>
> > +        const struct npfec npfec = {
> > +            .insn_fetch = 1,
> > +            .gla_valid = 1,
> > +            .kind = iabt.s1ptw ? npfec_kind_in_gpt : npfec_kind_with_gla
>
> The references to "gla" here are just because the interface has been
> refactored out of x86 into common code, right?
>

Yes, that is correct. On ARM I've seen gvaddr and gva being used as the
lingo, gla refers to the same thing.

Tamas


>
> (if not and this is in fact an arm specific thing then please rename)
>
> Ian.
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
>

[-- Attachment #1.2: Type: text/html, Size: 2032 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling
  2014-09-24 15:41   ` Julien Grall
@ 2014-09-24 17:08     ` Tamas K Lengyel
  0 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 17:08 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Tim Deegan, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 794 bytes --]

On Wed, Sep 24, 2014 at 5:41 PM, Julien Grall <julien.grall@linaro.org>
wrote:

> Hello Tamas,
>
> On 09/23/2014 02:14 PM, Tamas K Lengyel wrote:
> > +        unsigned long s1ptw:1; /* Fault during a stage 1 translation
> table walk */
>
> [..]
>
> > +        unsigned long s1ptw:1; /* Fault during a stage 1 translation
> table walk */
>
> The description is confusing, it gives the impression that this bit is
> used to know if the fault has occurred a stage 1 translation table walk
> or not. I would say: "Stage 2 fault during a stage 1 translation table
> walk".
>
> Regards,
>
> --
> Julien Grall
>

That's a bit too long to fit into 80 chars in that line and I don't want to
line-break for the comment (looks ugly). Maybe shorten it to "Stage 2 fault
during stage 1 translation"?

Tamas

[-- Attachment #1.2: Type: text/html, Size: 1357 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-24 16:51       ` Julien Grall
@ 2014-09-24 17:13         ` Tamas K Lengyel
  2014-09-24 20:52           ` Julien Grall
  0 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 17:13 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Tim Deegan, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 5130 bytes --]

On Wed, Sep 24, 2014 at 6:51 PM, Julien Grall <julien.grall@linaro.org>
wrote:

> Hello Tamas,
>
> On 09/24/2014 05:27 PM, Tamas K Lengyel wrote:
> >     >  /* Put any references on the single 4K page referenced by pte.
> TODO:
> >     > @@ -553,13 +584,22 @@ static int apply_one_level(struct domain *d,
> >     >          if ( p2m_valid(orig_pte) )
> >     >              return P2M_ONE_DESCEND;
> >     >
> >     > -        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size)
> )
> >     > +        if ( is_mapping_aligned(*addr, end_gpaddr, 0, level_size)
> &&
> >     > +           /* We only create superpages when mem_access is not in
> use. */
> >     > +             (level == 3 || (level < 3 && !p2m->access_in_use)) )
> >
> >     Can't this check be moved in is_mapping_aligned? You have nearly the
> >     same few lines below.
> >
> >
> > Unfortunately not, I already checked and it is used in REMOVE as well in
> > which case we would need an exception.. and that wasn't very straight
> > forward.
>
> Ok.
>
> >
> >     [..]
> >
> >     > +    case MEMACCESS:
> >     > +        if ( level < 3 )
> >     > +        {
> >     > +            if ( !p2m_valid(orig_pte) )
> >     > +            {
> >     > +                *addr += level_size;
> >     > +                return P2M_ONE_PROGRESS_NOP;
> >     > +            }
> >     > +
> >     > +            /* Shatter large pages as we descend */
> >     > +            if ( p2m_mapping(orig_pte) )
> >     > +            {
> >     > +                rc = p2m_shatter_page(d, entry, level,
> flush_cache);
> >     > +
> >     > +                if ( rc < 0 )
> >     > +                    return rc;
> >     > +            } /* else: an existing table mapping -> descend */
> >     > +
> >     > +            return P2M_ONE_DESCEND;
> >     > +        }
> >     > +        else
> >     > +        {
> >     > +            pte = orig_pte;
> >     > +
> >     > +            if ( !p2m_table(pte) )
> >     > +                pte.bits = 0;
> >     > +
> >     > +            if ( p2m_valid(pte) )
> >     > +            {
> >     > +                ASSERT(pte.p2m.type != p2m_invalid);
> >
> >     Why the ASSERT? I don't see why we wouldn't want to set permission
> for
> >     this type of page.
> >
> >
> > Not sure, this I copied from p2m_lookup. Can it even happen that
> > something passes p2m_valid() but have a type of p2m_invalid? I think
> > that just signals that something is very wrong.
>
> The ASSERT has been added in p2m_lookup, because p2m_invalid means the
> MFN is wrong. Hence, p2m_invalid is only used for page table.
>
> In your case, you don't need to use the MFN. So, IHMO, this ASSERT is
> not necessary.
>

Ack, will remove it.


>
> >
> >     > +                 && hypercall_preempt_check() )
> >     > +            {
> >     > +                rc = progress;
> >     > +                goto out;
> >
> >     Jumping directly to the label "out" will skip flushing the TLB for
> the
> >     domain. While it wasn't critical until now, partial redo during
> >     insertion/allocation or hypercall preemption only for relinquish, the
> >     guest may use the wrong permission because the TLB hasn't been
> flushed.
> >
> >     At the same time, it looks like you never request to flush for the
> >     MEMACCESS operation (see *flush = true). Does memaccess does a TLB
> flush
> >     somewhere else?
> >
> >
> > Yes, at the end of p2m_set_mem_access once all PTEs are updated
> > successfully. I guess we could flush the TLB as we are progressing as
> > well, it wouldn't hurt.
>
> We should flush the TLB as we are progressing because the guest may
> technically continue to run...
>

Hm, I think the guest is always paused while mem_access is being set via
memop but sure, it can't hurt.


>
> >     [..]
> >
> >     > +bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const
> struct npfec npfec)
> >     > +{
> >     > +    int rc;
> >     > +    bool_t violation;
> >     > +    xenmem_access_t xma;
> >     > +    mem_event_request_t *req;
> >     > +    struct vcpu *v = current;
> >     > +    struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
> >     > +
> >     > +    /* Mem_access is not in use. */
> >     > +    if ( !p2m->access_in_use )
> >     > +        return true;
> >
> >     AFAIU, it's not possible to call this function when mem access is
> not in
> >     use. I would turn this check into an ASSERT.
> >
> >
> > It is possible to call this function when mem_access is not in use and
> > it is called every time there is a permission fault in the second stage
> > translation. This check here just makes sure the function returns as
> > fast as possible when not in use.
>
> Oh right, sorry for the noise.
>
> This case made me also think about another possible issue. Permission
> are checked in raw_copy_{from,to}_guest_helper during virtual address
> translation to a physical address.
>
> As you modified the attribute in the P2M, the copy may failed because of
> the lake of permission.
>

I'm not entire sure what you mean. Can you elaborate?

Thanks,
Tamas


>
> Regards,
>
> --
> Julien Grall
>

[-- Attachment #1.2: Type: text/html, Size: 6999 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support
  2014-09-24 16:58     ` Tamas K Lengyel
@ 2014-09-24 17:14       ` Razvan Cojocaru
  0 siblings, 0 replies; 58+ messages in thread
From: Razvan Cojocaru @ 2014-09-24 17:14 UTC (permalink / raw)
  To: Tamas K Lengyel, Ian Campbell
  Cc: Tim Deegan, Julien Grall, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel

On 09/24/14 19:58, Tamas K Lengyel wrote:
> 
> 
> On Wed, Sep 24, 2014 at 4:40 PM, Ian Campbell <Ian.Campbell@citrix.com
> <mailto:Ian.Campbell@citrix.com>> wrote:
> 
>     On Tue, 2014-09-23 at 15:14 +0200, Tamas K Lengyel wrote:
>     > Add p2m_access_t to struct page_info and add necessary changes for
>     > page table construction routines to pass the default access information.
>     > We store the p2m_access_t info in page_info as the PTE lacks enough
>     > software programmable bits.
> 
>     The last bit of this is now out of date.
> 
> 
> Ack.
>  
> 
> 
>     > diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
>     > index 787e93c..3d69152 100644
>     > --- a/xen/include/asm-arm/domain.h
>     > +++ b/xen/include/asm-arm/domain.h
>     > @@ -17,6 +17,7 @@ struct hvm_domain
>     >  {
>     >      uint64_t              params[HVM_NR_PARAMS];
>     >      struct hvm_iommu      iommu;
>     > +    bool_t                introspection_enabled;
> 
>     I've not found the user of this yet, but is it not somewhat redundant
>     with p2m->access_in_use?
> 
> 
> It's used by mem_event memop for XEN_DOMCTL_MEM_EVENT_OP_ACCESS_DISABLE.
> I just added this one field to the hvm_domain for compat reasons instead
> of abstracting setting that value to 0 and adding an empty inline for
> ARM. This looked like less trouble.

Indeed, that's used (at the moment) to make sure x86 MSR write
interception doesn't get disabled for memory introspection clients. I
guess on ARM it is less useful now, but since hopefully ARM development
of this feature will happen at some point in the future, it would
explain Tamas' choice.


Regards,
Razvan Cojocaru

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

* Re: [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-24 17:13         ` Tamas K Lengyel
@ 2014-09-24 20:52           ` Julien Grall
  2014-09-24 21:24             ` Tamas K Lengyel
  0 siblings, 1 reply; 58+ messages in thread
From: Julien Grall @ 2014-09-24 20:52 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: Ian Campbell, Tim Deegan, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel

Hello Tamas,

On 24/09/2014 18:13, Tamas K Lengyel wrote:
>
>
> On Wed, Sep 24, 2014 at 6:51 PM, Julien Grall <julien.grall@linaro.org
> <mailto:julien.grall@linaro.org>> wrote:
>     >
>     >     > +                 && hypercall_preempt_check() )
>     >     > +            {
>     >     > +                rc = progress;
>     >     > +                goto out;
>     >
>     >     Jumping directly to the label "out" will skip flushing the TLB for the
>     >     domain. While it wasn't critical until now, partial redo during
>     >     insertion/allocation or hypercall preemption only for relinquish, the
>     >     guest may use the wrong permission because the TLB hasn't been flushed.
>     >
>     >     At the same time, it looks like you never request to flush for the
>     >     MEMACCESS operation (see *flush = true). Does memaccess does a TLB flush
>     >     somewhere else?
>     >
>     >
>     > Yes, at the end of p2m_set_mem_access once all PTEs are updated
>     > successfully. I guess we could flush the TLB as we are progressing as
>     > well, it wouldn't hurt.
>
>     We should flush the TLB as we are progressing because the guest may
>     technically continue to run...
>
>
> Hm, I think the guest is always paused while mem_access is being set via
> memop but sure, it can't hurt.

I didn't find any domain pause call neither in the hypervisor nor in 
xen-access.


Unless the pause is done by the hypervisor via the same hypercall, it's 
safer to flush the TLB if it's necessary.

>     This case made me also think about another possible issue. Permission
>     are checked in raw_copy_{from,to}_guest_helper during virtual address
>     translation to a physical address.
>
>     As you modified the attribute in the P2M, the copy may failed because of
>     the lake of permission.
>
>
> I'm not entire sure what you mean. Can you elaborate?

Xen has a bunch of functions raw_copy_{from,to}_guest helpers which copy 
data from/to the guest.

Since XSA-98, Xen checks that the guest has effectively the right to 
read/write (depending of the helpers) a specific mapping before copying 
the data.

If the guest page doesn't have the good right, the helper will fail and 
therefore so do the hypercall.

When memaccess is used, a RAM page may have its permission lower down.
When the helpers are called, the code to check memory access during 
permission violation will never be called... and the guest will receive 
an hypercall failure.

This is not the right behavior, the hypercall should only fail if the 
permissions are effectively wrong after check mem access has been called.

Regards,

-- 
Julien Grall

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

* Re: [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-24 20:52           ` Julien Grall
@ 2014-09-24 21:24             ` Tamas K Lengyel
  2014-09-24 22:07               ` Tamas K Lengyel
  0 siblings, 1 reply; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 21:24 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Tim Deegan, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 3601 bytes --]

On Wed, Sep 24, 2014 at 10:52 PM, Julien Grall <julien.grall@linaro.org>
wrote:

> Hello Tamas,
>
> On 24/09/2014 18:13, Tamas K Lengyel wrote:
>
>>
>>
>> On Wed, Sep 24, 2014 at 6:51 PM, Julien Grall <julien.grall@linaro.org
>> <mailto:julien.grall@linaro.org>> wrote:
>>     >
>>     >     > +                 && hypercall_preempt_check() )
>>     >     > +            {
>>     >     > +                rc = progress;
>>     >     > +                goto out;
>>     >
>>     >     Jumping directly to the label "out" will skip flushing the TLB
>> for the
>>     >     domain. While it wasn't critical until now, partial redo during
>>     >     insertion/allocation or hypercall preemption only for
>> relinquish, the
>>     >     guest may use the wrong permission because the TLB hasn't been
>> flushed.
>>     >
>>     >     At the same time, it looks like you never request to flush for
>> the
>>     >     MEMACCESS operation (see *flush = true). Does memaccess does a
>> TLB flush
>>     >     somewhere else?
>>     >
>>     >
>>     > Yes, at the end of p2m_set_mem_access once all PTEs are updated
>>     > successfully. I guess we could flush the TLB as we are progressing
>> as
>>     > well, it wouldn't hurt.
>>
>>     We should flush the TLB as we are progressing because the guest may
>>     technically continue to run...
>>
>>
>> Hm, I think the guest is always paused while mem_access is being set via
>> memop but sure, it can't hurt.
>>
>
> I didn't find any domain pause call neither in the hypervisor nor in
> xen-access.
>
>
> Unless the pause is done by the hypervisor via the same hypercall, it's
> safer to flush the TLB if it's necessary.
>

Ack, and you are right, I don't know why I thought it was paused.


>
>      This case made me also think about another possible issue. Permission
>>     are checked in raw_copy_{from,to}_guest_helper during virtual address
>>     translation to a physical address.
>>
>>     As you modified the attribute in the P2M, the copy may failed because
>> of
>>     the lake of permission.
>>
>>
>> I'm not entire sure what you mean. Can you elaborate?
>>
>
> Xen has a bunch of functions raw_copy_{from,to}_guest helpers which copy
> data from/to the guest.
>
> Since XSA-98, Xen checks that the guest has effectively the right to
> read/write (depending of the helpers) a specific mapping before copying the
> data.
>

Ah yes I remember seeing that, it's passed through get_page_from_gva and
uses the MMU to do the translation directly.


>
> If the guest page doesn't have the good right, the helper will fail and
> therefore so do the hypercall.
>
> When memaccess is used, a RAM page may have its permission lower down.
> When the helpers are called, the code to check memory access during
> permission violation will never be called... and the guest will receive an
> hypercall failure.
>

> This is not the right behavior, the hypercall should only fail if the
> permissions are effectively wrong after check mem access has been called.
>

Ack, I guess the straight forward solution here would be to forward the
read/write event to the mem_access listener in the inline gvirt_to_maddr
function. For mem_access however I should really include both the gvaddr
and gpaddr values, which means the translation would happen twice, once
with gva_to_ipa (that uses the MMU without the flag-based permission checks
to translate), forward to mem_access, then do the check with the flag-based
permission check again if mem_access is clear. Would that be an acceptable
approach in your opinion?

Tamas


>
> Regards,
>
> --
> Julien Grall
>

[-- Attachment #1.2: Type: text/html, Size: 5414 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events.
  2014-09-24 21:24             ` Tamas K Lengyel
@ 2014-09-24 22:07               ` Tamas K Lengyel
  0 siblings, 0 replies; 58+ messages in thread
From: Tamas K Lengyel @ 2014-09-24 22:07 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Tim Deegan, Ian Jackson, xen-devel,
	Stefano Stabellini, Andres Lagar-Cavilla, Jan Beulich,
	Daniel De Graaf, Tamas K Lengyel


[-- Attachment #1.1: Type: text/plain, Size: 4647 bytes --]

On Wed, Sep 24, 2014 at 11:24 PM, Tamas K Lengyel <
tamas.lengyel@zentific.com> wrote:

>
>
> On Wed, Sep 24, 2014 at 10:52 PM, Julien Grall <julien.grall@linaro.org>
> wrote:
>
>> Hello Tamas,
>>
>> On 24/09/2014 18:13, Tamas K Lengyel wrote:
>>
>>>
>>>
>>> On Wed, Sep 24, 2014 at 6:51 PM, Julien Grall <julien.grall@linaro.org
>>> <mailto:julien.grall@linaro.org>> wrote:
>>>     >
>>>     >     > +                 && hypercall_preempt_check() )
>>>     >     > +            {
>>>     >     > +                rc = progress;
>>>     >     > +                goto out;
>>>     >
>>>     >     Jumping directly to the label "out" will skip flushing the TLB
>>> for the
>>>     >     domain. While it wasn't critical until now, partial redo during
>>>     >     insertion/allocation or hypercall preemption only for
>>> relinquish, the
>>>     >     guest may use the wrong permission because the TLB hasn't been
>>> flushed.
>>>     >
>>>     >     At the same time, it looks like you never request to flush for
>>> the
>>>     >     MEMACCESS operation (see *flush = true). Does memaccess does a
>>> TLB flush
>>>     >     somewhere else?
>>>     >
>>>     >
>>>     > Yes, at the end of p2m_set_mem_access once all PTEs are updated
>>>     > successfully. I guess we could flush the TLB as we are progressing
>>> as
>>>     > well, it wouldn't hurt.
>>>
>>>     We should flush the TLB as we are progressing because the guest may
>>>     technically continue to run...
>>>
>>>
>>> Hm, I think the guest is always paused while mem_access is being set via
>>> memop but sure, it can't hurt.
>>>
>>
>> I didn't find any domain pause call neither in the hypervisor nor in
>> xen-access.
>>
>>
>> Unless the pause is done by the hypervisor via the same hypercall, it's
>> safer to flush the TLB if it's necessary.
>>
>
> Ack, and you are right, I don't know why I thought it was paused.
>
>
>>
>>      This case made me also think about another possible issue. Permission
>>>     are checked in raw_copy_{from,to}_guest_helper during virtual address
>>>     translation to a physical address.
>>>
>>>     As you modified the attribute in the P2M, the copy may failed
>>> because of
>>>     the lake of permission.
>>>
>>>
>>> I'm not entire sure what you mean. Can you elaborate?
>>>
>>
>> Xen has a bunch of functions raw_copy_{from,to}_guest helpers which copy
>> data from/to the guest.
>>
>> Since XSA-98, Xen checks that the guest has effectively the right to
>> read/write (depending of the helpers) a specific mapping before copying the
>> data.
>>
>
> Ah yes I remember seeing that, it's passed through get_page_from_gva and
> uses the MMU to do the translation directly.
>
>
>>
>> If the guest page doesn't have the good right, the helper will fail and
>> therefore so do the hypercall.
>>
>> When memaccess is used, a RAM page may have its permission lower down.
>> When the helpers are called, the code to check memory access during
>> permission violation will never be called... and the guest will receive an
>> hypercall failure.
>>
>
>> This is not the right behavior, the hypercall should only fail if the
>> permissions are effectively wrong after check mem access has been called.
>>
>
> Ack, I guess the straight forward solution here would be to forward the
> read/write event to the mem_access listener in the inline gvirt_to_maddr
> function. For mem_access however I should really include both the gvaddr
> and gpaddr values, which means the translation would happen twice, once
> with gva_to_ipa (that uses the MMU without the flag-based permission checks
> to translate), forward to mem_access, then do the check with the flag-based
> permission check again if mem_access is clear. Would that be an acceptable
> approach in your opinion?
>
>
So since this the hypervisor that's doing the memory access, we can just
fix up the mem_access permissions and forgo sending mem_events. This is
absolutely not the best solution and I would prefer in the future to
include forwarding these events as well, but based on the discussion about
a similar topic recently with Andres and Andrew Cooper (
http://www.gossamer-threads.com/lists/xen/devel/347276) this would be
consistent with how such accesses are handled on x86 as well.

To actually make the mem_access listener decide whether these accesses
should go forward or fail would require some significant more
infrastructure, as regular EPT/ARM memory accesses are automatically
re-tried after the mem_access listener unpauses the domain. Here, no such
luck, we would need to have the hypervisor wait for a reply (maybe with a
time-out limit) before it could go forward.

Tamas

[-- Attachment #1.2: Type: text/html, Size: 6717 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

end of thread, other threads:[~2014-09-24 22:07 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-23 13:14 [PATCH for-4.5 v8 00/19] Mem_event and mem_access for ARM Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 01/19] xen: Relocate mem_access and mem_event into common Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 02/19] xen: Relocate struct npfec definition " Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 03/19] xen: Relocate p2m_access_t into common and swap the order Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 04/19] xen: Relocate p2m_mem_access_resume to mem_access common Tamas K Lengyel
2014-09-23 13:28   ` Jan Beulich
2014-09-23 14:04     ` Tamas K Lengyel
2014-09-23 14:08       ` Jan Beulich
2014-09-23 14:15         ` Tamas K Lengyel
2014-09-23 15:02           ` Jan Beulich
2014-09-23 13:14 ` [PATCH for-4.5 v8 05/19] xen: Relocate set_access_required domctl into common Tamas K Lengyel
2014-09-24 14:18   ` Julien Grall
2014-09-24 15:05     ` Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 06/19] xen: Relocate mem_event_op domctl and access_op memop " Tamas K Lengyel
2014-09-23 13:32   ` Jan Beulich
2014-09-23 14:00     ` Razvan Cojocaru
2014-09-23 14:07       ` Jan Beulich
2014-09-23 14:13         ` Tamas K Lengyel
2014-09-23 14:23           ` Razvan Cojocaru
2014-09-23 14:28             ` Tamas K Lengyel
2014-09-23 14:19         ` Razvan Cojocaru
2014-09-23 14:08       ` Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 07/19] x86/p2m: Typo fix for spelling ambiguous Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 08/19] xen/mem_event: Clean out superfluous white-spaces Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 09/19] xen/mem_event: Relax error condition on debug builds Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 10/19] xen/mem_event: Abstract architecture specific sanity checks Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 11/19] xen/mem_access: Abstract architecture specific sanity check Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 12/19] xen/arm: p2m changes for mem_access support Tamas K Lengyel
2014-09-24 14:40   ` Ian Campbell
2014-09-24 16:58     ` Tamas K Lengyel
2014-09-24 17:14       ` Razvan Cojocaru
2014-09-24 14:43   ` Julien Grall
2014-09-24 16:48     ` Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 13/19] xen/arm: Implement domain_get_maximum_gpfn Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 14/19] xen/arm: Add p2m_set_permission and p2m_shatter_page helpers Tamas K Lengyel
2014-09-24 14:48   ` Julien Grall
2014-09-23 13:14 ` [PATCH for-4.5 v8 15/19] xen/arm: Data abort exception (R/W) mem_events Tamas K Lengyel
2014-09-24 15:02   ` Ian Campbell
2014-09-24 16:17     ` Tamas K Lengyel
2014-09-24 15:35   ` Julien Grall
2014-09-24 16:27     ` Tamas K Lengyel
2014-09-24 16:51       ` Julien Grall
2014-09-24 17:13         ` Tamas K Lengyel
2014-09-24 20:52           ` Julien Grall
2014-09-24 21:24             ` Tamas K Lengyel
2014-09-24 22:07               ` Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 16/19] xen/arm: Instruction prefetch abort (X) mem_event handling Tamas K Lengyel
2014-09-24 15:05   ` Ian Campbell
2014-09-24 17:04     ` Tamas K Lengyel
2014-09-24 15:41   ` Julien Grall
2014-09-24 17:08     ` Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 17/19] xen/arm: Enable the compilation of mem_access and mem_event on ARM Tamas K Lengyel
2014-09-24 15:08   ` Ian Campbell
2014-09-24 15:42   ` Julien Grall
2014-09-23 13:14 ` [PATCH for-4.5 v8 18/19] tools/libxc: Allocate magic page for mem access " Tamas K Lengyel
2014-09-23 13:14 ` [PATCH for-4.5 v8 19/19] tools/tests: Enable xen-access " Tamas K Lengyel
2014-09-24 15:12   ` Ian Campbell
2014-09-24 16:05     ` Tamas K Lengyel

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.