1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 30 #include <sys/types.h> 31 32 #include <machine/vmm.h> 33 34 #include <assert.h> 35 #ifndef WITHOUT_CAPSICUM 36 #include <capsicum_helpers.h> 37 #endif 38 #include <err.h> 39 #include <errno.h> 40 #include <pthread.h> 41 #include <stdbool.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <sysexits.h> 45 #include <termios.h> 46 #include <unistd.h> 47 #ifndef __FreeBSD__ 48 #include <sys/socket.h> 49 #include <fcntl.h> 50 #endif 51 52 53 #include "debug.h" 54 #include "mevent.h" 55 #include "uart_backend.h" 56 #include "uart_emul.h" 57 58 struct ttyfd { 59 bool opened; 60 int rfd; /* fd for reading */ 61 int wfd; /* fd for writing, may be == rfd */ 62 }; 63 64 #ifndef __FreeBSD__ 65 struct sockfd { 66 bool sock; 67 int clifd; /* console client unix domain socket */ 68 int servfd; /* console server unix domain socket */ 69 struct mevent *servmev; /* mevent for server socket */ 70 void (*drain)(int, enum ev_type, void *); 71 void *drainarg; 72 }; 73 #endif 74 75 #define FIFOSZ 16 76 77 struct fifo { 78 uint8_t buf[FIFOSZ]; 79 int rindex; /* index to read from */ 80 int windex; /* index to write to */ 81 int num; /* number of characters in the fifo */ 82 int size; /* size of the fifo */ 83 }; 84 85 struct uart_softc { 86 struct ttyfd tty; 87 #ifndef __FreeBSD__ 88 struct sockfd usc_sock; 89 #endif 90 struct fifo rxfifo; 91 struct mevent *mev; 92 pthread_mutex_t mtx; 93 }; 94 95 static bool uart_stdio; /* stdio in use for i/o */ 96 static struct termios tio_stdio_orig; 97 98 static void 99 ttyclose(void) 100 { 101 tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig); 102 } 103 104 static void 105 ttyopen(struct ttyfd *tf) 106 { 107 struct termios orig, new; 108 109 tcgetattr(tf->rfd, &orig); 110 new = orig; 111 cfmakeraw(&new); 112 new.c_cflag |= CLOCAL; 113 tcsetattr(tf->rfd, TCSANOW, &new); 114 if (uart_stdio) { 115 tio_stdio_orig = orig; 116 atexit(ttyclose); 117 } 118 raw_stdio = 1; 119 } 120 121 static int 122 ttyread(struct ttyfd *tf) 123 { 124 unsigned char rb; 125 126 if (read(tf->rfd, &rb, 1) == 1) 127 return (rb); 128 else 129 return (-1); 130 } 131 132 static void 133 ttywrite(struct ttyfd *tf, unsigned char wb) 134 { 135 (void)write(tf->wfd, &wb, 1); 136 } 137 138 #ifndef __FreeBSD__ 139 static void 140 sockwrite(struct uart_softc *sc, unsigned char wb) 141 { 142 (void) write(sc->usc_sock.clifd, &wb, 1); 143 } 144 #endif 145 146 static bool 147 rxfifo_available(struct uart_softc *sc) 148 { 149 return (sc->rxfifo.num < sc->rxfifo.size); 150 } 151 152 int 153 uart_rxfifo_getchar(struct uart_softc *sc) 154 { 155 struct fifo *fifo; 156 int c, error, wasfull; 157 158 wasfull = 0; 159 fifo = &sc->rxfifo; 160 if (fifo->num > 0) { 161 if (!rxfifo_available(sc)) 162 wasfull = 1; 163 c = fifo->buf[fifo->rindex]; 164 fifo->rindex = (fifo->rindex + 1) % fifo->size; 165 fifo->num--; 166 if (wasfull) { 167 if (sc->tty.opened) { 168 error = mevent_enable(sc->mev); 169 assert(error == 0); 170 } 171 #ifndef __FreeBSD__ 172 if (sc->usc_sock.sock && sc->usc_sock.clifd != -1) { 173 error = mevent_enable(sc->mev); 174 assert(error == 0); 175 } 176 #endif /* __FreeBSD__ */ 177 } 178 return (c); 179 } else 180 return (-1); 181 } 182 183 int 184 uart_rxfifo_numchars(struct uart_softc *sc) 185 { 186 return (sc->rxfifo.num); 187 } 188 189 static int 190 rxfifo_putchar(struct uart_softc *sc, uint8_t ch) 191 { 192 struct fifo *fifo; 193 int error; 194 195 fifo = &sc->rxfifo; 196 197 if (fifo->num < fifo->size) { 198 fifo->buf[fifo->windex] = ch; 199 fifo->windex = (fifo->windex + 1) % fifo->size; 200 fifo->num++; 201 if (!rxfifo_available(sc)) { 202 if (sc->tty.opened) { 203 /* 204 * Disable mevent callback if the FIFO is full. 205 */ 206 error = mevent_disable(sc->mev); 207 assert(error == 0); 208 } 209 #ifndef __FreeBSD__ 210 if (sc->usc_sock.sock && sc->usc_sock.clifd != -1) { 211 /* 212 * Disable mevent callback if the FIFO is full. 213 */ 214 error = mevent_disable(sc->mev); 215 assert(error == 0); 216 } 217 #endif /* __FreeBSD__ */ 218 } 219 return (0); 220 } else 221 return (-1); 222 } 223 224 void 225 uart_rxfifo_drain(struct uart_softc *sc, bool loopback) 226 { 227 int ch; 228 229 if (loopback) { 230 (void)ttyread(&sc->tty); 231 } else { 232 while (rxfifo_available(sc) && 233 ((ch = ttyread(&sc->tty)) != -1)) 234 rxfifo_putchar(sc, ch); 235 } 236 } 237 238 #ifndef __FreeBSD__ 239 void 240 uart_rxfifo_sock_drain(struct uart_softc *sc, bool loopback) 241 { 242 int ch; 243 244 if (loopback) { 245 (void) read(sc->usc_sock.clifd, &ch, 1); 246 } else { 247 bool err_close = false; 248 249 while (rxfifo_available(sc)) { 250 int res; 251 252 res = read(sc->usc_sock.clifd, &ch, 1); 253 if (res == 0) { 254 err_close = true; 255 break; 256 } else if (res == -1) { 257 if (errno != EAGAIN && errno != EINTR) { 258 err_close = true; 259 } 260 break; 261 } 262 263 rxfifo_putchar(sc, ch); 264 } 265 266 if (err_close) { 267 (void) fprintf(stderr, "uart: closing client conn\n"); 268 (void) shutdown(sc->usc_sock.clifd, SHUT_RDWR); 269 mevent_delete_close(sc->mev); 270 sc->mev = NULL; 271 sc->usc_sock.clifd = -1; 272 } 273 } 274 } 275 #endif 276 277 int 278 uart_rxfifo_putchar(struct uart_softc *sc, uint8_t ch, bool loopback) 279 { 280 if (loopback) { 281 return (rxfifo_putchar(sc, ch)); 282 } else if (sc->tty.opened) { 283 ttywrite(&sc->tty, ch); 284 return (0); 285 #ifndef __FreeBSD__ 286 } else if (sc->usc_sock.sock) { 287 sockwrite(sc, ch); 288 return (0); 289 #endif 290 } else { 291 /* Drop on the floor. */ 292 return (0); 293 } 294 } 295 296 void 297 uart_rxfifo_reset(struct uart_softc *sc, int size) 298 { 299 char flushbuf[32]; 300 struct fifo *fifo; 301 ssize_t nread; 302 int error; 303 304 fifo = &sc->rxfifo; 305 bzero(fifo, sizeof(struct fifo)); 306 fifo->size = size; 307 308 if (sc->tty.opened) { 309 /* 310 * Flush any unread input from the tty buffer. 311 */ 312 while (1) { 313 nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf)); 314 if (nread != sizeof(flushbuf)) 315 break; 316 } 317 318 /* 319 * Enable mevent to trigger when new characters are available 320 * on the tty fd. 321 */ 322 error = mevent_enable(sc->mev); 323 assert(error == 0); 324 } 325 #ifndef __FreeBSD__ 326 if (sc->usc_sock.sock && sc->usc_sock.clifd != -1) { 327 /* Flush any unread input from the socket buffer. */ 328 do { 329 nread = read(sc->usc_sock.clifd, flushbuf, 330 sizeof (flushbuf)); 331 } while (nread == sizeof (flushbuf)); 332 333 /* Enable mevent to trigger when new data available on sock */ 334 error = mevent_enable(sc->mev); 335 assert(error == 0); 336 } 337 #endif /* __FreeBSD__ */ 338 } 339 340 int 341 uart_rxfifo_size(struct uart_softc *sc __unused) 342 { 343 return (FIFOSZ); 344 } 345 346 #ifdef BHYVE_SNAPSHOT 347 int 348 uart_rxfifo_snapshot(struct uart_softc *sc, struct vm_snapshot_meta *meta) 349 { 350 int ret; 351 352 SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.rindex, meta, ret, done); 353 SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.windex, meta, ret, done); 354 SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.num, meta, ret, done); 355 SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.size, meta, ret, done); 356 SNAPSHOT_BUF_OR_LEAVE(sc->rxfifo.buf, sizeof(sc->rxfifo.buf), 357 meta, ret, done); 358 359 done: 360 return (ret); 361 } 362 #endif 363 364 static int 365 uart_stdio_backend(struct uart_softc *sc) 366 { 367 #ifndef WITHOUT_CAPSICUM 368 cap_rights_t rights; 369 cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 370 #endif 371 372 if (uart_stdio) 373 return (-1); 374 375 sc->tty.rfd = STDIN_FILENO; 376 sc->tty.wfd = STDOUT_FILENO; 377 sc->tty.opened = true; 378 379 if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0) 380 return (-1); 381 if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0) 382 return (-1); 383 384 #ifndef WITHOUT_CAPSICUM 385 cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ); 386 if (caph_rights_limit(sc->tty.rfd, &rights) == -1) 387 errx(EX_OSERR, "Unable to apply rights for sandbox"); 388 if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1) 389 errx(EX_OSERR, "Unable to apply rights for sandbox"); 390 #endif 391 392 uart_stdio = true; 393 394 return (0); 395 } 396 397 static int 398 uart_tty_backend(struct uart_softc *sc, const char *path) 399 { 400 #ifndef WITHOUT_CAPSICUM 401 cap_rights_t rights; 402 cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 403 #endif 404 int fd; 405 406 fd = open(path, O_RDWR | O_NONBLOCK); 407 if (fd < 0) 408 return (-1); 409 410 if (!isatty(fd)) { 411 close(fd); 412 return (-1); 413 } 414 415 sc->tty.rfd = sc->tty.wfd = fd; 416 sc->tty.opened = true; 417 418 #ifndef WITHOUT_CAPSICUM 419 cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE); 420 if (caph_rights_limit(fd, &rights) == -1) 421 errx(EX_OSERR, "Unable to apply rights for sandbox"); 422 if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1) 423 errx(EX_OSERR, "Unable to apply rights for sandbox"); 424 #endif 425 426 return (0); 427 } 428 429 #ifndef __FreeBSD__ 430 static void 431 uart_sock_accept(int fd, enum ev_type ev, void *arg) 432 { 433 struct uart_softc *sc = arg; 434 int connfd; 435 436 connfd = accept(sc->usc_sock.servfd, NULL, NULL); 437 if (connfd == -1) { 438 return; 439 } 440 441 /* 442 * Do client connection management under protection of the softc lock 443 * to avoid racing with concurrent UART events. 444 */ 445 pthread_mutex_lock(&sc->mtx); 446 447 if (sc->usc_sock.clifd != -1) { 448 /* we're already handling a client */ 449 (void) fprintf(stderr, "uart: unexpected client conn\n"); 450 (void) shutdown(connfd, SHUT_RDWR); 451 (void) close(connfd); 452 } else { 453 if (fcntl(connfd, F_SETFL, O_NONBLOCK) < 0) { 454 perror("uart: fcntl(O_NONBLOCK)"); 455 (void) shutdown(connfd, SHUT_RDWR); 456 (void) close(connfd); 457 } else { 458 sc->usc_sock.clifd = connfd; 459 sc->mev = mevent_add(sc->usc_sock.clifd, EVF_READ, 460 sc->usc_sock.drain, sc->usc_sock.drainarg); 461 } 462 } 463 464 pthread_mutex_unlock(&sc->mtx); 465 } 466 467 static int 468 init_sock(const char *path) 469 { 470 int servfd; 471 struct sockaddr_un servaddr; 472 473 bzero(&servaddr, sizeof (servaddr)); 474 servaddr.sun_family = AF_UNIX; 475 476 if (strlcpy(servaddr.sun_path, path, sizeof (servaddr.sun_path)) >= 477 sizeof (servaddr.sun_path)) { 478 (void) fprintf(stderr, "uart: path '%s' too long\n", 479 path); 480 return (-1); 481 } 482 483 if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 484 (void) fprintf(stderr, "uart: socket() error - %s\n", 485 strerror(errno)); 486 return (-1); 487 } 488 (void) unlink(servaddr.sun_path); 489 490 if (bind(servfd, (struct sockaddr *)&servaddr, 491 sizeof (servaddr)) == -1) { 492 (void) fprintf(stderr, "uart: bind() error - %s\n", 493 strerror(errno)); 494 goto out; 495 } 496 497 if (listen(servfd, 1) == -1) { 498 (void) fprintf(stderr, "uart: listen() error - %s\n", 499 strerror(errno)); 500 goto out; 501 } 502 return (servfd); 503 504 out: 505 (void) unlink(servaddr.sun_path); 506 (void) close(servfd); 507 return (-1); 508 } 509 510 static int 511 uart_sock_backend(struct uart_softc *sc, const char *inopts, 512 void (*drain)(int, enum ev_type, void *), void *drainarg) 513 { 514 char *opts, *tofree; 515 char *opt; 516 char *nextopt; 517 char *path = NULL; 518 519 if (strncmp(inopts, "socket,", 7) != 0) { 520 return (-1); 521 } 522 if ((opts = strdup(inopts + 7)) == NULL) { 523 return (-1); 524 } 525 526 tofree = nextopt = opts; 527 for (opt = strsep(&nextopt, ","); opt != NULL; 528 opt = strsep(&nextopt, ",")) { 529 if (path == NULL && *opt == '/') { 530 path = opt; 531 continue; 532 } 533 /* 534 * XXX check for server and client options here. For now, 535 * everything is a server 536 */ 537 free(tofree); 538 return (-1); 539 } 540 541 sc->usc_sock.clifd = -1; 542 if ((sc->usc_sock.servfd = init_sock(path)) == -1) { 543 free(tofree); 544 return (-1); 545 } 546 sc->usc_sock.sock = true; 547 sc->tty.rfd = sc->tty.wfd = -1; 548 sc->usc_sock.servmev = mevent_add(sc->usc_sock.servfd, EVF_READ, 549 uart_sock_accept, sc); 550 assert(sc->usc_sock.servmev != NULL); 551 552 sc->usc_sock.drain = drain; 553 sc->usc_sock.drainarg = drainarg; 554 555 free(tofree); 556 return (0); 557 } 558 #endif /* not __FreeBSD__ */ 559 560 struct uart_softc * 561 uart_init(void) 562 { 563 struct uart_softc *sc = calloc(1, sizeof(struct uart_softc)); 564 if (sc == NULL) 565 return (NULL); 566 567 pthread_mutex_init(&sc->mtx, NULL); 568 569 return (sc); 570 } 571 572 int 573 uart_tty_open(struct uart_softc *sc, const char *path, 574 void (*drain)(int, enum ev_type, void *), void *arg) 575 { 576 int retval; 577 578 #ifndef __FreeBSD__ 579 if (strncmp("socket,", path, 7) == 0) 580 return (uart_sock_backend(sc, path, drain, arg)); 581 #endif 582 if (strcmp("stdio", path) == 0) 583 retval = uart_stdio_backend(sc); 584 else 585 retval = uart_tty_backend(sc, path); 586 if (retval == 0) { 587 ttyopen(&sc->tty); 588 sc->mev = mevent_add(sc->tty.rfd, EVF_READ, drain, arg); 589 assert(sc->mev != NULL); 590 } 591 592 return (retval); 593 } 594 595 void 596 uart_softc_lock(struct uart_softc *sc) 597 { 598 pthread_mutex_lock(&sc->mtx); 599 } 600 601 void 602 uart_softc_unlock(struct uart_softc *sc) 603 { 604 pthread_mutex_unlock(&sc->mtx); 605 } 606