1*bf21cd93STycho Nightingale /*- 2*bf21cd93STycho Nightingale * Copyright (c) 2012 NetApp, Inc. 3*bf21cd93STycho Nightingale * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 4*bf21cd93STycho Nightingale * All rights reserved. 5*bf21cd93STycho Nightingale * 6*bf21cd93STycho Nightingale * Redistribution and use in source and binary forms, with or without 7*bf21cd93STycho Nightingale * modification, are permitted provided that the following conditions 8*bf21cd93STycho Nightingale * are met: 9*bf21cd93STycho Nightingale * 1. Redistributions of source code must retain the above copyright 10*bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer. 11*bf21cd93STycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright 12*bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer in the 13*bf21cd93STycho Nightingale * documentation and/or other materials provided with the distribution. 14*bf21cd93STycho Nightingale * 15*bf21cd93STycho Nightingale * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 16*bf21cd93STycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*bf21cd93STycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*bf21cd93STycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 19*bf21cd93STycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*bf21cd93STycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*bf21cd93STycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*bf21cd93STycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*bf21cd93STycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*bf21cd93STycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*bf21cd93STycho Nightingale * SUCH DAMAGE. 26*bf21cd93STycho Nightingale * 27*bf21cd93STycho Nightingale * $FreeBSD: head/usr.sbin/bhyve/uart_emul.c 257293 2013-10-29 00:18:11Z neel $ 28*bf21cd93STycho Nightingale */ 29*bf21cd93STycho Nightingale /* 30*bf21cd93STycho Nightingale * This file and its contents are supplied under the terms of the 31*bf21cd93STycho Nightingale * Common Development and Distribution License ("CDDL"), version 1.0. 32*bf21cd93STycho Nightingale * You may only use this file in accordance with the terms of version 33*bf21cd93STycho Nightingale * 1.0 of the CDDL. 34*bf21cd93STycho Nightingale * 35*bf21cd93STycho Nightingale * A full copy of the text of the CDDL should have accompanied this 36*bf21cd93STycho Nightingale * source. A copy of the CDDL is also available via the Internet at 37*bf21cd93STycho Nightingale * http://www.illumos.org/license/CDDL. 38*bf21cd93STycho Nightingale * 39*bf21cd93STycho Nightingale * Copyright 2015 Pluribus Networks Inc. 40*bf21cd93STycho Nightingale */ 41*bf21cd93STycho Nightingale 42*bf21cd93STycho Nightingale #include <sys/cdefs.h> 43*bf21cd93STycho Nightingale __FBSDID("$FreeBSD: head/usr.sbin/bhyve/uart_emul.c 257293 2013-10-29 00:18:11Z neel $"); 44*bf21cd93STycho Nightingale 45*bf21cd93STycho Nightingale #include <sys/types.h> 46*bf21cd93STycho Nightingale #include <dev/ic/ns16550.h> 47*bf21cd93STycho Nightingale 48*bf21cd93STycho Nightingale #ifndef __FreeBSD__ 49*bf21cd93STycho Nightingale #include <sys/socket.h> 50*bf21cd93STycho Nightingale #include <sys/stat.h> 51*bf21cd93STycho Nightingale #endif 52*bf21cd93STycho Nightingale #include <stdio.h> 53*bf21cd93STycho Nightingale #include <stdlib.h> 54*bf21cd93STycho Nightingale #include <assert.h> 55*bf21cd93STycho Nightingale #include <termios.h> 56*bf21cd93STycho Nightingale #include <unistd.h> 57*bf21cd93STycho Nightingale #include <stdbool.h> 58*bf21cd93STycho Nightingale #include <string.h> 59*bf21cd93STycho Nightingale #include <pthread.h> 60*bf21cd93STycho Nightingale #ifndef __FreeBSD__ 61*bf21cd93STycho Nightingale #include <errno.h> 62*bf21cd93STycho Nightingale #include <fcntl.h> 63*bf21cd93STycho Nightingale #include <poll.h> 64*bf21cd93STycho Nightingale #endif 65*bf21cd93STycho Nightingale 66*bf21cd93STycho Nightingale #ifndef __FreeBSD__ 67*bf21cd93STycho Nightingale #include <bhyve.h> 68*bf21cd93STycho Nightingale 69*bf21cd93STycho Nightingale #include "bhyverun.h" 70*bf21cd93STycho Nightingale #endif 71*bf21cd93STycho Nightingale #ifdef __FreeBSD__ 72*bf21cd93STycho Nightingale #include "mevent.h" 73*bf21cd93STycho Nightingale #endif 74*bf21cd93STycho Nightingale #include "uart_emul.h" 75*bf21cd93STycho Nightingale 76*bf21cd93STycho Nightingale #define COM1_BASE 0x3F8 77*bf21cd93STycho Nightingale #define COM1_IRQ 4 78*bf21cd93STycho Nightingale #define COM2_BASE 0x2F8 79*bf21cd93STycho Nightingale #define COM2_IRQ 3 80*bf21cd93STycho Nightingale 81*bf21cd93STycho Nightingale #define DEFAULT_RCLK 1843200 82*bf21cd93STycho Nightingale #define DEFAULT_BAUD 9600 83*bf21cd93STycho Nightingale 84*bf21cd93STycho Nightingale #define FCR_RX_MASK 0xC0 85*bf21cd93STycho Nightingale 86*bf21cd93STycho Nightingale #define MCR_OUT1 0x04 87*bf21cd93STycho Nightingale #define MCR_OUT2 0x08 88*bf21cd93STycho Nightingale 89*bf21cd93STycho Nightingale #define MSR_DELTA_MASK 0x0f 90*bf21cd93STycho Nightingale 91*bf21cd93STycho Nightingale #ifndef REG_SCR 92*bf21cd93STycho Nightingale #define REG_SCR com_scr 93*bf21cd93STycho Nightingale #endif 94*bf21cd93STycho Nightingale 95*bf21cd93STycho Nightingale #define FIFOSZ 16 96*bf21cd93STycho Nightingale 97*bf21cd93STycho Nightingale static bool uart_stdio; /* stdio in use for i/o */ 98*bf21cd93STycho Nightingale #ifndef __FreeBSD__ 99*bf21cd93STycho Nightingale static bool uart_bcons; /* bhyveconsole in use for i/o */ 100*bf21cd93STycho Nightingale #endif 101*bf21cd93STycho Nightingale 102*bf21cd93STycho Nightingale static struct { 103*bf21cd93STycho Nightingale int baseaddr; 104*bf21cd93STycho Nightingale int irq; 105*bf21cd93STycho Nightingale bool inuse; 106*bf21cd93STycho Nightingale } uart_lres[] = { 107*bf21cd93STycho Nightingale { COM1_BASE, COM1_IRQ, false}, 108*bf21cd93STycho Nightingale { COM2_BASE, COM2_IRQ, false}, 109*bf21cd93STycho Nightingale }; 110*bf21cd93STycho Nightingale 111*bf21cd93STycho Nightingale #define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0])) 112*bf21cd93STycho Nightingale 113*bf21cd93STycho Nightingale struct fifo { 114*bf21cd93STycho Nightingale uint8_t buf[FIFOSZ]; 115*bf21cd93STycho Nightingale int rindex; /* index to read from */ 116*bf21cd93STycho Nightingale int windex; /* index to write to */ 117*bf21cd93STycho Nightingale int num; /* number of characters in the fifo */ 118*bf21cd93STycho Nightingale int size; /* size of the fifo */ 119*bf21cd93STycho Nightingale }; 120*bf21cd93STycho Nightingale 121*bf21cd93STycho Nightingale struct uart_softc { 122*bf21cd93STycho Nightingale pthread_mutex_t mtx; /* protects all softc elements */ 123*bf21cd93STycho Nightingale uint8_t data; /* Data register (R/W) */ 124*bf21cd93STycho Nightingale uint8_t ier; /* Interrupt enable register (R/W) */ 125*bf21cd93STycho Nightingale uint8_t lcr; /* Line control register (R/W) */ 126*bf21cd93STycho Nightingale uint8_t mcr; /* Modem control register (R/W) */ 127*bf21cd93STycho Nightingale uint8_t lsr; /* Line status register (R/W) */ 128*bf21cd93STycho Nightingale uint8_t msr; /* Modem status register (R/W) */ 129*bf21cd93STycho Nightingale uint8_t fcr; /* FIFO control register (W) */ 130*bf21cd93STycho Nightingale uint8_t scr; /* Scratch register (R/W) */ 131*bf21cd93STycho Nightingale 132*bf21cd93STycho Nightingale uint8_t dll; /* Baudrate divisor latch LSB */ 133*bf21cd93STycho Nightingale uint8_t dlh; /* Baudrate divisor latch MSB */ 134*bf21cd93STycho Nightingale 135*bf21cd93STycho Nightingale struct fifo rxfifo; 136*bf21cd93STycho Nightingale 137*bf21cd93STycho Nightingale bool opened; 138*bf21cd93STycho Nightingale bool stdio; 139*bf21cd93STycho Nightingale #ifndef __FreeBSD__ 140*bf21cd93STycho Nightingale bool bcons; 141*bf21cd93STycho Nightingale struct { 142*bf21cd93STycho Nightingale pid_t clipid; 143*bf21cd93STycho Nightingale int clifd; /* console client unix domain socket */ 144*bf21cd93STycho Nightingale int servfd; /* console server unix domain socket */ 145*bf21cd93STycho Nightingale } usc_bcons; 146*bf21cd93STycho Nightingale #endif 147*bf21cd93STycho Nightingale 148*bf21cd93STycho Nightingale bool thre_int_pending; /* THRE interrupt pending */ 149*bf21cd93STycho Nightingale 150*bf21cd93STycho Nightingale void *arg; 151*bf21cd93STycho Nightingale uart_intr_func_t intr_assert; 152*bf21cd93STycho Nightingale uart_intr_func_t intr_deassert; 153*bf21cd93STycho Nightingale }; 154*bf21cd93STycho Nightingale 155*bf21cd93STycho Nightingale #ifdef __FreeBSD__ 156*bf21cd93STycho Nightingale static void uart_drain(int fd, enum ev_type ev, void *arg); 157*bf21cd93STycho Nightingale #else 158*bf21cd93STycho Nightingale static void uart_tty_drain(struct uart_softc *sc); 159*bf21cd93STycho Nightingale static int uart_bcons_drain(struct uart_softc *sc); 160*bf21cd93STycho Nightingale #endif 161*bf21cd93STycho Nightingale 162*bf21cd93STycho Nightingale static struct termios tio_orig, tio_new; /* I/O Terminals */ 163*bf21cd93STycho Nightingale 164*bf21cd93STycho Nightingale static void 165*bf21cd93STycho Nightingale ttyclose(void) 166*bf21cd93STycho Nightingale { 167*bf21cd93STycho Nightingale 168*bf21cd93STycho Nightingale tcsetattr(STDIN_FILENO, TCSANOW, &tio_orig); 169*bf21cd93STycho Nightingale } 170*bf21cd93STycho Nightingale 171*bf21cd93STycho Nightingale static void 172*bf21cd93STycho Nightingale ttyopen(void) 173*bf21cd93STycho Nightingale { 174*bf21cd93STycho Nightingale 175*bf21cd93STycho Nightingale tcgetattr(STDIN_FILENO, &tio_orig); 176*bf21cd93STycho Nightingale 177*bf21cd93STycho Nightingale tio_new = tio_orig; 178*bf21cd93STycho Nightingale cfmakeraw(&tio_new); 179*bf21cd93STycho Nightingale tcsetattr(STDIN_FILENO, TCSANOW, &tio_new); 180*bf21cd93STycho Nightingale 181*bf21cd93STycho Nightingale atexit(ttyclose); 182*bf21cd93STycho Nightingale } 183*bf21cd93STycho Nightingale 184*bf21cd93STycho Nightingale static bool 185*bf21cd93STycho Nightingale tty_char_available(void) 186*bf21cd93STycho Nightingale { 187*bf21cd93STycho Nightingale fd_set rfds; 188*bf21cd93STycho Nightingale struct timeval tv; 189*bf21cd93STycho Nightingale 190*bf21cd93STycho Nightingale FD_ZERO(&rfds); 191*bf21cd93STycho Nightingale FD_SET(STDIN_FILENO, &rfds); 192*bf21cd93STycho Nightingale tv.tv_sec = 0; 193*bf21cd93STycho Nightingale tv.tv_usec = 0; 194*bf21cd93STycho Nightingale if (select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) > 0 ) { 195*bf21cd93STycho Nightingale return (true); 196*bf21cd93STycho Nightingale } else { 197*bf21cd93STycho Nightingale return (false); 198*bf21cd93STycho Nightingale } 199*bf21cd93STycho Nightingale } 200*bf21cd93STycho Nightingale 201*bf21cd93STycho Nightingale static int 202*bf21cd93STycho Nightingale ttyread(void) 203*bf21cd93STycho Nightingale { 204*bf21cd93STycho Nightingale char rb; 205*bf21cd93STycho Nightingale 206*bf21cd93STycho Nightingale if (tty_char_available()) { 207*bf21cd93STycho Nightingale read(STDIN_FILENO, &rb, 1); 208*bf21cd93STycho Nightingale return (rb & 0xff); 209*bf21cd93STycho Nightingale } else { 210*bf21cd93STycho Nightingale return (-1); 211*bf21cd93STycho Nightingale } 212*bf21cd93STycho Nightingale } 213*bf21cd93STycho Nightingale 214*bf21cd93STycho Nightingale static void 215*bf21cd93STycho Nightingale ttywrite(unsigned char wb) 216*bf21cd93STycho Nightingale { 217*bf21cd93STycho Nightingale 218*bf21cd93STycho Nightingale (void)write(STDIN_FILENO, &wb, 1); 219*bf21cd93STycho Nightingale } 220*bf21cd93STycho Nightingale 221*bf21cd93STycho Nightingale #ifndef __FreeBSD__ 222*bf21cd93STycho Nightingale static void 223*bf21cd93STycho Nightingale bconswrite(struct uart_softc *sc, unsigned char wb) 224*bf21cd93STycho Nightingale { 225*bf21cd93STycho Nightingale (void) write(sc->usc_bcons.clifd, &wb, 1); 226*bf21cd93STycho Nightingale } 227*bf21cd93STycho Nightingale #endif 228*bf21cd93STycho Nightingale 229*bf21cd93STycho Nightingale static void 230*bf21cd93STycho Nightingale fifo_reset(struct fifo *fifo, int size) 231*bf21cd93STycho Nightingale { 232*bf21cd93STycho Nightingale bzero(fifo, sizeof(struct fifo)); 233*bf21cd93STycho Nightingale fifo->size = size; 234*bf21cd93STycho Nightingale } 235*bf21cd93STycho Nightingale 236*bf21cd93STycho Nightingale static int 237*bf21cd93STycho Nightingale fifo_putchar(struct fifo *fifo, uint8_t ch) 238*bf21cd93STycho Nightingale { 239*bf21cd93STycho Nightingale 240*bf21cd93STycho Nightingale if (fifo->num < fifo->size) { 241*bf21cd93STycho Nightingale fifo->buf[fifo->windex] = ch; 242*bf21cd93STycho Nightingale fifo->windex = (fifo->windex + 1) % fifo->size; 243*bf21cd93STycho Nightingale fifo->num++; 244*bf21cd93STycho Nightingale return (0); 245*bf21cd93STycho Nightingale } else 246*bf21cd93STycho Nightingale return (-1); 247*bf21cd93STycho Nightingale } 248*bf21cd93STycho Nightingale 249*bf21cd93STycho Nightingale static int 250*bf21cd93STycho Nightingale fifo_getchar(struct fifo *fifo) 251*bf21cd93STycho Nightingale { 252*bf21cd93STycho Nightingale int c; 253*bf21cd93STycho Nightingale 254*bf21cd93STycho Nightingale if (fifo->num > 0) { 255*bf21cd93STycho Nightingale c = fifo->buf[fifo->rindex]; 256*bf21cd93STycho Nightingale fifo->rindex = (fifo->rindex + 1) % fifo->size; 257*bf21cd93STycho Nightingale fifo->num--; 258*bf21cd93STycho Nightingale return (c); 259*bf21cd93STycho Nightingale } else 260*bf21cd93STycho Nightingale return (-1); 261*bf21cd93STycho Nightingale } 262*bf21cd93STycho Nightingale 263*bf21cd93STycho Nightingale static int 264*bf21cd93STycho Nightingale fifo_numchars(struct fifo *fifo) 265*bf21cd93STycho Nightingale { 266*bf21cd93STycho Nightingale 267*bf21cd93STycho Nightingale return (fifo->num); 268*bf21cd93STycho Nightingale } 269*bf21cd93STycho Nightingale 270*bf21cd93STycho Nightingale static int 271*bf21cd93STycho Nightingale fifo_available(struct fifo *fifo) 272*bf21cd93STycho Nightingale { 273*bf21cd93STycho Nightingale 274*bf21cd93STycho Nightingale return (fifo->num < fifo->size); 275*bf21cd93STycho Nightingale } 276*bf21cd93STycho Nightingale 277*bf21cd93STycho Nightingale static void 278*bf21cd93STycho Nightingale uart_opentty(struct uart_softc *sc) 279*bf21cd93STycho Nightingale { 280*bf21cd93STycho Nightingale struct mevent *mev; 281*bf21cd93STycho Nightingale 282*bf21cd93STycho Nightingale assert(!sc->opened && sc->stdio); 283*bf21cd93STycho Nightingale 284*bf21cd93STycho Nightingale ttyopen(); 285*bf21cd93STycho Nightingale #ifdef __FreeBSD__ 286*bf21cd93STycho Nightingale mev = mevent_add(STDIN_FILENO, EVF_READ, uart_drain, sc); 287*bf21cd93STycho Nightingale #endif 288*bf21cd93STycho Nightingale assert(mev); 289*bf21cd93STycho Nightingale } 290*bf21cd93STycho Nightingale 291*bf21cd93STycho Nightingale /* 292*bf21cd93STycho Nightingale * The IIR returns a prioritized interrupt reason: 293*bf21cd93STycho Nightingale * - receive data available 294*bf21cd93STycho Nightingale * - transmit holding register empty 295*bf21cd93STycho Nightingale * - modem status change 296*bf21cd93STycho Nightingale * 297*bf21cd93STycho Nightingale * Return an interrupt reason if one is available. 298*bf21cd93STycho Nightingale */ 299*bf21cd93STycho Nightingale static int 300*bf21cd93STycho Nightingale uart_intr_reason(struct uart_softc *sc) 301*bf21cd93STycho Nightingale { 302*bf21cd93STycho Nightingale 303*bf21cd93STycho Nightingale if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0) 304*bf21cd93STycho Nightingale return (IIR_RLS); 305*bf21cd93STycho Nightingale else if (fifo_numchars(&sc->rxfifo) > 0 && (sc->ier & IER_ERXRDY) != 0) 306*bf21cd93STycho Nightingale return (IIR_RXTOUT); 307*bf21cd93STycho Nightingale else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0) 308*bf21cd93STycho Nightingale return (IIR_TXRDY); 309*bf21cd93STycho Nightingale else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0) 310*bf21cd93STycho Nightingale return (IIR_MLSC); 311*bf21cd93STycho Nightingale else 312*bf21cd93STycho Nightingale return (IIR_NOPEND); 313*bf21cd93STycho Nightingale } 314*bf21cd93STycho Nightingale 315*bf21cd93STycho Nightingale static void 316*bf21cd93STycho Nightingale uart_reset(struct uart_softc *sc) 317*bf21cd93STycho Nightingale { 318*bf21cd93STycho Nightingale uint16_t divisor; 319*bf21cd93STycho Nightingale 320*bf21cd93STycho Nightingale divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16; 321*bf21cd93STycho Nightingale sc->dll = divisor; 322*bf21cd93STycho Nightingale sc->dlh = divisor >> 16; 323*bf21cd93STycho Nightingale 324*bf21cd93STycho Nightingale fifo_reset(&sc->rxfifo, 1); /* no fifo until enabled by software */ 325*bf21cd93STycho Nightingale } 326*bf21cd93STycho Nightingale 327*bf21cd93STycho Nightingale /* 328*bf21cd93STycho Nightingale * Toggle the COM port's intr pin depending on whether or not we have an 329*bf21cd93STycho Nightingale * interrupt condition to report to the processor. 330*bf21cd93STycho Nightingale */ 331*bf21cd93STycho Nightingale static void 332*bf21cd93STycho Nightingale uart_toggle_intr(struct uart_softc *sc) 333*bf21cd93STycho Nightingale { 334*bf21cd93STycho Nightingale uint8_t intr_reason; 335*bf21cd93STycho Nightingale 336*bf21cd93STycho Nightingale intr_reason = uart_intr_reason(sc); 337*bf21cd93STycho Nightingale 338*bf21cd93STycho Nightingale if (intr_reason == IIR_NOPEND) 339*bf21cd93STycho Nightingale (*sc->intr_deassert)(sc->arg); 340*bf21cd93STycho Nightingale else 341*bf21cd93STycho Nightingale (*sc->intr_assert)(sc->arg); 342*bf21cd93STycho Nightingale } 343*bf21cd93STycho Nightingale 344*bf21cd93STycho Nightingale #ifdef __FreeBSD__ 345*bf21cd93STycho Nightingale static void 346*bf21cd93STycho Nightingale uart_drain(int fd, enum ev_type ev, void *arg) 347*bf21cd93STycho Nightingale { 348*bf21cd93STycho Nightingale struct uart_softc *sc; 349*bf21cd93STycho Nightingale int ch; 350*bf21cd93STycho Nightingale 351*bf21cd93STycho Nightingale sc = arg; 352*bf21cd93STycho Nightingale 353*bf21cd93STycho Nightingale assert(fd == STDIN_FILENO); 354*bf21cd93STycho Nightingale assert(ev == EVF_READ); 355*bf21cd93STycho Nightingale 356*bf21cd93STycho Nightingale /* 357*bf21cd93STycho Nightingale * This routine is called in the context of the mevent thread 358*bf21cd93STycho Nightingale * to take out the softc lock to protect against concurrent 359*bf21cd93STycho Nightingale * access from a vCPU i/o exit 360*bf21cd93STycho Nightingale */ 361*bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 362*bf21cd93STycho Nightingale 363*bf21cd93STycho Nightingale if ((sc->mcr & MCR_LOOPBACK) != 0) { 364*bf21cd93STycho Nightingale (void) ttyread(); 365*bf21cd93STycho Nightingale } else { 366*bf21cd93STycho Nightingale while (fifo_available(&sc->rxfifo) && 367*bf21cd93STycho Nightingale ((ch = ttyread()) != -1)) { 368*bf21cd93STycho Nightingale fifo_putchar(&sc->rxfifo, ch); 369*bf21cd93STycho Nightingale } 370*bf21cd93STycho Nightingale uart_toggle_intr(sc); 371*bf21cd93STycho Nightingale } 372*bf21cd93STycho Nightingale 373*bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 374*bf21cd93STycho Nightingale } 375*bf21cd93STycho Nightingale #else 376*bf21cd93STycho Nightingale static void 377*bf21cd93STycho Nightingale uart_tty_drain(struct uart_softc *sc) 378*bf21cd93STycho Nightingale { 379*bf21cd93STycho Nightingale int ch; 380*bf21cd93STycho Nightingale 381*bf21cd93STycho Nightingale /* 382*bf21cd93STycho Nightingale * Take the softc lock to protect against concurrent 383*bf21cd93STycho Nightingale * access from a vCPU i/o exit 384*bf21cd93STycho Nightingale */ 385*bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 386*bf21cd93STycho Nightingale 387*bf21cd93STycho Nightingale if ((sc->mcr & MCR_LOOPBACK) != 0) { 388*bf21cd93STycho Nightingale (void) ttyread(); 389*bf21cd93STycho Nightingale } else { 390*bf21cd93STycho Nightingale while (fifo_available(&sc->rxfifo) && 391*bf21cd93STycho Nightingale ((ch = ttyread()) != -1)) { 392*bf21cd93STycho Nightingale fifo_putchar(&sc->rxfifo, ch); 393*bf21cd93STycho Nightingale } 394*bf21cd93STycho Nightingale uart_toggle_intr(sc); 395*bf21cd93STycho Nightingale } 396*bf21cd93STycho Nightingale 397*bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 398*bf21cd93STycho Nightingale } 399*bf21cd93STycho Nightingale 400*bf21cd93STycho Nightingale static int 401*bf21cd93STycho Nightingale uart_bcons_drain(struct uart_softc *sc) 402*bf21cd93STycho Nightingale { 403*bf21cd93STycho Nightingale char ch; 404*bf21cd93STycho Nightingale int nbytes; 405*bf21cd93STycho Nightingale int ret = 0; 406*bf21cd93STycho Nightingale 407*bf21cd93STycho Nightingale /* 408*bf21cd93STycho Nightingale * Take the softc lock to protect against concurrent 409*bf21cd93STycho Nightingale * access from a vCPU i/o exit 410*bf21cd93STycho Nightingale */ 411*bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 412*bf21cd93STycho Nightingale 413*bf21cd93STycho Nightingale if ((sc->mcr & MCR_LOOPBACK) != 0) { 414*bf21cd93STycho Nightingale (void) read(sc->usc_bcons.clifd, &ch, 1); 415*bf21cd93STycho Nightingale } else { 416*bf21cd93STycho Nightingale for (;;) { 417*bf21cd93STycho Nightingale nbytes = read(sc->usc_bcons.clifd, &ch, 1); 418*bf21cd93STycho Nightingale if (nbytes == 0) { 419*bf21cd93STycho Nightingale ret = 1; 420*bf21cd93STycho Nightingale break; 421*bf21cd93STycho Nightingale } 422*bf21cd93STycho Nightingale if (nbytes == -1 && 423*bf21cd93STycho Nightingale errno != EINTR && errno != EAGAIN) { 424*bf21cd93STycho Nightingale ret = -1; 425*bf21cd93STycho Nightingale break; 426*bf21cd93STycho Nightingale } 427*bf21cd93STycho Nightingale if (nbytes == -1) { 428*bf21cd93STycho Nightingale break; 429*bf21cd93STycho Nightingale } 430*bf21cd93STycho Nightingale 431*bf21cd93STycho Nightingale if (fifo_available(&sc->rxfifo)) { 432*bf21cd93STycho Nightingale fifo_putchar(&sc->rxfifo, ch); 433*bf21cd93STycho Nightingale } 434*bf21cd93STycho Nightingale } 435*bf21cd93STycho Nightingale uart_toggle_intr(sc); 436*bf21cd93STycho Nightingale } 437*bf21cd93STycho Nightingale 438*bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 439*bf21cd93STycho Nightingale 440*bf21cd93STycho Nightingale return (ret); 441*bf21cd93STycho Nightingale } 442*bf21cd93STycho Nightingale #endif 443*bf21cd93STycho Nightingale 444*bf21cd93STycho Nightingale void 445*bf21cd93STycho Nightingale uart_write(struct uart_softc *sc, int offset, uint8_t value) 446*bf21cd93STycho Nightingale { 447*bf21cd93STycho Nightingale int fifosz; 448*bf21cd93STycho Nightingale uint8_t msr; 449*bf21cd93STycho Nightingale 450*bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 451*bf21cd93STycho Nightingale 452*bf21cd93STycho Nightingale /* Open terminal */ 453*bf21cd93STycho Nightingale if (!sc->opened && sc->stdio) { 454*bf21cd93STycho Nightingale uart_opentty(sc); 455*bf21cd93STycho Nightingale sc->opened = true; 456*bf21cd93STycho Nightingale } 457*bf21cd93STycho Nightingale 458*bf21cd93STycho Nightingale /* 459*bf21cd93STycho Nightingale * Take care of the special case DLAB accesses first 460*bf21cd93STycho Nightingale */ 461*bf21cd93STycho Nightingale if ((sc->lcr & LCR_DLAB) != 0) { 462*bf21cd93STycho Nightingale if (offset == REG_DLL) { 463*bf21cd93STycho Nightingale sc->dll = value; 464*bf21cd93STycho Nightingale goto done; 465*bf21cd93STycho Nightingale } 466*bf21cd93STycho Nightingale 467*bf21cd93STycho Nightingale if (offset == REG_DLH) { 468*bf21cd93STycho Nightingale sc->dlh = value; 469*bf21cd93STycho Nightingale goto done; 470*bf21cd93STycho Nightingale } 471*bf21cd93STycho Nightingale } 472*bf21cd93STycho Nightingale 473*bf21cd93STycho Nightingale switch (offset) { 474*bf21cd93STycho Nightingale case REG_DATA: 475*bf21cd93STycho Nightingale if (sc->mcr & MCR_LOOPBACK) { 476*bf21cd93STycho Nightingale if (fifo_putchar(&sc->rxfifo, value) != 0) 477*bf21cd93STycho Nightingale sc->lsr |= LSR_OE; 478*bf21cd93STycho Nightingale } else if (sc->stdio) { 479*bf21cd93STycho Nightingale ttywrite(value); 480*bf21cd93STycho Nightingale #ifndef __FreeBSD__ 481*bf21cd93STycho Nightingale } else if (sc->bcons) { 482*bf21cd93STycho Nightingale bconswrite(sc, value); 483*bf21cd93STycho Nightingale #endif 484*bf21cd93STycho Nightingale } /* else drop on floor */ 485*bf21cd93STycho Nightingale sc->thre_int_pending = true; 486*bf21cd93STycho Nightingale break; 487*bf21cd93STycho Nightingale case REG_IER: 488*bf21cd93STycho Nightingale /* 489*bf21cd93STycho Nightingale * Apply mask so that bits 4-7 are 0 490*bf21cd93STycho Nightingale * Also enables bits 0-3 only if they're 1 491*bf21cd93STycho Nightingale */ 492*bf21cd93STycho Nightingale sc->ier = value & 0x0F; 493*bf21cd93STycho Nightingale break; 494*bf21cd93STycho Nightingale case REG_FCR: 495*bf21cd93STycho Nightingale /* 496*bf21cd93STycho Nightingale * When moving from FIFO and 16450 mode and vice versa, 497*bf21cd93STycho Nightingale * the FIFO contents are reset. 498*bf21cd93STycho Nightingale */ 499*bf21cd93STycho Nightingale if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) { 500*bf21cd93STycho Nightingale fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1; 501*bf21cd93STycho Nightingale fifo_reset(&sc->rxfifo, fifosz); 502*bf21cd93STycho Nightingale } 503*bf21cd93STycho Nightingale 504*bf21cd93STycho Nightingale /* 505*bf21cd93STycho Nightingale * The FCR_ENABLE bit must be '1' for the programming 506*bf21cd93STycho Nightingale * of other FCR bits to be effective. 507*bf21cd93STycho Nightingale */ 508*bf21cd93STycho Nightingale if ((value & FCR_ENABLE) == 0) { 509*bf21cd93STycho Nightingale sc->fcr = 0; 510*bf21cd93STycho Nightingale } else { 511*bf21cd93STycho Nightingale if ((value & FCR_RCV_RST) != 0) 512*bf21cd93STycho Nightingale fifo_reset(&sc->rxfifo, FIFOSZ); 513*bf21cd93STycho Nightingale 514*bf21cd93STycho Nightingale sc->fcr = value & 515*bf21cd93STycho Nightingale (FCR_ENABLE | FCR_DMA | FCR_RX_MASK); 516*bf21cd93STycho Nightingale } 517*bf21cd93STycho Nightingale break; 518*bf21cd93STycho Nightingale case REG_LCR: 519*bf21cd93STycho Nightingale sc->lcr = value; 520*bf21cd93STycho Nightingale break; 521*bf21cd93STycho Nightingale case REG_MCR: 522*bf21cd93STycho Nightingale /* Apply mask so that bits 5-7 are 0 */ 523*bf21cd93STycho Nightingale sc->mcr = value & 0x1F; 524*bf21cd93STycho Nightingale 525*bf21cd93STycho Nightingale msr = 0; 526*bf21cd93STycho Nightingale if (sc->mcr & MCR_LOOPBACK) { 527*bf21cd93STycho Nightingale /* 528*bf21cd93STycho Nightingale * In the loopback mode certain bits from the 529*bf21cd93STycho Nightingale * MCR are reflected back into MSR 530*bf21cd93STycho Nightingale */ 531*bf21cd93STycho Nightingale if (sc->mcr & MCR_RTS) 532*bf21cd93STycho Nightingale msr |= MSR_CTS; 533*bf21cd93STycho Nightingale if (sc->mcr & MCR_DTR) 534*bf21cd93STycho Nightingale msr |= MSR_DSR; 535*bf21cd93STycho Nightingale if (sc->mcr & MCR_OUT1) 536*bf21cd93STycho Nightingale msr |= MSR_RI; 537*bf21cd93STycho Nightingale if (sc->mcr & MCR_OUT2) 538*bf21cd93STycho Nightingale msr |= MSR_DCD; 539*bf21cd93STycho Nightingale } 540*bf21cd93STycho Nightingale 541*bf21cd93STycho Nightingale /* 542*bf21cd93STycho Nightingale * Detect if there has been any change between the 543*bf21cd93STycho Nightingale * previous and the new value of MSR. If there is 544*bf21cd93STycho Nightingale * then assert the appropriate MSR delta bit. 545*bf21cd93STycho Nightingale */ 546*bf21cd93STycho Nightingale if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS)) 547*bf21cd93STycho Nightingale sc->msr |= MSR_DCTS; 548*bf21cd93STycho Nightingale if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR)) 549*bf21cd93STycho Nightingale sc->msr |= MSR_DDSR; 550*bf21cd93STycho Nightingale if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD)) 551*bf21cd93STycho Nightingale sc->msr |= MSR_DDCD; 552*bf21cd93STycho Nightingale if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0) 553*bf21cd93STycho Nightingale sc->msr |= MSR_TERI; 554*bf21cd93STycho Nightingale 555*bf21cd93STycho Nightingale /* 556*bf21cd93STycho Nightingale * Update the value of MSR while retaining the delta 557*bf21cd93STycho Nightingale * bits. 558*bf21cd93STycho Nightingale */ 559*bf21cd93STycho Nightingale sc->msr &= MSR_DELTA_MASK; 560*bf21cd93STycho Nightingale sc->msr |= msr; 561*bf21cd93STycho Nightingale break; 562*bf21cd93STycho Nightingale case REG_LSR: 563*bf21cd93STycho Nightingale /* 564*bf21cd93STycho Nightingale * Line status register is not meant to be written to 565*bf21cd93STycho Nightingale * during normal operation. 566*bf21cd93STycho Nightingale */ 567*bf21cd93STycho Nightingale break; 568*bf21cd93STycho Nightingale case REG_MSR: 569*bf21cd93STycho Nightingale /* 570*bf21cd93STycho Nightingale * As far as I can tell MSR is a read-only register. 571*bf21cd93STycho Nightingale */ 572*bf21cd93STycho Nightingale break; 573*bf21cd93STycho Nightingale case REG_SCR: 574*bf21cd93STycho Nightingale sc->scr = value; 575*bf21cd93STycho Nightingale break; 576*bf21cd93STycho Nightingale default: 577*bf21cd93STycho Nightingale break; 578*bf21cd93STycho Nightingale } 579*bf21cd93STycho Nightingale 580*bf21cd93STycho Nightingale done: 581*bf21cd93STycho Nightingale uart_toggle_intr(sc); 582*bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 583*bf21cd93STycho Nightingale } 584*bf21cd93STycho Nightingale 585*bf21cd93STycho Nightingale uint8_t 586*bf21cd93STycho Nightingale uart_read(struct uart_softc *sc, int offset) 587*bf21cd93STycho Nightingale { 588*bf21cd93STycho Nightingale uint8_t iir, intr_reason, reg; 589*bf21cd93STycho Nightingale 590*bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 591*bf21cd93STycho Nightingale 592*bf21cd93STycho Nightingale /* Open terminal */ 593*bf21cd93STycho Nightingale if (!sc->opened && sc->stdio) { 594*bf21cd93STycho Nightingale uart_opentty(sc); 595*bf21cd93STycho Nightingale sc->opened = true; 596*bf21cd93STycho Nightingale } 597*bf21cd93STycho Nightingale 598*bf21cd93STycho Nightingale /* 599*bf21cd93STycho Nightingale * Take care of the special case DLAB accesses first 600*bf21cd93STycho Nightingale */ 601*bf21cd93STycho Nightingale if ((sc->lcr & LCR_DLAB) != 0) { 602*bf21cd93STycho Nightingale if (offset == REG_DLL) { 603*bf21cd93STycho Nightingale reg = sc->dll; 604*bf21cd93STycho Nightingale goto done; 605*bf21cd93STycho Nightingale } 606*bf21cd93STycho Nightingale 607*bf21cd93STycho Nightingale if (offset == REG_DLH) { 608*bf21cd93STycho Nightingale reg = sc->dlh; 609*bf21cd93STycho Nightingale goto done; 610*bf21cd93STycho Nightingale } 611*bf21cd93STycho Nightingale } 612*bf21cd93STycho Nightingale 613*bf21cd93STycho Nightingale switch (offset) { 614*bf21cd93STycho Nightingale case REG_DATA: 615*bf21cd93STycho Nightingale reg = fifo_getchar(&sc->rxfifo); 616*bf21cd93STycho Nightingale break; 617*bf21cd93STycho Nightingale case REG_IER: 618*bf21cd93STycho Nightingale reg = sc->ier; 619*bf21cd93STycho Nightingale break; 620*bf21cd93STycho Nightingale case REG_IIR: 621*bf21cd93STycho Nightingale iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0; 622*bf21cd93STycho Nightingale 623*bf21cd93STycho Nightingale intr_reason = uart_intr_reason(sc); 624*bf21cd93STycho Nightingale 625*bf21cd93STycho Nightingale /* 626*bf21cd93STycho Nightingale * Deal with side effects of reading the IIR register 627*bf21cd93STycho Nightingale */ 628*bf21cd93STycho Nightingale if (intr_reason == IIR_TXRDY) 629*bf21cd93STycho Nightingale sc->thre_int_pending = false; 630*bf21cd93STycho Nightingale 631*bf21cd93STycho Nightingale iir |= intr_reason; 632*bf21cd93STycho Nightingale 633*bf21cd93STycho Nightingale reg = iir; 634*bf21cd93STycho Nightingale break; 635*bf21cd93STycho Nightingale case REG_LCR: 636*bf21cd93STycho Nightingale reg = sc->lcr; 637*bf21cd93STycho Nightingale break; 638*bf21cd93STycho Nightingale case REG_MCR: 639*bf21cd93STycho Nightingale reg = sc->mcr; 640*bf21cd93STycho Nightingale break; 641*bf21cd93STycho Nightingale case REG_LSR: 642*bf21cd93STycho Nightingale /* Transmitter is always ready for more data */ 643*bf21cd93STycho Nightingale sc->lsr |= LSR_TEMT | LSR_THRE; 644*bf21cd93STycho Nightingale 645*bf21cd93STycho Nightingale /* Check for new receive data */ 646*bf21cd93STycho Nightingale if (fifo_numchars(&sc->rxfifo) > 0) 647*bf21cd93STycho Nightingale sc->lsr |= LSR_RXRDY; 648*bf21cd93STycho Nightingale else 649*bf21cd93STycho Nightingale sc->lsr &= ~LSR_RXRDY; 650*bf21cd93STycho Nightingale 651*bf21cd93STycho Nightingale reg = sc->lsr; 652*bf21cd93STycho Nightingale 653*bf21cd93STycho Nightingale /* The LSR_OE bit is cleared on LSR read */ 654*bf21cd93STycho Nightingale sc->lsr &= ~LSR_OE; 655*bf21cd93STycho Nightingale break; 656*bf21cd93STycho Nightingale case REG_MSR: 657*bf21cd93STycho Nightingale /* 658*bf21cd93STycho Nightingale * MSR delta bits are cleared on read 659*bf21cd93STycho Nightingale */ 660*bf21cd93STycho Nightingale reg = sc->msr; 661*bf21cd93STycho Nightingale sc->msr &= ~MSR_DELTA_MASK; 662*bf21cd93STycho Nightingale break; 663*bf21cd93STycho Nightingale case REG_SCR: 664*bf21cd93STycho Nightingale reg = sc->scr; 665*bf21cd93STycho Nightingale break; 666*bf21cd93STycho Nightingale default: 667*bf21cd93STycho Nightingale reg = 0xFF; 668*bf21cd93STycho Nightingale break; 669*bf21cd93STycho Nightingale } 670*bf21cd93STycho Nightingale 671*bf21cd93STycho Nightingale done: 672*bf21cd93STycho Nightingale uart_toggle_intr(sc); 673*bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 674*bf21cd93STycho Nightingale 675*bf21cd93STycho Nightingale return (reg); 676*bf21cd93STycho Nightingale } 677*bf21cd93STycho Nightingale 678*bf21cd93STycho Nightingale #ifndef __FreeBSD__ 679*bf21cd93STycho Nightingale static void * 680*bf21cd93STycho Nightingale uart_tty_thread(void *param) 681*bf21cd93STycho Nightingale { 682*bf21cd93STycho Nightingale struct uart_softc *sc = param; 683*bf21cd93STycho Nightingale pollfd_t pollset; 684*bf21cd93STycho Nightingale 685*bf21cd93STycho Nightingale pollset.fd = STDIN_FILENO; 686*bf21cd93STycho Nightingale pollset.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; 687*bf21cd93STycho Nightingale 688*bf21cd93STycho Nightingale for (;;) { 689*bf21cd93STycho Nightingale if (poll(&pollset, 1, -1) < 0) { 690*bf21cd93STycho Nightingale if (errno != EINTR) { 691*bf21cd93STycho Nightingale perror("poll failed"); 692*bf21cd93STycho Nightingale break; 693*bf21cd93STycho Nightingale } 694*bf21cd93STycho Nightingale continue; 695*bf21cd93STycho Nightingale } 696*bf21cd93STycho Nightingale uart_tty_drain(sc); 697*bf21cd93STycho Nightingale } 698*bf21cd93STycho Nightingale 699*bf21cd93STycho Nightingale return (NULL); 700*bf21cd93STycho Nightingale } 701*bf21cd93STycho Nightingale 702*bf21cd93STycho Nightingale /* 703*bf21cd93STycho Nightingale * Read the "ident" string from the client's descriptor; this routine also 704*bf21cd93STycho Nightingale * tolerates being called with pid=NULL, for times when you want to "eat" 705*bf21cd93STycho Nightingale * the ident string from a client without saving it. 706*bf21cd93STycho Nightingale */ 707*bf21cd93STycho Nightingale static int 708*bf21cd93STycho Nightingale get_client_ident(int clifd, pid_t *pid) 709*bf21cd93STycho Nightingale { 710*bf21cd93STycho Nightingale char buf[BUFSIZ], *bufp; 711*bf21cd93STycho Nightingale size_t buflen = sizeof (buf); 712*bf21cd93STycho Nightingale char c = '\0'; 713*bf21cd93STycho Nightingale int i = 0, r; 714*bf21cd93STycho Nightingale 715*bf21cd93STycho Nightingale /* "eat up the ident string" case, for simplicity */ 716*bf21cd93STycho Nightingale if (pid == NULL) { 717*bf21cd93STycho Nightingale while (read(clifd, &c, 1) == 1) { 718*bf21cd93STycho Nightingale if (c == '\n') 719*bf21cd93STycho Nightingale return (0); 720*bf21cd93STycho Nightingale } 721*bf21cd93STycho Nightingale } 722*bf21cd93STycho Nightingale 723*bf21cd93STycho Nightingale bzero(buf, sizeof (buf)); 724*bf21cd93STycho Nightingale while ((buflen > 1) && (r = read(clifd, &c, 1)) == 1) { 725*bf21cd93STycho Nightingale buflen--; 726*bf21cd93STycho Nightingale if (c == '\n') 727*bf21cd93STycho Nightingale break; 728*bf21cd93STycho Nightingale 729*bf21cd93STycho Nightingale buf[i] = c; 730*bf21cd93STycho Nightingale i++; 731*bf21cd93STycho Nightingale } 732*bf21cd93STycho Nightingale if (r == -1) 733*bf21cd93STycho Nightingale return (-1); 734*bf21cd93STycho Nightingale 735*bf21cd93STycho Nightingale /* 736*bf21cd93STycho Nightingale * We've filled the buffer, but still haven't seen \n. Keep eating 737*bf21cd93STycho Nightingale * until we find it; we don't expect this to happen, but this is 738*bf21cd93STycho Nightingale * defensive. 739*bf21cd93STycho Nightingale */ 740*bf21cd93STycho Nightingale if (c != '\n') { 741*bf21cd93STycho Nightingale while ((r = read(clifd, &c, sizeof (c))) > 0) 742*bf21cd93STycho Nightingale if (c == '\n') 743*bf21cd93STycho Nightingale break; 744*bf21cd93STycho Nightingale } 745*bf21cd93STycho Nightingale 746*bf21cd93STycho Nightingale /* 747*bf21cd93STycho Nightingale * Parse buffer for message of the form: IDENT <pid> 748*bf21cd93STycho Nightingale */ 749*bf21cd93STycho Nightingale bufp = buf; 750*bf21cd93STycho Nightingale if (strncmp(bufp, "IDENT ", 6) != 0) 751*bf21cd93STycho Nightingale return (-1); 752*bf21cd93STycho Nightingale bufp += 6; 753*bf21cd93STycho Nightingale errno = 0; 754*bf21cd93STycho Nightingale *pid = strtoll(bufp, &bufp, 10); 755*bf21cd93STycho Nightingale if (errno != 0) 756*bf21cd93STycho Nightingale return (-1); 757*bf21cd93STycho Nightingale 758*bf21cd93STycho Nightingale return (0); 759*bf21cd93STycho Nightingale } 760*bf21cd93STycho Nightingale 761*bf21cd93STycho Nightingale static int 762*bf21cd93STycho Nightingale uart_bcons_accept_client(struct uart_softc *sc) 763*bf21cd93STycho Nightingale { 764*bf21cd93STycho Nightingale int connfd; 765*bf21cd93STycho Nightingale struct sockaddr_un cliaddr; 766*bf21cd93STycho Nightingale socklen_t clilen; 767*bf21cd93STycho Nightingale pid_t pid; 768*bf21cd93STycho Nightingale 769*bf21cd93STycho Nightingale clilen = sizeof (cliaddr); 770*bf21cd93STycho Nightingale connfd = accept(sc->usc_bcons.servfd, 771*bf21cd93STycho Nightingale (struct sockaddr *)&cliaddr, &clilen); 772*bf21cd93STycho Nightingale if (connfd == -1) 773*bf21cd93STycho Nightingale return (-1); 774*bf21cd93STycho Nightingale if (get_client_ident(connfd, &pid) == -1) { 775*bf21cd93STycho Nightingale (void) shutdown(connfd, SHUT_RDWR); 776*bf21cd93STycho Nightingale (void) close(connfd); 777*bf21cd93STycho Nightingale return (-1); 778*bf21cd93STycho Nightingale } 779*bf21cd93STycho Nightingale 780*bf21cd93STycho Nightingale if (fcntl(connfd, F_SETFL, O_NONBLOCK) < 0) { 781*bf21cd93STycho Nightingale (void) shutdown(connfd, SHUT_RDWR); 782*bf21cd93STycho Nightingale (void) close(connfd); 783*bf21cd93STycho Nightingale return (-1); 784*bf21cd93STycho Nightingale } 785*bf21cd93STycho Nightingale (void) write(connfd, "OK\n", 3); 786*bf21cd93STycho Nightingale 787*bf21cd93STycho Nightingale sc->usc_bcons.clipid = pid; 788*bf21cd93STycho Nightingale sc->usc_bcons.clifd = connfd; 789*bf21cd93STycho Nightingale 790*bf21cd93STycho Nightingale printf("Connection from process ID %lu.\n", pid); 791*bf21cd93STycho Nightingale 792*bf21cd93STycho Nightingale return (0); 793*bf21cd93STycho Nightingale } 794*bf21cd93STycho Nightingale 795*bf21cd93STycho Nightingale static void 796*bf21cd93STycho Nightingale uart_bcons_reject_client(struct uart_softc *sc) 797*bf21cd93STycho Nightingale { 798*bf21cd93STycho Nightingale int connfd; 799*bf21cd93STycho Nightingale struct sockaddr_un cliaddr; 800*bf21cd93STycho Nightingale socklen_t clilen; 801*bf21cd93STycho Nightingale char nak[MAXPATHLEN]; 802*bf21cd93STycho Nightingale 803*bf21cd93STycho Nightingale clilen = sizeof (cliaddr); 804*bf21cd93STycho Nightingale connfd = accept(sc->usc_bcons.servfd, 805*bf21cd93STycho Nightingale (struct sockaddr *)&cliaddr, &clilen); 806*bf21cd93STycho Nightingale 807*bf21cd93STycho Nightingale /* 808*bf21cd93STycho Nightingale * After hear its ident string, tell client to get lost. 809*bf21cd93STycho Nightingale */ 810*bf21cd93STycho Nightingale if (get_client_ident(connfd, NULL) == 0) { 811*bf21cd93STycho Nightingale (void) snprintf(nak, sizeof (nak), "%lu\n", 812*bf21cd93STycho Nightingale sc->usc_bcons.clipid); 813*bf21cd93STycho Nightingale (void) write(connfd, nak, strlen(nak)); 814*bf21cd93STycho Nightingale } 815*bf21cd93STycho Nightingale (void) shutdown(connfd, SHUT_RDWR); 816*bf21cd93STycho Nightingale (void) close(connfd); 817*bf21cd93STycho Nightingale } 818*bf21cd93STycho Nightingale 819*bf21cd93STycho Nightingale static int 820*bf21cd93STycho Nightingale uart_bcons_client_event(struct uart_softc *sc) 821*bf21cd93STycho Nightingale { 822*bf21cd93STycho Nightingale int res; 823*bf21cd93STycho Nightingale 824*bf21cd93STycho Nightingale res = uart_bcons_drain(sc); 825*bf21cd93STycho Nightingale if (res < 0) 826*bf21cd93STycho Nightingale return (-1); 827*bf21cd93STycho Nightingale 828*bf21cd93STycho Nightingale if (res > 0) { 829*bf21cd93STycho Nightingale fprintf(stderr, "Closing connection with bhyve console\n"); 830*bf21cd93STycho Nightingale (void) shutdown(sc->usc_bcons.clifd, SHUT_RDWR); 831*bf21cd93STycho Nightingale (void) close(sc->usc_bcons.clifd); 832*bf21cd93STycho Nightingale sc->usc_bcons.clifd = -1; 833*bf21cd93STycho Nightingale } 834*bf21cd93STycho Nightingale 835*bf21cd93STycho Nightingale return (0); 836*bf21cd93STycho Nightingale } 837*bf21cd93STycho Nightingale 838*bf21cd93STycho Nightingale static void 839*bf21cd93STycho Nightingale uart_bcons_server_event(struct uart_softc *sc) 840*bf21cd93STycho Nightingale { 841*bf21cd93STycho Nightingale int clifd; 842*bf21cd93STycho Nightingale 843*bf21cd93STycho Nightingale if (sc->usc_bcons.clifd != -1) { 844*bf21cd93STycho Nightingale /* we're already handling a client */ 845*bf21cd93STycho Nightingale uart_bcons_reject_client(sc); 846*bf21cd93STycho Nightingale return; 847*bf21cd93STycho Nightingale } 848*bf21cd93STycho Nightingale 849*bf21cd93STycho Nightingale if (uart_bcons_accept_client(sc) == 0) { 850*bf21cd93STycho Nightingale pthread_mutex_lock(&bcons_wait_lock); 851*bf21cd93STycho Nightingale bcons_connected = B_TRUE; 852*bf21cd93STycho Nightingale pthread_cond_signal(&bcons_wait_done); 853*bf21cd93STycho Nightingale pthread_mutex_unlock(&bcons_wait_lock); 854*bf21cd93STycho Nightingale } 855*bf21cd93STycho Nightingale } 856*bf21cd93STycho Nightingale 857*bf21cd93STycho Nightingale static void * 858*bf21cd93STycho Nightingale uart_bcons_thread(void *param) 859*bf21cd93STycho Nightingale { 860*bf21cd93STycho Nightingale struct uart_softc *sc = param; 861*bf21cd93STycho Nightingale struct pollfd pollfds[2]; 862*bf21cd93STycho Nightingale int res; 863*bf21cd93STycho Nightingale 864*bf21cd93STycho Nightingale /* read from client and write to vm */ 865*bf21cd93STycho Nightingale pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | 866*bf21cd93STycho Nightingale POLLPRI | POLLERR | POLLHUP; 867*bf21cd93STycho Nightingale 868*bf21cd93STycho Nightingale /* the server socket; watch for events (new connections) */ 869*bf21cd93STycho Nightingale pollfds[1].events = pollfds[0].events; 870*bf21cd93STycho Nightingale 871*bf21cd93STycho Nightingale for (;;) { 872*bf21cd93STycho Nightingale pollfds[0].fd = sc->usc_bcons.clifd; 873*bf21cd93STycho Nightingale pollfds[1].fd = sc->usc_bcons.servfd; 874*bf21cd93STycho Nightingale pollfds[0].revents = pollfds[1].revents = 0; 875*bf21cd93STycho Nightingale 876*bf21cd93STycho Nightingale res = poll(pollfds, 877*bf21cd93STycho Nightingale sizeof (pollfds) / sizeof (struct pollfd), -1); 878*bf21cd93STycho Nightingale 879*bf21cd93STycho Nightingale if (res == -1 && errno != EINTR) { 880*bf21cd93STycho Nightingale perror("poll failed"); 881*bf21cd93STycho Nightingale /* we are hosed, close connection */ 882*bf21cd93STycho Nightingale break; 883*bf21cd93STycho Nightingale } 884*bf21cd93STycho Nightingale 885*bf21cd93STycho Nightingale /* event from client side */ 886*bf21cd93STycho Nightingale if (pollfds[0].revents) { 887*bf21cd93STycho Nightingale if (pollfds[0].revents & 888*bf21cd93STycho Nightingale (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) { 889*bf21cd93STycho Nightingale if (uart_bcons_client_event(sc) < 0) 890*bf21cd93STycho Nightingale break; 891*bf21cd93STycho Nightingale } else { 892*bf21cd93STycho Nightingale break; 893*bf21cd93STycho Nightingale } 894*bf21cd93STycho Nightingale } 895*bf21cd93STycho Nightingale 896*bf21cd93STycho Nightingale /* event from server socket */ 897*bf21cd93STycho Nightingale if (pollfds[1].revents) { 898*bf21cd93STycho Nightingale if (pollfds[1].revents & (POLLIN | POLLRDNORM)) { 899*bf21cd93STycho Nightingale uart_bcons_server_event(sc); 900*bf21cd93STycho Nightingale } else { 901*bf21cd93STycho Nightingale break; 902*bf21cd93STycho Nightingale } 903*bf21cd93STycho Nightingale } 904*bf21cd93STycho Nightingale } 905*bf21cd93STycho Nightingale 906*bf21cd93STycho Nightingale if (sc->usc_bcons.clifd != -1) { 907*bf21cd93STycho Nightingale fprintf(stderr, "Closing connection with bhyve console\n"); 908*bf21cd93STycho Nightingale (void) shutdown(sc->usc_bcons.clifd, SHUT_RDWR); 909*bf21cd93STycho Nightingale (void) close(sc->usc_bcons.clifd); 910*bf21cd93STycho Nightingale sc->usc_bcons.clifd = -1; 911*bf21cd93STycho Nightingale } 912*bf21cd93STycho Nightingale 913*bf21cd93STycho Nightingale return (NULL); 914*bf21cd93STycho Nightingale } 915*bf21cd93STycho Nightingale 916*bf21cd93STycho Nightingale static int 917*bf21cd93STycho Nightingale init_bcons_sock(void) 918*bf21cd93STycho Nightingale { 919*bf21cd93STycho Nightingale int servfd; 920*bf21cd93STycho Nightingale struct sockaddr_un servaddr; 921*bf21cd93STycho Nightingale 922*bf21cd93STycho Nightingale if (mkdir(BHYVE_TMPDIR, S_IRWXU) < 0 && errno != EEXIST) { 923*bf21cd93STycho Nightingale fprintf(stderr, "bhyve console setup: " 924*bf21cd93STycho Nightingale "could not mkdir %s", BHYVE_TMPDIR, strerror(errno)); 925*bf21cd93STycho Nightingale return (-1); 926*bf21cd93STycho Nightingale } 927*bf21cd93STycho Nightingale 928*bf21cd93STycho Nightingale bzero(&servaddr, sizeof (servaddr)); 929*bf21cd93STycho Nightingale servaddr.sun_family = AF_UNIX; 930*bf21cd93STycho Nightingale (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path), 931*bf21cd93STycho Nightingale BHYVE_CONS_SOCKPATH, vmname); 932*bf21cd93STycho Nightingale 933*bf21cd93STycho Nightingale if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 934*bf21cd93STycho Nightingale fprintf(stderr, "bhyve console setup: " 935*bf21cd93STycho Nightingale "could not create socket\n"); 936*bf21cd93STycho Nightingale return (-1); 937*bf21cd93STycho Nightingale } 938*bf21cd93STycho Nightingale (void) unlink(servaddr.sun_path); 939*bf21cd93STycho Nightingale 940*bf21cd93STycho Nightingale if (bind(servfd, (struct sockaddr *)&servaddr, 941*bf21cd93STycho Nightingale sizeof (servaddr)) == -1) { 942*bf21cd93STycho Nightingale fprintf(stderr, "bhyve console setup: " 943*bf21cd93STycho Nightingale "could not bind to socket\n"); 944*bf21cd93STycho Nightingale goto out; 945*bf21cd93STycho Nightingale } 946*bf21cd93STycho Nightingale 947*bf21cd93STycho Nightingale if (listen(servfd, 4) == -1) { 948*bf21cd93STycho Nightingale fprintf(stderr, "bhyve console setup: " 949*bf21cd93STycho Nightingale "could not listen on socket"); 950*bf21cd93STycho Nightingale goto out; 951*bf21cd93STycho Nightingale } 952*bf21cd93STycho Nightingale return (servfd); 953*bf21cd93STycho Nightingale 954*bf21cd93STycho Nightingale out: 955*bf21cd93STycho Nightingale (void) unlink(servaddr.sun_path); 956*bf21cd93STycho Nightingale (void) close(servfd); 957*bf21cd93STycho Nightingale return (-1); 958*bf21cd93STycho Nightingale } 959*bf21cd93STycho Nightingale #endif 960*bf21cd93STycho Nightingale 961*bf21cd93STycho Nightingale int 962*bf21cd93STycho Nightingale uart_legacy_alloc(int which, int *baseaddr, int *irq) 963*bf21cd93STycho Nightingale { 964*bf21cd93STycho Nightingale 965*bf21cd93STycho Nightingale if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse) 966*bf21cd93STycho Nightingale return (-1); 967*bf21cd93STycho Nightingale 968*bf21cd93STycho Nightingale uart_lres[which].inuse = true; 969*bf21cd93STycho Nightingale *baseaddr = uart_lres[which].baseaddr; 970*bf21cd93STycho Nightingale *irq = uart_lres[which].irq; 971*bf21cd93STycho Nightingale 972*bf21cd93STycho Nightingale return (0); 973*bf21cd93STycho Nightingale } 974*bf21cd93STycho Nightingale 975*bf21cd93STycho Nightingale struct uart_softc * 976*bf21cd93STycho Nightingale uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert, 977*bf21cd93STycho Nightingale void *arg) 978*bf21cd93STycho Nightingale { 979*bf21cd93STycho Nightingale struct uart_softc *sc; 980*bf21cd93STycho Nightingale 981*bf21cd93STycho Nightingale sc = malloc(sizeof(struct uart_softc)); 982*bf21cd93STycho Nightingale bzero(sc, sizeof(struct uart_softc)); 983*bf21cd93STycho Nightingale 984*bf21cd93STycho Nightingale sc->arg = arg; 985*bf21cd93STycho Nightingale sc->intr_assert = intr_assert; 986*bf21cd93STycho Nightingale sc->intr_deassert = intr_deassert; 987*bf21cd93STycho Nightingale 988*bf21cd93STycho Nightingale pthread_mutex_init(&sc->mtx, NULL); 989*bf21cd93STycho Nightingale 990*bf21cd93STycho Nightingale uart_reset(sc); 991*bf21cd93STycho Nightingale 992*bf21cd93STycho Nightingale return (sc); 993*bf21cd93STycho Nightingale } 994*bf21cd93STycho Nightingale 995*bf21cd93STycho Nightingale int 996*bf21cd93STycho Nightingale uart_set_backend(struct uart_softc *sc, const char *opts) 997*bf21cd93STycho Nightingale { 998*bf21cd93STycho Nightingale #ifndef __FreeBSD__ 999*bf21cd93STycho Nightingale int error; 1000*bf21cd93STycho Nightingale #endif 1001*bf21cd93STycho Nightingale /* 1002*bf21cd93STycho Nightingale * XXX one stdio backend supported at this time. 1003*bf21cd93STycho Nightingale */ 1004*bf21cd93STycho Nightingale if (opts == NULL) 1005*bf21cd93STycho Nightingale return (0); 1006*bf21cd93STycho Nightingale 1007*bf21cd93STycho Nightingale #ifdef __FreeBSD__ 1008*bf21cd93STycho Nightingale if (strcmp("stdio", opts) == 0 && !uart_stdio) { 1009*bf21cd93STycho Nightingale sc->stdio = true; 1010*bf21cd93STycho Nightingale uart_stdio = true; 1011*bf21cd93STycho Nightingale return (0); 1012*bf21cd93STycho Nightingale #else 1013*bf21cd93STycho Nightingale if (strcmp("stdio", opts) == 0 && !uart_stdio && !uart_bcons) { 1014*bf21cd93STycho Nightingale sc->stdio = true; 1015*bf21cd93STycho Nightingale uart_stdio = true; 1016*bf21cd93STycho Nightingale 1017*bf21cd93STycho Nightingale error = pthread_create(NULL, NULL, uart_tty_thread, sc); 1018*bf21cd93STycho Nightingale assert(error == 0); 1019*bf21cd93STycho Nightingale 1020*bf21cd93STycho Nightingale return (0); 1021*bf21cd93STycho Nightingale } else if (strstr(opts, "bcons") != 0 && !uart_stdio && !uart_bcons) { 1022*bf21cd93STycho Nightingale sc->bcons = true; 1023*bf21cd93STycho Nightingale uart_bcons= true; 1024*bf21cd93STycho Nightingale 1025*bf21cd93STycho Nightingale if (strstr(opts, "bcons,wait") != 0) { 1026*bf21cd93STycho Nightingale bcons_wait = true; 1027*bf21cd93STycho Nightingale } 1028*bf21cd93STycho Nightingale 1029*bf21cd93STycho Nightingale sc->usc_bcons.clifd = -1; 1030*bf21cd93STycho Nightingale if ((sc->usc_bcons.servfd = init_bcons_sock()) == -1) { 1031*bf21cd93STycho Nightingale fprintf(stderr, "bhyve console setup: " 1032*bf21cd93STycho Nightingale "socket initialization failed\n"); 1033*bf21cd93STycho Nightingale return (-1); 1034*bf21cd93STycho Nightingale } 1035*bf21cd93STycho Nightingale error = pthread_create(NULL, NULL, uart_bcons_thread, sc); 1036*bf21cd93STycho Nightingale assert(error == 0); 1037*bf21cd93STycho Nightingale 1038*bf21cd93STycho Nightingale return (0); 1039*bf21cd93STycho Nightingale #endif 1040*bf21cd93STycho Nightingale } else 1041*bf21cd93STycho Nightingale return (-1); 1042*bf21cd93STycho Nightingale } 1043