xref: /kvmtool/hw/serial.c (revision 251cf9a60d724ab0e69fdac297dc6c3c2554c551)
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 
16*251cf9a6SPekka Enberg 	uint8_t			rbr;		/* receive buffer */
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;
26133bedc1SPekka Enberg 
27133bedc1SPekka 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,
42133bedc1SPekka Enberg 
43133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
44e62c18deSPekka Enberg 	},
45e62c18deSPekka Enberg 	/* ttyS2 */
46e62c18deSPekka Enberg 	[2]	= {
47e62c18deSPekka Enberg 		.iobase			= 0x3e8,
48e62c18deSPekka Enberg 		.irq			= 4,
49133bedc1SPekka Enberg 
50133bedc1SPekka 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 
74*251cf9a6SPekka Enberg static void serial8250__receive(struct kvm *self, struct serial8250_device *dev)
75*251cf9a6SPekka Enberg {
76*251cf9a6SPekka Enberg 	int c;
77*251cf9a6SPekka Enberg 
78*251cf9a6SPekka Enberg 	if (dev->lsr & UART_LSR_DR)
79*251cf9a6SPekka Enberg 		return;
80*251cf9a6SPekka Enberg 
81*251cf9a6SPekka Enberg 	if (!is_readable(fileno(stdin)))
82*251cf9a6SPekka Enberg 		return;
83*251cf9a6SPekka Enberg 
84*251cf9a6SPekka Enberg 	c		= read_char(fileno(stdin));
85*251cf9a6SPekka Enberg 	if (c < 0)
86*251cf9a6SPekka Enberg 		return;
87*251cf9a6SPekka Enberg 
88*251cf9a6SPekka Enberg 	dev->rbr	= c;
89*251cf9a6SPekka Enberg 	dev->lsr	|= UART_LSR_DR;
90*251cf9a6SPekka Enberg }
91*251cf9a6SPekka Enberg 
92c6a69c61SPekka Enberg /*
93c6a69c61SPekka Enberg  * Interrupts are injected for ttyS0 only.
94c6a69c61SPekka Enberg  */
958bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self)
968bb34e0dSPekka Enberg {
97c6a69c61SPekka Enberg 	struct serial8250_device *dev = &devices[0];
98934c193bSPekka Enberg 	uint8_t new_iir;
99934c193bSPekka Enberg 
100c6a69c61SPekka Enberg 	dev->iir	= UART_IIR_NO_INT;
101934c193bSPekka Enberg 
102934c193bSPekka Enberg 	/* No interrupts enabled. Exit... */
103c6a69c61SPekka Enberg 	if (!(dev->ier & (UART_IER_THRI|UART_IER_RDI)))
104934c193bSPekka Enberg 		return;
105934c193bSPekka Enberg 
106*251cf9a6SPekka Enberg 	serial8250__receive(self, dev);
107*251cf9a6SPekka Enberg 
108934c193bSPekka Enberg 	new_iir		= 0;
109934c193bSPekka Enberg 
110*251cf9a6SPekka Enberg 	if (dev->lsr & UART_LSR_DR)
111934c193bSPekka Enberg 		new_iir			|= UART_IIR_RDI;
112*251cf9a6SPekka Enberg 	else if (dev->ier & UART_IER_THRI)
113*251cf9a6SPekka Enberg 		new_iir			|= UART_IIR_THRI;
11476b4a122SPekka Enberg 
115934c193bSPekka Enberg 	/* Only send an IRQ if there's work to do. */
116934c193bSPekka Enberg 	if (new_iir) {
1170bc4cf78SPekka Enberg 		dev->counter		= 0;
118c6a69c61SPekka Enberg 		dev->iir		= new_iir;
119c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
120c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
121e557eef9SPekka Enberg 	}
1228bb34e0dSPekka Enberg }
1238bb34e0dSPekka Enberg 
124c6a69c61SPekka Enberg static struct serial8250_device *find_device(uint16_t port)
125c6a69c61SPekka Enberg {
126c6a69c61SPekka Enberg 	unsigned int i;
127c6a69c61SPekka Enberg 
128c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
129c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
130c6a69c61SPekka Enberg 
131c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
132c6a69c61SPekka Enberg 			return dev;
133c6a69c61SPekka Enberg 	}
134c6a69c61SPekka Enberg 	return NULL;
135c6a69c61SPekka Enberg }
136c6a69c61SPekka Enberg 
13746aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
13813a7760fSPekka Enberg {
139c6a69c61SPekka Enberg 	struct serial8250_device *dev;
140c6a69c61SPekka Enberg 	uint16_t offset;
14146aa8d69SPekka Enberg 
142c6a69c61SPekka Enberg 	dev		= find_device(port);
143c6a69c61SPekka Enberg 	if (!dev)
144c6a69c61SPekka Enberg 		return false;
145c6a69c61SPekka Enberg 
146c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
147c6a69c61SPekka Enberg 
148c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
14946aa8d69SPekka Enberg 		switch (offset) {
1504e49b05bSCyrill Gorcunov 		case UART_DLL:
151c6a69c61SPekka Enberg 			dev->dll		= ioport__read8(data);
15246aa8d69SPekka Enberg 			break;
1534e49b05bSCyrill Gorcunov 		case UART_DLM:
154c6a69c61SPekka Enberg 			dev->dlm		= ioport__read8(data);
15546aa8d69SPekka Enberg 			break;
1564e49b05bSCyrill Gorcunov 		case UART_FCR:
157c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
15846aa8d69SPekka Enberg 			break;
1594e49b05bSCyrill Gorcunov 		case UART_LCR:
160c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
16146aa8d69SPekka Enberg 			break;
16246aa8d69SPekka Enberg 		default:
16346aa8d69SPekka Enberg 			return false;
16446aa8d69SPekka Enberg 		}
16546aa8d69SPekka Enberg 	} else {
16646aa8d69SPekka Enberg 		switch (offset) {
1674e49b05bSCyrill Gorcunov 		case UART_TX: {
16813a7760fSPekka Enberg 			char *p = data;
169f2d8dc88SCyrill Gorcunov 			int i;
17013a7760fSPekka Enberg 
171f2d8dc88SCyrill Gorcunov 			while (count--) {
172f2d8dc88SCyrill Gorcunov 				for (i = 0; i < size; i++)
173b7475544SPekka Enberg 					fprintf(stdout, "%c", *p++);
1745b9d0b58SAsias He 			}
175b7475544SPekka Enberg 			fflush(stdout);
176e557eef9SPekka Enberg 
1770bc4cf78SPekka Enberg 			if (dev->counter++ > 10)
178133bedc1SPekka Enberg 				dev->iir		= UART_IIR_NO_INT;
179133bedc1SPekka Enberg 
18046aa8d69SPekka Enberg 			break;
18146aa8d69SPekka Enberg 		}
1824e49b05bSCyrill Gorcunov 		case UART_IER:
183c6a69c61SPekka Enberg 			dev->ier		= ioport__read8(data);
18446aa8d69SPekka Enberg 			break;
1854e49b05bSCyrill Gorcunov 		case UART_FCR:
186c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
18746aa8d69SPekka Enberg 			break;
1884e49b05bSCyrill Gorcunov 		case UART_LCR:
189c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
19046aa8d69SPekka Enberg 			break;
1914e49b05bSCyrill Gorcunov 		case UART_MCR:
192c6a69c61SPekka Enberg 			dev->mcr		= ioport__read8(data);
19346aa8d69SPekka Enberg 			break;
1944e49b05bSCyrill Gorcunov 		case UART_SCR:
195c6a69c61SPekka Enberg 			dev->scr		= ioport__read8(data);
19646aa8d69SPekka Enberg 			break;
19746aa8d69SPekka Enberg 		default:
19846aa8d69SPekka Enberg 			return false;
19946aa8d69SPekka Enberg 		}
20046aa8d69SPekka Enberg 	}
20113a7760fSPekka Enberg 
20213a7760fSPekka Enberg 	return true;
20313a7760fSPekka Enberg }
20413a7760fSPekka Enberg 
20546aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
20625af6674SPekka Enberg {
207c6a69c61SPekka Enberg 	struct serial8250_device *dev;
208c6a69c61SPekka Enberg 	uint16_t offset;
20946aa8d69SPekka Enberg 
210c6a69c61SPekka Enberg 	dev		= find_device(port);
211c6a69c61SPekka Enberg 	if (!dev)
212c6a69c61SPekka Enberg 		return false;
213c6a69c61SPekka Enberg 
214c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
215c6a69c61SPekka Enberg 
216c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB)
21746aa8d69SPekka Enberg 		return false;
21846aa8d69SPekka Enberg 
21946aa8d69SPekka Enberg 	switch (offset) {
220*251cf9a6SPekka Enberg 	case UART_RX:
221c6a69c61SPekka Enberg 		if (dev->lsr & UART_LSR_DR) {
222133bedc1SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
223133bedc1SPekka Enberg 
224c6a69c61SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
225*251cf9a6SPekka Enberg 			ioport__write8(data, dev->rbr);
22676b4a122SPekka Enberg 		}
22746aa8d69SPekka Enberg 		break;
2284e49b05bSCyrill Gorcunov 	case UART_IER:
229c6a69c61SPekka Enberg 		ioport__write8(data, dev->ier);
23046aa8d69SPekka Enberg 		break;
2314e49b05bSCyrill Gorcunov 	case UART_IIR:
232c6a69c61SPekka Enberg 		ioport__write8(data, dev->iir);
23346aa8d69SPekka Enberg 		break;
2344e49b05bSCyrill Gorcunov 	case UART_LCR:
235c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
23646aa8d69SPekka Enberg 		break;
2374e49b05bSCyrill Gorcunov 	case UART_MCR:
238c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
23946aa8d69SPekka Enberg 		break;
2404e49b05bSCyrill Gorcunov 	case UART_LSR:
241c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
24246aa8d69SPekka Enberg 		break;
2434e49b05bSCyrill Gorcunov 	case UART_MSR:
2449a7428ddSPekka Enberg 		ioport__write8(data, UART_MSR_CTS);
24546aa8d69SPekka Enberg 		break;
2464e49b05bSCyrill Gorcunov 	case UART_SCR:
247c6a69c61SPekka Enberg 		ioport__write8(data, dev->scr);
24846aa8d69SPekka Enberg 		break;
24946aa8d69SPekka Enberg 	default:
25046aa8d69SPekka Enberg 		return false;
25125af6674SPekka Enberg 	}
25225af6674SPekka Enberg 
25313a7760fSPekka Enberg 	return true;
25413a7760fSPekka Enberg }
25513a7760fSPekka Enberg 
25646aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
25746aa8d69SPekka Enberg 	.io_in		= serial8250_in,
25846aa8d69SPekka Enberg 	.io_out		= serial8250_out,
259a93ec68bSPekka Enberg };
260a93ec68bSPekka Enberg 
261899fe063SPekka Enberg void serial8250__init(void)
26213a7760fSPekka Enberg {
263c6a69c61SPekka Enberg 	unsigned int i;
264c6a69c61SPekka Enberg 
265c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
266c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
267c6a69c61SPekka Enberg 
268c6a69c61SPekka Enberg 		ioport__register(dev->iobase, &serial8250_ops, 8);
269c6a69c61SPekka Enberg 	}
27013a7760fSPekka Enberg }
271