1 #include "libcflat.h" 2 #include "apic.h" 3 #include "vm.h" 4 #include "smp.h" 5 #include "desc.h" 6 #include "isr.h" 7 #include "msr.h" 8 #include "atomic.h" 9 10 #define MAX_TPR 0xf 11 12 static void test_lapic_existence(void) 13 { 14 u32 lvr; 15 16 lvr = apic_read(APIC_LVR); 17 printf("apic version: %x\n", lvr); 18 report("apic existence", (u16)lvr == 0x14); 19 } 20 21 #define TSC_DEADLINE_TIMER_VECTOR 0xef 22 #define BROADCAST_VECTOR 0xcf 23 24 static int tdt_count; 25 26 static void tsc_deadline_timer_isr(isr_regs_t *regs) 27 { 28 ++tdt_count; 29 eoi(); 30 } 31 32 static void __test_tsc_deadline_timer(void) 33 { 34 handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr); 35 irq_enable(); 36 37 wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC)); 38 asm volatile ("nop"); 39 report("tsc deadline timer", tdt_count == 1); 40 report("tsc deadline timer clearing", rdmsr(MSR_IA32_TSCDEADLINE) == 0); 41 } 42 43 static int enable_tsc_deadline_timer(void) 44 { 45 uint32_t lvtt; 46 47 if (cpuid(1).c & (1 << 24)) { 48 lvtt = APIC_LVT_TIMER_TSCDEADLINE | TSC_DEADLINE_TIMER_VECTOR; 49 apic_write(APIC_LVTT, lvtt); 50 return 1; 51 } else { 52 return 0; 53 } 54 } 55 56 static void test_tsc_deadline_timer(void) 57 { 58 if(enable_tsc_deadline_timer()) { 59 __test_tsc_deadline_timer(); 60 } else { 61 report_skip("tsc deadline timer not detected"); 62 } 63 } 64 65 static void do_write_apicbase(void *data) 66 { 67 wrmsr(MSR_IA32_APICBASE, *(u64 *)data); 68 } 69 70 void test_enable_x2apic(void) 71 { 72 u64 invalid_state = APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EXTD; 73 u64 apic_enabled = APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EN; 74 u64 x2apic_enabled = 75 APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EN | APIC_EXTD; 76 77 if (enable_x2apic()) { 78 printf("x2apic enabled\n"); 79 80 report("x2apic enabled to invalid state", 81 test_for_exception(GP_VECTOR, do_write_apicbase, 82 &invalid_state)); 83 report("x2apic enabled to apic enabled", 84 test_for_exception(GP_VECTOR, do_write_apicbase, 85 &apic_enabled)); 86 87 wrmsr(MSR_IA32_APICBASE, APIC_DEFAULT_PHYS_BASE | APIC_BSP); 88 report("disabled to invalid state", 89 test_for_exception(GP_VECTOR, do_write_apicbase, 90 &invalid_state)); 91 report("disabled to x2apic enabled", 92 test_for_exception(GP_VECTOR, do_write_apicbase, 93 &x2apic_enabled)); 94 95 wrmsr(MSR_IA32_APICBASE, apic_enabled); 96 report("apic enabled to invalid state", 97 test_for_exception(GP_VECTOR, do_write_apicbase, 98 &invalid_state)); 99 100 wrmsr(MSR_IA32_APICBASE, x2apic_enabled); 101 apic_write(APIC_SPIV, 0x1ff); 102 } else { 103 printf("x2apic not detected\n"); 104 105 report("enable unsupported x2apic", 106 test_for_exception(GP_VECTOR, do_write_apicbase, 107 &x2apic_enabled)); 108 } 109 } 110 111 static void verify_disabled_apic_mmio(void) 112 { 113 volatile u32 *lvr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_LVR); 114 volatile u32 *tpr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_TASKPRI); 115 u32 cr8 = read_cr8(); 116 117 memset((void *)APIC_DEFAULT_PHYS_BASE, 0xff, PAGE_SIZE); 118 report("*0xfee00030: %x", *lvr == ~0, *lvr); 119 report("CR8: %lx", read_cr8() == cr8, read_cr8()); 120 write_cr8(cr8 ^ MAX_TPR); 121 report("CR8: %lx", read_cr8() == (cr8 ^ MAX_TPR), read_cr8()); 122 report("*0xfee00080: %x", *tpr == ~0, *tpr); 123 write_cr8(cr8); 124 } 125 126 static void test_apic_disable(void) 127 { 128 volatile u32 *lvr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_LVR); 129 volatile u32 *tpr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_TASKPRI); 130 u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE); 131 u32 apic_version = apic_read(APIC_LVR); 132 u32 cr8 = read_cr8(); 133 134 report_prefix_push("apic_disable"); 135 assert_msg(orig_apicbase & APIC_EN, "APIC not enabled."); 136 137 disable_apic(); 138 report("Local apic disabled", !(rdmsr(MSR_IA32_APICBASE) & APIC_EN)); 139 report("CPUID.1H:EDX.APIC[bit 9] is clear", !(cpuid(1).d & (1 << 9))); 140 verify_disabled_apic_mmio(); 141 142 reset_apic(); 143 apic_write(APIC_SPIV, 0x1ff); 144 report("Local apic enabled in xAPIC mode", 145 (rdmsr(MSR_IA32_APICBASE) & (APIC_EN | APIC_EXTD)) == APIC_EN); 146 report("CPUID.1H:EDX.APIC[bit 9] is set", cpuid(1).d & (1 << 9)); 147 report("*0xfee00030: %x", *lvr == apic_version, *lvr); 148 report("*0xfee00080: %x", *tpr == cr8, *tpr); 149 write_cr8(cr8 ^ MAX_TPR); 150 report("*0xfee00080: %x", *tpr == (cr8 ^ MAX_TPR) << 4, *tpr); 151 write_cr8(cr8); 152 153 if (enable_x2apic()) { 154 apic_write(APIC_SPIV, 0x1ff); 155 report("Local apic enabled in x2APIC mode", 156 (rdmsr(MSR_IA32_APICBASE) & (APIC_EN | APIC_EXTD)) == 157 (APIC_EN | APIC_EXTD)); 158 report("CPUID.1H:EDX.APIC[bit 9] is set", cpuid(1).d & (1 << 9)); 159 verify_disabled_apic_mmio(); 160 if (!(orig_apicbase & APIC_EXTD)) 161 reset_apic(); 162 } 163 report_prefix_pop(); 164 } 165 166 #define ALTERNATE_APIC_BASE 0x42000000 167 168 static void test_apicbase(void) 169 { 170 u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE); 171 u32 lvr = apic_read(APIC_LVR); 172 u64 value; 173 174 wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~(APIC_EN | APIC_EXTD)); 175 wrmsr(MSR_IA32_APICBASE, ALTERNATE_APIC_BASE | APIC_BSP | APIC_EN); 176 177 report_prefix_push("apicbase"); 178 179 report("relocate apic", 180 *(volatile u32 *)(ALTERNATE_APIC_BASE + APIC_LVR) == lvr); 181 182 value = orig_apicbase | (1UL << cpuid_maxphyaddr()); 183 report("reserved physaddr bits", 184 test_for_exception(GP_VECTOR, do_write_apicbase, &value)); 185 186 value = orig_apicbase | 1; 187 report("reserved low bits", 188 test_for_exception(GP_VECTOR, do_write_apicbase, &value)); 189 190 wrmsr(MSR_IA32_APICBASE, orig_apicbase); 191 apic_write(APIC_SPIV, 0x1ff); 192 193 report_prefix_pop(); 194 } 195 196 static void do_write_apic_id(void *id) 197 { 198 apic_write(APIC_ID, *(u32 *)id); 199 } 200 201 static void __test_apic_id(void * unused) 202 { 203 u32 id, newid; 204 u8 initial_xapic_id = cpuid(1).b >> 24; 205 u32 initial_x2apic_id = cpuid(0xb).d; 206 bool x2apic_mode = rdmsr(MSR_IA32_APICBASE) & APIC_EXTD; 207 208 if (x2apic_mode) 209 reset_apic(); 210 211 id = apic_id(); 212 report("xapic id matches cpuid", initial_xapic_id == id); 213 214 newid = (id + 1) << 24; 215 report("writeable xapic id", 216 !test_for_exception(GP_VECTOR, do_write_apic_id, &newid) && 217 id + 1 == apic_id()); 218 219 if (!enable_x2apic()) 220 goto out; 221 222 report("non-writeable x2apic id", 223 test_for_exception(GP_VECTOR, do_write_apic_id, &newid)); 224 report("sane x2apic id", initial_xapic_id == (apic_id() & 0xff)); 225 226 /* old QEMUs do not set initial x2APIC ID */ 227 report("x2apic id matches cpuid", 228 initial_xapic_id == (initial_x2apic_id & 0xff) && 229 initial_x2apic_id == apic_id()); 230 231 out: 232 reset_apic(); 233 234 report("correct xapic id after reset", initial_xapic_id == apic_id()); 235 236 /* old KVMs do not reset xAPIC ID */ 237 if (id != apic_id()) 238 apic_write(APIC_ID, id << 24); 239 240 if (x2apic_mode) 241 enable_x2apic(); 242 } 243 244 static void test_apic_id(void) 245 { 246 if (cpu_count() < 2) 247 return; 248 249 on_cpu(1, __test_apic_id, NULL); 250 } 251 252 static int ipi_count; 253 254 static void self_ipi_isr(isr_regs_t *regs) 255 { 256 ++ipi_count; 257 eoi(); 258 } 259 260 static void test_self_ipi(void) 261 { 262 int vec = 0xf1; 263 264 handle_irq(vec, self_ipi_isr); 265 irq_enable(); 266 apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec, 267 0); 268 asm volatile ("nop"); 269 report("self ipi", ipi_count == 1); 270 } 271 272 volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active; 273 274 void sti_nop(char *p) 275 { 276 asm volatile ( 277 ".globl post_sti \n\t" 278 "sti \n" 279 /* 280 * vmx won't exit on external interrupt if blocked-by-sti, 281 * so give it a reason to exit by accessing an unmapped page. 282 */ 283 "post_sti: testb $0, %0 \n\t" 284 "nop \n\t" 285 "cli" 286 : : "m"(*p) 287 ); 288 nmi_counter = nmi_counter_private; 289 } 290 291 static void sti_loop(void *ignore) 292 { 293 unsigned k = 0; 294 295 while (sti_loop_active) { 296 sti_nop((char *)(ulong)((k++ * 4096) % (128 * 1024 * 1024))); 297 } 298 } 299 300 static void nmi_handler(isr_regs_t *regs) 301 { 302 extern void post_sti(void); 303 ++nmi_counter_private; 304 nmi_hlt_counter += regs->rip == (ulong)post_sti; 305 } 306 307 static void update_cr3(void *cr3) 308 { 309 write_cr3((ulong)cr3); 310 } 311 312 static void test_sti_nmi(void) 313 { 314 unsigned old_counter; 315 316 if (cpu_count() < 2) { 317 return; 318 } 319 320 handle_irq(2, nmi_handler); 321 on_cpu(1, update_cr3, (void *)read_cr3()); 322 323 sti_loop_active = 1; 324 on_cpu_async(1, sti_loop, 0); 325 while (nmi_counter < 30000) { 326 old_counter = nmi_counter; 327 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 1); 328 while (nmi_counter == old_counter) { 329 ; 330 } 331 } 332 sti_loop_active = 0; 333 report("nmi-after-sti", nmi_hlt_counter == 0); 334 } 335 336 static volatile bool nmi_done, nmi_flushed; 337 static volatile int nmi_received; 338 static volatile int cpu0_nmi_ctr1, cpu1_nmi_ctr1; 339 static volatile int cpu0_nmi_ctr2, cpu1_nmi_ctr2; 340 341 static void multiple_nmi_handler(isr_regs_t *regs) 342 { 343 ++nmi_received; 344 } 345 346 static void kick_me_nmi(void *blah) 347 { 348 while (!nmi_done) { 349 ++cpu1_nmi_ctr1; 350 while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1 && !nmi_done) { 351 pause(); 352 } 353 if (nmi_done) { 354 return; 355 } 356 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); 357 /* make sure the NMI has arrived by sending an IPI after it */ 358 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT 359 | 0x44, 0); 360 ++cpu1_nmi_ctr2; 361 while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done) { 362 pause(); 363 } 364 } 365 } 366 367 static void flush_nmi(isr_regs_t *regs) 368 { 369 nmi_flushed = true; 370 apic_write(APIC_EOI, 0); 371 } 372 373 static void test_multiple_nmi(void) 374 { 375 int i; 376 bool ok = true; 377 378 if (cpu_count() < 2) { 379 return; 380 } 381 382 sti(); 383 handle_irq(2, multiple_nmi_handler); 384 handle_irq(0x44, flush_nmi); 385 on_cpu_async(1, kick_me_nmi, 0); 386 for (i = 0; i < 1000000; ++i) { 387 nmi_flushed = false; 388 nmi_received = 0; 389 ++cpu0_nmi_ctr1; 390 while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1) { 391 pause(); 392 } 393 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); 394 while (!nmi_flushed) { 395 pause(); 396 } 397 if (nmi_received != 2) { 398 ok = false; 399 break; 400 } 401 ++cpu0_nmi_ctr2; 402 while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2) { 403 pause(); 404 } 405 } 406 nmi_done = true; 407 report("multiple nmi", ok); 408 } 409 410 static volatile int lvtt_counter = 0; 411 412 static void lvtt_handler(isr_regs_t *regs) 413 { 414 lvtt_counter++; 415 eoi(); 416 } 417 418 static void test_apic_timer_one_shot(void) 419 { 420 uint64_t tsc1, tsc2; 421 static const uint32_t interval = 0x10000; 422 423 #define APIC_LVT_TIMER_VECTOR (0xee) 424 425 handle_irq(APIC_LVT_TIMER_VECTOR, lvtt_handler); 426 irq_enable(); 427 428 /* One shot mode */ 429 apic_write(APIC_LVTT, APIC_LVT_TIMER_ONESHOT | 430 APIC_LVT_TIMER_VECTOR); 431 /* Divider == 1 */ 432 apic_write(APIC_TDCR, 0x0000000b); 433 434 tsc1 = rdtsc(); 435 /* Set "Initial Counter Register", which starts the timer */ 436 apic_write(APIC_TMICT, interval); 437 while (!lvtt_counter); 438 tsc2 = rdtsc(); 439 440 /* 441 * For LVT Timer clock, SDM vol 3 10.5.4 says it should be 442 * derived from processor's bus clock (IIUC which is the same 443 * as TSC), however QEMU seems to be using nanosecond. In all 444 * cases, the following should satisfy on all modern 445 * processors. 446 */ 447 report("APIC LVT timer one shot", (lvtt_counter == 1) && 448 (tsc2 - tsc1 >= interval)); 449 } 450 451 static atomic_t broadcast_counter; 452 453 static void broadcast_handler(isr_regs_t *regs) 454 { 455 atomic_inc(&broadcast_counter); 456 eoi(); 457 } 458 459 static bool broadcast_received(unsigned ncpus) 460 { 461 unsigned counter; 462 u64 start = rdtsc(); 463 464 do { 465 counter = atomic_read(&broadcast_counter); 466 if (counter >= ncpus) 467 break; 468 pause(); 469 } while (rdtsc() - start < 1000000000); 470 471 atomic_set(&broadcast_counter, 0); 472 473 return counter == ncpus; 474 } 475 476 static void test_physical_broadcast(void) 477 { 478 unsigned ncpus = cpu_count(); 479 unsigned long cr3 = read_cr3(); 480 u32 broadcast_address = enable_x2apic() ? 0xffffffff : 0xff; 481 482 handle_irq(BROADCAST_VECTOR, broadcast_handler); 483 for (int c = 1; c < ncpus; c++) 484 on_cpu(c, update_cr3, (void *)cr3); 485 486 printf("starting broadcast (%s)\n", enable_x2apic() ? "x2apic" : "xapic"); 487 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT | 488 BROADCAST_VECTOR, broadcast_address); 489 report("APIC physical broadcast address", broadcast_received(ncpus)); 490 491 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT | 492 BROADCAST_VECTOR | APIC_DEST_ALLINC, 0); 493 report("APIC physical broadcast shorthand", broadcast_received(ncpus)); 494 } 495 496 void wait_until_tmcct_is_zero(uint32_t initial_count, bool stop_when_half) 497 { 498 uint32_t tmcct = apic_read(APIC_TMCCT); 499 500 if (tmcct) { 501 while (tmcct > (initial_count / 2)) 502 tmcct = apic_read(APIC_TMCCT); 503 504 if ( stop_when_half ) 505 return; 506 507 /* Wait until the counter reach 0 or wrap-around */ 508 while ( tmcct <= (initial_count / 2) && tmcct > 0 ) 509 tmcct = apic_read(APIC_TMCCT); 510 } 511 } 512 513 static inline void apic_change_mode(unsigned long new_mode) 514 { 515 uint32_t lvtt; 516 517 lvtt = apic_read(APIC_LVTT); 518 apic_write(APIC_LVTT, (lvtt & ~APIC_LVT_TIMER_MASK) | new_mode); 519 } 520 521 static void test_apic_change_mode() 522 { 523 uint32_t tmict = 0x999999; 524 525 printf("starting apic change mode\n"); 526 527 apic_write(APIC_TMICT, tmict); 528 529 apic_change_mode(APIC_LVT_TIMER_PERIODIC); 530 531 report("TMICT value reset", apic_read(APIC_TMICT) == tmict); 532 533 /* Testing one-shot */ 534 apic_change_mode(APIC_LVT_TIMER_ONESHOT); 535 apic_write(APIC_TMICT, tmict); 536 report("TMCCT should have a non-zero value", apic_read(APIC_TMCCT)); 537 538 wait_until_tmcct_is_zero(tmict, false); 539 report("TMCCT should have reached 0", !apic_read(APIC_TMCCT)); 540 541 /* 542 * Write TMICT before changing mode from one-shot to periodic TMCCT should 543 * be reset to TMICT periodicly 544 */ 545 apic_write(APIC_TMICT, tmict); 546 wait_until_tmcct_is_zero(tmict, true); 547 apic_change_mode(APIC_LVT_TIMER_PERIODIC); 548 report("TMCCT should have a non-zero value", apic_read(APIC_TMCCT)); 549 550 /* 551 * After the change of mode, the counter should not be reset and continue 552 * counting down from where it was 553 */ 554 report("TMCCT should not be reset to TMICT value", apic_read(APIC_TMCCT) < (tmict / 2)); 555 wait_until_tmcct_is_zero(tmict, false); 556 report("TMCCT should be reset to the initial-count", apic_read(APIC_TMCCT) > (tmict / 2)); 557 558 wait_until_tmcct_is_zero(tmict, true); 559 /* 560 * Keep the same TMICT and change timer mode to one-shot 561 * TMCCT should be > 0 and count-down to 0 562 */ 563 apic_change_mode(APIC_LVT_TIMER_ONESHOT); 564 report("TMCCT should not be reset to init", apic_read(APIC_TMCCT) < (tmict / 2)); 565 wait_until_tmcct_is_zero(tmict, false); 566 report("TMCCT should have reach zero", !apic_read(APIC_TMCCT)); 567 568 /* now tmcct == 0 and tmict != 0 */ 569 apic_change_mode(APIC_LVT_TIMER_PERIODIC); 570 report("TMCCT should stay at zero", !apic_read(APIC_TMCCT)); 571 } 572 573 int main() 574 { 575 setup_vm(); 576 smp_init(); 577 578 test_lapic_existence(); 579 580 mask_pic_interrupts(); 581 test_apic_id(); 582 test_apic_disable(); 583 test_enable_x2apic(); 584 test_apicbase(); 585 586 test_self_ipi(); 587 test_physical_broadcast(); 588 589 test_sti_nmi(); 590 test_multiple_nmi(); 591 592 test_apic_timer_one_shot(); 593 test_apic_change_mode(); 594 test_tsc_deadline_timer(); 595 596 return report_summary(); 597 } 598