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