xref: /kvmtool/hw/serial.c (revision 4ef0f4d620fa5df6d61ff6d4fff7f03680c7e73e)
1899fe063SPekka Enberg #include "kvm/8250-serial.h"
213a7760fSPekka Enberg 
38eb47d29SSasha Levin #include "kvm/read-write.h"
413a7760fSPekka Enberg #include "kvm/ioport.h"
5*4ef0f4d6SPekka 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 
104e49b05bSCyrill Gorcunov #include <linux/serial_reg.h>
114e49b05bSCyrill Gorcunov 
122932c9ebSPekka Enberg #include <pthread.h>
1313a7760fSPekka Enberg 
1446aa8d69SPekka Enberg struct serial8250_device {
152932c9ebSPekka Enberg 	pthread_mutex_t		mutex;
162932c9ebSPekka Enberg 
1746aa8d69SPekka Enberg 	uint16_t		iobase;
18e557eef9SPekka Enberg 	uint8_t			irq;
1976b4a122SPekka Enberg 
20251cf9a6SPekka Enberg 	uint8_t			rbr;		/* receive buffer */
2146aa8d69SPekka Enberg 	uint8_t			dll;
2246aa8d69SPekka Enberg 	uint8_t			dlm;
23e557eef9SPekka Enberg 	uint8_t			iir;
2446aa8d69SPekka Enberg 	uint8_t			ier;
2546aa8d69SPekka Enberg 	uint8_t			fcr;
2646aa8d69SPekka Enberg 	uint8_t			lcr;
2746aa8d69SPekka Enberg 	uint8_t			mcr;
2876b4a122SPekka Enberg 	uint8_t			lsr;
29369c01c0SPekka Enberg 	uint8_t			msr;
3046aa8d69SPekka Enberg 	uint8_t			scr;
3146aa8d69SPekka Enberg };
3246aa8d69SPekka Enberg 
33e62c18deSPekka Enberg static struct serial8250_device devices[] = {
34c6a69c61SPekka Enberg 	/* ttyS0 */
35c6a69c61SPekka Enberg 	[0]	= {
362932c9ebSPekka Enberg 		.mutex			= PTHREAD_MUTEX_INITIALIZER,
372932c9ebSPekka Enberg 
38c6a69c61SPekka Enberg 		.iobase			= 0x3f8,
39e557eef9SPekka Enberg 		.irq			= 4,
40e557eef9SPekka Enberg 
41369c01c0SPekka Enberg 		.iir			= UART_IIR_NO_INT,
42bc4b0ffeSPekka Enberg 		.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
43bc4b0ffeSPekka Enberg 		.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS,
44bc4b0ffeSPekka Enberg 		.mcr			= UART_MCR_OUT2,
45c6a69c61SPekka Enberg 	},
46e62c18deSPekka Enberg 	/* ttyS1 */
47e62c18deSPekka Enberg 	[1]	= {
482932c9ebSPekka Enberg 		.mutex			= PTHREAD_MUTEX_INITIALIZER,
492932c9ebSPekka Enberg 
50e62c18deSPekka Enberg 		.iobase			= 0x2f8,
51e62c18deSPekka Enberg 		.irq			= 3,
52133bedc1SPekka Enberg 
53133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
54e62c18deSPekka Enberg 	},
55e62c18deSPekka Enberg 	/* ttyS2 */
56e62c18deSPekka Enberg 	[2]	= {
572932c9ebSPekka Enberg 		.mutex			= PTHREAD_MUTEX_INITIALIZER,
582932c9ebSPekka Enberg 
59e62c18deSPekka Enberg 		.iobase			= 0x3e8,
60e62c18deSPekka Enberg 		.irq			= 4,
61133bedc1SPekka Enberg 
62133bedc1SPekka Enberg 		.iir			= UART_IIR_NO_INT,
63e62c18deSPekka Enberg 	},
6446aa8d69SPekka Enberg };
6546aa8d69SPekka Enberg 
66a428f72eSPekka Enberg #define SYSRQ_PENDING_NONE		0
67a428f72eSPekka Enberg #define SYSRQ_PENDING_BREAK		1
68a428f72eSPekka Enberg #define SYSRQ_PENDING_CMD		2
69a428f72eSPekka Enberg 
70a428f72eSPekka Enberg static int sysrq_pending;
71a428f72eSPekka Enberg 
72a428f72eSPekka Enberg static void serial8250__sysrq(struct kvm *self, struct serial8250_device *dev)
73a428f72eSPekka Enberg {
74a428f72eSPekka Enberg 	switch (sysrq_pending) {
75a428f72eSPekka Enberg 	case SYSRQ_PENDING_BREAK:
76a428f72eSPekka Enberg 		dev->lsr	|= UART_LSR_DR | UART_LSR_BI;
77a428f72eSPekka Enberg 
78a428f72eSPekka Enberg 		sysrq_pending	= SYSRQ_PENDING_CMD;
79a428f72eSPekka Enberg 		break;
80a428f72eSPekka Enberg 	case SYSRQ_PENDING_CMD:
81a428f72eSPekka Enberg 		dev->rbr	= 'p';
82a428f72eSPekka Enberg 		dev->lsr	|= UART_LSR_DR;
83a428f72eSPekka Enberg 
84a428f72eSPekka Enberg 		sysrq_pending	= SYSRQ_PENDING_NONE;
85a428f72eSPekka Enberg 		break;
86a428f72eSPekka Enberg 	}
87a428f72eSPekka Enberg }
88a428f72eSPekka Enberg 
89251cf9a6SPekka Enberg static void serial8250__receive(struct kvm *self, struct serial8250_device *dev)
90251cf9a6SPekka Enberg {
91251cf9a6SPekka Enberg 	int c;
92251cf9a6SPekka Enberg 
93db34045cSPekka Enberg 	if (dev->lsr & UART_LSR_DR)
94db34045cSPekka Enberg 		return;
95db34045cSPekka Enberg 
96a428f72eSPekka Enberg 	if (sysrq_pending) {
97a428f72eSPekka Enberg 		serial8250__sysrq(self, dev);
98a428f72eSPekka Enberg 		return;
99a428f72eSPekka Enberg 	}
100a428f72eSPekka Enberg 
10105d1a2a6SAsias He 	if (!term_readable(CONSOLE_8250))
102251cf9a6SPekka Enberg 		return;
103251cf9a6SPekka Enberg 
10405d1a2a6SAsias He 	c		= term_getc(CONSOLE_8250);
10505d1a2a6SAsias He 
106251cf9a6SPekka Enberg 	if (c < 0)
107251cf9a6SPekka Enberg 		return;
108251cf9a6SPekka Enberg 
109251cf9a6SPekka Enberg 	dev->rbr	= c;
110251cf9a6SPekka Enberg 	dev->lsr	|= UART_LSR_DR;
111251cf9a6SPekka Enberg }
112251cf9a6SPekka Enberg 
113c6a69c61SPekka Enberg /*
114c6a69c61SPekka Enberg  * Interrupts are injected for ttyS0 only.
115c6a69c61SPekka Enberg  */
11605d1a2a6SAsias He void serial8250__inject_interrupt(struct kvm *self)
1178bb34e0dSPekka Enberg {
118c6a69c61SPekka Enberg 	struct serial8250_device *dev = &devices[0];
119934c193bSPekka Enberg 
120*4ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
1212932c9ebSPekka Enberg 
122251cf9a6SPekka Enberg 	serial8250__receive(self, dev);
123251cf9a6SPekka Enberg 
124369c01c0SPekka Enberg 	if (dev->ier & UART_IER_RDI && dev->lsr & UART_LSR_DR)
125369c01c0SPekka Enberg 		dev->iir		= UART_IIR_RDI;
126251cf9a6SPekka Enberg 	else if (dev->ier & UART_IER_THRI)
127369c01c0SPekka Enberg 		dev->iir		= UART_IIR_THRI;
128369c01c0SPekka Enberg 	else
129369c01c0SPekka Enberg 		dev->iir		= UART_IIR_NO_INT;
13076b4a122SPekka Enberg 
131369c01c0SPekka Enberg 	if (dev->iir != UART_IIR_NO_INT) {
132c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 0);
133c6a69c61SPekka Enberg 		kvm__irq_line(self, dev->irq, 1);
134e557eef9SPekka Enberg 	}
1352932c9ebSPekka Enberg 
136*4ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
1378bb34e0dSPekka Enberg }
1388bb34e0dSPekka Enberg 
139a428f72eSPekka Enberg void serial8250__inject_sysrq(struct kvm *self)
140a428f72eSPekka Enberg {
141a428f72eSPekka Enberg 	sysrq_pending	= SYSRQ_PENDING_BREAK;
142a428f72eSPekka Enberg }
143a428f72eSPekka Enberg 
144c6a69c61SPekka Enberg static struct serial8250_device *find_device(uint16_t port)
145c6a69c61SPekka Enberg {
146c6a69c61SPekka Enberg 	unsigned int i;
147c6a69c61SPekka Enberg 
148c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
149c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
150c6a69c61SPekka Enberg 
151c6a69c61SPekka Enberg 		if (dev->iobase == (port & ~0x7))
152c6a69c61SPekka Enberg 			return dev;
153c6a69c61SPekka Enberg 	}
154c6a69c61SPekka Enberg 	return NULL;
155c6a69c61SPekka Enberg }
156c6a69c61SPekka Enberg 
15746aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
15813a7760fSPekka Enberg {
159c6a69c61SPekka Enberg 	struct serial8250_device *dev;
160c6a69c61SPekka Enberg 	uint16_t offset;
1612932c9ebSPekka Enberg 	bool ret = true;
16246aa8d69SPekka Enberg 
163c6a69c61SPekka Enberg 	dev		= find_device(port);
164c6a69c61SPekka Enberg 	if (!dev)
165c6a69c61SPekka Enberg 		return false;
166c6a69c61SPekka Enberg 
167*4ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
1682932c9ebSPekka Enberg 
169c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
170c6a69c61SPekka Enberg 
171c6a69c61SPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
17246aa8d69SPekka Enberg 		switch (offset) {
1734e49b05bSCyrill Gorcunov 		case UART_DLL:
174c6a69c61SPekka Enberg 			dev->dll	= ioport__read8(data);
17546aa8d69SPekka Enberg 			break;
1764e49b05bSCyrill Gorcunov 		case UART_DLM:
177c6a69c61SPekka Enberg 			dev->dlm	= ioport__read8(data);
17846aa8d69SPekka Enberg 			break;
179369c01c0SPekka Enberg 		case UART_FCR:
180369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
181369c01c0SPekka Enberg 			break;
182369c01c0SPekka Enberg 		case UART_LCR:
183369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
184369c01c0SPekka Enberg 			break;
185369c01c0SPekka Enberg 		case UART_MCR:
186369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
187369c01c0SPekka Enberg 			break;
188369c01c0SPekka Enberg 		case UART_LSR:
189369c01c0SPekka Enberg 			/* Factory test */
190369c01c0SPekka Enberg 			break;
191369c01c0SPekka Enberg 		case UART_MSR:
192369c01c0SPekka Enberg 			/* Not used */
193369c01c0SPekka Enberg 			break;
194369c01c0SPekka Enberg 		case UART_SCR:
195369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
196369c01c0SPekka Enberg 			break;
197369c01c0SPekka Enberg 		default:
1982932c9ebSPekka Enberg 			ret		= false;
1992932c9ebSPekka Enberg 			goto out_unlock;
20046aa8d69SPekka Enberg 		}
20146aa8d69SPekka Enberg 	} else {
20246aa8d69SPekka Enberg 		switch (offset) {
2034e49b05bSCyrill Gorcunov 		case UART_TX: {
20405d1a2a6SAsias He 			char *addr = data;
2050ea58e5bSPekka Enberg 
2060ea58e5bSPekka Enberg 			if (!(dev->mcr & UART_MCR_LOOP))
20705d1a2a6SAsias He 				term_putc(CONSOLE_8250, addr, size * count);
2080ea58e5bSPekka Enberg 
209133bedc1SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
21046aa8d69SPekka Enberg 			break;
21146aa8d69SPekka Enberg 		}
212369c01c0SPekka Enberg 		case UART_FCR:
213369c01c0SPekka Enberg 			dev->fcr	= ioport__read8(data);
214369c01c0SPekka Enberg 			break;
2154e49b05bSCyrill Gorcunov 		case UART_IER:
216369c01c0SPekka Enberg 			dev->ier	= ioport__read8(data) & 0x3f;
21746aa8d69SPekka Enberg 			break;
218369c01c0SPekka Enberg 		case UART_LCR:
219369c01c0SPekka Enberg 			dev->lcr	= ioport__read8(data);
220369c01c0SPekka Enberg 			break;
221369c01c0SPekka Enberg 		case UART_MCR:
222369c01c0SPekka Enberg 			dev->mcr	= ioport__read8(data);
223369c01c0SPekka Enberg 			break;
224369c01c0SPekka Enberg 		case UART_LSR:
225369c01c0SPekka Enberg 			/* Factory test */
226369c01c0SPekka Enberg 			break;
227369c01c0SPekka Enberg 		case UART_MSR:
228369c01c0SPekka Enberg 			/* Not used */
229369c01c0SPekka Enberg 			break;
230369c01c0SPekka Enberg 		case UART_SCR:
231369c01c0SPekka Enberg 			dev->scr	= ioport__read8(data);
232369c01c0SPekka Enberg 			break;
233369c01c0SPekka Enberg 		default:
2342932c9ebSPekka Enberg 			ret		= false;
2352932c9ebSPekka Enberg 			goto out_unlock;
23646aa8d69SPekka Enberg 		}
23746aa8d69SPekka Enberg 	}
2382932c9ebSPekka Enberg 
2392932c9ebSPekka Enberg out_unlock:
240*4ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
2412932c9ebSPekka Enberg 
2422932c9ebSPekka Enberg 	return ret;
24313a7760fSPekka Enberg }
24413a7760fSPekka Enberg 
24546aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
24625af6674SPekka Enberg {
247c6a69c61SPekka Enberg 	struct serial8250_device *dev;
248c6a69c61SPekka Enberg 	uint16_t offset;
2492932c9ebSPekka Enberg 	bool ret = true;
25046aa8d69SPekka Enberg 
251c6a69c61SPekka Enberg 	dev		= find_device(port);
252c6a69c61SPekka Enberg 	if (!dev)
253c6a69c61SPekka Enberg 		return false;
254c6a69c61SPekka Enberg 
255*4ef0f4d6SPekka Enberg 	mutex_lock(&dev->mutex);
2562932c9ebSPekka Enberg 
257c6a69c61SPekka Enberg 	offset		= port - dev->iobase;
258c6a69c61SPekka Enberg 
25919a2bb7dSPekka Enberg 	if (dev->lcr & UART_LCR_DLAB) {
26019a2bb7dSPekka Enberg 		switch (offset) {
26119a2bb7dSPekka Enberg 		case UART_DLL:
26219a2bb7dSPekka Enberg 			ioport__write8(data, dev->dll);
2632932c9ebSPekka Enberg 			goto out_unlock;
2642932c9ebSPekka Enberg 
26519a2bb7dSPekka Enberg 		case UART_DLM:
26619a2bb7dSPekka Enberg 			ioport__write8(data, dev->dlm);
2672932c9ebSPekka Enberg 			goto out_unlock;
2682932c9ebSPekka Enberg 
269369c01c0SPekka Enberg 		default:
270369c01c0SPekka Enberg 			break;
27119a2bb7dSPekka Enberg 		}
27219a2bb7dSPekka Enberg 	} else {
27346aa8d69SPekka Enberg 		switch (offset) {
274251cf9a6SPekka Enberg 		case UART_RX:
275251cf9a6SPekka Enberg 			ioport__write8(data, dev->rbr);
276369c01c0SPekka Enberg 			dev->lsr		&= ~UART_LSR_DR;
277369c01c0SPekka Enberg 			dev->iir		= UART_IIR_NO_INT;
2782932c9ebSPekka Enberg 			goto out_unlock;
2792932c9ebSPekka Enberg 
2804e49b05bSCyrill Gorcunov 		case UART_IER:
281c6a69c61SPekka Enberg 			ioport__write8(data, dev->ier);
2822932c9ebSPekka Enberg 			goto out_unlock;
2832932c9ebSPekka Enberg 
284369c01c0SPekka Enberg 		default:
285369c01c0SPekka Enberg 			break;
28619a2bb7dSPekka Enberg 		}
28719a2bb7dSPekka Enberg 	}
28819a2bb7dSPekka Enberg 
28919a2bb7dSPekka Enberg 	switch (offset) {
290369c01c0SPekka Enberg 	case UART_IIR: {
291369c01c0SPekka Enberg 		uint8_t iir = dev->iir;
292369c01c0SPekka Enberg 
293369c01c0SPekka Enberg 		if (dev->fcr & UART_FCR_ENABLE_FIFO)
294369c01c0SPekka Enberg 			iir		|= 0xc0;
295369c01c0SPekka Enberg 
296369c01c0SPekka Enberg 		ioport__write8(data, iir);
29746aa8d69SPekka Enberg 		break;
298369c01c0SPekka Enberg 	}
2994e49b05bSCyrill Gorcunov 	case UART_LCR:
300c6a69c61SPekka Enberg 		ioport__write8(data, dev->lcr);
30146aa8d69SPekka Enberg 		break;
3024e49b05bSCyrill Gorcunov 	case UART_MCR:
303c6a69c61SPekka Enberg 		ioport__write8(data, dev->mcr);
30446aa8d69SPekka Enberg 		break;
3054e49b05bSCyrill Gorcunov 	case UART_LSR:
306c6a69c61SPekka Enberg 		ioport__write8(data, dev->lsr);
307369c01c0SPekka Enberg 		dev->lsr		&= ~(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI);
30846aa8d69SPekka Enberg 		break;
3094e49b05bSCyrill Gorcunov 	case UART_MSR:
310369c01c0SPekka Enberg 		ioport__write8(data, dev->msr);
31146aa8d69SPekka Enberg 		break;
3124e49b05bSCyrill Gorcunov 	case UART_SCR:
313369c01c0SPekka Enberg 		ioport__write8(data, dev->scr);
31446aa8d69SPekka Enberg 		break;
315369c01c0SPekka Enberg 	default:
3162932c9ebSPekka Enberg 		ret		= false;
3172932c9ebSPekka Enberg 		goto out_unlock;
31825af6674SPekka Enberg 	}
3192932c9ebSPekka Enberg out_unlock:
320*4ef0f4d6SPekka Enberg 	mutex_unlock(&dev->mutex);
3212932c9ebSPekka Enberg 
3222932c9ebSPekka Enberg 	return ret;
32313a7760fSPekka Enberg }
32413a7760fSPekka Enberg 
32546aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
32646aa8d69SPekka Enberg 	.io_in		= serial8250_in,
32746aa8d69SPekka Enberg 	.io_out		= serial8250_out,
328a93ec68bSPekka Enberg };
329a93ec68bSPekka Enberg 
330bc4b0ffeSPekka Enberg static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
331bc4b0ffeSPekka Enberg {
332bc4b0ffeSPekka Enberg 	ioport__register(dev->iobase, &serial8250_ops, 8);
333bc4b0ffeSPekka Enberg 	kvm__irq_line(kvm, dev->irq, 0);
334bc4b0ffeSPekka Enberg }
335bc4b0ffeSPekka Enberg 
336bc4b0ffeSPekka Enberg void serial8250__init(struct kvm *kvm)
33713a7760fSPekka Enberg {
338c6a69c61SPekka Enberg 	unsigned int i;
339c6a69c61SPekka Enberg 
340c6a69c61SPekka Enberg 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
341c6a69c61SPekka Enberg 		struct serial8250_device *dev = &devices[i];
342c6a69c61SPekka Enberg 
343bc4b0ffeSPekka Enberg 		serial8250__device_init(kvm, dev);
344c6a69c61SPekka Enberg 	}
34513a7760fSPekka Enberg }
346