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