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>
45 #include "instruction_emul.h"
50 #define IOAPIC_PADDR 0xFEC00000
55 #define REDIR_ENTRIES 16
56 #define INTR_ASSERTED(ioapic, pin) ((ioapic)->pinstate[(pin)] == true)
61 uint64_t redtbl[REDIR_ENTRIES];
62 bool pinstate[REDIR_ENTRIES];
64 uintptr_t paddr; /* gpa where the ioapic is mapped */
66 struct memory_region *region;
69 static struct ioapic ioapics[1]; /* only a single ioapic for now */
71 static int ioapic_region_read(struct ioapic *ioapic, uintptr_t paddr,
72 int size, uint64_t *data);
73 static int ioapic_region_write(struct ioapic *ioapic, uintptr_t paddr,
74 int size, uint64_t data);
75 static int ioapic_region_handler(struct vmctx *vm, int vcpu, int dir,
76 uintptr_t paddr, int size, uint64_t *val,
77 void *arg1, long arg2);
80 ioapic_set_pinstate(struct vmctx *ctx, int pin, bool newstate)
82 int vector, apicid, vcpu;
84 struct ioapic *ioapic;
86 ioapic = &ioapics[0]; /* assume a single ioapic */
88 if (pin < 0 || pin >= REDIR_ENTRIES)
91 /* Nothing to do if interrupt pin has not changed state */
92 if (ioapic->pinstate[pin] == newstate)
95 ioapic->pinstate[pin] = newstate; /* record it */
97 /* Nothing to do if interrupt pin is deasserted */
98 if (!INTR_ASSERTED(ioapic, pin))
104 * - edge triggered interrupts
105 * - physical destination mode
106 * - fixed delivery mode
108 low = ioapic->redtbl[pin];
109 high = ioapic->redtbl[pin] >> 32;
110 if ((low & IOART_INTMASK) == IOART_INTMCLR &&
111 (low & IOART_TRGRMOD) == IOART_TRGREDG &&
112 (low & IOART_DESTMOD) == IOART_DESTPHY &&
113 (low & IOART_DELMOD) == IOART_DELFIXED) {
114 vector = low & IOART_INTVEC;
115 apicid = high >> APIC_ID_SHIFT;
116 if (apicid != 0xff) {
118 vcpu = vm_apicid2vcpu(ctx, apicid);
119 vm_lapic_irq(ctx, vcpu, vector);
123 while (vcpu < guest_ncpus) {
124 vm_lapic_irq(ctx, vcpu, vector);
132 ioapic_deassert_pin(struct vmctx *ctx, int pin)
134 ioapic_set_pinstate(ctx, pin, false);
138 ioapic_assert_pin(struct vmctx *ctx, int pin)
140 ioapic_set_pinstate(ctx, pin, true);
144 ioapic_init(int which)
146 struct mem_range memp;
147 struct ioapic *ioapic;
153 ioapic = &ioapics[which];
154 assert(ioapic->inited == 0);
156 bzero(ioapic, sizeof(struct ioapic));
158 /* Initialize all redirection entries to mask all interrupts */
159 for (i = 0; i < REDIR_ENTRIES; i++)
160 ioapic->redtbl[i] = 0x0001000000010000UL;
162 ioapic->paddr = IOAPIC_PADDR;
164 /* Register emulated memory region */
165 memp.name = "ioapic";
166 memp.flags = MEM_F_RW;
167 memp.handler = ioapic_region_handler;
170 memp.base = ioapic->paddr;
171 memp.size = sizeof(struct IOAPIC);
172 error = register_mem(&memp);
180 ioapic_read(struct ioapic *ioapic, uint32_t addr)
182 int regnum, pin, rshift;
184 assert(ioapic->inited);
186 regnum = addr & 0xff;
192 return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11);
201 /* redirection table entries */
202 if (regnum >= IOAPIC_REDTBL &&
203 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
204 pin = (regnum - IOAPIC_REDTBL) / 2;
205 if ((regnum - IOAPIC_REDTBL) % 2)
210 return (ioapic->redtbl[pin] >> rshift);
217 ioapic_write(struct ioapic *ioapic, uint32_t addr, uint32_t data)
219 int regnum, pin, lshift;
221 assert(ioapic->inited);
223 regnum = addr & 0xff;
226 ioapic->id = data & APIC_ID_MASK;
236 /* redirection table entries */
237 if (regnum >= IOAPIC_REDTBL &&
238 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
239 pin = (regnum - IOAPIC_REDTBL) / 2;
240 if ((regnum - IOAPIC_REDTBL) % 2)
245 ioapic->redtbl[pin] &= ~((uint64_t)0xffffffff << lshift);
246 ioapic->redtbl[pin] |= ((uint64_t)data << lshift);
251 ioapic_region_read(struct ioapic *ioapic, uintptr_t paddr, int size,
256 offset = paddr - ioapic->paddr;
259 * The IOAPIC specification allows 32-bit wide accesses to the
260 * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
262 if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
264 printf("invalid access to ioapic%d: size %d, offset %d\n",
265 (int)(ioapic - ioapics), size, offset);
271 if (offset == IOREGSEL)
272 *data = ioapic->ioregsel;
274 *data = ioapic_read(ioapic, ioapic->ioregsel);
280 ioapic_region_write(struct ioapic *ioapic, uintptr_t paddr, int size,
285 offset = paddr - ioapic->paddr;
288 * The ioapic specification allows 32-bit wide accesses to the
289 * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
291 if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
293 printf("invalid access to ioapic%d: size %d, offset %d\n",
294 (int)(ioapic - ioapics), size, offset);
299 if (offset == IOREGSEL)
300 ioapic->ioregsel = data;
302 ioapic_write(ioapic, ioapic->ioregsel, data);
308 ioapic_region_handler(struct vmctx *vm, int vcpu, int dir, uintptr_t paddr,
309 int size, uint64_t *val, void *arg1, long arg2)
311 struct ioapic *ioapic;
317 assert(ioapic == &ioapics[which]);
319 if (dir == MEM_F_READ)
320 ioapic_region_read(ioapic, paddr, size, val);
322 ioapic_region_write(ioapic, paddr, size, *val);