Add --with-xen-datapath-only configure option.

From: Tim Smith <tim.smith@citrix.com>

This sets CONFIG_XEN_DATAPATH_ONLY as a compile-time definition and reduces the
Xen libraries required to a minimum, in particular removing any which might have
unstable ABIs.

In pursuit of this, CONFIG_XEN_DATAPATH_ONLY is used to compile out any code which
might need libxencall, libxenctrl, libxendevicemodel, libxenforeignmemory,
libxenfsimage, libxenguest, libxenlight, libxenstat or libxlutil. This results
in a binary which can ONLY be used with "-machine xenpv" as any attempt to use
it otherwise will fail.
---
 accel/xen/xen-all.c         |   10 ++++++++++
 configure                   |   29 ++++++++++++++++++++++-------
 hw/char/xen_console.c       |    3 +++
 hw/display/xenfb.c          |    5 +++++
 hw/i386/xen/xen-hvm.c       |   10 ++++++++++
 hw/i386/xen/xen-mapcache.c  |    2 ++
 hw/i386/xen/xen_platform.c  |    2 ++
 hw/xen/xen-legacy-backend.c |    6 ++++++
 hw/xenpv/xen_machine_pv.c   |    4 ++++
 include/exec/ram_addr.h     |    2 ++
 include/hw/xen/xen_common.h |   17 +++++++++++++++++
 softmmu/physmem.c           |   16 ++++++++++++++++
 12 files changed, 99 insertions(+), 7 deletions(-)

diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c
index 69aa7d018b..1923acdbb2 100644
--- a/accel/xen/xen-all.c
+++ b/accel/xen/xen-all.c
@@ -35,9 +35,11 @@
 
 bool xen_allowed;
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
 xc_interface *xen_xc;
 xenforeignmemory_handle *xen_fmem;
 xendevicemodel_handle *xen_dmod;
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 
 static int store_dev_info(int domid, Chardev *cs, const char *string)
 {
@@ -100,6 +102,7 @@ void xenstore_store_pv_console_info(int i, Chardev *chr)
 }
 
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
 static void xenstore_record_dm_state(struct xs_handle *xs, const char *state)
 {
     char path[50];
@@ -140,9 +143,11 @@ static void xen_set_igd_gfx_passthru(Object *obj, bool value, Error **errp)
 {
     xen_igd_gfx_pt_set(value, errp);
 }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 
 static void xen_setup_post(MachineState *ms, AccelState *accel)
 {
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     int rc;
 
     if (xen_domid_restrict) {
@@ -152,12 +157,14 @@ static void xen_setup_post(MachineState *ms, AccelState *accel)
             exit(1);
         }
     }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 }
 
 static int xen_init(MachineState *ms)
 {
     MachineClass *mc = MACHINE_GET_CLASS(ms);
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     xen_xc = xc_interface_open(0, 0, 0);
     if (xen_xc == NULL) {
         xen_pv_printf(NULL, 0, "can't open xen interface\n");
@@ -177,6 +184,7 @@ static int xen_init(MachineState *ms)
         return -1;
     }
     qemu_add_vm_change_state_handler(xen_change_state_handler, NULL);
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
     /*
      * opt out of system RAM being allocated by generic code
      */
@@ -201,10 +209,12 @@ static void xen_accel_class_init(ObjectClass *oc, void *data)
 
     compat_props_add(ac->compat_props, compat, G_N_ELEMENTS(compat));
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     object_class_property_add_bool(oc, "igd-passthru",
         xen_get_igd_gfx_passthru, xen_set_igd_gfx_passthru);
     object_class_property_set_description(oc, "igd-passthru",
         "Set on/off to enable/disable igd passthrou");
+#endif
 }
 
 #define TYPE_XEN_ACCEL ACCEL_CLASS_NAME("xen")
diff --git a/configure b/configure
index 7c08c18358..d43881ce6a 100755
--- a/configure
+++ b/configure
@@ -293,6 +293,7 @@ EXTRA_CXXFLAGS=""
 EXTRA_OBJCFLAGS=""
 EXTRA_LDFLAGS=""
 
