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

[Xen-changelog] New console transport and update xenconsoled.



# HG changeset patch
# User cl349@xxxxxxxxxxxxxxxxxxxx
# Node ID 8fe8a99b1c2a6ea88624546ab625eaa0758e3a17
# Parent  e69cbfee4011da1648718f1f5cbe8dabb956e72a
New console transport and update xenconsoled.
Add a new console interface using a seperate shared page and event channel
instead of passing the console input/output over control messages.
Update xenconsoled to use the new console interface.
Make xenconsoled garbage collect dying domains by subscribing to
the domain exception virq.
Signed-off-by: Robert Read <robert@xxxxxxxxxxxxx>
Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxx>

diff -r e69cbfee4011 -r 8fe8a99b1c2a 
linux-2.6-xen-sparse/drivers/xen/console/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/console/Makefile Tue Aug 30 08:47:51 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/console/Makefile Tue Aug 30 16:14:53 2005
@@ -1,2 +1,2 @@
 
-obj-y  := console.o
+obj-y  := console.o xencons_ring.o
diff -r e69cbfee4011 -r 8fe8a99b1c2a 
linux-2.6-xen-sparse/drivers/xen/console/console.c
--- a/linux-2.6-xen-sparse/drivers/xen/console/console.c        Tue Aug 30 
08:47:51 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c        Tue Aug 30 
16:14:53 2005
@@ -51,8 +51,8 @@
 #include <asm-xen/xen-public/event_channel.h>
 #include <asm-xen/hypervisor.h>
 #include <asm-xen/evtchn.h>
-#include <asm-xen/ctrl_if.h>
-
+
+#include "xencons_ring.h"
 /*
  * Modes:
  *  'xencons=off'  [XC_OFF]:     Console is disabled.
@@ -118,13 +118,6 @@
 /* Common transmit-kick routine. */
 static void __xencons_tx_flush(void);
 
-/* This task is used to defer sending console data until there is space. */
-static void xencons_tx_flush_task_routine(void *data);
-
-static DECLARE_TQUEUE(xencons_tx_flush_task, 
-                      xencons_tx_flush_task_routine,
-                      NULL);
-
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 static struct tty_driver *xencons_driver;
 #else
@@ -264,39 +257,22 @@
 /*** Forcibly flush console data before dying. ***/
 void xencons_force_flush(void)
 {
-    ctrl_msg_t msg;
     int        sz;
 
     /* Emergency console is synchronous, so there's nothing to flush. */
     if ( xen_start_info.flags & SIF_INITDOMAIN )
         return;
 
-    /*
-     * We use dangerous control-interface functions that require a quiescent
-     * system and no interrupts. Try to ensure this with a global cli().
-     */
-    local_irq_disable(); /* XXXsmp */
 
     /* Spin until console data is flushed through to the domain controller. */
-    while ( (wc != wp) && !ctrl_if_transmitter_empty() )
-    {
-        /* Interrupts are disabled -- we must manually reap responses. */
-        ctrl_if_discard_responses();
-
+    while ( (wc != wp) )
+    {
+       int sent = 0;
         if ( (sz = wp - wc) == 0 )
             continue;
-        if ( sz > sizeof(msg.msg) )
-            sz = sizeof(msg.msg);
-        if ( sz > (wbuf_size - WBUF_MASK(wc)) )
-            sz = wbuf_size - WBUF_MASK(wc);
-
-        msg.type    = CMSG_CONSOLE;
-        msg.subtype = CMSG_CONSOLE_DATA;
-        msg.length  = sz;
-        memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
-            
-        if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
-            wc += sz;
+       sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
+       if (sent > 0)
+           wc += sent;
     }
 }
 
@@ -320,7 +296,7 @@
 static char x_char;
 
 /* Non-privileged receive callback. */
-static void xencons_rx(ctrl_msg_t *msg, unsigned long id)
+static void xencons_rx(char *buf, unsigned len)
 {
     int           i;
     unsigned long flags;
@@ -328,21 +304,18 @@
     spin_lock_irqsave(&xencons_lock, flags);
     if ( xencons_tty != NULL )
     {
-        for ( i = 0; i < msg->length; i++ )
-            tty_insert_flip_char(xencons_tty, msg->msg[i], 0);
+        for ( i = 0; i < len; i++ )
+            tty_insert_flip_char(xencons_tty, buf[i], 0);
         tty_flip_buffer_push(xencons_tty);
     }
     spin_unlock_irqrestore(&xencons_lock, flags);
 
-    msg->length = 0;
-    ctrl_if_send_response(msg);
 }
 
 /* Privileged and non-privileged transmit worker. */
 static void __xencons_tx_flush(void)
 {
     int        sz, work_done = 0;
-    ctrl_msg_t msg;
 
     if ( xen_start_info.flags & SIF_INITDOMAIN )
     {
@@ -367,38 +340,23 @@
     {
         while ( x_char )
         {
-            msg.type    = CMSG_CONSOLE;
-            msg.subtype = CMSG_CONSOLE_DATA;
-            msg.length  = 1;
-            msg.msg[0]  = x_char;
-
-            if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
-                x_char = 0;
-            else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
-                break;
-
-            work_done = 1;
+           if (xencons_ring_send(&x_char, 1) == 1) {
+               x_char = 0;
+               work_done = 1;
+           }
         }
 
         while ( wc != wp )
         {
+           int sent;
             sz = wp - wc;
-            if ( sz > sizeof(msg.msg) )
-                sz = sizeof(msg.msg);
-            if ( sz > (wbuf_size - WBUF_MASK(wc)) )
-                sz = wbuf_size - WBUF_MASK(wc);
-
-            msg.type    = CMSG_CONSOLE;
-            msg.subtype = CMSG_CONSOLE_DATA;
-            msg.length  = sz;
-            memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
-            
-            if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
-                wc += sz;
-            else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
-                break;
-
-            work_done = 1;
+           if ( sz > (wbuf_size - WBUF_MASK(wc)) )
+               sz = wbuf_size - WBUF_MASK(wc);
+           sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
+           if ( sent > 0 ) {
+               wc += sent;
+               work_done = 1;
+           }
         }
     }
 
@@ -409,15 +367,6 @@
              (xencons_tty->ldisc.write_wakeup != NULL) )
             (xencons_tty->ldisc.write_wakeup)(xencons_tty);
     }
-}
-
-/* Non-privileged transmit kicker. */
-static void xencons_tx_flush_task_routine(void *data)
-{
-    unsigned long flags;
-    spin_lock_irqsave(&xencons_lock, flags);
-    __xencons_tx_flush();
-    spin_unlock_irqrestore(&xencons_lock, flags);
 }
 
 /* Privileged receive callback and transmit kicker. */
