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