xref: /kvm-unit-tests/x86/apic.c (revision 9111ccab0bb42d93d9f2b84c9089b5790e763056)
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 #define ALTERNATE_APIC_BASE	0x42000000
108 
109 static void test_apicbase(void)
110 {
111     u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE);
112     u32 lvr = apic_read(APIC_LVR);
113     u64 value;
114 
115     wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~(APIC_EN | APIC_EXTD));
116     wrmsr(MSR_IA32_APICBASE, ALTERNATE_APIC_BASE | APIC_BSP | APIC_EN);
117 
118     report_prefix_push("apicbase");
119 
120     report("relocate apic",
121            *(volatile u32 *)(ALTERNATE_APIC_BASE + APIC_LVR) == lvr);
122 
123     value = orig_apicbase | (1UL << cpuid_maxphyaddr());
124     report("reserved physaddr bits",
125            test_for_exception(GP_VECTOR, do_write_apicbase, &value));
126 
127     value = orig_apicbase | 1;
128     report("reserved low bits",
129            test_for_exception(GP_VECTOR, do_write_apicbase, &value));
130 
131     wrmsr(MSR_IA32_APICBASE, orig_apicbase);
132     apic_write(APIC_SPIV, 0x1ff);
133 
134     report_prefix_pop();
135 }
136 
137 static void do_write_apic_id(void *id)
138 {
139     apic_write(APIC_ID, *(u32 *)id);
140 }
141 
142 static void __test_apic_id(void * unused)
143 {
144     u32 id, newid;
145     u8  initial_xapic_id = cpuid(1).b >> 24;
146     u32 initial_x2apic_id = cpuid(0xb).d;
147     bool x2apic_mode = rdmsr(MSR_IA32_APICBASE) & APIC_EXTD;
148 
149     if (x2apic_mode)
150         reset_apic();
151 
152     id = apic_id();
153     report("xapic id matches cpuid", initial_xapic_id == id);
154 
155     newid = (id + 1) << 24;
156     report("writeable xapic id",
157             !test_for_exception(GP_VECTOR, do_write_apic_id, &newid) &&
158             id + 1 == apic_id());
159 
160     if (!enable_x2apic())
161         goto out;
162 
163     report("non-writeable x2apic id",
164             test_for_exception(GP_VECTOR, do_write_apic_id, &newid));
165     report("sane x2apic id", initial_xapic_id == (apic_id() & 0xff));
166 
167     /* old QEMUs do not set initial x2APIC ID */
168     report("x2apic id matches cpuid",
169            initial_xapic_id == (initial_x2apic_id & 0xff) &&
170            initial_x2apic_id == apic_id());
171 
172 out:
173     reset_apic();
174 
175     report("correct xapic id after reset", initial_xapic_id == apic_id());
176 
177     /* old KVMs do not reset xAPIC ID */
178     if (id != apic_id())
179         apic_write(APIC_ID, id << 24);
180 
181     if (x2apic_mode)
182         enable_x2apic();
183 }
184 
185 static void test_apic_id(void)
186 {
187     if (cpu_count() < 2)
188         return;
189 
190     on_cpu(1, __test_apic_id, NULL);
191 }
192 
193 static int ipi_count;
194 
195 static void self_ipi_isr(isr_regs_t *regs)
196 {
197     ++ipi_count;
198     eoi();
199 }
200 
201 static void test_self_ipi(void)
202 {
203     int vec = 0xf1;
204 
205     handle_irq(vec, self_ipi_isr);
206     irq_enable();
207     apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec,
208                    0);
209     asm volatile ("nop");
210     report("self ipi", ipi_count == 1);
211 }
212 
213 volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active;
214 
215 void sti_nop(char *p)
216 {
217     asm volatile (
218 		  ".globl post_sti \n\t"
219 		  "sti \n"
220 		  /*
221 		   * vmx won't exit on external interrupt if blocked-by-sti,
222 		   * so give it a reason to exit by accessing an unmapped page.
223 		   */
224 		  "post_sti: testb $0, %0 \n\t"
225 		  "nop \n\t"
226 		  "cli"
227 		  : : "m"(*p)
228 		  );
229     nmi_counter = nmi_counter_private;
230 }
231 
232 static void sti_loop(void *ignore)
233 {
234     unsigned k = 0;
235 
236     while (sti_loop_active) {
237 	sti_nop((char *)(ulong)((k++ * 4096) % (128 * 1024 * 1024)));
238     }
239 }
240 
241 static void nmi_handler(isr_regs_t *regs)
242 {
243     extern void post_sti(void);
244     ++nmi_counter_private;
245     nmi_hlt_counter += regs->rip == (ulong)post_sti;
246 }
247 
248 static void update_cr3(void *cr3)
249 {
250     write_cr3((ulong)cr3);
251 }
252 
253 static void test_sti_nmi(void)
254 {
255     unsigned old_counter;
256 
257     if (cpu_count() < 2) {
258 	return;
259     }
260 
261     handle_irq(2, nmi_handler);
262     on_cpu(1, update_cr3, (void *)read_cr3());
263 
264     sti_loop_active = 1;
265     on_cpu_async(1, sti_loop, 0);
266     while (nmi_counter < 30000) {
267 	old_counter = nmi_counter;
268 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 1);
269 	while (nmi_counter == old_counter) {
270 	    ;
271 	}
272     }
273     sti_loop_active = 0;
274     report("nmi-after-sti", nmi_hlt_counter == 0);
275 }
276 
277 static volatile bool nmi_done, nmi_flushed;
278 static volatile int nmi_received;
279 static volatile int cpu0_nmi_ctr1, cpu1_nmi_ctr1;
280 static volatile int cpu0_nmi_ctr2, cpu1_nmi_ctr2;
281 
282 static void multiple_nmi_handler(isr_regs_t *regs)
283 {
284     ++nmi_received;
285 }
286 
287 static void kick_me_nmi(void *blah)
288 {
289     while (!nmi_done) {
290 	++cpu1_nmi_ctr1;
291 	while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1 && !nmi_done) {
292 	    pause();
293 	}
294 	if (nmi_done) {
295 	    return;
296 	}
297 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
298 	/* make sure the NMI has arrived by sending an IPI after it */
299 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT
300 		       | 0x44, 0);
301 	++cpu1_nmi_ctr2;
302 	while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done) {
303 	    pause();
304 	}
305     }
306 }
307 
308 static void flush_nmi(isr_regs_t *regs)
309 {
310     nmi_flushed = true;
311     apic_write(APIC_EOI, 0);
312 }
313 
314 static void test_multiple_nmi(void)
315 {
316     int i;
317     bool ok = true;
318 
319     if (cpu_count() < 2) {
320 	return;
321     }
322 
323     sti();
324     handle_irq(2, multiple_nmi_handler);
325     handle_irq(0x44, flush_nmi);
326     on_cpu_async(1, kick_me_nmi, 0);
327     for (i = 0; i < 1000000; ++i) {
328 	nmi_flushed = false;
329 	nmi_received = 0;
330 	++cpu0_nmi_ctr1;
331 	while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1) {
332 	    pause();
333 	}
334 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
335 	while (!nmi_flushed) {
336 	    pause();
337 	}
338 	if (nmi_received != 2) {
339 	    ok = false;
340 	    break;
341 	}
342 	++cpu0_nmi_ctr2;
343 	while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2) {
344 	    pause();
345 	}
346     }
347     nmi_done = true;
348     report("multiple nmi", ok);
349 }
350 
351 static volatile int lvtt_counter = 0;
352 
353 static void lvtt_handler(isr_regs_t *regs)
354 {
355     lvtt_counter++;
356     eoi();
357 }
358 
359 static void test_apic_timer_one_shot(void)
360 {
361     uint64_t tsc1, tsc2;
362     static const uint32_t interval = 0x10000;
363 
364 #define APIC_LVT_TIMER_VECTOR    (0xee)
365 
366     handle_irq(APIC_LVT_TIMER_VECTOR, lvtt_handler);
367     irq_enable();
368 
369     /* One shot mode */
370     apic_write(APIC_LVTT, APIC_LVT_TIMER_ONESHOT |
371                APIC_LVT_TIMER_VECTOR);
372     /* Divider == 1 */
373     apic_write(APIC_TDCR, 0x0000000b);
374 
375     tsc1 = rdtsc();
376     /* Set "Initial Counter Register", which starts the timer */
377     apic_write(APIC_TMICT, interval);
378     while (!lvtt_counter);
379     tsc2 = rdtsc();
380 
381     /*
382      * For LVT Timer clock, SDM vol 3 10.5.4 says it should be
383      * derived from processor's bus clock (IIUC which is the same
384      * as TSC), however QEMU seems to be using nanosecond. In all
385      * cases, the following should satisfy on all modern
386      * processors.
387      */
388     report("APIC LVT timer one shot", (lvtt_counter == 1) &&
389            (tsc2 - tsc1 >= interval));
390 }
391 
392 int main()
393 {
394     setup_vm();
395     smp_init();
396     setup_idt();
397 
398     test_lapic_existence();
399 
400     mask_pic_interrupts();
401     test_apic_id();
402     test_enable_x2apic();
403     test_apicbase();
404 
405     test_self_ipi();
406 
407     test_sti_nmi();
408     test_multiple_nmi();
409 
410     test_apic_timer_one_shot();
411     test_tsc_deadline_timer();
412 
413     return report_summary();
414 }
415