]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/uart_emul.c
bhyve(8): Fix uart emulation bug
[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                 /* Set pending when IER_ETXRDY is raised (edge-triggered). */
435                 if ((sc->ier & IER_ETXRDY) == 0 && (value & IER_ETXRDY) != 0)
436                         sc->thre_int_pending = true;
437                 /*
438                  * Apply mask so that bits 4-7 are 0
439                  * Also enables bits 0-3 only if they're 1
440                  */
441                 sc->ier = value & 0x0F;
442                 break;
443                 case REG_FCR:
444                         /*
445                          * When moving from FIFO and 16450 mode and vice versa,
446                          * the FIFO contents are reset.
447                          */
448                         if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
449                                 fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
450                                 rxfifo_reset(sc, fifosz);
451                         }
452
453                         /*
454                          * The FCR_ENABLE bit must be '1' for the programming
455                          * of other FCR bits to be effective.
456                          */
457                         if ((value & FCR_ENABLE) == 0) {
458                                 sc->fcr = 0;
459                         } else {
460                                 if ((value & FCR_RCV_RST) != 0)
461                                         rxfifo_reset(sc, FIFOSZ);
462
463                                 sc->fcr = value &
464                                          (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
465                         }
466                         break;
467                 case REG_LCR:
468                         sc->lcr = value;
469                         break;
470                 case REG_MCR:
471                         /* Apply mask so that bits 5-7 are 0 */
472                         sc->mcr = value & 0x1F;
473                         msr = modem_status(sc->mcr);
474
475                         /*
476                          * Detect if there has been any change between the
477                          * previous and the new value of MSR. If there is
478                          * then assert the appropriate MSR delta bit.
479                          */
480                         if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
481                                 sc->msr |= MSR_DCTS;
482                         if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
483                                 sc->msr |= MSR_DDSR;
484                         if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
485                                 sc->msr |= MSR_DDCD;
486                         if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
487                                 sc->msr |= MSR_TERI;
488
489                         /*
490                          * Update the value of MSR while retaining the delta
491                          * bits.
492                          */
493                         sc->msr &= MSR_DELTA_MASK;
494                         sc->msr |= msr;
495                         break;
496                 case REG_LSR:
497                         /*
498                          * Line status register is not meant to be written to
499                          * during normal operation.
500                          */
501                         break;
502                 case REG_MSR:
503                         /*
504                          * As far as I can tell MSR is a read-only register.
505                          */
506                         break;
507                 case REG_SCR:
508                         sc->scr = value;
509                         break;
510                 default:
511                         break;
512         }
513
514 done:
515         uart_toggle_intr(sc);
516         pthread_mutex_unlock(&sc->mtx);
517 }
518
519 uint8_t
520 uart_read(struct uart_softc *sc, int offset)
521 {
522         uint8_t iir, intr_reason, reg;
523
524         pthread_mutex_lock(&sc->mtx);
525
526         /*
527          * Take care of the special case DLAB accesses first
528          */
529         if ((sc->lcr & LCR_DLAB) != 0) {
530                 if (offset == REG_DLL) {
531                         reg = sc->dll;
532                         goto done;
533                 }
534                 
535                 if (offset == REG_DLH) {
536                         reg = sc->dlh;
537                         goto done;
538                 }
539         }
540
541         switch (offset) {
542         case REG_DATA:
543                 reg = rxfifo_getchar(sc);
544                 break;
545         case REG_IER:
546                 reg = sc->ier;
547                 break;
548         case REG_IIR:
549                 iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
550
551                 intr_reason = uart_intr_reason(sc);
552                         
553                 /*
554                  * Deal with side effects of reading the IIR register
555                  */
556                 if (intr_reason == IIR_TXRDY)
557                         sc->thre_int_pending = false;
558
559                 iir |= intr_reason;
560
561                 reg = iir;
562                 break;
563         case REG_LCR:
564                 reg = sc->lcr;
565                 break;
566         case REG_MCR:
567                 reg = sc->mcr;
568                 break;
569         case REG_LSR:
570                 /* Transmitter is always ready for more data */
571                 sc->lsr |= LSR_TEMT | LSR_THRE;
572
573                 /* Check for new receive data */
574                 if (rxfifo_numchars(sc) > 0)
575                         sc->lsr |= LSR_RXRDY;
576                 else
577                         sc->lsr &= ~LSR_RXRDY;
578
579                 reg = sc->lsr;
580
581                 /* The LSR_OE bit is cleared on LSR read */
582                 sc->lsr &= ~LSR_OE;
583                 break;
584         case REG_MSR:
585                 /*
586                  * MSR delta bits are cleared on read
587                  */
588                 reg = sc->msr;
589                 sc->msr &= ~MSR_DELTA_MASK;
590                 break;
591         case REG_SCR:
592                 reg = sc->scr;
593                 break;
594         default:
595                 reg = 0xFF;
596                 break;
597         }
598
599 done:
600         uart_toggle_intr(sc);
601         pthread_mutex_unlock(&sc->mtx);
602
603         return (reg);
604 }
605
606 int
607 uart_legacy_alloc(int which, int *baseaddr, int *irq)
608 {
609
610         if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse)
611                 return (-1);
612
613         uart_lres[which].inuse = true;
614         *baseaddr = uart_lres[which].baseaddr;
615         *irq = uart_lres[which].irq;
616
617         return (0);
618 }
619
620 struct uart_softc *
621 uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
622     void *arg)
623 {
624         struct uart_softc *sc;
625
626         sc = calloc(1, sizeof(struct uart_softc));
627
628         sc->arg = arg;
629         sc->intr_assert = intr_assert;
630         sc->intr_deassert = intr_deassert;
631
632         pthread_mutex_init(&sc->mtx, NULL);
633
634         uart_reset(sc);
635
636         return (sc);
637 }
638
639 static int
640 uart_tty_backend(struct uart_softc *sc, const char *opts)
641 {
642         int fd;
643         int retval;
644
645         retval = -1;
646
647         fd = open(opts, O_RDWR | O_NONBLOCK);
648         if (fd > 0 && isatty(fd)) {
649                 sc->tty.fd = fd;
650                 sc->tty.opened = true;
651                 retval = 0;
652         }
653
654         return (retval);
655 }
656
657 int
658 uart_set_backend(struct uart_softc *sc, const char *opts)
659 {
660         int retval;
661 #ifndef WITHOUT_CAPSICUM
662         cap_rights_t rights;
663         cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
664 #endif
665
666         retval = -1;
667
668         if (opts == NULL)
669                 return (0);
670
671         if (strcmp("stdio", opts) == 0) {
672                 if (!uart_stdio) {
673                         sc->tty.fd = STDIN_FILENO;
674                         sc->tty.opened = true;
675                         uart_stdio = true;
676                         retval = 0;
677                 }
678         } else if (uart_tty_backend(sc, opts) == 0) {
679                 retval = 0;
680         }
681
682         /* Make the backend file descriptor non-blocking */
683         if (retval == 0)
684                 retval = fcntl(sc->tty.fd, F_SETFL, O_NONBLOCK);
685
686         if (retval == 0) {
687 #ifndef WITHOUT_CAPSICUM
688                 cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ,
689                     CAP_WRITE);
690                 if (caph_rights_limit(sc->tty.fd, &rights) == -1)
691                         errx(EX_OSERR, "Unable to apply rights for sandbox");
692                 if (caph_ioctls_limit(sc->tty.fd, cmds, nitems(cmds)) == -1)
693                         errx(EX_OSERR, "Unable to apply rights for sandbox");
694                 if (!uart_stdio) {
695                         if (caph_limit_stdin() == -1)
696                                 errx(EX_OSERR,
697                                     "Unable to apply rights for sandbox");
698                 }
699 #endif
700                 uart_opentty(sc);
701         }
702
703         return (retval);
704 }