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

[Xen-devel] [PATCH] valgrind: Support for ioctls used by Xen toolstack processes.



Under Xen the toolstack is responsible for managing the domains in
the system, e.g. creating, destroying, and otherwise manipulating
them.

To do this it uses a number of ioctls on the /proc/xen/privcmd
device. Most of these (the MMAPBATCH ones) simply set things up such
that a subsequenct mmap call will map the desired guest memory. Since
valgrind has no way of knowing what the memory contains we assume
that it is all initialised (to do otherwise would require valgrind to
be observing the complete state of the system and not just the given
process).

The most interesting ioctl is XEN_IOCTL_PRIVCMD_HYPERCALL which
allows the toolstack to make arbitrary hypercalls. Although the
mechanism here is specific to the OS of the guest running the
toolstack the hypercalls themselves are defined solely by the
hypervisor. Therefore I have split support for this ioctl into a part
in syswrap-linux.c which handles the ioctl itself and passes things
onto a new syswrap-xen.c which handles the specifics of the
hypercalls themselves. Porting this to another OS should just be a
matter of wiring up syswrap-$OS.c to decode the ioctl and call into
syswrap-xen.c. In the future we may want to split this into
syswrap-$ARCH-xen.c but for now this is x86 only.

The hypercall coverage here is pretty small but is enough to get
reasonable(-ish) results out of the xl toolstack when listing,
creating and destroying domains.

One issue is that the hypercalls which are exlusively used by the
toolstacks (as opposed to those used by guest operating systems) are
not considered a stable ABI, since the hypervisor and the lowlevel
tools are considered a matched pair. This covers the sysctl and
domctl hypercalls which are a fairly large chunk of the support
here. I'm not sure how to solve this without invoking a massive
amount of duplication. Right now this targets the Xen unstable
interface (which will shortly be released as Xen 4.2), perhaps I can
get away with deferring this problem until the first change ;-).

On the plus side the vast majority of hypercalls are not of interest
to the toolstack (they are used by guests) so we can get away without
implementing them.

There are some other wrinkles here I've not been sure how to solve:

Firstly, di_notify_mmap tries to read from the magic proc device:
     --20208-- WARNING: Serious error when reading debug info
     --20208-- When reading debug info from /proc/xen/privcmd:
     --20208-- can't read file to inspect ELF header

I've hacked around this with an explicit check for /proc/xen.
Hopefully someone can point to the right solution.

Secondly, a hypercall only reads as many words from the ioctl arg
struct as there are actual arguments to that hypercall and the
toolstack only initialises the arguments which are used. However
there is no space in the DEFN_PRE_TEMPLATE prototype to allow this to
be communicated from syswrap-xen.c back to syswrap-linux.c. Since a
hypercall can have at most 5 arguments I have hackily stolen ARG8 for
this purpose.
---
 configure.in                           |   19 +
 coregrind/Makefile.am                  |    8 +-
 coregrind/m_debuginfo/debuginfo.c      |    9 +
 coregrind/m_syswrap/priv_syswrap-xen.h |   10 +
 coregrind/m_syswrap/syswrap-linux.c    |  107 ++++-
 coregrind/m_syswrap/syswrap-xen.c      | 1023 ++++++++++++++++++++++++++++++++
 include/Makefile.am                    |    3 +-
 include/pub_tool_vki.h                 |    1 +
 include/vki/vki-linux.h                |   44 ++
 include/vki/vki-xen.h                  |    8 +
 10 files changed, 1229 insertions(+), 3 deletions(-)
 create mode 100644 coregrind/m_syswrap/priv_syswrap-xen.h
 create mode 100644 coregrind/m_syswrap/syswrap-xen.c
 create mode 100644 include/vki/vki-xen.h

diff --git a/configure.in b/configure.in
index b385aed..d94644c 100644
--- a/configure.in
+++ b/configure.in
@@ -2012,6 +2012,25 @@ AC_ARG_WITH(mpicc,
 )
 AC_SUBST(MPI_CC)

+#----------------------------------------------------------------------------
+# Xen checks
+#----------------------------------------------------------------------------
+AC_ARG_ENABLE(xen,
+      [  --enable-xen            Enable support for Xen hypervisor],
+      [vg_cv_xen=$enableval],
+      [vg_cv_xen=no])
+
+AC_ARG_WITH(xen,
+   [  --with-xen=             Specify location of Xen headers],
+   XEN_CFLAGS=-I$withval
+)
+AC_SUBST(XEN_CFLAGS)
+
+AM_CONDITIONAL([ENABLE_XEN], [test x$vg_cv_xen = xyes])
+if test x"$vg_cv_xen" = xyes; then
+    AC_DEFINE([ENABLE_XEN], 1, [configured to support Xen])
+fi
+
 ## We AM_COND_IF here instead of automake "if" in mpi/Makefile.am so that we 
can
 ## use these values in the check for a functioning mpicc.
 ##
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index 01015a7..58a7dce 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -224,6 +224,7 @@ noinst_HEADERS = \
        m_syswrap/priv_syswrap-linux-variants.h \
        m_syswrap/priv_syswrap-darwin.h \
        m_syswrap/priv_syswrap-main.h \
+       m_syswrap/priv_syswrap-xen.h \
        m_ume/priv_ume.h

 #----------------------------------------------------------------------------
@@ -371,6 +372,11 @@ COREGRIND_SOURCES_COMMON = \
        m_ume/main.c \
        m_ume/script.c

+if ENABLE_XEN
+COREGRIND_SOURCES_COMMON += m_syswrap/syswrap-xen.c
+CFLAGS += @XEN_CFLAGS@
+endif
+
 libcoregrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_a_SOURCES = \
     $(COREGRIND_SOURCES_COMMON)
 nodist_libcoregrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_a_SOURCES = \
