xref: /freebsd/sys/amd64/vmm/io/vlapic.c (revision 2d3a73ed6d731650efe54be793decf86c34a990b)
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>
33366f6083SPeter Grehan #include <sys/kernel.h>
34366f6083SPeter Grehan #include <sys/malloc.h>
35366f6083SPeter Grehan #include <sys/systm.h>
36a5615c90SPeter Grehan #include <sys/smp.h>
37366f6083SPeter Grehan 
38366f6083SPeter Grehan #include <machine/clock.h>
39*2d3a73edSNeel Natu #include <x86/specialreg.h>
4034a6b2d6SJohn Baldwin #include <x86/apicreg.h>
41366f6083SPeter Grehan 
42366f6083SPeter Grehan #include <machine/vmm.h>
43366f6083SPeter Grehan 
44366f6083SPeter Grehan #include "vmm_lapic.h"
45366f6083SPeter Grehan #include "vmm_ktr.h"
46366f6083SPeter Grehan #include "vdev.h"
47366f6083SPeter Grehan #include "vlapic.h"
48366f6083SPeter Grehan 
49366f6083SPeter Grehan #define	VLAPIC_CTR0(vlapic, format)					\
50366f6083SPeter Grehan 	VMM_CTR0((vlapic)->vm, (vlapic)->vcpuid, format)
51366f6083SPeter Grehan 
52366f6083SPeter Grehan #define	VLAPIC_CTR1(vlapic, format, p1)					\
53366f6083SPeter Grehan 	VMM_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1)
54366f6083SPeter Grehan 
55366f6083SPeter Grehan #define	VLAPIC_CTR_IRR(vlapic, msg)					\
56366f6083SPeter Grehan do {									\
57366f6083SPeter Grehan 	uint32_t *irrptr = &(vlapic)->apic.irr0;			\
58366f6083SPeter Grehan 	irrptr[0] = irrptr[0];	/* silence compiler */			\
59366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr0 0x%08x", irrptr[0 << 2]);	\
60366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr1 0x%08x", irrptr[1 << 2]);	\
61366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr2 0x%08x", irrptr[2 << 2]);	\
62366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr3 0x%08x", irrptr[3 << 2]);	\
63366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr4 0x%08x", irrptr[4 << 2]);	\
64366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr5 0x%08x", irrptr[5 << 2]);	\
65366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr6 0x%08x", irrptr[6 << 2]);	\
66366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " irr7 0x%08x", irrptr[7 << 2]);	\
67366f6083SPeter Grehan } while (0)
68366f6083SPeter Grehan 
69366f6083SPeter Grehan #define	VLAPIC_CTR_ISR(vlapic, msg)					\
70366f6083SPeter Grehan do {									\
71366f6083SPeter Grehan 	uint32_t *isrptr = &(vlapic)->apic.isr0;			\
72366f6083SPeter Grehan 	isrptr[0] = isrptr[0];	/* silence compiler */			\
73366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr0 0x%08x", isrptr[0 << 2]);	\
74366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr1 0x%08x", isrptr[1 << 2]);	\
75366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr2 0x%08x", isrptr[2 << 2]);	\
76366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr3 0x%08x", isrptr[3 << 2]);	\
77366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr4 0x%08x", isrptr[4 << 2]);	\
78366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr5 0x%08x", isrptr[5 << 2]);	\
79366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr6 0x%08x", isrptr[6 << 2]);	\
80366f6083SPeter Grehan 	VLAPIC_CTR1((vlapic), msg " isr7 0x%08x", isrptr[7 << 2]);	\
81366f6083SPeter Grehan } while (0)
82366f6083SPeter Grehan 
83366f6083SPeter Grehan static MALLOC_DEFINE(M_VLAPIC, "vlapic", "vlapic");
84366f6083SPeter Grehan 
85366f6083SPeter Grehan #define	PRIO(x)			((x) >> 4)
86366f6083SPeter Grehan 
87366f6083SPeter Grehan #define VLAPIC_VERSION		(16)
88366f6083SPeter Grehan #define VLAPIC_MAXLVT_ENTRIES	(5)
89366f6083SPeter Grehan 
90*2d3a73edSNeel Natu #define	x2apic(vlapic)		((vlapic)->msr_apicbase & APICBASE_X2APIC)
91*2d3a73edSNeel Natu 
92366f6083SPeter Grehan struct vlapic {
93366f6083SPeter Grehan 	struct vm		*vm;
94366f6083SPeter Grehan 	int			vcpuid;
95366f6083SPeter Grehan 
96366f6083SPeter Grehan 	struct io_region	*mmio;
97366f6083SPeter Grehan 	struct vdev_ops		*ops;
98366f6083SPeter Grehan 	struct LAPIC		 apic;
99366f6083SPeter Grehan 
100366f6083SPeter Grehan 	int			 esr_update;
101366f6083SPeter Grehan 
102366f6083SPeter Grehan 	int			 divisor;
103366f6083SPeter Grehan 	int			 ccr_ticks;
104366f6083SPeter Grehan 
105366f6083SPeter Grehan 	/*
106366f6083SPeter Grehan 	 * The 'isrvec_stk' is a stack of vectors injected by the local apic.
107366f6083SPeter Grehan 	 * A vector is popped from the stack when the processor does an EOI.
108366f6083SPeter Grehan 	 * The vector on the top of the stack is used to compute the
109366f6083SPeter Grehan 	 * Processor Priority in conjunction with the TPR.
110366f6083SPeter Grehan 	 */
111366f6083SPeter Grehan 	uint8_t			 isrvec_stk[ISRVEC_STK_SIZE];
112366f6083SPeter Grehan 	int			 isrvec_stk_top;
113*2d3a73edSNeel Natu 
114*2d3a73edSNeel Natu 	uint64_t		msr_apicbase;
115366f6083SPeter Grehan };
116366f6083SPeter Grehan 
117366f6083SPeter Grehan static void
118366f6083SPeter Grehan vlapic_mask_lvts(uint32_t *lvts, int num_lvt)
119366f6083SPeter Grehan {
120366f6083SPeter Grehan 	int i;
121366f6083SPeter Grehan 	for (i = 0; i < num_lvt; i++) {
122366f6083SPeter Grehan 		*lvts |= APIC_LVT_M;
123366f6083SPeter Grehan 		lvts += 4;
124366f6083SPeter Grehan 	}
125366f6083SPeter Grehan }
126366f6083SPeter Grehan 
127366f6083SPeter Grehan #if 0
128366f6083SPeter Grehan static inline void
129366f6083SPeter Grehan vlapic_dump_lvt(uint32_t offset, uint32_t *lvt)
130366f6083SPeter Grehan {
131366f6083SPeter Grehan 	printf("Offset %x: lvt %08x (V:%02x DS:%x M:%x)\n", offset,
132366f6083SPeter Grehan 	    *lvt, *lvt & APIC_LVTT_VECTOR, *lvt & APIC_LVTT_DS,
133366f6083SPeter Grehan 	    *lvt & APIC_LVTT_M);
134366f6083SPeter Grehan }
135366f6083SPeter Grehan #endif
136366f6083SPeter Grehan 
137366f6083SPeter Grehan static uint64_t
138366f6083SPeter Grehan vlapic_get_ccr(struct vlapic *vlapic)
139366f6083SPeter Grehan {
140366f6083SPeter Grehan 	struct LAPIC    *lapic = &vlapic->apic;
141366f6083SPeter Grehan 	return lapic->ccr_timer;
142366f6083SPeter Grehan }
143366f6083SPeter Grehan 
144366f6083SPeter Grehan static void
145366f6083SPeter Grehan vlapic_update_errors(struct vlapic *vlapic)
146366f6083SPeter Grehan {
147366f6083SPeter Grehan 	struct LAPIC    *lapic = &vlapic->apic;
148366f6083SPeter Grehan 	lapic->esr = 0; // XXX
149366f6083SPeter Grehan }
150366f6083SPeter Grehan 
151366f6083SPeter Grehan static void
152366f6083SPeter Grehan vlapic_init_ipi(struct vlapic *vlapic)
153366f6083SPeter Grehan {
154366f6083SPeter Grehan 	struct LAPIC    *lapic = &vlapic->apic;
155366f6083SPeter Grehan 	lapic->version = VLAPIC_VERSION;
156366f6083SPeter Grehan 	lapic->version |= (VLAPIC_MAXLVT_ENTRIES < MAXLVTSHIFT);
157366f6083SPeter Grehan 	lapic->dfr = 0xffffffff;
158366f6083SPeter Grehan 	lapic->svr = APIC_SVR_VECTOR;
159366f6083SPeter Grehan 	vlapic_mask_lvts(&lapic->lvt_timer, VLAPIC_MAXLVT_ENTRIES+1);
160366f6083SPeter Grehan }
161366f6083SPeter Grehan 
162366f6083SPeter Grehan static int
163366f6083SPeter Grehan vlapic_op_reset(void* dev)
164366f6083SPeter Grehan {
165366f6083SPeter Grehan 	struct vlapic 	*vlapic = (struct vlapic*)dev;
166366f6083SPeter Grehan 	struct LAPIC	*lapic = &vlapic->apic;
167366f6083SPeter Grehan 
168366f6083SPeter Grehan 	memset(lapic, 0, sizeof(*lapic));
169366f6083SPeter Grehan 	lapic->apr = vlapic->vcpuid;
170366f6083SPeter Grehan 	vlapic_init_ipi(vlapic);
171366f6083SPeter Grehan 
172366f6083SPeter Grehan 	return 0;
173366f6083SPeter Grehan 
174366f6083SPeter Grehan }
175366f6083SPeter Grehan 
176366f6083SPeter Grehan static int
177366f6083SPeter Grehan vlapic_op_init(void* dev)
178366f6083SPeter Grehan {
179366f6083SPeter Grehan 	struct vlapic *vlapic = (struct vlapic*)dev;
180366f6083SPeter Grehan 	vdev_register_region(vlapic->ops, vlapic, vlapic->mmio);
181366f6083SPeter Grehan 	return vlapic_op_reset(dev);
182366f6083SPeter Grehan }
183366f6083SPeter Grehan 
184366f6083SPeter Grehan static int
185366f6083SPeter Grehan vlapic_op_halt(void* dev)
186366f6083SPeter Grehan {
187366f6083SPeter Grehan 	struct vlapic *vlapic = (struct vlapic*)dev;
188366f6083SPeter Grehan 	vdev_unregister_region(vlapic, vlapic->mmio);
189366f6083SPeter Grehan 	return 0;
190366f6083SPeter Grehan 
191366f6083SPeter Grehan }
192366f6083SPeter Grehan 
193366f6083SPeter Grehan void
194366f6083SPeter Grehan vlapic_set_intr_ready(struct vlapic *vlapic, int vector)
195366f6083SPeter Grehan {
196366f6083SPeter Grehan 	struct LAPIC	*lapic = &vlapic->apic;
197366f6083SPeter Grehan 	uint32_t	*irrptr;
198366f6083SPeter Grehan 	int		idx;
199366f6083SPeter Grehan 
200366f6083SPeter Grehan 	if (vector < 0 || vector >= 256)
201366f6083SPeter Grehan 		panic("vlapic_set_intr_ready: invalid vector %d\n", vector);
202366f6083SPeter Grehan 
203366f6083SPeter Grehan 	idx = (vector / 32) * 4;
204366f6083SPeter Grehan 	irrptr = &lapic->irr0;
205366f6083SPeter Grehan 	atomic_set_int(&irrptr[idx], 1 << (vector % 32));
206366f6083SPeter Grehan 	VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready");
207366f6083SPeter Grehan }
208366f6083SPeter Grehan 
209366f6083SPeter Grehan #define VLAPIC_BUS_FREQ	tsc_freq
210366f6083SPeter Grehan #define VLAPIC_DCR(x)	((x->dcr_timer & 0x8) >> 1)|(x->dcr_timer & 0x3)
211366f6083SPeter Grehan 
212366f6083SPeter Grehan static int
213366f6083SPeter Grehan vlapic_timer_divisor(uint32_t dcr)
214366f6083SPeter Grehan {
215366f6083SPeter Grehan 	switch (dcr & 0xB) {
216366f6083SPeter Grehan 	case APIC_TDCR_2:
217366f6083SPeter Grehan 		return (2);
218366f6083SPeter Grehan 	case APIC_TDCR_4:
219366f6083SPeter Grehan 		return (4);
220366f6083SPeter Grehan 	case APIC_TDCR_8:
221366f6083SPeter Grehan 		return (8);
222366f6083SPeter Grehan 	case APIC_TDCR_16:
223366f6083SPeter Grehan 		return (16);
224366f6083SPeter Grehan 	case APIC_TDCR_32:
225366f6083SPeter Grehan 		return (32);
226366f6083SPeter Grehan 	case APIC_TDCR_64:
227366f6083SPeter Grehan 		return (64);
228366f6083SPeter Grehan 	case APIC_TDCR_128:
229366f6083SPeter Grehan 		return (128);
230366f6083SPeter Grehan 	default:
231366f6083SPeter Grehan 		panic("vlapic_timer_divisor: invalid dcr 0x%08x", dcr);
232366f6083SPeter Grehan 	}
233366f6083SPeter Grehan }
234366f6083SPeter Grehan 
235366f6083SPeter Grehan static void
236366f6083SPeter Grehan vlapic_start_timer(struct vlapic *vlapic, uint32_t elapsed)
237366f6083SPeter Grehan {
238366f6083SPeter Grehan 	uint32_t icr_timer;
239366f6083SPeter Grehan 
240366f6083SPeter Grehan 	icr_timer = vlapic->apic.icr_timer;
241366f6083SPeter Grehan 
242366f6083SPeter Grehan 	vlapic->ccr_ticks = ticks;
243366f6083SPeter Grehan 	if (elapsed < icr_timer)
244366f6083SPeter Grehan 		vlapic->apic.ccr_timer = icr_timer - elapsed;
245366f6083SPeter Grehan 	else {
246366f6083SPeter Grehan 		/*
247366f6083SPeter Grehan 		 * This can happen when the guest is trying to run its local
248366f6083SPeter Grehan 		 * apic timer higher that the setting of 'hz' in the host.
249366f6083SPeter Grehan 		 *
250366f6083SPeter Grehan 		 * We deal with this by running the guest local apic timer
251366f6083SPeter Grehan 		 * at the rate of the host's 'hz' setting.
252366f6083SPeter Grehan 		 */
253366f6083SPeter Grehan 		vlapic->apic.ccr_timer = 0;
254366f6083SPeter Grehan 	}
255366f6083SPeter Grehan }
256366f6083SPeter Grehan 
257366f6083SPeter Grehan static __inline uint32_t *
258366f6083SPeter Grehan vlapic_get_lvt(struct vlapic *vlapic, uint32_t offset)
259366f6083SPeter Grehan {
260366f6083SPeter Grehan 	struct LAPIC	*lapic = &vlapic->apic;
261366f6083SPeter Grehan 	int 		 i;
262366f6083SPeter Grehan 
263366f6083SPeter Grehan 	if (offset < APIC_OFFSET_TIMER_LVT || offset > APIC_OFFSET_ERROR_LVT) {
264366f6083SPeter Grehan 		panic("vlapic_get_lvt: invalid LVT\n");
265366f6083SPeter Grehan 	}
266366f6083SPeter Grehan 	i = (offset - APIC_OFFSET_TIMER_LVT) >> 2;
267366f6083SPeter Grehan 	return ((&lapic->lvt_timer) + i);;
268366f6083SPeter Grehan }
269366f6083SPeter Grehan 
270366f6083SPeter Grehan #if 1
271366f6083SPeter Grehan static void
272366f6083SPeter Grehan dump_isrvec_stk(struct vlapic *vlapic)
273366f6083SPeter Grehan {
274366f6083SPeter Grehan 	int i;
275366f6083SPeter Grehan 	uint32_t *isrptr;
276366f6083SPeter Grehan 
277366f6083SPeter Grehan 	isrptr = &vlapic->apic.isr0;
278366f6083SPeter Grehan 	for (i = 0; i < 8; i++)
279366f6083SPeter Grehan 		printf("ISR%d 0x%08x\n", i, isrptr[i * 4]);
280366f6083SPeter Grehan 
281366f6083SPeter Grehan 	for (i = 0; i <= vlapic->isrvec_stk_top; i++)
282366f6083SPeter Grehan 		printf("isrvec_stk[%d] = %d\n", i, vlapic->isrvec_stk[i]);
283366f6083SPeter Grehan }
284366f6083SPeter Grehan #endif
285366f6083SPeter Grehan 
286366f6083SPeter Grehan /*
287366f6083SPeter Grehan  * Algorithm adopted from section "Interrupt, Task and Processor Priority"
288366f6083SPeter Grehan  * in Intel Architecture Manual Vol 3a.
289366f6083SPeter Grehan  */
290366f6083SPeter Grehan static void
291366f6083SPeter Grehan vlapic_update_ppr(struct vlapic *vlapic)
292366f6083SPeter Grehan {
293366f6083SPeter Grehan 	int isrvec, tpr, ppr;
294366f6083SPeter Grehan 
295366f6083SPeter Grehan 	/*
296366f6083SPeter Grehan 	 * Note that the value on the stack at index 0 is always 0.
297366f6083SPeter Grehan 	 *
298366f6083SPeter Grehan 	 * This is a placeholder for the value of ISRV when none of the
299366f6083SPeter Grehan 	 * bits is set in the ISRx registers.
300366f6083SPeter Grehan 	 */
301366f6083SPeter Grehan 	isrvec = vlapic->isrvec_stk[vlapic->isrvec_stk_top];
302366f6083SPeter Grehan 	tpr = vlapic->apic.tpr;
303366f6083SPeter Grehan 
304366f6083SPeter Grehan #if 1
305366f6083SPeter Grehan 	{
306366f6083SPeter Grehan 		int i, lastprio, curprio, vector, idx;
307366f6083SPeter Grehan 		uint32_t *isrptr;
308366f6083SPeter Grehan 
309366f6083SPeter Grehan 		if (vlapic->isrvec_stk_top == 0 && isrvec != 0)
310366f6083SPeter Grehan 			panic("isrvec_stk is corrupted: %d", isrvec);
311366f6083SPeter Grehan 
312366f6083SPeter Grehan 		/*
313366f6083SPeter Grehan 		 * Make sure that the priority of the nested interrupts is
314366f6083SPeter Grehan 		 * always increasing.
315366f6083SPeter Grehan 		 */
316366f6083SPeter Grehan 		lastprio = -1;
317366f6083SPeter Grehan 		for (i = 1; i <= vlapic->isrvec_stk_top; i++) {
318366f6083SPeter Grehan 			curprio = PRIO(vlapic->isrvec_stk[i]);
319366f6083SPeter Grehan 			if (curprio <= lastprio) {
320366f6083SPeter Grehan 				dump_isrvec_stk(vlapic);
321366f6083SPeter Grehan 				panic("isrvec_stk does not satisfy invariant");
322366f6083SPeter Grehan 			}
323366f6083SPeter Grehan 			lastprio = curprio;
324366f6083SPeter Grehan 		}
325366f6083SPeter Grehan 
326366f6083SPeter Grehan 		/*
327366f6083SPeter Grehan 		 * Make sure that each bit set in the ISRx registers has a
328366f6083SPeter Grehan 		 * corresponding entry on the isrvec stack.
329366f6083SPeter Grehan 		 */
330366f6083SPeter Grehan 		i = 1;
331366f6083SPeter Grehan 		isrptr = &vlapic->apic.isr0;
332366f6083SPeter Grehan 		for (vector = 0; vector < 256; vector++) {
333366f6083SPeter Grehan 			idx = (vector / 32) * 4;
334366f6083SPeter Grehan 			if (isrptr[idx] & (1 << (vector % 32))) {
335366f6083SPeter Grehan 				if (i > vlapic->isrvec_stk_top ||
336366f6083SPeter Grehan 				    vlapic->isrvec_stk[i] != vector) {
337366f6083SPeter Grehan 					dump_isrvec_stk(vlapic);
338366f6083SPeter Grehan 					panic("ISR and isrvec_stk out of sync");
339366f6083SPeter Grehan 				}
340366f6083SPeter Grehan 				i++;
341366f6083SPeter Grehan 			}
342366f6083SPeter Grehan 		}
343366f6083SPeter Grehan 	}
344366f6083SPeter Grehan #endif
345366f6083SPeter Grehan 
346366f6083SPeter Grehan 	if (PRIO(tpr) >= PRIO(isrvec))
347366f6083SPeter Grehan 		ppr = tpr;
348366f6083SPeter Grehan 	else
349366f6083SPeter Grehan 		ppr = isrvec & 0xf0;
350366f6083SPeter Grehan 
351366f6083SPeter Grehan 	vlapic->apic.ppr = ppr;
352366f6083SPeter Grehan 	VLAPIC_CTR1(vlapic, "vlapic_update_ppr 0x%02x", ppr);
353366f6083SPeter Grehan }
354366f6083SPeter Grehan 
355366f6083SPeter Grehan static void
356366f6083SPeter Grehan vlapic_process_eoi(struct vlapic *vlapic)
357366f6083SPeter Grehan {
358366f6083SPeter Grehan 	struct LAPIC	*lapic = &vlapic->apic;
359366f6083SPeter Grehan 	uint32_t	*isrptr;
360366f6083SPeter Grehan 	int		i, idx, bitpos;
361366f6083SPeter Grehan 
362366f6083SPeter Grehan 	isrptr = &lapic->isr0;
363366f6083SPeter Grehan 
364366f6083SPeter Grehan 	/*
365366f6083SPeter Grehan 	 * The x86 architecture reserves the the first 32 vectors for use
366366f6083SPeter Grehan 	 * by the processor.
367366f6083SPeter Grehan 	 */
368366f6083SPeter Grehan 	for (i = 7; i > 0; i--) {
369366f6083SPeter Grehan 		idx = i * 4;
370366f6083SPeter Grehan 		bitpos = fls(isrptr[idx]);
371366f6083SPeter Grehan 		if (bitpos != 0) {
372366f6083SPeter Grehan 			if (vlapic->isrvec_stk_top <= 0) {
373366f6083SPeter Grehan 				panic("invalid vlapic isrvec_stk_top %d",
374366f6083SPeter Grehan 				      vlapic->isrvec_stk_top);
375366f6083SPeter Grehan 			}
376366f6083SPeter Grehan 			isrptr[idx] &= ~(1 << (bitpos - 1));
377366f6083SPeter Grehan 			VLAPIC_CTR_ISR(vlapic, "vlapic_process_eoi");
378366f6083SPeter Grehan 			vlapic->isrvec_stk_top--;
379366f6083SPeter Grehan 			vlapic_update_ppr(vlapic);
380366f6083SPeter Grehan 			return;
381366f6083SPeter Grehan 		}
382366f6083SPeter Grehan 	}
383366f6083SPeter Grehan }
384366f6083SPeter Grehan 
385366f6083SPeter Grehan static __inline int
386366f6083SPeter Grehan vlapic_get_lvt_field(uint32_t *lvt, uint32_t mask)
387366f6083SPeter Grehan {
388366f6083SPeter Grehan 	return (*lvt & mask);
389366f6083SPeter Grehan }
390366f6083SPeter Grehan 
391366f6083SPeter Grehan static __inline int
392366f6083SPeter Grehan vlapic_periodic_timer(struct vlapic *vlapic)
393366f6083SPeter Grehan {
394366f6083SPeter Grehan 	uint32_t *lvt;
395366f6083SPeter Grehan 
396366f6083SPeter Grehan 	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);
397366f6083SPeter Grehan 
398366f6083SPeter Grehan 	return (vlapic_get_lvt_field(lvt, APIC_LVTT_TM_PERIODIC));
399366f6083SPeter Grehan }
400366f6083SPeter Grehan 
401366f6083SPeter Grehan static void
402366f6083SPeter Grehan vlapic_fire_timer(struct vlapic *vlapic)
403366f6083SPeter Grehan {
404366f6083SPeter Grehan 	int vector;
405366f6083SPeter Grehan 	uint32_t *lvt;
406366f6083SPeter Grehan 
407366f6083SPeter Grehan 	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);
408366f6083SPeter Grehan 
409366f6083SPeter Grehan 	if (!vlapic_get_lvt_field(lvt, APIC_LVTT_M)) {
410366f6083SPeter Grehan 		vector = vlapic_get_lvt_field(lvt,APIC_LVTT_VECTOR);
411366f6083SPeter Grehan 		vlapic_set_intr_ready(vlapic, vector);
412366f6083SPeter Grehan 	}
413366f6083SPeter Grehan }
414366f6083SPeter Grehan 
415366f6083SPeter Grehan static int
416366f6083SPeter Grehan lapic_process_icr(struct vlapic *vlapic, uint64_t icrval)
417366f6083SPeter Grehan {
418366f6083SPeter Grehan 	int i;
419a5615c90SPeter Grehan 	cpuset_t dmask;
420366f6083SPeter Grehan 	uint32_t dest, vec, mode;
421366f6083SPeter Grehan 
422366f6083SPeter Grehan 	dest = icrval >> 32;
423366f6083SPeter Grehan 	vec = icrval & APIC_VECTOR_MASK;
424366f6083SPeter Grehan 	mode = icrval & APIC_DELMODE_MASK;
425366f6083SPeter Grehan 
426366f6083SPeter Grehan 	if (mode == APIC_DELMODE_FIXED || mode == APIC_DELMODE_NMI) {
427366f6083SPeter Grehan 		switch (icrval & APIC_DEST_MASK) {
428366f6083SPeter Grehan 		case APIC_DEST_DESTFLD:
429a5615c90SPeter Grehan 			CPU_SETOF(dest, &dmask);
430366f6083SPeter Grehan 			break;
431366f6083SPeter Grehan 		case APIC_DEST_SELF:
432a5615c90SPeter Grehan 			CPU_SETOF(vlapic->vcpuid, &dmask);
433366f6083SPeter Grehan 			break;
434366f6083SPeter Grehan 		case APIC_DEST_ALLISELF:
435366f6083SPeter Grehan 			dmask = vm_active_cpus(vlapic->vm);
436366f6083SPeter Grehan 			break;
437366f6083SPeter Grehan 		case APIC_DEST_ALLESELF:
438a5615c90SPeter Grehan 			dmask = vm_active_cpus(vlapic->vm);
439a5615c90SPeter Grehan 			CPU_CLR(vlapic->vcpuid, &dmask);
440366f6083SPeter Grehan 			break;
441366f6083SPeter Grehan 		}
442366f6083SPeter Grehan 
443a5615c90SPeter Grehan 		while ((i = cpusetobj_ffs(&dmask)) != 0) {
444a5615c90SPeter Grehan 			i--;
445a5615c90SPeter Grehan 			CPU_CLR(i, &dmask);
446366f6083SPeter Grehan 			if (mode == APIC_DELMODE_FIXED)
447366f6083SPeter Grehan 				lapic_set_intr(vlapic->vm, i, vec);
448366f6083SPeter Grehan 			else
449366f6083SPeter Grehan 				vm_inject_nmi(vlapic->vm, i);
450366f6083SPeter Grehan 		}
451366f6083SPeter Grehan 
452366f6083SPeter Grehan 		return (0);	/* handled completely in the kernel */
453366f6083SPeter Grehan 	}
454366f6083SPeter Grehan 
455366f6083SPeter Grehan 	/*
456366f6083SPeter Grehan 	 * XXX this assumes that the startup IPI always succeeds
457366f6083SPeter Grehan 	 */
458366f6083SPeter Grehan 	if (mode == APIC_DELMODE_STARTUP)
459366f6083SPeter Grehan 		vm_activate_cpu(vlapic->vm, dest);
460366f6083SPeter Grehan 
461366f6083SPeter Grehan 	/*
462366f6083SPeter Grehan 	 * This will cause a return to userland.
463366f6083SPeter Grehan 	 */
464366f6083SPeter Grehan 	return (1);
465366f6083SPeter Grehan }
466366f6083SPeter Grehan 
467366f6083SPeter Grehan int
468366f6083SPeter Grehan vlapic_pending_intr(struct vlapic *vlapic)
469366f6083SPeter Grehan {
470366f6083SPeter Grehan 	struct LAPIC	*lapic = &vlapic->apic;
471366f6083SPeter Grehan 	int	  	 idx, i, bitpos, vector;
472366f6083SPeter Grehan 	uint32_t	*irrptr, val;
473366f6083SPeter Grehan 
474366f6083SPeter Grehan 	irrptr = &lapic->irr0;
475366f6083SPeter Grehan 
476366f6083SPeter Grehan 	/*
477366f6083SPeter Grehan 	 * The x86 architecture reserves the the first 32 vectors for use
478366f6083SPeter Grehan 	 * by the processor.
479366f6083SPeter Grehan 	 */
480366f6083SPeter Grehan 	for (i = 7; i > 0; i--) {
481366f6083SPeter Grehan 		idx = i * 4;
482366f6083SPeter Grehan 		val = atomic_load_acq_int(&irrptr[idx]);
483366f6083SPeter Grehan 		bitpos = fls(val);
484366f6083SPeter Grehan 		if (bitpos != 0) {
485366f6083SPeter Grehan 			vector = i * 32 + (bitpos - 1);
486366f6083SPeter Grehan 			if (PRIO(vector) > PRIO(lapic->ppr)) {
487366f6083SPeter Grehan 				VLAPIC_CTR1(vlapic, "pending intr %d", vector);
488366f6083SPeter Grehan 				return (vector);
489366f6083SPeter Grehan 			} else
490366f6083SPeter Grehan 				break;
491366f6083SPeter Grehan 		}
492366f6083SPeter Grehan 	}
493366f6083SPeter Grehan 	VLAPIC_CTR0(vlapic, "no pending intr");
494366f6083SPeter Grehan 	return (-1);
495366f6083SPeter Grehan }
496366f6083SPeter Grehan 
497366f6083SPeter Grehan void
498366f6083SPeter Grehan vlapic_intr_accepted(struct vlapic *vlapic, int vector)
499366f6083SPeter Grehan {
500366f6083SPeter Grehan 	struct LAPIC	*lapic = &vlapic->apic;
501366f6083SPeter Grehan 	uint32_t	*irrptr, *isrptr;
502366f6083SPeter Grehan 	int		idx, stk_top;
503366f6083SPeter Grehan 
504366f6083SPeter Grehan 	/*
505366f6083SPeter Grehan 	 * clear the ready bit for vector being accepted in irr
506366f6083SPeter Grehan 	 * and set the vector as in service in isr.
507366f6083SPeter Grehan 	 */
508366f6083SPeter Grehan 	idx = (vector / 32) * 4;
509366f6083SPeter Grehan 
510366f6083SPeter Grehan 	irrptr = &lapic->irr0;
511366f6083SPeter Grehan 	atomic_clear_int(&irrptr[idx], 1 << (vector % 32));
512366f6083SPeter Grehan 	VLAPIC_CTR_IRR(vlapic, "vlapic_intr_accepted");
513366f6083SPeter Grehan 
514366f6083SPeter Grehan 	isrptr = &lapic->isr0;
515366f6083SPeter Grehan 	isrptr[idx] |= 1 << (vector % 32);
516366f6083SPeter Grehan 	VLAPIC_CTR_ISR(vlapic, "vlapic_intr_accepted");
517366f6083SPeter Grehan 
518366f6083SPeter Grehan 	/*
519366f6083SPeter Grehan 	 * Update the PPR
520366f6083SPeter Grehan 	 */
521366f6083SPeter Grehan 	vlapic->isrvec_stk_top++;
522366f6083SPeter Grehan 
523366f6083SPeter Grehan 	stk_top = vlapic->isrvec_stk_top;
524366f6083SPeter Grehan 	if (stk_top >= ISRVEC_STK_SIZE)
525366f6083SPeter Grehan 		panic("isrvec_stk_top overflow %d", stk_top);
526366f6083SPeter Grehan 
527366f6083SPeter Grehan 	vlapic->isrvec_stk[stk_top] = vector;
528366f6083SPeter Grehan 	vlapic_update_ppr(vlapic);
529366f6083SPeter Grehan }
530366f6083SPeter Grehan 
531366f6083SPeter Grehan int
532366f6083SPeter Grehan vlapic_op_mem_read(void* dev, uint64_t gpa, opsize_t size, uint64_t *data)
533366f6083SPeter Grehan {
534366f6083SPeter Grehan 	struct vlapic 	*vlapic = (struct vlapic*)dev;
535366f6083SPeter Grehan 	struct LAPIC	*lapic = &vlapic->apic;
536366f6083SPeter Grehan 	uint64_t	 offset = gpa & ~(PAGE_SIZE);
537366f6083SPeter Grehan 	uint32_t	*reg;
538366f6083SPeter Grehan 	int		 i;
539366f6083SPeter Grehan 
540366f6083SPeter Grehan 	if (offset > sizeof(*lapic)) {
541366f6083SPeter Grehan 		*data = 0;
542366f6083SPeter Grehan 		return 0;
543366f6083SPeter Grehan 	}
544366f6083SPeter Grehan 
545366f6083SPeter Grehan 	offset &= ~3;
546366f6083SPeter Grehan 	switch(offset)
547366f6083SPeter Grehan 	{
548366f6083SPeter Grehan 		case APIC_OFFSET_ID:
549*2d3a73edSNeel Natu 			if (x2apic(vlapic))
550*2d3a73edSNeel Natu 				*data = vlapic->vcpuid;
551*2d3a73edSNeel Natu 			else
552*2d3a73edSNeel Natu 				*data = vlapic->vcpuid << 24;
553366f6083SPeter Grehan 			break;
554366f6083SPeter Grehan 		case APIC_OFFSET_VER:
555366f6083SPeter Grehan 			*data = lapic->version;
556366f6083SPeter Grehan 			break;
557366f6083SPeter Grehan 		case APIC_OFFSET_TPR:
558366f6083SPeter Grehan 			*data = lapic->tpr;
559366f6083SPeter Grehan 			break;
560366f6083SPeter Grehan 		case APIC_OFFSET_APR:
561366f6083SPeter Grehan 			*data = lapic->apr;
562366f6083SPeter Grehan 			break;
563366f6083SPeter Grehan 		case APIC_OFFSET_PPR:
564366f6083SPeter Grehan 			*data = lapic->ppr;
565366f6083SPeter Grehan 			break;
566366f6083SPeter Grehan 		case APIC_OFFSET_EOI:
567366f6083SPeter Grehan 			*data = lapic->eoi;
568366f6083SPeter Grehan 			break;
569366f6083SPeter Grehan 		case APIC_OFFSET_LDR:
570366f6083SPeter Grehan 			*data = lapic->ldr;
571366f6083SPeter Grehan 			break;
572366f6083SPeter Grehan 		case APIC_OFFSET_DFR:
573366f6083SPeter Grehan 			*data = lapic->dfr;
574366f6083SPeter Grehan 			break;
575366f6083SPeter Grehan 		case APIC_OFFSET_SVR:
576366f6083SPeter Grehan 			*data = lapic->svr;
577366f6083SPeter Grehan 			break;
578366f6083SPeter Grehan 		case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7:
579366f6083SPeter Grehan 			i = (offset - APIC_OFFSET_ISR0) >> 2;
580366f6083SPeter Grehan 			reg = &lapic->isr0;
581366f6083SPeter Grehan 			*data = *(reg + i);
582366f6083SPeter Grehan 			break;
583366f6083SPeter Grehan 		case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7:
584366f6083SPeter Grehan 			i = (offset - APIC_OFFSET_TMR0) >> 2;
585366f6083SPeter Grehan 			reg = &lapic->tmr0;
586366f6083SPeter Grehan 			*data = *(reg + i);
587366f6083SPeter Grehan 			break;
588366f6083SPeter Grehan 		case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7:
589366f6083SPeter Grehan 			i = (offset - APIC_OFFSET_IRR0) >> 2;
590366f6083SPeter Grehan 			reg = &lapic->irr0;
591366f6083SPeter Grehan 			*data = atomic_load_acq_int(reg + i);
592366f6083SPeter Grehan 			break;
593366f6083SPeter Grehan 		case APIC_OFFSET_ESR:
594366f6083SPeter Grehan 			*data = lapic->esr;
595366f6083SPeter Grehan 			break;
596366f6083SPeter Grehan 		case APIC_OFFSET_ICR_LOW:
597366f6083SPeter Grehan 			*data = lapic->icr_lo;
598366f6083SPeter Grehan 			break;
599366f6083SPeter Grehan 		case APIC_OFFSET_ICR_HI:
600366f6083SPeter Grehan 			*data = lapic->icr_hi;
601366f6083SPeter Grehan 			break;
602366f6083SPeter Grehan 		case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT:
603366f6083SPeter Grehan 			reg = vlapic_get_lvt(vlapic, offset);
604366f6083SPeter Grehan 			*data = *(reg);
605366f6083SPeter Grehan 			break;
606366f6083SPeter Grehan 		case APIC_OFFSET_ICR:
607366f6083SPeter Grehan 			*data = lapic->icr_timer;
608366f6083SPeter Grehan 			break;
609366f6083SPeter Grehan 		case APIC_OFFSET_CCR:
610366f6083SPeter Grehan 			*data = vlapic_get_ccr(vlapic);
611366f6083SPeter Grehan 			break;
612366f6083SPeter Grehan 		case APIC_OFFSET_DCR:
613366f6083SPeter Grehan 			*data = lapic->dcr_timer;
614366f6083SPeter Grehan 			break;
615366f6083SPeter Grehan 		case APIC_OFFSET_RRR:
616366f6083SPeter Grehan 		default:
617366f6083SPeter Grehan 			*data = 0;
618366f6083SPeter Grehan 			break;
619366f6083SPeter Grehan 	}
620366f6083SPeter Grehan 	return 0;
621366f6083SPeter Grehan }
622366f6083SPeter Grehan 
623366f6083SPeter Grehan int
624366f6083SPeter Grehan vlapic_op_mem_write(void* dev, uint64_t gpa, opsize_t size, uint64_t data)
625366f6083SPeter Grehan {
626366f6083SPeter Grehan 	struct vlapic 	*vlapic = (struct vlapic*)dev;
627366f6083SPeter Grehan 	struct LAPIC	*lapic = &vlapic->apic;
628366f6083SPeter Grehan 	uint64_t	 offset = gpa & ~(PAGE_SIZE);
629366f6083SPeter Grehan 	uint32_t	*reg;
630366f6083SPeter Grehan 	int		retval;
631366f6083SPeter Grehan 
632366f6083SPeter Grehan 	if (offset > sizeof(*lapic)) {
633366f6083SPeter Grehan 		return 0;
634366f6083SPeter Grehan 	}
635366f6083SPeter Grehan 
636366f6083SPeter Grehan 	retval = 0;
637366f6083SPeter Grehan 	offset &= ~3;
638366f6083SPeter Grehan 	switch(offset)
639366f6083SPeter Grehan 	{
640366f6083SPeter Grehan 		case APIC_OFFSET_ID:
641366f6083SPeter Grehan 			break;
642366f6083SPeter Grehan 		case APIC_OFFSET_TPR:
643366f6083SPeter Grehan 			lapic->tpr = data & 0xff;
644366f6083SPeter Grehan 			vlapic_update_ppr(vlapic);
645366f6083SPeter Grehan 			break;
646366f6083SPeter Grehan 		case APIC_OFFSET_EOI:
647366f6083SPeter Grehan 			vlapic_process_eoi(vlapic);
648366f6083SPeter Grehan 			break;
649366f6083SPeter Grehan 		case APIC_OFFSET_LDR:
650366f6083SPeter Grehan 			break;
651366f6083SPeter Grehan 		case APIC_OFFSET_DFR:
652366f6083SPeter Grehan 			break;
653366f6083SPeter Grehan 		case APIC_OFFSET_SVR:
654366f6083SPeter Grehan 			lapic->svr = data;
655366f6083SPeter Grehan 			break;
656366f6083SPeter Grehan 		case APIC_OFFSET_ICR_LOW:
657366f6083SPeter Grehan 			retval = lapic_process_icr(vlapic, data);
658366f6083SPeter Grehan 			break;
659366f6083SPeter Grehan 		case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT:
660366f6083SPeter Grehan 			reg = vlapic_get_lvt(vlapic, offset);
661366f6083SPeter Grehan 			if (!(lapic->svr & APIC_SVR_ENABLE)) {
662366f6083SPeter Grehan 				data |= APIC_LVT_M;
663366f6083SPeter Grehan 			}
664366f6083SPeter Grehan 			*reg = data;
665366f6083SPeter Grehan 			// vlapic_dump_lvt(offset, reg);
666366f6083SPeter Grehan 			break;
667366f6083SPeter Grehan 		case APIC_OFFSET_ICR:
668366f6083SPeter Grehan 			lapic->icr_timer = data;
669366f6083SPeter Grehan 			vlapic_start_timer(vlapic, 0);
670366f6083SPeter Grehan 			break;
671366f6083SPeter Grehan 
672366f6083SPeter Grehan 		case APIC_OFFSET_DCR:
673366f6083SPeter Grehan 			lapic->dcr_timer = data;
674366f6083SPeter Grehan 			vlapic->divisor = vlapic_timer_divisor(data);
675366f6083SPeter Grehan 			break;
676366f6083SPeter Grehan 
677366f6083SPeter Grehan 		case APIC_OFFSET_ESR:
678366f6083SPeter Grehan 			vlapic_update_errors(vlapic);
679366f6083SPeter Grehan 			break;
680366f6083SPeter Grehan 		case APIC_OFFSET_VER:
681366f6083SPeter Grehan 		case APIC_OFFSET_APR:
682366f6083SPeter Grehan 		case APIC_OFFSET_PPR:
683366f6083SPeter Grehan 		case APIC_OFFSET_RRR:
684366f6083SPeter Grehan 		case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7:
685366f6083SPeter Grehan 		case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7:
686366f6083SPeter Grehan 		case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7:
687366f6083SPeter Grehan 		case APIC_OFFSET_CCR:
688366f6083SPeter Grehan 		default:
689366f6083SPeter Grehan 			// Read only.
690366f6083SPeter Grehan 			break;
691366f6083SPeter Grehan 	}
692366f6083SPeter Grehan 
693366f6083SPeter Grehan 	return (retval);
694366f6083SPeter Grehan }
695366f6083SPeter Grehan 
696366f6083SPeter Grehan void
697366f6083SPeter Grehan vlapic_timer_tick(struct vlapic *vlapic)
698366f6083SPeter Grehan {
699366f6083SPeter Grehan 	int curticks, delta, periodic;
700366f6083SPeter Grehan 	uint32_t ccr;
701366f6083SPeter Grehan 	uint32_t decrement, remainder;
702366f6083SPeter Grehan 
703366f6083SPeter Grehan 	curticks = ticks;
704366f6083SPeter Grehan 
705366f6083SPeter Grehan 	/* Common case */
706366f6083SPeter Grehan 	delta = curticks - vlapic->ccr_ticks;
707366f6083SPeter Grehan 	if (delta == 0)
708366f6083SPeter Grehan 		return;
709366f6083SPeter Grehan 
710366f6083SPeter Grehan 	/* Local APIC timer is disabled */
711366f6083SPeter Grehan 	if (vlapic->apic.icr_timer == 0)
712366f6083SPeter Grehan 		return;
713366f6083SPeter Grehan 
714366f6083SPeter Grehan 	/* One-shot mode and timer has already counted down to zero */
715366f6083SPeter Grehan 	periodic = vlapic_periodic_timer(vlapic);
716366f6083SPeter Grehan 	if (!periodic && vlapic->apic.ccr_timer == 0)
717366f6083SPeter Grehan 		return;
718366f6083SPeter Grehan 	/*
719366f6083SPeter Grehan 	 * The 'curticks' and 'ccr_ticks' are out of sync by more than
720366f6083SPeter Grehan 	 * 2^31 ticks. We deal with this by restarting the timer.
721366f6083SPeter Grehan 	 */
722366f6083SPeter Grehan 	if (delta < 0) {
723366f6083SPeter Grehan 		vlapic_start_timer(vlapic, 0);
724366f6083SPeter Grehan 		return;
725366f6083SPeter Grehan 	}
726366f6083SPeter Grehan 
727366f6083SPeter Grehan 	ccr = vlapic->apic.ccr_timer;
728366f6083SPeter Grehan 	decrement = (VLAPIC_BUS_FREQ / vlapic->divisor) / hz;
729366f6083SPeter Grehan 	while (delta-- > 0) {
730366f6083SPeter Grehan 		if (ccr <= decrement) {
731366f6083SPeter Grehan 			remainder = decrement - ccr;
732366f6083SPeter Grehan 			vlapic_fire_timer(vlapic);
733366f6083SPeter Grehan 			if (periodic) {
734366f6083SPeter Grehan 				vlapic_start_timer(vlapic, remainder);
735366f6083SPeter Grehan 				ccr = vlapic->apic.ccr_timer;
736366f6083SPeter Grehan 			} else {
737366f6083SPeter Grehan 				/*
738366f6083SPeter Grehan 				 * One-shot timer has counted down to zero.
739366f6083SPeter Grehan 				 */
740366f6083SPeter Grehan 				ccr = 0;
741366f6083SPeter Grehan 				break;
742366f6083SPeter Grehan 			}
743366f6083SPeter Grehan 		} else
744366f6083SPeter Grehan 			ccr -= decrement;
745366f6083SPeter Grehan 	}
746366f6083SPeter Grehan 
747366f6083SPeter Grehan 	vlapic->ccr_ticks = curticks;
748366f6083SPeter Grehan 	vlapic->apic.ccr_timer = ccr;
749366f6083SPeter Grehan }
750366f6083SPeter Grehan 
751366f6083SPeter Grehan struct vdev_ops vlapic_dev_ops = {
752366f6083SPeter Grehan 	.name = "vlapic",
753366f6083SPeter Grehan 	.init = vlapic_op_init,
754366f6083SPeter Grehan 	.reset = vlapic_op_reset,
755366f6083SPeter Grehan 	.halt = vlapic_op_halt,
756366f6083SPeter Grehan 	.memread = vlapic_op_mem_read,
757366f6083SPeter Grehan 	.memwrite = vlapic_op_mem_write,
758366f6083SPeter Grehan };
759366f6083SPeter Grehan static struct io_region vlapic_mmio[VM_MAXCPU];
760366f6083SPeter Grehan 
761366f6083SPeter Grehan struct vlapic *
762366f6083SPeter Grehan vlapic_init(struct vm *vm, int vcpuid)
763366f6083SPeter Grehan {
764366f6083SPeter Grehan 	struct vlapic 		*vlapic;
765366f6083SPeter Grehan 
766366f6083SPeter Grehan 	vlapic = malloc(sizeof(struct vlapic), M_VLAPIC, M_WAITOK | M_ZERO);
767366f6083SPeter Grehan 	vlapic->vm = vm;
768366f6083SPeter Grehan 	vlapic->vcpuid = vcpuid;
769*2d3a73edSNeel Natu 
770*2d3a73edSNeel Natu 	vlapic->msr_apicbase = DEFAULT_APIC_BASE |
771*2d3a73edSNeel Natu 			       APICBASE_ENABLED |
772*2d3a73edSNeel Natu 			       APICBASE_X2APIC;
773*2d3a73edSNeel Natu 
774*2d3a73edSNeel Natu 	if (vcpuid == 0)
775*2d3a73edSNeel Natu 		vlapic->msr_apicbase |= APICBASE_BSP;
776*2d3a73edSNeel Natu 
777366f6083SPeter Grehan 	vlapic->ops = &vlapic_dev_ops;
778366f6083SPeter Grehan 
779366f6083SPeter Grehan 	vlapic->mmio = vlapic_mmio + vcpuid;
780366f6083SPeter Grehan 	vlapic->mmio->base = DEFAULT_APIC_BASE;
781366f6083SPeter Grehan 	vlapic->mmio->len = PAGE_SIZE;
782366f6083SPeter Grehan 	vlapic->mmio->attr = MMIO_READ|MMIO_WRITE;
783366f6083SPeter Grehan 	vlapic->mmio->vcpu = vcpuid;
784366f6083SPeter Grehan 
785366f6083SPeter Grehan 	vdev_register(&vlapic_dev_ops, vlapic);
786366f6083SPeter Grehan 
787366f6083SPeter Grehan 	vlapic_op_init(vlapic);
788366f6083SPeter Grehan 
789366f6083SPeter Grehan 	return (vlapic);
790366f6083SPeter Grehan }
791366f6083SPeter Grehan 
792366f6083SPeter Grehan void
793366f6083SPeter Grehan vlapic_cleanup(struct vlapic *vlapic)
794366f6083SPeter Grehan {
795cd942e0fSPeter Grehan 	vlapic_op_halt(vlapic);
796366f6083SPeter Grehan 	vdev_unregister(vlapic);
797366f6083SPeter Grehan 	free(vlapic, M_VLAPIC);
798366f6083SPeter Grehan }
799*2d3a73edSNeel Natu 
800*2d3a73edSNeel Natu uint64_t
801*2d3a73edSNeel Natu vlapic_get_apicbase(struct vlapic *vlapic)
802*2d3a73edSNeel Natu {
803*2d3a73edSNeel Natu 
804*2d3a73edSNeel Natu 	return (vlapic->msr_apicbase);
805*2d3a73edSNeel Natu }
806*2d3a73edSNeel Natu 
807*2d3a73edSNeel Natu void
808*2d3a73edSNeel Natu vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val)
809*2d3a73edSNeel Natu {
810*2d3a73edSNeel Natu 
811*2d3a73edSNeel Natu 	vlapic->msr_apicbase = val;
812*2d3a73edSNeel Natu }
813