From owner-svn-src-all@FreeBSD.ORG Wed Nov 27 00:21:38 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id B572ADF7; Wed, 27 Nov 2013 00:21:38 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 9544D2989; Wed, 27 Nov 2013 00:21:38 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rAR0LcL5009604; Wed, 27 Nov 2013 00:21:38 GMT (envelope-from grehan@svn.freebsd.org) Received: (from grehan@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id rAR0LcX4009601; Wed, 27 Nov 2013 00:21:38 GMT (envelope-from grehan@svn.freebsd.org) Message-Id: <201311270021.rAR0LcX4009601@svn.freebsd.org> From: Peter Grehan Date: Wed, 27 Nov 2013 00:21:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r258668 - in head/usr.sbin: bhyve bhyveload X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 27 Nov 2013 00:21:38 -0000 Author: grehan Date: Wed Nov 27 00:21:37 2013 New Revision: 258668 URL: http://svnweb.freebsd.org/changeset/base/258668 Log: Allow bhyve and bhyveload to attach to tty devices. bhyveload: introduce the -c parameter to select a tty for output (or "stdio") bhyve: allow the puc and lpc-com backends to accept a tty in addition to "stdio" When used in conjunction with the null-modem device, nmdm(4), this allows attach/detach to the guest console and multiple concurrent serial ports. kgdb on a serial port is now functional. Reviewed by: neel Requested by: Almost everyone that has used bhyve MFC after: 10.0 Modified: head/usr.sbin/bhyve/uart_emul.c head/usr.sbin/bhyveload/bhyveload.8 head/usr.sbin/bhyveload/bhyveload.c Modified: head/usr.sbin/bhyve/uart_emul.c ============================================================================== --- head/usr.sbin/bhyve/uart_emul.c Tue Nov 26 22:41:40 2013 (r258667) +++ head/usr.sbin/bhyve/uart_emul.c Wed Nov 27 00:21:37 2013 (r258668) @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ __FBSDID("$FreeBSD$"); #define FIFOSZ 16 static bool uart_stdio; /* stdio in use for i/o */ +static struct termios tio_stdio_orig; static struct { int baseaddr; @@ -87,6 +89,12 @@ struct fifo { int size; /* size of the fifo */ }; +struct ttyfd { + bool opened; + int fd; /* tty device file descriptor */ + struct termios tio_orig, tio_new; /* I/O Terminals */ +}; + struct uart_softc { pthread_mutex_t mtx; /* protects all softc elements */ uint8_t data; /* Data register (R/W) */ @@ -103,8 +111,7 @@ struct uart_softc { struct fifo rxfifo; - bool opened; - bool stdio; + struct ttyfd tty; bool thre_int_pending; /* THRE interrupt pending */ void *arg; @@ -114,38 +121,41 @@ struct uart_softc { static void uart_drain(int fd, enum ev_type ev, void *arg); -static struct termios tio_orig, tio_new; /* I/O Terminals */ - static void ttyclose(void) { - tcsetattr(STDIN_FILENO, TCSANOW, &tio_orig); + tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig); } static void -ttyopen(void) +ttyopen(struct ttyfd *tf) { - tcgetattr(STDIN_FILENO, &tio_orig); + tcgetattr(tf->fd, &tf->tio_orig); - cfmakeraw(&tio_new); - tcsetattr(STDIN_FILENO, TCSANOW, &tio_new); + tf->tio_new = tf->tio_orig; + cfmakeraw(&tf->tio_new); + tf->tio_new.c_cflag |= CLOCAL; + tcsetattr(tf->fd, TCSANOW, &tf->tio_new); - atexit(ttyclose); + if (tf->fd == STDIN_FILENO) { + tio_stdio_orig = tf->tio_orig; + atexit(ttyclose); + } } static bool -tty_char_available(void) +tty_char_available(struct ttyfd *tf) { fd_set rfds; struct timeval tv; FD_ZERO(&rfds); - FD_SET(STDIN_FILENO, &rfds); + FD_SET(tf->fd, &rfds); tv.tv_sec = 0; tv.tv_usec = 0; - if (select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) > 0 ) { + if (select(tf->fd + 1, &rfds, NULL, NULL, &tv) > 0 ) { return (true); } else { return (false); @@ -153,12 +163,12 @@ tty_char_available(void) } static int -ttyread(void) +ttyread(struct ttyfd *tf) { char rb; - if (tty_char_available()) { - read(STDIN_FILENO, &rb, 1); + if (tty_char_available(tf)) { + read(tf->fd, &rb, 1); return (rb & 0xff); } else { return (-1); @@ -166,10 +176,10 @@ ttyread(void) } static void -ttywrite(unsigned char wb) +ttywrite(struct ttyfd *tf, unsigned char wb) { - (void)write(STDIN_FILENO, &wb, 1); + (void)write(tf->fd, &wb, 1); } static void @@ -226,10 +236,8 @@ uart_opentty(struct uart_softc *sc) { struct mevent *mev; - assert(!sc->opened && sc->stdio); - - ttyopen(); - mev = mevent_add(STDIN_FILENO, EVF_READ, uart_drain, sc); + ttyopen(&sc->tty); + mev = mevent_add(sc->tty.fd, EVF_READ, uart_drain, sc); assert(mev); } @@ -294,7 +302,7 @@ uart_drain(int fd, enum ev_type ev, void sc = arg; - assert(fd == STDIN_FILENO); + assert(fd == sc->tty.fd); assert(ev == EVF_READ); /* @@ -305,10 +313,10 @@ uart_drain(int fd, enum ev_type ev, void pthread_mutex_lock(&sc->mtx); if ((sc->mcr & MCR_LOOPBACK) != 0) { - (void) ttyread(); + (void) ttyread(&sc->tty); } else { while (fifo_available(&sc->rxfifo) && - ((ch = ttyread()) != -1)) { + ((ch = ttyread(&sc->tty)) != -1)) { fifo_putchar(&sc->rxfifo, ch); } uart_toggle_intr(sc); @@ -323,12 +331,6 @@ uart_write(struct uart_softc *sc, int of int fifosz; uint8_t msr; - /* Open terminal */ - if (!sc->opened && sc->stdio) { - uart_opentty(sc); - sc->opened = true; - } - pthread_mutex_lock(&sc->mtx); /* @@ -351,8 +353,8 @@ uart_write(struct uart_softc *sc, int of if (sc->mcr & MCR_LOOPBACK) { if (fifo_putchar(&sc->rxfifo, value) != 0) sc->lsr |= LSR_OE; - } else if (sc->stdio) { - ttywrite(value); + } else if (sc->tty.opened) { + ttywrite(&sc->tty, value); } /* else drop on floor */ sc->thre_int_pending = true; break; @@ -459,12 +461,6 @@ uart_read(struct uart_softc *sc, int off { uint8_t iir, intr_reason, reg; - /* Open terminal */ - if (!sc->opened && sc->stdio) { - uart_opentty(sc); - sc->opened = true; - } - pthread_mutex_lock(&sc->mtx); /* @@ -581,19 +577,47 @@ uart_init(uart_intr_func_t intr_assert, return (sc); } +static int +uart_tty_backend(struct uart_softc *sc, const char *opts) +{ + int fd; + int retval; + + retval = -1; + + fd = open(opts, O_RDWR); + if (fd > 0 && isatty(fd)) { + sc->tty.fd = fd; + sc->tty.opened = true; + retval = 0; + } + + return (retval); +} + int uart_set_backend(struct uart_softc *sc, const char *opts) { - /* - * XXX one stdio backend supported at this time. - */ + int retval; + + retval = -1; + if (opts == NULL) return (0); - if (strcmp("stdio", opts) == 0 && !uart_stdio) { - sc->stdio = true; - uart_stdio = true; - return (0); - } else - return (-1); + if (strcmp("stdio", opts) == 0) { + if (!uart_stdio) { + sc->tty.fd = STDIN_FILENO; + sc->tty.opened = true; + uart_stdio = true; + retval = 0; + } + } else if (uart_tty_backend(sc, opts) == 0) { + retval = 0; + } + + if (retval == 0) + uart_opentty(sc); + + return (retval); } Modified: head/usr.sbin/bhyveload/bhyveload.8 ============================================================================== --- head/usr.sbin/bhyveload/bhyveload.8 Tue Nov 26 22:41:40 2013 (r258667) +++ head/usr.sbin/bhyveload/bhyveload.8 Wed Nov 27 00:21:37 2013 (r258668) @@ -39,6 +39,7 @@ guest inside a bhyve virtual machine .Op Fl d Ar disk-path .Op Fl h Ar host-path .Op Fl e Ar name=value +.Op Fl c Ar cons-dev .Ar vmname .Sh DESCRIPTION .Nm @@ -100,6 +101,16 @@ to .Pp The option may be used more than once to set more than one environment variable. +.It Fl c Ar cons-dev +.Ar cons-dev +is a +.Xr tty 4 +device to use for +.Nm +terminal I/O. +.Pp +The text string "stdio" is also accepted and selects the use of +unbuffered standard I/O. This is the default value. .El .Sh EXAMPLES To create a virtual machine named @@ -109,10 +120,23 @@ that boots off the ISO image and has 1GB memory allocated to it: .Pp .Dl "bhyveload -m 1G -d /freebsd/release.iso freebsd-vm" +.Pp +To create a virtual machine named +.Ar test-vm +with 256MB of memory allocated, the guest root filesystem under the host +directory +.Pa /user/images/test +and terminal I/O sent to the +.Xr nmdm 4 +device +.Pa /dev/nmdm1B +.Pp +.Dl "bhyveload -m 256MB -h /usr/images/test -c /dev/nmdm1B test-vm .Sh SEE ALSO .Xr bhyve 4 , .Xr bhyve 8 , .Xr loader 8 , +.Xr nmdm 4, .Xr vmm 4 .Sh HISTORY .Nm Modified: head/usr.sbin/bhyveload/bhyveload.c ============================================================================== --- head/usr.sbin/bhyveload/bhyveload.c Tue Nov 26 22:41:40 2013 (r258667) +++ head/usr.sbin/bhyveload/bhyveload.c Wed Nov 27 00:21:37 2013 (r258668) @@ -91,6 +91,7 @@ __FBSDID("$FreeBSD$"); static char *host_base = "/"; static struct termios term, oldterm; static int disk_fd = -1; +static int consin_fd, consout_fd; static char *vmname, *progname; static struct vmctx *ctx; @@ -108,7 +109,7 @@ cb_putc(void *arg, int ch) { char c = ch; - write(1, &c, 1); + (void) write(consout_fd, &c, 1); } static int @@ -116,7 +117,7 @@ cb_getc(void *arg) { char c; - if (read(0, &c, 1) == 1) + if (read(consin_fd, &c, 1) == 1) return (c); return (-1); } @@ -126,7 +127,7 @@ cb_poll(void *arg) { int n; - if (ioctl(0, FIONREAD, &n) >= 0) + if (ioctl(consin_fd, FIONREAD, &n) >= 0) return (n > 0); return (0); } @@ -488,7 +489,7 @@ static void cb_exit(void *arg, int v) { - tcsetattr(0, TCSAFLUSH, &oldterm); + tcsetattr(consout_fd, TCSAFLUSH, &oldterm); exit(v); } @@ -564,13 +565,45 @@ static struct loader_callbacks cb = { .getenv = cb_getenv, }; +static int +altcons_open(char *path) +{ + struct stat sb; + int err; + int fd; + + /* + * Allow stdio to be passed in so that the same string + * can be used for the bhyveload console and bhyve com-port + * parameters + */ + if (!strcmp(path, "stdio")) + return (0); + + err = stat(path, &sb); + if (err == 0) { + if (!S_ISCHR(sb.st_mode)) + err = ENOTSUP; + else { + fd = open(path, O_RDWR | O_NONBLOCK); + if (fd < 0) + err = errno; + else + consin_fd = consout_fd = fd; + } + } + + return (err); +} + static void usage(void) { fprintf(stderr, "usage: %s [-m mem-size] [-d ] [-h ]\n" - " %*s [-e ] \n", progname, + " %*s [-e ] [-c ] \n", + progname, (int)strlen(progname), ""); exit(1); } @@ -589,8 +622,16 @@ main(int argc, char** argv) mem_size = 256 * MB; disk_image = NULL; - while ((opt = getopt(argc, argv, "d:e:h:m:")) != -1) { + consin_fd = STDIN_FILENO; + consout_fd = STDOUT_FILENO; + + while ((opt = getopt(argc, argv, "c:d:e:h:m:")) != -1) { switch (opt) { + case 'c': + error = altcons_open(optarg); + if (error != 0) + errx(EX_USAGE, "Could not open '%s'", optarg); + break; case 'd': disk_image = optarg; break; @@ -640,11 +681,13 @@ main(int argc, char** argv) exit(1); } - tcgetattr(0, &term); + tcgetattr(consout_fd, &term); oldterm = term; - term.c_lflag &= ~(ICANON|ECHO); - term.c_iflag &= ~ICRNL; - tcsetattr(0, TCSAFLUSH, &term); + cfmakeraw(&term); + term.c_cflag |= CLOCAL; + + tcsetattr(consout_fd, TCSAFLUSH, &term); + h = dlopen("/boot/userboot.so", RTLD_LOCAL); if (!h) { printf("%s\n", dlerror());