xref: /kvmtool/hw/serial.c (revision e62c18de5421cfeb5838da9c792340a5cd553835)
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;
2646aa8d69SPekka Enberg };
2746aa8d69SPekka Enberg 
28*e62c18deSPekka Enberg static struct serial8250_device devices[] = {
29c6a69c61SPekka Enberg 	/* ttyS0 */
30c6a69c61SPekka Enberg 	[0]	= {
31c6a69c61SPekka Enberg 		.iobase			= 0x3f8,
32e557eef9SPekka Enberg 		.irq			= 4,
33e557eef9SPekka Enberg 
346d620acbSCyrill Gorcunov 		.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
35c6a69c61SPekka Enberg 	},
36*e62c18deSPekka Enberg 	/* ttyS1 */
37*e62c18deSPekka Enberg 	[1]	= {
38*e62c18deSPekka Enberg 		.iobase			= 0x2f8,
39*e62c18deSPekka Enberg 		.irq			= 3,
40*e62c18deSPekka Enberg 	},
41*e62c18deSPekka Enberg 	/* ttyS2 */
42*e62c18deSPekka Enberg 	[2]	= {
43*e62c18deSPekka Enberg 		.iobase			= 0x3e8,
44*e62c18deSPekka Enberg 		.irq			= 4,
45*e62c18deSPekka Enberg 	},
4646aa8d69SPekka Enberg };
4746aa8d69SPekka Enberg 
4876b4a122SPekka Enberg static int read_char(int fd)
4976b4a122SPekka Enberg {
5076b4a122SPekka Enberg 	int c;
5176b4a122SPekka Enberg 
5276b4a122SPekka Enberg 	if (read(fd, &c, 1) < 0)
5376b4a122SPekka Enberg 		return -1;
5476b4a122SPekka Enberg 
5576b4a122SPekka Enberg 	return c;
5676b4a122SPekka Enberg }
5776b4a122SPekka Enberg 
5876b4a122SPekka Enberg static bool is_readable(int fd)
5976b4a122SPekka Enberg {
606d54df74SCyrill Gorcunov 	struct pollfd pollfd = (struct pollfd) {
6176b4a122SPekka Enberg 		.fd	= fd,
6276b4a122SPekka Enberg 		.events	= POLLIN,
6376b4a122SPekka Enberg 	};
6476b4a122SPekka Enberg 
656d54df74SCyrill Gorcunov 	return poll(&pollfd, 1, 0) > 0;
6676b4a122SPekka Enberg }
6776b4a122SPekka Enberg 
68c6a69c61SPekka Enberg /*
69c6a69c61SPekka Enberg  * Interrupts are injected for ttyS0 only.
70c6a69c61SPekka Enberg  */
718bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self)
728bb34e0dSPekka Enberg {
73c6a69c61SPekka Enberg 	struct serial8250_device *dev = &devices[0];
74934c193bSPekka Enberg 	uint8_t new_iir;
75934c193bSPekka Enberg 
76c6a69c61SPekka Enberg 	dev->iir	= UART_IIR_NO_INT;
77934c193bSPekka Enberg 
78934c193bSPekka Enberg 	/* No interrupts enabled. Exit... */
79c6a69c61SPekka Enberg 	if (!(dev->ier & (UART_IER_THRI|UART_IER_RDI)))
80934c193bSPekka Enberg 		return;
81934c193bSPekka Enberg 
82934c193bSPekka Enberg 	new_iir		= 0;
83934c193bSPekka Enberg 
84934c193bSPekka Enberg 	/* We're always good for guest sending data. */
85c6a69c61SPekka Enberg 	if (dev->ier & UART_IER_THRI)
86934c193bSPekka Enberg 		new_iir			|= UART_IIR_THRI;
87934c193bSPekka Enberg 
88934c193bSPekka Enberg 	/* Is there input in stdin to send to the guest? */
89c6a69c61SPekka Enberg 	if (!(dev->lsr & UART_LSR_DR) && is_readable(fileno(stdin))) {
9076b4a122SPekka Enberg 		int c;
9176b4a122SPekka Enberg 
9276b4a122SPekka Enberg 		c			= read_char(fileno(stdin));
9376b4a122SPekka Enberg 		if (c >= 0) {
94c6a69c61SPekka Enberg 			dev->thr		= c;
95c6a69c61SPekka Enberg 			dev->lsr		|= UART_LSR_DR;
96934c193bSPekka Enberg 			new_iir			|= UART_IIR_RDI;
9776b4a122SPekka Enberg 		}
9876b4a122SPekka Enberg 	}
9976b4a122SPekka Enberg 
100934c193bSPekka Enberg 	/* Only send an IRQ if there's work to do. */
101934c193bSPekka Enberg 	if (new_iir) {
102c6a69c61SPekka Enberg 		dev->iir		= new_iir;
103c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
104c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
105e557eef9SPekka Enberg 	}
1068bb34e0dSPekka Enberg }
1078bb34e0dSPekka Enberg 
108c6a69c61SPekka Enberg static struct serial8250_device *find_device(uint16_t port)
109c6a69c61SPekka Enberg {
110c6a69c61SPekka Enberg 	unsigned int i;
111c6a69c61SPekka Enberg 
112c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
113c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
114c6a69c61SPekka Enberg 
115c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
116c6a69c61SPekka Enberg 			return dev;
117c6a69c61SPekka Enberg 	}
118c6a69c61SPekka Enberg 	return NULL;
119c6a69c61SPekka Enberg }
120c6a69c61SPekka Enberg 
12146aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
12213a7760fSPekka Enberg {
123c6a69c61SPekka Enberg 	struct serial8250_device *dev;
124c6a69c61SPekka Enberg 	uint16_t offset;
12546aa8d69SPekka Enberg 
126c6a69c61SPekka Enberg 	dev		= find_device(port);
127c6a69c61SPekka Enberg 	if (!dev)
128c6a69c61SPekka Enberg 		return false;
129c6a69c61SPekka Enberg 
130c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
131c6a69c61SPekka Enberg 
132c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
13346aa8d69SPekka Enberg 		switch (offset) {
1344e49b05bSCyrill Gorcunov 		case UART_DLL:
135c6a69c61SPekka Enberg 			dev->dll		= ioport__read8(data);
13646aa8d69SPekka Enberg 			break;
1374e49b05bSCyrill Gorcunov 		case UART_DLM:
138c6a69c61SPekka Enberg 			dev->dlm		= ioport__read8(data);
13946aa8d69SPekka Enberg 			break;
1404e49b05bSCyrill Gorcunov 		case UART_FCR:
141c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
14246aa8d69SPekka Enberg 			break;
1434e49b05bSCyrill Gorcunov 		case UART_LCR:
144c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
14546aa8d69SPekka Enberg 			break;
14646aa8d69SPekka Enberg 		default:
14746aa8d69SPekka Enberg 			return false;
14846aa8d69SPekka Enberg 		}
14946aa8d69SPekka Enberg 	} else {
15046aa8d69SPekka Enberg 		switch (offset) {
1514e49b05bSCyrill Gorcunov 		case UART_TX: {
15213a7760fSPekka Enberg 			char *p = data;
153f2d8dc88SCyrill Gorcunov 			int i;
15413a7760fSPekka Enberg 
155f2d8dc88SCyrill Gorcunov 			while (count--) {
156f2d8dc88SCyrill Gorcunov 				for (i = 0; i < size; i++)
157b7475544SPekka Enberg 					fprintf(stdout, "%c", *p++);
1585b9d0b58SAsias He 			}
159b7475544SPekka Enberg 			fflush(stdout);
160e557eef9SPekka Enberg 
16146aa8d69SPekka Enberg 			break;
16246aa8d69SPekka Enberg 		}
1634e49b05bSCyrill Gorcunov 		case UART_IER:
164c6a69c61SPekka Enberg 			dev->ier		= ioport__read8(data);
16546aa8d69SPekka Enberg 			break;
1664e49b05bSCyrill Gorcunov 		case UART_FCR:
167c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
16846aa8d69SPekka Enberg 			break;
1694e49b05bSCyrill Gorcunov 		case UART_LCR:
170c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
17146aa8d69SPekka Enberg 			break;
1724e49b05bSCyrill Gorcunov 		case UART_MCR:
173c6a69c61SPekka Enberg 			dev->mcr		= ioport__read8(data);
17446aa8d69SPekka Enberg 			break;
1754e49b05bSCyrill Gorcunov 		case UART_SCR:
176c6a69c61SPekka Enberg 			dev->scr		= ioport__read8(data);
17746aa8d69SPekka Enberg 			break;
17846aa8d69SPekka Enberg 		default:
17946aa8d69SPekka Enberg 			return false;
18046aa8d69SPekka Enberg 		}
18146aa8d69SPekka Enberg 	}
18213a7760fSPekka Enberg 
18313a7760fSPekka Enberg 	return true;
18413a7760fSPekka Enberg }
18513a7760fSPekka Enberg 
18646aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
18725af6674SPekka Enberg {
188c6a69c61SPekka Enberg 	struct serial8250_device *dev;
189c6a69c61SPekka Enberg 	uint16_t offset;
19046aa8d69SPekka Enberg 
191c6a69c61SPekka Enberg 	dev		= find_device(port);
192c6a69c61SPekka Enberg 	if (!dev)
193c6a69c61SPekka Enberg 		return false;
194c6a69c61SPekka Enberg 
195c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
196c6a69c61SPekka Enberg 
197c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB)
19846aa8d69SPekka Enberg 		return false;
19946aa8d69SPekka Enberg 
20046aa8d69SPekka Enberg 	switch (offset) {
2014e49b05bSCyrill Gorcunov 	case UART_TX:
202c6a69c61SPekka Enberg 		if (dev->lsr & UART_LSR_DR) {
203c6a69c61SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
204c6a69c61SPekka Enberg 			ioport__write8(data, dev->thr);
20576b4a122SPekka Enberg 		}
20646aa8d69SPekka Enberg 		break;
2074e49b05bSCyrill Gorcunov 	case UART_IER:
208c6a69c61SPekka Enberg 		ioport__write8(data, dev->ier);
20946aa8d69SPekka Enberg 		break;
2104e49b05bSCyrill Gorcunov 	case UART_IIR:
211c6a69c61SPekka Enberg 		ioport__write8(data, dev->iir);
21246aa8d69SPekka Enberg 		break;
2134e49b05bSCyrill Gorcunov 	case UART_LCR:
214c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
21546aa8d69SPekka Enberg 		break;
2164e49b05bSCyrill Gorcunov 	case UART_MCR:
217c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
21846aa8d69SPekka Enberg 		break;
2194e49b05bSCyrill Gorcunov 	case UART_LSR:
220c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
22146aa8d69SPekka Enberg 		break;
2224e49b05bSCyrill Gorcunov 	case UART_MSR:
2239a7428ddSPekka Enberg 		ioport__write8(data, UART_MSR_CTS);
22446aa8d69SPekka Enberg 		break;
2254e49b05bSCyrill Gorcunov 	case UART_SCR:
226c6a69c61SPekka Enberg 		ioport__write8(data, dev->scr);
22746aa8d69SPekka Enberg 		break;
22846aa8d69SPekka Enberg 	default:
22946aa8d69SPekka Enberg 		return false;
23025af6674SPekka Enberg 	}
23125af6674SPekka Enberg 
23213a7760fSPekka Enberg 	return true;
23313a7760fSPekka Enberg }
23413a7760fSPekka Enberg 
23546aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
23646aa8d69SPekka Enberg 	.io_in		= serial8250_in,
23746aa8d69SPekka Enberg 	.io_out		= serial8250_out,
238a93ec68bSPekka Enberg };
239a93ec68bSPekka Enberg 
240899fe063SPekka Enberg void serial8250__init(void)
24113a7760fSPekka Enberg {
242c6a69c61SPekka Enberg 	unsigned int i;
243c6a69c61SPekka Enberg 
244c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
245c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
246c6a69c61SPekka Enberg 
247c6a69c61SPekka Enberg 		ioport__register(dev->iobase, &serial8250_ops, 8);
248c6a69c61SPekka Enberg 	}
24913a7760fSPekka Enberg }
250