]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/bhyve/ioapic.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 #include <pthread.h>
41
42 #include <vmmapi.h>
43
44 #include "inout.h"
45 #include "mem.h"
46 #include "bhyverun.h"
47
48 #include <stdio.h>
49
50 static uint64_t ioapic_clearpend, ioapic_togglepend, ioapic_setpend;
51
52 #define IOAPIC_PADDR    0xFEC00000
53
54 #define IOREGSEL        0x00
55 #define IOWIN           0x10
56
57 #define REDIR_ENTRIES   16
58 #define INTR_ASSERTED(ioapic, pin)      \
59         ((ioapic)->rtbl[(pin)].pinstate == true)
60
61 struct ioapic {
62         int             inited;
63         uint32_t        id;
64         struct {
65                 uint64_t reg;
66                 bool     pinstate;
67                 bool     pending;
68         } rtbl[REDIR_ENTRIES];
69
70         uintptr_t       paddr;          /* gpa where the ioapic is mapped */
71         uint32_t        ioregsel;
72         struct memory_region *region;
73         pthread_mutex_t mtx;
74 };
75
76 static struct ioapic ioapics[1];        /* only a single ioapic for now */
77
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);
84
85 static void
86 ioapic_set_pinstate(struct vmctx *ctx, int pin, bool newstate)
87 {
88         int vector, apicid, vcpu;
89         uint32_t low, high;
90         struct ioapic *ioapic;
91         
92         ioapic = &ioapics[0];           /* assume a single ioapic */
93
94         /* Nothing to do if interrupt pin has not changed state */
95         if (ioapic->rtbl[pin].pinstate == newstate)
96                 return;
97
98         ioapic->rtbl[pin].pinstate = newstate;  /* record it */
99
100         /* Nothing to do if interrupt pin is deasserted */
101         if (!INTR_ASSERTED(ioapic, pin))
102                 return;
103
104         /*
105          * XXX
106          * We only deal with:
107          * - edge triggered interrupts
108          * - fixed delivery mode
109          *  Level-triggered sources will work so long as there is
110          * no sharing.
111          */
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) {
120                         /* unicast */
121                         vcpu = vm_apicid2vcpu(ctx, apicid);
122                         vm_lapic_irq(ctx, vcpu, vector);
123                 } else {
124                         /* broadcast */
125                         vcpu = 0;
126                         while (vcpu < guest_ncpus) {
127                                 vm_lapic_irq(ctx, vcpu, vector);
128                                 vcpu++;
129                         }
130                 }
131         } else if ((low & IOART_INTMASK) != IOART_INTMCLR &&
132                    low & IOART_TRGRLVL) {
133                 /*
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
137                  * still asserted
138                  */
139                 ioapic_setpend++;
140                 ioapic->rtbl[pin].pending = true;
141         }
142 }
143
144 static void
145 ioapic_set_pinstate_locked(struct vmctx *ctx, int pin, bool newstate)
146 {
147         struct ioapic *ioapic;
148
149         if (pin < 0 || pin >= REDIR_ENTRIES)
150                 return;
151
152         ioapic = &ioapics[0];
153
154         pthread_mutex_lock(&ioapic->mtx);
155         ioapic_set_pinstate(ctx, pin, newstate);
156         pthread_mutex_unlock(&ioapic->mtx);
157 }
158
159 /*
160  * External entry points require locking
161  */
162 void
163 ioapic_deassert_pin(struct vmctx *ctx, int pin)
164 {
165         ioapic_set_pinstate_locked(ctx, pin, false);
166 }
167
168 void
169 ioapic_assert_pin(struct vmctx *ctx, int pin)
170 {
171         ioapic_set_pinstate_locked(ctx, pin, true);
172 }
173
174 void
175 ioapic_init(int which)
176 {
177         struct mem_range memp;
178         struct ioapic *ioapic;
179         int error;
180         int i;
181
182         assert(which == 0);
183
184         ioapic = &ioapics[which];
185         assert(ioapic->inited == 0);
186
187         bzero(ioapic, sizeof(struct ioapic));
188
189         pthread_mutex_init(&ioapic->mtx, NULL);
190
191         /* Initialize all redirection entries to mask all interrupts */
192         for (i = 0; i < REDIR_ENTRIES; i++)
193                 ioapic->rtbl[i].reg = 0x0001000000010000UL;
194
195         ioapic->paddr = IOAPIC_PADDR;
196
197         /* Register emulated memory region */
198         memp.name = "ioapic";
199         memp.flags = MEM_F_RW;
200         memp.handler = ioapic_region_handler;
201         memp.arg1 = ioapic;
202         memp.arg2 = which;
203         memp.base = ioapic->paddr;
204         memp.size = sizeof(struct IOAPIC);
205         error = register_mem(&memp);
206
207         assert (error == 0);
208
209         ioapic->inited = 1;
210 }
211
212 static uint32_t
213 ioapic_read(struct ioapic *ioapic, uint32_t addr)
214 {
215         int regnum, pin, rshift;
216
217         assert(ioapic->inited);
218
219         regnum = addr & 0xff;
220         switch (regnum) {
221         case IOAPIC_ID:
222                 return (ioapic->id);
223                 break;
224         case IOAPIC_VER:
225                 return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11);
226                 break;
227         case IOAPIC_ARB:
228                 return (ioapic->id);
229                 break;
230         default:
231                 break;
232         }
233
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)
239                         rshift = 32;
240                 else
241                         rshift = 0;
242
243                 return (ioapic->rtbl[pin].reg >> rshift);
244         }
245
246         return (0);
247 }
248
249 static void
250 ioapic_write(struct vmctx *vm, struct ioapic *ioapic, uint32_t addr,
251     uint32_t data)
252 {
253         int regnum, pin, lshift;
254
255         assert(ioapic->inited);
256
257         regnum = addr & 0xff;
258         switch (regnum) {
259         case IOAPIC_ID:
260                 ioapic->id = data & APIC_ID_MASK;
261                 break;
262         case IOAPIC_VER:
263         case IOAPIC_ARB:
264                 /* readonly */
265                 break;
266         default:
267                 break;
268         }
269
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)
275                         lshift = 32;
276                 else
277                         lshift = 0;
278
279                 ioapic->rtbl[pin].reg &= ~((uint64_t)0xffffffff << lshift);
280                 ioapic->rtbl[pin].reg |= ((uint64_t)data << lshift);
281         
282                 if (ioapic->rtbl[pin].pending &&
283                     ((ioapic->rtbl[pin].reg & IOART_INTMASK) ==
284                          IOART_INTMCLR)) {
285                         ioapic->rtbl[pin].pending = false;
286                         ioapic_clearpend++;
287                         /*
288                          * Inject the deferred level-triggered int if it is
289                          * still asserted. Simulate by toggling the pin
290                          * off and then on.
291                          */
292                         if (ioapic->rtbl[pin].pinstate == true) {
293                                 ioapic_togglepend++;
294                                 ioapic_set_pinstate(vm, pin, false);
295                                 ioapic_set_pinstate(vm, pin, true);
296                         }
297                 }
298         }
299 }
300
301 static int
302 ioapic_region_read(struct vmctx *vm, struct ioapic *ioapic, uintptr_t paddr,
303     int size, uint64_t *data)
304 {
305         int offset;
306
307         offset = paddr - ioapic->paddr;
308
309         /*
310          * The IOAPIC specification allows 32-bit wide accesses to the
311          * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
312          */
313         if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
314 #if 1
315                 printf("invalid access to ioapic%d: size %d, offset %d\n",
316                        (int)(ioapic - ioapics), size, offset);
317 #endif
318                 *data = 0;
319                 return (0);
320         }
321
322         if (offset == IOREGSEL)
323                 *data = ioapic->ioregsel;
324         else
325                 *data = ioapic_read(ioapic, ioapic->ioregsel);
326
327         return (0);
328 }
329
330 static int
331 ioapic_region_write(struct vmctx *vm, struct ioapic *ioapic, uintptr_t paddr,
332     int size, uint64_t data)
333 {
334         int offset;
335
336         offset = paddr - ioapic->paddr;
337
338         /*
339          * The ioapic specification allows 32-bit wide accesses to the
340          * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
341          */
342         if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
343 #if 1
344                 printf("invalid access to ioapic%d: size %d, offset %d\n",
345                        (int)(ioapic - ioapics), size, offset);
346 #endif
347                 return (0);
348         }
349
350         if (offset == IOREGSEL)
351                 ioapic->ioregsel = data;
352         else
353                 ioapic_write(vm, ioapic, ioapic->ioregsel, data);
354
355         return (0);
356 }
357
358 static int
359 ioapic_region_handler(struct vmctx *vm, int vcpu, int dir, uintptr_t paddr,
360     int size, uint64_t *val, void *arg1, long arg2)
361 {
362         struct ioapic *ioapic;
363         int which;
364
365         ioapic = arg1;
366         which = arg2;
367
368         assert(ioapic == &ioapics[which]);
369
370         pthread_mutex_lock(&ioapic->mtx);
371         if (dir == MEM_F_READ)
372                 ioapic_region_read(vm, ioapic, paddr, size, val);
373         else
374                 ioapic_region_write(vm, ioapic, paddr, size, *val);
375         pthread_mutex_unlock(&ioapic->mtx);
376
377         return (0);
378 }