1 /*- 2 * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 3 * Copyright (c) 2011 NetApp, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/types.h> 33 #include <sys/queue.h> 34 #include <sys/cpuset.h> 35 #include <sys/kernel.h> 36 #include <sys/lock.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) mtx_lock_spin(&((vatpit)->mtx)) 51 #define VATPIT_UNLOCK(vatpit) mtx_unlock_spin(&((vatpit)->mtx)) 52 #define VATPIT_LOCKED(vatpit) mtx_owned(&((vatpit)->mtx)) 53 54 #define TIMER_SEL_MASK 0xc0 55 #define TIMER_RW_MASK 0x30 56 #define TIMER_MODE_MASK 0x0f 57 #define TIMER_SEL_READBACK 0xc0 58 59 #define TMR2_OUT_STS 0x20 60 61 #define PIT_8254_FREQ 1193182 62 #define TIMER_DIV(freq, hz) (((freq) + (hz) / 2) / (hz)) 63 64 struct vatpit_callout_arg { 65 struct vatpit *vatpit; 66 int channel_num; 67 }; 68 69 70 struct channel { 71 int mode; 72 uint16_t initial; /* initial counter value */ 73 sbintime_t now_sbt; /* uptime when counter was loaded */ 74 uint8_t cr[2]; 75 uint8_t ol[2]; 76 int crbyte; 77 int olbyte; 78 int frbyte; 79 struct callout callout; 80 sbintime_t callout_sbt; /* target time */ 81 struct vatpit_callout_arg callout_arg; 82 }; 83 84 struct vatpit { 85 struct vm *vm; 86 struct mtx mtx; 87 88 sbintime_t freq_sbt; 89 90 struct channel channel[3]; 91 }; 92 93 static void pit_timer_start_cntr0(struct vatpit *vatpit); 94 95 static int 96 vatpit_get_out(struct vatpit *vatpit, int channel) 97 { 98 struct channel *c; 99 sbintime_t delta_ticks; 100 int out; 101 102 c = &vatpit->channel[channel]; 103 104 switch (c->mode) { 105 case TIMER_INTTC: 106 delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt; 107 out = ((c->initial - delta_ticks) <= 0); 108 break; 109 default: 110 out = 0; 111 break; 112 } 113 114 return (out); 115 } 116 117 static void 118 vatpit_callout_handler(void *a) 119 { 120 struct vatpit_callout_arg *arg = a; 121 struct vatpit *vatpit; 122 struct callout *callout; 123 struct channel *c; 124 125 vatpit = arg->vatpit; 126 c = &vatpit->channel[arg->channel_num]; 127 callout = &c->callout; 128 129 VM_CTR1(vatpit->vm, "atpit t%d fired", arg->channel_num); 130 131 VATPIT_LOCK(vatpit); 132 133 if (callout_pending(callout)) /* callout was reset */ 134 goto done; 135 136 if (!callout_active(callout)) /* callout was stopped */ 137 goto done; 138 139 callout_deactivate(callout); 140 141 if (c->mode == TIMER_RATEGEN) { 142 pit_timer_start_cntr0(vatpit); 143 } 144 145 vatpic_pulse_irq(vatpit->vm, 0); 146 vioapic_pulse_irq(vatpit->vm, 2); 147 148 done: 149 VATPIT_UNLOCK(vatpit); 150 return; 151 } 152 153 static void 154 pit_timer_start_cntr0(struct vatpit *vatpit) 155 { 156 struct channel *c; 157 sbintime_t now, delta, precision; 158 159 c = &vatpit->channel[0]; 160 if (c->initial != 0) { 161 delta = c->initial * vatpit->freq_sbt; 162 precision = delta >> tc_precexp; 163 c->callout_sbt = c->callout_sbt + delta; 164 165 /* 166 * Reset 'callout_sbt' if the time that the callout 167 * was supposed to fire is more than 'c->initial' 168 * ticks in the past. 169 */ 170 now = sbinuptime(); 171 if (c->callout_sbt < now) 172 c->callout_sbt = now + delta; 173 174 callout_reset_sbt(&c->callout, c->callout_sbt, 175 precision, vatpit_callout_handler, &c->callout_arg, 176 C_ABSOLUTE); 177 } 178 } 179 180 static uint16_t 181 pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch) 182 { 183 uint16_t lval; 184 sbintime_t delta_ticks; 185 186 /* cannot latch a new value until the old one has been consumed */ 187 if (latch && c->olbyte != 0) 188 return (0); 189 190 if (c->initial == 0) { 191 /* 192 * This is possibly an o/s bug - reading the value of 193 * the timer without having set up the initial value. 194 * 195 * The original user-space version of this code set 196 * the timer to 100hz in this condition; do the same 197 * here. 198 */ 199 c->initial = TIMER_DIV(PIT_8254_FREQ, 100); 200 c->now_sbt = sbinuptime(); 201 } 202 203 delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt; 204 205 lval = c->initial - delta_ticks % c->initial; 206 207 if (latch) { 208 c->olbyte = 2; 209 c->ol[1] = lval; /* LSB */ 210 c->ol[0] = lval >> 8; /* MSB */ 211 } 212 213 return (lval); 214 } 215 216 static int 217 vatpit_update_mode(struct vatpit *vatpit, uint8_t val) 218 { 219 struct channel *c; 220 int sel, rw, mode; 221 222 sel = val & TIMER_SEL_MASK; 223 rw = val & TIMER_RW_MASK; 224 mode = val & TIMER_MODE_MASK; 225 226 if (sel == TIMER_SEL_READBACK) 227 return (-1); 228 229 if (rw != TIMER_LATCH && rw != TIMER_16BIT) 230 return (-1); 231 232 if (rw != TIMER_LATCH) { 233 /* 234 * Counter mode is not affected when issuing a 235 * latch command. 236 */ 237 if (mode != TIMER_INTTC && 238 mode != TIMER_RATEGEN && 239 mode != TIMER_SQWAVE && 240 mode != TIMER_SWSTROBE) 241 return (-1); 242 } 243 244 c = &vatpit->channel[sel >> 6]; 245 if (rw == TIMER_LATCH) 246 pit_update_counter(vatpit, c, true); 247 else { 248 c->mode = mode; 249 c->olbyte = 0; /* reset latch after reprogramming */ 250 } 251 252 return (0); 253 } 254 255 int 256 vatpit_handler(void *vm, int vcpuid, struct vm_exit *vmexit) 257 { 258 struct vatpit *vatpit; 259 struct channel *c; 260 int port; 261 uint8_t val; 262 int error; 263 264 vatpit = vm_atpit(vm); 265 266 if (vmexit->u.inout.bytes != 1) 267 return (-1); 268 269 val = vmexit->u.inout.eax; 270 port = vmexit->u.inout.port; 271 272 if (port == TIMER_MODE) { 273 if (vmexit->u.inout.in) { 274 VM_CTR0(vatpit->vm, "vatpit attempt to read mode"); 275 return (-1); 276 } 277 278 VATPIT_LOCK(vatpit); 279 error = vatpit_update_mode(vatpit, val); 280 VATPIT_UNLOCK(vatpit); 281 282 return (error); 283 } 284 285 /* counter ports */ 286 KASSERT(port >= TIMER_CNTR0 && vmexit->u.inout.port <= TIMER_CNTR2, 287 ("invalid port 0x%x", port)); 288 c = &vatpit->channel[port - TIMER_CNTR0]; 289 290 VATPIT_LOCK(vatpit); 291 if (vmexit->u.inout.in) { 292 /* 293 * The spec says that once the output latch is completely 294 * read it should revert to "following" the counter. Use 295 * the free running counter for this case (i.e. Linux 296 * TSC calibration). Assuming the access mode is 16-bit, 297 * toggle the MSB/LSB bit on each read. 298 */ 299 if (c->olbyte == 0) { 300 uint16_t tmp; 301 302 tmp = pit_update_counter(vatpit, c, false); 303 if (c->frbyte) 304 tmp >>= 8; 305 tmp &= 0xff; 306 vmexit->u.inout.eax = tmp; 307 c->frbyte ^= 1; 308 } else 309 vmexit->u.inout.eax = c->ol[--c->olbyte]; 310 } else { 311 c->cr[c->crbyte++] = vmexit->u.inout.eax; 312 if (c->crbyte == 2) { 313 c->frbyte = 0; 314 c->crbyte = 0; 315 c->initial = c->cr[0] | (uint16_t)c->cr[1] << 8; 316 c->now_sbt = sbinuptime(); 317 /* Start an interval timer for channel 0 */ 318 if (port == TIMER_CNTR0) { 319 c->callout_sbt = c->now_sbt; 320 pit_timer_start_cntr0(vatpit); 321 } 322 if (c->initial == 0) 323 c->initial = 0xffff; 324 } 325 } 326 VATPIT_UNLOCK(vatpit); 327 328 return (0); 329 } 330 331 int 332 vatpit_nmisc_handler(void *vm, int vcpuid, struct vm_exit *vmexit) 333 { 334 struct vatpit *vatpit; 335 336 vatpit = vm_atpit(vm); 337 338 if (vmexit->u.inout.in) { 339 VATPIT_LOCK(vatpit); 340 if (vatpit_get_out(vatpit, 2)) 341 vmexit->u.inout.eax = TMR2_OUT_STS; 342 else 343 vmexit->u.inout.eax = 0; 344 345 VATPIT_UNLOCK(vatpit); 346 } 347 348 return (0); 349 } 350 351 struct vatpit * 352 vatpit_init(struct vm *vm) 353 { 354 struct vatpit *vatpit; 355 struct bintime bt; 356 struct vatpit_callout_arg *arg; 357 int i; 358 359 vatpit = malloc(sizeof(struct vatpit), M_VATPIT, M_WAITOK | M_ZERO); 360 vatpit->vm = vm; 361 362 mtx_init(&vatpit->mtx, "vatpit lock", NULL, MTX_SPIN); 363 364 FREQ2BT(PIT_8254_FREQ, &bt); 365 vatpit->freq_sbt = bttosbt(bt); 366 367 for (i = 0; i < 3; i++) { 368 callout_init(&vatpit->channel[i].callout, true); 369 arg = &vatpit->channel[i].callout_arg; 370 arg->vatpit = vatpit; 371 arg->channel_num = i; 372 } 373 374 return (vatpit); 375 } 376 377 void 378 vatpit_cleanup(struct vatpit *vatpit) 379 { 380 int i; 381 382 for (i = 0; i < 3; i++) 383 callout_drain(&vatpit->channel[i].callout); 384 385 free(vatpit, M_VATPIT); 386 } 387