xref: /kvm-unit-tests/x86/apic.c (revision e38858bce3bd3283b61ac7b32cf414ef6dcec3ae)
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