1/* 2 * Local APIC virtualization 3 * 4 * Copyright (C) 2006 Qumranet, Inc. 5 * Copyright (C) 2007 Novell 6 * Copyright (C) 2007 Intel 7 * Copyright 2009 Red Hat, Inc. and/or its affiliates. 8 * 9 * Authors: 10 * Dor Laor <dor.laor@qumranet.com> 11 * Gregory Haskins <ghaskins@novell.com> 12 * Yaozu (Eddie) Dong <eddie.dong@intel.com> 13 * 14 * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation. 15 * 16 * This work is licensed under the terms of the GNU GPL, version 2. See 17 * the COPYING file in the top-level directory. 18 */ 19 20// SPDX-License-Identifier: GPL-2.0-only 21 22#include <stdlib.h> 23#include <stdio.h> 24#include <string.h> 25#include <utils/util.h> 26 27#include <sel4vm/guest_vm.h> 28#include <sel4vm/boot.h> 29#include <sel4vm/guest_vcpu_fault.h> 30 31#include "processor/lapic.h" 32#include "processor/apicdef.h" 33#include "processor/msr.h" 34#include "i8259/i8259.h" 35#include "interrupt.h" 36 37#define APIC_BUS_CYCLE_NS 1 38 39#define APIC_DEBUG 0 40#define apic_debug(lvl,...) do{ if(lvl < APIC_DEBUG){printf(__VA_ARGS__);fflush(stdout);}}while (0) 41 42#define APIC_LVT_NUM 6 43/* 14 is the version for Xeon and Pentium 8.4.8*/ 44#define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16)) 45#define LAPIC_MMIO_LENGTH (BIT(12)) 46/* followed define is not in apicdef.h */ 47#define APIC_SHORT_MASK 0xc0000 48#define APIC_DEST_NOSHORT 0x0 49#define APIC_DEST_MASK 0x800 50#define MAX_APIC_VECTOR 256 51#define APIC_VECTORS_PER_REG 32 52 53inline static int pic_get_interrupt(vm_t *vm) 54{ 55 return i8259_get_interrupt(vm); 56} 57 58inline static int pic_has_interrupt(vm_t *vm) 59{ 60 return i8259_has_interrupt(vm); 61} 62 63struct vm_lapic_irq { 64 uint32_t vector; 65 uint32_t delivery_mode; 66 uint32_t dest_mode; 67 uint32_t level; 68 uint32_t trig_mode; 69 uint32_t shorthand; 70 uint32_t dest_id; 71}; 72 73/* Generic bit operations; TODO move these elsewhere */ 74static inline int fls(int x) 75{ 76 int r = 32; 77 78 if (!x) { 79 return 0; 80 } 81 82 if (!(x & 0xffff0000u)) { 83 x <<= 16; 84 r -= 16; 85 } 86 if (!(x & 0xff000000u)) { 87 x <<= 8; 88 r -= 8; 89 } 90 if (!(x & 0xf0000000u)) { 91 x <<= 4; 92 r -= 4; 93 } 94 if (!(x & 0xc0000000u)) { 95 x <<= 2; 96 r -= 2; 97 } 98 if (!(x & 0x80000000u)) { 99 x <<= 1; 100 r -= 1; 101 } 102 return r; 103} 104 105static uint32_t hweight32(unsigned int w) 106{ 107 uint32_t res = w - ((w >> 1) & 0x55555555); 108 res = (res & 0x33333333) + ((res >> 2) & 0x33333333); 109 res = (res + (res >> 4)) & 0x0F0F0F0F; 110 res = res + (res >> 8); 111 return (res + (res >> 16)) & 0x000000FF; 112} 113/* End generic bit ops */ 114 115void vm_lapic_reset(vm_vcpu_t *vcpu); 116 117// Returns whether the irq delivery mode is lowest prio 118inline static bool vm_is_dm_lowest_prio(struct vm_lapic_irq *irq) 119{ 120 return irq->delivery_mode == APIC_DM_LOWEST; 121} 122 123// Access register field 124static inline void apic_set_reg(vm_lapic_t *apic, int reg_off, uint32_t val) 125{ 126 *((uint32_t *)(apic->regs + reg_off)) = val; 127} 128 129static inline uint32_t vm_apic_get_reg(vm_lapic_t *apic, int reg_off) 130{ 131 return *((uint32_t *)(apic->regs + reg_off)); 132} 133 134static inline int apic_test_vector(int vec, void *bitmap) 135{ 136 return ((1UL << (vec & 31)) & ((uint32_t *)bitmap)[vec >> 5]) != 0; 137} 138 139bool vm_apic_pending_eoi(vm_vcpu_t *vcpu, int vector) 140{ 141 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 142 143 return apic_test_vector(vector, apic->regs + APIC_ISR) || 144 apic_test_vector(vector, apic->regs + APIC_IRR); 145} 146 147static inline void apic_set_vector(int vec, void *bitmap) 148{ 149 ((uint32_t *)bitmap)[vec >> 5] |= 1UL << (vec & 31); 150} 151 152static inline void apic_clear_vector(int vec, void *bitmap) 153{ 154 ((uint32_t *)bitmap)[vec >> 5] &= ~(1UL << (vec & 31)); 155} 156 157static inline int vm_apic_sw_enabled(vm_lapic_t *apic) 158{ 159 return vm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; 160} 161 162static inline int vm_apic_hw_enabled(vm_lapic_t *apic) 163{ 164 return apic->apic_base & MSR_IA32_APICBASE_ENABLE; 165} 166 167inline int vm_apic_enabled(vm_lapic_t *apic) 168{ 169 return vm_apic_sw_enabled(apic) && vm_apic_hw_enabled(apic); 170} 171 172#define LVT_MASK \ 173 (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK) 174 175#define LINT_MASK \ 176 (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \ 177 APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER) 178 179static inline int vm_apic_id(vm_lapic_t *apic) 180{ 181 return (vm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; 182} 183 184static inline void apic_set_spiv(vm_lapic_t *apic, uint32_t val) 185{ 186 apic_set_reg(apic, APIC_SPIV, val); 187} 188 189static const unsigned int apic_lvt_mask[APIC_LVT_NUM] = { 190 LVT_MASK, /* part LVTT mask, timer mode mask added at runtime */ 191 LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ 192 LVT_MASK | APIC_MODE_MASK, /* LVTPC */ 193 LINT_MASK, LINT_MASK, /* LVT0-1 */ 194 LVT_MASK /* LVTERR */ 195}; 196 197static inline void vm_apic_set_id(vm_lapic_t *apic, uint8_t id) 198{ 199 apic_set_reg(apic, APIC_ID, id << 24); 200} 201 202static inline void vm_apic_set_ldr(vm_lapic_t *apic, uint32_t id) 203{ 204 apic_set_reg(apic, APIC_LDR, id); 205} 206 207static inline int apic_lvt_enabled(vm_lapic_t *apic, int lvt_type) 208{ 209 return !(vm_apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); 210} 211 212static inline int apic_lvt_vector(vm_lapic_t *apic, int lvt_type) 213{ 214 return vm_apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; 215} 216 217static inline int vm_vcpu_is_bsp(vm_vcpu_t *vcpu) 218{ 219 return vcpu->vcpu_id == BOOT_VCPU; 220} 221 222static inline int apic_lvt_nmi_mode(uint32_t lvt_val) 223{ 224 return (lvt_val & (APIC_MODE_MASK | APIC_LVT_MASKED)) == APIC_DM_NMI; 225} 226 227int vm_apic_compare_prio(vm_vcpu_t *vcpu1, vm_vcpu_t *vcpu2) 228{ 229 return vcpu1->vcpu_arch.lapic->arb_prio - vcpu2->vcpu_arch.lapic->arb_prio; 230} 231 232static void UNUSED dump_vector(const char *name, void *bitmap) 233{ 234 int vec; 235 uint32_t *reg = bitmap; 236 237 printf("%s = 0x", name); 238 239 for (vec = MAX_APIC_VECTOR - APIC_VECTORS_PER_REG; 240 vec >= 0; vec -= APIC_VECTORS_PER_REG) { 241 printf("%08x", reg[vec >> 5]); 242 } 243 244 printf("\n"); 245} 246 247static int find_highest_vector(void *bitmap) 248{ 249 int vec; 250 uint32_t *reg = bitmap; 251 252 for (vec = MAX_APIC_VECTOR - APIC_VECTORS_PER_REG; 253 vec >= 0; vec -= APIC_VECTORS_PER_REG) { 254 if (reg[vec >> 5]) { 255 return fls(reg[vec >> 5]) - 1 + vec; 256 } 257 } 258 259 return -1; 260} 261 262static uint8_t UNUSED count_vectors(void *bitmap) 263{ 264 int vec; 265 uint32_t *reg = bitmap; 266 uint8_t count = 0; 267 268 for (vec = 0; vec < MAX_APIC_VECTOR; vec += APIC_VECTORS_PER_REG) { 269 count += hweight32(reg[vec >> 5]); 270 } 271 272 return count; 273} 274 275static inline int apic_search_irr(vm_lapic_t *apic) 276{ 277 return find_highest_vector(apic->regs + APIC_IRR); 278} 279 280static inline int apic_find_highest_irr(vm_lapic_t *apic) 281{ 282 int result; 283 284 if (!apic->irr_pending) { 285 return -1; 286 } 287 288 result = apic_search_irr(apic); 289 assert(result == -1 || result >= 16); 290 291 return result; 292} 293 294static inline void apic_set_irr(int vec, vm_lapic_t *apic) 295{ 296 if (vec != 0x30) { 297 apic_debug(5, "!settting irr 0x%x\n", vec); 298 } 299 300 apic->irr_pending = true; 301 apic_set_vector(vec, apic->regs + APIC_IRR); 302} 303 304static inline void apic_clear_irr(int vec, vm_lapic_t *apic) 305{ 306 apic_clear_vector(vec, apic->regs + APIC_IRR); 307 308 vec = apic_search_irr(apic); 309 apic->irr_pending = (vec != -1); 310} 311 312static inline void apic_set_isr(int vec, vm_lapic_t *apic) 313{ 314 if (apic_test_vector(vec, apic->regs + APIC_ISR)) { 315 return; 316 } 317 apic_set_vector(vec, apic->regs + APIC_ISR); 318 319 ++apic->isr_count; 320 /* 321 * ISR (in service register) bit is set when injecting an interrupt. 322 * The highest vector is injected. Thus the latest bit set matches 323 * the highest bit in ISR. 324 */ 325} 326 327static inline int apic_find_highest_isr(vm_lapic_t *apic) 328{ 329 int result; 330 331 /* 332 * Note that isr_count is always 1, and highest_isr_cache 333 * is always -1, with APIC virtualization enabled. 334 */ 335 if (!apic->isr_count) { 336 return -1; 337 } 338 if (apic->highest_isr_cache != -1) { 339 return apic->highest_isr_cache; 340 } 341 342 result = find_highest_vector(apic->regs + APIC_ISR); 343 assert(result == -1 || result >= 16); 344 345 return result; 346} 347 348static inline void apic_clear_isr(int vec, vm_lapic_t *apic) 349{ 350 if (!apic_test_vector(vec, apic->regs + APIC_ISR)) { 351 return; 352 } 353 apic_clear_vector(vec, apic->regs + APIC_ISR); 354 355 --apic->isr_count; 356 apic->highest_isr_cache = -1; 357} 358 359int vm_lapic_find_highest_irr(vm_vcpu_t *vcpu) 360{ 361 int highest_irr; 362 363 highest_irr = apic_find_highest_irr(vcpu->vcpu_arch.lapic); 364 365 return highest_irr; 366} 367 368static int __apic_accept_irq(vm_vcpu_t *vcpu, int delivery_mode, 369 int vector, int level, int trig_mode, 370 unsigned long *dest_map); 371 372int vm_apic_set_irq(vm_vcpu_t *vcpu, struct vm_lapic_irq *irq, 373 unsigned long *dest_map) 374{ 375 return __apic_accept_irq(vcpu, irq->delivery_mode, irq->vector, 376 irq->level, irq->trig_mode, dest_map); 377} 378 379void vm_apic_update_tmr(vm_vcpu_t *vcpu, uint32_t *tmr) 380{ 381 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 382 int i; 383 384 for (i = 0; i < 8; i++) { 385 apic_set_reg(apic, APIC_TMR + 0x10 * i, tmr[i]); 386 } 387} 388 389static void apic_update_ppr(vm_vcpu_t *vcpu) 390{ 391 uint32_t tpr, isrv, ppr, old_ppr; 392 int isr; 393 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 394 395 old_ppr = vm_apic_get_reg(apic, APIC_PROCPRI); 396 tpr = vm_apic_get_reg(apic, APIC_TASKPRI); 397 isr = apic_find_highest_isr(apic); 398 isrv = (isr != -1) ? isr : 0; 399 400 if ((tpr & 0xf0) >= (isrv & 0xf0)) { 401 ppr = tpr & 0xff; 402 } else { 403 ppr = isrv & 0xf0; 404 } 405 406 apic_debug(6, "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x\n", 407 apic, ppr, isr, isrv); 408 409 if (old_ppr != ppr) { 410 apic_set_reg(apic, APIC_PROCPRI, ppr); 411 if (ppr < old_ppr) { 412 /* Might have unmasked some pending interrupts */ 413 vm_vcpu_accept_interrupt(vcpu); 414 } 415 } 416} 417 418static void apic_set_tpr(vm_vcpu_t *vcpu, uint32_t tpr) 419{ 420 apic_set_reg(vcpu->vcpu_arch.lapic, APIC_TASKPRI, tpr); 421 apic_debug(3, "vcpu %d lapic TPR set to %d\n", vcpu->vcpu_id, tpr); 422 apic_update_ppr(vcpu); 423} 424 425int vm_apic_match_physical_addr(vm_lapic_t *apic, uint16_t dest) 426{ 427 return dest == 0xff || vm_apic_id(apic) == dest; 428} 429 430int vm_apic_match_logical_addr(vm_lapic_t *apic, uint8_t mda) 431{ 432 int result = 0; 433 uint32_t logical_id; 434 435 logical_id = GET_APIC_LOGICAL_ID(vm_apic_get_reg(apic, APIC_LDR)); 436 437 switch (vm_apic_get_reg(apic, APIC_DFR)) { 438 case APIC_DFR_FLAT: 439 if (logical_id & mda) { 440 result = 1; 441 } 442 break; 443 case APIC_DFR_CLUSTER: 444 if (((logical_id >> 4) == (mda >> 0x4)) 445 && (logical_id & mda & 0xf)) { 446 result = 1; 447 } 448 break; 449 default: 450 apic_debug(1, "Bad DFR: %08x\n", vm_apic_get_reg(apic, APIC_DFR)); 451 break; 452 } 453 454 return result; 455} 456 457int vm_apic_match_dest(vm_vcpu_t *vcpu, vm_lapic_t *source, 458 int short_hand, int dest, int dest_mode) 459{ 460 int result = 0; 461 vm_lapic_t *target = vcpu->vcpu_arch.lapic; 462 463 assert(target); 464 switch (short_hand) { 465 case APIC_DEST_NOSHORT: 466 if (dest_mode == 0) 467 /* Physical mode. */ 468 { 469 result = vm_apic_match_physical_addr(target, dest); 470 } else 471 /* Logical mode. */ 472 { 473 result = vm_apic_match_logical_addr(target, dest); 474 } 475 break; 476 case APIC_DEST_SELF: 477 result = (target == source); 478 break; 479 case APIC_DEST_ALLINC: 480 result = 1; 481 break; 482 case APIC_DEST_ALLBUT: 483 result = (target != source); 484 break; 485 default: 486 apic_debug(2, "apic: Bad dest shorthand value %x\n", 487 short_hand); 488 break; 489 } 490 491 apic_debug(4, "target %p, source %p, dest 0x%x, " 492 "dest_mode 0x%x, short_hand 0x%x", 493 target, source, dest, dest_mode, short_hand); 494 if (result) { 495 apic_debug(4, " MATCH\n"); 496 } else { 497 apic_debug(4, "\n"); 498 } 499 500 return result; 501} 502 503int vm_irq_delivery_to_apic(vm_vcpu_t *src_vcpu, struct vm_lapic_irq *irq, unsigned long *dest_map) 504{ 505 int i, r = -1; 506 vm_lapic_t *src = src_vcpu->vcpu_arch.lapic; 507 vm_t *vm = src_vcpu->vm; 508 509 vm_vcpu_t *lowest = NULL; 510 511 if (irq->shorthand == APIC_DEST_SELF) { 512 return vm_apic_set_irq(src_vcpu, irq, dest_map); 513 } 514 515 vm_vcpu_t *dest_vcpu = vm->vcpus[BOOT_VCPU]; 516 517 if (!vm_apic_hw_enabled(dest_vcpu->vcpu_arch.lapic)) { 518 return r; 519 } 520 521 if (!vm_apic_match_dest(dest_vcpu, src, irq->shorthand, 522 irq->dest_id, irq->dest_mode)) { 523 return r; 524 } 525 526 if (!vm_is_dm_lowest_prio(irq) || (vm_apic_enabled(dest_vcpu->vcpu_arch.lapic))) { 527 r = vm_apic_set_irq(dest_vcpu, irq, dest_map); 528 } 529 530 return r; 531} 532 533/* 534 * Add a pending IRQ into lapic. 535 * Return 1 if successfully added and 0 if discarded. 536 */ 537static int __apic_accept_irq(vm_vcpu_t *vcpu, int delivery_mode, 538 int vector, int level, int trig_mode, 539 unsigned long *dest_map) 540{ 541 int result = 0; 542 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 543 544 switch (delivery_mode) { 545 case APIC_DM_LOWEST: 546 apic->arb_prio++; 547 case APIC_DM_FIXED: 548 /* FIXME add logic for vcpu on reset */ 549 if (!vm_apic_enabled(apic)) { 550 break; 551 } 552 apic_debug(4, "####fixed ipi 0x%x to vcpu %d\n", vector, vcpu->vcpu_id); 553 554 result = 1; 555 apic_set_irr(vector, apic); 556 vm_vcpu_accept_interrupt(vcpu); 557 break; 558 559 case APIC_DM_NMI: 560 case APIC_DM_REMRD: 561 result = 1; 562 vm_vcpu_accept_interrupt(vcpu); 563 break; 564 565 case APIC_DM_SMI: 566 apic_debug(2, "Ignoring guest SMI\n"); 567 break; 568 569 case APIC_DM_INIT: 570 apic_debug(2, "Got init ipi on vcpu %d\n", vcpu->vcpu_id); 571 if (!trig_mode || level) { 572 if (apic->state == LAPIC_STATE_RUN) { 573 /* Already running, ignore inits */ 574 break; 575 } 576 result = 1; 577 vm_lapic_reset(vcpu); 578 apic->arb_prio = vm_apic_id(apic); 579 apic->state = LAPIC_STATE_WAITSIPI; 580 } else { 581 apic_debug(2, "Ignoring de-assert INIT to vcpu %d\n", 582 vcpu->vcpu_id); 583 } 584 break; 585 586 case APIC_DM_STARTUP: 587 if (apic->state != LAPIC_STATE_WAITSIPI) { 588 apic_debug(1, "Received SIPI while processor was not in wait for SIPI state\n"); 589 } else { 590 apic_debug(2, "SIPI to vcpu %d vector 0x%02x\n", 591 vcpu->vcpu_id, vector); 592 result = 1; 593 apic->sipi_vector = vector; 594 apic->state = LAPIC_STATE_RUN; 595 596 /* Start the VCPU thread. */ 597 vm_start_ap_vcpu(vcpu, vector); 598 } 599 break; 600 601 case APIC_DM_EXTINT: 602 /* extints are handled by vm_apic_consume_extints */ 603 printf("extint should not come to this function. vcpu %d\n", vcpu->vcpu_id); 604 assert(0); 605 break; 606 607 default: 608 printf("TODO: unsupported lapic ipi delivery mode %x", delivery_mode); 609 assert(0); 610 break; 611 } 612 return result; 613} 614 615static int apic_set_eoi(vm_vcpu_t *vcpu) 616{ 617 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 618 int vector = apic_find_highest_isr(apic); 619 620 /* 621 * Not every write EOI will has corresponding ISR, 622 * one example is when Kernel check timer on setup_IO_APIC 623 */ 624 if (vector == -1) { 625 return vector; 626 } 627 628 apic_clear_isr(vector, apic); 629 apic_update_ppr(vcpu); 630 631 /* If another interrupt is pending, raise it */ 632 vm_vcpu_accept_interrupt(vcpu); 633 634 return vector; 635} 636 637static void apic_send_ipi(vm_vcpu_t *vcpu) 638{ 639 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 640 uint32_t icr_low = vm_apic_get_reg(apic, APIC_ICR); 641 uint32_t icr_high = vm_apic_get_reg(apic, APIC_ICR2); 642 struct vm_lapic_irq irq; 643 644 irq.vector = icr_low & APIC_VECTOR_MASK; 645 irq.delivery_mode = icr_low & APIC_MODE_MASK; 646 irq.dest_mode = icr_low & APIC_DEST_MASK; 647 irq.level = icr_low & APIC_INT_ASSERT; 648 irq.trig_mode = icr_low & APIC_INT_LEVELTRIG; 649 irq.shorthand = icr_low & APIC_SHORT_MASK; 650 irq.dest_id = GET_APIC_DEST_FIELD(icr_high); 651 652 apic_debug(3, "icr_high 0x%x, icr_low 0x%x, " 653 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " 654 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", 655 icr_high, icr_low, irq.shorthand, irq.dest_id, 656 irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode, 657 irq.vector); 658 659 vm_irq_delivery_to_apic(vcpu, &irq, NULL); 660} 661 662static uint32_t __apic_read(vm_lapic_t *apic, unsigned int offset) 663{ 664 uint32_t val = 0; 665 666 if (offset >= LAPIC_MMIO_LENGTH) { 667 return 0; 668 } 669 670 switch (offset) { 671 case APIC_ID: 672 val = vm_apic_id(apic) << 24; 673 break; 674 case APIC_ARBPRI: 675 apic_debug(2, "Access APIC ARBPRI register which is for P6\n"); 676 break; 677 678 case APIC_TMCCT: /* Timer CCR */ 679 break; 680 case APIC_PROCPRI: 681 val = vm_apic_get_reg(apic, offset); 682 break; 683 default: 684 val = vm_apic_get_reg(apic, offset); 685 break; 686 } 687 688 return val; 689} 690 691static void apic_manage_nmi_watchdog(vm_lapic_t *apic, uint32_t lvt0_val) 692{ 693 int nmi_wd_enabled = apic_lvt_nmi_mode(vm_apic_get_reg(apic, APIC_LVT0)); 694 695 if (apic_lvt_nmi_mode(lvt0_val)) { 696 if (!nmi_wd_enabled) { 697 apic_debug(4, "Receive NMI setting on APIC_LVT0 \n"); 698 } 699 } 700} 701 702static int apic_reg_write(vm_vcpu_t *vcpu, uint32_t reg, uint32_t val) 703{ 704 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 705 int ret = 0; 706 707 switch (reg) { 708 case APIC_ID: /* Local APIC ID */ 709 vm_apic_set_id(apic, val >> 24); 710 break; 711 712 case APIC_TASKPRI: 713 apic_set_tpr(vcpu, val & 0xff); 714 break; 715 716 case APIC_EOI: 717 apic_set_eoi(vcpu); 718 break; 719 720 case APIC_LDR: 721 vm_apic_set_ldr(apic, val & APIC_LDR_MASK); 722 break; 723 724 case APIC_DFR: 725 apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); 726 break; 727 728 case APIC_SPIV: { 729 uint32_t mask = 0x3ff; 730 if (vm_apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI) { 731 mask |= APIC_SPIV_DIRECTED_EOI; 732 } 733 apic_set_spiv(apic, val & mask); 734 if (!(val & APIC_SPIV_APIC_ENABLED)) { 735 int i; 736 uint32_t lvt_val; 737 738 for (i = 0; i < APIC_LVT_NUM; i++) { 739 lvt_val = vm_apic_get_reg(apic, 740 APIC_LVTT + 0x10 * i); 741 apic_set_reg(apic, APIC_LVTT + 0x10 * i, 742 lvt_val | APIC_LVT_MASKED); 743 } 744 // atomic_set(&apic->lapic_timer.pending, 0); 745 746 } 747 break; 748 } 749 case APIC_ICR: 750 /* No delay here, so we always clear the pending bit */ 751 apic_set_reg(apic, APIC_ICR, val & ~(BIT(12))); 752 apic_send_ipi(vcpu); 753 break; 754 755 case APIC_ICR2: 756 val &= 0xff000000; 757 apic_set_reg(apic, APIC_ICR2, val); 758 break; 759 760 case APIC_LVT0: 761 apic_manage_nmi_watchdog(apic, val); 762 case APIC_LVTTHMR: 763 case APIC_LVTPC: 764 case APIC_LVT1: 765 case APIC_LVTERR: 766 /* TODO: Check vector */ 767 if (!vm_apic_sw_enabled(apic)) { 768 val |= APIC_LVT_MASKED; 769 } 770 771 val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4]; 772 apic_set_reg(apic, reg, val); 773 774 break; 775 776 case APIC_LVTT: 777 apic_set_reg(apic, APIC_LVTT, val); 778 break; 779 780 case APIC_TMICT: 781 apic_set_reg(apic, APIC_TMICT, val); 782 break; 783 784 case APIC_TDCR: 785 apic_set_reg(apic, APIC_TDCR, val); 786 break; 787 788 default: 789 ret = 1; 790 break; 791 } 792 if (ret) { 793 apic_debug(2, "Local APIC Write to read-only register %x\n", reg); 794 } 795 return ret; 796} 797 798void vm_apic_mmio_write(vm_vcpu_t *vcpu, void *cookie, uint32_t offset, 799 int len, const uint32_t data) 800{ 801 (void)cookie; 802 803 /* 804 * APIC register must be aligned on 128-bits boundary. 805 * 32/64/128 bits registers must be accessed thru 32 bits. 806 * Refer SDM 8.4.1 807 */ 808 if (len != 4 || (offset & 0xf)) { 809 apic_debug(1, "apic write: bad size=%d %x\n", len, offset); 810 return; 811 } 812 813 /* too common printing */ 814 if (offset != APIC_EOI) 815 apic_debug(6, "lapic mmio write at %s: offset 0x%x with length 0x%x, and value is " 816 "0x%x\n", __func__, offset, len, data); 817 818 apic_reg_write(vcpu, offset & 0xff0, data); 819} 820 821static int apic_reg_read(vm_lapic_t *apic, uint32_t offset, int len, 822 void *data) 823{ 824 unsigned char alignment = offset & 0xf; 825 uint32_t result; 826 /* this bitmask has a bit cleared for each reserved register */ 827 static const uint64_t rmask = 0x43ff01ffffffe70cULL; 828 829 if ((alignment + len) > 4) { 830 apic_debug(2, "APIC READ: alignment error %x %d\n", 831 offset, len); 832 return 1; 833 } 834 835 if (offset > 0x3f0 || !(rmask & (1ULL << (offset >> 4)))) { 836 apic_debug(2, "APIC_READ: read reserved register %x\n", 837 offset); 838 return 1; 839 } 840 841 result = __apic_read(apic, offset & ~0xf); 842 843 switch (len) { 844 case 1: 845 case 2: 846 case 4: 847 memcpy(data, (char *)&result + alignment, len); 848 break; 849 default: 850 apic_debug(2, "Local APIC read with len = %x, " 851 "should be 1,2, or 4 instead\n", len); 852 break; 853 } 854 return 0; 855} 856 857void vm_apic_mmio_read(vm_vcpu_t *vcpu, void *cookie, uint32_t offset, 858 int len, uint32_t *data) 859{ 860 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 861 (void)cookie; 862 863 apic_reg_read(apic, offset, len, data); 864 865 apic_debug(6, "lapic mmio read on vcpu %d, reg %08x = %08x\n", vcpu->vcpu_id, offset, *data); 866 867 return; 868} 869 870memory_fault_result_t apic_fault_callback(vm_t *vm, vm_vcpu_t *vcpu, uintptr_t fault_addr, size_t fault_length, 871 void *cookie) 872{ 873 uint32_t data; 874 if (is_vcpu_read_fault(vcpu)) { 875 vm_apic_mmio_read(vcpu, cookie, APIC_DEFAULT_PHYS_BASE - fault_addr, fault_length, &data); 876 set_vcpu_fault_data(vcpu, data); 877 } else { 878 data = get_vcpu_fault_data(vcpu); 879 vm_apic_mmio_write(vcpu, cookie, APIC_DEFAULT_PHYS_BASE - fault_addr, fault_length, data); 880 } 881 advance_vcpu_fault(vcpu); 882 return FAULT_HANDLED; 883} 884 885void vm_free_lapic(vm_vcpu_t *vcpu) 886{ 887 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 888 889 if (!apic) { 890 return; 891 } 892 893 if (apic->regs) { 894 free(apic->regs); 895 } 896 897 free(apic); 898} 899 900void vm_lapic_set_base_msr(vm_vcpu_t *vcpu, uint32_t value) 901{ 902 apic_debug(2, "IA32_APIC_BASE MSR set to %08x on vcpu %d\n", value, vcpu->vcpu_id); 903 904 if (!(value & MSR_IA32_APICBASE_ENABLE)) { 905 printf("Warning! Local apic has been disabled by MSR on vcpu %d. " 906 "This will probably not work!\n", vcpu->vcpu_id); 907 } 908 909 vcpu->vcpu_arch.lapic->apic_base = value; 910} 911 912uint32_t vm_lapic_get_base_msr(vm_vcpu_t *vcpu) 913{ 914 uint32_t value = vcpu->vcpu_arch.lapic->apic_base; 915 916 if (vm_vcpu_is_bsp(vcpu)) { 917 value |= MSR_IA32_APICBASE_BSP; 918 } else { 919 value &= ~MSR_IA32_APICBASE_BSP; 920 } 921 922 apic_debug(2, "Read from IA32_APIC_BASE MSR returns %08x on vcpu %d\n", value, vcpu->vcpu_id); 923 924 return value; 925} 926 927void vm_lapic_reset(vm_vcpu_t *vcpu) 928{ 929 vm_lapic_t *apic; 930 int i; 931 932 apic_debug(4, "%s\n", __func__); 933 934 assert(vcpu); 935 apic = vcpu->vcpu_arch.lapic; 936 assert(apic != NULL); 937 938 /* Stop the timer in case it's a reset to an active apic */ 939 940 vm_apic_set_id(apic, vcpu->vcpu_id); /* In agreement with ACPI code */ 941 apic_set_reg(apic, APIC_LVR, APIC_VERSION); 942 943 for (i = 0; i < APIC_LVT_NUM; i++) { 944 apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); 945 } 946 947 apic_set_reg(apic, APIC_DFR, 0xffffffffU); 948 apic_set_spiv(apic, 0xff); 949 apic_set_reg(apic, APIC_TASKPRI, 0); 950 vm_apic_set_ldr(apic, 0); 951 apic_set_reg(apic, APIC_ESR, 0); 952 apic_set_reg(apic, APIC_ICR, 0); 953 apic_set_reg(apic, APIC_ICR2, 0); 954 apic_set_reg(apic, APIC_TDCR, 0); 955 apic_set_reg(apic, APIC_TMICT, 0); 956 for (i = 0; i < 8; i++) { 957 apic_set_reg(apic, APIC_IRR + 0x10 * i, 0); 958 apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); 959 apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); 960 } 961 apic->irr_pending = 0; 962 apic->isr_count = 0; 963 apic->highest_isr_cache = -1; 964 apic_update_ppr(vcpu); 965 966 vcpu->vcpu_arch.lapic->arb_prio = 0; 967 968 apic_debug(4, "%s: vcpu=%p, id=%d, base_msr=" 969 "0x%016x\n", __func__, 970 vcpu, vm_apic_id(apic), 971 apic->apic_base); 972 973 if (vcpu->vcpu_id == BOOT_VCPU) { 974 /* Bootstrap boot vcpu lapic in virtual wire mode */ 975 apic_set_reg(apic, APIC_LVT0, 976 SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); 977 apic_set_reg(apic, APIC_SPIV, APIC_SPIV_APIC_ENABLED); 978 979 assert(vm_apic_sw_enabled(apic)); 980 } else { 981 apic_set_reg(apic, APIC_SPIV, 0); 982 } 983} 984 985int vm_create_lapic(vm_vcpu_t *vcpu, int enabled) 986{ 987 vm_lapic_t *apic; 988 989 assert(vcpu != NULL); 990 apic_debug(2, "apic_init %d\n", vcpu->vcpu_id); 991 992 apic = calloc(1, sizeof(*apic)); 993 if (!apic) { 994 goto nomem; 995 } 996 997 vcpu->vcpu_arch.lapic = apic; 998 999 apic->regs = calloc(1, sizeof(struct local_apic_regs)); // TODO this is a page; allocate a page 1000 if (!apic->regs) { 1001 printf("calloc apic regs error for vcpu %x\n", 1002 vcpu->vcpu_id); 1003 goto nomem_free_apic; 1004 } 1005 1006 if (enabled) { 1007 vm_lapic_set_base_msr(vcpu, APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE); 1008 } else { 1009 vm_lapic_set_base_msr(vcpu, APIC_DEFAULT_PHYS_BASE); 1010 } 1011 1012 /* mainly init registers */ 1013 vm_lapic_reset(vcpu); 1014 1015 return 0; 1016nomem_free_apic: 1017 free(apic); 1018nomem: 1019 return -1; 1020} 1021 1022/* Return 1 if this vcpu should accept a PIC interrupt */ 1023int vm_apic_accept_pic_intr(vm_vcpu_t *vcpu) 1024{ 1025 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 1026 uint32_t lvt0 = vm_apic_get_reg(apic, APIC_LVT0); 1027 1028 return ((lvt0 & APIC_LVT_MASKED) == 0 && 1029 GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT && 1030 vm_apic_sw_enabled(vcpu->vcpu_arch.lapic)); 1031} 1032 1033/* Service an interrupt */ 1034int vm_apic_get_interrupt(vm_vcpu_t *vcpu) 1035{ 1036 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 1037 int vector = vm_apic_has_interrupt(vcpu); 1038 1039 if (vector == 1) { 1040 return pic_get_interrupt(vcpu->vm); 1041 } else if (vector == -1) { 1042 return -1; 1043 } 1044 1045 apic_set_isr(vector, apic); 1046 apic_update_ppr(vcpu); 1047 apic_clear_irr(vector, apic); 1048 return vector; 1049} 1050 1051/* Return which vector is next up for servicing */ 1052int vm_apic_has_interrupt(vm_vcpu_t *vcpu) 1053{ 1054 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 1055 int highest_irr; 1056 1057 if (vm_apic_accept_pic_intr(vcpu) && pic_has_interrupt(vcpu->vm)) { 1058 return 1; 1059 } 1060 1061 highest_irr = apic_find_highest_irr(apic); 1062 if ((highest_irr == -1) || 1063 ((highest_irr & 0xF0) <= vm_apic_get_reg(apic, APIC_PROCPRI))) { 1064 return -1; 1065 } 1066 1067 return highest_irr; 1068} 1069 1070#if 0 1071int vm_apic_local_deliver(vm_vcpu_t *vcpu, int lvt_type) 1072{ 1073 vm_lapic_t *apic = vcpu->vcpu_arch.lapic; 1074 uint32_t reg = vm_apic_get_reg(apic, lvt_type); 1075 int vector, mode, trig_mode; 1076 1077 if (!(reg & APIC_LVT_MASKED)) { 1078 vector = reg & APIC_VECTOR_MASK; 1079 mode = reg & APIC_MODE_MASK; 1080 trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; 1081 return __apic_accept_irq(vcpu, mode, vector, 1, trig_mode, NULL); 1082 } 1083 return 0; 1084} 1085#endif 1086