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@gmail.com --- 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