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