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$ 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 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 56 struct 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 71 static 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 86 static const char * 87 pinstate_str(bool asserted) 88 { 89 90 if (asserted) 91 return ("asserted"); 92 else 93 return ("deasserted"); 94 } 95 #endif 96 97 static void 98 vioapic_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 129 static void 130 vioapic_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 168 enum irqstate { 169 IRQSTATE_ASSERT, 170 IRQSTATE_DEASSERT, 171 IRQSTATE_PULSE 172 }; 173 174 static int 175 vioapic_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 204 int 205 vioapic_assert_irq(struct vm *vm, int irq) 206 { 207 208 return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT)); 209 } 210 211 int 212 vioapic_deassert_irq(struct vm *vm, int irq) 213 { 214 215 return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT)); 216 } 217 218 int 219 vioapic_pulse_irq(struct vm *vm, int irq) 220 { 221 222 return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE)); 223 } 224 225 static uint32_t 226 vioapic_read(struct vioapic *vioapic, 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 260 static void 261 vioapic_write(struct vioapic *vioapic, uint32_t addr, uint32_t data) 262 { 263 uint64_t data64, mask64; 264 int regnum, pin, lshift; 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 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 /* 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 312 static int 313 vioapic_mmio_rw(struct vioapic *vioapic, uint64_t gpa, uint64_t *data, 314 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 { 337 if (doread) 338 *data = vioapic_read(vioapic, vioapic->ioregsel); 339 else 340 vioapic_write(vioapic, vioapic->ioregsel, *data); 341 } 342 VIOAPIC_UNLOCK(vioapic); 343 344 return (0); 345 } 346 347 int 348 vioapic_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); 355 error = vioapic_mmio_rw(vioapic, gpa, rval, size, true); 356 return (error); 357 } 358 359 int 360 vioapic_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); 367 error = vioapic_mmio_rw(vioapic, gpa, &wval, size, false); 368 return (error); 369 } 370 371 void 372 vioapic_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 403 struct vioapic * 404 vioapic_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 421 void 422 vioapic_cleanup(struct vioapic *vioapic) 423 { 424 425 free(vioapic, M_VIOAPIC); 426 } 427 428 int 429 vioapic_pincount(struct vm *vm) 430 { 431 432 return (REDIR_ENTRIES); 433 } 434