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

[Minios-devel] [UNIKRAFT PATCH 3/3] plat/xen: Add Xenbus support


  • To: minios-devel@xxxxxxxxxxxxx
  • From: Costin Lupu <costin.lupu@xxxxxxxxx>
  • Date: Wed, 11 Jul 2018 16:21:58 +0300
  • Cc: simon.kuenzer@xxxxxxxxx, sharan.santhanam@xxxxxxxxx, yuri.volchkov@xxxxxxxxx
  • Delivery-date: Wed, 11 Jul 2018 13:22:10 +0000
  • Ironport-phdr: 9a23:G2WEuBF8FJJ/eA/Zj5Dgx51GYnF86YWxBRYc798ds5kLTJ7ypMqwAkXT6L1XgUPTWs2DsrQY07SQ6/iocFdDyK7JiGoFfp1IWk1NouQttCtkPvS4D1bmJuXhdS0wEZcKflZk+3amLRodQ56mNBXdrXKo8DEdBAj0OxZrKeTpAI7SiNm82/yv95HJbAhEmDuwbaluIBmqsA7cqtQYjYx+J6gr1xDHuGFIe+NYxWNpIVKcgRPx7dqu8ZBg7ipdpesv+9ZPXqvmcas4S6dYDCk9PGAu+MLrrxjDQhCR6XYaT24bjwBHAwnB7BH9Q5fxri73vfdz1SWGIcH7S60/VDK/5KlpVRDokj8KOT4n/m/KhMJ+j6VVrxCvpxFk34LYfJuYOOZkc6/BYd8XQ3dKUMZLVyxGB4Oxd5UCD+0aPeZEron9oUYFox2jBQm0GePk1zhFiWPx3a0hz+QhEAfG0BYkH9ITqHTUsc74O7sJUeyv1KnI0C7MY+lM2Tf68YXFdA0qr/KUXb9obMbcxlQjGxnGg1iQs4DpIS2Z2+YXv2WV9+ZsSO2ih3M9pwxyojWj3Nkgh4fHi44P11zJ+jt1zYAoLtOiUkF7e8SrEJ5IuiGfMIt5X90tTnlzuCY/1r0GoZm7fDUWyJg/xx7QdfiHc4+Q7xL9UeaeOzZ4hHZ/dL2jnBa+61CgyvDnWcWuylZKqTJJktjKtn8Tyxze8tWLR/Rg8ku72juC1xrf5v9aLU02j6bWJYYtwrsqmZoStUTDEDX2mELzjKKOakok/fOo6/jmYrXgvJOcM5J0ihnjMqk1hsO/Gv40MhATX2eA4+i8zrrj8VXjQLpWlv02jrXZsJfCKMQep665BQ5V0oE46xqmEjipzsoYkmcDLF9efBKHjpPpO03VIPziAvawnVKsnC1sx/DcMb3rGo/NIWTbkLf9YbZ97FZRyBEzzd9F/ZJbELcBLOjoWkDrstzYEh85PBayw+n9DdVwzYUeVnyTDa+dKqzdqkWE6fwyI+OUfo8apC79K+Q55/7plXI5gl4dfayu3ZsRcny4HelmLFufYXvtnNgBC3wHvgwgQ+P2jF2NSyVca2ysUKIh/js7Ep6pDZ/fRoCxh7yMxCe6HoBMZmBHEFyMD3Dod4GYVPcMayKSJdFhnycCVbe/V4Ah0QuhuxTgx7V5M+qHshEf4Jfi0tly/KjfmA8/8RRwDt+ByCedQmcymXkHFBEs26Uqiktm1laFmYxlm+EQQddU/O9IVEE+KIbB5+dhTcjvUETbeYHaGx6dXty6DGRpHZoKyNgUbhMlFg==
  • List-id: Mini-os development list <minios-devel.lists.xenproject.org>

The current implementation is ported from Mini-OS.

Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx>
---
 plat/xen/Config.uk               |   8 +
 plat/xen/Makefile.uk             |  10 +
 plat/xen/include/xenbus/client.h | 139 +++++++++++
 plat/xen/include/xenbus/xenbus.h | 158 ++++++++++++
 plat/xen/include/xenbus/xs.h     | 221 +++++++++++++++++
 plat/xen/xenbus/client.c         | 278 +++++++++++++++++++++
 plat/xen/xenbus/xenbus.c         | 260 ++++++++++++++++++++
 plat/xen/xenbus/xs.c             | 518 +++++++++++++++++++++++++++++++++++++++
 plat/xen/xenbus/xs_comms.c       | 484 ++++++++++++++++++++++++++++++++++++
 plat/xen/xenbus/xs_comms.h       |  75 ++++++
 plat/xen/xenbus/xs_watch.c       | 159 ++++++++++++
 plat/xen/xenbus/xs_watch.h       |  91 +++++++
 12 files changed, 2401 insertions(+)
 create mode 100644 plat/xen/include/xenbus/client.h
 create mode 100644 plat/xen/include/xenbus/xenbus.h
 create mode 100644 plat/xen/include/xenbus/xs.h
 create mode 100644 plat/xen/xenbus/client.c
 create mode 100644 plat/xen/xenbus/xenbus.c
 create mode 100644 plat/xen/xenbus/xs.c
 create mode 100644 plat/xen/xenbus/xs_comms.c
 create mode 100644 plat/xen/xenbus/xs_comms.h
 create mode 100644 plat/xen/xenbus/xs_watch.c
 create mode 100644 plat/xen/xenbus/xs_watch.h

diff --git a/plat/xen/Config.uk b/plat/xen/Config.uk
index 9c398f1..d0143e9 100644
--- a/plat/xen/Config.uk
+++ b/plat/xen/Config.uk
@@ -20,4 +20,12 @@ if (PLAT_XEN)
                instead of the hypervisor console. When this
                option is enabled the hypervisor console is used
                for kernel messages only.
+
+menuconfig XEN_XENBUS
+       bool "Xenbus Driver"
+       default n
+       depends on (ARCH_X86_64)
+       select LIBUKBUS
+       help
+               Register a Xenbus driver as uk_bus
 endif
diff --git a/plat/xen/Makefile.uk b/plat/xen/Makefile.uk
index 45096cb..ff23459 100644
--- a/plat/xen/Makefile.uk
+++ b/plat/xen/Makefile.uk
@@ -72,3 +72,13 @@ LIBXENPLAT_SRCS-y              += 
$(LIBXENPLAT_BASE)/console.c
 LIBXENPLAT_SRCS-y              += $(LIBXENPLAT_BASE)/shutdown.c
 LIBXENPLAT_SRCS-y              += $(LIBXENPLAT_BASE)/events.c
 LIBXENPLAT_SRCS-y              += $(LIBXENPLAT_BASE)/gnttab.c
