xref: /kvmtool/hw/serial.c (revision 0bc4cf78724592b5139b514b189d8bdb3bc9adf5)
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;
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 
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) {
108*0bc4cf78SPekka Enberg 		dev->counter		= 0;
109c6a69c61SPekka Enberg 		dev->iir		= new_iir;
110c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
111c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
112e557eef9SPekka Enberg 	}
1138bb34e0dSPekka Enberg }
1148bb34e0dSPekka Enberg 
115c6a69c61SPekka Enberg static struct serial8250_device *find_device(uint16_t port)
116c6a69c61SPekka Enberg {
117c6a69c61SPekka Enberg 	unsigned int i;
118c6a69c61SPekka Enberg 
119c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
120c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
121c6a69c61SPekka Enberg 
122c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
123c6a69c61SPekka Enberg 			return dev;
124c6a69c61SPekka Enberg 	}
125c6a69c61SPekka Enberg 	return NULL;
126c6a69c61SPekka Enberg }
127c6a69c61SPekka Enberg 
12846aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
12913a7760fSPekka Enberg {
130c6a69c61SPekka Enberg 	struct serial8250_device *dev;
131c6a69c61SPekka Enberg 	uint16_t offset;
13246aa8d69SPekka Enberg 
133c6a69c61SPekka Enberg 	dev		= find_device(port);
134c6a69c61SPekka Enberg 	if (!dev)
135c6a69c61SPekka Enberg 		return false;
136c6a69c61SPekka Enberg 
137c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
138c6a69c61SPekka Enberg 
139c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
14046aa8d69SPekka Enberg 		switch (offset) {
1414e49b05bSCyrill Gorcunov 		case UART_DLL:
142c6a69c61SPekka Enberg 			dev->dll		= ioport__read8(data);
14346aa8d69SPekka Enberg 			break;
1444e49b05bSCyrill Gorcunov 		case UART_DLM:
145c6a69c61SPekka Enberg 			dev->dlm		= ioport__read8(data);
14646aa8d69SPekka Enberg 			break;
1474e49b05bSCyrill Gorcunov 		case UART_FCR:
148c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
14946aa8d69SPekka Enberg 			break;
1504e49b05bSCyrill Gorcunov 		case UART_LCR:
151c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
15246aa8d69SPekka Enberg 			break;
15346aa8d69SPekka Enberg 		default:
15446aa8d69SPekka Enberg 			return false;
15546aa8d69SPekka Enberg 		}
15646aa8d69SPekka Enberg 	} else {
15746aa8d69SPekka Enberg 		switch (offset) {
1584e49b05bSCyrill Gorcunov 		case UART_TX: {
15913a7760fSPekka Enberg 			char *p = data;
160f2d8dc88SCyrill Gorcunov 			int i;
16113a7760fSPekka Enberg 
162f2d8dc88SCyrill Gorcunov 			while (count--) {
163f2d8dc88SCyrill Gorcunov 				for (i = 0; i < size; i++)
164b7475544SPekka Enberg 					fprintf(stdout, "%c", *p++);
1655b9d0b58SAsias He 			}
166b7475544SPekka Enberg 			fflush(stdout);
167e557eef9SPekka Enberg 
168*0bc4cf78SPekka Enberg 			if (dev->counter++ > 10)
169133bedc1SPekka Enberg 				dev->iir		= UART_IIR_NO_INT;
170133bedc1SPekka Enberg 
17146aa8d69SPekka Enberg 			break;
17246aa8d69SPekka Enberg 		}
1734e49b05bSCyrill Gorcunov 		case UART_IER:
174c6a69c61SPekka Enberg 			dev->ier		= ioport__read8(data);
17546aa8d69SPekka Enberg 			break;
1764e49b05bSCyrill Gorcunov 		case UART_FCR:
177c6a69c61SPekka Enberg 			dev->fcr		= ioport__read8(data);
17846aa8d69SPekka Enberg 			break;
1794e49b05bSCyrill Gorcunov 		case UART_LCR:
180c6a69c61SPekka Enberg 			dev->lcr		= ioport__read8(data);
18146aa8d69SPekka Enberg 			break;
1824e49b05bSCyrill Gorcunov 		case UART_MCR:
183c6a69c61SPekka Enberg 			dev->mcr		= ioport__read8(data);
18446aa8d69SPekka Enberg 			break;
1854e49b05bSCyrill Gorcunov 		case UART_SCR:
186c6a69c61SPekka Enberg 			dev->scr		= ioport__read8(data);
18746aa8d69SPekka Enberg 			break;
18846aa8d69SPekka Enberg 		default:
18946aa8d69SPekka Enberg 			return false;
19046aa8d69SPekka Enberg 		}
19146aa8d69SPekka Enberg 	}
19213a7760fSPekka Enberg 
19313a7760fSPekka Enberg 	return true;
19413a7760fSPekka Enberg }
19513a7760fSPekka Enberg 
19646aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
19725af6674SPekka Enberg {
198c6a69c61SPekka Enberg 	struct serial8250_device *dev;
199c6a69c61SPekka Enberg 	uint16_t offset;
20046aa8d69SPekka Enberg 
201c6a69c61SPekka Enberg 	dev		= find_device(port);
202c6a69c61SPekka Enberg 	if (!dev)
203c6a69c61SPekka Enberg 		return false;
204c6a69c61SPekka Enberg 
205c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
206c6a69c61SPekka Enberg 
207c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB)
20846aa8d69SPekka Enberg 		return false;
20946aa8d69SPekka Enberg 
21046aa8d69SPekka Enberg 	switch (offset) {
2114e49b05bSCyrill Gorcunov 	case UART_TX:
212c6a69c61SPekka Enberg 		if (dev->lsr & UART_LSR_DR) {
213133bedc1SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
214133bedc1SPekka Enberg 
215c6a69c61SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
216c6a69c61SPekka Enberg 			ioport__write8(data, dev->thr);
21776b4a122SPekka Enberg 		}
21846aa8d69SPekka Enberg 		break;
2194e49b05bSCyrill Gorcunov 	case UART_IER:
220c6a69c61SPekka Enberg 		ioport__write8(data, dev->ier);
22146aa8d69SPekka Enberg 		break;
2224e49b05bSCyrill Gorcunov 	case UART_IIR:
223c6a69c61SPekka Enberg 		ioport__write8(data, dev->iir);
22446aa8d69SPekka Enberg 		break;
2254e49b05bSCyrill Gorcunov 	case UART_LCR:
226c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
22746aa8d69SPekka Enberg 		break;
2284e49b05bSCyrill Gorcunov 	case UART_MCR:
229c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
23046aa8d69SPekka Enberg 		break;
2314e49b05bSCyrill Gorcunov 	case UART_LSR:
232c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
23346aa8d69SPekka Enberg 		break;
2344e49b05bSCyrill Gorcunov 	case UART_MSR:
2359a7428ddSPekka Enberg 		ioport__write8(data, UART_MSR_CTS);
23646aa8d69SPekka Enberg 		break;
2374e49b05bSCyrill Gorcunov 	case UART_SCR:
238c6a69c61SPekka Enberg 		ioport__write8(data, dev->scr);
23946aa8d69SPekka Enberg 		break;
24046aa8d69SPekka Enberg 	default:
24146aa8d69SPekka Enberg 		return false;
24225af6674SPekka Enberg 	}
24325af6674SPekka Enberg 
24413a7760fSPekka Enberg 	return true;
24513a7760fSPekka Enberg }
24613a7760fSPekka Enberg 
24746aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
24846aa8d69SPekka Enberg 	.io_in		= serial8250_in,
24946aa8d69SPekka Enberg 	.io_out		= serial8250_out,
250a93ec68bSPekka Enberg };
251a93ec68bSPekka Enberg 
252899fe063SPekka Enberg void serial8250__init(void)
25313a7760fSPekka Enberg {
254c6a69c61SPekka Enberg 	unsigned int i;
255c6a69c61SPekka Enberg 
256c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
257c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
258c6a69c61SPekka Enberg 
259c6a69c61SPekka Enberg 		ioport__register(dev->iobase, &serial8250_ops, 8);
260c6a69c61SPekka Enberg 	}
26113a7760fSPekka Enberg }
262