+xen_datapath_only="no"
 xen_ctrl_version="$default_feature"
 vhost_kernel="$default_feature"
 vhost_net="$default_feature"
@@ -886,6 +887,8 @@ for opt do
   ;;
   --enable-xen) xen="enabled"
   ;;
+  --with-xen-datapath-only) xen_datapath_only="yes"
+  ;;
   --disable-tcg) tcg="disabled"
                  plugins="no"
   ;;
@@ -1751,13 +1754,22 @@ if test "$xen" != "disabled" ; then
   # overriding this setting with pkg-config output. If not, try pkg-config
   # to obtain all needed flags.
 
-  if ! echo $EXTRA_LDFLAGS | grep tools/libxc > /dev/null && \
-     $pkg_config --exists xencontrol ; then
-    xen_ctrl_version="$(printf '%d%02d%02d' \
-      $($pkg_config --modversion xencontrol | sed 's/\./ /g') )"
-    xen=enabled
-    xen_pc="xencontrol xenstore xenforeignmemory xengnttab"
-    xen_pc="$xen_pc xenevtchn xendevicemodel"
+  if ! echo $EXTRA_LDFLAGS | grep tools/libxc > /dev/null; then
+    if test "$xen_datapath_only" == "no"; then
+      if $pkg_config --exists xencontrol ; then
+        xen_ctrl_version="$(printf '%d%02d%02d' \
+        $($pkg_config --modversion xencontrol | sed 's/\./ /g') )"
+        xen=enabled
+        xen_pc="xencontrol xenstore xenguest xenforeignmemory xengnttab"
+        xen_pc="$xen_pc xenevtchn xendevicemodel"
+      fi
+    else
+      if $pkg_config --exists xenstore ; then
+        xen=enabled
+        xen_pc="xenstore xengnttab"
+        xen_pc="$xen_pc xenevtchn"
+      fi
+    fi
     if $pkg_config --exists xentoolcore; then
       xen_pc="$xen_pc xentoolcore"
     fi
@@ -2848,6 +2860,9 @@ if test "$xen" = "enabled" ; then
   echo "XEN_CFLAGS=$xen_cflags" >> $config_host_mak
   echo "XEN_LIBS=$xen_libs" >> $config_host_mak
 fi
+if test "$xen_datapath_only" = "yes"; then
+  echo "CONFIG_XEN_DATAPATH_ONLY=y" >> $config_host_mak
+fi
 if test "$vhost_scsi" = "yes" ; then
   echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
 fi
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 63153dfde4..c07e0efd6f 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -48,6 +48,8 @@ struct XenConsole {
     int               backlog;
 };
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
+
 static void buffer_append(struct XenConsole *con)
 {
     struct buffer *buffer = &con->buffer;
@@ -296,3 +298,4 @@ struct XenDevOps xen_console_ops = {
     .event      = con_event,
     .disconnect = con_disconnect,
 };
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index cea10fe3c7..8e53088ec1 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -81,8 +81,11 @@ struct XenFB {
     int               up_count;
     int               up_fullscreen;
 };
+
+#ifndef CONFIG_XEN_DATAPATH_ONLY
 static const GraphicHwOps xenfb_ops;
 
+
 /* -------------------------------------------------------------------- */
 
 static int common_bind(struct common *c)
@@ -985,3 +988,5 @@ static const GraphicHwOps xenfb_ops = {
     .gfx_update  = xenfb_update,
     .update_interval = xenfb_update_interval,
 };
+
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index 0731f70410..2fedce46ec 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -39,6 +39,8 @@
 
 //#define DEBUG_XEN_HVM
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
+
 #ifdef DEBUG_XEN_HVM
 #define DPRINTF(fmt, ...) \
     do { fprintf(stderr, "xen: " fmt, ## __VA_ARGS__); } while (0)
@@ -1620,3 +1622,11 @@ void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
         memory_global_dirty_log_stop(GLOBAL_DIRTY_MIGRATION);
     }
 }
+#else /* CONFIG_XEN_DATAPATH_ONLY */
+/* This is from xen-stubs.c, but that can only be build when Xen is entirely disabled,
+ * which we can't afford to do here */
+void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
+{
+}
+
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c
index a2f93096e7..99498ee641 100644
--- a/hw/i386/xen/xen-mapcache.c
+++ b/hw/i386/xen/xen-mapcache.c
@@ -21,6 +21,7 @@
 #include "sysemu/xen-mapcache.h"
 #include "trace.h"
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
 
 //#define MAPCACHE_DEBUG
 
@@ -597,3 +598,4 @@ uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
     mapcache_unlock();
     return p;
 }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c