@@ -726,6 +675,8 @@
     if ( xc_mode == XC_OFF )
         return 0;
 
+    xencons_ring_init();
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ? 
                                       1 : MAX_NR_CONSOLES);
@@ -802,7 +753,8 @@
     }
     else
     {
-        (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0);
+       
+       xencons_ring_register_receiver(xencons_rx);
     }
 
     printk("Xen virtual console successfully installed as %s%d\n",
diff -r e69cbfee4011 -r 8fe8a99b1c2a tools/console/daemon/io.c
--- a/tools/console/daemon/io.c Tue Aug 30 08:47:51 2005
+++ b/tools/console/daemon/io.c Tue Aug 30 16:14:53 2005
@@ -36,6 +36,9 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <termios.h>
+#include <stdarg.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
 
 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
@@ -48,41 +51,6 @@
        size_t max_capacity;
 };
 
-static void buffer_append(struct buffer *buffer, const void *data, size_t size)
-{
-       if ((buffer->capacity - buffer->size) < size) {
-               buffer->capacity += (size + 1024);
-               buffer->data = realloc(buffer->data, buffer->capacity);
-               if (buffer->data == NULL) {
-                       dolog(LOG_ERR, "Memory allocation failed");
-                       exit(ENOMEM);
-               }
-       }
-
-       memcpy(buffer->data + buffer->size, data, size);
-       buffer->size += size;
-
-       if (buffer->max_capacity &&
-           buffer->size > buffer->max_capacity) {
-               memmove(buffer->data + (buffer->size - buffer->max_capacity),
-                       buffer->data, buffer->max_capacity);
-               buffer->data = realloc(buffer->data, buffer->max_capacity);
-               buffer->capacity = buffer->max_capacity;
-       }
-}
-
-static bool buffer_empty(struct buffer *buffer)
-{
-       return buffer->size == 0;
-}
-
-static void buffer_advance(struct buffer *buffer, size_t size)
-{
-       size = MIN(size, buffer->size);
-       memmove(buffer->data, buffer + size, buffer->size - size);
-       buffer->size -= size;
-}
-
 struct domain
 {
        int domid;
@@ -90,9 +58,74 @@
        bool is_dead;
        struct buffer buffer;
        struct domain *next;
+       unsigned long mfn;
+       int local_port;
+       int remote_port;
+       char *page;
+       int evtchn_fd;
 };
 
 static struct domain *dom_head;
