uart_emul.c revision 268892
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: stable/10/usr.sbin/bhyve/uart_emul.c 268892 2014-07-19 22:13:12Z jhb $
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/uart_emul.c 268892 2014-07-19 22:13:12Z jhb $");
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 <fcntl.h>
40#include <termios.h>
41#include <unistd.h>
42#include <stdbool.h>
43#include <string.h>
44#include <pthread.h>
45
46#include "mevent.h"
47#include "uart_emul.h"
48
49#define	COM1_BASE      	0x3F8
50#define COM1_IRQ	4
51#define	COM2_BASE      	0x2F8
52#define COM2_IRQ	3
53
54#define	DEFAULT_RCLK	1843200
55#define	DEFAULT_BAUD	9600
56
57#define	FCR_RX_MASK	0xC0
58
59#define	MCR_OUT1	0x04
60#define	MCR_OUT2	0x08
61
62#define	MSR_DELTA_MASK	0x0f
63
64#ifndef REG_SCR
65#define REG_SCR		com_scr
66#endif
67
68#define	FIFOSZ	16
69
70static bool uart_stdio;		/* stdio in use for i/o */
71static struct termios tio_stdio_orig;
72
73static struct {
74	int	baseaddr;
75	int	irq;
76	bool	inuse;
77} uart_lres[] = {
78	{ COM1_BASE, COM1_IRQ, false},
79	{ COM2_BASE, COM2_IRQ, false},
80};
81
82#define	UART_NLDEVS	(sizeof(uart_lres) / sizeof(uart_lres[0]))
83
84struct fifo {
85	uint8_t	buf[FIFOSZ];
86	int	rindex;		/* index to read from */
87	int	windex;		/* index to write to */
88	int	num;		/* number of characters in the fifo */
89	int	size;		/* size of the fifo */
90};
91
92struct ttyfd {
93	bool	opened;
94	int	fd;		/* tty device file descriptor */
95	struct termios tio_orig, tio_new;    /* I/O Terminals */
96};
97
98struct uart_softc {
99	pthread_mutex_t mtx;	/* protects all softc elements */
100	uint8_t	data;		/* Data register (R/W) */
101	uint8_t ier;		/* Interrupt enable register (R/W) */
102	uint8_t lcr;		/* Line control register (R/W) */
103	uint8_t mcr;		/* Modem control register (R/W) */
104	uint8_t lsr;		/* Line status register (R/W) */
105	uint8_t msr;		/* Modem status register (R/W) */
106	uint8_t fcr;		/* FIFO control register (W) */
107	uint8_t scr;		/* Scratch register (R/W) */
108
109	uint8_t dll;		/* Baudrate divisor latch LSB */
110	uint8_t dlh;		/* Baudrate divisor latch MSB */
111
112	struct fifo rxfifo;
113	struct mevent *mev;
114
115	struct ttyfd tty;
116	bool	thre_int_pending;	/* THRE interrupt pending */
117
118	void	*arg;
119	uart_intr_func_t intr_assert;
120	uart_intr_func_t intr_deassert;
121};
122
123static void uart_drain(int fd, enum ev_type ev, void *arg);
124
125static void
126ttyclose(void)
127{
128
129	tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig);
130}
131
132static void
133ttyopen(struct ttyfd *tf)
134{
135
136	tcgetattr(tf->fd, &tf->tio_orig);
137
138	tf->tio_new = tf->tio_orig;
139	cfmakeraw(&tf->tio_new);
140	tf->tio_new.c_cflag |= CLOCAL;
141	tcsetattr(tf->fd, TCSANOW, &tf->tio_new);
142
143	if (tf->fd == STDIN_FILENO) {
144		tio_stdio_orig = tf->tio_orig;
145		atexit(ttyclose);
146	}
147}
148
149static int
150ttyread(struct ttyfd *tf)
151{
152	unsigned char rb;
153
154	if (read(tf->fd, &rb, 1) == 1)
155		return (rb);
156	else
157		return (-1);
158}
159
160static void
161ttywrite(struct ttyfd *tf, unsigned char wb)
162{
163
164	(void)write(tf->fd, &wb, 1);
165}
166
167static void
168rxfifo_reset(struct uart_softc *sc, int size)
169{
170	char flushbuf[32];
171	struct fifo *fifo;
172	ssize_t nread;
173	int error;
174
175	fifo = &sc->rxfifo;
176	bzero(fifo, sizeof(struct fifo));
177	fifo->size = size;
178
179	if (sc->tty.opened) {
180		/*
181		 * Flush any unread input from the tty buffer.
182		 */
183		while (1) {
184			nread = read(sc->tty.fd, flushbuf, sizeof(flushbuf));
185			if (nread != sizeof(flushbuf))
186				break;
187		}
188
189		/*
190		 * Enable mevent to trigger when new characters are available
191		 * on the tty fd.
192		 */
193		error = mevent_enable(sc->mev);
194		assert(error == 0);
195	}
196}
197
198static int
199rxfifo_available(struct uart_softc *sc)
200{
201	struct fifo *fifo;
202
203	fifo = &sc->rxfifo;
204	return (fifo->num < fifo->size);
205}
206
207static int
208rxfifo_putchar(struct uart_softc *sc, uint8_t ch)
209{
210	struct fifo *fifo;
211	int error;
212
213	fifo = &sc->rxfifo;
214
215	if (fifo->num < fifo->size) {
216		fifo->buf[fifo->windex] = ch;
217		fifo->windex = (fifo->windex + 1) % fifo->size;
218		fifo->num++;
219		if (!rxfifo_available(sc)) {
220			if (sc->tty.opened) {
221				/*
222				 * Disable mevent callback if the FIFO is full.
223				 */
224				error = mevent_disable(sc->mev);
225				assert(error == 0);
226			}
227		}
228		return (0);
229	} else
230		return (-1);
231}
232
233static int
234rxfifo_getchar(struct uart_softc *sc)
235{
236	struct fifo *fifo;
237	int c, error, wasfull;
238
239	wasfull = 0;
240	fifo = &sc->rxfifo;
241	if (fifo->num > 0) {
242		if (!rxfifo_available(sc))
243			wasfull = 1;
244		c = fifo->buf[fifo->rindex];
245		fifo->rindex = (fifo->rindex + 1) % fifo->size;
246		fifo->num--;
247		if (wasfull) {
248			if (sc->tty.opened) {
249				error = mevent_enable(sc->mev);
250				assert(error == 0);
251			}
252		}
253		return (c);
254	} else
255		return (-1);
256}
257
258static int
259rxfifo_numchars(struct uart_softc *sc)
260{
261	struct fifo *fifo = &sc->rxfifo;
262
263	return (fifo->num);
264}
265
266static void
267uart_opentty(struct uart_softc *sc)
268{
269
270	ttyopen(&sc->tty);
271	sc->mev = mevent_add(sc->tty.fd, EVF_READ, uart_drain, sc);
272	assert(sc->mev != NULL);
273}
274
275/*
276 * The IIR returns a prioritized interrupt reason:
277 * - receive data available
278 * - transmit holding register empty
279 * - modem status change
280 *
281 * Return an interrupt reason if one is available.
282 */
283static int
284uart_intr_reason(struct uart_softc *sc)
285{
286
287	if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
288		return (IIR_RLS);
289	else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0)
290		return (IIR_RXTOUT);
291	else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
292		return (IIR_TXRDY);
293	else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)
294		return (IIR_MLSC);
295	else
296		return (IIR_NOPEND);
297}
298
299static void
300uart_reset(struct uart_softc *sc)
301{
302	uint16_t divisor;
303
304	divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;
305	sc->dll = divisor;
306	sc->dlh = divisor >> 16;
307
308	rxfifo_reset(sc, 1);	/* no fifo until enabled by software */
309}
310
311/*
312 * Toggle the COM port's intr pin depending on whether or not we have an
313 * interrupt condition to report to the processor.
314 */
315static void
316uart_toggle_intr(struct uart_softc *sc)
317{
318	uint8_t intr_reason;
319
320	intr_reason = uart_intr_reason(sc);
321
322	if (intr_reason == IIR_NOPEND)
323		(*sc->intr_deassert)(sc->arg);
324	else
325		(*sc->intr_assert)(sc->arg);
326}
327
328static void
329uart_drain(int fd, enum ev_type ev, void *arg)
330{
331	struct uart_softc *sc;
332	int ch;
333
334	sc = arg;
335
336	assert(fd == sc->tty.fd);
337	assert(ev == EVF_READ);
338
339	/*
340	 * This routine is called in the context of the mevent thread
341	 * to take out the softc lock to protect against concurrent
342	 * access from a vCPU i/o exit
343	 */
344	pthread_mutex_lock(&sc->mtx);
345
346	if ((sc->mcr & MCR_LOOPBACK) != 0) {
347		(void) ttyread(&sc->tty);
348	} else {
349		while (rxfifo_available(sc) &&
350		       ((ch = ttyread(&sc->tty)) != -1)) {
351			rxfifo_putchar(sc, ch);
352		}
353		uart_toggle_intr(sc);
354	}
355
356	pthread_mutex_unlock(&sc->mtx);
357}
358
359void
360uart_write(struct uart_softc *sc, int offset, uint8_t value)
361{
362	int fifosz;
363	uint8_t msr;
364
365	pthread_mutex_lock(&sc->mtx);
366
367	/*
368	 * Take care of the special case DLAB accesses first
369	 */
370	if ((sc->lcr & LCR_DLAB) != 0) {
371		if (offset == REG_DLL) {
372			sc->dll = value;
373			goto done;
374		}
375
376		if (offset == REG_DLH) {
377			sc->dlh = value;
378			goto done;
379		}
380	}
381
382        switch (offset) {
383	case REG_DATA:
384		if (sc->mcr & MCR_LOOPBACK) {
385			if (rxfifo_putchar(sc, value) != 0)
386				sc->lsr |= LSR_OE;
387		} else if (sc->tty.opened) {
388			ttywrite(&sc->tty, value);
389		} /* else drop on floor */
390		sc->thre_int_pending = true;
391		break;
392	case REG_IER:
393		/*
394		 * Apply mask so that bits 4-7 are 0
395		 * Also enables bits 0-3 only if they're 1
396		 */
397		sc->ier = value & 0x0F;
398		break;
399		case REG_FCR:
400			/*
401			 * When moving from FIFO and 16450 mode and vice versa,
402			 * the FIFO contents are reset.
403			 */
404			if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
405				fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
406				rxfifo_reset(sc, fifosz);
407			}
408
409			/*
410			 * The FCR_ENABLE bit must be '1' for the programming
411			 * of other FCR bits to be effective.
412			 */
413			if ((value & FCR_ENABLE) == 0) {
414				sc->fcr = 0;
415			} else {
416				if ((value & FCR_RCV_RST) != 0)
417					rxfifo_reset(sc, FIFOSZ);
418
419				sc->fcr = value &
420					 (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
421			}
422			break;
423		case REG_LCR:
424			sc->lcr = value;
425			break;
426		case REG_MCR:
427			/* Apply mask so that bits 5-7 are 0 */
428			sc->mcr = value & 0x1F;
429
430			msr = 0;
431			if (sc->mcr & MCR_LOOPBACK) {
432				/*
433				 * In the loopback mode certain bits from the
434				 * MCR are reflected back into MSR
435				 */
436				if (sc->mcr & MCR_RTS)
437					msr |= MSR_CTS;
438				if (sc->mcr & MCR_DTR)
439					msr |= MSR_DSR;
440				if (sc->mcr & MCR_OUT1)
441					msr |= MSR_RI;
442				if (sc->mcr & MCR_OUT2)
443					msr |= MSR_DCD;
444			}
445
446			/*
447			 * Detect if there has been any change between the
448			 * previous and the new value of MSR. If there is
449			 * then assert the appropriate MSR delta bit.
450			 */
451			if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
452				sc->msr |= MSR_DCTS;
453			if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
454				sc->msr |= MSR_DDSR;
455			if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
456				sc->msr |= MSR_DDCD;
457			if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
458				sc->msr |= MSR_TERI;
459
460			/*
461			 * Update the value of MSR while retaining the delta
462			 * bits.
463			 */
464			sc->msr &= MSR_DELTA_MASK;
465			sc->msr |= msr;
466			break;
467		case REG_LSR:
468			/*
469			 * Line status register is not meant to be written to
470			 * during normal operation.
471			 */
472			break;
473		case REG_MSR:
474			/*
475			 * As far as I can tell MSR is a read-only register.
476			 */
477			break;
478		case REG_SCR:
479			sc->scr = value;
480			break;
481		default:
482			break;
483	}
484
485done:
486	uart_toggle_intr(sc);
487	pthread_mutex_unlock(&sc->mtx);
488}
489
490uint8_t
491uart_read(struct uart_softc *sc, int offset)
492{
493	uint8_t iir, intr_reason, reg;
494
495	pthread_mutex_lock(&sc->mtx);
496
497	/*
498	 * Take care of the special case DLAB accesses first
499	 */
500	if ((sc->lcr & LCR_DLAB) != 0) {
501		if (offset == REG_DLL) {
502			reg = sc->dll;
503			goto done;
504		}
505
506		if (offset == REG_DLH) {
507			reg = sc->dlh;
508			goto done;
509		}
510	}
511
512	switch (offset) {
513	case REG_DATA:
514		reg = rxfifo_getchar(sc);
515		break;
516	case REG_IER:
517		reg = sc->ier;
518		break;
519	case REG_IIR:
520		iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
521
522		intr_reason = uart_intr_reason(sc);
523
524		/*
525		 * Deal with side effects of reading the IIR register
526		 */
527		if (intr_reason == IIR_TXRDY)
528			sc->thre_int_pending = false;
529
530		iir |= intr_reason;
531
532		reg = iir;
533		break;
534	case REG_LCR:
535		reg = sc->lcr;
536		break;
537	case REG_MCR:
538		reg = sc->mcr;
539		break;
540	case REG_LSR:
541		/* Transmitter is always ready for more data */
542		sc->lsr |= LSR_TEMT | LSR_THRE;
543
544		/* Check for new receive data */
545		if (rxfifo_numchars(sc) > 0)
546			sc->lsr |= LSR_RXRDY;
547		else
548			sc->lsr &= ~LSR_RXRDY;
549
550		reg = sc->lsr;
551
552		/* The LSR_OE bit is cleared on LSR read */
553		sc->lsr &= ~LSR_OE;
554		break;
555	case REG_MSR:
556		/*
557		 * MSR delta bits are cleared on read
558		 */
559		reg = sc->msr;
560		sc->msr &= ~MSR_DELTA_MASK;
561		break;
562	case REG_SCR:
563		reg = sc->scr;
564		break;
565	default:
566		reg = 0xFF;
567		break;
568	}
569
570done:
571	uart_toggle_intr(sc);
572	pthread_mutex_unlock(&sc->mtx);
573
574	return (reg);
575}
576
577int
578uart_legacy_alloc(int which, int *baseaddr, int *irq)
579{
580
581	if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse)
582		return (-1);
583
584	uart_lres[which].inuse = true;
585	*baseaddr = uart_lres[which].baseaddr;
586	*irq = uart_lres[which].irq;
587
588	return (0);
589}
590
591struct uart_softc *
592uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
593    void *arg)
594{
595	struct uart_softc *sc;
596
597	sc = malloc(sizeof(struct uart_softc));
598	bzero(sc, sizeof(struct uart_softc));
599
600	sc->arg = arg;
601	sc->intr_assert = intr_assert;
602	sc->intr_deassert = intr_deassert;
603
604	pthread_mutex_init(&sc->mtx, NULL);
605
606	uart_reset(sc);
607
608	return (sc);
609}
610
611static int
612uart_tty_backend(struct uart_softc *sc, const char *opts)
613{
614	int fd;
615	int retval;
616
617	retval = -1;
618
619	fd = open(opts, O_RDWR | O_NONBLOCK);
620	if (fd > 0 && isatty(fd)) {
621		sc->tty.fd = fd;
622		sc->tty.opened = true;
623		retval = 0;
624	}
625
626	return (retval);
627}
628
629int
630uart_set_backend(struct uart_softc *sc, const char *opts)
631{
632	int retval;
633
634	retval = -1;
635
636	if (opts == NULL)
637		return (0);
638
639	if (strcmp("stdio", opts) == 0) {
640		if (!uart_stdio) {
641			sc->tty.fd = STDIN_FILENO;
642			sc->tty.opened = true;
643			uart_stdio = true;
644			retval = 0;
645		}
646	} else if (uart_tty_backend(sc, opts) == 0) {
647		retval = 0;
648	}
649
650	/* Make the backend file descriptor non-blocking */
651	if (retval == 0)
652		retval = fcntl(sc->tty.fd, F_SETFL, O_NONBLOCK);
653
654	if (retval == 0)
655		uart_opentty(sc);
656
657	return (retval);
658}
659