1e883c9bbSTycho Nightingale /*- 2e883c9bbSTycho Nightingale * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 3e883c9bbSTycho Nightingale * Copyright (c) 2011 NetApp, Inc. 4e883c9bbSTycho Nightingale * All rights reserved. 587c39157SJohn Baldwin * Copyright (c) 2018 Joyent, Inc. 6e883c9bbSTycho Nightingale * 7e883c9bbSTycho Nightingale * Redistribution and use in source and binary forms, with or without 8e883c9bbSTycho Nightingale * modification, are permitted provided that the following conditions 9e883c9bbSTycho Nightingale * are met: 10e883c9bbSTycho Nightingale * 1. Redistributions of source code must retain the above copyright 11e883c9bbSTycho Nightingale * notice, this list of conditions and the following disclaimer. 12e883c9bbSTycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright 13e883c9bbSTycho Nightingale * notice, this list of conditions and the following disclaimer in the 14e883c9bbSTycho Nightingale * documentation and/or other materials provided with the distribution. 15e883c9bbSTycho Nightingale * 16e883c9bbSTycho Nightingale * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17e883c9bbSTycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18e883c9bbSTycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19e883c9bbSTycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20e883c9bbSTycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21e883c9bbSTycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22e883c9bbSTycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23e883c9bbSTycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24e883c9bbSTycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25e883c9bbSTycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26e883c9bbSTycho Nightingale * SUCH DAMAGE. 27e883c9bbSTycho Nightingale */ 28e883c9bbSTycho Nightingale 29e883c9bbSTycho Nightingale #include <sys/cdefs.h> 30e883c9bbSTycho Nightingale __FBSDID("$FreeBSD$"); 31e883c9bbSTycho Nightingale 32*483d953aSJohn Baldwin #include "opt_bhyve_snapshot.h" 33*483d953aSJohn Baldwin 34e883c9bbSTycho Nightingale #include <sys/param.h> 35e883c9bbSTycho Nightingale #include <sys/types.h> 36e883c9bbSTycho Nightingale #include <sys/queue.h> 37e883c9bbSTycho Nightingale #include <sys/kernel.h> 38e883c9bbSTycho Nightingale #include <sys/lock.h> 39e883c9bbSTycho Nightingale #include <sys/malloc.h> 40e883c9bbSTycho Nightingale #include <sys/mutex.h> 41e883c9bbSTycho Nightingale #include <sys/systm.h> 42e883c9bbSTycho Nightingale 43e883c9bbSTycho Nightingale #include <machine/vmm.h> 44*483d953aSJohn Baldwin #include <machine/vmm_snapshot.h> 45e883c9bbSTycho Nightingale 46e883c9bbSTycho Nightingale #include "vmm_ktr.h" 47e883c9bbSTycho Nightingale #include "vatpic.h" 48e883c9bbSTycho Nightingale #include "vioapic.h" 49e883c9bbSTycho Nightingale #include "vatpit.h" 50e883c9bbSTycho Nightingale 51e883c9bbSTycho Nightingale static MALLOC_DEFINE(M_VATPIT, "atpit", "bhyve virtual atpit (8254)"); 52e883c9bbSTycho Nightingale 53e883c9bbSTycho Nightingale #define VATPIT_LOCK(vatpit) mtx_lock_spin(&((vatpit)->mtx)) 54e883c9bbSTycho Nightingale #define VATPIT_UNLOCK(vatpit) mtx_unlock_spin(&((vatpit)->mtx)) 55e883c9bbSTycho Nightingale #define VATPIT_LOCKED(vatpit) mtx_owned(&((vatpit)->mtx)) 56e883c9bbSTycho Nightingale 57e883c9bbSTycho Nightingale #define TIMER_SEL_MASK 0xc0 58e883c9bbSTycho Nightingale #define TIMER_RW_MASK 0x30 59e883c9bbSTycho Nightingale #define TIMER_MODE_MASK 0x0f 60e883c9bbSTycho Nightingale #define TIMER_SEL_READBACK 0xc0 61e883c9bbSTycho Nightingale 62c46ff7faSTycho Nightingale #define TIMER_STS_OUT 0x80 63c46ff7faSTycho Nightingale #define TIMER_STS_NULLCNT 0x40 64c46ff7faSTycho Nightingale 65c46ff7faSTycho Nightingale #define TIMER_RB_LCTR 0x20 66c46ff7faSTycho Nightingale #define TIMER_RB_LSTATUS 0x10 67c46ff7faSTycho Nightingale #define TIMER_RB_CTR_2 0x08 68c46ff7faSTycho Nightingale #define TIMER_RB_CTR_1 0x04 69c46ff7faSTycho Nightingale #define TIMER_RB_CTR_0 0x02 70c46ff7faSTycho Nightingale 7179d6ca33STycho Nightingale #define TMR2_OUT_STS 0x20 7279d6ca33STycho Nightingale 73e883c9bbSTycho Nightingale #define PIT_8254_FREQ 1193182 74e883c9bbSTycho Nightingale #define TIMER_DIV(freq, hz) (((freq) + (hz) / 2) / (hz)) 75e883c9bbSTycho Nightingale 76e883c9bbSTycho Nightingale struct vatpit_callout_arg { 77e883c9bbSTycho Nightingale struct vatpit *vatpit; 78e883c9bbSTycho Nightingale int channel_num; 79e883c9bbSTycho Nightingale }; 80e883c9bbSTycho Nightingale 81e883c9bbSTycho Nightingale 82e883c9bbSTycho Nightingale struct channel { 83e883c9bbSTycho Nightingale int mode; 84e883c9bbSTycho Nightingale uint16_t initial; /* initial counter value */ 8587c39157SJohn Baldwin struct bintime now_bt; /* uptime when counter was loaded */ 86e883c9bbSTycho Nightingale uint8_t cr[2]; 87e883c9bbSTycho Nightingale uint8_t ol[2]; 88c46ff7faSTycho Nightingale bool slatched; /* status latched */ 89c46ff7faSTycho Nightingale uint8_t status; 90e883c9bbSTycho Nightingale int crbyte; 91e883c9bbSTycho Nightingale int olbyte; 92e883c9bbSTycho Nightingale int frbyte; 93e883c9bbSTycho Nightingale struct callout callout; 9487c39157SJohn Baldwin struct bintime callout_bt; /* target time */ 95e883c9bbSTycho Nightingale struct vatpit_callout_arg callout_arg; 96e883c9bbSTycho Nightingale }; 97e883c9bbSTycho Nightingale 98e883c9bbSTycho Nightingale struct vatpit { 99e883c9bbSTycho Nightingale struct vm *vm; 100e883c9bbSTycho Nightingale struct mtx mtx; 101e883c9bbSTycho Nightingale 10287c39157SJohn Baldwin struct bintime freq_bt; 103e883c9bbSTycho Nightingale 104e883c9bbSTycho Nightingale struct channel channel[3]; 105e883c9bbSTycho Nightingale }; 106e883c9bbSTycho Nightingale 107e883c9bbSTycho Nightingale static void pit_timer_start_cntr0(struct vatpit *vatpit); 108e883c9bbSTycho Nightingale 10987c39157SJohn Baldwin static uint64_t 11087c39157SJohn Baldwin vatpit_delta_ticks(struct vatpit *vatpit, struct channel *c) 11187c39157SJohn Baldwin { 11287c39157SJohn Baldwin struct bintime delta; 11387c39157SJohn Baldwin uint64_t result; 11487c39157SJohn Baldwin 11587c39157SJohn Baldwin binuptime(&delta); 11687c39157SJohn Baldwin bintime_sub(&delta, &c->now_bt); 11787c39157SJohn Baldwin 11887c39157SJohn Baldwin result = delta.sec * PIT_8254_FREQ; 11987c39157SJohn Baldwin result += delta.frac / vatpit->freq_bt.frac; 12087c39157SJohn Baldwin 12187c39157SJohn Baldwin return (result); 12287c39157SJohn Baldwin } 12387c39157SJohn Baldwin 12479d6ca33STycho Nightingale static int 12579d6ca33STycho Nightingale vatpit_get_out(struct vatpit *vatpit, int channel) 12679d6ca33STycho Nightingale { 12779d6ca33STycho Nightingale struct channel *c; 12887c39157SJohn Baldwin uint64_t delta_ticks; 12979d6ca33STycho Nightingale int out; 13079d6ca33STycho Nightingale 13179d6ca33STycho Nightingale c = &vatpit->channel[channel]; 13279d6ca33STycho Nightingale 13379d6ca33STycho Nightingale switch (c->mode) { 13479d6ca33STycho Nightingale case TIMER_INTTC: 13587c39157SJohn Baldwin delta_ticks = vatpit_delta_ticks(vatpit, c); 13687c39157SJohn Baldwin out = (delta_ticks >= c->initial); 13779d6ca33STycho Nightingale break; 13879d6ca33STycho Nightingale default: 13979d6ca33STycho Nightingale out = 0; 14079d6ca33STycho Nightingale break; 14179d6ca33STycho Nightingale } 14279d6ca33STycho Nightingale 14379d6ca33STycho Nightingale return (out); 14479d6ca33STycho Nightingale } 14579d6ca33STycho Nightingale 146e883c9bbSTycho Nightingale static void 147e883c9bbSTycho Nightingale vatpit_callout_handler(void *a) 148e883c9bbSTycho Nightingale { 149e883c9bbSTycho Nightingale struct vatpit_callout_arg *arg = a; 150e883c9bbSTycho Nightingale struct vatpit *vatpit; 151e883c9bbSTycho Nightingale struct callout *callout; 152e883c9bbSTycho Nightingale struct channel *c; 153e883c9bbSTycho Nightingale 154e883c9bbSTycho Nightingale vatpit = arg->vatpit; 155e883c9bbSTycho Nightingale c = &vatpit->channel[arg->channel_num]; 156e883c9bbSTycho Nightingale callout = &c->callout; 157e883c9bbSTycho Nightingale 15879d6ca33STycho Nightingale VM_CTR1(vatpit->vm, "atpit t%d fired", arg->channel_num); 159e883c9bbSTycho Nightingale 160e883c9bbSTycho Nightingale VATPIT_LOCK(vatpit); 161e883c9bbSTycho Nightingale 162e883c9bbSTycho Nightingale if (callout_pending(callout)) /* callout was reset */ 163e883c9bbSTycho Nightingale goto done; 164e883c9bbSTycho Nightingale 165e883c9bbSTycho Nightingale if (!callout_active(callout)) /* callout was stopped */ 166e883c9bbSTycho Nightingale goto done; 167e883c9bbSTycho Nightingale 168e883c9bbSTycho Nightingale callout_deactivate(callout); 169e883c9bbSTycho Nightingale 170e883c9bbSTycho Nightingale if (c->mode == TIMER_RATEGEN) { 171e883c9bbSTycho Nightingale pit_timer_start_cntr0(vatpit); 172e883c9bbSTycho Nightingale } 173e883c9bbSTycho Nightingale 174e883c9bbSTycho Nightingale vatpic_pulse_irq(vatpit->vm, 0); 175e883c9bbSTycho Nightingale vioapic_pulse_irq(vatpit->vm, 2); 176e883c9bbSTycho Nightingale 177e883c9bbSTycho Nightingale done: 178e883c9bbSTycho Nightingale VATPIT_UNLOCK(vatpit); 179e883c9bbSTycho Nightingale return; 180e883c9bbSTycho Nightingale } 181e883c9bbSTycho Nightingale 182e883c9bbSTycho Nightingale static void 183e883c9bbSTycho Nightingale pit_timer_start_cntr0(struct vatpit *vatpit) 184e883c9bbSTycho Nightingale { 185e883c9bbSTycho Nightingale struct channel *c; 18687c39157SJohn Baldwin struct bintime now, delta; 18787c39157SJohn Baldwin sbintime_t precision; 188e883c9bbSTycho Nightingale 189e883c9bbSTycho Nightingale c = &vatpit->channel[0]; 190e883c9bbSTycho Nightingale if (c->initial != 0) { 19187c39157SJohn Baldwin delta.sec = 0; 19287c39157SJohn Baldwin delta.frac = vatpit->freq_bt.frac * c->initial; 19387c39157SJohn Baldwin bintime_add(&c->callout_bt, &delta); 19487c39157SJohn Baldwin precision = bttosbt(delta) >> tc_precexp; 195e883c9bbSTycho Nightingale 19679d6ca33STycho Nightingale /* 19787c39157SJohn Baldwin * Reset 'callout_bt' if the time that the callout 19879d6ca33STycho Nightingale * was supposed to fire is more than 'c->initial' 19979d6ca33STycho Nightingale * ticks in the past. 20079d6ca33STycho Nightingale */ 20187c39157SJohn Baldwin binuptime(&now); 20287c39157SJohn Baldwin if (bintime_cmp(&c->callout_bt, &now, <)) { 20387c39157SJohn Baldwin c->callout_bt = now; 20487c39157SJohn Baldwin bintime_add(&c->callout_bt, &delta); 20587c39157SJohn Baldwin } 20679d6ca33STycho Nightingale 20787c39157SJohn Baldwin callout_reset_sbt(&c->callout, bttosbt(c->callout_bt), 208e883c9bbSTycho Nightingale precision, vatpit_callout_handler, &c->callout_arg, 209e883c9bbSTycho Nightingale C_ABSOLUTE); 210e883c9bbSTycho Nightingale } 211e883c9bbSTycho Nightingale } 212e883c9bbSTycho Nightingale 213e883c9bbSTycho Nightingale static uint16_t 214e883c9bbSTycho Nightingale pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch) 215e883c9bbSTycho Nightingale { 216e883c9bbSTycho Nightingale uint16_t lval; 21787c39157SJohn Baldwin uint64_t delta_ticks; 218e883c9bbSTycho Nightingale 219e883c9bbSTycho Nightingale /* cannot latch a new value until the old one has been consumed */ 220e883c9bbSTycho Nightingale if (latch && c->olbyte != 0) 221e883c9bbSTycho Nightingale return (0); 222e883c9bbSTycho Nightingale 223e883c9bbSTycho Nightingale if (c->initial == 0) { 224e883c9bbSTycho Nightingale /* 225e883c9bbSTycho Nightingale * This is possibly an o/s bug - reading the value of 226e883c9bbSTycho Nightingale * the timer without having set up the initial value. 227e883c9bbSTycho Nightingale * 228e883c9bbSTycho Nightingale * The original user-space version of this code set 229e883c9bbSTycho Nightingale * the timer to 100hz in this condition; do the same 230e883c9bbSTycho Nightingale * here. 231e883c9bbSTycho Nightingale */ 232e883c9bbSTycho Nightingale c->initial = TIMER_DIV(PIT_8254_FREQ, 100); 23387c39157SJohn Baldwin binuptime(&c->now_bt); 234c46ff7faSTycho Nightingale c->status &= ~TIMER_STS_NULLCNT; 235e883c9bbSTycho Nightingale } 236e883c9bbSTycho Nightingale 23787c39157SJohn Baldwin delta_ticks = vatpit_delta_ticks(vatpit, c); 238e883c9bbSTycho Nightingale lval = c->initial - delta_ticks % c->initial; 239e883c9bbSTycho Nightingale 240e883c9bbSTycho Nightingale if (latch) { 241e883c9bbSTycho Nightingale c->olbyte = 2; 242e883c9bbSTycho Nightingale c->ol[1] = lval; /* LSB */ 243e883c9bbSTycho Nightingale c->ol[0] = lval >> 8; /* MSB */ 244e883c9bbSTycho Nightingale } 245e883c9bbSTycho Nightingale 246e883c9bbSTycho Nightingale return (lval); 247e883c9bbSTycho Nightingale } 248e883c9bbSTycho Nightingale 249e883c9bbSTycho Nightingale static int 250c46ff7faSTycho Nightingale pit_readback1(struct vatpit *vatpit, int channel, uint8_t cmd) 251c46ff7faSTycho Nightingale { 252c46ff7faSTycho Nightingale struct channel *c; 253c46ff7faSTycho Nightingale 254c46ff7faSTycho Nightingale c = &vatpit->channel[channel]; 255c46ff7faSTycho Nightingale 256c46ff7faSTycho Nightingale /* 257c46ff7faSTycho Nightingale * Latch the count/status of the timer if not already latched. 258c46ff7faSTycho Nightingale * N.B. that the count/status latch-select bits are active-low. 259c46ff7faSTycho Nightingale */ 260c46ff7faSTycho Nightingale if (!(cmd & TIMER_RB_LCTR) && !c->olbyte) { 261c46ff7faSTycho Nightingale (void) pit_update_counter(vatpit, c, true); 262c46ff7faSTycho Nightingale } 263c46ff7faSTycho Nightingale 264c46ff7faSTycho Nightingale if (!(cmd & TIMER_RB_LSTATUS) && !c->slatched) { 265c46ff7faSTycho Nightingale c->slatched = true; 266c46ff7faSTycho Nightingale /* 267c46ff7faSTycho Nightingale * For mode 0, see if the elapsed time is greater 268c46ff7faSTycho Nightingale * than the initial value - this results in the 269c46ff7faSTycho Nightingale * output pin being set to 1 in the status byte. 270c46ff7faSTycho Nightingale */ 271c46ff7faSTycho Nightingale if (c->mode == TIMER_INTTC && vatpit_get_out(vatpit, channel)) 272c46ff7faSTycho Nightingale c->status |= TIMER_STS_OUT; 273c46ff7faSTycho Nightingale else 274c46ff7faSTycho Nightingale c->status &= ~TIMER_STS_OUT; 275c46ff7faSTycho Nightingale } 276c46ff7faSTycho Nightingale 277c46ff7faSTycho Nightingale return (0); 278c46ff7faSTycho Nightingale } 279c46ff7faSTycho Nightingale 280c46ff7faSTycho Nightingale static int 281c46ff7faSTycho Nightingale pit_readback(struct vatpit *vatpit, uint8_t cmd) 282c46ff7faSTycho Nightingale { 283c46ff7faSTycho Nightingale int error; 284c46ff7faSTycho Nightingale 285c46ff7faSTycho Nightingale /* 286c46ff7faSTycho Nightingale * The readback command can apply to all timers. 287c46ff7faSTycho Nightingale */ 288c46ff7faSTycho Nightingale error = 0; 289c46ff7faSTycho Nightingale if (cmd & TIMER_RB_CTR_0) 290c46ff7faSTycho Nightingale error = pit_readback1(vatpit, 0, cmd); 291c46ff7faSTycho Nightingale if (!error && cmd & TIMER_RB_CTR_1) 292c46ff7faSTycho Nightingale error = pit_readback1(vatpit, 1, cmd); 293c46ff7faSTycho Nightingale if (!error && cmd & TIMER_RB_CTR_2) 294c46ff7faSTycho Nightingale error = pit_readback1(vatpit, 2, cmd); 295c46ff7faSTycho Nightingale 296c46ff7faSTycho Nightingale return (error); 297c46ff7faSTycho Nightingale } 298c46ff7faSTycho Nightingale 299c46ff7faSTycho Nightingale 300c46ff7faSTycho Nightingale static int 301e883c9bbSTycho Nightingale vatpit_update_mode(struct vatpit *vatpit, uint8_t val) 302e883c9bbSTycho Nightingale { 303e883c9bbSTycho Nightingale struct channel *c; 304e883c9bbSTycho Nightingale int sel, rw, mode; 305e883c9bbSTycho Nightingale 306e883c9bbSTycho Nightingale sel = val & TIMER_SEL_MASK; 307e883c9bbSTycho Nightingale rw = val & TIMER_RW_MASK; 308e883c9bbSTycho Nightingale mode = val & TIMER_MODE_MASK; 309e883c9bbSTycho Nightingale 310e883c9bbSTycho Nightingale if (sel == TIMER_SEL_READBACK) 311c46ff7faSTycho Nightingale return (pit_readback(vatpit, val)); 312e883c9bbSTycho Nightingale 313e883c9bbSTycho Nightingale if (rw != TIMER_LATCH && rw != TIMER_16BIT) 314e883c9bbSTycho Nightingale return (-1); 315e883c9bbSTycho Nightingale 316e883c9bbSTycho Nightingale if (rw != TIMER_LATCH) { 317e883c9bbSTycho Nightingale /* 318e883c9bbSTycho Nightingale * Counter mode is not affected when issuing a 319e883c9bbSTycho Nightingale * latch command. 320e883c9bbSTycho Nightingale */ 321e883c9bbSTycho Nightingale if (mode != TIMER_INTTC && 322e883c9bbSTycho Nightingale mode != TIMER_RATEGEN && 323e883c9bbSTycho Nightingale mode != TIMER_SQWAVE && 324e883c9bbSTycho Nightingale mode != TIMER_SWSTROBE) 325e883c9bbSTycho Nightingale return (-1); 326e883c9bbSTycho Nightingale } 327e883c9bbSTycho Nightingale 328e883c9bbSTycho Nightingale c = &vatpit->channel[sel >> 6]; 329e883c9bbSTycho Nightingale if (rw == TIMER_LATCH) 330e883c9bbSTycho Nightingale pit_update_counter(vatpit, c, true); 331e883c9bbSTycho Nightingale else { 332e883c9bbSTycho Nightingale c->mode = mode; 333e883c9bbSTycho Nightingale c->olbyte = 0; /* reset latch after reprogramming */ 334c46ff7faSTycho Nightingale c->status |= TIMER_STS_NULLCNT; 335e883c9bbSTycho Nightingale } 336e883c9bbSTycho Nightingale 337e883c9bbSTycho Nightingale return (0); 338e883c9bbSTycho Nightingale } 339e883c9bbSTycho Nightingale 340e883c9bbSTycho Nightingale int 341f0c8263eSNeel Natu vatpit_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, 342d6aa08c3STycho Nightingale uint32_t *eax) 343e883c9bbSTycho Nightingale { 344e883c9bbSTycho Nightingale struct vatpit *vatpit; 345e883c9bbSTycho Nightingale struct channel *c; 346e883c9bbSTycho Nightingale uint8_t val; 347e883c9bbSTycho Nightingale int error; 348e883c9bbSTycho Nightingale 349e883c9bbSTycho Nightingale vatpit = vm_atpit(vm); 350e883c9bbSTycho Nightingale 351d6aa08c3STycho Nightingale if (bytes != 1) 352e883c9bbSTycho Nightingale return (-1); 353e883c9bbSTycho Nightingale 354d6aa08c3STycho Nightingale val = *eax; 355e883c9bbSTycho Nightingale 356e883c9bbSTycho Nightingale if (port == TIMER_MODE) { 357d6aa08c3STycho Nightingale if (in) { 35879d6ca33STycho Nightingale VM_CTR0(vatpit->vm, "vatpit attempt to read mode"); 359e883c9bbSTycho Nightingale return (-1); 360e883c9bbSTycho Nightingale } 361e883c9bbSTycho Nightingale 362e883c9bbSTycho Nightingale VATPIT_LOCK(vatpit); 363e883c9bbSTycho Nightingale error = vatpit_update_mode(vatpit, val); 364e883c9bbSTycho Nightingale VATPIT_UNLOCK(vatpit); 365e883c9bbSTycho Nightingale 366e883c9bbSTycho Nightingale return (error); 367e883c9bbSTycho Nightingale } 368e883c9bbSTycho Nightingale 369e883c9bbSTycho Nightingale /* counter ports */ 370d6aa08c3STycho Nightingale KASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2, 371e883c9bbSTycho Nightingale ("invalid port 0x%x", port)); 372e883c9bbSTycho Nightingale c = &vatpit->channel[port - TIMER_CNTR0]; 373e883c9bbSTycho Nightingale 374e883c9bbSTycho Nightingale VATPIT_LOCK(vatpit); 375c46ff7faSTycho Nightingale if (in && c->slatched) { 376c46ff7faSTycho Nightingale /* 377c46ff7faSTycho Nightingale * Return the status byte if latched 378c46ff7faSTycho Nightingale */ 379c46ff7faSTycho Nightingale *eax = c->status; 380c46ff7faSTycho Nightingale c->slatched = false; 381c46ff7faSTycho Nightingale c->status = 0; 382c46ff7faSTycho Nightingale } else if (in) { 383e883c9bbSTycho Nightingale /* 384e883c9bbSTycho Nightingale * The spec says that once the output latch is completely 385e883c9bbSTycho Nightingale * read it should revert to "following" the counter. Use 386e883c9bbSTycho Nightingale * the free running counter for this case (i.e. Linux 387e883c9bbSTycho Nightingale * TSC calibration). Assuming the access mode is 16-bit, 388e883c9bbSTycho Nightingale * toggle the MSB/LSB bit on each read. 389e883c9bbSTycho Nightingale */ 390e883c9bbSTycho Nightingale if (c->olbyte == 0) { 391e883c9bbSTycho Nightingale uint16_t tmp; 392e883c9bbSTycho Nightingale 393e883c9bbSTycho Nightingale tmp = pit_update_counter(vatpit, c, false); 394e883c9bbSTycho Nightingale if (c->frbyte) 395e883c9bbSTycho Nightingale tmp >>= 8; 396e883c9bbSTycho Nightingale tmp &= 0xff; 397d6aa08c3STycho Nightingale *eax = tmp; 398e883c9bbSTycho Nightingale c->frbyte ^= 1; 399e883c9bbSTycho Nightingale } else 400d6aa08c3STycho Nightingale *eax = c->ol[--c->olbyte]; 401e883c9bbSTycho Nightingale } else { 402d6aa08c3STycho Nightingale c->cr[c->crbyte++] = *eax; 403e883c9bbSTycho Nightingale if (c->crbyte == 2) { 404c46ff7faSTycho Nightingale c->status &= ~TIMER_STS_NULLCNT; 405e883c9bbSTycho Nightingale c->frbyte = 0; 406e883c9bbSTycho Nightingale c->crbyte = 0; 407e883c9bbSTycho Nightingale c->initial = c->cr[0] | (uint16_t)c->cr[1] << 8; 40887c39157SJohn Baldwin binuptime(&c->now_bt); 409e883c9bbSTycho Nightingale /* Start an interval timer for channel 0 */ 410e883c9bbSTycho Nightingale if (port == TIMER_CNTR0) { 41187c39157SJohn Baldwin c->callout_bt = c->now_bt; 412e883c9bbSTycho Nightingale pit_timer_start_cntr0(vatpit); 413e883c9bbSTycho Nightingale } 414e883c9bbSTycho Nightingale if (c->initial == 0) 415e883c9bbSTycho Nightingale c->initial = 0xffff; 416e883c9bbSTycho Nightingale } 417e883c9bbSTycho Nightingale } 418e883c9bbSTycho Nightingale VATPIT_UNLOCK(vatpit); 419e883c9bbSTycho Nightingale 420e883c9bbSTycho Nightingale return (0); 421e883c9bbSTycho Nightingale } 422e883c9bbSTycho Nightingale 42379d6ca33STycho Nightingale int 424f0c8263eSNeel Natu vatpit_nmisc_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, 425d6aa08c3STycho Nightingale uint32_t *eax) 42679d6ca33STycho Nightingale { 42779d6ca33STycho Nightingale struct vatpit *vatpit; 42879d6ca33STycho Nightingale 42979d6ca33STycho Nightingale vatpit = vm_atpit(vm); 43079d6ca33STycho Nightingale 431d6aa08c3STycho Nightingale if (in) { 43279d6ca33STycho Nightingale VATPIT_LOCK(vatpit); 43379d6ca33STycho Nightingale if (vatpit_get_out(vatpit, 2)) 434d6aa08c3STycho Nightingale *eax = TMR2_OUT_STS; 43579d6ca33STycho Nightingale else 436d6aa08c3STycho Nightingale *eax = 0; 43779d6ca33STycho Nightingale 43879d6ca33STycho Nightingale VATPIT_UNLOCK(vatpit); 43979d6ca33STycho Nightingale } 44079d6ca33STycho Nightingale 44179d6ca33STycho Nightingale return (0); 44279d6ca33STycho Nightingale } 44379d6ca33STycho Nightingale 444e883c9bbSTycho Nightingale struct vatpit * 445e883c9bbSTycho Nightingale vatpit_init(struct vm *vm) 446e883c9bbSTycho Nightingale { 447e883c9bbSTycho Nightingale struct vatpit *vatpit; 448e883c9bbSTycho Nightingale struct vatpit_callout_arg *arg; 449e883c9bbSTycho Nightingale int i; 450e883c9bbSTycho Nightingale 451e883c9bbSTycho Nightingale vatpit = malloc(sizeof(struct vatpit), M_VATPIT, M_WAITOK | M_ZERO); 452e883c9bbSTycho Nightingale vatpit->vm = vm; 453e883c9bbSTycho Nightingale 454e883c9bbSTycho Nightingale mtx_init(&vatpit->mtx, "vatpit lock", NULL, MTX_SPIN); 455e883c9bbSTycho Nightingale 45687c39157SJohn Baldwin FREQ2BT(PIT_8254_FREQ, &vatpit->freq_bt); 457e883c9bbSTycho Nightingale 458e883c9bbSTycho Nightingale for (i = 0; i < 3; i++) { 459fd90e2edSJung-uk Kim callout_init(&vatpit->channel[i].callout, 1); 460e883c9bbSTycho Nightingale arg = &vatpit->channel[i].callout_arg; 461e883c9bbSTycho Nightingale arg->vatpit = vatpit; 462e883c9bbSTycho Nightingale arg->channel_num = i; 463e883c9bbSTycho Nightingale } 464e883c9bbSTycho Nightingale 465e883c9bbSTycho Nightingale return (vatpit); 466e883c9bbSTycho Nightingale } 467e883c9bbSTycho Nightingale 468e883c9bbSTycho Nightingale void 469e883c9bbSTycho Nightingale vatpit_cleanup(struct vatpit *vatpit) 470e883c9bbSTycho Nightingale { 471e883c9bbSTycho Nightingale int i; 472e883c9bbSTycho Nightingale 473e883c9bbSTycho Nightingale for (i = 0; i < 3; i++) 474e883c9bbSTycho Nightingale callout_drain(&vatpit->channel[i].callout); 475e883c9bbSTycho Nightingale 476e883c9bbSTycho Nightingale free(vatpit, M_VATPIT); 477e883c9bbSTycho Nightingale } 478*483d953aSJohn Baldwin 479*483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 480*483d953aSJohn Baldwin int 481*483d953aSJohn Baldwin vatpit_snapshot(struct vatpit *vatpit, struct vm_snapshot_meta *meta) 482*483d953aSJohn Baldwin { 483*483d953aSJohn Baldwin int ret; 484*483d953aSJohn Baldwin int i; 485*483d953aSJohn Baldwin struct channel *channel; 486*483d953aSJohn Baldwin 487*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vatpit->freq_bt.sec, meta, ret, done); 488*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vatpit->freq_bt.frac, meta, ret, done); 489*483d953aSJohn Baldwin 490*483d953aSJohn Baldwin /* properly restore timers; they will NOT work currently */ 491*483d953aSJohn Baldwin printf("%s: snapshot restore does not reset timers!\r\n", __func__); 492*483d953aSJohn Baldwin 493*483d953aSJohn Baldwin for (i = 0; i < nitems(vatpit->channel); i++) { 494*483d953aSJohn Baldwin channel = &vatpit->channel[i]; 495*483d953aSJohn Baldwin 496*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->mode, meta, ret, done); 497*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->initial, meta, ret, done); 498*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->now_bt.sec, meta, ret, done); 499*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->now_bt.frac, meta, ret, done); 500*483d953aSJohn Baldwin SNAPSHOT_BUF_OR_LEAVE(channel->cr, sizeof(channel->cr), 501*483d953aSJohn Baldwin meta, ret, done); 502*483d953aSJohn Baldwin SNAPSHOT_BUF_OR_LEAVE(channel->ol, sizeof(channel->ol), 503*483d953aSJohn Baldwin meta, ret, done); 504*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->slatched, meta, ret, done); 505*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->status, meta, ret, done); 506*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->crbyte, meta, ret, done); 507*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->frbyte, meta, ret, done); 508*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->callout_bt.sec, meta, ret, done); 509*483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->callout_bt.frac, meta, ret, 510*483d953aSJohn Baldwin done); 511*483d953aSJohn Baldwin } 512*483d953aSJohn Baldwin 513*483d953aSJohn Baldwin done: 514*483d953aSJohn Baldwin return (ret); 515*483d953aSJohn Baldwin } 516*483d953aSJohn Baldwin #endif 517