]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/uart_emul.c
MFC 325727:
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / uart_emul.c
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 #endif
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <assert.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <termios.h>
48 #include <unistd.h>
49 #include <stdbool.h>
50 #include <string.h>
51 #include <pthread.h>
52 #include <sysexits.h>
53
54 #include "mevent.h"
55 #include "uart_emul.h"
56
57 #define COM1_BASE       0x3F8
58 #define COM1_IRQ        4
59 #define COM2_BASE       0x2F8
60 #define COM2_IRQ        3
61
62 #define DEFAULT_RCLK    1843200
63 #define DEFAULT_BAUD    9600
64
65 #define FCR_RX_MASK     0xC0
66
67 #define MCR_OUT1        0x04
68 #define MCR_OUT2        0x08
69
70 #define MSR_DELTA_MASK  0x0f
71
72 #ifndef REG_SCR
73 #define REG_SCR         com_scr
74 #endif
75
76 #define FIFOSZ  16
77
78 static bool uart_stdio;         /* stdio in use for i/o */
79 static struct termios tio_stdio_orig;
80
81 static struct {
82         int     baseaddr;
83         int     irq;
84         bool    inuse;
85 } uart_lres[] = {
86         { COM1_BASE, COM1_IRQ, false},
87         { COM2_BASE, COM2_IRQ, false},
88 };
89
90 #define UART_NLDEVS     (sizeof(uart_lres) / sizeof(uart_lres[0]))
91
92 struct fifo {
93         uint8_t buf[FIFOSZ];
94         int     rindex;         /* index to read from */
95         int     windex;         /* index to write to */
96         int     num;            /* number of characters in the fifo */
97         int     size;           /* size of the fifo */
98 };
99
100 struct ttyfd {
101         bool    opened;
102         int     fd;             /* tty device file descriptor */
103         struct termios tio_orig, tio_new;    /* I/O Terminals */
104 };
105
106 struct uart_softc {
107         pthread_mutex_t mtx;    /* protects all softc elements */
108         uint8_t data;           /* Data register (R/W) */
109         uint8_t ier;            /* Interrupt enable register (R/W) */
110         uint8_t lcr;            /* Line control register (R/W) */
111         uint8_t mcr;            /* Modem control register (R/W) */
112         uint8_t lsr;            /* Line status register (R/W) */
113         uint8_t msr;            /* Modem status register (R/W) */
114         uint8_t fcr;            /* FIFO control register (W) */
115         uint8_t scr;            /* Scratch register (R/W) */
116
117         uint8_t dll;            /* Baudrate divisor latch LSB */
118         uint8_t dlh;            /* Baudrate divisor latch MSB */
119
120         struct fifo rxfifo;
121         struct mevent *mev;
122
123         struct ttyfd tty;
124         bool    thre_int_pending;       /* THRE interrupt pending */
125
126         void    *arg;
127         uart_intr_func_t intr_assert;
128         uart_intr_func_t intr_deassert;
129 };
130
131 static void uart_drain(int fd, enum ev_type ev, void *arg);
132
133 static void
134 ttyclose(void)
135 {
136
137         tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig);
138 }
139
140 static void
141 ttyopen(struct ttyfd *tf)
142 {
143
144         tcgetattr(tf->fd, &tf->tio_orig);
145
146         tf->tio_new = tf->tio_orig;
147         cfmakeraw(&tf->tio_new);
148         tf->tio_new.c_cflag |= CLOCAL;
149         tcsetattr(tf->fd, TCSANOW, &tf->tio_new);
150
151         if (tf->fd == STDIN_FILENO) {
152                 tio_stdio_orig = tf->tio_orig;
153                 atexit(ttyclose);
154         }
155 }
156
157 static int
158 ttyread(struct ttyfd *tf)
159 {
160         unsigned char rb;
161
162         if (read(tf->fd, &rb, 1) == 1)
163                 return (rb);
164         else
165                 return (-1);
166 }
167
168 static void
169 ttywrite(struct ttyfd *tf, unsigned char wb)
170 {
171
172         (void)write(tf->fd, &wb, 1);
173 }
174
175 static void
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.fd, 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
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
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
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
267 rxfifo_numchars(struct uart_softc *sc)
268 {
269         struct fifo *fifo = &sc->rxfifo;
270
271         return (fifo->num);
272 }
273
274 static void
275 uart_opentty(struct uart_softc *sc)
276 {
277
278         ttyopen(&sc->tty);
279         sc->mev = mevent_add(sc->tty.fd, EVF_READ, uart_drain, sc);
280         assert(sc->mev != NULL);
281 }
282
283 static uint8_t
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
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
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
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
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.fd);
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
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
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
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 *
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
636 uart_tty_backend(struct uart_softc *sc, const char *opts)
637 {
638         int fd;
639         int retval;
640
641         retval = -1;
642
643         fd = open(opts, O_RDWR | O_NONBLOCK);
644         if (fd > 0 && isatty(fd)) {
645                 sc->tty.fd = fd;
646                 sc->tty.opened = true;
647                 retval = 0;
648         }
649
650         return (retval);
651 }
652
653 int
654 uart_set_backend(struct uart_softc *sc, const char *opts)
655 {
656         int retval;
657 #ifndef WITHOUT_CAPSICUM
658         cap_rights_t rights;
659         cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
660         cap_ioctl_t sicmds[] = { TIOCGETA, TIOCGWINSZ };
661 #endif
662
663         retval = -1;
664
665         if (opts == NULL)
666                 return (0);
667
668         if (strcmp("stdio", opts) == 0) {
669                 if (!uart_stdio) {
670                         sc->tty.fd = STDIN_FILENO;
671                         sc->tty.opened = true;
672                         uart_stdio = true;
673                         retval = 0;
674                 }
675         } else if (uart_tty_backend(sc, opts) == 0) {
676                 retval = 0;
677         }
678
679         /* Make the backend file descriptor non-blocking */
680         if (retval == 0)
681                 retval = fcntl(sc->tty.fd, F_SETFL, O_NONBLOCK);
682
683         if (retval == 0) {
684 #ifndef WITHOUT_CAPSICUM
685                 cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ,
686                     CAP_WRITE);
687                 if (cap_rights_limit(sc->tty.fd, &rights) == -1 &&
688                     errno != ENOSYS)
689                         errx(EX_OSERR, "Unable to apply rights for sandbox");
690                 if (cap_ioctls_limit(sc->tty.fd, cmds, nitems(cmds)) == -1 &&
691                     errno != ENOSYS)
692                         errx(EX_OSERR, "Unable to apply rights for sandbox");
693                 if (!uart_stdio) {
694                         cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT,
695                             CAP_IOCTL, CAP_READ);
696                         if (cap_rights_limit(STDIN_FILENO, &rights) == -1 &&
697                             errno != ENOSYS)
698                                 errx(EX_OSERR,
699                                     "Unable to apply rights for sandbox");
700                         if (cap_ioctls_limit(STDIN_FILENO, sicmds,
701                             nitems(sicmds)) == -1 && errno != ENOSYS)
702                                 errx(EX_OSERR,
703                                     "Unable to apply rights for sandbox");
704                         if (cap_fcntls_limit(STDIN_FILENO, CAP_FCNTL_GETFL) ==
705                             -1 && errno != ENOSYS)
706                                 errx(EX_OSERR,
707                                     "Unable to apply rights for sandbox");
708                 }
709 #endif
710                 uart_opentty(sc);
711         }
712
713         return (retval);
714 }