]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/bhyve/ioapic.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / usr.sbin / bhyve / ioapic.c
1 /*-
2  * Copyright (c) 2012 NetApp, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/types.h>
33
34 #include <x86/apicreg.h>
35 #include <machine/vmm.h>
36
37 #include <string.h>
38 #include <assert.h>
39 #include <stdbool.h>
40
41 #include <vmmapi.h>
42
43 #include "inout.h"
44 #include "mem.h"
45 #include "bhyverun.h"
46
47 #include <stdio.h>
48
49 #define IOAPIC_PADDR    0xFEC00000
50
51 #define IOREGSEL        0x00
52 #define IOWIN           0x10
53
54 #define REDIR_ENTRIES   16
55 #define INTR_ASSERTED(ioapic, pin)      ((ioapic)->pinstate[(pin)] == true)
56
57 struct ioapic {
58         int             inited;
59         uint32_t        id;
60         uint64_t        redtbl[REDIR_ENTRIES];
61         bool            pinstate[REDIR_ENTRIES];
62
63         uintptr_t       paddr;          /* gpa where the ioapic is mapped */
64         uint32_t        ioregsel;
65         struct memory_region *region;
66 };
67
68 static struct ioapic ioapics[1];        /* only a single ioapic for now */
69
70 static int ioapic_region_read(struct ioapic *ioapic, uintptr_t paddr,
71                                 int size, uint64_t *data);
72 static int ioapic_region_write(struct ioapic *ioapic, uintptr_t paddr,
73                                 int size, uint64_t data);
74 static int ioapic_region_handler(struct vmctx *vm, int vcpu, int dir,
75                                  uintptr_t paddr, int size, uint64_t *val,
76                                  void *arg1, long arg2);
77
78 static void
79 ioapic_set_pinstate(struct vmctx *ctx, int pin, bool newstate)
80 {
81         int vector, apicid, vcpu;
82         uint32_t low, high;
83         struct ioapic *ioapic;
84         
85         ioapic = &ioapics[0];           /* assume a single ioapic */
86
87         if (pin < 0 || pin >= REDIR_ENTRIES)
88                 return;
89
90         /* Nothing to do if interrupt pin has not changed state */
91         if (ioapic->pinstate[pin] == newstate)
92                 return;
93
94         ioapic->pinstate[pin] = newstate;       /* record it */
95
96         /* Nothing to do if interrupt pin is deasserted */
97         if (!INTR_ASSERTED(ioapic, pin))
98                 return;
99
100         /*
101          * XXX
102          * We only deal with:
103          * - edge triggered interrupts
104          * - fixed delivery mode
105          *  Level-triggered sources will work so long as there is
106          * no sharing.
107          */
108         low = ioapic->redtbl[pin];
109         high = ioapic->redtbl[pin] >> 32;
110         if ((low & IOART_INTMASK) == IOART_INTMCLR &&
111             (low & IOART_DESTMOD) == IOART_DESTPHY &&
112             (low & IOART_DELMOD) == IOART_DELFIXED) {
113                 vector = low & IOART_INTVEC;
114                 apicid = high >> APIC_ID_SHIFT;
115                 if (apicid != 0xff) {
116                         /* unicast */
117                         vcpu = vm_apicid2vcpu(ctx, apicid);
118                         vm_lapic_irq(ctx, vcpu, vector);
119                 } else {
120                         /* broadcast */
121                         vcpu = 0;
122                         while (vcpu < guest_ncpus) {
123                                 vm_lapic_irq(ctx, vcpu, vector);
124                                 vcpu++;
125                         }
126                 }
127         }
128 }
129
130 void
131 ioapic_deassert_pin(struct vmctx *ctx, int pin)
132 {
133         ioapic_set_pinstate(ctx, pin, false);
134 }
135
136 void
137 ioapic_assert_pin(struct vmctx *ctx, int pin)
138 {
139         ioapic_set_pinstate(ctx, pin, true);
140 }
141
142 void
143 ioapic_init(int which)
144 {
145         struct mem_range memp;
146         struct ioapic *ioapic;
147         int error;
148         int i;
149
150         assert(which == 0);
151
152         ioapic = &ioapics[which];
153         assert(ioapic->inited == 0);
154
155         bzero(ioapic, sizeof(struct ioapic));
156
157         /* Initialize all redirection entries to mask all interrupts */
158         for (i = 0; i < REDIR_ENTRIES; i++)
159                 ioapic->redtbl[i] = 0x0001000000010000UL;
160
161         ioapic->paddr = IOAPIC_PADDR;
162
163         /* Register emulated memory region */
164         memp.name = "ioapic";
165         memp.flags = MEM_F_RW;
166         memp.handler = ioapic_region_handler;
167         memp.arg1 = ioapic;
168         memp.arg2 = which;
169         memp.base = ioapic->paddr;
170         memp.size = sizeof(struct IOAPIC);
171         error = register_mem(&memp);
172
173         assert (error == 0);
174
175         ioapic->inited = 1;
176 }
177
178 static uint32_t
179 ioapic_read(struct ioapic *ioapic, uint32_t addr)
180 {
181         int regnum, pin, rshift;
182
183         assert(ioapic->inited);
184
185         regnum = addr & 0xff;
186         switch (regnum) {
187         case IOAPIC_ID:
188                 return (ioapic->id);
189                 break;
190         case IOAPIC_VER:
191                 return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11);
192                 break;
193         case IOAPIC_ARB:
194                 return (ioapic->id);
195                 break;
196         default:
197                 break;
198         }
199
200         /* redirection table entries */
201         if (regnum >= IOAPIC_REDTBL &&
202             regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
203                 pin = (regnum - IOAPIC_REDTBL) / 2;
204                 if ((regnum - IOAPIC_REDTBL) % 2)
205                         rshift = 32;
206                 else
207                         rshift = 0;
208
209                 return (ioapic->redtbl[pin] >> rshift);
210         }
211
212         return (0);
213 }
214
215 static void
216 ioapic_write(struct ioapic *ioapic, uint32_t addr, uint32_t data)
217 {
218         int regnum, pin, lshift;
219
220         assert(ioapic->inited);
221
222         regnum = addr & 0xff;
223         switch (regnum) {
224         case IOAPIC_ID:
225                 ioapic->id = data & APIC_ID_MASK;
226                 break;
227         case IOAPIC_VER:
228         case IOAPIC_ARB:
229                 /* readonly */
230                 break;
231         default:
232                 break;
233         }
234
235         /* redirection table entries */
236         if (regnum >= IOAPIC_REDTBL &&
237             regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
238                 pin = (regnum - IOAPIC_REDTBL) / 2;
239                 if ((regnum - IOAPIC_REDTBL) % 2)
240                         lshift = 32;
241                 else
242                         lshift = 0;
243
244                 ioapic->redtbl[pin] &= ~((uint64_t)0xffffffff << lshift);
245                 ioapic->redtbl[pin] |= ((uint64_t)data << lshift);
246         }
247 }
248
249 static int
250 ioapic_region_read(struct ioapic *ioapic, uintptr_t paddr, int size,
251                    uint64_t *data)
252 {
253         int offset;
254
255         offset = paddr - ioapic->paddr;
256
257         /*
258          * The IOAPIC specification allows 32-bit wide accesses to the
259          * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
260          */
261         if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
262 #if 1
263                 printf("invalid access to ioapic%d: size %d, offset %d\n",
264                        (int)(ioapic - ioapics), size, offset);
265 #endif
266                 *data = 0;
267                 return (0);
268         }
269
270         if (offset == IOREGSEL)
271                 *data = ioapic->ioregsel;
272         else
273                 *data = ioapic_read(ioapic, ioapic->ioregsel);
274
275         return (0);
276 }
277
278 static int
279 ioapic_region_write(struct ioapic *ioapic, uintptr_t paddr, int size,
280                     uint64_t data)
281 {
282         int offset;
283
284         offset = paddr - ioapic->paddr;
285
286         /*
287          * The ioapic specification allows 32-bit wide accesses to the
288          * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
289          */
290         if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
291 #if 1
292                 printf("invalid access to ioapic%d: size %d, offset %d\n",
293                        (int)(ioapic - ioapics), size, offset);
294 #endif
295                 return (0);
296         }
297
298         if (offset == IOREGSEL)
299                 ioapic->ioregsel = data;
300         else
301                 ioapic_write(ioapic, ioapic->ioregsel, data);
302
303         return (0);
304 }
305
306 static int
307 ioapic_region_handler(struct vmctx *vm, int vcpu, int dir, uintptr_t paddr,
308                       int size, uint64_t *val, void *arg1, long arg2)
309 {
310         struct ioapic *ioapic;
311         int which;
312
313         ioapic = arg1;
314         which = arg2;
315
316         assert(ioapic == &ioapics[which]);
317
318         if (dir == MEM_F_READ)
319                 ioapic_region_read(ioapic, paddr, size, val);
320         else
321                 ioapic_region_write(ioapic, paddr, size, *val);
322
323         return (0);
324 }