[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] Mini-os Xenbus
Minimal Xenbus implementation by Steven Smith replacing the old (broken) implementation. The changeset also contains several bug fixes including: BSS clearing, trap handler fix. Signed-off-by: Grzegorz Milos <gm281@xxxxxxxxx> Keir could you apply? Thanks. diff -r 410b49759f02 -r c247056431f8 extras/mini-os/Makefile --- a/extras/mini-os/Makefile Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/Makefile Thu Mar 23 18:34:50 2006 @@ -41,8 +41,7 @@ links: [ -e include/xen ] || ln -sf ../../../xen/include/public include/xen - [ -e xenbus/xenstored.h ] || ln -sf ../../../tools/xenstore/xenstored.h xenbus/xenstored.h - + $(TARGET): links $(OBJS) $(LD) -N -T minios-$(TARGET_ARCH).lds $(OBJS) -o $@.elf gzip -f -9 -c $@.elf >$@.gz diff -r 410b49759f02 -r c247056431f8 extras/mini-os/console/console.c --- a/extras/mini-os/console/console.c Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/console/console.c Thu Mar 23 18:34:50 2006 @@ -116,12 +116,12 @@ { (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(buf), buf); return; + } else { + if(!console_initialised) + (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(buf), buf); + + console_print(buf, strlen(buf)); } - - if(!console_initialised) - (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(buf), buf); - - console_print(buf, strlen(buf)); } void printk(const char *fmt, ...) diff -r 410b49759f02 -r c247056431f8 extras/mini-os/console/xencons_ring.c --- a/extras/mini-os/console/xencons_ring.c Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/console/xencons_ring.c Thu Mar 23 18:34:50 2006 @@ -10,7 +10,6 @@ /* TODO - need to define BUG_ON for whole mini-os, need crash-dump as well */ -extern void do_exit(void); #define BUG_ON(_cond) do{if(_cond) do_exit();} while(0); static inline struct xencons_interface *xencons_interface(void) @@ -29,7 +28,6 @@ int sent = 0; struct xencons_interface *intf = xencons_interface(); XENCONS_RING_IDX cons, prod; - cons = intf->out_cons; prod = intf->out_prod; mb(); diff -r 410b49759f02 -r c247056431f8 extras/mini-os/events.c --- a/extras/mini-os/events.c Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/events.c Thu Mar 23 18:34:50 2006 @@ -74,9 +74,9 @@ void unbind_evtchn( u32 port ) { - if (ev_actions[port].handler) + if (ev_actions[port].handler == default_handler) printk("WARN: No handler for port %d when unbinding\n", port); - ev_actions[port].handler = NULL; + ev_actions[port].handler = default_handler; ev_actions[port].status |= EVS_DISABLED; } diff -r 410b49759f02 -r c247056431f8 extras/mini-os/include/os.h --- a/extras/mini-os/include/os.h Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/include/os.h Thu Mar 23 18:34:50 2006 @@ -9,6 +9,7 @@ #define NULL 0 + #if __GNUC__ == 2 && __GNUC_MINOR__ < 96 #define __builtin_expect(x, expected_value) (x) #endif @@ -20,6 +21,10 @@ #ifndef __ASSEMBLY__ #include <types.h> #include <hypervisor.h> + +extern void do_exit(void); +#define BUG do_exit + #endif #include <xen/xen.h> diff -r 410b49759f02 -r c247056431f8 extras/mini-os/include/wait.h --- a/extras/mini-os/include/wait.h Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/include/wait.h Thu Mar 23 18:34:50 2006 @@ -66,6 +66,14 @@ } } +#define add_waiter(w, wq) do { \ + unsigned long flags; \ + local_irq_save(flags); \ + add_wait_queue(&wq, &w); \ + block(current); \ + local_irq_restore(flags); \ +} while (0) + #define wait_event(wq, condition) do{ \ unsigned long flags; \ if(condition) \ diff -r 410b49759f02 -r c247056431f8 extras/mini-os/include/xenbus.h --- a/extras/mini-os/include/xenbus.h Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/include/xenbus.h Thu Mar 23 18:34:50 2006 @@ -1,224 +1,6 @@ -/****************************************************************************** - * xenbus.h - * - * Talks to Xen Store to figure out what devices we have. - * - * Copyright (C) 2005 Rusty Russell, IBM Corporation - * Copyright (C) 2005 XenSource Ltd. - * - * This file may be distributed separately from the Linux kernel, or - * incorporated into other software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ +#ifndef XENBUS_H__ +#define XENBUS_H__ -#ifndef _ASM_XEN_XENBUS_H -#define _ASM_XEN_XENBUS_H +void init_xenbus(void); -#include <errno.h> -#include <xen/io/xenbus.h> -#include <xen/io/xs_wire.h> - -/* Register callback to watch this node. */ -struct xenbus_watch -{ - struct list_head list; - - /* Path being watched. */ - const char *node; - - /* Callback (executed in a process context with no locks held). */ - void (*callback)(struct xenbus_watch *, - const char **vec, unsigned int len); -}; - - -/* A xenbus device. */ -struct xenbus_device { - const char *devicetype; - const char *nodename; - const char *otherend; - int otherend_id; - struct xenbus_watch otherend_watch; - int has_error; - void *data; -}; - -struct xenbus_device_id -{ - /* .../device/<device_type>/<identifier> */ - char devicetype[32]; /* General class of device. */ -}; - -/* A xenbus driver. */ -struct xenbus_driver { - char *name; - struct module *owner; - const struct xenbus_device_id *ids; - int (*probe)(struct xenbus_device *dev, - const struct xenbus_device_id *id); - void (*otherend_changed)(struct xenbus_device *dev, - XenbusState backend_state); - int (*remove)(struct xenbus_device *dev); - int (*suspend)(struct xenbus_device *dev); - int (*resume)(struct xenbus_device *dev); - int (*hotplug)(struct xenbus_device *, char **, int, char *, int); - int (*read_otherend_details)(struct xenbus_device *dev); -}; - -int xenbus_register_frontend(struct xenbus_driver *drv); -int xenbus_register_backend(struct xenbus_driver *drv); -void xenbus_unregister_driver(struct xenbus_driver *drv); - -struct xenbus_transaction; - -char **xenbus_directory(struct xenbus_transaction *t, - const char *dir, const char *node, unsigned int *num); -void *xenbus_read(struct xenbus_transaction *t, - const char *dir, const char *node, unsigned int *len); -int xenbus_write(struct xenbus_transaction *t, - const char *dir, const char *node, const char *string); -int xenbus_mkdir(struct xenbus_transaction *t, - const char *dir, const char *node); -int xenbus_exists(struct xenbus_transaction *t, - const char *dir, const char *node); -int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node); -struct xenbus_transaction *xenbus_transaction_start(void); -int xenbus_transaction_end(struct xenbus_transaction *t, int abort); - -/* Single read and scanf: returns -errno or num scanned if > 0. */ -int xenbus_scanf(struct xenbus_transaction *t, - const char *dir, const char *node, const char *fmt, ...) - __attribute__((format(scanf, 4, 5))); - -/* Single printf and write: returns -errno or 0. */ -int xenbus_printf(struct xenbus_transaction *t, - const char *dir, const char *node, const char *fmt, ...) - __attribute__((format(printf, 4, 5))); - -/* Generic read function: NULL-terminated triples of name, - * sprintf-style type string, and pointer. Returns 0 or errno.*/ -int xenbus_gather(struct xenbus_transaction *t, const char *dir, ...); - -int register_xenbus_watch(struct xenbus_watch *watch); -void unregister_xenbus_watch(struct xenbus_watch *watch); -void xs_suspend(void); -void xs_resume(void); - -/* Used by xenbus_dev to borrow kernel's store connection. */ -void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg); - -/* Called from xen core code. */ -void xenbus_suspend(void); -void xenbus_resume(void); - -#define XENBUS_IS_ERR_READ(str) ({ \ - if (!IS_ERR(str) && strlen(str) == 0) { \ - kfree(str); \ - str = ERR_PTR(-ERANGE); \ - } \ - IS_ERR(str); \ -}) - -#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE) - - -/** - * Register a watch on the given path, using the given xenbus_watch structure - * for storage, and the given callback function as the callback. Return 0 on - * success, or -errno on error. On success, the given path will be saved as - * watch->node, and remains the caller's to free. On error, watch->node will - * be NULL, the device will switch to XenbusStateClosing, and the error will - * be saved in the store. - */ -int xenbus_watch_path(struct xenbus_device *dev, const char *path, - struct xenbus_watch *watch, - void (*callback)(struct xenbus_watch *, - const char **, unsigned int)); - - -/** - * Register a watch on the given path/path2, using the given xenbus_watch - * structure for storage, and the given callback function as the callback. - * Return 0 on success, or -errno on error. On success, the watched path - * (path/path2) will be saved as watch->node, and becomes the caller's to - * kfree(). On error, watch->node will be NULL, so the caller has nothing to - * free, the device will switch to XenbusStateClosing, and the error will be - * saved in the store. - */ -int xenbus_watch_path2(struct xenbus_device *dev, const char *path, - const char *path2, struct xenbus_watch *watch, - void (*callback)(struct xenbus_watch *, - const char **, unsigned int)); - - -/** - * Advertise in the store a change of the given driver to the given new_state. - * Perform the change inside the given transaction xbt. xbt may be NULL, in - * which case this is performed inside its own transaction. Return 0 on - * success, or -errno on error. On error, the device will switch to - * XenbusStateClosing, and the error will be saved in the store. - */ -int xenbus_switch_state(struct xenbus_device *dev, - struct xenbus_transaction *xbt, - XenbusState new_state); - - -/** - * Grant access to the given ring_mfn to the peer of the given device. Return - * 0 on success, or -errno on error. On error, the device will switch to - * XenbusStateClosing, and the error will be saved in the store. - */ -int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn); - - -/** - * Allocate an event channel for the given xenbus_device, assigning the newly - * created local port to *port. Return 0 on success, or -errno on error. On - * error, the device will switch to XenbusStateClosing, and the error will be - * saved in the store. - */ -int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port); - - -/** - * Return the state of the driver rooted at the given store path, or - * XenbusStateClosed if no state can be read. - */ -XenbusState xenbus_read_driver_state(const char *path); - - -/*** - * Report the given negative errno into the store, along with the given - * formatted message. - */ -void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, - ...); - - -/*** - * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by - * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly - * closedown of this driver and its peer. - */ -void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, - ...); - - -#endif /* _ASM_XEN_XENBUS_H */ +#endif /* XENBUS_H__ */ diff -r 410b49759f02 -r c247056431f8 extras/mini-os/kernel.c --- a/extras/mini-os/kernel.c Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/kernel.c Thu Mar 23 18:34:50 2006 @@ -35,7 +35,6 @@ #include <lib.h> #include <sched.h> #include <xenbus.h> -#include "xenbus/xenbus_comms.h" /* * Shared page for communicating with the hypervisor. @@ -76,7 +75,15 @@ } -extern void init_console(void); +void test_xenbus(void); + +/* Do initialisation from a thread once the scheduler's available */ +static void init_xs(void *ign) +{ + init_xenbus(); + + test_xenbus(); +} /* * INITIAL C ENTRY POINT. @@ -84,11 +91,13 @@ void start_kernel(start_info_t *si) { static char hello[] = "Bootstrapping...\n"; + (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(hello), hello); /* Copy the start_info struct to a globally-accessible area. */ + /* WARN: don't do printk before here, it uses information from + shared_info. Use xprintk instead. */ memcpy(&start_info, si, sizeof(*si)); - /* Grab the shared_info pointer and put it in a safe place. */ HYPERVISOR_shared_info = map_shared_info(start_info.shared_info); @@ -120,28 +129,24 @@ si->cmd_line ? (const char *)si->cmd_line : "NULL"); - /* - * If used for porting another OS, start here to figure out your - * guest os entry point. Otherwise continue below... - */ - /* init memory management */ + /* Init memory management. */ init_mm(); - /* set up events */ + /* Set up events. */ init_events(); - /* init time and timers */ + /* Init time and timers. */ init_time(); - /* init the console driver */ + /* Init the console driver. */ init_console(); - - /* init scheduler */ + + /* Init scheduler. */ init_sched(); - - /* init xenbus */ - xs_init(); - + + /* Init XenBus from a separate thread */ + create_thread("init_xs", init_xs, NULL); + /* Everything initialised, start idle thread */ run_idle_thread(); } @@ -156,6 +161,6 @@ void do_exit(void) { - printk("do_exit called!\n"); + printk("Do_exit called!\n"); for ( ;; ) HYPERVISOR_sched_op(SCHEDOP_shutdown, SHUTDOWN_crash); } diff -r 410b49759f02 -r c247056431f8 extras/mini-os/minios-x86_32.lds --- a/extras/mini-os/minios-x86_32.lds Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/minios-x86_32.lds Thu Mar 23 18:34:50 2006 @@ -21,15 +21,6 @@ _edata = .; /* End of data section */ - . = ALIGN(8192); /* init_task */ - .data.init_task : { *(.data.init_task) } - - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - __bss_start = .; /* BSS */ .bss : { *(.bss) diff -r 410b49759f02 -r c247056431f8 extras/mini-os/mm.c --- a/extras/mini-os/mm.c Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/mm.c Thu Mar 23 18:34:50 2006 @@ -51,7 +51,6 @@ unsigned long *phys_to_machine_mapping; extern char *stack; extern char _text, _etext, _edata, _end; -extern void do_exit(void); extern void page_walk(unsigned long virt_addr); /********************* diff -r 410b49759f02 -r c247056431f8 extras/mini-os/sched.c --- a/extras/mini-os/sched.c Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/sched.c Thu Mar 23 18:34:50 2006 @@ -65,6 +65,8 @@ struct thread *idle_thread = NULL; LIST_HEAD(exited_threads); +void idle_thread_fn(void *unused); + void dump_stack(struct thread *thread) { unsigned long *bottom = (unsigned long *)thread->stack + 2048; @@ -132,7 +134,7 @@ xfree(thread); } } - next = idle_thread; + next = idle_thread; /* Thread list needs to be protected */ list_for_each(iterator, &idle_thread->thread_list) { @@ -203,8 +205,13 @@ set_runnable(thread); local_irq_save(flags); - if(idle_thread != NULL) + if(idle_thread != NULL) { list_add_tail(&thread->thread_list, &idle_thread->thread_list); + } else if(function != idle_thread_fn) + { + printk("BUG: Not allowed to create thread before initialising scheduler.\n"); + BUG(); + } local_irq_restore(flags); return thread; @@ -282,19 +289,9 @@ void init_sched(void) { - printk("Initialising scheduler\n"); - + printk("Initialising scheduler, idle_thread %p\n", idle_thread); + idle_thread = create_thread("Idle", idle_thread_fn, NULL); INIT_LIST_HEAD(&idle_thread->thread_list); - - -/* create_thread("1", th_f1, (void *)0x1234); - create_thread("2", th_f1, (void *)0x1234); - create_thread("3", th_f1, (void *)0x1234); - create_thread("4", th_f1, (void *)0x1234); - create_thread("5", th_f1, (void *)0x1234); - create_thread("6", th_f1, (void *)0x1234); - create_thread("second", th_f2, NULL); -*/ -} - +} + diff -r 410b49759f02 -r c247056431f8 extras/mini-os/traps.c --- a/extras/mini-os/traps.c Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/traps.c Thu Mar 23 18:34:50 2006 @@ -29,11 +29,18 @@ void machine_check(void); -extern void do_exit(void); - void dump_regs(struct pt_regs *regs) { - printk("FIXME: proper register dump (with the stack dump)\n"); + printk("EIP: %x, EFLAGS %x.\n", regs->eip, regs->eflags); + printk("EBX: %08x ECX: %08x EDX: %08x\n", + regs->ebx, regs->ecx, regs->edx); + printk("ESI: %08x EDI: %08x EBP: %08x EAX: %08x\n", + regs->esi, regs->edi, regs->ebp, regs->eax); + printk("DS: %04x ES: %04x orig_eax: %08x, eip: %08x\n", + regs->xds, regs->xes, regs->orig_eax, regs->eip); + printk("CS: %04x EFLAGS: %08x esp: %08x ss: %04x\n", + regs->xcs, regs->eflags, regs->esp, regs->xss); + } @@ -94,10 +101,14 @@ } -void do_page_fault(struct pt_regs *regs, unsigned long error_code, - unsigned long addr) -{ - printk("Page fault at linear address %p\n", addr); +#define read_cr2() \ + (HYPERVISOR_shared_info->vcpu_info[smp_processor_id()].arch.cr2) + +void do_page_fault(struct pt_regs *regs, unsigned long error_code) +{ + unsigned long addr = read_cr2(); + printk("Page fault at linear address %p, regs %p, code %lx\n", addr, regs, + error_code); dump_regs(regs); #ifdef __x86_64__ /* FIXME: _PAGE_PSE */ diff -r 410b49759f02 -r c247056431f8 extras/mini-os/x86_32.S --- a/extras/mini-os/x86_32.S Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/x86_32.S Thu Mar 23 18:34:50 2006 @@ -30,10 +30,10 @@ hypercall_page: .org 0x3000 -ES = 0x20 -ORIG_EAX = 0x24 -EIP = 0x28 -CS = 0x2C +ES = 0x1c +ORIG_EAX = 0x20 +EIP = 0x24 +CS = 0x28 #define ENTRY(X) .globl X ; X : @@ -94,32 +94,6 @@ call *%edi addl $8,%esp -/* pushl %ds - pushl %eax - xorl %eax,%eax - pushl %ebp - pushl %edi - pushl %esi - pushl %edx - decl %eax # eax = -1 - pushl %ecx - pushl %ebx - cld - movl %es,%ecx - movl ORIG_EAX(%esp), %esi # get the error code - movl ES(%esp), %edi # get the function address - movl %eax, ORIG_EAX(%esp) - movl %ecx, ES(%esp) - movl %esp,%edx - pushl %esi # push the error code - pushl %edx # push the pt_regs pointer - movl $(__KERNEL_DS),%edx - movl %edx,%ds - movl %edx,%es - call *%edi - addl $8,%esp */ - - ret_from_exception: movb CS(%esp),%cl test $2,%cl # slow return to ring 2 or 3 @@ -290,15 +264,16 @@ pushl %ecx pushl %ebx cld - movl %es,%edi - movl ES(%esp), %ecx /* get the faulting address */ - movl ORIG_EAX(%esp), %edx /* get the error code */ + movl ORIG_EAX(%esp), %edi movl %eax, ORIG_EAX(%esp) - movl %edi, ES(%esp) + movl %es, %ecx + movl %ecx, ES(%esp) movl $(__KERNEL_DS),%eax movl %eax, %ds movl %eax, %es - movl %esp,%eax /* pt_regs pointer */ + pushl %edi + movl %esp, %eax + pushl %eax call do_page_fault jmp ret_from_exception diff -r 410b49759f02 -r c247056431f8 extras/mini-os/xenbus/xenbus.c --- /dev/null Wed Mar 22 17:14:50 2006 +++ b/extras/mini-os/xenbus/xenbus.c Thu Mar 23 18:34:50 2006 @@ -0,0 +1,387 @@ +/* + **************************************************************************** + * (C) 2006 - Cambridge University + **************************************************************************** + * + * File: mm.c + * Author: Steven Smith (sos22@xxxxxxxxx) + * Changes: Grzegorz Milos (gm281@xxxxxxxxx) + * + * Date: Mar 2006, chages Aug 2005 + * + * Environment: Xen Minimal OS + * Description: Minimal implementation of xenbus + * + **************************************************************************** + **/ +#include <os.h> +#include <mm.h> +#include <traps.h> +#include <lib.h> +#include <xenbus.h> +#include <events.h> +#include <errno.h> +#include <sched.h> +#include <wait.h> +#include <xen/io/xs_wire.h> +#include <spinlock.h> +#include <xmalloc.h> + +#define BUG_ON(x) do { \ + if (x) {printk("BUG at %s:%d\n", __FILE__, __LINE__); BUG(); } \ +} while (0) + +#define min(x,y) ({ \ + typeof(x) tmpx = (x); \ + typeof(y) tmpy = (y); \ + tmpx < tmpy ? tmpx : tmpy; \ + }) + +#ifdef XENBUS_DEBUG +#define DEBUG(_f, _a...) \ + printk("MINI_OS(file=xenbus.c, line=%d) " _f , __LINE__, ## _a) +#else +#define DEBUG(_f, _a...) ((void)0) +#endif + + +static struct xenstore_domain_interface *xenstore_buf; +static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); +struct xenbus_req_info +{ + int in_use:1; + struct wait_queue_head waitq; + void *reply; +}; + +#define NR_REQS 32 +static struct xenbus_req_info req_info[NR_REQS]; + +static void memcpy_from_ring(const void *Ring, + void *Dest, + int off, + int len) +{ + int c1, c2; + const char *ring = Ring; + char *dest = Dest; + c1 = min(len, XENSTORE_RING_SIZE - off); + c2 = len - c1; + memcpy(dest, ring + off, c1); + memcpy(dest + c1, ring, c2); +} + +static void xenbus_thread_func(void *ign) +{ + struct xsd_sockmsg msg; + unsigned prod; + + for (;;) + { + wait_event(xb_waitq, prod != xenstore_buf->rsp_prod); + while (1) + { + prod = xenstore_buf->rsp_prod; + DEBUG("Rsp_cons %d, rsp_prod %d.\n", xenstore_buf->rsp_cons, + xenstore_buf->rsp_prod); + if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg)) + break; + rmb(); + memcpy_from_ring(xenstore_buf->rsp, + &msg, + MASK_XENSTORE_IDX(xenstore_buf->rsp_cons), + sizeof(msg)); + DEBUG("Msg len %d, %d avail, id %d.\n", + msg.len + sizeof(msg), + xenstore_buf->rsp_prod - xenstore_buf->rsp_cons, + msg.req_id); + if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < + sizeof(msg) + msg.len) + break; + + DEBUG("Message is good.\n"); + req_info[msg.req_id].reply = malloc(sizeof(msg) + msg.len); + memcpy_from_ring(xenstore_buf->rsp, + req_info[msg.req_id].reply, + MASK_XENSTORE_IDX(xenstore_buf->rsp_cons), + msg.len + sizeof(msg)); + wake_up(&req_info[msg.req_id].waitq); + xenstore_buf->rsp_cons += msg.len + sizeof(msg); + } + } +} + +static void xenbus_evtchn_handler(int port, struct pt_regs *regs) +{ + wake_up(&xb_waitq); +} + +static int nr_live_reqs; +static spinlock_t req_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_WAIT_QUEUE_HEAD(req_wq); + +/* Release a xenbus identifier */ +static void release_xenbus_id(int id) +{ + BUG_ON(!req_info[id].in_use); + spin_lock(&req_lock); + nr_live_reqs--; + if (nr_live_reqs == NR_REQS - 1) + wake_up(&req_wq); + spin_unlock(&req_lock); +} + +/* Allocate an identifier for a xenbus request. Blocks if none are + available. */ +static int allocate_xenbus_id(void) +{ + static int probe; + int o_probe; + + while (1) + { + spin_lock(&req_lock); + if (nr_live_reqs < NR_REQS) + break; + spin_unlock(&req_lock); + wait_event(req_wq, (nr_live_reqs < NR_REQS)); + } + + o_probe = probe; + for (;;) + { + if (!req_info[o_probe].in_use) + break; + o_probe = (o_probe + 1) % NR_REQS; + BUG_ON(o_probe == probe); + } + nr_live_reqs++; + req_info[o_probe].in_use = 1; + probe = o_probe + 1; + spin_unlock(&req_lock); + init_waitqueue_head(&req_info[o_probe].waitq); + return o_probe; +} + +/* Initialise xenbus. */ +void init_xenbus(void) +{ + int err; + DEBUG("init_xenbus called.\n"); + xenstore_buf = mfn_to_virt(start_info.store_mfn); + create_thread("xenstore", xenbus_thread_func, NULL); + DEBUG("buf at %p.\n", xenstore_buf); + err = bind_evtchn(start_info.store_evtchn, + xenbus_evtchn_handler); + DEBUG("xenbus on irq %d\n", err); +} + +struct write_req { + const void *data; + unsigned len; +}; + +/* Send data to xenbus. This can block. All of the requests are seen + by xenbus as if sent atomically. The header is added + automatically, using type %type, req_id %req_id, and trans_id + %trans_id. */ +static void xb_write(int type, int req_id, int trans_id, + const struct write_req *req, int nr_reqs) +{ + XENSTORE_RING_IDX prod; + int r; + int len = 0; + const struct write_req *cur_req; + int req_off; + int total_off; + int this_chunk; + struct xsd_sockmsg m = {.type = type, .req_id = req_id, + .tx_id = trans_id }; + struct write_req header_req = { &m, sizeof(m) }; + + for (r = 0; r < nr_reqs; r++) + len += req[r].len; + m.len = len; + len += sizeof(m); + + cur_req = &header_req; + + BUG_ON(len > XENSTORE_RING_SIZE); + /* Wait for the ring to drain to the point where we can send the + message. */ + prod = xenstore_buf->req_prod; + if (prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE) + { + /* Wait for there to be space on the ring */ + DEBUG("prod %d, len %d, cons %d, size %d; waiting.\n", + prod, len, xenstore_buf->req_cons, XENSTORE_RING_SIZE); + wait_event(xb_waitq, + xenstore_buf->req_prod + len - xenstore_buf->req_cons <= + XENSTORE_RING_SIZE); + DEBUG("Back from wait.\n"); + prod = xenstore_buf->req_prod; + } + + /* We're now guaranteed to be able to send the message without + overflowing the ring. Do so. */ + total_off = 0; + req_off = 0; + while (total_off < len) + { + this_chunk = min(cur_req->len - req_off, + XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod)); + memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod), + (char *)cur_req->data + req_off, this_chunk); + prod += this_chunk; + req_off += this_chunk; + total_off += this_chunk; + if (req_off == cur_req->len) + { + req_off = 0; + if (cur_req == &header_req) + cur_req = req; + else + cur_req++; + } + } + + DEBUG("Complete main loop of xb_write.\n"); + BUG_ON(req_off != 0); + BUG_ON(total_off != len); + BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE); + + /* Remote must see entire message before updating indexes */ + wmb(); + + xenstore_buf->req_prod += len; + + /* Send evtchn to notify remote */ + notify_remote_via_evtchn(start_info.store_evtchn); +} + +/* Send a mesasge to xenbus, in the same fashion as xb_write, and + block waiting for a reply. The reply is malloced and should be + freed by the caller. */ +static void *xenbus_msg_reply(int type, + int trans, + struct write_req *io, + int nr_reqs) +{ + int id; + DEFINE_WAIT(w); + void *rep; + struct xsd_sockmsg *repmsg; + + id = allocate_xenbus_id(); + add_waiter(w, req_info[id].waitq); + + xb_write(type, id, trans, io, nr_reqs); + + schedule(); + wake(current); + + rep = req_info[id].reply; + repmsg = rep; + BUG_ON(repmsg->req_id != id); + release_xenbus_id(id); + + return rep; +} + +/* Send a debug message to xenbus. Can block. */ +static void xenbus_debug_msg(const char *msg) +{ + int len = strlen(msg); + struct write_req req[] = { + { "print", sizeof("print") }, + { msg, len }, + { "", 1 }}; + void *reply; + struct xsd_sockmsg *repmsg; + + reply = xenbus_msg_reply(XS_DEBUG, 0, req, 3); + repmsg = reply; + DEBUG("Got a reply, type %d, id %d, len %d.\n", + repmsg->type, repmsg->req_id, repmsg->len); +} + +/* List the contents of a directory. Returns a malloc()ed array of + pointers to malloc()ed strings. The array is NULL terminated. May + block. */ +static char **xenbus_ls(const char *pre) +{ + void *reply; + struct xsd_sockmsg *repmsg; + struct write_req req[] = { { pre, strlen(pre)+1 } }; + int nr_elems, x, i; + char **res; + + repmsg = xenbus_msg_reply(XS_DIRECTORY, 0, req, 1); + reply = repmsg + 1; + for (x = nr_elems = 0; x < repmsg->len; x++) + nr_elems += (((char *)reply)[x] == 0); + res = malloc(sizeof(res[0]) * (nr_elems + 1)); + for (x = i = 0; i < nr_elems; i++) { + int l = strlen((char *)reply + x); + res[i] = malloc(l + 1); + memcpy(res[i], (char *)reply + x, l + 1); + x += l + 1; + } + res[i] = NULL; + free(repmsg); + return res; +} + +static char *xenbus_read(const char *path) +{ + struct write_req req[] = { {path, strlen(path) + 1}}; + struct xsd_sockmsg *rep; + char *res; + rep = xenbus_msg_reply(XS_READ, 0, req, 1); + res = malloc(rep->len + 1); + memcpy(res, rep + 1, rep->len); + res[rep->len] = 0; + free(rep); + return res; +} + +static void do_ls_test(const char *pre) +{ + char **dirs; + int x; + + DEBUG("ls %s...\n", pre); + dirs = xenbus_ls(pre); + for (x = 0; dirs[x]; x++) + { + DEBUG("ls %s[%d] -> %s\n", pre, x, dirs[x]); + free(dirs[x]); + } + free(dirs); +} + +static void do_read_test(const char *path) +{ + char *res; + DEBUG("Read %s...\n", path); + res = xenbus_read(path); + DEBUG("Read %s -> %s.\n", path, res); + free(res); +} + +/* Simple testing thing */ +void test_xenbus(void) +{ + DEBUG("Doing xenbus test.\n"); + xenbus_debug_msg("Testing xenbus...\n"); + + DEBUG("Doing ls test.\n"); + do_ls_test("device"); + do_ls_test("device/vif"); + do_ls_test("device/vif/0"); + + DEBUG("Doing read test.\n"); + do_read_test("device/vif/0/mac"); + do_read_test("device/vif/0/backend"); + printk("Xenbus initialised.\n"); +} _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |