Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145680264
D40993.1778433519.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
26 KB
Referenced Files
None
Subscribers
None
D40993.1778433519.diff
View Options
diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -53,6 +53,7 @@
tpm_device.c \
tpm_emul_passthru.c \
tpm_intf_crb.c \
+ uart_backend.c \
uart_emul.c \
usb_emul.c \
usb_mouse.c \
diff --git a/usr.sbin/bhyve/amd64/pci_lpc.c b/usr.sbin/bhyve/amd64/pci_lpc.c
--- a/usr.sbin/bhyve/amd64/pci_lpc.c
+++ b/usr.sbin/bhyve/amd64/pci_lpc.c
@@ -73,7 +73,7 @@
#define LPC_UART_NUM 4
static struct lpc_uart_softc {
- struct uart_softc *uart_softc;
+ struct uart_ns16550_softc *uart_softc;
int iobase;
int irq;
int enabled;
@@ -208,17 +208,19 @@
switch (bytes) {
case 1:
if (in)
- *eax = uart_read(sc->uart_softc, offset);
+ *eax = uart_ns16550_read(sc->uart_softc, offset);
else
- uart_write(sc->uart_softc, offset, *eax);
+ uart_ns16550_write(sc->uart_softc, offset, *eax);
break;
case 2:
if (in) {
- *eax = uart_read(sc->uart_softc, offset);
- *eax |= uart_read(sc->uart_softc, offset + 1) << 8;
+ *eax = uart_ns16550_read(sc->uart_softc, offset);
+ *eax |=
+ uart_ns16550_read(sc->uart_softc, offset + 1) << 8;
} else {
- uart_write(sc->uart_softc, offset, *eax);
- uart_write(sc->uart_softc, offset + 1, *eax >> 8);
+ uart_ns16550_write(sc->uart_softc, offset, *eax);
+ uart_ns16550_write(sc->uart_softc, offset + 1,
+ *eax >> 8);
}
break;
default:
@@ -257,13 +259,14 @@
}
pci_irq_reserve(sc->irq);
- sc->uart_softc = uart_init(lpc_uart_intr_assert,
- lpc_uart_intr_deassert, sc);
+ sc->uart_softc = uart_ns16550_init(lpc_uart_intr_assert,
+ lpc_uart_intr_deassert, sc);
asprintf(&node_name, "lpc.%s.path", name);
backend = get_config_value(node_name);
free(node_name);
- if (uart_set_backend(sc->uart_softc, backend) != 0) {
+ if (backend != NULL &&
+ uart_ns16550_tty_open(sc->uart_softc, backend) != 0) {
EPRINTLN("Unable to initialize backend '%s' "
"for LPC device %s", backend, name);
return (-1);
@@ -272,7 +275,7 @@
bzero(&iop, sizeof(struct inout_port));
iop.name = name;
iop.port = sc->iobase;
- iop.size = UART_IO_BAR_SIZE;
+ iop.size = UART_NS16550_IO_BAR_SIZE;
iop.flags = IOPORT_F_INOUT;
iop.handler = lpc_uart_io_handler;
iop.arg = sc;
@@ -405,7 +408,7 @@
dsdt_line(" Name (_CRS, ResourceTemplate ()");
dsdt_line(" {");
dsdt_indent(2);
- dsdt_fixed_ioport(sc->iobase, UART_IO_BAR_SIZE);
+ dsdt_fixed_ioport(sc->iobase, UART_NS16550_IO_BAR_SIZE);
dsdt_fixed_irq(sc->irq);
dsdt_unindent(2);
dsdt_line(" })");
@@ -570,12 +573,12 @@
pci_lpc_snapshot(struct vm_snapshot_meta *meta)
{
int unit, ret;
- struct uart_softc *sc;
+ struct uart_ns16550_softc *sc;
for (unit = 0; unit < LPC_UART_NUM; unit++) {
sc = lpc_uart_softc[unit].uart_softc;
- ret = uart_snapshot(sc, meta);
+ ret = uart_ns16550_snapshot(sc, meta);
if (ret != 0)
goto done;
}
diff --git a/usr.sbin/bhyve/pci_uart.c b/usr.sbin/bhyve/pci_uart.c
--- a/usr.sbin/bhyve/pci_uart.c
+++ b/usr.sbin/bhyve/pci_uart.c
@@ -72,7 +72,7 @@
assert(baridx == 0);
assert(size == 1);
- uart_write(pi->pi_arg, offset, value);
+ uart_ns16550_write(pi->pi_arg, offset, value);
}
static uint64_t
@@ -83,7 +83,7 @@
assert(baridx == 0);
assert(size == 1);
- val = uart_read(pi->pi_arg, offset);
+ val = uart_ns16550_read(pi->pi_arg, offset);
return (val);
}
@@ -99,10 +99,10 @@
static int
pci_uart_init(struct pci_devinst *pi, nvlist_t *nvl)
{
- struct uart_softc *sc;
+ struct uart_ns16550_softc *sc;
const char *device;
- pci_emul_alloc_bar(pi, 0, PCIBAR_IO, UART_IO_BAR_SIZE);
+ pci_emul_alloc_bar(pi, 0, PCIBAR_IO, UART_NS16550_IO_BAR_SIZE);
pci_lintr_request(pi);
/* initialize config space */
@@ -110,11 +110,12 @@
pci_set_cfgdata16(pi, PCIR_VENDOR, COM_VENDOR);
pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM);
- sc = uart_init(pci_uart_intr_assert, pci_uart_intr_deassert, pi);
+ sc = uart_ns16550_init(pci_uart_intr_assert, pci_uart_intr_deassert,
+ pi);
pi->pi_arg = sc;
device = get_config_value_node(nvl, "path");
- if (uart_set_backend(sc, device) != 0) {
+ if (device != NULL && uart_ns16550_tty_open(sc, device) != 0) {
EPRINTLN("Unable to initialize backend '%s' for "
"pci uart at %d:%d", device, pi->pi_slot, pi->pi_func);
return (-1);
diff --git a/usr.sbin/bhyve/uart_emul.h b/usr.sbin/bhyve/uart_backend.h
copy from usr.sbin/bhyve/uart_emul.h
copy to usr.sbin/bhyve/uart_backend.h
--- a/usr.sbin/bhyve/uart_emul.h
+++ b/usr.sbin/bhyve/uart_backend.h
@@ -1,6 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
+ * Copyright (c) 2012 NetApp, Inc.
* Copyright (c) 2013 Neel Natu <neel@freebsd.org>
* All rights reserved.
*
@@ -24,27 +25,31 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $FreeBSD$
*/
-#ifndef _UART_EMUL_H_
-#define _UART_EMUL_H_
+#ifndef _UART_BACKEND_H_
+#define _UART_BACKEND_H_
+
+#include <stdbool.h>
-#define UART_IO_BAR_SIZE 8
+#include "mevent.h"
struct uart_softc;
struct vm_snapshot_meta;
-typedef void (*uart_intr_func_t)(void *arg);
-struct uart_softc *uart_init(uart_intr_func_t intr_assert,
- uart_intr_func_t intr_deassert, void *arg);
-
-int uart_legacy_alloc(int unit, int *ioaddr, int *irq);
-uint8_t uart_read(struct uart_softc *sc, int offset);
-void uart_write(struct uart_softc *sc, int offset, uint8_t value);
-int uart_set_backend(struct uart_softc *sc, const char *device);
+void uart_rxfifo_drain(struct uart_softc *sc, bool loopback);
+int uart_rxfifo_getchar(struct uart_softc *sc);
+int uart_rxfifo_numchars(struct uart_softc *sc);
+int uart_rxfifo_putchar(struct uart_softc *sc, uint8_t ch, bool loopback);
+void uart_rxfifo_reset(struct uart_softc *sc, int size);
+int uart_rxfifo_size(struct uart_softc *sc);
#ifdef BHYVE_SNAPSHOT
-int uart_snapshot(struct uart_softc *sc, struct vm_snapshot_meta *meta);
-#endif
+int uart_rxfifo_snapshot(struct uart_softc *sc,
+ struct vm_snapshot_meta *meta);
#endif
+
+struct uart_softc *uart_init(void);
+int uart_tty_open(struct uart_softc *sc, const char *path,
+ void (*drain)(int, enum ev_type, void *), void *arg);
+
+#endif /* _UART_BACKEND_H_ */
diff --git a/usr.sbin/bhyve/uart_backend.c b/usr.sbin/bhyve/uart_backend.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/uart_backend.c
@@ -0,0 +1,348 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2012 NetApp, Inc.
+ * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <machine/vmm.h>
+#include <machine/vmm_snapshot.h>
+
+#include <assert.h>
+#include <capsicum_helpers.h>
+#include <err.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "debug.h"
+#include "mevent.h"
+#include "uart_backend.h"
+
+struct ttyfd {
+ bool opened;
+ int rfd; /* fd for reading */
+ int wfd; /* fd for writing, may be == rfd */
+};
+
+#define FIFOSZ 16
+
+struct fifo {
+ uint8_t buf[FIFOSZ];
+ int rindex; /* index to read from */
+ int windex; /* index to write to */
+ int num; /* number of characters in the fifo */
+ int size; /* size of the fifo */
+};
+
+struct uart_softc {
+ struct ttyfd tty;
+ struct fifo rxfifo;
+ struct mevent *mev;
+};
+
+static bool uart_stdio; /* stdio in use for i/o */
+static struct termios tio_stdio_orig;
+
+static void
+ttyclose(void)
+{
+ tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig);
+}
+
+static void
+ttyopen(struct ttyfd *tf)
+{
+ struct termios orig, new;
+
+ tcgetattr(tf->rfd, &orig);
+ new = orig;
+ cfmakeraw(&new);
+ new.c_cflag |= CLOCAL;
+ tcsetattr(tf->rfd, TCSANOW, &new);
+ if (uart_stdio) {
+ tio_stdio_orig = orig;
+ atexit(ttyclose);
+ }
+ raw_stdio = 1;
+}
+
+static int
+ttyread(struct ttyfd *tf)
+{
+ unsigned char rb;
+
+ if (read(tf->rfd, &rb, 1) == 1)
+ return (rb);
+ else
+ return (-1);
+}
+
+static void
+ttywrite(struct ttyfd *tf, unsigned char wb)
+{
+ (void)write(tf->wfd, &wb, 1);
+}
+
+static bool
+rxfifo_available(struct uart_softc *sc)
+{
+ return (sc->rxfifo.num < sc->rxfifo.size);
+}
+
+int
+uart_rxfifo_getchar(struct uart_softc *sc)
+{
+ struct fifo *fifo;
+ int c, error, wasfull;
+
+ wasfull = 0;
+ fifo = &sc->rxfifo;
+ if (fifo->num > 0) {
+ if (!rxfifo_available(sc))
+ wasfull = 1;
+ c = fifo->buf[fifo->rindex];
+ fifo->rindex = (fifo->rindex + 1) % fifo->size;
+ fifo->num--;
+ if (wasfull) {
+ if (sc->tty.opened) {
+ error = mevent_enable(sc->mev);
+ assert(error == 0);
+ }
+ }
+ return (c);
+ } else
+ return (-1);
+}
+
+int
+uart_rxfifo_numchars(struct uart_softc *sc)
+{
+ return (sc->rxfifo.num);
+}
+
+static int
+rxfifo_putchar(struct uart_softc *sc, uint8_t ch)
+{
+ struct fifo *fifo;
+ int error;
+
+ fifo = &sc->rxfifo;
+
+ if (fifo->num < fifo->size) {
+ fifo->buf[fifo->windex] = ch;
+ fifo->windex = (fifo->windex + 1) % fifo->size;
+ fifo->num++;
+ if (!rxfifo_available(sc)) {
+ if (sc->tty.opened) {
+ /*
+ * Disable mevent callback if the FIFO is full.
+ */
+ error = mevent_disable(sc->mev);
+ assert(error == 0);
+ }
+ }
+ return (0);
+ } else
+ return (-1);
+}
+
+void
+uart_rxfifo_drain(struct uart_softc *sc, bool loopback)
+{
+ int ch;
+
+ if (loopback) {
+ (void)ttyread(&sc->tty);
+ } else {
+ while (rxfifo_available(sc) &&
+ ((ch = ttyread(&sc->tty)) != -1))
+ rxfifo_putchar(sc, ch);
+ }
+}
+
+int
+uart_rxfifo_putchar(struct uart_softc *sc, uint8_t ch, bool loopback)
+{
+ if (loopback) {
+ return (rxfifo_putchar(sc, ch));
+ } else if (sc->tty.opened) {
+ ttywrite(&sc->tty, ch);
+ return (0);
+ } else {
+ /* Drop on the floor. */
+ return (0);
+ }
+}
+
+void
+uart_rxfifo_reset(struct uart_softc *sc, int size)
+{
+ char flushbuf[32];
+ struct fifo *fifo;
+ ssize_t nread;
+ int error;
+
+ fifo = &sc->rxfifo;
+ bzero(fifo, sizeof(struct fifo));
+ fifo->size = size;
+
+ if (sc->tty.opened) {
+ /*
+ * Flush any unread input from the tty buffer.
+ */
+ while (1) {
+ nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf));
+ if (nread != sizeof(flushbuf))
+ break;
+ }
+
+ /*
+ * Enable mevent to trigger when new characters are available
+ * on the tty fd.
+ */
+ error = mevent_enable(sc->mev);
+ assert(error == 0);
+ }
+}
+
+int
+uart_rxfifo_size(struct uart_softc *sc __unused)
+{
+ return (FIFOSZ);
+}
+
+#ifdef BHYVE_SNAPSHOT
+int
+uart_rxfifo_snapshot(struct uart_softc *sc, struct vm_snapshot_meta *meta)
+{
+ int ret;
+
+ SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.rindex, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.windex, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.num, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.size, meta, ret, done);
+ SNAPSHOT_BUF_OR_LEAVE(sc->rxfifo.buf, sizeof(sc->rxfifo.buf),
+ meta, ret, done);
+
+done:
+ return (ret);
+}
+#endif
+
+static int
+uart_stdio_backend(struct uart_softc *sc)
+{
+#ifndef WITHOUT_CAPSICUM
+ cap_rights_t rights;
+ cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
+#endif
+
+ if (uart_stdio)
+ return (-1);
+
+ sc->tty.rfd = STDIN_FILENO;
+ sc->tty.wfd = STDOUT_FILENO;
+ sc->tty.opened = true;
+
+ if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0)
+ return (-1);
+ if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0)
+ return (-1);
+
+#ifndef WITHOUT_CAPSICUM
+ cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ);
+ if (caph_rights_limit(sc->tty.rfd, &rights) == -1)
+ errx(EX_OSERR, "Unable to apply rights for sandbox");
+ if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1)
+ errx(EX_OSERR, "Unable to apply rights for sandbox");
+#endif
+
+ uart_stdio = true;
+
+ return (0);
+}
+
+static int
+uart_tty_backend(struct uart_softc *sc, const char *path)
+{
+#ifndef WITHOUT_CAPSICUM
+ cap_rights_t rights;
+ cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
+#endif
+ int fd;
+
+ fd = open(path, O_RDWR | O_NONBLOCK);
+ if (fd < 0)
+ return (-1);
+
+ if (!isatty(fd)) {
+ close(fd);
+ return (-1);
+ }
+
+ sc->tty.rfd = sc->tty.wfd = fd;
+ sc->tty.opened = true;
+
+#ifndef WITHOUT_CAPSICUM
+ cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE);
+ if (caph_rights_limit(fd, &rights) == -1)
+ errx(EX_OSERR, "Unable to apply rights for sandbox");
+ if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1)
+ errx(EX_OSERR, "Unable to apply rights for sandbox");
+#endif
+
+ return (0);
+}
+
+struct uart_softc *
+uart_init(void)
+{
+ return (calloc(1, sizeof(struct uart_softc)));
+}
+
+int
+uart_tty_open(struct uart_softc *sc, const char *path,
+ void (*drain)(int, enum ev_type, void *), void *arg)
+{
+ int retval;
+
+ if (strcmp("stdio", path) == 0)
+ retval = uart_stdio_backend(sc);
+ else
+ retval = uart_tty_backend(sc, path);
+ if (retval == 0) {
+ ttyopen(&sc->tty);
+ sc->mev = mevent_add(sc->tty.rfd, EVF_READ, drain, arg);
+ assert(sc->mev != NULL);
+ }
+
+ return (retval);
+}
diff --git a/usr.sbin/bhyve/uart_emul.h b/usr.sbin/bhyve/uart_emul.h
--- a/usr.sbin/bhyve/uart_emul.h
+++ b/usr.sbin/bhyve/uart_emul.h
@@ -31,20 +31,23 @@
#ifndef _UART_EMUL_H_
#define _UART_EMUL_H_
-#define UART_IO_BAR_SIZE 8
+#define UART_NS16550_IO_BAR_SIZE 8
-struct uart_softc;
+struct uart_ns16550_softc;
struct vm_snapshot_meta;
typedef void (*uart_intr_func_t)(void *arg);
-struct uart_softc *uart_init(uart_intr_func_t intr_assert,
- uart_intr_func_t intr_deassert, void *arg);
+struct uart_ns16550_softc *uart_ns16550_init(uart_intr_func_t intr_assert,
+ uart_intr_func_t intr_deassert, void *arg);
int uart_legacy_alloc(int unit, int *ioaddr, int *irq);
-uint8_t uart_read(struct uart_softc *sc, int offset);
-void uart_write(struct uart_softc *sc, int offset, uint8_t value);
-int uart_set_backend(struct uart_softc *sc, const char *device);
+uint8_t uart_ns16550_read(struct uart_ns16550_softc *sc, int offset);
+void uart_ns16550_write(struct uart_ns16550_softc *sc, int offset,
+ uint8_t value);
+int uart_ns16550_tty_open(struct uart_ns16550_softc *sc,
+ const char *device);
#ifdef BHYVE_SNAPSHOT
-int uart_snapshot(struct uart_softc *sc, struct vm_snapshot_meta *meta);
+int uart_ns16550_snapshot(struct uart_ns16550_softc *sc,
+ struct vm_snapshot_meta *meta);
#endif
#endif
diff --git a/usr.sbin/bhyve/uart_emul.c b/usr.sbin/bhyve/uart_emul.c
--- a/usr.sbin/bhyve/uart_emul.c
+++ b/usr.sbin/bhyve/uart_emul.c
@@ -34,29 +34,20 @@
#include <sys/types.h>
#include <dev/ic/ns16550.h>
-#ifndef WITHOUT_CAPSICUM
-#include <sys/capsicum.h>
-#include <capsicum_helpers.h>
-#endif
#include <machine/vmm_snapshot.h>
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
-#include <assert.h>
-#include <err.h>
#include <errno.h>
-#include <fcntl.h>
-#include <termios.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#include <pthread.h>
-#include <sysexits.h>
-#include "mevent.h"
+#include "uart_backend.h"
#include "uart_emul.h"
-#include "debug.h"
#define COM1_BASE 0x3F8
#define COM1_IRQ 4
@@ -81,11 +72,6 @@
#define REG_SCR com_scr
#endif
-#define FIFOSZ 16
-
-static bool uart_stdio; /* stdio in use for i/o */
-static struct termios tio_stdio_orig;
-
static struct {
int baseaddr;
int irq;
@@ -99,21 +85,9 @@
#define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0]))
-struct fifo {
- uint8_t buf[FIFOSZ];
- int rindex; /* index to read from */
- int windex; /* index to write to */
- int num; /* number of characters in the fifo */
- int size; /* size of the fifo */
-};
-
-struct ttyfd {
- bool opened;
- int rfd; /* fd for reading */
- int wfd; /* fd for writing, may be == rfd */
-};
+struct uart_ns16550_softc {
+ struct uart_softc *backend;
-struct uart_softc {
pthread_mutex_t mtx; /* protects all softc elements */
uint8_t data; /* Data register (R/W) */
uint8_t ier; /* Interrupt enable register (R/W) */
@@ -127,10 +101,6 @@
uint8_t dll; /* Baudrate divisor latch LSB */
uint8_t dlh; /* Baudrate divisor latch MSB */
- struct fifo rxfifo;
- struct mevent *mev;
-
- struct ttyfd tty;
bool thre_int_pending; /* THRE interrupt pending */
void *arg;
@@ -138,158 +108,6 @@
uart_intr_func_t intr_deassert;
};
-static void uart_drain(int fd, enum ev_type ev, void *arg);
-
-static void
-ttyclose(void)
-{
-
- tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig);
-}
-
-static void
-ttyopen(struct ttyfd *tf)
-{
- struct termios orig, new;
-
- tcgetattr(tf->rfd, &orig);
- new = orig;
- cfmakeraw(&new);
- new.c_cflag |= CLOCAL;
- tcsetattr(tf->rfd, TCSANOW, &new);
- if (uart_stdio) {
- tio_stdio_orig = orig;
- atexit(ttyclose);
- }
- raw_stdio = 1;
-}
-
-static int
-ttyread(struct ttyfd *tf)
-{
- unsigned char rb;
-
- if (read(tf->rfd, &rb, 1) == 1)
- return (rb);
- else
- return (-1);
-}
-
-static void
-ttywrite(struct ttyfd *tf, unsigned char wb)
-{
-
- (void)write(tf->wfd, &wb, 1);
-}
-
-static void
-rxfifo_reset(struct uart_softc *sc, int size)
-{
- char flushbuf[32];
- struct fifo *fifo;
- ssize_t nread;
- int error;
-
- fifo = &sc->rxfifo;
- bzero(fifo, sizeof(struct fifo));
- fifo->size = size;
-
- if (sc->tty.opened) {
- /*
- * Flush any unread input from the tty buffer.
- */
- while (1) {
- nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf));
- if (nread != sizeof(flushbuf))
- break;
- }
-
- /*
- * Enable mevent to trigger when new characters are available
- * on the tty fd.
- */
- error = mevent_enable(sc->mev);
- assert(error == 0);
- }
-}
-
-static int
-rxfifo_available(struct uart_softc *sc)
-{
- struct fifo *fifo;
-
- fifo = &sc->rxfifo;
- return (fifo->num < fifo->size);
-}
-
-static int
-rxfifo_putchar(struct uart_softc *sc, uint8_t ch)
-{
- struct fifo *fifo;
- int error;
-
- fifo = &sc->rxfifo;
-
- if (fifo->num < fifo->size) {
- fifo->buf[fifo->windex] = ch;
- fifo->windex = (fifo->windex + 1) % fifo->size;
- fifo->num++;
- if (!rxfifo_available(sc)) {
- if (sc->tty.opened) {
- /*
- * Disable mevent callback if the FIFO is full.
- */
- error = mevent_disable(sc->mev);
- assert(error == 0);
- }
- }
- return (0);
- } else
- return (-1);
-}
-
-static int
-rxfifo_getchar(struct uart_softc *sc)
-{
- struct fifo *fifo;
- int c, error, wasfull;
-
- wasfull = 0;
- fifo = &sc->rxfifo;
- if (fifo->num > 0) {
- if (!rxfifo_available(sc))
- wasfull = 1;
- c = fifo->buf[fifo->rindex];
- fifo->rindex = (fifo->rindex + 1) % fifo->size;
- fifo->num--;
- if (wasfull) {
- if (sc->tty.opened) {
- error = mevent_enable(sc->mev);
- assert(error == 0);
- }
- }
- return (c);
- } else
- return (-1);
-}
-
-static int
-rxfifo_numchars(struct uart_softc *sc)
-{
- struct fifo *fifo = &sc->rxfifo;
-
- return (fifo->num);
-}
-
-static void
-uart_opentty(struct uart_softc *sc)
-{
-
- ttyopen(&sc->tty);
- sc->mev = mevent_add(sc->tty.rfd, EVF_READ, uart_drain, sc);
- assert(sc->mev != NULL);
-}
-
static uint8_t
modem_status(uint8_t mcr)
{
@@ -330,12 +148,13 @@
* Return an interrupt reason if one is available.
*/
static int
-uart_intr_reason(struct uart_softc *sc)
+uart_intr_reason(struct uart_ns16550_softc *sc)
{
if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
return (IIR_RLS);
- else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0)
+ else if (uart_rxfifo_numchars(sc->backend) > 0 &&
+ (sc->ier & IER_ERXRDY) != 0)
return (IIR_RXTOUT);
else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
return (IIR_TXRDY);
@@ -346,7 +165,7 @@
}
static void
-uart_reset(struct uart_softc *sc)
+uart_reset(struct uart_ns16550_softc *sc)
{
uint16_t divisor;
@@ -355,7 +174,7 @@
sc->dlh = divisor >> 16;
sc->msr = modem_status(sc->mcr);
- rxfifo_reset(sc, 1); /* no fifo until enabled by software */
+ uart_rxfifo_reset(sc->backend, 1);
}
/*
@@ -363,7 +182,7 @@
* interrupt condition to report to the processor.
*/
static void
-uart_toggle_intr(struct uart_softc *sc)
+uart_toggle_intr(struct uart_ns16550_softc *sc)
{
uint8_t intr_reason;
@@ -376,14 +195,13 @@
}
static void
-uart_drain(int fd, enum ev_type ev, void *arg)
+uart_drain(int fd __unused, enum ev_type ev, void *arg)
{
- struct uart_softc *sc;
- int ch;
+ struct uart_ns16550_softc *sc;
+ bool loopback;
sc = arg;
- assert(fd == sc->tty.rfd);
assert(ev == EVF_READ);
/*
@@ -393,21 +211,16 @@
*/
pthread_mutex_lock(&sc->mtx);
- if ((sc->mcr & MCR_LOOPBACK) != 0) {
- (void) ttyread(&sc->tty);
- } else {
- while (rxfifo_available(sc) &&
- ((ch = ttyread(&sc->tty)) != -1)) {
- rxfifo_putchar(sc, ch);
- }
+ loopback = (sc->mcr & MCR_LOOPBACK) != 0;
+ uart_rxfifo_drain(sc->backend, loopback);
+ if (!loopback)
uart_toggle_intr(sc);
- }
pthread_mutex_unlock(&sc->mtx);
}
void
-uart_write(struct uart_softc *sc, int offset, uint8_t value)
+uart_ns16550_write(struct uart_ns16550_softc *sc, int offset, uint8_t value)
{
int fifosz;
uint8_t msr;
@@ -431,12 +244,9 @@
switch (offset) {
case REG_DATA:
- if (sc->mcr & MCR_LOOPBACK) {
- if (rxfifo_putchar(sc, value) != 0)
- sc->lsr |= LSR_OE;
- } else if (sc->tty.opened) {
- ttywrite(&sc->tty, value);
- } /* else drop on floor */
+ if (uart_rxfifo_putchar(sc->backend, value,
+ (sc->mcr & MCR_LOOPBACK) != 0))
+ sc->lsr |= LSR_OE;
sc->thre_int_pending = true;
break;
case REG_IER:
@@ -455,8 +265,9 @@
* the FIFO contents are reset.
*/
if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
- fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
- rxfifo_reset(sc, fifosz);
+ fifosz = (value & FCR_ENABLE) ?
+ uart_rxfifo_size(sc->backend) : 1;
+ uart_rxfifo_reset(sc->backend, fifosz);
}
/*
@@ -467,7 +278,8 @@
sc->fcr = 0;
} else {
if ((value & FCR_RCV_RST) != 0)
- rxfifo_reset(sc, FIFOSZ);
+ uart_rxfifo_reset(sc->backend,
+ uart_rxfifo_size(sc->backend));
sc->fcr = value &
(FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
@@ -526,7 +338,7 @@
}
uint8_t
-uart_read(struct uart_softc *sc, int offset)
+uart_ns16550_read(struct uart_ns16550_softc *sc, int offset)
{
uint8_t iir, intr_reason, reg;
@@ -549,7 +361,7 @@
switch (offset) {
case REG_DATA:
- reg = rxfifo_getchar(sc);
+ reg = uart_rxfifo_getchar(sc->backend);
break;
case REG_IER:
reg = sc->ier;
@@ -580,7 +392,7 @@
sc->lsr |= LSR_TEMT | LSR_THRE;
/* Check for new receive data */
- if (rxfifo_numchars(sc) > 0)
+ if (uart_rxfifo_numchars(sc->backend) > 0)
sc->lsr |= LSR_RXRDY;
else
sc->lsr &= ~LSR_RXRDY;
@@ -626,17 +438,18 @@
return (0);
}
-struct uart_softc *
-uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
+struct uart_ns16550_softc *
+uart_ns16550_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
void *arg)
{
- struct uart_softc *sc;
+ struct uart_ns16550_softc *sc;
- sc = calloc(1, sizeof(struct uart_softc));
+ sc = calloc(1, sizeof(struct uart_ns16550_softc));
sc->arg = arg;
sc->intr_assert = intr_assert;
sc->intr_deassert = intr_deassert;
+ sc->backend = uart_init();
pthread_mutex_init(&sc->mtx, NULL);
@@ -645,92 +458,16 @@
return (sc);
}
-static int
-uart_stdio_backend(struct uart_softc *sc)
-{
-#ifndef WITHOUT_CAPSICUM
- cap_rights_t rights;
- cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
-#endif
-
- if (uart_stdio)
- return (-1);
-
- sc->tty.rfd = STDIN_FILENO;
- sc->tty.wfd = STDOUT_FILENO;
- sc->tty.opened = true;
-
- if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0)
- return (-1);
- if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0)
- return (-1);
-
-#ifndef WITHOUT_CAPSICUM
- cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ);
- if (caph_rights_limit(sc->tty.rfd, &rights) == -1)
- errx(EX_OSERR, "Unable to apply rights for sandbox");
- if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1)
- errx(EX_OSERR, "Unable to apply rights for sandbox");
-#endif
-
- uart_stdio = true;
-
- return (0);
-}
-
-static int
-uart_tty_backend(struct uart_softc *sc, const char *path)
-{
-#ifndef WITHOUT_CAPSICUM
- cap_rights_t rights;
- cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
-#endif
- int fd;
-
- fd = open(path, O_RDWR | O_NONBLOCK);
- if (fd < 0)
- return (-1);
-
- if (!isatty(fd)) {
- close(fd);
- return (-1);
- }
-
- sc->tty.rfd = sc->tty.wfd = fd;
- sc->tty.opened = true;
-
-#ifndef WITHOUT_CAPSICUM
- cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE);
- if (caph_rights_limit(fd, &rights) == -1)
- errx(EX_OSERR, "Unable to apply rights for sandbox");
- if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1)
- errx(EX_OSERR, "Unable to apply rights for sandbox");
-#endif
-
- return (0);
-}
-
int
-uart_set_backend(struct uart_softc *sc, const char *device)
+uart_ns16550_tty_open(struct uart_ns16550_softc *sc, const char *device)
{
- int retval;
-
- if (device == NULL)
- return (0);
-
- if (strcmp("stdio", device) == 0)
- retval = uart_stdio_backend(sc);
- else
- retval = uart_tty_backend(sc, device);
- if (retval == 0)
- uart_opentty(sc);
-
- return (retval);
+ return (uart_tty_open(sc->backend, device, uart_drain, sc));
}
#ifdef BHYVE_SNAPSHOT
int
-uart_snapshot(struct uart_softc *sc, struct vm_snapshot_meta *meta)
+uart_ns16550_snapshot(struct uart_ns16550_softc *sc,
+ struct vm_snapshot_meta *meta)
{
int ret;
@@ -746,12 +483,7 @@
SNAPSHOT_VAR_OR_LEAVE(sc->dll, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(sc->dlh, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.rindex, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.windex, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.num, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.size, meta, ret, done);
- SNAPSHOT_BUF_OR_LEAVE(sc->rxfifo.buf, sizeof(sc->rxfifo.buf),
- meta, ret, done);
+ ret = uart_rxfifo_snapshot(sc->backend, meta);
sc->thre_int_pending = 1;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, May 10, 5:18 PM (16 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28640666
Default Alt Text
D40993.1778433519.diff (26 KB)
Attached To
Mode
D40993: bhyve: Move device model-independent UART code into a separate file
Attached
Detach File
Event Timeline
Log In to Comment