]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/uart_emul.c
cdn-patch: fix checkyesno warning in efi keysource
[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                 /*
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_stdio_backend(struct uart_softc *sc)
637 {
638 #ifndef WITHOUT_CAPSICUM
639         cap_rights_t rights;
640         cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
641 #endif
642
643         if (uart_stdio)
644                 return (-1);
645
646         sc->tty.rfd = STDIN_FILENO;
647         sc->tty.wfd = STDOUT_FILENO;
648         sc->tty.opened = true;
649
650         if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0)
651                 return (-1);
652         if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0)
653                 return (-1);
654
655 #ifndef WITHOUT_CAPSICUM
656         cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ);
657         if (caph_rights_limit(sc->tty.rfd, &rights) == -1)
658                 errx(EX_OSERR, "Unable to apply rights for sandbox");
659         if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1)
660                 errx(EX_OSERR, "Unable to apply rights for sandbox");
661 #endif
662
663         uart_stdio = true;
664
665         return (0);
666 }
667
668 static int
669 uart_tty_backend(struct uart_softc *sc, const char *opts)
670 {
671 #ifndef WITHOUT_CAPSICUM
672         cap_rights_t rights;
673         cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
674 #endif
675         int fd;
676
677         fd = open(opts, O_RDWR | O_NONBLOCK);
678         if (fd < 0 || !isatty(fd))
679                 return (-1);
680
681         sc->tty.rfd = sc->tty.wfd = fd;
682         sc->tty.opened = true;
683
684 #ifndef WITHOUT_CAPSICUM
685         cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE);
686         if (caph_rights_limit(fd, &rights) == -1)
687                 errx(EX_OSERR, "Unable to apply rights for sandbox");
688         if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1)
689                 errx(EX_OSERR, "Unable to apply rights for sandbox");
690 #endif
691
692         return (0);
693 }
694
695 int
696 uart_set_backend(struct uart_softc *sc, const char *opts)
697 {
698         int retval;
699
700         if (opts == NULL)
701                 return (0);
702
703         if (strcmp("stdio", opts) == 0)
704                 retval = uart_stdio_backend(sc);
705         else
706                 retval = uart_tty_backend(sc, opts);
707         if (retval == 0)
708                 uart_opentty(sc);
709
710         return (retval);
711 }