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, ¶m))
+ 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, ¶m))
+ 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
|