]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/mini-os.git/commitdiff
minios: support secondary guest consoles.
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 17 Jun 2009 06:22:18 +0000 (07:22 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 17 Jun 2009 06:22:18 +0000 (07:22 +0100)
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
console/console.c
console/xencons_ring.c
include/console.h
include/lib.h
kernel.c
lib/sys.c

index 3805943465550cbece16830e2a7c49c991446531..81cedcbd645fdd045942cb067371359286e092c7 100644 (file)
@@ -76,11 +76,11 @@ void xencons_tx(void)
 #endif
 
 
-void console_print(char *data, int length)
+void console_print(struct consfront_dev *dev, char *data, int length)
 {
     char *curr_char, saved_char;
     int part_len;
-    int (*ring_send_fn)(const char *data, unsigned length);
+    int (*ring_send_fn)(struct consfront_dev *dev, const char *data, unsigned length);
 
     if(!console_initialised)
         ring_send_fn = xencons_ring_send_no_notify;
@@ -94,17 +94,17 @@ void console_print(char *data, int length)
             saved_char = *(curr_char+1);
             *(curr_char+1) = '\r';
             part_len = curr_char - data + 2;
-            ring_send_fn(data, part_len);
+            ring_send_fn(dev, data, part_len);
             *(curr_char+1) = saved_char;
             data = curr_char+1;
             length -= part_len - 1;
         }
     }
     
-    ring_send_fn(data, length);
+    ring_send_fn(dev, data, length);
     
     if(data[length-1] == '\n')
-        ring_send_fn("\r", 1);
+        ring_send_fn(dev, "\r", 1);
 }
 
 void print(int direct, const char *fmt, va_list args)
@@ -123,7 +123,7 @@ void print(int direct, const char *fmt, va_list args)
 #endif    
             (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(buf), buf);
         
-        console_print(buf, strlen(buf));
+        console_print(NULL, buf, strlen(buf));
     }
 }
 
@@ -151,7 +151,7 @@ void init_console(void)
     printk("done.\n");
 }
 
-void fini_console(void)
+void fini_console(struct consfront_dev *dev)
 {
-    /* Destruct the console and get the parameters of the restarted one */
+    if (dev) free_consfront(dev);
 }
index 251a4f95f19fe5b26d5703238cae76c79ef596ce..a7a9827c00752e1209c8ac846aac41d213b281ba 100644 (file)
@@ -7,25 +7,38 @@
 #include <lib.h>
 #include <xenbus.h>
 #include <xen/io/console.h>
+#include <xen/io/protocols.h>
+#include <xen/io/ring.h>
+#include <xmalloc.h>
+#include <gnttab.h>
 
 DECLARE_WAIT_QUEUE_HEAD(console_queue);
 
-static inline struct xencons_interface *xencons_interface(void)
-{
-    return mfn_to_virt(start_info.console.domU.mfn);
-}
-
-static inline void notify_daemon(void)
+static inline void notify_daemon(struct consfront_dev *dev)
 {
     /* Use evtchn: this is called early, before irq is set up. */
-    notify_remote_via_evtchn(start_info.console.domU.evtchn);
+    if (!dev)
+        notify_remote_via_evtchn(start_info.console.domU.evtchn);
+    else
+        notify_remote_via_evtchn(dev->evtchn);
 }
 
-int xencons_ring_send_no_notify(const char *data, unsigned len)
+static inline struct xencons_interface *xencons_interface(void)
+{
+    return mfn_to_virt(start_info.console.domU.mfn);
+} 
+int xencons_ring_send_no_notify(struct consfront_dev *dev, const char *data, unsigned len)
 {      
     int sent = 0;
-       struct xencons_interface *intf = xencons_interface();
+       struct xencons_interface *intf;
        XENCONS_RING_IDX cons, prod;
+
+       if (!dev)
+            intf = xencons_interface();
+        else
+            intf = dev->ring;
+
        cons = intf->out_cons;
        prod = intf->out_prod;
        mb();
@@ -40,20 +53,27 @@ int xencons_ring_send_no_notify(const char *data, unsigned len)
     return sent;
 }
 
-int xencons_ring_send(const char *data, unsigned len)
+int xencons_ring_send(struct consfront_dev *dev, const char *data, unsigned len)
 {
     int sent;
-    sent = xencons_ring_send_no_notify(data, len);
-       notify_daemon();
 
-       return sent;
+    sent = xencons_ring_send_no_notify(dev, data, len);
+    notify_daemon(dev);
+
+    return sent;
 }      
 
 
 