index 72028449ba..ddafca25a3 100644
--- a/hw/i386/xen/xen_platform.c
+++ b/hw/i386/xen/xen_platform.c
@@ -37,6 +37,7 @@
 #include "qemu/module.h"
 #include "qom/object.h"
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
 //#define DEBUG_PLATFORM
 
 #ifdef DEBUG_PLATFORM
@@ -517,3 +518,4 @@ static void xen_platform_register_types(void)
 }
 
 type_init(xen_platform_register_types)
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c
index 085fd31ef7..8a9fb34efa 100644
--- a/hw/xen/xen-legacy-backend.c
+++ b/hw/xen/xen-legacy-backend.c
@@ -688,7 +688,11 @@ int xen_be_init(void)
 
     qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL);
 
+#ifdef CONFIG_XEN_DATAPATH_ONLY
+    if (xenstore == NULL) {
+#else /* CONFIG_XEN_DATAPATH_ONLY */
     if (xen_xc == NULL || xen_fmem == NULL) {
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
         /* Check if xen_init() have been called */
         goto err;
     }
@@ -748,6 +752,7 @@ void xen_be_register_common(void)
 {
     xen_set_dynamic_sysbus();
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     xen_be_register("console", &xen_console_ops);
     xen_be_register("vkbd", &xen_kbdmouse_ops);
 #ifdef CONFIG_VIRTFS
@@ -756,6 +761,7 @@ void xen_be_register_common(void)
 #ifdef CONFIG_USB_LIBUSB
     xen_be_register("qusb", &xen_usb_ops);
 #endif
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 }
 
 int xen_be_bind_evtchn(struct XenLegacyDevice *xendev)
diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c
index 8df575a457..8505efaab4 100644
--- a/hw/xenpv/xen_machine_pv.c
+++ b/hw/xenpv/xen_machine_pv.c
@@ -32,8 +32,10 @@
 
 static void xen_init_pv(MachineState *machine)
 {
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     DriveInfo *dinfo;
     int i;
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 
     /* Initialize backend core & drivers */
     if (xen_be_init() != 0) {
@@ -55,6 +57,7 @@ static void xen_init_pv(MachineState *machine)
         break;
     }
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     xen_be_register_common();
     xen_be_register("vfb", &xen_framebuffer_ops);
     xen_be_register("qnic", &xen_netdev_ops);
@@ -79,6 +82,7 @@ static void xen_init_pv(MachineState *machine)
             continue;
         xen_config_dev_nic(nd_table + i);
     }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 
     xen_bus_init();
 
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 64fb936c7c..bac05aff5e 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -330,7 +330,9 @@ static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
         }
     }
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     xen_hvm_modified_memory(start, length);
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 }
 
 #if !defined(_WIN32)
diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
index 179741ff79..2436dbfa88 100644
--- a/include/hw/xen/xen_common.h
+++ b/include/hw/xen/xen_common.h
@@ -10,7 +10,10 @@
 #undef XC_WANT_COMPAT_GNTTAB_API
 #undef XC_WANT_COMPAT_MAP_FOREIGN_API
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
 #include <xenctrl.h>
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
+
 #include <xenstore.h>
 #include "hw/xen/interface/io/xenbus.h"
 
@@ -18,6 +21,19 @@
 #include "hw/pci/pci.h"
 #include "hw/xen/trace.h"
 
