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