# HG changeset patch # User Tim Deegan # Date 1278671249 -3600 # Node ID 62b9338150160d6f7cea3e2c386f5e6f94e1b13b # Parent 82f8371effffc7f3f405fc524cf27c3f07d27249 Add a xenbus frontend to hvmloader so it can read values from xenstore. Signed-off-by: Tim Deegan diff -r 82f8371effff -r 62b933815016 tools/firmware/hvmloader/Makefile --- a/tools/firmware/hvmloader/Makefile Thu Jul 08 17:54:42 2010 +0100 +++ b/tools/firmware/hvmloader/Makefile Fri Jul 09 11:27:29 2010 +0100 @@ -29,7 +29,7 @@ CFLAGS += $(CFLAGS_include) -I. SRCS = hvmloader.c mp_tables.c util.c smbios.c -SRCS += 32bitbios_support.c smp.c cacheattr.c +SRCS += 32bitbios_support.c smp.c cacheattr.c xenbus.c ifeq ($(debug),y) SRCS += tests.c endif diff -r 82f8371effff -r 62b933815016 tools/firmware/hvmloader/hvmloader.c --- a/tools/firmware/hvmloader/hvmloader.c Thu Jul 08 17:54:42 2010 +0100 +++ b/tools/firmware/hvmloader/hvmloader.c Fri Jul 09 11:27:29 2010 +0100 @@ -704,6 +704,7 @@ printf("CPU speed is %u MHz\n", get_cpu_mhz()); + xenbus_setup(); apic_setup(); pci_setup(); @@ -803,6 +804,8 @@ bios_info->madt_lapic0_addr = madt_lapic0_addr; bios_info->bios32_entry = bios32_addr; + xenbus_shutdown(); + printf("Invoking ROMBIOS ...\n"); return 0; } diff -r 82f8371effff -r 62b933815016 tools/firmware/hvmloader/util.h --- a/tools/firmware/hvmloader/util.h Thu Jul 08 17:54:42 2010 +0100 +++ b/tools/firmware/hvmloader/util.h Fri Jul 09 11:27:29 2010 +0100 @@ -155,6 +155,18 @@ void *mem_alloc(uint32_t size, uint32_t align); #define virt_to_phys(v) ((unsigned long)(v)) +/* Connect our xenbus client to the backend. + * Call once, before any other xenbus actions. */ +void xenbus_setup(void); + +/* Reset the xenbus connection so the next kernel can start again. */ +void xenbus_shutdown(void); + +/* 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); + /* Prepare the 32bit BIOS */ uint32_t highbios_setup(void); diff -r 82f8371effff -r 62b933815016 tools/firmware/hvmloader/xenbus.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/firmware/hvmloader/xenbus.c Fri Jul 09 11:27:29 2010 +0100 @@ -0,0 +1,193 @@ +/* + * xenbus.c: static, synchronous, read-only xenbus client for hvmloader. + * + * Copyright (c) 2009 Tim Deegan, Citrix Systems (R&D) Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "util.h" +#include "hypercall.h" +#include +#include +#include +#include +#include + +struct xenstore_domain_interface *rings; /* Shared ring with dom0 */ +evtchn_port_t event; /* Event-channel to dom0 */ +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) +{ + xen_hvm_param_t param; + + /* Ask Xen where the xenbus shared page is. */ + param.domid = DOMID_SELF; + param.index = HVM_PARAM_STORE_PFN; + ASSERT(hypercall_hvm_op(HVMOP_get_param, ¶m) == 0); + 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; + ASSERT(hypercall_hvm_op(HVMOP_get_param, ¶m) == 0); + event = param.value; + + printf("Xenbus rings @0x%lx, event channel %lu\n", + (unsigned long) rings, (unsigned long) event); +} + +/* Reset the xenbus connection so the next kernel can start again. + * We zero out the whole ring -- the backend can handle this, and it's + * not going to surprise any frontends since it's equivalent to never + * having used the rings. */ +void xenbus_shutdown(void) +{ + ASSERT(rings); + memset(rings, 0, sizeof *rings); + rings = NULL; +} + +/* Helper functions: copy data in and out of the ring */ +static void ring_write(char *data, uint32_t len) +{ + uint32_t part; + ASSERT(len <= XENSTORE_PAYLOAD_MAX); + + while (len) { + /* Don't overrun the consumer pointer */ + part = (XENSTORE_RING_SIZE - 1) - + MASK_XENSTORE_IDX(rings->req_prod - rings->req_cons); + /* Don't overrun the end of the ring */ + if (part > XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(rings->req_prod)) + part = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(rings->req_prod); + /* Don't write more than we were asked for */ + if (part > len) + part = len; + + memcpy(rings->req + MASK_XENSTORE_IDX(rings->req_prod), data, part); + barrier(); /* = wmb before prod write, rmb before next cons read */ + rings->req_prod += part; + len -= part; + + if (len) + hypercall_sched_op(SCHEDOP_yield, NULL); + } +} + +static void ring_read(char *data, uint32_t len) +{ + uint32_t part; + ASSERT(len <= XENSTORE_PAYLOAD_MAX); + + while (len) { + /* Don't overrun the producer pointer */ + part = MASK_XENSTORE_IDX(rings->rsp_prod - rings->rsp_cons); + /* 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); + /* Don't read more than we were asked for */ + if (part > len) + part = len; + + memcpy(data, rings->rsp + MASK_XENSTORE_IDX(rings->rsp_cons), part); + barrier(); /* = wmb before cons write, rmb before next prod read */ + rings->rsp_cons += part; + len -= part; + + if (len) + hypercall_sched_op(SCHEDOP_yield, NULL); + } +} + + +/* Send a request and wait for the answer. + * Returns 0 for success, or an errno for error. + * The answer is returned in a static buffer which is only + * valid until the next call of xenbus_send(). */ +static int xenbus_send(uint32_t type, uint32_t len, char *data, + uint32_t *reply_len, char **reply_data) +{ + struct xsd_sockmsg hdr; + evtchn_send_t send; + int i; + + /* Not acceptable to use xenbus before setting it up */ + ASSERT(rings); + + /* Put the request on the ring */ + hdr.type = type; + hdr.req_id = 0; /* We only ever issue one request at a time */ + hdr.tx_id = 0; /* We never use transactions */ + hdr.len = len; + ring_write((char *) &hdr, sizeof hdr); + ring_write(data, len); + + /* Tell the other end about the request */ + send.port = event; + hypercall_event_channel_op(EVTCHNOP_send, &send); + + /* 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; + /* Default error value if we couldn't decode the ASCII error */ + return EIO; + } + + *reply_data = payload; + *reply_len = hdr.len; + return 0; +} + + +/* 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) +{ + uint32_t len = 0; + char *answer = NULL; + + /* Include the nul in the request */ + if (xenbus_send(XS_READ, strlen(path) + 1, path, &len, &answer)) + return NULL; + /* We know xenbus_send() nul-terminates its answer, so just pass it on. */ + return answer; +} + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */