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