xref: /kvmtool/hw/serial.c (revision 369c01c0e76cc5b78578ec8bd5c923fa0a800238)
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 
16251cf9a6SPekka 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;
25*369c01c0SPekka Enberg 	uint8_t			msr;
2646aa8d69SPekka Enberg 	uint8_t			scr;
2746aa8d69SPekka Enberg };
2846aa8d69SPekka Enberg 
29e62c18deSPekka Enberg static struct serial8250_device devices[] = {
30c6a69c61SPekka Enberg 	/* ttyS0 */
31c6a69c61SPekka Enberg 	[0]	= {
32c6a69c61SPekka Enberg 		.iobase			= 0x3f8,
33e557eef9SPekka Enberg 		.irq			= 4,
34e557eef9SPekka Enberg 
356d620acbSCyrill Gorcunov 		.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
36*369c01c0SPekka Enberg 		.iir			= UART_IIR_NO_INT,
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 
74251cf9a6SPekka Enberg static void serial8250__receive(struct kvm *self, struct serial8250_device *dev)
75251cf9a6SPekka Enberg {
76251cf9a6SPekka Enberg 	int c;
77251cf9a6SPekka Enberg 
78251cf9a6SPekka Enberg 	if (!is_readable(fileno(stdin)))
79251cf9a6SPekka Enberg 		return;
80251cf9a6SPekka Enberg 
81251cf9a6SPekka Enberg 	c		= read_char(fileno(stdin));
82251cf9a6SPekka Enberg 	if (c < 0)
83251cf9a6SPekka Enberg 		return;
84251cf9a6SPekka Enberg 
85*369c01c0SPekka Enberg 	if (dev->lsr & UART_LSR_DR)
86*369c01c0SPekka Enberg 		dev->lsr	|= UART_LSR_OE;
87*369c01c0SPekka Enberg 
88251cf9a6SPekka Enberg 	dev->rbr	= c;
89251cf9a6SPekka Enberg 	dev->lsr	|= UART_LSR_DR;
90251cf9a6SPekka Enberg }
91251cf9a6SPekka 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 
99251cf9a6SPekka Enberg 	serial8250__receive(self, dev);
100251cf9a6SPekka Enberg 
101*369c01c0SPekka Enberg 	if (dev->ier & UART_IER_RDI && dev->lsr & UART_LSR_DR)
102*369c01c0SPekka Enberg 		dev->iir		= UART_IIR_RDI;
103251cf9a6SPekka Enberg 	else if (dev->ier & UART_IER_THRI)
104*369c01c0SPekka Enberg 		dev->iir		= UART_IIR_THRI;
105*369c01c0SPekka Enberg 	else
106*369c01c0SPekka Enberg 		dev->iir		= UART_IIR_NO_INT;
10776b4a122SPekka Enberg 
108*369c01c0SPekka Enberg 	if (dev->iir != UART_IIR_NO_INT) {
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;
146*369c01c0SPekka Enberg 		case UART_FCR:
147*369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
148*369c01c0SPekka Enberg 			break;
149*369c01c0SPekka Enberg 		case UART_LCR:
150*369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
151*369c01c0SPekka Enberg 			break;
152*369c01c0SPekka Enberg 		case UART_MCR:
153*369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
154*369c01c0SPekka Enberg 			break;
155*369c01c0SPekka Enberg 		case UART_LSR:
156*369c01c0SPekka Enberg 			/* Factory test */
157*369c01c0SPekka Enberg 			break;
158*369c01c0SPekka Enberg 		case UART_MSR:
159*369c01c0SPekka Enberg 			/* Not used */
160*369c01c0SPekka Enberg 			break;
161*369c01c0SPekka Enberg 		case UART_SCR:
162*369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
163*369c01c0SPekka Enberg 			break;
164*369c01c0SPekka Enberg 		default:
165*369c01c0SPekka Enberg 			return false;
16646aa8d69SPekka Enberg 		}
16746aa8d69SPekka Enberg 	} else {
16846aa8d69SPekka Enberg 		switch (offset) {
1694e49b05bSCyrill Gorcunov 		case UART_TX: {
17013a7760fSPekka Enberg 			char *p = data;
171f2d8dc88SCyrill Gorcunov 			int i;
17213a7760fSPekka Enberg 
173*369c01c0SPekka Enberg 			if (!(dev->mcr & UART_MCR_LOOP)) {
174f2d8dc88SCyrill Gorcunov 				while (count--) {
175f2d8dc88SCyrill Gorcunov 					for (i = 0; i < size; i++)
176b7475544SPekka Enberg 						fprintf(stdout, "%c", *p++);
1775b9d0b58SAsias He 				}
178b7475544SPekka Enberg 				fflush(stdout);
179*369c01c0SPekka Enberg 			}
180133bedc1SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
18146aa8d69SPekka Enberg 			break;
18246aa8d69SPekka Enberg 		}
183*369c01c0SPekka Enberg 		case UART_FCR:
184*369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
185*369c01c0SPekka Enberg 			break;
1864e49b05bSCyrill Gorcunov 		case UART_IER:
187*369c01c0SPekka Enberg 			dev->ier	= ioport__read8(data) & 0x3f;
18846aa8d69SPekka Enberg 			break;
189*369c01c0SPekka Enberg 		case UART_LCR:
190*369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
191*369c01c0SPekka Enberg 			break;
192*369c01c0SPekka Enberg 		case UART_MCR:
193*369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
194*369c01c0SPekka Enberg 			break;
195*369c01c0SPekka Enberg 		case UART_LSR:
196*369c01c0SPekka Enberg 			/* Factory test */
197*369c01c0SPekka Enberg 			break;
198*369c01c0SPekka Enberg 		case UART_MSR:
199*369c01c0SPekka Enberg 			/* Not used */
200*369c01c0SPekka Enberg 			break;
201*369c01c0SPekka Enberg 		case UART_SCR:
202*369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
203*369c01c0SPekka Enberg 			break;
204*369c01c0SPekka Enberg 		default:
205*369c01c0SPekka Enberg 			return false;
20646aa8d69SPekka Enberg 		}
20746aa8d69SPekka Enberg 	}
20813a7760fSPekka Enberg 	return true;
20913a7760fSPekka Enberg }
21013a7760fSPekka Enberg 
21146aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
21225af6674SPekka Enberg {
213c6a69c61SPekka Enberg 	struct serial8250_device *dev;
214c6a69c61SPekka Enberg 	uint16_t offset;
21546aa8d69SPekka Enberg 
216c6a69c61SPekka Enberg 	dev		= find_device(port);
217c6a69c61SPekka Enberg 	if (!dev)
218c6a69c61SPekka Enberg 		return false;
219c6a69c61SPekka Enberg 
220c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
221c6a69c61SPekka Enberg 
22219a2bb7dSPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
22319a2bb7dSPekka Enberg 		switch (offset) {
22419a2bb7dSPekka Enberg 		case UART_DLL:
22519a2bb7dSPekka Enberg 			ioport__write8(data, dev->dll);
22619a2bb7dSPekka Enberg 			return true;
22719a2bb7dSPekka Enberg 		case UART_DLM:
22819a2bb7dSPekka Enberg 			ioport__write8(data, dev->dlm);
22919a2bb7dSPekka Enberg 			return true;
230*369c01c0SPekka Enberg 		default:
231*369c01c0SPekka Enberg 			break;
23219a2bb7dSPekka Enberg 		}
23319a2bb7dSPekka Enberg 	} else {
23446aa8d69SPekka Enberg 		switch (offset) {
235251cf9a6SPekka Enberg 		case UART_RX:
236251cf9a6SPekka Enberg 			ioport__write8(data, dev->rbr);
237*369c01c0SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
238*369c01c0SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
23919a2bb7dSPekka Enberg 			return true;
2404e49b05bSCyrill Gorcunov 		case UART_IER:
241c6a69c61SPekka Enberg 			ioport__write8(data, dev->ier);
24219a2bb7dSPekka Enberg 			return true;
243*369c01c0SPekka Enberg 		default:
244*369c01c0SPekka Enberg 			break;
24519a2bb7dSPekka Enberg 		}
24619a2bb7dSPekka Enberg 	}
24719a2bb7dSPekka Enberg 
24819a2bb7dSPekka Enberg 	switch (offset) {
249*369c01c0SPekka Enberg 	case UART_IIR: {
250*369c01c0SPekka Enberg 		uint8_t iir = dev->iir;
251*369c01c0SPekka Enberg 
252*369c01c0SPekka Enberg 		if (dev->fcr & UART_FCR_ENABLE_FIFO)
253*369c01c0SPekka Enberg 			iir		|= 0xc0;
254*369c01c0SPekka Enberg 
255*369c01c0SPekka Enberg 		ioport__write8(data, iir);
25646aa8d69SPekka Enberg 		break;
257*369c01c0SPekka Enberg 	}
2584e49b05bSCyrill Gorcunov 	case UART_LCR:
259c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
26046aa8d69SPekka Enberg 		break;
2614e49b05bSCyrill Gorcunov 	case UART_MCR:
262c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
26346aa8d69SPekka Enberg 		break;
2644e49b05bSCyrill Gorcunov 	case UART_LSR:
265c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
266*369c01c0SPekka Enberg 		dev->lsr		&= ~(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI);
26746aa8d69SPekka Enberg 		break;
2684e49b05bSCyrill Gorcunov 	case UART_MSR:
269*369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
27046aa8d69SPekka Enberg 		break;
2714e49b05bSCyrill Gorcunov 	case UART_SCR:
272*369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
27346aa8d69SPekka Enberg 		break;
274*369c01c0SPekka Enberg 	default:
275*369c01c0SPekka Enberg 		return false;
27625af6674SPekka Enberg 	}
27713a7760fSPekka Enberg 	return true;
27813a7760fSPekka Enberg }
27913a7760fSPekka Enberg 
28046aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
28146aa8d69SPekka Enberg 	.io_in		= serial8250_in,
28246aa8d69SPekka Enberg 	.io_out		= serial8250_out,
283a93ec68bSPekka Enberg };
284a93ec68bSPekka Enberg 
285899fe063SPekka Enberg void serial8250__init(void)
28613a7760fSPekka Enberg {
287c6a69c61SPekka Enberg 	unsigned int i;
288c6a69c61SPekka Enberg 
289c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
290c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
291c6a69c61SPekka Enberg 
292c6a69c61SPekka Enberg 		ioport__register(dev->iobase, &serial8250_ops, 8);
293c6a69c61SPekka Enberg 	}
29413a7760fSPekka Enberg }
295