+#ifdef CONFIG_XEN_DATAPATH_ONLY
+#define XC_PAGE_SHIFT           12
+#define XC_PAGE_SIZE            (1UL << XC_PAGE_SHIFT)
+#define XC_PAGE_MASK            (~(XC_PAGE_SIZE-1))
+
+#include "qemu/atomic.h"
+#define xen_mb  smp_mb
+#define xen_rmb smp_rmb
+#define xen_wmb smp_wmb
+
+#include <xenevtchn.h>
+#include <xengnttab.h>
+#else /* CONFIG_XEN_DATAPATH_ONLY */
 extern xc_interface *xen_xc;
 
 /*
@@ -692,5 +708,6 @@ static inline int xengnttab_grant_copy(xengnttab_handle *xgt, uint32_t count,
     return -ENOSYS;
 }
 #endif
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 
 #endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/softmmu/physmem.c b/softmmu/physmem.c
index 4e1b27a20e..7f7640e893 100644
--- a/softmmu/physmem.c
+++ b/softmmu/physmem.c
@@ -1967,7 +1967,9 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
     RAMBlock *block;
     RAMBlock *last_block = NULL;
     ram_addr_t old_ram_size, new_ram_size;
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     Error *err = NULL;
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 
     old_ram_size = last_ram_page();
 
@@ -1976,6 +1978,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
 
     if (!new_block->host) {
         if (xen_enabled()) {
+#ifndef CONFIG_XEN_DATAPATH_ONLY
             xen_ram_alloc(new_block->offset, new_block->max_length,
                           new_block->mr, &err);
             if (err) {
@@ -1983,6 +1986,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
                 qemu_mutex_unlock_ramlist();
                 return;
             }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
         } else {
             new_block->host = qemu_anon_ram_alloc(new_block->max_length,
                                                   &new_block->mr->align,
@@ -2203,8 +2207,10 @@ static void reclaim_ramblock(RAMBlock *block)
 {
     if (block->flags & RAM_PREALLOC) {
         ;
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     } else if (xen_enabled()) {
         xen_invalidate_map_cache_entry(block->host);
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 #ifndef _WIN32
     } else if (block->fd >= 0) {
         qemu_ram_munmap(block->fd, block->host, block->max_length);
@@ -2296,6 +2302,7 @@ void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr)
         addr -= block->offset;
     }
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     if (xen_enabled() && block->host == NULL) {
         /* We need to check if the requested address is in the RAM
          * because we don't want to map the entire memory in QEMU.
@@ -2307,6 +2314,7 @@ void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr)
 
         block->host = xen_map_cache(block->offset, block->max_length, 1, false);
     }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
     return ramblock_ptr(block, addr);
 }
 
@@ -2329,6 +2337,7 @@ static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,
     }
     *size = MIN(*size, block->max_length - addr);
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     if (xen_enabled() && block->host == NULL) {
         /* We need to check if the requested address is in the RAM
          * because we don't want to map the entire memory in QEMU.
@@ -2340,6 +2349,7 @@ static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,
 
         block->host = xen_map_cache(block->offset, block->max_length, 1, lock);
     }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 
     return ramblock_ptr(block, addr);
 }
@@ -2377,6 +2387,7 @@ RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset,
     RAMBlock *block;
     uint8_t *host = ptr;
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     if (xen_enabled()) {
         ram_addr_t ram_addr;
         RCU_READ_LOCK_GUARD();
@@ -2387,6 +2398,7 @@ RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset,
         }
         return block;
     }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
 
     RCU_READ_LOCK_GUARD();
     block = qatomic_rcu_read(&ram_list.mru_block);
@@ -3285,9 +3297,11 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
         if (is_write) {
             invalidate_and_set_dirty(mr, addr1, access_len);
         }
+#ifndef CONFIG_XEN_DATAPATH_ONLY
         if (xen_enabled()) {
             xen_invalidate_map_cache_entry(buffer);
         }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
         memory_region_unref(mr);
         return;
     }
@@ -3387,9 +3401,11 @@ void address_space_cache_destroy(MemoryRegionCache *cache)
         return;
     }
 
+#ifndef CONFIG_XEN_DATAPATH_ONLY
     if (xen_enabled()) {
         xen_invalidate_map_cache_entry(cache->ptr);
     }
+#endif /* CONFIG_XEN_DATAPATH_ONLY */
     memory_region_unref(cache->mrs.mr);
     flatview_unref(cache->fv);
     cache->mrs.mr = NULL;
