xref: /kvm-unit-tests/x86/hyperv_stimer.c (revision a2b7c4999fec95bc48e27d9ed48627a47216fc98)
169d4bf75SAndrey Smetanin #include "libcflat.h"
269d4bf75SAndrey Smetanin #include "processor.h"
369d4bf75SAndrey Smetanin #include "msr.h"
469d4bf75SAndrey Smetanin #include "isr.h"
569d4bf75SAndrey Smetanin #include "vm.h"
669d4bf75SAndrey Smetanin #include "apic.h"
769d4bf75SAndrey Smetanin #include "desc.h"
869d4bf75SAndrey Smetanin #include "io.h"
969d4bf75SAndrey Smetanin #include "smp.h"
1069d4bf75SAndrey Smetanin #include "atomic.h"
1169d4bf75SAndrey Smetanin #include "hyperv.h"
1269d4bf75SAndrey Smetanin 
1369d4bf75SAndrey Smetanin #define MAX_CPUS 4
1469d4bf75SAndrey Smetanin 
1569d4bf75SAndrey Smetanin #define SINT1_VEC 0xF1
1669d4bf75SAndrey Smetanin #define SINT2_VEC 0xF2
1769d4bf75SAndrey Smetanin 
1869d4bf75SAndrey Smetanin #define SINT1_NUM 2
1969d4bf75SAndrey Smetanin #define SINT2_NUM 3
2069d4bf75SAndrey Smetanin #define ONE_MS_IN_100NS 10000
2169d4bf75SAndrey Smetanin 
2269d4bf75SAndrey Smetanin static atomic_t g_cpus_comp_count;
2369d4bf75SAndrey Smetanin static int g_cpus_count;
2469d4bf75SAndrey Smetanin static struct spinlock g_synic_alloc_lock;
2569d4bf75SAndrey Smetanin 
2669d4bf75SAndrey Smetanin struct stimer {
2769d4bf75SAndrey Smetanin     int sint;
2869d4bf75SAndrey Smetanin     int index;
2969d4bf75SAndrey Smetanin     atomic_t fire_count;
3069d4bf75SAndrey Smetanin };
3169d4bf75SAndrey Smetanin 
3269d4bf75SAndrey Smetanin struct svcpu {
3369d4bf75SAndrey Smetanin     int vcpu;
3469d4bf75SAndrey Smetanin     void *msg_page;
3569d4bf75SAndrey Smetanin     void *evt_page;
3669d4bf75SAndrey Smetanin     struct stimer timer[HV_SYNIC_STIMER_COUNT];
3769d4bf75SAndrey Smetanin };
3869d4bf75SAndrey Smetanin 
3969d4bf75SAndrey Smetanin static struct svcpu g_synic_vcpu[MAX_CPUS];
4069d4bf75SAndrey Smetanin 
4169d4bf75SAndrey Smetanin static void *synic_alloc_page(void)
4269d4bf75SAndrey Smetanin {
4369d4bf75SAndrey Smetanin     void *page;
4469d4bf75SAndrey Smetanin 
4569d4bf75SAndrey Smetanin     spin_lock(&g_synic_alloc_lock);
4669d4bf75SAndrey Smetanin     page = alloc_page();
4769d4bf75SAndrey Smetanin     spin_unlock(&g_synic_alloc_lock);
4869d4bf75SAndrey Smetanin     return page;
4969d4bf75SAndrey Smetanin }
5069d4bf75SAndrey Smetanin 
5169d4bf75SAndrey Smetanin static void synic_free_page(void *page)
5269d4bf75SAndrey Smetanin {
5369d4bf75SAndrey Smetanin     spin_lock(&g_synic_alloc_lock);
5469d4bf75SAndrey Smetanin     free_page(page);
5569d4bf75SAndrey Smetanin     spin_unlock(&g_synic_alloc_lock);
5669d4bf75SAndrey Smetanin }
5769d4bf75SAndrey Smetanin 
5869d4bf75SAndrey Smetanin static void stimer_init(struct stimer *timer, int index)
5969d4bf75SAndrey Smetanin {
6069d4bf75SAndrey Smetanin     memset(timer, 0, sizeof(*timer));
6169d4bf75SAndrey Smetanin     timer->index = index;
6269d4bf75SAndrey Smetanin }
6369d4bf75SAndrey Smetanin 
6469d4bf75SAndrey Smetanin static void synic_enable(void)
6569d4bf75SAndrey Smetanin {
6669d4bf75SAndrey Smetanin     int vcpu = smp_id(), i;
6769d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
6869d4bf75SAndrey Smetanin 
6969d4bf75SAndrey Smetanin     memset(svcpu, 0, sizeof(*svcpu));
7069d4bf75SAndrey Smetanin     svcpu->vcpu = vcpu;
7169d4bf75SAndrey Smetanin     svcpu->msg_page = synic_alloc_page();
7269d4bf75SAndrey Smetanin     for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) {
7369d4bf75SAndrey Smetanin         stimer_init(&svcpu->timer[i], i);
7469d4bf75SAndrey Smetanin     }
7569d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(svcpu->msg_page) |
7669d4bf75SAndrey Smetanin             HV_SYNIC_SIMP_ENABLE);
7769d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE);
7869d4bf75SAndrey Smetanin }
7969d4bf75SAndrey Smetanin 
8069d4bf75SAndrey Smetanin static void stimer_shutdown(struct stimer *timer)
8169d4bf75SAndrey Smetanin {
8269d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_STIMER0_CONFIG + 2*timer->index, 0);
8369d4bf75SAndrey Smetanin }
8469d4bf75SAndrey Smetanin 
8569d4bf75SAndrey Smetanin static void process_stimer_expired(struct svcpu *svcpu, struct stimer *timer,
8669d4bf75SAndrey Smetanin                                    u64 expiration_time, u64 delivery_time)
8769d4bf75SAndrey Smetanin {
8869d4bf75SAndrey Smetanin     atomic_inc(&timer->fire_count);
8969d4bf75SAndrey Smetanin }
9069d4bf75SAndrey Smetanin 
9169d4bf75SAndrey Smetanin static void process_stimer_msg(struct svcpu *svcpu,
9269d4bf75SAndrey Smetanin                               struct hv_message *msg, int sint)
9369d4bf75SAndrey Smetanin {
9469d4bf75SAndrey Smetanin     struct hv_timer_message_payload *payload =
9569d4bf75SAndrey Smetanin                         (struct hv_timer_message_payload *)msg->u.payload;
9669d4bf75SAndrey Smetanin     struct stimer *timer;
9769d4bf75SAndrey Smetanin 
9869d4bf75SAndrey Smetanin     if (msg->header.message_type != HVMSG_TIMER_EXPIRED &&
9969d4bf75SAndrey Smetanin         msg->header.message_type != HVMSG_NONE) {
10069d4bf75SAndrey Smetanin         report("invalid Hyper-V SynIC msg type", false);
10169d4bf75SAndrey Smetanin         report_summary();
102*a2b7c499SAndrew Jones         abort();
10369d4bf75SAndrey Smetanin     }
10469d4bf75SAndrey Smetanin 
10569d4bf75SAndrey Smetanin     if (msg->header.message_type == HVMSG_NONE) {
10669d4bf75SAndrey Smetanin         return;
10769d4bf75SAndrey Smetanin     }
10869d4bf75SAndrey Smetanin 
10969d4bf75SAndrey Smetanin     if (msg->header.payload_size < sizeof(*payload)) {
11069d4bf75SAndrey Smetanin         report("invalid Hyper-V SynIC msg payload size", false);
11169d4bf75SAndrey Smetanin         report_summary();
112*a2b7c499SAndrew Jones         abort();
11369d4bf75SAndrey Smetanin     }
11469d4bf75SAndrey Smetanin 
11569d4bf75SAndrey Smetanin     /* Now process timer expiration message */
11669d4bf75SAndrey Smetanin 
11769d4bf75SAndrey Smetanin     if (payload->timer_index >= ARRAY_SIZE(svcpu->timer)) {
11869d4bf75SAndrey Smetanin         report("invalid Hyper-V SynIC timer index", false);
11969d4bf75SAndrey Smetanin         report_summary();
120*a2b7c499SAndrew Jones         abort();
12169d4bf75SAndrey Smetanin     }
12269d4bf75SAndrey Smetanin     timer = &svcpu->timer[payload->timer_index];
12369d4bf75SAndrey Smetanin     process_stimer_expired(svcpu, timer, payload->expiration_time,
12469d4bf75SAndrey Smetanin                           payload->delivery_time);
12569d4bf75SAndrey Smetanin 
12669d4bf75SAndrey Smetanin     msg->header.message_type = HVMSG_NONE;
12769d4bf75SAndrey Smetanin     mb();
12869d4bf75SAndrey Smetanin     if (msg->header.message_flags.msg_pending) {
12969d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_EOM, 0);
13069d4bf75SAndrey Smetanin     }
13169d4bf75SAndrey Smetanin }
13269d4bf75SAndrey Smetanin 
13369d4bf75SAndrey Smetanin static void __stimer_isr(int vcpu)
13469d4bf75SAndrey Smetanin {
13569d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
13669d4bf75SAndrey Smetanin     struct hv_message_page *msg_page;
13769d4bf75SAndrey Smetanin     struct hv_message *msg;
13869d4bf75SAndrey Smetanin     int i;
13969d4bf75SAndrey Smetanin 
14069d4bf75SAndrey Smetanin 
14169d4bf75SAndrey Smetanin     msg_page = (struct hv_message_page *)svcpu->msg_page;
14269d4bf75SAndrey Smetanin     for (i = 0; i < ARRAY_SIZE(msg_page->sint_message); i++) {
14369d4bf75SAndrey Smetanin         msg = &msg_page->sint_message[i];
14469d4bf75SAndrey Smetanin         process_stimer_msg(svcpu, msg, i);
14569d4bf75SAndrey Smetanin     }
14669d4bf75SAndrey Smetanin }
14769d4bf75SAndrey Smetanin 
14869d4bf75SAndrey Smetanin static void stimer_isr(isr_regs_t *regs)
14969d4bf75SAndrey Smetanin {
15069d4bf75SAndrey Smetanin     int vcpu = smp_id();
15169d4bf75SAndrey Smetanin 
15269d4bf75SAndrey Smetanin     __stimer_isr(vcpu);
15369d4bf75SAndrey Smetanin     eoi();
15469d4bf75SAndrey Smetanin }
15569d4bf75SAndrey Smetanin 
15669d4bf75SAndrey Smetanin static void stimer_isr_auto_eoi(isr_regs_t *regs)
15769d4bf75SAndrey Smetanin {
15869d4bf75SAndrey Smetanin     int vcpu = smp_id();
15969d4bf75SAndrey Smetanin 
16069d4bf75SAndrey Smetanin     __stimer_isr(vcpu);
16169d4bf75SAndrey Smetanin }
16269d4bf75SAndrey Smetanin 
16369d4bf75SAndrey Smetanin static void stimer_start(struct stimer *timer,
16469d4bf75SAndrey Smetanin                          bool auto_enable, bool periodic,
16569d4bf75SAndrey Smetanin                          u64 tick_100ns, int sint)
16669d4bf75SAndrey Smetanin {
16769d4bf75SAndrey Smetanin     u64 config, count;
16869d4bf75SAndrey Smetanin 
16969d4bf75SAndrey Smetanin     timer->sint = sint;
17069d4bf75SAndrey Smetanin     atomic_set(&timer->fire_count, 0);
17169d4bf75SAndrey Smetanin 
17269d4bf75SAndrey Smetanin     config = 0;
17369d4bf75SAndrey Smetanin     if (periodic) {
17469d4bf75SAndrey Smetanin         config |= HV_STIMER_PERIODIC;
17569d4bf75SAndrey Smetanin     }
17669d4bf75SAndrey Smetanin 
17769d4bf75SAndrey Smetanin     config |= ((u8)(sint & 0xFF)) << 16;
17869d4bf75SAndrey Smetanin     config |= HV_STIMER_ENABLE;
17969d4bf75SAndrey Smetanin     if (auto_enable) {
18069d4bf75SAndrey Smetanin         config |= HV_STIMER_AUTOENABLE;
18169d4bf75SAndrey Smetanin     }
18269d4bf75SAndrey Smetanin 
18369d4bf75SAndrey Smetanin     if (periodic) {
18469d4bf75SAndrey Smetanin         count = tick_100ns;
18569d4bf75SAndrey Smetanin     } else {
18669d4bf75SAndrey Smetanin         count = rdmsr(HV_X64_MSR_TIME_REF_COUNT) + tick_100ns;
18769d4bf75SAndrey Smetanin     }
18869d4bf75SAndrey Smetanin 
18969d4bf75SAndrey Smetanin     if (!auto_enable) {
19069d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count);
19169d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config);
19269d4bf75SAndrey Smetanin     } else {
19369d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config);
19469d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count);
19569d4bf75SAndrey Smetanin     }
19669d4bf75SAndrey Smetanin }
19769d4bf75SAndrey Smetanin 
19869d4bf75SAndrey Smetanin static void stimers_shutdown(void)
19969d4bf75SAndrey Smetanin {
20069d4bf75SAndrey Smetanin     int vcpu = smp_id(), i;
20169d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
20269d4bf75SAndrey Smetanin 
20369d4bf75SAndrey Smetanin     for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) {
20469d4bf75SAndrey Smetanin         stimer_shutdown(&svcpu->timer[i]);
20569d4bf75SAndrey Smetanin     }
20669d4bf75SAndrey Smetanin }
20769d4bf75SAndrey Smetanin 
20869d4bf75SAndrey Smetanin static void synic_disable(void)
20969d4bf75SAndrey Smetanin {
21069d4bf75SAndrey Smetanin     int vcpu = smp_id();
21169d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
21269d4bf75SAndrey Smetanin 
21369d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SCONTROL, 0);
21469d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SIMP, 0);
21569d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SIEFP, 0);
21669d4bf75SAndrey Smetanin     synic_free_page(svcpu->msg_page);
21769d4bf75SAndrey Smetanin }
21869d4bf75SAndrey Smetanin 
21969d4bf75SAndrey Smetanin static void cpu_comp(void)
22069d4bf75SAndrey Smetanin {
22169d4bf75SAndrey Smetanin     atomic_inc(&g_cpus_comp_count);
22269d4bf75SAndrey Smetanin }
22369d4bf75SAndrey Smetanin 
22469d4bf75SAndrey Smetanin static void stimer_test_prepare(void *ctx)
22569d4bf75SAndrey Smetanin {
22669d4bf75SAndrey Smetanin     int vcpu = smp_id();
22769d4bf75SAndrey Smetanin 
22869d4bf75SAndrey Smetanin     write_cr3((ulong)ctx);
22969d4bf75SAndrey Smetanin     synic_enable();
23069d4bf75SAndrey Smetanin     synic_sint_create(vcpu, SINT1_NUM, SINT1_VEC, false);
23169d4bf75SAndrey Smetanin     synic_sint_create(vcpu, SINT2_NUM, SINT2_VEC, true);
23269d4bf75SAndrey Smetanin     cpu_comp();
23369d4bf75SAndrey Smetanin }
23469d4bf75SAndrey Smetanin 
23569d4bf75SAndrey Smetanin static void stimer_test_periodic(int vcpu, struct stimer *timer1,
23669d4bf75SAndrey Smetanin                                  struct stimer *timer2)
23769d4bf75SAndrey Smetanin {
23869d4bf75SAndrey Smetanin     /* Check periodic timers */
23969d4bf75SAndrey Smetanin     stimer_start(timer1, false, true, ONE_MS_IN_100NS, SINT1_NUM);
24069d4bf75SAndrey Smetanin     stimer_start(timer2, false, true, ONE_MS_IN_100NS, SINT2_NUM);
24169d4bf75SAndrey Smetanin     while ((atomic_read(&timer1->fire_count) < 1000) ||
24269d4bf75SAndrey Smetanin            (atomic_read(&timer2->fire_count) < 1000)) {
24369d4bf75SAndrey Smetanin         pause();
24469d4bf75SAndrey Smetanin     }
24569d4bf75SAndrey Smetanin     report("Hyper-V SynIC periodic timers test vcpu %d", true, vcpu);
24669d4bf75SAndrey Smetanin     stimer_shutdown(timer1);
24769d4bf75SAndrey Smetanin     stimer_shutdown(timer2);
24869d4bf75SAndrey Smetanin }
24969d4bf75SAndrey Smetanin 
25069d4bf75SAndrey Smetanin static void stimer_test_one_shot(int vcpu, struct stimer *timer)
25169d4bf75SAndrey Smetanin {
25269d4bf75SAndrey Smetanin     /* Check one-shot timer */
25369d4bf75SAndrey Smetanin     stimer_start(timer, false, false, ONE_MS_IN_100NS, SINT1_NUM);
25469d4bf75SAndrey Smetanin     while (atomic_read(&timer->fire_count) < 1) {
25569d4bf75SAndrey Smetanin         pause();
25669d4bf75SAndrey Smetanin     }
25769d4bf75SAndrey Smetanin     report("Hyper-V SynIC one-shot test vcpu %d", true, vcpu);
25869d4bf75SAndrey Smetanin     stimer_shutdown(timer);
25969d4bf75SAndrey Smetanin }
26069d4bf75SAndrey Smetanin 
26169d4bf75SAndrey Smetanin static void stimer_test_auto_enable_one_shot(int vcpu, struct stimer *timer)
26269d4bf75SAndrey Smetanin {
26369d4bf75SAndrey Smetanin     /* Check auto-enable one-shot timer */
26469d4bf75SAndrey Smetanin     stimer_start(timer, true, false, ONE_MS_IN_100NS, SINT1_NUM);
26569d4bf75SAndrey Smetanin     while (atomic_read(&timer->fire_count) < 1) {
26669d4bf75SAndrey Smetanin         pause();
26769d4bf75SAndrey Smetanin     }
26869d4bf75SAndrey Smetanin     report("Hyper-V SynIC auto-enable one-shot timer test vcpu %d", true, vcpu);
26969d4bf75SAndrey Smetanin     stimer_shutdown(timer);
27069d4bf75SAndrey Smetanin }
27169d4bf75SAndrey Smetanin 
27269d4bf75SAndrey Smetanin static void stimer_test_auto_enable_periodic(int vcpu, struct stimer *timer)
27369d4bf75SAndrey Smetanin {
27469d4bf75SAndrey Smetanin     /* Check auto-enable periodic timer */
27569d4bf75SAndrey Smetanin     stimer_start(timer, true, true, ONE_MS_IN_100NS, SINT1_NUM);
27669d4bf75SAndrey Smetanin     while (atomic_read(&timer->fire_count) < 1000) {
27769d4bf75SAndrey Smetanin         pause();
27869d4bf75SAndrey Smetanin     }
27969d4bf75SAndrey Smetanin     report("Hyper-V SynIC auto-enable periodic timer test vcpu %d", true, vcpu);
28069d4bf75SAndrey Smetanin     stimer_shutdown(timer);
28169d4bf75SAndrey Smetanin }
28269d4bf75SAndrey Smetanin 
28369d4bf75SAndrey Smetanin static void stimer_test(void *ctx)
28469d4bf75SAndrey Smetanin {
28569d4bf75SAndrey Smetanin     int vcpu = smp_id();
28669d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
28769d4bf75SAndrey Smetanin     struct stimer *timer1, *timer2;
28869d4bf75SAndrey Smetanin 
28969d4bf75SAndrey Smetanin     irq_enable();
29069d4bf75SAndrey Smetanin 
29169d4bf75SAndrey Smetanin     timer1 = &svcpu->timer[0];
29269d4bf75SAndrey Smetanin     timer2 = &svcpu->timer[1];
29369d4bf75SAndrey Smetanin 
29469d4bf75SAndrey Smetanin     stimer_test_periodic(vcpu, timer1, timer2);
29569d4bf75SAndrey Smetanin     stimer_test_one_shot(vcpu, timer1);
29669d4bf75SAndrey Smetanin     stimer_test_auto_enable_one_shot(vcpu, timer2);
29769d4bf75SAndrey Smetanin     stimer_test_auto_enable_periodic(vcpu, timer1);
29869d4bf75SAndrey Smetanin 
29969d4bf75SAndrey Smetanin     irq_disable();
30069d4bf75SAndrey Smetanin     cpu_comp();
30169d4bf75SAndrey Smetanin }
30269d4bf75SAndrey Smetanin 
30369d4bf75SAndrey Smetanin static void stimer_test_cleanup(void *ctx)
30469d4bf75SAndrey Smetanin {
30569d4bf75SAndrey Smetanin     int vcpu = smp_id();
30669d4bf75SAndrey Smetanin 
30769d4bf75SAndrey Smetanin     stimers_shutdown();
30869d4bf75SAndrey Smetanin     synic_sint_destroy(vcpu, SINT1_NUM);
30969d4bf75SAndrey Smetanin     synic_sint_destroy(vcpu, SINT2_NUM);
31069d4bf75SAndrey Smetanin     synic_disable();
31169d4bf75SAndrey Smetanin     cpu_comp();
31269d4bf75SAndrey Smetanin }
31369d4bf75SAndrey Smetanin 
31469d4bf75SAndrey Smetanin static void on_each_cpu_async_wait(void (*func)(void *ctx), void *ctx)
31569d4bf75SAndrey Smetanin {
31669d4bf75SAndrey Smetanin     int i;
31769d4bf75SAndrey Smetanin 
31869d4bf75SAndrey Smetanin     atomic_set(&g_cpus_comp_count, 0);
31969d4bf75SAndrey Smetanin     for (i = 0; i < g_cpus_count; i++) {
32069d4bf75SAndrey Smetanin         on_cpu_async(i, func, ctx);
32169d4bf75SAndrey Smetanin     }
32269d4bf75SAndrey Smetanin     while (atomic_read(&g_cpus_comp_count) != g_cpus_count) {
32369d4bf75SAndrey Smetanin         pause();
32469d4bf75SAndrey Smetanin     }
32569d4bf75SAndrey Smetanin }
32669d4bf75SAndrey Smetanin 
32769d4bf75SAndrey Smetanin static void stimer_test_all(void)
32869d4bf75SAndrey Smetanin {
32969d4bf75SAndrey Smetanin     int ncpus;
33069d4bf75SAndrey Smetanin 
33169d4bf75SAndrey Smetanin     setup_vm();
33269d4bf75SAndrey Smetanin     smp_init();
33369d4bf75SAndrey Smetanin     setup_idt();
33469d4bf75SAndrey Smetanin     enable_apic();
33569d4bf75SAndrey Smetanin 
33669d4bf75SAndrey Smetanin     handle_irq(SINT1_VEC, stimer_isr);
33769d4bf75SAndrey Smetanin     handle_irq(SINT2_VEC, stimer_isr_auto_eoi);
33869d4bf75SAndrey Smetanin 
33969d4bf75SAndrey Smetanin     ncpus = cpu_count();
34069d4bf75SAndrey Smetanin     if (ncpus > MAX_CPUS) {
34169d4bf75SAndrey Smetanin         ncpus = MAX_CPUS;
34269d4bf75SAndrey Smetanin     }
34369d4bf75SAndrey Smetanin 
34469d4bf75SAndrey Smetanin     printf("cpus = %d\n", ncpus);
34569d4bf75SAndrey Smetanin     g_cpus_count = ncpus;
34669d4bf75SAndrey Smetanin 
34769d4bf75SAndrey Smetanin     on_each_cpu_async_wait(stimer_test_prepare, (void *)read_cr3());
34869d4bf75SAndrey Smetanin     on_each_cpu_async_wait(stimer_test, NULL);
34969d4bf75SAndrey Smetanin     on_each_cpu_async_wait(stimer_test_cleanup, NULL);
35069d4bf75SAndrey Smetanin }
35169d4bf75SAndrey Smetanin 
35269d4bf75SAndrey Smetanin int main(int ac, char **av)
35369d4bf75SAndrey Smetanin {
35469d4bf75SAndrey Smetanin 
35569d4bf75SAndrey Smetanin     if (!synic_supported()) {
35669d4bf75SAndrey Smetanin         report("Hyper-V SynIC is not supported", true);
35769d4bf75SAndrey Smetanin         goto done;
35869d4bf75SAndrey Smetanin     }
35969d4bf75SAndrey Smetanin 
36069d4bf75SAndrey Smetanin     if (!stimer_supported()) {
36169d4bf75SAndrey Smetanin         report("Hyper-V SynIC timers are not supported", true);
36269d4bf75SAndrey Smetanin         goto done;
36369d4bf75SAndrey Smetanin     }
36469d4bf75SAndrey Smetanin 
36569d4bf75SAndrey Smetanin     if (!hv_time_ref_counter_supported()) {
36669d4bf75SAndrey Smetanin         report("Hyper-V time reference counter is not supported", true);
36769d4bf75SAndrey Smetanin         goto done;
36869d4bf75SAndrey Smetanin     }
36969d4bf75SAndrey Smetanin 
37069d4bf75SAndrey Smetanin     stimer_test_all();
37169d4bf75SAndrey Smetanin done:
37269d4bf75SAndrey Smetanin     return report_summary();
37369d4bf75SAndrey Smetanin }
374