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 void test_lapic_existence(void) 107d36db35SAvi Kivity { 117d36db35SAvi Kivity u32 lvr; 127d36db35SAvi Kivity 137d36db35SAvi Kivity lvr = apic_read(APIC_LVR); 147d36db35SAvi Kivity printf("apic version: %x\n", lvr); 157d36db35SAvi Kivity report("apic existence", (u16)lvr == 0x14); 167d36db35SAvi Kivity } 177d36db35SAvi Kivity 18d423ca36SLiu, Jinsong #define TSC_DEADLINE_TIMER_VECTOR 0xef 19d423ca36SLiu, Jinsong 20d423ca36SLiu, Jinsong static int tdt_count; 21d423ca36SLiu, Jinsong 22d423ca36SLiu, Jinsong static void tsc_deadline_timer_isr(isr_regs_t *regs) 23d423ca36SLiu, Jinsong { 24d423ca36SLiu, Jinsong ++tdt_count; 250b04ed06SPeter Xu eoi(); 26d423ca36SLiu, Jinsong } 27d423ca36SLiu, Jinsong 2832b9603cSRadim Krčmář static void __test_tsc_deadline_timer(void) 29d423ca36SLiu, Jinsong { 30d423ca36SLiu, Jinsong handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr); 31d423ca36SLiu, Jinsong irq_enable(); 32d423ca36SLiu, Jinsong 33d423ca36SLiu, Jinsong wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC)); 34d423ca36SLiu, Jinsong asm volatile ("nop"); 35d423ca36SLiu, Jinsong report("tsc deadline timer", tdt_count == 1); 36f8833144SNadav Amit report("tsc deadline timer clearing", rdmsr(MSR_IA32_TSCDEADLINE) == 0); 37d423ca36SLiu, Jinsong } 38d423ca36SLiu, Jinsong 39d423ca36SLiu, Jinsong static int enable_tsc_deadline_timer(void) 40d423ca36SLiu, Jinsong { 41d423ca36SLiu, Jinsong uint32_t lvtt; 42d423ca36SLiu, Jinsong 43d423ca36SLiu, Jinsong if (cpuid(1).c & (1 << 24)) { 44*9111ccabSRadim Krčmář lvtt = APIC_LVT_TIMER_TSCDEADLINE | TSC_DEADLINE_TIMER_VECTOR; 45d423ca36SLiu, Jinsong apic_write(APIC_LVTT, lvtt); 46d423ca36SLiu, Jinsong return 1; 47d423ca36SLiu, Jinsong } else { 48d423ca36SLiu, Jinsong return 0; 49d423ca36SLiu, Jinsong } 50d423ca36SLiu, Jinsong } 51d423ca36SLiu, Jinsong 52d423ca36SLiu, Jinsong static void test_tsc_deadline_timer(void) 53d423ca36SLiu, Jinsong { 54d423ca36SLiu, Jinsong if(enable_tsc_deadline_timer()) { 5532b9603cSRadim Krčmář __test_tsc_deadline_timer(); 56d423ca36SLiu, Jinsong } else { 5732b9603cSRadim Krčmář report_skip("tsc deadline timer not detected"); 58d423ca36SLiu, Jinsong } 59d423ca36SLiu, Jinsong } 60d423ca36SLiu, Jinsong 6122c7d929SJan Kiszka static void do_write_apicbase(void *data) 6222c7d929SJan Kiszka { 6322c7d929SJan Kiszka wrmsr(MSR_IA32_APICBASE, *(u64 *)data); 6403f37ef2SPaolo Bonzini } 657d36db35SAvi Kivity 667d36db35SAvi Kivity void test_enable_x2apic(void) 677d36db35SAvi Kivity { 6822c7d929SJan Kiszka u64 invalid_state = APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EXTD; 6922c7d929SJan Kiszka u64 apic_enabled = APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EN; 7022c7d929SJan Kiszka u64 x2apic_enabled = 7122c7d929SJan Kiszka APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EN | APIC_EXTD; 7222c7d929SJan Kiszka 737d36db35SAvi Kivity if (enable_x2apic()) { 747d36db35SAvi Kivity printf("x2apic enabled\n"); 7522c7d929SJan Kiszka 7622c7d929SJan Kiszka report("x2apic enabled to invalid state", 7722c7d929SJan Kiszka test_for_exception(GP_VECTOR, do_write_apicbase, 7822c7d929SJan Kiszka &invalid_state)); 7922c7d929SJan Kiszka report("x2apic enabled to apic enabled", 8022c7d929SJan Kiszka test_for_exception(GP_VECTOR, do_write_apicbase, 8122c7d929SJan Kiszka &apic_enabled)); 8222c7d929SJan Kiszka 8322c7d929SJan Kiszka wrmsr(MSR_IA32_APICBASE, APIC_DEFAULT_PHYS_BASE | APIC_BSP); 8422c7d929SJan Kiszka report("disabled to invalid state", 8522c7d929SJan Kiszka test_for_exception(GP_VECTOR, do_write_apicbase, 8622c7d929SJan Kiszka &invalid_state)); 8722c7d929SJan Kiszka report("disabled to x2apic enabled", 8822c7d929SJan Kiszka test_for_exception(GP_VECTOR, do_write_apicbase, 8922c7d929SJan Kiszka &x2apic_enabled)); 9022c7d929SJan Kiszka 9122c7d929SJan Kiszka wrmsr(MSR_IA32_APICBASE, apic_enabled); 9222c7d929SJan Kiszka report("apic enabled to invalid state", 9322c7d929SJan Kiszka test_for_exception(GP_VECTOR, do_write_apicbase, 9422c7d929SJan Kiszka &invalid_state)); 9522c7d929SJan Kiszka 9622c7d929SJan Kiszka wrmsr(MSR_IA32_APICBASE, x2apic_enabled); 9722c7d929SJan Kiszka apic_write(APIC_SPIV, 0x1ff); 987d36db35SAvi Kivity } else { 997d36db35SAvi Kivity printf("x2apic not detected\n"); 10022c7d929SJan Kiszka 10122c7d929SJan Kiszka report("enable unsupported x2apic", 10222c7d929SJan Kiszka test_for_exception(GP_VECTOR, do_write_apicbase, 10322c7d929SJan Kiszka &x2apic_enabled)); 1047d36db35SAvi Kivity } 1057d36db35SAvi Kivity } 1067d36db35SAvi Kivity 1079b6bdb3fSJan Kiszka #define ALTERNATE_APIC_BASE 0x42000000 1089b6bdb3fSJan Kiszka 1099b6bdb3fSJan Kiszka static void test_apicbase(void) 1109b6bdb3fSJan Kiszka { 1119b6bdb3fSJan Kiszka u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE); 1129b6bdb3fSJan Kiszka u32 lvr = apic_read(APIC_LVR); 1139b6bdb3fSJan Kiszka u64 value; 1149b6bdb3fSJan Kiszka 1159b6bdb3fSJan Kiszka wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~(APIC_EN | APIC_EXTD)); 1169b6bdb3fSJan Kiszka wrmsr(MSR_IA32_APICBASE, ALTERNATE_APIC_BASE | APIC_BSP | APIC_EN); 1179b6bdb3fSJan Kiszka 1185bba1769SAndrew Jones report_prefix_push("apicbase"); 1195bba1769SAndrew Jones 1209b6bdb3fSJan Kiszka report("relocate apic", 1219b6bdb3fSJan Kiszka *(volatile u32 *)(ALTERNATE_APIC_BASE + APIC_LVR) == lvr); 1229b6bdb3fSJan Kiszka 123772befb7SEduardo Habkost value = orig_apicbase | (1UL << cpuid_maxphyaddr()); 1245bba1769SAndrew Jones report("reserved physaddr bits", 1259b6bdb3fSJan Kiszka test_for_exception(GP_VECTOR, do_write_apicbase, &value)); 1269b6bdb3fSJan Kiszka 1279b6bdb3fSJan Kiszka value = orig_apicbase | 1; 1285bba1769SAndrew Jones report("reserved low bits", 1299b6bdb3fSJan Kiszka test_for_exception(GP_VECTOR, do_write_apicbase, &value)); 1309b6bdb3fSJan Kiszka 1319b6bdb3fSJan Kiszka wrmsr(MSR_IA32_APICBASE, orig_apicbase); 1329b6bdb3fSJan Kiszka apic_write(APIC_SPIV, 0x1ff); 1335bba1769SAndrew Jones 1345bba1769SAndrew Jones report_prefix_pop(); 1359b6bdb3fSJan Kiszka } 1369b6bdb3fSJan Kiszka 137a222b5e2SRadim Krčmář static void do_write_apic_id(void *id) 138a222b5e2SRadim Krčmář { 139a222b5e2SRadim Krčmář apic_write(APIC_ID, *(u32 *)id); 140a222b5e2SRadim Krčmář } 141a222b5e2SRadim Krčmář 142a222b5e2SRadim Krčmář static void __test_apic_id(void * unused) 143a222b5e2SRadim Krčmář { 144a222b5e2SRadim Krčmář u32 id, newid; 145a222b5e2SRadim Krčmář u8 initial_xapic_id = cpuid(1).b >> 24; 146a222b5e2SRadim Krčmář u32 initial_x2apic_id = cpuid(0xb).d; 147a222b5e2SRadim Krčmář bool x2apic_mode = rdmsr(MSR_IA32_APICBASE) & APIC_EXTD; 148a222b5e2SRadim Krčmář 149a222b5e2SRadim Krčmář if (x2apic_mode) 150a222b5e2SRadim Krčmář reset_apic(); 151a222b5e2SRadim Krčmář 152a222b5e2SRadim Krčmář id = apic_id(); 153a222b5e2SRadim Krčmář report("xapic id matches cpuid", initial_xapic_id == id); 154a222b5e2SRadim Krčmář 155a222b5e2SRadim Krčmář newid = (id + 1) << 24; 156a222b5e2SRadim Krčmář report("writeable xapic id", 157a222b5e2SRadim Krčmář !test_for_exception(GP_VECTOR, do_write_apic_id, &newid) && 158a222b5e2SRadim Krčmář id + 1 == apic_id()); 159a222b5e2SRadim Krčmář 160a222b5e2SRadim Krčmář if (!enable_x2apic()) 161a222b5e2SRadim Krčmář goto out; 162a222b5e2SRadim Krčmář 163a222b5e2SRadim Krčmář report("non-writeable x2apic id", 164a222b5e2SRadim Krčmář test_for_exception(GP_VECTOR, do_write_apic_id, &newid)); 165a222b5e2SRadim Krčmář report("sane x2apic id", initial_xapic_id == (apic_id() & 0xff)); 166a222b5e2SRadim Krčmář 167a222b5e2SRadim Krčmář /* old QEMUs do not set initial x2APIC ID */ 168a222b5e2SRadim Krčmář report("x2apic id matches cpuid", 169a222b5e2SRadim Krčmář initial_xapic_id == (initial_x2apic_id & 0xff) && 170a222b5e2SRadim Krčmář initial_x2apic_id == apic_id()); 171a222b5e2SRadim Krčmář 172a222b5e2SRadim Krčmář out: 173a222b5e2SRadim Krčmář reset_apic(); 174a222b5e2SRadim Krčmář 175a222b5e2SRadim Krčmář report("correct xapic id after reset", initial_xapic_id == apic_id()); 176a222b5e2SRadim Krčmář 177a222b5e2SRadim Krčmář /* old KVMs do not reset xAPIC ID */ 178a222b5e2SRadim Krčmář if (id != apic_id()) 179a222b5e2SRadim Krčmář apic_write(APIC_ID, id << 24); 180a222b5e2SRadim Krčmář 181a222b5e2SRadim Krčmář if (x2apic_mode) 182a222b5e2SRadim Krčmář enable_x2apic(); 183a222b5e2SRadim Krčmář } 184a222b5e2SRadim Krčmář 185a222b5e2SRadim Krčmář static void test_apic_id(void) 186a222b5e2SRadim Krčmář { 187a222b5e2SRadim Krčmář if (cpu_count() < 2) 188a222b5e2SRadim Krčmář return; 189a222b5e2SRadim Krčmář 190a222b5e2SRadim Krčmář on_cpu(1, __test_apic_id, NULL); 191a222b5e2SRadim Krčmář } 192a222b5e2SRadim Krčmář 1937d36db35SAvi Kivity static int ipi_count; 1947d36db35SAvi Kivity 1957d36db35SAvi Kivity static void self_ipi_isr(isr_regs_t *regs) 1967d36db35SAvi Kivity { 1977d36db35SAvi Kivity ++ipi_count; 1987d36db35SAvi Kivity eoi(); 1997d36db35SAvi Kivity } 2007d36db35SAvi Kivity 2017d36db35SAvi Kivity static void test_self_ipi(void) 2027d36db35SAvi Kivity { 2037d36db35SAvi Kivity int vec = 0xf1; 2047d36db35SAvi Kivity 205d51bd17eSGleb Natapov handle_irq(vec, self_ipi_isr); 2067d36db35SAvi Kivity irq_enable(); 2077d36db35SAvi Kivity apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec, 2087d36db35SAvi Kivity 0); 2097d36db35SAvi Kivity asm volatile ("nop"); 2107d36db35SAvi Kivity report("self ipi", ipi_count == 1); 2117d36db35SAvi Kivity } 2127d36db35SAvi Kivity 213f2d2b7c7SAvi Kivity volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active; 214f2d2b7c7SAvi Kivity 215f2d2b7c7SAvi Kivity void sti_nop(char *p) 216f2d2b7c7SAvi Kivity { 217f2d2b7c7SAvi Kivity asm volatile ( 218f2d2b7c7SAvi Kivity ".globl post_sti \n\t" 219f2d2b7c7SAvi Kivity "sti \n" 220f2d2b7c7SAvi Kivity /* 221f2d2b7c7SAvi Kivity * vmx won't exit on external interrupt if blocked-by-sti, 222f2d2b7c7SAvi Kivity * so give it a reason to exit by accessing an unmapped page. 223f2d2b7c7SAvi Kivity */ 224f2d2b7c7SAvi Kivity "post_sti: testb $0, %0 \n\t" 225f2d2b7c7SAvi Kivity "nop \n\t" 226f2d2b7c7SAvi Kivity "cli" 227f2d2b7c7SAvi Kivity : : "m"(*p) 228f2d2b7c7SAvi Kivity ); 229f2d2b7c7SAvi Kivity nmi_counter = nmi_counter_private; 230f2d2b7c7SAvi Kivity } 231f2d2b7c7SAvi Kivity 232f2d2b7c7SAvi Kivity static void sti_loop(void *ignore) 233f2d2b7c7SAvi Kivity { 234f2d2b7c7SAvi Kivity unsigned k = 0; 235f2d2b7c7SAvi Kivity 236f2d2b7c7SAvi Kivity while (sti_loop_active) { 237f2d2b7c7SAvi Kivity sti_nop((char *)(ulong)((k++ * 4096) % (128 * 1024 * 1024))); 238f2d2b7c7SAvi Kivity } 239f2d2b7c7SAvi Kivity } 240f2d2b7c7SAvi Kivity 241f2d2b7c7SAvi Kivity static void nmi_handler(isr_regs_t *regs) 242f2d2b7c7SAvi Kivity { 243f2d2b7c7SAvi Kivity extern void post_sti(void); 244f2d2b7c7SAvi Kivity ++nmi_counter_private; 245f2d2b7c7SAvi Kivity nmi_hlt_counter += regs->rip == (ulong)post_sti; 246f2d2b7c7SAvi Kivity } 247f2d2b7c7SAvi Kivity 248f2d2b7c7SAvi Kivity static void update_cr3(void *cr3) 249f2d2b7c7SAvi Kivity { 250f2d2b7c7SAvi Kivity write_cr3((ulong)cr3); 251f2d2b7c7SAvi Kivity } 252f2d2b7c7SAvi Kivity 253f2d2b7c7SAvi Kivity static void test_sti_nmi(void) 254f2d2b7c7SAvi Kivity { 255f2d2b7c7SAvi Kivity unsigned old_counter; 256f2d2b7c7SAvi Kivity 257f2d2b7c7SAvi Kivity if (cpu_count() < 2) { 258f2d2b7c7SAvi Kivity return; 259f2d2b7c7SAvi Kivity } 260f2d2b7c7SAvi Kivity 261d51bd17eSGleb Natapov handle_irq(2, nmi_handler); 262f2d2b7c7SAvi Kivity on_cpu(1, update_cr3, (void *)read_cr3()); 263f2d2b7c7SAvi Kivity 264f2d2b7c7SAvi Kivity sti_loop_active = 1; 265f2d2b7c7SAvi Kivity on_cpu_async(1, sti_loop, 0); 266f2d2b7c7SAvi Kivity while (nmi_counter < 30000) { 267f2d2b7c7SAvi Kivity old_counter = nmi_counter; 268f2d2b7c7SAvi Kivity apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 1); 269f2d2b7c7SAvi Kivity while (nmi_counter == old_counter) { 270f2d2b7c7SAvi Kivity ; 271f2d2b7c7SAvi Kivity } 272f2d2b7c7SAvi Kivity } 273f2d2b7c7SAvi Kivity sti_loop_active = 0; 274f2d2b7c7SAvi Kivity report("nmi-after-sti", nmi_hlt_counter == 0); 275f2d2b7c7SAvi Kivity } 276f2d2b7c7SAvi Kivity 277173e7eacSAvi Kivity static volatile bool nmi_done, nmi_flushed; 278173e7eacSAvi Kivity static volatile int nmi_received; 279173e7eacSAvi Kivity static volatile int cpu0_nmi_ctr1, cpu1_nmi_ctr1; 280173e7eacSAvi Kivity static volatile int cpu0_nmi_ctr2, cpu1_nmi_ctr2; 281173e7eacSAvi Kivity 282173e7eacSAvi Kivity static void multiple_nmi_handler(isr_regs_t *regs) 283173e7eacSAvi Kivity { 284173e7eacSAvi Kivity ++nmi_received; 285173e7eacSAvi Kivity } 286173e7eacSAvi Kivity 287173e7eacSAvi Kivity static void kick_me_nmi(void *blah) 288173e7eacSAvi Kivity { 289173e7eacSAvi Kivity while (!nmi_done) { 290173e7eacSAvi Kivity ++cpu1_nmi_ctr1; 291173e7eacSAvi Kivity while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1 && !nmi_done) { 292173e7eacSAvi Kivity pause(); 293173e7eacSAvi Kivity } 294173e7eacSAvi Kivity if (nmi_done) { 295173e7eacSAvi Kivity return; 296173e7eacSAvi Kivity } 297173e7eacSAvi Kivity apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); 298173e7eacSAvi Kivity /* make sure the NMI has arrived by sending an IPI after it */ 299173e7eacSAvi Kivity apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT 300173e7eacSAvi Kivity | 0x44, 0); 301173e7eacSAvi Kivity ++cpu1_nmi_ctr2; 302173e7eacSAvi Kivity while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done) { 303173e7eacSAvi Kivity pause(); 304173e7eacSAvi Kivity } 305173e7eacSAvi Kivity } 306173e7eacSAvi Kivity } 307173e7eacSAvi Kivity 308173e7eacSAvi Kivity static void flush_nmi(isr_regs_t *regs) 309173e7eacSAvi Kivity { 310173e7eacSAvi Kivity nmi_flushed = true; 311173e7eacSAvi Kivity apic_write(APIC_EOI, 0); 312173e7eacSAvi Kivity } 313173e7eacSAvi Kivity 314173e7eacSAvi Kivity static void test_multiple_nmi(void) 315173e7eacSAvi Kivity { 316173e7eacSAvi Kivity int i; 317173e7eacSAvi Kivity bool ok = true; 318173e7eacSAvi Kivity 319173e7eacSAvi Kivity if (cpu_count() < 2) { 320173e7eacSAvi Kivity return; 321173e7eacSAvi Kivity } 322173e7eacSAvi Kivity 323173e7eacSAvi Kivity sti(); 324173e7eacSAvi Kivity handle_irq(2, multiple_nmi_handler); 325173e7eacSAvi Kivity handle_irq(0x44, flush_nmi); 326173e7eacSAvi Kivity on_cpu_async(1, kick_me_nmi, 0); 327173e7eacSAvi Kivity for (i = 0; i < 1000000; ++i) { 328173e7eacSAvi Kivity nmi_flushed = false; 329173e7eacSAvi Kivity nmi_received = 0; 330173e7eacSAvi Kivity ++cpu0_nmi_ctr1; 331173e7eacSAvi Kivity while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1) { 332173e7eacSAvi Kivity pause(); 333173e7eacSAvi Kivity } 334173e7eacSAvi Kivity apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); 335173e7eacSAvi Kivity while (!nmi_flushed) { 336173e7eacSAvi Kivity pause(); 337173e7eacSAvi Kivity } 338173e7eacSAvi Kivity if (nmi_received != 2) { 339173e7eacSAvi Kivity ok = false; 340173e7eacSAvi Kivity break; 341173e7eacSAvi Kivity } 342173e7eacSAvi Kivity ++cpu0_nmi_ctr2; 343173e7eacSAvi Kivity while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2) { 344173e7eacSAvi Kivity pause(); 345173e7eacSAvi Kivity } 346173e7eacSAvi Kivity } 347173e7eacSAvi Kivity nmi_done = true; 348173e7eacSAvi Kivity report("multiple nmi", ok); 349173e7eacSAvi Kivity } 350173e7eacSAvi Kivity 3519f815b29SPeter Xu static volatile int lvtt_counter = 0; 3529f815b29SPeter Xu 3539f815b29SPeter Xu static void lvtt_handler(isr_regs_t *regs) 3549f815b29SPeter Xu { 3559f815b29SPeter Xu lvtt_counter++; 3569f815b29SPeter Xu eoi(); 3579f815b29SPeter Xu } 3589f815b29SPeter Xu 3599f815b29SPeter Xu static void test_apic_timer_one_shot(void) 3609f815b29SPeter Xu { 3619f815b29SPeter Xu uint64_t tsc1, tsc2; 3629f815b29SPeter Xu static const uint32_t interval = 0x10000; 3639f815b29SPeter Xu 3649f815b29SPeter Xu #define APIC_LVT_TIMER_VECTOR (0xee) 3659f815b29SPeter Xu 3669f815b29SPeter Xu handle_irq(APIC_LVT_TIMER_VECTOR, lvtt_handler); 3679f815b29SPeter Xu irq_enable(); 3689f815b29SPeter Xu 3699f815b29SPeter Xu /* One shot mode */ 370*9111ccabSRadim Krčmář apic_write(APIC_LVTT, APIC_LVT_TIMER_ONESHOT | 3719f815b29SPeter Xu APIC_LVT_TIMER_VECTOR); 3729f815b29SPeter Xu /* Divider == 1 */ 3739f815b29SPeter Xu apic_write(APIC_TDCR, 0x0000000b); 3749f815b29SPeter Xu 3759f815b29SPeter Xu tsc1 = rdtsc(); 3769f815b29SPeter Xu /* Set "Initial Counter Register", which starts the timer */ 3779f815b29SPeter Xu apic_write(APIC_TMICT, interval); 3789f815b29SPeter Xu while (!lvtt_counter); 3799f815b29SPeter Xu tsc2 = rdtsc(); 3809f815b29SPeter Xu 3819f815b29SPeter Xu /* 3829f815b29SPeter Xu * For LVT Timer clock, SDM vol 3 10.5.4 says it should be 3839f815b29SPeter Xu * derived from processor's bus clock (IIUC which is the same 3849f815b29SPeter Xu * as TSC), however QEMU seems to be using nanosecond. In all 3859f815b29SPeter Xu * cases, the following should satisfy on all modern 3869f815b29SPeter Xu * processors. 3879f815b29SPeter Xu */ 3889f815b29SPeter Xu report("APIC LVT timer one shot", (lvtt_counter == 1) && 3899f815b29SPeter Xu (tsc2 - tsc1 >= interval)); 3909f815b29SPeter Xu } 3919f815b29SPeter Xu 3927d36db35SAvi Kivity int main() 3937d36db35SAvi Kivity { 3947d36db35SAvi Kivity setup_vm(); 395f2d2b7c7SAvi Kivity smp_init(); 396d51bd17eSGleb Natapov setup_idt(); 3977d36db35SAvi Kivity 3987d36db35SAvi Kivity test_lapic_existence(); 3997d36db35SAvi Kivity 4007d36db35SAvi Kivity mask_pic_interrupts(); 401a222b5e2SRadim Krčmář test_apic_id(); 4027d36db35SAvi Kivity test_enable_x2apic(); 4039b6bdb3fSJan Kiszka test_apicbase(); 4047d36db35SAvi Kivity 4057d36db35SAvi Kivity test_self_ipi(); 4067d36db35SAvi Kivity 407f2d2b7c7SAvi Kivity test_sti_nmi(); 408173e7eacSAvi Kivity test_multiple_nmi(); 4097d36db35SAvi Kivity 4109f815b29SPeter Xu test_apic_timer_one_shot(); 411d423ca36SLiu, Jinsong test_tsc_deadline_timer(); 412d423ca36SLiu, Jinsong 413f3cdd159SJan Kiszka return report_summary(); 4147d36db35SAvi Kivity } 415