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