-static void handle_input(evtchn_port_t port, struct pt_regs *regs, void *ign)
+static void handle_input(evtchn_port_t port, struct pt_regs *regs, void *data)
 {
 #ifdef HAVE_LIBC
+       struct consfront_dev *dev = (struct consfront_dev *) data;
+        int fd = dev ? dev->fd : -1;
+
+        if (fd != -1)
+            files[fd].read = 1;
+
         wake_up(&console_queue);
 #else
        struct xencons_interface *intf = xencons_interface();
@@ -72,18 +92,23 @@ static void handle_input(evtchn_port_t port, struct pt_regs *regs, void *ign)
        mb();
        intf->in_cons = cons;
 
-       notify_daemon();
+       notify_daemon(dev);
 
        xencons_tx();
 #endif
 }
 
 #ifdef HAVE_LIBC
-int xencons_ring_avail(void)
+int xencons_ring_avail(struct consfront_dev *dev)
 {
-       struct xencons_interface *intf = xencons_interface();
+       struct xencons_interface *intf;
        XENCONS_RING_IDX cons, prod;
 
+        if (!dev)
+            intf = xencons_interface();
+        else
+            intf = dev->ring;
+
        cons = intf->in_cons;
        prod = intf->in_prod;
        mb();
@@ -92,12 +117,17 @@ int xencons_ring_avail(void)
         return prod - cons;
 }
 
-int xencons_ring_recv(char *data, unsigned len)
+int xencons_ring_recv(struct consfront_dev *dev, char *data, unsigned len)
 {
-       struct xencons_interface *intf = xencons_interface();
+       struct xencons_interface *intf;
        XENCONS_RING_IDX cons, prod;
         unsigned filled = 0;
 
+        if (!dev)
+            intf = xencons_interface();
+        else
+            intf = dev->ring;
+
        cons = intf->in_cons;
        prod = intf->in_prod;
        mb();
@@ -111,31 +141,190 @@ int xencons_ring_recv(char *data, unsigned len)
        mb();
         intf->in_cons = cons + filled;
 
-       notify_daemon();
+       notify_daemon(dev);
 
         return filled;
 }
 #endif
 
