]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/uart_emul.c
Merge ^/head r339015 through r339669.
[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 #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     fd;             /* tty device file descriptor */
104         struct termios tio_orig, tio_new;    /* I/O Terminals */
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
135 ttyclose(void)
136 {
137
138         tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig);
139 }
140
141 static void
142 ttyopen(struct ttyfd *tf)
143 {
144
145         tcgetattr(tf->fd, &tf->tio_orig);
146
147         tf->tio_new = tf->tio_orig;
148         cfmakeraw(&tf->tio_new);
149         tf->tio_new.c_cflag |= CLOCAL;
150         tcsetattr(tf->fd, TCSANOW, &tf->tio_new);
151
152         if (tf->fd == STDIN_FILENO) {
153                 tio_stdio_orig = tf->tio_orig;
154                 atexit(ttyclose);
155         }
156 }
157
158 static int
159 ttyread(struct ttyfd *tf)
160 {
161         unsigned char rb;
162
163         if (read(tf->fd, &rb, 1) == 1)
164                 return (rb);
165         else
166                 return (-1);
167 }
168
169 static void
170 ttywrite(struct ttyfd *tf, unsigned char wb)
171 {
172
173         (void)write(tf->fd, &wb, 1);
174 }
175
176 static void
177 rxfifo_reset(struct uart_softc *sc, int size)
178 {
179         char flushbuf[32];
180         struct fifo *fifo;
181         ssize_t nread;
182         int error;
183
184         fifo = &sc->rxfifo;
185         bzero(fifo, sizeof(struct fifo));
186         fifo->size = size;
187
188         if (sc->tty.opened) {
189                 /*
190                  * Flush any unread input from the tty buffer.
191                  */
192                 while (1) {
193                         nread = read(sc->tty.fd, flushbuf, sizeof(flushbuf));
194                         if (nread != sizeof(flushbuf))
195                                 break;
196                 }
197
198                 /*
199                  * Enable mevent to trigger when new characters are available
200                  * on the tty fd.
201                  */
202                 error = mevent_enable(sc->mev);
203                 assert(error == 0);
204         }
205 }
206
207 static int
208 rxfifo_available(struct uart_softc *sc)
209 {
210         struct fifo *fifo;
211
212         fifo = &sc->rxfifo;
213         return (fifo->num < fifo->size);
214 }
215
216 static int
217 rxfifo_putchar(struct uart_softc *sc, uint8_t ch)
218 {
219         struct fifo *fifo;
220         int error;
221
222         fifo = &sc->rxfifo;
223
224         if (fifo->num < fifo->size) {
225                 fifo->buf[fifo->windex] = ch;
226                 fifo->windex = (fifo->windex + 1) % fifo->size;
227                 fifo->num++;
228                 if (!rxfifo_available(sc)) {
229                         if (sc->tty.opened) {
230                                 /*
231                                  * Disable mevent callback if the FIFO is full.
232                                  */
233                                 error = mevent_disable(sc->mev);
234                                 assert(error == 0);
235                         }
236                 }
237                 return (0);
238         } else
239                 return (-1);
240 }
241
242 static int
243 rxfifo_getchar(struct uart_softc *sc)
244 {
245         struct fifo *fifo;
246         int c, error, wasfull;
247
248         wasfull = 0;
249         fifo = &sc->rxfifo;
250         if (fifo->num > 0) {
251                 if (!rxfifo_available(sc))
252                         wasfull = 1;
253                 c = fifo->buf[fifo->rindex];
254                 fifo->rindex = (fifo->rindex + 1) % fifo->size;
255                 fifo->num--;
256                 if (wasfull) {
257                         if (sc->tty.opened) {
258                                 error = mevent_enable(sc->mev);
259                                 assert(error == 0);
260                         }
261                 }
262                 return (c);
263         } else
264                 return (-1);
265 }
266
267 static int
268 rxfifo_numchars(struct uart_softc *sc)
269 {
270         struct fifo *fifo = &sc->rxfifo;
271
272         return (fifo->num);
273 }
274
275 static void
276 uart_opentty(struct uart_softc *sc)
277 {
278
279         ttyopen(&sc->tty);
280         sc->mev = mevent_add(sc->tty.fd, EVF_READ, uart_drain, sc);
281         assert(sc->mev != NULL);
282 }
283
284 static uint8_t
285 modem_status(uint8_t mcr)
286 {
287         uint8_t msr;
288
289         if (mcr & MCR_LOOPBACK) {
290                 /*
291                  * In the loopback mode certain bits from the MCR are
292                  * reflected back into MSR.
293                  */
294                 msr = 0;
295                 if (mcr & MCR_RTS)
296                         msr |= MSR_CTS;
297                 if (mcr & MCR_DTR)
298                         msr |= MSR_DSR;
299                 if (mcr & MCR_OUT1)
300                         msr |= MSR_RI;
301                 if (mcr & MCR_OUT2)
302                         msr |= MSR_DCD;
303         } else {
304                 /*
305                  * Always assert DCD and DSR so tty open doesn't block
306                  * even if CLOCAL is turned off.
307                  */
308                 msr = MSR_DCD | MSR_DSR;
309         }
310         assert((msr & MSR_DELTA_MASK) == 0);
311
312         return (msr);
313 }
314
315 /*
316  * The IIR returns a prioritized interrupt reason:
317  * - receive data available
318  * - transmit holding register empty
319  * - modem status change
320  *
321  * Return an interrupt reason if one is available.
322  */
323 static int
324 uart_intr_reason(struct uart_softc *sc)
325 {
326
327         if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
328                 return (IIR_RLS);
329         else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0)
330                 return (IIR_RXTOUT);
331         else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
332                 return (IIR_TXRDY);
333         else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)
334                 return (IIR_MLSC);
335         else
336                 return (IIR_NOPEND);
337 }
338
339 static void
340 uart_reset(struct uart_softc *sc)
341 {
342         uint16_t divisor;
343
344         divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;
345         sc->dll = divisor;
346         sc->dlh = divisor >> 16;
347         sc->msr = modem_status(sc->mcr);
348
349         rxfifo_reset(sc, 1);    /* no fifo until enabled by software */
350 }
351
352 /*
353  * Toggle the COM port's intr pin depending on whether or not we have an
354  * interrupt condition to report to the processor.
355  */
356 static void
357 uart_toggle_intr(struct uart_softc *sc)
358 {
359         uint8_t intr_reason;
360
361         intr_reason = uart_intr_reason(sc);
362
363         if (intr_reason == IIR_NOPEND)
364                 (*sc->intr_deassert)(sc->arg);
365         else
366                 (*sc->intr_assert)(sc->arg);
367 }
368
369 static void
370 uart_drain(int fd, enum ev_type ev, void *arg)
371 {
372         struct uart_softc *sc;
373         int ch;
374
375         sc = arg;       
376
377         assert(fd == sc->tty.fd);
378         assert(ev == EVF_READ);
379         
380         /*
381          * This routine is called in the context of the mevent thread
382          * to take out 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(&sc->tty);
389         } else {
390                 while (rxfifo_available(sc) &&
391                        ((ch = ttyread(&sc->tty)) != -1)) {
392                         rxfifo_putchar(sc, ch);
393                 }
394                 uart_toggle_intr(sc);
395         }
396
397         pthread_mutex_unlock(&sc->mtx);
398 }
399
400 void
401 uart_write(struct uart_softc *sc, int offset, uint8_t value)
402 {
403         int fifosz;
404         uint8_t msr;
405
406         pthread_mutex_lock(&sc->mtx);
407
408         /*
409          * Take care of the special case DLAB accesses first
410          */
411         if ((sc->lcr & LCR_DLAB) != 0) {
412                 if (offset == REG_DLL) {
413                         sc->dll = value;
414                         goto done;
415                 }
416                 
417                 if (offset == REG_DLH) {
418                         sc->dlh = value;
419                         goto done;
420                 }
421         }
422
423         switch (offset) {
424         case REG_DATA:
425                 if (sc->mcr & MCR_LOOPBACK) {
426                         if (rxfifo_putchar(sc, value) != 0)
427                                 sc->lsr |= LSR_OE;
428                 } else if (sc->tty.opened) {
429                         ttywrite(&sc->tty, value);
430                 } /* else drop on floor */
431                 sc->thre_int_pending = true;
432                 break;
433         case REG_IER:
434                 /*
435                  * Apply mask so that bits 4-7 are 0
436                  * Also enables bits 0-3 only if they're 1
437                  */
438                 sc->ier = value & 0x0F;
439                 break;
440                 case REG_FCR:
441                         /*
442                          * When moving from FIFO and 16450 mode and vice versa,
443                          * the FIFO contents are reset.
444                          */
445                         if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
446                                 fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
447                                 rxfifo_reset(sc, fifosz);
448                         }
449
450                         /*
451                          * The FCR_ENABLE bit must be '1' for the programming
452                          * of other FCR bits to be effective.
453                          */
454                         if ((value & FCR_ENABLE) == 0) {
455                                 sc->fcr = 0;
456                         } else {
457                                 if ((value & FCR_RCV_RST) != 0)
458                                         rxfifo_reset(sc, FIFOSZ);
459
460                                 sc->fcr = value &
461                                          (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
462                         }
463                         break;
464                 case REG_LCR:
465                         sc->lcr = value;
466                         break;
467                 case REG_MCR:
468                         /* Apply mask so that bits 5-7 are 0 */
469                         sc->mcr = value & 0x1F;
470                         msr = modem_status(sc->mcr);
471
472                         /*
473                          * Detect if there has been any change between the
474                          * previous and the new value of MSR. If there is
475                          * then assert the appropriate MSR delta bit.
476                          */
477                         if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
478                                 sc->msr |= MSR_DCTS;
479                         if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
480                                 sc->msr |= MSR_DDSR;
481                         if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
482                                 sc->msr |= MSR_DDCD;
483                         if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
484                                 sc->msr |= MSR_TERI;
485
486                         /*
487                          * Update the value of MSR while retaining the delta
488                          * bits.
489                          */
490                         sc->msr &= MSR_DELTA_MASK;
491                         sc->msr |= msr;
492                         break;
493                 case REG_LSR:
494                         /*
495                          * Line status register is not meant to be written to
496                          * during normal operation.
497                          */
498                         break;
499                 case REG_MSR:
500                         /*
501                          * As far as I can tell MSR is a read-only register.
502                          */
503                         break;
504                 case REG_SCR:
505                         sc->scr = value;
506                         break;
507                 default:
508                         break;
509         }
510
511 done:
512         uart_toggle_intr(sc);
513         pthread_mutex_unlock(&sc->mtx);
514 }
515
516 uint8_t
517 uart_read(struct uart_softc *sc, int offset)
518 {
519         uint8_t iir, intr_reason, reg;
520
521         pthread_mutex_lock(&sc->mtx);
522
523         /*
524          * Take care of the special case DLAB accesses first
525          */
526         if ((sc->lcr & LCR_DLAB) != 0) {
527                 if (offset == REG_DLL) {
528                         reg = sc->dll;
529                         goto done;
530                 }
531                 
532                 if (offset == REG_DLH) {
533                         reg = sc->dlh;
534                         goto done;
535                 }
536         }
537
538         switch (offset) {
539         case REG_DATA:
540                 reg = rxfifo_getchar(sc);
541                 break;
542         case REG_IER:
543                 reg = sc->ier;
544                 break;
545         case REG_IIR:
546                 iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
547
548                 intr_reason = uart_intr_reason(sc);
549                         
550                 /*
551                  * Deal with side effects of reading the IIR register
552                  */
553                 if (intr_reason == IIR_TXRDY)
554                         sc->thre_int_pending = false;
555
556                 iir |= intr_reason;
557
558                 reg = iir;
559                 break;
560         case REG_LCR:
561                 reg = sc->lcr;
562                 break;
563         case REG_MCR:
564                 reg = sc->mcr;
565                 break;
566         case REG_LSR:
567                 /* Transmitter is always ready for more data */
568                 sc->lsr |= LSR_TEMT | LSR_THRE;
569
570                 /* Check for new receive data */
571                 if (rxfifo_numchars(sc) > 0)
572                         sc->lsr |= LSR_RXRDY;
573                 else
574                         sc->lsr &= ~LSR_RXRDY;
575
576                 reg = sc->lsr;
577
578                 /* The LSR_OE bit is cleared on LSR read */
579                 sc->lsr &= ~LSR_OE;
580                 break;
581         case REG_MSR:
582                 /*
583                  * MSR delta bits are cleared on read
584                  */
585                 reg = sc->msr;
586                 sc->msr &= ~MSR_DELTA_MASK;
587                 break;
588         case REG_SCR:
589                 reg = sc->scr;
590                 break;
591         default:
592                 reg = 0xFF;
593                 break;
594         }
595
596 done:
597         uart_toggle_intr(sc);
598         pthread_mutex_unlock(&sc->mtx);
599
600         return (reg);
601 }
602
603 int
604 uart_legacy_alloc(int which, int *baseaddr, int *irq)
605 {
606
607         if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse)
608                 return (-1);
609
610         uart_lres[which].inuse = true;
611         *baseaddr = uart_lres[which].baseaddr;
612         *irq = uart_lres[which].irq;
613
614         return (0);
615 }
616
617 struct uart_softc *
618 uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
619     void *arg)
620 {
621         struct uart_softc *sc;
622
623         sc = calloc(1, sizeof(struct uart_softc));
624
625         sc->arg = arg;
626         sc->intr_assert = intr_assert;
627         sc->intr_deassert = intr_deassert;
628
629         pthread_mutex_init(&sc->mtx, NULL);
630
631         uart_reset(sc);
632
633         return (sc);
634 }
635
636 static int
637 uart_tty_backend(struct uart_softc *sc, const char *opts)
638 {
639         int fd;
640         int retval;
641
642         retval = -1;
643
644         fd = open(opts, O_RDWR | O_NONBLOCK);
645         if (fd > 0 && isatty(fd)) {
646                 sc->tty.fd = fd;
647                 sc->tty.opened = true;
648                 retval = 0;
649         }
650
651         return (retval);
652 }
653
654 int
655 uart_set_backend(struct uart_softc *sc, const char *opts)
656 {
657         int retval;
658 #ifndef WITHOUT_CAPSICUM
659         cap_rights_t rights;
660         cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, 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                         if (caph_limit_stdin() == -1 && errno != ENOSYS)
695                                 errx(EX_OSERR,
696                                     "Unable to apply rights for sandbox");
697                 }
698 #endif
699                 uart_opentty(sc);
700         }
701
702         return (retval);
703 }