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 32483d953aSJohn Baldwin #include "opt_bhyve_snapshot.h" 33483d953aSJohn 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> 44483d953aSJohn 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 struct channel { 82e883c9bbSTycho Nightingale int mode; 83e883c9bbSTycho Nightingale uint16_t initial; /* initial counter value */ 8487c39157SJohn Baldwin struct bintime now_bt; /* uptime when counter was loaded */ 85e883c9bbSTycho Nightingale uint8_t cr[2]; 86e883c9bbSTycho Nightingale uint8_t ol[2]; 87c46ff7faSTycho Nightingale bool slatched; /* status latched */ 88c46ff7faSTycho Nightingale uint8_t status; 89e883c9bbSTycho Nightingale int crbyte; 90e883c9bbSTycho Nightingale int olbyte; 91e883c9bbSTycho Nightingale int frbyte; 92e883c9bbSTycho Nightingale struct callout callout; 9387c39157SJohn Baldwin struct bintime callout_bt; /* target time */ 94e883c9bbSTycho Nightingale struct vatpit_callout_arg callout_arg; 95e883c9bbSTycho Nightingale }; 96e883c9bbSTycho Nightingale 97e883c9bbSTycho Nightingale struct vatpit { 98e883c9bbSTycho Nightingale struct vm *vm; 99e883c9bbSTycho Nightingale struct mtx mtx; 100e883c9bbSTycho Nightingale 10187c39157SJohn Baldwin struct bintime freq_bt; 102e883c9bbSTycho Nightingale 103e883c9bbSTycho Nightingale struct channel channel[3]; 104e883c9bbSTycho Nightingale }; 105e883c9bbSTycho Nightingale 106e883c9bbSTycho Nightingale static void pit_timer_start_cntr0(struct vatpit *vatpit); 107e883c9bbSTycho Nightingale 10887c39157SJohn Baldwin static uint64_t 10987c39157SJohn Baldwin vatpit_delta_ticks(struct vatpit *vatpit, struct channel *c) 11087c39157SJohn Baldwin { 11187c39157SJohn Baldwin struct bintime delta; 11287c39157SJohn Baldwin uint64_t result; 11387c39157SJohn Baldwin 11487c39157SJohn Baldwin binuptime(&delta); 11587c39157SJohn Baldwin bintime_sub(&delta, &c->now_bt); 11687c39157SJohn Baldwin 11787c39157SJohn Baldwin result = delta.sec * PIT_8254_FREQ; 11887c39157SJohn Baldwin result += delta.frac / vatpit->freq_bt.frac; 11987c39157SJohn Baldwin 12087c39157SJohn Baldwin return (result); 12187c39157SJohn Baldwin } 12287c39157SJohn Baldwin 12379d6ca33STycho Nightingale static int 12479d6ca33STycho Nightingale vatpit_get_out(struct vatpit *vatpit, int channel) 12579d6ca33STycho Nightingale { 12679d6ca33STycho Nightingale struct channel *c; 12787c39157SJohn Baldwin uint64_t delta_ticks; 12879d6ca33STycho Nightingale int out; 12979d6ca33STycho Nightingale 13079d6ca33STycho Nightingale c = &vatpit->channel[channel]; 13179d6ca33STycho Nightingale 13279d6ca33STycho Nightingale switch (c->mode) { 13379d6ca33STycho Nightingale case TIMER_INTTC: 13487c39157SJohn Baldwin delta_ticks = vatpit_delta_ticks(vatpit, c); 13587c39157SJohn Baldwin out = (delta_ticks >= c->initial); 13679d6ca33STycho Nightingale break; 13779d6ca33STycho Nightingale default: 13879d6ca33STycho Nightingale out = 0; 13979d6ca33STycho Nightingale break; 14079d6ca33STycho Nightingale } 14179d6ca33STycho Nightingale 14279d6ca33STycho Nightingale return (out); 14379d6ca33STycho Nightingale } 14479d6ca33STycho Nightingale 145e883c9bbSTycho Nightingale static void 146e883c9bbSTycho Nightingale vatpit_callout_handler(void *a) 147e883c9bbSTycho Nightingale { 148e883c9bbSTycho Nightingale struct vatpit_callout_arg *arg = a; 149e883c9bbSTycho Nightingale struct vatpit *vatpit; 150e883c9bbSTycho Nightingale struct callout *callout; 151e883c9bbSTycho Nightingale struct channel *c; 152e883c9bbSTycho Nightingale 153e883c9bbSTycho Nightingale vatpit = arg->vatpit; 154e883c9bbSTycho Nightingale c = &vatpit->channel[arg->channel_num]; 155e883c9bbSTycho Nightingale callout = &c->callout; 156e883c9bbSTycho Nightingale 15779d6ca33STycho Nightingale VM_CTR1(vatpit->vm, "atpit t%d fired", arg->channel_num); 158e883c9bbSTycho Nightingale 159e883c9bbSTycho Nightingale VATPIT_LOCK(vatpit); 160e883c9bbSTycho Nightingale 161e883c9bbSTycho Nightingale if (callout_pending(callout)) /* callout was reset */ 162e883c9bbSTycho Nightingale goto done; 163e883c9bbSTycho Nightingale 164e883c9bbSTycho Nightingale if (!callout_active(callout)) /* callout was stopped */ 165e883c9bbSTycho Nightingale goto done; 166e883c9bbSTycho Nightingale 167e883c9bbSTycho Nightingale callout_deactivate(callout); 168e883c9bbSTycho Nightingale 169e883c9bbSTycho Nightingale if (c->mode == TIMER_RATEGEN) { 170e883c9bbSTycho Nightingale pit_timer_start_cntr0(vatpit); 171e883c9bbSTycho Nightingale } 172e883c9bbSTycho Nightingale 173e883c9bbSTycho Nightingale vatpic_pulse_irq(vatpit->vm, 0); 174e883c9bbSTycho Nightingale vioapic_pulse_irq(vatpit->vm, 2); 175e883c9bbSTycho Nightingale 176e883c9bbSTycho Nightingale done: 177e883c9bbSTycho Nightingale VATPIT_UNLOCK(vatpit); 178e883c9bbSTycho Nightingale return; 179e883c9bbSTycho Nightingale } 180e883c9bbSTycho Nightingale 181e883c9bbSTycho Nightingale static void 182e883c9bbSTycho Nightingale pit_timer_start_cntr0(struct vatpit *vatpit) 183e883c9bbSTycho Nightingale { 184e883c9bbSTycho Nightingale struct channel *c; 18587c39157SJohn Baldwin struct bintime now, delta; 18687c39157SJohn Baldwin sbintime_t precision; 187e883c9bbSTycho Nightingale 188e883c9bbSTycho Nightingale c = &vatpit->channel[0]; 189e883c9bbSTycho Nightingale if (c->initial != 0) { 19087c39157SJohn Baldwin delta.sec = 0; 19187c39157SJohn Baldwin delta.frac = vatpit->freq_bt.frac * c->initial; 19287c39157SJohn Baldwin bintime_add(&c->callout_bt, &delta); 19387c39157SJohn Baldwin precision = bttosbt(delta) >> tc_precexp; 194e883c9bbSTycho Nightingale 19579d6ca33STycho Nightingale /* 19687c39157SJohn Baldwin * Reset 'callout_bt' if the time that the callout 19779d6ca33STycho Nightingale * was supposed to fire is more than 'c->initial' 19879d6ca33STycho Nightingale * ticks in the past. 19979d6ca33STycho Nightingale */ 20087c39157SJohn Baldwin binuptime(&now); 20187c39157SJohn Baldwin if (bintime_cmp(&c->callout_bt, &now, <)) { 20287c39157SJohn Baldwin c->callout_bt = now; 20387c39157SJohn Baldwin bintime_add(&c->callout_bt, &delta); 20487c39157SJohn Baldwin } 20579d6ca33STycho Nightingale 20687c39157SJohn Baldwin callout_reset_sbt(&c->callout, bttosbt(c->callout_bt), 207e883c9bbSTycho Nightingale precision, vatpit_callout_handler, &c->callout_arg, 208e883c9bbSTycho Nightingale C_ABSOLUTE); 209e883c9bbSTycho Nightingale } 210e883c9bbSTycho Nightingale } 211e883c9bbSTycho Nightingale 212e883c9bbSTycho Nightingale static uint16_t 213e883c9bbSTycho Nightingale pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch) 214e883c9bbSTycho Nightingale { 215e883c9bbSTycho Nightingale uint16_t lval; 21687c39157SJohn Baldwin uint64_t delta_ticks; 217e883c9bbSTycho Nightingale 218e883c9bbSTycho Nightingale /* cannot latch a new value until the old one has been consumed */ 219e883c9bbSTycho Nightingale if (latch && c->olbyte != 0) 220e883c9bbSTycho Nightingale return (0); 221e883c9bbSTycho Nightingale 222e883c9bbSTycho Nightingale if (c->initial == 0) { 223e883c9bbSTycho Nightingale /* 224e883c9bbSTycho Nightingale * This is possibly an o/s bug - reading the value of 225e883c9bbSTycho Nightingale * the timer without having set up the initial value. 226e883c9bbSTycho Nightingale * 227e883c9bbSTycho Nightingale * The original user-space version of this code set 228e883c9bbSTycho Nightingale * the timer to 100hz in this condition; do the same 229e883c9bbSTycho Nightingale * here. 230e883c9bbSTycho Nightingale */ 231e883c9bbSTycho Nightingale c->initial = TIMER_DIV(PIT_8254_FREQ, 100); 23287c39157SJohn Baldwin binuptime(&c->now_bt); 233c46ff7faSTycho Nightingale c->status &= ~TIMER_STS_NULLCNT; 234e883c9bbSTycho Nightingale } 235e883c9bbSTycho Nightingale 23687c39157SJohn Baldwin delta_ticks = vatpit_delta_ticks(vatpit, c); 237e883c9bbSTycho Nightingale lval = c->initial - delta_ticks % c->initial; 238e883c9bbSTycho Nightingale 239e883c9bbSTycho Nightingale if (latch) { 240e883c9bbSTycho Nightingale c->olbyte = 2; 241e883c9bbSTycho Nightingale c->ol[1] = lval; /* LSB */ 242e883c9bbSTycho Nightingale c->ol[0] = lval >> 8; /* MSB */ 243e883c9bbSTycho Nightingale } 244e883c9bbSTycho Nightingale 245e883c9bbSTycho Nightingale return (lval); 246e883c9bbSTycho Nightingale } 247e883c9bbSTycho Nightingale 248e883c9bbSTycho Nightingale static int 249c46ff7faSTycho Nightingale pit_readback1(struct vatpit *vatpit, int channel, uint8_t cmd) 250c46ff7faSTycho Nightingale { 251c46ff7faSTycho Nightingale struct channel *c; 252c46ff7faSTycho Nightingale 253c46ff7faSTycho Nightingale c = &vatpit->channel[channel]; 254c46ff7faSTycho Nightingale 255c46ff7faSTycho Nightingale /* 256c46ff7faSTycho Nightingale * Latch the count/status of the timer if not already latched. 257c46ff7faSTycho Nightingale * N.B. that the count/status latch-select bits are active-low. 258c46ff7faSTycho Nightingale */ 259c46ff7faSTycho Nightingale if (!(cmd & TIMER_RB_LCTR) && !c->olbyte) { 260c46ff7faSTycho Nightingale (void) pit_update_counter(vatpit, c, true); 261c46ff7faSTycho Nightingale } 262c46ff7faSTycho Nightingale 263c46ff7faSTycho Nightingale if (!(cmd & TIMER_RB_LSTATUS) && !c->slatched) { 264c46ff7faSTycho Nightingale c->slatched = true; 265c46ff7faSTycho Nightingale /* 266c46ff7faSTycho Nightingale * For mode 0, see if the elapsed time is greater 267c46ff7faSTycho Nightingale * than the initial value - this results in the 268c46ff7faSTycho Nightingale * output pin being set to 1 in the status byte. 269c46ff7faSTycho Nightingale */ 270c46ff7faSTycho Nightingale if (c->mode == TIMER_INTTC && vatpit_get_out(vatpit, channel)) 271c46ff7faSTycho Nightingale c->status |= TIMER_STS_OUT; 272c46ff7faSTycho Nightingale else 273c46ff7faSTycho Nightingale c->status &= ~TIMER_STS_OUT; 274c46ff7faSTycho Nightingale } 275c46ff7faSTycho Nightingale 276c46ff7faSTycho Nightingale return (0); 277c46ff7faSTycho Nightingale } 278c46ff7faSTycho Nightingale 279c46ff7faSTycho Nightingale static int 280c46ff7faSTycho Nightingale pit_readback(struct vatpit *vatpit, uint8_t cmd) 281c46ff7faSTycho Nightingale { 282c46ff7faSTycho Nightingale int error; 283c46ff7faSTycho Nightingale 284c46ff7faSTycho Nightingale /* 285c46ff7faSTycho Nightingale * The readback command can apply to all timers. 286c46ff7faSTycho Nightingale */ 287c46ff7faSTycho Nightingale error = 0; 288c46ff7faSTycho Nightingale if (cmd & TIMER_RB_CTR_0) 289c46ff7faSTycho Nightingale error = pit_readback1(vatpit, 0, cmd); 290c46ff7faSTycho Nightingale if (!error && cmd & TIMER_RB_CTR_1) 291c46ff7faSTycho Nightingale error = pit_readback1(vatpit, 1, cmd); 292c46ff7faSTycho Nightingale if (!error && cmd & TIMER_RB_CTR_2) 293c46ff7faSTycho Nightingale error = pit_readback1(vatpit, 2, cmd); 294c46ff7faSTycho Nightingale 295c46ff7faSTycho Nightingale return (error); 296c46ff7faSTycho Nightingale } 297c46ff7faSTycho Nightingale 298c46ff7faSTycho Nightingale static int 299e883c9bbSTycho Nightingale vatpit_update_mode(struct vatpit *vatpit, uint8_t val) 300e883c9bbSTycho Nightingale { 301e883c9bbSTycho Nightingale struct channel *c; 302e883c9bbSTycho Nightingale int sel, rw, mode; 303e883c9bbSTycho Nightingale 304e883c9bbSTycho Nightingale sel = val & TIMER_SEL_MASK; 305e883c9bbSTycho Nightingale rw = val & TIMER_RW_MASK; 306e883c9bbSTycho Nightingale mode = val & TIMER_MODE_MASK; 307e883c9bbSTycho Nightingale 308e883c9bbSTycho Nightingale if (sel == TIMER_SEL_READBACK) 309c46ff7faSTycho Nightingale return (pit_readback(vatpit, val)); 310e883c9bbSTycho Nightingale 311e883c9bbSTycho Nightingale if (rw != TIMER_LATCH && rw != TIMER_16BIT) 312e883c9bbSTycho Nightingale return (-1); 313e883c9bbSTycho Nightingale 314e883c9bbSTycho Nightingale if (rw != TIMER_LATCH) { 315e883c9bbSTycho Nightingale /* 316e883c9bbSTycho Nightingale * Counter mode is not affected when issuing a 317e883c9bbSTycho Nightingale * latch command. 318e883c9bbSTycho Nightingale */ 319e883c9bbSTycho Nightingale if (mode != TIMER_INTTC && 320e883c9bbSTycho Nightingale mode != TIMER_RATEGEN && 321e883c9bbSTycho Nightingale mode != TIMER_SQWAVE && 322e883c9bbSTycho Nightingale mode != TIMER_SWSTROBE) 323e883c9bbSTycho Nightingale return (-1); 324e883c9bbSTycho Nightingale } 325e883c9bbSTycho Nightingale 326e883c9bbSTycho Nightingale c = &vatpit->channel[sel >> 6]; 327e883c9bbSTycho Nightingale if (rw == TIMER_LATCH) 328e883c9bbSTycho Nightingale pit_update_counter(vatpit, c, true); 329e883c9bbSTycho Nightingale else { 330e883c9bbSTycho Nightingale c->mode = mode; 331e883c9bbSTycho Nightingale c->olbyte = 0; /* reset latch after reprogramming */ 332c46ff7faSTycho Nightingale c->status |= TIMER_STS_NULLCNT; 333e883c9bbSTycho Nightingale } 334e883c9bbSTycho Nightingale 335e883c9bbSTycho Nightingale return (0); 336e883c9bbSTycho Nightingale } 337e883c9bbSTycho Nightingale 338e883c9bbSTycho Nightingale int 339*9388bc1eSJohn Baldwin vatpit_handler(struct vm *vm, bool in, int port, int bytes, uint32_t *eax) 340e883c9bbSTycho Nightingale { 341e883c9bbSTycho Nightingale struct vatpit *vatpit; 342e883c9bbSTycho Nightingale struct channel *c; 343e883c9bbSTycho Nightingale uint8_t val; 344e883c9bbSTycho Nightingale int error; 345e883c9bbSTycho Nightingale 346e883c9bbSTycho Nightingale vatpit = vm_atpit(vm); 347e883c9bbSTycho Nightingale 348d6aa08c3STycho Nightingale if (bytes != 1) 349e883c9bbSTycho Nightingale return (-1); 350e883c9bbSTycho Nightingale 351d6aa08c3STycho Nightingale val = *eax; 352e883c9bbSTycho Nightingale 353e883c9bbSTycho Nightingale if (port == TIMER_MODE) { 354d6aa08c3STycho Nightingale if (in) { 35579d6ca33STycho Nightingale VM_CTR0(vatpit->vm, "vatpit attempt to read mode"); 356e883c9bbSTycho Nightingale return (-1); 357e883c9bbSTycho Nightingale } 358e883c9bbSTycho Nightingale 359e883c9bbSTycho Nightingale VATPIT_LOCK(vatpit); 360e883c9bbSTycho Nightingale error = vatpit_update_mode(vatpit, val); 361e883c9bbSTycho Nightingale VATPIT_UNLOCK(vatpit); 362e883c9bbSTycho Nightingale 363e883c9bbSTycho Nightingale return (error); 364e883c9bbSTycho Nightingale } 365e883c9bbSTycho Nightingale 366e883c9bbSTycho Nightingale /* counter ports */ 367d6aa08c3STycho Nightingale KASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2, 368e883c9bbSTycho Nightingale ("invalid port 0x%x", port)); 369e883c9bbSTycho Nightingale c = &vatpit->channel[port - TIMER_CNTR0]; 370e883c9bbSTycho Nightingale 371e883c9bbSTycho Nightingale VATPIT_LOCK(vatpit); 372c46ff7faSTycho Nightingale if (in && c->slatched) { 373c46ff7faSTycho Nightingale /* 374c46ff7faSTycho Nightingale * Return the status byte if latched 375c46ff7faSTycho Nightingale */ 376c46ff7faSTycho Nightingale *eax = c->status; 377c46ff7faSTycho Nightingale c->slatched = false; 378c46ff7faSTycho Nightingale c->status = 0; 379c46ff7faSTycho Nightingale } else if (in) { 380e883c9bbSTycho Nightingale /* 381e883c9bbSTycho Nightingale * The spec says that once the output latch is completely 382e883c9bbSTycho Nightingale * read it should revert to "following" the counter. Use 383e883c9bbSTycho Nightingale * the free running counter for this case (i.e. Linux 384e883c9bbSTycho Nightingale * TSC calibration). Assuming the access mode is 16-bit, 385e883c9bbSTycho Nightingale * toggle the MSB/LSB bit on each read. 386e883c9bbSTycho Nightingale */ 387e883c9bbSTycho Nightingale if (c->olbyte == 0) { 388e883c9bbSTycho Nightingale uint16_t tmp; 389e883c9bbSTycho Nightingale 390e883c9bbSTycho Nightingale tmp = pit_update_counter(vatpit, c, false); 391e883c9bbSTycho Nightingale if (c->frbyte) 392e883c9bbSTycho Nightingale tmp >>= 8; 393e883c9bbSTycho Nightingale tmp &= 0xff; 394d6aa08c3STycho Nightingale *eax = tmp; 395e883c9bbSTycho Nightingale c->frbyte ^= 1; 396e883c9bbSTycho Nightingale } else 397d6aa08c3STycho Nightingale *eax = c->ol[--c->olbyte]; 398e883c9bbSTycho Nightingale } else { 399d6aa08c3STycho Nightingale c->cr[c->crbyte++] = *eax; 400e883c9bbSTycho Nightingale if (c->crbyte == 2) { 401c46ff7faSTycho Nightingale c->status &= ~TIMER_STS_NULLCNT; 402e883c9bbSTycho Nightingale c->frbyte = 0; 403e883c9bbSTycho Nightingale c->crbyte = 0; 404e883c9bbSTycho Nightingale c->initial = c->cr[0] | (uint16_t)c->cr[1] << 8; 40587c39157SJohn Baldwin binuptime(&c->now_bt); 406e883c9bbSTycho Nightingale /* Start an interval timer for channel 0 */ 407e883c9bbSTycho Nightingale if (port == TIMER_CNTR0) { 40887c39157SJohn Baldwin c->callout_bt = c->now_bt; 409e883c9bbSTycho Nightingale pit_timer_start_cntr0(vatpit); 410e883c9bbSTycho Nightingale } 411e883c9bbSTycho Nightingale if (c->initial == 0) 412e883c9bbSTycho Nightingale c->initial = 0xffff; 413e883c9bbSTycho Nightingale } 414e883c9bbSTycho Nightingale } 415e883c9bbSTycho Nightingale VATPIT_UNLOCK(vatpit); 416e883c9bbSTycho Nightingale 417e883c9bbSTycho Nightingale return (0); 418e883c9bbSTycho Nightingale } 419e883c9bbSTycho Nightingale 42079d6ca33STycho Nightingale int 421*9388bc1eSJohn Baldwin vatpit_nmisc_handler(struct vm *vm, bool in, int port, int bytes, 422d6aa08c3STycho Nightingale uint32_t *eax) 42379d6ca33STycho Nightingale { 42479d6ca33STycho Nightingale struct vatpit *vatpit; 42579d6ca33STycho Nightingale 42679d6ca33STycho Nightingale vatpit = vm_atpit(vm); 42779d6ca33STycho Nightingale 428d6aa08c3STycho Nightingale if (in) { 42979d6ca33STycho Nightingale VATPIT_LOCK(vatpit); 43079d6ca33STycho Nightingale if (vatpit_get_out(vatpit, 2)) 431d6aa08c3STycho Nightingale *eax = TMR2_OUT_STS; 43279d6ca33STycho Nightingale else 433d6aa08c3STycho Nightingale *eax = 0; 43479d6ca33STycho Nightingale 43579d6ca33STycho Nightingale VATPIT_UNLOCK(vatpit); 43679d6ca33STycho Nightingale } 43779d6ca33STycho Nightingale 43879d6ca33STycho Nightingale return (0); 43979d6ca33STycho Nightingale } 44079d6ca33STycho Nightingale 441e883c9bbSTycho Nightingale struct vatpit * 442e883c9bbSTycho Nightingale vatpit_init(struct vm *vm) 443e883c9bbSTycho Nightingale { 444e883c9bbSTycho Nightingale struct vatpit *vatpit; 445e883c9bbSTycho Nightingale struct vatpit_callout_arg *arg; 446e883c9bbSTycho Nightingale int i; 447e883c9bbSTycho Nightingale 448e883c9bbSTycho Nightingale vatpit = malloc(sizeof(struct vatpit), M_VATPIT, M_WAITOK | M_ZERO); 449e883c9bbSTycho Nightingale vatpit->vm = vm; 450e883c9bbSTycho Nightingale 451e883c9bbSTycho Nightingale mtx_init(&vatpit->mtx, "vatpit lock", NULL, MTX_SPIN); 452e883c9bbSTycho Nightingale 45387c39157SJohn Baldwin FREQ2BT(PIT_8254_FREQ, &vatpit->freq_bt); 454e883c9bbSTycho Nightingale 455e883c9bbSTycho Nightingale for (i = 0; i < 3; i++) { 456fd90e2edSJung-uk Kim callout_init(&vatpit->channel[i].callout, 1); 457e883c9bbSTycho Nightingale arg = &vatpit->channel[i].callout_arg; 458e883c9bbSTycho Nightingale arg->vatpit = vatpit; 459e883c9bbSTycho Nightingale arg->channel_num = i; 460e883c9bbSTycho Nightingale } 461e883c9bbSTycho Nightingale 462e883c9bbSTycho Nightingale return (vatpit); 463e883c9bbSTycho Nightingale } 464e883c9bbSTycho Nightingale 465e883c9bbSTycho Nightingale void 466e883c9bbSTycho Nightingale vatpit_cleanup(struct vatpit *vatpit) 467e883c9bbSTycho Nightingale { 468e883c9bbSTycho Nightingale int i; 469e883c9bbSTycho Nightingale 470e883c9bbSTycho Nightingale for (i = 0; i < 3; i++) 471e883c9bbSTycho Nightingale callout_drain(&vatpit->channel[i].callout); 472e883c9bbSTycho Nightingale 473e883c9bbSTycho Nightingale free(vatpit, M_VATPIT); 474e883c9bbSTycho Nightingale } 475483d953aSJohn Baldwin 476483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 477483d953aSJohn Baldwin int 478483d953aSJohn Baldwin vatpit_snapshot(struct vatpit *vatpit, struct vm_snapshot_meta *meta) 479483d953aSJohn Baldwin { 480483d953aSJohn Baldwin int ret; 481483d953aSJohn Baldwin int i; 482483d953aSJohn Baldwin struct channel *channel; 483483d953aSJohn Baldwin 484483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vatpit->freq_bt.sec, meta, ret, done); 485483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vatpit->freq_bt.frac, meta, ret, done); 486483d953aSJohn Baldwin 487483d953aSJohn Baldwin /* properly restore timers; they will NOT work currently */ 488483d953aSJohn Baldwin printf("%s: snapshot restore does not reset timers!\r\n", __func__); 489483d953aSJohn Baldwin 490483d953aSJohn Baldwin for (i = 0; i < nitems(vatpit->channel); i++) { 491483d953aSJohn Baldwin channel = &vatpit->channel[i]; 492483d953aSJohn Baldwin 493483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->mode, meta, ret, done); 494483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->initial, meta, ret, done); 495483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->now_bt.sec, meta, ret, done); 496483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->now_bt.frac, meta, ret, done); 497483d953aSJohn Baldwin SNAPSHOT_BUF_OR_LEAVE(channel->cr, sizeof(channel->cr), 498483d953aSJohn Baldwin meta, ret, done); 499483d953aSJohn Baldwin SNAPSHOT_BUF_OR_LEAVE(channel->ol, sizeof(channel->ol), 500483d953aSJohn Baldwin meta, ret, done); 501483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->slatched, meta, ret, done); 502483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->status, meta, ret, done); 503483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->crbyte, meta, ret, done); 504483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->frbyte, meta, ret, done); 505483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->callout_bt.sec, meta, ret, done); 506483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(channel->callout_bt.frac, meta, ret, 507483d953aSJohn Baldwin done); 508483d953aSJohn Baldwin } 509483d953aSJohn Baldwin 510483d953aSJohn Baldwin done: 511483d953aSJohn Baldwin return (ret); 512483d953aSJohn Baldwin } 513483d953aSJohn Baldwin #endif 514