xref: /kvmtool/hw/serial.c (revision e62c18de5421cfeb5838da9c792340a5cd553835)
1 #include "kvm/8250-serial.h"
2 
3 #include "kvm/ioport.h"
4 #include "kvm/util.h"
5 #include "kvm/kvm.h"
6 
7 #include <linux/serial_reg.h>
8 
9 #include <stdbool.h>
10 #include <poll.h>
11 
12 struct serial8250_device {
13 	uint16_t		iobase;
14 	uint8_t			irq;
15 
16 	uint8_t			thr;
17 	uint8_t			dll;
18 	uint8_t			dlm;
19 	uint8_t			iir;
20 	uint8_t			ier;
21 	uint8_t			fcr;
22 	uint8_t			lcr;
23 	uint8_t			mcr;
24 	uint8_t			lsr;
25 	uint8_t			scr;
26 };
27 
28 static struct serial8250_device devices[] = {
29 	/* ttyS0 */
30 	[0]	= {
31 		.iobase			= 0x3f8,
32 		.irq			= 4,
33 
34 		.lsr			= UART_LSR_TEMT | UART_LSR_THRE,
35 	},
36 	/* ttyS1 */
37 	[1]	= {
38 		.iobase			= 0x2f8,
39 		.irq			= 3,
40 	},
41 	/* ttyS2 */
42 	[2]	= {
43 		.iobase			= 0x3e8,
44 		.irq			= 4,
45 	},
46 };
47 
48 static int read_char(int fd)
49 {
50 	int c;
51 
52 	if (read(fd, &c, 1) < 0)
53 		return -1;
54 
55 	return c;
56 }
57 
58 static bool is_readable(int fd)
59 {
60 	struct pollfd pollfd = (struct pollfd) {
61 		.fd	= fd,
62 		.events	= POLLIN,
63 	};
64 
65 	return poll(&pollfd, 1, 0) > 0;
66 }
67 
68 /*
69  * Interrupts are injected for ttyS0 only.
70  */
71 void serial8250__interrupt(struct kvm *self)
72 {
73 	struct serial8250_device *dev = &devices[0];
74 	uint8_t new_iir;
75 
76 	dev->iir	= UART_IIR_NO_INT;
77 
78 	/* No interrupts enabled. Exit... */
79 	if (!(dev->ier & (UART_IER_THRI|UART_IER_RDI)))
80 		return;
81 
82 	new_iir		= 0;
83 
84 	/* We're always good for guest sending data. */
85 	if (dev->ier & UART_IER_THRI)
86 		new_iir			|= UART_IIR_THRI;
87 
88 	/* Is there input in stdin to send to the guest? */
89 	if (!(dev->lsr & UART_LSR_DR) && is_readable(fileno(stdin))) {
90 		int c;
91 
92 		c			= read_char(fileno(stdin));
93 		if (c >= 0) {
94 			dev->thr		= c;
95 			dev->lsr		|= UART_LSR_DR;
96 			new_iir			|= UART_IIR_RDI;
97 		}
98 	}
99 
100 	/* Only send an IRQ if there's work to do. */
101 	if (new_iir) {
102 		dev->iir		= new_iir;
103 		kvm__irq_line(self, dev->irq, 0);
104 		kvm__irq_line(self, dev->irq, 1);
105 	}
106 }
107 
108 static struct serial8250_device *find_device(uint16_t port)
109 {
110 	unsigned int i;
111 
112 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
113 		struct serial8250_device *dev = &devices[i];
114 
115 		if (dev->iobase == (port & ~0x7))
116 			return dev;
117 	}
118 	return NULL;
119 }
120 
121 static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
122 {
123 	struct serial8250_device *dev;
124 	uint16_t offset;
125 
126 	dev		= find_device(port);
127 	if (!dev)
128 		return false;
129 
130 	offset		= port - dev->iobase;
131 
132 	if (dev->lcr & UART_LCR_DLAB) {
133 		switch (offset) {
134 		case UART_DLL:
135 			dev->dll		= ioport__read8(data);
136 			break;
137 		case UART_DLM:
138 			dev->dlm		= ioport__read8(data);
139 			break;
140 		case UART_FCR:
141 			dev->fcr		= ioport__read8(data);
142 			break;
143 		case UART_LCR:
144 			dev->lcr		= ioport__read8(data);
145 			break;
146 		default:
147 			return false;
148 		}
149 	} else {
150 		switch (offset) {
151 		case UART_TX: {
152 			char *p = data;
153 			int i;
154 
155 			while (count--) {
156 				for (i = 0; i < size; i++)
157 					fprintf(stdout, "%c", *p++);
158 			}
159 			fflush(stdout);
160 
161 			break;
162 		}
163 		case UART_IER:
164 			dev->ier		= ioport__read8(data);
165 			break;
166 		case UART_FCR:
167 			dev->fcr		= ioport__read8(data);
168 			break;
169 		case UART_LCR:
170 			dev->lcr		= ioport__read8(data);
171 			break;
172 		case UART_MCR:
173 			dev->mcr		= ioport__read8(data);
174 			break;
175 		case UART_SCR:
176 			dev->scr		= ioport__read8(data);
177 			break;
178 		default:
179 			return false;
180 		}
181 	}
182 
183 	return true;
184 }
185 
186 static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
187 {
188 	struct serial8250_device *dev;
189 	uint16_t offset;
190 
191 	dev		= find_device(port);
192 	if (!dev)
193 		return false;
194 
195 	offset		= port - dev->iobase;
196 
197 	if (dev->lcr & UART_LCR_DLAB)
198 		return false;
199 
200 	switch (offset) {
201 	case UART_TX:
202 		if (dev->lsr & UART_LSR_DR) {
203 			dev->lsr		&= ~UART_LSR_DR;
204 			ioport__write8(data, dev->thr);
205 		}
206 		break;
207 	case UART_IER:
208 		ioport__write8(data, dev->ier);
209 		break;
210 	case UART_IIR:
211 		ioport__write8(data, dev->iir);
212 		break;
213 	case UART_LCR:
214 		ioport__write8(data, dev->lcr);
215 		break;
216 	case UART_MCR:
217 		ioport__write8(data, dev->mcr);
218 		break;
219 	case UART_LSR:
220 		ioport__write8(data, dev->lsr);
221 		break;
222 	case UART_MSR:
223 		ioport__write8(data, UART_MSR_CTS);
224 		break;
225 	case UART_SCR:
226 		ioport__write8(data, dev->scr);
227 		break;
228 	default:
229 		return false;
230 	}
231 
232 	return true;
233 }
234 
235 static struct ioport_operations serial8250_ops = {
236 	.io_in		= serial8250_in,
237 	.io_out		= serial8250_out,
238 };
239 
240 void serial8250__init(void)
241 {
242 	unsigned int i;
243 
244 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
245 		struct serial8250_device *dev = &devices[i];
246 
247 		ioport__register(dev->iobase, &serial8250_ops, 8);
248 	}
249 }
250