libxc: add abitility to dynamically load osdep.
authorIan Campbell <ian.campbell@citrix.com>
Fri, 3 Dec 2010 09:36:47 +0000 (09:36 +0000)
committerIan Campbell <ian.campbell@citrix.com>
Fri, 3 Dec 2010 09:36:47 +0000 (09:36 +0000)
Add a dummy backend which always returns ENOSYS. Mainly as a compile
time testbed rather than because it is a useful backend.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Ian Jackson <ian.jackson.citrix.com>
tools/libxc/Makefile
tools/libxc/xc_private.c
tools/libxc/xenctrl_osdep_ENOSYS.c [new file with mode: 0644]
tools/libxc/xenctrlosdep.h

index ff23f30c582ac4f73996c03aeb67674504426ae9..a2263438f199fdc5b4be3b802da87ba94edf394a 100644 (file)
@@ -92,6 +92,10 @@ ifneq ($(stubdom),y)
 LIB += libxenguest.so libxenguest.so.$(MAJOR) libxenguest.so.$(MAJOR).$(MINOR)
 endif
 
+ifneq ($(stubdom),y)
+LIB += xenctrl_osdep_ENOSYS.so
+endif
+
 .PHONY: all
 all: build
 
@@ -148,7 +152,7 @@ libxenctrl.so.$(MAJOR): libxenctrl.so.$(MAJOR).$(MINOR)
        ln -sf $< $@
 
 libxenctrl.so.$(MAJOR).$(MINOR): $(CTRL_PIC_OBJS)
-       $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenctrl.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $^ $(PTHREAD_LIBS)
+       $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenctrl.so.$(MAJOR) -ldl $(SHLIB_LDFLAGS) -o $@ $^ $(PTHREAD_LIBS)
 
 # libxenguest
 
@@ -186,5 +190,8 @@ libxenguest.so.$(MAJOR).$(MINOR): COMPRESSION_LIBS = $(call zlib-options,l)
 libxenguest.so.$(MAJOR).$(MINOR): $(GUEST_PIC_OBJS) libxenctrl.so
        $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenguest.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $(GUEST_PIC_OBJS) $(COMPRESSION_LIBS) -lz -lxenctrl $(PTHREAD_LIBS)
 
+xenctrl_osdep_ENOSYS.so: xenctrl_osdep_ENOSYS.o libxenctrl.so
+       $(CC) -g $(CFLAGS) $(LDFLAGS) $(SHLIB_LDFLAGS) -o $@ xenctrl_osdep_ENOSYS.o -lxenctrl
+
 -include $(DEPS)
 
index 03587ba17221eb2c42efdde6678f88bf7a7483fb..72ee07fd34cac9edcec99c0d8d0897787d535408 100644 (file)
 #include <pthread.h>
 #include <assert.h>
 
