xref: /kvm-unit-tests/x86/apic.c (revision 9b6bdb3f6ab6e47788c3cdf7217432bb8dd95b84)
17d36db35SAvi Kivity #include "libcflat.h"
27d36db35SAvi Kivity #include "apic.h"
37d36db35SAvi Kivity #include "vm.h"
4f2d2b7c7SAvi Kivity #include "smp.h"
5e7c37968SGleb Natapov #include "desc.h"
6110f0d93SGleb Natapov #include "isr.h"
722c7d929SJan Kiszka #include "msr.h"
87d36db35SAvi Kivity 
97d36db35SAvi Kivity static int g_fail;
107d36db35SAvi Kivity static int g_tests;
117d36db35SAvi Kivity 
127d36db35SAvi Kivity static void report(const char *msg, int pass)
137d36db35SAvi Kivity {
147d36db35SAvi Kivity     ++g_tests;
157d36db35SAvi Kivity     printf("%s: %s\n", msg, (pass ? "PASS" : "FAIL"));
167d36db35SAvi Kivity     if (!pass)
177d36db35SAvi Kivity         ++g_fail;
187d36db35SAvi Kivity }
197d36db35SAvi Kivity 
207d36db35SAvi Kivity static void test_lapic_existence(void)
217d36db35SAvi Kivity {
227d36db35SAvi Kivity     u32 lvr;
237d36db35SAvi Kivity 
247d36db35SAvi Kivity     lvr = apic_read(APIC_LVR);
257d36db35SAvi Kivity     printf("apic version: %x\n", lvr);
267d36db35SAvi Kivity     report("apic existence", (u16)lvr == 0x14);
277d36db35SAvi Kivity }
287d36db35SAvi Kivity 
29d423ca36SLiu, Jinsong #define TSC_DEADLINE_TIMER_MODE (2 << 17)
30d423ca36SLiu, Jinsong #define TSC_DEADLINE_TIMER_VECTOR 0xef
31d423ca36SLiu, Jinsong #define MSR_IA32_TSC            0x00000010
32d423ca36SLiu, Jinsong #define MSR_IA32_TSCDEADLINE    0x000006e0
33d423ca36SLiu, Jinsong 
34d423ca36SLiu, Jinsong static int tdt_count;
35d423ca36SLiu, Jinsong 
36d423ca36SLiu, Jinsong static void tsc_deadline_timer_isr(isr_regs_t *regs)
37d423ca36SLiu, Jinsong {
38d423ca36SLiu, Jinsong     ++tdt_count;
39d423ca36SLiu, Jinsong }
40d423ca36SLiu, Jinsong 
41d423ca36SLiu, Jinsong static void start_tsc_deadline_timer(void)
42d423ca36SLiu, Jinsong {
43d423ca36SLiu, Jinsong     handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr);
44d423ca36SLiu, Jinsong     irq_enable();
45d423ca36SLiu, Jinsong 
46d423ca36SLiu, Jinsong     wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC));
47d423ca36SLiu, Jinsong     asm volatile ("nop");
48d423ca36SLiu, Jinsong     report("tsc deadline timer", tdt_count == 1);
49d423ca36SLiu, Jinsong }
50d423ca36SLiu, Jinsong 
51d423ca36SLiu, Jinsong static int enable_tsc_deadline_timer(void)
52d423ca36SLiu, Jinsong {
53d423ca36SLiu, Jinsong     uint32_t lvtt;
54d423ca36SLiu, Jinsong 
55d423ca36SLiu, Jinsong     if (cpuid(1).c & (1 << 24)) {
56d423ca36SLiu, Jinsong         lvtt = TSC_DEADLINE_TIMER_MODE | TSC_DEADLINE_TIMER_VECTOR;
57d423ca36SLiu, Jinsong         apic_write(APIC_LVTT, lvtt);
58d423ca36SLiu, Jinsong         start_tsc_deadline_timer();
59d423ca36SLiu, Jinsong         return 1;
60d423ca36SLiu, Jinsong     } else {
61d423ca36SLiu, Jinsong         return 0;
62d423ca36SLiu, Jinsong     }
63d423ca36SLiu, Jinsong }
64d423ca36SLiu, Jinsong 
65d423ca36SLiu, Jinsong static void test_tsc_deadline_timer(void)
66d423ca36SLiu, Jinsong {
67d423ca36SLiu, Jinsong     if(enable_tsc_deadline_timer()) {
68d423ca36SLiu, Jinsong         printf("tsc deadline timer enabled\n");
69d423ca36SLiu, Jinsong     } else {
70d423ca36SLiu, Jinsong         printf("tsc deadline timer not detected\n");
71d423ca36SLiu, Jinsong     }
72d423ca36SLiu, Jinsong }
73d423ca36SLiu, Jinsong 
7422c7d929SJan Kiszka static void do_write_apicbase(void *data)
7522c7d929SJan Kiszka {
7622c7d929SJan Kiszka     set_exception_return(&&resume);
7722c7d929SJan Kiszka     wrmsr(MSR_IA32_APICBASE, *(u64 *)data);
7822c7d929SJan Kiszka resume:
7922c7d929SJan Kiszka     barrier();
8022c7d929SJan Kiszka }
817d36db35SAvi Kivity 
827d36db35SAvi Kivity void test_enable_x2apic(void)
837d36db35SAvi Kivity {
8422c7d929SJan Kiszka     u64 invalid_state = APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EXTD;
8522c7d929SJan Kiszka     u64 apic_enabled = APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EN;
8622c7d929SJan Kiszka     u64 x2apic_enabled =
8722c7d929SJan Kiszka         APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EN | APIC_EXTD;
8822c7d929SJan Kiszka 
897d36db35SAvi Kivity     if (enable_x2apic()) {
907d36db35SAvi Kivity         printf("x2apic enabled\n");
9122c7d929SJan Kiszka 
9222c7d929SJan Kiszka         report("x2apic enabled to invalid state",
9322c7d929SJan Kiszka                test_for_exception(GP_VECTOR, do_write_apicbase,
9422c7d929SJan Kiszka                                   &invalid_state));
9522c7d929SJan Kiszka         report("x2apic enabled to apic enabled",
9622c7d929SJan Kiszka                test_for_exception(GP_VECTOR, do_write_apicbase,
9722c7d929SJan Kiszka                                   &apic_enabled));
9822c7d929SJan Kiszka 
9922c7d929SJan Kiszka         wrmsr(MSR_IA32_APICBASE, APIC_DEFAULT_PHYS_BASE | APIC_BSP);
10022c7d929SJan Kiszka         report("disabled to invalid state",
10122c7d929SJan Kiszka                test_for_exception(GP_VECTOR, do_write_apicbase,
10222c7d929SJan Kiszka                                   &invalid_state));
10322c7d929SJan Kiszka         report("disabled to x2apic enabled",
10422c7d929SJan Kiszka                test_for_exception(GP_VECTOR, do_write_apicbase,
10522c7d929SJan Kiszka                                   &x2apic_enabled));
10622c7d929SJan Kiszka 
10722c7d929SJan Kiszka         wrmsr(MSR_IA32_APICBASE, apic_enabled);
10822c7d929SJan Kiszka         report("apic enabled to invalid state",
10922c7d929SJan Kiszka                test_for_exception(GP_VECTOR, do_write_apicbase,
11022c7d929SJan Kiszka                                   &invalid_state));
11122c7d929SJan Kiszka 
11222c7d929SJan Kiszka         wrmsr(MSR_IA32_APICBASE, x2apic_enabled);
11322c7d929SJan Kiszka         apic_write(APIC_SPIV, 0x1ff);
1147d36db35SAvi Kivity     } else {
1157d36db35SAvi Kivity         printf("x2apic not detected\n");
11622c7d929SJan Kiszka 
11722c7d929SJan Kiszka         report("enable unsupported x2apic",
11822c7d929SJan Kiszka                test_for_exception(GP_VECTOR, do_write_apicbase,
11922c7d929SJan Kiszka                                   &x2apic_enabled));
1207d36db35SAvi Kivity     }
1217d36db35SAvi Kivity }
1227d36db35SAvi Kivity 
123*9b6bdb3fSJan Kiszka #define ALTERNATE_APIC_BASE	0x42000000
124*9b6bdb3fSJan Kiszka 
125*9b6bdb3fSJan Kiszka static void test_apicbase(void)
126*9b6bdb3fSJan Kiszka {
127*9b6bdb3fSJan Kiszka     u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE);
128*9b6bdb3fSJan Kiszka     u32 lvr = apic_read(APIC_LVR);
129*9b6bdb3fSJan Kiszka     u64 value;
130*9b6bdb3fSJan Kiszka 
131*9b6bdb3fSJan Kiszka     wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~(APIC_EN | APIC_EXTD));
132*9b6bdb3fSJan Kiszka     wrmsr(MSR_IA32_APICBASE, ALTERNATE_APIC_BASE | APIC_BSP | APIC_EN);
133*9b6bdb3fSJan Kiszka 
134*9b6bdb3fSJan Kiszka     report("relocate apic",
135*9b6bdb3fSJan Kiszka            *(volatile u32 *)(ALTERNATE_APIC_BASE + APIC_LVR) == lvr);
136*9b6bdb3fSJan Kiszka 
137*9b6bdb3fSJan Kiszka     value = orig_apicbase | (1UL << (cpuid(0x80000008).a & 0xff));
138*9b6bdb3fSJan Kiszka     report("apicbase: reserved physaddr bits",
139*9b6bdb3fSJan Kiszka            test_for_exception(GP_VECTOR, do_write_apicbase, &value));
140*9b6bdb3fSJan Kiszka 
141*9b6bdb3fSJan Kiszka     value = orig_apicbase | 1;
142*9b6bdb3fSJan Kiszka     report("apicbase: reserved low bits",
143*9b6bdb3fSJan Kiszka            test_for_exception(GP_VECTOR, do_write_apicbase, &value));
144*9b6bdb3fSJan Kiszka 
145*9b6bdb3fSJan Kiszka     wrmsr(MSR_IA32_APICBASE, orig_apicbase);
146*9b6bdb3fSJan Kiszka     apic_write(APIC_SPIV, 0x1ff);
147*9b6bdb3fSJan Kiszka }
148*9b6bdb3fSJan Kiszka 
1497d36db35SAvi Kivity static void eoi(void)
1507d36db35SAvi Kivity {
1517d36db35SAvi Kivity     apic_write(APIC_EOI, 0);
1527d36db35SAvi Kivity }
1537d36db35SAvi Kivity 
1547d36db35SAvi Kivity static int ipi_count;
1557d36db35SAvi Kivity 
1567d36db35SAvi Kivity static void self_ipi_isr(isr_regs_t *regs)
1577d36db35SAvi Kivity {
1587d36db35SAvi Kivity     ++ipi_count;
1597d36db35SAvi Kivity     eoi();
1607d36db35SAvi Kivity }
1617d36db35SAvi Kivity 
1627d36db35SAvi Kivity static void test_self_ipi(void)
1637d36db35SAvi Kivity {
1647d36db35SAvi Kivity     int vec = 0xf1;
1657d36db35SAvi Kivity 
166d51bd17eSGleb Natapov     handle_irq(vec, self_ipi_isr);
1677d36db35SAvi Kivity     irq_enable();
1687d36db35SAvi Kivity     apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec,
1697d36db35SAvi Kivity                    0);
1707d36db35SAvi Kivity     asm volatile ("nop");
1717d36db35SAvi Kivity     report("self ipi", ipi_count == 1);
1727d36db35SAvi Kivity }
1737d36db35SAvi Kivity 
1747d36db35SAvi Kivity static void set_ioapic_redir(unsigned line, unsigned vec)
1757d36db35SAvi Kivity {
1767d36db35SAvi Kivity     ioapic_redir_entry_t e = {
1777d36db35SAvi Kivity         .vector = vec,
1787d36db35SAvi Kivity         .delivery_mode = 0,
1797d36db35SAvi Kivity         .trig_mode = 0,
1807d36db35SAvi Kivity     };
1817d36db35SAvi Kivity 
1827d36db35SAvi Kivity     ioapic_write_redir(line, e);
1837d36db35SAvi Kivity }
1847d36db35SAvi Kivity 
1857d36db35SAvi Kivity static void set_irq_line(unsigned line, int val)
1867d36db35SAvi Kivity {
1877d36db35SAvi Kivity     asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line)));
1887d36db35SAvi Kivity }
1897d36db35SAvi Kivity 
1907d36db35SAvi Kivity static void toggle_irq_line(unsigned line)
1917d36db35SAvi Kivity {
1927d36db35SAvi Kivity     set_irq_line(line, 1);
1937d36db35SAvi Kivity     set_irq_line(line, 0);
1947d36db35SAvi Kivity }
1957d36db35SAvi Kivity 
1967d36db35SAvi Kivity static int g_isr_77;
1977d36db35SAvi Kivity 
1987d36db35SAvi Kivity static void ioapic_isr_77(isr_regs_t *regs)
1997d36db35SAvi Kivity {
2007d36db35SAvi Kivity     ++g_isr_77;
2017d36db35SAvi Kivity     eoi();
2027d36db35SAvi Kivity }
2037d36db35SAvi Kivity 
2047d36db35SAvi Kivity static void test_ioapic_intr(void)
2057d36db35SAvi Kivity {
206d51bd17eSGleb Natapov     handle_irq(0x77, ioapic_isr_77);
207598f9fc4SJoerg Roedel     set_ioapic_redir(0x0e, 0x77);
208598f9fc4SJoerg Roedel     toggle_irq_line(0x0e);
2097d36db35SAvi Kivity     asm volatile ("nop");
2107d36db35SAvi Kivity     report("ioapic interrupt", g_isr_77 == 1);
2117d36db35SAvi Kivity }
2127d36db35SAvi Kivity 
2137d36db35SAvi Kivity static int g_78, g_66, g_66_after_78;
2147d36db35SAvi Kivity static ulong g_66_rip, g_78_rip;
2157d36db35SAvi Kivity 
2167d36db35SAvi Kivity static void ioapic_isr_78(isr_regs_t *regs)
2177d36db35SAvi Kivity {
2187d36db35SAvi Kivity     ++g_78;
2197d36db35SAvi Kivity     g_78_rip = regs->rip;
2207d36db35SAvi Kivity     eoi();
2217d36db35SAvi Kivity }
2227d36db35SAvi Kivity 
2237d36db35SAvi Kivity static void ioapic_isr_66(isr_regs_t *regs)
2247d36db35SAvi Kivity {
2257d36db35SAvi Kivity     ++g_66;
2267d36db35SAvi Kivity     if (g_78)
2277d36db35SAvi Kivity         ++g_66_after_78;
2287d36db35SAvi Kivity     g_66_rip = regs->rip;
2297d36db35SAvi Kivity     eoi();
2307d36db35SAvi Kivity }
2317d36db35SAvi Kivity 
2327d36db35SAvi Kivity static void test_ioapic_simultaneous(void)
2337d36db35SAvi Kivity {
234d51bd17eSGleb Natapov     handle_irq(0x78, ioapic_isr_78);
235d51bd17eSGleb Natapov     handle_irq(0x66, ioapic_isr_66);
236598f9fc4SJoerg Roedel     set_ioapic_redir(0x0e, 0x78);
237598f9fc4SJoerg Roedel     set_ioapic_redir(0x0f, 0x66);
2387d36db35SAvi Kivity     irq_disable();
239598f9fc4SJoerg Roedel     toggle_irq_line(0x0f);
240598f9fc4SJoerg Roedel     toggle_irq_line(0x0e);
2417d36db35SAvi Kivity     irq_enable();
2427d36db35SAvi Kivity     asm volatile ("nop");
2437d36db35SAvi Kivity     report("ioapic simultaneous interrupt",
2447d36db35SAvi Kivity            g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip);
2457d36db35SAvi Kivity }
2467d36db35SAvi Kivity 
247f2d2b7c7SAvi Kivity volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active;
248f2d2b7c7SAvi Kivity 
249f2d2b7c7SAvi Kivity void sti_nop(char *p)
250f2d2b7c7SAvi Kivity {
251f2d2b7c7SAvi Kivity     asm volatile (
252f2d2b7c7SAvi Kivity 		  ".globl post_sti \n\t"
253f2d2b7c7SAvi Kivity 		  "sti \n"
254f2d2b7c7SAvi Kivity 		  /*
255f2d2b7c7SAvi Kivity 		   * vmx won't exit on external interrupt if blocked-by-sti,
256f2d2b7c7SAvi Kivity 		   * so give it a reason to exit by accessing an unmapped page.
257f2d2b7c7SAvi Kivity 		   */
258f2d2b7c7SAvi Kivity 		  "post_sti: testb $0, %0 \n\t"
259f2d2b7c7SAvi Kivity 		  "nop \n\t"
260f2d2b7c7SAvi Kivity 		  "cli"
261f2d2b7c7SAvi Kivity 		  : : "m"(*p)
262f2d2b7c7SAvi Kivity 		  );
263f2d2b7c7SAvi Kivity     nmi_counter = nmi_counter_private;
264f2d2b7c7SAvi Kivity }
265f2d2b7c7SAvi Kivity 
266f2d2b7c7SAvi Kivity static void sti_loop(void *ignore)
267f2d2b7c7SAvi Kivity {
268f2d2b7c7SAvi Kivity     unsigned k = 0;
269f2d2b7c7SAvi Kivity 
270f2d2b7c7SAvi Kivity     while (sti_loop_active) {
271f2d2b7c7SAvi Kivity 	sti_nop((char *)(ulong)((k++ * 4096) % (128 * 1024 * 1024)));
272f2d2b7c7SAvi Kivity     }
273f2d2b7c7SAvi Kivity }
274f2d2b7c7SAvi Kivity 
275f2d2b7c7SAvi Kivity static void nmi_handler(isr_regs_t *regs)
276f2d2b7c7SAvi Kivity {
277f2d2b7c7SAvi Kivity     extern void post_sti(void);
278f2d2b7c7SAvi Kivity     ++nmi_counter_private;
279f2d2b7c7SAvi Kivity     nmi_hlt_counter += regs->rip == (ulong)post_sti;
280f2d2b7c7SAvi Kivity }
281f2d2b7c7SAvi Kivity 
282f2d2b7c7SAvi Kivity static void update_cr3(void *cr3)
283f2d2b7c7SAvi Kivity {
284f2d2b7c7SAvi Kivity     write_cr3((ulong)cr3);
285f2d2b7c7SAvi Kivity }
286f2d2b7c7SAvi Kivity 
287f2d2b7c7SAvi Kivity static void test_sti_nmi(void)
288f2d2b7c7SAvi Kivity {
289f2d2b7c7SAvi Kivity     unsigned old_counter;
290f2d2b7c7SAvi Kivity 
291f2d2b7c7SAvi Kivity     if (cpu_count() < 2) {
292f2d2b7c7SAvi Kivity 	return;
293f2d2b7c7SAvi Kivity     }
294f2d2b7c7SAvi Kivity 
295d51bd17eSGleb Natapov     handle_irq(2, nmi_handler);
296f2d2b7c7SAvi Kivity     on_cpu(1, update_cr3, (void *)read_cr3());
297f2d2b7c7SAvi Kivity 
298f2d2b7c7SAvi Kivity     sti_loop_active = 1;
299f2d2b7c7SAvi Kivity     on_cpu_async(1, sti_loop, 0);
300f2d2b7c7SAvi Kivity     while (nmi_counter < 30000) {
301f2d2b7c7SAvi Kivity 	old_counter = nmi_counter;
302f2d2b7c7SAvi Kivity 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 1);
303f2d2b7c7SAvi Kivity 	while (nmi_counter == old_counter) {
304f2d2b7c7SAvi Kivity 	    ;
305f2d2b7c7SAvi Kivity 	}
306f2d2b7c7SAvi Kivity     }
307f2d2b7c7SAvi Kivity     sti_loop_active = 0;
308f2d2b7c7SAvi Kivity     report("nmi-after-sti", nmi_hlt_counter == 0);
309f2d2b7c7SAvi Kivity }
310f2d2b7c7SAvi Kivity 
311173e7eacSAvi Kivity static volatile bool nmi_done, nmi_flushed;
312173e7eacSAvi Kivity static volatile int nmi_received;
313173e7eacSAvi Kivity static volatile int cpu0_nmi_ctr1, cpu1_nmi_ctr1;
314173e7eacSAvi Kivity static volatile int cpu0_nmi_ctr2, cpu1_nmi_ctr2;
315173e7eacSAvi Kivity 
316173e7eacSAvi Kivity static void multiple_nmi_handler(isr_regs_t *regs)
317173e7eacSAvi Kivity {
318173e7eacSAvi Kivity     ++nmi_received;
319173e7eacSAvi Kivity }
320173e7eacSAvi Kivity 
321173e7eacSAvi Kivity static void kick_me_nmi(void *blah)
322173e7eacSAvi Kivity {
323173e7eacSAvi Kivity     while (!nmi_done) {
324173e7eacSAvi Kivity 	++cpu1_nmi_ctr1;
325173e7eacSAvi Kivity 	while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1 && !nmi_done) {
326173e7eacSAvi Kivity 	    pause();
327173e7eacSAvi Kivity 	}
328173e7eacSAvi Kivity 	if (nmi_done) {
329173e7eacSAvi Kivity 	    return;
330173e7eacSAvi Kivity 	}
331173e7eacSAvi Kivity 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
332173e7eacSAvi Kivity 	/* make sure the NMI has arrived by sending an IPI after it */
333173e7eacSAvi Kivity 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT
334173e7eacSAvi Kivity 		       | 0x44, 0);
335173e7eacSAvi Kivity 	++cpu1_nmi_ctr2;
336173e7eacSAvi Kivity 	while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done) {
337173e7eacSAvi Kivity 	    pause();
338173e7eacSAvi Kivity 	}
339173e7eacSAvi Kivity     }
340173e7eacSAvi Kivity }
341173e7eacSAvi Kivity 
342173e7eacSAvi Kivity static void flush_nmi(isr_regs_t *regs)
343173e7eacSAvi Kivity {
344173e7eacSAvi Kivity     nmi_flushed = true;
345173e7eacSAvi Kivity     apic_write(APIC_EOI, 0);
346173e7eacSAvi Kivity }
347173e7eacSAvi Kivity 
348173e7eacSAvi Kivity static void test_multiple_nmi(void)
349173e7eacSAvi Kivity {
350173e7eacSAvi Kivity     int i;
351173e7eacSAvi Kivity     bool ok = true;
352173e7eacSAvi Kivity 
353173e7eacSAvi Kivity     if (cpu_count() < 2) {
354173e7eacSAvi Kivity 	return;
355173e7eacSAvi Kivity     }
356173e7eacSAvi Kivity 
357173e7eacSAvi Kivity     sti();
358173e7eacSAvi Kivity     handle_irq(2, multiple_nmi_handler);
359173e7eacSAvi Kivity     handle_irq(0x44, flush_nmi);
360173e7eacSAvi Kivity     on_cpu_async(1, kick_me_nmi, 0);
361173e7eacSAvi Kivity     for (i = 0; i < 1000000; ++i) {
362173e7eacSAvi Kivity 	nmi_flushed = false;
363173e7eacSAvi Kivity 	nmi_received = 0;
364173e7eacSAvi Kivity 	++cpu0_nmi_ctr1;
365173e7eacSAvi Kivity 	while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1) {
366173e7eacSAvi Kivity 	    pause();
367173e7eacSAvi Kivity 	}
368173e7eacSAvi Kivity 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
369173e7eacSAvi Kivity 	while (!nmi_flushed) {
370173e7eacSAvi Kivity 	    pause();
371173e7eacSAvi Kivity 	}
372173e7eacSAvi Kivity 	if (nmi_received != 2) {
373173e7eacSAvi Kivity 	    ok = false;
374173e7eacSAvi Kivity 	    break;
375173e7eacSAvi Kivity 	}
376173e7eacSAvi Kivity 	++cpu0_nmi_ctr2;
377173e7eacSAvi Kivity 	while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2) {
378173e7eacSAvi Kivity 	    pause();
379173e7eacSAvi Kivity 	}
380173e7eacSAvi Kivity     }
381173e7eacSAvi Kivity     nmi_done = true;
382173e7eacSAvi Kivity     report("multiple nmi", ok);
383173e7eacSAvi Kivity }
384173e7eacSAvi Kivity 
3857d36db35SAvi Kivity int main()
3867d36db35SAvi Kivity {
3877d36db35SAvi Kivity     setup_vm();
388f2d2b7c7SAvi Kivity     smp_init();
389d51bd17eSGleb Natapov     setup_idt();
3907d36db35SAvi Kivity 
3917d36db35SAvi Kivity     test_lapic_existence();
3927d36db35SAvi Kivity 
3937d36db35SAvi Kivity     mask_pic_interrupts();
3947d36db35SAvi Kivity     test_enable_x2apic();
395*9b6bdb3fSJan Kiszka     test_apicbase();
3967d36db35SAvi Kivity 
3977d36db35SAvi Kivity     test_self_ipi();
3987d36db35SAvi Kivity 
3997d36db35SAvi Kivity     test_ioapic_intr();
4007d36db35SAvi Kivity     test_ioapic_simultaneous();
401f2d2b7c7SAvi Kivity     test_sti_nmi();
402173e7eacSAvi Kivity     test_multiple_nmi();
4037d36db35SAvi Kivity 
404d423ca36SLiu, Jinsong     test_tsc_deadline_timer();
405d423ca36SLiu, Jinsong 
4067d36db35SAvi Kivity     printf("\nsummary: %d tests, %d failures\n", g_tests, g_fail);
4077d36db35SAvi Kivity 
4087d36db35SAvi Kivity     return g_fail != 0;
4097d36db35SAvi Kivity }
410