-int xencons_ring_init(void)
+struct consfront_dev *xencons_ring_init(void)
 {
        int err;
+       struct consfront_dev *dev;
 
        if (!start_info.console.domU.evtchn)
                return 0;
 
-       err = bind_evtchn(start_info.console.domU.evtchn, handle_input,
-                         NULL);
+       dev = malloc(sizeof(struct consfront_dev));
+       memset(dev, 0, sizeof(struct consfront_dev));
+       dev->nodename = "device/console";
+       dev->dom = 0;
+       dev->backend = 0;
+       dev->ring_ref = 0;
+
+#ifdef HAVE_LIBC
+       dev->fd = -1;
+#endif
+       dev->evtchn = start_info.console.domU.evtchn;
+       dev->ring = (struct xencons_interface *) mfn_to_virt(start_info.console.domU.mfn);
+
+       err = bind_evtchn(dev->evtchn, handle_input, dev);
        if (err <= 0) {
                printk("XEN console request chn bind failed %i\n", err);
-               return err;
+                free(dev);
+               return NULL;
        }
-        unmask_evtchn(start_info.console.domU.evtchn);
+        unmask_evtchn(dev->evtchn);
 
        /* In case we have in-flight data after save/restore... */
-       notify_daemon();
+       notify_daemon(dev);
+
+       return dev;
+}
+
+void free_consfront(struct consfront_dev *dev)
+{
+    mask_evtchn(dev->evtchn);
+
+    free(dev->backend);
+
+    gnttab_end_access(dev->ring_ref);
+    free_page(dev->ring);
+
+    unbind_evtchn(dev->evtchn);
+
+    free(dev->nodename);
+    free(dev);
+}
+
+struct consfront_dev *init_consfront(char *_nodename)
+{
+    xenbus_transaction_t xbt;
+    char* err;
+    char* message=NULL;
+    int retry=0;
+    char* msg;
+    char nodename[256];
+    char path[256];
+    static int consfrontends = 1;
+    struct consfront_dev *dev;
+    int res;
+
+    if (!_nodename)
+        snprintf(nodename, sizeof(nodename), "device/console/%d", consfrontends);
+    else
+        strncpy(nodename, _nodename, sizeof(nodename));
+
+    printk("******************* CONSFRONT for %s **********\n\n\n", nodename);
+
+    consfrontends++;
+    dev = malloc(sizeof(*dev));
+    memset(dev, 0, sizeof(*dev));
+    dev->nodename = strdup(nodename);
+#ifdef HAVE_LIBC
+    dev->fd = -1;
+#endif
 
-       return 0;
+    snprintf(path, sizeof(path), "%s/backend-id", nodename);
+    if ((res = xenbus_read_integer(path)) < 0) 
+        return NULL;
+    else
+        dev->dom = res;
+    evtchn_alloc_unbound(dev->dom, handle_input, dev, &dev->evtchn);
+
+    dev->ring = (struct xencons_interface *) alloc_page();
+    memset(dev->ring, 0, PAGE_SIZE);
+    dev->ring_ref = gnttab_grant_access(dev->dom, virt_to_mfn(dev->ring), 0);
+
+    dev->events = NULL;
+
+again:
+    err = xenbus_transaction_start(&xbt);
+    if (err) {
+        printk("starting transaction\n");
+    }
+
+    err = xenbus_printf(xbt, nodename, "ring-ref","%u",
+                dev->ring_ref);
+    if (err) {
+        message = "writing ring-ref";
+        goto abort_transaction;
+    }
+    err = xenbus_printf(xbt, nodename,
+                "port", "%u", dev->evtchn);
+    if (err) {
+        message = "writing event-channel";
+        goto abort_transaction;
+    }
+    err = xenbus_printf(xbt, nodename,
+                "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE);
+    if (err) {
+        message = "writing protocol";
+        goto abort_transaction;
+    }
+
+    err = xenbus_printf(xbt, nodename, "type", "%s", "ioemu");
+    if (err) {
+        message = "writing type";
+        goto abort_transaction;
+    }
+
+    snprintf(path, sizeof(path), "%s/state", nodename);
+    err = xenbus_switch_state(xbt, path, XenbusStateConnected);
+    if (err) {
+        message = "switching state";
+        goto abort_transaction;
+    }
+
+
+    err = xenbus_transaction_end(xbt, 0, &retry);
+    if (retry) {
+            goto again;
+        printk("completing transaction\n");
+    }
+
+    goto done;
+
+abort_transaction:
+    xenbus_transaction_end(xbt, 1, &retry);
+    goto error;
+
+done:
+
+    snprintf(path, sizeof(path), "%s/backend", nodename);
+    msg = xenbus_read(XBT_NIL, path, &dev->backend);
+    if (msg) {
+        printk("Error %s when reading the backend path %s\n", msg, path);
+        goto error;
+    }
+
+    printk("backend at %s\n", dev->backend);
+
+    {
+        XenbusState state;
+        char path[strlen(dev->backend) + 1 + 19 + 1];
+        snprintf(path, sizeof(path), "%s/state", dev->backend);
+        
+       xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
+        msg = NULL;
+        state = xenbus_read_integer(path);
+        while (msg == NULL && state < XenbusStateConnected)
+            msg = xenbus_wait_for_state_change(path, &state, &dev->events);
+        if (msg != NULL || state != XenbusStateConnected) {
+            printk("backend not available, state=%d\n", state);
+            xenbus_unwatch_path(XBT_NIL, path);
+            goto error;
+        }
+    }
+    unmask_evtchn(dev->evtchn);
+
+    printk("**************************\n");
+
+    return dev;
+
+error:
+    free_consfront(dev);
+    return NULL;
 }
 
 void xencons_resume(void)
index e9e516116635e587bc62279c514fa07031ac7a3e..3755b6655d98626eed836f9bf514265373bc4b99 100644 (file)
 #ifndef _LIB_CONSOLE_H_
 #define _LIB_CONSOLE_H_
 
-#include<mini-os/os.h>
-#include<mini-os/traps.h>
-#include<stdarg.h>
+#include <mini-os/os.h>
+#include <mini-os/traps.h>
+#include <mini-os/types.h>
+#include <xen/grant_table.h>
+#include <xenbus.h>
+#include <xen/io/console.h>
+#include <stdarg.h>
+
+struct consfront_dev {
+    domid_t dom;
+
+    struct xencons_interface *ring;
+    grant_ref_t ring_ref;
+    evtchn_port_t evtchn;
+
+    char *nodename;
+    char *backend;
+
+    xenbus_event_queue events;
+
+#ifdef HAVE_LIBC
+    int fd;
+#endif
+};
+
+
 
 void print(int direct, const char *fmt, va_list args);
 void printk(const char *fmt, ...);
@@ -50,16 +73,17 @@ void xencons_rx(char *buf, unsigned len, struct pt_regs *regs);
 void xencons_tx(void);
 
 void init_console(void);
-void console_print(char *data, int length);
-void fini_console(void);
+void console_print(struct consfront_dev *dev, char *data, int length);
+void fini_console(struct consfront_dev *dev);
 
 /* Low level functions defined in xencons_ring.c */
 extern struct wait_queue_head console_queue;
-int xencons_ring_init(void);
-int xencons_ring_send(const char *data, unsigned len);
-int xencons_ring_send_no_notify(const char *data, unsigned len);
-int xencons_ring_avail(void);
-int xencons_ring_recv(char *data, unsigned len);
-
+struct consfront_dev *xencons_ring_init(void);
+struct consfront_dev *init_consfront(char *_nodename);
+int xencons_ring_send(struct consfront_dev *dev, const char *data, unsigned len);
+int xencons_ring_send_no_notify(struct consfront_dev *dev, const char *data, unsigned len);
+int xencons_ring_avail(struct consfront_dev *dev);
+int xencons_ring_recv(struct consfront_dev *dev, char *data, unsigned len);
+void free_consfront(struct consfront_dev *dev);
 
 #endif /* _LIB_CONSOLE_H_ */
index 8822dd14a7121a77134a764479287a7213b96563..4aa34d4e7c48d81dfd83bab3039d70c05c62ea58 100644 (file)
@@ -101,6 +101,7 @@ char * strcat(char * dest, const char * src);
 char  *strdup(const char *s);
 #endif
 #include <mini-os/console.h>
+int openpty(void);
 
 #define RAND_MIX 2654435769U
 
@@ -183,6 +184,9 @@ extern struct file {
        struct {
            struct fbfront_dev *dev;
        } fb;
+       struct {
+           struct consfront_dev *dev;
+       } cons;
         struct {
             /* To each xenbus FD is associated a queue of watch events for this
              * FD.  */
index bdd866462b011f671b0e7be8613829b831e0b1ed..f2bd01f8ebf0a7835c4658ac8a2d3ae1b65e47f1 100644 (file)
--- a/kernel.c
+++ b/kernel.c
@@ -562,7 +562,7 @@ void stop_kernel(void)
     fini_gnttab();
 
     /* Reset the console driver. */
-    fini_console();
+    fini_console(NULL);
     /* TODO: record new ring mfn & event in start_info */
 
     /* Reset XenBus */
index d0bc76a6595c50b6ca43b49e7db8914cb654d4da..045481e73f97e12160bd41925724e345ecf0029d 100644 (file)
--- a/lib/sys.c
+++ b/lib/sys.c
@@ -167,6 +167,18 @@ int mkdir(const char *pathname, mode_t mode)
     return 0;
 }
 
+int openpty(void)
+{
+    struct consfront_dev *dev;
+
+    dev = init_consfront(NULL);
+    dev->fd = alloc_fd(FTYPE_CONSOLE);
+    files[dev->fd].cons.dev = dev;
+
+    printk("fd(%d) = openpty\n", dev->fd);
+    return(dev->fd);
+}
+
 int open(const char *pathname, int flags, ...)
 {
     int fs_fd, fd;
@@ -219,7 +231,7 @@ int read(int fd, void *buf, size_t nbytes)
             DEFINE_WAIT(w);
             while(1) {
                 add_waiter(w, console_queue);
-                ret = xencons_ring_recv(buf, nbytes);
+                ret = xencons_ring_recv(files[fd].cons.dev, buf, nbytes);
                 if (ret)
                     break;
                 schedule();
@@ -286,7 +298,7 @@ int write(int fd, const void *buf, size_t nbytes)
 {
     switch (files[fd].type) {
        case FTYPE_CONSOLE:
-           console_print((char *)buf, nbytes);
+           console_print(files[fd].cons.dev, (char *)buf, nbytes);
            return nbytes;
        case FTYPE_FILE: {
            ssize_t ret;
@@ -416,6 +428,10 @@ int close(int fd)
             shutdown_fbfront(files[fd].fb.dev);
             files[fd].type = FTYPE_NONE;
             return 0;
+        case FTYPE_CONSOLE:
+            fini_console(files[fd].cons.dev);
+            files[fd].type = FTYPE_NONE;
+            return 0;
        case FTYPE_NONE:
            break;
     }
@@ -735,7 +751,7 @@ static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exce
            break;
        case FTYPE_CONSOLE:
            if (FD_ISSET(i, readfds)) {
-                if (xencons_ring_avail())
+                if (xencons_ring_avail(files[i].cons.dev))
                    n++;
                else
                    FD_CLR(i, readfds);