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