[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |