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_MODE (2 << 17) 19 #define TSC_DEADLINE_TIMER_VECTOR 0xef 20 #define MSR_IA32_TSC 0x00000010 21 #define MSR_IA32_TSCDEADLINE 0x000006e0 22 23 static int tdt_count; 24 25 static void tsc_deadline_timer_isr(isr_regs_t *regs) 26 { 27 ++tdt_count; 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 = TSC_DEADLINE_TIMER_MODE | 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 #define ALTERNATE_APIC_BASE 0x42000000 110 111 static void test_apicbase(void) 112 { 113 u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE); 114 u32 lvr = apic_read(APIC_LVR); 115 u64 value; 116 117 wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~(APIC_EN | APIC_EXTD)); 118 wrmsr(MSR_IA32_APICBASE, ALTERNATE_APIC_BASE | APIC_BSP | APIC_EN); 119 120 report_prefix_push("apicbase"); 121 122 report("relocate apic", 123 *(volatile u32 *)(ALTERNATE_APIC_BASE + APIC_LVR) == lvr); 124 125 value = orig_apicbase | (1UL << cpuid_maxphyaddr()); 126 report("reserved physaddr bits", 127 test_for_exception(GP_VECTOR, do_write_apicbase, &value)); 128 129 value = orig_apicbase | 1; 130 report("reserved low bits", 131 test_for_exception(GP_VECTOR, do_write_apicbase, &value)); 132 133 wrmsr(MSR_IA32_APICBASE, orig_apicbase); 134 apic_write(APIC_SPIV, 0x1ff); 135 136 report_prefix_pop(); 137 } 138 139 static void do_write_apic_id(void *id) 140 { 141 apic_write(APIC_ID, *(u32 *)id); 142 } 143 144 static void __test_apic_id(void * unused) 145 { 146 u32 id, newid; 147 u8 initial_xapic_id = cpuid(1).b >> 24; 148 u32 initial_x2apic_id = cpuid(0xb).d; 149 bool x2apic_mode = rdmsr(MSR_IA32_APICBASE) & APIC_EXTD; 150 151 if (x2apic_mode) 152 reset_apic(); 153 154 id = apic_id(); 155 report("xapic id matches cpuid", initial_xapic_id == id); 156 157 newid = (id + 1) << 24; 158 report("writeable xapic id", 159 !test_for_exception(GP_VECTOR, do_write_apic_id, &newid) && 160 id + 1 == apic_id()); 161 162 if (!enable_x2apic()) 163 goto out; 164 165 report("non-writeable x2apic id", 166 test_for_exception(GP_VECTOR, do_write_apic_id, &newid)); 167 report("sane x2apic id", initial_xapic_id == (apic_id() & 0xff)); 168 169 /* old QEMUs do not set initial x2APIC ID */ 170 report("x2apic id matches cpuid", 171 initial_xapic_id == (initial_x2apic_id & 0xff) && 172 initial_x2apic_id == apic_id()); 173 174 out: 175 reset_apic(); 176 177 report("correct xapic id after reset", initial_xapic_id == apic_id()); 178 179 /* old KVMs do not reset xAPIC ID */ 180 if (id != apic_id()) 181 apic_write(APIC_ID, id << 24); 182 183 if (x2apic_mode) 184 enable_x2apic(); 185 } 186 187 static void test_apic_id(void) 188 { 189 if (cpu_count() < 2) 190 return; 191 192 on_cpu(1, __test_apic_id, NULL); 193 } 194 195 static int ipi_count; 196 197 static void self_ipi_isr(isr_regs_t *regs) 198 { 199 ++ipi_count; 200 eoi(); 201 } 202 203 static void test_self_ipi(void) 204 { 205 int vec = 0xf1; 206 207 handle_irq(vec, self_ipi_isr); 208 irq_enable(); 209 apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec, 210 0); 211 asm volatile ("nop"); 212 report("self ipi", ipi_count == 1); 213 } 214 215 volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active; 216 217 void sti_nop(char *p) 218 { 219 asm volatile ( 220 ".globl post_sti \n\t" 221 "sti \n" 222 /* 223 * vmx won't exit on external interrupt if blocked-by-sti, 224 * so give it a reason to exit by accessing an unmapped page. 225 */ 226 "post_sti: testb $0, %0 \n\t" 227 "nop \n\t" 228 "cli" 229 : : "m"(*p) 230 ); 231 nmi_counter = nmi_counter_private; 232 } 233 234 static void sti_loop(void *ignore) 235 { 236 unsigned k = 0; 237 238 while (sti_loop_active) { 239 sti_nop((char *)(ulong)((k++ * 4096) % (128 * 1024 * 1024))); 240 } 241 } 242 243 static void nmi_handler(isr_regs_t *regs) 244 { 245 extern void post_sti(void); 246 ++nmi_counter_private; 247 nmi_hlt_counter += regs->rip == (ulong)post_sti; 248 } 249 250 static void update_cr3(void *cr3) 251 { 252 write_cr3((ulong)cr3); 253 } 254 255 static void test_sti_nmi(void) 256 { 257 unsigned old_counter; 258 259 if (cpu_count() < 2) { 260 return; 261 } 262 263 handle_irq(2, nmi_handler); 264 on_cpu(1, update_cr3, (void *)read_cr3()); 265 266 sti_loop_active = 1; 267 on_cpu_async(1, sti_loop, 0); 268 while (nmi_counter < 30000) { 269 old_counter = nmi_counter; 270 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 1); 271 while (nmi_counter == old_counter) { 272 ; 273 } 274 } 275 sti_loop_active = 0; 276 report("nmi-after-sti", nmi_hlt_counter == 0); 277 } 278 279 static volatile bool nmi_done, nmi_flushed; 280 static volatile int nmi_received; 281 static volatile int cpu0_nmi_ctr1, cpu1_nmi_ctr1; 282 static volatile int cpu0_nmi_ctr2, cpu1_nmi_ctr2; 283 284 static void multiple_nmi_handler(isr_regs_t *regs) 285 { 286 ++nmi_received; 287 } 288 289 static void kick_me_nmi(void *blah) 290 { 291 while (!nmi_done) { 292 ++cpu1_nmi_ctr1; 293 while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1 && !nmi_done) { 294 pause(); 295 } 296 if (nmi_done) { 297 return; 298 } 299 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); 300 /* make sure the NMI has arrived by sending an IPI after it */ 301 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT 302 | 0x44, 0); 303 ++cpu1_nmi_ctr2; 304 while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done) { 305 pause(); 306 } 307 } 308 } 309 310 static void flush_nmi(isr_regs_t *regs) 311 { 312 nmi_flushed = true; 313 apic_write(APIC_EOI, 0); 314 } 315 316 static void test_multiple_nmi(void) 317 { 318 int i; 319 bool ok = true; 320 321 if (cpu_count() < 2) { 322 return; 323 } 324 325 sti(); 326 handle_irq(2, multiple_nmi_handler); 327 handle_irq(0x44, flush_nmi); 328 on_cpu_async(1, kick_me_nmi, 0); 329 for (i = 0; i < 1000000; ++i) { 330 nmi_flushed = false; 331 nmi_received = 0; 332 ++cpu0_nmi_ctr1; 333 while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1) { 334 pause(); 335 } 336 apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); 337 while (!nmi_flushed) { 338 pause(); 339 } 340 if (nmi_received != 2) { 341 ok = false; 342 break; 343 } 344 ++cpu0_nmi_ctr2; 345 while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2) { 346 pause(); 347 } 348 } 349 nmi_done = true; 350 report("multiple nmi", ok); 351 } 352 353 int main() 354 { 355 setup_vm(); 356 smp_init(); 357 setup_idt(); 358 359 test_lapic_existence(); 360 361 mask_pic_interrupts(); 362 test_apic_id(); 363 test_enable_x2apic(); 364 test_apicbase(); 365 366 test_self_ipi(); 367 368 test_sti_nmi(); 369 test_multiple_nmi(); 370 371 test_tsc_deadline_timer(); 372 373 return report_summary(); 374 } 375