xref: /kvmtool/hw/serial.c (revision 934c193b93076a2aa43719914c1f33200ef940ad)
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 
326d620acbSCyrill Gorcunov 	.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
3346aa8d69SPekka Enberg };
3446aa8d69SPekka Enberg 
3576b4a122SPekka Enberg static int read_char(int fd)
3676b4a122SPekka Enberg {
3776b4a122SPekka Enberg 	int c;
3876b4a122SPekka Enberg 
3976b4a122SPekka Enberg 	if (read(fd, &c, 1) < 0)
4076b4a122SPekka Enberg 		return -1;
4176b4a122SPekka Enberg 
4276b4a122SPekka Enberg 	return c;
4376b4a122SPekka Enberg }
4476b4a122SPekka Enberg 
4576b4a122SPekka Enberg static bool is_readable(int fd)
4676b4a122SPekka Enberg {
476d54df74SCyrill Gorcunov 	struct pollfd pollfd = (struct pollfd) {
4876b4a122SPekka Enberg 		.fd	= fd,
4976b4a122SPekka Enberg 		.events	= POLLIN,
5076b4a122SPekka Enberg 	};
5176b4a122SPekka Enberg 
526d54df74SCyrill Gorcunov 	return poll(&pollfd, 1, 0) > 0;
5376b4a122SPekka Enberg }
5476b4a122SPekka Enberg 
558bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self)
568bb34e0dSPekka Enberg {
57*934c193bSPekka Enberg 	uint8_t new_iir;
58*934c193bSPekka Enberg 
59*934c193bSPekka Enberg 	device.iir	= UART_IIR_NO_INT;
60*934c193bSPekka Enberg 
61*934c193bSPekka Enberg 	/* No interrupts enabled. Exit... */
62*934c193bSPekka Enberg 	if (!(device.ier & (UART_IER_THRI|UART_IER_RDI)))
63*934c193bSPekka Enberg 		return;
64*934c193bSPekka Enberg 
65*934c193bSPekka Enberg 	new_iir		= 0;
66*934c193bSPekka Enberg 
67*934c193bSPekka Enberg 	/* We're always good for guest sending data. */
68*934c193bSPekka Enberg 	if (device.ier & UART_IER_THRI)
69*934c193bSPekka Enberg 		new_iir			|= UART_IIR_THRI;
70*934c193bSPekka Enberg 
71*934c193bSPekka Enberg 	/* Is there input in stdin to send to the guest? */
7276b4a122SPekka Enberg 	if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) {
7376b4a122SPekka Enberg 		int c;
7476b4a122SPekka Enberg 
7576b4a122SPekka Enberg 		c			= read_char(fileno(stdin));
7676b4a122SPekka Enberg 		if (c >= 0) {
7776b4a122SPekka Enberg 			device.thr		= c;
7876b4a122SPekka Enberg 			device.lsr		|= UART_LSR_DR;
79*934c193bSPekka Enberg 			new_iir			|= UART_IIR_RDI;
8076b4a122SPekka Enberg 		}
8176b4a122SPekka Enberg 	}
8276b4a122SPekka Enberg 
83*934c193bSPekka Enberg 	/* Only send an IRQ if there's work to do. */
84*934c193bSPekka Enberg 	if (new_iir) {
85*934c193bSPekka Enberg 		device.iir		= new_iir;
86*934c193bSPekka Enberg 		kvm__irq_line(self, device.irq, 0);
87e557eef9SPekka Enberg 		kvm__irq_line(self, device.irq, 1);
88e557eef9SPekka Enberg 	}
898bb34e0dSPekka Enberg }
908bb34e0dSPekka Enberg 
9146aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
9213a7760fSPekka Enberg {
9346aa8d69SPekka Enberg 	uint16_t offset = port - device.iobase;
9446aa8d69SPekka Enberg 
959a7428ddSPekka Enberg 	if (device.lcr & UART_LCR_DLAB) {
9646aa8d69SPekka Enberg 		switch (offset) {
974e49b05bSCyrill Gorcunov 		case UART_DLL:
9846aa8d69SPekka Enberg 			device.dll		= ioport__read8(data);
9946aa8d69SPekka Enberg 			break;
1004e49b05bSCyrill Gorcunov 		case UART_DLM:
10146aa8d69SPekka Enberg 			device.dlm		= ioport__read8(data);
10246aa8d69SPekka Enberg 			break;
1034e49b05bSCyrill Gorcunov 		case UART_FCR:
10446aa8d69SPekka Enberg 			device.fcr		= ioport__read8(data);
10546aa8d69SPekka Enberg 			break;
1064e49b05bSCyrill Gorcunov 		case UART_LCR:
10746aa8d69SPekka Enberg 			device.lcr		= ioport__read8(data);
10846aa8d69SPekka Enberg 			break;
10946aa8d69SPekka Enberg 		default:
11046aa8d69SPekka Enberg 			return false;
11146aa8d69SPekka Enberg 		}
11246aa8d69SPekka Enberg 	} else {
11346aa8d69SPekka Enberg 		switch (offset) {
1144e49b05bSCyrill Gorcunov 		case UART_TX: {
11513a7760fSPekka Enberg 			char *p = data;
116f2d8dc88SCyrill Gorcunov 			int i;
11713a7760fSPekka Enberg 
118f2d8dc88SCyrill Gorcunov 			while (count--) {
119f2d8dc88SCyrill Gorcunov 				for (i = 0; i < size; i++)
120b7475544SPekka Enberg 					fprintf(stdout, "%c", *p++);
1215b9d0b58SAsias He 			}
122b7475544SPekka Enberg 			fflush(stdout);
123e557eef9SPekka Enberg 
12446aa8d69SPekka Enberg 			break;
12546aa8d69SPekka Enberg 		}
1264e49b05bSCyrill Gorcunov 		case UART_IER:
12746aa8d69SPekka Enberg 			device.ier		= ioport__read8(data);
12846aa8d69SPekka Enberg 			break;
1294e49b05bSCyrill Gorcunov 		case UART_FCR:
13046aa8d69SPekka Enberg 			device.fcr		= ioport__read8(data);
13146aa8d69SPekka Enberg 			break;
1324e49b05bSCyrill Gorcunov 		case UART_LCR:
13346aa8d69SPekka Enberg 			device.lcr		= ioport__read8(data);
13446aa8d69SPekka Enberg 			break;
1354e49b05bSCyrill Gorcunov 		case UART_MCR:
13646aa8d69SPekka Enberg 			device.mcr		= ioport__read8(data);
13746aa8d69SPekka Enberg 			break;
1384e49b05bSCyrill Gorcunov 		case UART_SCR:
13946aa8d69SPekka Enberg 			device.scr		= ioport__read8(data);
14046aa8d69SPekka Enberg 			break;
14146aa8d69SPekka Enberg 		default:
14246aa8d69SPekka Enberg 			return false;
14346aa8d69SPekka Enberg 		}
14446aa8d69SPekka Enberg 	}
14513a7760fSPekka Enberg 
14613a7760fSPekka Enberg 	return true;
14713a7760fSPekka Enberg }
14813a7760fSPekka Enberg 
14946aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
15025af6674SPekka Enberg {
15146aa8d69SPekka Enberg 	uint16_t offset = port - device.iobase;
15246aa8d69SPekka Enberg 
1539a7428ddSPekka Enberg 	if (device.lcr & UART_LCR_DLAB)
15446aa8d69SPekka Enberg 		return false;
15546aa8d69SPekka Enberg 
15646aa8d69SPekka Enberg 	switch (offset) {
1574e49b05bSCyrill Gorcunov 	case UART_TX:
15876b4a122SPekka Enberg 		if (device.lsr & UART_LSR_DR) {
15976b4a122SPekka Enberg 			device.lsr		&= ~UART_LSR_DR;
16076b4a122SPekka Enberg 			ioport__write8(data, device.thr);
16176b4a122SPekka Enberg 		}
16246aa8d69SPekka Enberg 		break;
1634e49b05bSCyrill Gorcunov 	case UART_IER:
16446aa8d69SPekka Enberg 		ioport__write8(data, device.ier);
16546aa8d69SPekka Enberg 		break;
1664e49b05bSCyrill Gorcunov 	case UART_IIR:
167e557eef9SPekka Enberg 		ioport__write8(data, device.iir);
16846aa8d69SPekka Enberg 		break;
1694e49b05bSCyrill Gorcunov 	case UART_LCR:
17046aa8d69SPekka Enberg 		ioport__write8(data, device.lcr);
17146aa8d69SPekka Enberg 		break;
1724e49b05bSCyrill Gorcunov 	case UART_MCR:
17346aa8d69SPekka Enberg 		ioport__write8(data, device.mcr);
17446aa8d69SPekka Enberg 		break;
1754e49b05bSCyrill Gorcunov 	case UART_LSR:
17676b4a122SPekka Enberg 		ioport__write8(data, device.lsr);
17746aa8d69SPekka Enberg 		break;
1784e49b05bSCyrill Gorcunov 	case UART_MSR:
1799a7428ddSPekka Enberg 		ioport__write8(data, UART_MSR_CTS);
18046aa8d69SPekka Enberg 		break;
1814e49b05bSCyrill Gorcunov 	case UART_SCR:
18246aa8d69SPekka Enberg 		ioport__write8(data, device.scr);
18346aa8d69SPekka Enberg 		break;
18446aa8d69SPekka Enberg 	default:
18546aa8d69SPekka Enberg 		return false;
18625af6674SPekka Enberg 	}
18725af6674SPekka Enberg 
18813a7760fSPekka Enberg 	return true;
18913a7760fSPekka Enberg }
19013a7760fSPekka Enberg 
19146aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = {
19246aa8d69SPekka Enberg 	.io_in		= serial8250_in,
19346aa8d69SPekka Enberg 	.io_out		= serial8250_out,
194a93ec68bSPekka Enberg };
195a93ec68bSPekka Enberg 
196899fe063SPekka Enberg void serial8250__init(void)
19713a7760fSPekka Enberg {
19846aa8d69SPekka Enberg 	ioport__register(device.iobase, &serial8250_ops, 8);
19913a7760fSPekka Enberg }
200