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

[Xen-devel] [PATCH XEN v2 14/15] tools: Refactor foreign memory mapping into libxenforeignmemory



libxenforeignmemory will provide a stable API and ABI for mapping
foreign domain memory (subject to appropriate privileges).

The new library exposes an interface equivalent to
xc_map_foreign_memory_bulk, which all the other
xc_map_foreign_memory_* functions (which remain in libxc) are
implemented in terms of.

Upon request (via #define XC_WANT_COMPAT_MAP_FOREIGN_API) libxenctrl
will provide a compat API for the old names. This is used by qemu-xen
and qemu-trad as well as various in tree things (which required
de-dupping various #includes in some too to get the #define before the
first).

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
Must be applied with:
  - "qemu-xen-traditional: qemu-xen-traditional: Add
    libxenforeignmemory to rpath-link" and a corresponding QEMU_TAG
    update folded here.
  - "mini-os: mini-os: Include libxenforeignmemory with libxc" and a
    corresponding bump to MINIOS_UPSTREAM_REVISION folded in here.
---
 .gitignore                                         |   2 +
 docs/misc/toolstack-library-abis.pandoc            |  22 +-
 stubdom/Makefile                                   |  21 +-
 tools/Makefile                                     |   3 +
 tools/Rules.mk                                     |  11 +-
 tools/console/daemon/utils.c                       |   1 -
 tools/console/daemon/utils.h                       |   1 +
 tools/libxc/Makefile                               |   8 +-
 tools/libxc/include/xenctrl.h                      |  26 --
 tools/libxc/include/xenctrl_compat.h               |  36 +++
 tools/libxc/xc_domain_restore.c                    |   4 +-
 tools/libxc/xc_domain_save.c                       |   4 +-
 tools/libxc/xc_foreign_memory.c                    |  49 +---
 tools/libxc/xc_freebsd_osdep.c                     | 137 ----------
 tools/libxc/xc_linux_osdep.c                       | 296 ---------------------
 tools/libxc/xc_minios.c                            |  29 --
 tools/libxc/xc_netbsd.c                            |  73 -----
 tools/libxc/xc_private.c                           |  13 +-
 tools/libxc/xc_private.h                           |  11 +-
 tools/libxc/xc_solaris.c                           |  73 -----
 tools/libxc/xc_sr_restore.c                        |   4 +-
 tools/libxc/xc_sr_save.c                           |   4 +-
 tools/libxc/xc_vm_event.c                          |  10 +-
 tools/libxc/xg_private.h                           |   3 +-
 tools/libxenforeignmemory/Makefile                 |  67 +++++
 tools/libxenforeignmemory/compat.c                 |  72 +++++
 tools/libxenforeignmemory/core.c                   |  65 +++++
 tools/libxenforeignmemory/freebsd.c                | 126 +++++++++
 .../libxenforeignmemory/include/xenforeignmemory.h |  68 +++++
 tools/libxenforeignmemory/libxenforeignmemory.map  |   7 +
 tools/libxenforeignmemory/linux.c                  | 284 ++++++++++++++++++++
 tools/libxenforeignmemory/minios.c                 |  59 ++++
 tools/libxenforeignmemory/netbsd.c                 |  92 +++++++
 tools/libxenforeignmemory/private.h                |  47 ++++
 tools/libxenforeignmemory/solaris.c                |  95 +++++++
 tools/libxl/libxl_internal.h                       |   1 +
 tools/misc/xen-mfndump.c                           |   1 +
 tools/ocaml/libs/xc/xenctrl_stubs.c                |   1 +
 tools/python/xen/lowlevel/xc/xc.c                  |   2 +-
 tools/xenmon/xenbaked.c                            |   1 +
 tools/xenpaging/pagein.c                           |   1 -
 tools/xenpaging/xenpaging.c                        |   1 -
 tools/xenpaging/xenpaging.h                        |   2 +
 tools/xenstore/xenstored_core.c                    |   1 -
 tools/xenstore/xenstored_core.h                    |   1 +
 tools/xentrace/xenctx.c                            |   3 +-
 tools/xentrace/xentrace.c                          |   1 +
 47 files changed, 1118 insertions(+), 721 deletions(-)
 delete mode 100644 tools/libxc/xc_freebsd_osdep.c
 delete mode 100644 tools/libxc/xc_linux_osdep.c
 create mode 100644 tools/libxenforeignmemory/Makefile
 create mode 100644 tools/libxenforeignmemory/compat.c
 create mode 100644 tools/libxenforeignmemory/core.c
 create mode 100644 tools/libxenforeignmemory/freebsd.c
 create mode 100644 tools/libxenforeignmemory/include/xenforeignmemory.h
 create mode 100644 tools/libxenforeignmemory/libxenforeignmemory.map
 create mode 100644 tools/libxenforeignmemory/linux.c
 create mode 100644 tools/libxenforeignmemory/minios.c
 create mode 100644 tools/libxenforeignmemory/netbsd.c
 create mode 100644 tools/libxenforeignmemory/private.h
 create mode 100644 tools/libxenforeignmemory/solaris.c

diff --git a/.gitignore b/.gitignore
index 5841570..bb643f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,6 +63,7 @@ stubdom/libxentoollog-*
 stubdom/libxenevtchn-*
 stubdom/libxengnttab-*
 stubdom/libxencall-*
+stubdom/libxenforeignmemory-*
 stubdom/libxc-*
 stubdom/lwip-*
 stubdom/mini-os-*
@@ -93,6 +94,7 @@ tools/libxentoollog/headers.chk
 tools/libxenevtchn/headers.chk
 tools/libxengnttab/headers.chk
 tools/libxencall/headers.chk
+tools/libxenforeignmemory/headers.chk
 tools/blktap2/daemon/blktapctrl
 tools/blktap2/drivers/img2qcow
 tools/blktap2/drivers/lock-util
diff --git a/docs/misc/toolstack-library-abis.pandoc 
b/docs/misc/toolstack-library-abis.pandoc
index 35674cc..63b83bc 100644
--- a/docs/misc/toolstack-library-abis.pandoc
+++ b/docs/misc/toolstack-library-abis.pandoc
@@ -166,6 +166,16 @@ Interface                         Underlying interface     
      Known external
 `xencall_free_buffer`             `xencall_free_buffer_pages`
 `xencall_free_buffer_pages`       `munmap(2)`, `madvise(2)`
 
+## `libxenforeignmemory`: privileged foreign mappings
+
+Mapping foreign guest memory.
+
+Interface                         Underlying interface           Known 
external users
+--------------------------------- ------------------------------ 
--------------------
+`xenforeignmemory_open`           `open(2)`
+`xenforeignmemory_close`          `close(2)`
+`xenforeignmemory_map`            `IOCTL_PRIVCMD_MMAPBATCH` etc
+
 # Unstable libraries
 
 These libraries do not provide a stable interface and are required to
@@ -269,12 +279,14 @@ The following are private:
 
 ### Mapping foreign memory
 
-Interface                         Underlying interface           Known 
external users
---------------------------------- ------------------------------ 
--------------------
-`xc_map_foreign_pages`            `IOCTL_PRIVCMD_MMAP...`        qemu-pv
-`xc_map_foreign_range`            `IOCTL_PRIVCMD_MMAP...`        qemu-dm, and 
qemu-pv
+All implemented in terms of `xenforeignmemory_map`.
+
+Interface                         Known external users
+--------------------------------- --------------------
+`xc_map_foreign_pages`            qemu-pv
+`xc_map_foreign_range`            qemu-dm, qemu-pv
 `xc_map_foreign_ranges`
-`xc_map_foreign_bulk`             `IOCTL_PRIVCMD_MMAPBATCH_V2`   qemu-dm
+`xc_map_foreign_bulk`             qemu-dm
 
 ### Managing guest memory map
 
diff --git a/stubdom/Makefile b/stubdom/Makefile
index ec058ca..529f5c3 100644
--- a/stubdom/Makefile
+++ b/stubdom/Makefile
@@ -336,6 +336,12 @@ mk-headers-$(XEN_TARGET_ARCH): $(IOEMU_LINKFARM_TARGET)
          ln -sf $(XEN_ROOT)/tools/libxencall/include/*.h include/ && \
          ln -sf $(XEN_ROOT)/tools/libxencall/*.c . && \
          ln -sf $(XEN_ROOT)/tools/libxencall/Makefile . )
+       mkdir -p libxenforeignmemory-$(XEN_TARGET_ARCH)/include
+       [ -h libxenforeignmemory-$(XEN_TARGET_ARCH)/Makefile ] || ( cd 
libxenforeignmemory-$(XEN_TARGET_ARCH) && \
+         ln -sf $(XEN_ROOT)/tools/libxenforeignmemory/*.h . && \
+         ln -sf $(XEN_ROOT)/tools/libxenforeignmemory/include/*.h include/ && \
+         ln -sf $(XEN_ROOT)/tools/libxenforeignmemory/*.c . && \
+         ln -sf $(XEN_ROOT)/tools/libxenforeignmemory/Makefile . )
        mkdir -p libxc-$(XEN_TARGET_ARCH)
        [ -h libxc-$(XEN_TARGET_ARCH)/Makefile ] || ( cd 
libxc-$(XEN_TARGET_ARCH) && \
          ln -sf $(XEN_ROOT)/tools/libxc/*.h . && \
@@ -390,6 +396,7 @@ libxengnttab-$(XEN_TARGET_ARCH)/libxengnttab.a: 
$(NEWLIB_STAMPFILE)
        $(MAKE) -C $(XEN_ROOT)/tools/include
        $(MAKE) DESTDIR= -C $(MINI_OS) links
        CPPFLAGS="$(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" $(MAKE) 
DESTDIR= -C libxengnttab-$(XEN_TARGET_ARCH)
+APP_LDLIBS += -L$(XEN_ROOT)/stubdom/libxencall-$(MINIOS_TARGET_ARCH) 
-whole-archive -lxencall -no-whole-archive
 
 #######
 # libxencall
@@ -401,6 +408,18 @@ libxencall-$(XEN_TARGET_ARCH)/libxencall.a: 
$(NEWLIB_STAMPFILE)
        $(MAKE) -C $(XEN_ROOT)/tools/include
        $(MAKE) DESTDIR= -C $(MINI_OS) links
        CPPFLAGS="$(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" $(MAKE) 
DESTDIR= -C libxencall-$(XEN_TARGET_ARCH)
+APP_LDLIBS += -L$(XEN_ROOT)/stubdom/libxencall-$(MINIOS_TARGET_ARCH) 
-whole-archive -lxencall -no-whole-archive
+
+#######
+# libxenforeignmemory
+#######
+
+.PHONY: libxenforeignmemory
+libxenforeignmemory: 
libxenforeignmemory-$(XEN_TARGET_ARCH)/libxenforeignmemory.a
+libxenforeignmemory-$(XEN_TARGET_ARCH)/libxenforeignmemory.a: 
$(NEWLIB_STAMPFILE)
+       $(MAKE) -C $(XEN_ROOT)/tools/include
+       $(MAKE) DESTDIR= -C $(MINI_OS) links
+       CPPFLAGS="$(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" $(MAKE) 
DESTDIR= -C libxenforeignmemory-$(XEN_TARGET_ARCH)
 
 #######
 # libxc
@@ -408,7 +427,7 @@ libxencall-$(XEN_TARGET_ARCH)/libxencall.a: 
$(NEWLIB_STAMPFILE)
 
 .PHONY: libxc
 libxc: libxc-$(XEN_TARGET_ARCH)/libxenctrl.a 
libxc-$(XEN_TARGET_ARCH)/libxenguest.a
-libxc-$(XEN_TARGET_ARCH)/libxenctrl.a: libxentoollog libxenevtchn libxengnttab 
libxencall cross-zlib
+libxc-$(XEN_TARGET_ARCH)/libxenctrl.a: libxentoollog libxenevtchn libxengnttab 
libxencall libxenforeignmemory cross-zlib
        $(MAKE) -C $(XEN_ROOT)/tools/include
        $(MAKE) DESTDIR= -C $(MINI_OS) links
        CPPFLAGS="$(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" $(MAKE) 
DESTDIR= CONFIG_LIBXC_MINIOS=y -C libxc-$(XEN_TARGET_ARCH)
diff --git a/tools/Makefile b/tools/Makefile
index e5c8879..30abd57 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -7,6 +7,7 @@ SUBDIRS-y += libxentoollog
 SUBDIRS-y += libxenevtchn
 SUBDIRS-y += libxengnttab
 SUBDIRS-y += libxencall
+SUBDIRS-y += libxenforeignmemory
 SUBDIRS-y += libxc
 SUBDIRS-$(FLASK_ENABLE) += flask
 SUBDIRS-y += xenstore
@@ -253,6 +254,7 @@ subdir-all-qemu-xen-dir: qemu-xen-dir-find
                --source-path=$$source \
                --extra-cflags="-DXC_WANT_COMPAT_EVTCHN_API=1 \
                -DXC_WANT_COMPAT_GNTTAB_API=1 \
+               -DXC_WANT_COMPAT_MAP_FOREIGN_API=1 \
                -I$(XEN_ROOT)/tools/include \
                -I$(XEN_ROOT)/tools/libxentoollog/include \
                -I$(XEN_ROOT)/tools/libxenevtchn/include \
@@ -267,6 +269,7 @@ subdir-all-qemu-xen-dir: qemu-xen-dir-find
                -Wl,-rpath-link=$(XEN_ROOT)/tools/libxenevtchn \
                -Wl,-rpath-link=$(XEN_ROOT)/tools/libxengnttab \
                -Wl,-rpath-link=$(XEN_ROOT)/tools/libxencall \
+               -Wl,-rpath-link=$(XEN_ROOT)/tools/libxenforeignmemory \
                $(QEMU_UPSTREAM_RPATH)" \
                --bindir=$(LIBEXEC_BIN) \
                --datadir=$(SHAREDIR)/qemu-xen \
diff --git a/tools/Rules.mk b/tools/Rules.mk
index 405a6a5..4a67f1f 100644
--- a/tools/Rules.mk
+++ b/tools/Rules.mk
@@ -14,6 +14,7 @@ XEN_LIBXENTOOLLOG  = $(XEN_ROOT)/tools/libxentoollog
 XEN_LIBXENEVTCHN   = $(XEN_ROOT)/tools/libxenevtchn
 XEN_LIBXENGNTTAB   = $(XEN_ROOT)/tools/libxengnttab
 XEN_LIBXENCALL     = $(XEN_ROOT)/tools/libxencall
+XEN_LIBXENFOREIGNMEMORY = $(XEN_ROOT)/tools/libxenforeignmemory
 XEN_LIBXC          = $(XEN_ROOT)/tools/libxc
 XEN_XENLIGHT       = $(XEN_ROOT)/tools/libxl
 XEN_XENSTORE       = $(XEN_ROOT)/tools/xenstore
@@ -103,12 +104,16 @@ CFLAGS_libxencall = -I$(XEN_LIBXENCALL)/include 
$(CFLAGS_xeninclude)
 LDLIBS_libxencall = $(XEN_LIBXENCALL)/libxencall$(libextension)
 SHLIB_libxencall  = -Wl,-rpath-link=$(XEN_LIBXENCALL)
 
-CFLAGS_libxenctrl = -I$(XEN_LIBXC)/include $(CFLAGS_libxentoollog) 
$(CFLAGS_xeninclude)
-SHDEPS_libxenctrl = $(SHLIB_libxentoollog) $(SHLIB_libxenevtchn) 
$(SHLIB_libxengnttab) $(SHLIB_libxengntshr) $(SHLIB_libxencall)
+CFLAGS_libxenforeignmemory = -I$(XEN_LIBXENFOREIGNMEMORY)/include 
$(CFLAGS_xeninclude)
+LDLIBS_libxenforeignmemory = 
$(XEN_LIBXENFOREIGNMEMORY)/libxenforeignmemory$(libextension)
+SHLIB_libxenforeignmemory  = -Wl,-rpath-link=$(XEN_LIBXENFOREIGNMEMORY)
+
+CFLAGS_libxenctrl = -I$(XEN_LIBXC)/include $(CFLAGS_libxentoollog) 
$(CFLAGS_libxenforeignmemory) $(CFLAGS_xeninclude)
+SHDEPS_libxenctrl = $(SHLIB_libxentoollog) $(SHLIB_libxenevtchn) 
$(SHLIB_libxengnttab) $(SHLIB_libxengntshr) $(SHLIB_libxencall) 
$(SHLIB_libxenforeignmemory)
 LDLIBS_libxenctrl = $(SHDEPS_libxenctrl) $(XEN_LIBXC)/libxenctrl$(libextension)
 SHLIB_libxenctrl  = $(SHDEPS_libxenctrl) -Wl,-rpath-link=$(XEN_LIBXC)
 
-CFLAGS_libxenguest = -I$(XEN_LIBXC)/include $(CFLAGS_libxenevtchn) 
$(CFLAGS_xeninclude)
+CFLAGS_libxenguest = -I$(XEN_LIBXC)/include $(CFLAGS_libxenevtchn) 
$(CFLAGS_libxenforeignmemory) $(CFLAGS_xeninclude)
 SHDEPS_libxenguest = $(SHLIB_libxenevtchn)
 LDLIBS_libxenguest = $(SHDEPS_libxenguest) 
$(XEN_LIBXC)/libxenguest$(libextension)
 SHLIB_libxenguest  = $(SHDEPS_libxenguest) -Wl,-rpath-link=L$(XEN_LIBXC)
diff --git a/tools/console/daemon/utils.c b/tools/console/daemon/utils.c
index 71dd185..edc1595 100644
--- a/tools/console/daemon/utils.c
+++ b/tools/console/daemon/utils.c
@@ -34,7 +34,6 @@
 #include <string.h>
 #include <signal.h>
 
-#include "xenctrl.h"
 #include "utils.h"
 
 struct xs_handle *xs;
diff --git a/tools/console/daemon/utils.h b/tools/console/daemon/utils.h
index 8725dcd..45c7c34 100644
--- a/tools/console/daemon/utils.h
+++ b/tools/console/daemon/utils.h
@@ -24,6 +24,7 @@
 #include <stdbool.h>
 #include <syslog.h>
 #include <stdio.h>
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
 #include <xenctrl.h>
 
 #include <xenstore.h>
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index 42fbabe..79afb78 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -41,8 +41,8 @@ CTRL_SRCS-y       += xc_kexec.c
 CTRL_SRCS-y       += xc_resource.c
 CTRL_SRCS-$(CONFIG_X86) += xc_psr.c
 CTRL_SRCS-$(CONFIG_X86) += xc_pagetab.c
-CTRL_SRCS-$(CONFIG_Linux) += xc_linux.c xc_linux_osdep.c
-CTRL_SRCS-$(CONFIG_FreeBSD) += xc_freebsd.c xc_freebsd_osdep.c
+CTRL_SRCS-$(CONFIG_Linux) += xc_linux.c
+CTRL_SRCS-$(CONFIG_FreeBSD) += xc_freebsd.c
 CTRL_SRCS-$(CONFIG_SunOS) += xc_solaris.c
 CTRL_SRCS-$(CONFIG_NetBSD) += xc_netbsd.c
 CTRL_SRCS-$(CONFIG_NetBSDRump) += xc_netbsd.c
@@ -126,7 +126,7 @@ $(CTRL_PIC_OBJS) $(GUEST_PIC_OBJS): CFLAGS += -include 
$(XEN_ROOT)/tools/config.
 # libxenguest includes xc_private.h, so needs this despite not using
 # this functionality directly.
 $(CTRL_LIB_OBJS) $(GUEST_LIB_OBJS) \
-$(CTRL_PIC_OBJS) $(GUEST_PIC_OBJS): CFLAGS += $(CFLAGS_libxencall)
+$(CTRL_PIC_OBJS) $(GUEST_PIC_OBJS): CFLAGS += $(CFLAGS_libxencall) 
$(CFLAGS_libxenforeignmemory)
 
 $(CTRL_LIB_OBJS) $(CTRL_PIC_OBJS): CFLAGS += $(CFLAGS_libxengnttab) 
$(CFLAGS_libxengntshr)
 
@@ -208,7 +208,7 @@ libxenctrl.so.$(MAJOR): libxenctrl.so.$(MAJOR).$(MINOR)
        $(SYMLINK_SHLIB) $< $@
 
 libxenctrl.so.$(MAJOR).$(MINOR): $(CTRL_PIC_OBJS)
-       $(CC) $(LDFLAGS) $(PTHREAD_LDFLAGS) -Wl,$(SONAME_LDFLAG) 
-Wl,libxenctrl.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $^ $(LDLIBS_libxentoollog) 
$(LDLIBS_libxenevtchn) $(LDLIBS_libxengnttab) $(LDLIBS_libxengntshr) 
$(LDLIBS_libxencall) $(PTHREAD_LIBS) $(APPEND_LDFLAGS)
+       $(CC) $(LDFLAGS) $(PTHREAD_LDFLAGS) -Wl,$(SONAME_LDFLAG) 
-Wl,libxenctrl.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $^ $(LDLIBS_libxentoollog) 
$(LDLIBS_libxenevtchn) $(LDLIBS_libxengnttab) $(LDLIBS_libxengntshr) 
$(LDLIBS_libxencall) $(LDLIBS_libxenforeignmemory) $(PTHREAD_LIBS) 
$(APPEND_LDFLAGS)
 
 # libxenguest
 
diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 201fd70..bfa11a7 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1349,32 +1349,6 @@ int xc_lockprof_query(xc_interface *xch,
 void *xc_memalign(xc_interface *xch, size_t alignment, size_t size);
 
 /**
- * Memory maps a range within one domain to a local address range.  Mappings
- * should be unmapped with munmap and should follow the same rules as mmap
- * regarding page alignment.  Returns NULL on failure.
- *
- * @parm xch a handle on an open hypervisor interface
- * @parm dom the domain to map memory from
- * @parm size the amount of memory to map (in multiples of page size)
- * @parm prot same flag as in mmap().
- * @parm mfn the frame address to map.
- */
-void *xc_map_foreign_range(xc_interface *xch, uint32_t dom,
-                            int size, int prot,
-                            unsigned long mfn );
-
-void *xc_map_foreign_pages(xc_interface *xch, uint32_t dom, int prot,
-                           const xen_pfn_t *arr, int num );
-
-/**
- * Like xc_map_foreign_pages(), except it can succeed partially.
- * When a page cannot be mapped, its respective field in @err is
- * set to the corresponding errno value.
- */
-void *xc_map_foreign_bulk(xc_interface *xch, uint32_t dom, int prot,
-                          const xen_pfn_t *arr, int *err, unsigned int num);
-
-/**
  * Translates a virtual address in the context of a given domain and
  * vcpu returning the GFN containing the address (that is, an MFN for 
  * PV guests, a PFN for HVM guests).  Returns 0 for failure.
diff --git a/tools/libxc/include/xenctrl_compat.h 
b/tools/libxc/include/xenctrl_compat.h
index d99fa11..54c23a4 100644
--- a/tools/libxc/include/xenctrl_compat.h
+++ b/tools/libxc/include/xenctrl_compat.h
@@ -12,6 +12,42 @@
 #ifndef XENCTRL_COMPAT_H
 #define XENCTRL_COMPAT_H
 
+#ifdef XC_WANT_COMPAT_MAP_FOREIGN_API
+/**
+ * Memory maps a range within one domain to a local address range.  Mappings
+ * should be unmapped with munmap and should follow the same rules as mmap
+ * regarding page alignment.  Returns NULL on failure.
+ *
+ * @parm xch a handle on an open hypervisor interface
+ * @parm dom the domain to map memory from
+ * @parm size the amount of memory to map (in multiples of page size)
+ * @parm prot same flag as in mmap().
+ * @parm mfn the frame address to map.
+ */
+void *xc_map_foreign_range(xc_interface *xch, uint32_t dom,
+                            int size, int prot,
+                            unsigned long mfn );
+
+void *xc_map_foreign_pages(xc_interface *xch, uint32_t dom, int prot,
+                           const xen_pfn_t *arr, int num );
+
+/* Nothing within the library itself other than the compat wrapper
+ * itself should be using this, everything inside has access to
+ * xenforeignmemory_map().
+ */
+#if !defined(XC_INTERNAL_COMPAT_MAP_FOREIGN_API) || \
+     defined(XC_BUILDING_COMPAT_MAP_FOREIGN_API)
+/**
+ * Like xc_map_foreign_pages(), except it can succeed partially.
+ * When a page cannot be mapped, its respective field in @err is
+ * set to the corresponding errno value.
+ */
+void *xc_map_foreign_bulk(xc_interface *xch, uint32_t dom, int prot,
+                          const xen_pfn_t *arr, int *err, unsigned int num);
+#endif
+
+#endif
+
 #ifdef XC_WANT_COMPAT_EVTCHN_API
 
 typedef struct xenevtchn_handle xc_evtchn;
diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c
index 8435f6b..5d44512 100644
--- a/tools/libxc/xc_domain_restore.c
+++ b/tools/libxc/xc_domain_restore.c
@@ -1284,8 +1284,8 @@ static int apply_batch(xc_interface *xch, uint32_t dom, 
struct restore_ctx *ctx,
         PERROR("allocation for pfn_err failed");
         return -1;
     }
-    region_base = xc_map_foreign_bulk(
-        xch, dom, PROT_WRITE, region_mfn, pfn_err, j);
+    region_base = xenforeignmemory_map(xch->fmem,
+        dom, PROT_WRITE, region_mfn, pfn_err, j);
 
     if ( region_base == NULL )
     {
diff --git a/tools/libxc/xc_domain_save.c b/tools/libxc/xc_domain_save.c
index 3222473..412819f 100644
--- a/tools/libxc/xc_domain_save.c
+++ b/tools/libxc/xc_domain_save.c
@@ -1265,8 +1265,8 @@ int xc_domain_save(xc_interface *xch, int io_fd, uint32_t 
dom, uint32_t max_iter
             if ( batch == 0 )
                 goto skip; /* vanishingly unlikely... */
 
-            region_base = xc_map_foreign_bulk(
-                xch, dom, PROT_READ, pfn_type, pfn_err, batch);
+            region_base = xenforeignmemory_map(xch->fmem,
+                dom, PROT_READ, pfn_type, pfn_err, batch);
             if ( region_base == NULL )
             {
                 PERROR("map batch failed");
diff --git a/tools/libxc/xc_foreign_memory.c b/tools/libxc/xc_foreign_memory.c
index c96489d..b6bf132 100644
--- a/tools/libxc/xc_foreign_memory.c
+++ b/tools/libxc/xc_foreign_memory.c
@@ -18,6 +18,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
  */
 
+#define XC_BUILDING_COMPAT_MAP_FOREIGN_API
 #include "xc_private.h"
 
 void *xc_map_foreign_pages(xc_interface *xch, uint32_t dom, int prot,
@@ -35,7 +36,7 @@ void *xc_map_foreign_pages(xc_interface *xch, uint32_t dom, 
int prot,
     if (!err)
         return NULL;
 
-    res = xc_map_foreign_bulk(xch, dom, prot, arr, err, num);
+    res = xenforeignmemory_map(xch->fmem, dom, prot, arr, err, num);
     if (res) {
         for (i = 0; i < num; i++) {
             if (err[i]) {
@@ -101,53 +102,11 @@ void *xc_map_foreign_ranges(xc_interface *xch,
     return ret;
 }
 
-/*
- * stub for all not yet converted OSes (NetBSD and Solaris). New OSes should
- * just implement xc_map_foreign_bulk.
- */
-#if defined(__NetBSD__) || defined(__sun__)
-void *osdep_map_foreign_batch(xc_interface *xch, uint32_t dom, int prot,
-                              xen_pfn_t *arr, int num );
-void *xc_map_foreign_bulk(xc_interface *xch,
-                          uint32_t dom, int prot,
+void *xc_map_foreign_bulk(xc_interface *xch, uint32_t dom, int prot,
                           const xen_pfn_t *arr, int *err, unsigned int num)
 {
-    xen_pfn_t *pfn;
-    unsigned int i;
-    void *ret;
-
-    if ((int)num <= 0) {
-        errno = EINVAL;
-        return NULL;
-    }
-
-    pfn = malloc(num * sizeof(*pfn));
-    if (!pfn) {
-        errno = ENOMEM;
-        return NULL;
-    }
-
-    memcpy(pfn, arr, num * sizeof(*arr));
-    ret = osdep_map_foreign_batch(xch, dom, prot, pfn, num);
-
-    if (ret) {
-        for (i = 0; i < num; ++i)
-            switch (pfn[i] ^ arr[i]) {
-            case 0:
-                err[i] = 0;
-                break;
-            default:
-                err[i] = -EINVAL;
-                break;
-            }
-    } else
-        memset(err, 0, num * sizeof(*err));
-
-    free(pfn);
-
-    return ret;
+    return xenforeignmemory_map(xch->fmem, dom, prot, arr, err, num);
 }
-#endif
 
 /*
  * Local variables:
diff --git a/tools/libxc/xc_freebsd_osdep.c b/tools/libxc/xc_freebsd_osdep.c
deleted file mode 100644
index d09e0da..0000000
--- a/tools/libxc/xc_freebsd_osdep.c
+++ /dev/null
@@ -1,137 +0,0 @@
- 
/******************************************************************************
- *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- *
- * xc_gnttab functions:
- * Copyright (c) 2007-2008, D G Murray <Derek.Murray@xxxxxxxxxxxx>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-
-#include <xen/memory.h>
-
-#include "xc_private.h"
-
-#define PRIVCMD_DEV     "/dev/xen/privcmd"
-
-/*------------------------- Privcmd device interface 
-------------------------*/
-int osdep_privcmd_open(xc_interface *xch)
-{
-    int flags, saved_errno;
-    int fd = open(PRIVCMD_DEV, O_RDWR);
-
-    if ( fd == -1 )
-    {
-        PERROR("Could not obtain handle on privileged command interface "
-               PRIVCMD_DEV);
-        return -1
-    }
-
-    /*
-     * Although we return the file handle as the 'xc handle' the API
-     * does not specify / guarentee that this integer is in fact
-     * a file handle. Thus we must take responsiblity to ensure
-     * it doesn't propagate (ie leak) outside the process.
-     */
-    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
-    {
-        PERROR("Could not get file handle flags");
-        goto error;
-    }
-
-    flags |= FD_CLOEXEC;
-
-    if ( fcntl(fd, F_SETFD, flags) < 0 )
-    {
-        PERROR("Could not set file handle flags");
-        goto error;
-    }
-
-    xch->privcmdfd = fd;
-    return 0;
-
- error:
-    saved_errno = errno;
-    close(fd);
-    errno = saved_errno;
-
-    return -1;
-}
-
-int osdep_privcmd_close(xc_interface *xch)
-{
-    int fd = xch->privcmdfd;
-    if ( fd == -1 )
-        return 0;
-    return close(fd);
-}
-
-/*----------------------- Privcmd foreign map interface 
----------------------*/
-void *xc_map_foreign_bulk(xc_interface *xch,
-                          uint32_t dom, int prot,
-                          const xen_pfn_t *arr, int *err,
-                          unsigned int num)
-{
-    int fd = xch->privcmdfd;
-    privcmd_mmapbatch_t ioctlx;
-    void *addr;
-    int rc;
-
-    addr = mmap(NULL, num << XC_PAGE_SHIFT, prot, MAP_SHARED, fd, 0);
-    if ( addr == MAP_FAILED )
-    {
-        PERROR("xc_map_foreign_bulk: mmap failed");
-        return NULL;
-    }
-
-    ioctlx.num = num;
-    ioctlx.dom = dom;
-    ioctlx.addr = (unsigned long)addr;
-    ioctlx.arr = arr;
-    ioctlx.err = err;
-
-    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
-    if ( rc < 0 )
-    {
-        int saved_errno = errno;
-        PERROR("xc_map_foreign_bulk: ioctl failed");
-        (void)munmap(addr, num << XC_PAGE_SHIFT);
-        errno = saved_errno;
-        return NULL;
-    }
-
-    return addr;
-}
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/tools/libxc/xc_linux_osdep.c b/tools/libxc/xc_linux_osdep.c
deleted file mode 100644
index 9f8805a..0000000
--- a/tools/libxc/xc_linux_osdep.c
+++ /dev/null
@@ -1,296 +0,0 @@
- 
/******************************************************************************
- *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- *
- * xc_gnttab functions:
- * Copyright (c) 2007-2008, D G Murray <Derek.Murray@xxxxxxxxxxxx>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-
-#include <xen/memory.h>
-
-#include "xenctrl.h"
-
-#include "xc_private.h"
-
-#define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
-
-int osdep_privcmd_open(xc_interface *xch)
-{
-    int flags, saved_errno;
-    int fd = open("/proc/xen/privcmd", O_RDWR);
-
-    if ( fd == -1 )
-    {
-        PERROR("Could not obtain handle on privileged command interface");
-        return -1;
-    }
-
-    /* Although we return the file handle as the 'xc handle' the API
-       does not specify / guarentee that this integer is in fact
-       a file handle. Thus we must take responsiblity to ensure
-       it doesn't propagate (ie leak) outside the process */
-    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
-    {
-        PERROR("Could not get file handle flags");
-        goto error;
-    }
-
-    flags |= FD_CLOEXEC;
-
-    if ( fcntl(fd, F_SETFD, flags) < 0 )
-    {
-        PERROR("Could not set file handle flags");
-        goto error;
-    }
-
-    xch->privcmdfd = fd;
-    return 0;
-
- error:
-    saved_errno = errno;
-    close(fd);
-    errno = saved_errno;
-    return -1;
-}
-
-int osdep_privcmd_close(xc_interface *xch)
-{
-    int fd = xch->privcmdfd;
-    if (fd == -1)
-        return 0;
-    return close(fd);
-}
-
-static int map_foreign_batch_single(int fd, uint32_t dom,
-                                    xen_pfn_t *mfn, unsigned long addr)
-{
-    privcmd_mmapbatch_t ioctlx;
-    int rc;
-
-    ioctlx.num = 1;
-    ioctlx.dom = dom;
-    ioctlx.addr = addr;
-    ioctlx.arr = mfn;
-
-    do
-    {
-        *mfn ^= PRIVCMD_MMAPBATCH_PAGED_ERROR;
-        usleep(100);
-        rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
-    }
-    while ( (rc < 0) && (errno == ENOENT) );
-
-    return rc;
-}
-
-/*
- * Retry mmap of all paged gfns in batches
- * retuns < 0 on fatal error
- * returns 0 if all gfns left paging state
- * returns > 0 if some gfns are still in paging state
- *
- * Walk all gfns and try to assemble blocks of gfns in paging state.
- * This will keep the request ring full and avoids delays.
- */
-static int retry_paged(int fd, uint32_t dom, void *addr,
-                       const xen_pfn_t *arr, int *err, unsigned int num)
-{
-    privcmd_mmapbatch_v2_t ioctlx;
-    int rc, paged = 0, i = 0;
-    
-    do
-    {
-        /* Skip gfns not in paging state */
-        if ( err[i] != -ENOENT )
-        {
-            i++;
-            continue;
-        }
-
-        paged++;
-
-        /* At least one gfn is still in paging state */
-        ioctlx.num = 1;
-        ioctlx.dom = dom;
-        ioctlx.addr = (unsigned long)addr + ((unsigned long)i<<XC_PAGE_SHIFT);
-        ioctlx.arr = arr + i;
-        ioctlx.err = err + i;
-        
-        /* Assemble a batch of requests */
-        while ( ++i < num )
-        {
-            if ( err[i] != -ENOENT )
-                break;
-            ioctlx.num++;
-        }
-        
-        /* Send request and abort on fatal error */
-        rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
-        if ( rc < 0 && errno != ENOENT )
-            goto out;
-
-    } while ( i < num );
-    
-    rc = paged;
-out:
-    return rc;
-}
-
-void *xc_map_foreign_bulk(xc_interface *xch,
-                          uint32_t dom, int prot,
-                          const xen_pfn_t *arr, int *err, unsigned int num)
-{
-    int fd = xch->privcmdfd;
-    privcmd_mmapbatch_v2_t ioctlx;
-    void *addr;
-    unsigned int i;
-    int rc;
-
-    addr = mmap(NULL, (unsigned long)num << XC_PAGE_SHIFT, prot, MAP_SHARED,
-                fd, 0);
-    if ( addr == MAP_FAILED )
-    {
-        PERROR("xc_map_foreign_bulk: mmap failed");
-        return NULL;
-    }
-
-    ioctlx.num = num;
-    ioctlx.dom = dom;
-    ioctlx.addr = (unsigned long)addr;
-    ioctlx.arr = arr;
-    ioctlx.err = err;
-
-    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
-
-    /* Command was recognized, some gfn in arr are in paging state */
-    if ( rc < 0 && errno == ENOENT )
-    {
-        do {
-            usleep(100);
-            rc = retry_paged(fd, dom, addr, arr, err, num);
-        } while ( rc > 0 );
-    }
-    /* Command was not recognized, use fall back */
-    else if ( rc < 0 && errno == EINVAL && (int)num > 0 )
-    {
-        /*
-         * IOCTL_PRIVCMD_MMAPBATCH_V2 is not supported - fall back to
-         * IOCTL_PRIVCMD_MMAPBATCH.
-         */
-        privcmd_mmapbatch_t ioctlx;
-        xen_pfn_t *pfn;
-        unsigned int pfn_arr_size = ROUNDUP((num * sizeof(*pfn)), 
XC_PAGE_SHIFT);
-
-        if ( pfn_arr_size <= XC_PAGE_SIZE )
-            pfn = alloca(num * sizeof(*pfn));
-        else
-        {
-            pfn = mmap(NULL, pfn_arr_size, PROT_READ | PROT_WRITE,
-                       MAP_PRIVATE | MAP_ANON | MAP_POPULATE, -1, 0);
-            if ( pfn == MAP_FAILED )
-            {
-                PERROR("xc_map_foreign_bulk: mmap of pfn array failed");
-                (void)munmap(addr, (unsigned long)num << XC_PAGE_SHIFT);
-                return NULL;
-            }
-        }
-
-        memcpy(pfn, arr, num * sizeof(*arr));
-
-        ioctlx.num = num;
-        ioctlx.dom = dom;
-        ioctlx.addr = (unsigned long)addr;
-        ioctlx.arr = pfn;
-
-        rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
-
-        rc = rc < 0 ? -errno : 0;
-
-        for ( i = 0; i < num; ++i )
-        {
-            switch ( pfn[i] ^ arr[i] )
-            {
-            case 0:
-                err[i] = rc != -ENOENT ? rc : 0;
-                continue;
-            default:
-                err[i] = -EINVAL;
-                continue;
-            case PRIVCMD_MMAPBATCH_PAGED_ERROR:
-                if ( rc != -ENOENT )
-                {
-                    err[i] = rc ?: -EINVAL;
-                    continue;
-                }
-                rc = map_foreign_batch_single(fd, dom, pfn + i,
-                        (unsigned long)addr + ((unsigned 
long)i<<XC_PAGE_SHIFT));
-                if ( rc < 0 )
-                {
-                    rc = -errno;
-                    break;
-                }
-                rc = -ENOENT;
-                continue;
-            }
-            break;
-        }
-
-        if ( pfn_arr_size > XC_PAGE_SIZE )
-            munmap(pfn, pfn_arr_size);
-
-        if ( rc == -ENOENT && i == num )
-            rc = 0;
-        else if ( rc )
-        {
-            errno = -rc;
-            rc = -1;
-        }
-    }
-
-    if ( rc < 0 )
-    {
-        int saved_errno = errno;
-
-        PERROR("xc_map_foreign_bulk: ioctl failed");
-        (void)munmap(addr, (unsigned long)num << XC_PAGE_SHIFT);
-        errno = saved_errno;
-        return NULL;
-    }
-
-    return addr;
-}
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/tools/libxc/xc_minios.c b/tools/libxc/xc_minios.c
index 1616c58..7373e54 100644
--- a/tools/libxc/xc_minios.c
+++ b/tools/libxc/xc_minios.c
@@ -40,40 +40,11 @@ void minios_interface_close_fd(int fd);
 
 extern void minios_interface_close_fd(int fd);
 
-int osdep_privcmd_open(xc_interface *xch)
-{
-    int fd = alloc_fd(FTYPE_XC);
-
-    if ( fd == -1)
-        return -1;
-
-    xch->privcmdfd = fd;
-    return 0;
-}
-
-int osdep_privcmd_close(xc_interface *xch)
-{
-    int fd = xch->privcmdfd;
-    return close(fd);
-}
-
 void minios_interface_close_fd(int fd)
 {
     files[fd].type = FTYPE_NONE;
 }
 
-void *xc_map_foreign_bulk(xc_interface *xch,
-                          uint32_t dom, int prot,
-                          const xen_pfn_t *arr, int *err, unsigned int num)
-{
-    unsigned long pt_prot = 0;
-    if (prot & PROT_READ)
-       pt_prot = L1_PROT_RO;
-    if (prot & PROT_WRITE)
-       pt_prot = L1_PROT;
-    return map_frames_ex(arr, num, 1, 0, 1, dom, err, pt_prot);
-}
-
 /* Optionally flush file to disk and discard page cache */
 void discard_file_cache(xc_interface *xch, int fd, int flush)
 {
diff --git a/tools/libxc/xc_netbsd.c b/tools/libxc/xc_netbsd.c
index 2654d18..8d6742d 100644
--- a/tools/libxc/xc_netbsd.c
+++ b/tools/libxc/xc_netbsd.c
@@ -23,79 +23,6 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <malloc.h>
-#include <sys/mman.h>
-
-int osdep_privcmd_open(xc_interface *xch)
-{
-    int flags, saved_errno;
-    int fd = open("/kern/xen/privcmd", O_RDWR);
-
-    if ( fd == -1 )
-    {
-        PERROR("Could not obtain handle on privileged command interface");
-        return -1;
-    }
-
-    /* Although we return the file handle as the 'xc handle' the API
-       does not specify / guarentee that this integer is in fact
-       a file handle. Thus we must take responsiblity to ensure
-       it doesn't propagate (ie leak) outside the process */
-    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
-    {
-        PERROR("Could not get file handle flags");
-        goto error;
-    }
-    flags |= FD_CLOEXEC;
-    if ( fcntl(fd, F_SETFD, flags) < 0 )
-    {
-        PERROR("Could not set file handle flags");
-        goto error;
-    }
-
-    xch->privcmdfd = fd;
-    return 0;
-
- error:
-    saved_errno = errno;
-    close(fd);
-    errno = saved_errno;
-    return -1;
-}
-
-int osdep_privcmd_close(xc_interface *xch)
-{
-    int fd = xch->privcmdfd;
-    return close(fd);
-}
-
-void *osdep_map_foreign_batch(xc_interface *xch,
-                              uint32_t dom, int prot,
-                              xen_pfn_t *arr, int num)
-{
-    int fd = xch->privcmdfd;
-    privcmd_mmapbatch_t ioctlx;
-    void *addr;
-    addr = mmap(NULL, num*XC_PAGE_SIZE, prot, MAP_ANON | MAP_SHARED, -1, 0);
-    if ( addr == MAP_FAILED ) {
-        PERROR("osdep_map_foreign_batch: mmap failed");
-        return NULL;
-    }
-
-    ioctlx.num=num;
-    ioctlx.dom=dom;
-    ioctlx.addr=(unsigned long)addr;
-    ioctlx.arr=arr;
-    if ( ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx) < 0 )
-    {
-        int saved_errno = errno;
-        PERROR("osdep_map_foreign_batch: ioctl failed");
-        (void)munmap(addr, num*XC_PAGE_SIZE);
-        errno = saved_errno;
-        return NULL;
-    }
-    return addr;
-
-}
 
 /* Optionally flush file to disk and discard page cache */
 void discard_file_cache(xc_interface *xch, int fd, int flush) 
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
index 00f96ba..94ec444 100644
--- a/tools/libxc/xc_private.c
+++ b/tools/libxc/xc_private.c
@@ -59,11 +59,12 @@ struct xc_interface_core 
*xc_interface_open(xentoollog_logger *logger,
     if (open_flags & XC_OPENFLAG_DUMMY)
         return xch; /* We are done */
 
-    if ( osdep_privcmd_open(xch) < 0 )
-        goto err;
-
     xch->xcall = xencall_open(xch->error_handler,
         open_flags & XC_OPENFLAG_NON_REENTRANT ? 
XENCALL_OPENFLAG_NON_REENTRANT : 0U);
+    if ( xch->xcall == NULL )
+        goto err;
+
+    xch->fmem = xenforeignmemory_open(xch->error_handler, 0);
 
     if ( xch->xcall == NULL )
         goto err;
@@ -71,7 +72,7 @@ struct xc_interface_core *xc_interface_open(xentoollog_logger 
*logger,
     return xch;
 
  err:
-    osdep_privcmd_close(xch);
+    xencall_close(xch->xcall);
     xtl_logger_destroy(xch->error_handler_tofree);
     if (xch != &xch_buf) free(xch);
     return NULL;
@@ -87,8 +88,8 @@ int xc_interface_close(xc_interface *xch)
     rc = xencall_close(xch->xcall);
     if (rc) PERROR("Could not close xencall interface");
 
-    rc = osdep_privcmd_close(xch);
-    if (rc) PERROR("Could not close hypervisor interface");
+    rc = xenforeignmemory_close(xch->fmem);
+    if (rc) PERROR("Could not close foreign memory interface");
 
     xtl_logger_destroy(xch->dombuild_logger_tofree);
     xtl_logger_destroy(xch->error_handler_tofree);
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index c8c2bdc..b230854 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -30,8 +30,13 @@
 #include <sys/ioctl.h>
 
 #include "_paths.h"
+
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
+#define XC_INTERNAL_COMPAT_MAP_FOREIGN_API
 #include "xenctrl.h"
+
 #include <xencall.h>
+#include <xenforeignmemory.h>
 
 #include <xen/sys/privcmd.h>
 
@@ -95,11 +100,11 @@ struct xc_interface_core {
     FILE *dombuild_logger_file;
     const char *currently_progress_reporting;
 
-    /* Privcmd interface */
-    int privcmdfd;
-
     /* Hypercall interface */
     xencall_handle *xcall;
+
+    /* Foreign mappings */
+    xenforeignmemory_handle *fmem;
 };
 
 int osdep_privcmd_open(xc_interface *xch);
diff --git a/tools/libxc/xc_solaris.c b/tools/libxc/xc_solaris.c
index e1e126d..c2e87d1 100644
--- a/tools/libxc/xc_solaris.c
+++ b/tools/libxc/xc_solaris.c
@@ -20,81 +20,8 @@
 
 #include "xc_private.h"
 
-#include <xen/memory.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <malloc.h>
 
-int osdep_privcmd_open(xc_interface *xch)
-{
-    int flags, saved_errno;
-    int fd = open("/dev/xen/privcmd", O_RDWR);
-
-    if ( fd == -1 )
-    {
-        PERROR("Could not obtain handle on privileged command interface");
-        return -1;
-    }
-
-    /* Although we return the file handle as the 'xc handle' the API
-       does not specify / guarentee that this integer is in fact
-       a file handle. Thus we must take responsiblity to ensure
-       it doesn't propagate (ie leak) outside the process */
-    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
-    {
-        PERROR("Could not get file handle flags");
-        goto error;
-    }
-    flags |= FD_CLOEXEC;
-    if ( fcntl(fd, F_SETFD, flags) < 0 )
-    {
-        PERROR("Could not set file handle flags");
-        goto error;
-    }
-
-    xch->privcmdfd = fd;
-    return 0;
-
- error:
-    saved_errno = errno;
-    close(fd);
-    errno = saved_errno;
-    return -1;
-}
-
-int osdep_privcmd_close(xc_interface *xch)
-{
-    int fd = xch->privcmdfd;
-    return close(fd);
-}
-
-void *osdep_map_foreign_batch(xc_interface *xch,
-                              uint32_t dom, int prot,
-                              xen_pfn_t *arr, int num)
-{
-    int fd = xch->privcmdfd;
-    privcmd_mmapbatch_t ioctlx;
-    void *addr;
-    addr = mmap(NULL, num*XC_PAGE_SIZE, prot, MAP_SHARED, fd, 0);
-    if ( addr == MAP_FAILED )
-        return NULL;
-
-    ioctlx.num=num;
-    ioctlx.dom=dom;
-    ioctlx.addr=(unsigned long)addr;
-    ioctlx.arr=arr;
-    if ( ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx) < 0 )
-    {
-        int saved_errno = errno;
-        PERROR("XXXXXXXX");
-        (void)munmap(addr, num*XC_PAGE_SIZE);
-        errno = saved_errno;
-        return NULL;
-    }
-    return addr;
-
-}
-
 /* Optionally flush file to disk and discard page cache */
 void discard_file_cache(xc_interface *xch, int fd, int flush) 
 {
diff --git a/tools/libxc/xc_sr_restore.c b/tools/libxc/xc_sr_restore.c
index bf1ee15..4bbda9d 100644
--- a/tools/libxc/xc_sr_restore.c
+++ b/tools/libxc/xc_sr_restore.c
@@ -315,8 +315,8 @@ static int process_page_data(struct xc_sr_context *ctx, 
unsigned count,
     if ( nr_pages == 0 )
         goto done;
 
-    mapping = guest_page = xc_map_foreign_bulk(
-        xch, ctx->domid, PROT_READ | PROT_WRITE,
+    mapping = guest_page = xenforeignmemory_map(xch->fmem,
+        ctx->domid, PROT_READ | PROT_WRITE,
         mfns, map_errs, nr_pages);
     if ( !mapping )
     {
diff --git a/tools/libxc/xc_sr_save.c b/tools/libxc/xc_sr_save.c
index d63b783..2672ad3 100644
--- a/tools/libxc/xc_sr_save.c
+++ b/tools/libxc/xc_sr_save.c
@@ -153,8 +153,8 @@ static int write_batch(struct xc_sr_context *ctx)
 
     if ( nr_pages > 0 )
     {
-        guest_mapping = xc_map_foreign_bulk(
-            xch, ctx->domid, PROT_READ, mfns, errors, nr_pages);
+        guest_mapping = xenforeignmemory_map(xch->fmem,
+            ctx->domid, PROT_READ, mfns, errors, nr_pages);
         if ( !guest_mapping )
         {
             PERROR("Failed to map guest pages");
diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
index 4d7e7cc..940efd7 100644
--- a/tools/libxc/xc_vm_event.c
+++ b/tools/libxc/xc_vm_event.c
@@ -74,8 +74,9 @@ void *xc_vm_event_enable(xc_interface *xch, domid_t 
domain_id, int param,
 
     ring_pfn = pfn;
     mmap_pfn = pfn;
-    ring_page = xc_map_foreign_bulk(xch, domain_id, PROT_READ | PROT_WRITE,
-                                   &mmap_pfn, &err, 1);
+    ring_page = xenforeignmemory_map(xch->fmem,
+                                    domain_id, PROT_READ | PROT_WRITE,
+                                    &mmap_pfn, &err, 1);
     if ( !ring_page )
     {
         /* Map failed, populate ring page */
@@ -88,8 +89,9 @@ void *xc_vm_event_enable(xc_interface *xch, domid_t 
domain_id, int param,
         }
 
         mmap_pfn = ring_pfn;
-        ring_page = xc_map_foreign_bulk(xch, domain_id, PROT_READ | PROT_WRITE,
-                                       &mmap_pfn, &err, 1);
+        ring_page = xenforeignmemory_map(xch->fmem,
+                                        domain_id, PROT_READ | PROT_WRITE,
+                                        &mmap_pfn, &err, 1);
         if ( !ring_page )
         {
             PERROR("Could not map the ring page: %d\n", err);
diff --git a/tools/libxc/xg_private.h b/tools/libxc/xg_private.h
index 1910361..0baf403 100644
--- a/tools/libxc/xg_private.h
+++ b/tools/libxc/xg_private.h
@@ -27,9 +27,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include "xenctrl.h"
-#include "xenguest.h"
 #include "xc_private.h"
+#include "xenguest.h"
 
 #include <xen/memory.h>
 #include <xen/elfnote.h>
diff --git a/tools/libxenforeignmemory/Makefile 
b/tools/libxenforeignmemory/Makefile
new file mode 100644
index 0000000..4c84115
--- /dev/null
+++ b/tools/libxenforeignmemory/Makefile
@@ -0,0 +1,67 @@
+XEN_ROOT = $(CURDIR)/../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+MAJOR    = 1
+MINOR    = 0
+SHLIB_LDFLAGS += -Wl,--version-script=libxenforeignmemory.map
+
+CFLAGS   += -Werror -Wmissing-prototypes
+CFLAGS   += -I./include $(CFLAGS_xeninclude)
+CFLAGS   += $(CFLAGS_libxentoollog)
+
+SRCS-y                 += core.c
+SRCS-$(CONFIG_Linux)   += linux.c
+SRCS-$(CONFIG_FreeBSD) += freebsd.c
+SRCS-$(CONFIG_SunOS)   += compat.c solaris.c
+SRCS-$(CONFIG_NetBSD)  += compat.c netbsd.c
+SRCS-$(CONFIG_MiniOS)  += minios.c
+
+LIB_OBJS := $(patsubst %.c,%.o,$(SRCS-y))
+PIC_OBJS := $(patsubst %.c,%.opic,$(SRCS-y))
+
+LIB := libxenforeignmemory.a
+ifneq ($(nosharedlibs),y)
+LIB += libxenforeignmemory.so
+endif
+
+.PHONY: all
+all: build
+
+.PHONY: build
+build:
+       $(MAKE) libs
+
+.PHONY: libs
+libs: headers.chk $(LIB)
+
+headers.chk: $(wildcard include/*.h)
+
+libxenforeignmemory.a: $(LIB_OBJS)
+       $(AR) rc $@ $^
+
+libxenforeignmemory.so: libxenforeignmemory.so.$(MAJOR)
+       $(SYMLINK_SHLIB) $< $@
+libxenforeignmemory.so.$(MAJOR): libxenforeignmemory.so.$(MAJOR).$(MINOR)
+       $(SYMLINK_SHLIB) $< $@
+
+libxenforeignmemory.so.$(MAJOR).$(MINOR): $(PIC_OBJS) libxenforeignmemory.map
+       $(CC) $(LDFLAGS) $(PTHREAD_LDFLAGS) -Wl,$(SONAME_LDFLAG) 
-Wl,libxenforeignmemory.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $(PIC_OBJS) 
$(LDLIBS_libxentoollog) $(APPEND_LDFLAGS)
+
+.PHONY: install
+install: build
+       $(INSTALL_DIR) $(DESTDIR)$(libdir)
+       $(INSTALL_DIR) $(DESTDIR)$(includedir)
+       $(INSTALL_SHLIB) libxenforeignmemory.so.$(MAJOR).$(MINOR) 
$(DESTDIR)$(libdir)
+       $(INSTALL_DATA) libxenforeignmemory.a $(DESTDIR)$(libdir)
+       $(SYMLINK_SHLIB) libxenforeignmemory.so.$(MAJOR).$(MINOR) 
$(DESTDIR)$(libdir)/libxenforeignmemory.so.$(MAJOR)
+       $(SYMLINK_SHLIB) libxenforeignmemory.so.$(MAJOR) 
$(DESTDIR)$(libdir)/libxenforeignmemory.so
+       $(INSTALL_DATA) include/xenforeignmemory.h $(DESTDIR)$(includedir)
+
+.PHONY: TAGS
+TAGS:
+       etags -t *.c *.h
+
+.PHONY: clean
+clean:
+       rm -rf *.rpm $(LIB) *~ $(DEPS) $(LIB_OBJS) $(PIC_OBJS)
+       rm -f headers.chk
diff --git a/tools/libxenforeignmemory/compat.c 
b/tools/libxenforeignmemory/compat.c
new file mode 100644
index 0000000..0d2cf36
--- /dev/null
+++ b/tools/libxenforeignmemory/compat.c
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ * Compatibility functions for mapping foreign domain's memory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Split out from xc_foreign_memory.c
+ */
+#if !defined(__NetBSD__) && !defined(__sun__)
+#error Please implement xc_map_foreign_bulk directly for new ports.
+#endif
+
+#include "private.h"
+
+void *xc_map_foreign_bulk(xenforeignmem_handle *fmem,
+                          uint32_t dom, int prot,
+                          const xen_pfn_t *arr, int *err, unsigned int num)
+{
+    xen_pfn_t *pfn;
+    unsigned int i;
+    void *ret;
+
+    if ((int)num <= 0) {
+        errno = EINVAL;
+        return NULL;
+    }
+
+    pfn = malloc(num * sizeof(*pfn));
+    if (!pfn) {
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    memcpy(pfn, arr, num * sizeof(*arr));
+    ret = osdep_map_foreign_batch(fmem, dom, prot, pfn, num);
+
+    if (ret) {
+        for (i = 0; i < num; ++i)
+            switch (pfn[i] ^ arr[i]) {
+            case 0:
+                err[i] = 0;
+                break;
+            default:
+                err[i] = -EINVAL;
+                break;
+            }
+    } else
+        memset(err, 0, num * sizeof(*err));
+
+    free(pfn);
+
+    return ret;
+}
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxenforeignmemory/core.c b/tools/libxenforeignmemory/core.c
new file mode 100644
index 0000000..efb3e54
--- /dev/null
+++ b/tools/libxenforeignmemory/core.c
@@ -0,0 +1,65 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ */
+
+#include <stdlib.h>
+
+#include "private.h"
+
+xenforeignmemory_handle *xenforeignmemory_open(xentoollog_logger *logger,
+                                               unsigned open_flags)
+{
+    xenforeignmemory_handle *fmem = malloc(sizeof(*fmem));
+    int rc;
+
+    if (!fmem) return NULL;
+
+    fmem->logger = logger;
+    fmem->logger_tofree = NULL;
+
+    if (!fmem->logger) {
+        fmem->logger = fmem->logger_tofree =
+            (xentoollog_logger*)
+            xtl_createlogger_stdiostream(stderr, XTL_PROGRESS, 0);
+        if (!fmem->logger) goto err;
+    }
+
+    rc = osdep_xenforeignmemory_open(fmem);
+    if ( rc  < 0 ) goto err;
+
+    return fmem;
+
+err:
+    osdep_xenforeignmemory_close(fmem);
+    xtl_logger_destroy(fmem->logger_tofree);
+    free(fmem);
+    return NULL;
+}
+
+int xenforeignmemory_close(xenforeignmemory_handle *fmem)
+{
+    int rc;
+
+    rc = osdep_xenforeignmemory_close(fmem);
+    xtl_logger_destroy(fmem->logger_tofree);
+    free(fmem);
+    return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxenforeignmemory/freebsd.c 
b/tools/libxenforeignmemory/freebsd.c
new file mode 100644
index 0000000..b93db51
--- /dev/null
+++ b/tools/libxenforeignmemory/freebsd.c
@@ -0,0 +1,126 @@
+ 
/******************************************************************************
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "private.h"
+
+#define PRIVCMD_DEV     "/dev/xen/privcmd"
+
+int osdep_xenforeignmemory_open(xenforeignmemory_handle *fmem)
+{
+    int flags, saved_errno;
+    int fd = open(PRIVCMD_DEV, O_RDWR);
+
+    if ( fd == -1 )
+    {
+        PERROR("Could not obtain handle on privileged command interface "
+               PRIVCMD_DEV);
+        return -1;
+    }
+
+    /*
+     * Although we return the file handle as the 'xc handle' the API
+     * does not specify / guarentee that this integer is in fact
+     * a file handle. Thus we must take responsiblity to ensure
+     * it doesn't propagate (ie leak) outside the process.
+     */
+    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
+    {
+        PERROR("Could not get file handle flags");
+        goto error;
+    }
+
+    flags |= FD_CLOEXEC;
+
+    if ( fcntl(fd, F_SETFD, flags) < 0 )
+    {
+        PERROR("Could not set file handle flags");
+        goto error;
+    }
+
+    fmem->fd = fd;
+    return 0;
+
+ error:
+    saved_errno = errno;
+    close(fd);
+    errno = saved_errno;
+
+    return -1;
+}
+
+int osdep_xenforeignmemory_close(xenforeignmemory_handle *fmem)
+{
+    int fd = fmem->fd;
+    if ( fd == -1 )
+        return 0;
+    return close(fd);
+}
+
+void *xenforeignmemory_map(xenforeignmemory_handle *fmem,
+                           uint32_t dom, int prot,
+                           const xen_pfn_t *arr, int *err,
+                           unsigned int num)
+{
+    int fd = fmem->fd;
+    privcmd_mmapbatch_t ioctlx;
+    void *addr;
+    int rc;
+
+    addr = mmap(NULL, num << PAGE_SHIFT, prot, MAP_SHARED, fd, 0);
+    if ( addr == MAP_FAILED )
+    {
+        PERROR("xc_map_foreign_bulk: mmap failed");
+        return NULL;
+    }
+
+    ioctlx.num = num;
+    ioctlx.dom = dom;
+    ioctlx.addr = (unsigned long)addr;
+    ioctlx.arr = arr;
+    ioctlx.err = err;
+
+    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
+    if ( rc < 0 )
+    {
+        int saved_errno = errno;
+        PERROR("xc_map_foreign_bulk: ioctl failed");
+        (void)munmap(addr, num << PAGE_SHIFT);
+        errno = saved_errno;
+        return NULL;
+    }
+
+    return addr;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxenforeignmemory/include/xenforeignmemory.h 
b/tools/libxenforeignmemory/include/xenforeignmemory.h
new file mode 100644
index 0000000..3f3d1c7
--- /dev/null
+++ b/tools/libxenforeignmemory/include/xenforeignmemory.h
@@ -0,0 +1,68 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ */
+#ifndef XENFOREIGNMEMORY_H
+#define XENFOREIGNMEMORY_H
+
+/*
+ * This library allows you to map foreign domain memory, subject to
+ * permissions for both the process and the domain in which the
+ * process runs.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <xen/xen.h>
+
+/* Callers who don't care don't need to #include <xentoollog.h> */
+typedef struct xentoollog_logger xentoollog_logger;
+
+typedef struct xenforeignmemory_handle xenforeignmemory_handle;
+
+/*
+ * Return a handle onto the hypercall driver.  Logs errors.
+ */
+xenforeignmemory_handle *xenforeignmemory_open(xentoollog_logger *logger,
+                                               unsigned open_flags);
+
+/*
+ * Close a handle previously allocated with xenforeignmemory_open().
+ */
+int xenforeignmemory_close(xenforeignmemory_handle *xmem);
+
+/*
+ * Maps a range within one domain to a local address range.  Mappings
+ * should be unmapped with munmap and should follow the same rules as mmap
+ * regarding page alignment.
+ *
+ * prot is as for mmap(2).
+ *
+ * Can partially succeed. When a page cannot be mapped, its respective
+ * field in @err is set to the corresponding errno value.
+ *
+ * Returns NULL if no pages can be mapped.
+ */
+void *xenforeignmemory_map(xenforeignmemory_handle *fmem, uint32_t dom,
+                           int prot, const xen_pfn_t *arr, int *err,
+                           unsigned int num);
+
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxenforeignmemory/libxenforeignmemory.map 
b/tools/libxenforeignmemory/libxenforeignmemory.map
new file mode 100644
index 0000000..11f0d2b
--- /dev/null
+++ b/tools/libxenforeignmemory/libxenforeignmemory.map
@@ -0,0 +1,7 @@
+VERS_1.0 {
+       global:
+               xenforeignmemory_open;
+               xenforeignmemory_close;
+               xenforeignmemory_map;
+       local: *; /* Do not expose anything by default */
+};
diff --git a/tools/libxenforeignmemory/linux.c 
b/tools/libxenforeignmemory/linux.c
new file mode 100644
index 0000000..6343ebe
--- /dev/null
+++ b/tools/libxenforeignmemory/linux.c
@@ -0,0 +1,284 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Split out from xc_linus_osdep.c:
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ */
+
+#include <alloca.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "private.h"
+
+#define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
+
+int osdep_xenforeignmemory_open(xenforeignmemory_handle *fmem)
+{
+    int flags, saved_errno;
+    int fd = open("/proc/xen/privcmd", O_RDWR);
+
+    if ( fd == -1 )
+    {
+        PERROR("Could not obtain handle on privileged command interface");
+        return -1;
+    }
+
+    /* Although we return the file handle as the 'xc handle' the API
+       does not specify / guarentee that this integer is in fact
+       a file handle. Thus we must take responsiblity to ensure
+       it doesn't propagate (ie leak) outside the process */
+    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
+    {
+        PERROR("Could not get file handle flags");
+        goto error;
+    }
+
+    flags |= FD_CLOEXEC;
+
+    if ( fcntl(fd, F_SETFD, flags) < 0 )
+    {
+        PERROR("Could not set file handle flags");
+        goto error;
+    }
+
+    fmem->fd = fd;
+    return 0;
+
+ error:
+    saved_errno = errno;
+    close(fd);
+    errno = saved_errno;
+    return -1;
+}
+
+int osdep_xenforeignmemory_close(xenforeignmemory_handle *fmem)
+{
+    int fd = fmem->fd;
+    if (fd == -1)
+        return 0;
+    return close(fd);
+}
+
+static int map_foreign_batch_single(int fd, uint32_t dom,
+                                    xen_pfn_t *mfn, unsigned long addr)
+{
+    privcmd_mmapbatch_t ioctlx;
+    int rc;
+
+    ioctlx.num = 1;
+    ioctlx.dom = dom;
+    ioctlx.addr = addr;
+    ioctlx.arr = mfn;
+
+    do
+    {
+        *mfn ^= PRIVCMD_MMAPBATCH_PAGED_ERROR;
+        usleep(100);
+        rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
+    }
+    while ( (rc < 0) && (errno == ENOENT) );
+
+    return rc;
+}
+
+/*
+ * Retry mmap of all paged gfns in batches
+ * retuns < 0 on fatal error
+ * returns 0 if all gfns left paging state
+ * returns > 0 if some gfns are still in paging state
+ *
+ * Walk all gfns and try to assemble blocks of gfns in paging state.
+ * This will keep the request ring full and avoids delays.
+ */
+static int retry_paged(int fd, uint32_t dom, void *addr,
+                       const xen_pfn_t *arr, int *err, unsigned int num)
+{
+    privcmd_mmapbatch_v2_t ioctlx;
+    int rc, paged = 0, i = 0;
+
+    do
+    {
+        /* Skip gfns not in paging state */
+        if ( err[i] != -ENOENT )
+        {
+            i++;
+            continue;
+        }
+
+        paged++;
+
+        /* At least one gfn is still in paging state */
+        ioctlx.num = 1;
+        ioctlx.dom = dom;
+        ioctlx.addr = (unsigned long)addr + ((unsigned long)i<<PAGE_SHIFT);
+        ioctlx.arr = arr + i;
+        ioctlx.err = err + i;
+
+        /* Assemble a batch of requests */
+        while ( ++i < num )
+        {
+            if ( err[i] != -ENOENT )
+                break;
+            ioctlx.num++;
+        }
+
+        /* Send request and abort on fatal error */
+        rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
+        if ( rc < 0 && errno != ENOENT )
+            goto out;
+
+    } while ( i < num );
+
+    rc = paged;
+out:
+    return rc;
+}
+
+void *xenforeignmemory_map(xenforeignmemory_handle *fmem,
+                          uint32_t dom, int prot,
+                          const xen_pfn_t *arr, int *err, unsigned int num)
+{
+    int fd = fmem->fd;
+    privcmd_mmapbatch_v2_t ioctlx;
+    void *addr;
+    unsigned int i;
+    int rc;
+
+    addr = mmap(NULL, (unsigned long)num << PAGE_SHIFT, prot, MAP_SHARED,
+                fd, 0);
+    if ( addr == MAP_FAILED )
+    {
+        PERROR("mmap failed");
+        return NULL;
+    }
+
+    ioctlx.num = num;
+    ioctlx.dom = dom;
+    ioctlx.addr = (unsigned long)addr;
+    ioctlx.arr = arr;
+    ioctlx.err = err;
+
+    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
+
+    /* Command was recognized, some gfn in arr are in paging state */
+    if ( rc < 0 && errno == ENOENT )
+    {
+        do {
+            usleep(100);
+            rc = retry_paged(fd, dom, addr, arr, err, num);
+        } while ( rc > 0 );
+    }
+    /* Command was not recognized, use fall back */
+    else if ( rc < 0 && errno == EINVAL && (int)num > 0 )
+    {
+        /*
+         * IOCTL_PRIVCMD_MMAPBATCH_V2 is not supported - fall back to
+         * IOCTL_PRIVCMD_MMAPBATCH.
+         */
+        privcmd_mmapbatch_t ioctlx;
+        xen_pfn_t *pfn;
+        unsigned int pfn_arr_size = ROUNDUP((num * sizeof(*pfn)), PAGE_SHIFT);
+
+        if ( pfn_arr_size <= PAGE_SIZE )
+            pfn = alloca(num * sizeof(*pfn));
+        else
+        {
+            pfn = mmap(NULL, pfn_arr_size, PROT_READ | PROT_WRITE,
+                       MAP_PRIVATE | MAP_ANON | MAP_POPULATE, -1, 0);
+            if ( pfn == MAP_FAILED )
+            {
+                PERROR("mmap of pfn array failed");
+                (void)munmap(addr, (unsigned long)num << PAGE_SHIFT);
+                return NULL;
+            }
+        }
+
+        memcpy(pfn, arr, num * sizeof(*arr));
+
+        ioctlx.num = num;
+        ioctlx.dom = dom;
+        ioctlx.addr = (unsigned long)addr;
+        ioctlx.arr = pfn;
+
+        rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
+
+        rc = rc < 0 ? -errno : 0;
+
+        for ( i = 0; i < num; ++i )
+        {
+            switch ( pfn[i] ^ arr[i] )
+            {
+            case 0:
+                err[i] = rc != -ENOENT ? rc : 0;
+                continue;
+            default:
+                err[i] = -EINVAL;
+                continue;
+            case PRIVCMD_MMAPBATCH_PAGED_ERROR:
+                if ( rc != -ENOENT )
+                {
+                    err[i] = rc ?: -EINVAL;
+                    continue;
+                }
+                rc = map_foreign_batch_single(fd, dom, pfn + i,
+                        (unsigned long)addr + ((unsigned long)i<<PAGE_SHIFT));
+                if ( rc < 0 )
+                {
+                    rc = -errno;
+                    break;
+                }
+                rc = -ENOENT;
+                continue;
+            }
+            break;
+        }
+
+        if ( pfn_arr_size > PAGE_SIZE )
+            munmap(pfn, pfn_arr_size);
+
+        if ( rc == -ENOENT && i == num )
+            rc = 0;
+        else if ( rc )
+        {
+            errno = -rc;
+            rc = -1;
+        }
+    }
+
+    if ( rc < 0 )
+    {
+        int saved_errno = errno;
+
+        PERROR("ioctl failed");
+        (void)munmap(addr, (unsigned long)num << PAGE_SHIFT);
+        errno = saved_errno;
+        return NULL;
+    }
+
+    return addr;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxenforeignmemory/minios.c 
b/tools/libxenforeignmemory/minios.c
new file mode 100644
index 0000000..ac7c0ce
--- /dev/null
+++ b/tools/libxenforeignmemory/minios.c
@@ -0,0 +1,59 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * Split out from xc_minios.c
+ *
+ * Copyright 2007-2008 Samuel Thibault <samuel.thibault@xxxxxxxxxxxxx>.
+ */
+
+#include <mini-os/types.h>
+#include <mini-os/os.h>
+#include <mini-os/mm.h>
+#include <mini-os/lib.h>
+
+#include <errno.h>
+
+#include <sys/mman.h>
+
+#include "private.h"
+
+int osdep_xenforeignmemory_open(xenforeignmemory_handle *fmem)
+{
+    /* No fd required */
+    return 0;
+}
+
+int osdep_xenforeignmemory_close(xenforeignmemory_handle *fmem)
+{
+    return 0;
+}
+
+void *xenforeignmemory_map(xenforeignmemory_handle *fmem,
+                          uint32_t dom, int prot,
+                          const xen_pfn_t *arr, int *err, unsigned int num)
+{
+    unsigned long pt_prot = 0;
+    if (prot & PROT_READ)
+       pt_prot = L1_PROT_RO;
+    if (prot & PROT_WRITE)
+       pt_prot = L1_PROT;
+    return map_frames_ex(arr, num, 1, 0, 1, dom, err, pt_prot);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxenforeignmemory/netbsd.c 
b/tools/libxenforeignmemory/netbsd.c
new file mode 100644
index 0000000..b2d8b88
--- /dev/null
+++ b/tools/libxenforeignmemory/netbsd.c
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "private.h"
+
+int osdep_xenforeignmemory_open(xenforeignmemory_handle *fmem)
+{
+    int flags, saved_errno;
+    int fd = open("/kern/xen/privcmd", O_RDWR);
+
+    if ( fd == -1 )
+    {
+        PERROR("Could not obtain handle on privileged command interface");
+        return -1;
+    }
+
+    /* Although we return the file handle as the 'xc handle' the API
+       does not specify / guarentee that this integer is in fact
+       a file handle. Thus we must take responsiblity to ensure
+       it doesn't propagate (ie leak) outside the process */
+    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
+    {
+        PERROR("Could not get file handle flags");
+        goto error;
+    }
+    flags |= FD_CLOEXEC;
+    if ( fcntl(fd, F_SETFD, flags) < 0 )
+    {
+        PERROR("Could not set file handle flags");
+        goto error;
+    }
+
+    fmem->fd = fd;
+    return 0;
+
+ error:
+    saved_errno = errno;
+    close(fd);
+    errno = saved_errno;
+    return -1;
+}
+
+int osdep_xenforeignmemory_close(xenforeignmemory_handle *fmem)
+{
+    int fd = fmem->fd;
+    return close(fd);
+}
+
+void *compat_mapforeign_batch(xenforeignmem_handle *fmem, uint32_t dom,
+                              int prot, xen_pfn_t *arr, int num)
+{
+    int fd = fmem->fd;
+    privcmd_mmapbatch_t ioctlx;
+    void *addr;
+    addr = mmap(NULL, num*XC_PAGE_SIZE, prot, MAP_ANON | MAP_SHARED, -1, 0);
+    if ( addr == MAP_FAILED ) {
+        PERROR("osdep_map_foreign_batch: mmap failed");
+        return NULL;
+    }
+
+    ioctlx.num=num;
+    ioctlx.dom=dom;
+    ioctlx.addr=(unsigned long)addr;
+    ioctlx.arr=arr;
+    if ( ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx) < 0 )
+    {
+        int saved_errno = errno;
+        PERROR("osdep_map_foreign_batch: ioctl failed");
+        (void)munmap(addr, num*XC_PAGE_SIZE);
+        errno = saved_errno;
+        return NULL;
+    }
+    return addr;
+
+}
diff --git a/tools/libxenforeignmemory/private.h 
b/tools/libxenforeignmemory/private.h
new file mode 100644
index 0000000..54dd7d5
--- /dev/null
+++ b/tools/libxenforeignmemory/private.h
@@ -0,0 +1,47 @@
+#ifndef XENFOREIGNMEMORY_PRIVATE_H
+#define XENFOREIGNMEMORY_PRIVATE_H
+
+#include <xentoollog.h>
+
+#include <xenforeignmemory.h>
+
+#include <xen/xen.h>
+#include <xen/sys/privcmd.h>
+
+#ifndef PAGE_SHIFT /* Mini-os, Yukk */
+#define PAGE_SHIFT           12
+#endif
+#ifndef __MINIOS__ /* Yukk */
+#define PAGE_SIZE            (1UL << PAGE_SHIFT)
+#define PAGE_MASK            (~(PAGE_SIZE-1))
+#endif
+
+struct xenforeignmemory_handle {
+    xentoollog_logger *logger, *logger_tofree;
+    unsigned flags;
+    int fd;
+};
+
+int osdep_xenforeignmemory_open(xenforeignmemory_handle *fmem);
+int osdep_xenforeignmemory_close(xenforeignmemory_handle *fmem);
+
+#if defined(__NetBSD__) || defined(__sun__)
+/* Strictly compat for those two only only */
+void *compat_mapforeign_batch(xenforeignmem_handle *fmem, uint32_t dom,
+                              int prot, xen_pfn_t *arr, int num);
+#endif
+
+#define PERROR(_f...) \
+       xtl_log(fmem->logger, XTL_ERROR, errno, "xenforeignmemory", _f)
+
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxenforeignmemory/solaris.c 
b/tools/libxenforeignmemory/solaris.c
new file mode 100644
index 0000000..035484b
--- /dev/null
+++ b/tools/libxenforeignmemory/solaris.c
@@ -0,0 +1,95 @@
+/******************************************************************************
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+ */
+
+#include "xc_private.h"
+
+#include <xen/memory.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <malloc.h>
+
+int osdep_xenforeignmemory_open(xenforeignmemory_handle *fmem)
+{
+    int flags, saved_errno;
+    int fd = open("/dev/xen/privcmd", O_RDWR);
+
+    if ( fd == -1 )
+    {
+        PERROR("Could not obtain handle on privileged command interface");
+        return -1;
+    }
+
+    /* Although we return the file handle as the 'xc handle' the API
+       does not specify / guarentee that this integer is in fact
+       a file handle. Thus we must take responsiblity to ensure
+       it doesn't propagate (ie leak) outside the process */
+    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
+    {
+        PERROR("Could not get file handle flags");
+        goto error;
+    }
+    flags |= FD_CLOEXEC;
+    if ( fcntl(fd, F_SETFD, flags) < 0 )
+    {
+        PERROR("Could not set file handle flags");
+        goto error;
+    }
+
+    fmem->fd = fd;
+    return 0;
+
+ error:
+    saved_errno = errno;
+    close(fd);
+    errno = saved_errno;
+    return -1;
+}
+
+int osdep_xenforeignmemory_close(xenforeignmemory_handle *fmem)
+{
+    int fd = fmem->fd;
+    return close(fd);
+}
+
+void *compat_mapforeign_batch(xenforeignmem_handle *fmem, uint32_t dom,
+                              int prot, xen_pfn_t *arr, int num)
+{
+    int fd = fmem->fd;
+    privcmd_mmapbatch_t ioctlx;
+    void *addr;
+    addr = mmap(NULL, num*XC_PAGE_SIZE, prot, MAP_SHARED, fd, 0);
+    if ( addr == MAP_FAILED )
+        return NULL;
+
+    ioctlx.num=num;
+    ioctlx.dom=dom;
+    ioctlx.addr=(unsigned long)addr;
+    ioctlx.arr=arr;
+    if ( ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx) < 0 )
+    {
+        int saved_errno = errno;
+        PERROR("XXXXXXXX");
+        (void)munmap(addr, num*XC_PAGE_SIZE);
+        errno = saved_errno;
+        return NULL;
+    }
+    return addr;
+
+}
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 4b59cad..101acb0 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -50,6 +50,7 @@
 
 #include <xenevtchn.h>
 #include <xenstore.h>
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
 #include <xenctrl.h>
 #include <xenguest.h>
 
diff --git a/tools/misc/xen-mfndump.c b/tools/misc/xen-mfndump.c
index ceeeaa9..1b22ad7 100644
--- a/tools/misc/xen-mfndump.c
+++ b/tools/misc/xen-mfndump.c
@@ -1,3 +1,4 @@
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
 #include <xenctrl.h>
 #include <xc_private.h>
 #include <xc_core.h>
diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c 
b/tools/ocaml/libs/xc/xenctrl_stubs.c
index 9a201ee..1f5aba7 100644
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -29,6 +29,7 @@
 #include <stdint.h>
 #include <string.h>
 
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
 #include <xenctrl.h>
 
 #include "mmap_stubs.h"
diff --git a/tools/python/xen/lowlevel/xc/xc.c 
b/tools/python/xen/lowlevel/xc/xc.c
index ee3e1d0..6750ee1 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -5,6 +5,7 @@
  */
 
 #include <Python.h>
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
 #include <xenctrl.h>
 #include <xenguest.h>
 #include <zlib.h>
@@ -17,7 +18,6 @@
 #include <netdb.h>
 #include <arpa/inet.h>
 
-#include "xenctrl.h"
 #include <xen/elfnote.h>
 #include <xen/tmem.h>
 #include "xc_dom.h"
diff --git a/tools/xenmon/xenbaked.c b/tools/xenmon/xenbaked.c
index 9e2a49b..ad77286 100644
--- a/tools/xenmon/xenbaked.c
+++ b/tools/xenmon/xenbaked.c
@@ -39,6 +39,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <xenevtchn.h>
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
 #include <xenctrl.h>
 #include <xen/xen.h>
 #include <string.h>
diff --git a/tools/xenpaging/pagein.c b/tools/xenpaging/pagein.c
index 18699ec..0ea8680 100644
--- a/tools/xenpaging/pagein.c
+++ b/tools/xenpaging/pagein.c
@@ -1,6 +1,5 @@
 /* Trigger a page-in in a separate thread-of-execution to avoid deadlock */
 #include <pthread.h>
-#include <xc_private.h>
 #include "xenpaging.h"
 
 struct page_in_args {
diff --git a/tools/xenpaging/xenpaging.c b/tools/xenpaging/xenpaging.c
index a819a5b..8a05e98 100644
--- a/tools/xenpaging/xenpaging.c
+++ b/tools/xenpaging/xenpaging.c
@@ -28,7 +28,6 @@
 #include <signal.h>
 #include <unistd.h>
 #include <poll.h>
-#include <xc_private.h>
 #include <xenstore.h>
 #include <getopt.h>
 
diff --git a/tools/xenpaging/xenpaging.h b/tools/xenpaging/xenpaging.h
index 6c12030..3cdd1a8 100644
--- a/tools/xenpaging/xenpaging.h
+++ b/tools/xenpaging/xenpaging.h
@@ -26,6 +26,8 @@
 
 
 #include <xenevtchn.h>
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
+#include <xenctrl.h>
 #include <xc_private.h>
 #include <xen/event_channel.h>
 #include <xen/vm_event.h>
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 7f1e489..120fd64 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -51,7 +51,6 @@
 #include "xenstored_watch.h"
 #include "xenstored_transaction.h"
 #include "xenstored_domain.h"
-#include "xenctrl.h"
 #include "tdb.h"
 
 #include "hashtable.h"
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 2b01076..e0fa843 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -20,6 +20,7 @@
 #ifndef _XENSTORED_CORE_H
 #define _XENSTORED_CORE_H
 
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
 #include <xenctrl.h>
 #include <xengnttab.h>
 
diff --git a/tools/xentrace/xenctx.c b/tools/xentrace/xenctx.c
index 4ed120a..e647179 100644
--- a/tools/xentrace/xenctx.c
+++ b/tools/xentrace/xenctx.c
@@ -25,7 +25,8 @@
 #include <getopt.h>
 #include <limits.h>
 
-#include "xenctrl.h"
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
+#include <xenctrl.h>
 #include <xen/foreign/x86_32.h>
 #include <xen/foreign/x86_64.h>
 #include <xen/hvm/save.h>
diff --git a/tools/xentrace/xentrace.c b/tools/xentrace/xentrace.c
index f66a77c..28c2b3c 100644
--- a/tools/xentrace/xentrace.c
+++ b/tools/xentrace/xentrace.c
@@ -30,6 +30,7 @@
 #include <xen/xen.h>
 #include <xen/trace.h>
 
+#define XC_WANT_COMPAT_MAP_FOREIGN_API
 #include <xenevtchn.h>
 #include <xenctrl.h>
 
-- 
2.1.4


_______________________________________________
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®.