+
+struct ring_head
+{
+       u32 cons;
+       u32 prod;
+       char buf[0];
+} __attribute__((packed));
+
+#define PAGE_SIZE (getpagesize())
+#define XENCONS_RING_SIZE (PAGE_SIZE/2 - sizeof (struct ring_head))
+#define XENCONS_IDX(cnt) ((cnt) % XENCONS_RING_SIZE)
+#define XENCONS_FULL(ring) (((ring)->prod - (ring)->cons) == XENCONS_RING_SIZE)
+#define XENCONS_SPACE(ring) (XENCONS_RING_SIZE - ((ring)->prod - (ring)->cons))
+
+static void buffer_append(struct domain *dom)
+{
+       struct buffer *buffer = &dom->buffer;
+       struct ring_head *ring = (struct ring_head *)dom->page;
+       size_t size;
+
+       while ((size = ring->prod - ring->cons) != 0) {
+               if ((buffer->capacity - buffer->size) < size) {
+                       buffer->capacity += (size + 1024);
+                       buffer->data = realloc(buffer->data, buffer->capacity);
+                       if (buffer->data == NULL) {
+                               dolog(LOG_ERR, "Memory allocation failed");
+                               exit(ENOMEM);
+                       }
+               }
+
+               while (ring->cons < ring->prod) {
+                       buffer->data[buffer->size] =
+                               ring->buf[XENCONS_IDX(ring->cons)];
+                       buffer->size++;
+                       ring->cons++;
+               }
+
+               if (buffer->max_capacity &&
+                   buffer->size > buffer->max_capacity) {
+                       memmove(buffer->data + (buffer->size -
+                                               buffer->max_capacity),
+                               buffer->data, buffer->max_capacity);
+                       buffer->data = realloc(buffer->data,
+                                              buffer->max_capacity);
+                       buffer->capacity = buffer->max_capacity;
+               }
+       }
+}
+
+static bool buffer_empty(struct buffer *buffer)
+{
+       return buffer->size == 0;
+}
+
+static void buffer_advance(struct buffer *buffer, size_t size)
+{
+       size = MIN(size, buffer->size);
+       memmove(buffer->data, buffer + size, buffer->size - size);
+       buffer->size -= size;
+}
 
 static bool domain_is_valid(int domid)
 {
@@ -107,7 +140,7 @@
 
 static int domain_create_tty(struct domain *dom)
 {
-       char path[1024];
+       char *path;
        int master;
 
        if ((master = getpt()) == -1 ||
@@ -126,22 +159,106 @@
                        tcsetattr(master, TCSAFLUSH, &term);
                }
 
-               xs_mkdir(xs, "/console");
-               snprintf(path, sizeof(path), "/console/%d", dom->domid);
-               xs_mkdir(xs, path);
-               strcat(path, "/tty");
-
+               asprintf(&path, "/console/%d/tty", dom->domid);
                xs_write(xs, path, slave, strlen(slave), O_CREAT);
-
-               snprintf(path, sizeof(path), "/console/%d/limit", dom->domid);
+               free(path);
+
+               asprintf(&path, "/console/%d/limit", dom->domid);
                data = xs_read(xs, path, &len);
                if (data) {
                        dom->buffer.max_capacity = strtoul(data, 0, 0);
                        free(data);
                }
+               free(path);
        }
 
        return master;
+}
+
+/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
+int xs_gather(struct xs_handle *xs, const char *dir, ...)
+{
+       va_list ap;
+       const char *name;
+       char *path;
+       int ret = 0;
+
+       va_start(ap, dir);
+       while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+               const char *fmt = va_arg(ap, char *);
+               void *result = va_arg(ap, void *);
+               char *p;
+
+               asprintf(&path, "%s/%s", dir, name);
+               p = xs_read(xs, path, NULL);
+               free(path);
+               if (p == NULL) {
+                       ret = ENOENT;
+                       break;
+               }
+               if (fmt) {
+                       if (sscanf(p, fmt, result) == 0)
+                               ret = EINVAL;
+                       free(p);
+               } else
+                       *(char **)result = p;
+       }
+       va_end(ap);
+       return ret;
+}
+
+#define EVENTCHN_BIND          _IO('E', 2)
+#define EVENTCHN_UNBIND        _IO('E', 3)
+
+static int domain_create_ring(struct domain *dom)
+{
+       char *dompath, *path;
+       int err;
+
+       dom->page = NULL;
+       dom->evtchn_fd = -1;
+
+       asprintf(&path, "/console/%d/domain", dom->domid);
+       dompath = xs_read(xs, path, NULL);
+       free(path);
+       if (!dompath)
+               return ENOENT;
+
+       err = xs_gather(xs, dompath,
+                       "console_mfn", "%li", &dom->mfn,
+                       "console_channel/port1", "%i", &dom->local_port,
+                       "console_channel/port2", "%i", &dom->remote_port,
+                       NULL);
+       if (err)
+               goto out;
+
+       dom->page = xc_map_foreign_range(xc, dom->domid, getpagesize(),
+                                        PROT_READ|PROT_WRITE, dom->mfn);
+       if (dom->page == NULL) {
+               err = EINVAL;
+               goto out;
+       }
+
+       /* Opening evtchn independently for each console is a bit
+        * wastefule, but that's how the code is structured... */
+       err = open("/dev/xen/evtchn", O_RDWR);
+       if (err == -1) {
+               err = errno;
+               goto out;
+       }
+       dom->evtchn_fd = err;
+
+       if (ioctl(dom->evtchn_fd, EVENTCHN_BIND, dom->local_port) == -1) {
+               err = errno;
+               munmap(dom->page, getpagesize());
+               close(dom->evtchn_fd);
+               dom->evtchn_fd = -1;
+               goto out;
+       }
+
+ out:
+       free(dompath);
+       return err;
 }
 
 static struct domain *create_domain(int domid)
@@ -162,7 +279,9 @@
        dom->buffer.size = 0;
        dom->buffer.capacity = 0;
        dom->buffer.max_capacity = 0;
-       dom->next = 0;
+       dom->next = NULL;
+
+       domain_create_ring(dom);
 
        dolog(LOG_DEBUG, "New domain %d", domid);
 
@@ -200,9 +319,14 @@
 
                if (dom->domid == d->domid) {
                        *pp = d->next;
-                       if (d->buffer.data) {
+                       if (d->buffer.data)
                                free(d->buffer.data);
-                       }
+                       if (d->page)
+                               munmap(d->page, getpagesize());
+                       if (d->evtchn_fd != -1)
+                               close(d->evtchn_fd);
+                       if (d->tty_fd != -1)
+                               close(d->tty_fd);
                        free(d);
                        break;
                }
