xref: /kvmtool/hw/serial.c (revision a428f72ec339b72f6656e1d13773e50b2a546b82)
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"
605d1a2a6SAsias 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 
56*a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE		0
57*a428f72eSPekka Enberg #define SYSRQ_PENDING_BREAK		1
58*a428f72eSPekka Enberg #define SYSRQ_PENDING_CMD		2
59*a428f72eSPekka Enberg 
60*a428f72eSPekka Enberg static int sysrq_pending;
61*a428f72eSPekka Enberg 
62*a428f72eSPekka Enberg static void serial8250__sysrq(struct kvm *self, struct serial8250_device *dev)
63*a428f72eSPekka Enberg {
64*a428f72eSPekka Enberg 	switch (sysrq_pending) {
65*a428f72eSPekka Enberg 	case SYSRQ_PENDING_BREAK:
66*a428f72eSPekka Enberg 		dev->lsr	|= UART_LSR_DR | UART_LSR_BI;
67*a428f72eSPekka Enberg 
68*a428f72eSPekka Enberg 		sysrq_pending	= SYSRQ_PENDING_CMD;
69*a428f72eSPekka Enberg 		break;
70*a428f72eSPekka Enberg 	case SYSRQ_PENDING_CMD:
71*a428f72eSPekka Enberg 		dev->rbr	= 'p';
72*a428f72eSPekka Enberg 		dev->lsr	|= UART_LSR_DR;
73*a428f72eSPekka Enberg 
74*a428f72eSPekka Enberg 		sysrq_pending	= SYSRQ_PENDING_NONE;
75*a428f72eSPekka Enberg 		break;
76*a428f72eSPekka Enberg 	}
77*a428f72eSPekka Enberg }
78*a428f72eSPekka Enberg 
79251cf9a6SPekka Enberg static void serial8250__receive(struct kvm *self, struct serial8250_device *dev)
80251cf9a6SPekka Enberg {
81251cf9a6SPekka Enberg 	int c;
82251cf9a6SPekka Enberg 
83db34045cSPekka Enberg 	if (dev->lsr & UART_LSR_DR)
84db34045cSPekka Enberg 		return;
85db34045cSPekka Enberg 
86*a428f72eSPekka Enberg 	if (sysrq_pending) {
87*a428f72eSPekka Enberg 		serial8250__sysrq(self, dev);
88*a428f72eSPekka Enberg 		return;
89*a428f72eSPekka Enberg 	}
90*a428f72eSPekka Enberg 
9105d1a2a6SAsias He 	if (!term_readable(CONSOLE_8250))
92251cf9a6SPekka Enberg 		return;
93251cf9a6SPekka Enberg 
9405d1a2a6SAsias He 	c		= term_getc(CONSOLE_8250);
9505d1a2a6SAsias He 
96251cf9a6SPekka Enberg 	if (c < 0)
97251cf9a6SPekka Enberg 		return;
98251cf9a6SPekka Enberg 
99251cf9a6SPekka Enberg 	dev->rbr	= c;
100251cf9a6SPekka Enberg 	dev->lsr	|= UART_LSR_DR;
101251cf9a6SPekka Enberg }
102251cf9a6SPekka Enberg 
103c6a69c61SPekka Enberg /*
104c6a69c61SPekka Enberg  * Interrupts are injected for ttyS0 only.
105c6a69c61SPekka Enberg  */
10605d1a2a6SAsias He void serial8250__inject_interrupt(struct kvm *self)
1078bb34e0dSPekka Enberg {
108c6a69c61SPekka Enberg 	struct serial8250_device *dev = &devices[0];
109934c193bSPekka Enberg 
110251cf9a6SPekka Enberg 	serial8250__receive(self, dev);
111251cf9a6SPekka Enberg 
112369c01c0SPekka Enberg 	if (dev->ier & UART_IER_RDI && dev->lsr & UART_LSR_DR)
113369c01c0SPekka Enberg 		dev->iir		= UART_IIR_RDI;
114251cf9a6SPekka Enberg 	else if (dev->ier & UART_IER_THRI)
115369c01c0SPekka Enberg 		dev->iir		= UART_IIR_THRI;
116369c01c0SPekka Enberg 	else
117369c01c0SPekka Enberg 		dev->iir		= UART_IIR_NO_INT;
11876b4a122SPekka Enberg 
119369c01c0SPekka Enberg 	if (dev->iir != UART_IIR_NO_INT) {
120c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
121c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
122e557eef9SPekka Enberg 	}
1238bb34e0dSPekka Enberg }
1248bb34e0dSPekka Enberg 
125*a428f72eSPekka Enberg void serial8250__inject_sysrq(struct kvm *self)
126*a428f72eSPekka Enberg {
127*a428f72eSPekka Enberg 	sysrq_pending	= SYSRQ_PENDING_BREAK;
128*a428f72eSPekka Enberg }
129*a428f72eSPekka Enberg 
130c6a69c61SPekka Enberg static struct serial8250_device *find_device(uint16_t port)
131c6a69c61SPekka Enberg {
132c6a69c61SPekka Enberg 	unsigned int i;
133c6a69c61SPekka Enberg 
134c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
135c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
136c6a69c61SPekka Enberg 
137c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
138c6a69c61SPekka Enberg 			return dev;
139c6a69c61SPekka Enberg 	}
140c6a69c61SPekka Enberg 	return NULL;
141c6a69c61SPekka Enberg }
142c6a69c61SPekka Enberg 
14346aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
14413a7760fSPekka Enberg {
145c6a69c61SPekka Enberg 	struct serial8250_device *dev;
146c6a69c61SPekka Enberg 	uint16_t offset;
14746aa8d69SPekka Enberg 
148c6a69c61SPekka Enberg 	dev		= find_device(port);
149c6a69c61SPekka Enberg 	if (!dev)
150c6a69c61SPekka Enberg 		return false;
151c6a69c61SPekka Enberg 
152c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
153c6a69c61SPekka Enberg 
154c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
15546aa8d69SPekka Enberg 		switch (offset) {
1564e49b05bSCyrill Gorcunov 		case UART_DLL:
157c6a69c61SPekka Enberg 			dev->dll	= ioport__read8(data);
15846aa8d69SPekka Enberg 			break;
1594e49b05bSCyrill Gorcunov 		case UART_DLM:
160c6a69c61SPekka Enberg 			dev->dlm	= ioport__read8(data);
16146aa8d69SPekka Enberg 			break;
162369c01c0SPekka Enberg 		case UART_FCR:
163369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
164369c01c0SPekka Enberg 			break;
165369c01c0SPekka Enberg 		case UART_LCR:
166369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
167369c01c0SPekka Enberg 			break;
168369c01c0SPekka Enberg 		case UART_MCR:
169369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
170369c01c0SPekka Enberg 			break;
171369c01c0SPekka Enberg 		case UART_LSR:
172369c01c0SPekka Enberg 			/* Factory test */
173369c01c0SPekka Enberg 			break;
174369c01c0SPekka Enberg 		case UART_MSR:
175369c01c0SPekka Enberg 			/* Not used */
176369c01c0SPekka Enberg 			break;
177369c01c0SPekka Enberg 		case UART_SCR:
178369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
179369c01c0SPekka Enberg 			break;
180369c01c0SPekka Enberg 		default:
181369c01c0SPekka Enberg 			return false;
18246aa8d69SPekka Enberg 		}
18346aa8d69SPekka Enberg 	} else {
18446aa8d69SPekka Enberg 		switch (offset) {
1854e49b05bSCyrill Gorcunov 		case UART_TX: {
18605d1a2a6SAsias He 			char *addr = data;
187369c01c0SPekka Enberg 			if (!(dev->mcr & UART_MCR_LOOP)) {
18805d1a2a6SAsias He 				term_putc(CONSOLE_8250, addr, size * count);
189369c01c0SPekka Enberg 			}
190133bedc1SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
19146aa8d69SPekka Enberg 			break;
19246aa8d69SPekka Enberg 		}
193369c01c0SPekka Enberg 		case UART_FCR:
194369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
195369c01c0SPekka Enberg 			break;
1964e49b05bSCyrill Gorcunov 		case UART_IER:
197369c01c0SPekka Enberg 			dev->ier	= ioport__read8(data) & 0x3f;
19846aa8d69SPekka Enberg 			break;
199369c01c0SPekka Enberg 		case UART_LCR:
200369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
201369c01c0SPekka Enberg 			break;
202369c01c0SPekka Enberg 		case UART_MCR:
203369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
204369c01c0SPekka Enberg 			break;
205369c01c0SPekka Enberg 		case UART_LSR:
206369c01c0SPekka Enberg 			/* Factory test */
207369c01c0SPekka Enberg 			break;
208369c01c0SPekka Enberg 		case UART_MSR:
209369c01c0SPekka Enberg 			/* Not used */
210369c01c0SPekka Enberg 			break;
211369c01c0SPekka Enberg 		case UART_SCR:
212369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
213369c01c0SPekka Enberg 			break;
214369c01c0SPekka Enberg 		default:
215369c01c0SPekka Enberg 			return false;
21646aa8d69SPekka Enberg 		}
21746aa8d69SPekka Enberg 	}
21813a7760fSPekka Enberg 	return true;
21913a7760fSPekka Enberg }
22013a7760fSPekka Enberg 
22146aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
22225af6674SPekka Enberg {
223c6a69c61SPekka Enberg 	struct serial8250_device *dev;
224c6a69c61SPekka Enberg 	uint16_t offset;
22546aa8d69SPekka Enberg 
226c6a69c61SPekka Enberg 	dev		= find_device(port);
227c6a69c61SPekka Enberg 	if (!dev)
228c6a69c61SPekka Enberg 		return false;
229c6a69c61SPekka Enberg 
230c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
231c6a69c61SPekka Enberg 
23219a2bb7dSPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
23319a2bb7dSPekka Enberg 		switch (offset) {
23419a2bb7dSPekka Enberg 		case UART_DLL:
23519a2bb7dSPekka Enberg 			ioport__write8(data, dev->dll);
23619a2bb7dSPekka Enberg 			return true;
23719a2bb7dSPekka Enberg 		case UART_DLM:
23819a2bb7dSPekka Enberg 			ioport__write8(data, dev->dlm);
23919a2bb7dSPekka Enberg 			return true;
240369c01c0SPekka Enberg 		default:
241369c01c0SPekka Enberg 			break;
24219a2bb7dSPekka Enberg 		}
24319a2bb7dSPekka Enberg 	} else {
24446aa8d69SPekka Enberg 		switch (offset) {
245251cf9a6SPekka Enberg 		case UART_RX:
246251cf9a6SPekka Enberg 			ioport__write8(data, dev->rbr);
247369c01c0SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
248369c01c0SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
24919a2bb7dSPekka Enberg 			return true;
2504e49b05bSCyrill Gorcunov 		case UART_IER:
251c6a69c61SPekka Enberg 			ioport__write8(data, dev->ier);
25219a2bb7dSPekka Enberg 			return true;
253369c01c0SPekka Enberg 		default:
254369c01c0SPekka Enberg 			break;
25519a2bb7dSPekka Enberg 		}
25619a2bb7dSPekka Enberg 	}
25719a2bb7dSPekka Enberg 
25819a2bb7dSPekka Enberg 	switch (offset) {
259369c01c0SPekka Enberg 	case UART_IIR: {
260369c01c0SPekka Enberg 		uint8_t iir = dev->iir;
261369c01c0SPekka Enberg 
262369c01c0SPekka Enberg 		if (dev->fcr & UART_FCR_ENABLE_FIFO)
263369c01c0SPekka Enberg 			iir		|= 0xc0;
264369c01c0SPekka Enberg 
265369c01c0SPekka Enberg 		ioport__write8(data, iir);
26646aa8d69SPekka Enberg 		break;
267369c01c0SPekka Enberg 	}
2684e49b05bSCyrill Gorcunov 	case UART_LCR:
269c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
27046aa8d69SPekka Enberg 		break;
2714e49b05bSCyrill Gorcunov 	case UART_MCR:
272c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
27346aa8d69SPekka Enberg 		break;
2744e49b05bSCyrill Gorcunov 	case UART_LSR:
275c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
276369c01c0SPekka Enberg 		dev->lsr		&= ~(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI);
27746aa8d69SPekka Enberg 		break;
2784e49b05bSCyrill Gorcunov 	case UART_MSR:
279369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
28046aa8d69SPekka Enberg 		break;
2814e49b05bSCyrill Gorcunov 	case UART_SCR:
282369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
28346aa8d69SPekka Enberg 		break;
284369c01c0SPekka Enberg 	default:
285369c01c0SPekka Enberg 		return false;
28625af6674SPekka Enberg 	}
28713a7760fSPekka Enberg 	return true;
28813a7760fSPekka Enberg }
28913a7760fSPekka Enberg 
29046aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
29146aa8d69SPekka Enberg 	.io_in		= serial8250_in,
29246aa8d69SPekka Enberg 	.io_out		= serial8250_out,
293a93ec68bSPekka Enberg };
294a93ec68bSPekka Enberg 
295bc4b0ffeSPekka Enberg static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
296bc4b0ffeSPekka Enberg {
297bc4b0ffeSPekka Enberg 	ioport__register(dev->iobase, &serial8250_ops, 8);
298bc4b0ffeSPekka Enberg 	kvm__irq_line(kvm, dev->irq, 0);
299bc4b0ffeSPekka Enberg }
300bc4b0ffeSPekka Enberg 
301bc4b0ffeSPekka Enberg void serial8250__init(struct kvm *kvm)
30213a7760fSPekka Enberg {
303c6a69c61SPekka Enberg 	unsigned int i;
304c6a69c61SPekka Enberg 
305c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
306c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
307c6a69c61SPekka Enberg 
308bc4b0ffeSPekka Enberg 		serial8250__device_init(kvm, dev);
309c6a69c61SPekka Enberg 	}
31013a7760fSPekka Enberg }
311