xref: /freebsd/sys/amd64/vmm/io/vioapic.c (revision ac7304a758c0f6696b029a1e5d5d23e2a99c72af)
1565bbb86SNeel Natu /*-
2565bbb86SNeel Natu  * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3565bbb86SNeel Natu  * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
4565bbb86SNeel Natu  * All rights reserved.
5565bbb86SNeel Natu  *
6565bbb86SNeel Natu  * Redistribution and use in source and binary forms, with or without
7565bbb86SNeel Natu  * modification, are permitted provided that the following conditions
8565bbb86SNeel Natu  * are met:
9565bbb86SNeel Natu  * 1. Redistributions of source code must retain the above copyright
10565bbb86SNeel Natu  *    notice, this list of conditions and the following disclaimer.
11565bbb86SNeel Natu  * 2. Redistributions in binary form must reproduce the above copyright
12565bbb86SNeel Natu  *    notice, this list of conditions and the following disclaimer in the
13565bbb86SNeel Natu  *    documentation and/or other materials provided with the distribution.
14565bbb86SNeel Natu  *
15565bbb86SNeel Natu  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16565bbb86SNeel Natu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17565bbb86SNeel Natu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18565bbb86SNeel Natu  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19565bbb86SNeel Natu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20565bbb86SNeel Natu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21565bbb86SNeel Natu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22565bbb86SNeel Natu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23565bbb86SNeel Natu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24565bbb86SNeel Natu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25565bbb86SNeel Natu  * SUCH DAMAGE.
26565bbb86SNeel Natu  *
27565bbb86SNeel Natu  * $FreeBSD$
28565bbb86SNeel Natu  */
29565bbb86SNeel Natu 
30565bbb86SNeel Natu #include <sys/cdefs.h>
31565bbb86SNeel Natu __FBSDID("$FreeBSD$");
32565bbb86SNeel Natu 
33565bbb86SNeel Natu #include <sys/param.h>
34565bbb86SNeel Natu #include <sys/queue.h>
35565bbb86SNeel Natu #include <sys/cpuset.h>
36565bbb86SNeel Natu #include <sys/lock.h>
37565bbb86SNeel Natu #include <sys/mutex.h>
38565bbb86SNeel Natu #include <sys/systm.h>
39565bbb86SNeel Natu #include <sys/kernel.h>
40565bbb86SNeel Natu #include <sys/malloc.h>
41565bbb86SNeel Natu 
42565bbb86SNeel Natu #include <x86/apicreg.h>
43565bbb86SNeel Natu #include <machine/vmm.h>
44565bbb86SNeel Natu 
45565bbb86SNeel Natu #include "vmm_ktr.h"
46565bbb86SNeel Natu #include "vmm_lapic.h"
47565bbb86SNeel Natu #include "vioapic.h"
48565bbb86SNeel Natu 
49565bbb86SNeel Natu #define	IOREGSEL	0x00
50565bbb86SNeel Natu #define	IOWIN		0x10
51565bbb86SNeel Natu 
52565bbb86SNeel Natu #define	REDIR_ENTRIES	16
53565bbb86SNeel Natu #define	INTR_ASSERTED(vioapic, pin) ((vioapic)->rtbl[(pin)].pinstate == true)
54565bbb86SNeel Natu 
55565bbb86SNeel Natu struct vioapic {
56565bbb86SNeel Natu 	struct vm	*vm;
57565bbb86SNeel Natu 	struct mtx	mtx;
58565bbb86SNeel Natu 	uint32_t	id;
59565bbb86SNeel Natu 	uint32_t	ioregsel;
60565bbb86SNeel Natu 	struct {
61565bbb86SNeel Natu 		uint64_t reg;
62565bbb86SNeel Natu 		bool     pinstate;
63565bbb86SNeel Natu 		bool     pending;
64565bbb86SNeel Natu 	} rtbl[REDIR_ENTRIES];
65565bbb86SNeel Natu };
66565bbb86SNeel Natu 
67565bbb86SNeel Natu #define	VIOAPIC_LOCK(vioapic)		mtx_lock(&((vioapic)->mtx))
68565bbb86SNeel Natu #define	VIOAPIC_UNLOCK(vioapic)		mtx_unlock(&((vioapic)->mtx))
69565bbb86SNeel Natu #define	VIOAPIC_LOCKED(vioapic)		mtx_owned(&((vioapic)->mtx))
70565bbb86SNeel Natu 
71565bbb86SNeel Natu static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic");
72565bbb86SNeel Natu 
73565bbb86SNeel Natu #define	VIOAPIC_CTR1(vioapic, fmt, a1)					\
74565bbb86SNeel Natu 	VM_CTR1((vioapic)->vm, fmt, a1)
75565bbb86SNeel Natu 
76565bbb86SNeel Natu #define	VIOAPIC_CTR2(vioapic, fmt, a1, a2)				\
77565bbb86SNeel Natu 	VM_CTR2((vioapic)->vm, fmt, a1, a2)
78565bbb86SNeel Natu 
79565bbb86SNeel Natu #define	VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3)				\
80565bbb86SNeel Natu 	VM_CTR3((vioapic)->vm, fmt, a1, a2, a3)
81565bbb86SNeel Natu 
82565bbb86SNeel Natu #ifdef KTR
83565bbb86SNeel Natu static const char *
84565bbb86SNeel Natu pinstate_str(bool asserted)
85565bbb86SNeel Natu {
86565bbb86SNeel Natu 
87565bbb86SNeel Natu 	if (asserted)
88565bbb86SNeel Natu 		return ("asserted");
89565bbb86SNeel Natu 	else
90565bbb86SNeel Natu 		return ("deasserted");
91565bbb86SNeel Natu }
92565bbb86SNeel Natu #endif
93565bbb86SNeel Natu 
94565bbb86SNeel Natu static void
95565bbb86SNeel Natu vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate)
96565bbb86SNeel Natu {
97565bbb86SNeel Natu 	int vector, apicid, vcpuid;
98565bbb86SNeel Natu 	uint32_t low, high;
99565bbb86SNeel Natu 	cpuset_t dmask;
100565bbb86SNeel Natu 
101565bbb86SNeel Natu 	KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
102565bbb86SNeel Natu 	    ("vioapic_set_pinstate: invalid pin number %d", pin));
103565bbb86SNeel Natu 
104565bbb86SNeel Natu 	KASSERT(VIOAPIC_LOCKED(vioapic),
105565bbb86SNeel Natu 	    ("vioapic_set_pinstate: vioapic is not locked"));
106565bbb86SNeel Natu 
107565bbb86SNeel Natu 	VIOAPIC_CTR2(vioapic, "ioapic pin%d %s", pin, pinstate_str(newstate));
108565bbb86SNeel Natu 
109565bbb86SNeel Natu 	/* Nothing to do if interrupt pin has not changed state */
110565bbb86SNeel Natu 	if (vioapic->rtbl[pin].pinstate == newstate)
111565bbb86SNeel Natu 		return;
112565bbb86SNeel Natu 
113565bbb86SNeel Natu 	vioapic->rtbl[pin].pinstate = newstate;	/* record it */
114565bbb86SNeel Natu 
115565bbb86SNeel Natu 	/* Nothing to do if interrupt pin is deasserted */
116565bbb86SNeel Natu 	if (!INTR_ASSERTED(vioapic, pin))
117565bbb86SNeel Natu 		return;
118565bbb86SNeel Natu 
119565bbb86SNeel Natu 	/*
120565bbb86SNeel Natu 	 * XXX
121565bbb86SNeel Natu 	 * We only deal with:
122565bbb86SNeel Natu 	 * - edge triggered interrupts
123565bbb86SNeel Natu 	 * - fixed delivery mode
124565bbb86SNeel Natu 	 *  Level-triggered sources will work so long as there is no sharing.
125565bbb86SNeel Natu 	 */
126565bbb86SNeel Natu 	low = vioapic->rtbl[pin].reg;
127565bbb86SNeel Natu 	high = vioapic->rtbl[pin].reg >> 32;
128565bbb86SNeel Natu 	if ((low & IOART_INTMASK) == IOART_INTMCLR &&
129565bbb86SNeel Natu 	    (low & IOART_DESTMOD) == IOART_DESTPHY &&
130565bbb86SNeel Natu 	    (low & IOART_DELMOD) == IOART_DELFIXED) {
131565bbb86SNeel Natu 		vector = low & IOART_INTVEC;
132565bbb86SNeel Natu 		apicid = high >> APIC_ID_SHIFT;
133565bbb86SNeel Natu 		if (apicid != 0xff) {
134565bbb86SNeel Natu 			/* unicast */
135565bbb86SNeel Natu 			vcpuid = vm_apicid2vcpuid(vioapic->vm, apicid);
136565bbb86SNeel Natu 			VIOAPIC_CTR3(vioapic, "ioapic pin%d triggering "
137565bbb86SNeel Natu 			    "intr vector %d on vcpuid %d", pin, vector, vcpuid);
138565bbb86SNeel Natu 			lapic_set_intr(vioapic->vm, vcpuid, vector);
139565bbb86SNeel Natu 		} else {
140565bbb86SNeel Natu 			/* broadcast */
141565bbb86SNeel Natu 			VIOAPIC_CTR2(vioapic, "ioapic pin%d triggering intr "
142565bbb86SNeel Natu 			    "vector %d on all vcpus", pin, vector);
143565bbb86SNeel Natu 			dmask = vm_active_cpus(vioapic->vm);
144565bbb86SNeel Natu 			while ((vcpuid = CPU_FFS(&dmask)) != 0) {
145565bbb86SNeel Natu 				vcpuid--;
146565bbb86SNeel Natu 				CPU_CLR(vcpuid, &dmask);
147565bbb86SNeel Natu 				lapic_set_intr(vioapic->vm, vcpuid, vector);
148565bbb86SNeel Natu 			}
149565bbb86SNeel Natu 		}
150565bbb86SNeel Natu 	} else if ((low & IOART_INTMASK) != IOART_INTMCLR &&
151565bbb86SNeel Natu 		   (low & IOART_TRGRLVL) != 0) {
152565bbb86SNeel Natu 		/*
153565bbb86SNeel Natu 		 * For level-triggered interrupts that have been
154565bbb86SNeel Natu 		 * masked, set the pending bit so that an interrupt
155565bbb86SNeel Natu 		 * will be generated on unmask and if the level is
156565bbb86SNeel Natu 		 * still asserted
157565bbb86SNeel Natu 		 */
158565bbb86SNeel Natu 		VIOAPIC_CTR1(vioapic, "ioapic pin%d interrupt pending", pin);
159565bbb86SNeel Natu 		vioapic->rtbl[pin].pending = true;
160565bbb86SNeel Natu 	}
161565bbb86SNeel Natu }
162565bbb86SNeel Natu 
163*ac7304a7SNeel Natu enum irqstate {
164*ac7304a7SNeel Natu 	IRQSTATE_ASSERT,
165*ac7304a7SNeel Natu 	IRQSTATE_DEASSERT,
166*ac7304a7SNeel Natu 	IRQSTATE_PULSE
167*ac7304a7SNeel Natu };
168*ac7304a7SNeel Natu 
169565bbb86SNeel Natu static int
170*ac7304a7SNeel Natu vioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
171565bbb86SNeel Natu {
172565bbb86SNeel Natu 	struct vioapic *vioapic;
173565bbb86SNeel Natu 
174565bbb86SNeel Natu 	if (irq < 0 || irq >= REDIR_ENTRIES)
175565bbb86SNeel Natu 		return (EINVAL);
176565bbb86SNeel Natu 
177565bbb86SNeel Natu 	vioapic = vm_ioapic(vm);
178565bbb86SNeel Natu 
179565bbb86SNeel Natu 	VIOAPIC_LOCK(vioapic);
180*ac7304a7SNeel Natu 	switch (irqstate) {
181*ac7304a7SNeel Natu 	case IRQSTATE_ASSERT:
182*ac7304a7SNeel Natu 		vioapic_set_pinstate(vioapic, irq, true);
183*ac7304a7SNeel Natu 		break;
184*ac7304a7SNeel Natu 	case IRQSTATE_DEASSERT:
185*ac7304a7SNeel Natu 		vioapic_set_pinstate(vioapic, irq, false);
186*ac7304a7SNeel Natu 		break;
187*ac7304a7SNeel Natu 	case IRQSTATE_PULSE:
188*ac7304a7SNeel Natu 		vioapic_set_pinstate(vioapic, irq, true);
189*ac7304a7SNeel Natu 		vioapic_set_pinstate(vioapic, irq, false);
190*ac7304a7SNeel Natu 		break;
191*ac7304a7SNeel Natu 	default:
192*ac7304a7SNeel Natu 		panic("vioapic_set_irqstate: invalid irqstate %d", irqstate);
193*ac7304a7SNeel Natu 	}
194565bbb86SNeel Natu 	VIOAPIC_UNLOCK(vioapic);
195565bbb86SNeel Natu 
196565bbb86SNeel Natu 	return (0);
197565bbb86SNeel Natu }
198565bbb86SNeel Natu 
199565bbb86SNeel Natu int
200565bbb86SNeel Natu vioapic_assert_irq(struct vm *vm, int irq)
201565bbb86SNeel Natu {
202565bbb86SNeel Natu 
203*ac7304a7SNeel Natu 	return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
204565bbb86SNeel Natu }
205565bbb86SNeel Natu 
206565bbb86SNeel Natu int
207565bbb86SNeel Natu vioapic_deassert_irq(struct vm *vm, int irq)
208565bbb86SNeel Natu {
209565bbb86SNeel Natu 
210*ac7304a7SNeel Natu 	return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
211*ac7304a7SNeel Natu }
212*ac7304a7SNeel Natu 
213*ac7304a7SNeel Natu int
214*ac7304a7SNeel Natu vioapic_pulse_irq(struct vm *vm, int irq)
215*ac7304a7SNeel Natu {
216*ac7304a7SNeel Natu 
217*ac7304a7SNeel Natu 	return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE));
218565bbb86SNeel Natu }
219565bbb86SNeel Natu 
220565bbb86SNeel Natu static uint32_t
221565bbb86SNeel Natu vioapic_read(struct vioapic *vioapic, uint32_t addr)
222565bbb86SNeel Natu {
223565bbb86SNeel Natu 	int regnum, pin, rshift;
224565bbb86SNeel Natu 
225565bbb86SNeel Natu 	regnum = addr & 0xff;
226565bbb86SNeel Natu 	switch (regnum) {
227565bbb86SNeel Natu 	case IOAPIC_ID:
228565bbb86SNeel Natu 		return (vioapic->id);
229565bbb86SNeel Natu 		break;
230565bbb86SNeel Natu 	case IOAPIC_VER:
231565bbb86SNeel Natu 		return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11);
232565bbb86SNeel Natu 		break;
233565bbb86SNeel Natu 	case IOAPIC_ARB:
234565bbb86SNeel Natu 		return (vioapic->id);
235565bbb86SNeel Natu 		break;
236565bbb86SNeel Natu 	default:
237565bbb86SNeel Natu 		break;
238565bbb86SNeel Natu 	}
239565bbb86SNeel Natu 
240565bbb86SNeel Natu 	/* redirection table entries */
241565bbb86SNeel Natu 	if (regnum >= IOAPIC_REDTBL &&
242565bbb86SNeel Natu 	    regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
243565bbb86SNeel Natu 		pin = (regnum - IOAPIC_REDTBL) / 2;
244565bbb86SNeel Natu 		if ((regnum - IOAPIC_REDTBL) % 2)
245565bbb86SNeel Natu 			rshift = 32;
246565bbb86SNeel Natu 		else
247565bbb86SNeel Natu 			rshift = 0;
248565bbb86SNeel Natu 
249565bbb86SNeel Natu 		return (vioapic->rtbl[pin].reg >> rshift);
250565bbb86SNeel Natu 	}
251565bbb86SNeel Natu 
252565bbb86SNeel Natu 	return (0);
253565bbb86SNeel Natu }
254565bbb86SNeel Natu 
255565bbb86SNeel Natu static void
256565bbb86SNeel Natu vioapic_write(struct vioapic *vioapic, uint32_t addr, uint32_t data)
257565bbb86SNeel Natu {
258565bbb86SNeel Natu 	int regnum, pin, lshift;
259565bbb86SNeel Natu 
260565bbb86SNeel Natu 	regnum = addr & 0xff;
261565bbb86SNeel Natu 	switch (regnum) {
262565bbb86SNeel Natu 	case IOAPIC_ID:
263565bbb86SNeel Natu 		vioapic->id = data & APIC_ID_MASK;
264565bbb86SNeel Natu 		break;
265565bbb86SNeel Natu 	case IOAPIC_VER:
266565bbb86SNeel Natu 	case IOAPIC_ARB:
267565bbb86SNeel Natu 		/* readonly */
268565bbb86SNeel Natu 		break;
269565bbb86SNeel Natu 	default:
270565bbb86SNeel Natu 		break;
271565bbb86SNeel Natu 	}
272565bbb86SNeel Natu 
273565bbb86SNeel Natu 	/* redirection table entries */
274565bbb86SNeel Natu 	if (regnum >= IOAPIC_REDTBL &&
275565bbb86SNeel Natu 	    regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
276565bbb86SNeel Natu 		pin = (regnum - IOAPIC_REDTBL) / 2;
277565bbb86SNeel Natu 		if ((regnum - IOAPIC_REDTBL) % 2)
278565bbb86SNeel Natu 			lshift = 32;
279565bbb86SNeel Natu 		else
280565bbb86SNeel Natu 			lshift = 0;
281565bbb86SNeel Natu 
282565bbb86SNeel Natu 		vioapic->rtbl[pin].reg &= ~((uint64_t)0xffffffff << lshift);
283565bbb86SNeel Natu 		vioapic->rtbl[pin].reg |= ((uint64_t)data << lshift);
284565bbb86SNeel Natu 
285565bbb86SNeel Natu 		VIOAPIC_CTR2(vioapic, "ioapic pin%d redir table entry %#lx",
286565bbb86SNeel Natu 		    pin, vioapic->rtbl[pin].reg);
287565bbb86SNeel Natu 
288565bbb86SNeel Natu 		if (vioapic->rtbl[pin].pending &&
289565bbb86SNeel Natu 		    ((vioapic->rtbl[pin].reg & IOART_INTMASK) ==
290565bbb86SNeel Natu 		    IOART_INTMCLR)) {
291565bbb86SNeel Natu 			vioapic->rtbl[pin].pending = false;
292565bbb86SNeel Natu 			/*
293565bbb86SNeel Natu 			 * Inject the deferred level-triggered int if it is
294565bbb86SNeel Natu 			 * still asserted. Simulate by toggling the pin
295565bbb86SNeel Natu 			 * off and then on.
296565bbb86SNeel Natu 			 */
297565bbb86SNeel Natu 			if (vioapic->rtbl[pin].pinstate == true) {
298565bbb86SNeel Natu 				VIOAPIC_CTR1(vioapic, "ioapic pin%d pending "
299565bbb86SNeel Natu 				    "interrupt delivered", pin);
300565bbb86SNeel Natu 				vioapic_set_pinstate(vioapic, pin, false);
301565bbb86SNeel Natu 				vioapic_set_pinstate(vioapic, pin, true);
302565bbb86SNeel Natu 			} else {
303565bbb86SNeel Natu 				VIOAPIC_CTR1(vioapic, "ioapic pin%d pending "
304565bbb86SNeel Natu 				    "interrupt dismissed", pin);
305565bbb86SNeel Natu 			}
306565bbb86SNeel Natu 		}
307565bbb86SNeel Natu 	}
308565bbb86SNeel Natu }
309565bbb86SNeel Natu 
310565bbb86SNeel Natu static int
311565bbb86SNeel Natu vioapic_mmio_rw(struct vioapic *vioapic, uint64_t gpa, uint64_t *data,
312565bbb86SNeel Natu     int size, bool doread)
313565bbb86SNeel Natu {
314565bbb86SNeel Natu 	uint64_t offset;
315565bbb86SNeel Natu 
316565bbb86SNeel Natu 	offset = gpa - VIOAPIC_BASE;
317565bbb86SNeel Natu 
318565bbb86SNeel Natu 	/*
319565bbb86SNeel Natu 	 * The IOAPIC specification allows 32-bit wide accesses to the
320565bbb86SNeel Natu 	 * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
321565bbb86SNeel Natu 	 */
322565bbb86SNeel Natu 	if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
323565bbb86SNeel Natu 		if (doread)
324565bbb86SNeel Natu 			*data = 0;
325565bbb86SNeel Natu 		return (0);
326565bbb86SNeel Natu 	}
327565bbb86SNeel Natu 
328565bbb86SNeel Natu 	VIOAPIC_LOCK(vioapic);
329565bbb86SNeel Natu 	if (offset == IOREGSEL) {
330565bbb86SNeel Natu 		if (doread)
331565bbb86SNeel Natu 			*data = vioapic->ioregsel;
332565bbb86SNeel Natu 		else
333565bbb86SNeel Natu 			vioapic->ioregsel = *data;
334565bbb86SNeel Natu 	} else {
335565bbb86SNeel Natu 		if (doread)
336565bbb86SNeel Natu 			*data = vioapic_read(vioapic, vioapic->ioregsel);
337565bbb86SNeel Natu 		else
338565bbb86SNeel Natu 			vioapic_write(vioapic, vioapic->ioregsel, *data);
339565bbb86SNeel Natu 	}
340565bbb86SNeel Natu 	VIOAPIC_UNLOCK(vioapic);
341565bbb86SNeel Natu 
342565bbb86SNeel Natu 	return (0);
343565bbb86SNeel Natu }
344565bbb86SNeel Natu 
345565bbb86SNeel Natu int
346565bbb86SNeel Natu vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval,
347565bbb86SNeel Natu     int size, void *arg)
348565bbb86SNeel Natu {
349565bbb86SNeel Natu 	int error;
350565bbb86SNeel Natu 	struct vioapic *vioapic;
351565bbb86SNeel Natu 
352565bbb86SNeel Natu 	vioapic = vm_ioapic(vm);
353565bbb86SNeel Natu 	error = vioapic_mmio_rw(vioapic, gpa, rval, size, true);
354565bbb86SNeel Natu 	return (error);
355565bbb86SNeel Natu }
356565bbb86SNeel Natu 
357565bbb86SNeel Natu int
358565bbb86SNeel Natu vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval,
359565bbb86SNeel Natu     int size, void *arg)
360565bbb86SNeel Natu {
361565bbb86SNeel Natu 	int error;
362565bbb86SNeel Natu 	struct vioapic *vioapic;
363565bbb86SNeel Natu 
364565bbb86SNeel Natu 	vioapic = vm_ioapic(vm);
365565bbb86SNeel Natu 	error = vioapic_mmio_rw(vioapic, gpa, &wval, size, false);
366565bbb86SNeel Natu 	return (error);
367565bbb86SNeel Natu }
368565bbb86SNeel Natu 
369565bbb86SNeel Natu struct vioapic *
370565bbb86SNeel Natu vioapic_init(struct vm *vm)
371565bbb86SNeel Natu {
372565bbb86SNeel Natu 	int i;
373565bbb86SNeel Natu 	struct vioapic *vioapic;
374565bbb86SNeel Natu 
375565bbb86SNeel Natu 	vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO);
376565bbb86SNeel Natu 
377565bbb86SNeel Natu 	vioapic->vm = vm;
378565bbb86SNeel Natu 	mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_DEF);
379565bbb86SNeel Natu 
380565bbb86SNeel Natu 	/* Initialize all redirection entries to mask all interrupts */
381565bbb86SNeel Natu 	for (i = 0; i < REDIR_ENTRIES; i++)
382565bbb86SNeel Natu 		vioapic->rtbl[i].reg = 0x0001000000010000UL;
383565bbb86SNeel Natu 
384565bbb86SNeel Natu 	return (vioapic);
385565bbb86SNeel Natu }
386565bbb86SNeel Natu 
387565bbb86SNeel Natu void
388565bbb86SNeel Natu vioapic_cleanup(struct vioapic *vioapic)
389565bbb86SNeel Natu {
390565bbb86SNeel Natu 
391565bbb86SNeel Natu 	free(vioapic, M_VIOAPIC);
392565bbb86SNeel Natu }
393