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