1 /* $OpenBSD: i8253.c,v 1.15 2017/05/08 09:08:40 reyk 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 <unistd.h> 29 30 #include "i8253.h" 31 #include "proc.h" 32 #include "vmm.h" 33 #include "atomicio.h" 34 35 extern char *__progname; 36 37 /* 38 * Channel 0 is used to generate the legacy hardclock interrupt (HZ). 39 * Channels 1 and 2 are not connected to any output (although someone 40 * could hook channel 2 up to an emulated pcppi(4) at some point). 41 */ 42 struct i8253_channel i8253_channel[3]; 43 44 /* 45 * i8253_init 46 * 47 * Initialize the emulated i8253 PIT. 48 * 49 * Parameters: 50 * vm_id: vmm(4)-assigned ID of the VM 51 */ 52 void 53 i8253_init(uint32_t vm_id) 54 { 55 memset(&i8253_channel, 0, sizeof(struct i8253_channel)); 56 gettimeofday(&i8253_channel[0].tv, NULL); 57 i8253_channel[0].start = 0xFFFF; 58 i8253_channel[0].mode = TIMER_INTTC; 59 i8253_channel[0].last_r = 1; 60 i8253_channel[0].vm_id = vm_id; 61 62 i8253_channel[1].start = 0xFFFF; 63 i8253_channel[1].mode = TIMER_INTTC; 64 i8253_channel[1].last_r = 1; 65 i8253_channel[1].vm_id = vm_id; 66 67 i8253_channel[2].start = 0xFFFF; 68 i8253_channel[2].mode = TIMER_INTTC; 69 i8253_channel[2].last_r = 1; 70 i8253_channel[2].vm_id = vm_id; 71 72 evtimer_set(&i8253_channel[0].timer, i8253_fire, &i8253_channel[0]); 73 evtimer_set(&i8253_channel[1].timer, i8253_fire, &i8253_channel[1]); 74 evtimer_set(&i8253_channel[2].timer, i8253_fire, &i8253_channel[2]); 75 } 76 77 /* 78 * i8253_do_readback 79 * 80 * Handles the readback status command. The readback status command latches 81 * the current counter value plus various status bits. 82 * 83 * Parameters: 84 * data: The command word written by the guest VM 85 */ 86 void 87 i8253_do_readback(uint32_t data) 88 { 89 struct timeval now, delta; 90 uint64_t ns, ticks; 91 92 /* bits are inverted here - !TIMER_RB_STATUS == enable chan readback */ 93 if (data & ~TIMER_RB_STATUS) { 94 i8253_channel[0].rbs = (data & TIMER_RB_C0) ? 1 : 0; 95 i8253_channel[1].rbs = (data & TIMER_RB_C1) ? 1 : 0; 96 i8253_channel[2].rbs = (data & TIMER_RB_C2) ? 1 : 0; 97 } 98 99 /* !TIMER_RB_COUNT == enable counter readback */ 100 if (data & ~TIMER_RB_COUNT) { 101 if (data & TIMER_RB_C0) { 102 gettimeofday(&now, NULL); 103 delta.tv_sec = now.tv_sec - i8253_channel[0].tv.tv_sec; 104 delta.tv_usec = now.tv_usec - 105 i8253_channel[0].tv.tv_usec; 106 if (delta.tv_usec < 0) { 107 delta.tv_sec--; 108 delta.tv_usec += 1000000; 109 } 110 if (delta.tv_usec > 1000000) { 111 delta.tv_sec++; 112 delta.tv_usec -= 1000000; 113 } 114 ns = delta.tv_usec * 1000 + delta.tv_sec * 1000000000; 115 ticks = ns / NS_PER_TICK; 116 if (i8253_channel[0].start) 117 i8253_channel[0].olatch = 118 i8253_channel[0].start - 119 ticks % i8253_channel[0].start; 120 else 121 i8253_channel[0].olatch = 0; 122 } 123 124 if (data & TIMER_RB_C1) { 125 gettimeofday(&now, NULL); 126 delta.tv_sec = now.tv_sec - i8253_channel[1].tv.tv_sec; 127 delta.tv_usec = now.tv_usec - 128 i8253_channel[1].tv.tv_usec; 129 if (delta.tv_usec < 0) { 130 delta.tv_sec--; 131 delta.tv_usec += 1000000; 132 } 133 if (delta.tv_usec > 1000000) { 134 delta.tv_sec++; 135 delta.tv_usec -= 1000000; 136 } 137 ns = delta.tv_usec * 1000 + delta.tv_sec * 1000000000; 138 ticks = ns / NS_PER_TICK; 139 if (i8253_channel[1].start) 140 i8253_channel[1].olatch = 141 i8253_channel[1].start - 142 ticks % i8253_channel[1].start; 143 else 144 i8253_channel[1].olatch = 0; 145 } 146 147 if (data & TIMER_RB_C2) { 148 gettimeofday(&now, NULL); 149 delta.tv_sec = now.tv_sec - i8253_channel[2].tv.tv_sec; 150 delta.tv_usec = now.tv_usec - 151 i8253_channel[2].tv.tv_usec; 152 if (delta.tv_usec < 0) { 153 delta.tv_sec--; 154 delta.tv_usec += 1000000; 155 } 156 if (delta.tv_usec > 1000000) { 157 delta.tv_sec++; 158 delta.tv_usec -= 1000000; 159 } 160 ns = delta.tv_usec * 1000 + delta.tv_sec * 1000000000; 161 ticks = ns / NS_PER_TICK; 162 if (i8253_channel[2].start) 163 i8253_channel[2].olatch = 164 i8253_channel[2].start - 165 ticks % i8253_channel[2].start; 166 else 167 i8253_channel[2].olatch = 0; 168 } 169 } 170 } 171 172 /* 173 * vcpu_exit_i8253 174 * 175 * Handles emulated i8253 PIT access (in/out instruction to PIT ports). 176 * 177 * Parameters: 178 * vrp: vm run parameters containing exit information for the I/O 179 * instruction being performed 180 * 181 * Return value: 182 * Interrupt to inject to the guest VM, or 0xFF if no interrupt should 183 * be injected. 184 */ 185 uint8_t 186 vcpu_exit_i8253(struct vm_run_params *vrp) 187 { 188 uint32_t out_data; 189 uint8_t sel, rw, data, mode; 190 uint64_t ns, ticks; 191 struct timeval now, delta; 192 union vm_exit *vei = vrp->vrp_exit; 193 194 get_input_data(vei, &out_data); 195 196 if (vei->vei.vei_port == TIMER_CTRL) { 197 if (vei->vei.vei_dir == VEI_DIR_OUT) { /* OUT instruction */ 198 sel = out_data & 199 (TIMER_SEL0 | TIMER_SEL1 | TIMER_SEL2); 200 sel = sel >> 6; 201 202 if (sel == 3) { 203 i8253_do_readback(out_data); 204 return (0xFF); 205 } 206 207 rw = out_data & (TIMER_LATCH | TIMER_16BIT); 208 209 /* 210 * Since we don't truly emulate each tick of the PIT 211 * counter, when the guest asks for the timer to be 212 * latched, simulate what the counter would have been 213 * had we performed full emulation. We do this by 214 * calculating when the counter was reset vs how much 215 * time has elapsed, then bias by the counter tick 216 * rate. 217 */ 218 if (rw == TIMER_LATCH) { 219 gettimeofday(&now, NULL); 220 delta.tv_sec = now.tv_sec - 221 i8253_channel[sel].tv.tv_sec; 222 delta.tv_usec = now.tv_usec - 223 i8253_channel[sel].tv.tv_usec; 224 if (delta.tv_usec < 0) { 225 delta.tv_sec--; 226 delta.tv_usec += 1000000; 227 } 228 if (delta.tv_usec > 1000000) { 229 delta.tv_sec++; 230 delta.tv_usec -= 1000000; 231 } 232 ns = delta.tv_usec * 1000 + 233 delta.tv_sec * 1000000000; 234 ticks = ns / NS_PER_TICK; 235 if (i8253_channel[sel].start) { 236 i8253_channel[sel].olatch = 237 i8253_channel[sel].start - 238 ticks % i8253_channel[sel].start; 239 } else 240 i8253_channel[sel].olatch = 0; 241 goto ret; 242 } else if (rw != TIMER_16BIT) { 243 log_warnx("%s: i8253 PIT: unsupported counter " 244 "%d rw mode 0x%x selected", __func__, 245 sel, (rw & TIMER_16BIT)); 246 } 247 248 goto ret; 249 } else { 250 log_warnx("%s: i8253 PIT: read from control port " 251 "unsupported", __progname); 252 set_return_data(vei, 0); 253 } 254 } else { 255 sel = vei->vei.vei_port - (TIMER_CNTR0 + TIMER_BASE); 256 257 if (vei->vei.vei_dir == VEI_DIR_OUT) { /* OUT instruction */ 258 if (i8253_channel[sel].last_w == 0) { 259 i8253_channel[sel].ilatch |= (out_data & 0xff); 260 i8253_channel[sel].last_w = 1; 261 } else { 262 i8253_channel[sel].ilatch |= ((out_data & 0xff) << 8); 263 i8253_channel[sel].start = 264 i8253_channel[sel].ilatch; 265 i8253_channel[sel].last_w = 0; 266 mode = (out_data & 0xe) >> 1; 267 268 if (i8253_channel[sel].start == 0) 269 i8253_channel[sel].start = 0xffff; 270 271 log_debug("%s: channel %d reset, mode=%d, start=%d", __func__, 272 sel, mode, i8253_channel[sel].start); 273 i8253_channel[sel].mode = mode; 274 i8253_reset(sel); 275 } 276 } else { 277 if (i8253_channel[sel].rbs) { 278 i8253_channel[sel].rbs = 0; 279 data = i8253_channel[sel].mode << 1; 280 data |= TIMER_16BIT; 281 set_return_data(vei, data); 282 goto ret; 283 } 284 285 if (i8253_channel[sel].last_r == 0) { 286 data = i8253_channel[sel].olatch >> 8; 287 set_return_data(vei, data); 288 i8253_channel[sel].last_r = 1; 289 } else { 290 data = i8253_channel[sel].olatch & 0xFF; 291 set_return_data(vei, data); 292 i8253_channel[sel].last_r = 0; 293 } 294 } 295 } 296 297 ret: 298 return (0xFF); 299 } 300 301 /* 302 * i8253_reset 303 * 304 * Resets the i8253's counter timer 305 * 306 * Parameters: 307 * chn: counter ID. Only channel ID 0 is presently emulated. 308 */ 309 void 310 i8253_reset(uint8_t chn) 311 { 312 struct timeval tv; 313 314 evtimer_del(&i8253_channel[chn].timer); 315 timerclear(&tv); 316 317 tv.tv_usec = (i8253_channel[chn].start * NS_PER_TICK) / 1000; 318 evtimer_add(&i8253_channel[chn].timer, &tv); 319 } 320 321 /* 322 * i8253_fire 323 * 324 * Callback invoked when the 8253 PIT timer fires. This will assert 325 * IRQ0 on the legacy PIC attached to VCPU0. 326 * 327 * Parameters: 328 * fd: unused 329 * type: unused 330 * arg: VM ID 331 */ 332 void 333 i8253_fire(int fd, short type, void *arg) 334 { 335 struct timeval tv; 336 struct i8253_channel *ctr = (struct i8253_channel *)arg; 337 338 timerclear(&tv); 339 tv.tv_usec = (ctr->start * NS_PER_TICK) / 1000; 340 341 vcpu_assert_pic_irq(ctr->vm_id, 0, 0); 342 343 if (ctr->mode != TIMER_INTTC) 344 evtimer_add(&ctr->timer, &tv); 345 } 346 347 int 348 i8253_dump(int fd) 349 { 350 log_debug("%s: sending PIT", __func__); 351 if (atomicio(vwrite, fd, &i8253_channel, sizeof(i8253_channel)) != 352 sizeof(i8253_channel)) { 353 log_warnx("%s: error writing PIT to fd", __func__); 354 return (-1); 355 } 356 return (0); 357 } 358 359 int 360 i8253_restore(int fd, uint32_t vm_id) 361 { 362 log_debug("%s: restoring PIT", __func__); 363 if (atomicio(read, fd, &i8253_channel, sizeof(i8253_channel)) != 364 sizeof(i8253_channel)) { 365 log_warnx("%s: error reading PIT from fd", __func__); 366 return (-1); 367 } 368 memset(&i8253_channel[0].timer, 0, sizeof(struct event)); 369 memset(&i8253_channel[1].timer, 0, sizeof(struct event)); 370 memset(&i8253_channel[2].timer, 0, sizeof(struct event)); 371 i8253_channel[0].vm_id = vm_id; 372 i8253_channel[1].vm_id = vm_id; 373 i8253_channel[2].vm_id = vm_id; 374 375 evtimer_set(&i8253_channel[0].timer, i8253_fire, &i8253_channel[0]); 376 evtimer_set(&i8253_channel[1].timer, i8253_fire, &i8253_channel[1]); 377 evtimer_set(&i8253_channel[2].timer, i8253_fire, &i8253_channel[2]); 378 i8253_reset(0); 379 return (0); 380 } 381 382 void 383 i8253_stop() 384 { 385 evtimer_del(&i8253_channel[0].timer); 386 evtimer_del(&i8253_channel[1].timer); 387 evtimer_del(&i8253_channel[2].timer); 388 } 389