1 /*- 2 * Copyright (c) 2018 Joyent, Inc. 3 * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 4 * Copyright (c) 2011 NetApp, Inc. 5 * All rights reserved. 6 * Copyright (c) 2018 Joyent, Inc. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/queue.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/mutex.h> 39 #include <sys/systm.h> 40 41 #include <machine/vmm.h> 42 43 #include "vmm_ktr.h" 44 #include "vatpic.h" 45 #include "vioapic.h" 46 #include "vatpit.h" 47 48 static MALLOC_DEFINE(M_VATPIT, "atpit", "bhyve virtual atpit (8254)"); 49 50 #define VATPIT_LOCK(vatpit) mutex_enter(&((vatpit)->lock)) 51 #define VATPIT_UNLOCK(vatpit) mutex_exit(&((vatpit)->lock)) 52 53 #define TIMER_SEL_MASK 0xc0 54 #define TIMER_RW_MASK 0x30 55 #define TIMER_MODE_MASK 0x0f 56 #define TIMER_SEL_READBACK 0xc0 57 58 #define TIMER_STS_OUT 0x80 59 #define TIMER_STS_NULLCNT 0x40 60 61 #define TIMER_RB_LCTR 0x20 62 #define TIMER_RB_LSTATUS 0x10 63 #define TIMER_RB_CTR_2 0x08 64 #define TIMER_RB_CTR_1 0x04 65 #define TIMER_RB_CTR_0 0x02 66 67 #define TMR2_OUT_STS 0x20 68 69 #define PIT_8254_FREQ 1193182 70 #define TIMER_DIV(freq, hz) (((freq) + (hz) / 2) / (hz)) 71 72 struct vatpit_callout_arg { 73 struct vatpit *vatpit; 74 int channel_num; 75 }; 76 77 struct channel { 78 uint8_t mode; 79 uint16_t initial; /* initial counter value */ 80 81 uint8_t reg_cr[2]; 82 uint8_t reg_ol[2]; 83 uint8_t reg_status; 84 85 bool slatched; /* status latched */ 86 bool olatched; /* output latched */ 87 bool cr_sel; /* read MSB from control register */ 88 bool ol_sel; /* read MSB from output latch */ 89 bool fr_sel; /* read MSB from free-running timer */ 90 91 hrtime_t time_loaded; /* time when counter was loaded */ 92 hrtime_t time_target; /* target time */ 93 uint64_t total_target; 94 95 struct callout callout; 96 struct vatpit_callout_arg callout_arg; 97 }; 98 99 struct vatpit { 100 struct vm *vm; 101 kmutex_t lock; 102 103 struct channel channel[3]; 104 }; 105 106 static void pit_timer_start_cntr0(struct vatpit *vatpit); 107 108 static uint64_t 109 vatpit_delta_ticks(struct vatpit *vatpit, struct channel *c) 110 { 111 const hrtime_t delta = gethrtime() - c->time_loaded; 112 113 return (hrt_freq_count(delta, PIT_8254_FREQ)); 114 } 115 116 static int 117 vatpit_get_out(struct vatpit *vatpit, int channel) 118 { 119 struct channel *c; 120 uint64_t delta_ticks; 121 int out; 122 123 c = &vatpit->channel[channel]; 124 125 switch (c->mode) { 126 case TIMER_INTTC: 127 delta_ticks = vatpit_delta_ticks(vatpit, c); 128 out = (delta_ticks >= c->initial); 129 break; 130 default: 131 out = 0; 132 break; 133 } 134 135 return (out); 136 } 137 138 static void 139 vatpit_callout_handler(void *a) 140 { 141 struct vatpit_callout_arg *arg = a; 142 struct vatpit *vatpit; 143 struct callout *callout; 144 struct channel *c; 145 146 vatpit = arg->vatpit; 147 c = &vatpit->channel[arg->channel_num]; 148 callout = &c->callout; 149 150 VM_CTR1(vatpit->vm, "atpit t%d fired", arg->channel_num); 151 152 VATPIT_LOCK(vatpit); 153 154 if (callout_pending(callout)) /* callout was reset */ 155 goto done; 156 157 if (!callout_active(callout)) /* callout was stopped */ 158 goto done; 159 160 callout_deactivate(callout); 161 162 if (c->mode == TIMER_RATEGEN || c->mode == TIMER_SQWAVE) { 163 pit_timer_start_cntr0(vatpit); 164 } 165 166 (void) vatpic_pulse_irq(vatpit->vm, 0); 167 (void) vioapic_pulse_irq(vatpit->vm, 2); 168 169 done: 170 VATPIT_UNLOCK(vatpit); 171 } 172 173 static void 174 pit_timer_start_cntr0(struct vatpit *vatpit) 175 { 176 struct channel *c = &vatpit->channel[0]; 177 178 if (c->initial == 0) { 179 return; 180 } 181 182 c->total_target += c->initial; 183 c->time_target = c->time_loaded + 184 hrt_freq_interval(PIT_8254_FREQ, c->total_target); 185 186 /* 187 * If we are more than 'c->initial' ticks behind, reset the timer base 188 * to fire at the next 'c->initial' interval boundary. 189 */ 190 hrtime_t now = gethrtime(); 191 if (c->time_target < now) { 192 const uint64_t ticks_behind = 193 hrt_freq_count(c->time_target - now, PIT_8254_FREQ); 194 195 c->total_target += roundup(ticks_behind, c->initial); 196 c->time_target = c->time_loaded + 197 hrt_freq_interval(PIT_8254_FREQ, c->total_target); 198 } 199 200 callout_reset_hrtime(&c->callout, c->time_target, 201 vatpit_callout_handler, &c->callout_arg, C_ABSOLUTE); 202 } 203 204 static uint16_t 205 pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch) 206 { 207 uint16_t lval; 208 uint64_t delta_ticks; 209 210 /* cannot latch a new value until the old one has been consumed */ 211 if (latch && c->olatched) 212 return (0); 213 214 if (c->initial == 0) { 215 /* 216 * This is possibly an OS bug - reading the value of the timer 217 * without having set up the initial value. 218 * 219 * The original user-space version of this code set the timer to 220 * 100hz in this condition; do the same here. 221 */ 222 c->initial = TIMER_DIV(PIT_8254_FREQ, 100); 223 c->time_loaded = gethrtime(); 224 c->reg_status &= ~TIMER_STS_NULLCNT; 225 } 226 227 delta_ticks = vatpit_delta_ticks(vatpit, c); 228 lval = c->initial - delta_ticks % c->initial; 229 230 if (latch) { 231 c->olatched = true; 232 c->ol_sel = true; 233 c->reg_ol[1] = lval; /* LSB */ 234 c->reg_ol[0] = lval >> 8; /* MSB */ 235 } 236 237 return (lval); 238 } 239 240 static int 241 pit_readback1(struct vatpit *vatpit, int channel, uint8_t cmd) 242 { 243 struct channel *c; 244 245 c = &vatpit->channel[channel]; 246 247 /* 248 * Latch the count/status of the timer if not already latched. 249 * N.B. that the count/status latch-select bits are active-low. 250 */ 251 if ((cmd & TIMER_RB_LCTR) == 0 && !c->olatched) { 252 (void) pit_update_counter(vatpit, c, true); 253 } 254 255 if ((cmd & TIMER_RB_LSTATUS) == 0 && !c->slatched) { 256 c->slatched = true; 257 /* 258 * For mode 0, see if the elapsed time is greater 259 * than the initial value - this results in the 260 * output pin being set to 1 in the status byte. 261 */ 262 if (c->mode == TIMER_INTTC && vatpit_get_out(vatpit, channel)) 263 c->reg_status |= TIMER_STS_OUT; 264 else 265 c->reg_status &= ~TIMER_STS_OUT; 266 } 267 268 return (0); 269 } 270 271 static int 272 pit_readback(struct vatpit *vatpit, uint8_t cmd) 273 { 274 int error; 275 276 /* 277 * The readback command can apply to all timers. 278 */ 279 error = 0; 280 if (cmd & TIMER_RB_CTR_0) 281 error = pit_readback1(vatpit, 0, cmd); 282 if (!error && cmd & TIMER_RB_CTR_1) 283 error = pit_readback1(vatpit, 1, cmd); 284 if (!error && cmd & TIMER_RB_CTR_2) 285 error = pit_readback1(vatpit, 2, cmd); 286 287 return (error); 288 } 289 290 static int 291 vatpit_update_mode(struct vatpit *vatpit, uint8_t val) 292 { 293 struct channel *c; 294 int sel, rw; 295 uint8_t mode; 296 297 sel = val & TIMER_SEL_MASK; 298 rw = val & TIMER_RW_MASK; 299 mode = val & TIMER_MODE_MASK; 300 301 /* Clear don't-care bit (M2) when M1 is set */ 302 if ((mode & TIMER_RATEGEN) != 0) { 303 mode &= ~TIMER_SWSTROBE; 304 } 305 306 if (sel == TIMER_SEL_READBACK) 307 return (pit_readback(vatpit, val)); 308 309 if (rw != TIMER_LATCH && rw != TIMER_16BIT) 310 return (-1); 311 312 if (rw != TIMER_LATCH) { 313 /* 314 * Counter mode is not affected when issuing a 315 * latch command. 316 */ 317 if (mode != TIMER_INTTC && 318 mode != TIMER_RATEGEN && 319 mode != TIMER_SQWAVE && 320 mode != TIMER_SWSTROBE) 321 return (-1); 322 } 323 324 c = &vatpit->channel[sel >> 6]; 325 if (rw == TIMER_LATCH) { 326 (void) pit_update_counter(vatpit, c, true); 327 } else { 328 c->mode = mode; 329 c->olatched = false; /* reset latch after reprogramming */ 330 c->reg_status |= TIMER_STS_NULLCNT; 331 } 332 333 return (0); 334 } 335 336 int 337 vatpit_handler(void *arg, bool in, uint16_t port, uint8_t bytes, uint32_t *eax) 338 { 339 struct vatpit *vatpit = arg; 340 struct channel *c; 341 uint8_t val; 342 int error; 343 344 if (bytes != 1) 345 return (-1); 346 347 val = *eax; 348 349 if (port == TIMER_MODE) { 350 if (in) { 351 VM_CTR0(vatpit->vm, "vatpit attempt to read mode"); 352 return (-1); 353 } 354 355 VATPIT_LOCK(vatpit); 356 error = vatpit_update_mode(vatpit, val); 357 VATPIT_UNLOCK(vatpit); 358 359 return (error); 360 } 361 362 /* counter ports */ 363 KASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2, 364 ("invalid port 0x%x", port)); 365 c = &vatpit->channel[port - TIMER_CNTR0]; 366 367 VATPIT_LOCK(vatpit); 368 if (in && c->slatched) { 369 /* Return the status byte if latched */ 370 *eax = c->reg_status; 371 c->slatched = false; 372 c->reg_status = 0; 373 } else if (in) { 374 /* 375 * The spec says that once the output latch is completely 376 * read it should revert to "following" the counter. Use 377 * the free running counter for this case (i.e. Linux 378 * TSC calibration). Assuming the access mode is 16-bit, 379 * toggle the MSB/LSB bit on each read. 380 */ 381 if (!c->olatched) { 382 uint16_t tmp; 383 384 tmp = pit_update_counter(vatpit, c, false); 385 if (c->fr_sel) { 386 tmp >>= 8; 387 } 388 tmp &= 0xff; 389 *eax = tmp; 390 c->fr_sel = !c->fr_sel; 391 } else { 392 if (c->ol_sel) { 393 *eax = c->reg_ol[1]; 394 c->ol_sel = false; 395 } else { 396 *eax = c->reg_ol[0]; 397 c->olatched = false; 398 } 399 } 400 } else { 401 if (!c->cr_sel) { 402 c->reg_cr[0] = *eax; 403 c->cr_sel = true; 404 } else { 405 c->reg_cr[1] = *eax; 406 c->cr_sel = false; 407 408 c->reg_status &= ~TIMER_STS_NULLCNT; 409 c->fr_sel = false; 410 c->initial = c->reg_cr[0] | (uint16_t)c->reg_cr[1] << 8; 411 c->time_loaded = gethrtime(); 412 /* Start an interval timer for channel 0 */ 413 if (port == TIMER_CNTR0) { 414 c->time_target = c->time_loaded; 415 c->total_target = 0; 416 pit_timer_start_cntr0(vatpit); 417 } 418 if (c->initial == 0) 419 c->initial = 0xffff; 420 } 421 } 422 VATPIT_UNLOCK(vatpit); 423 424 return (0); 425 } 426 427 int 428 vatpit_nmisc_handler(void *arg, bool in, uint16_t port, uint8_t bytes, 429 uint32_t *eax) 430 { 431 struct vatpit *vatpit = arg; 432 433 if (in) { 434 VATPIT_LOCK(vatpit); 435 if (vatpit_get_out(vatpit, 2)) 436 *eax = TMR2_OUT_STS; 437 else 438 *eax = 0; 439 440 VATPIT_UNLOCK(vatpit); 441 } 442 443 return (0); 444 } 445 446 struct vatpit * 447 vatpit_init(struct vm *vm) 448 { 449 struct vatpit *vatpit; 450 struct vatpit_callout_arg *arg; 451 int i; 452 453 vatpit = malloc(sizeof (struct vatpit), M_VATPIT, M_WAITOK | M_ZERO); 454 vatpit->vm = vm; 455 456 mutex_init(&vatpit->lock, NULL, MUTEX_ADAPTIVE, NULL); 457 458 for (i = 0; i < 3; i++) { 459 callout_init(&vatpit->channel[i].callout, 1); 460 arg = &vatpit->channel[i].callout_arg; 461 arg->vatpit = vatpit; 462 arg->channel_num = i; 463 } 464 465 return (vatpit); 466 } 467 468 void 469 vatpit_cleanup(struct vatpit *vatpit) 470 { 471 int i; 472 473 for (i = 0; i < 3; i++) 474 callout_drain(&vatpit->channel[i].callout); 475 476 mutex_destroy(&vatpit->lock); 477 free(vatpit, M_VATPIT); 478 } 479 480 void 481 vatpit_localize_resources(struct vatpit *vatpit) 482 { 483 for (uint_t i = 0; i < 3; i++) { 484 /* Only localize channels which might be running */ 485 if (vatpit->channel[i].mode != 0) { 486 vmm_glue_callout_localize(&vatpit->channel[i].callout); 487 } 488 } 489 } 490