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

[Xen-devel] [PATCH 09/10] Xen: Xenstore communication via xenbus



Communication with Xenstore is now possible via xenbus. Initially
only xenstore_read and xenstore_directory are provided, but more
operations will be added. Xenbus rings are initialized on post.c
hardware init.

Signed-off-by: Daniel Castro <evil.dani@xxxxxxxxx>
---
 Makefile     |    2 +-
 src/post.c   |    2 +
 src/xen-xs.c |  243 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/xen-xs.h |    8 ++
 4 files changed, 254 insertions(+), 1 deletions(-)
 create mode 100644 src/xen-xs.c
 create mode 100644 src/xen-xs.h

diff --git a/Makefile b/Makefile
index 109091b..e4dd814 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ SRC16=$(SRCBOTH) system.c disk.c font.c
 SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
       acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
       lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c \
-      biostables.c xen.c bmp.c
+      biostables.c xen.c bmp.c xen-xs.c
 SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
 
 cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
diff --git a/src/post.c b/src/post.c
index e195e89..be8f5ed 100644
--- a/src/post.c
+++ b/src/post.c
@@ -26,6 +26,7 @@
 #include "xen.h" // xen_probe_hvm_info
 #include "ps2port.h" // ps2port_setup
 #include "virtio-blk.h" // virtio_blk_setup
