xref: /freebsd/sys/amd64/vmm/io/vioapic.c (revision 565bbb86983d390d4d83f49eaad81c46ea65f188)
1*565bbb86SNeel Natu /*-
2*565bbb86SNeel Natu  * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3*565bbb86SNeel Natu  * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
4*565bbb86SNeel Natu  * All rights reserved.
5*565bbb86SNeel Natu  *
6*565bbb86SNeel Natu  * Redistribution and use in source and binary forms, with or without
7*565bbb86SNeel Natu  * modification, are permitted provided that the following conditions
8*565bbb86SNeel Natu  * are met:
9*565bbb86SNeel Natu  * 1. Redistributions of source code must retain the above copyright
10*565bbb86SNeel Natu  *    notice, this list of conditions and the following disclaimer.
11*565bbb86SNeel Natu  * 2. Redistributions in binary form must reproduce the above copyright
12*565bbb86SNeel Natu  *    notice, this list of conditions and the following disclaimer in the
13*565bbb86SNeel Natu  *    documentation and/or other materials provided with the distribution.
14*565bbb86SNeel Natu  *
15*565bbb86SNeel Natu  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16*565bbb86SNeel Natu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*565bbb86SNeel Natu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*565bbb86SNeel Natu  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19*565bbb86SNeel Natu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*565bbb86SNeel Natu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*565bbb86SNeel Natu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*565bbb86SNeel Natu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*565bbb86SNeel Natu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*565bbb86SNeel Natu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*565bbb86SNeel Natu  * SUCH DAMAGE.
26*565bbb86SNeel Natu  *
27*565bbb86SNeel Natu  * $FreeBSD$
28*565bbb86SNeel Natu  */
29*565bbb86SNeel Natu 
30*565bbb86SNeel Natu #include <sys/cdefs.h>
31*565bbb86SNeel Natu __FBSDID("$FreeBSD$");
32*565bbb86SNeel Natu 
33*565bbb86SNeel Natu #include <sys/param.h>
34*565bbb86SNeel Natu #include <sys/queue.h>
35*565bbb86SNeel Natu #include <sys/cpuset.h>
36*565bbb86SNeel Natu #include <sys/lock.h>
37*565bbb86SNeel Natu #include <sys/mutex.h>
38*565bbb86SNeel Natu #include <sys/systm.h>
39*565bbb86SNeel Natu #include <sys/kernel.h>
40*565bbb86SNeel Natu #include <sys/malloc.h>
41*565bbb86SNeel Natu 
42*565bbb86SNeel Natu #include <x86/apicreg.h>
43*565bbb86SNeel Natu #include <machine/vmm.h>
44*565bbb86SNeel Natu 
45*565bbb86SNeel Natu #include "vmm_ktr.h"
46*565bbb86SNeel Natu #include "vmm_lapic.h"
47*565bbb86SNeel Natu #include "vioapic.h"
48*565bbb86SNeel Natu 
49*565bbb86SNeel Natu #define	IOREGSEL	0x00
50*565bbb86SNeel Natu #define	IOWIN		0x10
51*565bbb86SNeel Natu 
52*565bbb86SNeel Natu #define	REDIR_ENTRIES	16
53*565bbb86SNeel Natu #define	INTR_ASSERTED(vioapic, pin) ((vioapic)->rtbl[(pin)].pinstate == true)
54*565bbb86SNeel Natu 
55*565bbb86SNeel Natu struct vioapic {
56*565bbb86SNeel Natu 	struct vm	*vm;
57*565bbb86SNeel Natu 	struct mtx	mtx;
58*565bbb86SNeel Natu 	uint32_t	id;
59*565bbb86SNeel Natu 	uint32_t	ioregsel;
60*565bbb86SNeel Natu 	struct {
61*565bbb86SNeel Natu 		uint64_t reg;
62*565bbb86SNeel Natu 		bool     pinstate;
63*565bbb86SNeel Natu 		bool     pending;
64*565bbb86SNeel Natu 	} rtbl[REDIR_ENTRIES];
65*565bbb86SNeel Natu };
66*565bbb86SNeel Natu 
67*565bbb86SNeel Natu #define	VIOAPIC_LOCK(vioapic)		mtx_lock(&((vioapic)->mtx))
68*565bbb86SNeel Natu #define	VIOAPIC_UNLOCK(vioapic)		mtx_unlock(&((vioapic)->mtx))
69*565bbb86SNeel Natu #define	VIOAPIC_LOCKED(vioapic)		mtx_owned(&((vioapic)->mtx))
70*565bbb86SNeel Natu 
71*565bbb86SNeel Natu static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic");
72*565bbb86SNeel Natu 
73*565bbb86SNeel Natu #define	VIOAPIC_CTR1(vioapic, fmt, a1)					\
74*565bbb86SNeel Natu 	VM_CTR1((vioapic)->vm, fmt, a1)
75*565bbb86SNeel Natu 
76*565bbb86SNeel Natu #define	VIOAPIC_CTR2(vioapic, fmt, a1, a2)				\
77*565bbb86SNeel Natu 	VM_CTR2((vioapic)->vm, fmt, a1, a2)
78*565bbb86SNeel Natu 
79*565bbb86SNeel Natu #define	VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3)				\
80*565bbb86SNeel Natu 	VM_CTR3((vioapic)->vm, fmt, a1, a2, a3)
81*565bbb86SNeel Natu 
82*565bbb86SNeel Natu #ifdef KTR
83*565bbb86SNeel Natu static const char *
84*565bbb86SNeel Natu pinstate_str(bool asserted)
85*565bbb86SNeel Natu {
86*565bbb86SNeel Natu 
87*565bbb86SNeel Natu 	if (asserted)
88*565bbb86SNeel Natu 		return ("asserted");
89*565bbb86SNeel Natu 	else
90*565bbb86SNeel Natu 		return ("deasserted");
91*565bbb86SNeel Natu }
92*565bbb86SNeel Natu #endif
93*565bbb86SNeel Natu 
94*565bbb86SNeel Natu static void
95*565bbb86SNeel Natu vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate)
96*565bbb86SNeel Natu {
97*565bbb86SNeel Natu 	int vector, apicid, vcpuid;
98*565bbb86SNeel Natu 	uint32_t low, high;
99*565bbb86SNeel Natu 	cpuset_t dmask;
100*565bbb86SNeel Natu 
101*565bbb86SNeel Natu 	KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
102*565bbb86SNeel Natu 	    ("vioapic_set_pinstate: invalid pin number %d", pin));
103*565bbb86SNeel Natu 
104*565bbb86SNeel Natu 	KASSERT(VIOAPIC_LOCKED(vioapic),
105*565bbb86SNeel Natu 	    ("vioapic_set_pinstate: vioapic is not locked"));
106*565bbb86SNeel Natu 
107*565bbb86SNeel Natu 	VIOAPIC_CTR2(vioapic, "ioapic pin%d %s", pin, pinstate_str(newstate));
108*565bbb86SNeel Natu 
109*565bbb86SNeel Natu 	/* Nothing to do if interrupt pin has not changed state */
110*565bbb86SNeel Natu 	if (vioapic->rtbl[pin].pinstate == newstate)
111*565bbb86SNeel Natu 		return;
112*565bbb86SNeel Natu 
113*565bbb86SNeel Natu 	vioapic->rtbl[pin].pinstate = newstate;	/* record it */
114*565bbb86SNeel Natu 
115*565bbb86SNeel Natu 	/* Nothing to do if interrupt pin is deasserted */
116*565bbb86SNeel Natu 	if (!INTR_ASSERTED(vioapic, pin))
117*565bbb86SNeel Natu 		return;
118*565bbb86SNeel Natu 
119*565bbb86SNeel Natu 	/*
120*565bbb86SNeel Natu 	 * XXX
121*565bbb86SNeel Natu 	 * We only deal with:
122*565bbb86SNeel Natu 	 * - edge triggered interrupts
123*565bbb86SNeel Natu 	 * - fixed delivery mode
124*565bbb86SNeel Natu 	 *  Level-triggered sources will work so long as there is no sharing.
125*565bbb86SNeel Natu 	 */
126*565bbb86SNeel Natu 	low = vioapic->rtbl[pin].reg;
127*565bbb86SNeel Natu 	high = vioapic->rtbl[pin].reg >> 32;
128*565bbb86SNeel Natu 	if ((low & IOART_INTMASK) == IOART_INTMCLR &&
129*565bbb86SNeel Natu 	    (low & IOART_DESTMOD) == IOART_DESTPHY &&
130*565bbb86SNeel Natu 	    (low & IOART_DELMOD) == IOART_DELFIXED) {
131*565bbb86SNeel Natu 		vector = low & IOART_INTVEC;
132*565bbb86SNeel Natu 		apicid = high >> APIC_ID_SHIFT;
133*565bbb86SNeel Natu 		if (apicid != 0xff) {
134*565bbb86SNeel Natu 			/* unicast */
135*565bbb86SNeel Natu 			vcpuid = vm_apicid2vcpuid(vioapic->vm, apicid);
136*565bbb86SNeel Natu 			VIOAPIC_CTR3(vioapic, "ioapic pin%d triggering "
137*565bbb86SNeel Natu 			    "intr vector %d on vcpuid %d", pin, vector, vcpuid);
138*565bbb86SNeel Natu 			lapic_set_intr(vioapic->vm, vcpuid, vector);
139*565bbb86SNeel Natu 		} else {
140*565bbb86SNeel Natu 			/* broadcast */
141*565bbb86SNeel Natu 			VIOAPIC_CTR2(vioapic, "ioapic pin%d triggering intr "
142*565bbb86SNeel Natu 			    "vector %d on all vcpus", pin, vector);
143*565bbb86SNeel Natu 			dmask = vm_active_cpus(vioapic->vm);
144*565bbb86SNeel Natu 			while ((vcpuid = CPU_FFS(&dmask)) != 0) {
145*565bbb86SNeel Natu 				vcpuid--;
146*565bbb86SNeel Natu 				CPU_CLR(vcpuid, &dmask);
147*565bbb86SNeel Natu 				lapic_set_intr(vioapic->vm, vcpuid, vector);
148*565bbb86SNeel Natu 			}
149*565bbb86SNeel Natu 		}
150*565bbb86SNeel Natu 	} else if ((low & IOART_INTMASK) != IOART_INTMCLR &&
151*565bbb86SNeel Natu 		   (low & IOART_TRGRLVL) != 0) {
152*565bbb86SNeel Natu 		/*
153*565bbb86SNeel Natu 		 * For level-triggered interrupts that have been
154*565bbb86SNeel Natu 		 * masked, set the pending bit so that an interrupt
155*565bbb86SNeel Natu 		 * will be generated on unmask and if the level is
156*565bbb86SNeel Natu 		 * still asserted
157*565bbb86SNeel Natu 		 */
158*565bbb86SNeel Natu 		VIOAPIC_CTR1(vioapic, "ioapic pin%d interrupt pending", pin);
159*565bbb86SNeel Natu 		vioapic->rtbl[pin].pending = true;
160*565bbb86SNeel Natu 	}
161*565bbb86SNeel Natu }
162*565bbb86SNeel Natu 
163*565bbb86SNeel Natu static int
164*565bbb86SNeel Natu vioapic_set_irqstate(struct vm *vm, int irq, bool state)
165*565bbb86SNeel Natu {
166*565bbb86SNeel Natu 	struct vioapic *vioapic;
167*565bbb86SNeel Natu 
168*565bbb86SNeel Natu 	if (irq < 0 || irq >= REDIR_ENTRIES)
169*565bbb86SNeel Natu 		return (EINVAL);
170*565bbb86SNeel Natu 
171*565bbb86SNeel Natu 	vioapic = vm_ioapic(vm);
172*565bbb86SNeel Natu 
173*565bbb86SNeel Natu 	VIOAPIC_LOCK(vioapic);
174*565bbb86SNeel Natu 	vioapic_set_pinstate(vioapic, irq, state);
175*565bbb86SNeel Natu 	VIOAPIC_UNLOCK(vioapic);
176*565bbb86SNeel Natu 
177*565bbb86SNeel Natu 	return (0);
178*565bbb86SNeel Natu }
179*565bbb86SNeel Natu 
180*565bbb86SNeel Natu int
181*565bbb86SNeel Natu vioapic_assert_irq(struct vm *vm, int irq)
182*565bbb86SNeel Natu {
183*565bbb86SNeel Natu 
184*565bbb86SNeel Natu 	return (vioapic_set_irqstate(vm, irq, true));
185*565bbb86SNeel Natu }
186*565bbb86SNeel Natu 
187*565bbb86SNeel Natu int
188*565bbb86SNeel Natu vioapic_deassert_irq(struct vm *vm, int irq)
189*565bbb86SNeel Natu {
190*565bbb86SNeel Natu 
191*565bbb86SNeel Natu 	return (vioapic_set_irqstate(vm, irq, false));
192*565bbb86SNeel Natu }
193*565bbb86SNeel Natu 
194*565bbb86SNeel Natu static uint32_t
195*565bbb86SNeel Natu vioapic_read(struct vioapic *vioapic, uint32_t addr)
196*565bbb86SNeel Natu {
197*565bbb86SNeel Natu 	int regnum, pin, rshift;
198*565bbb86SNeel Natu 
199*565bbb86SNeel Natu 	regnum = addr & 0xff;
200*565bbb86SNeel Natu 	switch (regnum) {
201*565bbb86SNeel Natu 	case IOAPIC_ID:
202*565bbb86SNeel Natu 		return (vioapic->id);
203*565bbb86SNeel Natu 		break;
204*565bbb86SNeel Natu 	case IOAPIC_VER:
205*565bbb86SNeel Natu 		return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11);
206*565bbb86SNeel Natu 		break;
207*565bbb86SNeel Natu 	case IOAPIC_ARB:
208*565bbb86SNeel Natu 		return (vioapic->id);
209*565bbb86SNeel Natu 		break;
210*565bbb86SNeel Natu 	default:
211*565bbb86SNeel Natu 		break;
212*565bbb86SNeel Natu 	}
213*565bbb86SNeel Natu 
214*565bbb86SNeel Natu 	/* redirection table entries */
215*565bbb86SNeel Natu 	if (regnum >= IOAPIC_REDTBL &&
216*565bbb86SNeel Natu 	    regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
217*565bbb86SNeel Natu 		pin = (regnum - IOAPIC_REDTBL) / 2;
218*565bbb86SNeel Natu 		if ((regnum - IOAPIC_REDTBL) % 2)
219*565bbb86SNeel Natu 			rshift = 32;
220*565bbb86SNeel Natu 		else
221*565bbb86SNeel Natu 			rshift = 0;
222*565bbb86SNeel Natu 
223*565bbb86SNeel Natu 		return (vioapic->rtbl[pin].reg >> rshift);
224*565bbb86SNeel Natu 	}
225*565bbb86SNeel Natu 
226*565bbb86SNeel Natu 	return (0);
227*565bbb86SNeel Natu }
228*565bbb86SNeel Natu 
229*565bbb86SNeel Natu static void
230*565bbb86SNeel Natu vioapic_write(struct vioapic *vioapic, uint32_t addr, uint32_t data)
231*565bbb86SNeel Natu {
232*565bbb86SNeel Natu 	int regnum, pin, lshift;
233*565bbb86SNeel Natu 
234*565bbb86SNeel Natu 	regnum = addr & 0xff;
235*565bbb86SNeel Natu 	switch (regnum) {
236*565bbb86SNeel Natu 	case IOAPIC_ID:
237*565bbb86SNeel Natu 		vioapic->id = data & APIC_ID_MASK;
238*565bbb86SNeel Natu 		break;
239*565bbb86SNeel Natu 	case IOAPIC_VER:
240*565bbb86SNeel Natu 	case IOAPIC_ARB:
241*565bbb86SNeel Natu 		/* readonly */
242*565bbb86SNeel Natu 		break;
243*565bbb86SNeel Natu 	default:
244*565bbb86SNeel Natu 		break;
245*565bbb86SNeel Natu 	}
246*565bbb86SNeel Natu 
247*565bbb86SNeel Natu 	/* redirection table entries */
248*565bbb86SNeel Natu 	if (regnum >= IOAPIC_REDTBL &&
249*565bbb86SNeel Natu 	    regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
250*565bbb86SNeel Natu 		pin = (regnum - IOAPIC_REDTBL) / 2;
251*565bbb86SNeel Natu 		if ((regnum - IOAPIC_REDTBL) % 2)
252*565bbb86SNeel Natu 			lshift = 32;
253*565bbb86SNeel Natu 		else
254*565bbb86SNeel Natu 			lshift = 0;
255*565bbb86SNeel Natu 
256*565bbb86SNeel Natu 		vioapic->rtbl[pin].reg &= ~((uint64_t)0xffffffff << lshift);
257*565bbb86SNeel Natu 		vioapic->rtbl[pin].reg |= ((uint64_t)data << lshift);
258*565bbb86SNeel Natu 
259*565bbb86SNeel Natu 		VIOAPIC_CTR2(vioapic, "ioapic pin%d redir table entry %#lx",
260*565bbb86SNeel Natu 		    pin, vioapic->rtbl[pin].reg);
261*565bbb86SNeel Natu 
262*565bbb86SNeel Natu 		if (vioapic->rtbl[pin].pending &&
263*565bbb86SNeel Natu 		    ((vioapic->rtbl[pin].reg & IOART_INTMASK) ==
264*565bbb86SNeel Natu 		    IOART_INTMCLR)) {
265*565bbb86SNeel Natu 			vioapic->rtbl[pin].pending = false;
266*565bbb86SNeel Natu 			/*
267*565bbb86SNeel Natu 			 * Inject the deferred level-triggered int if it is
268*565bbb86SNeel Natu 			 * still asserted. Simulate by toggling the pin
269*565bbb86SNeel Natu 			 * off and then on.
270*565bbb86SNeel Natu 			 */
271*565bbb86SNeel Natu 			if (vioapic->rtbl[pin].pinstate == true) {
272*565bbb86SNeel Natu 				VIOAPIC_CTR1(vioapic, "ioapic pin%d pending "
273*565bbb86SNeel Natu 				    "interrupt delivered", pin);
274*565bbb86SNeel Natu 				vioapic_set_pinstate(vioapic, pin, false);
275*565bbb86SNeel Natu 				vioapic_set_pinstate(vioapic, pin, true);
276*565bbb86SNeel Natu 			} else {
277*565bbb86SNeel Natu 				VIOAPIC_CTR1(vioapic, "ioapic pin%d pending "
278*565bbb86SNeel Natu 				    "interrupt dismissed", pin);
279*565bbb86SNeel Natu 			}
280*565bbb86SNeel Natu 		}
281*565bbb86SNeel Natu 	}
282*565bbb86SNeel Natu }
283*565bbb86SNeel Natu 
284*565bbb86SNeel Natu static int
285*565bbb86SNeel Natu vioapic_mmio_rw(struct vioapic *vioapic, uint64_t gpa, uint64_t *data,
286*565bbb86SNeel Natu     int size, bool doread)
287*565bbb86SNeel Natu {
288*565bbb86SNeel Natu 	uint64_t offset;
289*565bbb86SNeel Natu 
290*565bbb86SNeel Natu 	offset = gpa - VIOAPIC_BASE;
291*565bbb86SNeel Natu 
292*565bbb86SNeel Natu 	/*
293*565bbb86SNeel Natu 	 * The IOAPIC specification allows 32-bit wide accesses to the
294*565bbb86SNeel Natu 	 * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
295*565bbb86SNeel Natu 	 */
296*565bbb86SNeel Natu 	if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
297*565bbb86SNeel Natu 		if (doread)
298*565bbb86SNeel Natu 			*data = 0;
299*565bbb86SNeel Natu 		return (0);
300*565bbb86SNeel Natu 	}
301*565bbb86SNeel Natu 
302*565bbb86SNeel Natu 	VIOAPIC_LOCK(vioapic);
303*565bbb86SNeel Natu 	if (offset == IOREGSEL) {
304*565bbb86SNeel Natu 		if (doread)
305*565bbb86SNeel Natu 			*data = vioapic->ioregsel;
306*565bbb86SNeel Natu 		else
307*565bbb86SNeel Natu 			vioapic->ioregsel = *data;
308*565bbb86SNeel Natu 	} else {
309*565bbb86SNeel Natu 		if (doread)
310*565bbb86SNeel Natu 			*data = vioapic_read(vioapic, vioapic->ioregsel);
311*565bbb86SNeel Natu 		else
312*565bbb86SNeel Natu 			vioapic_write(vioapic, vioapic->ioregsel, *data);
313*565bbb86SNeel Natu 	}
314*565bbb86SNeel Natu 	VIOAPIC_UNLOCK(vioapic);
315*565bbb86SNeel Natu 
316*565bbb86SNeel Natu 	return (0);
317*565bbb86SNeel Natu }
318*565bbb86SNeel Natu 
319*565bbb86SNeel Natu int
320*565bbb86SNeel Natu vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval,
321*565bbb86SNeel Natu     int size, void *arg)
322*565bbb86SNeel Natu {
323*565bbb86SNeel Natu 	int error;
324*565bbb86SNeel Natu 	struct vioapic *vioapic;
325*565bbb86SNeel Natu 
326*565bbb86SNeel Natu 	vioapic = vm_ioapic(vm);
327*565bbb86SNeel Natu 	error = vioapic_mmio_rw(vioapic, gpa, rval, size, true);
328*565bbb86SNeel Natu 	return (error);
329*565bbb86SNeel Natu }
330*565bbb86SNeel Natu 
331*565bbb86SNeel Natu int
332*565bbb86SNeel Natu vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval,
333*565bbb86SNeel Natu     int size, void *arg)
334*565bbb86SNeel Natu {
335*565bbb86SNeel Natu 	int error;
336*565bbb86SNeel Natu 	struct vioapic *vioapic;
337*565bbb86SNeel Natu 
338*565bbb86SNeel Natu 	vioapic = vm_ioapic(vm);
339*565bbb86SNeel Natu 	error = vioapic_mmio_rw(vioapic, gpa, &wval, size, false);
340*565bbb86SNeel Natu 	return (error);
341*565bbb86SNeel Natu }
342*565bbb86SNeel Natu 
343*565bbb86SNeel Natu struct vioapic *
344*565bbb86SNeel Natu vioapic_init(struct vm *vm)
345*565bbb86SNeel Natu {
346*565bbb86SNeel Natu 	int i;
347*565bbb86SNeel Natu 	struct vioapic *vioapic;
348*565bbb86SNeel Natu 
349*565bbb86SNeel Natu 	vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO);
350*565bbb86SNeel Natu 
351*565bbb86SNeel Natu 	vioapic->vm = vm;
352*565bbb86SNeel Natu 	mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_DEF);
353*565bbb86SNeel Natu 
354*565bbb86SNeel Natu 	/* Initialize all redirection entries to mask all interrupts */
355*565bbb86SNeel Natu 	for (i = 0; i < REDIR_ENTRIES; i++)
356*565bbb86SNeel Natu 		vioapic->rtbl[i].reg = 0x0001000000010000UL;
357*565bbb86SNeel Natu 
358*565bbb86SNeel Natu 	return (vioapic);
359*565bbb86SNeel Natu }
360*565bbb86SNeel Natu 
361*565bbb86SNeel Natu void
362*565bbb86SNeel Natu vioapic_cleanup(struct vioapic *vioapic)
363*565bbb86SNeel Natu {
364*565bbb86SNeel Natu 
365*565bbb86SNeel Natu 	free(vioapic, M_VIOAPIC);
366*565bbb86SNeel Natu }
367