2 * Copyright (c) 2012 NetApp, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/types.h>
34 #include <x86/apicreg.h>
35 #include <machine/vmm.h>
50 static uint64_t ioapic_clearpend, ioapic_togglepend, ioapic_setpend;
52 #define IOAPIC_PADDR 0xFEC00000
57 #define REDIR_ENTRIES 16
58 #define INTR_ASSERTED(ioapic, pin) \
59 ((ioapic)->rtbl[(pin)].pinstate == true)
68 } rtbl[REDIR_ENTRIES];
70 uintptr_t paddr; /* gpa where the ioapic is mapped */
72 struct memory_region *region;
76 static struct ioapic ioapics[1]; /* only a single ioapic for now */
78 static int ioapic_region_read(struct vmctx *vm, struct ioapic *ioapic,
79 uintptr_t paddr, int size, uint64_t *data);
80 static int ioapic_region_write(struct vmctx *vm, struct ioapic *ioapic,
81 uintptr_t paddr, int size, uint64_t data);
82 static int ioapic_region_handler(struct vmctx *vm, int vcpu, int dir,
83 uintptr_t paddr, int size, uint64_t *val, void *arg1, long arg2);
86 ioapic_set_pinstate(struct vmctx *ctx, int pin, bool newstate)
88 int vector, apicid, vcpu;
90 struct ioapic *ioapic;
92 ioapic = &ioapics[0]; /* assume a single ioapic */
94 /* Nothing to do if interrupt pin has not changed state */
95 if (ioapic->rtbl[pin].pinstate == newstate)
98 ioapic->rtbl[pin].pinstate = newstate; /* record it */
100 /* Nothing to do if interrupt pin is deasserted */
101 if (!INTR_ASSERTED(ioapic, pin))
107 * - edge triggered interrupts
108 * - fixed delivery mode
109 * Level-triggered sources will work so long as there is
112 low = ioapic->rtbl[pin].reg;
113 high = ioapic->rtbl[pin].reg >> 32;
114 if ((low & IOART_INTMASK) == IOART_INTMCLR &&
115 (low & IOART_DESTMOD) == IOART_DESTPHY &&
116 (low & IOART_DELMOD) == IOART_DELFIXED) {
117 vector = low & IOART_INTVEC;
118 apicid = high >> APIC_ID_SHIFT;
119 if (apicid != 0xff) {
121 vcpu = vm_apicid2vcpu(ctx, apicid);
122 vm_lapic_irq(ctx, vcpu, vector);
126 while (vcpu < guest_ncpus) {
127 vm_lapic_irq(ctx, vcpu, vector);
131 } else if ((low & IOART_INTMASK) != IOART_INTMCLR &&
132 low & IOART_TRGRLVL) {
134 * For level-triggered interrupts that have been
135 * masked, set the pending bit so that an interrupt
136 * will be generated on unmask and if the level is
140 ioapic->rtbl[pin].pending = true;
145 ioapic_set_pinstate_locked(struct vmctx *ctx, int pin, bool newstate)
147 struct ioapic *ioapic;
149 if (pin < 0 || pin >= REDIR_ENTRIES)
152 ioapic = &ioapics[0];
154 pthread_mutex_lock(&ioapic->mtx);
155 ioapic_set_pinstate(ctx, pin, newstate);
156 pthread_mutex_unlock(&ioapic->mtx);
160 * External entry points require locking
163 ioapic_deassert_pin(struct vmctx *ctx, int pin)
165 ioapic_set_pinstate_locked(ctx, pin, false);
169 ioapic_assert_pin(struct vmctx *ctx, int pin)
171 ioapic_set_pinstate_locked(ctx, pin, true);
175 ioapic_init(int which)
177 struct mem_range memp;
178 struct ioapic *ioapic;
184 ioapic = &ioapics[which];
185 assert(ioapic->inited == 0);
187 bzero(ioapic, sizeof(struct ioapic));
189 pthread_mutex_init(&ioapic->mtx, NULL);
191 /* Initialize all redirection entries to mask all interrupts */
192 for (i = 0; i < REDIR_ENTRIES; i++)
193 ioapic->rtbl[i].reg = 0x0001000000010000UL;
195 ioapic->paddr = IOAPIC_PADDR;
197 /* Register emulated memory region */
198 memp.name = "ioapic";
199 memp.flags = MEM_F_RW;
200 memp.handler = ioapic_region_handler;
203 memp.base = ioapic->paddr;
204 memp.size = sizeof(struct IOAPIC);
205 error = register_mem(&memp);
213 ioapic_read(struct ioapic *ioapic, uint32_t addr)
215 int regnum, pin, rshift;
217 assert(ioapic->inited);
219 regnum = addr & 0xff;
225 return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11);
234 /* redirection table entries */
235 if (regnum >= IOAPIC_REDTBL &&
236 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
237 pin = (regnum - IOAPIC_REDTBL) / 2;
238 if ((regnum - IOAPIC_REDTBL) % 2)
243 return (ioapic->rtbl[pin].reg >> rshift);
250 ioapic_write(struct vmctx *vm, struct ioapic *ioapic, uint32_t addr,
253 int regnum, pin, lshift;
255 assert(ioapic->inited);
257 regnum = addr & 0xff;
260 ioapic->id = data & APIC_ID_MASK;
270 /* redirection table entries */
271 if (regnum >= IOAPIC_REDTBL &&
272 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
273 pin = (regnum - IOAPIC_REDTBL) / 2;
274 if ((regnum - IOAPIC_REDTBL) % 2)
279 ioapic->rtbl[pin].reg &= ~((uint64_t)0xffffffff << lshift);
280 ioapic->rtbl[pin].reg |= ((uint64_t)data << lshift);
282 if (ioapic->rtbl[pin].pending &&
283 ((ioapic->rtbl[pin].reg & IOART_INTMASK) ==
285 ioapic->rtbl[pin].pending = false;
288 * Inject the deferred level-triggered int if it is
289 * still asserted. Simulate by toggling the pin
292 if (ioapic->rtbl[pin].pinstate == true) {
294 ioapic_set_pinstate(vm, pin, false);
295 ioapic_set_pinstate(vm, pin, true);
302 ioapic_region_read(struct vmctx *vm, struct ioapic *ioapic, uintptr_t paddr,
303 int size, uint64_t *data)
307 offset = paddr - ioapic->paddr;
310 * The IOAPIC specification allows 32-bit wide accesses to the
311 * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
313 if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
315 printf("invalid access to ioapic%d: size %d, offset %d\n",
316 (int)(ioapic - ioapics), size, offset);
322 if (offset == IOREGSEL)
323 *data = ioapic->ioregsel;
325 *data = ioapic_read(ioapic, ioapic->ioregsel);
331 ioapic_region_write(struct vmctx *vm, struct ioapic *ioapic, uintptr_t paddr,
332 int size, uint64_t data)
336 offset = paddr - ioapic->paddr;
339 * The ioapic specification allows 32-bit wide accesses to the
340 * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
342 if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
344 printf("invalid access to ioapic%d: size %d, offset %d\n",
345 (int)(ioapic - ioapics), size, offset);
350 if (offset == IOREGSEL)
351 ioapic->ioregsel = data;
353 ioapic_write(vm, ioapic, ioapic->ioregsel, data);
359 ioapic_region_handler(struct vmctx *vm, int vcpu, int dir, uintptr_t paddr,
360 int size, uint64_t *val, void *arg1, long arg2)
362 struct ioapic *ioapic;
368 assert(ioapic == &ioapics[which]);
370 pthread_mutex_lock(&ioapic->mtx);
371 if (dir == MEM_F_READ)
372 ioapic_region_read(vm, ioapic, paddr, size, val);
374 ioapic_region_write(vm, ioapic, paddr, size, *val);
375 pthread_mutex_unlock(&ioapic->mtx);