1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 5 * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/param.h> 36 #include <sys/queue.h> 37 #include <sys/lock.h> 38 #include <sys/mutex.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/malloc.h> 42 43 #include <x86/apicreg.h> 44 #include <machine/vmm.h> 45 46 #include "vmm_ktr.h" 47 #include "vmm_lapic.h" 48 #include "vlapic.h" 49 #include "vioapic.h" 50 51 #define IOREGSEL 0x00 52 #define IOWIN 0x10 53 54 #define REDIR_ENTRIES 32 55 #define RTBL_RO_BITS ((uint64_t)(IOART_REM_IRR | IOART_DELIVS)) 56 57 struct vioapic { 58 struct vm *vm; 59 struct mtx mtx; 60 uint32_t id; 61 uint32_t ioregsel; 62 struct { 63 uint64_t reg; 64 int acnt; /* sum of pin asserts (+1) and deasserts (-1) */ 65 } rtbl[REDIR_ENTRIES]; 66 }; 67 68 #define VIOAPIC_LOCK(vioapic) mtx_lock_spin(&((vioapic)->mtx)) 69 #define VIOAPIC_UNLOCK(vioapic) mtx_unlock_spin(&((vioapic)->mtx)) 70 #define VIOAPIC_LOCKED(vioapic) mtx_owned(&((vioapic)->mtx)) 71 72 static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic"); 73 74 #define VIOAPIC_CTR1(vioapic, fmt, a1) \ 75 VM_CTR1((vioapic)->vm, fmt, a1) 76 77 #define VIOAPIC_CTR2(vioapic, fmt, a1, a2) \ 78 VM_CTR2((vioapic)->vm, fmt, a1, a2) 79 80 #define VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3) \ 81 VM_CTR3((vioapic)->vm, fmt, a1, a2, a3) 82 83 #define VIOAPIC_CTR4(vioapic, fmt, a1, a2, a3, a4) \ 84 VM_CTR4((vioapic)->vm, fmt, a1, a2, a3, a4) 85 86 #ifdef KTR 87 static const char * 88 pinstate_str(bool asserted) 89 { 90 91 if (asserted) 92 return ("asserted"); 93 else 94 return ("deasserted"); 95 } 96 #endif 97 98 static void 99 vioapic_send_intr(struct vioapic *vioapic, int pin) 100 { 101 int vector, delmode; 102 uint32_t low, high, dest; 103 bool level, phys; 104 105 KASSERT(pin >= 0 && pin < REDIR_ENTRIES, 106 ("vioapic_set_pinstate: invalid pin number %d", pin)); 107 108 KASSERT(VIOAPIC_LOCKED(vioapic), 109 ("vioapic_set_pinstate: vioapic is not locked")); 110 111 low = vioapic->rtbl[pin].reg; 112 high = vioapic->rtbl[pin].reg >> 32; 113 114 if ((low & IOART_INTMASK) == IOART_INTMSET) { 115 VIOAPIC_CTR1(vioapic, "ioapic pin%d: masked", pin); 116 return; 117 } 118 119 phys = ((low & IOART_DESTMOD) == IOART_DESTPHY); 120 delmode = low & IOART_DELMOD; 121 level = low & IOART_TRGRLVL ? true : false; 122 if (level) 123 vioapic->rtbl[pin].reg |= IOART_REM_IRR; 124 125 vector = low & IOART_INTVEC; 126 dest = high >> APIC_ID_SHIFT; 127 vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector); 128 } 129 130 static void 131 vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate) 132 { 133 int oldcnt, newcnt; 134 bool needintr; 135 136 KASSERT(pin >= 0 && pin < REDIR_ENTRIES, 137 ("vioapic_set_pinstate: invalid pin number %d", pin)); 138 139 KASSERT(VIOAPIC_LOCKED(vioapic), 140 ("vioapic_set_pinstate: vioapic is not locked")); 141 142 oldcnt = vioapic->rtbl[pin].acnt; 143 if (newstate) 144 vioapic->rtbl[pin].acnt++; 145 else 146 vioapic->rtbl[pin].acnt--; 147 newcnt = vioapic->rtbl[pin].acnt; 148 149 if (newcnt < 0) { 150 VIOAPIC_CTR2(vioapic, "ioapic pin%d: bad acnt %d", 151 pin, newcnt); 152 } 153 154 needintr = false; 155 if (oldcnt == 0 && newcnt == 1) { 156 needintr = true; 157 VIOAPIC_CTR1(vioapic, "ioapic pin%d: asserted", pin); 158 } else if (oldcnt == 1 && newcnt == 0) { 159 VIOAPIC_CTR1(vioapic, "ioapic pin%d: deasserted", pin); 160 } else { 161 VIOAPIC_CTR3(vioapic, "ioapic pin%d: %s, ignored, acnt %d", 162 pin, pinstate_str(newstate), newcnt); 163 } 164 165 if (needintr) 166 vioapic_send_intr(vioapic, pin); 167 } 168 169 enum irqstate { 170 IRQSTATE_ASSERT, 171 IRQSTATE_DEASSERT, 172 IRQSTATE_PULSE 173 }; 174 175 static int 176 vioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate) 177 { 178 struct vioapic *vioapic; 179 180 if (irq < 0 || irq >= REDIR_ENTRIES) 181 return (EINVAL); 182 183 vioapic = vm_ioapic(vm); 184 185 VIOAPIC_LOCK(vioapic); 186 switch (irqstate) { 187 case IRQSTATE_ASSERT: 188 vioapic_set_pinstate(vioapic, irq, true); 189 break; 190 case IRQSTATE_DEASSERT: 191 vioapic_set_pinstate(vioapic, irq, false); 192 break; 193 case IRQSTATE_PULSE: 194 vioapic_set_pinstate(vioapic, irq, true); 195 vioapic_set_pinstate(vioapic, irq, false); 196 break; 197 default: 198 panic("vioapic_set_irqstate: invalid irqstate %d", irqstate); 199 } 200 VIOAPIC_UNLOCK(vioapic); 201 202 return (0); 203 } 204 205 int 206 vioapic_assert_irq(struct vm *vm, int irq) 207 { 208 209 return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT)); 210 } 211 212 int 213 vioapic_deassert_irq(struct vm *vm, int irq) 214 { 215 216 return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT)); 217 } 218 219 int 220 vioapic_pulse_irq(struct vm *vm, int irq) 221 { 222 223 return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE)); 224 } 225 226 /* 227 * Reset the vlapic's trigger-mode register to reflect the ioapic pin 228 * configuration. 229 */ 230 static void 231 vioapic_update_tmr(struct vm *vm, int vcpuid, void *arg) 232 { 233 struct vioapic *vioapic; 234 struct vlapic *vlapic; 235 uint32_t low, high, dest; 236 int delmode, pin, vector; 237 bool level, phys; 238 239 vlapic = vm_lapic(vm, vcpuid); 240 vioapic = vm_ioapic(vm); 241 242 VIOAPIC_LOCK(vioapic); 243 /* 244 * Reset all vectors to be edge-triggered. 245 */ 246 vlapic_reset_tmr(vlapic); 247 for (pin = 0; pin < REDIR_ENTRIES; pin++) { 248 low = vioapic->rtbl[pin].reg; 249 high = vioapic->rtbl[pin].reg >> 32; 250 251 level = low & IOART_TRGRLVL ? true : false; 252 if (!level) 253 continue; 254 255 /* 256 * For a level-triggered 'pin' let the vlapic figure out if 257 * an assertion on this 'pin' would result in an interrupt 258 * being delivered to it. If yes, then it will modify the 259 * TMR bit associated with this vector to level-triggered. 260 */ 261 phys = ((low & IOART_DESTMOD) == IOART_DESTPHY); 262 delmode = low & IOART_DELMOD; 263 vector = low & IOART_INTVEC; 264 dest = high >> APIC_ID_SHIFT; 265 vlapic_set_tmr_level(vlapic, dest, phys, delmode, vector); 266 } 267 VIOAPIC_UNLOCK(vioapic); 268 } 269 270 static uint32_t 271 vioapic_read(struct vioapic *vioapic, int vcpuid, uint32_t addr) 272 { 273 int regnum, pin, rshift; 274 275 regnum = addr & 0xff; 276 switch (regnum) { 277 case IOAPIC_ID: 278 return (vioapic->id); 279 break; 280 case IOAPIC_VER: 281 return (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11); 282 break; 283 case IOAPIC_ARB: 284 return (vioapic->id); 285 break; 286 default: 287 break; 288 } 289 290 /* redirection table entries */ 291 if (regnum >= IOAPIC_REDTBL && 292 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) { 293 pin = (regnum - IOAPIC_REDTBL) / 2; 294 if ((regnum - IOAPIC_REDTBL) % 2) 295 rshift = 32; 296 else 297 rshift = 0; 298 299 return (vioapic->rtbl[pin].reg >> rshift); 300 } 301 302 return (0); 303 } 304 305 static void 306 vioapic_write(struct vioapic *vioapic, int vcpuid, uint32_t addr, uint32_t data) 307 { 308 uint64_t data64, mask64; 309 uint64_t last, changed; 310 int regnum, pin, lshift; 311 cpuset_t allvcpus; 312 313 regnum = addr & 0xff; 314 switch (regnum) { 315 case IOAPIC_ID: 316 vioapic->id = data & APIC_ID_MASK; 317 break; 318 case IOAPIC_VER: 319 case IOAPIC_ARB: 320 /* readonly */ 321 break; 322 default: 323 break; 324 } 325 326 /* redirection table entries */ 327 if (regnum >= IOAPIC_REDTBL && 328 regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) { 329 pin = (regnum - IOAPIC_REDTBL) / 2; 330 if ((regnum - IOAPIC_REDTBL) % 2) 331 lshift = 32; 332 else 333 lshift = 0; 334 335 last = vioapic->rtbl[pin].reg; 336 337 data64 = (uint64_t)data << lshift; 338 mask64 = (uint64_t)0xffffffff << lshift; 339 vioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS; 340 vioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS; 341 342 VIOAPIC_CTR2(vioapic, "ioapic pin%d: redir table entry %#lx", 343 pin, vioapic->rtbl[pin].reg); 344 345 /* 346 * If any fields in the redirection table entry (except mask 347 * or polarity) have changed then rendezvous all the vcpus 348 * to update their vlapic trigger-mode registers. 349 */ 350 changed = last ^ vioapic->rtbl[pin].reg; 351 if (changed & ~(IOART_INTMASK | IOART_INTPOL)) { 352 VIOAPIC_CTR1(vioapic, "ioapic pin%d: recalculate " 353 "vlapic trigger-mode register", pin); 354 VIOAPIC_UNLOCK(vioapic); 355 allvcpus = vm_active_cpus(vioapic->vm); 356 (void)vm_smp_rendezvous(vioapic->vm, vcpuid, allvcpus, 357 vioapic_update_tmr, NULL); 358 VIOAPIC_LOCK(vioapic); 359 } 360 361 /* 362 * Generate an interrupt if the following conditions are met: 363 * - pin is not masked 364 * - previous interrupt has been EOIed 365 * - pin level is asserted 366 */ 367 if ((vioapic->rtbl[pin].reg & IOART_INTMASK) == IOART_INTMCLR && 368 (vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0 && 369 (vioapic->rtbl[pin].acnt > 0)) { 370 VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at rtbl " 371 "write, acnt %d", pin, vioapic->rtbl[pin].acnt); 372 vioapic_send_intr(vioapic, pin); 373 } 374 } 375 } 376 377 static int 378 vioapic_mmio_rw(struct vioapic *vioapic, int vcpuid, uint64_t gpa, 379 uint64_t *data, int size, bool doread) 380 { 381 uint64_t offset; 382 383 offset = gpa - VIOAPIC_BASE; 384 385 /* 386 * The IOAPIC specification allows 32-bit wide accesses to the 387 * IOREGSEL (offset 0) and IOWIN (offset 16) registers. 388 */ 389 if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) { 390 if (doread) 391 *data = 0; 392 return (0); 393 } 394 395 VIOAPIC_LOCK(vioapic); 396 if (offset == IOREGSEL) { 397 if (doread) 398 *data = vioapic->ioregsel; 399 else 400 vioapic->ioregsel = *data; 401 } else { 402 if (doread) { 403 *data = vioapic_read(vioapic, vcpuid, 404 vioapic->ioregsel); 405 } else { 406 vioapic_write(vioapic, vcpuid, vioapic->ioregsel, 407 *data); 408 } 409 } 410 VIOAPIC_UNLOCK(vioapic); 411 412 return (0); 413 } 414 415 int 416 vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval, 417 int size, void *arg) 418 { 419 int error; 420 struct vioapic *vioapic; 421 422 vioapic = vm_ioapic(vm); 423 error = vioapic_mmio_rw(vioapic, vcpuid, gpa, rval, size, true); 424 return (error); 425 } 426 427 int 428 vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval, 429 int size, void *arg) 430 { 431 int error; 432 struct vioapic *vioapic; 433 434 vioapic = vm_ioapic(vm); 435 error = vioapic_mmio_rw(vioapic, vcpuid, gpa, &wval, size, false); 436 return (error); 437 } 438 439 void 440 vioapic_process_eoi(struct vm *vm, int vcpuid, int vector) 441 { 442 struct vioapic *vioapic; 443 int pin; 444 445 KASSERT(vector >= 0 && vector < 256, 446 ("vioapic_process_eoi: invalid vector %d", vector)); 447 448 vioapic = vm_ioapic(vm); 449 VIOAPIC_CTR1(vioapic, "ioapic processing eoi for vector %d", vector); 450 451 /* 452 * XXX keep track of the pins associated with this vector instead 453 * of iterating on every single pin each time. 454 */ 455 VIOAPIC_LOCK(vioapic); 456 for (pin = 0; pin < REDIR_ENTRIES; pin++) { 457 if ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0) 458 continue; 459 if ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector) 460 continue; 461 vioapic->rtbl[pin].reg &= ~IOART_REM_IRR; 462 if (vioapic->rtbl[pin].acnt > 0) { 463 VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at eoi, " 464 "acnt %d", pin, vioapic->rtbl[pin].acnt); 465 vioapic_send_intr(vioapic, pin); 466 } 467 } 468 VIOAPIC_UNLOCK(vioapic); 469 } 470 471 struct vioapic * 472 vioapic_init(struct vm *vm) 473 { 474 int i; 475 struct vioapic *vioapic; 476 477 vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO); 478 479 vioapic->vm = vm; 480 mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_SPIN); 481 482 /* Initialize all redirection entries to mask all interrupts */ 483 for (i = 0; i < REDIR_ENTRIES; i++) 484 vioapic->rtbl[i].reg = 0x0001000000010000UL; 485 486 return (vioapic); 487 } 488 489 void 490 vioapic_cleanup(struct vioapic *vioapic) 491 { 492 493 free(vioapic, M_VIOAPIC); 494 } 495 496 int 497 vioapic_pincount(struct vm *vm) 498 { 499 500 return (REDIR_ENTRIES); 501 } 502