+
+LIBXENBUS_ASFLAGS-y            += $(LIBXENPLAT_ASFLAGS-y)
+LIBXENBUS_ASINCLUDES-y         += $(LIBXENPLAT_ASINCLUDES-y)
+LIBXENBUS_CFLAGS-y             += $(LIBXENPLAT_CFLAGS-y)
+LIBXENBUS_CINCLUDES-y          += $(LIBXENPLAT_CINCLUDES-y)
+LIBXENBUS_SRCS-y               += $(LIBXENPLAT_BASE)/xenbus/xenbus.c
+LIBXENBUS_SRCS-y               += $(LIBXENPLAT_BASE)/xenbus/client.c
+LIBXENBUS_SRCS-y               += $(LIBXENPLAT_BASE)/xenbus/xs_comms.c
+LIBXENBUS_SRCS-y               += $(LIBXENPLAT_BASE)/xenbus/xs_watch.c
+LIBXENBUS_SRCS-y               += $(LIBXENPLAT_BASE)/xenbus/xs.c
diff --git a/plat/xen/include/xenbus/client.h b/plat/xen/include/xenbus/client.h
new file mode 100644
index 0000000..112c8c9
--- /dev/null
+++ b/plat/xen/include/xenbus/client.h
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+/*
+ * Client interface between the device and the Xenbus driver.
+ * Ported from Mini-OS xenbus.c
+ */
+
+#ifndef __XENBUS_CLIENT_H__
+#define __XENBUS_CLIENT_H__
+
+#include <xenbus/xenbus.h>
+#include <xenbus/xs.h>
+
+/*
+ * Returns the name of the state for tracing/debugging purposes.
+ *
+ * @param state The Xenbus state
+ * @return A string representing the state name
+ */
+const char *xenbus_state_to_str(XenbusState state);
+
+/*
+ * Converts a device type value to name
+ *
+ * @param devtype The Xenbus device type
+ * @return A string representing the device type name
+ */
+const char *xenbus_devtype_to_str(enum xenbus_dev_type devtype);
+
+/*
+ * Converts a device type name to value
+ *
+ * @param devtypestr The Xenbus device type name
+ * @return The Xenbus device type
+ */
+enum xenbus_dev_type xenbus_str_to_devtype(const char *devtypestr);
+
+
+/*
+ * Watches
+ */
+
+/*
+ * Waits for a watch event associated with the event list. If no event list is
+ * provided, a global event list is used instead. Called by a client driver.
+ *
+ * @param evlist The watch event list
+ */
+void xenbus_wait_watch_event(xenbus_watch_evlist_t *evlist);
+
+/*
+ * Notifies a client driver waiting for watch events.
+ *
+ * @param evlist The watch event list
+ * @param event The watch event
+ * @return 0 on success, a negative errno value on error.
+ */
+int xenbus_notify_watch_event(xenbus_watch_evlist_t *evlist,
+               struct xenbus_watch_event *event);
+
+/*
+ * Waits for a value in Xenstore to change by using watches. If no event list 
is
+ * provided, a global event list is used instead.
+ *
+ * @param path Xenstore path
+ * @param value The expected value
+ * @param evlist The watch event list
+ * @return 0 on success, a negative errno value on error.
+ */
+int xenbus_wait_for_value(const char *path, const char *value,
+               xenbus_watch_evlist_t *evlist);
+
+/*
+ * Driver states
+ */
+
+/*
+ * Returns the driver state found at the given Xenstore path.
+ *
+ * @param path Xenstore path
+ * @return The Xenbus driver state
+ */
+XenbusState xenbus_read_driver_state(const char *path);
+
+/*
+ * Changes the state of a Xen PV driver
+ *
+ * @param xendev Xenbus device
+ * @param state The new Xenbus state
+ * @param xbt Xenbus transaction id
+ * @return 0 on success, a negative errno value on error.
+ */
+int xenbus_switch_state(struct xenbus_device *xendev, XenbusState state,
+               xenbus_transaction_t xbt);
+
+/*
+ * Waits for the driver state found at the given Xenstore path to change by
+ * using watches.
+ *
+ * @param path Xenstore path
+ * @param state The returned Xenbus state
+ * @param evlist The watch event list
+ * @return 0 on success, a negative errno value on error.
+ */
+int xenbus_wait_for_state_change(const char *path, XenbusState *state,
+               xenbus_watch_evlist_t *evlist);
+
+#endif /* __XENBUS_CLIENT_H__ */
diff --git a/plat/xen/include/xenbus/xenbus.h b/plat/xen/include/xenbus/xenbus.h
new file mode 100644
index 0000000..2836a85
--- /dev/null
+++ b/plat/xen/include/xenbus/xenbus.h
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#ifndef __XENBUS_H__
+#define __XENBUS_H__
+
+#include <uk/bus.h>
+#include <uk/alloc.h>
+#include <xen/xen.h>
+#include <xen/io/xenbus.h>
+
+
+/*
+ * Supported device types
+ */
+typedef enum xenbus_dev_type {
+       xenbus_dev_none = 0,
+       xenbus_dev_sysctl,    /* System wise control device */
+       xenbus_dev_vif,       /* Virtual network interface */
+       xenbus_dev_vbd,       /* Virtual block device */
+} xenbus_dev_type_t;
+
+struct xenbus_device;
+
+/*
+ * Xenbus driver
+ */
+
+typedef int (*xenbus_driver_init_func_t)(struct uk_alloc *a);
+typedef int (*xenbus_driver_add_func_t)(struct xenbus_device *dev);
+
+
+struct xenbus_driver {
+       UK_TAILQ_ENTRY(struct xenbus_driver) next;
+       const xenbus_dev_type_t *device_types;
+
+       xenbus_driver_init_func_t init;
+       xenbus_driver_add_func_t add_dev;
+};
+UK_TAILQ_HEAD(xenbus_driver_list, struct xenbus_driver);
+
+
+#define XENBUS_REGISTER_DRIVER(b) \
+       _XENBUS_REGISTER_DRIVER(__LIBNAME__, (b))
+
+#define _XENBUS_REGFNNAME(x, y)      x##y
+
+#define _XENBUS_REGISTER_DRIVER(libname, b) \
+       static void __constructor_prio(104) \
+       _XENBUS_REGFNNAME(libname, _xenbus_register_driver)(void) \
+       { \
+               _xenbus_register_driver((b)); \
+       }
+
+/* Do not use this function directly: */
+void _xenbus_register_driver(struct xenbus_driver *drv);
+
+
+/*
+ * Xenbus watch
+ */
+
+/* Watch event list */
+struct xenbus_watch_event {
+       struct xenbus_watch_event *next;
+};
+typedef struct xenbus_watch_event *xenbus_watch_evlist_t;
+
+struct xenbus_watch {
+       struct xenbus_watch *next;
+       xenbus_watch_evlist_t *events;
+};
+
+
+/*
+ * Xenbus device
+ */
+
+struct xenbus_device {
+       /**< in use by Xenbus handler */
+       UK_TAILQ_ENTRY(struct xenbus_device) next;
+       /**< Device state */
+       XenbusState state;
+       /**< Device type */
+       enum xenbus_dev_type devtype;
+       /**< Xenstore path of the device */
+       char *nodename;
+       /**< Xenstore path of the device peer (e.g. backend for frontend) */
+       char *otherend;
+       /**< Domain id of the other end */
+       domid_t otherend_id;
+       /**< Watch events list */
+       xenbus_watch_evlist_t watch_events;
+       /**< Xenbus driver */
+       struct xenbus_driver *drv;
+};
+UK_TAILQ_HEAD(xenbus_device_list, struct xenbus_device);
+
+
+/*
+ * Xenbus handler
+ */
+
+struct xenbus_handler {
+       struct uk_bus b;
+       struct uk_alloc *a;
+       struct xenbus_driver_list drv_list;  /**< List of Xenbus drivers */
+       int drv_list_initialized;
+       struct xenbus_device_list dev_list;  /**< List of Xenbus devices */
+};
+
+extern struct xenbus_handler xbh;
+
+/* Helper macros for Xenbus related allocations */
+#define uk_xb_malloc(size)     uk_malloc(xbh.a, (size))
+#define uk_xb_calloc(n, size)  uk_calloc(xbh.a, (n), (size))
+#define uk_xb_free(ptr)        uk_free(xbh.a, (ptr))
+
+
+/* Debugging */
+#if DEBUG_XENBUS
+#define DBGXB(fmt, ...)   uk_printd(DLVL_EXTRA, fmt, __VA_ARGS__)
+#else
+#define DBGXB(fmt, ...)
+#endif
+
+#endif /* __XENBUS_H__ */
diff --git a/plat/xen/include/xenbus/xs.h b/plat/xen/include/xenbus/xs.h
new file mode 100644
index 0000000..d6e1f9e
--- /dev/null
+++ b/plat/xen/include/xenbus/xs.h
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+/* Xenstore API */
+
+#ifndef __XS_H__
+#define __XS_H__
+
+#include <xenbus/xenbus.h>
+
+
+typedef unsigned long xenbus_transaction_t;
+#define XBT_NIL ((xenbus_transaction_t) 0)
+
+
+/*
+ * Equivalent of asprintf function.
+ *
+ * @param fmt Format string
+ * @return On success, returns a malloc'd string. On error, returns a negative
+ * error number which should be checked using PTRISERR.
+ */
+char *xs_join(const char *fmt, ...) __printf(1, 2);
+
+/*
+ * Read the value associated with a path.
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore path
+ * @return On success, returns a malloc'd copy of the value. On error, returns
+ * a negative error number which should be checked using PTRISERR.
+ */
+char *xs_read(xenbus_transaction_t xbt, const char *path);
+
+/*
+ * Associates a value with a path.
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore path
+ * @param value Xenstore value
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_write(xenbus_transaction_t xbt, const char *path, const char *value);
+
+/*
+ * List the contents of a directory.
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore directory path
+ * @return On success, returns a malloc'd array of pointers to malloc'd 
strings.
+ * The array is NULL terminated. On error, returns a negative error number 
which
+ * should be checked using PTRISERR. May block.
+ */
+char **xs_ls(xenbus_transaction_t xbt, const char *path);
+
+/*
+ * Removes the value associated with a path.
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore path
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_rm(xenbus_transaction_t xbt, const char *path);
+
+/*
+ * Reads permissions associated with a path.
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore path
+ * @return On success, returns a malloc'd copy of the value. On error, returns
+ * a negative error number which should be checked using PTRISERR.
+ */
+char *xs_get_perms(xenbus_transaction_t xbt, const char *path);
+
+/*
+ * Sets the permissions associated with a path.
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore path
+ * @param domid The id of the domain for which permissions are set
+ * @param perm Permissions character (e.g. 'w', 'r', 'b', 'n')
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_set_perms(xenbus_transaction_t xbt, const char *path,
+       domid_t domid, char perm);
+
+/*
+ * Start a xenbus transaction. Returns the transaction in xbt on
+ * success or an error number otherwise.
+ *
+ * @param xbt Address for returning the Xenbus transaction id
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_transaction_start(xenbus_transaction_t *xbt);
+
+/*
+ * End a xenbus transaction. Returns non-zero on failure.
+ * Parameter abort says whether the transaction should be aborted.
+ * Returns 1 in *retry iff the transaction should be retried.
+ *
+ * @param xbt Xenbus transaction id
+ * @param abort Non-zero if transaction should be aborted
+ * @param retry Address for returning the retry suggestion
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_transaction_end(xenbus_transaction_t xbt, int abort, int *retry);
+
+/*
+ * Sends a debug message to the Xenstore daemon for writing it in the debug log
+ *
+ * @param msg The logged message
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_debug_msg(const char *msg);
+
+/*
+ * Read path and parse it as an integer.
+ *
+ * @param path Xenstore path
+ * @param value Returned int value
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_read_integer(const char *path, int *value);
+
+/*
+ * Contraction of sprintf and xs_read(path/node).
+ *
+ * @param xbt Xenbus transaction id
+ * @param fmt Path format string
+ * @return On success, returns a malloc'd copy of the value. On error, returns
+ * a negative error number which should be checked using PTRISERR.
+ */
+char *xs_readf(xenbus_transaction_t xbt,
+       const char *fmt, ...) __printf(2, 3);
+
+/*
+ * Contraction of sprintf and xs_write(path/node).
+ */
+int xs_printf(xenbus_transaction_t xbt, const char *node, const char *path,
+       const char *fmt, ...) __printf(4, 5);
+
+/*
+ * Utility function to figure out our domain id
+ *
+ * @return Our domain id
+ */
+domid_t xs_get_self_id(void);
+
+/*
+ * Registers a Xenstore watch
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore path
+ * @param token Watch identification token
+ * @param events The associated watch events list
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_watch_path_token(xenbus_transaction_t xbt,
+       const char *path, const char *token,
+       xenbus_watch_evlist_t *events);
+
+/*
+ * Unregisters a Xenstore watch
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore path
+ * @param token Watch identification token
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_unwatch_path_token(xenbus_transaction_t xbt,
+       const char *path, const char *token);
+
+/*
+ * Registers a Xenstore watch using the default global token and event list.
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore path
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_watch_path(xenbus_transaction_t xbt, const char *path);
+
+/*
+ * Unregisters a Xenstore watch using the default global token.
+ *
+ * @param xbt Xenbus transaction id
+ * @param path Xenstore path
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_unwatch_path(xenbus_transaction_t xbt, const char *path);
+
+#endif /* __XS_H__ */
diff --git a/plat/xen/xenbus/client.c b/plat/xen/xenbus/client.c
new file mode 100644
index 0000000..f50f469
--- /dev/null
+++ b/plat/xen/xenbus/client.c
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Steven Smith (sos22@xxxxxxxxx)
+ *          Grzegorz Milos (gm281@xxxxxxxxx)
+ *          John D. Ramsdell
+ *          Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2006, Cambridge University
+ *               2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+/*
+ * Client interface between the device and the Xenbus driver.
+ * Ported from Mini-OS xenbus.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <uk/errptr.h>
+#include <uk/wait.h>
+#include <xenbus/client.h>
+
+
+#define XENBUS_STATE_ENTRY(name) \
+       [XenbusState##name] = #name
+
+static const char *const xb_state_tbl[] = {
+       XENBUS_STATE_ENTRY(Unknown),
+       XENBUS_STATE_ENTRY(Initialising),
+       XENBUS_STATE_ENTRY(InitWait),
+       XENBUS_STATE_ENTRY(Initialised),
+       XENBUS_STATE_ENTRY(Connected),
+       XENBUS_STATE_ENTRY(Closing),
+       XENBUS_STATE_ENTRY(Closed),
+       XENBUS_STATE_ENTRY(Reconfiguring),
+       XENBUS_STATE_ENTRY(Reconfigured),
+};
+
+const char *xenbus_state_to_str(XenbusState state)
+{
+       return (state < ARRAY_SIZE(xb_state_tbl)) ?
+               xb_state_tbl[state] : "INVALID";
+}
+
+#define XENBUS_DEVTYPE_ENTRY(name) \
+       [xenbus_dev_##name] = #name
+
+static const char *const xb_devtype_tbl[] = {
+       XENBUS_DEVTYPE_ENTRY(none),
+       XENBUS_DEVTYPE_ENTRY(sysctl),
+       XENBUS_DEVTYPE_ENTRY(vif),
+       XENBUS_DEVTYPE_ENTRY(vbd),
+};
+
+const char *xenbus_devtype_to_str(enum xenbus_dev_type devtype)
+{
+       return (devtype < ARRAY_SIZE(xb_devtype_tbl)) ?
+               xb_devtype_tbl[devtype] : "INVALID";
+}
+
+enum xenbus_dev_type xenbus_str_to_devtype(const char *devtypestr)
+{
+       for (int i = 0; i < (int) ARRAY_SIZE(xb_devtype_tbl); i++) {
+               if (!strcmp(xb_devtype_tbl[i], devtypestr))
+                       return (enum xenbus_dev_type) i;
+       }
+
+       return xenbus_dev_none;
+}
+
+/*
+ * Watches
+ */
+
+static DEFINE_WAIT_QUEUE(xenbus_watch_wq);
+static xenbus_watch_evlist_t xenbus_watch_evlist;
+
+/*
+ * The split between 'xenbus_wait_watch_event_return' and
+ * 'xenbus_wait_watch_event' was taken from Mini-OS which uses this approach
+ * to handle the events explicitly in the TPM frontend.
+ */
+static struct xenbus_watch_event *
+xenbus_wait_watch_event_return(xenbus_watch_evlist_t *evlist)
+{
+       struct xenbus_watch_event *event;
+       DEFINE_WAIT(w);
+
+       if (!evlist)
+               evlist = &xenbus_watch_evlist;
+
+       while (!(event = *evlist)) {
+               uk_waitq_add_waiter(&xenbus_watch_wq, &w);
+               uk_sched_yield();
+       }
+       uk_waitq_remove_waiter(&xenbus_watch_wq, &w);
+
+       /* pop the event */
+       *evlist = event->next;
+
+       return event;
+}
+
+void xenbus_wait_watch_event(xenbus_watch_evlist_t *evlist)
+{
+       struct xenbus_watch_event *event;
+
+       if (!evlist)
+               evlist = &xenbus_watch_evlist;
+
+       event = xenbus_wait_watch_event_return(evlist);
+       UK_ASSERT(event != NULL);
+
+       uk_xb_free(event);
+}
+
+int xenbus_notify_watch_event(xenbus_watch_evlist_t *evlist,
+               struct xenbus_watch_event *event)
+{
+       if (evlist == NULL || event == NULL)
+               return -EINVAL;
+
+       /* add the event at the beginning of the list */
+       event->next = *evlist;
+       *evlist = event;
+
+       uk_waitq_wake_up(&xenbus_watch_wq);
+
+       return 0;
+}
+
+int xenbus_wait_for_value(const char *path, const char *value,
+               xenbus_watch_evlist_t *evlist)
+{
+       char *res;
+       int rc;
+
+       if (!evlist)
+               evlist = &xenbus_watch_evlist;
+
+       for (;;) {
+               res = xs_read(XBT_NIL, path);
+               if (PTRISERR(res))
+                       return PTR2ERR(res);
+
+               rc = strcmp(value, res);
+               uk_xb_free(res);
+
+               if (rc == 0)
+                       break;
+
+               xenbus_wait_watch_event(evlist);
+       }
+
+       return 0;
+}
+
+XenbusState xenbus_read_driver_state(const char *path)
+{
+       char state_path[strlen(path) + sizeof("/state")];
+       XenbusState state = XenbusStateUnknown;
+
+       sprintf(state_path, "%s/state", path);
+       xs_read_integer(state_path, (int *) &state);
+
+       return state;
+}
+
+int xenbus_switch_state(struct xenbus_device *xendev, XenbusState state,
+               xenbus_transaction_t xbt)
+{
+       char state_path[strlen(xendev->nodename) + sizeof("/state")];
+       char *current_state_str;
+       XenbusState current_state;
+       int xbt_flag = 0; /* non-zero if transaction started */
+       int retry = 0;
+       int err;
+
+       sprintf(state_path, "%s/state", xendev->nodename);
+
+       do {
+               if (xbt == XBT_NIL) {
+                       err = xs_transaction_start(&xbt);
+                       if (err)
+                               goto exit;
+                       xbt_flag = 1;
+               }
+
+               /* check if state is already set */
+               current_state_str = xs_read(xbt, state_path);
+               if (PTRISERR(current_state_str)) {
+                       err = PTR2ERR(current_state_str);
+                       goto exit;
+               }
+
+               /* convert to int */
+               current_state = (XenbusState) (current_state_str[0] - '0');
+               uk_xb_free(current_state_str);
+
+               if (current_state == state)
+                       /* state already set */
+                       goto exit;
+
+               /* set new state */
+               err = xs_printf(xbt, xendev->nodename, "state", "%d", state);
+
+exit:
+               if (xbt_flag) {
+                       int _err;
+
+                       _err = xs_transaction_end(xbt, 0, &retry);
+                       if (!err)
+                               err = _err;
+                       xbt = XBT_NIL;
+               }
+       } while (retry);
+
+       if (err)
+               uk_printd(DLVL_ERR, "Error switching state to %s: %d\n",
+                       xenbus_state_to_str(state), err);
+
+       return err;
+}
+
+int xenbus_wait_for_state_change(const char *path, XenbusState *state,
+               xenbus_watch_evlist_t *evlist)
+{
+       char *current_state_str;
+       XenbusState current_state;
+
+       if (!evlist)
+               evlist = &xenbus_watch_evlist;
+
+       for (;;) {
+               current_state_str = xs_read(XBT_NIL, path);
+               if (PTRISERR(current_state_str))
+                       return PTR2ERR(current_state_str);
+
+               /* convert to int */
+               current_state = (XenbusState) (current_state_str[0] - '0');
+               uk_xb_free(current_state_str);
+
+               if (current_state == *state)
+                       xenbus_wait_watch_event(evlist);
+               else {
+                       *state = current_state;
+                       break;
+               }
+       }
+
+       return 0;
+}
diff --git a/plat/xen/xenbus/xenbus.c b/plat/xen/xenbus/xenbus.c
new file mode 100644
index 0000000..cb177e1
--- /dev/null
+++ b/plat/xen/xenbus/xenbus.c
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <uk/essentials.h>
+#include <uk/list.h>
+#include <uk/bus.h>
+#include <uk/print.h>
+#include <uk/errptr.h>
+#include <uk/assert.h>
+#include <xenbus/xenbus.h>
+#include <xenbus/xs.h>
+#include <xenbus/client.h>
+#include "xs_comms.h"
+
+#define XS_DEV_PATH "device"
+
+#define FOREACH_DRIVER(drv) \
+       UK_TAILQ_FOREACH(drv, &xbh.drv_list, next)
+
+#define FOREACH_DRIVER_SAFE(drv, drv_next) \
+       UK_TAILQ_FOREACH_SAFE(drv, &xbh.drv_list, next, drv_next)
+
+#define FOREACH_DEVICE(dev) \
+       UK_TAILQ_FOREACH(dev, &xbh.dev_list, ph_next)
+
+
+static struct xenbus_driver *xenbus_find_driver(xenbus_dev_type_t devtype)
+{
+       struct xenbus_driver *drv;
+       const xenbus_dev_type_t *pdevtype;
+
+       FOREACH_DRIVER(drv) {
+               for (pdevtype = drv->device_types;
+                               *pdevtype != xenbus_dev_none; pdevtype++) {
+                       if (*pdevtype == devtype)
+                               return drv;
+               }
+       }
+
+       return NULL; /* no driver found */
+}
+
+static int xenbus_probe_device(struct xenbus_driver *drv,
+               xenbus_dev_type_t type, const char *name)
+{
+       int err;
+       struct xenbus_device *dev;
+       char *nodename;
+       XenbusState state;
+
+       /* device/type/name */
+       nodename = xs_join("%s/%s/%s",
+               XS_DEV_PATH, xenbus_devtype_to_str(type), name);
+       if (PTRISERR(nodename)) {
+               err = PTR2ERR(nodename);
+               goto out;
+       }
+
+       state = xenbus_read_driver_state(nodename);
+       if (state != XenbusStateInitialising)
+               return 0;
+
+       uk_printd(DLVL_INFO, "Xenbus device: %s\n", nodename);
+
+       dev = uk_xb_calloc(1, sizeof(*dev) + strlen(nodename) + 1);
+       if (!dev) {
+               uk_printd(DLVL_ERR, "Failed to initialize: Out of memory!\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       dev->state = XenbusStateInitialising;
+       dev->devtype = type;
+       dev->nodename = (char *) (dev + 1);
+       strcpy(dev->nodename, nodename);
+
+       err = drv->add_dev(dev);
+       if (err) {
+               uk_printd(DLVL_ERR, "Failed to add device.\n");
+               uk_xb_free(dev);
+       }
+
+out:
+       if (!PTRISERR(nodename))
+               uk_xb_free(nodename);
+
+       return err;
+}
+
+static int xenbus_probe_device_type(const char *devtype_str)
+{
+       struct xenbus_driver *drv;
+       xenbus_dev_type_t devtype;
+       char dirname[sizeof(XS_DEV_PATH) + strlen(devtype_str)];
+       char **devices = NULL;
+       int err = 0;
+
+       devtype = xenbus_str_to_devtype(devtype_str);
+       if (!devtype) {
+               uk_printd(DLVL_WARN,
+                       "Unsupported device type: %s\n", devtype_str);
+               goto out;
+       }
+
+       drv = xenbus_find_driver(devtype);
+       if (!drv) {
+               uk_printd(DLVL_WARN,
+                       "No driver for device type: %s\n", devtype_str);
+               goto out;
+       }
+
+       sprintf(dirname, "%s/%s", XS_DEV_PATH, devtype_str);
+
+       /* Get device list */
+       devices = xs_ls(XBT_NIL, dirname);
+       if (PTRISERR(devices)) {
+               err = PTR2ERR(devices);
+               uk_printd(DLVL_ERR,
+                       "Error reading %s devices: %d\n", devtype_str, err);
+               goto out;
+       }
+
+       for (int i = 0; devices[i] != NULL; i++) {
+               /* Probe only if no prior error */
+               if (err == 0)
+                       err = xenbus_probe_device(drv, devtype, devices[i]);
+
+               uk_xb_free(devices[i]);
+       }
+
+out:
+       if (!PTRISERR(devices))
+               uk_xb_free(devices);
+
+       return err;
+}
+
+static int xenbus_probe(void)
+{
+       char **devtypes;
+       int err = 0;
+
+       uk_printd(DLVL_INFO, "Probe Xenbus\n");
+
+       /* Get device types list */
+       devtypes = xs_ls(XBT_NIL, XS_DEV_PATH);
+       if (PTRISERR(devtypes)) {
+               err = PTR2ERR(devtypes);
+               uk_printd(DLVL_ERR, "Error reading device types: %d\n", err);
+               goto out;
+       }
+
+       for (int i = 0; devtypes[i] != NULL; i++) {
+               /* Probe only if no previous error */
+               if (err == 0)
+                       err = xenbus_probe_device_type(devtypes[i]);
+
+               uk_xb_free(devtypes[i]);
+       }
+
+out:
+       if (!PTRISERR(devtypes))
+               uk_xb_free(devtypes);
+
+       return err;
+}
+
+static int xenbus_init(struct uk_alloc *a)
+{
+       struct xenbus_driver *drv, *drv_next;
+       int ret = 0;
+
+       UK_ASSERT(a != NULL);
+
+       xbh.a = a;
+
+       ret = xs_comms_init();
+       if (ret) {
+               uk_printd(DLVL_ERR,
+                       "Error initializing Xenstore communication.");
+               return ret;
+       }
+
+       if (!xbh.drv_list_initialized) {
+               UK_TAILQ_INIT(&xbh.drv_list);
+               xbh.drv_list_initialized = 1;
+       }
+       UK_TAILQ_INIT(&xbh.dev_list);
+
+       FOREACH_DRIVER_SAFE(drv, drv_next) {
+               if (drv->init) {
+                       ret = drv->init(a);
+                       if (ret == 0)
+                               continue;
+                       uk_printd(DLVL_ERR,
+                               "Failed to initialize driver %p: %d\n",
+                               drv, ret);
+                       UK_TAILQ_REMOVE(&xbh.drv_list, drv, next);
+               }
+       }
+
+       return 0;
+}
+
+void _xenbus_register_driver(struct xenbus_driver *drv)
+{
+       UK_ASSERT(drv != NULL);
+
+       if (!xbh.drv_list_initialized) {
+               UK_TAILQ_INIT(&xbh.drv_list);
+               xbh.drv_list_initialized = 1;
+       }
+
+       UK_TAILQ_INSERT_TAIL(&xbh.drv_list, drv, next);
+}
+
+/*
+ * Register this bus driver to libukbus:
+ */
+struct xenbus_handler xbh = {
+       .b.init  = xenbus_init,
+       .b.probe = xenbus_probe
+};
+
+UK_BUS_REGISTER(&xbh.b);
diff --git a/plat/xen/xenbus/xs.c b/plat/xen/xenbus/xs.c
new file mode 100644
index 0000000..ca9f6a2
--- /dev/null
+++ b/plat/xen/xenbus/xs.c
@@ -0,0 +1,518 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Steven Smith (sos22@xxxxxxxxx)
+ *          Grzegorz Milos (gm281@xxxxxxxxx)
+ *          John D. Ramsdell
+ *          Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2006, Cambridge University
+ *               2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+/*
+ * Ported from Mini-OS xenbus.c
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <uk/errptr.h>
+#include <xen/io/xs_wire.h>
+#include <xenbus/xs.h>
+#include "xs_comms.h"
+#include "xs_watch.h"
+
+
+static char *vjoin(const char *fmt, va_list ap)
+{
+       char *path;
+       unsigned int path_len;
+       va_list aq;
+
+       /* figure out the path length */
+       va_copy(aq, ap);
+       path_len = vsnprintf(NULL, 0, fmt, aq);
+       va_end(aq);
+
+       path = uk_xb_malloc(path_len + 1);
+       if (!path)
+               return ERR2PTR(ENOMEM);
+
+       vsnprintf(path, path_len + 1, fmt, ap);
+
+       return path;
+}
+
+char *xs_join(const char *fmt, ...)
+{
+       char *ret;
+       va_list ap;
+
+       if (fmt == NULL)
+               return ERR2PTR(EINVAL);
+
+       va_start(ap, fmt);
+       ret = vjoin(fmt, ap);
+       va_end(ap);
+
+       return ret;
+}
+
+/*
+ * Converts a Xenstore reply error to a positive error number.
+ * Returns 0 if the reply is successful.
+ */
+static int reply_to_errno(struct xsd_sockmsg *rep)
+{
+       int err = 0;
+       char *errstring;
+
+       if (PTRISERR(rep)) {
+               err = PTR2ERR(rep);
+               goto out;
+       }
+
+       if (rep->type != XS_ERROR)
+               goto out;
+
+       errstring = (char *) (rep + 1);
+
+       for (int i = 0; i < (int) ARRAY_SIZE(xsd_errors); i++) {
+               if (!strcmp(errstring, xsd_errors[i].errstring)) {
+                       err = xsd_errors[i].errnum;
+                       goto out;
+               }
+       }
+
+       uk_printd(DLVL_WARN, "Unknown Xenstore error: %s\n", errstring);
+       err = EINVAL;
+
+out:
+       return err;
+}
+
+/* Common function used for sending requests when replies aren't handled */
+static int xs_msg(enum xsd_sockmsg_type type, xenbus_transaction_t xbt,
+               struct xs_req *req, int req_num)
+{
+       struct xsd_sockmsg *rep;
+       int err;
+
+       rep = xs_msg_reply(type, xbt, req, req_num);
+       err = -reply_to_errno(rep);
+
+       uk_xb_free(rep);
+
+       return err;
+}
+
+char *xs_read(xenbus_transaction_t xbt, const char *path)
+{
+       struct xs_req req;
+       struct xsd_sockmsg *rep;
+       char *value;
+       int err;
+
+       if (path == NULL)
+               return ERR2PTR(EINVAL);
+
+       req = XS_REQ_STR_NULL(path);
+       rep = xs_msg_reply(XS_READ, xbt, &req, 1);
+       err = reply_to_errno(rep);
+       if (err) {
+               value = ERR2PTR(err);
+               goto out;
+       }
+
+       value = uk_xb_malloc(rep->len + 1);
+       if (!value) {
+               value = ERR2PTR(ENOMEM);
+               goto out;
+       }
+
+       memcpy(value, rep + 1, rep->len);
+       value[rep->len] = 0;
+
+out:
+       uk_xb_free(rep);
+
+       return value;
+}
+
+int xs_write(xenbus_transaction_t xbt,
+               const char *path, const char *value)
+{
+       struct xs_req req[2];
+
+       if (path == NULL || value == NULL)
+               return -EINVAL;
+
+       req[0] = XS_REQ_STR_NULL(path);
+       req[1] = XS_REQ_STR(value);
+
+       return xs_msg(XS_WRITE, xbt, req, ARRAY_SIZE(req));
+}
+
+char **xs_ls(xenbus_transaction_t xbt, const char *path)
+{
+       struct xs_req req;
+       struct xsd_sockmsg *rep;
+       int nr_elems, offs, i;
+       char *rep_values, **res = NULL;
+       int err;
+
+       if (path == NULL)
+               return ERR2PTR(EINVAL);
+
+       req = XS_REQ_STR_NULL(path);
+       rep = xs_msg_reply(XS_DIRECTORY, xbt, &req, 1);
+       err = reply_to_errno(rep);
+       if (err)
+               goto out_err;
+
+       rep_values = (char *) (rep + 1);
+
+       for (offs = nr_elems = 0; offs < (int) rep->len; offs++)
+               nr_elems += (rep_values[offs] == 0);
+
+       res = uk_xb_calloc(nr_elems + 1, sizeof(res[0]));
+       if (!res) {
+               err = ENOMEM;
+               goto out_err;
+       }
+
+       for (offs = i = 0; i < nr_elems; i++) {
+               char *elem = rep_values + offs;
+               int elem_len = strlen(elem);
+
+               res[i] = uk_xb_malloc(elem_len + 1);
+               if (!res[i]) {
+                       err = ENOMEM;
+                       goto out_err;
+               }
+
+               memcpy(res[i], elem, elem_len + 1);
+
+               offs += elem_len + 1;
+       }
+
+       uk_xb_free(rep);
+
+       return res;
+
+out_err:
+       if (!PTRISERR(res)) {
+               for (i = 0; i < nr_elems; i++) {
+                       if (res[i])
+                               uk_xb_free(res[i]);
+               }
+               uk_xb_free(res);
+       }
+       uk_xb_free(rep);
+
+       return ERR2PTR(err);
+}
+
+int xs_rm(xenbus_transaction_t xbt, const char *path)
+{
+       struct xs_req req;
+
+       if (path == NULL)
+               return -EINVAL;
+
+       req = XS_REQ_STR_NULL(path);
+
+       return xs_msg(XS_RM, xbt, &req, 1);
+}
+
+char *xs_get_perms(xenbus_transaction_t xbt, const char *path)
+{
+       struct xs_req req;
+       struct xsd_sockmsg *rep;
+       char *value;
+       int err;
+
+       if (path == NULL)
+               return ERR2PTR(EINVAL);
+
+       req = XS_REQ_STR_NULL(path);
+       rep = xs_msg_reply(XS_GET_PERMS, xbt, &req, 1);
+       err = reply_to_errno(rep);
+       if (err) {
+               value = ERR2PTR(err);
+               goto out;
+       }
+
+       value = uk_xb_malloc(rep->len + 1);
+       if (!value) {
+               value = ERR2PTR(ENOMEM);
+               goto out;
+       }
+
+       memcpy(value, rep + 1, rep->len);
+       value[rep->len] = 0;
+
+out:
+       uk_xb_free(rep);
+
+       return value;
+}
+
+#define PERM_MAX_SIZE 32
+int xs_set_perms(xenbus_transaction_t xbt, const char *path,
+               domid_t domid, char perm)
+{
+       char value[PERM_MAX_SIZE];
+       struct xs_req req[2];
+
+       if (path == NULL)
+               return -EINVAL;
+
+       req[0] = XS_REQ_STR_NULL(path);
+
+       snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, domid);
+       req[1].data = value;
+       req[1].len  = strlen(value) + 1;
+
+       return xs_msg(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req));
+}
+
+int xs_transaction_start(xenbus_transaction_t *xbt)
+{
+       /*
+        * xenstored becomes angry if you send a length 0 message,
+        * so just shove a nul terminator on the end
+        */
+       struct xs_req req;
+       struct xsd_sockmsg *rep;
+       int err;
+
+       if (xbt == NULL)
+               return -EINVAL;
+
+       req = XS_REQ_STR_NULL("");
+       rep = xs_msg_reply(XS_TRANSACTION_START, 0, &req, 1);
+       err = -reply_to_errno(rep);
+       if (err)
+               goto out;
+
+       *xbt = strtoul((char *) (rep + 1), NULL, 10);
+
+out:
+       uk_xb_free(rep);
+
+       return err;
+}
+
+int xs_transaction_end(xenbus_transaction_t xbt, int abort, int *retry)
+{
+       struct xs_req req;
+       int err;
+
+       if (retry == NULL)
+               return -EINVAL;
+
+       req.data = abort ? "F" : "T";
+       req.len = 2;
+
+       err = xs_msg(XS_TRANSACTION_END, xbt, &req, 1);
+
+       *retry = (err == EAGAIN) ? 1 : 0;
+
+       return err;
+}
+
+/* Send a debug message to xenbus. Can block. */
+int xs_debug_msg(const char *msg)
+{
+       struct xs_req req[3];
+       struct xsd_sockmsg *rep;
+       int err;
+
+       if (msg == NULL)
+               return -EINVAL;
+
+       req[0] = XS_REQ_STR_NULL("print");
+       req[1] = XS_REQ_STR(msg);
+       req[2] = XS_REQ_STR_NULL("");
+
+       rep = xs_msg_reply(XS_DEBUG, XBT_NIL, req, ARRAY_SIZE(req));
+       err = -reply_to_errno(rep);
+       if (err)
+               goto out;
+
+       uk_printd(DLVL_EXTRA,
+               "Got a reply, type %"__PRIu32", id %"__PRIu32", len 
%"__PRIu32".\n",
+               rep->type, rep->req_id, rep->len);
+
+out:
+       uk_xb_free(rep);
+
+       return err;
+}
+
+int xs_read_integer(const char *path, int *value)
+{
+       char *value_str;
+
+       if (path == NULL || value == NULL)
+               return -EINVAL;
+
+       value_str = xs_read(XBT_NIL, path);
+       if (PTRISERR(value_str))
+               return PTR2ERR(value_str);
+
+       *value = atoi(value_str);
+
+       uk_xb_free(value_str);
+
+       return 0;
+}
+
+char *xs_readf(xenbus_transaction_t xbt, const char *fmt, ...)
+{
+       char *fullpath;
+       char *val;
+       va_list args;
+
+       if (fmt == NULL)
+               return ERR2PTR(EINVAL);
+
+       va_start(args, fmt);
+       fullpath = vjoin(fmt, args);
+       va_end(args);
+
+       if (PTRISERR(fullpath))
+               return fullpath;
+
+       val = xs_read(xbt, fullpath);
+
+       uk_xb_free(fullpath);
+
+       return val;
+}
+
+int xs_printf(xenbus_transaction_t xbt,
+               const char *node, const char *path, const char *fmt, ...)
+{
+#define BUFFER_SIZE 256
+       char fullpath[BUFFER_SIZE];
+       char val[BUFFER_SIZE];
+       va_list args;
+       int err;
+
+       if (node == NULL || path == NULL || fmt == NULL)
+               return -EINVAL;
+
+       if (strlen(node) + strlen(path) + 1 >= BUFFER_SIZE)
+               return -ENOMEM;
+
+       sprintf(fullpath, "%s/%s", node, path);
+
+       va_start(args, fmt);
+       vsprintf(val, fmt, args);
+       va_end(args);
+
+       err = xs_write(xbt, fullpath, val);
+
+       return err;
+}
+
+domid_t xs_get_self_id(void)
+{
+       char *domid_str;
+       domid_t domid;
+
+       domid_str = xs_read(XBT_NIL, "domid");
+       if (PTRISERR(domid_str))
+               UK_CRASH("Error reading domain id.");
+
+       domid = (domid_t) strtoul(domid_str, NULL, 10);
+
+       uk_xb_free(domid_str);
+
+       return domid;
+}
+
+int xs_watch_path_token(xenbus_transaction_t xbt,
+               const char *path, const char *token,
+               xenbus_watch_evlist_t *events)
+{
+       struct xs_watch *watch;
+       struct xs_req req[2];
+
+       if (path == NULL || token == NULL || events == NULL)
+               return -EINVAL;
+
+       watch = xs_watch_create(path, token, events);
+       if (PTRISERR(watch))
+               return PTR2ERR(watch);
+
+       req[0] = XS_REQ_STR_NULL(path);
+       req[1] = XS_REQ_STR_NULL(token);
+
+       return xs_msg(XS_WATCH, xbt, req, ARRAY_SIZE(req));
+}
+
+int xs_unwatch_path_token(xenbus_transaction_t xbt,
+               const char *path, const char *token)
+{
+       struct xs_req req[2];
+       int err;
+
+       if (path == NULL || token == NULL)
+               return -EINVAL;
+
+       req[0] = XS_REQ_STR_NULL(path);
+       req[1] = XS_REQ_STR_NULL(token);
+
+       err = xs_msg(XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
+       if (err)
+               goto out;
+
+       err = xs_watch_destroy(path, token);
+
+out:
+       return err;
+}
+
+#define GLOBAL_XS_WATCH_TOKEN "global_xenstore_watch"
+static xenbus_watch_evlist_t global_xs_watch_evlist;
+
+int xs_watch_path(xenbus_transaction_t xbt, const char *path)
+{
+       return xs_watch_path_token(xbt, path, GLOBAL_XS_WATCH_TOKEN,
+               &global_xs_watch_evlist);
+}
+
+int xs_unwatch_path(xenbus_transaction_t xbt, const char *path)
+{
+       return xs_unwatch_path_token(xbt, path, GLOBAL_XS_WATCH_TOKEN);
+}
diff --git a/plat/xen/xenbus/xs_comms.c b/plat/xen/xenbus/xs_comms.c
new file mode 100644
index 0000000..80c2bdf
--- /dev/null
+++ b/plat/xen/xenbus/xs_comms.c
@@ -0,0 +1,484 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Steven Smith (sos22@xxxxxxxxx)
+ *          Grzegorz Milos (gm281@xxxxxxxxx)
+ *          John D. Ramsdell
+ *          Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2006, Cambridge University
+ *               2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+/*
+ * Communication with Xenstore
+ * Ported from Mini-OS xenbus.c
+ */
+
+#include <string.h>
+#include <uk/errptr.h>
+#include <uk/wait.h>
+#include <uk/arch/spinlock.h>
+#include <common/events.h>
+#include <xen-x86/mm.h>
+#include <xen-x86/setup.h>
+#include "xs_comms.h"
+#include "xs_watch.h"
+
+
+/*
+ * Xenstore handler structure
+ */
+struct xs_handler {
+       /**< Non-zero if initialized */
+       int initialized;
+       /**< Communication: event channel */
+       evtchn_port_t evtchn;
+       /**< Communication: shared memory */
+       struct xenstore_domain_interface *buf;
+       /**< Thread processing incoming xs replies */
+       struct uk_thread *thread;
+       /**< Waiting queue for notifying incoming xs replies */
+       struct uk_waitq waitq;
+};
+
+static struct xs_handler xsh;
+
+
+struct reqid_map_value {
+       /**< Non-zero if used and waiting for reply */
+       int in_use;
+       /**< Waiting queue for incoming reply notification */
+       struct uk_waitq waitq;
+       /**< Received reply */
+       void *reply;
+};
+
+/*
+ * Structure for mapping in-flight requests IDs to incoming replies.
+ * Request IDs are reused, hence the limited set of ID values.
+ */
+struct reqid_map {
+       /**< Number of live requests */
+       __u32 num_live;
+       /**< Current available request ID */
+       __u32 probe;
+       /**< Lock */
+       spinlock_t lock;
+       /**< Waiting queue for 'not-full' notifications */
+       struct uk_waitq waitq;
+
+       /* Map size is power of 2 */
+#define REQID_MAP_SHIFT  5
+#define REQID_MAP_SIZE   (1 << REQID_MAP_SHIFT)
+       /**< Device bus */
+       struct reqid_map_value values[REQID_MAP_SIZE];
+};
+
+static struct reqid_map reqid_map;
+
+static void reqid_map_init(struct reqid_map *reqidm)
+{
+       reqidm->num_live = 0;
+       reqidm->probe = 0;
+       ukarch_spin_lock_init(&reqidm->lock);
+       uk_waitq_init(&reqidm->waitq);
+}
+
+/*
+ * Allocate an identifier for a Xenstore request.
+ * Blocks if none are available.
+ */
+static int reqid_map_get_id(void)
+{
+       struct reqid_map_value *reqid_map_val;
+       __u32 probe;
+
+       /* wait for an available entry */
+       while (1) {
+               ukarch_spin_lock(&reqid_map.lock);
+
+               if (reqid_map.num_live < REQID_MAP_SIZE)
+                       break;
+
+               ukarch_spin_unlock(&reqid_map.lock);
+
+               uk_waitq_wait_event(&reqid_map.waitq,
+                       (reqid_map.num_live < REQID_MAP_SIZE));
+       }
+
+       /* find an available entry */
+       probe = reqid_map.probe;
+       while (1) {
+               reqid_map_val = &reqid_map.values[probe];
+
+               if (!reqid_map_val->in_use)
+                       break;
+
+               probe = (probe + 1) & ~REQID_MAP_SIZE;
+               /*
+                * The request IDs set must be big enough to hold the
+                * maximum number of in-flight Xenstore requests.
+                */
+               UK_ASSERT(probe != reqid_map.probe);
+       }
+
+       reqid_map_val->in_use = 1;
+       reqid_map.num_live++;
+       reqid_map.probe = (probe + 1) & ~REQID_MAP_SIZE;
+
+       ukarch_spin_unlock(&reqid_map.lock);
+
+       uk_waitq_init(&reqid_map_val->waitq);
+
+       return probe;
+}
+
+/* Release a request identifier */
+static void reqid_map_put_id(int id)
+{
+       struct reqid_map_value *reqid_map_val = &reqid_map.values[id];
+
+       UK_ASSERT(reqid_map_val->in_use);
+
+       ukarch_spin_lock(&reqid_map.lock);
+
+       reqid_map_val->in_use = 0;
+       reqid_map_val->reply = NULL;
+       reqid_map.num_live--;
+       reqid_map.probe = id;
+
+       if (reqid_map.num_live == 0 || reqid_map.num_live == REQID_MAP_SIZE - 1)
+               uk_waitq_wake_up(&reqid_map.waitq);
+
+       ukarch_spin_unlock(&reqid_map.lock);
+}
+
+static int xs_avail_space_for_read(unsigned int req_size)
+{
+       return (xsh.buf->rsp_prod - xsh.buf->rsp_cons >= req_size);
+}
+
+static int xs_avail_space_for_write(unsigned int req_size)
+{
+       return (xsh.buf->req_prod - xsh.buf->req_cons +
+               req_size <= XENSTORE_RING_SIZE);
+}
+
+static void memcpy_from_ring(const char *ring, char *dest, int off, int len)
+{
+       int c1, c2;
+
+       c1 = MIN(len, XENSTORE_RING_SIZE - off);
+       c2 = len - c1;
+
+       memcpy(dest, ring + off, c1);
+       memcpy(dest + c1, ring, c2);
+}
+
+/*
+ * Send data to Xenstore. This can block. All of the requests are seen
+ * by Xenstore as if sent atomically.
+ */
+static void xs_msg_write(struct xsd_sockmsg *xsd_req, struct xs_req *req)
+{
+       XENSTORE_RING_IDX prod;
+       const struct xs_req *crnt_req;
+       struct xs_req req_hdr;
+       unsigned int req_size, req_off;
+       unsigned int buf_off;
+       unsigned int this_chunk;
+       int rc;
+
+       req_size = sizeof(*xsd_req) + xsd_req->len;
+       UK_ASSERT(req_size <= XENSTORE_RING_SIZE);
+
+       req_hdr.data = xsd_req;
+       req_hdr.len  = sizeof(*xsd_req);
+
+       crnt_req = &req_hdr;
+
+       /*
+        * Wait for the ring to drain to the point where
+        * we can send the message.
+        */
+       if (!xs_avail_space_for_write(req_size)) {
+               /* Wait for there to be space on the ring */
+               DBGXB("prod %d, len %d, cons %d, size %d; waiting.\n",
+                       prod, req_size, buf->req_cons, XENSTORE_RING_SIZE);
+
+               uk_waitq_wait_event(&xsh.waitq,
+                       xs_avail_space_for_write(req_size));
+               DBGXB("Back from wait.\n");
+       }
+
+       /*
+        * We're now guaranteed to be able to send the message
+        * without overflowing the ring. Do so.
+        */
+
+       prod = xsh.buf->req_prod;
+       req_off = 0;
+       buf_off = 0;
+       while (req_off < req_size) {
+               this_chunk = MIN(crnt_req->len - buf_off,
+                       XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
+
+               memcpy(
+                       (char *) xsh.buf->req + MASK_XENSTORE_IDX(prod),
+                       (char *) crnt_req->data + buf_off,
+                       this_chunk
+               );
+
+               prod += this_chunk;
+               req_off += this_chunk;
+               buf_off += this_chunk;
+
+               if (buf_off == crnt_req->len) {
+                       buf_off = 0;
+                       if (crnt_req == &req_hdr)
+                               crnt_req = req;
+                       else
+                               crnt_req++;
+               }
+       }
+
+       DBGXB("Complete main loop of xb_write.\n");
+       UK_ASSERT(buf_off == 0);
+       UK_ASSERT(req_off == req_size);
+       UK_ASSERT(prod <= xsh.buf->req_cons + XENSTORE_RING_SIZE);
+
+       /* Remote must see entire message before updating indexes */
+       wmb();
+
+       xsh.buf->req_prod += req_size;
+
+       /* Send evtchn to notify remote */
+       rc = notify_remote_via_evtchn(xsh.evtchn);
+       UK_ASSERT(rc == 0);
+}
+
+struct xsd_sockmsg *xs_msg_reply(enum xsd_sockmsg_type msg_type,
+       xenbus_transaction_t xbt,
+       struct xs_req *req, int req_num)
+{
+       __u32 reqid;
+       struct reqid_map_value *reqid_map_val;
+       struct xsd_sockmsg xsd_req;
+       struct xsd_sockmsg *xsd_rep;
+
+       /* get a request id */
+       reqid = reqid_map_get_id();
+       reqid_map_val = &reqid_map.values[reqid];
+
+       xsd_req.type = msg_type;
+       xsd_req.req_id = reqid;
+       xsd_req.tx_id = xbt;
+       xsd_req.len = 0;
+       for (int i = 0; i < req_num; i++)
+               xsd_req.len += req[i].len;
+
+       /* send the request */
+       xs_msg_write(&xsd_req, req);
+
+       /* wait reply */
+       uk_waitq_wait_event(&reqid_map_val->waitq,
+               reqid_map_val->reply != NULL);
+
+       xsd_rep = reqid_map_val->reply;
+       UK_ASSERT(xsd_rep->req_id == reqid);
+
+       /* free request id */
+       reqid_map_put_id(reqid);
+
+       return xsd_rep;
+}
+
+/* Process an incoming xs reply */
+static void process_reply(struct xsd_sockmsg *msg)
+{
+       struct reqid_map_value *req_map_val = &reqid_map.values[msg->req_id];
+       int msg_size = sizeof(*msg) + msg->len;
+
+       req_map_val->reply = uk_xb_malloc(msg_size);
+       if (req_map_val->reply == NULL) {
+               uk_printd(DLVL_ERR,
+                       "No memory available for saving Xenstore reply!");
+               return;
+       }
+
+       memcpy_from_ring(
+               xsh.buf->rsp,
+               req_map_val->reply,
+               MASK_XENSTORE_IDX(xsh.buf->rsp_cons),
+               msg_size
+       );
+
+       xsh.buf->rsp_cons += msg_size;
+
+       /* notify waiting requester */
+       uk_waitq_wake_up(&req_map_val->waitq);
+}
+
+/* Process an incoming xs watch event */
+static void process_watch_event(struct xsd_sockmsg *msg)
+{
+       struct xs_watch_event *event;
+       char *data;
+       int err;
+
+       event = uk_xb_malloc(sizeof(*event) + msg->len);
+       if (event == NULL) {
+               uk_printd(DLVL_ERR,
+                       "No memory available for saving Xenstore watch 
notification info!");
+               return;
+       }
+
+       data = (char *) event + sizeof(*event);
+
+       memcpy_from_ring(
+               xsh.buf->rsp,
+               data,
+               MASK_XENSTORE_IDX(xsh.buf->rsp_cons + sizeof(*msg)),
+               msg->len
+       );
+       xsh.buf->rsp_cons += sizeof(*msg) + msg->len;
+
+       event->xs.path  = data;
+       event->xs.token = data + strlen(data) + 1;
+
+       err = xs_watch_notify(event);
+       if (err) {
+               uk_printd(DLVL_ERR, "Invalid watch event.");
+               uk_xb_free(event);
+       }
+}
+
+static void xs_thread_func(void *ign __unused)
+{
+       struct xsd_sockmsg msg;
+       XENSTORE_RING_IDX prod = xsh.buf->rsp_prod;
+
+       for (;;) {
+               /* wait for incoming xs response */
+               uk_waitq_wait_event(&xsh.waitq, prod != xsh.buf->rsp_prod);
+
+               while (1) {
+                       prod = xsh.buf->rsp_prod;
+
+                       DBGXB("Rsp_cons %d, rsp_prod %d.\n",
+                               buf->rsp_cons, buf->rsp_prod);
+
+                       if (!xs_avail_space_for_read(sizeof(msg)))
+                               break;
+
+                       /* Make sure data is read after reading the indexes */
+                       rmb();
+
+                       /* copy the message */
+                       memcpy_from_ring(
+                               xsh.buf->rsp,
+                               (char *) &msg,
+                               MASK_XENSTORE_IDX(xsh.buf->rsp_cons),
+                               sizeof(msg)
+                       );
+
+                       DBGXB("Msg len %d, %d avail, id %d.\n",
+                               msg.len + sizeof(msg),
+                               xsh.buf->rsp_prod - xsh.buf->rsp_cons,
+                               msg.req_id);
+
+                       if (!xs_avail_space_for_read(sizeof(msg) + msg.len))
+                               break;
+
+                       DBGXB("Message is good.\n");
+
+                       if (msg.type == XS_WATCH_EVENT)
+                               process_watch_event(&msg);
+                       else
+                               process_reply(&msg);
+               }
+       }
+}
+
+static void xs_evtchn_handler(evtchn_port_t port,
+               struct __regs *regs __unused, void *ign __unused)
+{
+       UK_ASSERT(xsh.initialized == 1);
+       UK_ASSERT(xsh.evtchn == port);
+       uk_waitq_wake_up(&xsh.waitq);
+}
+
+int xs_comms_init(void)
+{
+       struct uk_thread *thread;
+       evtchn_port_t port;
+
+       UK_ASSERT(xsh.initialized == 0);
+
+       reqid_map_init(&reqid_map);
+
+       uk_waitq_init(&xsh.waitq);
+
+       thread = uk_thread_create("xenstore", xs_thread_func, NULL);
+       if (PTRISERR(thread))
+               return PTR2ERR(thread);
+
+       xsh.thread = thread;
+
+       xsh.evtchn = HYPERVISOR_start_info->store_evtchn;
+       xsh.buf = mfn_to_virt(HYPERVISOR_start_info->store_mfn);
+
+       port = bind_evtchn(xsh.evtchn, xs_evtchn_handler, NULL);
+       UK_ASSERT(port == xsh.evtchn);
+       unmask_evtchn(xsh.evtchn);
+
+       xsh.initialized = 1;
+
+       uk_printd(DLVL_INFO,
+               "Xenstore connection initialised on port %d, buf %p (mfn 
%#lx)\n",
+               port, xsh.buf, HYPERVISOR_start_info->store_mfn);
+
+       return 0;
+}
+
+void xs_comms_fini(void)
+{
+       UK_ASSERT(xsh.initialized == 1);
+
+       mask_evtchn(xsh.evtchn);
+       unbind_evtchn(xsh.evtchn);
+
+       xsh.buf = NULL;
+
+       /* TODO stop thread, instead of killing it */
+       uk_thread_destroy(xsh.thread);
+       xsh.thread = NULL;
+
+       xsh.initialized = 0;
+}
diff --git a/plat/xen/xenbus/xs_comms.h b/plat/xen/xenbus/xs_comms.h
new file mode 100644
index 0000000..230c4ad
--- /dev/null
+++ b/plat/xen/xenbus/xs_comms.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#ifndef __XS_COMMS_H__
+#define __XS_COMMS_H__
+
+#include <xen/io/xs_wire.h>
+#include <xenbus/xenbus.h>
+#include <xenbus/xs.h>
+
+int  xs_comms_init(void);
+void xs_comms_fini(void);
+
+struct xs_req {
+       const void *data;
+       unsigned int len;
+};
+
+/* Helper macro for initializing xs requests from strings */
+#define XS_REQ_STR(str) \
+       ((struct xs_req) { str, strlen(str) })
+
+/* Helper macro for initializing xs requests from strings
+ * (w/ null terminator)
+ */
+#define XS_REQ_STR_NULL(str) \
+       ((struct xs_req) { str, strlen(str) + 1 })
+
+/*
+ * Sends a message to Xenstore and blocks waiting for a reply.
+ * The reply is malloc'ed and should be freed by the caller.
+ *
+ * @param msg_type Xenstore message type
+ * @param xbt Xenbus transaction id
+ * @param req Array of requests
+ * @param req_num Requests number
+ * @return On success, returns a malloc'd copy of the reply. On error, returns
+ * a negative error number which should be checked using PTRISERR.
+ */
+struct xsd_sockmsg *xs_msg_reply(enum xsd_sockmsg_type msg_type,
+       xenbus_transaction_t xbt,
+       struct xs_req *req, int req_num);
+
+#endif /* __XS_COMMS_H__ */
diff --git a/plat/xen/xenbus/xs_watch.c b/plat/xen/xenbus/xs_watch.c
new file mode 100644
index 0000000..912fdd2
--- /dev/null
+++ b/plat/xen/xenbus/xs_watch.c
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+/* Internal API for Xenstore watches */
+
+#include <string.h>
+#include <uk/errptr.h>
+#include <xenbus/client.h>
+#include "xs_watch.h"
+
+/* Watches list */
+static struct xenbus_watch *xs_watch_list;
+
+static void watch_list_add(struct xs_watch *xsw)
+{
+       xsw->base.next = xs_watch_list;
+       xs_watch_list = &xsw->base;
+}
+
+static int xs_watch_info_equal(const struct xs_watch_info *xswi,
+       const char *path, const char *token)
+{
+       return (strcmp(xswi->path, path) == 0 &&
+               strcmp(xswi->token, token) == 0);
+}
+
+static struct xs_watch *watch_list_remove(const char *path, const char *token)
+{
+       struct xenbus_watch *xbw, **prev_xbw;
+
+       for (prev_xbw = &xs_watch_list, xbw = *prev_xbw;
+                       xbw != NULL;
+                       prev_xbw = &xbw->next, xbw = *prev_xbw) {
+               struct xs_watch *xsw = (struct xs_watch *) xbw;
+
+               if (xs_watch_info_equal(&xsw->xs, path, token)) {
+                       *prev_xbw = xbw->next;
+                       return xsw;
+               }
+       }
+
+       return NULL;
+}
+
+static struct xs_watch *watch_list_find(const char *path, const char *token)
+{
+       struct xenbus_watch *xbw;
+
+       for (xbw = xs_watch_list; xbw != NULL; xbw = xbw->next) {
+               struct xs_watch *xsw = (struct xs_watch *) xbw;
+
+               if (xs_watch_info_equal(&xsw->xs, path, token))
+                       return xsw;
+       }
+
+       return NULL;
+}
+
+struct xs_watch *xs_watch_create(const char *path, const char *token,
+               xenbus_watch_evlist_t *events)
+{
+       struct xs_watch *xsw;
+       char *tmpstr;
+       int stringlen;
+
+       UK_ASSERT(path != NULL);
+       UK_ASSERT(token != NULL);
+       UK_ASSERT(events != NULL);
+
+       stringlen = strlen(token) + 1 + strlen(path) + 1;
+
+       xsw = uk_xb_malloc(sizeof(*xsw) + stringlen);
+       if (!xsw)
+               return ERR2PTR(ENOMEM);
+
+       xsw->base.events = events;
+
+       /* set token */
+       tmpstr = (char *) (xsw + 1);
+       strcpy(tmpstr, token);
+       xsw->xs.token = tmpstr;
+
+       /* set path */
+       tmpstr += strlen(token) + 1;
+       strcpy(tmpstr, path);
+       xsw->xs.path = tmpstr;
+
+       watch_list_add(xsw);
+
+       return xsw;
+}
+
+int xs_watch_destroy(const char *path, const char *token)
+{
+       struct xs_watch *xsw;
+       int err = 0;
+
+       UK_ASSERT(path != NULL);
+       UK_ASSERT(token != NULL);
+
+       xsw = watch_list_remove(path, token);
+       if (xsw)
+               uk_xb_free(xsw);
+       else
+               err = -ENOENT;
+
+       return err;
+}
+
+int xs_watch_notify(struct xs_watch_event *event)
+{
+       struct xs_watch *xsw;
+       int err;
+
+       UK_ASSERT(event != NULL);
+
+       /* check if we have a local watch for it */
+       xsw = watch_list_find(event->xs.path, event->xs.token);
+       if (!xsw) {
+               uk_printd(DLVL_WARN, "Unexpected watch: token %s, path %s\n",
+                       event->xs.token, event->xs.path);
+               return -ENOENT;
+       }
+
+       /* notify the waiting client */
+       err = xenbus_notify_watch_event(xsw->base.events, &event->base);
+
+       return err;
+}
diff --git a/plat/xen/xenbus/xs_watch.h b/plat/xen/xenbus/xs_watch.h
new file mode 100644
index 0000000..77dd575
--- /dev/null
+++ b/plat/xen/xenbus/xs_watch.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Costin Lupu <costin.lupu@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+/* Internal API for Xenstore watches */
+
+#ifndef __XS_WATCH_H__
+#define __XS_WATCH_H__
+
+#include <xenbus/xenbus.h>
+
+/* Xenstore watch info */
+struct xs_watch_info {
+       /**< Watched Xenstore path */
+       char *path;
+       /**< Watch identification token */
+       char *token;
+};
+
+/* Xenstore watch event */
+struct xs_watch_event {
+       struct xenbus_watch_event base;
+       struct xs_watch_info xs;
+};
+
+/* Xenstore watch */
+struct xs_watch {
+       struct xenbus_watch base;
+       struct xs_watch_info xs;
+};
+
+/*
+ * Create a Xenstore watch associated with a path.
+ *
+ * @param path Xenstore path
+ * @param token Watch identification token
+ * @param events List of watch events
+ * @return On success, returns a malloc'd Xenstore watch. On error, returns
+ * a negative error number which should be checked using PTRISERR.
+ */
+struct xs_watch *xs_watch_create(const char *path, const char *token,
+               xenbus_watch_evlist_t *events);
+
+/*
+ * Destroy a previously created Xenstore watch.
+ *
+ * @param path Xenstore path
+ * @param token Watch identification token
+ * @return 0 on success, a negative errno value on error.
+ */
+int xs_watch_destroy(const char *path, const char *token);
+
+/*
+ * Notifies the watch associated with the incoming event.
+ *
+ * @param event Incoming watch event
+ * @return 0 on success (if there is a watch for the input event token), a
+ * negative errno value on error.
+ */
+int xs_watch_notify(struct xs_watch_event *event);
+
+#endif /* __XS_WATCH_H__ */
-- 
2.11.0


_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

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