[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-tools] [PATCH] An example console driver using the store
Cool!Do we want to go with this? I can update the console daemon to use this code if we do. Regards, Anthony Liguori Rusty Russell wrote: Sorry this took so long, distracted by other things. This patch adds xenbus_early_write, for use before we can sleep, and illustrates how a console driver can use the store. The console driver replaces the normal one for testing, and uses the same ringbuf code as xenbus (which really should be extracted into a separate library). The toy client only handles a single page for the buffer, doesn't handle ^C etc.This uncovered some bugs in xenstored: patches coming. Cheers!Rusty. Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx> diff -r 079dce7cc5e3 linux-2.6.11-xen-sparse/arch/xen/kernel/reboot.c --- a/linux-2.6.11-xen-sparse/arch/xen/kernel/reboot.c Sun Aug 7 13:13:19 2005 +++ b/linux-2.6.11-xen-sparse/arch/xen/kernel/reboot.c Mon Aug 8 16:53:16 2005 @@ -21,8 +21,8 @@ void machine_restart(char * __unused) { /* We really want to get pending console data out before we die. */ - extern void xencons_force_flush(void); - xencons_force_flush(); +// extern void xencons_force_flush(void); +// xencons_force_flush(); HYPERVISOR_reboot(); } @@ -34,8 +34,8 @@ void machine_power_off(void) { /* We really want to get pending console data out before we die. */ - extern void xencons_force_flush(void); - xencons_force_flush(); +// extern void xencons_force_flush(void); +// xencons_force_flush(); HYPERVISOR_shutdown(); } diff -r 079dce7cc5e3 linux-2.6.11-xen-sparse/drivers/xen/Makefile --- a/linux-2.6.11-xen-sparse/drivers/xen/Makefile Sun Aug 7 13:13:19 2005 +++ b/linux-2.6.11-xen-sparse/drivers/xen/Makefile Mon Aug 8 16:53:16 2005 @@ -1,6 +1,7 @@ obj-y += console/ +obj-y += test-console/ obj-y += evtchn/ obj-y += balloon/ obj-y += privcmd/ diff -r 079dce7cc5e3 linux-2.6.11-xen-sparse/drivers/xen/console/Makefile --- a/linux-2.6.11-xen-sparse/drivers/xen/console/Makefile Sun Aug 7 13:13:19 2005 +++ b/linux-2.6.11-xen-sparse/drivers/xen/console/Makefile Mon Aug 8 16:53:16 2005 @@ -1,2 +1,3 @@ -obj-y := console.o +obj-$(CONFIG_XEN_PRIVILEGED_GUEST) += console.o +obj-y += test-console.c diff -r 079dce7cc5e3 linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c --- a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c Sun Aug 7 13:13:19 2005 +++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c Mon Aug 8 16:53:16 2005 @@ -119,35 +119,41 @@ return avail != 0; } -int xb_write(const void *data, unsigned len) +int __xb_write(const void *data, unsigned len) { struct ringbuf_head h; struct ringbuf_head *out = outbuf(); - + unsigned int avail; + void *dst; + + /* The world would be nicer if we could just *trust* the daemons. */ + h = *out; + mb(); + if (!check_buffer(&h)) + return -EIO; + + dst = get_output_chunk(&h, out->buf, &avail); + if (avail > len) + avail = len; + memcpy(dst, data, avail); + data += avail; + len -= avail; + update_output_chunk(out, avail); + notify_via_evtchn(xen_start_info.store_evtchn); + + return avail; +} + +int xb_write(const void *data, unsigned len) +{ do { - void *dst; - unsigned int avail; - - wait_event(xb_waitq, output_avail(out)); - - /* Read, then check: not that we don't trust store. - * Hell, some of my best friends are daemons. But, - * in this post-911 world... */ - h = *out; - mb(); - if (!check_buffer(&h)) { - set_current_state(TASK_RUNNING); - return -EIO; /* ETERRORIST! */ - } - - dst = get_output_chunk(&h, out->buf, &avail); - if (avail > len) - avail = len; - memcpy(dst, data, avail); - data += avail; - len -= avail; - update_output_chunk(out, avail); - notify_via_evtchn(xen_start_info.store_evtchn); + int ret; + + wait_event(xb_waitq, output_avail(outbuf())); + ret = __xb_write(data, len); + if (ret < 0) + return ret; + len -= ret; } while (len != 0); return 0; @@ -217,11 +223,6 @@ unbind_evtchn_from_irq(xen_start_info.store_evtchn); return err; } - - /* FIXME zero out page -- domain builder should probably do this*/ - memset(machine_to_virt(xen_start_info.store_mfn << PAGE_SHIFT), - 0, PAGE_SIZE); - return 0; } diff -r 079dce7cc5e3 linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h --- a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h Sun Aug 7 13:13:19 2005 +++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h Mon Aug 8 16:53:16 2005 @@ -7,6 +7,7 @@ /* Low level routines. */ int xb_write(const void *data, unsigned len); +int __xb_write(const void *data, unsigned len); diff -r 079dce7cc5e3 linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h --- a/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h Sun Aug 7 13:13:19 2005 +++ b/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h Mon Aug 8 16:53:16 2005 @@ -121,6 +121,9 @@ /* For backends, does lookup on uuid (up to /). Returns domid, or -errno. */ int xenbus_uuid_to_domid(const char *uuid); +/* Can be used immediately: writes a value and doesn't wait for response. */ +void __init xenbus_early_write(const char *path, const char *value); + /* Called from xen core code. */ void xenbus_suspend(void); void xenbus_resume(void); diff -r 079dce7cc5e3 linux-2.6.11-xen-sparse/drivers/xen/console/test-console.c --- /dev/null Sun Aug 7 13:13:19 2005 +++ b/linux-2.6.11-xen-sparse/drivers/xen/console/test-console.c Mon Aug 8 16:53:16 2005 @@ -0,0 +1,463 @@ +/****************************************************************************** + * Simple console. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation+ * + * This file may be distributed separately from the Linux kernel, or+ * incorporated into other software packages, subject to the following license:+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#define DEBUG + +#include <asm-xen/hypervisor.h> +#include <asm-xen/xenbus.h> +#include <asm-xen/evtchn.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/console.h> +#include <linux/init.h> +#include <asm/uaccess.h> + +#define XEN_CONSOLE_FLAG_OVERFLOW 0x1 +#define XEN_CONSOLE_FLAG_EIO 0x2 + +struct ringbuf_head +{ + __u32 write; /* Next place to write to */ + __u32 read; /* Next place to read from */ + __u8 flags; + char buf[0]; +} __attribute__((packed)); + +/* FIXME: Use 1 << CONFIG_LOG_BUF_SHIFT. */+#define BUFFER_SIZE 4096 ++/* Two circular buffers: small one for input, large one for output. */ +struct xen_console_buffer +{ + struct ringbuf_head inbuf; + char inbuf_buf[128 - sizeof(struct ringbuf_head)]; + + struct ringbuf_head outbuf; + char outbuf_buf[BUFFER_SIZE - 128 - sizeof(struct ringbuf_head)]; +} __attribute__((packed, aligned(PAGE_SIZE))); + +static struct xen_console_buffer xen_console_buffer; + +/* We have only one, but for future convenience we keep a struct. */ +struct xen_console { + struct xen_console_buffer *buf; + struct tty_struct *tty; + spinlock_t lock; + int count; + u16 evtchn; +}; +static struct xen_console console; + +static inline int check_buffer(const struct ringbuf_head *h, __u32 bufsize) +{ + return (h->write < bufsize && h->read < bufsize); +} + +/* We can't fill last byte: would look like empty buffer. */ +static char *get_write_chunk(const struct ringbuf_head *h, + char *buf, __u32 bufsize, + __u32 *len) +{ + __u32 read_mark; + + if (h->read == 0) + read_mark = bufsize - 1; + else + read_mark = h->read - 1; + + /* Here to the end of buffer, unless they haven't read some out. */ + *len = bufsize - h->write; + if (read_mark >= h->write) + *len = read_mark - h->write; + return buf + h->write; +} + +static void update_write_chunk(struct ringbuf_head *h, + __u32 bufsize, __u32 len) +{ + h->write += len; + if (h->write == bufsize) + h->write = 0; +} + +static const char *get_read_chunk(const struct ringbuf_head *h, + const char *buf, __u32 bufsize, + __u32 *len) +{ + /* Here to the end of buffer, unless they haven't written some. */ + *len = bufsize - h->read; + if (h->write >= h->read) + *len = h->write - h->read; + return buf + h->read; +} + +static void update_read_chunk(struct ringbuf_head *h, + __u32 bufsize, __u32 len) +{ + h->read += len; + if (h->read == bufsize) + h->read = 0; +} + +static int write_buf(struct ringbuf_head *head, __u32 bufsize, + const char *src, __u32 len) +{ + int ret = 0; + struct ringbuf_head h; + + /* Must read head once, and before anything else. */ + h = *head; + mb(); + + if (!check_buffer(&h, bufsize)) + return -EIO; + + while (len > 0) { + __u32 thislen; + char *dst = get_write_chunk(&h, head->buf, bufsize, &thislen); + + if (thislen == 0) + break; + if (thislen > len) + thislen = len; + memcpy(dst, src, thislen); + update_write_chunk(&h, bufsize, thislen); + src += thislen; + len -= thislen; + ret += thislen; + } + + /* Must have written data before updating head. */ + mb(); + *head = h; + return ret; +} + +static int read_buf(struct ringbuf_head *head, __u32 bufsize, + char *dst, __u32 len) +{ + int ret = 0; + struct ringbuf_head h; + + /* Must read head once, and before anything else. */ + h = *head; + mb(); + + if (!check_buffer(&h, bufsize)) + return -EIO; + + while (len > 0) { + __u32 thislen; + const char *src; + + src = get_read_chunk(&h, head->buf, bufsize, &thislen); + + if (thislen == 0) + break; + if (thislen > len) + thislen = len; + memcpy(dst, src, thislen); + update_read_chunk(&h, bufsize, thislen); + dst += thislen; + len -= thislen; + ret += thislen; + } + + /* Must have read data before updating head. */ + mb(); + *head = h; + return ret; +} + +static int xen_console_open(struct tty_struct *tty, struct file *filp) +{ + if (tty->index != 0) + return -ENODEV; + + spin_lock_irq(&console.lock); + console.tty = tty; + console.count++; + tty->driver_data = &console; + spin_unlock_irq(&console.lock); + + return 0; +} + +static void xen_console_hangup(struct tty_struct *tty) +{ + struct xen_console *c = tty->driver_data; + + spin_lock_irq(&c->lock); + c->tty = NULL; + spin_unlock_irq(&c->lock); +} + +static void xen_console_close(struct tty_struct *tty, struct file *filp) +{ + struct xen_console *c = tty->driver_data; + + if (tty_hung_up_p(filp)) + return; + + spin_lock_irq(&c->lock); + if (--c->count == 0) + c->tty = NULL; + spin_unlock_irq(&c->lock); +} + +static int xen_console_put(struct xen_console *c, + const unsigned char *buf, + int len) +{ + int done; + unsigned long flags; + + spin_lock_irqsave(&c->lock, flags); + done = write_buf(&c->buf->outbuf, sizeof(c->buf->outbuf_buf), buf,len); + + /* Error, overflow, or OK. */ + if (done < 0) + c->buf->outbuf.flags |= XEN_CONSOLE_FLAG_EIO; + else if (done < len) + c->buf->outbuf.flags |= XEN_CONSOLE_FLAG_OVERFLOW; + else if (c->buf->outbuf.flags) + c->buf->outbuf.flags = 0; + + /* Tell the other side we changed the field. */ + notify_via_evtchn(c->evtchn); + spin_unlock_irqrestore(&c->lock, flags); + return len; +} + +static int xen_console_write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + return xen_console_put(tty->driver_data, buf, count); +} + +static irqreturn_t irq_handler(int irq, void *val, struct pt_regs *regs) +{ + struct xen_console *c = val; + unsigned long flags; + int done = 0, len; + + spin_lock_irqsave(&c->lock, flags); + if (c->tty) { + len = TTY_FLIPBUF_SIZE - c->tty->flip.count;+ done = read_buf(&c->buf->inbuf, sizeof(c->buf->inbuf_buf), + c->tty->flip.char_buf_ptr, len);+ if (done < 0) + c->buf->outbuf.flags |= XEN_CONSOLE_FLAG_EIO; + else { + memset(c->tty->flip.flag_buf_ptr, 0, done); + c->tty->flip.count += done; + tty_schedule_flip(c->tty); + } + } + spin_unlock_irqrestore(&c->lock, flags); + + if (!done) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static int xen_console_write_room(struct tty_struct *tty) +{ + struct xen_console *c = tty->driver_data; + + /* + * Pretend to be infinite: we want to discard ourselves so we know. + * Also, tty layer seems not to call us again if we ever return 0. + */ + return sizeof(c->buf->outbuf_buf); +} + +static int xen_console_chars_in_buffer(struct tty_struct *tty) +{ + struct xen_console *c = tty->driver_data; + struct ringbuf_head h; + unsigned long flags; + u32 len; + + spin_lock_irqsave(&c->lock, flags); + h = c->buf->inbuf; + rmb(); /* Ensure we read only once. */ + get_read_chunk(&h, NULL, sizeof(c->buf->inbuf_buf), &len); + spin_unlock_irqrestore(&c->lock, flags); + return len; +} + +static struct tty_operations xen_console_ops = { + .open = xen_console_open, + .close = xen_console_close, + .write = xen_console_write, + .hangup = xen_console_hangup, + .write_room = xen_console_write_room, + .chars_in_buffer = xen_console_chars_in_buffer, +}; + +static struct tty_driver *xen_console_driver; + +/* FIXME: Go dynamic.... --RR */ +#define XEN_CONSOLE_MAJOR 249 +#define XEN_CONSOLE_MINOR 0 + +/* Upper bound to sprintf this simple type? Each 3 bits < 1 digit. */ +#define CHAR_SIZE(type) (((sizeof(type)*8 + 2) / 3) + 1) + +/* FIXME: Assumes console will be read from domain 0. */ +static int __init get_eventchannel(void) +{ + evtchn_op_t op = { .cmd = EVTCHNOP_alloc_unbound }; + int err; + + op.u.alloc_unbound.dom = 0; + err = HYPERVISOR_event_channel_op(&op); + if (err) + return err; + return op.u.alloc_unbound.port; +} + +static char *__init console_frames_string(void) +{ + /* Room for one long + separator per page, */ + static char str[CHAR_SIZE(long) + * sizeof(xen_console_buffer)/PAGE_SIZE]; + unsigned int i; + void *p; + + p = &xen_console_buffer; + for (i = 0; i < sizeof(xen_console_buffer)/PAGE_SIZE; i++) + sprintf(str + strlen(str), "%s%li", + i ? "," : "", + virt_to_machine(p + i*PAGE_SIZE) >> PAGE_SHIFT); + return str; +} + +static int __init init(void) +{ + int err, irq; + + printk("test-console init\n"); + if (!xen_start_info.store_evtchn) + return 0; + + if (!console.evtchn) { + err = get_eventchannel(); + if (err < 0) + return err; + console.evtchn = err; + down(&xenbus_lock); + xenbus_write("console", "frames", + console_frames_string(), O_CREAT); + xenbus_printf("console", "event-channel", "%i",console.evtchn); + up(&xenbus_lock); + } + irq = bind_evtchn_to_irq(console.evtchn); + err = request_irq(irq, irq_handler, SA_SHIRQ, "xenconsole", &console); + if (err) + return err; + + xen_console_driver = alloc_tty_driver(1); + if (!xen_console_driver) + return -ENOMEM; + + xen_console_driver->owner = THIS_MODULE; + xen_console_driver->devfs_name = "xencons/"; + xen_console_driver->driver_name = "xencons"; + xen_console_driver->name = "xencons"; + xen_console_driver->major = XEN_CONSOLE_MAJOR; + xen_console_driver->minor_start = XEN_CONSOLE_MINOR; + xen_console_driver->type = TTY_DRIVER_TYPE_SYSTEM; + xen_console_driver->init_termios = tty_std_termios; + xen_console_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(xen_console_driver, &xen_console_ops); + if (tty_register_driver(xen_console_driver)) + panic("Couldn't register xen_console tty driver\n"); + + return 0; +} + +static void __exit fini(void) +{ + tty_unregister_driver(xen_console_driver); + put_tty_driver(xen_console_driver); +} + +module_init(init); +module_exit(fini); + +static void xen_console_print(struct console *c, const char *b, unsigned count) +{ + xen_console_put(&console, b, count); +} + +static struct tty_driver *xen_console_device(struct console *c, int *index) +{ + *index = c->index; + return xen_console_driver; +} + +static struct console xen_console_console = { + .name = "xencons", + .write = xen_console_print, + .device = xen_console_device, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +static void __init output_console_info(void) +{ + char evtchn[sizeof(console.evtchn) * 3 + 1]; + + sprintf(evtchn, "%u", console.evtchn); + xenbus_early_write("console/event-channel", evtchn); + xenbus_early_write("console/frames", console_frames_string()); +} + +static int __init xen_console_init(void) +{ + int err; + + if (!xen_start_info.store_evtchn) + return 0; + + console.buf = &xen_console_buffer; + spin_lock_init(&console.lock); + + err = get_eventchannel(); + if (err < 0) + return err; + console.evtchn = err; + output_console_info(); + register_console(&xen_console_console); + return 0; +} + +console_initcall(xen_console_init);------------------------------------------------------------------------ /* Simple hacked up console userspace. */ #include <xc.h> #include <xs.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/select.h> #include <sys/mman.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define XEN_CONSOLE_FLAG_OVERFLOW 0x1 #define XEN_CONSOLE_FLAG_EIO 0x2 #define EVENTCHN_BIND _IO('E', 2) #define EVENTCHN_UNBIND _IO('E', 3) struct ringbuf_head { u32 write; /* Next place to write to */ u32 read; /* Next place to read from */ u8 flags; char buf[0]; } __attribute__((packed)); /* Two circular buffers: small one for input, large one for output. */ struct xen_console_buffer { struct ringbuf_head inbuf; char inbuf_buf[128 - sizeof(struct ringbuf_head)]; struct ringbuf_head outbuf; char outbuf_buf[4096 - 128 - sizeof(struct ringbuf_head)]; } __attribute__((packed, aligned(4096))); static int xc_handle; struct xen_console { struct xen_console_buffer *buf; unsigned int evtchn; }; static inline int check_buffer(const struct ringbuf_head *h, u32 bufsize) { return (h->write < bufsize && h->read < bufsize); } /* We can't fill last byte: would look like empty buffer. */ static char *get_write_chunk(const struct ringbuf_head *h, char *buf, u32 bufsize, u32 *len) { u32 read_mark; if (h->read == 0) read_mark = bufsize - 1; else read_mark = h->read - 1; /* Here to the end of buffer, unless they haven't read some out. */ *len = bufsize - h->write; if (read_mark >= h->write) *len = read_mark - h->write; return buf + h->write; } static void update_write_chunk(struct ringbuf_head *h, u32 bufsize, u32 len) { h->write += len; if (h->write == bufsize) h->write = 0; } static const char *get_read_chunk(const struct ringbuf_head *h, const char *buf, u32 bufsize, u32 *len) { /* Here to the end of buffer, unless they haven't written some. */ *len = bufsize - h->read; if (h->write >= h->read) *len = h->write - h->read; return buf + h->read; } static void update_read_chunk(struct ringbuf_head *h, u32 bufsize, u32 len) { h->read += len; if (h->read == bufsize) h->read = 0; } static int write_buf(struct ringbuf_head *head, u32 bufsize, const char *src, u32 len) { int ret = 0; struct ringbuf_head h; /* Must read head once, and before anything else. */ h = *head; mb(); if (!check_buffer(&h, bufsize)) { errno = EIO; return -1; } while (len > 0) { u32 thislen; char *dst = get_write_chunk(&h, head->buf, bufsize, &thislen); if (thislen == 0) break; if (thislen > len) thislen = len; memcpy(dst, src, thislen); update_write_chunk(&h, bufsize, thislen); src += thislen; len -= thislen; ret += thislen; } /* Must have written data before updating head. */ mb(); *head = h; return ret; } static int read_buf(struct ringbuf_head *head, u32 bufsize, char *dst, u32 len) { int ret = 0; struct ringbuf_head h; /* Must read head once, and before anything else. */ h = *head; mb(); if (!check_buffer(&h, bufsize)) { errno = EIO; return -1; } while (len > 0) { u32 thislen; const char *src; src = get_read_chunk(&h, head->buf, bufsize, &thislen); if (thislen == 0) break; if (thislen > len) thislen = len; memcpy(dst, src, thislen); update_read_chunk(&h, bufsize, thislen); dst += thislen; len -= thislen; ret += thislen; } /* Must have read data before updating head. */ mb(); *head = h; return ret; } static int write_console(struct xen_console *con, const void *data, unsigned int len) { int ret; ret = write_buf(&con->buf->inbuf, sizeof(con->buf->inbuf_buf), data, len); if (ret >= 0) xc_evtchn_send(xc_handle, con->evtchn); return ret; } static int read_console(struct xen_console *con, void *data, unsigned int len) { int ret; if (con->buf->outbuf.flags) fprintf(stderr, "*** WARNING: console %s\n", con->buf->outbuf.flags & XEN_CONSOLE_FLAG_EIO ? "reports IO error" : con->buf->outbuf.flags & XEN_CONSOLE_FLAG_OVERFLOW ? "has overflowed: missed output" : "deeply confused"); ret = read_buf(&con->buf->outbuf, sizeof(con->buf->outbuf_buf), data, len); if (ret >= 0) xc_evtchn_send(xc_handle, con->evtchn); return ret; } static void report_buffer(const struct xen_console *con) { printf("input: write marker %i read marker %i\n", con->buf->inbuf.write, con->buf->inbuf.read); printf("output: write marker %i read marker %i\n", con->buf->outbuf.write, con->buf->outbuf.read); } int main(int argc, char **argv) { int port1 = 0, port2 = 0, eventchn_fd, rlen; long frame; unsigned int len; struct xs_handle *xs; char buffer[4096]; struct xen_console console; char *p; if (argc != 2) { printf("Usage: %s DOMID\n", argv[0]); return 1; } xc_handle = xc_interface_open(); if (xc_handle == -1) { printf("xc_interface_open() failed: %m"); return 1; } xs = xs_daemon_open(); if (xs == NULL) { printf("xs_daemon_open() failed: %m\n"); return 1; } sprintf(buffer, "/domain/%s/console/event-channel", argv[1]); p = xs_read(xs, buffer, &len); if (!p) { printf("reading %s failed: %m\n", buffer); return 1; } port2 = atoi(p); /* FIXME: Handle multi-page */ sprintf(buffer, "/domain/%s/console/frames", argv[1]); p = xs_read(xs, buffer, &len); if (!p) { printf("reading %s failed: %m\n", buffer); return 1; } frame = atol(p); if (xc_evtchn_bind_interdomain(xc_handle, DOMID_SELF, atoi(argv[1]), &port1, &port2) == -1) { printf("xc_evtchn_bind_interdomain() failed: %m\n"); return 1; } console.evtchn = port1; console.buf = xc_map_foreign_range(xc_handle, atoi(argv[1]), getpagesize(), PROT_READ|PROT_WRITE, frame); if (!console.buf) { printf("xc_map_foreign_range of %li failed: %m\n", frame); return 1; } eventchn_fd = open("/dev/xen/evtchn", O_RDWR); if (eventchn_fd < 0) { printf("opening %s: %m\n", "/dev/xen/evtchn"); return 1; } if (ioctl(eventchn_fd, EVENTCHN_BIND, console.evtchn) != 0) { printf("binding to %i: %m\n", console.evtchn); return 1; } printf("Got event channel %i, frame %li\n", port2, frame); /* Dump backlog. */ while ((rlen = read_console(&console, buffer, 4096))>0) write(STDOUT_FILENO, buffer, rlen); if (rlen < 0) { printf("Failed to read from console: %m\n"); exit(1); } /* FIXME: We assume we can write without blocking. */ for (;;) { fd_set inset; FD_ZERO(&inset); FD_SET(STDIN_FILENO, &inset); FD_SET(eventchn_fd, &inset); select(eventchn_fd+1, &inset, NULL, NULL, NULL); report_buffer(&console); if (FD_ISSET(eventchn_fd, &inset)) { u16 port; printf("Eventchn fd!\n"); if (read(eventchn_fd, &port, 2) != 2) { printf("Failed to read from event fd: %m\n"); exit(1); } while ((rlen = read_console(&console, buffer, 4096))>0) write(STDOUT_FILENO, buffer, rlen); if (rlen < 0) { printf("Failed to read from console: %m\n"); exit(1); } if (write(eventchn_fd, &port, 2) != 2) { printf("Failed to write to event fd: %m\n"); exit(1); } } if (FD_ISSET(STDIN_FILENO, &inset)) { printf("Stdin fd!\n"); rlen = read(STDIN_FILENO, buffer, 4096); if (rlen < 0) { printf("Failed to read from stdin: %m\n"); exit(1); } if (write_console(&console, buffer, rlen) != rlen) { printf("Failed to write to console: %m\n"); exit(1); } } report_buffer(&console); } }------------------------------------------------------------------------ _______________________________________________ Xen-tools mailing list Xen-tools@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-tools _______________________________________________ Xen-tools mailing list Xen-tools@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-tools
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |