1 /*- 2 * Copyright (c) 2011 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/param.h> 33 #include <sys/kernel.h> 34 #include <sys/malloc.h> 35 #include <sys/systm.h> 36 #include <sys/smp.h> 37 38 #include <machine/clock.h> 39 #include <x86/specialreg.h> 40 #include <x86/apicreg.h> 41 42 #include <machine/vmm.h> 43 44 #include "vmm_stat.h" 45 #include "vmm_lapic.h" 46 #include "vmm_ktr.h" 47 #include "vlapic.h" 48 49 #define VLAPIC_CTR0(vlapic, format) \ 50 VCPU_CTR0((vlapic)->vm, (vlapic)->vcpuid, format) 51 52 #define VLAPIC_CTR1(vlapic, format, p1) \ 53 VCPU_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1) 54 55 #define VLAPIC_CTR_IRR(vlapic, msg) \ 56 do { \ 57 uint32_t *irrptr = &(vlapic)->apic.irr0; \ 58 irrptr[0] = irrptr[0]; /* silence compiler */ \ 59 VLAPIC_CTR1((vlapic), msg " irr0 0x%08x", irrptr[0 << 2]); \ 60 VLAPIC_CTR1((vlapic), msg " irr1 0x%08x", irrptr[1 << 2]); \ 61 VLAPIC_CTR1((vlapic), msg " irr2 0x%08x", irrptr[2 << 2]); \ 62 VLAPIC_CTR1((vlapic), msg " irr3 0x%08x", irrptr[3 << 2]); \ 63 VLAPIC_CTR1((vlapic), msg " irr4 0x%08x", irrptr[4 << 2]); \ 64 VLAPIC_CTR1((vlapic), msg " irr5 0x%08x", irrptr[5 << 2]); \ 65 VLAPIC_CTR1((vlapic), msg " irr6 0x%08x", irrptr[6 << 2]); \ 66 VLAPIC_CTR1((vlapic), msg " irr7 0x%08x", irrptr[7 << 2]); \ 67 } while (0) 68 69 #define VLAPIC_CTR_ISR(vlapic, msg) \ 70 do { \ 71 uint32_t *isrptr = &(vlapic)->apic.isr0; \ 72 isrptr[0] = isrptr[0]; /* silence compiler */ \ 73 VLAPIC_CTR1((vlapic), msg " isr0 0x%08x", isrptr[0 << 2]); \ 74 VLAPIC_CTR1((vlapic), msg " isr1 0x%08x", isrptr[1 << 2]); \ 75 VLAPIC_CTR1((vlapic), msg " isr2 0x%08x", isrptr[2 << 2]); \ 76 VLAPIC_CTR1((vlapic), msg " isr3 0x%08x", isrptr[3 << 2]); \ 77 VLAPIC_CTR1((vlapic), msg " isr4 0x%08x", isrptr[4 << 2]); \ 78 VLAPIC_CTR1((vlapic), msg " isr5 0x%08x", isrptr[5 << 2]); \ 79 VLAPIC_CTR1((vlapic), msg " isr6 0x%08x", isrptr[6 << 2]); \ 80 VLAPIC_CTR1((vlapic), msg " isr7 0x%08x", isrptr[7 << 2]); \ 81 } while (0) 82 83 static MALLOC_DEFINE(M_VLAPIC, "vlapic", "vlapic"); 84 85 #define PRIO(x) ((x) >> 4) 86 87 #define VLAPIC_VERSION (16) 88 #define VLAPIC_MAXLVT_ENTRIES (5) 89 90 #define x2apic(vlapic) (((vlapic)->msr_apicbase & APICBASE_X2APIC) ? 1 : 0) 91 92 enum boot_state { 93 BS_INIT, 94 BS_SIPI, 95 BS_RUNNING 96 }; 97 98 struct vlapic { 99 struct vm *vm; 100 int vcpuid; 101 102 struct LAPIC apic; 103 104 int esr_update; 105 106 int divisor; 107 int ccr_ticks; 108 109 /* 110 * The 'isrvec_stk' is a stack of vectors injected by the local apic. 111 * A vector is popped from the stack when the processor does an EOI. 112 * The vector on the top of the stack is used to compute the 113 * Processor Priority in conjunction with the TPR. 114 */ 115 uint8_t isrvec_stk[ISRVEC_STK_SIZE]; 116 int isrvec_stk_top; 117 118 uint64_t msr_apicbase; 119 enum boot_state boot_state; 120 }; 121 122 #define VLAPIC_BUS_FREQ tsc_freq 123 124 static int 125 vlapic_timer_divisor(uint32_t dcr) 126 { 127 switch (dcr & 0xB) { 128 case APIC_TDCR_1: 129 return (1); 130 case APIC_TDCR_2: 131 return (2); 132 case APIC_TDCR_4: 133 return (4); 134 case APIC_TDCR_8: 135 return (8); 136 case APIC_TDCR_16: 137 return (16); 138 case APIC_TDCR_32: 139 return (32); 140 case APIC_TDCR_64: 141 return (64); 142 case APIC_TDCR_128: 143 return (128); 144 default: 145 panic("vlapic_timer_divisor: invalid dcr 0x%08x", dcr); 146 } 147 } 148 149 static void 150 vlapic_mask_lvts(uint32_t *lvts, int num_lvt) 151 { 152 int i; 153 for (i = 0; i < num_lvt; i++) { 154 *lvts |= APIC_LVT_M; 155 lvts += 4; 156 } 157 } 158 159 #if 0 160 static inline void 161 vlapic_dump_lvt(uint32_t offset, uint32_t *lvt) 162 { 163 printf("Offset %x: lvt %08x (V:%02x DS:%x M:%x)\n", offset, 164 *lvt, *lvt & APIC_LVTT_VECTOR, *lvt & APIC_LVTT_DS, 165 *lvt & APIC_LVTT_M); 166 } 167 #endif 168 169 static uint64_t 170 vlapic_get_ccr(struct vlapic *vlapic) 171 { 172 struct LAPIC *lapic = &vlapic->apic; 173 return lapic->ccr_timer; 174 } 175 176 static void 177 vlapic_update_errors(struct vlapic *vlapic) 178 { 179 struct LAPIC *lapic = &vlapic->apic; 180 lapic->esr = 0; // XXX 181 } 182 183 static void 184 vlapic_init_ipi(struct vlapic *vlapic) 185 { 186 struct LAPIC *lapic = &vlapic->apic; 187 lapic->version = VLAPIC_VERSION; 188 lapic->version |= (VLAPIC_MAXLVT_ENTRIES < MAXLVTSHIFT); 189 lapic->dfr = 0xffffffff; 190 lapic->svr = APIC_SVR_VECTOR; 191 vlapic_mask_lvts(&lapic->lvt_timer, VLAPIC_MAXLVT_ENTRIES+1); 192 } 193 194 static int 195 vlapic_reset(struct vlapic *vlapic) 196 { 197 struct LAPIC *lapic = &vlapic->apic; 198 199 memset(lapic, 0, sizeof(*lapic)); 200 lapic->apr = vlapic->vcpuid; 201 vlapic_init_ipi(vlapic); 202 vlapic->divisor = vlapic_timer_divisor(lapic->dcr_timer); 203 204 if (vlapic->vcpuid == 0) 205 vlapic->boot_state = BS_RUNNING; /* BSP */ 206 else 207 vlapic->boot_state = BS_INIT; /* AP */ 208 209 return 0; 210 211 } 212 213 void 214 vlapic_set_intr_ready(struct vlapic *vlapic, int vector) 215 { 216 struct LAPIC *lapic = &vlapic->apic; 217 uint32_t *irrptr; 218 int idx; 219 220 if (vector < 0 || vector >= 256) 221 panic("vlapic_set_intr_ready: invalid vector %d\n", vector); 222 223 idx = (vector / 32) * 4; 224 irrptr = &lapic->irr0; 225 atomic_set_int(&irrptr[idx], 1 << (vector % 32)); 226 VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready"); 227 } 228 229 static void 230 vlapic_start_timer(struct vlapic *vlapic, uint32_t elapsed) 231 { 232 uint32_t icr_timer; 233 234 icr_timer = vlapic->apic.icr_timer; 235 236 vlapic->ccr_ticks = ticks; 237 if (elapsed < icr_timer) 238 vlapic->apic.ccr_timer = icr_timer - elapsed; 239 else { 240 /* 241 * This can happen when the guest is trying to run its local 242 * apic timer higher that the setting of 'hz' in the host. 243 * 244 * We deal with this by running the guest local apic timer 245 * at the rate of the host's 'hz' setting. 246 */ 247 vlapic->apic.ccr_timer = 0; 248 } 249 } 250 251 static __inline uint32_t * 252 vlapic_get_lvt(struct vlapic *vlapic, uint32_t offset) 253 { 254 struct LAPIC *lapic = &vlapic->apic; 255 int i; 256 257 if (offset < APIC_OFFSET_TIMER_LVT || offset > APIC_OFFSET_ERROR_LVT) { 258 panic("vlapic_get_lvt: invalid LVT\n"); 259 } 260 i = (offset - APIC_OFFSET_TIMER_LVT) >> 2; 261 return ((&lapic->lvt_timer) + i);; 262 } 263 264 #if 1 265 static void 266 dump_isrvec_stk(struct vlapic *vlapic) 267 { 268 int i; 269 uint32_t *isrptr; 270 271 isrptr = &vlapic->apic.isr0; 272 for (i = 0; i < 8; i++) 273 printf("ISR%d 0x%08x\n", i, isrptr[i * 4]); 274 275 for (i = 0; i <= vlapic->isrvec_stk_top; i++) 276 printf("isrvec_stk[%d] = %d\n", i, vlapic->isrvec_stk[i]); 277 } 278 #endif 279 280 /* 281 * Algorithm adopted from section "Interrupt, Task and Processor Priority" 282 * in Intel Architecture Manual Vol 3a. 283 */ 284 static void 285 vlapic_update_ppr(struct vlapic *vlapic) 286 { 287 int isrvec, tpr, ppr; 288 289 /* 290 * Note that the value on the stack at index 0 is always 0. 291 * 292 * This is a placeholder for the value of ISRV when none of the 293 * bits is set in the ISRx registers. 294 */ 295 isrvec = vlapic->isrvec_stk[vlapic->isrvec_stk_top]; 296 tpr = vlapic->apic.tpr; 297 298 #if 1 299 { 300 int i, lastprio, curprio, vector, idx; 301 uint32_t *isrptr; 302 303 if (vlapic->isrvec_stk_top == 0 && isrvec != 0) 304 panic("isrvec_stk is corrupted: %d", isrvec); 305 306 /* 307 * Make sure that the priority of the nested interrupts is 308 * always increasing. 309 */ 310 lastprio = -1; 311 for (i = 1; i <= vlapic->isrvec_stk_top; i++) { 312 curprio = PRIO(vlapic->isrvec_stk[i]); 313 if (curprio <= lastprio) { 314 dump_isrvec_stk(vlapic); 315 panic("isrvec_stk does not satisfy invariant"); 316 } 317 lastprio = curprio; 318 } 319 320 /* 321 * Make sure that each bit set in the ISRx registers has a 322 * corresponding entry on the isrvec stack. 323 */ 324 i = 1; 325 isrptr = &vlapic->apic.isr0; 326 for (vector = 0; vector < 256; vector++) { 327 idx = (vector / 32) * 4; 328 if (isrptr[idx] & (1 << (vector % 32))) { 329 if (i > vlapic->isrvec_stk_top || 330 vlapic->isrvec_stk[i] != vector) { 331 dump_isrvec_stk(vlapic); 332 panic("ISR and isrvec_stk out of sync"); 333 } 334 i++; 335 } 336 } 337 } 338 #endif 339 340 if (PRIO(tpr) >= PRIO(isrvec)) 341 ppr = tpr; 342 else 343 ppr = isrvec & 0xf0; 344 345 vlapic->apic.ppr = ppr; 346 VLAPIC_CTR1(vlapic, "vlapic_update_ppr 0x%02x", ppr); 347 } 348 349 static void 350 vlapic_process_eoi(struct vlapic *vlapic) 351 { 352 struct LAPIC *lapic = &vlapic->apic; 353 uint32_t *isrptr; 354 int i, idx, bitpos; 355 356 isrptr = &lapic->isr0; 357 358 /* 359 * The x86 architecture reserves the the first 32 vectors for use 360 * by the processor. 361 */ 362 for (i = 7; i > 0; i--) { 363 idx = i * 4; 364 bitpos = fls(isrptr[idx]); 365 if (bitpos != 0) { 366 if (vlapic->isrvec_stk_top <= 0) { 367 panic("invalid vlapic isrvec_stk_top %d", 368 vlapic->isrvec_stk_top); 369 } 370 isrptr[idx] &= ~(1 << (bitpos - 1)); 371 VLAPIC_CTR_ISR(vlapic, "vlapic_process_eoi"); 372 vlapic->isrvec_stk_top--; 373 vlapic_update_ppr(vlapic); 374 return; 375 } 376 } 377 } 378 379 static __inline int 380 vlapic_get_lvt_field(uint32_t *lvt, uint32_t mask) 381 { 382 return (*lvt & mask); 383 } 384 385 static __inline int 386 vlapic_periodic_timer(struct vlapic *vlapic) 387 { 388 uint32_t *lvt; 389 390 lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT); 391 392 return (vlapic_get_lvt_field(lvt, APIC_LVTT_TM_PERIODIC)); 393 } 394 395 static VMM_STAT(VLAPIC_INTR_TIMER, "timer interrupts generated by vlapic"); 396 397 static void 398 vlapic_fire_timer(struct vlapic *vlapic) 399 { 400 int vector; 401 uint32_t *lvt; 402 403 lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT); 404 405 if (!vlapic_get_lvt_field(lvt, APIC_LVTT_M)) { 406 vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_TIMER, 1); 407 vector = vlapic_get_lvt_field(lvt,APIC_LVTT_VECTOR); 408 vlapic_set_intr_ready(vlapic, vector); 409 } 410 } 411 412 static VMM_STAT_ARRAY(IPIS_SENT, VM_MAXCPU, "ipis sent to vcpu"); 413 414 static int 415 lapic_process_icr(struct vlapic *vlapic, uint64_t icrval) 416 { 417 int i; 418 cpuset_t dmask; 419 uint32_t dest, vec, mode; 420 struct vlapic *vlapic2; 421 struct vm_exit *vmexit; 422 423 if (x2apic(vlapic)) 424 dest = icrval >> 32; 425 else 426 dest = icrval >> (32 + 24); 427 vec = icrval & APIC_VECTOR_MASK; 428 mode = icrval & APIC_DELMODE_MASK; 429 430 if (mode == APIC_DELMODE_FIXED || mode == APIC_DELMODE_NMI) { 431 switch (icrval & APIC_DEST_MASK) { 432 case APIC_DEST_DESTFLD: 433 CPU_SETOF(dest, &dmask); 434 break; 435 case APIC_DEST_SELF: 436 CPU_SETOF(vlapic->vcpuid, &dmask); 437 break; 438 case APIC_DEST_ALLISELF: 439 dmask = vm_active_cpus(vlapic->vm); 440 break; 441 case APIC_DEST_ALLESELF: 442 dmask = vm_active_cpus(vlapic->vm); 443 CPU_CLR(vlapic->vcpuid, &dmask); 444 break; 445 default: 446 CPU_ZERO(&dmask); /* satisfy gcc */ 447 break; 448 } 449 450 while ((i = CPU_FFS(&dmask)) != 0) { 451 i--; 452 CPU_CLR(i, &dmask); 453 if (mode == APIC_DELMODE_FIXED) { 454 lapic_set_intr(vlapic->vm, i, vec); 455 vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid, 456 IPIS_SENT, i, 1); 457 } else 458 vm_inject_nmi(vlapic->vm, i); 459 } 460 461 return (0); /* handled completely in the kernel */ 462 } 463 464 if (mode == APIC_DELMODE_INIT) { 465 if ((icrval & APIC_LEVEL_MASK) == APIC_LEVEL_DEASSERT) 466 return (0); 467 468 if (vlapic->vcpuid == 0 && dest != 0 && dest < VM_MAXCPU) { 469 vlapic2 = vm_lapic(vlapic->vm, dest); 470 471 /* move from INIT to waiting-for-SIPI state */ 472 if (vlapic2->boot_state == BS_INIT) { 473 vlapic2->boot_state = BS_SIPI; 474 } 475 476 return (0); 477 } 478 } 479 480 if (mode == APIC_DELMODE_STARTUP) { 481 if (vlapic->vcpuid == 0 && dest != 0 && dest < VM_MAXCPU) { 482 vlapic2 = vm_lapic(vlapic->vm, dest); 483 484 /* 485 * Ignore SIPIs in any state other than wait-for-SIPI 486 */ 487 if (vlapic2->boot_state != BS_SIPI) 488 return (0); 489 490 vmexit = vm_exitinfo(vlapic->vm, vlapic->vcpuid); 491 vmexit->exitcode = VM_EXITCODE_SPINUP_AP; 492 vmexit->u.spinup_ap.vcpu = dest; 493 vmexit->u.spinup_ap.rip = vec << PAGE_SHIFT; 494 495 /* 496 * XXX this assumes that the startup IPI always succeeds 497 */ 498 vlapic2->boot_state = BS_RUNNING; 499 vm_activate_cpu(vlapic2->vm, dest); 500 501 return (0); 502 } 503 } 504 505 /* 506 * This will cause a return to userland. 507 */ 508 return (1); 509 } 510 511 int 512 vlapic_pending_intr(struct vlapic *vlapic) 513 { 514 struct LAPIC *lapic = &vlapic->apic; 515 int idx, i, bitpos, vector; 516 uint32_t *irrptr, val; 517 518 irrptr = &lapic->irr0; 519 520 /* 521 * The x86 architecture reserves the the first 32 vectors for use 522 * by the processor. 523 */ 524 for (i = 7; i > 0; i--) { 525 idx = i * 4; 526 val = atomic_load_acq_int(&irrptr[idx]); 527 bitpos = fls(val); 528 if (bitpos != 0) { 529 vector = i * 32 + (bitpos - 1); 530 if (PRIO(vector) > PRIO(lapic->ppr)) { 531 VLAPIC_CTR1(vlapic, "pending intr %d", vector); 532 return (vector); 533 } else 534 break; 535 } 536 } 537 VLAPIC_CTR0(vlapic, "no pending intr"); 538 return (-1); 539 } 540 541 void 542 vlapic_intr_accepted(struct vlapic *vlapic, int vector) 543 { 544 struct LAPIC *lapic = &vlapic->apic; 545 uint32_t *irrptr, *isrptr; 546 int idx, stk_top; 547 548 /* 549 * clear the ready bit for vector being accepted in irr 550 * and set the vector as in service in isr. 551 */ 552 idx = (vector / 32) * 4; 553 554 irrptr = &lapic->irr0; 555 atomic_clear_int(&irrptr[idx], 1 << (vector % 32)); 556 VLAPIC_CTR_IRR(vlapic, "vlapic_intr_accepted"); 557 558 isrptr = &lapic->isr0; 559 isrptr[idx] |= 1 << (vector % 32); 560 VLAPIC_CTR_ISR(vlapic, "vlapic_intr_accepted"); 561 562 /* 563 * Update the PPR 564 */ 565 vlapic->isrvec_stk_top++; 566 567 stk_top = vlapic->isrvec_stk_top; 568 if (stk_top >= ISRVEC_STK_SIZE) 569 panic("isrvec_stk_top overflow %d", stk_top); 570 571 vlapic->isrvec_stk[stk_top] = vector; 572 vlapic_update_ppr(vlapic); 573 } 574 575 int 576 vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data) 577 { 578 struct LAPIC *lapic = &vlapic->apic; 579 uint32_t *reg; 580 int i; 581 582 if (offset > sizeof(*lapic)) { 583 *data = 0; 584 return 0; 585 } 586 587 offset &= ~3; 588 switch(offset) 589 { 590 case APIC_OFFSET_ID: 591 if (x2apic(vlapic)) 592 *data = vlapic->vcpuid; 593 else 594 *data = vlapic->vcpuid << 24; 595 break; 596 case APIC_OFFSET_VER: 597 *data = lapic->version; 598 break; 599 case APIC_OFFSET_TPR: 600 *data = lapic->tpr; 601 break; 602 case APIC_OFFSET_APR: 603 *data = lapic->apr; 604 break; 605 case APIC_OFFSET_PPR: 606 *data = lapic->ppr; 607 break; 608 case APIC_OFFSET_EOI: 609 *data = lapic->eoi; 610 break; 611 case APIC_OFFSET_LDR: 612 *data = lapic->ldr; 613 break; 614 case APIC_OFFSET_DFR: 615 *data = lapic->dfr; 616 break; 617 case APIC_OFFSET_SVR: 618 *data = lapic->svr; 619 break; 620 case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7: 621 i = (offset - APIC_OFFSET_ISR0) >> 2; 622 reg = &lapic->isr0; 623 *data = *(reg + i); 624 break; 625 case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7: 626 i = (offset - APIC_OFFSET_TMR0) >> 2; 627 reg = &lapic->tmr0; 628 *data = *(reg + i); 629 break; 630 case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7: 631 i = (offset - APIC_OFFSET_IRR0) >> 2; 632 reg = &lapic->irr0; 633 *data = atomic_load_acq_int(reg + i); 634 break; 635 case APIC_OFFSET_ESR: 636 *data = lapic->esr; 637 break; 638 case APIC_OFFSET_ICR_LOW: 639 *data = lapic->icr_lo; 640 break; 641 case APIC_OFFSET_ICR_HI: 642 *data = lapic->icr_hi; 643 break; 644 case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: 645 reg = vlapic_get_lvt(vlapic, offset); 646 *data = *(reg); 647 break; 648 case APIC_OFFSET_ICR: 649 *data = lapic->icr_timer; 650 break; 651 case APIC_OFFSET_CCR: 652 *data = vlapic_get_ccr(vlapic); 653 break; 654 case APIC_OFFSET_DCR: 655 *data = lapic->dcr_timer; 656 break; 657 case APIC_OFFSET_RRR: 658 default: 659 *data = 0; 660 break; 661 } 662 return 0; 663 } 664 665 int 666 vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data) 667 { 668 struct LAPIC *lapic = &vlapic->apic; 669 uint32_t *reg; 670 int retval; 671 672 if (offset > sizeof(*lapic)) { 673 return 0; 674 } 675 676 retval = 0; 677 offset &= ~3; 678 switch(offset) 679 { 680 case APIC_OFFSET_ID: 681 break; 682 case APIC_OFFSET_TPR: 683 lapic->tpr = data & 0xff; 684 vlapic_update_ppr(vlapic); 685 break; 686 case APIC_OFFSET_EOI: 687 vlapic_process_eoi(vlapic); 688 break; 689 case APIC_OFFSET_LDR: 690 break; 691 case APIC_OFFSET_DFR: 692 break; 693 case APIC_OFFSET_SVR: 694 lapic->svr = data; 695 break; 696 case APIC_OFFSET_ICR_LOW: 697 if (!x2apic(vlapic)) { 698 data &= 0xffffffff; 699 data |= (uint64_t)lapic->icr_hi << 32; 700 } 701 retval = lapic_process_icr(vlapic, data); 702 break; 703 case APIC_OFFSET_ICR_HI: 704 if (!x2apic(vlapic)) { 705 retval = 0; 706 lapic->icr_hi = data; 707 } 708 break; 709 case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: 710 reg = vlapic_get_lvt(vlapic, offset); 711 if (!(lapic->svr & APIC_SVR_ENABLE)) { 712 data |= APIC_LVT_M; 713 } 714 *reg = data; 715 // vlapic_dump_lvt(offset, reg); 716 break; 717 case APIC_OFFSET_ICR: 718 lapic->icr_timer = data; 719 vlapic_start_timer(vlapic, 0); 720 break; 721 722 case APIC_OFFSET_DCR: 723 lapic->dcr_timer = data; 724 vlapic->divisor = vlapic_timer_divisor(data); 725 break; 726 727 case APIC_OFFSET_ESR: 728 vlapic_update_errors(vlapic); 729 break; 730 case APIC_OFFSET_VER: 731 case APIC_OFFSET_APR: 732 case APIC_OFFSET_PPR: 733 case APIC_OFFSET_RRR: 734 case APIC_OFFSET_ISR0 ... APIC_OFFSET_ISR7: 735 case APIC_OFFSET_TMR0 ... APIC_OFFSET_TMR7: 736 case APIC_OFFSET_IRR0 ... APIC_OFFSET_IRR7: 737 case APIC_OFFSET_CCR: 738 default: 739 // Read only. 740 break; 741 } 742 743 return (retval); 744 } 745 746 int 747 vlapic_timer_tick(struct vlapic *vlapic) 748 { 749 int curticks, delta, periodic, fired; 750 uint32_t ccr; 751 uint32_t decrement, leftover; 752 753 restart: 754 curticks = ticks; 755 delta = curticks - vlapic->ccr_ticks; 756 757 /* Local APIC timer is disabled */ 758 if (vlapic->apic.icr_timer == 0) 759 return (-1); 760 761 /* One-shot mode and timer has already counted down to zero */ 762 periodic = vlapic_periodic_timer(vlapic); 763 if (!periodic && vlapic->apic.ccr_timer == 0) 764 return (-1); 765 /* 766 * The 'curticks' and 'ccr_ticks' are out of sync by more than 767 * 2^31 ticks. We deal with this by restarting the timer. 768 */ 769 if (delta < 0) { 770 vlapic_start_timer(vlapic, 0); 771 goto restart; 772 } 773 774 fired = 0; 775 decrement = (VLAPIC_BUS_FREQ / vlapic->divisor) / hz; 776 777 vlapic->ccr_ticks = curticks; 778 ccr = vlapic->apic.ccr_timer; 779 780 while (delta-- > 0) { 781 if (ccr > decrement) { 782 ccr -= decrement; 783 continue; 784 } 785 786 /* Trigger the local apic timer interrupt */ 787 vlapic_fire_timer(vlapic); 788 if (periodic) { 789 leftover = decrement - ccr; 790 vlapic_start_timer(vlapic, leftover); 791 ccr = vlapic->apic.ccr_timer; 792 } else { 793 /* 794 * One-shot timer has counted down to zero. 795 */ 796 ccr = 0; 797 } 798 fired = 1; 799 break; 800 } 801 802 vlapic->apic.ccr_timer = ccr; 803 804 if (!fired) 805 return ((ccr / decrement) + 1); 806 else 807 return (0); 808 } 809 810 struct vlapic * 811 vlapic_init(struct vm *vm, int vcpuid) 812 { 813 struct vlapic *vlapic; 814 815 vlapic = malloc(sizeof(struct vlapic), M_VLAPIC, M_WAITOK | M_ZERO); 816 vlapic->vm = vm; 817 vlapic->vcpuid = vcpuid; 818 819 vlapic->msr_apicbase = DEFAULT_APIC_BASE | APICBASE_ENABLED; 820 821 if (vcpuid == 0) 822 vlapic->msr_apicbase |= APICBASE_BSP; 823 824 vlapic_reset(vlapic); 825 826 return (vlapic); 827 } 828 829 void 830 vlapic_cleanup(struct vlapic *vlapic) 831 { 832 833 free(vlapic, M_VLAPIC); 834 } 835 836 uint64_t 837 vlapic_get_apicbase(struct vlapic *vlapic) 838 { 839 840 return (vlapic->msr_apicbase); 841 } 842 843 void 844 vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val) 845 { 846 int err; 847 enum x2apic_state state; 848 849 err = vm_get_x2apic_state(vlapic->vm, vlapic->vcpuid, &state); 850 if (err) 851 panic("vlapic_set_apicbase: err %d fetching x2apic state", err); 852 853 if (state == X2APIC_DISABLED) 854 val &= ~APICBASE_X2APIC; 855 856 vlapic->msr_apicbase = val; 857 } 858 859 void 860 vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 861 { 862 struct vlapic *vlapic; 863 864 vlapic = vm_lapic(vm, vcpuid); 865 866 if (state == X2APIC_DISABLED) 867 vlapic->msr_apicbase &= ~APICBASE_X2APIC; 868 } 869