xref: /kvmtool/hw/serial.c (revision 3fdf659d959233a543d1f29a358f8da994cec0fb)
1899fe063SPekka Enberg #include "kvm/8250-serial.h"
213a7760fSPekka Enberg 
38eb47d29SSasha Levin #include "kvm/read-write.h"
413a7760fSPekka Enberg #include "kvm/ioport.h"
54ef0f4d6SPekka Enberg #include "kvm/mutex.h"
646aa8d69SPekka Enberg #include "kvm/util.h"
705d1a2a6SAsias He #include "kvm/term.h"
8e557eef9SPekka Enberg #include "kvm/kvm.h"
913a7760fSPekka Enberg 
10*3fdf659dSSasha Levin #include <linux/types.h>
114e49b05bSCyrill Gorcunov #include <linux/serial_reg.h>
124e49b05bSCyrill Gorcunov 
132932c9ebSPekka Enberg #include <pthread.h>
1413a7760fSPekka Enberg 
1546aa8d69SPekka Enberg struct serial8250_device {
162932c9ebSPekka Enberg 	pthread_mutex_t		mutex;
172932c9ebSPekka Enberg 
18*3fdf659dSSasha Levin 	u16			iobase;
19*3fdf659dSSasha Levin 	u8			irq;
2076b4a122SPekka Enberg 
21*3fdf659dSSasha Levin 	u8			rbr;		/* receive buffer */
22*3fdf659dSSasha Levin 	u8			dll;
23*3fdf659dSSasha Levin 	u8			dlm;
24*3fdf659dSSasha Levin 	u8			iir;
25*3fdf659dSSasha Levin 	u8			ier;
26*3fdf659dSSasha Levin 	u8			fcr;
27*3fdf659dSSasha Levin 	u8			lcr;
28*3fdf659dSSasha Levin 	u8			mcr;
29*3fdf659dSSasha Levin 	u8			lsr;
30*3fdf659dSSasha Levin 	u8			msr;
31*3fdf659dSSasha Levin 	u8			scr;
3246aa8d69SPekka Enberg };
3346aa8d69SPekka Enberg 
34e62c18deSPekka Enberg static struct serial8250_device devices[] = {
35c6a69c61SPekka Enberg 	/* ttyS0 */
36c6a69c61SPekka Enberg 	[0]	= {
372932c9ebSPekka Enberg 		.mutex			= PTHREAD_MUTEX_INITIALIZER,
382932c9ebSPekka Enberg 
39c6a69c61SPekka Enberg 		.iobase			= 0x3f8,
40e557eef9SPekka Enberg 		.irq			= 4,
41e557eef9SPekka Enberg 
42369c01c0SPekka Enberg 		.iir			= UART_IIR_NO_INT,
43bc4b0ffeSPekka Enberg 		.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
44bc4b0ffeSPekka Enberg 		.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS,
45bc4b0ffeSPekka Enberg 		.mcr			= UART_MCR_OUT2,
46c6a69c61SPekka Enberg 	},
47e62c18deSPekka Enberg 	/* ttyS1 */
48e62c18deSPekka Enberg 	[1]	= {
492932c9ebSPekka Enberg 		.mutex			= PTHREAD_MUTEX_INITIALIZER,
502932c9ebSPekka Enberg 
51e62c18deSPekka Enberg 		.iobase			= 0x2f8,
52e62c18deSPekka Enberg 		.irq			= 3,
53133bedc1SPekka Enberg 
54133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
55e62c18deSPekka Enberg 	},
56e62c18deSPekka Enberg 	/* ttyS2 */
57e62c18deSPekka Enberg 	[2]	= {
582932c9ebSPekka Enberg 		.mutex			= PTHREAD_MUTEX_INITIALIZER,
592932c9ebSPekka Enberg 
60e62c18deSPekka Enberg 		.iobase			= 0x3e8,
61e62c18deSPekka Enberg 		.irq			= 4,
62133bedc1SPekka Enberg 
63133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
64e62c18deSPekka Enberg 	},
6546aa8d69SPekka Enberg };
6646aa8d69SPekka Enberg 
67a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE		0
68a428f72eSPekka Enberg #define SYSRQ_PENDING_BREAK		1
69a428f72eSPekka Enberg #define SYSRQ_PENDING_CMD		2
70a428f72eSPekka Enberg 
71a428f72eSPekka Enberg static int sysrq_pending;
72a428f72eSPekka Enberg 
73a428f72eSPekka Enberg static void serial8250__sysrq(struct kvm *self, struct serial8250_device *dev)
74a428f72eSPekka Enberg {
75a428f72eSPekka Enberg 	switch (sysrq_pending) {
76a428f72eSPekka Enberg 	case SYSRQ_PENDING_BREAK:
77a428f72eSPekka Enberg 		dev->lsr	|= UART_LSR_DR | UART_LSR_BI;
78a428f72eSPekka Enberg 
79a428f72eSPekka Enberg 		sysrq_pending	= SYSRQ_PENDING_CMD;
80a428f72eSPekka Enberg 		break;
81a428f72eSPekka Enberg 	case SYSRQ_PENDING_CMD:
82a428f72eSPekka Enberg 		dev->rbr	= 'p';
83a428f72eSPekka Enberg 		dev->lsr	|= UART_LSR_DR;
84a428f72eSPekka Enberg 
85a428f72eSPekka Enberg 		sysrq_pending	= SYSRQ_PENDING_NONE;
86a428f72eSPekka Enberg 		break;
87a428f72eSPekka Enberg 	}
88a428f72eSPekka Enberg }
89a428f72eSPekka Enberg 
90251cf9a6SPekka Enberg static void serial8250__receive(struct kvm *self, struct serial8250_device *dev)
91251cf9a6SPekka Enberg {
92251cf9a6SPekka Enberg 	int c;
93251cf9a6SPekka Enberg 
94db34045cSPekka Enberg 	if (dev->lsr & UART_LSR_DR)
95db34045cSPekka Enberg 		return;
96db34045cSPekka Enberg 
97a428f72eSPekka Enberg 	if (sysrq_pending) {
98a428f72eSPekka Enberg 		serial8250__sysrq(self, dev);
99a428f72eSPekka Enberg 		return;
100a428f72eSPekka Enberg 	}
101a428f72eSPekka Enberg 
10205d1a2a6SAsias He 	if (!term_readable(CONSOLE_8250))
103251cf9a6SPekka Enberg 		return;
104251cf9a6SPekka Enberg 
10505d1a2a6SAsias He 	c		= term_getc(CONSOLE_8250);
10605d1a2a6SAsias He 
107251cf9a6SPekka Enberg 	if (c < 0)
108251cf9a6SPekka Enberg 		return;
109251cf9a6SPekka Enberg 
110251cf9a6SPekka Enberg 	dev->rbr	= c;
111251cf9a6SPekka Enberg 	dev->lsr	|= UART_LSR_DR;
112251cf9a6SPekka Enberg }
113251cf9a6SPekka Enberg 
114c6a69c61SPekka Enberg /*
115c6a69c61SPekka Enberg  * Interrupts are injected for ttyS0 only.
116c6a69c61SPekka Enberg  */
11705d1a2a6SAsias He void serial8250__inject_interrupt(struct kvm *self)
1188bb34e0dSPekka Enberg {
119c6a69c61SPekka Enberg 	struct serial8250_device *dev = &devices[0];
120934c193bSPekka Enberg 
1214ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
1222932c9ebSPekka Enberg 
123251cf9a6SPekka Enberg 	serial8250__receive(self, dev);
124251cf9a6SPekka Enberg 
125369c01c0SPekka Enberg 	if (dev->ier & UART_IER_RDI && dev->lsr & UART_LSR_DR)
126369c01c0SPekka Enberg 		dev->iir		= UART_IIR_RDI;
127251cf9a6SPekka Enberg 	else if (dev->ier & UART_IER_THRI)
128369c01c0SPekka Enberg 		dev->iir		= UART_IIR_THRI;
129369c01c0SPekka Enberg 	else
130369c01c0SPekka Enberg 		dev->iir		= UART_IIR_NO_INT;
13176b4a122SPekka Enberg 
132369c01c0SPekka Enberg 	if (dev->iir != UART_IIR_NO_INT) {
133c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
134c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
135e557eef9SPekka Enberg 	}
1362932c9ebSPekka Enberg 
1374ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
1388bb34e0dSPekka Enberg }
1398bb34e0dSPekka Enberg 
140a428f72eSPekka Enberg void serial8250__inject_sysrq(struct kvm *self)
141a428f72eSPekka Enberg {
142a428f72eSPekka Enberg 	sysrq_pending	= SYSRQ_PENDING_BREAK;
143a428f72eSPekka Enberg }
144a428f72eSPekka Enberg 
145*3fdf659dSSasha Levin static struct serial8250_device *find_device(u16 port)
146c6a69c61SPekka Enberg {
147c6a69c61SPekka Enberg 	unsigned int i;
148c6a69c61SPekka Enberg 
149c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
150c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
151c6a69c61SPekka Enberg 
152c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
153c6a69c61SPekka Enberg 			return dev;
154c6a69c61SPekka Enberg 	}
155c6a69c61SPekka Enberg 	return NULL;
156c6a69c61SPekka Enberg }
157c6a69c61SPekka Enberg 
158*3fdf659dSSasha Levin static bool serial8250_out(struct kvm *self, u16 port, void *data, int size, u32 count)
15913a7760fSPekka Enberg {
160c6a69c61SPekka Enberg 	struct serial8250_device *dev;
161*3fdf659dSSasha Levin 	u16 offset;
1622932c9ebSPekka Enberg 	bool ret = true;
16346aa8d69SPekka Enberg 
164c6a69c61SPekka Enberg 	dev		= find_device(port);
165c6a69c61SPekka Enberg 	if (!dev)
166c6a69c61SPekka Enberg 		return false;
167c6a69c61SPekka Enberg 
1684ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
1692932c9ebSPekka Enberg 
170c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
171c6a69c61SPekka Enberg 
172c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
17346aa8d69SPekka Enberg 		switch (offset) {
1744e49b05bSCyrill Gorcunov 		case UART_DLL:
175c6a69c61SPekka Enberg 			dev->dll	= ioport__read8(data);
17646aa8d69SPekka Enberg 			break;
1774e49b05bSCyrill Gorcunov 		case UART_DLM:
178c6a69c61SPekka Enberg 			dev->dlm	= ioport__read8(data);
17946aa8d69SPekka Enberg 			break;
180369c01c0SPekka Enberg 		case UART_FCR:
181369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
182369c01c0SPekka Enberg 			break;
183369c01c0SPekka Enberg 		case UART_LCR:
184369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
185369c01c0SPekka Enberg 			break;
186369c01c0SPekka Enberg 		case UART_MCR:
187369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
188369c01c0SPekka Enberg 			break;
189369c01c0SPekka Enberg 		case UART_LSR:
190369c01c0SPekka Enberg 			/* Factory test */
191369c01c0SPekka Enberg 			break;
192369c01c0SPekka Enberg 		case UART_MSR:
193369c01c0SPekka Enberg 			/* Not used */
194369c01c0SPekka Enberg 			break;
195369c01c0SPekka Enberg 		case UART_SCR:
196369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
197369c01c0SPekka Enberg 			break;
198369c01c0SPekka Enberg 		default:
1992932c9ebSPekka Enberg 			ret		= false;
2002932c9ebSPekka Enberg 			goto out_unlock;
20146aa8d69SPekka Enberg 		}
20246aa8d69SPekka Enberg 	} else {
20346aa8d69SPekka Enberg 		switch (offset) {
2044e49b05bSCyrill Gorcunov 		case UART_TX: {
20505d1a2a6SAsias He 			char *addr = data;
2060ea58e5bSPekka Enberg 
2070ea58e5bSPekka Enberg 			if (!(dev->mcr & UART_MCR_LOOP))
20805d1a2a6SAsias He 				term_putc(CONSOLE_8250, addr, size * count);
2090ea58e5bSPekka Enberg 
210133bedc1SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
21146aa8d69SPekka Enberg 			break;
21246aa8d69SPekka Enberg 		}
213369c01c0SPekka Enberg 		case UART_FCR:
214369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
215369c01c0SPekka Enberg 			break;
2164e49b05bSCyrill Gorcunov 		case UART_IER:
217369c01c0SPekka Enberg 			dev->ier	= ioport__read8(data) & 0x3f;
21846aa8d69SPekka Enberg 			break;
219369c01c0SPekka Enberg 		case UART_LCR:
220369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
221369c01c0SPekka Enberg 			break;
222369c01c0SPekka Enberg 		case UART_MCR:
223369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
224369c01c0SPekka Enberg 			break;
225369c01c0SPekka Enberg 		case UART_LSR:
226369c01c0SPekka Enberg 			/* Factory test */
227369c01c0SPekka Enberg 			break;
228369c01c0SPekka Enberg 		case UART_MSR:
229369c01c0SPekka Enberg 			/* Not used */
230369c01c0SPekka Enberg 			break;
231369c01c0SPekka Enberg 		case UART_SCR:
232369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
233369c01c0SPekka Enberg 			break;
234369c01c0SPekka Enberg 		default:
2352932c9ebSPekka Enberg 			ret		= false;
2362932c9ebSPekka Enberg 			goto out_unlock;
23746aa8d69SPekka Enberg 		}
23846aa8d69SPekka Enberg 	}
2392932c9ebSPekka Enberg 
2402932c9ebSPekka Enberg out_unlock:
2414ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
2422932c9ebSPekka Enberg 
2432932c9ebSPekka Enberg 	return ret;
24413a7760fSPekka Enberg }
24513a7760fSPekka Enberg 
246*3fdf659dSSasha Levin static bool serial8250_in(struct kvm *self, u16 port, void *data, int size, u32 count)
24725af6674SPekka Enberg {
248c6a69c61SPekka Enberg 	struct serial8250_device *dev;
249*3fdf659dSSasha Levin 	u16 offset;
2502932c9ebSPekka Enberg 	bool ret = true;
25146aa8d69SPekka Enberg 
252c6a69c61SPekka Enberg 	dev		= find_device(port);
253c6a69c61SPekka Enberg 	if (!dev)
254c6a69c61SPekka Enberg 		return false;
255c6a69c61SPekka Enberg 
2564ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
2572932c9ebSPekka Enberg 
258c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
259c6a69c61SPekka Enberg 
26019a2bb7dSPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
26119a2bb7dSPekka Enberg 		switch (offset) {
26219a2bb7dSPekka Enberg 		case UART_DLL:
26319a2bb7dSPekka Enberg 			ioport__write8(data, dev->dll);
2642932c9ebSPekka Enberg 			goto out_unlock;
2652932c9ebSPekka Enberg 
26619a2bb7dSPekka Enberg 		case UART_DLM:
26719a2bb7dSPekka Enberg 			ioport__write8(data, dev->dlm);
2682932c9ebSPekka Enberg 			goto out_unlock;
2692932c9ebSPekka Enberg 
270369c01c0SPekka Enberg 		default:
271369c01c0SPekka Enberg 			break;
27219a2bb7dSPekka Enberg 		}
27319a2bb7dSPekka Enberg 	} else {
27446aa8d69SPekka Enberg 		switch (offset) {
275251cf9a6SPekka Enberg 		case UART_RX:
276251cf9a6SPekka Enberg 			ioport__write8(data, dev->rbr);
277369c01c0SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
278369c01c0SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
2792932c9ebSPekka Enberg 			goto out_unlock;
2802932c9ebSPekka Enberg 
2814e49b05bSCyrill Gorcunov 		case UART_IER:
282c6a69c61SPekka Enberg 			ioport__write8(data, dev->ier);
2832932c9ebSPekka Enberg 			goto out_unlock;
2842932c9ebSPekka Enberg 
285369c01c0SPekka Enberg 		default:
286369c01c0SPekka Enberg 			break;
28719a2bb7dSPekka Enberg 		}
28819a2bb7dSPekka Enberg 	}
28919a2bb7dSPekka Enberg 
29019a2bb7dSPekka Enberg 	switch (offset) {
291369c01c0SPekka Enberg 	case UART_IIR: {
292*3fdf659dSSasha Levin 		u8 iir = dev->iir;
293369c01c0SPekka Enberg 
294369c01c0SPekka Enberg 		if (dev->fcr & UART_FCR_ENABLE_FIFO)
295369c01c0SPekka Enberg 			iir		|= 0xc0;
296369c01c0SPekka Enberg 
297369c01c0SPekka Enberg 		ioport__write8(data, iir);
29846aa8d69SPekka Enberg 		break;
299369c01c0SPekka Enberg 	}
3004e49b05bSCyrill Gorcunov 	case UART_LCR:
301c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
30246aa8d69SPekka Enberg 		break;
3034e49b05bSCyrill Gorcunov 	case UART_MCR:
304c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
30546aa8d69SPekka Enberg 		break;
3064e49b05bSCyrill Gorcunov 	case UART_LSR:
307c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
308369c01c0SPekka Enberg 		dev->lsr		&= ~(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI);
30946aa8d69SPekka Enberg 		break;
3104e49b05bSCyrill Gorcunov 	case UART_MSR:
311369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
31246aa8d69SPekka Enberg 		break;
3134e49b05bSCyrill Gorcunov 	case UART_SCR:
314369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
31546aa8d69SPekka Enberg 		break;
316369c01c0SPekka Enberg 	default:
3172932c9ebSPekka Enberg 		ret		= false;
3182932c9ebSPekka Enberg 		goto out_unlock;
31925af6674SPekka Enberg 	}
3202932c9ebSPekka Enberg out_unlock:
3214ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
3222932c9ebSPekka Enberg 
3232932c9ebSPekka Enberg 	return ret;
32413a7760fSPekka Enberg }
32513a7760fSPekka Enberg 
32646aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
32746aa8d69SPekka Enberg 	.io_in		= serial8250_in,
32846aa8d69SPekka Enberg 	.io_out		= serial8250_out,
329a93ec68bSPekka Enberg };
330a93ec68bSPekka Enberg 
331bc4b0ffeSPekka Enberg static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
332bc4b0ffeSPekka Enberg {
333bc4b0ffeSPekka Enberg 	ioport__register(dev->iobase, &serial8250_ops, 8);
334bc4b0ffeSPekka Enberg 	kvm__irq_line(kvm, dev->irq, 0);
335bc4b0ffeSPekka Enberg }
336bc4b0ffeSPekka Enberg 
337bc4b0ffeSPekka Enberg void serial8250__init(struct kvm *kvm)
33813a7760fSPekka Enberg {
339c6a69c61SPekka Enberg 	unsigned int i;
340c6a69c61SPekka Enberg 
341c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
342c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
343c6a69c61SPekka Enberg 
344bc4b0ffeSPekka Enberg 		serial8250__device_init(kvm, dev);
345c6a69c61SPekka Enberg 	}
34613a7760fSPekka Enberg }
347