+#ifndef __MINIOS__
+#include <dlfcn.h>
+#endif
+
+#define XENCTRL_OSDEP "XENCTRL_OSDEP"
+
 /*
  * Returns a (shallow) copy of the xc_osdep_info_t for the
  * active OS interface.
  *
+ * On success a handle to the relevant library is opened.  The user
+ * must subsequently call xc_osdep_put_info() when it is
+ * finished with the library.
+ *
+ * Logs IFF xch != NULL.
+ *
  * Returns:
  *  0 - on success
  * -1 - on error
 static int xc_osdep_get_info(xc_interface *xch, xc_osdep_info_t *info)
 {
     int rc = -1;
+#ifndef __MINIOS__
+    const char *lib = getenv(XENCTRL_OSDEP);
+    xc_osdep_info_t *pinfo;
+    void *dl_handle = NULL;
 
-    *info = xc_osdep_info;
+    if ( lib != NULL )
+    {
+        if ( getuid() != geteuid() )
+        {
+            if ( xch ) ERROR("cannot use %s=%s with setuid application", XENCTRL_OSDEP, lib);
+            abort();
+        }
+        if ( getgid() != getegid() )
+        {
+            if ( xch ) ERROR("cannot use %s=%s with setgid application", XENCTRL_OSDEP, lib);
+            abort();
+        }
+
+        dl_handle = dlopen(lib, RTLD_LAZY|RTLD_LOCAL);
+        if ( !dl_handle )
+        {
+            if ( xch ) ERROR("unable to open osdep library %s: %s", lib, dlerror());
+            goto out;
+        }
+
+        pinfo = dlsym(dl_handle, "xc_osdep_info");
+        if ( !pinfo )
+        {
+            if ( xch ) ERROR("unable to find xc_osinteface_info in %s: %s", lib, dlerror());
+            goto out;
+        }
+
+        *info = *pinfo;
+        info->dl_handle = dl_handle;
+    }
+    else
+#endif
+    {
+        *info = xc_osdep_info;
+        info->dl_handle = NULL;
+    }
 
     rc = 0;
 
+#ifndef __MINIOS__
+out:
+    if ( dl_handle && rc == -1 )
+        dlclose(dl_handle);
+#endif
+
     return rc;
 }
 
 static void xc_osdep_put(xc_osdep_info_t *info)
 {
+#ifndef __MINIOS__
+    if ( info->dl_handle )
+        dlclose(info->dl_handle);
+#endif
 }
 
 static struct xc_interface_core *xc_interface_open_common(xentoollog_logger *logger,
diff --git a/tools/libxc/xenctrl_osdep_ENOSYS.c b/tools/libxc/xenctrl_osdep_ENOSYS.c
new file mode 100644 (file)
index 0000000..90ae348
--- /dev/null
@@ -0,0 +1,206 @@
+/* Dummy backend which just logs and returns ENOSYS. */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "xenctrl.h"
+#include "xenctrlosdep.h"
+
+#define IPRINTF(_x, _f, _a...) xc_osdep_log(_x,XTL_INFO,0, _f , ## _a)
+
+#define ERROR(_x, _m, _a...)  xc_osdep_log(_x,XTL_ERROR,XC_INTERNAL_ERROR,_m , ## _a )
+#define PERROR(_x, _m, _a...) xc_osdep_log(_x,XTL_ERROR,XC_INTERNAL_ERROR,_m \
+                  " (%d = %s)", ## _a , errno, xc_strerror(xch, errno))
+
+static xc_osdep_handle ENOSYS_privcmd_open(xc_interface *xch)
+{
+    IPRINTF(xch, "ENOSYS_privcmd: opening handle %p\n", (void *)1);
+    return (xc_osdep_handle)1; /*dummy*/
+}
+
+static int ENOSYS_privcmd_close(xc_interface *xch, xc_osdep_handle h)
+{
+    IPRINTF(xch, "ENOSYS_privcmd: closing handle %p\n", h);
+    return 0;
+}
+
+static int ENOSYS_privcmd_hypercall(xc_interface *xch, xc_osdep_handle h, privcmd_hypercall_t *hypercall)
+{
+    IPRINTF(xch, "ENOSYS_privcmd %p: hypercall: %02lld(%#llx,%#llx,%#llx,%#llx,%#llx,%#llx)\n",
+            h, hypercall->op,
+            hypercall->arg[0], hypercall->arg[1], hypercall->arg[2],
+            hypercall->arg[3], hypercall->arg[4], hypercall->arg[5]);
+    return -ENOSYS;
+}
+
+static void *ENOSYS_privcmd_map_foreign_batch(xc_interface *xch, xc_osdep_handle h, uint32_t dom, int prot,
+                                      xen_pfn_t *arr, int num)
+{
+    IPRINTF(xch, "ENOSYS_privcmd %p: map_foreign_batch: dom%d prot %#x arr %p num %d\n", h, dom, prot, arr, num);
+    return MAP_FAILED;
+}
+
+static void *ENOSYS_privcmd_map_foreign_bulk(xc_interface *xch, xc_osdep_handle h, uint32_t dom, int prot,
+                                     const xen_pfn_t *arr, int *err, unsigned int num)
+{
+    IPRINTF(xch, "ENOSYS_privcmd %p: map_foreign_buld: dom%d prot %#x arr %p err %p num %d\n", h, dom, prot, arr, err, num);
+    return MAP_FAILED;
+}
+
+static void *ENOSYS_privcmd_map_foreign_range(xc_interface *xch, xc_osdep_handle h, uint32_t dom, int size, int prot,
+                                      unsigned long mfn)
+{
+    IPRINTF(xch, "ENOSYS_privcmd %p: map_foreign_range: dom%d size %#x prot %#x mfn %ld\n", h, dom, size, prot, mfn);
+    return MAP_FAILED;
+}
+
+static void *ENOSYS_privcmd_map_foreign_ranges(xc_interface *xch, xc_osdep_handle h, uint32_t dom, size_t size, int prot,
+                                       size_t chunksize, privcmd_mmap_entry_t entries[],
+                                       int nentries)
+{
+    IPRINTF(xch, "ENOSYS_privcmd %p: map_foreign_ranges: dom%d size %zd prot %#x chunksize %zd entries %p num %d\n", h, dom, size, prot, chunksize, entries, nentries);
+    return MAP_FAILED;
+}
+
+static struct xc_osdep_ops ENOSYS_privcmd_ops =
+{
+    .open      = &ENOSYS_privcmd_open,
+    .close     = &ENOSYS_privcmd_close,
+    .u.privcmd   = {
+        .hypercall = &ENOSYS_privcmd_hypercall,
+
+        .map_foreign_batch = &ENOSYS_privcmd_map_foreign_batch,
+        .map_foreign_bulk = &ENOSYS_privcmd_map_foreign_bulk,
+        .map_foreign_range = &ENOSYS_privcmd_map_foreign_range,
+        .map_foreign_ranges = &ENOSYS_privcmd_map_foreign_ranges,
+    }
+};
+
+static xc_osdep_handle ENOSYS_evtchn_open(xc_interface *xce)
+{
+    IPRINTF(xce, "ENOSYS_evtchn: opening handle %p\n", (void *)1);
+    return (xc_osdep_handle)2; /*dummy*/
+}
+
+static int ENOSYS_evtchn_close(xc_interface *xce, xc_osdep_handle h)
+{
+    IPRINTF(xce, "ENOSYS_evtchn: closing handle %p\n", h);
+    return 0;
+}
+
+static int ENOSYS_evtchn_fd(xc_interface *xce, xc_osdep_handle h)
+{
+    IPRINTF(xce, "ENOSYS_fd %p: fd\n", h);
+    return (int)h;
+}
+
+static int ENOSYS_evtchn_notify(xc_interface *xce, xc_osdep_handle h, evtchn_port_t port)
+{
+    IPRINTF(xce, "ENOSYS_evtchn %p: notify: %d\n", h, port);
+    return -ENOSYS;
+}
+
+static int ENOSYS_evtchn_bind_unbound_port(xc_interface *xce, xc_osdep_handle h, int domid)
+{
+    IPRINTF(xce, "ENOSYS_evtchn %p: bind_unbound_port: dom%d\n", h, domid);
+    return -ENOSYS;
+}
+
+
+static int ENOSYS_evtchn_bind_interdomain(xc_interface *xce, xc_osdep_handle h, int domid, evtchn_port_t remote_port)
+{
+    IPRINTF(xce, "ENOSYS_evtchn %p: bind_interdomain: dmo%d %d\n", h, domid, remote_port);
+    return -ENOSYS;
+}
+
+
+static int ENOSYS_evtchn_bind_virq(xc_interface *xce, xc_osdep_handle h, unsigned int virq)
+{
+    IPRINTF(xce, "ENOSYS_evtchn %p: bind_virq: %d\n", h, virq);
+    return -ENOSYS;
+}
+
+
+static int ENOSYS_evtchn_unbind(xc_interface *xce, xc_osdep_handle h, evtchn_port_t port)
+{
+    IPRINTF(xce, "ENOSYS_evtchn %p: unbind: %d\n", h, port);
+    return -ENOSYS;
+}
+
+
+static evtchn_port_or_error_t ENOSYS_evtchn_pending(xc_interface *xce, xc_osdep_handle h)
+{
+    IPRINTF(xce, "ENOSYS_evtchn %p: pending\n", h);
+    return -ENOSYS;
+}
+
+static int ENOSYS_evtchn_unmask(xc_interface *xce, xc_osdep_handle h, evtchn_port_t port)
+{
+    IPRINTF(xce, "ENOSYS_evtchn %p: unmask: %d\n", h, port);
+    return -ENOSYS;
+}
+
+static struct xc_osdep_ops ENOSYS_evtchn_ops = {
+    .open = &ENOSYS_evtchn_open,
+    .close = &ENOSYS_evtchn_close,
+
+    .u.evtchn = {
+        .fd = &ENOSYS_evtchn_fd,
+
+        .notify = &ENOSYS_evtchn_notify,
+
+        .bind_unbound_port = &ENOSYS_evtchn_bind_unbound_port,
+        .bind_interdomain = &ENOSYS_evtchn_bind_interdomain,
+        .bind_virq = &ENOSYS_evtchn_bind_virq,
+
+        .unbind = &ENOSYS_evtchn_unbind,
+
+        .pending = &ENOSYS_evtchn_pending,
+        .unmask = &ENOSYS_evtchn_unmask,
+    },
+};
+
+static struct xc_osdep_ops * ENOSYS_osdep_init(xc_interface *xch, enum xc_osdep_type type)
+{
+    struct xc_osdep_ops *ops;
+
+    if (getenv("ENOSYS") == NULL)
+    {
+        PERROR(xch, "ENOSYS: not configured\n");
+        return NULL;
+    }
+
+    switch ( type )
+    {
+    case XC_OSDEP_PRIVCMD:
+        ops = &ENOSYS_privcmd_ops;
+        break;
+    case XC_OSDEP_EVTCHN:
+        ops = &ENOSYS_evtchn_ops;
+        break;
+    default:
+        ops = NULL;
+        break;
+    }
+
+    IPRINTF(xch, "ENOSYS_osdep_init: initialising handle ops at %p\n", ops);
+
+    return ops;
+}
+
+xc_osdep_info_t xc_osdep_info = {
+    .name = "Pessimistic ENOSYS OS interface",
+    .init = &ENOSYS_osdep_init,
+    .fake = 1,
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index a2680b220c294377af9eae2f0571c0d1bd168ded..efdc3b37dee5e6e461cd75e23623b348899d5a3e 100644 (file)
  * This interface defines the interactions between the Xen control
  * libraries and the OS facilities used to communicate with the
  * hypervisor.
+ *
+ * It is possible to override the default (native) implementation by
+ * setting the XENCTRL_OSDEP environment variable to point to a
+ * plugin library. Userspace can use this facility to intercept
+ * hypervisor operations. This can be used e.g. to implement a
+ * userspace simulator for Xen hypercalls.
+ *
+ * The plugin must contain a data structure:
+ *  xc_osdep_info_t xc_osdep_info;
+ *
+ * xc_osdep_init:
+ *   Must return a suitable struct xc_osdep_ops pointer or NULL on failure.
  */
 
 #ifndef XC_OSDEP_H
@@ -125,6 +137,9 @@ struct xc_osdep_info
 
     /* True if this interface backs onto a fake Xen. */
     int fake;
+
+    /* For internal use by loader. */
+    void *dl_handle;
 };
 typedef struct xc_osdep_info xc_osdep_info_t;