xref: /kvmtool/hw/serial.c (revision 6d620acb6617e21e9b82b93d7ae50aca0b542dd8)
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 
74e49b05bSCyrill Gorcunov #include <linux/serial_reg.h>
84e49b05bSCyrill Gorcunov 
946aa8d69SPekka Enberg #include <stdbool.h>
1076b4a122SPekka Enberg #include <poll.h>
1113a7760fSPekka Enberg 
1246aa8d69SPekka Enberg struct serial8250_device {
1346aa8d69SPekka Enberg 	uint16_t		iobase;
14e557eef9SPekka Enberg 	uint8_t			irq;
1576b4a122SPekka Enberg 
1676b4a122SPekka Enberg 	uint8_t			thr;
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;
2546aa8d69SPekka Enberg 	uint8_t			scr;
2646aa8d69SPekka Enberg };
2746aa8d69SPekka Enberg 
2846aa8d69SPekka Enberg static struct serial8250_device device = {
2946aa8d69SPekka Enberg 	.iobase			= 0x3f8,	/* ttyS0 */
30e557eef9SPekka Enberg 	.irq			= 4,
31e557eef9SPekka Enberg 
3276b4a122SPekka Enberg 	.iir			= UART_IIR_NO_INT,
33*6d620acbSCyrill Gorcunov 	.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
3446aa8d69SPekka Enberg };
3546aa8d69SPekka Enberg 
3676b4a122SPekka Enberg static int read_char(int fd)
3776b4a122SPekka Enberg {
3876b4a122SPekka Enberg 	int c;
3976b4a122SPekka Enberg 
4076b4a122SPekka Enberg 	if (read(fd, &c, 1) < 0)
4176b4a122SPekka Enberg 		return -1;
4276b4a122SPekka Enberg 
4376b4a122SPekka Enberg 	return c;
4476b4a122SPekka Enberg }
4576b4a122SPekka Enberg 
4676b4a122SPekka Enberg static bool is_readable(int fd)
4776b4a122SPekka Enberg {
486d54df74SCyrill Gorcunov 	struct pollfd pollfd = (struct pollfd) {
4976b4a122SPekka Enberg 		.fd	= fd,
5076b4a122SPekka Enberg 		.events	= POLLIN,
5176b4a122SPekka Enberg 	};
5276b4a122SPekka Enberg 
536d54df74SCyrill Gorcunov 	return poll(&pollfd, 1, 0) > 0;
5476b4a122SPekka Enberg }
5576b4a122SPekka Enberg 
568bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self)
578bb34e0dSPekka Enberg {
5876b4a122SPekka Enberg 	if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) {
5976b4a122SPekka Enberg 		int c;
6076b4a122SPekka Enberg 
6176b4a122SPekka Enberg 		c			= read_char(fileno(stdin));
6276b4a122SPekka Enberg 		if (c >= 0) {
6376b4a122SPekka Enberg 			device.thr		= c;
6476b4a122SPekka Enberg 			device.lsr		|= UART_LSR_DR;
6576b4a122SPekka Enberg 		}
6676b4a122SPekka Enberg 	}
6776b4a122SPekka Enberg 
6876b4a122SPekka Enberg 	if (device.ier & UART_IER_THRI || device.lsr & UART_LSR_DR) {
69e557eef9SPekka Enberg 		device.iir		&= ~UART_IIR_NO_INT;
70e557eef9SPekka Enberg 		kvm__irq_line(self, device.irq, 1);
71e557eef9SPekka Enberg 	}
728bb34e0dSPekka Enberg }
738bb34e0dSPekka Enberg 
7446aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
7513a7760fSPekka Enberg {
7646aa8d69SPekka Enberg 	uint16_t offset = port - device.iobase;
7746aa8d69SPekka Enberg 
789a7428ddSPekka Enberg 	if (device.lcr & UART_LCR_DLAB) {
7946aa8d69SPekka Enberg 		switch (offset) {
804e49b05bSCyrill Gorcunov 		case UART_DLL:
8146aa8d69SPekka Enberg 			device.dll		= ioport__read8(data);
8246aa8d69SPekka Enberg 			break;
834e49b05bSCyrill Gorcunov 		case UART_DLM:
8446aa8d69SPekka Enberg 			device.dlm		= ioport__read8(data);
8546aa8d69SPekka Enberg 			break;
864e49b05bSCyrill Gorcunov 		case UART_FCR:
8746aa8d69SPekka Enberg 			device.fcr		= ioport__read8(data);
8846aa8d69SPekka Enberg 			break;
894e49b05bSCyrill Gorcunov 		case UART_LCR:
9046aa8d69SPekka Enberg 			device.lcr		= ioport__read8(data);
9146aa8d69SPekka Enberg 			break;
9246aa8d69SPekka Enberg 		default:
9346aa8d69SPekka Enberg 			return false;
9446aa8d69SPekka Enberg 		}
9546aa8d69SPekka Enberg 	} else {
9646aa8d69SPekka Enberg 		switch (offset) {
974e49b05bSCyrill Gorcunov 		case UART_TX: {
9813a7760fSPekka Enberg 			char *p = data;
99f2d8dc88SCyrill Gorcunov 			int i;
10013a7760fSPekka Enberg 
101f2d8dc88SCyrill Gorcunov 			while (count--) {
102f2d8dc88SCyrill Gorcunov 				for (i = 0; i < size; i++)
103b7475544SPekka Enberg 					fprintf(stdout, "%c", *p++);
1045b9d0b58SAsias He 			}
105b7475544SPekka Enberg 			fflush(stdout);
106e557eef9SPekka Enberg 
107e557eef9SPekka Enberg 			device.iir		|= UART_IIR_NO_INT;
108e557eef9SPekka Enberg 			kvm__irq_line(self, device.irq, 0);
109e557eef9SPekka Enberg 
11046aa8d69SPekka Enberg 			break;
11146aa8d69SPekka Enberg 		}
1124e49b05bSCyrill Gorcunov 		case UART_IER:
11346aa8d69SPekka Enberg 			device.ier		= ioport__read8(data);
11446aa8d69SPekka Enberg 			break;
1154e49b05bSCyrill Gorcunov 		case UART_FCR:
11646aa8d69SPekka Enberg 			device.fcr		= ioport__read8(data);
11746aa8d69SPekka Enberg 			break;
1184e49b05bSCyrill Gorcunov 		case UART_LCR:
11946aa8d69SPekka Enberg 			device.lcr		= ioport__read8(data);
12046aa8d69SPekka Enberg 			break;
1214e49b05bSCyrill Gorcunov 		case UART_MCR:
12246aa8d69SPekka Enberg 			device.mcr		= ioport__read8(data);
12346aa8d69SPekka Enberg 			break;
1244e49b05bSCyrill Gorcunov 		case UART_SCR:
12546aa8d69SPekka Enberg 			device.scr		= ioport__read8(data);
12646aa8d69SPekka Enberg 			break;
12746aa8d69SPekka Enberg 		default:
12846aa8d69SPekka Enberg 			return false;
12946aa8d69SPekka Enberg 		}
13046aa8d69SPekka Enberg 	}
13113a7760fSPekka Enberg 
13213a7760fSPekka Enberg 	return true;
13313a7760fSPekka Enberg }
13413a7760fSPekka Enberg 
13546aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
13625af6674SPekka Enberg {
13746aa8d69SPekka Enberg 	uint16_t offset = port - device.iobase;
13846aa8d69SPekka Enberg 
1399a7428ddSPekka Enberg 	if (device.lcr & UART_LCR_DLAB)
14046aa8d69SPekka Enberg 		return false;
14146aa8d69SPekka Enberg 
14246aa8d69SPekka Enberg 	switch (offset) {
1434e49b05bSCyrill Gorcunov 	case UART_TX:
14476b4a122SPekka Enberg 		if (device.lsr & UART_LSR_DR) {
14576b4a122SPekka Enberg 			device.lsr		&= ~UART_LSR_DR;
14676b4a122SPekka Enberg 			ioport__write8(data, device.thr);
14776b4a122SPekka Enberg 
14876b4a122SPekka Enberg 			device.iir		|= UART_IIR_NO_INT;
14976b4a122SPekka Enberg 			kvm__irq_line(self, device.irq, 0);
15076b4a122SPekka Enberg 		}
15146aa8d69SPekka Enberg 		break;
1524e49b05bSCyrill Gorcunov 	case UART_IER:
15346aa8d69SPekka Enberg 		ioport__write8(data, device.ier);
15446aa8d69SPekka Enberg 		break;
1554e49b05bSCyrill Gorcunov 	case UART_IIR:
156e557eef9SPekka Enberg 		ioport__write8(data, device.iir);
15746aa8d69SPekka Enberg 		break;
1584e49b05bSCyrill Gorcunov 	case UART_LCR:
15946aa8d69SPekka Enberg 		ioport__write8(data, device.lcr);
16046aa8d69SPekka Enberg 		break;
1614e49b05bSCyrill Gorcunov 	case UART_MCR:
16246aa8d69SPekka Enberg 		ioport__write8(data, device.mcr);
16346aa8d69SPekka Enberg 		break;
1644e49b05bSCyrill Gorcunov 	case UART_LSR:
16576b4a122SPekka Enberg 		ioport__write8(data, device.lsr);
16646aa8d69SPekka Enberg 		break;
1674e49b05bSCyrill Gorcunov 	case UART_MSR:
1689a7428ddSPekka Enberg 		ioport__write8(data, UART_MSR_CTS);
16946aa8d69SPekka Enberg 		break;
1704e49b05bSCyrill Gorcunov 	case UART_SCR:
17146aa8d69SPekka Enberg 		ioport__write8(data, device.scr);
17246aa8d69SPekka Enberg 		break;
17346aa8d69SPekka Enberg 	default:
17446aa8d69SPekka Enberg 		return false;
17525af6674SPekka Enberg 	}
17625af6674SPekka Enberg 
17713a7760fSPekka Enberg 	return true;
17813a7760fSPekka Enberg }
17913a7760fSPekka Enberg 
18046aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
18146aa8d69SPekka Enberg 	.io_in		= serial8250_in,
18246aa8d69SPekka Enberg 	.io_out		= serial8250_out,
183a93ec68bSPekka Enberg };
184a93ec68bSPekka Enberg 
185899fe063SPekka Enberg void serial8250__init(void)
18613a7760fSPekka Enberg {
18746aa8d69SPekka Enberg 	ioport__register(device.iobase, &serial8250_ops, 8);
18813a7760fSPekka Enberg }
189