[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] Mini-os Xenbus


  • To: xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxx>
  • From: Grzegorz Milos <gm281@xxxxxxxxx>
  • Date: Thu, 23 Mar 2006 18:38:31 +0000
  • Delivery-date: Thu, 23 Mar 2006 18:39:57 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xensource.com>

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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.