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