1565bbb86SNeel Natu /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3c49761ddSPedro F. Giffuni *
4565bbb86SNeel Natu * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5565bbb86SNeel Natu * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
6565bbb86SNeel Natu * All rights reserved.
7565bbb86SNeel Natu *
8565bbb86SNeel Natu * Redistribution and use in source and binary forms, with or without
9565bbb86SNeel Natu * modification, are permitted provided that the following conditions
10565bbb86SNeel Natu * are met:
11565bbb86SNeel Natu * 1. Redistributions of source code must retain the above copyright
12565bbb86SNeel Natu * notice, this list of conditions and the following disclaimer.
13565bbb86SNeel Natu * 2. Redistributions in binary form must reproduce the above copyright
14565bbb86SNeel Natu * notice, this list of conditions and the following disclaimer in the
15565bbb86SNeel Natu * documentation and/or other materials provided with the distribution.
16565bbb86SNeel Natu *
17565bbb86SNeel Natu * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
18565bbb86SNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19565bbb86SNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20565bbb86SNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
21565bbb86SNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22565bbb86SNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23565bbb86SNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24565bbb86SNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25565bbb86SNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26565bbb86SNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27565bbb86SNeel Natu * SUCH DAMAGE.
28565bbb86SNeel Natu */
29565bbb86SNeel Natu
30565bbb86SNeel Natu #include <sys/cdefs.h>
31483d953aSJohn Baldwin #include "opt_bhyve_snapshot.h"
32483d953aSJohn Baldwin
33565bbb86SNeel Natu #include <sys/param.h>
34565bbb86SNeel Natu #include <sys/queue.h>
35565bbb86SNeel Natu #include <sys/lock.h>
36565bbb86SNeel Natu #include <sys/mutex.h>
37565bbb86SNeel Natu #include <sys/systm.h>
38565bbb86SNeel Natu #include <sys/kernel.h>
39565bbb86SNeel Natu #include <sys/malloc.h>
40565bbb86SNeel Natu
41565bbb86SNeel Natu #include <x86/apicreg.h>
42565bbb86SNeel Natu #include <machine/vmm.h>
43483d953aSJohn Baldwin #include <machine/vmm_snapshot.h>
44565bbb86SNeel Natu
45*3ccb0233SMark Johnston #include <dev/vmm/vmm_ktr.h>
46*3ccb0233SMark Johnston
47565bbb86SNeel Natu #include "vmm_lapic.h"
484f8be175SNeel Natu #include "vlapic.h"
49565bbb86SNeel Natu #include "vioapic.h"
50565bbb86SNeel Natu
51565bbb86SNeel Natu #define IOREGSEL 0x00
52565bbb86SNeel Natu #define IOWIN 0x10
53565bbb86SNeel Natu
544cefe96cSAlexander Motin #define REDIR_ENTRIES 32
55b5b28fc9SNeel Natu #define RTBL_RO_BITS ((uint64_t)(IOART_REM_IRR | IOART_DELIVS))
56565bbb86SNeel Natu
57565bbb86SNeel Natu struct vioapic {
58565bbb86SNeel Natu struct vm *vm;
59565bbb86SNeel Natu struct mtx mtx;
60565bbb86SNeel Natu uint32_t id;
61565bbb86SNeel Natu uint32_t ioregsel;
62565bbb86SNeel Natu struct {
63565bbb86SNeel Natu uint64_t reg;
64b5b28fc9SNeel Natu int acnt; /* sum of pin asserts (+1) and deasserts (-1) */
65565bbb86SNeel Natu } rtbl[REDIR_ENTRIES];
66565bbb86SNeel Natu };
67565bbb86SNeel Natu
689c43cd07SNeel Natu #define VIOAPIC_LOCK(vioapic) mtx_lock_spin(&((vioapic)->mtx))
699c43cd07SNeel Natu #define VIOAPIC_UNLOCK(vioapic) mtx_unlock_spin(&((vioapic)->mtx))
70565bbb86SNeel Natu #define VIOAPIC_LOCKED(vioapic) mtx_owned(&((vioapic)->mtx))
71565bbb86SNeel Natu
72565bbb86SNeel Natu static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic");
73565bbb86SNeel Natu
74565bbb86SNeel Natu #define VIOAPIC_CTR1(vioapic, fmt, a1) \
75565bbb86SNeel Natu VM_CTR1((vioapic)->vm, fmt, a1)
76565bbb86SNeel Natu
77565bbb86SNeel Natu #define VIOAPIC_CTR2(vioapic, fmt, a1, a2) \
78565bbb86SNeel Natu VM_CTR2((vioapic)->vm, fmt, a1, a2)
79565bbb86SNeel Natu
80565bbb86SNeel Natu #define VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3) \
81565bbb86SNeel Natu VM_CTR3((vioapic)->vm, fmt, a1, a2, a3)
82565bbb86SNeel Natu
83b5b28fc9SNeel Natu #define VIOAPIC_CTR4(vioapic, fmt, a1, a2, a3, a4) \
84b5b28fc9SNeel Natu VM_CTR4((vioapic)->vm, fmt, a1, a2, a3, a4)
85b5b28fc9SNeel Natu
86565bbb86SNeel Natu #ifdef KTR
87565bbb86SNeel Natu static const char *
pinstate_str(bool asserted)88565bbb86SNeel Natu pinstate_str(bool asserted)
89565bbb86SNeel Natu {
90565bbb86SNeel Natu
91565bbb86SNeel Natu if (asserted)
92565bbb86SNeel Natu return ("asserted");
93565bbb86SNeel Natu else
94565bbb86SNeel Natu return ("deasserted");
95565bbb86SNeel Natu }
96565bbb86SNeel Natu #endif
97565bbb86SNeel Natu
98565bbb86SNeel Natu static void
vioapic_send_intr(struct vioapic * vioapic,int pin)99b5b28fc9SNeel Natu vioapic_send_intr(struct vioapic *vioapic, int pin)
100565bbb86SNeel Natu {
1014f8be175SNeel Natu int vector, delmode;
1024f8be175SNeel Natu uint32_t low, high, dest;
1034f8be175SNeel Natu bool level, phys;
104565bbb86SNeel Natu
105565bbb86SNeel Natu KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
106565bbb86SNeel Natu ("vioapic_set_pinstate: invalid pin number %d", pin));
107565bbb86SNeel Natu
108565bbb86SNeel Natu KASSERT(VIOAPIC_LOCKED(vioapic),
109565bbb86SNeel Natu ("vioapic_set_pinstate: vioapic is not locked"));
110565bbb86SNeel Natu
111565bbb86SNeel Natu low = vioapic->rtbl[pin].reg;
112565bbb86SNeel Natu high = vioapic->rtbl[pin].reg >> 32;
113b5b28fc9SNeel Natu
114b5b28fc9SNeel Natu if ((low & IOART_INTMASK) == IOART_INTMSET) {
115b5b28fc9SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d: masked", pin);
116b5b28fc9SNeel Natu return;
117b5b28fc9SNeel Natu }
118b5b28fc9SNeel Natu
1194f8be175SNeel Natu phys = ((low & IOART_DESTMOD) == IOART_DESTPHY);
1204f8be175SNeel Natu delmode = low & IOART_DELMOD;
121b5b28fc9SNeel Natu level = low & IOART_TRGRLVL ? true : false;
1225ea87868SRoger Pau Monné if (level) {
1235ea87868SRoger Pau Monné if ((low & IOART_REM_IRR) != 0) {
1245ea87868SRoger Pau Monné VIOAPIC_CTR1(vioapic, "ioapic pin%d: irr pending",
1255ea87868SRoger Pau Monné pin);
1265ea87868SRoger Pau Monné return;
1275ea87868SRoger Pau Monné }
128b5b28fc9SNeel Natu vioapic->rtbl[pin].reg |= IOART_REM_IRR;
1295ea87868SRoger Pau Monné }
130b5b28fc9SNeel Natu
131565bbb86SNeel Natu vector = low & IOART_INTVEC;
1324f8be175SNeel Natu dest = high >> APIC_ID_SHIFT;
1334f8be175SNeel Natu vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector);
134565bbb86SNeel Natu }
135b5b28fc9SNeel Natu
136b5b28fc9SNeel Natu static void
vioapic_set_pinstate(struct vioapic * vioapic,int pin,bool newstate)137b5b28fc9SNeel Natu vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate)
138b5b28fc9SNeel Natu {
139b5b28fc9SNeel Natu int oldcnt, newcnt;
140b5b28fc9SNeel Natu bool needintr;
141b5b28fc9SNeel Natu
142b5b28fc9SNeel Natu KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
143b5b28fc9SNeel Natu ("vioapic_set_pinstate: invalid pin number %d", pin));
144b5b28fc9SNeel Natu
145b5b28fc9SNeel Natu KASSERT(VIOAPIC_LOCKED(vioapic),
146b5b28fc9SNeel Natu ("vioapic_set_pinstate: vioapic is not locked"));
147b5b28fc9SNeel Natu
148b5b28fc9SNeel Natu oldcnt = vioapic->rtbl[pin].acnt;
149b5b28fc9SNeel Natu if (newstate)
150b5b28fc9SNeel Natu vioapic->rtbl[pin].acnt++;
151b5b28fc9SNeel Natu else
152b5b28fc9SNeel Natu vioapic->rtbl[pin].acnt--;
153b5b28fc9SNeel Natu newcnt = vioapic->rtbl[pin].acnt;
154b5b28fc9SNeel Natu
155b5b28fc9SNeel Natu if (newcnt < 0) {
156b5b28fc9SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d: bad acnt %d",
157b5b28fc9SNeel Natu pin, newcnt);
158b5b28fc9SNeel Natu }
159b5b28fc9SNeel Natu
160b5b28fc9SNeel Natu needintr = false;
161b5b28fc9SNeel Natu if (oldcnt == 0 && newcnt == 1) {
162b5b28fc9SNeel Natu needintr = true;
163b5b28fc9SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d: asserted", pin);
164b5b28fc9SNeel Natu } else if (oldcnt == 1 && newcnt == 0) {
165b5b28fc9SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d: deasserted", pin);
166b5b28fc9SNeel Natu } else {
167b5b28fc9SNeel Natu VIOAPIC_CTR3(vioapic, "ioapic pin%d: %s, ignored, acnt %d",
168b5b28fc9SNeel Natu pin, pinstate_str(newstate), newcnt);
169b5b28fc9SNeel Natu }
170b5b28fc9SNeel Natu
171b5b28fc9SNeel Natu if (needintr)
172b5b28fc9SNeel Natu vioapic_send_intr(vioapic, pin);
173565bbb86SNeel Natu }
174565bbb86SNeel Natu
175ac7304a7SNeel Natu enum irqstate {
176ac7304a7SNeel Natu IRQSTATE_ASSERT,
177ac7304a7SNeel Natu IRQSTATE_DEASSERT,
178ac7304a7SNeel Natu IRQSTATE_PULSE
179ac7304a7SNeel Natu };
180ac7304a7SNeel Natu
181565bbb86SNeel Natu static int
vioapic_set_irqstate(struct vm * vm,int irq,enum irqstate irqstate)182ac7304a7SNeel Natu vioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
183565bbb86SNeel Natu {
184565bbb86SNeel Natu struct vioapic *vioapic;
185565bbb86SNeel Natu
186565bbb86SNeel Natu if (irq < 0 || irq >= REDIR_ENTRIES)
187565bbb86SNeel Natu return (EINVAL);
188565bbb86SNeel Natu
189565bbb86SNeel Natu vioapic = vm_ioapic(vm);
190565bbb86SNeel Natu
191565bbb86SNeel Natu VIOAPIC_LOCK(vioapic);
192ac7304a7SNeel Natu switch (irqstate) {
193ac7304a7SNeel Natu case IRQSTATE_ASSERT:
194ac7304a7SNeel Natu vioapic_set_pinstate(vioapic, irq, true);
195ac7304a7SNeel Natu break;
196ac7304a7SNeel Natu case IRQSTATE_DEASSERT:
197ac7304a7SNeel Natu vioapic_set_pinstate(vioapic, irq, false);
198ac7304a7SNeel Natu break;
199ac7304a7SNeel Natu case IRQSTATE_PULSE:
200ac7304a7SNeel Natu vioapic_set_pinstate(vioapic, irq, true);
201ac7304a7SNeel Natu vioapic_set_pinstate(vioapic, irq, false);
202ac7304a7SNeel Natu break;
203ac7304a7SNeel Natu default:
204ac7304a7SNeel Natu panic("vioapic_set_irqstate: invalid irqstate %d", irqstate);
205ac7304a7SNeel Natu }
206565bbb86SNeel Natu VIOAPIC_UNLOCK(vioapic);
207565bbb86SNeel Natu
208565bbb86SNeel Natu return (0);
209565bbb86SNeel Natu }
210565bbb86SNeel Natu
211565bbb86SNeel Natu int
vioapic_assert_irq(struct vm * vm,int irq)212565bbb86SNeel Natu vioapic_assert_irq(struct vm *vm, int irq)
213565bbb86SNeel Natu {
214565bbb86SNeel Natu
215ac7304a7SNeel Natu return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
216565bbb86SNeel Natu }
217565bbb86SNeel Natu
218565bbb86SNeel Natu int
vioapic_deassert_irq(struct vm * vm,int irq)219565bbb86SNeel Natu vioapic_deassert_irq(struct vm *vm, int irq)
220565bbb86SNeel Natu {
221565bbb86SNeel Natu
222ac7304a7SNeel Natu return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
223ac7304a7SNeel Natu }
224ac7304a7SNeel Natu
225ac7304a7SNeel Natu int
vioapic_pulse_irq(struct vm * vm,int irq)226ac7304a7SNeel Natu vioapic_pulse_irq(struct vm *vm, int irq)
227ac7304a7SNeel Natu {
228ac7304a7SNeel Natu
229ac7304a7SNeel Natu return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE));
230565bbb86SNeel Natu }
231565bbb86SNeel Natu
2325b8a8cd1SNeel Natu /*
2335b8a8cd1SNeel Natu * Reset the vlapic's trigger-mode register to reflect the ioapic pin
2345b8a8cd1SNeel Natu * configuration.
2355b8a8cd1SNeel Natu */
2365b8a8cd1SNeel Natu static void
vioapic_update_tmr(struct vcpu * vcpu,void * arg)237d8be3d52SJohn Baldwin vioapic_update_tmr(struct vcpu *vcpu, void *arg)
2385b8a8cd1SNeel Natu {
2395b8a8cd1SNeel Natu struct vioapic *vioapic;
2405b8a8cd1SNeel Natu struct vlapic *vlapic;
2415b8a8cd1SNeel Natu uint32_t low, high, dest;
2425b8a8cd1SNeel Natu int delmode, pin, vector;
2435b8a8cd1SNeel Natu bool level, phys;
2445b8a8cd1SNeel Natu
245d8be3d52SJohn Baldwin vlapic = vm_lapic(vcpu);
246d8be3d52SJohn Baldwin vioapic = vm_ioapic(vcpu_vm(vcpu));
2475b8a8cd1SNeel Natu
2485b8a8cd1SNeel Natu VIOAPIC_LOCK(vioapic);
2495b8a8cd1SNeel Natu /*
2505b8a8cd1SNeel Natu * Reset all vectors to be edge-triggered.
2515b8a8cd1SNeel Natu */
2525b8a8cd1SNeel Natu vlapic_reset_tmr(vlapic);
2535b8a8cd1SNeel Natu for (pin = 0; pin < REDIR_ENTRIES; pin++) {
2545b8a8cd1SNeel Natu low = vioapic->rtbl[pin].reg;
2555b8a8cd1SNeel Natu high = vioapic->rtbl[pin].reg >> 32;
2565b8a8cd1SNeel Natu
2575b8a8cd1SNeel Natu level = low & IOART_TRGRLVL ? true : false;
2585b8a8cd1SNeel Natu if (!level)
2595b8a8cd1SNeel Natu continue;
2605b8a8cd1SNeel Natu
2615b8a8cd1SNeel Natu /*
2625b8a8cd1SNeel Natu * For a level-triggered 'pin' let the vlapic figure out if
2635b8a8cd1SNeel Natu * an assertion on this 'pin' would result in an interrupt
2645b8a8cd1SNeel Natu * being delivered to it. If yes, then it will modify the
2655b8a8cd1SNeel Natu * TMR bit associated with this vector to level-triggered.
2665b8a8cd1SNeel Natu */
2675b8a8cd1SNeel Natu phys = ((low & IOART_DESTMOD) == IOART_DESTPHY);
2685b8a8cd1SNeel Natu delmode = low & IOART_DELMOD;
2695b8a8cd1SNeel Natu vector = low & IOART_INTVEC;
2705b8a8cd1SNeel Natu dest = high >> APIC_ID_SHIFT;
2715b8a8cd1SNeel Natu vlapic_set_tmr_level(vlapic, dest, phys, delmode, vector);
2725b8a8cd1SNeel Natu }
2735b8a8cd1SNeel Natu VIOAPIC_UNLOCK(vioapic);
2745b8a8cd1SNeel Natu }
2755b8a8cd1SNeel Natu
276565bbb86SNeel Natu static uint32_t
vioapic_read(struct vioapic * vioapic,struct vcpu * vcpu,uint32_t addr)277d3956e46SJohn Baldwin vioapic_read(struct vioapic *vioapic, struct vcpu *vcpu, uint32_t addr)
278565bbb86SNeel Natu {
279565bbb86SNeel Natu int regnum, pin, rshift;
280565bbb86SNeel Natu
281565bbb86SNeel Natu regnum = addr & 0xff;
282565bbb86SNeel Natu switch (regnum) {
283565bbb86SNeel Natu case IOAPIC_ID:
284565bbb86SNeel Natu return (vioapic->id);
285565bbb86SNeel Natu break;
286565bbb86SNeel Natu case IOAPIC_VER:
287b5b28fc9SNeel Natu return (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11);
288565bbb86SNeel Natu break;
289565bbb86SNeel Natu case IOAPIC_ARB:
290565bbb86SNeel Natu return (vioapic->id);
291565bbb86SNeel Natu break;
292565bbb86SNeel Natu default:
293565bbb86SNeel Natu break;
294565bbb86SNeel Natu }
295565bbb86SNeel Natu
296565bbb86SNeel Natu /* redirection table entries */
297565bbb86SNeel Natu if (regnum >= IOAPIC_REDTBL &&
298565bbb86SNeel Natu regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
299565bbb86SNeel Natu pin = (regnum - IOAPIC_REDTBL) / 2;
300565bbb86SNeel Natu if ((regnum - IOAPIC_REDTBL) % 2)
301565bbb86SNeel Natu rshift = 32;
302565bbb86SNeel Natu else
303565bbb86SNeel Natu rshift = 0;
304565bbb86SNeel Natu
305565bbb86SNeel Natu return (vioapic->rtbl[pin].reg >> rshift);
306565bbb86SNeel Natu }
307565bbb86SNeel Natu
308565bbb86SNeel Natu return (0);
309565bbb86SNeel Natu }
310565bbb86SNeel Natu
311565bbb86SNeel Natu static void
vioapic_write(struct vioapic * vioapic,struct vcpu * vcpu,uint32_t addr,uint32_t data)312d3956e46SJohn Baldwin vioapic_write(struct vioapic *vioapic, struct vcpu *vcpu, uint32_t addr,
313d3956e46SJohn Baldwin uint32_t data)
314565bbb86SNeel Natu {
315b5b28fc9SNeel Natu uint64_t data64, mask64;
3165b8a8cd1SNeel Natu uint64_t last, changed;
317d8be3d52SJohn Baldwin int regnum, pin, lshift;
3185b8a8cd1SNeel Natu cpuset_t allvcpus;
319565bbb86SNeel Natu
320565bbb86SNeel Natu regnum = addr & 0xff;
321565bbb86SNeel Natu switch (regnum) {
322565bbb86SNeel Natu case IOAPIC_ID:
323565bbb86SNeel Natu vioapic->id = data & APIC_ID_MASK;
324565bbb86SNeel Natu break;
325565bbb86SNeel Natu case IOAPIC_VER:
326565bbb86SNeel Natu case IOAPIC_ARB:
327565bbb86SNeel Natu /* readonly */
328565bbb86SNeel Natu break;
329565bbb86SNeel Natu default:
330565bbb86SNeel Natu break;
331565bbb86SNeel Natu }
332565bbb86SNeel Natu
333565bbb86SNeel Natu /* redirection table entries */
334565bbb86SNeel Natu if (regnum >= IOAPIC_REDTBL &&
335565bbb86SNeel Natu regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
336565bbb86SNeel Natu pin = (regnum - IOAPIC_REDTBL) / 2;
337565bbb86SNeel Natu if ((regnum - IOAPIC_REDTBL) % 2)
338565bbb86SNeel Natu lshift = 32;
339565bbb86SNeel Natu else
340565bbb86SNeel Natu lshift = 0;
341565bbb86SNeel Natu
3425b8a8cd1SNeel Natu last = vioapic->rtbl[pin].reg;
3435b8a8cd1SNeel Natu
344b5b28fc9SNeel Natu data64 = (uint64_t)data << lshift;
345b5b28fc9SNeel Natu mask64 = (uint64_t)0xffffffff << lshift;
346b5b28fc9SNeel Natu vioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS;
347b5b28fc9SNeel Natu vioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS;
348565bbb86SNeel Natu
3495ea87868SRoger Pau Monné /*
3505ea87868SRoger Pau Monné * Switching from level to edge triggering will clear the IRR
3515ea87868SRoger Pau Monné * bit. This is what FreeBSD will do in order to EOI an
3525ea87868SRoger Pau Monné * interrupt when the IO-APIC doesn't support targeted EOI (see
3535ea87868SRoger Pau Monné * _ioapic_eoi_source).
3545ea87868SRoger Pau Monné */
3555ea87868SRoger Pau Monné if ((vioapic->rtbl[pin].reg & IOART_TRGRMOD) == IOART_TRGREDG &&
3565ea87868SRoger Pau Monné (vioapic->rtbl[pin].reg & IOART_REM_IRR) != 0)
3575ea87868SRoger Pau Monné vioapic->rtbl[pin].reg &= ~IOART_REM_IRR;
3585ea87868SRoger Pau Monné
359b5b28fc9SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d: redir table entry %#lx",
360565bbb86SNeel Natu pin, vioapic->rtbl[pin].reg);
361565bbb86SNeel Natu
362565bbb86SNeel Natu /*
3635b8a8cd1SNeel Natu * If any fields in the redirection table entry (except mask
3645b8a8cd1SNeel Natu * or polarity) have changed then rendezvous all the vcpus
3655b8a8cd1SNeel Natu * to update their vlapic trigger-mode registers.
3665b8a8cd1SNeel Natu */
3675b8a8cd1SNeel Natu changed = last ^ vioapic->rtbl[pin].reg;
3685b8a8cd1SNeel Natu if (changed & ~(IOART_INTMASK | IOART_INTPOL)) {
3695b8a8cd1SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d: recalculate "
3705b8a8cd1SNeel Natu "vlapic trigger-mode register", pin);
3715b8a8cd1SNeel Natu VIOAPIC_UNLOCK(vioapic);
3725b8a8cd1SNeel Natu allvcpus = vm_active_cpus(vioapic->vm);
373d8be3d52SJohn Baldwin (void)vm_smp_rendezvous(vcpu, allvcpus,
3745b8a8cd1SNeel Natu vioapic_update_tmr, NULL);
3755b8a8cd1SNeel Natu VIOAPIC_LOCK(vioapic);
3765b8a8cd1SNeel Natu }
3775b8a8cd1SNeel Natu
3785b8a8cd1SNeel Natu /*
379b5b28fc9SNeel Natu * Generate an interrupt if the following conditions are met:
380d7d06769SRoger Pau Monné * - pin trigger mode is level
381b5b28fc9SNeel Natu * - pin level is asserted
382565bbb86SNeel Natu */
3835ea87868SRoger Pau Monné if ((vioapic->rtbl[pin].reg & IOART_TRGRMOD) == IOART_TRGRLVL &&
384b5b28fc9SNeel Natu (vioapic->rtbl[pin].acnt > 0)) {
385b5b28fc9SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at rtbl "
386b5b28fc9SNeel Natu "write, acnt %d", pin, vioapic->rtbl[pin].acnt);
387b5b28fc9SNeel Natu vioapic_send_intr(vioapic, pin);
388565bbb86SNeel Natu }
389565bbb86SNeel Natu }
390565bbb86SNeel Natu }
391565bbb86SNeel Natu
392565bbb86SNeel Natu static int
vioapic_mmio_rw(struct vioapic * vioapic,struct vcpu * vcpu,uint64_t gpa,uint64_t * data,int size,bool doread)393d3956e46SJohn Baldwin vioapic_mmio_rw(struct vioapic *vioapic, struct vcpu *vcpu, uint64_t gpa,
3945b8a8cd1SNeel Natu uint64_t *data, int size, bool doread)
395565bbb86SNeel Natu {
396565bbb86SNeel Natu uint64_t offset;
397565bbb86SNeel Natu
398565bbb86SNeel Natu offset = gpa - VIOAPIC_BASE;
399565bbb86SNeel Natu
400565bbb86SNeel Natu /*
401565bbb86SNeel Natu * The IOAPIC specification allows 32-bit wide accesses to the
402565bbb86SNeel Natu * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
403565bbb86SNeel Natu */
404565bbb86SNeel Natu if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
405565bbb86SNeel Natu if (doread)
406565bbb86SNeel Natu *data = 0;
407565bbb86SNeel Natu return (0);
408565bbb86SNeel Natu }
409565bbb86SNeel Natu
410565bbb86SNeel Natu VIOAPIC_LOCK(vioapic);
411565bbb86SNeel Natu if (offset == IOREGSEL) {
412565bbb86SNeel Natu if (doread)
413565bbb86SNeel Natu *data = vioapic->ioregsel;
414565bbb86SNeel Natu else
415565bbb86SNeel Natu vioapic->ioregsel = *data;
416565bbb86SNeel Natu } else {
4175b8a8cd1SNeel Natu if (doread) {
418d3956e46SJohn Baldwin *data = vioapic_read(vioapic, vcpu,
4195b8a8cd1SNeel Natu vioapic->ioregsel);
4205b8a8cd1SNeel Natu } else {
421d3956e46SJohn Baldwin vioapic_write(vioapic, vcpu, vioapic->ioregsel,
4225b8a8cd1SNeel Natu *data);
4235b8a8cd1SNeel Natu }
424565bbb86SNeel Natu }
425565bbb86SNeel Natu VIOAPIC_UNLOCK(vioapic);
426565bbb86SNeel Natu
427565bbb86SNeel Natu return (0);
428565bbb86SNeel Natu }
429565bbb86SNeel Natu
430565bbb86SNeel Natu int
vioapic_mmio_read(struct vcpu * vcpu,uint64_t gpa,uint64_t * rval,int size,void * arg)431d3956e46SJohn Baldwin vioapic_mmio_read(struct vcpu *vcpu, uint64_t gpa, uint64_t *rval,
432565bbb86SNeel Natu int size, void *arg)
433565bbb86SNeel Natu {
434565bbb86SNeel Natu int error;
435565bbb86SNeel Natu struct vioapic *vioapic;
436565bbb86SNeel Natu
437d3956e46SJohn Baldwin vioapic = vm_ioapic(vcpu_vm(vcpu));
438d3956e46SJohn Baldwin error = vioapic_mmio_rw(vioapic, vcpu, gpa, rval, size, true);
439565bbb86SNeel Natu return (error);
440565bbb86SNeel Natu }
441565bbb86SNeel Natu
442565bbb86SNeel Natu int
vioapic_mmio_write(struct vcpu * vcpu,uint64_t gpa,uint64_t wval,int size,void * arg)443d3956e46SJohn Baldwin vioapic_mmio_write(struct vcpu *vcpu, uint64_t gpa, uint64_t wval,
444565bbb86SNeel Natu int size, void *arg)
445565bbb86SNeel Natu {
446565bbb86SNeel Natu int error;
447565bbb86SNeel Natu struct vioapic *vioapic;
448565bbb86SNeel Natu
449d3956e46SJohn Baldwin vioapic = vm_ioapic(vcpu_vm(vcpu));
450d3956e46SJohn Baldwin error = vioapic_mmio_rw(vioapic, vcpu, gpa, &wval, size, false);
451565bbb86SNeel Natu return (error);
452565bbb86SNeel Natu }
453565bbb86SNeel Natu
454b5b28fc9SNeel Natu void
vioapic_process_eoi(struct vm * vm,int vector)455e42c24d5SJohn Baldwin vioapic_process_eoi(struct vm *vm, int vector)
456b5b28fc9SNeel Natu {
457b5b28fc9SNeel Natu struct vioapic *vioapic;
458b5b28fc9SNeel Natu int pin;
459b5b28fc9SNeel Natu
460b5b28fc9SNeel Natu KASSERT(vector >= 0 && vector < 256,
461b5b28fc9SNeel Natu ("vioapic_process_eoi: invalid vector %d", vector));
462b5b28fc9SNeel Natu
463b5b28fc9SNeel Natu vioapic = vm_ioapic(vm);
464b5b28fc9SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic processing eoi for vector %d", vector);
465b5b28fc9SNeel Natu
466b5b28fc9SNeel Natu /*
467b5b28fc9SNeel Natu * XXX keep track of the pins associated with this vector instead
468b5b28fc9SNeel Natu * of iterating on every single pin each time.
469b5b28fc9SNeel Natu */
470b5b28fc9SNeel Natu VIOAPIC_LOCK(vioapic);
471b5b28fc9SNeel Natu for (pin = 0; pin < REDIR_ENTRIES; pin++) {
472b5b28fc9SNeel Natu if ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0)
473b5b28fc9SNeel Natu continue;
474b5b28fc9SNeel Natu if ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector)
475b5b28fc9SNeel Natu continue;
476b5b28fc9SNeel Natu vioapic->rtbl[pin].reg &= ~IOART_REM_IRR;
477b5b28fc9SNeel Natu if (vioapic->rtbl[pin].acnt > 0) {
478b5b28fc9SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at eoi, "
479b5b28fc9SNeel Natu "acnt %d", pin, vioapic->rtbl[pin].acnt);
480b5b28fc9SNeel Natu vioapic_send_intr(vioapic, pin);
481b5b28fc9SNeel Natu }
482b5b28fc9SNeel Natu }
483b5b28fc9SNeel Natu VIOAPIC_UNLOCK(vioapic);
484b5b28fc9SNeel Natu }
485b5b28fc9SNeel Natu
486565bbb86SNeel Natu struct vioapic *
vioapic_init(struct vm * vm)487565bbb86SNeel Natu vioapic_init(struct vm *vm)
488565bbb86SNeel Natu {
489565bbb86SNeel Natu int i;
490565bbb86SNeel Natu struct vioapic *vioapic;
491565bbb86SNeel Natu
492565bbb86SNeel Natu vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO);
493565bbb86SNeel Natu
494565bbb86SNeel Natu vioapic->vm = vm;
4959c43cd07SNeel Natu mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_SPIN);
496565bbb86SNeel Natu
497565bbb86SNeel Natu /* Initialize all redirection entries to mask all interrupts */
498565bbb86SNeel Natu for (i = 0; i < REDIR_ENTRIES; i++)
499565bbb86SNeel Natu vioapic->rtbl[i].reg = 0x0001000000010000UL;
500565bbb86SNeel Natu
501565bbb86SNeel Natu return (vioapic);
502565bbb86SNeel Natu }
503565bbb86SNeel Natu
504565bbb86SNeel Natu void
vioapic_cleanup(struct vioapic * vioapic)505565bbb86SNeel Natu vioapic_cleanup(struct vioapic *vioapic)
506565bbb86SNeel Natu {
507565bbb86SNeel Natu
50808ebb360SJohn Baldwin mtx_destroy(&vioapic->mtx);
509565bbb86SNeel Natu free(vioapic, M_VIOAPIC);
510565bbb86SNeel Natu }
511b5b28fc9SNeel Natu
512b5b28fc9SNeel Natu int
vioapic_pincount(struct vm * vm)513b5b28fc9SNeel Natu vioapic_pincount(struct vm *vm)
514b5b28fc9SNeel Natu {
515b5b28fc9SNeel Natu
516b5b28fc9SNeel Natu return (REDIR_ENTRIES);
517b5b28fc9SNeel Natu }
518483d953aSJohn Baldwin
519483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
520483d953aSJohn Baldwin int
vioapic_snapshot(struct vioapic * vioapic,struct vm_snapshot_meta * meta)521483d953aSJohn Baldwin vioapic_snapshot(struct vioapic *vioapic, struct vm_snapshot_meta *meta)
522483d953aSJohn Baldwin {
523483d953aSJohn Baldwin int ret;
524483d953aSJohn Baldwin int i;
525483d953aSJohn Baldwin
526483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vioapic->ioregsel, meta, ret, done);
527483d953aSJohn Baldwin
528483d953aSJohn Baldwin for (i = 0; i < nitems(vioapic->rtbl); i++) {
529483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vioapic->rtbl[i].reg, meta, ret, done);
530483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vioapic->rtbl[i].acnt, meta, ret, done);
531483d953aSJohn Baldwin }
532483d953aSJohn Baldwin
533483d953aSJohn Baldwin done:
534483d953aSJohn Baldwin return (ret);
535483d953aSJohn Baldwin }
536483d953aSJohn Baldwin #endif
537