xref: /kvmtool/hw/serial.c (revision 05d1a2a69d0fc68b7771a889e7acaaba2fda10b2)
1899fe063SPekka Enberg #include "kvm/8250-serial.h"
213a7760fSPekka Enberg 
38eb47d29SSasha Levin #include "kvm/read-write.h"
413a7760fSPekka Enberg #include "kvm/ioport.h"
546aa8d69SPekka Enberg #include "kvm/util.h"
6*05d1a2a6SAsias He #include "kvm/term.h"
7e557eef9SPekka Enberg #include "kvm/kvm.h"
813a7760fSPekka Enberg 
94e49b05bSCyrill Gorcunov #include <linux/serial_reg.h>
104e49b05bSCyrill Gorcunov 
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;
25369c01c0SPekka 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 
35369c01c0SPekka Enberg 		.iir			= UART_IIR_NO_INT,
36bc4b0ffeSPekka Enberg 		.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
37bc4b0ffeSPekka Enberg 		.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS,
38bc4b0ffeSPekka Enberg 		.mcr			= UART_MCR_OUT2,
39c6a69c61SPekka Enberg 	},
40e62c18deSPekka Enberg 	/* ttyS1 */
41e62c18deSPekka Enberg 	[1]	= {
42e62c18deSPekka Enberg 		.iobase			= 0x2f8,
43e62c18deSPekka Enberg 		.irq			= 3,
44133bedc1SPekka Enberg 
45133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
46e62c18deSPekka Enberg 	},
47e62c18deSPekka Enberg 	/* ttyS2 */
48e62c18deSPekka Enberg 	[2]	= {
49e62c18deSPekka Enberg 		.iobase			= 0x3e8,
50e62c18deSPekka Enberg 		.irq			= 4,
51133bedc1SPekka Enberg 
52133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
53e62c18deSPekka Enberg 	},
5446aa8d69SPekka Enberg };
5546aa8d69SPekka Enberg 
56251cf9a6SPekka Enberg static void serial8250__receive(struct kvm *self, struct serial8250_device *dev)
57251cf9a6SPekka Enberg {
58251cf9a6SPekka Enberg 	int c;
59251cf9a6SPekka Enberg 
60db34045cSPekka Enberg 	if (dev->lsr & UART_LSR_DR)
61db34045cSPekka Enberg 		return;
62db34045cSPekka Enberg 
63*05d1a2a6SAsias He 	if (!term_readable(CONSOLE_8250))
64251cf9a6SPekka Enberg 		return;
65251cf9a6SPekka Enberg 
66*05d1a2a6SAsias He 	c		= term_getc(CONSOLE_8250);
67*05d1a2a6SAsias He 
68251cf9a6SPekka Enberg 	if (c < 0)
69251cf9a6SPekka Enberg 		return;
70251cf9a6SPekka Enberg 
71251cf9a6SPekka Enberg 	dev->rbr	= c;
72251cf9a6SPekka Enberg 	dev->lsr	|= UART_LSR_DR;
73251cf9a6SPekka Enberg }
74251cf9a6SPekka Enberg 
75c6a69c61SPekka Enberg /*
76c6a69c61SPekka Enberg  * Interrupts are injected for ttyS0 only.
77c6a69c61SPekka Enberg  */
78*05d1a2a6SAsias He void serial8250__inject_interrupt(struct kvm *self)
798bb34e0dSPekka Enberg {
80c6a69c61SPekka Enberg 	struct serial8250_device *dev = &devices[0];
81934c193bSPekka Enberg 
82251cf9a6SPekka Enberg 	serial8250__receive(self, dev);
83251cf9a6SPekka Enberg 
84369c01c0SPekka Enberg 	if (dev->ier & UART_IER_RDI && dev->lsr & UART_LSR_DR)
85369c01c0SPekka Enberg 		dev->iir		= UART_IIR_RDI;
86251cf9a6SPekka Enberg 	else if (dev->ier & UART_IER_THRI)
87369c01c0SPekka Enberg 		dev->iir		= UART_IIR_THRI;
88369c01c0SPekka Enberg 	else
89369c01c0SPekka Enberg 		dev->iir		= UART_IIR_NO_INT;
9076b4a122SPekka Enberg 
91369c01c0SPekka Enberg 	if (dev->iir != UART_IIR_NO_INT) {
92c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
93c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
94e557eef9SPekka Enberg 	}
958bb34e0dSPekka Enberg }
968bb34e0dSPekka Enberg 
97c6a69c61SPekka Enberg static struct serial8250_device *find_device(uint16_t port)
98c6a69c61SPekka Enberg {
99c6a69c61SPekka Enberg 	unsigned int i;
100c6a69c61SPekka Enberg 
101c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
102c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
103c6a69c61SPekka Enberg 
104c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
105c6a69c61SPekka Enberg 			return dev;
106c6a69c61SPekka Enberg 	}
107c6a69c61SPekka Enberg 	return NULL;
108c6a69c61SPekka Enberg }
109c6a69c61SPekka Enberg 
11046aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
11113a7760fSPekka Enberg {
112c6a69c61SPekka Enberg 	struct serial8250_device *dev;
113c6a69c61SPekka Enberg 	uint16_t offset;
11446aa8d69SPekka Enberg 
115c6a69c61SPekka Enberg 	dev		= find_device(port);
116c6a69c61SPekka Enberg 	if (!dev)
117c6a69c61SPekka Enberg 		return false;
118c6a69c61SPekka Enberg 
119c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
120c6a69c61SPekka Enberg 
121c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
12246aa8d69SPekka Enberg 		switch (offset) {
1234e49b05bSCyrill Gorcunov 		case UART_DLL:
124c6a69c61SPekka Enberg 			dev->dll	= ioport__read8(data);
12546aa8d69SPekka Enberg 			break;
1264e49b05bSCyrill Gorcunov 		case UART_DLM:
127c6a69c61SPekka Enberg 			dev->dlm	= ioport__read8(data);
12846aa8d69SPekka Enberg 			break;
129369c01c0SPekka Enberg 		case UART_FCR:
130369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
131369c01c0SPekka Enberg 			break;
132369c01c0SPekka Enberg 		case UART_LCR:
133369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
134369c01c0SPekka Enberg 			break;
135369c01c0SPekka Enberg 		case UART_MCR:
136369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
137369c01c0SPekka Enberg 			break;
138369c01c0SPekka Enberg 		case UART_LSR:
139369c01c0SPekka Enberg 			/* Factory test */
140369c01c0SPekka Enberg 			break;
141369c01c0SPekka Enberg 		case UART_MSR:
142369c01c0SPekka Enberg 			/* Not used */
143369c01c0SPekka Enberg 			break;
144369c01c0SPekka Enberg 		case UART_SCR:
145369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
146369c01c0SPekka Enberg 			break;
147369c01c0SPekka Enberg 		default:
148369c01c0SPekka Enberg 			return false;
14946aa8d69SPekka Enberg 		}
15046aa8d69SPekka Enberg 	} else {
15146aa8d69SPekka Enberg 		switch (offset) {
1524e49b05bSCyrill Gorcunov 		case UART_TX: {
153*05d1a2a6SAsias He 			char *addr = data;
154369c01c0SPekka Enberg 			if (!(dev->mcr & UART_MCR_LOOP)) {
155*05d1a2a6SAsias He 				term_putc(CONSOLE_8250, addr, size * count);
156369c01c0SPekka Enberg 			}
157133bedc1SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
15846aa8d69SPekka Enberg 			break;
15946aa8d69SPekka Enberg 		}
160369c01c0SPekka Enberg 		case UART_FCR:
161369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
162369c01c0SPekka Enberg 			break;
1634e49b05bSCyrill Gorcunov 		case UART_IER:
164369c01c0SPekka Enberg 			dev->ier	= ioport__read8(data) & 0x3f;
16546aa8d69SPekka Enberg 			break;
166369c01c0SPekka Enberg 		case UART_LCR:
167369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
168369c01c0SPekka Enberg 			break;
169369c01c0SPekka Enberg 		case UART_MCR:
170369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
171369c01c0SPekka Enberg 			break;
172369c01c0SPekka Enberg 		case UART_LSR:
173369c01c0SPekka Enberg 			/* Factory test */
174369c01c0SPekka Enberg 			break;
175369c01c0SPekka Enberg 		case UART_MSR:
176369c01c0SPekka Enberg 			/* Not used */
177369c01c0SPekka Enberg 			break;
178369c01c0SPekka Enberg 		case UART_SCR:
179369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
180369c01c0SPekka Enberg 			break;
181369c01c0SPekka Enberg 		default:
182369c01c0SPekka Enberg 			return false;
18346aa8d69SPekka Enberg 		}
18446aa8d69SPekka Enberg 	}
18513a7760fSPekka Enberg 	return true;
18613a7760fSPekka Enberg }
18713a7760fSPekka Enberg 
18846aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
18925af6674SPekka Enberg {
190c6a69c61SPekka Enberg 	struct serial8250_device *dev;
191c6a69c61SPekka Enberg 	uint16_t offset;
19246aa8d69SPekka Enberg 
193c6a69c61SPekka Enberg 	dev		= find_device(port);
194c6a69c61SPekka Enberg 	if (!dev)
195c6a69c61SPekka Enberg 		return false;
196c6a69c61SPekka Enberg 
197c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
198c6a69c61SPekka Enberg 
19919a2bb7dSPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
20019a2bb7dSPekka Enberg 		switch (offset) {
20119a2bb7dSPekka Enberg 		case UART_DLL:
20219a2bb7dSPekka Enberg 			ioport__write8(data, dev->dll);
20319a2bb7dSPekka Enberg 			return true;
20419a2bb7dSPekka Enberg 		case UART_DLM:
20519a2bb7dSPekka Enberg 			ioport__write8(data, dev->dlm);
20619a2bb7dSPekka Enberg 			return true;
207369c01c0SPekka Enberg 		default:
208369c01c0SPekka Enberg 			break;
20919a2bb7dSPekka Enberg 		}
21019a2bb7dSPekka Enberg 	} else {
21146aa8d69SPekka Enberg 		switch (offset) {
212251cf9a6SPekka Enberg 		case UART_RX:
213251cf9a6SPekka Enberg 			ioport__write8(data, dev->rbr);
214369c01c0SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
215369c01c0SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
21619a2bb7dSPekka Enberg 			return true;
2174e49b05bSCyrill Gorcunov 		case UART_IER:
218c6a69c61SPekka Enberg 			ioport__write8(data, dev->ier);
21919a2bb7dSPekka Enberg 			return true;
220369c01c0SPekka Enberg 		default:
221369c01c0SPekka Enberg 			break;
22219a2bb7dSPekka Enberg 		}
22319a2bb7dSPekka Enberg 	}
22419a2bb7dSPekka Enberg 
22519a2bb7dSPekka Enberg 	switch (offset) {
226369c01c0SPekka Enberg 	case UART_IIR: {
227369c01c0SPekka Enberg 		uint8_t iir = dev->iir;
228369c01c0SPekka Enberg 
229369c01c0SPekka Enberg 		if (dev->fcr & UART_FCR_ENABLE_FIFO)
230369c01c0SPekka Enberg 			iir		|= 0xc0;
231369c01c0SPekka Enberg 
232369c01c0SPekka Enberg 		ioport__write8(data, iir);
23346aa8d69SPekka Enberg 		break;
234369c01c0SPekka Enberg 	}
2354e49b05bSCyrill Gorcunov 	case UART_LCR:
236c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
23746aa8d69SPekka Enberg 		break;
2384e49b05bSCyrill Gorcunov 	case UART_MCR:
239c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
24046aa8d69SPekka Enberg 		break;
2414e49b05bSCyrill Gorcunov 	case UART_LSR:
242c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
243369c01c0SPekka Enberg 		dev->lsr		&= ~(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI);
24446aa8d69SPekka Enberg 		break;
2454e49b05bSCyrill Gorcunov 	case UART_MSR:
246369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
24746aa8d69SPekka Enberg 		break;
2484e49b05bSCyrill Gorcunov 	case UART_SCR:
249369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
25046aa8d69SPekka Enberg 		break;
251369c01c0SPekka Enberg 	default:
252369c01c0SPekka Enberg 		return false;
25325af6674SPekka Enberg 	}
25413a7760fSPekka Enberg 	return true;
25513a7760fSPekka Enberg }
25613a7760fSPekka Enberg 
25746aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
25846aa8d69SPekka Enberg 	.io_in		= serial8250_in,
25946aa8d69SPekka Enberg 	.io_out		= serial8250_out,
260a93ec68bSPekka Enberg };
261a93ec68bSPekka Enberg 
262bc4b0ffeSPekka Enberg static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
263bc4b0ffeSPekka Enberg {
264bc4b0ffeSPekka Enberg 	ioport__register(dev->iobase, &serial8250_ops, 8);
265bc4b0ffeSPekka Enberg 	kvm__irq_line(kvm, dev->irq, 0);
266bc4b0ffeSPekka Enberg }
267bc4b0ffeSPekka Enberg 
268bc4b0ffeSPekka Enberg void serial8250__init(struct kvm *kvm)
26913a7760fSPekka Enberg {
270c6a69c61SPekka Enberg 	unsigned int i;
271c6a69c61SPekka Enberg 
272c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
273c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
274c6a69c61SPekka Enberg 
275bc4b0ffeSPekka Enberg 		serial8250__device_init(kvm, dev);
276c6a69c61SPekka Enberg 	}
27713a7760fSPekka Enberg }
278