@@ -211,28 +335,28 @@
 
 static void remove_dead_domains(struct domain *dom)
 {
-       if (dom == NULL) return;
-       remove_dead_domains(dom->next);
-
-       if (dom->is_dead) {
-               remove_domain(dom);
+       struct domain *n;
+
+       while (dom != NULL) {
+               n = dom->next;
+               if (dom->is_dead)
+                       remove_domain(dom);
+               dom = n;
        }
 }
 
 static void handle_tty_read(struct domain *dom)
 {
        ssize_t len;
-       xcs_msg_t msg;
-
-       msg.type = XCS_REQUEST;
-       msg.u.control.remote_dom = dom->domid;
-       msg.u.control.msg.type = CMSG_CONSOLE;
-       msg.u.control.msg.subtype = CMSG_CONSOLE_DATA;
-       msg.u.control.msg.id = 1;
-
-       len = read(dom->tty_fd, msg.u.control.msg.msg, 60);
+       char msg[80];
+       struct ring_head *inring =
+               (struct ring_head *)(dom->page + PAGE_SIZE/2);
+       int i;
+
+       len = read(dom->tty_fd, msg, MAX(XENCONS_SPACE(inring), sizeof(msg)));
        if (len < 1) {
                close(dom->tty_fd);
+               dom->tty_fd = -1;
 
                if (domain_is_valid(dom->domid)) {
                        dom->tty_fd = domain_create_tty(dom);
@@ -240,14 +364,14 @@
                        dom->is_dead = true;
                }
        } else if (domain_is_valid(dom->domid)) {
-               msg.u.control.msg.length = len;
-
-               if (!write_sync(xcs_data_fd, &msg, sizeof(msg))) {
-                       dolog(LOG_ERR, "Write to xcs failed: %m");
-                       exit(1);
-               }
+               for (i = 0; i < len; i++) {
+                       inring->buf[XENCONS_IDX(inring->prod)] = msg[i];
+                       inring->prod++;
+               }
+               xc_evtchn_send(xc, dom->local_port);
        } else {
                close(dom->tty_fd);
+               dom->tty_fd = -1;
                dom->is_dead = true;
        }
 }
@@ -259,6 +383,7 @@
        len = write(dom->tty_fd, dom->buffer.data, dom->buffer.size);
        if (len < 1) {
                close(dom->tty_fd);
+               dom->tty_fd = -1;
 
                if (domain_is_valid(dom->domid)) {
                        dom->tty_fd = domain_create_tty(dom);
@@ -270,6 +395,18 @@
        }
 }
 
+static void handle_ring_read(struct domain *dom)
+{
+       u16 v;
+
+       if (!read_sync(dom->evtchn_fd, &v, sizeof(v)))
+               return;
+
+       buffer_append(dom);
+
+       (void)write_sync(dom->evtchn_fd, &v, sizeof(v));
+}
+
 static void handle_xcs_msg(int fd)
 {
        xcs_msg_t msg;
@@ -277,13 +414,6 @@
        if (!read_sync(fd, &msg, sizeof(msg))) {
                dolog(LOG_ERR, "read from xcs failed! %m");
                exit(1);
-       } else if (msg.type == XCS_REQUEST) {
-               struct domain *dom;
-
-               dom = lookup_domain(msg.u.control.remote_dom);
-               buffer_append(&dom->buffer,
-                             msg.u.control.msg.msg,
-                             msg.u.control.msg.length);
        }
 }
 
@@ -291,9 +421,12 @@
 {
        int domid = 0;
        xc_dominfo_t dominfo;
+       struct domain *dom;
 
        while (xc_domain_getinfo(xc, domid, 1, &dominfo) == 1) {
-               lookup_domain(dominfo.domid);
+               dom = lookup_domain(dominfo.domid);
+               if (dominfo.dying || dominfo.crashed || dominfo.shutdown)
+                       dom->is_dead = true;
                domid = dominfo.domid + 1;
        }
 }
@@ -302,12 +435,11 @@
 {
        fd_set readfds, writefds;
        int ret;
-       int max_fd = -1;
-       int num_of_writes = 0;
 
        do {
                struct domain *d;
                struct timeval tv = { 1, 0 };
+               int max_fd = -1;
 
                FD_ZERO(&readfds);
                FD_ZERO(&writefds);
@@ -319,42 +451,36 @@
                        if (d->tty_fd != -1) {
                                FD_SET(d->tty_fd, &readfds);
                        }
+                       if (d->evtchn_fd != -1)
+                               FD_SET(d->evtchn_fd, &readfds);
 
                        if (d->tty_fd != -1 && !buffer_empty(&d->buffer)) {
                                FD_SET(d->tty_fd, &writefds);
                        }
 
                        max_fd = MAX(d->tty_fd, max_fd);
+                       max_fd = MAX(d->evtchn_fd, max_fd);
                }
 
                ret = select(max_fd + 1, &readfds, &writefds, 0, &tv);
-               if (tv.tv_sec == 1 && (++num_of_writes % 100) == 0) {
-#if 0
-                       /* FIXME */
-                       /* This is a nasty hack.  xcs does not handle the
-                          control channels filling up well at all.  We'll
-                          throttle ourselves here since we do proper
-                          queueing to give the domains a shot at pulling out
-                          the data.  Fixing xcs is not worth it as it's
-                          going away */
-                       tv.tv_usec = 1000;
-                       select(0, 0, 0, 0, &tv);
-#endif
-               }
                enum_domains();
 
-               if (FD_ISSET(xcs_data_fd, &readfds)) {
+               if (FD_ISSET(xcs_data_fd, &readfds))
                        handle_xcs_msg(xcs_data_fd);
-               }
 
                for (d = dom_head; d; d = d->next) {
-                       if (!d->is_dead && FD_ISSET(d->tty_fd, &readfds)) {
+                       if (d->is_dead || d->tty_fd == -1 ||
+                           d->evtchn_fd == -1)
+                               continue;
+
+                       if (FD_ISSET(d->tty_fd, &readfds))
                                handle_tty_read(d);
-                       }
-
-                       if (!d->is_dead && FD_ISSET(d->tty_fd, &writefds)) {
+
+                       if (FD_ISSET(d->evtchn_fd, &readfds))
+                               handle_ring_read(d);
+
+                       if (FD_ISSET(d->tty_fd, &writefds))
                                handle_tty_write(d);
-                       }
                }
 
                remove_dead_domains(dom_head);
diff -r e69cbfee4011 -r 8fe8a99b1c2a tools/console/daemon/utils.c
--- a/tools/console/daemon/utils.c      Tue Aug 30 08:47:51 2005
+++ b/tools/console/daemon/utils.c      Tue Aug 30 16:14:53 2005
@@ -226,14 +226,10 @@
                goto out_close_data;
        }
 
-       /* Since the vast majority of control messages are console messages
-          it's just easier to ignore other messages that try to bind to 
-          a specific type. */
-       msg.type = XCS_MSG_BIND;
-       msg.u.bind.port = PORT_WILDCARD;
-       msg.u.bind.type = TYPE_WILDCARD;
+       msg.type = XCS_VIRQ_BIND;
+       msg.u.virq.virq = VIRQ_DOM_EXC;
        if (!xcs_send_recv(xcs_ctrl_fd, &msg) || msg.result != XCS_RSLT_OK) {
-               dolog(LOG_ERR, "xcs vind failed.  Possible bug.");
+               dolog(LOG_ERR, "xcs virq bind failed.  Possible bug.");
                goto out_close_data;
        }
        
diff -r e69cbfee4011 -r 8fe8a99b1c2a tools/libxc/xc_linux_build.c
--- a/tools/libxc/xc_linux_build.c      Tue Aug 30 08:47:51 2005
+++ b/tools/libxc/xc_linux_build.c      Tue Aug 30 16:14:53 2005
@@ -335,7 +335,8 @@
                        unsigned int control_evtchn,
                        unsigned long flags,
                        unsigned int vcpus,
-                      unsigned int store_evtchn, unsigned long *store_mfn)
+                      unsigned int store_evtchn, unsigned long *store_mfn,
+                      unsigned int console_evtchn, unsigned long *console_mfn)
 {
     unsigned long *page_array = NULL;
     unsigned long count, i;
@@ -358,6 +359,8 @@
     unsigned long vstartinfo_end;
     unsigned long vstoreinfo_start;
     unsigned long vstoreinfo_end;
+    unsigned long vconsole_start;
+    unsigned long vconsole_end;
     unsigned long vstack_start;
     unsigned long vstack_end;
     unsigned long vpt_start;
@@ -393,7 +396,9 @@
     vphysmap_end     = vphysmap_start + (nr_pages * sizeof(unsigned long));
     vstoreinfo_start = round_pgup(vphysmap_end);
     vstoreinfo_end   = vstoreinfo_start + PAGE_SIZE;
-    vpt_start        = vstoreinfo_end; 
+    vconsole_start   = vstoreinfo_end;
+    vconsole_end     = vstoreinfo_end + PAGE_SIZE;
+    vpt_start        = vconsole_end; 
 
     for ( nr_pt_pages = 2; ; nr_pt_pages++ )
     {
@@ -437,6 +442,7 @@
            " Init. ramdisk: %p->%p\n"
            " Phys-Mach map: %p->%p\n"
            " Store page:    %p->%p\n"
+           " Console page:  %p->%p\n"
            " Page tables:   %p->%p\n"
            " Start info:    %p->%p\n"
            " Boot stack:    %p->%p\n"
@@ -445,6 +451,7 @@
            _p(vinitrd_start), _p(vinitrd_end),
            _p(vphysmap_start), _p(vphysmap_end),
            _p(vstoreinfo_start), _p(vstoreinfo_end),
+           _p(vconsole_start), _p(vconsole_end),
            _p(vpt_start), _p(vpt_end),
            _p(vstartinfo_start), _p(vstartinfo_end),
            _p(vstack_start), _p(vstack_end),
@@ -566,6 +573,8 @@
 #endif
 
     *store_mfn = page_array[(vstoreinfo_start-dsi.v_start) >> PAGE_SHIFT];
+    *console_mfn = page_array[(vconsole_start-dsi.v_start) >> PAGE_SHIFT];
+
 
     start_info = xc_map_foreign_range(
         xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
@@ -580,6 +589,8 @@
     start_info->domain_controller_evtchn = control_evtchn;
     start_info->store_mfn    = *store_mfn;
     start_info->store_evtchn = store_evtchn;
+    start_info->console_mfn   = *console_mfn;
+    start_info->console_evtchn = console_evtchn;
     if ( initrd_len != 0 )
     {
         start_info->mod_start    = vinitrd_start;
@@ -631,7 +642,9 @@
                    unsigned long flags,
                    unsigned int vcpus,
                    unsigned int store_evtchn,
-                   unsigned long *store_mfn)
+                   unsigned long *store_mfn,
+                   unsigned int console_evtchn,
+                   unsigned long *console_mfn)
 {
     dom0_op_t launch_op, op;
     int initrd_fd = -1;
@@ -707,7 +720,8 @@
                      &vstack_start, ctxt, cmdline,
                      op.u.getdomaininfo.shared_info_frame,
                      control_evtchn, flags, vcpus,
-                     store_evtchn, store_mfn) < 0 )
+                     store_evtchn, store_mfn,
+                    console_evtchn, console_mfn) < 0 )
     {
         ERROR("Error constructing guest OS");
         goto error_out;
diff -r e69cbfee4011 -r 8fe8a99b1c2a tools/libxc/xenguest.h
--- a/tools/libxc/xenguest.h    Tue Aug 30 08:47:51 2005
+++ b/tools/libxc/xenguest.h    Tue Aug 30 16:14:53 2005
@@ -47,7 +47,9 @@
                    unsigned long flags,
                    unsigned int vcpus,
                    unsigned int store_evtchn,
-                   unsigned long *store_mfn);
+                   unsigned long *store_mfn,
+                   unsigned int console_evtchn,
+                   unsigned long *console_mfn);
 
 struct mem_map;
 int xc_vmx_build(int xc_handle,
diff -r e69cbfee4011 -r 8fe8a99b1c2a tools/python/xen/lowlevel/xc/xc.c
--- a/tools/python/xen/lowlevel/xc/xc.c Tue Aug 30 08:47:51 2005
+++ b/tools/python/xen/lowlevel/xc/xc.c Tue Aug 30 16:14:53 2005
@@ -268,25 +268,33 @@
     u32 dom;
     char *image, *ramdisk = NULL, *cmdline = "";
     int flags = 0, vcpus = 1;
-    int control_evtchn, store_evtchn;
+    int control_evtchn, store_evtchn, console_evtchn;
     unsigned long store_mfn = 0;
+    unsigned long console_mfn = 0;
 
     static char *kwd_list[] = { "dom", "control_evtchn", "store_evtchn", 
-                                "image", "ramdisk", "cmdline", "flags",
+                                "console_evtchn", "image", 
+                               /* optional */
+                               "ramdisk", "cmdline", "flags",
                                "vcpus", NULL };
 
-    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiis|ssii", kwd_list,
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiis|ssii", kwd_list,
                                       &dom, &control_evtchn, &store_evtchn,
-                                      &image, &ramdisk, &cmdline, &flags,
+                                     &console_evtchn, &image, 
+                                     /* optional */
+                                     &ramdisk, &cmdline, &flags,
                                       &vcpus) )
         return NULL;
 
     if ( xc_linux_build(xc->xc_handle, dom, image,
                         ramdisk, cmdline, control_evtchn, flags, vcpus,
-                        store_evtchn, &store_mfn) != 0 )
-        return PyErr_SetFromErrno(xc_error);
-    
-    return Py_BuildValue("{s:i}", "store_mfn", store_mfn);
+                        store_evtchn, &store_mfn, 
+                       console_evtchn, &console_mfn) != 0 )
+        return PyErr_SetFromErrno(xc_error);
+    
+    return Py_BuildValue("{s:i,s:i}", 
+                        "store_mfn", store_mfn,
+                        "console_mfn", console_mfn);
 }
 
 static PyObject *pyxc_vmx_build(PyObject *self,
diff -r e69cbfee4011 -r 8fe8a99b1c2a tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Tue Aug 30 08:47:51 2005
+++ b/tools/python/xen/xend/XendDomainInfo.py   Tue Aug 30 16:14:53 2005
@@ -47,7 +47,7 @@
 from xen.xend.XendRoot import get_component
 
 from xen.xend.uuid import getUuid
-from xen.xend.xenstore import DBVar
+from xen.xend.xenstore import DBVar, XenNode, DBMap
 
 """Shutdown code for poweroff."""
 DOMAIN_POWEROFF = 0
@@ -231,6 +231,7 @@
         DBVar('start_time',    ty='float'),
         DBVar('state',         ty='str'),
         DBVar('store_mfn',     ty='long'),
+        DBVar('console_mfn',     ty='long'),
         DBVar('restart_mode',  ty='str'),
         DBVar('restart_state', ty='str'),
         DBVar('restart_time',  ty='float'),
@@ -260,6 +261,8 @@
         self.channel = None
         self.store_channel = None
         self.store_mfn = None
+        self.console_channel = None
+        self.console_mfn = None
         self.controllers = {}
         
         self.info = None
@@ -297,6 +300,9 @@
         if self.store_channel:
             self.store_channel.saveToDB(self.db.addChild("store_channel"),
                                         save=save)
+        if self.console_channel:
+            self.console_channel.saveToDB(self.db.addChild("console_channel"),
+                                        save=save)
         if self.image:
             self.image.exportToDB(save=save, sync=sync)
         self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
@@ -328,6 +334,9 @@
 
     def getStoreChannel(self):
         return self.store_channel
+
+    def getConsoleChannel(self):
+        return self.console_channel
 
     def update(self, info):
         """Update with  info from xc.domain_getinfo().
@@ -518,6 +527,14 @@
             sxpr.append(self.store_channel.sxpr())
         if self.store_mfn:
             sxpr.append(['store_mfn', self.store_mfn])
+        if self.console_channel:
+            sxpr.append(['console_channel', self.console_channel.sxpr()])
+        if self.console_mfn:
+            sxpr.append(['console_mfn', self.console_mfn])
+# already in (devices)
+#        console = self.getConsole()
+#        if console:
+#            sxpr.append(console.sxpr())
 
         if self.restart_count:
             sxpr.append(['restart_count', self.restart_count])
@@ -712,6 +729,13 @@
             except Exception, ex:
                 log.warning("error in domain release on xenstore: %s", ex)
                 pass
+        if self.console_channel:
+            # notify processes using this cosole?
+            try:
+                self.console_channel.close()
+                self.console_channel = None
+            except:
+                pass
         if self.image:
             try:
                 self.device_model_pid = 0
@@ -808,6 +832,7 @@
         """
         self.channel = self.openChannel("channel", 0, 1)
         self.store_channel = self.eventChannel("store_channel")
+        self.console_channel = self.eventChannel("console_channel")
 
     def create_configured_devices(self):
         devices = sxp.children(self.config, 'device')
@@ -1003,6 +1028,7 @@
         self.configure_fields()
         self.create_devices()
         self.create_blkif()
+        self.publish_console()
 
     def create_blkif(self):
         """Create the block device interface (blkif) for the vm.
@@ -1017,6 +1043,12 @@
             backend = blkif.getBackend(0)
             backend.connect(recreate=self.recreate)
 
+    def publish_console(self):
+        db = DBMap(db=XenNode("/console/%d" % self.id))
+        db.clear()
+        db['domain'] = self.db.getPath()
+        db.saveDB(save=True)
+        
     def configure_fields(self):
         """Process the vm configuration fields using the registered handlers.
         """
diff -r e69cbfee4011 -r 8fe8a99b1c2a tools/python/xen/xend/image.py
--- a/tools/python/xen/xend/image.py    Tue Aug 30 08:47:51 2005
+++ b/tools/python/xen/xend/image.py    Tue Aug 30 16:14:53 2005
@@ -238,16 +238,33 @@
             store_evtchn = self.vm.store_channel.port2
         else:
             store_evtchn = 0
+        if self.vm.console_channel:
+            console_evtchn = self.vm.console_channel.port2
+        else:
+            console_evtchn = 0
+
+        log.debug("dom            = %d", self.vm.getDomain())
+        log.debug("image          = %s", self.kernel)
+        log.debug("control_evtchn = %s", self.vm.channel.getRemotePort())
+        log.debug("store_evtchn   = %d", store_evtchn)
+        log.debug("console_evtchn = %d", console_evtchn)
+        log.debug("cmdline        = %s", self.cmdline)
+        log.debug("ramdisk        = %s", self.ramdisk)
+        log.debug("flags          = %d", self.flags)
+        log.debug("vcpus          = %d", self.vm.vcpus)
+
         ret = xc.linux_build(dom            = self.vm.getDomain(),
                              image          = self.kernel,
                              control_evtchn = self.vm.channel.getRemotePort(),
                              store_evtchn   = store_evtchn,
+                             console_evtchn = console_evtchn,
                              cmdline        = self.cmdline,
                              ramdisk        = self.ramdisk,
                              flags          = self.flags,
                              vcpus          = self.vm.vcpus)
         if isinstance(ret, dict):
             self.vm.store_mfn = ret.get('store_mfn')
+            self.vm.console_mfn = ret.get('console_mfn')
             return 0
         return ret
 
diff -r e69cbfee4011 -r 8fe8a99b1c2a xen/include/public/xen.h
--- a/xen/include/public/xen.h  Tue Aug 30 08:47:51 2005
+++ b/xen/include/public/xen.h  Tue Aug 30 16:14:53 2005
@@ -438,19 +438,21 @@
 #define MAX_GUEST_CMDLINE 1024
 typedef struct start_info {
     /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME.    */
-    unsigned long nr_pages;   /* Total pages allocated to this domain.    */
-    unsigned long shared_info;/* MACHINE address of shared info struct.   */
-    u32      flags;           /* SIF_xxx flags.                           */
+    unsigned long nr_pages;     /* Total pages allocated to this domain.  */
+    unsigned long shared_info;  /* MACHINE address of shared info struct. */
+    u32      flags;             /* SIF_xxx flags.                         */
     u16      domain_controller_evtchn;
     /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME).     */
-    unsigned long pt_base;    /* VIRTUAL address of page directory.       */
-    unsigned long nr_pt_frames;/* Number of bootstrap p.t. frames.        */
-    unsigned long mfn_list;   /* VIRTUAL address of page-frame list.      */
-    unsigned long mod_start;  /* VIRTUAL address of pre-loaded module.    */
-    unsigned long mod_len;    /* Size (bytes) of pre-loaded module.       */
+    unsigned long pt_base;      /* VIRTUAL address of page directory.     */
+    unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames.       */
+    unsigned long mfn_list;     /* VIRTUAL address of page-frame list.    */
+    unsigned long mod_start;    /* VIRTUAL address of pre-loaded module.  */
+    unsigned long mod_len;      /* Size (bytes) of pre-loaded module.     */
     s8 cmd_line[MAX_GUEST_CMDLINE];
-    unsigned long store_mfn;  /* MACHINE page number of shared page.      */
-    u16      store_evtchn;    /* Event channel for store communication.   */
+    unsigned long store_mfn;    /* MACHINE page number of shared page.    */
+    u16      store_evtchn;      /* Event channel for store communication. */
+    unsigned long console_mfn;  /* MACHINE address of console page.       */
+    u16      console_evtchn;    /* Event channel for console messages.    */
 } start_info_t;
 
 /* These flags are passed in the 'flags' field of start_info_t. */
diff -r e69cbfee4011 -r 8fe8a99b1c2a 
linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c
--- /dev/null   Tue Aug 30 08:47:51 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c   Tue Aug 30 
16:14:53 2005
@@ -0,0 +1,124 @@
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <asm-xen/hypervisor.h>
+#include <asm-xen/evtchn.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include "xencons_ring.h"
+
+
+struct ring_head
+{
+       u32 cons;
+       u32 prod;
+       char buf[0];
+} __attribute__((packed));
+
+
+#define XENCONS_RING_SIZE (PAGE_SIZE/2 - sizeof (struct ring_head))
+#define XENCONS_IDX(cnt) ((cnt) % XENCONS_RING_SIZE)
+#define XENCONS_FULL(ring) (((ring)->prod - (ring)->cons) == XENCONS_RING_SIZE)
+
+static inline struct ring_head *outring(void)
+{
+       return machine_to_virt(xen_start_info.console_mfn << PAGE_SHIFT);
+}
+
+static inline struct ring_head *inring(void)
+{
+       return machine_to_virt(xen_start_info.console_mfn << PAGE_SHIFT)
+               + PAGE_SIZE/2;
+}
+
+
+/* don't block -  write as much as possible and return */
+static int __xencons_ring_send(struct ring_head *ring, const char *data, 
unsigned len)
+{
+       int copied = 0;
+
+       mb();
+       while (copied < len && !XENCONS_FULL(ring)) {
+               ring->buf[XENCONS_IDX(ring->prod)] = data[copied];
+               ring->prod++;
+               copied++;
+       }
+       mb();
+
+       return copied;
+}
+
+int xencons_ring_send(const char *data, unsigned len)
+{
+       struct ring_head *out = outring();
+       int sent = 0;
+       
+       sent = __xencons_ring_send(out, data, len);
+       notify_via_evtchn(xen_start_info.console_evtchn);
+       return sent;
+
+}      
+
+
+static xencons_receiver_func *xencons_receiver;
+
+static irqreturn_t handle_input(int irq, void *unused, struct pt_regs *regs)
+{
+       struct ring_head *ring = inring();
+       while (ring->cons < ring->prod) {
+               if (xencons_receiver != NULL) {
+                       xencons_receiver(ring->buf + XENCONS_IDX(ring->cons),
+                                        1);
+               }
+               ring->cons++;
+       }
+       return IRQ_HANDLED;
+}
+
+void xencons_ring_register_receiver(xencons_receiver_func *f)
+{
+       xencons_receiver = f;
+}
+
+int xencons_ring_init(void)
+{
+       int err;
+
+       if (!xen_start_info.console_evtchn)
+               return 0;
+
+       err = bind_evtchn_to_irqhandler(
+               xen_start_info.console_evtchn, handle_input,
+               0, "xencons", inring());
+       if (err) {
+               xprintk(KERN_ERR "XEN console request irq failed %i\n", err);
+               unbind_evtchn_from_irq(xen_start_info.console_evtchn);
+               return err;
+       }
+
+       return 0;
+}
+
+void xencons_suspend_comms(void)
+{
+
+       if (!xen_start_info.console_evtchn)
+               return;
+
+       unbind_evtchn_from_irqhandler(xen_start_info.console_evtchn, inring());
+}
+
diff -r e69cbfee4011 -r 8fe8a99b1c2a 
linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.h
--- /dev/null   Tue Aug 30 08:47:51 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.h   Tue Aug 30 
16:14:53 2005
@@ -0,0 +1,13 @@
+#ifndef _XENCONS_RING_H
+#define _XENCONS_RING_H
+
+asmlinkage int xprintk(const char *fmt, ...);
+
+
+int xencons_ring_init(void);
+int xencons_ring_send(const char *data, unsigned len);
+
+typedef void (xencons_receiver_func)(char *buf, unsigned len);
+void xencons_ring_register_receiver(xencons_receiver_func *f);
+
+#endif /* _XENCONS_RING_H */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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