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: releng/11.0/usr.sbin/bhyve/uart_emul.c 285217 2015-07-06 19:33:29Z neel $
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: releng/11.0/usr.sbin/bhyve/uart_emul.c 285217 2015-07-06 19:33:29Z neel $");
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
275static uint8_t
276modem_status(uint8_t mcr)
277{
278	uint8_t msr;
279
280	if (mcr & MCR_LOOPBACK) {
281		/*
282		 * In the loopback mode certain bits from the MCR are
283		 * reflected back into MSR.
284		 */
285		msr = 0;
286		if (mcr & MCR_RTS)
287			msr |= MSR_CTS;
288		if (mcr & MCR_DTR)
289			msr |= MSR_DSR;
290		if (mcr & MCR_OUT1)
291			msr |= MSR_RI;
292		if (mcr & MCR_OUT2)
293			msr |= MSR_DCD;
294	} else {
295		/*
296		 * Always assert DCD and DSR so tty open doesn't block
297		 * even if CLOCAL is turned off.
298		 */
299		msr = MSR_DCD | MSR_DSR;
300	}
301	assert((msr & MSR_DELTA_MASK) == 0);
302
303	return (msr);
304}
305
306/*
307 * The IIR returns a prioritized interrupt reason:
308 * - receive data available
309 * - transmit holding register empty
310 * - modem status change
311 *
312 * Return an interrupt reason if one is available.
313 */
314static int
315uart_intr_reason(struct uart_softc *sc)
316{
317
318	if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
319		return (IIR_RLS);
320	else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0)
321		return (IIR_RXTOUT);
322	else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
323		return (IIR_TXRDY);
324	else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)
325		return (IIR_MLSC);
326	else
327		return (IIR_NOPEND);
328}
329
330static void
331uart_reset(struct uart_softc *sc)
332{
333	uint16_t divisor;
334
335	divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;
336	sc->dll = divisor;
337	sc->dlh = divisor >> 16;
338	sc->msr = modem_status(sc->mcr);
339
340	rxfifo_reset(sc, 1);	/* no fifo until enabled by software */
341}
342
343/*
344 * Toggle the COM port's intr pin depending on whether or not we have an
345 * interrupt condition to report to the processor.
346 */
347static void
348uart_toggle_intr(struct uart_softc *sc)
349{
350	uint8_t intr_reason;
351
352	intr_reason = uart_intr_reason(sc);
353
354	if (intr_reason == IIR_NOPEND)
355		(*sc->intr_deassert)(sc->arg);
356	else
357		(*sc->intr_assert)(sc->arg);
358}
359
360static void
361uart_drain(int fd, enum ev_type ev, void *arg)
362{
363	struct uart_softc *sc;
364	int ch;
365
366	sc = arg;
367
368	assert(fd == sc->tty.fd);
369	assert(ev == EVF_READ);
370
371	/*
372	 * This routine is called in the context of the mevent thread
373	 * to take out the softc lock to protect against concurrent
374	 * access from a vCPU i/o exit
375	 */
376	pthread_mutex_lock(&sc->mtx);
377
378	if ((sc->mcr & MCR_LOOPBACK) != 0) {
379		(void) ttyread(&sc->tty);
380	} else {
381		while (rxfifo_available(sc) &&
382		       ((ch = ttyread(&sc->tty)) != -1)) {
383			rxfifo_putchar(sc, ch);
384		}
385		uart_toggle_intr(sc);
386	}
387
388	pthread_mutex_unlock(&sc->mtx);
389}
390
391void
392uart_write(struct uart_softc *sc, int offset, uint8_t value)
393{
394	int fifosz;
395	uint8_t msr;
396
397	pthread_mutex_lock(&sc->mtx);
398
399	/*
400	 * Take care of the special case DLAB accesses first
401	 */
402	if ((sc->lcr & LCR_DLAB) != 0) {
403		if (offset == REG_DLL) {
404			sc->dll = value;
405			goto done;
406		}
407
408		if (offset == REG_DLH) {
409			sc->dlh = value;
410			goto done;
411		}
412	}
413
414        switch (offset) {
415	case REG_DATA:
416		if (sc->mcr & MCR_LOOPBACK) {
417			if (rxfifo_putchar(sc, value) != 0)
418				sc->lsr |= LSR_OE;
419		} else if (sc->tty.opened) {
420			ttywrite(&sc->tty, value);
421		} /* else drop on floor */
422		sc->thre_int_pending = true;
423		break;
424	case REG_IER:
425		/*
426		 * Apply mask so that bits 4-7 are 0
427		 * Also enables bits 0-3 only if they're 1
428		 */
429		sc->ier = value & 0x0F;
430		break;
431		case REG_FCR:
432			/*
433			 * When moving from FIFO and 16450 mode and vice versa,
434			 * the FIFO contents are reset.
435			 */
436			if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
437				fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
438				rxfifo_reset(sc, fifosz);
439			}
440
441			/*
442			 * The FCR_ENABLE bit must be '1' for the programming
443			 * of other FCR bits to be effective.
444			 */
445			if ((value & FCR_ENABLE) == 0) {
446				sc->fcr = 0;
447			} else {
448				if ((value & FCR_RCV_RST) != 0)
449					rxfifo_reset(sc, FIFOSZ);
450
451				sc->fcr = value &
452					 (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
453			}
454			break;
455		case REG_LCR:
456			sc->lcr = value;
457			break;
458		case REG_MCR:
459			/* Apply mask so that bits 5-7 are 0 */
460			sc->mcr = value & 0x1F;
461			msr = modem_status(sc->mcr);
462
463			/*
464			 * Detect if there has been any change between the
465			 * previous and the new value of MSR. If there is
466			 * then assert the appropriate MSR delta bit.
467			 */
468			if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
469				sc->msr |= MSR_DCTS;
470			if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
471				sc->msr |= MSR_DDSR;
472			if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
473				sc->msr |= MSR_DDCD;
474			if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
475				sc->msr |= MSR_TERI;
476
477			/*
478			 * Update the value of MSR while retaining the delta
479			 * bits.
480			 */
481			sc->msr &= MSR_DELTA_MASK;
482			sc->msr |= msr;
483			break;
484		case REG_LSR:
485			/*
486			 * Line status register is not meant to be written to
487			 * during normal operation.
488			 */
489			break;
490		case REG_MSR:
491			/*
492			 * As far as I can tell MSR is a read-only register.
493			 */
494			break;
495		case REG_SCR:
496			sc->scr = value;
497			break;
498		default:
499			break;
500	}
501
502done:
503	uart_toggle_intr(sc);
504	pthread_mutex_unlock(&sc->mtx);
505}
506
507uint8_t
508uart_read(struct uart_softc *sc, int offset)
509{
510	uint8_t iir, intr_reason, reg;
511
512	pthread_mutex_lock(&sc->mtx);
513
514	/*
515	 * Take care of the special case DLAB accesses first
516	 */
517	if ((sc->lcr & LCR_DLAB) != 0) {
518		if (offset == REG_DLL) {
519			reg = sc->dll;
520			goto done;
521		}
522
523		if (offset == REG_DLH) {
524			reg = sc->dlh;
525			goto done;
526		}
527	}
528
529	switch (offset) {
530	case REG_DATA:
531		reg = rxfifo_getchar(sc);
532		break;
533	case REG_IER:
534		reg = sc->ier;
535		break;
536	case REG_IIR:
537		iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
538
539		intr_reason = uart_intr_reason(sc);
540
541		/*
542		 * Deal with side effects of reading the IIR register
543		 */
544		if (intr_reason == IIR_TXRDY)
545			sc->thre_int_pending = false;
546
547		iir |= intr_reason;
548
549		reg = iir;
550		break;
551	case REG_LCR:
552		reg = sc->lcr;
553		break;
554	case REG_MCR:
555		reg = sc->mcr;
556		break;
557	case REG_LSR:
558		/* Transmitter is always ready for more data */
559		sc->lsr |= LSR_TEMT | LSR_THRE;
560
561		/* Check for new receive data */
562		if (rxfifo_numchars(sc) > 0)
563			sc->lsr |= LSR_RXRDY;
564		else
565			sc->lsr &= ~LSR_RXRDY;
566
567		reg = sc->lsr;
568
569		/* The LSR_OE bit is cleared on LSR read */
570		sc->lsr &= ~LSR_OE;
571		break;
572	case REG_MSR:
573		/*
574		 * MSR delta bits are cleared on read
575		 */
576		reg = sc->msr;
577		sc->msr &= ~MSR_DELTA_MASK;
578		break;
579	case REG_SCR:
580		reg = sc->scr;
581		break;
582	default:
583		reg = 0xFF;
584		break;
585	}
586
587done:
588	uart_toggle_intr(sc);
589	pthread_mutex_unlock(&sc->mtx);
590
591	return (reg);
592}
593
594int
595uart_legacy_alloc(int which, int *baseaddr, int *irq)
596{
597
598	if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse)
599		return (-1);
600
601	uart_lres[which].inuse = true;
602	*baseaddr = uart_lres[which].baseaddr;
603	*irq = uart_lres[which].irq;
604
605	return (0);
606}
607
608struct uart_softc *
609uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
610    void *arg)
611{
612	struct uart_softc *sc;
613
614	sc = calloc(1, sizeof(struct uart_softc));
615
616	sc->arg = arg;
617	sc->intr_assert = intr_assert;
618	sc->intr_deassert = intr_deassert;
619
620	pthread_mutex_init(&sc->mtx, NULL);
621
622	uart_reset(sc);
623
624	return (sc);
625}
626
627static int
628uart_tty_backend(struct uart_softc *sc, const char *opts)
629{
630	int fd;
631	int retval;
632
633	retval = -1;
634
635	fd = open(opts, O_RDWR | O_NONBLOCK);
636	if (fd > 0 && isatty(fd)) {
637		sc->tty.fd = fd;
638		sc->tty.opened = true;
639		retval = 0;
640	}
641
642	return (retval);
643}
644
645int
646uart_set_backend(struct uart_softc *sc, const char *opts)
647{
648	int retval;
649
650	retval = -1;
651
652	if (opts == NULL)
653		return (0);
654
655	if (strcmp("stdio", opts) == 0) {
656		if (!uart_stdio) {
657			sc->tty.fd = STDIN_FILENO;
658			sc->tty.opened = true;
659			uart_stdio = true;
660			retval = 0;
661		}
662	} else if (uart_tty_backend(sc, opts) == 0) {
663		retval = 0;
664	}
665
666	/* Make the backend file descriptor non-blocking */
667	if (retval == 0)
668		retval = fcntl(sc->tty.fd, F_SETFL, O_NONBLOCK);
669
670	if (retval == 0)
671		uart_opentty(sc);
672
673	return (retval);
674}
675