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