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
|