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