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