xref: /openbsd/usr.sbin/vmd/i8253.c (revision 097a140d)
1 /* $OpenBSD: i8253.c,v 1.33 2021/03/29 13:09:41 dv Exp $ */
2 /*
3  * Copyright (c) 2016 Mike Larkin <mlarkin@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/time.h>
19 #include <sys/types.h>
20 
21 #include <dev/ic/i8253reg.h>
22 
23 #include <machine/vmmvar.h>
24 
25 #include <event.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <time.h>
29 #include <unistd.h>
30 
31 #include "i8253.h"
32 #include "proc.h"
33 #include "vmd.h"
34 #include "vmm.h"
35 #include "atomicio.h"
36 
37 extern char *__progname;
38 
39 /*
40  * Channel 0 is used to generate the legacy hardclock interrupt (HZ).
41  * Channels 1 and 2 can be used by the guest OS as regular timers,
42  * but channel 2 is not connected to any pcppi(4)-like device. Like
43  * a regular PC, channel 2 status can also be read from port 0x61.
44  */
45 struct i8253_channel i8253_channel[3];
46 
47 static struct vm_dev_pipe dev_pipe;
48 
49 /*
50  * i8253_pipe_dispatch
51  *
52  * Reads a message off the pipe, expecting one that corresponds to a
53  * reset request for a specific channel.
54  */
55 static void
56 i8253_pipe_dispatch(int fd, short event, void *arg)
57 {
58 	enum pipe_msg_type msg;
59 
60 	msg = vm_pipe_recv(&dev_pipe);
61 	switch (msg) {
62 	case I8253_RESET_CHAN_0:
63 		i8253_reset(0);
64 		break;
65 	case I8253_RESET_CHAN_1:
66 		i8253_reset(1);
67 		break;
68 	case I8253_RESET_CHAN_2:
69 		i8253_reset(2);
70 		break;
71 	default:
72 		fatalx("%s: unexpected pipe message %d", __func__, msg);
73 	}
74 }
75 
76 /*
77  * i8253_init
78  *
79  * Initialize the emulated i8253 PIT.
80  *
81  * Parameters:
82  *  vm_id: vmm(4)-assigned ID of the VM
83  */
84 void
85 i8253_init(uint32_t vm_id)
86 {
87 	memset(&i8253_channel, 0, sizeof(struct i8253_channel));
88 	clock_gettime(CLOCK_MONOTONIC, &i8253_channel[0].ts);
89 	i8253_channel[0].start = 0xFFFF;
90 	i8253_channel[0].mode = TIMER_INTTC;
91 	i8253_channel[0].last_r = 1;
92 	i8253_channel[0].vm_id = vm_id;
93 	i8253_channel[0].state = 0;
94 
95 	i8253_channel[1].start = 0xFFFF;
96 	i8253_channel[1].mode = TIMER_INTTC;
97 	i8253_channel[1].last_r = 1;
98 	i8253_channel[1].vm_id = vm_id;
99 	i8253_channel[1].state = 0;
100 
101 	i8253_channel[2].start = 0xFFFF;
102 	i8253_channel[2].mode = TIMER_INTTC;
103 	i8253_channel[2].last_r = 1;
104 	i8253_channel[2].vm_id = vm_id;
105 	i8253_channel[2].state = 0;
106 
107 	evtimer_set(&i8253_channel[0].timer, i8253_fire, &i8253_channel[0]);
108 	evtimer_set(&i8253_channel[1].timer, i8253_fire, &i8253_channel[1]);
109 	evtimer_set(&i8253_channel[2].timer, i8253_fire, &i8253_channel[2]);
110 
111 	vm_pipe_init(&dev_pipe, i8253_pipe_dispatch);
112 	event_add(&dev_pipe.read_ev, NULL);
113 }
114 
115 /*
116  * i8253_do_readback
117  *
118  * Handles the readback status command. The readback status command latches
119  * the current counter value plus various status bits.
120  *
121  * Parameters:
122  *  data: The command word written by the guest VM
123  */
124 void
125 i8253_do_readback(uint32_t data)
126 {
127 	struct timespec now, delta;
128 	uint64_t ns, ticks;
129 	int readback_channel[3] = { TIMER_RB_C0, TIMER_RB_C1, TIMER_RB_C2 };
130 	int i;
131 
132 	/* bits are inverted here - !TIMER_RB_STATUS == enable chan readback */
133 	if (data & ~TIMER_RB_STATUS) {
134 		i8253_channel[0].rbs = (data & TIMER_RB_C0) ? 1 : 0;
135 		i8253_channel[1].rbs = (data & TIMER_RB_C1) ? 1 : 0;
136 		i8253_channel[2].rbs = (data & TIMER_RB_C2) ? 1 : 0;
137 	}
138 
139 	/* !TIMER_RB_COUNT == enable counter readback */
140 	if (data & ~TIMER_RB_COUNT) {
141 		for (i = 0; i < 3; i++) {
142 			if (data & readback_channel[i]) {
143 				clock_gettime(CLOCK_MONOTONIC, &now);
144 				timespecsub(&now, &i8253_channel[i].ts, &delta);
145 				ns = delta.tv_sec * 1000000000 + delta.tv_nsec;
146 				ticks = ns / NS_PER_TICK;
147 				if (i8253_channel[i].start)
148 					i8253_channel[i].olatch =
149 					    i8253_channel[i].start -
150 					    ticks % i8253_channel[i].start;
151 				else
152 					i8253_channel[i].olatch = 0;
153 			}
154 		}
155 	}
156 }
157 
158 /*
159  * vcpu_exit_i8253_misc
160  *
161  * Handles the 0x61 misc i8253 PIT register in/out exits.
162  *
163  * Parameters:
164  *  vrp: vm run parameters containing exit information for the I/O
165  *      instruction being performed
166  *
167  * Return value:
168  *  Always 0xFF (no interrupt should be injected)
169  */
170 uint8_t
171 vcpu_exit_i8253_misc(struct vm_run_params *vrp)
172 {
173 	struct vm_exit *vei = vrp->vrp_exit;
174 	uint16_t cur;
175 	uint64_t ns, ticks;
176 	struct timespec now, delta;
177 
178 	if (vei->vei.vei_dir == VEI_DIR_IN) {
179 		/* Port 0x61[5] = counter channel 2 state */
180 		if (i8253_channel[2].mode == TIMER_INTTC) {
181 			if (i8253_channel[2].state) {
182 				set_return_data(vei, (1 << 5));
183 				log_debug("%s: counter 2 fired, returning "
184 				    "0x20", __func__);
185 			} else {
186 				set_return_data(vei, 0);
187 				log_debug("%s: counter 2 clear, returning 0x0",
188 				    __func__);
189 			}
190 		} else if (i8253_channel[2].mode == TIMER_SQWAVE) {
191 			clock_gettime(CLOCK_MONOTONIC, &now);
192 			timespecsub(&now, &i8253_channel[2].ts, &delta);
193 			ns = delta.tv_sec * 1000000000 + delta.tv_nsec;
194 			ticks = ns / NS_PER_TICK;
195 			if (i8253_channel[2].start) {
196 				cur = i8253_channel[2].start -
197 				    ticks % i8253_channel[2].start;
198 
199 				if (cur > i8253_channel[2].start / 2)
200 					set_return_data(vei, 1);
201 				else
202 					set_return_data(vei, 0);
203 			}
204 		}
205 	} else {
206 		log_debug("%s: discarding data written to PIT misc port",
207 		    __func__);
208 	}
209 
210 	return 0xFF;
211 }
212 
213 /*
214  * vcpu_exit_i8253
215  *
216  * Handles emulated i8253 PIT access (in/out instruction to PIT ports).
217  *
218  * Parameters:
219  *  vrp: vm run parameters containing exit information for the I/O
220  *      instruction being performed
221  *
222  * Return value:
223  *  Interrupt to inject to the guest VM, or 0xFF if no interrupt should
224  *      be injected.
225  */
226 uint8_t
227 vcpu_exit_i8253(struct vm_run_params *vrp)
228 {
229 	uint32_t out_data;
230 	uint8_t sel, rw, data;
231 	uint64_t ns, ticks;
232 	struct timespec now, delta;
233 	struct vm_exit *vei = vrp->vrp_exit;
234 
235 	get_input_data(vei, &out_data);
236 
237 	if (vei->vei.vei_port == TIMER_CTRL) {
238 		if (vei->vei.vei_dir == VEI_DIR_OUT) { /* OUT instruction */
239 			sel = out_data &
240 			    (TIMER_SEL0 | TIMER_SEL1 | TIMER_SEL2);
241 			sel = sel >> 6;
242 
243 			if (sel == 3) {
244 				i8253_do_readback(out_data);
245 				return (0xFF);
246 			}
247 
248 			rw = out_data & (TIMER_LATCH | TIMER_16BIT);
249 
250 			/*
251 			 * Since we don't truly emulate each tick of the PIT
252 			 * counter, when the guest asks for the timer to be
253 			 * latched, simulate what the counter would have been
254 			 * had we performed full emulation. We do this by
255 			 * calculating when the counter was reset vs how much
256 			 * time has elapsed, then bias by the counter tick
257 			 * rate.
258 			 */
259 			if (rw == TIMER_LATCH) {
260 				clock_gettime(CLOCK_MONOTONIC, &now);
261 				timespecsub(&now, &i8253_channel[sel].ts,
262 				    &delta);
263 				ns = delta.tv_sec * 1000000000 + delta.tv_nsec;
264 				ticks = ns / NS_PER_TICK;
265 				if (i8253_channel[sel].start) {
266 					i8253_channel[sel].olatch =
267 					    i8253_channel[sel].start -
268 					    ticks % i8253_channel[sel].start;
269 				} else
270 					i8253_channel[sel].olatch = 0;
271 				goto ret;
272 			} else if (rw != TIMER_16BIT) {
273 				log_warnx("%s: i8253 PIT: unsupported counter "
274 				    "%d rw mode 0x%x selected", __func__,
275 				    sel, (rw & TIMER_16BIT));
276 			}
277 			i8253_channel[sel].mode = (out_data & 0xe) >> 1;
278 
279 			goto ret;
280 		} else {
281 			log_warnx("%s: i8253 PIT: read from control port "
282 			    "unsupported", __progname);
283 			set_return_data(vei, 0);
284 		}
285 	} else {
286 		sel = vei->vei.vei_port - (TIMER_CNTR0 + TIMER_BASE);
287 
288 		if (vei->vei.vei_dir == VEI_DIR_OUT) { /* OUT instruction */
289 			if (i8253_channel[sel].last_w == 0) {
290 				i8253_channel[sel].ilatch |= (out_data & 0xff);
291 				i8253_channel[sel].last_w = 1;
292 			} else {
293 				i8253_channel[sel].ilatch |=
294 				    ((out_data & 0xff) << 8);
295 				i8253_channel[sel].start =
296 				    i8253_channel[sel].ilatch;
297 				i8253_channel[sel].last_w = 0;
298 
299 				if (i8253_channel[sel].start == 0)
300 					i8253_channel[sel].start = 0xffff;
301 
302 				log_debug("%s: channel %d reset, mode=%d, "
303 				    "start=%d", __func__,
304 				    sel, i8253_channel[sel].mode,
305 				    i8253_channel[sel].start);
306 
307 				vm_pipe_send(&dev_pipe, sel);
308 			}
309 		} else {
310 			if (i8253_channel[sel].rbs) {
311 				i8253_channel[sel].rbs = 0;
312 				data = i8253_channel[sel].mode << 1;
313 				data |= TIMER_16BIT;
314 				set_return_data(vei, data);
315 				goto ret;
316 			}
317 
318 			if (i8253_channel[sel].last_r == 0) {
319 				data = i8253_channel[sel].olatch >> 8;
320 				set_return_data(vei, data);
321 				i8253_channel[sel].last_r = 1;
322 			} else {
323 				data = i8253_channel[sel].olatch & 0xFF;
324 				set_return_data(vei, data);
325 				i8253_channel[sel].last_r = 0;
326 			}
327 		}
328 	}
329 
330 ret:
331 	return (0xFF);
332 }
333 
334 /*
335  * i8253_reset
336  *
337  * Resets the i8253's counter timer
338  *
339  * Parameters:
340  *  chn: counter ID. Only channel ID 0 is presently emulated.
341  */
342 void
343 i8253_reset(uint8_t chn)
344 {
345 	struct timeval tv;
346 
347 	evtimer_del(&i8253_channel[chn].timer);
348 	timerclear(&tv);
349 
350 	i8253_channel[chn].in_use = 1;
351 	i8253_channel[chn].state = 0;
352 	tv.tv_usec = (i8253_channel[chn].start * NS_PER_TICK) / 1000;
353 	clock_gettime(CLOCK_MONOTONIC, &i8253_channel[chn].ts);
354 	evtimer_add(&i8253_channel[chn].timer, &tv);
355 }
356 
357 /*
358  * i8253_fire
359  *
360  * Callback invoked when the 8253 PIT timer fires. This will assert
361  * IRQ0 on the legacy PIC attached to VCPU0.
362  *
363  * Parameters:
364  *  fd: unused
365  *  type: unused
366  *  arg: VM ID
367  */
368 void
369 i8253_fire(int fd, short type, void *arg)
370 {
371 	struct timeval tv;
372 	struct i8253_channel *ctr = (struct i8253_channel *)arg;
373 
374 	vcpu_assert_pic_irq(ctr->vm_id, 0, 0);
375 	vcpu_deassert_pic_irq(ctr->vm_id, 0, 0);
376 
377 	if (ctr->mode != TIMER_INTTC) {
378 		timerclear(&tv);
379 		tv.tv_usec = (ctr->start * NS_PER_TICK) / 1000;
380 		evtimer_add(&ctr->timer, &tv);
381 	} else
382 		ctr->state = 1;
383 }
384 
385 int
386 i8253_dump(int fd)
387 {
388 	log_debug("%s: sending PIT", __func__);
389 	if (atomicio(vwrite, fd, &i8253_channel, sizeof(i8253_channel)) !=
390 	    sizeof(i8253_channel)) {
391 		log_warnx("%s: error writing PIT to fd", __func__);
392 		return (-1);
393 	}
394 	return (0);
395 }
396 
397 int
398 i8253_restore(int fd, uint32_t vm_id)
399 {
400 	int i;
401 	log_debug("%s: restoring PIT", __func__);
402 	if (atomicio(read, fd, &i8253_channel, sizeof(i8253_channel)) !=
403 	    sizeof(i8253_channel)) {
404 		log_warnx("%s: error reading PIT from fd", __func__);
405 		return (-1);
406 	}
407 
408 	for (i = 0; i < 3; i++) {
409 		memset(&i8253_channel[i].timer, 0, sizeof(struct event));
410 		i8253_channel[i].vm_id = vm_id;
411 		evtimer_set(&i8253_channel[i].timer, i8253_fire,
412 		    &i8253_channel[i]);
413 		i8253_reset(i);
414 	}
415 
416 	vm_pipe_init(&dev_pipe, i8253_pipe_dispatch);
417 
418 	return (0);
419 }
420 
421 void
422 i8253_stop()
423 {
424 	int i;
425 	for (i = 0; i < 3; i++)
426 		evtimer_del(&i8253_channel[i].timer);
427 	event_del(&dev_pipe.read_ev);
428 }
429 
430 void
431 i8253_start()
432 {
433 	int i;
434 	for (i = 0; i < 3; i++)
435 		if (i8253_channel[i].in_use)
436 			i8253_reset(i);
437 	event_add(&dev_pipe.read_ev, NULL);
438 }
439