xref: /kvmtool/hw/serial.c (revision 8eb47d298631e727f9747e56faa14a40234b2d22)
1899fe063SPekka Enberg #include "kvm/8250-serial.h"
213a7760fSPekka Enberg 
3*8eb47d29SSasha Levin #include "kvm/read-write.h"
413a7760fSPekka Enberg #include "kvm/ioport.h"
546aa8d69SPekka Enberg #include "kvm/util.h"
6e557eef9SPekka Enberg #include "kvm/kvm.h"
713a7760fSPekka Enberg 
84e49b05bSCyrill Gorcunov #include <linux/serial_reg.h>
94e49b05bSCyrill Gorcunov 
1046aa8d69SPekka Enberg #include <stdbool.h>
1176b4a122SPekka Enberg #include <poll.h>
1213a7760fSPekka Enberg 
1346aa8d69SPekka Enberg struct serial8250_device {
1446aa8d69SPekka Enberg 	uint16_t		iobase;
15e557eef9SPekka Enberg 	uint8_t			irq;
1676b4a122SPekka Enberg 
17251cf9a6SPekka Enberg 	uint8_t			rbr;		/* receive buffer */
1846aa8d69SPekka Enberg 	uint8_t			dll;
1946aa8d69SPekka Enberg 	uint8_t			dlm;
20e557eef9SPekka Enberg 	uint8_t			iir;
2146aa8d69SPekka Enberg 	uint8_t			ier;
2246aa8d69SPekka Enberg 	uint8_t			fcr;
2346aa8d69SPekka Enberg 	uint8_t			lcr;
2446aa8d69SPekka Enberg 	uint8_t			mcr;
2576b4a122SPekka Enberg 	uint8_t			lsr;
26369c01c0SPekka Enberg 	uint8_t			msr;
2746aa8d69SPekka Enberg 	uint8_t			scr;
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 
36369c01c0SPekka Enberg 		.iir			= UART_IIR_NO_INT,
37bc4b0ffeSPekka Enberg 		.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
38bc4b0ffeSPekka Enberg 		.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS,
39bc4b0ffeSPekka Enberg 		.mcr			= UART_MCR_OUT2,
40c6a69c61SPekka Enberg 	},
41e62c18deSPekka Enberg 	/* ttyS1 */
42e62c18deSPekka Enberg 	[1]	= {
43e62c18deSPekka Enberg 		.iobase			= 0x2f8,
44e62c18deSPekka Enberg 		.irq			= 3,
45133bedc1SPekka Enberg 
46133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
47e62c18deSPekka Enberg 	},
48e62c18deSPekka Enberg 	/* ttyS2 */
49e62c18deSPekka Enberg 	[2]	= {
50e62c18deSPekka Enberg 		.iobase			= 0x3e8,
51e62c18deSPekka Enberg 		.irq			= 4,
52133bedc1SPekka Enberg 
53133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
54e62c18deSPekka Enberg 	},
5546aa8d69SPekka Enberg };
5646aa8d69SPekka Enberg 
5776b4a122SPekka Enberg static int read_char(int fd)
5876b4a122SPekka Enberg {
59*8eb47d29SSasha Levin 	char c;
6076b4a122SPekka Enberg 
61*8eb47d29SSasha Levin 	if (read_in_full(fd, &c, 1) == 0)
6276b4a122SPekka Enberg 		return -1;
6376b4a122SPekka Enberg 
6476b4a122SPekka Enberg 	return c;
6576b4a122SPekka Enberg }
6676b4a122SPekka Enberg 
6776b4a122SPekka Enberg static bool is_readable(int fd)
6876b4a122SPekka Enberg {
696d54df74SCyrill Gorcunov 	struct pollfd pollfd = (struct pollfd) {
7076b4a122SPekka Enberg 		.fd	= fd,
7176b4a122SPekka Enberg 		.events	= POLLIN,
7276b4a122SPekka Enberg 	};
7376b4a122SPekka Enberg 
746d54df74SCyrill Gorcunov 	return poll(&pollfd, 1, 0) > 0;
7576b4a122SPekka Enberg }
7676b4a122SPekka Enberg 
77251cf9a6SPekka Enberg static void serial8250__receive(struct kvm *self, struct serial8250_device *dev)
78251cf9a6SPekka Enberg {
79251cf9a6SPekka Enberg 	int c;
80251cf9a6SPekka Enberg 
81db34045cSPekka Enberg 	if (dev->lsr & UART_LSR_DR)
82db34045cSPekka Enberg 		return;
83db34045cSPekka Enberg 
84b4068fdfSPekka Enberg 	if (!is_readable(STDIN_FILENO))
85251cf9a6SPekka Enberg 		return;
86251cf9a6SPekka Enberg 
87b4068fdfSPekka Enberg 	c		= read_char(STDIN_FILENO);
88251cf9a6SPekka Enberg 	if (c < 0)
89251cf9a6SPekka Enberg 		return;
90251cf9a6SPekka Enberg 
91251cf9a6SPekka Enberg 	dev->rbr	= c;
92251cf9a6SPekka Enberg 	dev->lsr	|= UART_LSR_DR;
93251cf9a6SPekka Enberg }
94251cf9a6SPekka Enberg 
95c6a69c61SPekka Enberg /*
96c6a69c61SPekka Enberg  * Interrupts are injected for ttyS0 only.
97c6a69c61SPekka Enberg  */
988bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self)
998bb34e0dSPekka Enberg {
100c6a69c61SPekka Enberg 	struct serial8250_device *dev = &devices[0];
101934c193bSPekka Enberg 
102251cf9a6SPekka Enberg 	serial8250__receive(self, dev);
103251cf9a6SPekka Enberg 
104369c01c0SPekka Enberg 	if (dev->ier & UART_IER_RDI && dev->lsr & UART_LSR_DR)
105369c01c0SPekka Enberg 		dev->iir		= UART_IIR_RDI;
106251cf9a6SPekka Enberg 	else if (dev->ier & UART_IER_THRI)
107369c01c0SPekka Enberg 		dev->iir		= UART_IIR_THRI;
108369c01c0SPekka Enberg 	else
109369c01c0SPekka Enberg 		dev->iir		= UART_IIR_NO_INT;
11076b4a122SPekka Enberg 
111369c01c0SPekka Enberg 	if (dev->iir != UART_IIR_NO_INT) {
112c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
113c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
114e557eef9SPekka Enberg 	}
1158bb34e0dSPekka Enberg }
1168bb34e0dSPekka Enberg 
117c6a69c61SPekka Enberg static struct serial8250_device *find_device(uint16_t port)
118c6a69c61SPekka Enberg {
119c6a69c61SPekka Enberg 	unsigned int i;
120c6a69c61SPekka Enberg 
121c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
122c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
123c6a69c61SPekka Enberg 
124c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
125c6a69c61SPekka Enberg 			return dev;
126c6a69c61SPekka Enberg 	}
127c6a69c61SPekka Enberg 	return NULL;
128c6a69c61SPekka Enberg }
129c6a69c61SPekka Enberg 
13046aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
13113a7760fSPekka Enberg {
132c6a69c61SPekka Enberg 	struct serial8250_device *dev;
133c6a69c61SPekka Enberg 	uint16_t offset;
13446aa8d69SPekka Enberg 
135c6a69c61SPekka Enberg 	dev		= find_device(port);
136c6a69c61SPekka Enberg 	if (!dev)
137c6a69c61SPekka Enberg 		return false;
138c6a69c61SPekka Enberg 
139c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
140c6a69c61SPekka Enberg 
141c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
14246aa8d69SPekka Enberg 		switch (offset) {
1434e49b05bSCyrill Gorcunov 		case UART_DLL:
144c6a69c61SPekka Enberg 			dev->dll	= ioport__read8(data);
14546aa8d69SPekka Enberg 			break;
1464e49b05bSCyrill Gorcunov 		case UART_DLM:
147c6a69c61SPekka Enberg 			dev->dlm	= ioport__read8(data);
14846aa8d69SPekka Enberg 			break;
149369c01c0SPekka Enberg 		case UART_FCR:
150369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
151369c01c0SPekka Enberg 			break;
152369c01c0SPekka Enberg 		case UART_LCR:
153369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
154369c01c0SPekka Enberg 			break;
155369c01c0SPekka Enberg 		case UART_MCR:
156369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
157369c01c0SPekka Enberg 			break;
158369c01c0SPekka Enberg 		case UART_LSR:
159369c01c0SPekka Enberg 			/* Factory test */
160369c01c0SPekka Enberg 			break;
161369c01c0SPekka Enberg 		case UART_MSR:
162369c01c0SPekka Enberg 			/* Not used */
163369c01c0SPekka Enberg 			break;
164369c01c0SPekka Enberg 		case UART_SCR:
165369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
166369c01c0SPekka Enberg 			break;
167369c01c0SPekka Enberg 		default:
168369c01c0SPekka Enberg 			return false;
16946aa8d69SPekka Enberg 		}
17046aa8d69SPekka Enberg 	} else {
17146aa8d69SPekka Enberg 		switch (offset) {
1724e49b05bSCyrill Gorcunov 		case UART_TX: {
17313a7760fSPekka Enberg 			char *p = data;
174f2d8dc88SCyrill Gorcunov 			int i;
17513a7760fSPekka Enberg 
176369c01c0SPekka Enberg 			if (!(dev->mcr & UART_MCR_LOOP)) {
177f2d8dc88SCyrill Gorcunov 				while (count--) {
178f2d8dc88SCyrill Gorcunov 					for (i = 0; i < size; i++)
179b7475544SPekka Enberg 						fprintf(stdout, "%c", *p++);
1805b9d0b58SAsias He 				}
181b7475544SPekka Enberg 				fflush(stdout);
182369c01c0SPekka Enberg 			}
183133bedc1SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
18446aa8d69SPekka Enberg 			break;
18546aa8d69SPekka Enberg 		}
186369c01c0SPekka Enberg 		case UART_FCR:
187369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
188369c01c0SPekka Enberg 			break;
1894e49b05bSCyrill Gorcunov 		case UART_IER:
190369c01c0SPekka Enberg 			dev->ier	= ioport__read8(data) & 0x3f;
19146aa8d69SPekka Enberg 			break;
192369c01c0SPekka Enberg 		case UART_LCR:
193369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
194369c01c0SPekka Enberg 			break;
195369c01c0SPekka Enberg 		case UART_MCR:
196369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
197369c01c0SPekka Enberg 			break;
198369c01c0SPekka Enberg 		case UART_LSR:
199369c01c0SPekka Enberg 			/* Factory test */
200369c01c0SPekka Enberg 			break;
201369c01c0SPekka Enberg 		case UART_MSR:
202369c01c0SPekka Enberg 			/* Not used */
203369c01c0SPekka Enberg 			break;
204369c01c0SPekka Enberg 		case UART_SCR:
205369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
206369c01c0SPekka Enberg 			break;
207369c01c0SPekka Enberg 		default:
208369c01c0SPekka Enberg 			return false;
20946aa8d69SPekka Enberg 		}
21046aa8d69SPekka Enberg 	}
21113a7760fSPekka Enberg 	return true;
21213a7760fSPekka Enberg }
21313a7760fSPekka Enberg 
21446aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
21525af6674SPekka Enberg {
216c6a69c61SPekka Enberg 	struct serial8250_device *dev;
217c6a69c61SPekka Enberg 	uint16_t offset;
21846aa8d69SPekka Enberg 
219c6a69c61SPekka Enberg 	dev		= find_device(port);
220c6a69c61SPekka Enberg 	if (!dev)
221c6a69c61SPekka Enberg 		return false;
222c6a69c61SPekka Enberg 
223c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
224c6a69c61SPekka Enberg 
22519a2bb7dSPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
22619a2bb7dSPekka Enberg 		switch (offset) {
22719a2bb7dSPekka Enberg 		case UART_DLL:
22819a2bb7dSPekka Enberg 			ioport__write8(data, dev->dll);
22919a2bb7dSPekka Enberg 			return true;
23019a2bb7dSPekka Enberg 		case UART_DLM:
23119a2bb7dSPekka Enberg 			ioport__write8(data, dev->dlm);
23219a2bb7dSPekka Enberg 			return true;
233369c01c0SPekka Enberg 		default:
234369c01c0SPekka Enberg 			break;
23519a2bb7dSPekka Enberg 		}
23619a2bb7dSPekka Enberg 	} else {
23746aa8d69SPekka Enberg 		switch (offset) {
238251cf9a6SPekka Enberg 		case UART_RX:
239251cf9a6SPekka Enberg 			ioport__write8(data, dev->rbr);
240369c01c0SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
241369c01c0SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
24219a2bb7dSPekka Enberg 			return true;
2434e49b05bSCyrill Gorcunov 		case UART_IER:
244c6a69c61SPekka Enberg 			ioport__write8(data, dev->ier);
24519a2bb7dSPekka Enberg 			return true;
246369c01c0SPekka Enberg 		default:
247369c01c0SPekka Enberg 			break;
24819a2bb7dSPekka Enberg 		}
24919a2bb7dSPekka Enberg 	}
25019a2bb7dSPekka Enberg 
25119a2bb7dSPekka Enberg 	switch (offset) {
252369c01c0SPekka Enberg 	case UART_IIR: {
253369c01c0SPekka Enberg 		uint8_t iir = dev->iir;
254369c01c0SPekka Enberg 
255369c01c0SPekka Enberg 		if (dev->fcr & UART_FCR_ENABLE_FIFO)
256369c01c0SPekka Enberg 			iir		|= 0xc0;
257369c01c0SPekka Enberg 
258369c01c0SPekka Enberg 		ioport__write8(data, iir);
25946aa8d69SPekka Enberg 		break;
260369c01c0SPekka Enberg 	}
2614e49b05bSCyrill Gorcunov 	case UART_LCR:
262c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
26346aa8d69SPekka Enberg 		break;
2644e49b05bSCyrill Gorcunov 	case UART_MCR:
265c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
26646aa8d69SPekka Enberg 		break;
2674e49b05bSCyrill Gorcunov 	case UART_LSR:
268c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
269369c01c0SPekka Enberg 		dev->lsr		&= ~(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI);
27046aa8d69SPekka Enberg 		break;
2714e49b05bSCyrill Gorcunov 	case UART_MSR:
272369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
27346aa8d69SPekka Enberg 		break;
2744e49b05bSCyrill Gorcunov 	case UART_SCR:
275369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
27646aa8d69SPekka Enberg 		break;
277369c01c0SPekka Enberg 	default:
278369c01c0SPekka Enberg 		return false;
27925af6674SPekka Enberg 	}
28013a7760fSPekka Enberg 	return true;
28113a7760fSPekka Enberg }
28213a7760fSPekka Enberg 
28346aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
28446aa8d69SPekka Enberg 	.io_in		= serial8250_in,
28546aa8d69SPekka Enberg 	.io_out		= serial8250_out,
286a93ec68bSPekka Enberg };
287a93ec68bSPekka Enberg 
288bc4b0ffeSPekka Enberg static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
289bc4b0ffeSPekka Enberg {
290bc4b0ffeSPekka Enberg 	ioport__register(dev->iobase, &serial8250_ops, 8);
291bc4b0ffeSPekka Enberg 	kvm__irq_line(kvm, dev->irq, 0);
292bc4b0ffeSPekka Enberg }
293bc4b0ffeSPekka Enberg 
294bc4b0ffeSPekka Enberg void serial8250__init(struct kvm *kvm)
29513a7760fSPekka Enberg {
296c6a69c61SPekka Enberg 	unsigned int i;
297c6a69c61SPekka Enberg 
298c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
299c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
300c6a69c61SPekka Enberg 
301bc4b0ffeSPekka Enberg 		serial8250__device_init(kvm, dev);
302c6a69c61SPekka Enberg 	}
30313a7760fSPekka Enberg }
304