Deleted Added
full compact
vioapic.c (262350) vioapic.c (266339)
1/*-
2 * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3 * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
1/*-
2 * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3 * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: stable/10/sys/amd64/vmm/io/vioapic.c 262350 2014-02-23 00:46:05Z jhb $
27 * $FreeBSD: stable/10/sys/amd64/vmm/io/vioapic.c 266339 2014-05-17 19:11:08Z jhb $
28 */
29
30#include <sys/cdefs.h>
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/io/vioapic.c 262350 2014-02-23 00:46:05Z jhb $");
31__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/io/vioapic.c 266339 2014-05-17 19:11:08Z jhb $");
32
33#include <sys/param.h>
34#include <sys/queue.h>
35#include <sys/cpuset.h>
36#include <sys/lock.h>
37#include <sys/mutex.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41
42#include <x86/apicreg.h>
43#include <machine/vmm.h>
44
45#include "vmm_ktr.h"
46#include "vmm_lapic.h"
47#include "vlapic.h"
48#include "vioapic.h"
49
50#define IOREGSEL 0x00
51#define IOWIN 0x10
52
53#define REDIR_ENTRIES 24
54#define RTBL_RO_BITS ((uint64_t)(IOART_REM_IRR | IOART_DELIVS))
55
56struct vioapic {
57 struct vm *vm;
58 struct mtx mtx;
59 uint32_t id;
60 uint32_t ioregsel;
61 struct {
62 uint64_t reg;
63 int acnt; /* sum of pin asserts (+1) and deasserts (-1) */
64 } rtbl[REDIR_ENTRIES];
65};
66
67#define VIOAPIC_LOCK(vioapic) mtx_lock(&((vioapic)->mtx))
68#define VIOAPIC_UNLOCK(vioapic) mtx_unlock(&((vioapic)->mtx))
69#define VIOAPIC_LOCKED(vioapic) mtx_owned(&((vioapic)->mtx))
70
71static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic");
72
73#define VIOAPIC_CTR1(vioapic, fmt, a1) \
74 VM_CTR1((vioapic)->vm, fmt, a1)
75
76#define VIOAPIC_CTR2(vioapic, fmt, a1, a2) \
77 VM_CTR2((vioapic)->vm, fmt, a1, a2)
78
79#define VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3) \
80 VM_CTR3((vioapic)->vm, fmt, a1, a2, a3)
81
82#define VIOAPIC_CTR4(vioapic, fmt, a1, a2, a3, a4) \
83 VM_CTR4((vioapic)->vm, fmt, a1, a2, a3, a4)
84
85#ifdef KTR
86static const char *
87pinstate_str(bool asserted)
88{
89
90 if (asserted)
91 return ("asserted");
92 else
93 return ("deasserted");
94}
95#endif
96
97static void
98vioapic_send_intr(struct vioapic *vioapic, int pin)
99{
100 int vector, delmode;
101 uint32_t low, high, dest;
102 bool level, phys;
103
104 KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
105 ("vioapic_set_pinstate: invalid pin number %d", pin));
106
107 KASSERT(VIOAPIC_LOCKED(vioapic),
108 ("vioapic_set_pinstate: vioapic is not locked"));
109
110 low = vioapic->rtbl[pin].reg;
111 high = vioapic->rtbl[pin].reg >> 32;
112
113 if ((low & IOART_INTMASK) == IOART_INTMSET) {
114 VIOAPIC_CTR1(vioapic, "ioapic pin%d: masked", pin);
115 return;
116 }
117
118 phys = ((low & IOART_DESTMOD) == IOART_DESTPHY);
119 delmode = low & IOART_DELMOD;
120 level = low & IOART_TRGRLVL ? true : false;
121 if (level)
122 vioapic->rtbl[pin].reg |= IOART_REM_IRR;
123
124 vector = low & IOART_INTVEC;
125 dest = high >> APIC_ID_SHIFT;
126 vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector);
127}
128
129static void
130vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate)
131{
132 int oldcnt, newcnt;
133 bool needintr;
134
135 KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
136 ("vioapic_set_pinstate: invalid pin number %d", pin));
137
138 KASSERT(VIOAPIC_LOCKED(vioapic),
139 ("vioapic_set_pinstate: vioapic is not locked"));
140
141 oldcnt = vioapic->rtbl[pin].acnt;
142 if (newstate)
143 vioapic->rtbl[pin].acnt++;
144 else
145 vioapic->rtbl[pin].acnt--;
146 newcnt = vioapic->rtbl[pin].acnt;
147
148 if (newcnt < 0) {
149 VIOAPIC_CTR2(vioapic, "ioapic pin%d: bad acnt %d",
150 pin, newcnt);
151 }
152
153 needintr = false;
154 if (oldcnt == 0 && newcnt == 1) {
155 needintr = true;
156 VIOAPIC_CTR1(vioapic, "ioapic pin%d: asserted", pin);
157 } else if (oldcnt == 1 && newcnt == 0) {
158 VIOAPIC_CTR1(vioapic, "ioapic pin%d: deasserted", pin);
159 } else {
160 VIOAPIC_CTR3(vioapic, "ioapic pin%d: %s, ignored, acnt %d",
161 pin, pinstate_str(newstate), newcnt);
162 }
163
164 if (needintr)
165 vioapic_send_intr(vioapic, pin);
166}
167
168enum irqstate {
169 IRQSTATE_ASSERT,
170 IRQSTATE_DEASSERT,
171 IRQSTATE_PULSE
172};
173
174static int
175vioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
176{
177 struct vioapic *vioapic;
178
179 if (irq < 0 || irq >= REDIR_ENTRIES)
180 return (EINVAL);
181
182 vioapic = vm_ioapic(vm);
183
184 VIOAPIC_LOCK(vioapic);
185 switch (irqstate) {
186 case IRQSTATE_ASSERT:
187 vioapic_set_pinstate(vioapic, irq, true);
188 break;
189 case IRQSTATE_DEASSERT:
190 vioapic_set_pinstate(vioapic, irq, false);
191 break;
192 case IRQSTATE_PULSE:
193 vioapic_set_pinstate(vioapic, irq, true);
194 vioapic_set_pinstate(vioapic, irq, false);
195 break;
196 default:
197 panic("vioapic_set_irqstate: invalid irqstate %d", irqstate);
198 }
199 VIOAPIC_UNLOCK(vioapic);
200
201 return (0);
202}
203
204int
205vioapic_assert_irq(struct vm *vm, int irq)
206{
207
208 return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
209}
210
211int
212vioapic_deassert_irq(struct vm *vm, int irq)
213{
214
215 return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
216}
217
218int
219vioapic_pulse_irq(struct vm *vm, int irq)
220{
221
222 return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE));
223}
224
32
33#include <sys/param.h>
34#include <sys/queue.h>
35#include <sys/cpuset.h>
36#include <sys/lock.h>
37#include <sys/mutex.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41
42#include <x86/apicreg.h>
43#include <machine/vmm.h>
44
45#include "vmm_ktr.h"
46#include "vmm_lapic.h"
47#include "vlapic.h"
48#include "vioapic.h"
49
50#define IOREGSEL 0x00
51#define IOWIN 0x10
52
53#define REDIR_ENTRIES 24
54#define RTBL_RO_BITS ((uint64_t)(IOART_REM_IRR | IOART_DELIVS))
55
56struct vioapic {
57 struct vm *vm;
58 struct mtx mtx;
59 uint32_t id;
60 uint32_t ioregsel;
61 struct {
62 uint64_t reg;
63 int acnt; /* sum of pin asserts (+1) and deasserts (-1) */
64 } rtbl[REDIR_ENTRIES];
65};
66
67#define VIOAPIC_LOCK(vioapic) mtx_lock(&((vioapic)->mtx))
68#define VIOAPIC_UNLOCK(vioapic) mtx_unlock(&((vioapic)->mtx))
69#define VIOAPIC_LOCKED(vioapic) mtx_owned(&((vioapic)->mtx))
70
71static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic");
72
73#define VIOAPIC_CTR1(vioapic, fmt, a1) \
74 VM_CTR1((vioapic)->vm, fmt, a1)
75
76#define VIOAPIC_CTR2(vioapic, fmt, a1, a2) \
77 VM_CTR2((vioapic)->vm, fmt, a1, a2)
78
79#define VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3) \
80 VM_CTR3((vioapic)->vm, fmt, a1, a2, a3)
81
82#define VIOAPIC_CTR4(vioapic, fmt, a1, a2, a3, a4) \
83 VM_CTR4((vioapic)->vm, fmt, a1, a2, a3, a4)
84
85#ifdef KTR
86static const char *
87pinstate_str(bool asserted)
88{
89
90 if (asserted)
91 return ("asserted");
92 else
93 return ("deasserted");
94}
95#endif
96
97static void
98vioapic_send_intr(struct vioapic *vioapic, int pin)
99{
100 int vector, delmode;
101 uint32_t low, high, dest;
102 bool level, phys;
103
104 KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
105 ("vioapic_set_pinstate: invalid pin number %d", pin));
106
107 KASSERT(VIOAPIC_LOCKED(vioapic),
108 ("vioapic_set_pinstate: vioapic is not locked"));
109
110 low = vioapic->rtbl[pin].reg;
111 high = vioapic->rtbl[pin].reg >> 32;
112
113 if ((low & IOART_INTMASK) == IOART_INTMSET) {
114 VIOAPIC_CTR1(vioapic, "ioapic pin%d: masked", pin);
115 return;
116 }
117
118 phys = ((low & IOART_DESTMOD) == IOART_DESTPHY);
119 delmode = low & IOART_DELMOD;
120 level = low & IOART_TRGRLVL ? true : false;
121 if (level)
122 vioapic->rtbl[pin].reg |= IOART_REM_IRR;
123
124 vector = low & IOART_INTVEC;
125 dest = high >> APIC_ID_SHIFT;
126 vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector);
127}
128
129static void
130vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate)
131{
132 int oldcnt, newcnt;
133 bool needintr;
134
135 KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
136 ("vioapic_set_pinstate: invalid pin number %d", pin));
137
138 KASSERT(VIOAPIC_LOCKED(vioapic),
139 ("vioapic_set_pinstate: vioapic is not locked"));
140
141 oldcnt = vioapic->rtbl[pin].acnt;
142 if (newstate)
143 vioapic->rtbl[pin].acnt++;
144 else
145 vioapic->rtbl[pin].acnt--;
146 newcnt = vioapic->rtbl[pin].acnt;
147
148 if (newcnt < 0) {
149 VIOAPIC_CTR2(vioapic, "ioapic pin%d: bad acnt %d",
150 pin, newcnt);
151 }
152
153 needintr = false;
154 if (oldcnt == 0 && newcnt == 1) {
155 needintr = true;
156 VIOAPIC_CTR1(vioapic, "ioapic pin%d: asserted", pin);
157 } else if (oldcnt == 1 && newcnt == 0) {
158 VIOAPIC_CTR1(vioapic, "ioapic pin%d: deasserted", pin);
159 } else {
160 VIOAPIC_CTR3(vioapic, "ioapic pin%d: %s, ignored, acnt %d",
161 pin, pinstate_str(newstate), newcnt);
162 }
163
164 if (needintr)
165 vioapic_send_intr(vioapic, pin);
166}
167
168enum irqstate {
169 IRQSTATE_ASSERT,
170 IRQSTATE_DEASSERT,
171 IRQSTATE_PULSE
172};
173
174static int
175vioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
176{
177 struct vioapic *vioapic;
178
179 if (irq < 0 || irq >= REDIR_ENTRIES)
180 return (EINVAL);
181
182 vioapic = vm_ioapic(vm);
183
184 VIOAPIC_LOCK(vioapic);
185 switch (irqstate) {
186 case IRQSTATE_ASSERT:
187 vioapic_set_pinstate(vioapic, irq, true);
188 break;
189 case IRQSTATE_DEASSERT:
190 vioapic_set_pinstate(vioapic, irq, false);
191 break;
192 case IRQSTATE_PULSE:
193 vioapic_set_pinstate(vioapic, irq, true);
194 vioapic_set_pinstate(vioapic, irq, false);
195 break;
196 default:
197 panic("vioapic_set_irqstate: invalid irqstate %d", irqstate);
198 }
199 VIOAPIC_UNLOCK(vioapic);
200
201 return (0);
202}
203
204int
205vioapic_assert_irq(struct vm *vm, int irq)
206{
207
208 return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
209}
210
211int
212vioapic_deassert_irq(struct vm *vm, int irq)
213{
214
215 return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
216}
217
218int
219vioapic_pulse_irq(struct vm *vm, int irq)
220{
221
222 return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE));
223}
224
225/*
226 * Reset the vlapic's trigger-mode register to reflect the ioapic pin
227 * configuration.
228 */
229static void
230vioapic_update_tmr(struct vm *vm, int vcpuid, void *arg)
231{
232 struct vioapic *vioapic;
233 struct vlapic *vlapic;
234 uint32_t low, high, dest;
235 int delmode, pin, vector;
236 bool level, phys;
237
238 vlapic = vm_lapic(vm, vcpuid);
239 vioapic = vm_ioapic(vm);
240
241 VIOAPIC_LOCK(vioapic);
242 /*
243 * Reset all vectors to be edge-triggered.
244 */
245 vlapic_reset_tmr(vlapic);
246 for (pin = 0; pin < REDIR_ENTRIES; pin++) {
247 low = vioapic->rtbl[pin].reg;
248 high = vioapic->rtbl[pin].reg >> 32;
249
250 level = low & IOART_TRGRLVL ? true : false;
251 if (!level)
252 continue;
253
254 /*
255 * For a level-triggered 'pin' let the vlapic figure out if
256 * an assertion on this 'pin' would result in an interrupt
257 * being delivered to it. If yes, then it will modify the
258 * TMR bit associated with this vector to level-triggered.
259 */
260 phys = ((low & IOART_DESTMOD) == IOART_DESTPHY);
261 delmode = low & IOART_DELMOD;
262 vector = low & IOART_INTVEC;
263 dest = high >> APIC_ID_SHIFT;
264 vlapic_set_tmr_level(vlapic, dest, phys, delmode, vector);
265 }
266 VIOAPIC_UNLOCK(vioapic);
267}
268
225static uint32_t
269static uint32_t
226vioapic_read(struct vioapic *vioapic, uint32_t addr)
270vioapic_read(struct vioapic *vioapic, int vcpuid, uint32_t addr)
227{
228 int regnum, pin, rshift;
229
230 regnum = addr & 0xff;
231 switch (regnum) {
232 case IOAPIC_ID:
233 return (vioapic->id);
234 break;
235 case IOAPIC_VER:
236 return (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11);
237 break;
238 case IOAPIC_ARB:
239 return (vioapic->id);
240 break;
241 default:
242 break;
243 }
244
245 /* redirection table entries */
246 if (regnum >= IOAPIC_REDTBL &&
247 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
248 pin = (regnum - IOAPIC_REDTBL) / 2;
249 if ((regnum - IOAPIC_REDTBL) % 2)
250 rshift = 32;
251 else
252 rshift = 0;
253
254 return (vioapic->rtbl[pin].reg >> rshift);
255 }
256
257 return (0);
258}
259
260static void
271{
272 int regnum, pin, rshift;
273
274 regnum = addr & 0xff;
275 switch (regnum) {
276 case IOAPIC_ID:
277 return (vioapic->id);
278 break;
279 case IOAPIC_VER:
280 return (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11);
281 break;
282 case IOAPIC_ARB:
283 return (vioapic->id);
284 break;
285 default:
286 break;
287 }
288
289 /* redirection table entries */
290 if (regnum >= IOAPIC_REDTBL &&
291 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
292 pin = (regnum - IOAPIC_REDTBL) / 2;
293 if ((regnum - IOAPIC_REDTBL) % 2)
294 rshift = 32;
295 else
296 rshift = 0;
297
298 return (vioapic->rtbl[pin].reg >> rshift);
299 }
300
301 return (0);
302}
303
304static void
261vioapic_write(struct vioapic *vioapic, uint32_t addr, uint32_t data)
305vioapic_write(struct vioapic *vioapic, int vcpuid, uint32_t addr, uint32_t data)
262{
263 uint64_t data64, mask64;
306{
307 uint64_t data64, mask64;
308 uint64_t last, changed;
264 int regnum, pin, lshift;
309 int regnum, pin, lshift;
310 cpuset_t allvcpus;
265
266 regnum = addr & 0xff;
267 switch (regnum) {
268 case IOAPIC_ID:
269 vioapic->id = data & APIC_ID_MASK;
270 break;
271 case IOAPIC_VER:
272 case IOAPIC_ARB:
273 /* readonly */
274 break;
275 default:
276 break;
277 }
278
279 /* redirection table entries */
280 if (regnum >= IOAPIC_REDTBL &&
281 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
282 pin = (regnum - IOAPIC_REDTBL) / 2;
283 if ((regnum - IOAPIC_REDTBL) % 2)
284 lshift = 32;
285 else
286 lshift = 0;
287
311
312 regnum = addr & 0xff;
313 switch (regnum) {
314 case IOAPIC_ID:
315 vioapic->id = data & APIC_ID_MASK;
316 break;
317 case IOAPIC_VER:
318 case IOAPIC_ARB:
319 /* readonly */
320 break;
321 default:
322 break;
323 }
324
325 /* redirection table entries */
326 if (regnum >= IOAPIC_REDTBL &&
327 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
328 pin = (regnum - IOAPIC_REDTBL) / 2;
329 if ((regnum - IOAPIC_REDTBL) % 2)
330 lshift = 32;
331 else
332 lshift = 0;
333
334 last = vioapic->rtbl[pin].reg;
335
288 data64 = (uint64_t)data << lshift;
289 mask64 = (uint64_t)0xffffffff << lshift;
290 vioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS;
291 vioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS;
292
293 VIOAPIC_CTR2(vioapic, "ioapic pin%d: redir table entry %#lx",
294 pin, vioapic->rtbl[pin].reg);
295
296 /*
336 data64 = (uint64_t)data << lshift;
337 mask64 = (uint64_t)0xffffffff << lshift;
338 vioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS;
339 vioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS;
340
341 VIOAPIC_CTR2(vioapic, "ioapic pin%d: redir table entry %#lx",
342 pin, vioapic->rtbl[pin].reg);
343
344 /*
345 * If any fields in the redirection table entry (except mask
346 * or polarity) have changed then rendezvous all the vcpus
347 * to update their vlapic trigger-mode registers.
348 */
349 changed = last ^ vioapic->rtbl[pin].reg;
350 if (changed & ~(IOART_INTMASK | IOART_INTPOL)) {
351 VIOAPIC_CTR1(vioapic, "ioapic pin%d: recalculate "
352 "vlapic trigger-mode register", pin);
353 VIOAPIC_UNLOCK(vioapic);
354 allvcpus = vm_active_cpus(vioapic->vm);
355 vm_smp_rendezvous(vioapic->vm, vcpuid, allvcpus,
356 vioapic_update_tmr, NULL);
357 VIOAPIC_LOCK(vioapic);
358 }
359
360 /*
297 * Generate an interrupt if the following conditions are met:
298 * - pin is not masked
299 * - previous interrupt has been EOIed
300 * - pin level is asserted
301 */
302 if ((vioapic->rtbl[pin].reg & IOART_INTMASK) == IOART_INTMCLR &&
303 (vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0 &&
304 (vioapic->rtbl[pin].acnt > 0)) {
305 VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at rtbl "
306 "write, acnt %d", pin, vioapic->rtbl[pin].acnt);
307 vioapic_send_intr(vioapic, pin);
308 }
309 }
310}
311
312static int
361 * Generate an interrupt if the following conditions are met:
362 * - pin is not masked
363 * - previous interrupt has been EOIed
364 * - pin level is asserted
365 */
366 if ((vioapic->rtbl[pin].reg & IOART_INTMASK) == IOART_INTMCLR &&
367 (vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0 &&
368 (vioapic->rtbl[pin].acnt > 0)) {
369 VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at rtbl "
370 "write, acnt %d", pin, vioapic->rtbl[pin].acnt);
371 vioapic_send_intr(vioapic, pin);
372 }
373 }
374}
375
376static int
313vioapic_mmio_rw(struct vioapic *vioapic, uint64_t gpa, uint64_t *data,
314 int size, bool doread)
377vioapic_mmio_rw(struct vioapic *vioapic, int vcpuid, uint64_t gpa,
378 uint64_t *data, int size, bool doread)
315{
316 uint64_t offset;
317
318 offset = gpa - VIOAPIC_BASE;
319
320 /*
321 * The IOAPIC specification allows 32-bit wide accesses to the
322 * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
323 */
324 if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
325 if (doread)
326 *data = 0;
327 return (0);
328 }
329
330 VIOAPIC_LOCK(vioapic);
331 if (offset == IOREGSEL) {
332 if (doread)
333 *data = vioapic->ioregsel;
334 else
335 vioapic->ioregsel = *data;
336 } else {
379{
380 uint64_t offset;
381
382 offset = gpa - VIOAPIC_BASE;
383
384 /*
385 * The IOAPIC specification allows 32-bit wide accesses to the
386 * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
387 */
388 if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
389 if (doread)
390 *data = 0;
391 return (0);
392 }
393
394 VIOAPIC_LOCK(vioapic);
395 if (offset == IOREGSEL) {
396 if (doread)
397 *data = vioapic->ioregsel;
398 else
399 vioapic->ioregsel = *data;
400 } else {
337 if (doread)
338 *data = vioapic_read(vioapic, vioapic->ioregsel);
339 else
340 vioapic_write(vioapic, vioapic->ioregsel, *data);
401 if (doread) {
402 *data = vioapic_read(vioapic, vcpuid,
403 vioapic->ioregsel);
404 } else {
405 vioapic_write(vioapic, vcpuid, vioapic->ioregsel,
406 *data);
407 }
341 }
342 VIOAPIC_UNLOCK(vioapic);
343
344 return (0);
345}
346
347int
348vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval,
349 int size, void *arg)
350{
351 int error;
352 struct vioapic *vioapic;
353
354 vioapic = vm_ioapic(vm);
408 }
409 VIOAPIC_UNLOCK(vioapic);
410
411 return (0);
412}
413
414int
415vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval,
416 int size, void *arg)
417{
418 int error;
419 struct vioapic *vioapic;
420
421 vioapic = vm_ioapic(vm);
355 error = vioapic_mmio_rw(vioapic, gpa, rval, size, true);
422 error = vioapic_mmio_rw(vioapic, vcpuid, gpa, rval, size, true);
356 return (error);
357}
358
359int
360vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval,
361 int size, void *arg)
362{
363 int error;
364 struct vioapic *vioapic;
365
366 vioapic = vm_ioapic(vm);
423 return (error);
424}
425
426int
427vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval,
428 int size, void *arg)
429{
430 int error;
431 struct vioapic *vioapic;
432
433 vioapic = vm_ioapic(vm);
367 error = vioapic_mmio_rw(vioapic, gpa, &wval, size, false);
434 error = vioapic_mmio_rw(vioapic, vcpuid, gpa, &wval, size, false);
368 return (error);
369}
370
371void
372vioapic_process_eoi(struct vm *vm, int vcpuid, int vector)
373{
374 struct vioapic *vioapic;
375 int pin;
376
377 KASSERT(vector >= 0 && vector < 256,
378 ("vioapic_process_eoi: invalid vector %d", vector));
379
380 vioapic = vm_ioapic(vm);
381 VIOAPIC_CTR1(vioapic, "ioapic processing eoi for vector %d", vector);
382
383 /*
384 * XXX keep track of the pins associated with this vector instead
385 * of iterating on every single pin each time.
386 */
387 VIOAPIC_LOCK(vioapic);
388 for (pin = 0; pin < REDIR_ENTRIES; pin++) {
389 if ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0)
390 continue;
391 if ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector)
392 continue;
393 vioapic->rtbl[pin].reg &= ~IOART_REM_IRR;
394 if (vioapic->rtbl[pin].acnt > 0) {
395 VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at eoi, "
396 "acnt %d", pin, vioapic->rtbl[pin].acnt);
397 vioapic_send_intr(vioapic, pin);
398 }
399 }
400 VIOAPIC_UNLOCK(vioapic);
401}
402
403struct vioapic *
404vioapic_init(struct vm *vm)
405{
406 int i;
407 struct vioapic *vioapic;
408
409 vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO);
410
411 vioapic->vm = vm;
412 mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_DEF);
413
414 /* Initialize all redirection entries to mask all interrupts */
415 for (i = 0; i < REDIR_ENTRIES; i++)
416 vioapic->rtbl[i].reg = 0x0001000000010000UL;
417
418 return (vioapic);
419}
420
421void
422vioapic_cleanup(struct vioapic *vioapic)
423{
424
425 free(vioapic, M_VIOAPIC);
426}
427
428int
429vioapic_pincount(struct vm *vm)
430{
431
432 return (REDIR_ENTRIES);
433}
435 return (error);
436}
437
438void
439vioapic_process_eoi(struct vm *vm, int vcpuid, int vector)
440{
441 struct vioapic *vioapic;
442 int pin;
443
444 KASSERT(vector >= 0 && vector < 256,
445 ("vioapic_process_eoi: invalid vector %d", vector));
446
447 vioapic = vm_ioapic(vm);
448 VIOAPIC_CTR1(vioapic, "ioapic processing eoi for vector %d", vector);
449
450 /*
451 * XXX keep track of the pins associated with this vector instead
452 * of iterating on every single pin each time.
453 */
454 VIOAPIC_LOCK(vioapic);
455 for (pin = 0; pin < REDIR_ENTRIES; pin++) {
456 if ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0)
457 continue;
458 if ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector)
459 continue;
460 vioapic->rtbl[pin].reg &= ~IOART_REM_IRR;
461 if (vioapic->rtbl[pin].acnt > 0) {
462 VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at eoi, "
463 "acnt %d", pin, vioapic->rtbl[pin].acnt);
464 vioapic_send_intr(vioapic, pin);
465 }
466 }
467 VIOAPIC_UNLOCK(vioapic);
468}
469
470struct vioapic *
471vioapic_init(struct vm *vm)
472{
473 int i;
474 struct vioapic *vioapic;
475
476 vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO);
477
478 vioapic->vm = vm;
479 mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_DEF);
480
481 /* Initialize all redirection entries to mask all interrupts */
482 for (i = 0; i < REDIR_ENTRIES; i++)
483 vioapic->rtbl[i].reg = 0x0001000000010000UL;
484
485 return (vioapic);
486}
487
488void
489vioapic_cleanup(struct vioapic *vioapic)
490{
491
492 free(vioapic, M_VIOAPIC);
493}
494
495int
496vioapic_pincount(struct vm *vm)
497{
498
499 return (REDIR_ENTRIES);
500}