+#include "xen-xs.h"
 
 
 /****************************************************************
@@ -190,6 +191,7 @@ init_hw(void)
     cbfs_payload_setup();
     ramdisk_setup();
     virtio_blk_setup();
+    xenbus_setup();
 }
 
 // Begin the boot process by invoking an int0x19 in 16bit mode.
diff --git a/src/xen-xs.c b/src/xen-xs.c
new file mode 100644
index 0000000..d4b6b26
--- /dev/null
+++ b/src/xen-xs.c
@@ -0,0 +1,243 @@
+/*
+ * xenbus.c: static, synchronous, read-only xenbus client for hvmloader.
+ *
+ * Copyright (c) 2009 Tim Deegan, Citrix Systems (R&D) Ltd.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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.
+ */
+
+#include "xen.h" // hypercalls
+#include "config.h" // CONFIG_*
+#include "util.h"
+#include "bitops.h"
+#include "memmap.h"
+
+
+static struct xenstore_domain_interface *rings; /* Shared ring with dom0 */
+static evtchn_port_t event;                     /* Event-channel to dom0 */
+static char payload[XENSTORE_PAYLOAD_MAX + 1];  /* Unmarshalling area */
+
+
+/*
+ * Connect our xenbus client to the backend.
+ * Call once, before any other xenbus actions.
+ */
+void xenbus_setup(void)
+{
+       struct xen_hvm_param param;
+       if (!CONFIG_XEN)
+               return;
+
+       /* Ask Xen where the xenbus shared page is. */
+       param.domid = DOMID_SELF;
+       param.index = HVM_PARAM_STORE_PFN;
+       if (hypercall_hvm_op(HVMOP_get_param, &param))
+               panic("Error on setup");
+       rings = (void *) (unsigned long) (param.value << PAGE_SHIFT);
+
+       /* Ask Xen where the xenbus event channel is. */
+       param.domid = DOMID_SELF;
+       param.index = HVM_PARAM_STORE_EVTCHN;
+       if (hypercall_hvm_op(HVMOP_get_param, &param))
+               panic("error on hypercall to define rings and channel");
+       event = param.value;
+       dprintf(1,"Xenbus rings @0x%lx, event channel %lu\n",
+                       (unsigned long) rings, (unsigned long) event);
+}
+
+/*
+ * Reset the xenbus connection
+ */
+void xenbus_shutdown(void)
+{
+       if (rings == NULL)
+               panic("rings not defined");
+       memset(rings, 0, sizeof *rings);
+       memset(get_shared_info(), 0, 1024);
+       rings = NULL;
+}
+
+/*
+ * 1. Get xen shared info
+ * 2. get the guest event handle
+ * 3. while no events pending
+ * 4 .issue a yield to the CPU until event arrives
+ */
+static void ring_wait(void)
+{
+       struct shared_info *shinfo = get_shared_info();
+       struct sched_poll poll;
+
+       memset(&poll, 0, sizeof(poll));
+       set_xen_guest_handle(poll.ports, &event);
+       poll.nr_ports = 1;
+
+       while (!test_and_clear_bit(event, shinfo->evtchn_pending))
+               hypercall_sched_op(SCHEDOP_poll, &poll);
+}
+
+/*
+ * Writes data to xenstore ring
+ */
+static void ring_write(char *data, u32 len)
+{
+       u32 part;
+
+       if (len >= XENSTORE_PAYLOAD_MAX)
+               panic("Write Error on RINGS, more data than available buffer");
+
+       while (len)
+       {
+               while ((part = (XENSTORE_RING_SIZE - 1) -
+                               MASK_XENSTORE_IDX(rings->req_prod - 
rings->req_cons)) == 0) {
+                       ring_wait();
+                       //The ring is not empty or not ready
+               }
+               if (part > (XENSTORE_RING_SIZE - 
MASK_XENSTORE_IDX(rings->req_prod)))
+                       part = XENSTORE_RING_SIZE - 
MASK_XENSTORE_IDX(rings->req_prod);
+
+               if (part > len) /* Don't write more than we were asked for */
+                       part = len;
+               memcpy(rings->req + MASK_XENSTORE_IDX(rings->req_prod), data, 
part);
+               barrier();
+               rings->req_prod += part;
+               len -= part;
+       }
+}
+
+/*
+ * reads response from xenstore ring
+ */
+static void ring_read(char *data, u32 len)
+{
+       u32 part;
+
+       if (len >= XENSTORE_PAYLOAD_MAX)
+               panic("RING READ ERROR, more data that buffer space on rings");
+
+       while (len) {
+               while ((part = MASK_XENSTORE_IDX(rings->rsp_prod 
-rings->rsp_cons)) == 0) {
+                       ring_wait(); //The ring is not ready or not empty
+               }
+               /* Don't overrun the end of the ring */
+               if (part > (XENSTORE_RING_SIZE - 
MASK_XENSTORE_IDX(rings->rsp_cons)))
+                       part = XENSTORE_RING_SIZE - 
MASK_XENSTORE_IDX(rings->rsp_cons);
+
+               if (part > len) /* Don't read more than we were asked for */
+                       part = len;
+               memcpy(data, rings->rsp + MASK_XENSTORE_IDX(rings->rsp_cons), 
part);
+               barrier();
+               rings->rsp_cons += part;
+               len -= part;
+       }
+}
+
+
+/*
+ * Send a request and wait for the answer.
+ * Returns 0 for success, or an errno for error.
+ */
+static int xenbus_send(u32 type, u32 len, char *data,
+               u32 *reply_len, char **reply_data)
+{
+       struct xsd_sockmsg hdr;
+       evtchn_send_t send;
+       int i,ret;
+
+       /* Not acceptable to use xenbus before setting it up */
+       if (rings == NULL)
+               panic("XENBUS rings not defined\n");
+
+       /* Put the request on the ring */
+       hdr.type = type;
+       /* We only ever issue one request at a time */
+       hdr.req_id = 222;
+       /* We never use transactions */
+       hdr.tx_id = 0;
+       hdr.len = len;
+       ring_write((char *) &hdr, sizeof hdr);
+       ring_write(data, len);
+       /* Tell the other end about the request */
+       send.port = event;
+       ret = hypercall_event_channel_op(EVTCHNOP_send, &send);
+       dprintf(1,"Hypercall event channel notification %d\n",ret);
+       /* Properly we should poll the event channel now but that involves
+        * mapping the shared-info page and handling the bitmaps. */
+       /* Pull the reply off the ring */
+       ring_read((char *) &hdr, sizeof(hdr));
+       ring_read(payload, hdr.len);
+       /* For sanity's sake, nul-terminate the answer */
+       payload[hdr.len] = '\0';
+       /* Handle errors */
+       if ( hdr.type == XS_ERROR )
+       {
+               *reply_len = 0;
+               for ( i = 0; i < ((sizeof xsd_errors) / (sizeof 
xsd_errors[0])); i++ ){
+                       if ( !strcmp(xsd_errors[i].errstring, payload) ){
+                               return xsd_errors[i].errnum;
+                       }
+               }
+               return EIO;
+       }
+       *reply_data = payload;
+       *reply_len = hdr.len;
+       return hdr.type;
+}
+
+
+/*
+ * Read a xenstore key.  Returns a nul-terminated string (even if the XS
+ * data wasn't nul-terminated) or NULL.  The returned string is in a
+ * static buffer, so only valid until the next xenstore/xenbus operation.
+ */
+char * xenstore_read(char *path){
+       if (rings == NULL)
+               panic("rings not defined");
+       u32 len = 0;
+       char *answer = NULL;
+
+       /* Include the nul in the request */
+       if ( xenbus_send(XS_READ, strlen(path)+1, path, &len, &answer)== 
XS_ERROR ){
+               return NULL;
+       }
+       /* We know xenbus_send() nul-terminates its answer, so just pass it on. 
*/
+       return answer;
+}
+
+/*
+ * Read a xenstore directory.  Returns a nul-separeted and nul-terminated 
string (even if the XS
+ * data wasn't nul-terminated) or NULL.  The returned string is in a
+ * static buffer, so only valid until the next xenstore/xenbus operation.
+ * ans_len will tell the caller the length of the response
+ */
+char * xenstore_directory(char *path, u32 *ans_len){
+       if (rings == NULL)
+               panic("rings not defined");
+       char *answer = NULL;
+
+       /* Include the nul in the request */
+       if ( xenbus_send(XS_DIRECTORY, strlen(path)+1, path, ans_len, 
&answer)== XS_ERROR ){
+               return NULL;
+       }
+       /* We know xenbus_send() nul-terminates its answer, so just pass it on. 
*/
+       return answer;
+}
diff --git a/src/xen-xs.h b/src/xen-xs.h
new file mode 100644
index 0000000..91e8da0
--- /dev/null
+++ b/src/xen-xs.h
@@ -0,0 +1,8 @@
+#ifndef _XEN_XS_H
+#define _XEN_XS_H
+
+void xenbus_setup(void);
+char * xenstore_read(char *path);
+char * xenstore_directory(char *path, u32 *ans_len);
+
+#endif
-- 
1.7.4.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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