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