xref: /kvm-unit-tests/x86/apic.c (revision 0d32963903ce75c404923fde61b3cb5a8176f16d)
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"
89931b88cSRadim Krčmář #include "atomic.h"
903b1e457SNadav Amit #include "fwcfg.h"
107d36db35SAvi Kivity 
11e38858bcSJim Mattson #define MAX_TPR			0xf
12e38858bcSJim Mattson 
13*0d329639SSean Christopherson static bool is_apic_hw_enabled(void)
14*0d329639SSean Christopherson {
15*0d329639SSean Christopherson 	return rdmsr(MSR_IA32_APICBASE) & APIC_EN;
16*0d329639SSean Christopherson }
17*0d329639SSean Christopherson 
18*0d329639SSean Christopherson static bool is_x2apic_enabled(void)
19*0d329639SSean Christopherson {
20*0d329639SSean Christopherson 	return (rdmsr(MSR_IA32_APICBASE) & (APIC_EN | APIC_EXTD)) == (APIC_EN | APIC_EXTD);
21*0d329639SSean Christopherson }
22*0d329639SSean Christopherson 
23*0d329639SSean Christopherson static bool is_xapic_enabled(void)
24*0d329639SSean Christopherson {
25*0d329639SSean Christopherson 	return (rdmsr(MSR_IA32_APICBASE) & (APIC_EN | APIC_EXTD)) == APIC_EN;
26*0d329639SSean Christopherson }
27*0d329639SSean Christopherson 
287d36db35SAvi Kivity static void test_lapic_existence(void)
297d36db35SAvi Kivity {
303ee24f29SNadav Amit 	u8 version;
317d36db35SAvi Kivity 
323ee24f29SNadav Amit 	version = (u8)apic_read(APIC_LVR);
333ee24f29SNadav Amit 	printf("apic version: %x\n", version);
34a299895bSThomas Huth 	report(version >= 0x10 && version <= 0x15, "apic existence");
357d36db35SAvi Kivity }
367d36db35SAvi Kivity 
37d423ca36SLiu, Jinsong #define TSC_DEADLINE_TIMER_VECTOR 0xef
389931b88cSRadim Krčmář #define BROADCAST_VECTOR 0xcf
39d423ca36SLiu, Jinsong 
40d423ca36SLiu, Jinsong static int tdt_count;
41d423ca36SLiu, Jinsong 
42d423ca36SLiu, Jinsong static void tsc_deadline_timer_isr(isr_regs_t *regs)
43d423ca36SLiu, Jinsong {
44d423ca36SLiu, Jinsong 	++tdt_count;
450b04ed06SPeter Xu 	eoi();
46d423ca36SLiu, Jinsong }
47d423ca36SLiu, Jinsong 
4832b9603cSRadim Krčmář static void __test_tsc_deadline_timer(void)
49d423ca36SLiu, Jinsong {
50d423ca36SLiu, Jinsong 	handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr);
51d423ca36SLiu, Jinsong 	irq_enable();
52d423ca36SLiu, Jinsong 
53d423ca36SLiu, Jinsong 	wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC));
54d423ca36SLiu, Jinsong 	asm volatile ("nop");
55a299895bSThomas Huth 	report(tdt_count == 1, "tsc deadline timer");
56a299895bSThomas Huth 	report(rdmsr(MSR_IA32_TSCDEADLINE) == 0, "tsc deadline timer clearing");
57d423ca36SLiu, Jinsong }
58d423ca36SLiu, Jinsong 
59d423ca36SLiu, Jinsong static int enable_tsc_deadline_timer(void)
60d423ca36SLiu, Jinsong {
61d423ca36SLiu, Jinsong 	uint32_t lvtt;
62d423ca36SLiu, Jinsong 
63badc98caSKrish Sadhukhan 	if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) {
649111ccabSRadim Krčmář 		lvtt = APIC_LVT_TIMER_TSCDEADLINE | TSC_DEADLINE_TIMER_VECTOR;
65d423ca36SLiu, Jinsong 		apic_write(APIC_LVTT, lvtt);
66d423ca36SLiu, Jinsong 		return 1;
67d423ca36SLiu, Jinsong 	} else {
68d423ca36SLiu, Jinsong 		return 0;
69d423ca36SLiu, Jinsong 	}
70d423ca36SLiu, Jinsong }
71d423ca36SLiu, Jinsong 
72d423ca36SLiu, Jinsong static void test_tsc_deadline_timer(void)
73d423ca36SLiu, Jinsong {
7427cc2e49SSean Christopherson 	if(enable_tsc_deadline_timer())
7532b9603cSRadim Krčmář 		__test_tsc_deadline_timer();
7627cc2e49SSean Christopherson 	else
7732b9603cSRadim Krčmář 		report_skip("tsc deadline timer not detected");
78d423ca36SLiu, Jinsong }
79d423ca36SLiu, Jinsong 
8022c7d929SJan Kiszka static void do_write_apicbase(void *data)
8122c7d929SJan Kiszka {
8222c7d929SJan Kiszka 	wrmsr(MSR_IA32_APICBASE, *(u64 *)data);
8303f37ef2SPaolo Bonzini }
847d36db35SAvi Kivity 
8549f5ad9eSPaolo Bonzini static bool test_write_apicbase_exception(u64 data)
8649f5ad9eSPaolo Bonzini {
8749f5ad9eSPaolo Bonzini 	return test_for_exception(GP_VECTOR, do_write_apicbase, &data);
8849f5ad9eSPaolo Bonzini }
8949f5ad9eSPaolo Bonzini 
90db4898e8SThomas Huth static void test_enable_x2apic(void)
917d36db35SAvi Kivity {
922092999cSSean Christopherson 	u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE);
932092999cSSean Christopherson 	u64 apicbase;
942092999cSSean Christopherson 
957d36db35SAvi Kivity 	if (enable_x2apic()) {
967d36db35SAvi Kivity 		printf("x2apic enabled\n");
9722c7d929SJan Kiszka 
982092999cSSean Christopherson 		apicbase = orig_apicbase & ~(APIC_EN | APIC_EXTD);
99a299895bSThomas Huth 		report(test_write_apicbase_exception(apicbase | APIC_EXTD),
100a299895bSThomas Huth 			"x2apic enabled to invalid state");
101a299895bSThomas Huth 		report(test_write_apicbase_exception(apicbase | APIC_EN),
102a299895bSThomas Huth 			"x2apic enabled to apic enabled");
10322c7d929SJan Kiszka 
104a299895bSThomas Huth 		report(!test_write_apicbase_exception(apicbase | 0),
105a299895bSThomas Huth 			"x2apic enabled to disabled state");
106a299895bSThomas Huth 		report(test_write_apicbase_exception(apicbase | APIC_EXTD),
107a299895bSThomas Huth 			"disabled to invalid state");
108a299895bSThomas Huth 		report(test_write_apicbase_exception(apicbase | APIC_EN | APIC_EXTD),
109a299895bSThomas Huth 			"disabled to x2apic enabled");
11022c7d929SJan Kiszka 
111a299895bSThomas Huth 		report(!test_write_apicbase_exception(apicbase | APIC_EN),
112a299895bSThomas Huth 			"apic disabled to apic enabled");
113a299895bSThomas Huth 		report(test_write_apicbase_exception(apicbase | APIC_EXTD),
114a299895bSThomas Huth 			"apic enabled to invalid state");
11522c7d929SJan Kiszka 
1162092999cSSean Christopherson 		if (orig_apicbase & APIC_EXTD)
1172092999cSSean Christopherson 			enable_x2apic();
1182092999cSSean Christopherson 		else
1192092999cSSean Christopherson 			reset_apic();
1202092999cSSean Christopherson 
1212092999cSSean Christopherson 		/*
12227cc2e49SSean Christopherson 		 * Disabling the APIC resets various APIC registers, restore
12327cc2e49SSean Christopherson 		 * them to their desired values.
1242092999cSSean Christopherson 		 */
12522c7d929SJan Kiszka 		apic_write(APIC_SPIV, 0x1ff);
1267d36db35SAvi Kivity 	} else {
1277d36db35SAvi Kivity 		printf("x2apic not detected\n");
12822c7d929SJan Kiszka 
129a299895bSThomas Huth 		report(test_write_apicbase_exception(APIC_EN | APIC_EXTD),
130a299895bSThomas Huth 		       "enable unsupported x2apic");
1317d36db35SAvi Kivity 	}
1327d36db35SAvi Kivity }
1337d36db35SAvi Kivity 
134e38858bcSJim Mattson static void verify_disabled_apic_mmio(void)
135e38858bcSJim Mattson {
136e38858bcSJim Mattson 	volatile u32 *lvr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_LVR);
137e38858bcSJim Mattson 	volatile u32 *tpr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_TASKPRI);
138e38858bcSJim Mattson 	u32 cr8 = read_cr8();
139e38858bcSJim Mattson 
140e38858bcSJim Mattson 	memset((void *)APIC_DEFAULT_PHYS_BASE, 0xff, PAGE_SIZE);
141a299895bSThomas Huth 	report(*lvr == ~0, "*0xfee00030: %x", *lvr);
142a299895bSThomas Huth 	report(read_cr8() == cr8, "CR8: %lx", read_cr8());
143e38858bcSJim Mattson 	write_cr8(cr8 ^ MAX_TPR);
144a299895bSThomas Huth 	report(read_cr8() == (cr8 ^ MAX_TPR), "CR8: %lx", read_cr8());
145a299895bSThomas Huth 	report(*tpr == ~0, "*0xfee00080: %x", *tpr);
146e38858bcSJim Mattson 	write_cr8(cr8);
147e38858bcSJim Mattson }
148e38858bcSJim Mattson 
149c3ccca3fSJim Mattson static void test_apic_disable(void)
150c3ccca3fSJim Mattson {
151e38858bcSJim Mattson 	volatile u32 *lvr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_LVR);
152e38858bcSJim Mattson 	volatile u32 *tpr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_TASKPRI);
153c3ccca3fSJim Mattson 	u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE);
154e38858bcSJim Mattson 	u32 apic_version = apic_read(APIC_LVR);
155e38858bcSJim Mattson 	u32 cr8 = read_cr8();
156c3ccca3fSJim Mattson 
157c3ccca3fSJim Mattson 	report_prefix_push("apic_disable");
158e38858bcSJim Mattson 	assert_msg(orig_apicbase & APIC_EN, "APIC not enabled.");
159c3ccca3fSJim Mattson 
160e38858bcSJim Mattson 	disable_apic();
161*0d329639SSean Christopherson 	report(!is_apic_hw_enabled(), "Local apic disabled");
162a299895bSThomas Huth 	report(!this_cpu_has(X86_FEATURE_APIC),
163a299895bSThomas Huth 	       "CPUID.1H:EDX.APIC[bit 9] is clear");
164e38858bcSJim Mattson 	verify_disabled_apic_mmio();
165c3ccca3fSJim Mattson 
166e38858bcSJim Mattson 	reset_apic();
167*0d329639SSean Christopherson 	report(is_xapic_enabled(), "Local apic enabled in xAPIC mode");
168a299895bSThomas Huth 	report(this_cpu_has(X86_FEATURE_APIC), "CPUID.1H:EDX.APIC[bit 9] is set");
169a299895bSThomas Huth 	report(*lvr == apic_version, "*0xfee00030: %x", *lvr);
170a299895bSThomas Huth 	report(*tpr == cr8, "*0xfee00080: %x", *tpr);
171e38858bcSJim Mattson 	write_cr8(cr8 ^ MAX_TPR);
172a299895bSThomas Huth 	report(*tpr == (cr8 ^ MAX_TPR) << 4, "*0xfee00080: %x", *tpr);
173e38858bcSJim Mattson 	write_cr8(cr8);
174c3ccca3fSJim Mattson 
175e38858bcSJim Mattson 	if (enable_x2apic()) {
176e38858bcSJim Mattson 		apic_write(APIC_SPIV, 0x1ff);
177*0d329639SSean Christopherson 		report(is_x2apic_enabled(), "Local apic enabled in x2APIC mode");
178a299895bSThomas Huth 		report(this_cpu_has(X86_FEATURE_APIC),
179a299895bSThomas Huth 		       "CPUID.1H:EDX.APIC[bit 9] is set");
180e38858bcSJim Mattson 		verify_disabled_apic_mmio();
181e38858bcSJim Mattson 		if (!(orig_apicbase & APIC_EXTD))
182e38858bcSJim Mattson 			reset_apic();
183e38858bcSJim Mattson 	}
184c3ccca3fSJim Mattson 	report_prefix_pop();
185c3ccca3fSJim Mattson }
186c3ccca3fSJim Mattson 
187615a8838SNadav Amit #define ALTERNATE_APIC_BASE	0xfed40000
1889b6bdb3fSJan Kiszka 
1899b6bdb3fSJan Kiszka static void test_apicbase(void)
1909b6bdb3fSJan Kiszka {
1919b6bdb3fSJan Kiszka 	u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE);
1929b6bdb3fSJan Kiszka 	u32 lvr = apic_read(APIC_LVR);
1939b6bdb3fSJan Kiszka 	u64 value;
1949b6bdb3fSJan Kiszka 
1959b6bdb3fSJan Kiszka 	wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~(APIC_EN | APIC_EXTD));
1969b6bdb3fSJan Kiszka 	wrmsr(MSR_IA32_APICBASE, ALTERNATE_APIC_BASE | APIC_BSP | APIC_EN);
1979b6bdb3fSJan Kiszka 
1985bba1769SAndrew Jones 	report_prefix_push("apicbase");
1995bba1769SAndrew Jones 
200a299895bSThomas Huth 	report(*(volatile u32 *)(ALTERNATE_APIC_BASE + APIC_LVR) == lvr,
201a299895bSThomas Huth 	       "relocate apic");
2029b6bdb3fSJan Kiszka 
203772befb7SEduardo Habkost 	value = orig_apicbase | (1UL << cpuid_maxphyaddr());
204a299895bSThomas Huth 	report(test_for_exception(GP_VECTOR, do_write_apicbase, &value),
205a299895bSThomas Huth 	       "reserved physaddr bits");
2069b6bdb3fSJan Kiszka 
2079b6bdb3fSJan Kiszka 	value = orig_apicbase | 1;
208a299895bSThomas Huth 	report(test_for_exception(GP_VECTOR, do_write_apicbase, &value),
209a299895bSThomas Huth 	       "reserved low bits");
2109b6bdb3fSJan Kiszka 
2119b6bdb3fSJan Kiszka 	wrmsr(MSR_IA32_APICBASE, orig_apicbase);
2129b6bdb3fSJan Kiszka 	apic_write(APIC_SPIV, 0x1ff);
2135bba1769SAndrew Jones 
2145bba1769SAndrew Jones 	report_prefix_pop();
2159b6bdb3fSJan Kiszka }
2169b6bdb3fSJan Kiszka 
217a222b5e2SRadim Krčmář static void do_write_apic_id(void *id)
218a222b5e2SRadim Krčmář {
219a222b5e2SRadim Krčmář 	apic_write(APIC_ID, *(u32 *)id);
220a222b5e2SRadim Krčmář }
221a222b5e2SRadim Krčmář 
222a222b5e2SRadim Krčmář static void __test_apic_id(void * unused)
223a222b5e2SRadim Krčmář {
224a222b5e2SRadim Krčmář 	u32 id, newid;
225a222b5e2SRadim Krčmář 	u8  initial_xapic_id = cpuid(1).b >> 24;
226a222b5e2SRadim Krčmář 	u32 initial_x2apic_id = cpuid(0xb).d;
227*0d329639SSean Christopherson 	bool x2apic_mode = is_x2apic_enabled();
228a222b5e2SRadim Krčmář 
229a222b5e2SRadim Krčmář 	if (x2apic_mode)
230a222b5e2SRadim Krčmář 		reset_apic();
231a222b5e2SRadim Krčmář 
232a222b5e2SRadim Krčmář 	id = apic_id();
233a299895bSThomas Huth 	report(initial_xapic_id == id, "xapic id matches cpuid");
234a222b5e2SRadim Krčmář 
235a222b5e2SRadim Krčmář 	newid = (id + 1) << 24;
236a299895bSThomas Huth 	report(!test_for_exception(GP_VECTOR, do_write_apic_id, &newid) &&
237a299895bSThomas Huth 	       (id == apic_id() || id + 1 == apic_id()),
238a299895bSThomas Huth 	       "writeable xapic id");
239a222b5e2SRadim Krčmář 
240a222b5e2SRadim Krčmář 	if (!enable_x2apic())
241a222b5e2SRadim Krčmář 		goto out;
242a222b5e2SRadim Krčmář 
243a299895bSThomas Huth 	report(test_for_exception(GP_VECTOR, do_write_apic_id, &newid),
244a299895bSThomas Huth 	       "non-writeable x2apic id");
245a299895bSThomas Huth 	report(initial_xapic_id == (apic_id() & 0xff), "sane x2apic id");
246a222b5e2SRadim Krčmář 
247a222b5e2SRadim Krčmář 	/* old QEMUs do not set initial x2APIC ID */
248a299895bSThomas Huth 	report(initial_xapic_id == (initial_x2apic_id & 0xff) &&
249a299895bSThomas Huth 	       initial_x2apic_id == apic_id(),
250a299895bSThomas Huth 	       "x2apic id matches cpuid");
251a222b5e2SRadim Krčmář 
252a222b5e2SRadim Krčmář out:
253a222b5e2SRadim Krčmář 	reset_apic();
254a222b5e2SRadim Krčmář 
255a299895bSThomas Huth 	report(initial_xapic_id == apic_id(), "correct xapic id after reset");
256a222b5e2SRadim Krčmář 
257a222b5e2SRadim Krčmář 	/* old KVMs do not reset xAPIC ID */
258a222b5e2SRadim Krčmář 	if (id != apic_id())
259a222b5e2SRadim Krčmář 		apic_write(APIC_ID, id << 24);
260a222b5e2SRadim Krčmář 
261a222b5e2SRadim Krčmář 	if (x2apic_mode)
262a222b5e2SRadim Krčmář 		enable_x2apic();
263a222b5e2SRadim Krčmář }
264a222b5e2SRadim Krčmář 
265a222b5e2SRadim Krčmář static void test_apic_id(void)
266a222b5e2SRadim Krčmář {
267a222b5e2SRadim Krčmář 	if (cpu_count() < 2)
268a222b5e2SRadim Krčmář 		return;
269a222b5e2SRadim Krčmář 
270a222b5e2SRadim Krčmář 	on_cpu(1, __test_apic_id, NULL);
271a222b5e2SRadim Krčmář }
272a222b5e2SRadim Krčmář 
2737d36db35SAvi Kivity static int ipi_count;
2747d36db35SAvi Kivity 
2757d36db35SAvi Kivity static void self_ipi_isr(isr_regs_t *regs)
2767d36db35SAvi Kivity {
2777d36db35SAvi Kivity 	++ipi_count;
2787d36db35SAvi Kivity 	eoi();
2797d36db35SAvi Kivity }
2807d36db35SAvi Kivity 
281685d5f62SRicardo Koller static void __test_self_ipi(void)
2827d36db35SAvi Kivity {
2836c0999f4SNadav Amit 	u64 start = rdtsc();
2847d36db35SAvi Kivity 	int vec = 0xf1;
2857d36db35SAvi Kivity 
286d51bd17eSGleb Natapov 	handle_irq(vec, self_ipi_isr);
2877d36db35SAvi Kivity 	irq_enable();
2887d36db35SAvi Kivity 	apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec,
28918a34cceSNadav Amit 		       id_map[0]);
2906c0999f4SNadav Amit 
2916c0999f4SNadav Amit 	do {
2926c0999f4SNadav Amit 		pause();
2936c0999f4SNadav Amit 	} while (rdtsc() - start < 1000000000 && ipi_count == 0);
294685d5f62SRicardo Koller }
2956c0999f4SNadav Amit 
296685d5f62SRicardo Koller static void test_self_ipi_xapic(void)
297685d5f62SRicardo Koller {
298*0d329639SSean Christopherson 	u64 was_x2apic = is_x2apic_enabled();
299685d5f62SRicardo Koller 
300685d5f62SRicardo Koller 	report_prefix_push("self_ipi_xapic");
301685d5f62SRicardo Koller 
302685d5f62SRicardo Koller 	/* Reset to xAPIC mode. */
303685d5f62SRicardo Koller 	reset_apic();
304*0d329639SSean Christopherson 	report(is_xapic_enabled(), "Local apic enabled in xAPIC mode");
305685d5f62SRicardo Koller 
306685d5f62SRicardo Koller 	ipi_count = 0;
307685d5f62SRicardo Koller 	__test_self_ipi();
308a299895bSThomas Huth 	report(ipi_count == 1, "self ipi");
309685d5f62SRicardo Koller 
310685d5f62SRicardo Koller 	/* Enable x2APIC mode if it was already enabled. */
311*0d329639SSean Christopherson 	if (was_x2apic)
312685d5f62SRicardo Koller 		enable_x2apic();
313685d5f62SRicardo Koller 
314685d5f62SRicardo Koller 	report_prefix_pop();
315685d5f62SRicardo Koller }
316685d5f62SRicardo Koller 
317685d5f62SRicardo Koller static void test_self_ipi_x2apic(void)
318685d5f62SRicardo Koller {
319*0d329639SSean Christopherson 	u64 was_xapic = is_xapic_enabled();
320685d5f62SRicardo Koller 
321685d5f62SRicardo Koller 	report_prefix_push("self_ipi_x2apic");
322685d5f62SRicardo Koller 
323685d5f62SRicardo Koller 	if (enable_x2apic()) {
324*0d329639SSean Christopherson 		report(is_x2apic_enabled(), "Local apic enabled in x2APIC mode");
325685d5f62SRicardo Koller 
326685d5f62SRicardo Koller 		ipi_count = 0;
327685d5f62SRicardo Koller 		__test_self_ipi();
328685d5f62SRicardo Koller 		report(ipi_count == 1, "self ipi");
329685d5f62SRicardo Koller 
330685d5f62SRicardo Koller 		/* Reset to xAPIC mode unless x2APIC was already enabled. */
331*0d329639SSean Christopherson 		if (was_xapic)
332685d5f62SRicardo Koller 			reset_apic();
333685d5f62SRicardo Koller 	} else {
334685d5f62SRicardo Koller 		report_skip("x2apic not detected");
335685d5f62SRicardo Koller 	}
336685d5f62SRicardo Koller 
337685d5f62SRicardo Koller 	report_prefix_pop();
3387d36db35SAvi Kivity }
3397d36db35SAvi Kivity 
340f2d2b7c7SAvi Kivity volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active;
341f2d2b7c7SAvi Kivity 
342db4898e8SThomas Huth static void sti_nop(char *p)
343f2d2b7c7SAvi Kivity {
344f2d2b7c7SAvi Kivity 	asm volatile (
345f2d2b7c7SAvi Kivity 		  ".globl post_sti \n\t"
346f2d2b7c7SAvi Kivity 		  "sti \n"
347f2d2b7c7SAvi Kivity 		  /*
348f2d2b7c7SAvi Kivity 		   * vmx won't exit on external interrupt if blocked-by-sti,
349f2d2b7c7SAvi Kivity 		   * so give it a reason to exit by accessing an unmapped page.
350f2d2b7c7SAvi Kivity 		   */
351f2d2b7c7SAvi Kivity 		  "post_sti: testb $0, %0 \n\t"
352f2d2b7c7SAvi Kivity 		  "nop \n\t"
353f2d2b7c7SAvi Kivity 		  "cli"
354f2d2b7c7SAvi Kivity 		  : : "m"(*p)
355f2d2b7c7SAvi Kivity 		  );
356f2d2b7c7SAvi Kivity 	nmi_counter = nmi_counter_private;
357f2d2b7c7SAvi Kivity }
358f2d2b7c7SAvi Kivity 
359f2d2b7c7SAvi Kivity static void sti_loop(void *ignore)
360f2d2b7c7SAvi Kivity {
361f2d2b7c7SAvi Kivity 	unsigned k = 0;
362f2d2b7c7SAvi Kivity 
36327cc2e49SSean Christopherson 	while (sti_loop_active)
364f2d2b7c7SAvi Kivity 		sti_nop((char *)(ulong)((k++ * 4096) % (128 * 1024 * 1024)));
365f2d2b7c7SAvi Kivity }
366f2d2b7c7SAvi Kivity 
367f2d2b7c7SAvi Kivity static void nmi_handler(isr_regs_t *regs)
368f2d2b7c7SAvi Kivity {
369f2d2b7c7SAvi Kivity 	extern void post_sti(void);
370f2d2b7c7SAvi Kivity 	++nmi_counter_private;
371f2d2b7c7SAvi Kivity 	nmi_hlt_counter += regs->rip == (ulong)post_sti;
372f2d2b7c7SAvi Kivity }
373f2d2b7c7SAvi Kivity 
374f2d2b7c7SAvi Kivity static void test_sti_nmi(void)
375f2d2b7c7SAvi Kivity {
376f2d2b7c7SAvi Kivity 	unsigned old_counter;
377f2d2b7c7SAvi Kivity 
37827cc2e49SSean Christopherson 	if (cpu_count() < 2)
379f2d2b7c7SAvi Kivity 		return;
380f2d2b7c7SAvi Kivity 
381d51bd17eSGleb Natapov 	handle_irq(2, nmi_handler);
382f2d2b7c7SAvi Kivity 	on_cpu(1, update_cr3, (void *)read_cr3());
383f2d2b7c7SAvi Kivity 
384f2d2b7c7SAvi Kivity 	sti_loop_active = 1;
385f2d2b7c7SAvi Kivity 	on_cpu_async(1, sti_loop, 0);
386f2d2b7c7SAvi Kivity 	while (nmi_counter < 30000) {
387f2d2b7c7SAvi Kivity 		old_counter = nmi_counter;
38818a34cceSNadav Amit 		apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[1]);
38927cc2e49SSean Christopherson 		while (nmi_counter == old_counter)
390f2d2b7c7SAvi Kivity 			;
391f2d2b7c7SAvi Kivity 	}
392f2d2b7c7SAvi Kivity 	sti_loop_active = 0;
393a299895bSThomas Huth 	report(nmi_hlt_counter == 0, "nmi-after-sti");
394f2d2b7c7SAvi Kivity }
395f2d2b7c7SAvi Kivity 
396173e7eacSAvi Kivity static volatile bool nmi_done, nmi_flushed;
397173e7eacSAvi Kivity static volatile int nmi_received;
398173e7eacSAvi Kivity static volatile int cpu0_nmi_ctr1, cpu1_nmi_ctr1;
399173e7eacSAvi Kivity static volatile int cpu0_nmi_ctr2, cpu1_nmi_ctr2;
400173e7eacSAvi Kivity 
401173e7eacSAvi Kivity static void multiple_nmi_handler(isr_regs_t *regs)
402173e7eacSAvi Kivity {
403173e7eacSAvi Kivity 	++nmi_received;
404173e7eacSAvi Kivity }
405173e7eacSAvi Kivity 
406173e7eacSAvi Kivity static void kick_me_nmi(void *blah)
407173e7eacSAvi Kivity {
408173e7eacSAvi Kivity 	while (!nmi_done) {
409173e7eacSAvi Kivity 		++cpu1_nmi_ctr1;
41027cc2e49SSean Christopherson 		while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1 && !nmi_done)
411173e7eacSAvi Kivity 			pause();
41227cc2e49SSean Christopherson 
41327cc2e49SSean Christopherson 		if (nmi_done)
414173e7eacSAvi Kivity 			return;
41527cc2e49SSean Christopherson 
41618a34cceSNadav Amit 		apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]);
417173e7eacSAvi Kivity 		/* make sure the NMI has arrived by sending an IPI after it */
418173e7eacSAvi Kivity 		apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT
41918a34cceSNadav Amit 				| 0x44, id_map[0]);
420173e7eacSAvi Kivity 		++cpu1_nmi_ctr2;
42127cc2e49SSean Christopherson 		while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done)
422173e7eacSAvi Kivity 			pause();
423173e7eacSAvi Kivity 	}
424173e7eacSAvi Kivity }
425173e7eacSAvi Kivity 
426173e7eacSAvi Kivity static void flush_nmi(isr_regs_t *regs)
427173e7eacSAvi Kivity {
428173e7eacSAvi Kivity 	nmi_flushed = true;
429173e7eacSAvi Kivity 	apic_write(APIC_EOI, 0);
430173e7eacSAvi Kivity }
431173e7eacSAvi Kivity 
432173e7eacSAvi Kivity static void test_multiple_nmi(void)
433173e7eacSAvi Kivity {
434173e7eacSAvi Kivity 	int i;
435173e7eacSAvi Kivity 	bool ok = true;
436173e7eacSAvi Kivity 
43727cc2e49SSean Christopherson 	if (cpu_count() < 2)
438173e7eacSAvi Kivity 		return;
439173e7eacSAvi Kivity 
440173e7eacSAvi Kivity 	sti();
441173e7eacSAvi Kivity 	handle_irq(2, multiple_nmi_handler);
442173e7eacSAvi Kivity 	handle_irq(0x44, flush_nmi);
443173e7eacSAvi Kivity 	on_cpu_async(1, kick_me_nmi, 0);
444a7f60697SPaolo Bonzini 	for (i = 0; i < 100000; ++i) {
445173e7eacSAvi Kivity 		nmi_flushed = false;
446173e7eacSAvi Kivity 		nmi_received = 0;
447173e7eacSAvi Kivity 		++cpu0_nmi_ctr1;
44827cc2e49SSean Christopherson 		while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1)
449173e7eacSAvi Kivity 			pause();
45027cc2e49SSean Christopherson 
45118a34cceSNadav Amit 		apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]);
45227cc2e49SSean Christopherson 		while (!nmi_flushed)
453173e7eacSAvi Kivity 			pause();
45427cc2e49SSean Christopherson 
455173e7eacSAvi Kivity 		if (nmi_received != 2) {
456173e7eacSAvi Kivity 			ok = false;
457173e7eacSAvi Kivity 			break;
458173e7eacSAvi Kivity 		}
45927cc2e49SSean Christopherson 
460173e7eacSAvi Kivity 		++cpu0_nmi_ctr2;
46127cc2e49SSean Christopherson 		while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2)
462173e7eacSAvi Kivity 			pause();
463173e7eacSAvi Kivity 	}
464173e7eacSAvi Kivity 	nmi_done = true;
465a299895bSThomas Huth 	report(ok, "multiple nmi");
466173e7eacSAvi Kivity }
467173e7eacSAvi Kivity 
4689f23b246SSean Christopherson static void pending_nmi_handler(isr_regs_t *regs)
4699f23b246SSean Christopherson {
4709f23b246SSean Christopherson 	int i;
4719f23b246SSean Christopherson 
4729f23b246SSean Christopherson 	if (++nmi_received == 1) {
4739f23b246SSean Christopherson 		for (i = 0; i < 10; ++i)
4749f23b246SSean Christopherson 			apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI, 0);
4759f23b246SSean Christopherson 	}
4769f23b246SSean Christopherson }
4779f23b246SSean Christopherson 
4789f23b246SSean Christopherson static void test_pending_nmi(void)
4799f23b246SSean Christopherson {
4809f23b246SSean Christopherson 	int i;
4819f23b246SSean Christopherson 
4829f23b246SSean Christopherson 	handle_irq(2, pending_nmi_handler);
4839f23b246SSean Christopherson 	for (i = 0; i < 100000; ++i) {
4849f23b246SSean Christopherson 		nmi_received = 0;
4859f23b246SSean Christopherson 
4869f23b246SSean Christopherson 		apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI, 0);
4879f23b246SSean Christopherson 		while (nmi_received < 2)
4889f23b246SSean Christopherson 			pause();
4899f23b246SSean Christopherson 
4909f23b246SSean Christopherson 		if (nmi_received != 2)
4919f23b246SSean Christopherson 			break;
4929f23b246SSean Christopherson 	}
493a299895bSThomas Huth 	report(nmi_received == 2, "pending nmi");
4949f23b246SSean Christopherson }
4959f23b246SSean Christopherson 
4969f815b29SPeter Xu static volatile int lvtt_counter = 0;
4979f815b29SPeter Xu 
4989f815b29SPeter Xu static void lvtt_handler(isr_regs_t *regs)
4999f815b29SPeter Xu {
5009f815b29SPeter Xu 	lvtt_counter++;
5019f815b29SPeter Xu 	eoi();
5029f815b29SPeter Xu }
5039f815b29SPeter Xu 
5049f815b29SPeter Xu static void test_apic_timer_one_shot(void)
5059f815b29SPeter Xu {
5069f815b29SPeter Xu 	uint64_t tsc1, tsc2;
5079f815b29SPeter Xu 	static const uint32_t interval = 0x10000;
5089f815b29SPeter Xu 
5099f815b29SPeter Xu #define APIC_LVT_TIMER_VECTOR    (0xee)
5109f815b29SPeter Xu 
5119f815b29SPeter Xu 	handle_irq(APIC_LVT_TIMER_VECTOR, lvtt_handler);
5129f815b29SPeter Xu 	irq_enable();
5139f815b29SPeter Xu 
5149f815b29SPeter Xu 	/* One shot mode */
5159111ccabSRadim Krčmář 	apic_write(APIC_LVTT, APIC_LVT_TIMER_ONESHOT |
5169f815b29SPeter Xu 		   APIC_LVT_TIMER_VECTOR);
5179f815b29SPeter Xu 	/* Divider == 1 */
5189f815b29SPeter Xu 	apic_write(APIC_TDCR, 0x0000000b);
5199f815b29SPeter Xu 
5209f815b29SPeter Xu 	tsc1 = rdtsc();
5219f815b29SPeter Xu 	/* Set "Initial Counter Register", which starts the timer */
5229f815b29SPeter Xu 	apic_write(APIC_TMICT, interval);
5239f815b29SPeter Xu 	while (!lvtt_counter);
5249f815b29SPeter Xu 	tsc2 = rdtsc();
5259f815b29SPeter Xu 
5269f815b29SPeter Xu 	/*
5279f815b29SPeter Xu 	 * For LVT Timer clock, SDM vol 3 10.5.4 says it should be
5289f815b29SPeter Xu 	 * derived from processor's bus clock (IIUC which is the same
5299f815b29SPeter Xu 	 * as TSC), however QEMU seems to be using nanosecond. In all
5309f815b29SPeter Xu 	 * cases, the following should satisfy on all modern
5319f815b29SPeter Xu 	 * processors.
5329f815b29SPeter Xu 	 */
533a299895bSThomas Huth 	report((lvtt_counter == 1) && (tsc2 - tsc1 >= interval),
534a299895bSThomas Huth 	       "APIC LVT timer one shot");
5359f815b29SPeter Xu }
5369f815b29SPeter Xu 
5379931b88cSRadim Krčmář static atomic_t broadcast_counter;
5389931b88cSRadim Krčmář 
5399931b88cSRadim Krčmář static void broadcast_handler(isr_regs_t *regs)
5409931b88cSRadim Krčmář {
5419931b88cSRadim Krčmář 	atomic_inc(&broadcast_counter);
5429931b88cSRadim Krčmář 	eoi();
5439931b88cSRadim Krčmář }
5449931b88cSRadim Krčmář 
5459931b88cSRadim Krčmář static bool broadcast_received(unsigned ncpus)
5469931b88cSRadim Krčmář {
5479931b88cSRadim Krčmář 	unsigned counter;
5489931b88cSRadim Krčmář 	u64 start = rdtsc();
5499931b88cSRadim Krčmář 
5509931b88cSRadim Krčmář 	do {
5519931b88cSRadim Krčmář 		counter = atomic_read(&broadcast_counter);
5529931b88cSRadim Krčmář 		if (counter >= ncpus)
5539931b88cSRadim Krčmář 			break;
5549931b88cSRadim Krčmář 		pause();
5559931b88cSRadim Krčmář 	} while (rdtsc() - start < 1000000000);
5569931b88cSRadim Krčmář 
5579931b88cSRadim Krčmář 	atomic_set(&broadcast_counter, 0);
5589931b88cSRadim Krčmář 
5599931b88cSRadim Krčmář 	return counter == ncpus;
5609931b88cSRadim Krčmář }
5619931b88cSRadim Krčmář 
5629931b88cSRadim Krčmář static void test_physical_broadcast(void)
5639931b88cSRadim Krčmář {
5649931b88cSRadim Krčmář 	unsigned ncpus = cpu_count();
5659931b88cSRadim Krčmář 	unsigned long cr3 = read_cr3();
5669931b88cSRadim Krčmář 	u32 broadcast_address = enable_x2apic() ? 0xffffffff : 0xff;
5679931b88cSRadim Krčmář 
5689931b88cSRadim Krčmář 	handle_irq(BROADCAST_VECTOR, broadcast_handler);
5699931b88cSRadim Krčmář 	for (int c = 1; c < ncpus; c++)
5709931b88cSRadim Krčmář 		on_cpu(c, update_cr3, (void *)cr3);
5719931b88cSRadim Krčmář 
5729931b88cSRadim Krčmář 	printf("starting broadcast (%s)\n", enable_x2apic() ? "x2apic" : "xapic");
5739931b88cSRadim Krčmář 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT |
5749931b88cSRadim Krčmář 		       BROADCAST_VECTOR, broadcast_address);
575a299895bSThomas Huth 	report(broadcast_received(ncpus), "APIC physical broadcast address");
5769931b88cSRadim Krčmář 
5779931b88cSRadim Krčmář 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT |
5789931b88cSRadim Krčmář 		       BROADCAST_VECTOR | APIC_DEST_ALLINC, 0);
579a299895bSThomas Huth 	report(broadcast_received(ncpus), "APIC physical broadcast shorthand");
5809931b88cSRadim Krčmář }
5819931b88cSRadim Krčmář 
5820eac5394SEvgeny Yakovlev static void wait_until_tmcct_common(uint32_t initial_count, bool stop_when_half, bool should_wrap_around)
583d9b2b283SWanpeng Li {
584d9b2b283SWanpeng Li 	uint32_t tmcct = apic_read(APIC_TMCCT);
585d9b2b283SWanpeng Li 
586d9b2b283SWanpeng Li 	if (tmcct) {
587d9b2b283SWanpeng Li 		while (tmcct > (initial_count / 2))
588d9b2b283SWanpeng Li 			tmcct = apic_read(APIC_TMCCT);
589d9b2b283SWanpeng Li 
590d9b2b283SWanpeng Li 		if ( stop_when_half )
591d9b2b283SWanpeng Li 			return;
592d9b2b283SWanpeng Li 
593d9b2b283SWanpeng Li 		/* Wait until the counter reach 0 or wrap-around */
594d9b2b283SWanpeng Li 		while ( tmcct <= (initial_count / 2) && tmcct > 0 )
595d9b2b283SWanpeng Li 			tmcct = apic_read(APIC_TMCCT);
5960eac5394SEvgeny Yakovlev 
5970eac5394SEvgeny Yakovlev 		/* Wait specifically for wrap around to skip 0 TMCCR if we were asked to */
5980eac5394SEvgeny Yakovlev 		while (should_wrap_around && !tmcct)
5990eac5394SEvgeny Yakovlev 			tmcct = apic_read(APIC_TMCCT);
600d9b2b283SWanpeng Li 	}
601d9b2b283SWanpeng Li }
602d9b2b283SWanpeng Li 
6030eac5394SEvgeny Yakovlev static void wait_until_tmcct_is_zero(uint32_t initial_count, bool stop_when_half)
6040eac5394SEvgeny Yakovlev {
6050eac5394SEvgeny Yakovlev 	return wait_until_tmcct_common(initial_count, stop_when_half, false);
6060eac5394SEvgeny Yakovlev }
6070eac5394SEvgeny Yakovlev 
6080eac5394SEvgeny Yakovlev static void wait_until_tmcct_wrap_around(uint32_t initial_count, bool stop_when_half)
6090eac5394SEvgeny Yakovlev {
6100eac5394SEvgeny Yakovlev 	return wait_until_tmcct_common(initial_count, stop_when_half, true);
6110eac5394SEvgeny Yakovlev }
6120eac5394SEvgeny Yakovlev 
613d9b2b283SWanpeng Li static inline void apic_change_mode(unsigned long new_mode)
614d9b2b283SWanpeng Li {
615d9b2b283SWanpeng Li 	uint32_t lvtt;
616d9b2b283SWanpeng Li 
617d9b2b283SWanpeng Li 	lvtt = apic_read(APIC_LVTT);
618d9b2b283SWanpeng Li 	apic_write(APIC_LVTT, (lvtt & ~APIC_LVT_TIMER_MASK) | new_mode);
619d9b2b283SWanpeng Li }
620d9b2b283SWanpeng Li 
6217db17e21SThomas Huth static void test_apic_change_mode(void)
622d9b2b283SWanpeng Li {
623d9b2b283SWanpeng Li 	uint32_t tmict = 0x999999;
624d9b2b283SWanpeng Li 
625d9b2b283SWanpeng Li 	printf("starting apic change mode\n");
626d9b2b283SWanpeng Li 
627d9b2b283SWanpeng Li 	apic_write(APIC_TMICT, tmict);
628d9b2b283SWanpeng Li 
629d9b2b283SWanpeng Li 	apic_change_mode(APIC_LVT_TIMER_PERIODIC);
630d9b2b283SWanpeng Li 
631a299895bSThomas Huth 	report(apic_read(APIC_TMICT) == tmict, "TMICT value reset");
632d9b2b283SWanpeng Li 
633d9b2b283SWanpeng Li 	/* Testing one-shot */
634d9b2b283SWanpeng Li 	apic_change_mode(APIC_LVT_TIMER_ONESHOT);
635d9b2b283SWanpeng Li 	apic_write(APIC_TMICT, tmict);
636a299895bSThomas Huth 	report(apic_read(APIC_TMCCT), "TMCCT should have a non-zero value");
637d9b2b283SWanpeng Li 
638d9b2b283SWanpeng Li 	wait_until_tmcct_is_zero(tmict, false);
639a299895bSThomas Huth 	report(!apic_read(APIC_TMCCT), "TMCCT should have reached 0");
640d9b2b283SWanpeng Li 
641d9b2b283SWanpeng Li 	/*
642d9b2b283SWanpeng Li 	 * Write TMICT before changing mode from one-shot to periodic TMCCT should
643d9b2b283SWanpeng Li 	 * be reset to TMICT periodicly
644d9b2b283SWanpeng Li 	 */
645d9b2b283SWanpeng Li 	apic_write(APIC_TMICT, tmict);
646d9b2b283SWanpeng Li 	wait_until_tmcct_is_zero(tmict, true);
647d9b2b283SWanpeng Li 	apic_change_mode(APIC_LVT_TIMER_PERIODIC);
648a299895bSThomas Huth 	report(apic_read(APIC_TMCCT), "TMCCT should have a non-zero value");
649d9b2b283SWanpeng Li 
650d9b2b283SWanpeng Li 	/*
651d9b2b283SWanpeng Li 	 * After the change of mode, the counter should not be reset and continue
652d9b2b283SWanpeng Li 	 * counting down from where it was
653d9b2b283SWanpeng Li 	 */
654a299895bSThomas Huth 	report(apic_read(APIC_TMCCT) < (tmict / 2),
655a299895bSThomas Huth 	       "TMCCT should not be reset to TMICT value");
6560eac5394SEvgeny Yakovlev 	/*
6570eac5394SEvgeny Yakovlev 	 * Specifically wait for timer wrap around and skip 0.
6580eac5394SEvgeny Yakovlev 	 * Under KVM lapic there is a possibility that a small amount of consecutive
6590eac5394SEvgeny Yakovlev 	 * TMCCR reads return 0 while hrtimer is reset in an async callback
6600eac5394SEvgeny Yakovlev 	 */
6610eac5394SEvgeny Yakovlev 	wait_until_tmcct_wrap_around(tmict, false);
662a299895bSThomas Huth 	report(apic_read(APIC_TMCCT) > (tmict / 2),
663a299895bSThomas Huth 	       "TMCCT should be reset to the initial-count");
664d9b2b283SWanpeng Li 
665d9b2b283SWanpeng Li 	wait_until_tmcct_is_zero(tmict, true);
666d9b2b283SWanpeng Li 	/*
667d9b2b283SWanpeng Li 	 * Keep the same TMICT and change timer mode to one-shot
668d9b2b283SWanpeng Li 	 * TMCCT should be > 0 and count-down to 0
669d9b2b283SWanpeng Li 	 */
670d9b2b283SWanpeng Li 	apic_change_mode(APIC_LVT_TIMER_ONESHOT);
671a299895bSThomas Huth 	report(apic_read(APIC_TMCCT) < (tmict / 2),
672a299895bSThomas Huth 	       "TMCCT should not be reset to init");
673d9b2b283SWanpeng Li 	wait_until_tmcct_is_zero(tmict, false);
674a299895bSThomas Huth 	report(!apic_read(APIC_TMCCT), "TMCCT should have reach zero");
675d9b2b283SWanpeng Li 
676d9b2b283SWanpeng Li 	/* now tmcct == 0 and tmict != 0 */
677d9b2b283SWanpeng Li 	apic_change_mode(APIC_LVT_TIMER_PERIODIC);
678a299895bSThomas Huth 	report(!apic_read(APIC_TMCCT), "TMCCT should stay at zero");
679d9b2b283SWanpeng Li }
680d9b2b283SWanpeng Li 
681de8d3fccSWanpeng Li #define KVM_HC_SEND_IPI 10
682de8d3fccSWanpeng Li 
683de8d3fccSWanpeng Li static void test_pv_ipi(void)
684de8d3fccSWanpeng Li {
685de8d3fccSWanpeng Li 	int ret;
686de8d3fccSWanpeng Li 	unsigned long a0 = 0xFFFFFFFF, a1 = 0, a2 = 0xFFFFFFFF, a3 = 0x0;
687de8d3fccSWanpeng Li 
688de8d3fccSWanpeng Li 	asm volatile("vmcall" : "=a"(ret) :"a"(KVM_HC_SEND_IPI), "b"(a0), "c"(a1), "d"(a2), "S"(a3));
689a299895bSThomas Huth 	report(!ret, "PV IPIs testing");
690de8d3fccSWanpeng Li }
691de8d3fccSWanpeng Li 
6927db17e21SThomas Huth int main(void)
6937d36db35SAvi Kivity {
6947d36db35SAvi Kivity 	setup_vm();
6957d36db35SAvi Kivity 
6967d36db35SAvi Kivity 	test_lapic_existence();
6977d36db35SAvi Kivity 
6987d36db35SAvi Kivity 	mask_pic_interrupts();
699a222b5e2SRadim Krčmář 	test_apic_id();
700c3ccca3fSJim Mattson 	test_apic_disable();
7017d36db35SAvi Kivity 	test_enable_x2apic();
7029b6bdb3fSJan Kiszka 	test_apicbase();
7037d36db35SAvi Kivity 
704685d5f62SRicardo Koller 	test_self_ipi_xapic();
705685d5f62SRicardo Koller 	test_self_ipi_x2apic();
7069931b88cSRadim Krčmář 	test_physical_broadcast();
70703b1e457SNadav Amit 	if (test_device_enabled())
708de8d3fccSWanpeng Li 		test_pv_ipi();
7097d36db35SAvi Kivity 
710f2d2b7c7SAvi Kivity 	test_sti_nmi();
711173e7eacSAvi Kivity 	test_multiple_nmi();
7129f23b246SSean Christopherson 	test_pending_nmi();
7137d36db35SAvi Kivity 
7149f815b29SPeter Xu 	test_apic_timer_one_shot();
715d9b2b283SWanpeng Li 	test_apic_change_mode();
716d423ca36SLiu, Jinsong 	test_tsc_deadline_timer();
717d423ca36SLiu, Jinsong 
718f3cdd159SJan Kiszka 	return report_summary();
7197d36db35SAvi Kivity }
720