1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012 NetApp, Inc. 5 * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD$"); 34 35#include <sys/types.h> 36#include <dev/ic/ns16550.h> 37#ifndef WITHOUT_CAPSICUM 38#include <sys/capsicum.h> 39#include <capsicum_helpers.h> 40#endif 41 42#include <stdio.h> 43#include <stdlib.h> 44#include <assert.h> 45#include <err.h> 46#include <errno.h> 47#include <fcntl.h> 48#include <termios.h> 49#include <unistd.h> 50#include <stdbool.h> 51#include <string.h> 52#include <pthread.h> 53#include <sysexits.h> 54 55#include "mevent.h" 56#include "uart_emul.h" 57#include "debug.h" 58 59#define COM1_BASE 0x3F8 60#define COM1_IRQ 4 61#define COM2_BASE 0x2F8 62#define COM2_IRQ 3 63 64#define DEFAULT_RCLK 1843200 65#define DEFAULT_BAUD 9600 66 67#define FCR_RX_MASK 0xC0 68 69#define MCR_OUT1 0x04 70#define MCR_OUT2 0x08 71 72#define MSR_DELTA_MASK 0x0f 73 74#ifndef REG_SCR 75#define REG_SCR com_scr 76#endif 77 78#define FIFOSZ 16 79 80static bool uart_stdio; /* stdio in use for i/o */ 81static struct termios tio_stdio_orig; 82 83static struct { 84 int baseaddr; 85 int irq; 86 bool inuse; 87} uart_lres[] = { 88 { COM1_BASE, COM1_IRQ, false}, 89 { COM2_BASE, COM2_IRQ, false}, 90}; 91 92#define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0])) 93 94struct fifo { 95 uint8_t buf[FIFOSZ]; 96 int rindex; /* index to read from */ 97 int windex; /* index to write to */ 98 int num; /* number of characters in the fifo */ 99 int size; /* size of the fifo */ 100}; 101 102struct ttyfd { 103 bool opened; 104 int rfd; /* fd for reading */ 105 int wfd; /* fd for writing, may be == rfd */ 106}; 107 108struct uart_softc { 109 pthread_mutex_t mtx; /* protects all softc elements */ 110 uint8_t data; /* Data register (R/W) */ 111 uint8_t ier; /* Interrupt enable register (R/W) */ 112 uint8_t lcr; /* Line control register (R/W) */ 113 uint8_t mcr; /* Modem control register (R/W) */ 114 uint8_t lsr; /* Line status register (R/W) */ 115 uint8_t msr; /* Modem status register (R/W) */ 116 uint8_t fcr; /* FIFO control register (W) */ 117 uint8_t scr; /* Scratch register (R/W) */ 118 119 uint8_t dll; /* Baudrate divisor latch LSB */ 120 uint8_t dlh; /* Baudrate divisor latch MSB */ 121 122 struct fifo rxfifo; 123 struct mevent *mev; 124 125 struct ttyfd tty; 126 bool thre_int_pending; /* THRE interrupt pending */ 127 128 void *arg; 129 uart_intr_func_t intr_assert; 130 uart_intr_func_t intr_deassert; 131}; 132 133static void uart_drain(int fd, enum ev_type ev, void *arg); 134 135static void 136ttyclose(void) 137{ 138 139 tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig); 140} 141 142static void 143ttyopen(struct ttyfd *tf) 144{ 145 struct termios orig, new; 146 147 tcgetattr(tf->rfd, &orig); 148 new = orig; 149 cfmakeraw(&new); 150 new.c_cflag |= CLOCAL; 151 tcsetattr(tf->rfd, TCSANOW, &new); 152 if (uart_stdio) { 153 tio_stdio_orig = orig; 154 atexit(ttyclose); 155 } 156 raw_stdio = 1; 157} 158 159static int 160ttyread(struct ttyfd *tf) 161{ 162 unsigned char rb; 163 164 if (read(tf->rfd, &rb, 1) == 1) 165 return (rb); 166 else 167 return (-1); 168} 169 170static void 171ttywrite(struct ttyfd *tf, unsigned char wb) 172{ 173 174 (void)write(tf->wfd, &wb, 1); 175} 176 177static void 178rxfifo_reset(struct uart_softc *sc, int size) 179{ 180 char flushbuf[32]; 181 struct fifo *fifo; 182 ssize_t nread; 183 int error; 184 185 fifo = &sc->rxfifo; 186 bzero(fifo, sizeof(struct fifo)); 187 fifo->size = size; 188 189 if (sc->tty.opened) { 190 /* 191 * Flush any unread input from the tty buffer. 192 */ 193 while (1) { 194 nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf)); 195 if (nread != sizeof(flushbuf)) 196 break; 197 } 198 199 /* 200 * Enable mevent to trigger when new characters are available 201 * on the tty fd. 202 */ 203 error = mevent_enable(sc->mev); 204 assert(error == 0); 205 } 206} 207 208static int 209rxfifo_available(struct uart_softc *sc) 210{ 211 struct fifo *fifo; 212 213 fifo = &sc->rxfifo; 214 return (fifo->num < fifo->size); 215} 216 217static int 218rxfifo_putchar(struct uart_softc *sc, uint8_t ch) 219{ 220 struct fifo *fifo; 221 int error; 222 223 fifo = &sc->rxfifo; 224 225 if (fifo->num < fifo->size) { 226 fifo->buf[fifo->windex] = ch; 227 fifo->windex = (fifo->windex + 1) % fifo->size; 228 fifo->num++; 229 if (!rxfifo_available(sc)) { 230 if (sc->tty.opened) { 231 /* 232 * Disable mevent callback if the FIFO is full. 233 */ 234 error = mevent_disable(sc->mev); 235 assert(error == 0); 236 } 237 } 238 return (0); 239 } else 240 return (-1); 241} 242 243static int 244rxfifo_getchar(struct uart_softc *sc) 245{ 246 struct fifo *fifo; 247 int c, error, wasfull; 248 249 wasfull = 0; 250 fifo = &sc->rxfifo; 251 if (fifo->num > 0) { 252 if (!rxfifo_available(sc)) 253 wasfull = 1; 254 c = fifo->buf[fifo->rindex]; 255 fifo->rindex = (fifo->rindex + 1) % fifo->size; 256 fifo->num--; 257 if (wasfull) { 258 if (sc->tty.opened) { 259 error = mevent_enable(sc->mev); 260 assert(error == 0); 261 } 262 } 263 return (c); 264 } else 265 return (-1); 266} 267 268static int 269rxfifo_numchars(struct uart_softc *sc) 270{ 271 struct fifo *fifo = &sc->rxfifo; 272 273 return (fifo->num); 274} 275 276static void 277uart_opentty(struct uart_softc *sc) 278{ 279 280 ttyopen(&sc->tty); 281 sc->mev = mevent_add(sc->tty.rfd, EVF_READ, uart_drain, sc); 282 assert(sc->mev != NULL); 283} 284 285static uint8_t 286modem_status(uint8_t mcr) 287{ 288 uint8_t msr; 289 290 if (mcr & MCR_LOOPBACK) { 291 /* 292 * In the loopback mode certain bits from the MCR are 293 * reflected back into MSR. 294 */ 295 msr = 0; 296 if (mcr & MCR_RTS) 297 msr |= MSR_CTS; 298 if (mcr & MCR_DTR) 299 msr |= MSR_DSR; 300 if (mcr & MCR_OUT1) 301 msr |= MSR_RI; 302 if (mcr & MCR_OUT2) 303 msr |= MSR_DCD; 304 } else { 305 /* 306 * Always assert DCD and DSR so tty open doesn't block 307 * even if CLOCAL is turned off. 308 */ 309 msr = MSR_DCD | MSR_DSR; 310 } 311 assert((msr & MSR_DELTA_MASK) == 0); 312 313 return (msr); 314} 315 316/* 317 * The IIR returns a prioritized interrupt reason: 318 * - receive data available 319 * - transmit holding register empty 320 * - modem status change 321 * 322 * Return an interrupt reason if one is available. 323 */ 324static int 325uart_intr_reason(struct uart_softc *sc) 326{ 327 328 if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0) 329 return (IIR_RLS); 330 else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0) 331 return (IIR_RXTOUT); 332 else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0) 333 return (IIR_TXRDY); 334 else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0) 335 return (IIR_MLSC); 336 else 337 return (IIR_NOPEND); 338} 339 340static void 341uart_reset(struct uart_softc *sc) 342{ 343 uint16_t divisor; 344 345 divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16; 346 sc->dll = divisor; 347 sc->dlh = divisor >> 16; 348 sc->msr = modem_status(sc->mcr); 349 350 rxfifo_reset(sc, 1); /* no fifo until enabled by software */ 351} 352 353/* 354 * Toggle the COM port's intr pin depending on whether or not we have an 355 * interrupt condition to report to the processor. 356 */ 357static void 358uart_toggle_intr(struct uart_softc *sc) 359{ 360 uint8_t intr_reason; 361 362 intr_reason = uart_intr_reason(sc); 363 364 if (intr_reason == IIR_NOPEND) 365 (*sc->intr_deassert)(sc->arg); 366 else 367 (*sc->intr_assert)(sc->arg); 368} 369 370static void 371uart_drain(int fd, enum ev_type ev, void *arg) 372{ 373 struct uart_softc *sc; 374 int ch; 375 376 sc = arg; 377 378 assert(fd == sc->tty.rfd); 379 assert(ev == EVF_READ); 380 381 /* 382 * This routine is called in the context of the mevent thread 383 * to take out the softc lock to protect against concurrent 384 * access from a vCPU i/o exit 385 */ 386 pthread_mutex_lock(&sc->mtx); 387 388 if ((sc->mcr & MCR_LOOPBACK) != 0) { 389 (void) ttyread(&sc->tty); 390 } else { 391 while (rxfifo_available(sc) && 392 ((ch = ttyread(&sc->tty)) != -1)) { 393 rxfifo_putchar(sc, ch); 394 } 395 uart_toggle_intr(sc); 396 } 397 398 pthread_mutex_unlock(&sc->mtx); 399} 400 401void 402uart_write(struct uart_softc *sc, int offset, uint8_t value) 403{ 404 int fifosz; 405 uint8_t msr; 406 407 pthread_mutex_lock(&sc->mtx); 408 409 /* 410 * Take care of the special case DLAB accesses first 411 */ 412 if ((sc->lcr & LCR_DLAB) != 0) { 413 if (offset == REG_DLL) { 414 sc->dll = value; 415 goto done; 416 } 417 418 if (offset == REG_DLH) { 419 sc->dlh = value; 420 goto done; 421 } 422 } 423 424 switch (offset) { 425 case REG_DATA: 426 if (sc->mcr & MCR_LOOPBACK) { 427 if (rxfifo_putchar(sc, value) != 0) 428 sc->lsr |= LSR_OE; 429 } else if (sc->tty.opened) { 430 ttywrite(&sc->tty, value); 431 } /* else drop on floor */ 432 sc->thre_int_pending = true; 433 break; 434 case REG_IER: 435 /* 436 * Apply mask so that bits 4-7 are 0 437 * Also enables bits 0-3 only if they're 1 438 */ 439 sc->ier = value & 0x0F; 440 break; 441 case REG_FCR: 442 /* 443 * When moving from FIFO and 16450 mode and vice versa, 444 * the FIFO contents are reset. 445 */ 446 if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) { 447 fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1; 448 rxfifo_reset(sc, fifosz); 449 } 450 451 /* 452 * The FCR_ENABLE bit must be '1' for the programming 453 * of other FCR bits to be effective. 454 */ 455 if ((value & FCR_ENABLE) == 0) { 456 sc->fcr = 0; 457 } else { 458 if ((value & FCR_RCV_RST) != 0) 459 rxfifo_reset(sc, FIFOSZ); 460 461 sc->fcr = value & 462 (FCR_ENABLE | FCR_DMA | FCR_RX_MASK); 463 } 464 break; 465 case REG_LCR: 466 sc->lcr = value; 467 break; 468 case REG_MCR: 469 /* Apply mask so that bits 5-7 are 0 */ 470 sc->mcr = value & 0x1F; 471 msr = modem_status(sc->mcr); 472 473 /* 474 * Detect if there has been any change between the 475 * previous and the new value of MSR. If there is 476 * then assert the appropriate MSR delta bit. 477 */ 478 if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS)) 479 sc->msr |= MSR_DCTS; 480 if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR)) 481 sc->msr |= MSR_DDSR; 482 if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD)) 483 sc->msr |= MSR_DDCD; 484 if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0) 485 sc->msr |= MSR_TERI; 486 487 /* 488 * Update the value of MSR while retaining the delta 489 * bits. 490 */ 491 sc->msr &= MSR_DELTA_MASK; 492 sc->msr |= msr; 493 break; 494 case REG_LSR: 495 /* 496 * Line status register is not meant to be written to 497 * during normal operation. 498 */ 499 break; 500 case REG_MSR: 501 /* 502 * As far as I can tell MSR is a read-only register. 503 */ 504 break; 505 case REG_SCR: 506 sc->scr = value; 507 break; 508 default: 509 break; 510 } 511 512done: 513 uart_toggle_intr(sc); 514 pthread_mutex_unlock(&sc->mtx); 515} 516 517uint8_t 518uart_read(struct uart_softc *sc, int offset) 519{ 520 uint8_t iir, intr_reason, reg; 521 522 pthread_mutex_lock(&sc->mtx); 523 524 /* 525 * Take care of the special case DLAB accesses first 526 */ 527 if ((sc->lcr & LCR_DLAB) != 0) { 528 if (offset == REG_DLL) { 529 reg = sc->dll; 530 goto done; 531 } 532 533 if (offset == REG_DLH) { 534 reg = sc->dlh; 535 goto done; 536 } 537 } 538 539 switch (offset) { 540 case REG_DATA: 541 reg = rxfifo_getchar(sc); 542 break; 543 case REG_IER: 544 reg = sc->ier; 545 break; 546 case REG_IIR: 547 iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0; 548 549 intr_reason = uart_intr_reason(sc); 550 551 /* 552 * Deal with side effects of reading the IIR register 553 */ 554 if (intr_reason == IIR_TXRDY) 555 sc->thre_int_pending = false; 556 557 iir |= intr_reason; 558 559 reg = iir; 560 break; 561 case REG_LCR: 562 reg = sc->lcr; 563 break; 564 case REG_MCR: 565 reg = sc->mcr; 566 break; 567 case REG_LSR: 568 /* Transmitter is always ready for more data */ 569 sc->lsr |= LSR_TEMT | LSR_THRE; 570 571 /* Check for new receive data */ 572 if (rxfifo_numchars(sc) > 0) 573 sc->lsr |= LSR_RXRDY; 574 else 575 sc->lsr &= ~LSR_RXRDY; 576 577 reg = sc->lsr; 578 579 /* The LSR_OE bit is cleared on LSR read */ 580 sc->lsr &= ~LSR_OE; 581 break; 582 case REG_MSR: 583 /* 584 * MSR delta bits are cleared on read 585 */ 586 reg = sc->msr; 587 sc->msr &= ~MSR_DELTA_MASK; 588 break; 589 case REG_SCR: 590 reg = sc->scr; 591 break; 592 default: 593 reg = 0xFF; 594 break; 595 } 596 597done: 598 uart_toggle_intr(sc); 599 pthread_mutex_unlock(&sc->mtx); 600 601 return (reg); 602} 603 604int 605uart_legacy_alloc(int which, int *baseaddr, int *irq) 606{ 607 608 if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse) 609 return (-1); 610 611 uart_lres[which].inuse = true; 612 *baseaddr = uart_lres[which].baseaddr; 613 *irq = uart_lres[which].irq; 614 615 return (0); 616} 617 618struct uart_softc * 619uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert, 620 void *arg) 621{ 622 struct uart_softc *sc; 623 624 sc = calloc(1, sizeof(struct uart_softc)); 625 626 sc->arg = arg; 627 sc->intr_assert = intr_assert; 628 sc->intr_deassert = intr_deassert; 629 630 pthread_mutex_init(&sc->mtx, NULL); 631 632 uart_reset(sc); 633 634 return (sc); 635} 636 637static int 638uart_stdio_backend(struct uart_softc *sc) 639{ 640#ifndef WITHOUT_CAPSICUM 641 cap_rights_t rights; 642 cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 643#endif 644 645 if (uart_stdio) 646 return (-1); 647 648 sc->tty.rfd = STDIN_FILENO; 649 sc->tty.wfd = STDOUT_FILENO; 650 sc->tty.opened = true; 651 652 if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0) 653 return (-1); 654 if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0) 655 return (-1); 656 657#ifndef WITHOUT_CAPSICUM 658 cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ); 659 if (caph_rights_limit(sc->tty.rfd, &rights) == -1) 660 errx(EX_OSERR, "Unable to apply rights for sandbox"); 661 if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1) 662 errx(EX_OSERR, "Unable to apply rights for sandbox"); 663#endif 664 665 uart_stdio = true; 666 667 return (0); 668} 669 670static int 671uart_tty_backend(struct uart_softc *sc, const char *opts) 672{ 673#ifndef WITHOUT_CAPSICUM 674 cap_rights_t rights; 675 cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 676#endif 677 int fd; 678 679 fd = open(opts, O_RDWR | O_NONBLOCK); 680 if (fd < 0 || !isatty(fd)) 681 return (-1); 682 683 sc->tty.rfd = sc->tty.wfd = fd; 684 sc->tty.opened = true; 685 686#ifndef WITHOUT_CAPSICUM 687 cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE); 688 if (caph_rights_limit(fd, &rights) == -1) 689 errx(EX_OSERR, "Unable to apply rights for sandbox"); 690 if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1) 691 errx(EX_OSERR, "Unable to apply rights for sandbox"); 692#endif 693 694 return (0); 695} 696 697int 698uart_set_backend(struct uart_softc *sc, const char *opts) 699{ 700 int retval; 701 702 if (opts == NULL) 703 return (0); 704 705 if (strcmp("stdio", opts) == 0) 706 retval = uart_stdio_backend(sc); 707 else 708 retval = uart_tty_backend(sc, opts); 709 if (retval == 0) 710 uart_opentty(sc); 711 712 return (retval); 713} 714