xref: /kvmtool/hw/serial.c (revision 133bedc1b844e1c883e202c511d2686a2468fb7f)
1899fe063SPekka Enberg #include "kvm/8250-serial.h"
213a7760fSPekka Enberg 
313a7760fSPekka Enberg #include "kvm/ioport.h"
446aa8d69SPekka Enberg #include "kvm/util.h"
5e557eef9SPekka Enberg #include "kvm/kvm.h"
613a7760fSPekka Enberg 
74e49b05bSCyrill Gorcunov #include <linux/serial_reg.h>
84e49b05bSCyrill Gorcunov 
946aa8d69SPekka Enberg #include <stdbool.h>
1076b4a122SPekka Enberg #include <poll.h>
1113a7760fSPekka Enberg 
1246aa8d69SPekka Enberg struct serial8250_device {
1346aa8d69SPekka Enberg 	uint16_t		iobase;
14e557eef9SPekka Enberg 	uint8_t			irq;
1576b4a122SPekka Enberg 
1676b4a122SPekka Enberg 	uint8_t			thr;
1746aa8d69SPekka Enberg 	uint8_t			dll;
1846aa8d69SPekka Enberg 	uint8_t			dlm;
19e557eef9SPekka Enberg 	uint8_t			iir;
2046aa8d69SPekka Enberg 	uint8_t			ier;
2146aa8d69SPekka Enberg 	uint8_t			fcr;
2246aa8d69SPekka Enberg 	uint8_t			lcr;
2346aa8d69SPekka Enberg 	uint8_t			mcr;
2476b4a122SPekka Enberg 	uint8_t			lsr;
2546aa8d69SPekka Enberg 	uint8_t			scr;
26*133bedc1SPekka Enberg 
27*133bedc1SPekka Enberg 	uint8_t			counter;
2846aa8d69SPekka Enberg };
2946aa8d69SPekka Enberg 
30e62c18deSPekka Enberg static struct serial8250_device devices[] = {
31c6a69c61SPekka Enberg 	/* ttyS0 */
32c6a69c61SPekka Enberg 	[0]	= {
33c6a69c61SPekka Enberg 		.iobase			= 0x3f8,
34e557eef9SPekka Enberg 		.irq			= 4,
35e557eef9SPekka Enberg 
366d620acbSCyrill Gorcunov 		.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
37c6a69c61SPekka Enberg 	},
38e62c18deSPekka Enberg 	/* ttyS1 */
39e62c18deSPekka Enberg 	[1]	= {
40e62c18deSPekka Enberg 		.iobase			= 0x2f8,
41e62c18deSPekka Enberg 		.irq			= 3,
42*133bedc1SPekka Enberg 
43*133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
44e62c18deSPekka Enberg 	},
45e62c18deSPekka Enberg 	/* ttyS2 */
46e62c18deSPekka Enberg 	[2]	= {
47e62c18deSPekka Enberg 		.iobase			= 0x3e8,
48e62c18deSPekka Enberg 		.irq			= 4,
49*133bedc1SPekka Enberg 
50*133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
51e62c18deSPekka Enberg 	},
5246aa8d69SPekka Enberg };
5346aa8d69SPekka Enberg 
5476b4a122SPekka Enberg static int read_char(int fd)
5576b4a122SPekka Enberg {
5676b4a122SPekka Enberg 	int c;
5776b4a122SPekka Enberg 
5876b4a122SPekka Enberg 	if (read(fd, &c, 1) < 0)
5976b4a122SPekka Enberg 		return -1;
6076b4a122SPekka Enberg 
6176b4a122SPekka Enberg 	return c;
6276b4a122SPekka Enberg }
6376b4a122SPekka Enberg 
6476b4a122SPekka Enberg static bool is_readable(int fd)
6576b4a122SPekka Enberg {
666d54df74SCyrill Gorcunov 	struct pollfd pollfd = (struct pollfd) {
6776b4a122SPekka Enberg 		.fd	= fd,
6876b4a122SPekka Enberg 		.events	= POLLIN,
6976b4a122SPekka Enberg 	};
7076b4a122SPekka Enberg 
716d54df74SCyrill Gorcunov 	return poll(&pollfd, 1, 0) > 0;
7276b4a122SPekka Enberg }
7376b4a122SPekka Enberg 
74c6a69c61SPekka Enberg /*
75c6a69c61SPekka Enberg  * Interrupts are injected for ttyS0 only.
76c6a69c61SPekka Enberg  */
778bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self)
788bb34e0dSPekka Enberg {
79c6a69c61SPekka Enberg 	struct serial8250_device *dev = &devices[0];
80934c193bSPekka Enberg 	uint8_t new_iir;
81934c193bSPekka Enberg 
82c6a69c61SPekka Enberg 	dev->iir	= UART_IIR_NO_INT;
83934c193bSPekka Enberg 
84934c193bSPekka Enberg 	/* No interrupts enabled. Exit... */
85c6a69c61SPekka Enberg 	if (!(dev->ier & (UART_IER_THRI|UART_IER_RDI)))
86934c193bSPekka Enberg 		return;
87934c193bSPekka Enberg 
88934c193bSPekka Enberg 	new_iir		= 0;
89934c193bSPekka Enberg 
90934c193bSPekka Enberg 	/* We're always good for guest sending data. */
91c6a69c61SPekka Enberg 	if (dev->ier & UART_IER_THRI)
92934c193bSPekka Enberg 		new_iir			|= UART_IIR_THRI;
93934c193bSPekka Enberg 
94934c193bSPekka Enberg 	/* Is there input in stdin to send to the guest? */
95c6a69c61SPekka Enberg 	if (!(dev->lsr & UART_LSR_DR) && is_readable(fileno(stdin))) {
9676b4a122SPekka Enberg 		int c;
9776b4a122SPekka Enberg 
9876b4a122SPekka Enberg 		c			= read_char(fileno(stdin));
9976b4a122SPekka Enberg 		if (c >= 0) {
100c6a69c61SPekka Enberg 			dev->thr		= c;
101c6a69c61SPekka Enberg 			dev->lsr		|= UART_LSR_DR;
102934c193bSPekka Enberg 			new_iir			|= UART_IIR_RDI;
10376b4a122SPekka Enberg 		}
10476b4a122SPekka Enberg 	}
10576b4a122SPekka Enberg 
106934c193bSPekka Enberg 	/* Only send an IRQ if there's work to do. */
107934c193bSPekka Enberg 	if (new_iir) {
108c6a69c61SPekka Enberg 		dev->iir		= new_iir;
109c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
110c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
111e557eef9SPekka Enberg 	}
1128bb34e0dSPekka Enberg }
1138bb34e0dSPekka Enberg 
114c6a69c61SPekka Enberg static struct serial8250_device *find_device(uint16_t port)
115c6a69c61SPekka Enberg {
116c6a69c61SPekka Enberg 	unsigned int i;
117c6a69c61SPekka Enberg 
118c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
119c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
120c6a69c61SPekka Enberg 
121c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
122c6a69c61SPekka Enberg 			return dev;
123c6a69c61SPekka Enberg 	}
124c6a69c61SPekka Enberg 	return NULL;
125c6a69c61SPekka Enberg }
126c6a69c61SPekka Enberg 
12746aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
12813a7760fSPekka Enberg {
129c6a69c61SPekka Enberg 	struct serial8250_device *dev;
130c6a69c61SPekka Enberg 	uint16_t offset;
13146aa8d69SPekka Enberg 
132c6a69c61SPekka Enberg 	dev		= find_device(port);
133c6a69c61SPekka Enberg 	if (!dev)
134c6a69c61SPekka Enberg 		return false;
135c6a69c61SPekka Enberg 
136c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
137c6a69c61SPekka Enberg 
138c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
13946aa8d69SPekka Enberg 		switch (offset) {
1404e49b05bSCyrill Gorcunov 		case UART_DLL:
141c6a69c61SPekka Enberg 			dev->dll		= ioport__read8(data);
14246aa8d69SPekka Enberg 			break;
1434e49b05bSCyrill Gorcunov 		case UART_DLM:
144c6a69c61SPekka Enberg 			dev->dlm		= ioport__read8(data);
14546aa8d69SPekka Enberg 			break;
1464e49b05bSCyrill Gorcunov 		case UART_FCR:
147c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
14846aa8d69SPekka Enberg 			break;
1494e49b05bSCyrill Gorcunov 		case UART_LCR:
150c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
15146aa8d69SPekka Enberg 			break;
15246aa8d69SPekka Enberg 		default:
15346aa8d69SPekka Enberg 			return false;
15446aa8d69SPekka Enberg 		}
15546aa8d69SPekka Enberg 	} else {
15646aa8d69SPekka Enberg 		switch (offset) {
1574e49b05bSCyrill Gorcunov 		case UART_TX: {
15813a7760fSPekka Enberg 			char *p = data;
159f2d8dc88SCyrill Gorcunov 			int i;
16013a7760fSPekka Enberg 
161f2d8dc88SCyrill Gorcunov 			while (count--) {
162f2d8dc88SCyrill Gorcunov 				for (i = 0; i < size; i++)
163b7475544SPekka Enberg 					fprintf(stdout, "%c", *p++);
1645b9d0b58SAsias He 			}
165b7475544SPekka Enberg 			fflush(stdout);
166e557eef9SPekka Enberg 
167*133bedc1SPekka Enberg 			if (dev->counter++ > 10) {
168*133bedc1SPekka Enberg 				dev->iir		= UART_IIR_NO_INT;
169*133bedc1SPekka Enberg 				dev->counter		= 0;
170*133bedc1SPekka Enberg 			}
171*133bedc1SPekka Enberg 
17246aa8d69SPekka Enberg 			break;
17346aa8d69SPekka Enberg 		}
1744e49b05bSCyrill Gorcunov 		case UART_IER:
175c6a69c61SPekka Enberg 			dev->ier		= ioport__read8(data);
17646aa8d69SPekka Enberg 			break;
1774e49b05bSCyrill Gorcunov 		case UART_FCR:
178c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
17946aa8d69SPekka Enberg 			break;
1804e49b05bSCyrill Gorcunov 		case UART_LCR:
181c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
18246aa8d69SPekka Enberg 			break;
1834e49b05bSCyrill Gorcunov 		case UART_MCR:
184c6a69c61SPekka Enberg 			dev->mcr		= ioport__read8(data);
18546aa8d69SPekka Enberg 			break;
1864e49b05bSCyrill Gorcunov 		case UART_SCR:
187c6a69c61SPekka Enberg 			dev->scr		= ioport__read8(data);
18846aa8d69SPekka Enberg 			break;
18946aa8d69SPekka Enberg 		default:
19046aa8d69SPekka Enberg 			return false;
19146aa8d69SPekka Enberg 		}
19246aa8d69SPekka Enberg 	}
19313a7760fSPekka Enberg 
19413a7760fSPekka Enberg 	return true;
19513a7760fSPekka Enberg }
19613a7760fSPekka Enberg 
19746aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
19825af6674SPekka Enberg {
199c6a69c61SPekka Enberg 	struct serial8250_device *dev;
200c6a69c61SPekka Enberg 	uint16_t offset;
20146aa8d69SPekka Enberg 
202c6a69c61SPekka Enberg 	dev		= find_device(port);
203c6a69c61SPekka Enberg 	if (!dev)
204c6a69c61SPekka Enberg 		return false;
205c6a69c61SPekka Enberg 
206c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
207c6a69c61SPekka Enberg 
208c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB)
20946aa8d69SPekka Enberg 		return false;
21046aa8d69SPekka Enberg 
21146aa8d69SPekka Enberg 	switch (offset) {
2124e49b05bSCyrill Gorcunov 	case UART_TX:
213c6a69c61SPekka Enberg 		if (dev->lsr & UART_LSR_DR) {
214*133bedc1SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
215*133bedc1SPekka Enberg 
216c6a69c61SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
217c6a69c61SPekka Enberg 			ioport__write8(data, dev->thr);
21876b4a122SPekka Enberg 		}
21946aa8d69SPekka Enberg 		break;
2204e49b05bSCyrill Gorcunov 	case UART_IER:
221c6a69c61SPekka Enberg 		ioport__write8(data, dev->ier);
22246aa8d69SPekka Enberg 		break;
2234e49b05bSCyrill Gorcunov 	case UART_IIR:
224c6a69c61SPekka Enberg 		ioport__write8(data, dev->iir);
22546aa8d69SPekka Enberg 		break;
2264e49b05bSCyrill Gorcunov 	case UART_LCR:
227c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
22846aa8d69SPekka Enberg 		break;
2294e49b05bSCyrill Gorcunov 	case UART_MCR:
230c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
23146aa8d69SPekka Enberg 		break;
2324e49b05bSCyrill Gorcunov 	case UART_LSR:
233c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
23446aa8d69SPekka Enberg 		break;
2354e49b05bSCyrill Gorcunov 	case UART_MSR:
2369a7428ddSPekka Enberg 		ioport__write8(data, UART_MSR_CTS);
23746aa8d69SPekka Enberg 		break;
2384e49b05bSCyrill Gorcunov 	case UART_SCR:
239c6a69c61SPekka Enberg 		ioport__write8(data, dev->scr);
24046aa8d69SPekka Enberg 		break;
24146aa8d69SPekka Enberg 	default:
24246aa8d69SPekka Enberg 		return false;
24325af6674SPekka Enberg 	}
24425af6674SPekka Enberg 
24513a7760fSPekka Enberg 	return true;
24613a7760fSPekka Enberg }
24713a7760fSPekka Enberg 
24846aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
24946aa8d69SPekka Enberg 	.io_in		= serial8250_in,
25046aa8d69SPekka Enberg 	.io_out		= serial8250_out,
251a93ec68bSPekka Enberg };
252a93ec68bSPekka Enberg 
253899fe063SPekka Enberg void serial8250__init(void)
25413a7760fSPekka Enberg {
255c6a69c61SPekka Enberg 	unsigned int i;
256c6a69c61SPekka Enberg 
257c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
258c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
259c6a69c61SPekka Enberg 
260c6a69c61SPekka Enberg 		ioport__register(dev->iobase, &serial8250_ops, 8);
261c6a69c61SPekka Enberg 	}
26213a7760fSPekka Enberg }
263