1366f6083SPeter Grehan /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3c49761ddSPedro F. Giffuni * 4366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc. 5366f6083SPeter Grehan * All rights reserved. 66a1e1c2cSJohn Baldwin * Copyright (c) 2019 Joyent, Inc. 7366f6083SPeter Grehan * 8366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without 9366f6083SPeter Grehan * modification, are permitted provided that the following conditions 10366f6083SPeter Grehan * are met: 11366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright 12366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer. 13366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 14366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the 15366f6083SPeter Grehan * documentation and/or other materials provided with the distribution. 16366f6083SPeter Grehan * 17366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27366f6083SPeter Grehan * SUCH DAMAGE. 28366f6083SPeter Grehan */ 29366f6083SPeter Grehan 30366f6083SPeter Grehan #include <sys/cdefs.h> 31483d953aSJohn Baldwin #include "opt_bhyve_snapshot.h" 32483d953aSJohn Baldwin 33366f6083SPeter Grehan #include <sys/param.h> 34fb03ca4eSNeel Natu #include <sys/lock.h> 35366f6083SPeter Grehan #include <sys/kernel.h> 36366f6083SPeter Grehan #include <sys/malloc.h> 37fb03ca4eSNeel Natu #include <sys/mutex.h> 38366f6083SPeter Grehan #include <sys/systm.h> 39a5615c90SPeter Grehan #include <sys/smp.h> 40366f6083SPeter Grehan 412d3a73edSNeel Natu #include <x86/specialreg.h> 4234a6b2d6SJohn Baldwin #include <x86/apicreg.h> 43366f6083SPeter Grehan 44de5ea6b6SNeel Natu #include <machine/clock.h> 45de5ea6b6SNeel Natu #include <machine/smp.h> 46366f6083SPeter Grehan #include <machine/vmm.h> 47483d953aSJohn Baldwin #include <machine/vmm_snapshot.h> 48366f6083SPeter Grehan 49*3ccb0233SMark Johnston #include <dev/vmm/vmm_ktr.h> 50*3ccb0233SMark Johnston 51366f6083SPeter Grehan #include "vmm_lapic.h" 52de5ea6b6SNeel Natu #include "vmm_stat.h" 53de5ea6b6SNeel Natu 54366f6083SPeter Grehan #include "vlapic.h" 55de5ea6b6SNeel Natu #include "vlapic_priv.h" 56b5b28fc9SNeel Natu #include "vioapic.h" 57366f6083SPeter Grehan 58366f6083SPeter Grehan #define PRIO(x) ((x) >> 4) 59366f6083SPeter Grehan 60f56801d6SCorvin Köhne #define VLAPIC_VERSION (0x14) 61366f6083SPeter Grehan 62a2da7af6SNeel Natu #define x2apic(vlapic) (((vlapic)->msr_apicbase & APICBASE_X2APIC) ? 1 : 0) 632d3a73edSNeel Natu 64fb03ca4eSNeel Natu /* 65fb03ca4eSNeel Natu * The 'vlapic->timer_mtx' is used to provide mutual exclusion between the 66fafe8844SNeel Natu * vlapic_callout_handler() and vcpu accesses to: 67fafe8844SNeel Natu * - timer_freq_bt, timer_period_bt, timer_fire_bt 68fb03ca4eSNeel Natu * - timer LVT register 69fb03ca4eSNeel Natu */ 70becd9849SNeel Natu #define VLAPIC_TIMER_LOCK(vlapic) mtx_lock_spin(&((vlapic)->timer_mtx)) 71becd9849SNeel Natu #define VLAPIC_TIMER_UNLOCK(vlapic) mtx_unlock_spin(&((vlapic)->timer_mtx)) 72fb03ca4eSNeel Natu #define VLAPIC_TIMER_LOCKED(vlapic) mtx_owned(&((vlapic)->timer_mtx)) 73fb03ca4eSNeel Natu 74c5d216b7SNeel Natu /* 75c5d216b7SNeel Natu * APIC timer frequency: 76c5d216b7SNeel Natu * - arbitrary but chosen to be in the ballpark of contemporary hardware. 77c5d216b7SNeel Natu * - power-of-two to avoid loss of precision when converted to a bintime. 78c5d216b7SNeel Natu */ 79c5d216b7SNeel Natu #define VLAPIC_BUS_FREQ (128 * 1024 * 1024) 802e25737aSNeel Natu 816a1e1c2cSJohn Baldwin static void vlapic_set_error(struct vlapic *, uint32_t, bool); 824c812fe6SMark Johnston static void vlapic_callout_handler(void *arg); 830bda8d3eSCorvin Köhne static void vlapic_reset(struct vlapic *vlapic); 846a1e1c2cSJohn Baldwin 854f8be175SNeel Natu static __inline uint32_t 864f8be175SNeel Natu vlapic_get_id(struct vlapic *vlapic) 874f8be175SNeel Natu { 884f8be175SNeel Natu 894f8be175SNeel Natu if (x2apic(vlapic)) 904f8be175SNeel Natu return (vlapic->vcpuid); 914f8be175SNeel Natu else 924f8be175SNeel Natu return (vlapic->vcpuid << 24); 934f8be175SNeel Natu } 944f8be175SNeel Natu 953f0ddc7cSNeel Natu static uint32_t 963f0ddc7cSNeel Natu x2apic_ldr(struct vlapic *vlapic) 974f8be175SNeel Natu { 984f8be175SNeel Natu int apicid; 994f8be175SNeel Natu uint32_t ldr; 1004f8be175SNeel Natu 1014f8be175SNeel Natu apicid = vlapic_get_id(vlapic); 1024f8be175SNeel Natu ldr = 1 << (apicid & 0xf); 1034f8be175SNeel Natu ldr |= (apicid & 0xffff0) << 12; 1044f8be175SNeel Natu return (ldr); 1054f8be175SNeel Natu } 1064f8be175SNeel Natu 1073f0ddc7cSNeel Natu void 1083f0ddc7cSNeel Natu vlapic_dfr_write_handler(struct vlapic *vlapic) 1094f8be175SNeel Natu { 1104f8be175SNeel Natu struct LAPIC *lapic; 1114f8be175SNeel Natu 112de5ea6b6SNeel Natu lapic = vlapic->apic_page; 1134f8be175SNeel Natu if (x2apic(vlapic)) { 1143f0ddc7cSNeel Natu VM_CTR1(vlapic->vm, "ignoring write to DFR in x2apic mode: %#x", 1153f0ddc7cSNeel Natu lapic->dfr); 1163f0ddc7cSNeel Natu lapic->dfr = 0; 1174f8be175SNeel Natu return; 1184f8be175SNeel Natu } 1194f8be175SNeel Natu 1203f0ddc7cSNeel Natu lapic->dfr &= APIC_DFR_MODEL_MASK; 1213f0ddc7cSNeel Natu lapic->dfr |= APIC_DFR_RESERVED; 1223f0ddc7cSNeel Natu 1233f0ddc7cSNeel Natu if ((lapic->dfr & APIC_DFR_MODEL_MASK) == APIC_DFR_MODEL_FLAT) 1244f8be175SNeel Natu VLAPIC_CTR0(vlapic, "vlapic DFR in Flat Model"); 1253f0ddc7cSNeel Natu else if ((lapic->dfr & APIC_DFR_MODEL_MASK) == APIC_DFR_MODEL_CLUSTER) 1264f8be175SNeel Natu VLAPIC_CTR0(vlapic, "vlapic DFR in Cluster Model"); 1274f8be175SNeel Natu else 1283f0ddc7cSNeel Natu VLAPIC_CTR1(vlapic, "DFR in Unknown Model %#x", lapic->dfr); 1294f8be175SNeel Natu } 1304f8be175SNeel Natu 1313f0ddc7cSNeel Natu void 1323f0ddc7cSNeel Natu vlapic_ldr_write_handler(struct vlapic *vlapic) 1334f8be175SNeel Natu { 1344f8be175SNeel Natu struct LAPIC *lapic; 1354f8be175SNeel Natu 1363f0ddc7cSNeel Natu lapic = vlapic->apic_page; 1373f0ddc7cSNeel Natu 1384f8be175SNeel Natu /* LDR is read-only in x2apic mode */ 1394f8be175SNeel Natu if (x2apic(vlapic)) { 1403f0ddc7cSNeel Natu VLAPIC_CTR1(vlapic, "ignoring write to LDR in x2apic mode: %#x", 1413f0ddc7cSNeel Natu lapic->ldr); 1423f0ddc7cSNeel Natu lapic->ldr = x2apic_ldr(vlapic); 1433f0ddc7cSNeel Natu } else { 1443f0ddc7cSNeel Natu lapic->ldr &= ~APIC_LDR_RESERVED; 1453f0ddc7cSNeel Natu VLAPIC_CTR1(vlapic, "vlapic LDR set to %#x", lapic->ldr); 1463f0ddc7cSNeel Natu } 1474f8be175SNeel Natu } 1484f8be175SNeel Natu 1493f0ddc7cSNeel Natu void 1503f0ddc7cSNeel Natu vlapic_id_write_handler(struct vlapic *vlapic) 1513f0ddc7cSNeel Natu { 1523f0ddc7cSNeel Natu struct LAPIC *lapic; 1533f0ddc7cSNeel Natu 1543f0ddc7cSNeel Natu /* 1553f0ddc7cSNeel Natu * We don't allow the ID register to be modified so reset it back to 1563f0ddc7cSNeel Natu * its default value. 1573f0ddc7cSNeel Natu */ 158de5ea6b6SNeel Natu lapic = vlapic->apic_page; 1593f0ddc7cSNeel Natu lapic->id = vlapic_get_id(vlapic); 1604f8be175SNeel Natu } 1614f8be175SNeel Natu 1622e25737aSNeel Natu static int 1632e25737aSNeel Natu vlapic_timer_divisor(uint32_t dcr) 1642e25737aSNeel Natu { 1652e25737aSNeel Natu switch (dcr & 0xB) { 166117e8f37SPeter Grehan case APIC_TDCR_1: 167117e8f37SPeter Grehan return (1); 1682e25737aSNeel Natu case APIC_TDCR_2: 1692e25737aSNeel Natu return (2); 1702e25737aSNeel Natu case APIC_TDCR_4: 1712e25737aSNeel Natu return (4); 1722e25737aSNeel Natu case APIC_TDCR_8: 1732e25737aSNeel Natu return (8); 1742e25737aSNeel Natu case APIC_TDCR_16: 1752e25737aSNeel Natu return (16); 1762e25737aSNeel Natu case APIC_TDCR_32: 1772e25737aSNeel Natu return (32); 1782e25737aSNeel Natu case APIC_TDCR_64: 1792e25737aSNeel Natu return (64); 1802e25737aSNeel Natu case APIC_TDCR_128: 1812e25737aSNeel Natu return (128); 1822e25737aSNeel Natu default: 1832e25737aSNeel Natu panic("vlapic_timer_divisor: invalid dcr 0x%08x", dcr); 1842e25737aSNeel Natu } 1852e25737aSNeel Natu } 1862e25737aSNeel Natu 187366f6083SPeter Grehan #if 0 188366f6083SPeter Grehan static inline void 189366f6083SPeter Grehan vlapic_dump_lvt(uint32_t offset, uint32_t *lvt) 190366f6083SPeter Grehan { 191366f6083SPeter Grehan printf("Offset %x: lvt %08x (V:%02x DS:%x M:%x)\n", offset, 192366f6083SPeter Grehan *lvt, *lvt & APIC_LVTT_VECTOR, *lvt & APIC_LVTT_DS, 193366f6083SPeter Grehan *lvt & APIC_LVTT_M); 194366f6083SPeter Grehan } 195366f6083SPeter Grehan #endif 196366f6083SPeter Grehan 197fb03ca4eSNeel Natu static uint32_t 198366f6083SPeter Grehan vlapic_get_ccr(struct vlapic *vlapic) 199366f6083SPeter Grehan { 200fb03ca4eSNeel Natu struct bintime bt_now, bt_rem; 2012062ce99SRobert Wing struct LAPIC *lapic __diagused; 202fb03ca4eSNeel Natu uint32_t ccr; 203fb03ca4eSNeel Natu 204fb03ca4eSNeel Natu ccr = 0; 205de5ea6b6SNeel Natu lapic = vlapic->apic_page; 206fb03ca4eSNeel Natu 207fb03ca4eSNeel Natu VLAPIC_TIMER_LOCK(vlapic); 208fb03ca4eSNeel Natu if (callout_active(&vlapic->callout)) { 209fb03ca4eSNeel Natu /* 210fb03ca4eSNeel Natu * If the timer is scheduled to expire in the future then 211fb03ca4eSNeel Natu * compute the value of 'ccr' based on the remaining time. 212fb03ca4eSNeel Natu */ 213fb03ca4eSNeel Natu binuptime(&bt_now); 214fb03ca4eSNeel Natu if (bintime_cmp(&vlapic->timer_fire_bt, &bt_now, >)) { 215fb03ca4eSNeel Natu bt_rem = vlapic->timer_fire_bt; 216fb03ca4eSNeel Natu bintime_sub(&bt_rem, &bt_now); 217fb03ca4eSNeel Natu ccr += bt_rem.sec * BT2FREQ(&vlapic->timer_freq_bt); 218fb03ca4eSNeel Natu ccr += bt_rem.frac / vlapic->timer_freq_bt.frac; 219fb03ca4eSNeel Natu } 220fb03ca4eSNeel Natu } 221fb03ca4eSNeel Natu KASSERT(ccr <= lapic->icr_timer, ("vlapic_get_ccr: invalid ccr %#x, " 222fb03ca4eSNeel Natu "icr_timer is %#x", ccr, lapic->icr_timer)); 223fb03ca4eSNeel Natu VLAPIC_CTR2(vlapic, "vlapic ccr_timer = %#x, icr_timer = %#x", 224fb03ca4eSNeel Natu ccr, lapic->icr_timer); 225fb03ca4eSNeel Natu VLAPIC_TIMER_UNLOCK(vlapic); 226fb03ca4eSNeel Natu return (ccr); 227fb03ca4eSNeel Natu } 228fb03ca4eSNeel Natu 229fafe8844SNeel Natu void 230fafe8844SNeel Natu vlapic_dcr_write_handler(struct vlapic *vlapic) 231fb03ca4eSNeel Natu { 232fb03ca4eSNeel Natu struct LAPIC *lapic; 233fb03ca4eSNeel Natu int divisor; 234fb03ca4eSNeel Natu 235de5ea6b6SNeel Natu lapic = vlapic->apic_page; 236fb03ca4eSNeel Natu VLAPIC_TIMER_LOCK(vlapic); 237fb03ca4eSNeel Natu 238fafe8844SNeel Natu divisor = vlapic_timer_divisor(lapic->dcr_timer); 239fafe8844SNeel Natu VLAPIC_CTR2(vlapic, "vlapic dcr_timer=%#x, divisor=%d", 240fafe8844SNeel Natu lapic->dcr_timer, divisor); 241fb03ca4eSNeel Natu 242fb03ca4eSNeel Natu /* 243fb03ca4eSNeel Natu * Update the timer frequency and the timer period. 244fb03ca4eSNeel Natu * 245fb03ca4eSNeel Natu * XXX changes to the frequency divider will not take effect until 246fb03ca4eSNeel Natu * the timer is reloaded. 247fb03ca4eSNeel Natu */ 248fb03ca4eSNeel Natu FREQ2BT(VLAPIC_BUS_FREQ / divisor, &vlapic->timer_freq_bt); 249fb03ca4eSNeel Natu vlapic->timer_period_bt = vlapic->timer_freq_bt; 250fb03ca4eSNeel Natu bintime_mul(&vlapic->timer_period_bt, lapic->icr_timer); 251fb03ca4eSNeel Natu 252fb03ca4eSNeel Natu VLAPIC_TIMER_UNLOCK(vlapic); 253366f6083SPeter Grehan } 254366f6083SPeter Grehan 255fafe8844SNeel Natu void 256fafe8844SNeel Natu vlapic_esr_write_handler(struct vlapic *vlapic) 257366f6083SPeter Grehan { 258de5ea6b6SNeel Natu struct LAPIC *lapic; 259de5ea6b6SNeel Natu 260de5ea6b6SNeel Natu lapic = vlapic->apic_page; 261330baf58SJohn Baldwin lapic->esr = vlapic->esr_pending; 262330baf58SJohn Baldwin vlapic->esr_pending = 0; 263366f6083SPeter Grehan } 264366f6083SPeter Grehan 2654d1e82a8SNeel Natu int 266b5b28fc9SNeel Natu vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level) 267366f6083SPeter Grehan { 2684d1e82a8SNeel Natu struct LAPIC *lapic; 269b5b28fc9SNeel Natu uint32_t *irrptr, *tmrptr, mask; 270366f6083SPeter Grehan int idx; 271366f6083SPeter Grehan 2724d1e82a8SNeel Natu KASSERT(vector >= 0 && vector < 256, ("invalid vector %d", vector)); 273366f6083SPeter Grehan 2744d1e82a8SNeel Natu lapic = vlapic->apic_page; 2751c052192SNeel Natu if (!(lapic->svr & APIC_SVR_ENABLE)) { 2761c052192SNeel Natu VLAPIC_CTR1(vlapic, "vlapic is software disabled, ignoring " 2771c052192SNeel Natu "interrupt %d", vector); 2784d1e82a8SNeel Natu return (0); 2791c052192SNeel Natu } 2801c052192SNeel Natu 281330baf58SJohn Baldwin if (vector < 16) { 2826a1e1c2cSJohn Baldwin vlapic_set_error(vlapic, APIC_ESR_RECEIVE_ILLEGAL_VECTOR, 2836a1e1c2cSJohn Baldwin false); 2844d1e82a8SNeel Natu VLAPIC_CTR1(vlapic, "vlapic ignoring interrupt to vector %d", 2854d1e82a8SNeel Natu vector); 2864d1e82a8SNeel Natu return (1); 287330baf58SJohn Baldwin } 288330baf58SJohn Baldwin 28988c4b8d1SNeel Natu if (vlapic->ops.set_intr_ready) 29088c4b8d1SNeel Natu return ((*vlapic->ops.set_intr_ready)(vlapic, vector, level)); 29188c4b8d1SNeel Natu 292366f6083SPeter Grehan idx = (vector / 32) * 4; 293b5b28fc9SNeel Natu mask = 1 << (vector % 32); 294b5b28fc9SNeel Natu 295366f6083SPeter Grehan irrptr = &lapic->irr0; 296b5b28fc9SNeel Natu atomic_set_int(&irrptr[idx], mask); 297b5b28fc9SNeel Natu 298b5b28fc9SNeel Natu /* 2995b8a8cd1SNeel Natu * Verify that the trigger-mode of the interrupt matches with 3005b8a8cd1SNeel Natu * the vlapic TMR registers. 301b5b28fc9SNeel Natu */ 302b5b28fc9SNeel Natu tmrptr = &lapic->tmr0; 303294d0d88SNeel Natu if ((tmrptr[idx] & mask) != (level ? mask : 0)) { 304294d0d88SNeel Natu VLAPIC_CTR3(vlapic, "vlapic TMR[%d] is 0x%08x but " 305294d0d88SNeel Natu "interrupt is %s-triggered", idx / 4, tmrptr[idx], 306294d0d88SNeel Natu level ? "level" : "edge"); 307294d0d88SNeel Natu } 308b5b28fc9SNeel Natu 309366f6083SPeter Grehan VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready"); 3104d1e82a8SNeel Natu return (1); 311366f6083SPeter Grehan } 312366f6083SPeter Grehan 313366f6083SPeter Grehan static __inline uint32_t * 314fb03ca4eSNeel Natu vlapic_get_lvtptr(struct vlapic *vlapic, uint32_t offset) 315366f6083SPeter Grehan { 316de5ea6b6SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 317366f6083SPeter Grehan int i; 318366f6083SPeter Grehan 319330baf58SJohn Baldwin switch (offset) { 320330baf58SJohn Baldwin case APIC_OFFSET_CMCI_LVT: 321330baf58SJohn Baldwin return (&lapic->lvt_cmci); 322330baf58SJohn Baldwin case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: 323366f6083SPeter Grehan i = (offset - APIC_OFFSET_TIMER_LVT) >> 2; 324ba084c18SEd Maste return ((&lapic->lvt_timer) + i); 325330baf58SJohn Baldwin default: 326330baf58SJohn Baldwin panic("vlapic_get_lvt: invalid LVT\n"); 327330baf58SJohn Baldwin } 328366f6083SPeter Grehan } 329366f6083SPeter Grehan 3307c05bc31SNeel Natu static __inline int 3317c05bc31SNeel Natu lvt_off_to_idx(uint32_t offset) 3327c05bc31SNeel Natu { 3337c05bc31SNeel Natu int index; 3347c05bc31SNeel Natu 3357c05bc31SNeel Natu switch (offset) { 3367c05bc31SNeel Natu case APIC_OFFSET_CMCI_LVT: 3377c05bc31SNeel Natu index = APIC_LVT_CMCI; 3387c05bc31SNeel Natu break; 3397c05bc31SNeel Natu case APIC_OFFSET_TIMER_LVT: 3407c05bc31SNeel Natu index = APIC_LVT_TIMER; 3417c05bc31SNeel Natu break; 3427c05bc31SNeel Natu case APIC_OFFSET_THERM_LVT: 3437c05bc31SNeel Natu index = APIC_LVT_THERMAL; 3447c05bc31SNeel Natu break; 3457c05bc31SNeel Natu case APIC_OFFSET_PERF_LVT: 3467c05bc31SNeel Natu index = APIC_LVT_PMC; 3477c05bc31SNeel Natu break; 3487c05bc31SNeel Natu case APIC_OFFSET_LINT0_LVT: 3497c05bc31SNeel Natu index = APIC_LVT_LINT0; 3507c05bc31SNeel Natu break; 3517c05bc31SNeel Natu case APIC_OFFSET_LINT1_LVT: 3527c05bc31SNeel Natu index = APIC_LVT_LINT1; 3537c05bc31SNeel Natu break; 3547c05bc31SNeel Natu case APIC_OFFSET_ERROR_LVT: 3557c05bc31SNeel Natu index = APIC_LVT_ERROR; 3567c05bc31SNeel Natu break; 3577c05bc31SNeel Natu default: 3587c05bc31SNeel Natu index = -1; 3597c05bc31SNeel Natu break; 3607c05bc31SNeel Natu } 3617c05bc31SNeel Natu KASSERT(index >= 0 && index <= VLAPIC_MAXLVT_INDEX, ("lvt_off_to_idx: " 3627c05bc31SNeel Natu "invalid lvt index %d for offset %#x", index, offset)); 3637c05bc31SNeel Natu 3647c05bc31SNeel Natu return (index); 3657c05bc31SNeel Natu } 3667c05bc31SNeel Natu 367fb03ca4eSNeel Natu static __inline uint32_t 368fb03ca4eSNeel Natu vlapic_get_lvt(struct vlapic *vlapic, uint32_t offset) 369fb03ca4eSNeel Natu { 3707c05bc31SNeel Natu int idx; 3717c05bc31SNeel Natu uint32_t val; 372fb03ca4eSNeel Natu 3737c05bc31SNeel Natu idx = lvt_off_to_idx(offset); 3747c05bc31SNeel Natu val = atomic_load_acq_32(&vlapic->lvt_last[idx]); 3757c05bc31SNeel Natu return (val); 376fb03ca4eSNeel Natu } 377fb03ca4eSNeel Natu 3787c05bc31SNeel Natu void 3797c05bc31SNeel Natu vlapic_lvt_write_handler(struct vlapic *vlapic, uint32_t offset) 380fb03ca4eSNeel Natu { 3817c05bc31SNeel Natu uint32_t *lvtptr, mask, val; 382fb03ca4eSNeel Natu struct LAPIC *lapic; 3837c05bc31SNeel Natu int idx; 384fb03ca4eSNeel Natu 385de5ea6b6SNeel Natu lapic = vlapic->apic_page; 386fb03ca4eSNeel Natu lvtptr = vlapic_get_lvtptr(vlapic, offset); 3877c05bc31SNeel Natu val = *lvtptr; 3887c05bc31SNeel Natu idx = lvt_off_to_idx(offset); 389fb03ca4eSNeel Natu 390fb03ca4eSNeel Natu if (!(lapic->svr & APIC_SVR_ENABLE)) 391fb03ca4eSNeel Natu val |= APIC_LVT_M; 392330baf58SJohn Baldwin mask = APIC_LVT_M | APIC_LVT_DS | APIC_LVT_VECTOR; 393330baf58SJohn Baldwin switch (offset) { 394330baf58SJohn Baldwin case APIC_OFFSET_TIMER_LVT: 395330baf58SJohn Baldwin mask |= APIC_LVTT_TM; 396330baf58SJohn Baldwin break; 397330baf58SJohn Baldwin case APIC_OFFSET_ERROR_LVT: 398330baf58SJohn Baldwin break; 399330baf58SJohn Baldwin case APIC_OFFSET_LINT0_LVT: 400330baf58SJohn Baldwin case APIC_OFFSET_LINT1_LVT: 401330baf58SJohn Baldwin mask |= APIC_LVT_TM | APIC_LVT_RIRR | APIC_LVT_IIPP; 402330baf58SJohn Baldwin /* FALLTHROUGH */ 403330baf58SJohn Baldwin default: 404330baf58SJohn Baldwin mask |= APIC_LVT_DM; 405330baf58SJohn Baldwin break; 406330baf58SJohn Baldwin } 4077c05bc31SNeel Natu val &= mask; 4087c05bc31SNeel Natu *lvtptr = val; 4097c05bc31SNeel Natu atomic_store_rel_32(&vlapic->lvt_last[idx], val); 4107c05bc31SNeel Natu } 411fb03ca4eSNeel Natu 4127c05bc31SNeel Natu static void 4137c05bc31SNeel Natu vlapic_mask_lvts(struct vlapic *vlapic) 4147c05bc31SNeel Natu { 4157c05bc31SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 4167c05bc31SNeel Natu 4177c05bc31SNeel Natu lapic->lvt_cmci |= APIC_LVT_M; 4187c05bc31SNeel Natu vlapic_lvt_write_handler(vlapic, APIC_OFFSET_CMCI_LVT); 4197c05bc31SNeel Natu 4207c05bc31SNeel Natu lapic->lvt_timer |= APIC_LVT_M; 4217c05bc31SNeel Natu vlapic_lvt_write_handler(vlapic, APIC_OFFSET_TIMER_LVT); 4227c05bc31SNeel Natu 4237c05bc31SNeel Natu lapic->lvt_thermal |= APIC_LVT_M; 4247c05bc31SNeel Natu vlapic_lvt_write_handler(vlapic, APIC_OFFSET_THERM_LVT); 4257c05bc31SNeel Natu 4267c05bc31SNeel Natu lapic->lvt_pcint |= APIC_LVT_M; 4277c05bc31SNeel Natu vlapic_lvt_write_handler(vlapic, APIC_OFFSET_PERF_LVT); 4287c05bc31SNeel Natu 4297c05bc31SNeel Natu lapic->lvt_lint0 |= APIC_LVT_M; 4307c05bc31SNeel Natu vlapic_lvt_write_handler(vlapic, APIC_OFFSET_LINT0_LVT); 4317c05bc31SNeel Natu 4327c05bc31SNeel Natu lapic->lvt_lint1 |= APIC_LVT_M; 4337c05bc31SNeel Natu vlapic_lvt_write_handler(vlapic, APIC_OFFSET_LINT1_LVT); 4347c05bc31SNeel Natu 4357c05bc31SNeel Natu lapic->lvt_error |= APIC_LVT_M; 4367c05bc31SNeel Natu vlapic_lvt_write_handler(vlapic, APIC_OFFSET_ERROR_LVT); 437fb03ca4eSNeel Natu } 438fb03ca4eSNeel Natu 439330baf58SJohn Baldwin static int 4406a1e1c2cSJohn Baldwin vlapic_fire_lvt(struct vlapic *vlapic, u_int lvt) 441330baf58SJohn Baldwin { 4426a1e1c2cSJohn Baldwin uint32_t mode, reg, vec; 443330baf58SJohn Baldwin 4446a1e1c2cSJohn Baldwin reg = atomic_load_acq_32(&vlapic->lvt_last[lvt]); 4456a1e1c2cSJohn Baldwin 4466a1e1c2cSJohn Baldwin if (reg & APIC_LVT_M) 447330baf58SJohn Baldwin return (0); 4486a1e1c2cSJohn Baldwin vec = reg & APIC_LVT_VECTOR; 4496a1e1c2cSJohn Baldwin mode = reg & APIC_LVT_DM; 450330baf58SJohn Baldwin 451330baf58SJohn Baldwin switch (mode) { 452330baf58SJohn Baldwin case APIC_LVT_DM_FIXED: 453330baf58SJohn Baldwin if (vec < 16) { 4546a1e1c2cSJohn Baldwin vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR, 4556a1e1c2cSJohn Baldwin lvt == APIC_LVT_ERROR); 456330baf58SJohn Baldwin return (0); 457330baf58SJohn Baldwin } 4584d1e82a8SNeel Natu if (vlapic_set_intr_ready(vlapic, vec, false)) 4593f0f4b15SJohn Baldwin vcpu_notify_event(vlapic->vcpu, true); 460330baf58SJohn Baldwin break; 461330baf58SJohn Baldwin case APIC_LVT_DM_NMI: 4623f0f4b15SJohn Baldwin vm_inject_nmi(vlapic->vcpu); 463330baf58SJohn Baldwin break; 464762fd208STycho Nightingale case APIC_LVT_DM_EXTINT: 4653f0f4b15SJohn Baldwin vm_inject_extint(vlapic->vcpu); 466762fd208STycho Nightingale break; 467330baf58SJohn Baldwin default: 468330baf58SJohn Baldwin // Other modes ignored 469330baf58SJohn Baldwin return (0); 470330baf58SJohn Baldwin } 471330baf58SJohn Baldwin return (1); 472330baf58SJohn Baldwin } 473330baf58SJohn Baldwin 474366f6083SPeter Grehan #if 1 475366f6083SPeter Grehan static void 476366f6083SPeter Grehan dump_isrvec_stk(struct vlapic *vlapic) 477366f6083SPeter Grehan { 478366f6083SPeter Grehan int i; 479366f6083SPeter Grehan uint32_t *isrptr; 480366f6083SPeter Grehan 481de5ea6b6SNeel Natu isrptr = &vlapic->apic_page->isr0; 482366f6083SPeter Grehan for (i = 0; i < 8; i++) 483366f6083SPeter Grehan printf("ISR%d 0x%08x\n", i, isrptr[i * 4]); 484366f6083SPeter Grehan 485366f6083SPeter Grehan for (i = 0; i <= vlapic->isrvec_stk_top; i++) 486366f6083SPeter Grehan printf("isrvec_stk[%d] = %d\n", i, vlapic->isrvec_stk[i]); 487366f6083SPeter Grehan } 488366f6083SPeter Grehan #endif 489366f6083SPeter Grehan 490366f6083SPeter Grehan /* 491366f6083SPeter Grehan * Algorithm adopted from section "Interrupt, Task and Processor Priority" 492366f6083SPeter Grehan * in Intel Architecture Manual Vol 3a. 493366f6083SPeter Grehan */ 494366f6083SPeter Grehan static void 495366f6083SPeter Grehan vlapic_update_ppr(struct vlapic *vlapic) 496366f6083SPeter Grehan { 497366f6083SPeter Grehan int isrvec, tpr, ppr; 498366f6083SPeter Grehan 499366f6083SPeter Grehan /* 500366f6083SPeter Grehan * Note that the value on the stack at index 0 is always 0. 501366f6083SPeter Grehan * 502366f6083SPeter Grehan * This is a placeholder for the value of ISRV when none of the 503366f6083SPeter Grehan * bits is set in the ISRx registers. 504366f6083SPeter Grehan */ 505366f6083SPeter Grehan isrvec = vlapic->isrvec_stk[vlapic->isrvec_stk_top]; 506de5ea6b6SNeel Natu tpr = vlapic->apic_page->tpr; 507366f6083SPeter Grehan 508366f6083SPeter Grehan #if 1 509366f6083SPeter Grehan { 510366f6083SPeter Grehan int i, lastprio, curprio, vector, idx; 511366f6083SPeter Grehan uint32_t *isrptr; 512366f6083SPeter Grehan 513366f6083SPeter Grehan if (vlapic->isrvec_stk_top == 0 && isrvec != 0) 514366f6083SPeter Grehan panic("isrvec_stk is corrupted: %d", isrvec); 515366f6083SPeter Grehan 516366f6083SPeter Grehan /* 517366f6083SPeter Grehan * Make sure that the priority of the nested interrupts is 518366f6083SPeter Grehan * always increasing. 519366f6083SPeter Grehan */ 520366f6083SPeter Grehan lastprio = -1; 521366f6083SPeter Grehan for (i = 1; i <= vlapic->isrvec_stk_top; i++) { 522366f6083SPeter Grehan curprio = PRIO(vlapic->isrvec_stk[i]); 523366f6083SPeter Grehan if (curprio <= lastprio) { 524366f6083SPeter Grehan dump_isrvec_stk(vlapic); 525366f6083SPeter Grehan panic("isrvec_stk does not satisfy invariant"); 526366f6083SPeter Grehan } 527366f6083SPeter Grehan lastprio = curprio; 528366f6083SPeter Grehan } 529366f6083SPeter Grehan 530366f6083SPeter Grehan /* 531366f6083SPeter Grehan * Make sure that each bit set in the ISRx registers has a 532366f6083SPeter Grehan * corresponding entry on the isrvec stack. 533366f6083SPeter Grehan */ 534366f6083SPeter Grehan i = 1; 535de5ea6b6SNeel Natu isrptr = &vlapic->apic_page->isr0; 536366f6083SPeter Grehan for (vector = 0; vector < 256; vector++) { 537366f6083SPeter Grehan idx = (vector / 32) * 4; 538366f6083SPeter Grehan if (isrptr[idx] & (1 << (vector % 32))) { 539366f6083SPeter Grehan if (i > vlapic->isrvec_stk_top || 540366f6083SPeter Grehan vlapic->isrvec_stk[i] != vector) { 541366f6083SPeter Grehan dump_isrvec_stk(vlapic); 542366f6083SPeter Grehan panic("ISR and isrvec_stk out of sync"); 543366f6083SPeter Grehan } 544366f6083SPeter Grehan i++; 545366f6083SPeter Grehan } 546366f6083SPeter Grehan } 547366f6083SPeter Grehan } 548366f6083SPeter Grehan #endif 549366f6083SPeter Grehan 550366f6083SPeter Grehan if (PRIO(tpr) >= PRIO(isrvec)) 551366f6083SPeter Grehan ppr = tpr; 552366f6083SPeter Grehan else 553366f6083SPeter Grehan ppr = isrvec & 0xf0; 554366f6083SPeter Grehan 555de5ea6b6SNeel Natu vlapic->apic_page->ppr = ppr; 556366f6083SPeter Grehan VLAPIC_CTR1(vlapic, "vlapic_update_ppr 0x%02x", ppr); 557366f6083SPeter Grehan } 558366f6083SPeter Grehan 5591bc51badSMichael Reifenberger void 5601bc51badSMichael Reifenberger vlapic_sync_tpr(struct vlapic *vlapic) 5611bc51badSMichael Reifenberger { 5621bc51badSMichael Reifenberger vlapic_update_ppr(vlapic); 5631bc51badSMichael Reifenberger } 5641bc51badSMichael Reifenberger 56544e2f0feSNeel Natu static VMM_STAT(VLAPIC_GRATUITOUS_EOI, "EOI without any in-service interrupt"); 56644e2f0feSNeel Natu 567366f6083SPeter Grehan static void 568366f6083SPeter Grehan vlapic_process_eoi(struct vlapic *vlapic) 569366f6083SPeter Grehan { 570de5ea6b6SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 571b5b28fc9SNeel Natu uint32_t *isrptr, *tmrptr; 572b5b28fc9SNeel Natu int i, idx, bitpos, vector; 573366f6083SPeter Grehan 574366f6083SPeter Grehan isrptr = &lapic->isr0; 575b5b28fc9SNeel Natu tmrptr = &lapic->tmr0; 576366f6083SPeter Grehan 57744e2f0feSNeel Natu for (i = 7; i >= 0; i--) { 578366f6083SPeter Grehan idx = i * 4; 579366f6083SPeter Grehan bitpos = fls(isrptr[idx]); 580b5b28fc9SNeel Natu if (bitpos-- != 0) { 581366f6083SPeter Grehan if (vlapic->isrvec_stk_top <= 0) { 582366f6083SPeter Grehan panic("invalid vlapic isrvec_stk_top %d", 583366f6083SPeter Grehan vlapic->isrvec_stk_top); 584366f6083SPeter Grehan } 585b5b28fc9SNeel Natu isrptr[idx] &= ~(1 << bitpos); 58644e2f0feSNeel Natu vector = i * 32 + bitpos; 587d030f941SJohn Baldwin VLAPIC_CTR1(vlapic, "EOI vector %d", vector); 588366f6083SPeter Grehan VLAPIC_CTR_ISR(vlapic, "vlapic_process_eoi"); 589366f6083SPeter Grehan vlapic->isrvec_stk_top--; 590366f6083SPeter Grehan vlapic_update_ppr(vlapic); 591b5b28fc9SNeel Natu if ((tmrptr[idx] & (1 << bitpos)) != 0) { 592e42c24d5SJohn Baldwin vioapic_process_eoi(vlapic->vm, vector); 593b5b28fc9SNeel Natu } 594366f6083SPeter Grehan return; 595366f6083SPeter Grehan } 596366f6083SPeter Grehan } 597d030f941SJohn Baldwin VLAPIC_CTR0(vlapic, "Gratuitous EOI"); 5983dc3d32aSJohn Baldwin vmm_stat_incr(vlapic->vcpu, VLAPIC_GRATUITOUS_EOI, 1); 599366f6083SPeter Grehan } 600366f6083SPeter Grehan 601366f6083SPeter Grehan static __inline int 602fb03ca4eSNeel Natu vlapic_get_lvt_field(uint32_t lvt, uint32_t mask) 603366f6083SPeter Grehan { 604fb03ca4eSNeel Natu 605fb03ca4eSNeel Natu return (lvt & mask); 606366f6083SPeter Grehan } 607366f6083SPeter Grehan 608366f6083SPeter Grehan static __inline int 609366f6083SPeter Grehan vlapic_periodic_timer(struct vlapic *vlapic) 610366f6083SPeter Grehan { 611fb03ca4eSNeel Natu uint32_t lvt; 612366f6083SPeter Grehan 613366f6083SPeter Grehan lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT); 614366f6083SPeter Grehan 615366f6083SPeter Grehan return (vlapic_get_lvt_field(lvt, APIC_LVTT_TM_PERIODIC)); 616366f6083SPeter Grehan } 617366f6083SPeter Grehan 618330baf58SJohn Baldwin static VMM_STAT(VLAPIC_INTR_ERROR, "error interrupts generated by vlapic"); 619330baf58SJohn Baldwin 6206a1e1c2cSJohn Baldwin static void 6216a1e1c2cSJohn Baldwin vlapic_set_error(struct vlapic *vlapic, uint32_t mask, bool lvt_error) 622330baf58SJohn Baldwin { 623330baf58SJohn Baldwin 624330baf58SJohn Baldwin vlapic->esr_pending |= mask; 625330baf58SJohn Baldwin 6266a1e1c2cSJohn Baldwin /* 6276a1e1c2cSJohn Baldwin * Avoid infinite recursion if the error LVT itself is configured with 6286a1e1c2cSJohn Baldwin * an illegal vector. 6296a1e1c2cSJohn Baldwin */ 6306a1e1c2cSJohn Baldwin if (lvt_error) 6316a1e1c2cSJohn Baldwin return; 6326a1e1c2cSJohn Baldwin 6336a1e1c2cSJohn Baldwin if (vlapic_fire_lvt(vlapic, APIC_LVT_ERROR)) { 6343dc3d32aSJohn Baldwin vmm_stat_incr(vlapic->vcpu, VLAPIC_INTR_ERROR, 1); 635330baf58SJohn Baldwin } 636330baf58SJohn Baldwin } 637330baf58SJohn Baldwin 63877d8fd9bSNeel Natu static VMM_STAT(VLAPIC_INTR_TIMER, "timer interrupts generated by vlapic"); 63977d8fd9bSNeel Natu 640366f6083SPeter Grehan static void 641366f6083SPeter Grehan vlapic_fire_timer(struct vlapic *vlapic) 642366f6083SPeter Grehan { 643fb03ca4eSNeel Natu 644fb03ca4eSNeel Natu KASSERT(VLAPIC_TIMER_LOCKED(vlapic), ("vlapic_fire_timer not locked")); 645366f6083SPeter Grehan 6466a1e1c2cSJohn Baldwin if (vlapic_fire_lvt(vlapic, APIC_LVT_TIMER)) { 6479d8d8e3eSNeel Natu VLAPIC_CTR0(vlapic, "vlapic timer fired"); 6483dc3d32aSJohn Baldwin vmm_stat_incr(vlapic->vcpu, VLAPIC_INTR_TIMER, 1); 649366f6083SPeter Grehan } 650366f6083SPeter Grehan } 651366f6083SPeter Grehan 652330baf58SJohn Baldwin static VMM_STAT(VLAPIC_INTR_CMC, 653330baf58SJohn Baldwin "corrected machine check interrupts generated by vlapic"); 654330baf58SJohn Baldwin 655330baf58SJohn Baldwin void 656330baf58SJohn Baldwin vlapic_fire_cmci(struct vlapic *vlapic) 657330baf58SJohn Baldwin { 658330baf58SJohn Baldwin 6596a1e1c2cSJohn Baldwin if (vlapic_fire_lvt(vlapic, APIC_LVT_CMCI)) { 6603dc3d32aSJohn Baldwin vmm_stat_incr(vlapic->vcpu, VLAPIC_INTR_CMC, 1); 661330baf58SJohn Baldwin } 662330baf58SJohn Baldwin } 663330baf58SJohn Baldwin 6647c05bc31SNeel Natu static VMM_STAT_ARRAY(LVTS_TRIGGERRED, VLAPIC_MAXLVT_INDEX + 1, 665330baf58SJohn Baldwin "lvts triggered"); 666330baf58SJohn Baldwin 667330baf58SJohn Baldwin int 668330baf58SJohn Baldwin vlapic_trigger_lvt(struct vlapic *vlapic, int vector) 669330baf58SJohn Baldwin { 670330baf58SJohn Baldwin 671762fd208STycho Nightingale if (vlapic_enabled(vlapic) == false) { 672762fd208STycho Nightingale /* 673762fd208STycho Nightingale * When the local APIC is global/hardware disabled, 674762fd208STycho Nightingale * LINT[1:0] pins are configured as INTR and NMI pins, 675762fd208STycho Nightingale * respectively. 676762fd208STycho Nightingale */ 677762fd208STycho Nightingale switch (vector) { 678762fd208STycho Nightingale case APIC_LVT_LINT0: 6793f0f4b15SJohn Baldwin vm_inject_extint(vlapic->vcpu); 680762fd208STycho Nightingale break; 681762fd208STycho Nightingale case APIC_LVT_LINT1: 6823f0f4b15SJohn Baldwin vm_inject_nmi(vlapic->vcpu); 683762fd208STycho Nightingale break; 684762fd208STycho Nightingale default: 685762fd208STycho Nightingale break; 686762fd208STycho Nightingale } 687762fd208STycho Nightingale return (0); 688762fd208STycho Nightingale } 689762fd208STycho Nightingale 690330baf58SJohn Baldwin switch (vector) { 691330baf58SJohn Baldwin case APIC_LVT_LINT0: 692330baf58SJohn Baldwin case APIC_LVT_LINT1: 693330baf58SJohn Baldwin case APIC_LVT_TIMER: 694330baf58SJohn Baldwin case APIC_LVT_ERROR: 695330baf58SJohn Baldwin case APIC_LVT_PMC: 696330baf58SJohn Baldwin case APIC_LVT_THERMAL: 697330baf58SJohn Baldwin case APIC_LVT_CMCI: 6986a1e1c2cSJohn Baldwin if (vlapic_fire_lvt(vlapic, vector)) { 6993dc3d32aSJohn Baldwin vmm_stat_array_incr(vlapic->vcpu, LVTS_TRIGGERRED, 7003dc3d32aSJohn Baldwin vector, 1); 7016a1e1c2cSJohn Baldwin } 702330baf58SJohn Baldwin break; 703330baf58SJohn Baldwin default: 704330baf58SJohn Baldwin return (EINVAL); 705330baf58SJohn Baldwin } 706330baf58SJohn Baldwin return (0); 707330baf58SJohn Baldwin } 708330baf58SJohn Baldwin 709fb03ca4eSNeel Natu static void 7104c812fe6SMark Johnston vlapic_callout_reset(struct vlapic *vlapic, sbintime_t t) 7114c812fe6SMark Johnston { 7124c812fe6SMark Johnston callout_reset_sbt_curcpu(&vlapic->callout, t, 0, 7134c812fe6SMark Johnston vlapic_callout_handler, vlapic, 0); 7144c812fe6SMark Johnston } 7154c812fe6SMark Johnston 7164c812fe6SMark Johnston static void 717fb03ca4eSNeel Natu vlapic_callout_handler(void *arg) 718fb03ca4eSNeel Natu { 719fb03ca4eSNeel Natu struct vlapic *vlapic; 720fb03ca4eSNeel Natu struct bintime bt, btnow; 721fb03ca4eSNeel Natu sbintime_t rem_sbt; 722fb03ca4eSNeel Natu 723fb03ca4eSNeel Natu vlapic = arg; 724fb03ca4eSNeel Natu 725fb03ca4eSNeel Natu VLAPIC_TIMER_LOCK(vlapic); 726fb03ca4eSNeel Natu if (callout_pending(&vlapic->callout)) /* callout was reset */ 727fb03ca4eSNeel Natu goto done; 728fb03ca4eSNeel Natu 729fb03ca4eSNeel Natu if (!callout_active(&vlapic->callout)) /* callout was stopped */ 730fb03ca4eSNeel Natu goto done; 731fb03ca4eSNeel Natu 732fb03ca4eSNeel Natu callout_deactivate(&vlapic->callout); 733fb03ca4eSNeel Natu 734fb03ca4eSNeel Natu vlapic_fire_timer(vlapic); 735fb03ca4eSNeel Natu 736fb03ca4eSNeel Natu if (vlapic_periodic_timer(vlapic)) { 737fb03ca4eSNeel Natu binuptime(&btnow); 738fb03ca4eSNeel Natu KASSERT(bintime_cmp(&btnow, &vlapic->timer_fire_bt, >=), 739fb03ca4eSNeel Natu ("vlapic callout at %#lx.%#lx, expected at %#lx.#%lx", 740fb03ca4eSNeel Natu btnow.sec, btnow.frac, vlapic->timer_fire_bt.sec, 741fb03ca4eSNeel Natu vlapic->timer_fire_bt.frac)); 742fb03ca4eSNeel Natu 743fb03ca4eSNeel Natu /* 744fb03ca4eSNeel Natu * Compute the delta between when the timer was supposed to 745fb03ca4eSNeel Natu * fire and the present time. 746fb03ca4eSNeel Natu */ 747fb03ca4eSNeel Natu bt = btnow; 748fb03ca4eSNeel Natu bintime_sub(&bt, &vlapic->timer_fire_bt); 749fb03ca4eSNeel Natu 750fb03ca4eSNeel Natu rem_sbt = bttosbt(vlapic->timer_period_bt); 751fb03ca4eSNeel Natu if (bintime_cmp(&bt, &vlapic->timer_period_bt, <)) { 752fb03ca4eSNeel Natu /* 753fb03ca4eSNeel Natu * Adjust the time until the next countdown downward 754fb03ca4eSNeel Natu * to account for the lost time. 755fb03ca4eSNeel Natu */ 756fb03ca4eSNeel Natu rem_sbt -= bttosbt(bt); 757fb03ca4eSNeel Natu } else { 758fb03ca4eSNeel Natu /* 759fb03ca4eSNeel Natu * If the delta is greater than the timer period then 760fb03ca4eSNeel Natu * just reset our time base instead of trying to catch 761fb03ca4eSNeel Natu * up. 762fb03ca4eSNeel Natu */ 763fb03ca4eSNeel Natu vlapic->timer_fire_bt = btnow; 764fb03ca4eSNeel Natu VLAPIC_CTR2(vlapic, "vlapic timer lagging by %lu " 765fb03ca4eSNeel Natu "usecs, period is %lu usecs - resetting time base", 766fb03ca4eSNeel Natu bttosbt(bt) / SBT_1US, 767fb03ca4eSNeel Natu bttosbt(vlapic->timer_period_bt) / SBT_1US); 768fb03ca4eSNeel Natu } 769fb03ca4eSNeel Natu 770fb03ca4eSNeel Natu bintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt); 7714c812fe6SMark Johnston vlapic_callout_reset(vlapic, rem_sbt); 772fb03ca4eSNeel Natu } 773fb03ca4eSNeel Natu done: 774fb03ca4eSNeel Natu VLAPIC_TIMER_UNLOCK(vlapic); 775fb03ca4eSNeel Natu } 776fb03ca4eSNeel Natu 777fafe8844SNeel Natu void 778fafe8844SNeel Natu vlapic_icrtmr_write_handler(struct vlapic *vlapic) 779fb03ca4eSNeel Natu { 780fb03ca4eSNeel Natu struct LAPIC *lapic; 781fb03ca4eSNeel Natu sbintime_t sbt; 782fafe8844SNeel Natu uint32_t icr_timer; 783fb03ca4eSNeel Natu 784fb03ca4eSNeel Natu VLAPIC_TIMER_LOCK(vlapic); 785fb03ca4eSNeel Natu 786de5ea6b6SNeel Natu lapic = vlapic->apic_page; 787fafe8844SNeel Natu icr_timer = lapic->icr_timer; 788fb03ca4eSNeel Natu 789fb03ca4eSNeel Natu vlapic->timer_period_bt = vlapic->timer_freq_bt; 790fb03ca4eSNeel Natu bintime_mul(&vlapic->timer_period_bt, icr_timer); 791fb03ca4eSNeel Natu 792fb03ca4eSNeel Natu if (icr_timer != 0) { 793fb03ca4eSNeel Natu binuptime(&vlapic->timer_fire_bt); 794fb03ca4eSNeel Natu bintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt); 795fb03ca4eSNeel Natu 796fb03ca4eSNeel Natu sbt = bttosbt(vlapic->timer_period_bt); 7974c812fe6SMark Johnston vlapic_callout_reset(vlapic, sbt); 798fb03ca4eSNeel Natu } else 799fb03ca4eSNeel Natu callout_stop(&vlapic->callout); 800fb03ca4eSNeel Natu 801fb03ca4eSNeel Natu VLAPIC_TIMER_UNLOCK(vlapic); 802fb03ca4eSNeel Natu } 803fb03ca4eSNeel Natu 8044f8be175SNeel Natu /* 8054f8be175SNeel Natu * This function populates 'dmask' with the set of vcpus that match the 8064f8be175SNeel Natu * addressing specified by the (dest, phys, lowprio) tuple. 8074f8be175SNeel Natu * 8084f8be175SNeel Natu * 'x2apic_dest' specifies whether 'dest' is interpreted as x2APIC (32-bit) 8094f8be175SNeel Natu * or xAPIC (8-bit) destination field. 8104f8be175SNeel Natu */ 8114f8be175SNeel Natu static void 8124f8be175SNeel Natu vlapic_calcdest(struct vm *vm, cpuset_t *dmask, uint32_t dest, bool phys, 8134f8be175SNeel Natu bool lowprio, bool x2apic_dest) 8144f8be175SNeel Natu { 8154f8be175SNeel Natu struct vlapic *vlapic; 8164f8be175SNeel Natu uint32_t dfr, ldr, ldest, cluster; 8174f8be175SNeel Natu uint32_t mda_flat_ldest, mda_cluster_ldest, mda_ldest, mda_cluster_id; 8184f8be175SNeel Natu cpuset_t amask; 8194f8be175SNeel Natu int vcpuid; 8204f8be175SNeel Natu 8214f8be175SNeel Natu if ((x2apic_dest && dest == 0xffffffff) || 8224f8be175SNeel Natu (!x2apic_dest && dest == 0xff)) { 8234f8be175SNeel Natu /* 8244f8be175SNeel Natu * Broadcast in both logical and physical modes. 8254f8be175SNeel Natu */ 8264f8be175SNeel Natu *dmask = vm_active_cpus(vm); 8274f8be175SNeel Natu return; 8284f8be175SNeel Natu } 8294f8be175SNeel Natu 8304f8be175SNeel Natu if (phys) { 8314f8be175SNeel Natu /* 8324f8be175SNeel Natu * Physical mode: destination is APIC ID. 8334f8be175SNeel Natu */ 8344f8be175SNeel Natu CPU_ZERO(dmask); 8354f8be175SNeel Natu vcpuid = vm_apicid2vcpuid(vm, dest); 836e5506316SKonstantin Belousov amask = vm_active_cpus(vm); 837e5506316SKonstantin Belousov if (vcpuid < vm_get_maxcpus(vm) && CPU_ISSET(vcpuid, &amask)) 8384f8be175SNeel Natu CPU_SET(vcpuid, dmask); 8394f8be175SNeel Natu } else { 8404f8be175SNeel Natu /* 8414f8be175SNeel Natu * In the "Flat Model" the MDA is interpreted as an 8-bit wide 842500eb14aSPedro F. Giffuni * bitmask. This model is only available in the xAPIC mode. 8434f8be175SNeel Natu */ 8444f8be175SNeel Natu mda_flat_ldest = dest & 0xff; 8454f8be175SNeel Natu 8464f8be175SNeel Natu /* 8474f8be175SNeel Natu * In the "Cluster Model" the MDA is used to identify a 8484f8be175SNeel Natu * specific cluster and a set of APICs in that cluster. 8494f8be175SNeel Natu */ 8504f8be175SNeel Natu if (x2apic_dest) { 8514f8be175SNeel Natu mda_cluster_id = dest >> 16; 8524f8be175SNeel Natu mda_cluster_ldest = dest & 0xffff; 8534f8be175SNeel Natu } else { 8544f8be175SNeel Natu mda_cluster_id = (dest >> 4) & 0xf; 8554f8be175SNeel Natu mda_cluster_ldest = dest & 0xf; 8564f8be175SNeel Natu } 8574f8be175SNeel Natu 8584f8be175SNeel Natu /* 8594f8be175SNeel Natu * Logical mode: match each APIC that has a bit set 86028323addSBryan Drewery * in its LDR that matches a bit in the ldest. 8614f8be175SNeel Natu */ 8624f8be175SNeel Natu CPU_ZERO(dmask); 8634f8be175SNeel Natu amask = vm_active_cpus(vm); 864de855429SMark Johnston CPU_FOREACH_ISSET(vcpuid, &amask) { 865d3956e46SJohn Baldwin vlapic = vm_lapic(vm_vcpu(vm, vcpuid)); 8663f0ddc7cSNeel Natu dfr = vlapic->apic_page->dfr; 8673f0ddc7cSNeel Natu ldr = vlapic->apic_page->ldr; 8684f8be175SNeel Natu 8694f8be175SNeel Natu if ((dfr & APIC_DFR_MODEL_MASK) == 8704f8be175SNeel Natu APIC_DFR_MODEL_FLAT) { 8714f8be175SNeel Natu ldest = ldr >> 24; 8724f8be175SNeel Natu mda_ldest = mda_flat_ldest; 8734f8be175SNeel Natu } else if ((dfr & APIC_DFR_MODEL_MASK) == 8744f8be175SNeel Natu APIC_DFR_MODEL_CLUSTER) { 8754f8be175SNeel Natu if (x2apic(vlapic)) { 8764f8be175SNeel Natu cluster = ldr >> 16; 8774f8be175SNeel Natu ldest = ldr & 0xffff; 8784f8be175SNeel Natu } else { 8794f8be175SNeel Natu cluster = ldr >> 28; 8804f8be175SNeel Natu ldest = (ldr >> 24) & 0xf; 8814f8be175SNeel Natu } 8824f8be175SNeel Natu if (cluster != mda_cluster_id) 8834f8be175SNeel Natu continue; 8844f8be175SNeel Natu mda_ldest = mda_cluster_ldest; 8854f8be175SNeel Natu } else { 8864f8be175SNeel Natu /* 8874f8be175SNeel Natu * Guest has configured a bad logical 8884f8be175SNeel Natu * model for this vcpu - skip it. 8894f8be175SNeel Natu */ 8904f8be175SNeel Natu VLAPIC_CTR1(vlapic, "vlapic has bad logical " 8914f8be175SNeel Natu "model %x - cannot deliver interrupt", dfr); 8924f8be175SNeel Natu continue; 8934f8be175SNeel Natu } 8944f8be175SNeel Natu 8954f8be175SNeel Natu if ((mda_ldest & ldest) != 0) { 8964f8be175SNeel Natu CPU_SET(vcpuid, dmask); 8974f8be175SNeel Natu if (lowprio) 8984f8be175SNeel Natu break; 8994f8be175SNeel Natu } 9004f8be175SNeel Natu } 9014f8be175SNeel Natu } 9024f8be175SNeel Natu } 9034f8be175SNeel Natu 90494a3876dSVitaliy Gusev static VMM_STAT(VLAPIC_IPI_SEND, "ipis sent from vcpu"); 90594a3876dSVitaliy Gusev static VMM_STAT(VLAPIC_IPI_RECV, "ipis received by vcpu"); 9060acb0d84SNeel Natu 907051f2bd1SNeel Natu static void 908051f2bd1SNeel Natu vlapic_set_tpr(struct vlapic *vlapic, uint8_t val) 909051f2bd1SNeel Natu { 910051f2bd1SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 911051f2bd1SNeel Natu 91279ad53fbSNeel Natu if (lapic->tpr != val) { 913d030f941SJohn Baldwin VLAPIC_CTR2(vlapic, "vlapic TPR changed from %#x to %#x", 914d030f941SJohn Baldwin lapic->tpr, val); 915051f2bd1SNeel Natu lapic->tpr = val; 916051f2bd1SNeel Natu vlapic_update_ppr(vlapic); 917051f2bd1SNeel Natu } 91879ad53fbSNeel Natu } 919051f2bd1SNeel Natu 920051f2bd1SNeel Natu static uint8_t 921051f2bd1SNeel Natu vlapic_get_tpr(struct vlapic *vlapic) 922051f2bd1SNeel Natu { 923051f2bd1SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 924051f2bd1SNeel Natu 925051f2bd1SNeel Natu return (lapic->tpr); 926051f2bd1SNeel Natu } 927051f2bd1SNeel Natu 928051f2bd1SNeel Natu void 929051f2bd1SNeel Natu vlapic_set_cr8(struct vlapic *vlapic, uint64_t val) 930051f2bd1SNeel Natu { 931051f2bd1SNeel Natu uint8_t tpr; 932051f2bd1SNeel Natu 933051f2bd1SNeel Natu if (val & ~0xf) { 934d3956e46SJohn Baldwin vm_inject_gp(vlapic->vcpu); 935051f2bd1SNeel Natu return; 936051f2bd1SNeel Natu } 937051f2bd1SNeel Natu 938051f2bd1SNeel Natu tpr = val << 4; 939051f2bd1SNeel Natu vlapic_set_tpr(vlapic, tpr); 940051f2bd1SNeel Natu } 941051f2bd1SNeel Natu 942051f2bd1SNeel Natu uint64_t 943051f2bd1SNeel Natu vlapic_get_cr8(struct vlapic *vlapic) 944051f2bd1SNeel Natu { 945051f2bd1SNeel Natu uint8_t tpr; 946051f2bd1SNeel Natu 947051f2bd1SNeel Natu tpr = vlapic_get_tpr(vlapic); 948051f2bd1SNeel Natu return (tpr >> 4); 949051f2bd1SNeel Natu } 950051f2bd1SNeel Natu 9512a2a64c4SCorvin Köhne static bool 9522a2a64c4SCorvin Köhne vlapic_is_icr_valid(uint64_t icrval) 9532a2a64c4SCorvin Köhne { 9542a2a64c4SCorvin Köhne uint32_t mode = icrval & APIC_DELMODE_MASK; 9552a2a64c4SCorvin Köhne uint32_t level = icrval & APIC_LEVEL_MASK; 9562a2a64c4SCorvin Köhne uint32_t trigger = icrval & APIC_TRIGMOD_MASK; 9572a2a64c4SCorvin Köhne uint32_t shorthand = icrval & APIC_DEST_MASK; 9582a2a64c4SCorvin Köhne 9592a2a64c4SCorvin Köhne switch (mode) { 9602a2a64c4SCorvin Köhne case APIC_DELMODE_FIXED: 9612a2a64c4SCorvin Köhne if (trigger == APIC_TRIGMOD_EDGE) 9622a2a64c4SCorvin Köhne return (true); 9632a2a64c4SCorvin Köhne /* 9642a2a64c4SCorvin Köhne * AMD allows a level assert IPI and Intel converts a level 9652a2a64c4SCorvin Köhne * assert IPI into an edge IPI. 9662a2a64c4SCorvin Köhne */ 9672a2a64c4SCorvin Köhne if (trigger == APIC_TRIGMOD_LEVEL && level == APIC_LEVEL_ASSERT) 9682a2a64c4SCorvin Köhne return (true); 9692a2a64c4SCorvin Köhne break; 9702a2a64c4SCorvin Köhne case APIC_DELMODE_LOWPRIO: 9712a2a64c4SCorvin Köhne case APIC_DELMODE_SMI: 9722a2a64c4SCorvin Köhne case APIC_DELMODE_NMI: 9732a2a64c4SCorvin Köhne case APIC_DELMODE_INIT: 9742a2a64c4SCorvin Köhne if (trigger == APIC_TRIGMOD_EDGE && 9752a2a64c4SCorvin Köhne (shorthand == APIC_DEST_DESTFLD || 9762a2a64c4SCorvin Köhne shorthand == APIC_DEST_ALLESELF)) 9772a2a64c4SCorvin Köhne return (true); 9782a2a64c4SCorvin Köhne /* 9792a2a64c4SCorvin Köhne * AMD allows a level assert IPI and Intel converts a level 9802a2a64c4SCorvin Köhne * assert IPI into an edge IPI. 9812a2a64c4SCorvin Köhne */ 9822a2a64c4SCorvin Köhne if (trigger == APIC_TRIGMOD_LEVEL && 9832a2a64c4SCorvin Köhne level == APIC_LEVEL_ASSERT && 9842a2a64c4SCorvin Köhne (shorthand == APIC_DEST_DESTFLD || 9852a2a64c4SCorvin Köhne shorthand == APIC_DEST_ALLESELF)) 9862a2a64c4SCorvin Köhne return (true); 9872a2a64c4SCorvin Köhne /* 9882a2a64c4SCorvin Köhne * An level triggered deassert INIT is defined in the Intel 9892a2a64c4SCorvin Köhne * Multiprocessor Specification and the Intel Software Developer 9902a2a64c4SCorvin Köhne * Manual. Due to the MPS it's required to send a level assert 9912a2a64c4SCorvin Köhne * INIT to a cpu and then a level deassert INIT. Some operating 9922a2a64c4SCorvin Köhne * systems e.g. FreeBSD or Linux use that algorithm. According 9932a2a64c4SCorvin Köhne * to the SDM a level deassert INIT is only supported by Pentium 9942a2a64c4SCorvin Köhne * and P6 processors. It's always send to all cpus regardless of 9952a2a64c4SCorvin Köhne * the destination or shorthand field. It resets the arbitration 9962a2a64c4SCorvin Köhne * id register. This register is not software accessible and 9972a2a64c4SCorvin Köhne * only required for the APIC bus arbitration. So, the level 9982a2a64c4SCorvin Köhne * deassert INIT doesn't need any emulation and we should ignore 9992a2a64c4SCorvin Köhne * it. The SDM also defines that newer processors don't support 10002a2a64c4SCorvin Köhne * the level deassert INIT and it's not valid any more. As it's 10012a2a64c4SCorvin Köhne * defined for older systems, it can't be invalid per se. 10022a2a64c4SCorvin Köhne * Otherwise, backward compatibility would be broken. However, 10032a2a64c4SCorvin Köhne * when returning false here, it'll be ignored which is the 10042a2a64c4SCorvin Köhne * desired behaviour. 10052a2a64c4SCorvin Köhne */ 10062a2a64c4SCorvin Köhne if (mode == APIC_DELMODE_INIT && 10072a2a64c4SCorvin Köhne trigger == APIC_TRIGMOD_LEVEL && 10082a2a64c4SCorvin Köhne level == APIC_LEVEL_DEASSERT) 10092a2a64c4SCorvin Köhne return (false); 10102a2a64c4SCorvin Köhne break; 10112a2a64c4SCorvin Köhne case APIC_DELMODE_STARTUP: 10122a2a64c4SCorvin Köhne if (shorthand == APIC_DEST_DESTFLD || 10132a2a64c4SCorvin Köhne shorthand == APIC_DEST_ALLESELF) 10142a2a64c4SCorvin Köhne return (true); 10152a2a64c4SCorvin Köhne break; 10162a2a64c4SCorvin Köhne case APIC_DELMODE_RR: 10172a2a64c4SCorvin Köhne /* Only available on AMD! */ 10182a2a64c4SCorvin Köhne if (trigger == APIC_TRIGMOD_EDGE && 10192a2a64c4SCorvin Köhne shorthand == APIC_DEST_DESTFLD) 10202a2a64c4SCorvin Köhne return (true); 10212a2a64c4SCorvin Köhne break; 10222a2a64c4SCorvin Köhne case APIC_DELMODE_RESV: 10232a2a64c4SCorvin Köhne return (false); 10242a2a64c4SCorvin Köhne default: 10252a2a64c4SCorvin Köhne __assert_unreachable(); 10262a2a64c4SCorvin Köhne } 10272a2a64c4SCorvin Köhne 10282a2a64c4SCorvin Köhne return (false); 10292a2a64c4SCorvin Köhne } 10302a2a64c4SCorvin Köhne 1031fafe8844SNeel Natu int 1032fafe8844SNeel Natu vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu) 1033366f6083SPeter Grehan { 1034366f6083SPeter Grehan int i; 10354f8be175SNeel Natu bool phys; 10360bda8d3eSCorvin Köhne cpuset_t dmask, ipimask; 1037fafe8844SNeel Natu uint64_t icrval; 10380bda8d3eSCorvin Köhne uint32_t dest, vec, mode, shorthand; 10393f0f4b15SJohn Baldwin struct vcpu *vcpu; 1040edf89256SNeel Natu struct vm_exit *vmexit; 1041fafe8844SNeel Natu struct LAPIC *lapic; 1042fafe8844SNeel Natu 1043fafe8844SNeel Natu lapic = vlapic->apic_page; 1044fafe8844SNeel Natu lapic->icr_lo &= ~APIC_DELSTAT_PEND; 1045fafe8844SNeel Natu icrval = ((uint64_t)lapic->icr_hi << 32) | lapic->icr_lo; 1046366f6083SPeter Grehan 1047a2da7af6SNeel Natu if (x2apic(vlapic)) 1048366f6083SPeter Grehan dest = icrval >> 32; 1049a2da7af6SNeel Natu else 1050a2da7af6SNeel Natu dest = icrval >> (32 + 24); 1051366f6083SPeter Grehan vec = icrval & APIC_VECTOR_MASK; 1052366f6083SPeter Grehan mode = icrval & APIC_DELMODE_MASK; 10530bda8d3eSCorvin Köhne phys = (icrval & APIC_DESTMODE_LOG) == 0; 10540bda8d3eSCorvin Köhne shorthand = icrval & APIC_DEST_MASK; 105583b65d0aSEmmanuel Vadot 10564d1e82a8SNeel Natu VLAPIC_CTR2(vlapic, "icrlo 0x%016lx triggered ipi %d", icrval, vec); 10574d1e82a8SNeel Natu 10580bda8d3eSCorvin Köhne switch (shorthand) { 1059366f6083SPeter Grehan case APIC_DEST_DESTFLD: 10600bda8d3eSCorvin Köhne vlapic_calcdest(vlapic->vm, &dmask, dest, phys, false, x2apic(vlapic)); 1061366f6083SPeter Grehan break; 1062366f6083SPeter Grehan case APIC_DEST_SELF: 1063a5615c90SPeter Grehan CPU_SETOF(vlapic->vcpuid, &dmask); 1064366f6083SPeter Grehan break; 1065366f6083SPeter Grehan case APIC_DEST_ALLISELF: 1066366f6083SPeter Grehan dmask = vm_active_cpus(vlapic->vm); 1067366f6083SPeter Grehan break; 1068366f6083SPeter Grehan case APIC_DEST_ALLESELF: 1069a5615c90SPeter Grehan dmask = vm_active_cpus(vlapic->vm); 1070a5615c90SPeter Grehan CPU_CLR(vlapic->vcpuid, &dmask); 1071366f6083SPeter Grehan break; 10721e2751ddSSergey Kandaurov default: 10730bda8d3eSCorvin Köhne __assert_unreachable(); 10740bda8d3eSCorvin Köhne } 10750bda8d3eSCorvin Köhne 10760bda8d3eSCorvin Köhne /* 10772a2a64c4SCorvin Köhne * Ignore invalid combinations of the icr. 10782a2a64c4SCorvin Köhne */ 10792a2a64c4SCorvin Köhne if (!vlapic_is_icr_valid(icrval)) { 10802a2a64c4SCorvin Köhne VLAPIC_CTR1(vlapic, "Ignoring invalid ICR %016lx", icrval); 10812a2a64c4SCorvin Köhne return (0); 10822a2a64c4SCorvin Köhne } 10832a2a64c4SCorvin Köhne 10842a2a64c4SCorvin Köhne /* 10850bda8d3eSCorvin Köhne * ipimask is a set of vCPUs needing userland handling of the current 10860bda8d3eSCorvin Köhne * IPI. 10870bda8d3eSCorvin Köhne */ 10880bda8d3eSCorvin Köhne CPU_ZERO(&ipimask); 10890bda8d3eSCorvin Köhne 10900bda8d3eSCorvin Köhne switch (mode) { 10910bda8d3eSCorvin Köhne case APIC_DELMODE_FIXED: 10920bda8d3eSCorvin Köhne if (vec < 16) { 10930bda8d3eSCorvin Köhne vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR, 10940bda8d3eSCorvin Köhne false); 10950bda8d3eSCorvin Köhne VLAPIC_CTR1(vlapic, "Ignoring invalid IPI %d", vec); 10960bda8d3eSCorvin Köhne return (0); 1097366f6083SPeter Grehan } 1098366f6083SPeter Grehan 1099de855429SMark Johnston CPU_FOREACH_ISSET(i, &dmask) { 11003f0f4b15SJohn Baldwin vcpu = vm_vcpu(vlapic->vm, i); 11013f0f4b15SJohn Baldwin lapic_intr_edge(vcpu, vec); 110294a3876dSVitaliy Gusev vmm_stat_incr(vlapic->vcpu, VLAPIC_IPI_SEND, 1); 110394a3876dSVitaliy Gusev vmm_stat_incr(vcpu, VLAPIC_IPI_RECV, 1); 11040bda8d3eSCorvin Köhne VLAPIC_CTR2(vlapic, 11050bda8d3eSCorvin Köhne "vlapic sending ipi %d to vcpuid %d", vec, i); 11060bda8d3eSCorvin Köhne } 11070bda8d3eSCorvin Köhne 11080bda8d3eSCorvin Köhne break; 11090bda8d3eSCorvin Köhne case APIC_DELMODE_NMI: 11100bda8d3eSCorvin Köhne CPU_FOREACH_ISSET(i, &dmask) { 11113f0f4b15SJohn Baldwin vcpu = vm_vcpu(vlapic->vm, i); 11123f0f4b15SJohn Baldwin vm_inject_nmi(vcpu); 11130bda8d3eSCorvin Köhne VLAPIC_CTR1(vlapic, 11140bda8d3eSCorvin Köhne "vlapic sending ipi nmi to vcpuid %d", i); 1115366f6083SPeter Grehan } 1116366f6083SPeter Grehan 11170bda8d3eSCorvin Köhne break; 11180bda8d3eSCorvin Köhne case APIC_DELMODE_INIT: 11190bda8d3eSCorvin Köhne case APIC_DELMODE_STARTUP: 1120769b884eSJohn Baldwin if (!vlapic->ipi_exit) { 1121769b884eSJohn Baldwin if (!phys) 1122769b884eSJohn Baldwin break; 1123769b884eSJohn Baldwin 1124769b884eSJohn Baldwin i = vm_apicid2vcpuid(vlapic->vm, dest); 1125769b884eSJohn Baldwin if (i >= vm_get_maxcpus(vlapic->vm) || 1126769b884eSJohn Baldwin i == vlapic->vcpuid) 1127769b884eSJohn Baldwin break; 1128769b884eSJohn Baldwin 11297c326ab5SCorvin Köhne CPU_SETOF(i, &ipimask); 1130769b884eSJohn Baldwin 1131769b884eSJohn Baldwin break; 1132769b884eSJohn Baldwin } 1133769b884eSJohn Baldwin 11347c326ab5SCorvin Köhne CPU_COPY(&dmask, &ipimask); 11350bda8d3eSCorvin Köhne break; 11360bda8d3eSCorvin Köhne default: 11370bda8d3eSCorvin Köhne return (1); 11380bda8d3eSCorvin Köhne } 11390bda8d3eSCorvin Köhne 11400bda8d3eSCorvin Köhne if (!CPU_EMPTY(&ipimask)) { 114180cb5d84SJohn Baldwin vmexit = vm_exitinfo(vlapic->vcpu); 11420bda8d3eSCorvin Köhne vmexit->exitcode = VM_EXITCODE_IPI; 11430bda8d3eSCorvin Köhne vmexit->u.ipi.mode = mode; 11440bda8d3eSCorvin Köhne vmexit->u.ipi.vector = vec; 1145e17eca32SMark Johnston *vm_exitinfo_cpuset(vlapic->vcpu) = ipimask; 1146edf89256SNeel Natu 1147becd9849SNeel Natu *retu = true; 11480bda8d3eSCorvin Köhne } 1149a5a918b7SCorvin Köhne 1150a5a918b7SCorvin Köhne return (0); 1151366f6083SPeter Grehan } 11520bda8d3eSCorvin Köhne 11530bda8d3eSCorvin Köhne static void 1154d8be3d52SJohn Baldwin vlapic_handle_init(struct vcpu *vcpu, void *arg) 11550bda8d3eSCorvin Köhne { 1156d8be3d52SJohn Baldwin struct vlapic *vlapic = vm_lapic(vcpu); 11570bda8d3eSCorvin Köhne 11580bda8d3eSCorvin Köhne vlapic_reset(vlapic); 11593fc17484SEmmanuel Vadot } 11603fc17484SEmmanuel Vadot 11610bda8d3eSCorvin Köhne int 1162d8be3d52SJohn Baldwin vm_handle_ipi(struct vcpu *vcpu, struct vm_exit *vme, bool *retu) 11630bda8d3eSCorvin Köhne { 11647c326ab5SCorvin Köhne struct vlapic *vlapic = vm_lapic(vcpu); 1165e17eca32SMark Johnston cpuset_t *dmask = vm_exitinfo_cpuset(vcpu); 11667c326ab5SCorvin Köhne uint8_t vec = vme->u.ipi.vector; 11677c326ab5SCorvin Köhne 11680bda8d3eSCorvin Köhne *retu = true; 11690bda8d3eSCorvin Köhne switch (vme->u.ipi.mode) { 1170b265a2e0SMark Johnston case APIC_DELMODE_INIT: { 1171b265a2e0SMark Johnston cpuset_t active, reinit; 1172b265a2e0SMark Johnston 1173b265a2e0SMark Johnston active = vm_active_cpus(vcpu_vm(vcpu)); 1174b265a2e0SMark Johnston CPU_AND(&reinit, &active, dmask); 1175b265a2e0SMark Johnston if (!CPU_EMPTY(&reinit)) { 1176b265a2e0SMark Johnston vm_smp_rendezvous(vcpu, reinit, vlapic_handle_init, 1177d8be3d52SJohn Baldwin NULL); 1178b265a2e0SMark Johnston } 11797c326ab5SCorvin Köhne vm_await_start(vcpu_vm(vcpu), dmask); 11807c326ab5SCorvin Köhne 1181b265a2e0SMark Johnston if (!vlapic->ipi_exit) 11827c326ab5SCorvin Köhne *retu = false; 11837c326ab5SCorvin Köhne 11840bda8d3eSCorvin Köhne break; 1185b265a2e0SMark Johnston } 11860bda8d3eSCorvin Köhne case APIC_DELMODE_STARTUP: 11877c326ab5SCorvin Köhne /* 11887c326ab5SCorvin Köhne * Ignore SIPIs in any state other than wait-for-SIPI 11897c326ab5SCorvin Köhne */ 11907c326ab5SCorvin Köhne *dmask = vm_start_cpus(vcpu_vm(vcpu), dmask); 11917c326ab5SCorvin Köhne 11927c326ab5SCorvin Köhne if (CPU_EMPTY(dmask)) { 11937c326ab5SCorvin Köhne *retu = false; 11947c326ab5SCorvin Köhne break; 11957c326ab5SCorvin Köhne } 11967c326ab5SCorvin Köhne 11977c326ab5SCorvin Köhne /* 11987c326ab5SCorvin Köhne * Old bhyve versions don't support the IPI 11997c326ab5SCorvin Köhne * exit. Translate it into the old style. 12007c326ab5SCorvin Köhne */ 12017c326ab5SCorvin Köhne if (!vlapic->ipi_exit) { 12027c326ab5SCorvin Köhne vme->exitcode = VM_EXITCODE_SPINUP_AP; 1203b265a2e0SMark Johnston vme->u.spinup_ap.vcpu = CPU_FFS(dmask) - 1; 12047c326ab5SCorvin Köhne vme->u.spinup_ap.rip = vec << PAGE_SHIFT; 12057c326ab5SCorvin Köhne } 12067c326ab5SCorvin Köhne 12070bda8d3eSCorvin Köhne break; 12080bda8d3eSCorvin Köhne default: 1209b265a2e0SMark Johnston __assert_unreachable(); 12103fc17484SEmmanuel Vadot } 1211366f6083SPeter Grehan 12120bda8d3eSCorvin Köhne return (0); 12130bda8d3eSCorvin Köhne } 12140bda8d3eSCorvin Köhne 1215159dd56fSNeel Natu void 1216294d0d88SNeel Natu vlapic_self_ipi_handler(struct vlapic *vlapic, uint64_t val) 1217294d0d88SNeel Natu { 1218294d0d88SNeel Natu int vec; 1219294d0d88SNeel Natu 1220159dd56fSNeel Natu KASSERT(x2apic(vlapic), ("SELF_IPI does not exist in xAPIC mode")); 1221159dd56fSNeel Natu 1222294d0d88SNeel Natu vec = val & 0xff; 12233f0f4b15SJohn Baldwin lapic_intr_edge(vlapic->vcpu, vec); 122494a3876dSVitaliy Gusev vmm_stat_incr(vlapic->vcpu, VLAPIC_IPI_SEND, 1); 122594a3876dSVitaliy Gusev vmm_stat_incr(vlapic->vcpu, VLAPIC_IPI_RECV, 1); 1226294d0d88SNeel Natu VLAPIC_CTR1(vlapic, "vlapic self-ipi %d", vec); 1227294d0d88SNeel Natu } 1228294d0d88SNeel Natu 1229366f6083SPeter Grehan int 12304d1e82a8SNeel Natu vlapic_pending_intr(struct vlapic *vlapic, int *vecptr) 1231366f6083SPeter Grehan { 1232de5ea6b6SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 1233366f6083SPeter Grehan int idx, i, bitpos, vector; 1234366f6083SPeter Grehan uint32_t *irrptr, val; 1235366f6083SPeter Grehan 12361bc51badSMichael Reifenberger vlapic_update_ppr(vlapic); 12371bc51badSMichael Reifenberger 123888c4b8d1SNeel Natu if (vlapic->ops.pending_intr) 123988c4b8d1SNeel Natu return ((*vlapic->ops.pending_intr)(vlapic, vecptr)); 124088c4b8d1SNeel Natu 1241366f6083SPeter Grehan irrptr = &lapic->irr0; 1242366f6083SPeter Grehan 124344e2f0feSNeel Natu for (i = 7; i >= 0; i--) { 1244366f6083SPeter Grehan idx = i * 4; 1245366f6083SPeter Grehan val = atomic_load_acq_int(&irrptr[idx]); 1246366f6083SPeter Grehan bitpos = fls(val); 1247366f6083SPeter Grehan if (bitpos != 0) { 1248366f6083SPeter Grehan vector = i * 32 + (bitpos - 1); 1249366f6083SPeter Grehan if (PRIO(vector) > PRIO(lapic->ppr)) { 1250366f6083SPeter Grehan VLAPIC_CTR1(vlapic, "pending intr %d", vector); 12514d1e82a8SNeel Natu if (vecptr != NULL) 12524d1e82a8SNeel Natu *vecptr = vector; 12534d1e82a8SNeel Natu return (1); 1254366f6083SPeter Grehan } else 1255366f6083SPeter Grehan break; 1256366f6083SPeter Grehan } 1257366f6083SPeter Grehan } 12584d1e82a8SNeel Natu return (0); 1259366f6083SPeter Grehan } 1260366f6083SPeter Grehan 1261366f6083SPeter Grehan void 1262366f6083SPeter Grehan vlapic_intr_accepted(struct vlapic *vlapic, int vector) 1263366f6083SPeter Grehan { 1264de5ea6b6SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 1265366f6083SPeter Grehan uint32_t *irrptr, *isrptr; 1266366f6083SPeter Grehan int idx, stk_top; 1267366f6083SPeter Grehan 126888c4b8d1SNeel Natu if (vlapic->ops.intr_accepted) 126988c4b8d1SNeel Natu return ((*vlapic->ops.intr_accepted)(vlapic, vector)); 127088c4b8d1SNeel Natu 1271366f6083SPeter Grehan /* 1272366f6083SPeter Grehan * clear the ready bit for vector being accepted in irr 1273366f6083SPeter Grehan * and set the vector as in service in isr. 1274366f6083SPeter Grehan */ 1275366f6083SPeter Grehan idx = (vector / 32) * 4; 1276366f6083SPeter Grehan 1277366f6083SPeter Grehan irrptr = &lapic->irr0; 1278366f6083SPeter Grehan atomic_clear_int(&irrptr[idx], 1 << (vector % 32)); 1279366f6083SPeter Grehan VLAPIC_CTR_IRR(vlapic, "vlapic_intr_accepted"); 1280366f6083SPeter Grehan 1281366f6083SPeter Grehan isrptr = &lapic->isr0; 1282366f6083SPeter Grehan isrptr[idx] |= 1 << (vector % 32); 1283366f6083SPeter Grehan VLAPIC_CTR_ISR(vlapic, "vlapic_intr_accepted"); 1284366f6083SPeter Grehan 1285366f6083SPeter Grehan /* 1286366f6083SPeter Grehan * Update the PPR 1287366f6083SPeter Grehan */ 1288366f6083SPeter Grehan vlapic->isrvec_stk_top++; 1289366f6083SPeter Grehan 1290366f6083SPeter Grehan stk_top = vlapic->isrvec_stk_top; 1291366f6083SPeter Grehan if (stk_top >= ISRVEC_STK_SIZE) 1292366f6083SPeter Grehan panic("isrvec_stk_top overflow %d", stk_top); 1293366f6083SPeter Grehan 1294366f6083SPeter Grehan vlapic->isrvec_stk[stk_top] = vector; 1295366f6083SPeter Grehan } 1296366f6083SPeter Grehan 12972c52dcd9SNeel Natu void 12982c52dcd9SNeel Natu vlapic_svr_write_handler(struct vlapic *vlapic) 12991c052192SNeel Natu { 13001c052192SNeel Natu struct LAPIC *lapic; 13012c52dcd9SNeel Natu uint32_t old, new, changed; 13021c052192SNeel Natu 1303de5ea6b6SNeel Natu lapic = vlapic->apic_page; 13042c52dcd9SNeel Natu 13052c52dcd9SNeel Natu new = lapic->svr; 13062c52dcd9SNeel Natu old = vlapic->svr_last; 13072c52dcd9SNeel Natu vlapic->svr_last = new; 13082c52dcd9SNeel Natu 13091c052192SNeel Natu changed = old ^ new; 13101c052192SNeel Natu if ((changed & APIC_SVR_ENABLE) != 0) { 13111c052192SNeel Natu if ((new & APIC_SVR_ENABLE) == 0) { 1312fb03ca4eSNeel Natu /* 13132c52dcd9SNeel Natu * The apic is now disabled so stop the apic timer 13142c52dcd9SNeel Natu * and mask all the LVT entries. 1315fb03ca4eSNeel Natu */ 13161c052192SNeel Natu VLAPIC_CTR0(vlapic, "vlapic is software-disabled"); 1317fb03ca4eSNeel Natu VLAPIC_TIMER_LOCK(vlapic); 1318fb03ca4eSNeel Natu callout_stop(&vlapic->callout); 1319fb03ca4eSNeel Natu VLAPIC_TIMER_UNLOCK(vlapic); 13202c52dcd9SNeel Natu vlapic_mask_lvts(vlapic); 13211c052192SNeel Natu } else { 1322fb03ca4eSNeel Natu /* 1323fb03ca4eSNeel Natu * The apic is now enabled so restart the apic timer 1324fb03ca4eSNeel Natu * if it is configured in periodic mode. 1325fb03ca4eSNeel Natu */ 13261c052192SNeel Natu VLAPIC_CTR0(vlapic, "vlapic is software-enabled"); 1327fb03ca4eSNeel Natu if (vlapic_periodic_timer(vlapic)) 1328fafe8844SNeel Natu vlapic_icrtmr_write_handler(vlapic); 13291c052192SNeel Natu } 13301c052192SNeel Natu } 13311c052192SNeel Natu } 13321c052192SNeel Natu 1333366f6083SPeter Grehan int 133452e5c8a2SNeel Natu vlapic_read(struct vlapic *vlapic, int mmio_access, uint64_t offset, 133552e5c8a2SNeel Natu uint64_t *data, bool *retu) 1336366f6083SPeter Grehan { 1337de5ea6b6SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 1338366f6083SPeter Grehan uint32_t *reg; 1339366f6083SPeter Grehan int i; 1340366f6083SPeter Grehan 134152e5c8a2SNeel Natu /* Ignore MMIO accesses in x2APIC mode */ 134252e5c8a2SNeel Natu if (x2apic(vlapic) && mmio_access) { 134352e5c8a2SNeel Natu VLAPIC_CTR1(vlapic, "MMIO read from offset %#lx in x2APIC mode", 134452e5c8a2SNeel Natu offset); 134552e5c8a2SNeel Natu *data = 0; 134652e5c8a2SNeel Natu goto done; 134752e5c8a2SNeel Natu } 134852e5c8a2SNeel Natu 134952e5c8a2SNeel Natu if (!x2apic(vlapic) && !mmio_access) { 135052e5c8a2SNeel Natu /* 135152e5c8a2SNeel Natu * XXX Generate GP fault for MSR accesses in xAPIC mode 135252e5c8a2SNeel Natu */ 135352e5c8a2SNeel Natu VLAPIC_CTR1(vlapic, "x2APIC MSR read from offset %#lx in " 135452e5c8a2SNeel Natu "xAPIC mode", offset); 135552e5c8a2SNeel Natu *data = 0; 135652e5c8a2SNeel Natu goto done; 135752e5c8a2SNeel Natu } 135852e5c8a2SNeel Natu 1359366f6083SPeter Grehan if (offset > sizeof(*lapic)) { 1360366f6083SPeter Grehan *data = 0; 13611c052192SNeel Natu goto done; 1362366f6083SPeter Grehan } 1363366f6083SPeter Grehan 1364366f6083SPeter Grehan offset &= ~3; 1365366f6083SPeter Grehan switch(offset) 1366366f6083SPeter Grehan { 1367366f6083SPeter Grehan case APIC_OFFSET_ID: 13683f0ddc7cSNeel Natu *data = lapic->id; 1369366f6083SPeter Grehan break; 1370366f6083SPeter Grehan case APIC_OFFSET_VER: 1371366f6083SPeter Grehan *data = lapic->version; 1372366f6083SPeter Grehan break; 1373366f6083SPeter Grehan case APIC_OFFSET_TPR: 1374594db002STycho Nightingale *data = vlapic_get_tpr(vlapic); 1375366f6083SPeter Grehan break; 1376366f6083SPeter Grehan case APIC_OFFSET_APR: 1377366f6083SPeter Grehan *data = lapic->apr; 1378366f6083SPeter Grehan break; 1379366f6083SPeter Grehan case APIC_OFFSET_PPR: 1380366f6083SPeter Grehan *data = lapic->ppr; 1381366f6083SPeter Grehan break; 1382366f6083SPeter Grehan case APIC_OFFSET_EOI: 1383366f6083SPeter Grehan *data = lapic->eoi; 1384366f6083SPeter Grehan break; 1385366f6083SPeter Grehan case APIC_OFFSET_LDR: 13863f0ddc7cSNeel Natu *data = lapic->ldr; 1387366f6083SPeter Grehan break; 1388366f6083SPeter Grehan case APIC_OFFSET_DFR: 13893f0ddc7cSNeel Natu *data = lapic->dfr; 1390366f6083SPeter Grehan break; 1391366f6083SPeter Grehan case APIC_OFFSET_SVR: 1392366f6083SPeter Grehan *data = lapic->svr; 1393366f6083SPeter Grehan break; 1394366f6083SPeter Grehan case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7: 1395366f6083SPeter Grehan i = (offset - APIC_OFFSET_ISR0) >> 2; 1396366f6083SPeter Grehan reg = &lapic->isr0; 1397366f6083SPeter Grehan *data = *(reg + i); 1398366f6083SPeter Grehan break; 1399366f6083SPeter Grehan case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7: 1400366f6083SPeter Grehan i = (offset - APIC_OFFSET_TMR0) >> 2; 1401366f6083SPeter Grehan reg = &lapic->tmr0; 1402366f6083SPeter Grehan *data = *(reg + i); 1403366f6083SPeter Grehan break; 1404366f6083SPeter Grehan case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7: 1405366f6083SPeter Grehan i = (offset - APIC_OFFSET_IRR0) >> 2; 1406366f6083SPeter Grehan reg = &lapic->irr0; 1407366f6083SPeter Grehan *data = atomic_load_acq_int(reg + i); 1408366f6083SPeter Grehan break; 1409366f6083SPeter Grehan case APIC_OFFSET_ESR: 1410366f6083SPeter Grehan *data = lapic->esr; 1411366f6083SPeter Grehan break; 1412366f6083SPeter Grehan case APIC_OFFSET_ICR_LOW: 1413366f6083SPeter Grehan *data = lapic->icr_lo; 1414fafe8844SNeel Natu if (x2apic(vlapic)) 1415fafe8844SNeel Natu *data |= (uint64_t)lapic->icr_hi << 32; 1416366f6083SPeter Grehan break; 1417366f6083SPeter Grehan case APIC_OFFSET_ICR_HI: 1418366f6083SPeter Grehan *data = lapic->icr_hi; 1419366f6083SPeter Grehan break; 1420330baf58SJohn Baldwin case APIC_OFFSET_CMCI_LVT: 1421366f6083SPeter Grehan case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: 1422fb03ca4eSNeel Natu *data = vlapic_get_lvt(vlapic, offset); 14237c05bc31SNeel Natu #ifdef INVARIANTS 14247c05bc31SNeel Natu reg = vlapic_get_lvtptr(vlapic, offset); 14257c05bc31SNeel Natu KASSERT(*data == *reg, ("inconsistent lvt value at " 14267c05bc31SNeel Natu "offset %#lx: %#lx/%#x", offset, *data, *reg)); 14277c05bc31SNeel Natu #endif 1428366f6083SPeter Grehan break; 1429de5ea6b6SNeel Natu case APIC_OFFSET_TIMER_ICR: 1430366f6083SPeter Grehan *data = lapic->icr_timer; 1431366f6083SPeter Grehan break; 1432de5ea6b6SNeel Natu case APIC_OFFSET_TIMER_CCR: 1433366f6083SPeter Grehan *data = vlapic_get_ccr(vlapic); 1434366f6083SPeter Grehan break; 1435de5ea6b6SNeel Natu case APIC_OFFSET_TIMER_DCR: 1436366f6083SPeter Grehan *data = lapic->dcr_timer; 1437366f6083SPeter Grehan break; 1438294d0d88SNeel Natu case APIC_OFFSET_SELF_IPI: 1439294d0d88SNeel Natu /* 1440294d0d88SNeel Natu * XXX generate a GP fault if vlapic is in x2apic mode 1441294d0d88SNeel Natu */ 1442294d0d88SNeel Natu *data = 0; 1443294d0d88SNeel Natu break; 1444366f6083SPeter Grehan case APIC_OFFSET_RRR: 1445366f6083SPeter Grehan default: 1446366f6083SPeter Grehan *data = 0; 1447366f6083SPeter Grehan break; 1448366f6083SPeter Grehan } 14491c052192SNeel Natu done: 14501c052192SNeel Natu VLAPIC_CTR2(vlapic, "vlapic read offset %#x, data %#lx", offset, *data); 1451366f6083SPeter Grehan return 0; 1452366f6083SPeter Grehan } 1453366f6083SPeter Grehan 1454366f6083SPeter Grehan int 145552e5c8a2SNeel Natu vlapic_write(struct vlapic *vlapic, int mmio_access, uint64_t offset, 145652e5c8a2SNeel Natu uint64_t data, bool *retu) 1457366f6083SPeter Grehan { 1458de5ea6b6SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 14597c05bc31SNeel Natu uint32_t *regptr; 1460366f6083SPeter Grehan int retval; 1461366f6083SPeter Grehan 14623f0ddc7cSNeel Natu KASSERT((offset & 0xf) == 0 && offset < PAGE_SIZE, 14633f0ddc7cSNeel Natu ("vlapic_write: invalid offset %#lx", offset)); 14643f0ddc7cSNeel Natu 146552e5c8a2SNeel Natu VLAPIC_CTR2(vlapic, "vlapic write offset %#lx, data %#lx", 146652e5c8a2SNeel Natu offset, data); 14671c052192SNeel Natu 146852e5c8a2SNeel Natu if (offset > sizeof(*lapic)) 146952e5c8a2SNeel Natu return (0); 147052e5c8a2SNeel Natu 147152e5c8a2SNeel Natu /* Ignore MMIO accesses in x2APIC mode */ 147252e5c8a2SNeel Natu if (x2apic(vlapic) && mmio_access) { 147352e5c8a2SNeel Natu VLAPIC_CTR2(vlapic, "MMIO write of %#lx to offset %#lx " 147452e5c8a2SNeel Natu "in x2APIC mode", data, offset); 147552e5c8a2SNeel Natu return (0); 147652e5c8a2SNeel Natu } 147752e5c8a2SNeel Natu 147852e5c8a2SNeel Natu /* 147952e5c8a2SNeel Natu * XXX Generate GP fault for MSR accesses in xAPIC mode 148052e5c8a2SNeel Natu */ 148152e5c8a2SNeel Natu if (!x2apic(vlapic) && !mmio_access) { 148252e5c8a2SNeel Natu VLAPIC_CTR2(vlapic, "x2APIC MSR write of %#lx to offset %#lx " 148352e5c8a2SNeel Natu "in xAPIC mode", data, offset); 148452e5c8a2SNeel Natu return (0); 1485366f6083SPeter Grehan } 1486366f6083SPeter Grehan 1487366f6083SPeter Grehan retval = 0; 1488366f6083SPeter Grehan switch(offset) 1489366f6083SPeter Grehan { 1490366f6083SPeter Grehan case APIC_OFFSET_ID: 14913f0ddc7cSNeel Natu lapic->id = data; 14923f0ddc7cSNeel Natu vlapic_id_write_handler(vlapic); 1493366f6083SPeter Grehan break; 1494366f6083SPeter Grehan case APIC_OFFSET_TPR: 1495594db002STycho Nightingale vlapic_set_tpr(vlapic, data & 0xff); 1496366f6083SPeter Grehan break; 1497366f6083SPeter Grehan case APIC_OFFSET_EOI: 1498366f6083SPeter Grehan vlapic_process_eoi(vlapic); 1499366f6083SPeter Grehan break; 1500366f6083SPeter Grehan case APIC_OFFSET_LDR: 15013f0ddc7cSNeel Natu lapic->ldr = data; 15023f0ddc7cSNeel Natu vlapic_ldr_write_handler(vlapic); 1503366f6083SPeter Grehan break; 1504366f6083SPeter Grehan case APIC_OFFSET_DFR: 15053f0ddc7cSNeel Natu lapic->dfr = data; 15063f0ddc7cSNeel Natu vlapic_dfr_write_handler(vlapic); 1507366f6083SPeter Grehan break; 1508366f6083SPeter Grehan case APIC_OFFSET_SVR: 15092c52dcd9SNeel Natu lapic->svr = data; 15102c52dcd9SNeel Natu vlapic_svr_write_handler(vlapic); 1511366f6083SPeter Grehan break; 1512366f6083SPeter Grehan case APIC_OFFSET_ICR_LOW: 1513fafe8844SNeel Natu lapic->icr_lo = data; 1514fafe8844SNeel Natu if (x2apic(vlapic)) 1515fafe8844SNeel Natu lapic->icr_hi = data >> 32; 1516fafe8844SNeel Natu retval = vlapic_icrlo_write_handler(vlapic, retu); 1517366f6083SPeter Grehan break; 1518a2da7af6SNeel Natu case APIC_OFFSET_ICR_HI: 1519a2da7af6SNeel Natu lapic->icr_hi = data; 1520a2da7af6SNeel Natu break; 1521330baf58SJohn Baldwin case APIC_OFFSET_CMCI_LVT: 1522366f6083SPeter Grehan case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: 15237c05bc31SNeel Natu regptr = vlapic_get_lvtptr(vlapic, offset); 15247c05bc31SNeel Natu *regptr = data; 15257c05bc31SNeel Natu vlapic_lvt_write_handler(vlapic, offset); 1526366f6083SPeter Grehan break; 1527de5ea6b6SNeel Natu case APIC_OFFSET_TIMER_ICR: 1528fafe8844SNeel Natu lapic->icr_timer = data; 1529fafe8844SNeel Natu vlapic_icrtmr_write_handler(vlapic); 1530366f6083SPeter Grehan break; 1531366f6083SPeter Grehan 1532de5ea6b6SNeel Natu case APIC_OFFSET_TIMER_DCR: 1533fafe8844SNeel Natu lapic->dcr_timer = data; 1534fafe8844SNeel Natu vlapic_dcr_write_handler(vlapic); 1535366f6083SPeter Grehan break; 1536366f6083SPeter Grehan 1537366f6083SPeter Grehan case APIC_OFFSET_ESR: 1538fafe8844SNeel Natu vlapic_esr_write_handler(vlapic); 1539366f6083SPeter Grehan break; 1540294d0d88SNeel Natu 1541294d0d88SNeel Natu case APIC_OFFSET_SELF_IPI: 1542294d0d88SNeel Natu if (x2apic(vlapic)) 1543294d0d88SNeel Natu vlapic_self_ipi_handler(vlapic, data); 1544294d0d88SNeel Natu break; 1545294d0d88SNeel Natu 1546366f6083SPeter Grehan case APIC_OFFSET_VER: 1547366f6083SPeter Grehan case APIC_OFFSET_APR: 1548366f6083SPeter Grehan case APIC_OFFSET_PPR: 1549366f6083SPeter Grehan case APIC_OFFSET_RRR: 1550366f6083SPeter Grehan case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7: 1551366f6083SPeter Grehan case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7: 1552366f6083SPeter Grehan case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7: 1553de5ea6b6SNeel Natu case APIC_OFFSET_TIMER_CCR: 1554366f6083SPeter Grehan default: 1555366f6083SPeter Grehan // Read only. 1556366f6083SPeter Grehan break; 1557366f6083SPeter Grehan } 1558366f6083SPeter Grehan 1559366f6083SPeter Grehan return (retval); 1560366f6083SPeter Grehan } 1561366f6083SPeter Grehan 15627c05bc31SNeel Natu static void 15637c05bc31SNeel Natu vlapic_reset(struct vlapic *vlapic) 15647c05bc31SNeel Natu { 15657c05bc31SNeel Natu struct LAPIC *lapic; 15667c05bc31SNeel Natu 15677c05bc31SNeel Natu lapic = vlapic->apic_page; 15687c05bc31SNeel Natu bzero(lapic, sizeof(struct LAPIC)); 15697c05bc31SNeel Natu 15707c05bc31SNeel Natu lapic->id = vlapic_get_id(vlapic); 15717c05bc31SNeel Natu lapic->version = VLAPIC_VERSION; 15727c05bc31SNeel Natu lapic->version |= (VLAPIC_MAXLVT_INDEX << MAXLVTSHIFT); 15737c05bc31SNeel Natu lapic->dfr = 0xffffffff; 15747c05bc31SNeel Natu lapic->svr = APIC_SVR_VECTOR; 15757c05bc31SNeel Natu vlapic_mask_lvts(vlapic); 157630b94db8SNeel Natu vlapic_reset_tmr(vlapic); 15777c05bc31SNeel Natu 15787c05bc31SNeel Natu lapic->dcr_timer = 0; 15797c05bc31SNeel Natu vlapic_dcr_write_handler(vlapic); 15807c05bc31SNeel Natu 15817c05bc31SNeel Natu vlapic->svr_last = lapic->svr; 15827c05bc31SNeel Natu } 15837c05bc31SNeel Natu 1584de5ea6b6SNeel Natu void 1585de5ea6b6SNeel Natu vlapic_init(struct vlapic *vlapic) 1586366f6083SPeter Grehan { 1587de5ea6b6SNeel Natu KASSERT(vlapic->vm != NULL, ("vlapic_init: vm is not initialized")); 1588a488c9c9SRodney W. Grimes KASSERT(vlapic->vcpuid >= 0 && 1589a488c9c9SRodney W. Grimes vlapic->vcpuid < vm_get_maxcpus(vlapic->vm), 1590de5ea6b6SNeel Natu ("vlapic_init: vcpuid is not initialized")); 1591de5ea6b6SNeel Natu KASSERT(vlapic->apic_page != NULL, ("vlapic_init: apic_page is not " 1592de5ea6b6SNeel Natu "initialized")); 15932d3a73edSNeel Natu 1594becd9849SNeel Natu /* 1595becd9849SNeel Natu * If the vlapic is configured in x2apic mode then it will be 1596becd9849SNeel Natu * accessed in the critical section via the MSR emulation code. 1597becd9849SNeel Natu * 1598becd9849SNeel Natu * Therefore the timer mutex must be a spinlock because blockable 1599becd9849SNeel Natu * mutexes cannot be acquired in a critical section. 1600becd9849SNeel Natu */ 1601becd9849SNeel Natu mtx_init(&vlapic->timer_mtx, "vlapic timer mtx", NULL, MTX_SPIN); 1602fb03ca4eSNeel Natu callout_init(&vlapic->callout, 1); 1603fb03ca4eSNeel Natu 1604a2da7af6SNeel Natu vlapic->msr_apicbase = DEFAULT_APIC_BASE | APICBASE_ENABLED; 16052d3a73edSNeel Natu 1606de5ea6b6SNeel Natu if (vlapic->vcpuid == 0) 16072d3a73edSNeel Natu vlapic->msr_apicbase |= APICBASE_BSP; 16082d3a73edSNeel Natu 16090bda8d3eSCorvin Köhne vlapic->ipi_exit = false; 16100bda8d3eSCorvin Köhne 161103cd0501SNeel Natu vlapic_reset(vlapic); 1612366f6083SPeter Grehan } 1613366f6083SPeter Grehan 1614366f6083SPeter Grehan void 1615366f6083SPeter Grehan vlapic_cleanup(struct vlapic *vlapic) 1616366f6083SPeter Grehan { 161703cd0501SNeel Natu 1618fb03ca4eSNeel Natu callout_drain(&vlapic->callout); 161908ebb360SJohn Baldwin mtx_destroy(&vlapic->timer_mtx); 1620366f6083SPeter Grehan } 16212d3a73edSNeel Natu 16222d3a73edSNeel Natu uint64_t 16232d3a73edSNeel Natu vlapic_get_apicbase(struct vlapic *vlapic) 16242d3a73edSNeel Natu { 16252d3a73edSNeel Natu 16262d3a73edSNeel Natu return (vlapic->msr_apicbase); 16272d3a73edSNeel Natu } 16282d3a73edSNeel Natu 162952e5c8a2SNeel Natu int 16303f0ddc7cSNeel Natu vlapic_set_apicbase(struct vlapic *vlapic, uint64_t new) 16312d3a73edSNeel Natu { 1632a2da7af6SNeel Natu 163352e5c8a2SNeel Natu if (vlapic->msr_apicbase != new) { 163452e5c8a2SNeel Natu VLAPIC_CTR2(vlapic, "Changing APIC_BASE MSR from %#lx to %#lx " 163552e5c8a2SNeel Natu "not supported", vlapic->msr_apicbase, new); 163652e5c8a2SNeel Natu return (-1); 163752e5c8a2SNeel Natu } 163852e5c8a2SNeel Natu 163952e5c8a2SNeel Natu return (0); 164052e5c8a2SNeel Natu } 164152e5c8a2SNeel Natu 164252e5c8a2SNeel Natu void 1643d3956e46SJohn Baldwin vlapic_set_x2apic_state(struct vcpu *vcpu, enum x2apic_state state) 164452e5c8a2SNeel Natu { 164552e5c8a2SNeel Natu struct vlapic *vlapic; 164652e5c8a2SNeel Natu struct LAPIC *lapic; 164752e5c8a2SNeel Natu 1648d3956e46SJohn Baldwin vlapic = vm_lapic(vcpu); 1649a2da7af6SNeel Natu 1650a2da7af6SNeel Natu if (state == X2APIC_DISABLED) 165152e5c8a2SNeel Natu vlapic->msr_apicbase &= ~APICBASE_X2APIC; 165252e5c8a2SNeel Natu else 165352e5c8a2SNeel Natu vlapic->msr_apicbase |= APICBASE_X2APIC; 16543f0ddc7cSNeel Natu 16553f0ddc7cSNeel Natu /* 165652e5c8a2SNeel Natu * Reset the local APIC registers whose values are mode-dependent. 165752e5c8a2SNeel Natu * 165852e5c8a2SNeel Natu * XXX this works because the APIC mode can be changed only at vcpu 165952e5c8a2SNeel Natu * initialization time. 16603f0ddc7cSNeel Natu */ 16613f0ddc7cSNeel Natu lapic = vlapic->apic_page; 16623f0ddc7cSNeel Natu lapic->id = vlapic_get_id(vlapic); 16633f0ddc7cSNeel Natu if (x2apic(vlapic)) { 16643f0ddc7cSNeel Natu lapic->ldr = x2apic_ldr(vlapic); 16653f0ddc7cSNeel Natu lapic->dfr = 0; 16663f0ddc7cSNeel Natu } else { 16673f0ddc7cSNeel Natu lapic->ldr = 0; 16683f0ddc7cSNeel Natu lapic->dfr = 0xffffffff; 16693f0ddc7cSNeel Natu } 1670159dd56fSNeel Natu 1671159dd56fSNeel Natu if (state == X2APIC_ENABLED) { 1672159dd56fSNeel Natu if (vlapic->ops.enable_x2apic_mode) 1673159dd56fSNeel Natu (*vlapic->ops.enable_x2apic_mode)(vlapic); 1674159dd56fSNeel Natu } 16753f0ddc7cSNeel Natu } 16761c052192SNeel Natu 16774f8be175SNeel Natu void 16784f8be175SNeel Natu vlapic_deliver_intr(struct vm *vm, bool level, uint32_t dest, bool phys, 16794f8be175SNeel Natu int delmode, int vec) 16804f8be175SNeel Natu { 16813f0f4b15SJohn Baldwin struct vcpu *vcpu; 16824f8be175SNeel Natu bool lowprio; 16834f8be175SNeel Natu int vcpuid; 16844f8be175SNeel Natu cpuset_t dmask; 16854f8be175SNeel Natu 1686762fd208STycho Nightingale if (delmode != IOART_DELFIXED && 1687762fd208STycho Nightingale delmode != IOART_DELLOPRI && 1688762fd208STycho Nightingale delmode != IOART_DELEXINT) { 16894f8be175SNeel Natu VM_CTR1(vm, "vlapic intr invalid delmode %#x", delmode); 16904f8be175SNeel Natu return; 16914f8be175SNeel Natu } 1692762fd208STycho Nightingale lowprio = (delmode == IOART_DELLOPRI); 16934f8be175SNeel Natu 16944f8be175SNeel Natu /* 16954f8be175SNeel Natu * We don't provide any virtual interrupt redirection hardware so 16964f8be175SNeel Natu * all interrupts originating from the ioapic or MSI specify the 16974f8be175SNeel Natu * 'dest' in the legacy xAPIC format. 16984f8be175SNeel Natu */ 16994f8be175SNeel Natu vlapic_calcdest(vm, &dmask, dest, phys, lowprio, false); 17004f8be175SNeel Natu 1701de855429SMark Johnston CPU_FOREACH_ISSET(vcpuid, &dmask) { 17023f0f4b15SJohn Baldwin vcpu = vm_vcpu(vm, vcpuid); 1703762fd208STycho Nightingale if (delmode == IOART_DELEXINT) { 17043f0f4b15SJohn Baldwin vm_inject_extint(vcpu); 1705762fd208STycho Nightingale } else { 17063f0f4b15SJohn Baldwin lapic_set_intr(vcpu, vec, level); 17074f8be175SNeel Natu } 17084f8be175SNeel Natu } 1709762fd208STycho Nightingale } 17104f8be175SNeel Natu 1711de5ea6b6SNeel Natu void 1712add611fdSNeel Natu vlapic_post_intr(struct vlapic *vlapic, int hostcpu, int ipinum) 1713de5ea6b6SNeel Natu { 1714de5ea6b6SNeel Natu /* 1715de5ea6b6SNeel Natu * Post an interrupt to the vcpu currently running on 'hostcpu'. 1716de5ea6b6SNeel Natu * 1717de5ea6b6SNeel Natu * This is done by leveraging features like Posted Interrupts (Intel) 1718de5ea6b6SNeel Natu * Doorbell MSR (AMD AVIC) that avoid a VM exit. 1719de5ea6b6SNeel Natu * 1720de5ea6b6SNeel Natu * If neither of these features are available then fallback to 1721de5ea6b6SNeel Natu * sending an IPI to 'hostcpu'. 1722de5ea6b6SNeel Natu */ 172388c4b8d1SNeel Natu if (vlapic->ops.post_intr) 172488c4b8d1SNeel Natu (*vlapic->ops.post_intr)(vlapic, hostcpu); 172588c4b8d1SNeel Natu else 1726add611fdSNeel Natu ipi_cpu(hostcpu, ipinum); 1727de5ea6b6SNeel Natu } 1728de5ea6b6SNeel Natu 17291c052192SNeel Natu bool 17301c052192SNeel Natu vlapic_enabled(struct vlapic *vlapic) 17311c052192SNeel Natu { 1732de5ea6b6SNeel Natu struct LAPIC *lapic = vlapic->apic_page; 17331c052192SNeel Natu 17341c052192SNeel Natu if ((vlapic->msr_apicbase & APICBASE_ENABLED) != 0 && 17351c052192SNeel Natu (lapic->svr & APIC_SVR_ENABLE) != 0) 17361c052192SNeel Natu return (true); 17371c052192SNeel Natu else 17381c052192SNeel Natu return (false); 17391c052192SNeel Natu } 17405b8a8cd1SNeel Natu 174130b94db8SNeel Natu static void 174230b94db8SNeel Natu vlapic_set_tmr(struct vlapic *vlapic, int vector, bool level) 174330b94db8SNeel Natu { 174430b94db8SNeel Natu struct LAPIC *lapic; 174530b94db8SNeel Natu uint32_t *tmrptr, mask; 174630b94db8SNeel Natu int idx; 174730b94db8SNeel Natu 174830b94db8SNeel Natu lapic = vlapic->apic_page; 174930b94db8SNeel Natu tmrptr = &lapic->tmr0; 175030b94db8SNeel Natu idx = (vector / 32) * 4; 175130b94db8SNeel Natu mask = 1 << (vector % 32); 175230b94db8SNeel Natu if (level) 175330b94db8SNeel Natu tmrptr[idx] |= mask; 175430b94db8SNeel Natu else 175530b94db8SNeel Natu tmrptr[idx] &= ~mask; 175630b94db8SNeel Natu 175730b94db8SNeel Natu if (vlapic->ops.set_tmr != NULL) 175830b94db8SNeel Natu (*vlapic->ops.set_tmr)(vlapic, vector, level); 175930b94db8SNeel Natu } 176030b94db8SNeel Natu 17615b8a8cd1SNeel Natu void 17625b8a8cd1SNeel Natu vlapic_reset_tmr(struct vlapic *vlapic) 17635b8a8cd1SNeel Natu { 176430b94db8SNeel Natu int vector; 17655b8a8cd1SNeel Natu 17665b8a8cd1SNeel Natu VLAPIC_CTR0(vlapic, "vlapic resetting all vectors to edge-triggered"); 17675b8a8cd1SNeel Natu 176830b94db8SNeel Natu for (vector = 0; vector <= 255; vector++) 176930b94db8SNeel Natu vlapic_set_tmr(vlapic, vector, false); 17705b8a8cd1SNeel Natu } 17715b8a8cd1SNeel Natu 17725b8a8cd1SNeel Natu void 17735b8a8cd1SNeel Natu vlapic_set_tmr_level(struct vlapic *vlapic, uint32_t dest, bool phys, 17745b8a8cd1SNeel Natu int delmode, int vector) 17755b8a8cd1SNeel Natu { 17765b8a8cd1SNeel Natu cpuset_t dmask; 17775b8a8cd1SNeel Natu bool lowprio; 17785b8a8cd1SNeel Natu 17795b8a8cd1SNeel Natu KASSERT(vector >= 0 && vector <= 255, ("invalid vector %d", vector)); 17805b8a8cd1SNeel Natu 17815b8a8cd1SNeel Natu /* 17825b8a8cd1SNeel Natu * A level trigger is valid only for fixed and lowprio delivery modes. 17835b8a8cd1SNeel Natu */ 17845b8a8cd1SNeel Natu if (delmode != APIC_DELMODE_FIXED && delmode != APIC_DELMODE_LOWPRIO) { 17855b8a8cd1SNeel Natu VLAPIC_CTR1(vlapic, "Ignoring level trigger-mode for " 17865b8a8cd1SNeel Natu "delivery-mode %d", delmode); 17875b8a8cd1SNeel Natu return; 17885b8a8cd1SNeel Natu } 17895b8a8cd1SNeel Natu 17905b8a8cd1SNeel Natu lowprio = (delmode == APIC_DELMODE_LOWPRIO); 17915b8a8cd1SNeel Natu vlapic_calcdest(vlapic->vm, &dmask, dest, phys, lowprio, false); 17925b8a8cd1SNeel Natu 17935b8a8cd1SNeel Natu if (!CPU_ISSET(vlapic->vcpuid, &dmask)) 17945b8a8cd1SNeel Natu return; 17955b8a8cd1SNeel Natu 17965b8a8cd1SNeel Natu VLAPIC_CTR1(vlapic, "vector %d set to level-triggered", vector); 179730b94db8SNeel Natu vlapic_set_tmr(vlapic, vector, true); 17985b8a8cd1SNeel Natu } 1799483d953aSJohn Baldwin 1800483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 1801483d953aSJohn Baldwin static void 1802483d953aSJohn Baldwin vlapic_reset_callout(struct vlapic *vlapic, uint32_t ccr) 1803483d953aSJohn Baldwin { 1804483d953aSJohn Baldwin /* The implementation is similar to the one in the 1805483d953aSJohn Baldwin * `vlapic_icrtmr_write_handler` function 1806483d953aSJohn Baldwin */ 1807483d953aSJohn Baldwin sbintime_t sbt; 1808483d953aSJohn Baldwin struct bintime bt; 1809483d953aSJohn Baldwin 1810483d953aSJohn Baldwin VLAPIC_TIMER_LOCK(vlapic); 1811483d953aSJohn Baldwin 1812483d953aSJohn Baldwin bt = vlapic->timer_freq_bt; 1813483d953aSJohn Baldwin bintime_mul(&bt, ccr); 1814483d953aSJohn Baldwin 1815483d953aSJohn Baldwin if (ccr != 0) { 1816483d953aSJohn Baldwin binuptime(&vlapic->timer_fire_bt); 1817483d953aSJohn Baldwin bintime_add(&vlapic->timer_fire_bt, &bt); 1818483d953aSJohn Baldwin 1819483d953aSJohn Baldwin sbt = bttosbt(bt); 18204c812fe6SMark Johnston vlapic_callout_reset(vlapic, sbt); 1821483d953aSJohn Baldwin } else { 1822483d953aSJohn Baldwin /* even if the CCR was 0, periodic timers should be reset */ 1823483d953aSJohn Baldwin if (vlapic_periodic_timer(vlapic)) { 1824483d953aSJohn Baldwin binuptime(&vlapic->timer_fire_bt); 1825483d953aSJohn Baldwin bintime_add(&vlapic->timer_fire_bt, 1826483d953aSJohn Baldwin &vlapic->timer_period_bt); 1827483d953aSJohn Baldwin sbt = bttosbt(vlapic->timer_period_bt); 1828483d953aSJohn Baldwin 1829483d953aSJohn Baldwin callout_stop(&vlapic->callout); 18304c812fe6SMark Johnston vlapic_callout_reset(vlapic, sbt); 1831483d953aSJohn Baldwin } 1832483d953aSJohn Baldwin } 1833483d953aSJohn Baldwin 1834483d953aSJohn Baldwin VLAPIC_TIMER_UNLOCK(vlapic); 1835483d953aSJohn Baldwin } 1836483d953aSJohn Baldwin 1837483d953aSJohn Baldwin int 1838483d953aSJohn Baldwin vlapic_snapshot(struct vm *vm, struct vm_snapshot_meta *meta) 1839483d953aSJohn Baldwin { 184035abc6c2SJohn Baldwin int ret; 184198568a00SJohn Baldwin struct vcpu *vcpu; 1842483d953aSJohn Baldwin struct vlapic *vlapic; 1843483d953aSJohn Baldwin struct LAPIC *lapic; 1844483d953aSJohn Baldwin uint32_t ccr; 184535abc6c2SJohn Baldwin uint16_t i, maxcpus; 1846483d953aSJohn Baldwin 1847483d953aSJohn Baldwin KASSERT(vm != NULL, ("%s: arg was NULL", __func__)); 1848483d953aSJohn Baldwin 1849483d953aSJohn Baldwin ret = 0; 1850483d953aSJohn Baldwin 185135abc6c2SJohn Baldwin maxcpus = vm_get_maxcpus(vm); 185235abc6c2SJohn Baldwin for (i = 0; i < maxcpus; i++) { 185398568a00SJohn Baldwin vcpu = vm_vcpu(vm, i); 185498568a00SJohn Baldwin if (vcpu == NULL) 185598568a00SJohn Baldwin continue; 185698568a00SJohn Baldwin vlapic = vm_lapic(vcpu); 1857483d953aSJohn Baldwin 1858483d953aSJohn Baldwin /* snapshot the page first; timer period depends on icr_timer */ 1859483d953aSJohn Baldwin lapic = vlapic->apic_page; 1860483d953aSJohn Baldwin SNAPSHOT_BUF_OR_LEAVE(lapic, PAGE_SIZE, meta, ret, done); 1861483d953aSJohn Baldwin 1862483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vlapic->esr_pending, meta, ret, done); 1863483d953aSJohn Baldwin 1864483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vlapic->timer_freq_bt.sec, 1865483d953aSJohn Baldwin meta, ret, done); 1866483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vlapic->timer_freq_bt.frac, 1867483d953aSJohn Baldwin meta, ret, done); 1868483d953aSJohn Baldwin 1869483d953aSJohn Baldwin /* 1870483d953aSJohn Baldwin * Timer period is equal to 'icr_timer' ticks at a frequency of 1871483d953aSJohn Baldwin * 'timer_freq_bt'. 1872483d953aSJohn Baldwin */ 1873483d953aSJohn Baldwin if (meta->op == VM_SNAPSHOT_RESTORE) { 1874483d953aSJohn Baldwin vlapic->timer_period_bt = vlapic->timer_freq_bt; 1875483d953aSJohn Baldwin bintime_mul(&vlapic->timer_period_bt, lapic->icr_timer); 1876483d953aSJohn Baldwin } 1877483d953aSJohn Baldwin 1878483d953aSJohn Baldwin SNAPSHOT_BUF_OR_LEAVE(vlapic->isrvec_stk, 1879483d953aSJohn Baldwin sizeof(vlapic->isrvec_stk), 1880483d953aSJohn Baldwin meta, ret, done); 1881483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vlapic->isrvec_stk_top, meta, ret, done); 1882483d953aSJohn Baldwin 1883483d953aSJohn Baldwin SNAPSHOT_BUF_OR_LEAVE(vlapic->lvt_last, 1884483d953aSJohn Baldwin sizeof(vlapic->lvt_last), 1885483d953aSJohn Baldwin meta, ret, done); 1886483d953aSJohn Baldwin 1887483d953aSJohn Baldwin if (meta->op == VM_SNAPSHOT_SAVE) 1888483d953aSJohn Baldwin ccr = vlapic_get_ccr(vlapic); 1889483d953aSJohn Baldwin 1890483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(ccr, meta, ret, done); 1891483d953aSJohn Baldwin 1892c72e914cSVitaliy Gusev if (meta->op == VM_SNAPSHOT_RESTORE && 1893c72e914cSVitaliy Gusev vlapic_enabled(vlapic) && lapic->icr_timer != 0) { 1894483d953aSJohn Baldwin /* Reset the value of the 'timer_fire_bt' and the vlapic 1895483d953aSJohn Baldwin * callout based on the value of the current count 1896c72e914cSVitaliy Gusev * register saved when the VM snapshot was created. 1897c72e914cSVitaliy Gusev * If initial count register is 0, timer is not used. 1898c72e914cSVitaliy Gusev * Look at "10.5.4 APIC Timer" in Software Developer Manual. 1899483d953aSJohn Baldwin */ 1900483d953aSJohn Baldwin vlapic_reset_callout(vlapic, ccr); 1901483d953aSJohn Baldwin } 1902483d953aSJohn Baldwin } 1903483d953aSJohn Baldwin 1904483d953aSJohn Baldwin done: 1905483d953aSJohn Baldwin return (ret); 1906483d953aSJohn Baldwin } 1907483d953aSJohn Baldwin #endif 1908