xref: /kvmtool/hw/serial.c (revision 76b4a12288e7d78618a30c26f71ef4099793a2f5)
1899fe063SPekka Enberg #include "kvm/8250-serial.h"
213a7760fSPekka Enberg 
313a7760fSPekka Enberg #include "kvm/ioport.h"
446aa8d69SPekka Enberg #include "kvm/util.h"
5e557eef9SPekka Enberg #include "kvm/kvm.h"
613a7760fSPekka Enberg 
746aa8d69SPekka Enberg #include <stdbool.h>
8*76b4a122SPekka Enberg #include <poll.h>
913a7760fSPekka Enberg 
1046aa8d69SPekka Enberg /* Transmitter holding register */
1146aa8d69SPekka Enberg #define THR             0
123f55f3acSPekka Enberg 
1346aa8d69SPekka Enberg /* Receive buffer register */
1446aa8d69SPekka Enberg #define RBR             0
153f55f3acSPekka Enberg 
1646aa8d69SPekka Enberg /* Divisor latch low byte */
1746aa8d69SPekka Enberg #define DLL		0
183f55f3acSPekka Enberg 
1946aa8d69SPekka Enberg /* Divisor latch high byte */
2046aa8d69SPekka Enberg #define DLM		1
2146aa8d69SPekka Enberg 
2246aa8d69SPekka Enberg /* Interrupt enable register */
2346aa8d69SPekka Enberg #define IER		1
2446aa8d69SPekka Enberg 
25*76b4a122SPekka Enberg #define UART_IER_RDI		0x01
26e557eef9SPekka Enberg #define UART_IER_THRI		0x02
27e557eef9SPekka Enberg 
2846aa8d69SPekka Enberg /* Interrupt identification register */
2946aa8d69SPekka Enberg #define IIR		2
3046aa8d69SPekka Enberg 
319a7428ddSPekka Enberg #define UART_IIR_NO_INT		0x01
32900d32c1SPekka Enberg #define UART_IIR_THRI		0x02
339a7428ddSPekka Enberg 
3446aa8d69SPekka Enberg /* 16550 FIFO Control Register */
3546aa8d69SPekka Enberg #define FCR		2
3646aa8d69SPekka Enberg 
3746aa8d69SPekka Enberg /* Line control register */
3846aa8d69SPekka Enberg #define LCR		3
399a7428ddSPekka Enberg 
409a7428ddSPekka Enberg #define UART_LCR_DLAB		0x80
4146aa8d69SPekka Enberg 
4246aa8d69SPekka Enberg /* Modem control register */
4346aa8d69SPekka Enberg #define MCR		4
4446aa8d69SPekka Enberg 
4546aa8d69SPekka Enberg /* Line status register */
4646aa8d69SPekka Enberg #define LSR		5
4746aa8d69SPekka Enberg 
48*76b4a122SPekka Enberg #define UART_LSR_DR		0x01
499a7428ddSPekka Enberg #define UART_LSR_THRE		0x20
509a7428ddSPekka Enberg 
5146aa8d69SPekka Enberg /* Modem status register */
5246aa8d69SPekka Enberg #define MSR		6
5346aa8d69SPekka Enberg 
549a7428ddSPekka Enberg #define UART_MSR_CTS		0x10
559a7428ddSPekka Enberg 
5646aa8d69SPekka Enberg /* Scratch register */
5746aa8d69SPekka Enberg #define SCR		7
5846aa8d69SPekka Enberg 
5946aa8d69SPekka Enberg struct serial8250_device {
6046aa8d69SPekka Enberg 	uint16_t		iobase;
61e557eef9SPekka Enberg 	uint8_t			irq;
62*76b4a122SPekka Enberg 
63*76b4a122SPekka Enberg 	uint8_t			thr;
6446aa8d69SPekka Enberg 	uint8_t			dll;
6546aa8d69SPekka Enberg 	uint8_t			dlm;
66e557eef9SPekka Enberg 	uint8_t			iir;
6746aa8d69SPekka Enberg 	uint8_t			ier;
6846aa8d69SPekka Enberg 	uint8_t			fcr;
6946aa8d69SPekka Enberg 	uint8_t			lcr;
7046aa8d69SPekka Enberg 	uint8_t			mcr;
71*76b4a122SPekka Enberg 	uint8_t			lsr;
7246aa8d69SPekka Enberg 	uint8_t			scr;
7346aa8d69SPekka Enberg };
7446aa8d69SPekka Enberg 
7546aa8d69SPekka Enberg static struct serial8250_device device = {
7646aa8d69SPekka Enberg 	.iobase			= 0x3f8,	/* ttyS0 */
77e557eef9SPekka Enberg 	.irq			= 4,
78e557eef9SPekka Enberg 
79*76b4a122SPekka Enberg 	.iir			= UART_IIR_NO_INT,
80*76b4a122SPekka Enberg 	.lsr			= UART_LSR_THRE,
8146aa8d69SPekka Enberg };
8246aa8d69SPekka Enberg 
83*76b4a122SPekka Enberg static int read_char(int fd)
84*76b4a122SPekka Enberg {
85*76b4a122SPekka Enberg 	int c;
86*76b4a122SPekka Enberg 
87*76b4a122SPekka Enberg 	if (read(fd, &c, 1) < 0)
88*76b4a122SPekka Enberg 		return -1;
89*76b4a122SPekka Enberg 
90*76b4a122SPekka Enberg 	return c;
91*76b4a122SPekka Enberg }
92*76b4a122SPekka Enberg 
93*76b4a122SPekka Enberg static bool is_readable(int fd)
94*76b4a122SPekka Enberg {
95*76b4a122SPekka Enberg 	struct pollfd pollfd;
96*76b4a122SPekka Enberg 	int err;
97*76b4a122SPekka Enberg 
98*76b4a122SPekka Enberg 	pollfd		= (struct pollfd) {
99*76b4a122SPekka Enberg 		.fd		= fd,
100*76b4a122SPekka Enberg 		.events		= POLLIN,
101*76b4a122SPekka Enberg 	};
102*76b4a122SPekka Enberg 
103*76b4a122SPekka Enberg 	err		= poll(&pollfd, 1, 0);
104*76b4a122SPekka Enberg 	return err > 0;
105*76b4a122SPekka Enberg }
106*76b4a122SPekka Enberg 
1078bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self)
1088bb34e0dSPekka Enberg {
109*76b4a122SPekka Enberg 	if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) {
110*76b4a122SPekka Enberg 		int c;
111*76b4a122SPekka Enberg 
112*76b4a122SPekka Enberg 		c			= read_char(fileno(stdin));
113*76b4a122SPekka Enberg 		if (c >= 0) {
114*76b4a122SPekka Enberg 			device.thr		= c;
115*76b4a122SPekka Enberg 			device.lsr		|= UART_LSR_DR;
116*76b4a122SPekka Enberg 		}
117*76b4a122SPekka Enberg 	}
118*76b4a122SPekka Enberg 
119*76b4a122SPekka Enberg 	if (device.ier & UART_IER_THRI || device.lsr & UART_LSR_DR) {
120e557eef9SPekka Enberg 		device.iir		&= ~UART_IIR_NO_INT;
121e557eef9SPekka Enberg 		kvm__irq_line(self, device.irq, 1);
122e557eef9SPekka Enberg 	}
1238bb34e0dSPekka Enberg }
1248bb34e0dSPekka Enberg 
12546aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
12613a7760fSPekka Enberg {
12746aa8d69SPekka Enberg 	uint16_t offset = port - device.iobase;
12846aa8d69SPekka Enberg 
1299a7428ddSPekka Enberg 	if (device.lcr & UART_LCR_DLAB) {
13046aa8d69SPekka Enberg 		switch (offset) {
13146aa8d69SPekka Enberg 		case DLL:
13246aa8d69SPekka Enberg 			device.dll		= ioport__read8(data);
13346aa8d69SPekka Enberg 			break;
13446aa8d69SPekka Enberg 		case DLM:
13546aa8d69SPekka Enberg 			device.dlm		= ioport__read8(data);
13646aa8d69SPekka Enberg 			break;
13746aa8d69SPekka Enberg 		case FCR:
13846aa8d69SPekka Enberg 			device.fcr		= ioport__read8(data);
13946aa8d69SPekka Enberg 			break;
14046aa8d69SPekka Enberg 		case LCR:
14146aa8d69SPekka Enberg 			device.lcr		= ioport__read8(data);
14246aa8d69SPekka Enberg 			break;
14346aa8d69SPekka Enberg 		default:
14446aa8d69SPekka Enberg 			return false;
14546aa8d69SPekka Enberg 		}
14646aa8d69SPekka Enberg 	} else {
14746aa8d69SPekka Enberg 		switch (offset) {
14846aa8d69SPekka Enberg 		case THR: {
14913a7760fSPekka Enberg 			char *p = data;
150f2d8dc88SCyrill Gorcunov 			int i;
15113a7760fSPekka Enberg 
152f2d8dc88SCyrill Gorcunov 			while (count--) {
153f2d8dc88SCyrill Gorcunov 				for (i = 0; i < size; i++)
154b7475544SPekka Enberg 					fprintf(stdout, "%c", *p++);
1555b9d0b58SAsias He 			}
156b7475544SPekka Enberg 			fflush(stdout);
157e557eef9SPekka Enberg 
158e557eef9SPekka Enberg 			device.iir		|= UART_IIR_NO_INT;
159e557eef9SPekka Enberg 			kvm__irq_line(self, device.irq, 0);
160e557eef9SPekka Enberg 
16146aa8d69SPekka Enberg 			break;
16246aa8d69SPekka Enberg 		}
16346aa8d69SPekka Enberg 		case IER:
16446aa8d69SPekka Enberg 			device.ier		= ioport__read8(data);
16546aa8d69SPekka Enberg 			break;
16646aa8d69SPekka Enberg 		case FCR:
16746aa8d69SPekka Enberg 			device.fcr		= ioport__read8(data);
16846aa8d69SPekka Enberg 			break;
16946aa8d69SPekka Enberg 		case LCR:
17046aa8d69SPekka Enberg 			device.lcr		= ioport__read8(data);
17146aa8d69SPekka Enberg 			break;
17246aa8d69SPekka Enberg 		case MCR:
17346aa8d69SPekka Enberg 			device.mcr		= ioport__read8(data);
17446aa8d69SPekka Enberg 			break;
17546aa8d69SPekka Enberg 		case SCR:
17646aa8d69SPekka Enberg 			device.scr		= ioport__read8(data);
17746aa8d69SPekka Enberg 			break;
17846aa8d69SPekka Enberg 		default:
17946aa8d69SPekka Enberg 			return false;
18046aa8d69SPekka Enberg 		}
18146aa8d69SPekka Enberg 	}
18213a7760fSPekka Enberg 
18313a7760fSPekka Enberg 	return true;
18413a7760fSPekka Enberg }
18513a7760fSPekka Enberg 
18646aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
18725af6674SPekka Enberg {
18846aa8d69SPekka Enberg 	uint16_t offset = port - device.iobase;
18946aa8d69SPekka Enberg 
1909a7428ddSPekka Enberg 	if (device.lcr & UART_LCR_DLAB)
19146aa8d69SPekka Enberg 		return false;
19246aa8d69SPekka Enberg 
19346aa8d69SPekka Enberg 	switch (offset) {
19446aa8d69SPekka Enberg 	case THR:
195*76b4a122SPekka Enberg 		if (device.lsr & UART_LSR_DR) {
196*76b4a122SPekka Enberg 			device.lsr		&= ~UART_LSR_DR;
197*76b4a122SPekka Enberg 			ioport__write8(data, device.thr);
198*76b4a122SPekka Enberg 
199*76b4a122SPekka Enberg 			device.iir		|= UART_IIR_NO_INT;
200*76b4a122SPekka Enberg 			kvm__irq_line(self, device.irq, 0);
201*76b4a122SPekka Enberg 		}
20246aa8d69SPekka Enberg 		break;
20346aa8d69SPekka Enberg 	case IER:
20446aa8d69SPekka Enberg 		ioport__write8(data, device.ier);
20546aa8d69SPekka Enberg 		break;
20646aa8d69SPekka Enberg 	case IIR:
207e557eef9SPekka Enberg 		ioport__write8(data, device.iir);
20846aa8d69SPekka Enberg 		break;
20946aa8d69SPekka Enberg 	case LCR:
21046aa8d69SPekka Enberg 		ioport__write8(data, device.lcr);
21146aa8d69SPekka Enberg 		break;
21246aa8d69SPekka Enberg 	case MCR:
21346aa8d69SPekka Enberg 		ioport__write8(data, device.mcr);
21446aa8d69SPekka Enberg 		break;
21546aa8d69SPekka Enberg 	case LSR:
216*76b4a122SPekka Enberg 		ioport__write8(data, device.lsr);
21746aa8d69SPekka Enberg 		break;
21846aa8d69SPekka Enberg 	case MSR:
2199a7428ddSPekka Enberg 		ioport__write8(data, UART_MSR_CTS);
22046aa8d69SPekka Enberg 		break;
22146aa8d69SPekka Enberg 	case SCR:
22246aa8d69SPekka Enberg 		ioport__write8(data, device.scr);
22346aa8d69SPekka Enberg 		break;
22446aa8d69SPekka Enberg 	default:
22546aa8d69SPekka Enberg 		return false;
22625af6674SPekka Enberg 	}
22725af6674SPekka Enberg 
22813a7760fSPekka Enberg 	return true;
22913a7760fSPekka Enberg }
23013a7760fSPekka Enberg 
23146aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
23246aa8d69SPekka Enberg 	.io_in		= serial8250_in,
23346aa8d69SPekka Enberg 	.io_out		= serial8250_out,
234a93ec68bSPekka Enberg };
235a93ec68bSPekka Enberg 
236899fe063SPekka Enberg void serial8250__init(void)
23713a7760fSPekka Enberg {
23846aa8d69SPekka Enberg 	ioport__register(device.iobase, &serial8250_ops, 8);
23913a7760fSPekka Enberg }
240