@@ -378,7 +384,7 @@ nodist_libcoregrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_a_SOURCES 
= \
 libcoregrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_a_CPPFLAGS = \
     $(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
 libcoregrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_a_CFLAGS = \
-    $(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
+    $(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) @XEN_CFLAGS@
 libcoregrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_a_CCASFLAGS = \
     $(AM_CCASFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
 if ENABLE_LINUX_TICKET_LOCK_PRIMARY
diff --git a/coregrind/m_debuginfo/debuginfo.c 
b/coregrind/m_debuginfo/debuginfo.c
index 218547b..b634ce0 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -729,6 +729,15 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int 
use_fd )
    if (!filename)
       return 0;

+   /*
+    * Cannot read from these magic files:
+    * --20208-- WARNING: Serious error when reading debug info
+    * --20208-- When reading debug info from /proc/xen/privcmd:
+    * --20208-- can't read file to inspect ELF header
+    */
+   if (VG_(strncmp)(filename, "/proc/xen/", 10) == 0)
+      return 0;
+
    if (debug)
       VG_(printf)("di_notify_mmap-2: %s\n", filename);

diff --git a/coregrind/m_syswrap/priv_syswrap-xen.h 
b/coregrind/m_syswrap/priv_syswrap-xen.h
new file mode 100644
index 0000000..4dc4748
--- /dev/null
+++ b/coregrind/m_syswrap/priv_syswrap-xen.h
@@ -0,0 +1,10 @@
+#ifndef __PRIV_SYSWRAP_XEN_H
+#define __PRIV_SYSWRAP_XEN_H
+
+DECL_TEMPLATE(xen, hypercall);
+
+#endif   // __PRIV_SYSWRAP_XEN_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-linux.c 
b/coregrind/m_syswrap/syswrap-linux.c
index 2f1155f..22c1842 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -63,7 +63,7 @@
 #include "priv_types_n_macros.h"
 #include "priv_syswrap-generic.h"
 #include "priv_syswrap-linux.h"
-
+#include "priv_syswrap-xen.h"

 // Run a thread from beginning to end and return the thread's
 // scheduler-return-code.
@@ -5527,6 +5527,73 @@ PRE(sys_ioctl)
    case VKI_KVM_RUN:
       break;

+#ifdef ENABLE_XEN
+   case VKI_XEN_IOCTL_PRIVCMD_HYPERCALL: {
+      SyscallArgs harrghs;
+      struct vki_xen_privcmd_hypercall *args =
+         (struct vki_xen_privcmd_hypercall *)(ARG3);
+
+      if (!args)
+         break;
+
+      VG_(memset)(&harrghs, 0, sizeof(harrghs));
+      harrghs.sysno = args->op;
+      harrghs.arg1 = args->arg[0];
+      harrghs.arg2 = args->arg[1];
+      harrghs.arg3 = args->arg[2];
+      harrghs.arg4 = args->arg[3];
+      harrghs.arg5 = args->arg[4];
+      harrghs.arg6 = harrghs.arg7 = harrghs.arg8 = 0;
+
+      WRAPPER_PRE_NAME(xen, hypercall) (tid, layout, &harrghs, status, flags);
+
+      /* HACK. arg8 is used to return the number of hypercall
+       * arguments actually consumed! */
+      PRE_MEM_READ("hypercall", ARG3, sizeof(args->op) +
+                   ( sizeof(args->arg[0]) * harrghs.arg8 ) );
+
+      break;
+   }
+
+   case VKI_XEN_IOCTL_PRIVCMD_MMAP: {
+       struct vki_xen_privcmd_mmap *args =
+           (struct vki_xen_privcmd_mmap *)(ARG3);
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAP",
+                    (Addr)&args->num, sizeof(args->num));
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAP",
+                    (Addr)&args->dom, sizeof(args->dom));
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAP",
+                    (Addr)args->entry, sizeof(*(args->entry)) * args->num);
+      break;
+   }
+   case VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH: {
+       struct vki_xen_privcmd_mmapbatch *args =
+           (struct vki_xen_privcmd_mmapbatch *)(ARG3);
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH",
+                    (Addr)&args->num, sizeof(args->num));
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH",
+                    (Addr)&args->dom, sizeof(args->dom));
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH",
+                    (Addr)&args->addr, sizeof(args->addr));
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH",
+                    (Addr)args->arr, sizeof(*(args->arr)) * args->num);
+      break;
+   }
+   case VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2: {
+       struct vki_xen_privcmd_mmapbatch_v2 *args =
+           (struct vki_xen_privcmd_mmapbatch_v2 *)(ARG3);
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2",
+                    (Addr)&args->num, sizeof(args->num));
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2",
+                    (Addr)&args->dom, sizeof(args->dom));
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2",
+                    (Addr)&args->addr, sizeof(args->addr));
+       PRE_MEM_READ("VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2",
+                    (Addr)args->arr, sizeof(*(args->arr)) * args->num);
+      break;
+   }
+#endif
+
    default:
       /* EVIOC* are variable length and return size written on success */
       switch (ARG2 & ~(_VKI_IOC_SIZEMASK << _VKI_IOC_SIZESHIFT)) {
@@ -6524,6 +6591,44 @@ POST(sys_ioctl)
    case VKI_KVM_S390_INITIAL_RESET:
       break;

+#ifdef ENABLE_XEN
+   case VKI_XEN_IOCTL_PRIVCMD_HYPERCALL: {
+      SyscallArgs harrghs;
+      struct vki_xen_privcmd_hypercall *args =
+         (struct vki_xen_privcmd_hypercall *)(ARG3);
+
+      if (!args)
+         break;
+
+      VG_(memset)(&harrghs, 0, sizeof(harrghs));
+      harrghs.sysno = args->op;
+      harrghs.arg1 = args->arg[0];
+      harrghs.arg2 = args->arg[1];
+      harrghs.arg3 = args->arg[2];
+      harrghs.arg4 = args->arg[3];
+      harrghs.arg5 = args->arg[4];
+      harrghs.arg6 = harrghs.arg7 = harrghs.arg8 = 0;
+
+      WRAPPER_POST_NAME(xen, hypercall) (tid, &harrghs, status);
+      break;
+   };
+
+   case VKI_XEN_IOCTL_PRIVCMD_MMAP:
+      break;
+   case VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH: {
+       struct vki_xen_privcmd_mmapbatch *args =
+           (struct vki_xen_privcmd_mmapbatch *)(ARG3);
+       POST_MEM_WRITE((Addr)args->arr, sizeof(*(args->arr)) * args->num);
+      }
+      break;
+   case VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2: {
+       struct vki_xen_privcmd_mmapbatch_v2 *args =
+           (struct vki_xen_privcmd_mmapbatch_v2 *)(ARG3);
+       POST_MEM_WRITE((Addr)args->err, sizeof(*(args->err)) * args->num);
+      }
+      break;
+#endif
+
    default:
       /* EVIOC* are variable length and return size written on success */
       switch (ARG2 & ~(_VKI_IOC_SIZEMASK << _VKI_IOC_SIZESHIFT)) {
diff --git a/coregrind/m_syswrap/syswrap-xen.c 
b/coregrind/m_syswrap/syswrap-xen.c
new file mode 100644
index 0000000..00192bf
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-xen.c
@@ -0,0 +1,1023 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Xen Hypercalls                                 syswrap-xen.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2012 Citrix Systems
+      ian.campbell@xxxxxxxxxx
+
+   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.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_libcsetjmp.h"   // to keep _threadstate.h happy
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_debuginfo.h"    // VG_(di_notify_*)
+#include "pub_core_transtab.h"     // VG_(discard_translations)
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_libcsignal.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_options.h"
+#include "pub_core_scheduler.h"
+#include "pub_core_signals.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_stacktrace.h"    // For VG_(get_and_pp_StackTrace)()
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h"
+#include "priv_syswrap-xen.h"
+
+#include <stdint.h>
+
+#define __XEN_TOOLS__
+
+#include <xen/xen.h>
+#include <xen/sysctl.h>
+#include <xen/domctl.h>
+#include <xen/memory.h>
+#include <xen/event_channel.h>
+#include <xen/version.h>
+
+#include <xen/hvm/hvm_op.h>
+
+#define PRE(name) static DEFN_PRE_TEMPLATE(xen, name)
+#define POST(name) static DEFN_POST_TEMPLATE(xen, name)
+
+static void bad_subop ( ThreadId              tid,
+                        SyscallArgLayout*     layout,
+                        /*MOD*/SyscallArgs*   args,
+                        /*OUT*/SyscallStatus* status,
+                        /*OUT*/UWord*         flags,
+                        const char*           hypercall,
+                        UWord                 subop)
+{
+   VG_(dmsg)("WARNING: unhandled %s subop: %ld\n",
+             hypercall, subop);
+   if (VG_(clo_verbosity) > 1) {
+      VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
+   }
+   VG_(dmsg)("You may be able to write your own handler.\n");
+   VG_(dmsg)("Read the file README_MISSING_SYSCALL_OR_IOCTL.\n");
+   VG_(dmsg)("Nevertheless we consider this a bug.  Please report\n");
+   VG_(dmsg)("it at http://valgrind.org/support/bug_reports.html &\n");
+   VG_(dmsg)("http://wiki.xen.org/wiki/Reporting_Bugs_against_Xen.\n";);
+
+   SET_STATUS_Failure(VKI_ENOSYS);
+}
+
+PRE(memory_op)
+{
+   PRINT("__HYPERVISOR_memory_op ( %ld, %lx )", ARG1, ARG2);
+
+   switch (ARG1) {
+   case XENMEM_set_memory_map: {
+      xen_foreign_memory_map_t *arg =
+         (xen_foreign_memory_map_t *)(unsigned int)ARG2;
+      PRE_MEM_READ("XENMEM_set_memory_map",
+                   (Addr)&arg->domid, sizeof(arg->domid));
+      PRE_MEM_READ("XENMEM_set_memory_map",
+                   (Addr)&arg->map, sizeof(arg->map));
+      break;
+   }
+   case XENMEM_increase_reservation:
+   case XENMEM_decrease_reservation:
+   case XENMEM_populate_physmap: {
+      struct xen_memory_reservation *memory_reservation =
+         (struct xen_memory_reservation *)(unsigned int)ARG2;
+      char *which;
+
+      switch (ARG1) {
+      case XENMEM_increase_reservation:
+         which = "XENMEM_increase_reservation";
+         break;
+      case XENMEM_decrease_reservation:
+         which = "XENMEM_decrease_reservation";
+         PRE_MEM_READ(which,
+                      (Addr)memory_reservation->extent_start.p,
+                      sizeof(xen_pfn_t) * memory_reservation->nr_extents);
+      case XENMEM_populate_physmap:
+         which = "XENMEM_populate_physmap";
+         PRE_MEM_READ(which,
+                      (Addr)memory_reservation->extent_start.p,
+                      sizeof(xen_pfn_t) * memory_reservation->nr_extents);
+         break;
+      default:
+         which = "XENMEM_unknown";
+         break;
+      }
+
+      PRE_MEM_READ(which,
+                   (Addr)&memory_reservation->extent_start,
+                   sizeof(memory_reservation->extent_start));
+      PRE_MEM_READ(which,
+                   (Addr)&memory_reservation->nr_extents,
+                   sizeof(memory_reservation->nr_extents));
+      PRE_MEM_READ(which,
+                   (Addr)&memory_reservation->extent_order,
+                   sizeof(memory_reservation->extent_order));
+      PRE_MEM_READ(which,
+                   (Addr)&memory_reservation->mem_flags,
+                   sizeof(memory_reservation->mem_flags));
+      PRE_MEM_READ(which,
+                   (Addr)&memory_reservation->domid,
+                   sizeof(memory_reservation->domid));
+      break;
+   }
+
+   default:
+      bad_subop(tid, layout, arrghs, status, flags,
+                "__HYPERVISOR_memory_op", ARG1);
+      break;
+   }
+}
+
+PRE(mmuext_op)
+{
+   mmuext_op_t *ops = (void *)(unsigned int)ARG1;
+   unsigned int i, nr = ARG2;
+
+
+   for (i=0; i<nr; i++) {
+      mmuext_op_t *op = ops + i;
+      PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP",
+                   (Addr)&op->cmd, sizeof(op->cmd));
+      switch(op->cmd) {
+      case MMUEXT_PIN_L1_TABLE:
+      case MMUEXT_PIN_L2_TABLE:
+      case MMUEXT_PIN_L3_TABLE:
+      case MMUEXT_PIN_L4_TABLE:
+      case MMUEXT_UNPIN_TABLE:
+      case MMUEXT_NEW_BASEPTR:
+      case MMUEXT_CLEAR_PAGE:
+      case MMUEXT_COPY_PAGE:
+      case MMUEXT_MARK_SUPER:
+      case MMUEXT_UNMARK_SUPER:
+         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg1.mfn",
+                      (Addr)&op->arg1.mfn,
+                      sizeof(op->arg1.mfn));
+         break;
+
+      case MMUEXT_INVLPG_LOCAL:
+      case MMUEXT_INVLPG_ALL:
+      case MMUEXT_SET_LDT:
+         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg1.mfn",
+                      (Addr)&op->arg1.linear_addr,
+                      sizeof(op->arg1.linear_addr));
+         break;
+
+      case MMUEXT_TLB_FLUSH_LOCAL:
+      case MMUEXT_TLB_FLUSH_MULTI:
+      case MMUEXT_INVLPG_MULTI:
+      case MMUEXT_TLB_FLUSH_ALL:
+      case MMUEXT_FLUSH_CACHE:
+      case MMUEXT_NEW_USER_BASEPTR:
+      case MMUEXT_FLUSH_CACHE_GLOBAL:
+         /* None */
+         break;
+      }
+
+      switch(op->cmd) {
+      case MMUEXT_SET_LDT:
+         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg2.nr_ents",
+                      (Addr)&op->arg2.nr_ents,
+                      sizeof(op->arg2.nr_ents));
+         break;
+
+      case MMUEXT_TLB_FLUSH_MULTI:
+      case MMUEXT_INVLPG_MULTI:
+         /* How many??? */
+         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg2.vcpumask",
+                      (Addr)&op->arg2.vcpumask,
+                      sizeof(op->arg2.vcpumask));
+         break;
+
+      case MMUEXT_COPY_PAGE:
+         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg2.src_mfn",
+                      (Addr)&op->arg2.src_mfn,
+                      sizeof(op->arg2.src_mfn));
+         break;
+
+      case MMUEXT_PIN_L1_TABLE:
+      case MMUEXT_PIN_L2_TABLE:
+      case MMUEXT_PIN_L3_TABLE:
+      case MMUEXT_PIN_L4_TABLE:
+      case MMUEXT_UNPIN_TABLE:
+      case MMUEXT_NEW_BASEPTR:
+      case MMUEXT_TLB_FLUSH_LOCAL:
+      case MMUEXT_INVLPG_LOCAL:
+      case MMUEXT_TLB_FLUSH_ALL:
+      case MMUEXT_INVLPG_ALL:
+      case MMUEXT_FLUSH_CACHE:
+      case MMUEXT_NEW_USER_BASEPTR:
+      case MMUEXT_CLEAR_PAGE:
+      case MMUEXT_FLUSH_CACHE_GLOBAL:
+      case MMUEXT_MARK_SUPER:
+      case MMUEXT_UNMARK_SUPER:
+         /* None */
+         break;
+      }
+   }
+}
+
+static void pre_evtchn_op(ThreadId tid,
+                          SyscallArgLayout*     layout,
+                          /*MOD*/SyscallArgs*   arrghs,
+                          /*OUT*/SyscallStatus* status,
+                          /*OUT*/UWord*         flags,
+                          __vki_u32 cmd, void *arg, int compat)
+{
+   PRINT("__HYPERVISOR_event_channel_op%s ( %d, %p )",
+         compat ? "_compat" : "", cmd, arg);
+
+   switch (cmd) {
+   case EVTCHNOP_alloc_unbound: {
+      struct evtchn_alloc_unbound *alloc_unbound = arg;
+      PRE_MEM_READ("EVTCHNOP_alloc_unbound",
+                   (Addr)&alloc_unbound->dom, sizeof(alloc_unbound->dom));
+      PRE_MEM_READ("EVTCHNOP_alloc_unbound",
+                   (Addr)&alloc_unbound->remote_dom,
+                   sizeof(alloc_unbound->remote_dom));
+      break;
+   }
+   default:
+      if ( compat )
+         bad_subop(tid, layout, arrghs, status, flags,
+                   "__HYPERVISOR_event_channel_op_compat", cmd);
+      else
+         bad_subop(tid, layout, arrghs, status, flags,
+                   "__HYPERVISOR_event_channel_op", cmd);
+      break;
+   }
+}
+
+PRE(evtchn_op)
+{
+   pre_evtchn_op(tid, layout, arrghs, status, flags,
+                 ARG1, (void *)(unsigned int)ARG2, 0);
+}
+
+PRE(evtchn_op_compat)
+{
+   struct evtchn_op *evtchn = (struct evtchn_op *)(unsigned int)ARG1;
+   PRE_MEM_READ("__HYPERVISOR_event_channel_op_compat",
+                ARG1, sizeof(*evtchn));
+
+   pre_evtchn_op(tid, layout, arrghs, status, flags,
+                 evtchn->cmd, &evtchn->u, 1);
+}
+
+PRE(xen_version)
+{
+   PRINT("__HYPERVISOR_xen_version ( %ld, %lx )", ARG1, ARG2);
+
+   switch (ARG1) {
+   case XENVER_version:
+   case XENVER_extraversion:
+   case XENVER_compile_info:
+   case XENVER_capabilities:
+   case XENVER_changeset:
+   case XENVER_platform_parameters:
+   case XENVER_get_features:
+   case XENVER_pagesize:
+   case XENVER_guest_handle:
+   case XENVER_commandline:
+      /* No inputs */
+      break;
+
+   default:
+      bad_subop(tid, layout, arrghs, status, flags,
+                "__HYPERVISOR_xen_version", ARG1);
+      break;
+   }
+}
+
+PRE(grant_table_op)
+{
+   PRINT("__HYPERVISOR_grant_table_op ( %ld, 0x%lx, %ld )", ARG1, ARG2, ARG3);
+   switch (ARG1) {
+   case GNTTABOP_setup_table: {
+      struct gnttab_setup_table *gst = (void *)(intptr_t)ARG2;
+      PRE_MEM_READ("GNTTABOP_setup_table", (Addr)&gst->dom, sizeof(gst->dom));
+      PRE_MEM_READ("GNTTABOP_setup_table",
+                   (Addr)&gst->nr_frames, sizeof(gst->nr_frames));
+      break;
+   }
+   default:
+      bad_subop(tid, layout, arrghs, status, flags,
+                "__HYPERVISOR_grant_table_op", ARG1);
+      break;
+   }
+}
+
+PRE(sysctl) {
+   struct xen_sysctl *sysctl = (struct xen_sysctl *)(unsigned int)ARG1;
+
+   PRINT("__HYPERVISOR_sysctl ( %d )", sysctl->cmd);
+
+   /*
+    * Common part of xen_sysctl:
+    *    uint32_t cmd;
+    *    uint32_t interface_version;
+    */
+   PRE_MEM_READ("__HYPERVISOR_sysctl", ARG1,
+                sizeof(uint32_t) + sizeof(uint32_t));
+
+   if (!sysctl || sysctl->interface_version != XEN_SYSCTL_INTERFACE_VERSION)
+      /* BUG ? */
+      return;
+
+#define __PRE_XEN_SYSCTL_READ(_sysctl, _union, _field)  \
+      PRE_MEM_READ("XEN_SYSCTL_" # _sysctl,             \
+                   (Addr)&sysctl->u._union._field,      \
+                   sizeof(sysctl->u._union._field))
+#define PRE_XEN_SYSCTL_READ(_sysctl, _field) \
+      __PRE_XEN_SYSCTL_READ(_sysctl, _sysctl, _field)
+
+   switch (sysctl->cmd) {
+   case XEN_SYSCTL_getdomaininfolist:
+      PRE_XEN_SYSCTL_READ(getdomaininfolist, first_domain);
+      PRE_XEN_SYSCTL_READ(getdomaininfolist, max_domains);
+      PRE_XEN_SYSCTL_READ(getdomaininfolist, buffer);
+      break;
+
+   case XEN_SYSCTL_cpupool_op:
+      PRE_XEN_SYSCTL_READ(cpupool_op, op);
+
+      switch(sysctl->u.cpupool_op.op) {
+      case XEN_SYSCTL_CPUPOOL_OP_CREATE:
+      case XEN_SYSCTL_CPUPOOL_OP_DESTROY:
+      case XEN_SYSCTL_CPUPOOL_OP_INFO:
+      case XEN_SYSCTL_CPUPOOL_OP_ADDCPU:
+      case XEN_SYSCTL_CPUPOOL_OP_RMCPU:
+      case XEN_SYSCTL_CPUPOOL_OP_MOVEDOMAIN:
+         PRE_XEN_SYSCTL_READ(cpupool_op, cpupool_id);
+      }
+
+      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_CREATE)
+         PRE_XEN_SYSCTL_READ(cpupool_op, sched_id);
+
+      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_MOVEDOMAIN)
+         PRE_XEN_SYSCTL_READ(cpupool_op, domid);
+
+      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_ADDCPU ||
+          sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_RMCPU)
+         PRE_XEN_SYSCTL_READ(cpupool_op, cpu);
+
+      break;
+
+   case XEN_SYSCTL_physinfo:
+      /* No input params */
+      break;
+
+   case XEN_SYSCTL_topologyinfo:
+      PRE_XEN_SYSCTL_READ(topologyinfo, max_cpu_index);
+      PRE_XEN_SYSCTL_READ(topologyinfo, cpu_to_core);
+      PRE_XEN_SYSCTL_READ(topologyinfo, cpu_to_socket);
+      PRE_XEN_SYSCTL_READ(topologyinfo, cpu_to_node);
+      break;
+
+   case XEN_SYSCTL_numainfo:
+      PRE_XEN_SYSCTL_READ(numainfo, max_node_index);
+      PRE_XEN_SYSCTL_READ(numainfo, node_to_memsize);
+      PRE_XEN_SYSCTL_READ(numainfo, node_to_memfree);
+      PRE_XEN_SYSCTL_READ(numainfo, node_to_node_distance);
+      break;
+
+   default:
+      bad_subop(tid, layout, arrghs, status, flags,
+                "__HYPERVISOR_sysctl", sysctl->cmd);
+      break;
+   }
+#undef PRE_XEN_SYSCTL_READ
+#undef __PRE_XEN_SYSCTL_READ
+}
+
+PRE(domctl)
+{
+   struct xen_domctl *domctl = (struct xen_domctl *)(unsigned int)ARG1;
+
+   PRINT("__HYPERVISOR_domctl ( %d ) on dom%d", domctl->cmd, domctl->domain);
+
+   /*
+    * Common part of xen_domctl:
+    *    uint32_t cmd;
+    *    uint32_t interface_version;
+    *    domid_t  domain;
+    */
+   PRE_MEM_READ("__HYPERVISOR_domctl", ARG1,
+                sizeof(uint32_t) + sizeof(uint32_t) + sizeof(domid_t));
+
+   if (!domctl || domctl->interface_version != XEN_DOMCTL_INTERFACE_VERSION)
+      /* BUG ? */
+      return;
+
+#define __PRE_XEN_DOMCTL_READ(_domctl, _union, _field)  \
+      PRE_MEM_READ("XEN_DOMCTL_" # _domctl,             \
+                   (Addr)&domctl->u._union._field,      \
+                   sizeof(domctl->u._union._field))
+#define PRE_XEN_DOMCTL_READ(_domctl, _field) \
+      __PRE_XEN_DOMCTL_READ(_domctl, _domctl, _field)
+
+   switch (domctl->cmd) {
+   case XEN_DOMCTL_destroydomain:
+   case XEN_DOMCTL_pausedomain:
+   case XEN_DOMCTL_max_vcpus:
+   case XEN_DOMCTL_get_address_size:
+   case XEN_DOMCTL_gettscinfo:
+   case XEN_DOMCTL_getdomaininfo:
+   case XEN_DOMCTL_unpausedomain:
+      /* No input fields. */
+      break;
+
+   case XEN_DOMCTL_createdomain:
+      PRE_XEN_DOMCTL_READ(createdomain, ssidref);
+      PRE_XEN_DOMCTL_READ(createdomain, handle);
+      PRE_XEN_DOMCTL_READ(createdomain, flags);
+      break;
+
+   case XEN_DOMCTL_max_mem:
+      PRE_XEN_DOMCTL_READ(max_mem, max_memkb);
+      break;
+
+   case XEN_DOMCTL_set_address_size:
+      __PRE_XEN_DOMCTL_READ(set_address_size, address_size, size);
+      break;
+
+   case XEN_DOMCTL_settscinfo:
+      __PRE_XEN_DOMCTL_READ(settscinfo, tsc_info, info.tsc_mode);
+      __PRE_XEN_DOMCTL_READ(settscinfo, tsc_info, info.gtsc_khz);
+      __PRE_XEN_DOMCTL_READ(settscinfo, tsc_info, info.incarnation);
+      __PRE_XEN_DOMCTL_READ(settscinfo, tsc_info, info.elapsed_nsec);
+      break;
+
+   case XEN_DOMCTL_hypercall_init:
+      PRE_XEN_DOMCTL_READ(hypercall_init, gmfn);
+      break;
+
+   case XEN_DOMCTL_getvcpuinfo:
+      PRE_XEN_DOMCTL_READ(getvcpuinfo, vcpu);
+      break;
+
+   case XEN_DOMCTL_scheduler_op:
+      PRE_XEN_DOMCTL_READ(scheduler_op, sched_id);
+      PRE_XEN_DOMCTL_READ(scheduler_op, cmd);
+      if ( domctl->u.scheduler_op.cmd == XEN_DOMCTL_SCHEDOP_putinfo ) {
+         switch(domctl->u.scheduler_op.sched_id) {
+         case XEN_SCHEDULER_SEDF:
+            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.period);
+            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.slice);
+            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.latency);
+            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.extratime);
+            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.weight);
+            break;
+         case XEN_SCHEDULER_CREDIT:
+            PRE_XEN_DOMCTL_READ(scheduler_op, u.credit.weight);
+            PRE_XEN_DOMCTL_READ(scheduler_op, u.credit.cap);
+            break;
+         case XEN_SCHEDULER_CREDIT2:
+            PRE_XEN_DOMCTL_READ(scheduler_op, u.credit2.weight);
+            break;
+         case XEN_SCHEDULER_ARINC653:
+            break;
+         }
+      }
+      break;
+
+   case XEN_DOMCTL_getvcpuaffinity:
+      __PRE_XEN_DOMCTL_READ(getvcpuaffinity, vcpuaffinity, vcpu);
+      break;
+
+   case XEN_DOMCTL_setvcpuaffinity:
+      __PRE_XEN_DOMCTL_READ(setvcpuaffinity, vcpuaffinity, vcpu);
+      PRE_MEM_READ("XEN_DOMCTL_setvcpuaffinity",
+                   (Addr)domctl->u.vcpuaffinity.cpumap.bitmap.p,
+                   domctl->u.vcpuaffinity.cpumap.nr_cpus / 8);
+      break;
+
+   case XEN_DOMCTL_getvcpucontext:
+      __PRE_XEN_DOMCTL_READ(getvcpucontext, vcpucontext, vcpu);
+      break;
+
+   case XEN_DOMCTL_setvcpucontext:
+      __PRE_XEN_DOMCTL_READ(setvcpucontext, vcpucontext, vcpu);
+      __PRE_XEN_DOMCTL_READ(setvcpucontext, vcpucontext, ctxt.p);
+      break;
+
+   case XEN_DOMCTL_set_cpuid:
+      PRE_MEM_READ("XEN_DOMCTL_set_cpuid",
+                   (Addr)&domctl->u.cpuid, sizeof(domctl->u.cpuid));
+      break;
+
+   case XEN_DOMCTL_getvcpuextstate:
+      __PRE_XEN_DOMCTL_READ(getvcpuextstate, vcpuextstate, vcpu);
+      __PRE_XEN_DOMCTL_READ(getvcpuextstate, vcpuextstate, xfeature_mask);
+      __PRE_XEN_DOMCTL_READ(getvcpuextstate, vcpuextstate, size);
+      __PRE_XEN_DOMCTL_READ(getvcpuextstate, vcpuextstate, buffer);
+      break;
+
+   default:
+      bad_subop(tid, layout, arrghs, status, flags,
+                "__HYPERVISOR_domctl", domctl->cmd);
+      break;
+   }
+#undef PRE_XEN_DOMCTL_READ
+#undef __PRE_XEN_DOMCTL_READ
+}
+
+PRE(hvm_op)
+{
+   unsigned long op = ARG1;
+   void *arg = (void *)(unsigned long)ARG2;
+
+   PRINT("__HYPERVISOR_hvm_op ( %ld, %p )", op, arg);
+
+#define __PRE_XEN_HVMOP_READ(_hvm_op, _type, _field)    \
+   PRE_MEM_READ("XEN_HVMOP_" # _hvm_op,                 \
+                (Addr)&((_type*)arg)->_field,           \
+                sizeof(((_type*)arg)->_field))
+#define PRE_XEN_HVMOP_READ(_hvm_op, _field)                             \
+   __PRE_XEN_HVMOP_READ(_hvm_op, "xen_hvm_" # _hvm_op "_t", _field)
+
+   switch (op) {
+   case HVMOP_set_param:
+      __PRE_XEN_HVMOP_READ(set_param, xen_hvm_param_t, domid);
+      __PRE_XEN_HVMOP_READ(set_param, xen_hvm_param_t, index);
+      __PRE_XEN_HVMOP_READ(set_param, xen_hvm_param_t, value);
+      break;
+
+   case HVMOP_get_param:
+      __PRE_XEN_HVMOP_READ(get_param, xen_hvm_param_t, domid);
+      __PRE_XEN_HVMOP_READ(get_param, xen_hvm_param_t, index);
+      break;
+
+   default:
+      bad_subop(tid, layout, arrghs, status, flags,
+                "__HYPERVISOR_hvm_op", op);
+      break;
+   }
+#undef __PRE_XEN_HVMOP_READ
+#undef PRE_XEN_HVMOP_READ
+}
+
+POST(memory_op)
+{
+   switch (ARG1) {
+   case XENMEM_set_memory_map:
+   case XENMEM_decrease_reservation:
+      /* No outputs */
+      break;
+   case XENMEM_increase_reservation:
+   case XENMEM_populate_physmap: {
+      struct xen_memory_reservation *memory_reservation =
+         (struct xen_memory_reservation *)(unsigned int)ARG2;
+
+      POST_MEM_WRITE((Addr)memory_reservation->extent_start.p,
+                     sizeof(xen_pfn_t) * memory_reservation->nr_extents);
+      break;
+   }
+   }
+}
+
+POST(mmuext_op)
+{
+   unsigned int *pdone = (void *)(unsigned int)ARG3;
+   /* simplistic */
+   POST_MEM_WRITE((Addr)pdone, sizeof(*pdone));
+}
+
+static void post_evtchn_op(ThreadId tid, __vki_u32 cmd, void *arg, int compat)
+{
+   switch (cmd) {
+   case EVTCHNOP_alloc_unbound: {
+      struct evtchn_alloc_unbound *alloc_unbound = arg;
+      POST_MEM_WRITE((Addr)&alloc_unbound->port, sizeof(alloc_unbound->port));
+      break;
+   }
+   }
+}
+
+POST(evtchn_op)
+{
+   post_evtchn_op(tid, ARG1, (void *)(unsigned int)ARG2, 0);
+}
+
+POST(evtchn_op_compat)
+{
+   struct evtchn_op *evtchn = (struct evtchn_op *)(unsigned int)ARG1;
+   post_evtchn_op(tid, evtchn->cmd, &evtchn->u, 1);
+}
+
+POST(xen_version)
+{
+   switch (ARG1) {
+   case XENVER_version:
+      /* No outputs */
+      break;
+   case XENVER_extraversion:
+      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_extraversion_t));
+      break;
+   case XENVER_compile_info:
+      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_compile_info_t));
+      break;
+   case XENVER_capabilities:
+      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_capabilities_info_t));
+      break;
+   case XENVER_changeset:
+      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_changeset_info_t));
+      break;
+   case XENVER_platform_parameters:
+      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_platform_parameters_t));
+      break;
+   case XENVER_get_features:
+      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_feature_info_t));
+      break;
+   case XENVER_pagesize:
+      /* No outputs */
+      break;
+   case XENVER_guest_handle:
+      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_domain_handle_t));
+      break;
+   case XENVER_commandline:
+      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_commandline_t));
+      break;
+   }
+}
+
+POST(grant_table_op)
+{
+   switch (ARG1) {
+   case GNTTABOP_setup_table: {
+      struct gnttab_setup_table *gst = (void *)(uintptr_t)ARG2;
+      PRE_MEM_WRITE("GNTTABOP_setup_table",
+                    (Addr)&gst->status, sizeof(gst->status));
+      PRE_MEM_WRITE("GNTTABOP_setup_table",
+                    (Addr)gst->frame_list.p,
+                    sizeof(*gst->frame_list.p) & gst->nr_frames);
+      break;
+   }
+   }
+}
+
+POST(sysctl)
+{
+   struct xen_sysctl *sysctl = (struct xen_sysctl *)(unsigned int)ARG1;
+
+   if (!sysctl || sysctl->interface_version != XEN_SYSCTL_INTERFACE_VERSION)
+      return;
+
+#define __POST_XEN_SYSCTL_WRITE(_sysctl, _union, _field)        \
+      POST_MEM_WRITE((Addr)&sysctl->u._union._field,            \
+                     sizeof(sysctl->u._union._field))
+#define POST_XEN_SYSCTL_WRITE(_sysctl, _field) \
+      __POST_XEN_SYSCTL_WRITE(_sysctl, _sysctl, _field)
+
+   switch (sysctl->cmd) {
+   case XEN_SYSCTL_getdomaininfolist:
+      POST_XEN_SYSCTL_WRITE(getdomaininfolist, num_domains);
+      POST_MEM_WRITE((Addr)sysctl->u.getdomaininfolist.buffer.p,
+                     sizeof(xen_domctl_getdomaininfo_t)
+                     * sysctl->u.getdomaininfolist.num_domains);
+      break;
+
+   case XEN_SYSCTL_cpupool_op:
+      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_CREATE ||
+          sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_INFO)
+         POST_XEN_SYSCTL_WRITE(cpupool_op, cpupool_id);
+      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_INFO) {
+         POST_XEN_SYSCTL_WRITE(cpupool_op, sched_id);
+         POST_XEN_SYSCTL_WRITE(cpupool_op, n_dom);
+      }
+      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_INFO ||
+          sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_FREEINFO)
+         POST_XEN_SYSCTL_WRITE(cpupool_op, cpumap);
+      break;
+
+   case XEN_SYSCTL_physinfo:
+      POST_XEN_SYSCTL_WRITE(physinfo, threads_per_core);
+      POST_XEN_SYSCTL_WRITE(physinfo, cores_per_socket);
+      POST_XEN_SYSCTL_WRITE(physinfo, nr_cpus);
+      POST_XEN_SYSCTL_WRITE(physinfo, max_cpu_id);
+      POST_XEN_SYSCTL_WRITE(physinfo, nr_nodes);
+      POST_XEN_SYSCTL_WRITE(physinfo, max_node_id);
+      POST_XEN_SYSCTL_WRITE(physinfo, cpu_khz);
+      POST_XEN_SYSCTL_WRITE(physinfo, total_pages);
+      POST_XEN_SYSCTL_WRITE(physinfo, free_pages);
+      POST_XEN_SYSCTL_WRITE(physinfo, scrub_pages);
+      POST_XEN_SYSCTL_WRITE(physinfo, hw_cap[8]);
+      POST_XEN_SYSCTL_WRITE(physinfo, capabilities);
+      break;
+
+   case XEN_SYSCTL_topologyinfo:
+      POST_XEN_SYSCTL_WRITE(topologyinfo, max_cpu_index);
+      POST_MEM_WRITE((Addr)sysctl->u.topologyinfo.cpu_to_core.p,
+                     sizeof(uint32_t) * sysctl->u.topologyinfo.max_cpu_index);
+      POST_MEM_WRITE((Addr)sysctl->u.topologyinfo.cpu_to_socket.p,
+                     sizeof(uint32_t) * sysctl->u.topologyinfo.max_cpu_index);
+      POST_MEM_WRITE((Addr)sysctl->u.topologyinfo.cpu_to_node.p,
+                     sizeof(uint32_t) * sysctl->u.topologyinfo.max_cpu_index);
+      break;
+
+   case XEN_SYSCTL_numainfo:
+      POST_XEN_SYSCTL_WRITE(numainfo, max_node_index);
+      POST_MEM_WRITE((Addr)sysctl->u.numainfo.node_to_memsize.p,
+                     sizeof(uint64_t) * sysctl->u.numainfo.max_node_index);
+      POST_MEM_WRITE((Addr)sysctl->u.numainfo.node_to_memfree.p,
+                     sizeof(uint64_t) * sysctl->u.numainfo.max_node_index);
+      POST_MEM_WRITE((Addr)sysctl->u.numainfo.node_to_node_distance.p,
+                     sizeof(uint32_t) * sysctl->u.numainfo.max_node_index);
+   }
+#undef POST_XEN_SYSCTL_WRITE
+#undef __POST_XEN_SYSCTL_WRITE
+}
+
+POST(domctl){
+   struct xen_domctl *domctl = (struct xen_domctl *)(unsigned int)ARG1;
+
+   if (!domctl || domctl->interface_version != XEN_DOMCTL_INTERFACE_VERSION)
+      return;
+
+#define __POST_XEN_DOMCTL_WRITE(_domctl, _union, _field)        \
+   POST_MEM_WRITE((Addr)&domctl->u._union._field,               \
+                  sizeof(domctl->u._union._field));
+#define POST_XEN_DOMCTL_WRITE(_domctl, _field)          \
+   __POST_XEN_DOMCTL_WRITE(_domctl, _domctl, _field)
+
+   switch (domctl->cmd) {
+   case XEN_DOMCTL_createdomain:
+   case XEN_DOMCTL_destroydomain:
+   case XEN_DOMCTL_pausedomain:
+   case XEN_DOMCTL_max_mem:
+   case XEN_DOMCTL_set_address_size:
+   case XEN_DOMCTL_settscinfo:
+   case XEN_DOMCTL_hypercall_init:
+   case XEN_DOMCTL_setvcpuaffinity:
+   case XEN_DOMCTL_setvcpucontext:
+   case XEN_DOMCTL_set_cpuid:
+   case XEN_DOMCTL_unpausedomain:
+      /* No output fields */
+      break;
+
+   case XEN_DOMCTL_max_vcpus:
+      POST_XEN_DOMCTL_WRITE(max_vcpus, max);
+
+   case XEN_DOMCTL_get_address_size:
+      __POST_XEN_DOMCTL_WRITE(get_address_size, address_size, size);
+      break;
+
+   case XEN_DOMCTL_gettscinfo:
+      __POST_XEN_DOMCTL_WRITE(settscinfo, tsc_info, info.tsc_mode);
+      __POST_XEN_DOMCTL_WRITE(settscinfo, tsc_info, info.gtsc_khz);
+      __POST_XEN_DOMCTL_WRITE(settscinfo, tsc_info, info.incarnation);
+      __POST_XEN_DOMCTL_WRITE(settscinfo, tsc_info, info.elapsed_nsec);
+      break;
+
+   case XEN_DOMCTL_getvcpuinfo:
+      POST_XEN_DOMCTL_WRITE(getvcpuinfo, online);
+      POST_XEN_DOMCTL_WRITE(getvcpuinfo, blocked);
+      POST_XEN_DOMCTL_WRITE(getvcpuinfo, running);
+      POST_XEN_DOMCTL_WRITE(getvcpuinfo, cpu_time);
+      POST_XEN_DOMCTL_WRITE(getvcpuinfo, cpu);
+      break;
+
+   case XEN_DOMCTL_scheduler_op:
+      if ( domctl->u.scheduler_op.cmd == XEN_DOMCTL_SCHEDOP_getinfo ) {
+         switch(domctl->u.scheduler_op.sched_id) {
+         case XEN_SCHEDULER_SEDF:
+            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.period);
+            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.slice);
+            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.latency);
+            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.extratime);
+            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.weight);
+            break;
+         case XEN_SCHEDULER_CREDIT:
+            POST_XEN_DOMCTL_WRITE(scheduler_op, u.credit.weight);
+            POST_XEN_DOMCTL_WRITE(scheduler_op, u.credit.cap);
+            break;
+         case XEN_SCHEDULER_CREDIT2:
+            POST_XEN_DOMCTL_WRITE(scheduler_op, u.credit2.weight);
+            break;
+         case XEN_SCHEDULER_ARINC653:
+            break;
+         }
+      }
+      break;
+
+   case XEN_DOMCTL_getvcpuaffinity:
+      POST_MEM_WRITE((Addr)domctl->u.vcpuaffinity.cpumap.bitmap.p,
+                     domctl->u.vcpuaffinity.cpumap.nr_cpus / 8);
+      break;
+
+   case XEN_DOMCTL_getdomaininfo:
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, domain);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, flags);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, tot_pages);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, max_pages);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, shr_pages);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, shared_info_frame);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, cpu_time);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, nr_online_vcpus);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, max_vcpu_id);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, ssidref);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, handle);
+      POST_XEN_DOMCTL_WRITE(getdomaininfo, cpupool);
+      break;
+
+   case XEN_DOMCTL_getvcpucontext:
+      __POST_XEN_DOMCTL_WRITE(getvcpucontext, vcpucontext, ctxt.p);
+      break;
+
+   case XEN_DOMCTL_getvcpuextstate:
+      __POST_XEN_DOMCTL_WRITE(getvcpuextstate, vcpuextstate, xfeature_mask);
+      __POST_XEN_DOMCTL_WRITE(getvcpuextstate, vcpuextstate, size);
+      POST_MEM_WRITE((Addr)domctl->u.vcpuextstate.buffer.p,
+                     domctl->u.vcpuextstate.size);
+      break;
+
+   }
+#undef POST_XEN_DOMCTL_WRITE
+#undef __POST_XEN_DOMCTL_WRITE
+}
+
+POST(hvm_op)
+{
+   unsigned long op = ARG1;
+   void *arg = (void *)(unsigned long)ARG2;
+
+#define __POST_XEN_HVMOP_WRITE(_hvm_op, _type, _field)  \
+      POST_MEM_WRITE((Addr)&((_type*)arg)->_field,      \
+                     sizeof(((_type*)arg)->_field))
+#define POST_XEN_HVMOP_WRITE(_hvm_op, _field) \
+      __PRE_XEN_HVMOP_READ(_hvm_op, "xen_hvm_" # _hvm_op "_t", _field)
+
+   switch (op) {
+   case HVMOP_set_param:
+      /* No output paramters */
+      break;
+
+   case HVMOP_get_param:
+      __POST_XEN_HVMOP_WRITE(get_param, xen_hvm_param_t, value);
+      break;
+   }
+#undef __POST_XEN_HVMOP_WRITE
+#undef POST_XEN_HVMOP_WRITE
+}
+
+typedef
+   struct {
+      SyscallTableEntry entry;
+      int nr_args;
+   }
+   XenHypercallTableEntry;
+
+#define HYPX_(const, name, nr_args) \
+   [const] = { { vgSysWrap_xen_##name##_before, NULL }, nr_args }
+#define HYPXY(const, name, nr_args)                     \
+   [const] = { { vgSysWrap_xen_##name##_before,         \
+                 vgSysWrap_xen_##name##_after },        \
+               nr_args }
+
+static XenHypercallTableEntry hypercall_table[] = {
+   //    __HYPERVISOR_set_trap_table                                  // 0
+   //    __HYPERVISOR_mmu_update                                      // 1
+   //    __HYPERVISOR_set_gdt                                         // 2
+   //    __HYPERVISOR_stack_switch                                    // 3
+   //    __HYPERVISOR_set_callbacks                                   // 4
+
+   //    __HYPERVISOR_fpu_taskswitch                                  // 5
+   //    __HYPERVISOR_sched_op_compat                                 // 6
+   //    __HYPERVISOR_platform_op                                     // 7
+   //    __HYPERVISOR_set_debugreg                                    // 8
+   //    __HYPERVISOR_get_debugreg                                    // 9
+
+   //    __HYPERVISOR_update_descriptor                               // 10
+   //                                                                 // 11
+   HYPXY(__HYPERVISOR_memory_op,               memory_op,         2), // 12
+   //    __HYPERVISOR_multicall                                       // 13
+   //    __HYPERVISOR_update_va_mapping                               // 14
+
+   //    __HYPERVISOR_set_timer_op                                    // 15
+   HYPXY(__HYPERVISOR_event_channel_op_compat, evtchn_op_compat,  1), // 16
+   HYPXY(__HYPERVISOR_xen_version,             xen_version,       2), // 17
+   //    __HYPERVISOR_console_io                                      // 18
+   //    __HYPERVISOR_physdev_op_compat                               // 19
+
+   HYPXY(__HYPERVISOR_grant_table_op,          grant_table_op,    3), // 20
+   //    __HYPERVISOR_vm_assist                                       // 21
+   //    __HYPERVISOR_update_va_mapping_otherdomain                   // 22
+   //    __HYPERVISOR_iret,                    iret                   // 23
+   //    __HYPERVISOR_vcpu_op,                 vcpu_op                // 24
+
+   //    __HYPERVISOR_set_segment_base                                // 25
+   HYPXY(__HYPERVISOR_mmuext_op,               mmuext_op,         2), // 26
+   //    __HYPERVISOR_xsm_op                                          // 27
+   //    __HYPERVISOR_nmi_op                                          // 28
+   //    __HYPERVISOR_sched_op                                        // 29
+
+   //    __HYPERVISOR_callback_op                                     // 30
+   //    __HYPERVISOR_xenoprof_op                                     // 31
+   HYPXY(__HYPERVISOR_event_channel_op,        evtchn_op,         2), // 32
+   //    __HYPERVISOR_physdev_op                                      // 33
+   HYPXY(__HYPERVISOR_hvm_op,                  hvm_op,            2), // 34
+
+   HYPXY(__HYPERVISOR_sysctl,                  sysctl,            1), // 35
+   HYPXY(__HYPERVISOR_domctl,                  domctl,            1), // 36
+   //    __HYPERVISOR_kexec_op                                        // 37
+   //    __HYPERVISOR_tmem_op                                         // 38
+};
+
+static void bad_before ( ThreadId              tid,
+                         SyscallArgLayout*     layout,
+                         /*MOD*/SyscallArgs*   args,
+                         /*OUT*/SyscallStatus* status,
+                         /*OUT*/UWord*         flags )
+{
+   VG_(dmsg)("WARNING: unhandled hypercall: %s\n",
+      VG_SYSNUM_STRING_EXTRA(args->sysno));
+   if (VG_(clo_verbosity) > 1) {
+      VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
+   }
+   VG_(dmsg)("You may be able to write your own handler.\n");
+   VG_(dmsg)("Read the file README_MISSING_SYSCALL_OR_IOCTL.\n");
+   VG_(dmsg)("Nevertheless we consider this a bug.  Please report\n");
+   VG_(dmsg)("it at http://valgrind.org/support/bug_reports.html &\n");
+   VG_(dmsg)("http://wiki.xen.org/wiki/Reporting_Bugs_against_Xen.\n";);
+
+   SET_STATUS_Failure(VKI_ENOSYS);
+}
+
+static XenHypercallTableEntry bad_hyper =
+{ { bad_before, NULL }, 0 };
+
+static XenHypercallTableEntry* ML_(get_xen_hypercall_entry) ( UInt sysno )
+{
+   XenHypercallTableEntry *ret = &bad_hyper;
+
+   const UInt hypercall_table_size
+      = sizeof(hypercall_table) / sizeof(hypercall_table[0]);
+
+   /* Is it in the contiguous initial section of the table? */
+   if (sysno < hypercall_table_size) {
+      XenHypercallTableEntry* ent = &hypercall_table[sysno];
+      if (ent->entry.before != NULL)
+         ret = ent;
+   }
+
+   /* Can't find a wrapper */
+   return ret;
+}
+
+DEFN_PRE_TEMPLATE(xen, hypercall)
+{
+   XenHypercallTableEntry *ent = ML_(get_xen_hypercall_entry)(SYSNO);
+
+   /* Return number of arguments consumed */
+   ARG8 = ent->nr_args;
+
+   vg_assert(ent);
+   vg_assert(ent->entry.before);
+   (ent->entry.before)( tid, layout, arrghs, status, flags );
+
+}
+
+DEFN_POST_TEMPLATE(xen, hypercall)
+{
+   XenHypercallTableEntry *ent = ML_(get_xen_hypercall_entry)(SYSNO);
+
+   /* Return number of arguments consumed */
+   ARG8 = ent->nr_args;
+
+   vg_assert(ent);
+   if (ent->entry.after)
+      (ent->entry.after)( tid, arrghs, status );
+}
diff --git a/include/Makefile.am b/include/Makefile.am
index ade27c2..f1a3443 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -64,4 +64,5 @@ nobase_pkginclude_HEADERS = \
        vki/vki-scnums-arm-linux.h      \
        vki/vki-scnums-s390x-linux.h    \
        vki/vki-scnums-mips32-linux.h   \
-       vki/vki-scnums-darwin.h
+       vki/vki-scnums-darwin.h         \
+       vki/vki-xen.h
diff --git a/include/pub_tool_vki.h b/include/pub_tool_vki.h
index a0996f9..6598106 100644
--- a/include/pub_tool_vki.h
+++ b/include/pub_tool_vki.h
@@ -47,6 +47,7 @@

 #if defined(VGO_linux)
 #  include "vki/vki-linux.h"
+#  include "vki/vki-xen.h"
 #elif defined(VGO_darwin)
 #  include "vki/vki-darwin.h"
 #else
diff --git a/include/vki/vki-linux.h b/include/vki/vki-linux.h
index c18195e..4fdc353 100644
--- a/include/vki/vki-linux.h
+++ b/include/vki/vki-linux.h
@@ -3009,6 +3009,50 @@ struct vki_hwtstamp_config {
 #define VKI_UI_SET_SWBIT               _VKI_IOW(VKI_UINPUT_IOCTL_BASE, 109, 
int)
 #define VKI_UI_SET_PROPBIT             _VKI_IOW(VKI_UINPUT_IOCTL_BASE, 110, 
int)

+//----------------------------------------------------------------------
+// Xen privcmd IOCTL
+//----------------------------------------------------------------------
+
+typedef unsigned long __vki_xen_pfn_t;
+
+struct vki_xen_privcmd_hypercall {
+       __vki_u64 op;
+       __vki_u64 arg[5];
+};
+
+struct vki_xen_privcmd_mmap_entry {
+        __vki_u64 va;
+        __vki_u64 mfn;
+        __vki_u64 npages;
+};
+
+struct vki_xen_privcmd_mmap {
+        int num;
+        __vki_u16 dom; /* target domain */
+        struct vki_xen_privcmd_mmap_entry *entry;
+};
+
+struct vki_xen_privcmd_mmapbatch {
+        int num;     /* number of pages to populate */
+        __vki_u16 dom; /* target domain */
+        __vki_u64 addr;  /* virtual address */
+        __vki_xen_pfn_t *arr; /* array of mfns - top nibble set on err */
+};
+
+struct vki_xen_privcmd_mmapbatch_v2 {
+        unsigned int num; /* number of pages to populate */
+        __vki_u16 dom;      /* target domain */
+        __vki_u64 addr;       /* virtual address */
+        const __vki_xen_pfn_t *arr; /* array of mfns */
+        int __user *err;  /* array of error codes */
+};
+
+#define VKI_XEN_IOCTL_PRIVCMD_HYPERCALL    _VKI_IOC(_VKI_IOC_NONE, 'P', 0, 
sizeof(struct vki_xen_privcmd_hypercall))
+#define VKI_XEN_IOCTL_PRIVCMD_MMAP         _VKI_IOC(_VKI_IOC_NONE, 'P', 2, 
sizeof(struct vki_xen_privcmd_mmap))
+
+#define VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH    _VKI_IOC(_VKI_IOC_NONE, 'P', 3, 
sizeof(struct vki_xen_privcmd_mmapbatch))
+#define VKI_XEN_IOCTL_PRIVCMD_MMAPBATCH_V2 _VKI_IOC(_VKI_IOC_NONE, 'P', 4, 
sizeof(struct vki_xen_privcmd_mmapbatch_v2))
+
 #endif // __VKI_LINUX_H

 /*--------------------------------------------------------------------*/
diff --git a/include/vki/vki-xen.h b/include/vki/vki-xen.h
new file mode 100644
index 0000000..7842cc9
--- /dev/null
+++ b/include/vki/vki-xen.h
@@ -0,0 +1,8 @@
+#ifndef __VKI_XEN_H
+#define __VKI_XEN_H
+
+#endif // __VKI_XEN_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
--
1.7.2.5





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


 


Rackspace

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