xref: /freebsd/sys/amd64/vmm/io/vlapic.c (revision 2c52dcd9a88d213b62e4a00a63b91e74215542a8)
1366f6083SPeter Grehan /*-
2366f6083SPeter Grehan  * Copyright (c) 2011 NetApp, Inc.
3366f6083SPeter Grehan  * All rights reserved.
4366f6083SPeter Grehan  *
5366f6083SPeter Grehan  * Redistribution and use in source and binary forms, with or without
6366f6083SPeter Grehan  * modification, are permitted provided that the following conditions
7366f6083SPeter Grehan  * are met:
8366f6083SPeter Grehan  * 1. Redistributions of source code must retain the above copyright
9366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer.
10366f6083SPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
11366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
12366f6083SPeter Grehan  *    documentation and/or other materials provided with the distribution.
13366f6083SPeter Grehan  *
14366f6083SPeter Grehan  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15366f6083SPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16366f6083SPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17366f6083SPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18366f6083SPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19366f6083SPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20366f6083SPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21366f6083SPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22366f6083SPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23366f6083SPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24366f6083SPeter Grehan  * SUCH DAMAGE.
25366f6083SPeter Grehan  *
26366f6083SPeter Grehan  * $FreeBSD$
27366f6083SPeter Grehan  */
28366f6083SPeter Grehan 
29366f6083SPeter Grehan #include <sys/cdefs.h>
30366f6083SPeter Grehan __FBSDID("$FreeBSD$");
31366f6083SPeter Grehan 
32366f6083SPeter Grehan #include <sys/param.h>
33fb03ca4eSNeel Natu #include <sys/lock.h>
34366f6083SPeter Grehan #include <sys/kernel.h>
35366f6083SPeter Grehan #include <sys/malloc.h>
36fb03ca4eSNeel Natu #include <sys/mutex.h>
37366f6083SPeter Grehan #include <sys/systm.h>
38a5615c90SPeter Grehan #include <sys/smp.h>
39366f6083SPeter Grehan 
402d3a73edSNeel Natu #include <x86/specialreg.h>
4134a6b2d6SJohn Baldwin #include <x86/apicreg.h>
42366f6083SPeter Grehan 
43de5ea6b6SNeel Natu #include <machine/clock.h>
44de5ea6b6SNeel Natu #include <machine/smp.h>
45de5ea6b6SNeel Natu 
46366f6083SPeter Grehan #include <machine/vmm.h>
47366f6083SPeter Grehan 
48de5ea6b6SNeel Natu #include "vmm_ipi.h"
49366f6083SPeter Grehan #include "vmm_lapic.h"
50366f6083SPeter Grehan #include "vmm_ktr.h"
51de5ea6b6SNeel Natu #include "vmm_stat.h"
52de5ea6b6SNeel Natu 
53366f6083SPeter Grehan #include "vlapic.h"
54de5ea6b6SNeel Natu #include "vlapic_priv.h"
55b5b28fc9SNeel Natu #include "vioapic.h"
56366f6083SPeter Grehan 
57366f6083SPeter Grehan #define	VLAPIC_CTR0(vlapic, format)					\
58513c8d33SNeel Natu 	VCPU_CTR0((vlapic)->vm, (vlapic)->vcpuid, format)
59366f6083SPeter Grehan 
60366f6083SPeter Grehan #define	VLAPIC_CTR1(vlapic, format, p1)					\
61513c8d33SNeel Natu 	VCPU_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1)
62366f6083SPeter Grehan 
631c052192SNeel Natu #define	VLAPIC_CTR2(vlapic, format, p1, p2)				\
641c052192SNeel Natu 	VCPU_CTR2((vlapic)->vm, (vlapic)->vcpuid, format, p1, p2)
651c052192SNeel Natu 
66366f6083SPeter Grehan #define	VLAPIC_CTR_IRR(vlapic, msg)					\
67366f6083SPeter Grehan do {									\
68de5ea6b6SNeel Natu 	uint32_t *irrptr = &(vlapic)->apic_page->irr0;			\
69366f6083SPeter Grehan 	irrptr[0] = irrptr[0];	/* silence compiler */			\
70366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr0 0x%08x", irrptr[0 << 2]);	\
71366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr1 0x%08x", irrptr[1 << 2]);	\
72366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr2 0x%08x", irrptr[2 << 2]);	\
73366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr3 0x%08x", irrptr[3 << 2]);	\
74366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr4 0x%08x", irrptr[4 << 2]);	\
75366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr5 0x%08x", irrptr[5 << 2]);	\
76366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr6 0x%08x", irrptr[6 << 2]);	\
77366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr7 0x%08x", irrptr[7 << 2]);	\
78366f6083SPeter Grehan } while (0)
79366f6083SPeter Grehan 
80366f6083SPeter Grehan #define	VLAPIC_CTR_ISR(vlapic, msg)					\
81366f6083SPeter Grehan do {									\
82de5ea6b6SNeel Natu 	uint32_t *isrptr = &(vlapic)->apic_page->isr0;			\
83366f6083SPeter Grehan 	isrptr[0] = isrptr[0];	/* silence compiler */			\
84366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr0 0x%08x", isrptr[0 << 2]);	\
85366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr1 0x%08x", isrptr[1 << 2]);	\
86366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr2 0x%08x", isrptr[2 << 2]);	\
87366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr3 0x%08x", isrptr[3 << 2]);	\
88366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr4 0x%08x", isrptr[4 << 2]);	\
89366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr5 0x%08x", isrptr[5 << 2]);	\
90366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr6 0x%08x", isrptr[6 << 2]);	\
91366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr7 0x%08x", isrptr[7 << 2]);	\
92366f6083SPeter Grehan } while (0)
93366f6083SPeter Grehan 
94366f6083SPeter Grehan #define	PRIO(x)			((x) >> 4)
95366f6083SPeter Grehan 
96366f6083SPeter Grehan #define VLAPIC_VERSION		(16)
97330baf58SJohn Baldwin #define VLAPIC_MAXLVT_ENTRIES	(APIC_LVT_CMCI)
98366f6083SPeter Grehan 
99a2da7af6SNeel Natu #define	x2apic(vlapic)	(((vlapic)->msr_apicbase & APICBASE_X2APIC) ? 1 : 0)
1002d3a73edSNeel Natu 
101fb03ca4eSNeel Natu /*
102fb03ca4eSNeel Natu  * The 'vlapic->timer_mtx' is used to provide mutual exclusion between the
103fb03ca4eSNeel Natu  * vlapic_callout_handler() and vcpu accesses to the following registers:
104fb03ca4eSNeel Natu  * - initial count register aka icr_timer
105fb03ca4eSNeel Natu  * - current count register aka ccr_timer
106fb03ca4eSNeel Natu  * - divide config register aka dcr_timer
107fb03ca4eSNeel Natu  * - timer LVT register
108fb03ca4eSNeel Natu  *
109fb03ca4eSNeel Natu  * Note that the vlapic_callout_handler() does not write to any of these
110fb03ca4eSNeel Natu  * registers so they can be safely read from the vcpu context without locking.
111fb03ca4eSNeel Natu  */
112becd9849SNeel Natu #define	VLAPIC_TIMER_LOCK(vlapic)	mtx_lock_spin(&((vlapic)->timer_mtx))
113becd9849SNeel Natu #define	VLAPIC_TIMER_UNLOCK(vlapic)	mtx_unlock_spin(&((vlapic)->timer_mtx))
114fb03ca4eSNeel Natu #define	VLAPIC_TIMER_LOCKED(vlapic)	mtx_owned(&((vlapic)->timer_mtx))
115fb03ca4eSNeel Natu 
1162e25737aSNeel Natu #define VLAPIC_BUS_FREQ	tsc_freq
1172e25737aSNeel Natu 
1184f8be175SNeel Natu static __inline uint32_t
1194f8be175SNeel Natu vlapic_get_id(struct vlapic *vlapic)
1204f8be175SNeel Natu {
1214f8be175SNeel Natu 
1224f8be175SNeel Natu 	if (x2apic(vlapic))
1234f8be175SNeel Natu 		return (vlapic->vcpuid);
1244f8be175SNeel Natu 	else
1254f8be175SNeel Natu 		return (vlapic->vcpuid << 24);
1264f8be175SNeel Natu }
1274f8be175SNeel Natu 
1283f0ddc7cSNeel Natu static uint32_t
1293f0ddc7cSNeel Natu x2apic_ldr(struct vlapic *vlapic)
1304f8be175SNeel Natu {
1314f8be175SNeel Natu 	int apicid;
1324f8be175SNeel Natu 	uint32_t ldr;
1334f8be175SNeel Natu 
1344f8be175SNeel Natu 	apicid = vlapic_get_id(vlapic);
1354f8be175SNeel Natu 	ldr = 1 << (apicid & 0xf);
1364f8be175SNeel Natu 	ldr |= (apicid & 0xffff0) << 12;
1374f8be175SNeel Natu 	return (ldr);
1384f8be175SNeel Natu }
1394f8be175SNeel Natu 
1403f0ddc7cSNeel Natu void
1413f0ddc7cSNeel Natu vlapic_dfr_write_handler(struct vlapic *vlapic)
1424f8be175SNeel Natu {
1434f8be175SNeel Natu 	struct LAPIC *lapic;
1444f8be175SNeel Natu 
145de5ea6b6SNeel Natu 	lapic = vlapic->apic_page;
1464f8be175SNeel Natu 	if (x2apic(vlapic)) {
1473f0ddc7cSNeel Natu 		VM_CTR1(vlapic->vm, "ignoring write to DFR in x2apic mode: %#x",
1483f0ddc7cSNeel Natu 		    lapic->dfr);
1493f0ddc7cSNeel Natu 		lapic->dfr = 0;
1504f8be175SNeel Natu 		return;
1514f8be175SNeel Natu 	}
1524f8be175SNeel Natu 
1533f0ddc7cSNeel Natu 	lapic->dfr &= APIC_DFR_MODEL_MASK;
1543f0ddc7cSNeel Natu 	lapic->dfr |= APIC_DFR_RESERVED;
1553f0ddc7cSNeel Natu 
1563f0ddc7cSNeel Natu 	if ((lapic->dfr & APIC_DFR_MODEL_MASK) == APIC_DFR_MODEL_FLAT)
1574f8be175SNeel Natu 		VLAPIC_CTR0(vlapic, "vlapic DFR in Flat Model");
1583f0ddc7cSNeel Natu 	else if ((lapic->dfr & APIC_DFR_MODEL_MASK) == APIC_DFR_MODEL_CLUSTER)
1594f8be175SNeel Natu 		VLAPIC_CTR0(vlapic, "vlapic DFR in Cluster Model");
1604f8be175SNeel Natu 	else
1613f0ddc7cSNeel Natu 		VLAPIC_CTR1(vlapic, "DFR in Unknown Model %#x", lapic->dfr);
1624f8be175SNeel Natu }
1634f8be175SNeel Natu 
1643f0ddc7cSNeel Natu void
1653f0ddc7cSNeel Natu vlapic_ldr_write_handler(struct vlapic *vlapic)
1664f8be175SNeel Natu {
1674f8be175SNeel Natu 	struct LAPIC *lapic;
1684f8be175SNeel Natu 
1693f0ddc7cSNeel Natu 	lapic = vlapic->apic_page;
1703f0ddc7cSNeel Natu 
1714f8be175SNeel Natu 	/* LDR is read-only in x2apic mode */
1724f8be175SNeel Natu 	if (x2apic(vlapic)) {
1733f0ddc7cSNeel Natu 		VLAPIC_CTR1(vlapic, "ignoring write to LDR in x2apic mode: %#x",
1743f0ddc7cSNeel Natu 		    lapic->ldr);
1753f0ddc7cSNeel Natu 		lapic->ldr = x2apic_ldr(vlapic);
1763f0ddc7cSNeel Natu 	} else {
1773f0ddc7cSNeel Natu 		lapic->ldr &= ~APIC_LDR_RESERVED;
1783f0ddc7cSNeel Natu 		VLAPIC_CTR1(vlapic, "vlapic LDR set to %#x", lapic->ldr);
1793f0ddc7cSNeel Natu 	}
1804f8be175SNeel Natu }
1814f8be175SNeel Natu 
1823f0ddc7cSNeel Natu void
1833f0ddc7cSNeel Natu vlapic_id_write_handler(struct vlapic *vlapic)
1843f0ddc7cSNeel Natu {
1853f0ddc7cSNeel Natu 	struct LAPIC *lapic;
1863f0ddc7cSNeel Natu 
1873f0ddc7cSNeel Natu 	/*
1883f0ddc7cSNeel Natu 	 * We don't allow the ID register to be modified so reset it back to
1893f0ddc7cSNeel Natu 	 * its default value.
1903f0ddc7cSNeel Natu 	 */
191de5ea6b6SNeel Natu 	lapic = vlapic->apic_page;
1923f0ddc7cSNeel Natu 	lapic->id = vlapic_get_id(vlapic);
1934f8be175SNeel Natu }
1944f8be175SNeel Natu 
1952e25737aSNeel Natu static int
1962e25737aSNeel Natu vlapic_timer_divisor(uint32_t dcr)
1972e25737aSNeel Natu {
1982e25737aSNeel Natu 	switch (dcr & 0xB) {
199117e8f37SPeter Grehan 	case APIC_TDCR_1:
200117e8f37SPeter Grehan 		return (1);
2012e25737aSNeel Natu 	case APIC_TDCR_2:
2022e25737aSNeel Natu 		return (2);
2032e25737aSNeel Natu 	case APIC_TDCR_4:
2042e25737aSNeel Natu 		return (4);
2052e25737aSNeel Natu 	case APIC_TDCR_8:
2062e25737aSNeel Natu 		return (8);
2072e25737aSNeel Natu 	case APIC_TDCR_16:
2082e25737aSNeel Natu 		return (16);
2092e25737aSNeel Natu 	case APIC_TDCR_32:
2102e25737aSNeel Natu 		return (32);
2112e25737aSNeel Natu 	case APIC_TDCR_64:
2122e25737aSNeel Natu 		return (64);
2132e25737aSNeel Natu 	case APIC_TDCR_128:
2142e25737aSNeel Natu 		return (128);
2152e25737aSNeel Natu 	default:
2162e25737aSNeel Natu 		panic("vlapic_timer_divisor: invalid dcr 0x%08x", dcr);
2172e25737aSNeel Natu 	}
2182e25737aSNeel Natu }
2192e25737aSNeel Natu 
220366f6083SPeter Grehan static void
221*2c52dcd9SNeel Natu vlapic_mask_lvts(struct vlapic *vlapic)
222366f6083SPeter Grehan {
223*2c52dcd9SNeel Natu 	struct LAPIC *lapic = vlapic->apic_page;
224*2c52dcd9SNeel Natu 
225*2c52dcd9SNeel Natu 	lapic->lvt_cmci |= APIC_LVT_M;
226*2c52dcd9SNeel Natu 	lapic->lvt_timer |= APIC_LVT_M;
227*2c52dcd9SNeel Natu 	lapic->lvt_thermal |= APIC_LVT_M;
228*2c52dcd9SNeel Natu 	lapic->lvt_pcint |= APIC_LVT_M;
229*2c52dcd9SNeel Natu 	lapic->lvt_lint0 |= APIC_LVT_M;
230*2c52dcd9SNeel Natu 	lapic->lvt_lint1 |= APIC_LVT_M;
231*2c52dcd9SNeel Natu 	lapic->lvt_error |= APIC_LVT_M;
232366f6083SPeter Grehan }
233366f6083SPeter Grehan 
234366f6083SPeter Grehan #if 0
235366f6083SPeter Grehan static inline void
236366f6083SPeter Grehan vlapic_dump_lvt(uint32_t offset, uint32_t *lvt)
237366f6083SPeter Grehan {
238366f6083SPeter Grehan 	printf("Offset %x: lvt %08x (V:%02x DS:%x M:%x)\n", offset,
239366f6083SPeter Grehan 	    *lvt, *lvt & APIC_LVTT_VECTOR, *lvt & APIC_LVTT_DS,
240366f6083SPeter Grehan 	    *lvt & APIC_LVTT_M);
241366f6083SPeter Grehan }
242366f6083SPeter Grehan #endif
243366f6083SPeter Grehan 
244fb03ca4eSNeel Natu static uint32_t
245366f6083SPeter Grehan vlapic_get_ccr(struct vlapic *vlapic)
246366f6083SPeter Grehan {
247fb03ca4eSNeel Natu 	struct bintime bt_now, bt_rem;
248fb03ca4eSNeel Natu 	struct LAPIC *lapic;
249fb03ca4eSNeel Natu 	uint32_t ccr;
250fb03ca4eSNeel Natu 
251fb03ca4eSNeel Natu 	ccr = 0;
252de5ea6b6SNeel Natu 	lapic = vlapic->apic_page;
253fb03ca4eSNeel Natu 
254fb03ca4eSNeel Natu 	VLAPIC_TIMER_LOCK(vlapic);
255fb03ca4eSNeel Natu 	if (callout_active(&vlapic->callout)) {
256fb03ca4eSNeel Natu 		/*
257fb03ca4eSNeel Natu 		 * If the timer is scheduled to expire in the future then
258fb03ca4eSNeel Natu 		 * compute the value of 'ccr' based on the remaining time.
259fb03ca4eSNeel Natu 		 */
260fb03ca4eSNeel Natu 		binuptime(&bt_now);
261fb03ca4eSNeel Natu 		if (bintime_cmp(&vlapic->timer_fire_bt, &bt_now, >)) {
262fb03ca4eSNeel Natu 			bt_rem = vlapic->timer_fire_bt;
263fb03ca4eSNeel Natu 			bintime_sub(&bt_rem, &bt_now);
264fb03ca4eSNeel Natu 			ccr += bt_rem.sec * BT2FREQ(&vlapic->timer_freq_bt);
265fb03ca4eSNeel Natu 			ccr += bt_rem.frac / vlapic->timer_freq_bt.frac;
266fb03ca4eSNeel Natu 		}
267fb03ca4eSNeel Natu 	}
268fb03ca4eSNeel Natu 	KASSERT(ccr <= lapic->icr_timer, ("vlapic_get_ccr: invalid ccr %#x, "
269fb03ca4eSNeel Natu 	    "icr_timer is %#x", ccr, lapic->icr_timer));
270fb03ca4eSNeel Natu 	VLAPIC_CTR2(vlapic, "vlapic ccr_timer = %#x, icr_timer = %#x",
271fb03ca4eSNeel Natu 	    ccr, lapic->icr_timer);
272fb03ca4eSNeel Natu 	VLAPIC_TIMER_UNLOCK(vlapic);
273fb03ca4eSNeel Natu 	return (ccr);
274fb03ca4eSNeel Natu }
275fb03ca4eSNeel Natu 
276fb03ca4eSNeel Natu static void
277fb03ca4eSNeel Natu vlapic_set_dcr(struct vlapic *vlapic, uint32_t dcr)
278fb03ca4eSNeel Natu {
279fb03ca4eSNeel Natu 	struct LAPIC *lapic;
280fb03ca4eSNeel Natu 	int divisor;
281fb03ca4eSNeel Natu 
282de5ea6b6SNeel Natu 	lapic = vlapic->apic_page;
283fb03ca4eSNeel Natu 	VLAPIC_TIMER_LOCK(vlapic);
284fb03ca4eSNeel Natu 
285fb03ca4eSNeel Natu 	lapic->dcr_timer = dcr;
286fb03ca4eSNeel Natu 	divisor = vlapic_timer_divisor(dcr);
287fb03ca4eSNeel Natu 	VLAPIC_CTR2(vlapic, "vlapic dcr_timer=%#x, divisor=%d", dcr, divisor);
288fb03ca4eSNeel Natu 
289fb03ca4eSNeel Natu 	/*
290fb03ca4eSNeel Natu 	 * Update the timer frequency and the timer period.
291fb03ca4eSNeel Natu 	 *
292fb03ca4eSNeel Natu 	 * XXX changes to the frequency divider will not take effect until
293fb03ca4eSNeel Natu 	 * the timer is reloaded.
294fb03ca4eSNeel Natu 	 */
295fb03ca4eSNeel Natu 	FREQ2BT(VLAPIC_BUS_FREQ / divisor, &vlapic->timer_freq_bt);
296fb03ca4eSNeel Natu 	vlapic->timer_period_bt = vlapic->timer_freq_bt;
297fb03ca4eSNeel Natu 	bintime_mul(&vlapic->timer_period_bt, lapic->icr_timer);
298fb03ca4eSNeel Natu 
299fb03ca4eSNeel Natu 	VLAPIC_TIMER_UNLOCK(vlapic);
300366f6083SPeter Grehan }
301366f6083SPeter Grehan 
302366f6083SPeter Grehan static void
303366f6083SPeter Grehan vlapic_update_errors(struct vlapic *vlapic)
304366f6083SPeter Grehan {
305de5ea6b6SNeel Natu 	struct LAPIC *lapic;
306de5ea6b6SNeel Natu 
307de5ea6b6SNeel Natu 	lapic = vlapic->apic_page;
308330baf58SJohn Baldwin 	lapic->esr = vlapic->esr_pending;
309330baf58SJohn Baldwin 	vlapic->esr_pending = 0;
310366f6083SPeter Grehan }
311366f6083SPeter Grehan 
312366f6083SPeter Grehan static void
313a7835785SNeel Natu vlapic_reset(struct vlapic *vlapic)
314366f6083SPeter Grehan {
315a7835785SNeel Natu 	struct LAPIC *lapic;
316a7835785SNeel Natu 
317de5ea6b6SNeel Natu 	lapic = vlapic->apic_page;
318a7835785SNeel Natu 	bzero(lapic, sizeof(struct LAPIC));
319a7835785SNeel Natu 
3203f0ddc7cSNeel Natu 	lapic->id = vlapic_get_id(vlapic);
321366f6083SPeter Grehan 	lapic->version = VLAPIC_VERSION;
322a83011d2SNeel Natu 	lapic->version |= (VLAPIC_MAXLVT_ENTRIES << MAXLVTSHIFT);
323366f6083SPeter Grehan 	lapic->dfr = 0xffffffff;
324366f6083SPeter Grehan 	lapic->svr = APIC_SVR_VECTOR;
325*2c52dcd9SNeel Natu 	vlapic_mask_lvts(vlapic);
326fb03ca4eSNeel Natu 	vlapic_set_dcr(vlapic, 0);
327366f6083SPeter Grehan 
328edf89256SNeel Natu 	if (vlapic->vcpuid == 0)
329edf89256SNeel Natu 		vlapic->boot_state = BS_RUNNING;	/* BSP */
330edf89256SNeel Natu 	else
331edf89256SNeel Natu 		vlapic->boot_state = BS_INIT;		/* AP */
332*2c52dcd9SNeel Natu 
333*2c52dcd9SNeel Natu 	vlapic->svr_last = lapic->svr;
334366f6083SPeter Grehan }
335366f6083SPeter Grehan 
336366f6083SPeter Grehan void
337b5b28fc9SNeel Natu vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level)
338366f6083SPeter Grehan {
339de5ea6b6SNeel Natu 	struct LAPIC	*lapic = vlapic->apic_page;
340b5b28fc9SNeel Natu 	uint32_t	*irrptr, *tmrptr, mask;
341366f6083SPeter Grehan 	int		idx;
342366f6083SPeter Grehan 
343366f6083SPeter Grehan 	if (vector < 0 || vector >= 256)
344366f6083SPeter Grehan 		panic("vlapic_set_intr_ready: invalid vector %d\n", vector);
345366f6083SPeter Grehan 
3461c052192SNeel Natu 	if (!(lapic->svr & APIC_SVR_ENABLE)) {
3471c052192SNeel Natu 		VLAPIC_CTR1(vlapic, "vlapic is software disabled, ignoring "
3481c052192SNeel Natu 		    "interrupt %d", vector);
3491c052192SNeel Natu 		return;
3501c052192SNeel Natu 	}
3511c052192SNeel Natu 
352330baf58SJohn Baldwin 	if (vector < 16) {
353330baf58SJohn Baldwin 		vlapic_set_error(vlapic, APIC_ESR_RECEIVE_ILLEGAL_VECTOR);
354330baf58SJohn Baldwin 		return;
355330baf58SJohn Baldwin 	}
356330baf58SJohn Baldwin 
357366f6083SPeter Grehan 	idx = (vector / 32) * 4;
358b5b28fc9SNeel Natu 	mask = 1 << (vector % 32);
359b5b28fc9SNeel Natu 
360366f6083SPeter Grehan 	irrptr = &lapic->irr0;
361b5b28fc9SNeel Natu 	atomic_set_int(&irrptr[idx], mask);
362b5b28fc9SNeel Natu 
363b5b28fc9SNeel Natu 	/*
364b5b28fc9SNeel Natu 	 * Upon acceptance of an interrupt into the IRR the corresponding
365b5b28fc9SNeel Natu 	 * TMR bit is cleared for edge-triggered interrupts and set for
366b5b28fc9SNeel Natu 	 * level-triggered interrupts.
367b5b28fc9SNeel Natu 	 */
368b5b28fc9SNeel Natu 	tmrptr = &lapic->tmr0;
369b5b28fc9SNeel Natu 	if (level)
370b5b28fc9SNeel Natu 		atomic_set_int(&tmrptr[idx], mask);
371b5b28fc9SNeel Natu 	else
372b5b28fc9SNeel Natu 		atomic_clear_int(&tmrptr[idx], mask);
373b5b28fc9SNeel Natu 
374366f6083SPeter Grehan 	VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready");
375366f6083SPeter Grehan }
376366f6083SPeter Grehan 
377366f6083SPeter Grehan static __inline uint32_t *
378fb03ca4eSNeel Natu vlapic_get_lvtptr(struct vlapic *vlapic, uint32_t offset)
379366f6083SPeter Grehan {
380de5ea6b6SNeel Natu 	struct LAPIC	*lapic = vlapic->apic_page;
381366f6083SPeter Grehan 	int 		 i;
382366f6083SPeter Grehan 
383330baf58SJohn Baldwin 	switch (offset) {
384330baf58SJohn Baldwin 	case APIC_OFFSET_CMCI_LVT:
385330baf58SJohn Baldwin 		return (&lapic->lvt_cmci);
386330baf58SJohn Baldwin 	case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT:
387366f6083SPeter Grehan 		i = (offset - APIC_OFFSET_TIMER_LVT) >> 2;
388366f6083SPeter Grehan 		return ((&lapic->lvt_timer) + i);;
389330baf58SJohn Baldwin 	default:
390330baf58SJohn Baldwin 		panic("vlapic_get_lvt: invalid LVT\n");
391330baf58SJohn Baldwin 	}
392366f6083SPeter Grehan }
393366f6083SPeter Grehan 
394fb03ca4eSNeel Natu static __inline uint32_t
395fb03ca4eSNeel Natu vlapic_get_lvt(struct vlapic *vlapic, uint32_t offset)
396fb03ca4eSNeel Natu {
397fb03ca4eSNeel Natu 
398fb03ca4eSNeel Natu 	return (*vlapic_get_lvtptr(vlapic, offset));
399fb03ca4eSNeel Natu }
400fb03ca4eSNeel Natu 
401fb03ca4eSNeel Natu static void
402fb03ca4eSNeel Natu vlapic_set_lvt(struct vlapic *vlapic, uint32_t offset, uint32_t val)
403fb03ca4eSNeel Natu {
404330baf58SJohn Baldwin 	uint32_t *lvtptr, mask;
405fb03ca4eSNeel Natu 	struct LAPIC *lapic;
406fb03ca4eSNeel Natu 
407de5ea6b6SNeel Natu 	lapic = vlapic->apic_page;
408fb03ca4eSNeel Natu 	lvtptr = vlapic_get_lvtptr(vlapic, offset);
409fb03ca4eSNeel Natu 
410fb03ca4eSNeel Natu 	if (offset == APIC_OFFSET_TIMER_LVT)
411fb03ca4eSNeel Natu 		VLAPIC_TIMER_LOCK(vlapic);
412fb03ca4eSNeel Natu 
413fb03ca4eSNeel Natu 	if (!(lapic->svr & APIC_SVR_ENABLE))
414fb03ca4eSNeel Natu 		val |= APIC_LVT_M;
415330baf58SJohn Baldwin 	mask = APIC_LVT_M | APIC_LVT_DS | APIC_LVT_VECTOR;
416330baf58SJohn Baldwin 	switch (offset) {
417330baf58SJohn Baldwin 	case APIC_OFFSET_TIMER_LVT:
418330baf58SJohn Baldwin 		mask |= APIC_LVTT_TM;
419330baf58SJohn Baldwin 		break;
420330baf58SJohn Baldwin 	case APIC_OFFSET_ERROR_LVT:
421330baf58SJohn Baldwin 		break;
422330baf58SJohn Baldwin 	case APIC_OFFSET_LINT0_LVT:
423330baf58SJohn Baldwin 	case APIC_OFFSET_LINT1_LVT:
424330baf58SJohn Baldwin 		mask |= APIC_LVT_TM | APIC_LVT_RIRR | APIC_LVT_IIPP;
425330baf58SJohn Baldwin 		/* FALLTHROUGH */
426330baf58SJohn Baldwin 	default:
427330baf58SJohn Baldwin 		mask |= APIC_LVT_DM;
428330baf58SJohn Baldwin 		break;
429330baf58SJohn Baldwin 	}
430330baf58SJohn Baldwin 	*lvtptr = val & mask;
431fb03ca4eSNeel Natu 
432fb03ca4eSNeel Natu 	if (offset == APIC_OFFSET_TIMER_LVT)
433fb03ca4eSNeel Natu 		VLAPIC_TIMER_UNLOCK(vlapic);
434fb03ca4eSNeel Natu }
435fb03ca4eSNeel Natu 
436330baf58SJohn Baldwin static int
437330baf58SJohn Baldwin vlapic_fire_lvt(struct vlapic *vlapic, uint32_t lvt)
438330baf58SJohn Baldwin {
439330baf58SJohn Baldwin 	uint32_t vec, mode;
440330baf58SJohn Baldwin 
441330baf58SJohn Baldwin 	if (lvt & APIC_LVT_M)
442330baf58SJohn Baldwin 		return (0);
443330baf58SJohn Baldwin 
444330baf58SJohn Baldwin 	vec = lvt & APIC_LVT_VECTOR;
445330baf58SJohn Baldwin 	mode = lvt & APIC_LVT_DM;
446330baf58SJohn Baldwin 
447330baf58SJohn Baldwin 	switch (mode) {
448330baf58SJohn Baldwin 	case APIC_LVT_DM_FIXED:
449330baf58SJohn Baldwin 		if (vec < 16) {
450330baf58SJohn Baldwin 			vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);
451330baf58SJohn Baldwin 			return (0);
452330baf58SJohn Baldwin 		}
453330baf58SJohn Baldwin 		vlapic_set_intr_ready(vlapic, vec, false);
454de5ea6b6SNeel Natu 		vcpu_notify_event(vlapic->vm, vlapic->vcpuid, true);
455330baf58SJohn Baldwin 		break;
456330baf58SJohn Baldwin 	case APIC_LVT_DM_NMI:
457330baf58SJohn Baldwin 		vm_inject_nmi(vlapic->vm, vlapic->vcpuid);
458330baf58SJohn Baldwin 		break;
459330baf58SJohn Baldwin 	default:
460330baf58SJohn Baldwin 		// Other modes ignored
461330baf58SJohn Baldwin 		return (0);
462330baf58SJohn Baldwin 	}
463330baf58SJohn Baldwin 	return (1);
464330baf58SJohn Baldwin }
465330baf58SJohn Baldwin 
466366f6083SPeter Grehan #if 1
467366f6083SPeter Grehan static void
468366f6083SPeter Grehan dump_isrvec_stk(struct vlapic *vlapic)
469366f6083SPeter Grehan {
470366f6083SPeter Grehan 	int i;
471366f6083SPeter Grehan 	uint32_t *isrptr;
472366f6083SPeter Grehan 
473de5ea6b6SNeel Natu 	isrptr = &vlapic->apic_page->isr0;
474366f6083SPeter Grehan 	for (i = 0; i < 8; i++)
475366f6083SPeter Grehan 		printf("ISR%d 0x%08x\n", i, isrptr[i * 4]);
476366f6083SPeter Grehan 
477366f6083SPeter Grehan 	for (i = 0; i <= vlapic->isrvec_stk_top; i++)
478366f6083SPeter Grehan 		printf("isrvec_stk[%d] = %d\n", i, vlapic->isrvec_stk[i]);
479366f6083SPeter Grehan }
480366f6083SPeter Grehan #endif
481366f6083SPeter Grehan 
482366f6083SPeter Grehan /*
483366f6083SPeter Grehan  * Algorithm adopted from section "Interrupt, Task and Processor Priority"
484366f6083SPeter Grehan  * in Intel Architecture Manual Vol 3a.
485366f6083SPeter Grehan  */
486366f6083SPeter Grehan static void
487366f6083SPeter Grehan vlapic_update_ppr(struct vlapic *vlapic)
488366f6083SPeter Grehan {
489366f6083SPeter Grehan 	int isrvec, tpr, ppr;
490366f6083SPeter Grehan 
491366f6083SPeter Grehan 	/*
492366f6083SPeter Grehan 	 * Note that the value on the stack at index 0 is always 0.
493366f6083SPeter Grehan 	 *
494366f6083SPeter Grehan 	 * This is a placeholder for the value of ISRV when none of the
495366f6083SPeter Grehan 	 * bits is set in the ISRx registers.
496366f6083SPeter Grehan 	 */
497366f6083SPeter Grehan 	isrvec = vlapic->isrvec_stk[vlapic->isrvec_stk_top];
498de5ea6b6SNeel Natu 	tpr = vlapic->apic_page->tpr;
499366f6083SPeter Grehan 
500366f6083SPeter Grehan #if 1
501366f6083SPeter Grehan 	{
502366f6083SPeter Grehan 		int i, lastprio, curprio, vector, idx;
503366f6083SPeter Grehan 		uint32_t *isrptr;
504366f6083SPeter Grehan 
505366f6083SPeter Grehan 		if (vlapic->isrvec_stk_top == 0 && isrvec != 0)
506366f6083SPeter Grehan 			panic("isrvec_stk is corrupted: %d", isrvec);
507366f6083SPeter Grehan 
508366f6083SPeter Grehan 		/*
509366f6083SPeter Grehan 		 * Make sure that the priority of the nested interrupts is
510366f6083SPeter Grehan 		 * always increasing.
511366f6083SPeter Grehan 		 */
512366f6083SPeter Grehan 		lastprio = -1;
513366f6083SPeter Grehan 		for (i = 1; i <= vlapic->isrvec_stk_top; i++) {
514366f6083SPeter Grehan 			curprio = PRIO(vlapic->isrvec_stk[i]);
515366f6083SPeter Grehan 			if (curprio <= lastprio) {
516366f6083SPeter Grehan 				dump_isrvec_stk(vlapic);
517366f6083SPeter Grehan 				panic("isrvec_stk does not satisfy invariant");
518366f6083SPeter Grehan 			}
519366f6083SPeter Grehan 			lastprio = curprio;
520366f6083SPeter Grehan 		}
521366f6083SPeter Grehan 
522366f6083SPeter Grehan 		/*
523366f6083SPeter Grehan 		 * Make sure that each bit set in the ISRx registers has a
524366f6083SPeter Grehan 		 * corresponding entry on the isrvec stack.
525366f6083SPeter Grehan 		 */
526366f6083SPeter Grehan 		i = 1;
527de5ea6b6SNeel Natu 		isrptr = &vlapic->apic_page->isr0;
528366f6083SPeter Grehan 		for (vector = 0; vector < 256; vector++) {
529366f6083SPeter Grehan 			idx = (vector / 32) * 4;
530366f6083SPeter Grehan 			if (isrptr[idx] & (1 << (vector % 32))) {
531366f6083SPeter Grehan 				if (i > vlapic->isrvec_stk_top ||
532366f6083SPeter Grehan 				    vlapic->isrvec_stk[i] != vector) {
533366f6083SPeter Grehan 					dump_isrvec_stk(vlapic);
534366f6083SPeter Grehan 					panic("ISR and isrvec_stk out of sync");
535366f6083SPeter Grehan 				}
536366f6083SPeter Grehan 				i++;
537366f6083SPeter Grehan 			}
538366f6083SPeter Grehan 		}
539366f6083SPeter Grehan 	}
540366f6083SPeter Grehan #endif
541366f6083SPeter Grehan 
542366f6083SPeter Grehan 	if (PRIO(tpr) >= PRIO(isrvec))
543366f6083SPeter Grehan 		ppr = tpr;
544366f6083SPeter Grehan 	else
545366f6083SPeter Grehan 		ppr = isrvec & 0xf0;
546366f6083SPeter Grehan 
547de5ea6b6SNeel Natu 	vlapic->apic_page->ppr = ppr;
548366f6083SPeter Grehan 	VLAPIC_CTR1(vlapic, "vlapic_update_ppr 0x%02x", ppr);
549366f6083SPeter Grehan }
550366f6083SPeter Grehan 
551366f6083SPeter Grehan static void
552366f6083SPeter Grehan vlapic_process_eoi(struct vlapic *vlapic)
553366f6083SPeter Grehan {
554de5ea6b6SNeel Natu 	struct LAPIC	*lapic = vlapic->apic_page;
555b5b28fc9SNeel Natu 	uint32_t	*isrptr, *tmrptr;
556b5b28fc9SNeel Natu 	int		i, idx, bitpos, vector;
557366f6083SPeter Grehan 
558366f6083SPeter Grehan 	isrptr = &lapic->isr0;
559b5b28fc9SNeel Natu 	tmrptr = &lapic->tmr0;
560366f6083SPeter Grehan 
561366f6083SPeter Grehan 	/*
562366f6083SPeter Grehan 	 * The x86 architecture reserves the the first 32 vectors for use
563366f6083SPeter Grehan 	 * by the processor.
564366f6083SPeter Grehan 	 */
565366f6083SPeter Grehan 	for (i = 7; i > 0; i--) {
566366f6083SPeter Grehan 		idx = i * 4;
567366f6083SPeter Grehan 		bitpos = fls(isrptr[idx]);
568b5b28fc9SNeel Natu 		if (bitpos-- != 0) {
569366f6083SPeter Grehan 			if (vlapic->isrvec_stk_top <= 0) {
570366f6083SPeter Grehan 				panic("invalid vlapic isrvec_stk_top %d",
571366f6083SPeter Grehan 				      vlapic->isrvec_stk_top);
572366f6083SPeter Grehan 			}
573b5b28fc9SNeel Natu 			isrptr[idx] &= ~(1 << bitpos);
574366f6083SPeter Grehan 			VLAPIC_CTR_ISR(vlapic, "vlapic_process_eoi");
575366f6083SPeter Grehan 			vlapic->isrvec_stk_top--;
576366f6083SPeter Grehan 			vlapic_update_ppr(vlapic);
577b5b28fc9SNeel Natu 			if ((tmrptr[idx] & (1 << bitpos)) != 0) {
578b5b28fc9SNeel Natu 				vector = i * 32 + bitpos;
579b5b28fc9SNeel Natu 				vioapic_process_eoi(vlapic->vm, vlapic->vcpuid,
580b5b28fc9SNeel Natu 				    vector);
581b5b28fc9SNeel Natu 			}
582366f6083SPeter Grehan 			return;
583366f6083SPeter Grehan 		}
584366f6083SPeter Grehan 	}
585366f6083SPeter Grehan }
586366f6083SPeter Grehan 
587366f6083SPeter Grehan static __inline int
588fb03ca4eSNeel Natu vlapic_get_lvt_field(uint32_t lvt, uint32_t mask)
589366f6083SPeter Grehan {
590fb03ca4eSNeel Natu 
591fb03ca4eSNeel Natu 	return (lvt & mask);
592366f6083SPeter Grehan }
593366f6083SPeter Grehan 
594366f6083SPeter Grehan static __inline int
595366f6083SPeter Grehan vlapic_periodic_timer(struct vlapic *vlapic)
596366f6083SPeter Grehan {
597fb03ca4eSNeel Natu 	uint32_t lvt;
598366f6083SPeter Grehan 
599366f6083SPeter Grehan 	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);
600366f6083SPeter Grehan 
601366f6083SPeter Grehan 	return (vlapic_get_lvt_field(lvt, APIC_LVTT_TM_PERIODIC));
602366f6083SPeter Grehan }
603366f6083SPeter Grehan 
604330baf58SJohn Baldwin static VMM_STAT(VLAPIC_INTR_ERROR, "error interrupts generated by vlapic");
605330baf58SJohn Baldwin 
606330baf58SJohn Baldwin void
607330baf58SJohn Baldwin vlapic_set_error(struct vlapic *vlapic, uint32_t mask)
608330baf58SJohn Baldwin {
609330baf58SJohn Baldwin 	uint32_t lvt;
610330baf58SJohn Baldwin 
611330baf58SJohn Baldwin 	vlapic->esr_pending |= mask;
612330baf58SJohn Baldwin 	if (vlapic->esr_firing)
613330baf58SJohn Baldwin 		return;
614330baf58SJohn Baldwin 	vlapic->esr_firing = 1;
615330baf58SJohn Baldwin 
616330baf58SJohn Baldwin 	// The error LVT always uses the fixed delivery mode.
617330baf58SJohn Baldwin 	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_ERROR_LVT);
618330baf58SJohn Baldwin 	if (vlapic_fire_lvt(vlapic, lvt | APIC_LVT_DM_FIXED)) {
619330baf58SJohn Baldwin 		vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_ERROR, 1);
620330baf58SJohn Baldwin 	}
621330baf58SJohn Baldwin 	vlapic->esr_firing = 0;
622330baf58SJohn Baldwin }
623330baf58SJohn Baldwin 
62477d8fd9bSNeel Natu static VMM_STAT(VLAPIC_INTR_TIMER, "timer interrupts generated by vlapic");
62577d8fd9bSNeel Natu 
626366f6083SPeter Grehan static void
627366f6083SPeter Grehan vlapic_fire_timer(struct vlapic *vlapic)
628366f6083SPeter Grehan {
629fb03ca4eSNeel Natu 	uint32_t lvt;
630fb03ca4eSNeel Natu 
631fb03ca4eSNeel Natu 	KASSERT(VLAPIC_TIMER_LOCKED(vlapic), ("vlapic_fire_timer not locked"));
632366f6083SPeter Grehan 
633330baf58SJohn Baldwin 	// The timer LVT always uses the fixed delivery mode.
634366f6083SPeter Grehan 	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);
635330baf58SJohn Baldwin 	if (vlapic_fire_lvt(vlapic, lvt | APIC_LVT_DM_FIXED)) {
63677d8fd9bSNeel Natu 		vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_TIMER, 1);
637366f6083SPeter Grehan 	}
638366f6083SPeter Grehan }
639366f6083SPeter Grehan 
640330baf58SJohn Baldwin static VMM_STAT(VLAPIC_INTR_CMC,
641330baf58SJohn Baldwin     "corrected machine check interrupts generated by vlapic");
642330baf58SJohn Baldwin 
643330baf58SJohn Baldwin void
644330baf58SJohn Baldwin vlapic_fire_cmci(struct vlapic *vlapic)
645330baf58SJohn Baldwin {
646330baf58SJohn Baldwin 	uint32_t lvt;
647330baf58SJohn Baldwin 
648330baf58SJohn Baldwin 	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_CMCI_LVT);
649330baf58SJohn Baldwin 	if (vlapic_fire_lvt(vlapic, lvt)) {
650330baf58SJohn Baldwin 		vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_CMC, 1);
651330baf58SJohn Baldwin 	}
652330baf58SJohn Baldwin }
653330baf58SJohn Baldwin 
654330baf58SJohn Baldwin static VMM_STAT_ARRAY(LVTS_TRIGGERRED, VLAPIC_MAXLVT_ENTRIES,
655330baf58SJohn Baldwin     "lvts triggered");
656330baf58SJohn Baldwin 
657330baf58SJohn Baldwin int
658330baf58SJohn Baldwin vlapic_trigger_lvt(struct vlapic *vlapic, int vector)
659330baf58SJohn Baldwin {
660330baf58SJohn Baldwin 	uint32_t lvt;
661330baf58SJohn Baldwin 
662330baf58SJohn Baldwin 	switch (vector) {
663330baf58SJohn Baldwin 	case APIC_LVT_LINT0:
664330baf58SJohn Baldwin 		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_LINT0_LVT);
665330baf58SJohn Baldwin 		break;
666330baf58SJohn Baldwin 	case APIC_LVT_LINT1:
667330baf58SJohn Baldwin 		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_LINT1_LVT);
668330baf58SJohn Baldwin 		break;
669330baf58SJohn Baldwin 	case APIC_LVT_TIMER:
670330baf58SJohn Baldwin 		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);
671330baf58SJohn Baldwin 		lvt |= APIC_LVT_DM_FIXED;
672330baf58SJohn Baldwin 		break;
673330baf58SJohn Baldwin 	case APIC_LVT_ERROR:
674330baf58SJohn Baldwin 		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_ERROR_LVT);
675330baf58SJohn Baldwin 		lvt |= APIC_LVT_DM_FIXED;
676330baf58SJohn Baldwin 		break;
677330baf58SJohn Baldwin 	case APIC_LVT_PMC:
678330baf58SJohn Baldwin 		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_PERF_LVT);
679330baf58SJohn Baldwin 		break;
680330baf58SJohn Baldwin 	case APIC_LVT_THERMAL:
681330baf58SJohn Baldwin 		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_THERM_LVT);
682330baf58SJohn Baldwin 		break;
683330baf58SJohn Baldwin 	case APIC_LVT_CMCI:
684330baf58SJohn Baldwin 		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_CMCI_LVT);
685330baf58SJohn Baldwin 		break;
686330baf58SJohn Baldwin 	default:
687330baf58SJohn Baldwin 		return (EINVAL);
688330baf58SJohn Baldwin 	}
689330baf58SJohn Baldwin 	if (vlapic_fire_lvt(vlapic, lvt)) {
690330baf58SJohn Baldwin 		vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid,
691330baf58SJohn Baldwin 		    LVTS_TRIGGERRED, vector, 1);
692330baf58SJohn Baldwin 	}
693330baf58SJohn Baldwin 	return (0);
694330baf58SJohn Baldwin }
695330baf58SJohn Baldwin 
696fb03ca4eSNeel Natu static void
697fb03ca4eSNeel Natu vlapic_callout_handler(void *arg)
698fb03ca4eSNeel Natu {
699fb03ca4eSNeel Natu 	struct vlapic *vlapic;
700fb03ca4eSNeel Natu 	struct bintime bt, btnow;
701fb03ca4eSNeel Natu 	sbintime_t rem_sbt;
702fb03ca4eSNeel Natu 
703fb03ca4eSNeel Natu 	vlapic = arg;
704fb03ca4eSNeel Natu 
705fb03ca4eSNeel Natu 	VLAPIC_TIMER_LOCK(vlapic);
706fb03ca4eSNeel Natu 	if (callout_pending(&vlapic->callout))	/* callout was reset */
707fb03ca4eSNeel Natu 		goto done;
708fb03ca4eSNeel Natu 
709fb03ca4eSNeel Natu 	if (!callout_active(&vlapic->callout))	/* callout was stopped */
710fb03ca4eSNeel Natu 		goto done;
711fb03ca4eSNeel Natu 
712fb03ca4eSNeel Natu 	callout_deactivate(&vlapic->callout);
713fb03ca4eSNeel Natu 
714de5ea6b6SNeel Natu 	KASSERT(vlapic->apic_page->icr_timer != 0, ("timer is disabled"));
715fb03ca4eSNeel Natu 
716fb03ca4eSNeel Natu 	vlapic_fire_timer(vlapic);
717fb03ca4eSNeel Natu 
718fb03ca4eSNeel Natu 	if (vlapic_periodic_timer(vlapic)) {
719fb03ca4eSNeel Natu 		binuptime(&btnow);
720fb03ca4eSNeel Natu 		KASSERT(bintime_cmp(&btnow, &vlapic->timer_fire_bt, >=),
721fb03ca4eSNeel Natu 		    ("vlapic callout at %#lx.%#lx, expected at %#lx.#%lx",
722fb03ca4eSNeel Natu 		    btnow.sec, btnow.frac, vlapic->timer_fire_bt.sec,
723fb03ca4eSNeel Natu 		    vlapic->timer_fire_bt.frac));
724fb03ca4eSNeel Natu 
725fb03ca4eSNeel Natu 		/*
726fb03ca4eSNeel Natu 		 * Compute the delta between when the timer was supposed to
727fb03ca4eSNeel Natu 		 * fire and the present time.
728fb03ca4eSNeel Natu 		 */
729fb03ca4eSNeel Natu 		bt = btnow;
730fb03ca4eSNeel Natu 		bintime_sub(&bt, &vlapic->timer_fire_bt);
731fb03ca4eSNeel Natu 
732fb03ca4eSNeel Natu 		rem_sbt = bttosbt(vlapic->timer_period_bt);
733fb03ca4eSNeel Natu 		if (bintime_cmp(&bt, &vlapic->timer_period_bt, <)) {
734fb03ca4eSNeel Natu 			/*
735fb03ca4eSNeel Natu 			 * Adjust the time until the next countdown downward
736fb03ca4eSNeel Natu 			 * to account for the lost time.
737fb03ca4eSNeel Natu 			 */
738fb03ca4eSNeel Natu 			rem_sbt -= bttosbt(bt);
739fb03ca4eSNeel Natu 		} else {
740fb03ca4eSNeel Natu 			/*
741fb03ca4eSNeel Natu 			 * If the delta is greater than the timer period then
742fb03ca4eSNeel Natu 			 * just reset our time base instead of trying to catch
743fb03ca4eSNeel Natu 			 * up.
744fb03ca4eSNeel Natu 			 */
745fb03ca4eSNeel Natu 			vlapic->timer_fire_bt = btnow;
746fb03ca4eSNeel Natu 			VLAPIC_CTR2(vlapic, "vlapic timer lagging by %lu "
747fb03ca4eSNeel Natu 			    "usecs, period is %lu usecs - resetting time base",
748fb03ca4eSNeel Natu 			    bttosbt(bt) / SBT_1US,
749fb03ca4eSNeel Natu 			    bttosbt(vlapic->timer_period_bt) / SBT_1US);
750fb03ca4eSNeel Natu 		}
751fb03ca4eSNeel Natu 
752fb03ca4eSNeel Natu 		bintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt);
753fb03ca4eSNeel Natu 		callout_reset_sbt(&vlapic->callout, rem_sbt, 0,
754fb03ca4eSNeel Natu 		    vlapic_callout_handler, vlapic, 0);
755fb03ca4eSNeel Natu 	}
756fb03ca4eSNeel Natu done:
757fb03ca4eSNeel Natu 	VLAPIC_TIMER_UNLOCK(vlapic);
758fb03ca4eSNeel Natu }
759fb03ca4eSNeel Natu 
760fb03ca4eSNeel Natu static void
761fb03ca4eSNeel Natu vlapic_set_icr_timer(struct vlapic *vlapic, uint32_t icr_timer)
762fb03ca4eSNeel Natu {
763fb03ca4eSNeel Natu 	struct LAPIC *lapic;
764fb03ca4eSNeel Natu 	sbintime_t sbt;
765fb03ca4eSNeel Natu 
766fb03ca4eSNeel Natu 	VLAPIC_TIMER_LOCK(vlapic);
767fb03ca4eSNeel Natu 
768de5ea6b6SNeel Natu 	lapic = vlapic->apic_page;
769fb03ca4eSNeel Natu 	lapic->icr_timer = icr_timer;
770fb03ca4eSNeel Natu 
771fb03ca4eSNeel Natu 	vlapic->timer_period_bt = vlapic->timer_freq_bt;
772fb03ca4eSNeel Natu 	bintime_mul(&vlapic->timer_period_bt, icr_timer);
773fb03ca4eSNeel Natu 
774fb03ca4eSNeel Natu 	if (icr_timer != 0) {
775fb03ca4eSNeel Natu 		binuptime(&vlapic->timer_fire_bt);
776fb03ca4eSNeel Natu 		bintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt);
777fb03ca4eSNeel Natu 
778fb03ca4eSNeel Natu 		sbt = bttosbt(vlapic->timer_period_bt);
779fb03ca4eSNeel Natu 		callout_reset_sbt(&vlapic->callout, sbt, 0,
780fb03ca4eSNeel Natu 		    vlapic_callout_handler, vlapic, 0);
781fb03ca4eSNeel Natu 	} else
782fb03ca4eSNeel Natu 		callout_stop(&vlapic->callout);
783fb03ca4eSNeel Natu 
784fb03ca4eSNeel Natu 	VLAPIC_TIMER_UNLOCK(vlapic);
785fb03ca4eSNeel Natu }
786fb03ca4eSNeel Natu 
7874f8be175SNeel Natu /*
7884f8be175SNeel Natu  * This function populates 'dmask' with the set of vcpus that match the
7894f8be175SNeel Natu  * addressing specified by the (dest, phys, lowprio) tuple.
7904f8be175SNeel Natu  *
7914f8be175SNeel Natu  * 'x2apic_dest' specifies whether 'dest' is interpreted as x2APIC (32-bit)
7924f8be175SNeel Natu  * or xAPIC (8-bit) destination field.
7934f8be175SNeel Natu  */
7944f8be175SNeel Natu static void
7954f8be175SNeel Natu vlapic_calcdest(struct vm *vm, cpuset_t *dmask, uint32_t dest, bool phys,
7964f8be175SNeel Natu     bool lowprio, bool x2apic_dest)
7974f8be175SNeel Natu {
7984f8be175SNeel Natu 	struct vlapic *vlapic;
7994f8be175SNeel Natu 	uint32_t dfr, ldr, ldest, cluster;
8004f8be175SNeel Natu 	uint32_t mda_flat_ldest, mda_cluster_ldest, mda_ldest, mda_cluster_id;
8014f8be175SNeel Natu 	cpuset_t amask;
8024f8be175SNeel Natu 	int vcpuid;
8034f8be175SNeel Natu 
8044f8be175SNeel Natu 	if ((x2apic_dest && dest == 0xffffffff) ||
8054f8be175SNeel Natu 	    (!x2apic_dest && dest == 0xff)) {
8064f8be175SNeel Natu 		/*
8074f8be175SNeel Natu 		 * Broadcast in both logical and physical modes.
8084f8be175SNeel Natu 		 */
8094f8be175SNeel Natu 		*dmask = vm_active_cpus(vm);
8104f8be175SNeel Natu 		return;
8114f8be175SNeel Natu 	}
8124f8be175SNeel Natu 
8134f8be175SNeel Natu 	if (phys) {
8144f8be175SNeel Natu 		/*
8154f8be175SNeel Natu 		 * Physical mode: destination is APIC ID.
8164f8be175SNeel Natu 		 */
8174f8be175SNeel Natu 		CPU_ZERO(dmask);
8184f8be175SNeel Natu 		vcpuid = vm_apicid2vcpuid(vm, dest);
8194f8be175SNeel Natu 		if (vcpuid < VM_MAXCPU)
8204f8be175SNeel Natu 			CPU_SET(vcpuid, dmask);
8214f8be175SNeel Natu 	} else {
8224f8be175SNeel Natu 		/*
8234f8be175SNeel Natu 		 * In the "Flat Model" the MDA is interpreted as an 8-bit wide
8244f8be175SNeel Natu 		 * bitmask. This model is only avilable in the xAPIC mode.
8254f8be175SNeel Natu 		 */
8264f8be175SNeel Natu 		mda_flat_ldest = dest & 0xff;
8274f8be175SNeel Natu 
8284f8be175SNeel Natu 		/*
8294f8be175SNeel Natu 		 * In the "Cluster Model" the MDA is used to identify a
8304f8be175SNeel Natu 		 * specific cluster and a set of APICs in that cluster.
8314f8be175SNeel Natu 		 */
8324f8be175SNeel Natu 		if (x2apic_dest) {
8334f8be175SNeel Natu 			mda_cluster_id = dest >> 16;
8344f8be175SNeel Natu 			mda_cluster_ldest = dest & 0xffff;
8354f8be175SNeel Natu 		} else {
8364f8be175SNeel Natu 			mda_cluster_id = (dest >> 4) & 0xf;
8374f8be175SNeel Natu 			mda_cluster_ldest = dest & 0xf;
8384f8be175SNeel Natu 		}
8394f8be175SNeel Natu 
8404f8be175SNeel Natu 		/*
8414f8be175SNeel Natu 		 * Logical mode: match each APIC that has a bit set
8424f8be175SNeel Natu 		 * in it's LDR that matches a bit in the ldest.
8434f8be175SNeel Natu 		 */
8444f8be175SNeel Natu 		CPU_ZERO(dmask);
8454f8be175SNeel Natu 		amask = vm_active_cpus(vm);
8464f8be175SNeel Natu 		while ((vcpuid = CPU_FFS(&amask)) != 0) {
8474f8be175SNeel Natu 			vcpuid--;
8484f8be175SNeel Natu 			CPU_CLR(vcpuid, &amask);
8494f8be175SNeel Natu 
8504f8be175SNeel Natu 			vlapic = vm_lapic(vm, vcpuid);
8513f0ddc7cSNeel Natu 			dfr = vlapic->apic_page->dfr;
8523f0ddc7cSNeel Natu 			ldr = vlapic->apic_page->ldr;
8534f8be175SNeel Natu 
8544f8be175SNeel Natu 			if ((dfr & APIC_DFR_MODEL_MASK) ==
8554f8be175SNeel Natu 			    APIC_DFR_MODEL_FLAT) {
8564f8be175SNeel Natu 				ldest = ldr >> 24;
8574f8be175SNeel Natu 				mda_ldest = mda_flat_ldest;
8584f8be175SNeel Natu 			} else if ((dfr & APIC_DFR_MODEL_MASK) ==
8594f8be175SNeel Natu 			    APIC_DFR_MODEL_CLUSTER) {
8604f8be175SNeel Natu 				if (x2apic(vlapic)) {
8614f8be175SNeel Natu 					cluster = ldr >> 16;
8624f8be175SNeel Natu 					ldest = ldr & 0xffff;
8634f8be175SNeel Natu 				} else {
8644f8be175SNeel Natu 					cluster = ldr >> 28;
8654f8be175SNeel Natu 					ldest = (ldr >> 24) & 0xf;
8664f8be175SNeel Natu 				}
8674f8be175SNeel Natu 				if (cluster != mda_cluster_id)
8684f8be175SNeel Natu 					continue;
8694f8be175SNeel Natu 				mda_ldest = mda_cluster_ldest;
8704f8be175SNeel Natu 			} else {
8714f8be175SNeel Natu 				/*
8724f8be175SNeel Natu 				 * Guest has configured a bad logical
8734f8be175SNeel Natu 				 * model for this vcpu - skip it.
8744f8be175SNeel Natu 				 */
8754f8be175SNeel Natu 				VLAPIC_CTR1(vlapic, "vlapic has bad logical "
8764f8be175SNeel Natu 				    "model %x - cannot deliver interrupt", dfr);
8774f8be175SNeel Natu 				continue;
8784f8be175SNeel Natu 			}
8794f8be175SNeel Natu 
8804f8be175SNeel Natu 			if ((mda_ldest & ldest) != 0) {
8814f8be175SNeel Natu 				CPU_SET(vcpuid, dmask);
8824f8be175SNeel Natu 				if (lowprio)
8834f8be175SNeel Natu 					break;
8844f8be175SNeel Natu 			}
8854f8be175SNeel Natu 		}
8864f8be175SNeel Natu 	}
8874f8be175SNeel Natu }
8884f8be175SNeel Natu 
8890acb0d84SNeel Natu static VMM_STAT_ARRAY(IPIS_SENT, VM_MAXCPU, "ipis sent to vcpu");
8900acb0d84SNeel Natu 
891366f6083SPeter Grehan static int
892becd9849SNeel Natu lapic_process_icr(struct vlapic *vlapic, uint64_t icrval, bool *retu)
893366f6083SPeter Grehan {
894366f6083SPeter Grehan 	int i;
8954f8be175SNeel Natu 	bool phys;
896a5615c90SPeter Grehan 	cpuset_t dmask;
897366f6083SPeter Grehan 	uint32_t dest, vec, mode;
898edf89256SNeel Natu 	struct vlapic *vlapic2;
899edf89256SNeel Natu 	struct vm_exit *vmexit;
900366f6083SPeter Grehan 
901a2da7af6SNeel Natu 	if (x2apic(vlapic))
902366f6083SPeter Grehan 		dest = icrval >> 32;
903a2da7af6SNeel Natu 	else
904a2da7af6SNeel Natu 		dest = icrval >> (32 + 24);
905366f6083SPeter Grehan 	vec = icrval & APIC_VECTOR_MASK;
906366f6083SPeter Grehan 	mode = icrval & APIC_DELMODE_MASK;
907366f6083SPeter Grehan 
908330baf58SJohn Baldwin 	if (mode == APIC_DELMODE_FIXED && vec < 16) {
909330baf58SJohn Baldwin 		vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);
910330baf58SJohn Baldwin 		return (0);
911330baf58SJohn Baldwin 	}
912330baf58SJohn Baldwin 
913366f6083SPeter Grehan 	if (mode == APIC_DELMODE_FIXED || mode == APIC_DELMODE_NMI) {
914366f6083SPeter Grehan 		switch (icrval & APIC_DEST_MASK) {
915366f6083SPeter Grehan 		case APIC_DEST_DESTFLD:
9164f8be175SNeel Natu 			phys = ((icrval & APIC_DESTMODE_LOG) == 0);
9174f8be175SNeel Natu 			vlapic_calcdest(vlapic->vm, &dmask, dest, phys, false,
9184f8be175SNeel Natu 			    x2apic(vlapic));
919366f6083SPeter Grehan 			break;
920366f6083SPeter Grehan 		case APIC_DEST_SELF:
921a5615c90SPeter Grehan 			CPU_SETOF(vlapic->vcpuid, &dmask);
922366f6083SPeter Grehan 			break;
923366f6083SPeter Grehan 		case APIC_DEST_ALLISELF:
924366f6083SPeter Grehan 			dmask = vm_active_cpus(vlapic->vm);
925366f6083SPeter Grehan 			break;
926366f6083SPeter Grehan 		case APIC_DEST_ALLESELF:
927a5615c90SPeter Grehan 			dmask = vm_active_cpus(vlapic->vm);
928a5615c90SPeter Grehan 			CPU_CLR(vlapic->vcpuid, &dmask);
929366f6083SPeter Grehan 			break;
9301e2751ddSSergey Kandaurov 		default:
9311e2751ddSSergey Kandaurov 			CPU_ZERO(&dmask);	/* satisfy gcc */
9321e2751ddSSergey Kandaurov 			break;
933366f6083SPeter Grehan 		}
934366f6083SPeter Grehan 
93582f2974aSSergey Kandaurov 		while ((i = CPU_FFS(&dmask)) != 0) {
936a5615c90SPeter Grehan 			i--;
937a5615c90SPeter Grehan 			CPU_CLR(i, &dmask);
9380acb0d84SNeel Natu 			if (mode == APIC_DELMODE_FIXED) {
939b5b28fc9SNeel Natu 				lapic_intr_edge(vlapic->vm, i, vec);
9400acb0d84SNeel Natu 				vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid,
9410acb0d84SNeel Natu 						    IPIS_SENT, i, 1);
9420acb0d84SNeel Natu 			} else
943366f6083SPeter Grehan 				vm_inject_nmi(vlapic->vm, i);
944366f6083SPeter Grehan 		}
945366f6083SPeter Grehan 
946366f6083SPeter Grehan 		return (0);	/* handled completely in the kernel */
947366f6083SPeter Grehan 	}
948366f6083SPeter Grehan 
949edf89256SNeel Natu 	if (mode == APIC_DELMODE_INIT) {
950edf89256SNeel Natu 		if ((icrval & APIC_LEVEL_MASK) == APIC_LEVEL_DEASSERT)
951edf89256SNeel Natu 			return (0);
952edf89256SNeel Natu 
953edf89256SNeel Natu 		if (vlapic->vcpuid == 0 && dest != 0 && dest < VM_MAXCPU) {
954edf89256SNeel Natu 			vlapic2 = vm_lapic(vlapic->vm, dest);
955edf89256SNeel Natu 
956edf89256SNeel Natu 			/* move from INIT to waiting-for-SIPI state */
957edf89256SNeel Natu 			if (vlapic2->boot_state == BS_INIT) {
958edf89256SNeel Natu 				vlapic2->boot_state = BS_SIPI;
959edf89256SNeel Natu 			}
960edf89256SNeel Natu 
961edf89256SNeel Natu 			return (0);
962edf89256SNeel Natu 		}
963edf89256SNeel Natu 	}
964edf89256SNeel Natu 
965edf89256SNeel Natu 	if (mode == APIC_DELMODE_STARTUP) {
966edf89256SNeel Natu 		if (vlapic->vcpuid == 0 && dest != 0 && dest < VM_MAXCPU) {
967edf89256SNeel Natu 			vlapic2 = vm_lapic(vlapic->vm, dest);
968edf89256SNeel Natu 
969edf89256SNeel Natu 			/*
970edf89256SNeel Natu 			 * Ignore SIPIs in any state other than wait-for-SIPI
971edf89256SNeel Natu 			 */
972edf89256SNeel Natu 			if (vlapic2->boot_state != BS_SIPI)
973edf89256SNeel Natu 				return (0);
974edf89256SNeel Natu 
975366f6083SPeter Grehan 			/*
976366f6083SPeter Grehan 			 * XXX this assumes that the startup IPI always succeeds
977366f6083SPeter Grehan 			 */
978edf89256SNeel Natu 			vlapic2->boot_state = BS_RUNNING;
979edf89256SNeel Natu 			vm_activate_cpu(vlapic2->vm, dest);
980edf89256SNeel Natu 
981becd9849SNeel Natu 			*retu = true;
982becd9849SNeel Natu 			vmexit = vm_exitinfo(vlapic->vm, vlapic->vcpuid);
983becd9849SNeel Natu 			vmexit->exitcode = VM_EXITCODE_SPINUP_AP;
984becd9849SNeel Natu 			vmexit->u.spinup_ap.vcpu = dest;
985becd9849SNeel Natu 			vmexit->u.spinup_ap.rip = vec << PAGE_SHIFT;
986becd9849SNeel Natu 
987edf89256SNeel Natu 			return (0);
988edf89256SNeel Natu 		}
989edf89256SNeel Natu 	}
990366f6083SPeter Grehan 
991366f6083SPeter Grehan 	/*
992366f6083SPeter Grehan 	 * This will cause a return to userland.
993366f6083SPeter Grehan 	 */
994366f6083SPeter Grehan 	return (1);
995366f6083SPeter Grehan }
996366f6083SPeter Grehan 
997366f6083SPeter Grehan int
998366f6083SPeter Grehan vlapic_pending_intr(struct vlapic *vlapic)
999366f6083SPeter Grehan {
1000de5ea6b6SNeel Natu 	struct LAPIC	*lapic = vlapic->apic_page;
1001366f6083SPeter Grehan 	int	  	 idx, i, bitpos, vector;
1002366f6083SPeter Grehan 	uint32_t	*irrptr, val;
1003366f6083SPeter Grehan 
1004366f6083SPeter Grehan 	irrptr = &lapic->irr0;
1005366f6083SPeter Grehan 
1006366f6083SPeter Grehan 	/*
1007366f6083SPeter Grehan 	 * The x86 architecture reserves the the first 32 vectors for use
1008366f6083SPeter Grehan 	 * by the processor.
1009366f6083SPeter Grehan 	 */
1010366f6083SPeter Grehan 	for (i = 7; i > 0; i--) {
1011366f6083SPeter Grehan 		idx = i * 4;
1012366f6083SPeter Grehan 		val = atomic_load_acq_int(&irrptr[idx]);
1013366f6083SPeter Grehan 		bitpos = fls(val);
1014366f6083SPeter Grehan 		if (bitpos != 0) {
1015366f6083SPeter Grehan 			vector = i * 32 + (bitpos - 1);
1016366f6083SPeter Grehan 			if (PRIO(vector) > PRIO(lapic->ppr)) {
1017366f6083SPeter Grehan 				VLAPIC_CTR1(vlapic, "pending intr %d", vector);
1018366f6083SPeter Grehan 				return (vector);
1019366f6083SPeter Grehan 			} else
1020366f6083SPeter Grehan 				break;
1021366f6083SPeter Grehan 		}
1022366f6083SPeter Grehan 	}
1023366f6083SPeter Grehan 	return (-1);
1024366f6083SPeter Grehan }
1025366f6083SPeter Grehan 
1026366f6083SPeter Grehan void
1027366f6083SPeter Grehan vlapic_intr_accepted(struct vlapic *vlapic, int vector)
1028366f6083SPeter Grehan {
1029de5ea6b6SNeel Natu 	struct LAPIC	*lapic = vlapic->apic_page;
1030366f6083SPeter Grehan 	uint32_t	*irrptr, *isrptr;
1031366f6083SPeter Grehan 	int		idx, stk_top;
1032366f6083SPeter Grehan 
1033366f6083SPeter Grehan 	/*
1034366f6083SPeter Grehan 	 * clear the ready bit for vector being accepted in irr
1035366f6083SPeter Grehan 	 * and set the vector as in service in isr.
1036366f6083SPeter Grehan 	 */
1037366f6083SPeter Grehan 	idx = (vector / 32) * 4;
1038366f6083SPeter Grehan 
1039366f6083SPeter Grehan 	irrptr = &lapic->irr0;
1040366f6083SPeter Grehan 	atomic_clear_int(&irrptr[idx], 1 << (vector % 32));
1041366f6083SPeter Grehan 	VLAPIC_CTR_IRR(vlapic, "vlapic_intr_accepted");
1042366f6083SPeter Grehan 
1043366f6083SPeter Grehan 	isrptr = &lapic->isr0;
1044366f6083SPeter Grehan 	isrptr[idx] |= 1 << (vector % 32);
1045366f6083SPeter Grehan 	VLAPIC_CTR_ISR(vlapic, "vlapic_intr_accepted");
1046366f6083SPeter Grehan 
1047366f6083SPeter Grehan 	/*
1048366f6083SPeter Grehan 	 * Update the PPR
1049366f6083SPeter Grehan 	 */
1050366f6083SPeter Grehan 	vlapic->isrvec_stk_top++;
1051366f6083SPeter Grehan 
1052366f6083SPeter Grehan 	stk_top = vlapic->isrvec_stk_top;
1053366f6083SPeter Grehan 	if (stk_top >= ISRVEC_STK_SIZE)
1054366f6083SPeter Grehan 		panic("isrvec_stk_top overflow %d", stk_top);
1055366f6083SPeter Grehan 
1056366f6083SPeter Grehan 	vlapic->isrvec_stk[stk_top] = vector;
1057366f6083SPeter Grehan 	vlapic_update_ppr(vlapic);
1058366f6083SPeter Grehan }
1059366f6083SPeter Grehan 
1060*2c52dcd9SNeel Natu void
1061*2c52dcd9SNeel Natu vlapic_svr_write_handler(struct vlapic *vlapic)
10621c052192SNeel Natu {
10631c052192SNeel Natu 	struct LAPIC *lapic;
1064*2c52dcd9SNeel Natu 	uint32_t old, new, changed;
10651c052192SNeel Natu 
1066de5ea6b6SNeel Natu 	lapic = vlapic->apic_page;
1067*2c52dcd9SNeel Natu 
1068*2c52dcd9SNeel Natu 	new = lapic->svr;
1069*2c52dcd9SNeel Natu 	old = vlapic->svr_last;
1070*2c52dcd9SNeel Natu 	vlapic->svr_last = new;
1071*2c52dcd9SNeel Natu 
10721c052192SNeel Natu 	changed = old ^ new;
10731c052192SNeel Natu 	if ((changed & APIC_SVR_ENABLE) != 0) {
10741c052192SNeel Natu 		if ((new & APIC_SVR_ENABLE) == 0) {
1075fb03ca4eSNeel Natu 			/*
1076*2c52dcd9SNeel Natu 			 * The apic is now disabled so stop the apic timer
1077*2c52dcd9SNeel Natu 			 * and mask all the LVT entries.
1078fb03ca4eSNeel Natu 			 */
10791c052192SNeel Natu 			VLAPIC_CTR0(vlapic, "vlapic is software-disabled");
1080fb03ca4eSNeel Natu 			VLAPIC_TIMER_LOCK(vlapic);
1081fb03ca4eSNeel Natu 			callout_stop(&vlapic->callout);
1082fb03ca4eSNeel Natu 			VLAPIC_TIMER_UNLOCK(vlapic);
1083*2c52dcd9SNeel Natu 			vlapic_mask_lvts(vlapic);
10841c052192SNeel Natu 		} else {
1085fb03ca4eSNeel Natu 			/*
1086fb03ca4eSNeel Natu 			 * The apic is now enabled so restart the apic timer
1087fb03ca4eSNeel Natu 			 * if it is configured in periodic mode.
1088fb03ca4eSNeel Natu 			 */
10891c052192SNeel Natu 			VLAPIC_CTR0(vlapic, "vlapic is software-enabled");
1090fb03ca4eSNeel Natu 			if (vlapic_periodic_timer(vlapic))
1091fb03ca4eSNeel Natu 				vlapic_set_icr_timer(vlapic, lapic->icr_timer);
10921c052192SNeel Natu 		}
10931c052192SNeel Natu 	}
10941c052192SNeel Natu }
10951c052192SNeel Natu 
1096366f6083SPeter Grehan int
1097becd9849SNeel Natu vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data, bool *retu)
1098366f6083SPeter Grehan {
1099de5ea6b6SNeel Natu 	struct LAPIC	*lapic = vlapic->apic_page;
1100366f6083SPeter Grehan 	uint32_t	*reg;
1101366f6083SPeter Grehan 	int		 i;
1102366f6083SPeter Grehan 
1103366f6083SPeter Grehan 	if (offset > sizeof(*lapic)) {
1104366f6083SPeter Grehan 		*data = 0;
11051c052192SNeel Natu 		goto done;
1106366f6083SPeter Grehan 	}
1107366f6083SPeter Grehan 
1108366f6083SPeter Grehan 	offset &= ~3;
1109366f6083SPeter Grehan 	switch(offset)
1110366f6083SPeter Grehan 	{
1111366f6083SPeter Grehan 		case APIC_OFFSET_ID:
11123f0ddc7cSNeel Natu 			*data = lapic->id;
1113366f6083SPeter Grehan 			break;
1114366f6083SPeter Grehan 		case APIC_OFFSET_VER:
1115366f6083SPeter Grehan 			*data = lapic->version;
1116366f6083SPeter Grehan 			break;
1117366f6083SPeter Grehan 		case APIC_OFFSET_TPR:
1118366f6083SPeter Grehan 			*data = lapic->tpr;
1119366f6083SPeter Grehan 			break;
1120366f6083SPeter Grehan 		case APIC_OFFSET_APR:
1121366f6083SPeter Grehan 			*data = lapic->apr;
1122366f6083SPeter Grehan 			break;
1123366f6083SPeter Grehan 		case APIC_OFFSET_PPR:
1124366f6083SPeter Grehan 			*data = lapic->ppr;
1125366f6083SPeter Grehan 			break;
1126366f6083SPeter Grehan 		case APIC_OFFSET_EOI:
1127366f6083SPeter Grehan 			*data = lapic->eoi;
1128366f6083SPeter Grehan 			break;
1129366f6083SPeter Grehan 		case APIC_OFFSET_LDR:
11303f0ddc7cSNeel Natu 			*data = lapic->ldr;
1131366f6083SPeter Grehan 			break;
1132366f6083SPeter Grehan 		case APIC_OFFSET_DFR:
11333f0ddc7cSNeel Natu 			*data = lapic->dfr;
1134366f6083SPeter Grehan 			break;
1135366f6083SPeter Grehan 		case APIC_OFFSET_SVR:
1136366f6083SPeter Grehan 			*data = lapic->svr;
1137366f6083SPeter Grehan 			break;
1138366f6083SPeter Grehan 		case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7:
1139366f6083SPeter Grehan 			i = (offset - APIC_OFFSET_ISR0) >> 2;
1140366f6083SPeter Grehan 			reg = &lapic->isr0;
1141366f6083SPeter Grehan 			*data = *(reg + i);
1142366f6083SPeter Grehan 			break;
1143366f6083SPeter Grehan 		case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7:
1144366f6083SPeter Grehan 			i = (offset - APIC_OFFSET_TMR0) >> 2;
1145366f6083SPeter Grehan 			reg = &lapic->tmr0;
1146366f6083SPeter Grehan 			*data = *(reg + i);
1147366f6083SPeter Grehan 			break;
1148366f6083SPeter Grehan 		case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7:
1149366f6083SPeter Grehan 			i = (offset - APIC_OFFSET_IRR0) >> 2;
1150366f6083SPeter Grehan 			reg = &lapic->irr0;
1151366f6083SPeter Grehan 			*data = atomic_load_acq_int(reg + i);
1152366f6083SPeter Grehan 			break;
1153366f6083SPeter Grehan 		case APIC_OFFSET_ESR:
1154366f6083SPeter Grehan 			*data = lapic->esr;
1155366f6083SPeter Grehan 			break;
1156366f6083SPeter Grehan 		case APIC_OFFSET_ICR_LOW:
1157366f6083SPeter Grehan 			*data = lapic->icr_lo;
1158366f6083SPeter Grehan 			break;
1159366f6083SPeter Grehan 		case APIC_OFFSET_ICR_HI:
1160366f6083SPeter Grehan 			*data = lapic->icr_hi;
1161366f6083SPeter Grehan 			break;
1162330baf58SJohn Baldwin 		case APIC_OFFSET_CMCI_LVT:
1163366f6083SPeter Grehan 		case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT:
1164fb03ca4eSNeel Natu 			*data = vlapic_get_lvt(vlapic, offset);
1165366f6083SPeter Grehan 			break;
1166de5ea6b6SNeel Natu 		case APIC_OFFSET_TIMER_ICR:
1167366f6083SPeter Grehan 			*data = lapic->icr_timer;
1168366f6083SPeter Grehan 			break;
1169de5ea6b6SNeel Natu 		case APIC_OFFSET_TIMER_CCR:
1170366f6083SPeter Grehan 			*data = vlapic_get_ccr(vlapic);
1171366f6083SPeter Grehan 			break;
1172de5ea6b6SNeel Natu 		case APIC_OFFSET_TIMER_DCR:
1173366f6083SPeter Grehan 			*data = lapic->dcr_timer;
1174366f6083SPeter Grehan 			break;
1175366f6083SPeter Grehan 		case APIC_OFFSET_RRR:
1176366f6083SPeter Grehan 		default:
1177366f6083SPeter Grehan 			*data = 0;
1178366f6083SPeter Grehan 			break;
1179366f6083SPeter Grehan 	}
11801c052192SNeel Natu done:
11811c052192SNeel Natu 	VLAPIC_CTR2(vlapic, "vlapic read offset %#x, data %#lx", offset, *data);
1182366f6083SPeter Grehan 	return 0;
1183366f6083SPeter Grehan }
1184366f6083SPeter Grehan 
1185366f6083SPeter Grehan int
1186becd9849SNeel Natu vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu)
1187366f6083SPeter Grehan {
1188de5ea6b6SNeel Natu 	struct LAPIC	*lapic = vlapic->apic_page;
1189366f6083SPeter Grehan 	int		retval;
1190366f6083SPeter Grehan 
11913f0ddc7cSNeel Natu 	KASSERT((offset & 0xf) == 0 && offset < PAGE_SIZE,
11923f0ddc7cSNeel Natu 	    ("vlapic_write: invalid offset %#lx", offset));
11933f0ddc7cSNeel Natu 
11941c052192SNeel Natu 	VLAPIC_CTR2(vlapic, "vlapic write offset %#x, data %#lx", offset, data);
11951c052192SNeel Natu 
1196366f6083SPeter Grehan 	if (offset > sizeof(*lapic)) {
1197366f6083SPeter Grehan 		return 0;
1198366f6083SPeter Grehan 	}
1199366f6083SPeter Grehan 
1200366f6083SPeter Grehan 	retval = 0;
1201366f6083SPeter Grehan 	switch(offset)
1202366f6083SPeter Grehan 	{
1203366f6083SPeter Grehan 		case APIC_OFFSET_ID:
12043f0ddc7cSNeel Natu 			lapic->id = data;
12053f0ddc7cSNeel Natu 			vlapic_id_write_handler(vlapic);
1206366f6083SPeter Grehan 			break;
1207366f6083SPeter Grehan 		case APIC_OFFSET_TPR:
1208366f6083SPeter Grehan 			lapic->tpr = data & 0xff;
1209366f6083SPeter Grehan 			vlapic_update_ppr(vlapic);
1210366f6083SPeter Grehan 			break;
1211366f6083SPeter Grehan 		case APIC_OFFSET_EOI:
1212366f6083SPeter Grehan 			vlapic_process_eoi(vlapic);
1213366f6083SPeter Grehan 			break;
1214366f6083SPeter Grehan 		case APIC_OFFSET_LDR:
12153f0ddc7cSNeel Natu 			lapic->ldr = data;
12163f0ddc7cSNeel Natu 			vlapic_ldr_write_handler(vlapic);
1217366f6083SPeter Grehan 			break;
1218366f6083SPeter Grehan 		case APIC_OFFSET_DFR:
12193f0ddc7cSNeel Natu 			lapic->dfr = data;
12203f0ddc7cSNeel Natu 			vlapic_dfr_write_handler(vlapic);
1221366f6083SPeter Grehan 			break;
1222366f6083SPeter Grehan 		case APIC_OFFSET_SVR:
1223*2c52dcd9SNeel Natu 			lapic->svr = data;
1224*2c52dcd9SNeel Natu 			vlapic_svr_write_handler(vlapic);
1225366f6083SPeter Grehan 			break;
1226366f6083SPeter Grehan 		case APIC_OFFSET_ICR_LOW:
1227a2da7af6SNeel Natu 			if (!x2apic(vlapic)) {
1228a2da7af6SNeel Natu 				data &= 0xffffffff;
1229a2da7af6SNeel Natu 				data |= (uint64_t)lapic->icr_hi << 32;
1230a2da7af6SNeel Natu 			}
1231becd9849SNeel Natu 			retval = lapic_process_icr(vlapic, data, retu);
1232366f6083SPeter Grehan 			break;
1233a2da7af6SNeel Natu 		case APIC_OFFSET_ICR_HI:
1234a2da7af6SNeel Natu 			if (!x2apic(vlapic)) {
1235a2da7af6SNeel Natu 				retval = 0;
1236a2da7af6SNeel Natu 				lapic->icr_hi = data;
1237a2da7af6SNeel Natu 			}
1238a2da7af6SNeel Natu 			break;
1239330baf58SJohn Baldwin 		case APIC_OFFSET_CMCI_LVT:
1240366f6083SPeter Grehan 		case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT:
1241fb03ca4eSNeel Natu 			vlapic_set_lvt(vlapic, offset, data);
1242366f6083SPeter Grehan 			break;
1243de5ea6b6SNeel Natu 		case APIC_OFFSET_TIMER_ICR:
1244fb03ca4eSNeel Natu 			vlapic_set_icr_timer(vlapic, data);
1245366f6083SPeter Grehan 			break;
1246366f6083SPeter Grehan 
1247de5ea6b6SNeel Natu 		case APIC_OFFSET_TIMER_DCR:
1248fb03ca4eSNeel Natu 			vlapic_set_dcr(vlapic, data);
1249366f6083SPeter Grehan 			break;
1250366f6083SPeter Grehan 
1251366f6083SPeter Grehan 		case APIC_OFFSET_ESR:
1252366f6083SPeter Grehan 			vlapic_update_errors(vlapic);
1253366f6083SPeter Grehan 			break;
1254366f6083SPeter Grehan 		case APIC_OFFSET_VER:
1255366f6083SPeter Grehan 		case APIC_OFFSET_APR:
1256366f6083SPeter Grehan 		case APIC_OFFSET_PPR:
1257366f6083SPeter Grehan 		case APIC_OFFSET_RRR:
1258366f6083SPeter Grehan 		case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7:
1259366f6083SPeter Grehan 		case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7:
1260366f6083SPeter Grehan 		case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7:
1261de5ea6b6SNeel Natu 		case APIC_OFFSET_TIMER_CCR:
1262366f6083SPeter Grehan 		default:
1263366f6083SPeter Grehan 			// Read only.
1264366f6083SPeter Grehan 			break;
1265366f6083SPeter Grehan 	}
1266366f6083SPeter Grehan 
1267366f6083SPeter Grehan 	return (retval);
1268366f6083SPeter Grehan }
1269366f6083SPeter Grehan 
1270de5ea6b6SNeel Natu void
1271de5ea6b6SNeel Natu vlapic_init(struct vlapic *vlapic)
1272366f6083SPeter Grehan {
1273de5ea6b6SNeel Natu 	KASSERT(vlapic->vm != NULL, ("vlapic_init: vm is not initialized"));
1274de5ea6b6SNeel Natu 	KASSERT(vlapic->vcpuid >= 0 && vlapic->vcpuid < VM_MAXCPU,
1275de5ea6b6SNeel Natu 	    ("vlapic_init: vcpuid is not initialized"));
1276de5ea6b6SNeel Natu 	KASSERT(vlapic->apic_page != NULL, ("vlapic_init: apic_page is not "
1277de5ea6b6SNeel Natu 	    "initialized"));
12782d3a73edSNeel Natu 
1279becd9849SNeel Natu 	/*
1280becd9849SNeel Natu 	 * If the vlapic is configured in x2apic mode then it will be
1281becd9849SNeel Natu 	 * accessed in the critical section via the MSR emulation code.
1282becd9849SNeel Natu 	 *
1283becd9849SNeel Natu 	 * Therefore the timer mutex must be a spinlock because blockable
1284becd9849SNeel Natu 	 * mutexes cannot be acquired in a critical section.
1285becd9849SNeel Natu 	 */
1286becd9849SNeel Natu 	mtx_init(&vlapic->timer_mtx, "vlapic timer mtx", NULL, MTX_SPIN);
1287fb03ca4eSNeel Natu 	callout_init(&vlapic->callout, 1);
1288fb03ca4eSNeel Natu 
1289a2da7af6SNeel Natu 	vlapic->msr_apicbase = DEFAULT_APIC_BASE | APICBASE_ENABLED;
12902d3a73edSNeel Natu 
1291de5ea6b6SNeel Natu 	if (vlapic->vcpuid == 0)
12922d3a73edSNeel Natu 		vlapic->msr_apicbase |= APICBASE_BSP;
12932d3a73edSNeel Natu 
129403cd0501SNeel Natu 	vlapic_reset(vlapic);
1295366f6083SPeter Grehan }
1296366f6083SPeter Grehan 
1297366f6083SPeter Grehan void
1298366f6083SPeter Grehan vlapic_cleanup(struct vlapic *vlapic)
1299366f6083SPeter Grehan {
130003cd0501SNeel Natu 
1301fb03ca4eSNeel Natu 	callout_drain(&vlapic->callout);
1302366f6083SPeter Grehan }
13032d3a73edSNeel Natu 
13042d3a73edSNeel Natu uint64_t
13052d3a73edSNeel Natu vlapic_get_apicbase(struct vlapic *vlapic)
13062d3a73edSNeel Natu {
13072d3a73edSNeel Natu 
13082d3a73edSNeel Natu 	return (vlapic->msr_apicbase);
13092d3a73edSNeel Natu }
13102d3a73edSNeel Natu 
13112d3a73edSNeel Natu void
13123f0ddc7cSNeel Natu vlapic_set_apicbase(struct vlapic *vlapic, uint64_t new)
13132d3a73edSNeel Natu {
13143f0ddc7cSNeel Natu 	struct LAPIC *lapic;
1315a2da7af6SNeel Natu 	enum x2apic_state state;
13163f0ddc7cSNeel Natu 	uint64_t old;
13173f0ddc7cSNeel Natu 	int err;
1318a2da7af6SNeel Natu 
1319a2da7af6SNeel Natu 	err = vm_get_x2apic_state(vlapic->vm, vlapic->vcpuid, &state);
1320a2da7af6SNeel Natu 	if (err)
1321a2da7af6SNeel Natu 		panic("vlapic_set_apicbase: err %d fetching x2apic state", err);
1322a2da7af6SNeel Natu 
1323a2da7af6SNeel Natu 	if (state == X2APIC_DISABLED)
13243f0ddc7cSNeel Natu 		new &= ~APICBASE_X2APIC;
13252d3a73edSNeel Natu 
13263f0ddc7cSNeel Natu 	old = vlapic->msr_apicbase;
13273f0ddc7cSNeel Natu 	vlapic->msr_apicbase = new;
13283f0ddc7cSNeel Natu 
13293f0ddc7cSNeel Natu 	/*
13303f0ddc7cSNeel Natu 	 * If the vlapic is switching between xAPIC and x2APIC modes then
13313f0ddc7cSNeel Natu 	 * reset the mode-dependent registers.
13323f0ddc7cSNeel Natu 	 */
13333f0ddc7cSNeel Natu 	if ((old ^ new) & APICBASE_X2APIC) {
13343f0ddc7cSNeel Natu 		lapic = vlapic->apic_page;
13353f0ddc7cSNeel Natu 		lapic->id = vlapic_get_id(vlapic);
13363f0ddc7cSNeel Natu 		if (x2apic(vlapic)) {
13373f0ddc7cSNeel Natu 			lapic->ldr = x2apic_ldr(vlapic);
13383f0ddc7cSNeel Natu 			lapic->dfr = 0;
13393f0ddc7cSNeel Natu 		} else {
13403f0ddc7cSNeel Natu 			lapic->ldr = 0;
13413f0ddc7cSNeel Natu 			lapic->dfr = 0xffffffff;
13423f0ddc7cSNeel Natu 		}
13433f0ddc7cSNeel Natu 	}
13442d3a73edSNeel Natu }
134573820fb0SNeel Natu 
134673820fb0SNeel Natu void
134773820fb0SNeel Natu vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state)
134873820fb0SNeel Natu {
134973820fb0SNeel Natu 	struct vlapic *vlapic;
135073820fb0SNeel Natu 
135173820fb0SNeel Natu 	vlapic = vm_lapic(vm, vcpuid);
135273820fb0SNeel Natu 
1353485f986aSNeel Natu 	if (state == X2APIC_DISABLED)
135473820fb0SNeel Natu 		vlapic->msr_apicbase &= ~APICBASE_X2APIC;
135573820fb0SNeel Natu }
13561c052192SNeel Natu 
13574f8be175SNeel Natu void
13584f8be175SNeel Natu vlapic_deliver_intr(struct vm *vm, bool level, uint32_t dest, bool phys,
13594f8be175SNeel Natu     int delmode, int vec)
13604f8be175SNeel Natu {
13614f8be175SNeel Natu 	bool lowprio;
13624f8be175SNeel Natu 	int vcpuid;
13634f8be175SNeel Natu 	cpuset_t dmask;
13644f8be175SNeel Natu 
13654f8be175SNeel Natu 	if (delmode != APIC_DELMODE_FIXED && delmode != APIC_DELMODE_LOWPRIO) {
13664f8be175SNeel Natu 		VM_CTR1(vm, "vlapic intr invalid delmode %#x", delmode);
13674f8be175SNeel Natu 		return;
13684f8be175SNeel Natu 	}
13694f8be175SNeel Natu 	lowprio = (delmode == APIC_DELMODE_LOWPRIO);
13704f8be175SNeel Natu 
13714f8be175SNeel Natu 	/*
13724f8be175SNeel Natu 	 * We don't provide any virtual interrupt redirection hardware so
13734f8be175SNeel Natu 	 * all interrupts originating from the ioapic or MSI specify the
13744f8be175SNeel Natu 	 * 'dest' in the legacy xAPIC format.
13754f8be175SNeel Natu 	 */
13764f8be175SNeel Natu 	vlapic_calcdest(vm, &dmask, dest, phys, lowprio, false);
13774f8be175SNeel Natu 
13784f8be175SNeel Natu 	while ((vcpuid = CPU_FFS(&dmask)) != 0) {
13794f8be175SNeel Natu 		vcpuid--;
13804f8be175SNeel Natu 		CPU_CLR(vcpuid, &dmask);
13814f8be175SNeel Natu 		lapic_set_intr(vm, vcpuid, vec, level);
13824f8be175SNeel Natu 	}
13834f8be175SNeel Natu }
13844f8be175SNeel Natu 
1385de5ea6b6SNeel Natu void
1386de5ea6b6SNeel Natu vlapic_post_intr(struct vlapic *vlapic, int hostcpu)
1387de5ea6b6SNeel Natu {
1388de5ea6b6SNeel Natu 	/*
1389de5ea6b6SNeel Natu 	 * Post an interrupt to the vcpu currently running on 'hostcpu'.
1390de5ea6b6SNeel Natu 	 *
1391de5ea6b6SNeel Natu 	 * This is done by leveraging features like Posted Interrupts (Intel)
1392de5ea6b6SNeel Natu 	 * Doorbell MSR (AMD AVIC) that avoid a VM exit.
1393de5ea6b6SNeel Natu 	 *
1394de5ea6b6SNeel Natu 	 * If neither of these features are available then fallback to
1395de5ea6b6SNeel Natu 	 * sending an IPI to 'hostcpu'.
1396de5ea6b6SNeel Natu 	 */
1397de5ea6b6SNeel Natu 	ipi_cpu(hostcpu, vmm_ipinum);
1398de5ea6b6SNeel Natu }
1399de5ea6b6SNeel Natu 
14001c052192SNeel Natu bool
14011c052192SNeel Natu vlapic_enabled(struct vlapic *vlapic)
14021c052192SNeel Natu {
1403de5ea6b6SNeel Natu 	struct LAPIC *lapic = vlapic->apic_page;
14041c052192SNeel Natu 
14051c052192SNeel Natu 	if ((vlapic->msr_apicbase & APICBASE_ENABLED) != 0 &&
14061c052192SNeel Natu 	    (lapic->svr & APIC_SVR_ENABLE) != 0)
14071c052192SNeel Natu 		return (true);
14081c052192SNeel Natu 	else
14091c052192SNeel Natu 		return (false);
14101c052192SNeel Natu }
1411