xref: /kvmtool/hw/serial.c (revision c6a69c614f9dfc56623dc85800c6551a219a3ff2)
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*c6a69c61SPekka Enberg static struct serial8250_device devices[1] = {
29*c6a69c61SPekka Enberg 	/* ttyS0 */
30*c6a69c61SPekka Enberg 	[0]	= {
31*c6a69c61SPekka Enberg 		.iobase			= 0x3f8,
32e557eef9SPekka Enberg 		.irq			= 4,
33e557eef9SPekka Enberg 
346d620acbSCyrill Gorcunov 		.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
35*c6a69c61SPekka Enberg 	},
3646aa8d69SPekka Enberg };
3746aa8d69SPekka Enberg 
3876b4a122SPekka Enberg static int read_char(int fd)
3976b4a122SPekka Enberg {
4076b4a122SPekka Enberg 	int c;
4176b4a122SPekka Enberg 
4276b4a122SPekka Enberg 	if (read(fd, &c, 1) < 0)
4376b4a122SPekka Enberg 		return -1;
4476b4a122SPekka Enberg 
4576b4a122SPekka Enberg 	return c;
4676b4a122SPekka Enberg }
4776b4a122SPekka Enberg 
4876b4a122SPekka Enberg static bool is_readable(int fd)
4976b4a122SPekka Enberg {
506d54df74SCyrill Gorcunov 	struct pollfd pollfd = (struct pollfd) {
5176b4a122SPekka Enberg 		.fd	= fd,
5276b4a122SPekka Enberg 		.events	= POLLIN,
5376b4a122SPekka Enberg 	};
5476b4a122SPekka Enberg 
556d54df74SCyrill Gorcunov 	return poll(&pollfd, 1, 0) > 0;
5676b4a122SPekka Enberg }
5776b4a122SPekka Enberg 
58*c6a69c61SPekka Enberg /*
59*c6a69c61SPekka Enberg  * Interrupts are injected for ttyS0 only.
60*c6a69c61SPekka Enberg  */
618bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self)
628bb34e0dSPekka Enberg {
63*c6a69c61SPekka Enberg 	struct serial8250_device *dev = &devices[0];
64934c193bSPekka Enberg 	uint8_t new_iir;
65934c193bSPekka Enberg 
66*c6a69c61SPekka Enberg 	dev->iir	= UART_IIR_NO_INT;
67934c193bSPekka Enberg 
68934c193bSPekka Enberg 	/* No interrupts enabled. Exit... */
69*c6a69c61SPekka Enberg 	if (!(dev->ier & (UART_IER_THRI|UART_IER_RDI)))
70934c193bSPekka Enberg 		return;
71934c193bSPekka Enberg 
72934c193bSPekka Enberg 	new_iir		= 0;
73934c193bSPekka Enberg 
74934c193bSPekka Enberg 	/* We're always good for guest sending data. */
75*c6a69c61SPekka Enberg 	if (dev->ier & UART_IER_THRI)
76934c193bSPekka Enberg 		new_iir			|= UART_IIR_THRI;
77934c193bSPekka Enberg 
78934c193bSPekka Enberg 	/* Is there input in stdin to send to the guest? */
79*c6a69c61SPekka Enberg 	if (!(dev->lsr & UART_LSR_DR) && is_readable(fileno(stdin))) {
8076b4a122SPekka Enberg 		int c;
8176b4a122SPekka Enberg 
8276b4a122SPekka Enberg 		c			= read_char(fileno(stdin));
8376b4a122SPekka Enberg 		if (c >= 0) {
84*c6a69c61SPekka Enberg 			dev->thr		= c;
85*c6a69c61SPekka Enberg 			dev->lsr		|= UART_LSR_DR;
86934c193bSPekka Enberg 			new_iir			|= UART_IIR_RDI;
8776b4a122SPekka Enberg 		}
8876b4a122SPekka Enberg 	}
8976b4a122SPekka Enberg 
90934c193bSPekka Enberg 	/* Only send an IRQ if there's work to do. */
91934c193bSPekka Enberg 	if (new_iir) {
92*c6a69c61SPekka Enberg 		dev->iir		= new_iir;
93*c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
94*c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
95e557eef9SPekka Enberg 	}
968bb34e0dSPekka Enberg }
978bb34e0dSPekka Enberg 
98*c6a69c61SPekka Enberg static struct serial8250_device *find_device(uint16_t port)
99*c6a69c61SPekka Enberg {
100*c6a69c61SPekka Enberg 	unsigned int i;
101*c6a69c61SPekka Enberg 
102*c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
103*c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
104*c6a69c61SPekka Enberg 
105*c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
106*c6a69c61SPekka Enberg 			return dev;
107*c6a69c61SPekka Enberg 	}
108*c6a69c61SPekka Enberg 	return NULL;
109*c6a69c61SPekka Enberg }
110*c6a69c61SPekka Enberg 
11146aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
11213a7760fSPekka Enberg {
113*c6a69c61SPekka Enberg 	struct serial8250_device *dev;
114*c6a69c61SPekka Enberg 	uint16_t offset;
11546aa8d69SPekka Enberg 
116*c6a69c61SPekka Enberg 	dev		= find_device(port);
117*c6a69c61SPekka Enberg 	if (!dev)
118*c6a69c61SPekka Enberg 		return false;
119*c6a69c61SPekka Enberg 
120*c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
121*c6a69c61SPekka Enberg 
122*c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
12346aa8d69SPekka Enberg 		switch (offset) {
1244e49b05bSCyrill Gorcunov 		case UART_DLL:
125*c6a69c61SPekka Enberg 			dev->dll		= ioport__read8(data);
12646aa8d69SPekka Enberg 			break;
1274e49b05bSCyrill Gorcunov 		case UART_DLM:
128*c6a69c61SPekka Enberg 			dev->dlm		= ioport__read8(data);
12946aa8d69SPekka Enberg 			break;
1304e49b05bSCyrill Gorcunov 		case UART_FCR:
131*c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
13246aa8d69SPekka Enberg 			break;
1334e49b05bSCyrill Gorcunov 		case UART_LCR:
134*c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
13546aa8d69SPekka Enberg 			break;
13646aa8d69SPekka Enberg 		default:
13746aa8d69SPekka Enberg 			return false;
13846aa8d69SPekka Enberg 		}
13946aa8d69SPekka Enberg 	} else {
14046aa8d69SPekka Enberg 		switch (offset) {
1414e49b05bSCyrill Gorcunov 		case UART_TX: {
14213a7760fSPekka Enberg 			char *p = data;
143f2d8dc88SCyrill Gorcunov 			int i;
14413a7760fSPekka Enberg 
145f2d8dc88SCyrill Gorcunov 			while (count--) {
146f2d8dc88SCyrill Gorcunov 				for (i = 0; i < size; i++)
147b7475544SPekka Enberg 					fprintf(stdout, "%c", *p++);
1485b9d0b58SAsias He 			}
149b7475544SPekka Enberg 			fflush(stdout);
150e557eef9SPekka Enberg 
15146aa8d69SPekka Enberg 			break;
15246aa8d69SPekka Enberg 		}
1534e49b05bSCyrill Gorcunov 		case UART_IER:
154*c6a69c61SPekka Enberg 			dev->ier		= ioport__read8(data);
15546aa8d69SPekka Enberg 			break;
1564e49b05bSCyrill Gorcunov 		case UART_FCR:
157*c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
15846aa8d69SPekka Enberg 			break;
1594e49b05bSCyrill Gorcunov 		case UART_LCR:
160*c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
16146aa8d69SPekka Enberg 			break;
1624e49b05bSCyrill Gorcunov 		case UART_MCR:
163*c6a69c61SPekka Enberg 			dev->mcr		= ioport__read8(data);
16446aa8d69SPekka Enberg 			break;
1654e49b05bSCyrill Gorcunov 		case UART_SCR:
166*c6a69c61SPekka Enberg 			dev->scr		= ioport__read8(data);
16746aa8d69SPekka Enberg 			break;
16846aa8d69SPekka Enberg 		default:
16946aa8d69SPekka Enberg 			return false;
17046aa8d69SPekka Enberg 		}
17146aa8d69SPekka Enberg 	}
17213a7760fSPekka Enberg 
17313a7760fSPekka Enberg 	return true;
17413a7760fSPekka Enberg }
17513a7760fSPekka Enberg 
17646aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
17725af6674SPekka Enberg {
178*c6a69c61SPekka Enberg 	struct serial8250_device *dev;
179*c6a69c61SPekka Enberg 	uint16_t offset;
18046aa8d69SPekka Enberg 
181*c6a69c61SPekka Enberg 	dev		= find_device(port);
182*c6a69c61SPekka Enberg 	if (!dev)
183*c6a69c61SPekka Enberg 		return false;
184*c6a69c61SPekka Enberg 
185*c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
186*c6a69c61SPekka Enberg 
187*c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB)
18846aa8d69SPekka Enberg 		return false;
18946aa8d69SPekka Enberg 
19046aa8d69SPekka Enberg 	switch (offset) {
1914e49b05bSCyrill Gorcunov 	case UART_TX:
192*c6a69c61SPekka Enberg 		if (dev->lsr & UART_LSR_DR) {
193*c6a69c61SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
194*c6a69c61SPekka Enberg 			ioport__write8(data, dev->thr);
19576b4a122SPekka Enberg 		}
19646aa8d69SPekka Enberg 		break;
1974e49b05bSCyrill Gorcunov 	case UART_IER:
198*c6a69c61SPekka Enberg 		ioport__write8(data, dev->ier);
19946aa8d69SPekka Enberg 		break;
2004e49b05bSCyrill Gorcunov 	case UART_IIR:
201*c6a69c61SPekka Enberg 		ioport__write8(data, dev->iir);
20246aa8d69SPekka Enberg 		break;
2034e49b05bSCyrill Gorcunov 	case UART_LCR:
204*c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
20546aa8d69SPekka Enberg 		break;
2064e49b05bSCyrill Gorcunov 	case UART_MCR:
207*c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
20846aa8d69SPekka Enberg 		break;
2094e49b05bSCyrill Gorcunov 	case UART_LSR:
210*c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
21146aa8d69SPekka Enberg 		break;
2124e49b05bSCyrill Gorcunov 	case UART_MSR:
2139a7428ddSPekka Enberg 		ioport__write8(data, UART_MSR_CTS);
21446aa8d69SPekka Enberg 		break;
2154e49b05bSCyrill Gorcunov 	case UART_SCR:
216*c6a69c61SPekka Enberg 		ioport__write8(data, dev->scr);
21746aa8d69SPekka Enberg 		break;
21846aa8d69SPekka Enberg 	default:
21946aa8d69SPekka Enberg 		return false;
22025af6674SPekka Enberg 	}
22125af6674SPekka Enberg 
22213a7760fSPekka Enberg 	return true;
22313a7760fSPekka Enberg }
22413a7760fSPekka Enberg 
22546aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
22646aa8d69SPekka Enberg 	.io_in		= serial8250_in,
22746aa8d69SPekka Enberg 	.io_out		= serial8250_out,
228a93ec68bSPekka Enberg };
229a93ec68bSPekka Enberg 
230899fe063SPekka Enberg void serial8250__init(void)
23113a7760fSPekka Enberg {
232*c6a69c61SPekka Enberg 	unsigned int i;
233*c6a69c61SPekka Enberg 
234*c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
235*c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
236*c6a69c61SPekka Enberg 
237*c6a69c61SPekka Enberg 		ioport__register(dev->iobase, &serial8250_ops, 8);
238*c6a69c61SPekka Enberg 	}
23913a7760fSPekka Enberg }
240