]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/bhyve/uart_emul.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / bhyve / uart_emul.c
1 /*-
2  * Copyright (c) 2012 NetApp, Inc.
3  * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/types.h>
34 #include <dev/ic/ns16550.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <assert.h>
39 #include <termios.h>
40 #include <unistd.h>
41 #include <stdbool.h>
42 #include <string.h>
43 #include <pthread.h>
44
45 #include "mevent.h"
46 #include "uart_emul.h"
47
48 #define COM1_BASE       0x3F8
49 #define COM1_IRQ        4
50 #define COM2_BASE       0x2F8
51 #define COM2_IRQ        3
52
53 #define DEFAULT_RCLK    1843200
54 #define DEFAULT_BAUD    9600
55
56 #define FCR_RX_MASK     0xC0
57
58 #define MCR_OUT1        0x04
59 #define MCR_OUT2        0x08
60
61 #define MSR_DELTA_MASK  0x0f
62
63 #ifndef REG_SCR
64 #define REG_SCR         com_scr
65 #endif
66
67 #define FIFOSZ  16
68
69 static bool uart_stdio;         /* stdio in use for i/o */
70
71 static struct {
72         int     baseaddr;
73         int     irq;
74         bool    inuse;
75 } uart_lres[] = {
76         { COM1_BASE, COM1_IRQ, false},
77         { COM2_BASE, COM2_IRQ, false},
78 };
79
80 #define UART_NLDEVS     (sizeof(uart_lres) / sizeof(uart_lres[0]))
81
82 struct fifo {
83         uint8_t buf[FIFOSZ];
84         int     rindex;         /* index to read from */
85         int     windex;         /* index to write to */
86         int     num;            /* number of characters in the fifo */
87         int     size;           /* size of the fifo */
88 };
89
90 struct uart_softc {
91         pthread_mutex_t mtx;    /* protects all softc elements */
92         uint8_t data;           /* Data register (R/W) */
93         uint8_t ier;            /* Interrupt enable register (R/W) */
94         uint8_t lcr;            /* Line control register (R/W) */
95         uint8_t mcr;            /* Modem control register (R/W) */
96         uint8_t lsr;            /* Line status register (R/W) */
97         uint8_t msr;            /* Modem status register (R/W) */
98         uint8_t fcr;            /* FIFO control register (W) */
99         uint8_t scr;            /* Scratch register (R/W) */
100
101         uint8_t dll;            /* Baudrate divisor latch LSB */
102         uint8_t dlh;            /* Baudrate divisor latch MSB */
103
104         struct fifo rxfifo;
105
106         bool    opened;
107         bool    stdio;
108         bool    thre_int_pending;       /* THRE interrupt pending */
109
110         void    *arg;
111         uart_intr_func_t intr_assert;
112         uart_intr_func_t intr_deassert;
113 };
114
115 static void uart_drain(int fd, enum ev_type ev, void *arg);
116
117 static struct termios tio_orig, tio_new;        /* I/O Terminals */
118
119 static void
120 ttyclose(void)
121 {
122
123         tcsetattr(STDIN_FILENO, TCSANOW, &tio_orig);
124 }
125
126 static void
127 ttyopen(void)
128 {
129
130         tcgetattr(STDIN_FILENO, &tio_orig);
131
132         cfmakeraw(&tio_new);
133         tcsetattr(STDIN_FILENO, TCSANOW, &tio_new);
134
135         atexit(ttyclose);
136 }
137
138 static bool
139 tty_char_available(void)
140 {
141         fd_set rfds;
142         struct timeval tv;
143
144         FD_ZERO(&rfds);
145         FD_SET(STDIN_FILENO, &rfds);
146         tv.tv_sec = 0;
147         tv.tv_usec = 0;
148         if (select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) > 0 ) {
149                 return (true);
150         } else {
151                 return (false);
152         }
153 }
154
155 static int
156 ttyread(void)
157 {
158         char rb;
159
160         if (tty_char_available()) {
161                 read(STDIN_FILENO, &rb, 1);
162                 return (rb & 0xff);
163         } else {
164                 return (-1);
165         }
166 }
167
168 static void
169 ttywrite(unsigned char wb)
170 {
171
172         (void)write(STDIN_FILENO, &wb, 1);
173 }
174
175 static void
176 fifo_reset(struct fifo *fifo, int size)
177 {
178
179         bzero(fifo, sizeof(struct fifo));
180         fifo->size = size;
181 }
182
183 static int
184 fifo_putchar(struct fifo *fifo, uint8_t ch)
185 {
186
187         if (fifo->num < fifo->size) {
188                 fifo->buf[fifo->windex] = ch;
189                 fifo->windex = (fifo->windex + 1) % fifo->size;
190                 fifo->num++;
191                 return (0);
192         } else
193                 return (-1);
194 }
195
196 static int
197 fifo_getchar(struct fifo *fifo)
198 {
199         int c;
200
201         if (fifo->num > 0) {
202                 c = fifo->buf[fifo->rindex];
203                 fifo->rindex = (fifo->rindex + 1) % fifo->size;
204                 fifo->num--;
205                 return (c);
206         } else
207                 return (-1);
208 }
209
210 static int
211 fifo_numchars(struct fifo *fifo)
212 {
213
214         return (fifo->num);
215 }
216
217 static int
218 fifo_available(struct fifo *fifo)
219 {
220
221         return (fifo->num < fifo->size);
222 }
223
224 static void
225 uart_opentty(struct uart_softc *sc)
226 {
227         struct mevent *mev;
228
229         assert(!sc->opened && sc->stdio);
230
231         ttyopen();
232         mev = mevent_add(STDIN_FILENO, EVF_READ, uart_drain, sc);
233         assert(mev);
234 }
235
236 /*
237  * The IIR returns a prioritized interrupt reason:
238  * - receive data available
239  * - transmit holding register empty
240  * - modem status change
241  *
242  * Return an interrupt reason if one is available.
243  */
244 static int
245 uart_intr_reason(struct uart_softc *sc)
246 {
247
248         if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
249                 return (IIR_RLS);
250         else if (fifo_numchars(&sc->rxfifo) > 0 && (sc->ier & IER_ERXRDY) != 0)
251                 return (IIR_RXTOUT);
252         else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
253                 return (IIR_TXRDY);
254         else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)
255                 return (IIR_MLSC);
256         else
257                 return (IIR_NOPEND);
258 }
259
260 static void
261 uart_reset(struct uart_softc *sc)
262 {
263         uint16_t divisor;
264
265         divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;
266         sc->dll = divisor;
267         sc->dlh = divisor >> 16;
268
269         fifo_reset(&sc->rxfifo, 1);     /* no fifo until enabled by software */
270 }
271
272 /*
273  * Toggle the COM port's intr pin depending on whether or not we have an
274  * interrupt condition to report to the processor.
275  */
276 static void
277 uart_toggle_intr(struct uart_softc *sc)
278 {
279         uint8_t intr_reason;
280
281         intr_reason = uart_intr_reason(sc);
282
283         if (intr_reason == IIR_NOPEND)
284                 (*sc->intr_deassert)(sc->arg);
285         else
286                 (*sc->intr_assert)(sc->arg);
287 }
288
289 static void
290 uart_drain(int fd, enum ev_type ev, void *arg)
291 {
292         struct uart_softc *sc;
293         int ch;
294
295         sc = arg;       
296
297         assert(fd == STDIN_FILENO);
298         assert(ev == EVF_READ);
299         
300         /*
301          * This routine is called in the context of the mevent thread
302          * to take out the softc lock to protect against concurrent
303          * access from a vCPU i/o exit
304          */
305         pthread_mutex_lock(&sc->mtx);
306
307         if ((sc->mcr & MCR_LOOPBACK) != 0) {
308                 (void) ttyread();
309         } else {
310                 while (fifo_available(&sc->rxfifo) &&
311                        ((ch = ttyread()) != -1)) {
312                         fifo_putchar(&sc->rxfifo, ch);
313                 }
314                 uart_toggle_intr(sc);
315         }
316
317         pthread_mutex_unlock(&sc->mtx);
318 }
319
320 void
321 uart_write(struct uart_softc *sc, int offset, uint8_t value)
322 {
323         int fifosz;
324         uint8_t msr;
325
326         /* Open terminal */
327         if (!sc->opened && sc->stdio) {
328                 uart_opentty(sc);
329                 sc->opened = true;
330         }
331
332         pthread_mutex_lock(&sc->mtx);
333         
334         /*
335          * Take care of the special case DLAB accesses first
336          */
337         if ((sc->lcr & LCR_DLAB) != 0) {
338                 if (offset == REG_DLL) {
339                         sc->dll = value;
340                         goto done;
341                 }
342                 
343                 if (offset == REG_DLH) {
344                         sc->dlh = value;
345                         goto done;
346                 }
347         }
348
349         switch (offset) {
350         case REG_DATA:
351                 if (sc->mcr & MCR_LOOPBACK) {
352                         if (fifo_putchar(&sc->rxfifo, value) != 0)
353                                 sc->lsr |= LSR_OE;
354                 } else if (sc->stdio) {
355                         ttywrite(value);
356                 } /* else drop on floor */
357                 sc->thre_int_pending = true;
358                 break;
359         case REG_IER:
360                 /*
361                  * Apply mask so that bits 4-7 are 0
362                  * Also enables bits 0-3 only if they're 1
363                  */
364                 sc->ier = value & 0x0F;
365                 break;
366                 case REG_FCR:
367                         /*
368                          * When moving from FIFO and 16450 mode and vice versa,
369                          * the FIFO contents are reset.
370                          */
371                         if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
372                                 fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
373                                 fifo_reset(&sc->rxfifo, fifosz);
374                         }
375
376                         /*
377                          * The FCR_ENABLE bit must be '1' for the programming
378                          * of other FCR bits to be effective.
379                          */
380                         if ((value & FCR_ENABLE) == 0) {
381                                 sc->fcr = 0;
382                         } else {
383                                 if ((value & FCR_RCV_RST) != 0)
384                                         fifo_reset(&sc->rxfifo, FIFOSZ);
385
386                                 sc->fcr = value &
387                                          (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
388                         }
389                         break;
390                 case REG_LCR:
391                         sc->lcr = value;
392                         break;
393                 case REG_MCR:
394                         /* Apply mask so that bits 5-7 are 0 */
395                         sc->mcr = value & 0x1F;
396
397                         msr = 0;
398                         if (sc->mcr & MCR_LOOPBACK) {
399                                 /*
400                                  * In the loopback mode certain bits from the
401                                  * MCR are reflected back into MSR
402                                  */
403                                 if (sc->mcr & MCR_RTS)
404                                         msr |= MSR_CTS;
405                                 if (sc->mcr & MCR_DTR)
406                                         msr |= MSR_DSR;
407                                 if (sc->mcr & MCR_OUT1)
408                                         msr |= MSR_RI;
409                                 if (sc->mcr & MCR_OUT2)
410                                         msr |= MSR_DCD;
411                         }
412
413                         /*
414                          * Detect if there has been any change between the
415                          * previous and the new value of MSR. If there is
416                          * then assert the appropriate MSR delta bit.
417                          */
418                         if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
419                                 sc->msr |= MSR_DCTS;
420                         if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
421                                 sc->msr |= MSR_DDSR;
422                         if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
423                                 sc->msr |= MSR_DDCD;
424                         if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
425                                 sc->msr |= MSR_TERI;
426
427                         /*
428                          * Update the value of MSR while retaining the delta
429                          * bits.
430                          */
431                         sc->msr &= MSR_DELTA_MASK;
432                         sc->msr |= msr;
433                         break;
434                 case REG_LSR:
435                         /*
436                          * Line status register is not meant to be written to
437                          * during normal operation.
438                          */
439                         break;
440                 case REG_MSR:
441                         /*
442                          * As far as I can tell MSR is a read-only register.
443                          */
444                         break;
445                 case REG_SCR:
446                         sc->scr = value;
447                         break;
448                 default:
449                         break;
450         }
451
452 done:
453         uart_toggle_intr(sc);
454         pthread_mutex_unlock(&sc->mtx);
455 }
456
457 uint8_t
458 uart_read(struct uart_softc *sc, int offset)
459 {
460         uint8_t iir, intr_reason, reg;
461
462         /* Open terminal */
463         if (!sc->opened && sc->stdio) {
464                 uart_opentty(sc);
465                 sc->opened = true;
466         }
467
468         pthread_mutex_lock(&sc->mtx);
469
470         /*
471          * Take care of the special case DLAB accesses first
472          */
473         if ((sc->lcr & LCR_DLAB) != 0) {
474                 if (offset == REG_DLL) {
475                         reg = sc->dll;
476                         goto done;
477                 }
478                 
479                 if (offset == REG_DLH) {
480                         reg = sc->dlh;
481                         goto done;
482                 }
483         }
484
485         switch (offset) {
486         case REG_DATA:
487                 reg = fifo_getchar(&sc->rxfifo);
488                 break;
489         case REG_IER:
490                 reg = sc->ier;
491                 break;
492         case REG_IIR:
493                 iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
494
495                 intr_reason = uart_intr_reason(sc);
496                         
497                 /*
498                  * Deal with side effects of reading the IIR register
499                  */
500                 if (intr_reason == IIR_TXRDY)
501                         sc->thre_int_pending = false;
502
503                 iir |= intr_reason;
504
505                 reg = iir;
506                 break;
507         case REG_LCR:
508                 reg = sc->lcr;
509                 break;
510         case REG_MCR:
511                 reg = sc->mcr;
512                 break;
513         case REG_LSR:
514                 /* Transmitter is always ready for more data */
515                 sc->lsr |= LSR_TEMT | LSR_THRE;
516
517                 /* Check for new receive data */
518                 if (fifo_numchars(&sc->rxfifo) > 0)
519                         sc->lsr |= LSR_RXRDY;
520                 else
521                         sc->lsr &= ~LSR_RXRDY;
522
523                 reg = sc->lsr;
524
525                 /* The LSR_OE bit is cleared on LSR read */
526                 sc->lsr &= ~LSR_OE;
527                 break;
528         case REG_MSR:
529                 /*
530                  * MSR delta bits are cleared on read
531                  */
532                 reg = sc->msr;
533                 sc->msr &= ~MSR_DELTA_MASK;
534                 break;
535         case REG_SCR:
536                 reg = sc->scr;
537                 break;
538         default:
539                 reg = 0xFF;
540                 break;
541         }
542
543 done:
544         uart_toggle_intr(sc);
545         pthread_mutex_unlock(&sc->mtx);
546
547         return (reg);
548 }
549
550 int
551 uart_legacy_alloc(int which, int *baseaddr, int *irq)
552 {
553
554         if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse)
555                 return (-1);
556
557         uart_lres[which].inuse = true;
558         *baseaddr = uart_lres[which].baseaddr;
559         *irq = uart_lres[which].irq;
560
561         return (0);
562 }
563
564 struct uart_softc *
565 uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
566     void *arg)
567 {
568         struct uart_softc *sc;
569
570         sc = malloc(sizeof(struct uart_softc));
571         bzero(sc, sizeof(struct uart_softc));
572
573         sc->arg = arg;
574         sc->intr_assert = intr_assert;
575         sc->intr_deassert = intr_deassert;
576
577         pthread_mutex_init(&sc->mtx, NULL);
578
579         uart_reset(sc);
580
581         return (sc);
582 }
583
584 int
585 uart_set_backend(struct uart_softc *sc, const char *opts)
586 {
587         /*
588          * XXX one stdio backend supported at this time.
589          */
590         if (opts == NULL)
591                 return (0);
592
593         if (strcmp("stdio", opts) == 0 && !uart_stdio) {
594                 sc->stdio = true;
595                 uart_stdio = true;
596                 return (0);
597         } else
598                 return (-1);
599 }