xref: /kvm-unit-tests/x86/hyperv_stimer.c (revision 69d4bf751641520f5b2d8e3f160c63c8966fcd8b)
1*69d4bf75SAndrey Smetanin #include "libcflat.h"
2*69d4bf75SAndrey Smetanin #include "processor.h"
3*69d4bf75SAndrey Smetanin #include "msr.h"
4*69d4bf75SAndrey Smetanin #include "isr.h"
5*69d4bf75SAndrey Smetanin #include "vm.h"
6*69d4bf75SAndrey Smetanin #include "apic.h"
7*69d4bf75SAndrey Smetanin #include "desc.h"
8*69d4bf75SAndrey Smetanin #include "io.h"
9*69d4bf75SAndrey Smetanin #include "smp.h"
10*69d4bf75SAndrey Smetanin #include "atomic.h"
11*69d4bf75SAndrey Smetanin #include "hyperv.h"
12*69d4bf75SAndrey Smetanin 
13*69d4bf75SAndrey Smetanin #define MAX_CPUS 4
14*69d4bf75SAndrey Smetanin 
15*69d4bf75SAndrey Smetanin #define SINT1_VEC 0xF1
16*69d4bf75SAndrey Smetanin #define SINT2_VEC 0xF2
17*69d4bf75SAndrey Smetanin 
18*69d4bf75SAndrey Smetanin #define SINT1_NUM 2
19*69d4bf75SAndrey Smetanin #define SINT2_NUM 3
20*69d4bf75SAndrey Smetanin #define ONE_MS_IN_100NS 10000
21*69d4bf75SAndrey Smetanin 
22*69d4bf75SAndrey Smetanin static atomic_t g_cpus_comp_count;
23*69d4bf75SAndrey Smetanin static int g_cpus_count;
24*69d4bf75SAndrey Smetanin static struct spinlock g_synic_alloc_lock;
25*69d4bf75SAndrey Smetanin 
26*69d4bf75SAndrey Smetanin struct stimer {
27*69d4bf75SAndrey Smetanin     int sint;
28*69d4bf75SAndrey Smetanin     int index;
29*69d4bf75SAndrey Smetanin     atomic_t fire_count;
30*69d4bf75SAndrey Smetanin };
31*69d4bf75SAndrey Smetanin 
32*69d4bf75SAndrey Smetanin struct svcpu {
33*69d4bf75SAndrey Smetanin     int vcpu;
34*69d4bf75SAndrey Smetanin     void *msg_page;
35*69d4bf75SAndrey Smetanin     void *evt_page;
36*69d4bf75SAndrey Smetanin     struct stimer timer[HV_SYNIC_STIMER_COUNT];
37*69d4bf75SAndrey Smetanin };
38*69d4bf75SAndrey Smetanin 
39*69d4bf75SAndrey Smetanin static struct svcpu g_synic_vcpu[MAX_CPUS];
40*69d4bf75SAndrey Smetanin 
41*69d4bf75SAndrey Smetanin static void *synic_alloc_page(void)
42*69d4bf75SAndrey Smetanin {
43*69d4bf75SAndrey Smetanin     void *page;
44*69d4bf75SAndrey Smetanin 
45*69d4bf75SAndrey Smetanin     spin_lock(&g_synic_alloc_lock);
46*69d4bf75SAndrey Smetanin     page = alloc_page();
47*69d4bf75SAndrey Smetanin     spin_unlock(&g_synic_alloc_lock);
48*69d4bf75SAndrey Smetanin     return page;
49*69d4bf75SAndrey Smetanin }
50*69d4bf75SAndrey Smetanin 
51*69d4bf75SAndrey Smetanin static void synic_free_page(void *page)
52*69d4bf75SAndrey Smetanin {
53*69d4bf75SAndrey Smetanin     spin_lock(&g_synic_alloc_lock);
54*69d4bf75SAndrey Smetanin     free_page(page);
55*69d4bf75SAndrey Smetanin     spin_unlock(&g_synic_alloc_lock);
56*69d4bf75SAndrey Smetanin }
57*69d4bf75SAndrey Smetanin 
58*69d4bf75SAndrey Smetanin static void stimer_init(struct stimer *timer, int index)
59*69d4bf75SAndrey Smetanin {
60*69d4bf75SAndrey Smetanin     memset(timer, 0, sizeof(*timer));
61*69d4bf75SAndrey Smetanin     timer->index = index;
62*69d4bf75SAndrey Smetanin }
63*69d4bf75SAndrey Smetanin 
64*69d4bf75SAndrey Smetanin static void synic_enable(void)
65*69d4bf75SAndrey Smetanin {
66*69d4bf75SAndrey Smetanin     int vcpu = smp_id(), i;
67*69d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
68*69d4bf75SAndrey Smetanin 
69*69d4bf75SAndrey Smetanin     memset(svcpu, 0, sizeof(*svcpu));
70*69d4bf75SAndrey Smetanin     svcpu->vcpu = vcpu;
71*69d4bf75SAndrey Smetanin     svcpu->msg_page = synic_alloc_page();
72*69d4bf75SAndrey Smetanin     for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) {
73*69d4bf75SAndrey Smetanin         stimer_init(&svcpu->timer[i], i);
74*69d4bf75SAndrey Smetanin     }
75*69d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(svcpu->msg_page) |
76*69d4bf75SAndrey Smetanin             HV_SYNIC_SIMP_ENABLE);
77*69d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE);
78*69d4bf75SAndrey Smetanin }
79*69d4bf75SAndrey Smetanin 
80*69d4bf75SAndrey Smetanin static void stimer_shutdown(struct stimer *timer)
81*69d4bf75SAndrey Smetanin {
82*69d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_STIMER0_CONFIG + 2*timer->index, 0);
83*69d4bf75SAndrey Smetanin }
84*69d4bf75SAndrey Smetanin 
85*69d4bf75SAndrey Smetanin static void process_stimer_expired(struct svcpu *svcpu, struct stimer *timer,
86*69d4bf75SAndrey Smetanin                                    u64 expiration_time, u64 delivery_time)
87*69d4bf75SAndrey Smetanin {
88*69d4bf75SAndrey Smetanin     atomic_inc(&timer->fire_count);
89*69d4bf75SAndrey Smetanin }
90*69d4bf75SAndrey Smetanin 
91*69d4bf75SAndrey Smetanin static void process_stimer_msg(struct svcpu *svcpu,
92*69d4bf75SAndrey Smetanin                               struct hv_message *msg, int sint)
93*69d4bf75SAndrey Smetanin {
94*69d4bf75SAndrey Smetanin     struct hv_timer_message_payload *payload =
95*69d4bf75SAndrey Smetanin                         (struct hv_timer_message_payload *)msg->u.payload;
96*69d4bf75SAndrey Smetanin     struct stimer *timer;
97*69d4bf75SAndrey Smetanin 
98*69d4bf75SAndrey Smetanin     if (msg->header.message_type != HVMSG_TIMER_EXPIRED &&
99*69d4bf75SAndrey Smetanin         msg->header.message_type != HVMSG_NONE) {
100*69d4bf75SAndrey Smetanin         report("invalid Hyper-V SynIC msg type", false);
101*69d4bf75SAndrey Smetanin         report_summary();
102*69d4bf75SAndrey Smetanin         exit(-1);
103*69d4bf75SAndrey Smetanin         return;
104*69d4bf75SAndrey Smetanin     }
105*69d4bf75SAndrey Smetanin 
106*69d4bf75SAndrey Smetanin     if (msg->header.message_type == HVMSG_NONE) {
107*69d4bf75SAndrey Smetanin         return;
108*69d4bf75SAndrey Smetanin     }
109*69d4bf75SAndrey Smetanin 
110*69d4bf75SAndrey Smetanin     if (msg->header.payload_size < sizeof(*payload)) {
111*69d4bf75SAndrey Smetanin         report("invalid Hyper-V SynIC msg payload size", false);
112*69d4bf75SAndrey Smetanin         report_summary();
113*69d4bf75SAndrey Smetanin         exit(-1);
114*69d4bf75SAndrey Smetanin         return;
115*69d4bf75SAndrey Smetanin     }
116*69d4bf75SAndrey Smetanin 
117*69d4bf75SAndrey Smetanin     /* Now process timer expiration message */
118*69d4bf75SAndrey Smetanin 
119*69d4bf75SAndrey Smetanin     if (payload->timer_index >= ARRAY_SIZE(svcpu->timer)) {
120*69d4bf75SAndrey Smetanin         report("invalid Hyper-V SynIC timer index", false);
121*69d4bf75SAndrey Smetanin         report_summary();
122*69d4bf75SAndrey Smetanin         exit(-1);
123*69d4bf75SAndrey Smetanin         return;
124*69d4bf75SAndrey Smetanin     }
125*69d4bf75SAndrey Smetanin     timer = &svcpu->timer[payload->timer_index];
126*69d4bf75SAndrey Smetanin     process_stimer_expired(svcpu, timer, payload->expiration_time,
127*69d4bf75SAndrey Smetanin                           payload->delivery_time);
128*69d4bf75SAndrey Smetanin 
129*69d4bf75SAndrey Smetanin     msg->header.message_type = HVMSG_NONE;
130*69d4bf75SAndrey Smetanin     mb();
131*69d4bf75SAndrey Smetanin     if (msg->header.message_flags.msg_pending) {
132*69d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_EOM, 0);
133*69d4bf75SAndrey Smetanin     }
134*69d4bf75SAndrey Smetanin }
135*69d4bf75SAndrey Smetanin 
136*69d4bf75SAndrey Smetanin static void __stimer_isr(int vcpu)
137*69d4bf75SAndrey Smetanin {
138*69d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
139*69d4bf75SAndrey Smetanin     struct hv_message_page *msg_page;
140*69d4bf75SAndrey Smetanin     struct hv_message *msg;
141*69d4bf75SAndrey Smetanin     int i;
142*69d4bf75SAndrey Smetanin 
143*69d4bf75SAndrey Smetanin 
144*69d4bf75SAndrey Smetanin     msg_page = (struct hv_message_page *)svcpu->msg_page;
145*69d4bf75SAndrey Smetanin     for (i = 0; i < ARRAY_SIZE(msg_page->sint_message); i++) {
146*69d4bf75SAndrey Smetanin         msg = &msg_page->sint_message[i];
147*69d4bf75SAndrey Smetanin         process_stimer_msg(svcpu, msg, i);
148*69d4bf75SAndrey Smetanin     }
149*69d4bf75SAndrey Smetanin }
150*69d4bf75SAndrey Smetanin 
151*69d4bf75SAndrey Smetanin static void stimer_isr(isr_regs_t *regs)
152*69d4bf75SAndrey Smetanin {
153*69d4bf75SAndrey Smetanin     int vcpu = smp_id();
154*69d4bf75SAndrey Smetanin 
155*69d4bf75SAndrey Smetanin     __stimer_isr(vcpu);
156*69d4bf75SAndrey Smetanin     eoi();
157*69d4bf75SAndrey Smetanin }
158*69d4bf75SAndrey Smetanin 
159*69d4bf75SAndrey Smetanin static void stimer_isr_auto_eoi(isr_regs_t *regs)
160*69d4bf75SAndrey Smetanin {
161*69d4bf75SAndrey Smetanin     int vcpu = smp_id();
162*69d4bf75SAndrey Smetanin 
163*69d4bf75SAndrey Smetanin     __stimer_isr(vcpu);
164*69d4bf75SAndrey Smetanin }
165*69d4bf75SAndrey Smetanin 
166*69d4bf75SAndrey Smetanin static void stimer_start(struct stimer *timer,
167*69d4bf75SAndrey Smetanin                          bool auto_enable, bool periodic,
168*69d4bf75SAndrey Smetanin                          u64 tick_100ns, int sint)
169*69d4bf75SAndrey Smetanin {
170*69d4bf75SAndrey Smetanin     u64 config, count;
171*69d4bf75SAndrey Smetanin 
172*69d4bf75SAndrey Smetanin     timer->sint = sint;
173*69d4bf75SAndrey Smetanin     atomic_set(&timer->fire_count, 0);
174*69d4bf75SAndrey Smetanin 
175*69d4bf75SAndrey Smetanin     config = 0;
176*69d4bf75SAndrey Smetanin     if (periodic) {
177*69d4bf75SAndrey Smetanin         config |= HV_STIMER_PERIODIC;
178*69d4bf75SAndrey Smetanin     }
179*69d4bf75SAndrey Smetanin 
180*69d4bf75SAndrey Smetanin     config |= ((u8)(sint & 0xFF)) << 16;
181*69d4bf75SAndrey Smetanin     config |= HV_STIMER_ENABLE;
182*69d4bf75SAndrey Smetanin     if (auto_enable) {
183*69d4bf75SAndrey Smetanin         config |= HV_STIMER_AUTOENABLE;
184*69d4bf75SAndrey Smetanin     }
185*69d4bf75SAndrey Smetanin 
186*69d4bf75SAndrey Smetanin     if (periodic) {
187*69d4bf75SAndrey Smetanin         count = tick_100ns;
188*69d4bf75SAndrey Smetanin     } else {
189*69d4bf75SAndrey Smetanin         count = rdmsr(HV_X64_MSR_TIME_REF_COUNT) + tick_100ns;
190*69d4bf75SAndrey Smetanin     }
191*69d4bf75SAndrey Smetanin 
192*69d4bf75SAndrey Smetanin     if (!auto_enable) {
193*69d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count);
194*69d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config);
195*69d4bf75SAndrey Smetanin     } else {
196*69d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config);
197*69d4bf75SAndrey Smetanin         wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count);
198*69d4bf75SAndrey Smetanin     }
199*69d4bf75SAndrey Smetanin }
200*69d4bf75SAndrey Smetanin 
201*69d4bf75SAndrey Smetanin static void stimers_shutdown(void)
202*69d4bf75SAndrey Smetanin {
203*69d4bf75SAndrey Smetanin     int vcpu = smp_id(), i;
204*69d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
205*69d4bf75SAndrey Smetanin 
206*69d4bf75SAndrey Smetanin     for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) {
207*69d4bf75SAndrey Smetanin         stimer_shutdown(&svcpu->timer[i]);
208*69d4bf75SAndrey Smetanin     }
209*69d4bf75SAndrey Smetanin }
210*69d4bf75SAndrey Smetanin 
211*69d4bf75SAndrey Smetanin static void synic_disable(void)
212*69d4bf75SAndrey Smetanin {
213*69d4bf75SAndrey Smetanin     int vcpu = smp_id();
214*69d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
215*69d4bf75SAndrey Smetanin 
216*69d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SCONTROL, 0);
217*69d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SIMP, 0);
218*69d4bf75SAndrey Smetanin     wrmsr(HV_X64_MSR_SIEFP, 0);
219*69d4bf75SAndrey Smetanin     synic_free_page(svcpu->msg_page);
220*69d4bf75SAndrey Smetanin }
221*69d4bf75SAndrey Smetanin 
222*69d4bf75SAndrey Smetanin static void cpu_comp(void)
223*69d4bf75SAndrey Smetanin {
224*69d4bf75SAndrey Smetanin     atomic_inc(&g_cpus_comp_count);
225*69d4bf75SAndrey Smetanin }
226*69d4bf75SAndrey Smetanin 
227*69d4bf75SAndrey Smetanin static void stimer_test_prepare(void *ctx)
228*69d4bf75SAndrey Smetanin {
229*69d4bf75SAndrey Smetanin     int vcpu = smp_id();
230*69d4bf75SAndrey Smetanin 
231*69d4bf75SAndrey Smetanin     write_cr3((ulong)ctx);
232*69d4bf75SAndrey Smetanin     synic_enable();
233*69d4bf75SAndrey Smetanin     synic_sint_create(vcpu, SINT1_NUM, SINT1_VEC, false);
234*69d4bf75SAndrey Smetanin     synic_sint_create(vcpu, SINT2_NUM, SINT2_VEC, true);
235*69d4bf75SAndrey Smetanin     cpu_comp();
236*69d4bf75SAndrey Smetanin }
237*69d4bf75SAndrey Smetanin 
238*69d4bf75SAndrey Smetanin static void stimer_test_periodic(int vcpu, struct stimer *timer1,
239*69d4bf75SAndrey Smetanin                                  struct stimer *timer2)
240*69d4bf75SAndrey Smetanin {
241*69d4bf75SAndrey Smetanin     /* Check periodic timers */
242*69d4bf75SAndrey Smetanin     stimer_start(timer1, false, true, ONE_MS_IN_100NS, SINT1_NUM);
243*69d4bf75SAndrey Smetanin     stimer_start(timer2, false, true, ONE_MS_IN_100NS, SINT2_NUM);
244*69d4bf75SAndrey Smetanin     while ((atomic_read(&timer1->fire_count) < 1000) ||
245*69d4bf75SAndrey Smetanin            (atomic_read(&timer2->fire_count) < 1000)) {
246*69d4bf75SAndrey Smetanin         pause();
247*69d4bf75SAndrey Smetanin     }
248*69d4bf75SAndrey Smetanin     report("Hyper-V SynIC periodic timers test vcpu %d", true, vcpu);
249*69d4bf75SAndrey Smetanin     stimer_shutdown(timer1);
250*69d4bf75SAndrey Smetanin     stimer_shutdown(timer2);
251*69d4bf75SAndrey Smetanin }
252*69d4bf75SAndrey Smetanin 
253*69d4bf75SAndrey Smetanin static void stimer_test_one_shot(int vcpu, struct stimer *timer)
254*69d4bf75SAndrey Smetanin {
255*69d4bf75SAndrey Smetanin     /* Check one-shot timer */
256*69d4bf75SAndrey Smetanin     stimer_start(timer, false, false, ONE_MS_IN_100NS, SINT1_NUM);
257*69d4bf75SAndrey Smetanin     while (atomic_read(&timer->fire_count) < 1) {
258*69d4bf75SAndrey Smetanin         pause();
259*69d4bf75SAndrey Smetanin     }
260*69d4bf75SAndrey Smetanin     report("Hyper-V SynIC one-shot test vcpu %d", true, vcpu);
261*69d4bf75SAndrey Smetanin     stimer_shutdown(timer);
262*69d4bf75SAndrey Smetanin }
263*69d4bf75SAndrey Smetanin 
264*69d4bf75SAndrey Smetanin static void stimer_test_auto_enable_one_shot(int vcpu, struct stimer *timer)
265*69d4bf75SAndrey Smetanin {
266*69d4bf75SAndrey Smetanin     /* Check auto-enable one-shot timer */
267*69d4bf75SAndrey Smetanin     stimer_start(timer, true, false, ONE_MS_IN_100NS, SINT1_NUM);
268*69d4bf75SAndrey Smetanin     while (atomic_read(&timer->fire_count) < 1) {
269*69d4bf75SAndrey Smetanin         pause();
270*69d4bf75SAndrey Smetanin     }
271*69d4bf75SAndrey Smetanin     report("Hyper-V SynIC auto-enable one-shot timer test vcpu %d", true, vcpu);
272*69d4bf75SAndrey Smetanin     stimer_shutdown(timer);
273*69d4bf75SAndrey Smetanin }
274*69d4bf75SAndrey Smetanin 
275*69d4bf75SAndrey Smetanin static void stimer_test_auto_enable_periodic(int vcpu, struct stimer *timer)
276*69d4bf75SAndrey Smetanin {
277*69d4bf75SAndrey Smetanin     /* Check auto-enable periodic timer */
278*69d4bf75SAndrey Smetanin     stimer_start(timer, true, true, ONE_MS_IN_100NS, SINT1_NUM);
279*69d4bf75SAndrey Smetanin     while (atomic_read(&timer->fire_count) < 1000) {
280*69d4bf75SAndrey Smetanin         pause();
281*69d4bf75SAndrey Smetanin     }
282*69d4bf75SAndrey Smetanin     report("Hyper-V SynIC auto-enable periodic timer test vcpu %d", true, vcpu);
283*69d4bf75SAndrey Smetanin     stimer_shutdown(timer);
284*69d4bf75SAndrey Smetanin }
285*69d4bf75SAndrey Smetanin 
286*69d4bf75SAndrey Smetanin static void stimer_test(void *ctx)
287*69d4bf75SAndrey Smetanin {
288*69d4bf75SAndrey Smetanin     int vcpu = smp_id();
289*69d4bf75SAndrey Smetanin     struct svcpu *svcpu = &g_synic_vcpu[vcpu];
290*69d4bf75SAndrey Smetanin     struct stimer *timer1, *timer2;
291*69d4bf75SAndrey Smetanin 
292*69d4bf75SAndrey Smetanin     irq_enable();
293*69d4bf75SAndrey Smetanin 
294*69d4bf75SAndrey Smetanin     timer1 = &svcpu->timer[0];
295*69d4bf75SAndrey Smetanin     timer2 = &svcpu->timer[1];
296*69d4bf75SAndrey Smetanin 
297*69d4bf75SAndrey Smetanin     stimer_test_periodic(vcpu, timer1, timer2);
298*69d4bf75SAndrey Smetanin     stimer_test_one_shot(vcpu, timer1);
299*69d4bf75SAndrey Smetanin     stimer_test_auto_enable_one_shot(vcpu, timer2);
300*69d4bf75SAndrey Smetanin     stimer_test_auto_enable_periodic(vcpu, timer1);
301*69d4bf75SAndrey Smetanin 
302*69d4bf75SAndrey Smetanin     irq_disable();
303*69d4bf75SAndrey Smetanin     cpu_comp();
304*69d4bf75SAndrey Smetanin }
305*69d4bf75SAndrey Smetanin 
306*69d4bf75SAndrey Smetanin static void stimer_test_cleanup(void *ctx)
307*69d4bf75SAndrey Smetanin {
308*69d4bf75SAndrey Smetanin     int vcpu = smp_id();
309*69d4bf75SAndrey Smetanin 
310*69d4bf75SAndrey Smetanin     stimers_shutdown();
311*69d4bf75SAndrey Smetanin     synic_sint_destroy(vcpu, SINT1_NUM);
312*69d4bf75SAndrey Smetanin     synic_sint_destroy(vcpu, SINT2_NUM);
313*69d4bf75SAndrey Smetanin     synic_disable();
314*69d4bf75SAndrey Smetanin     cpu_comp();
315*69d4bf75SAndrey Smetanin }
316*69d4bf75SAndrey Smetanin 
317*69d4bf75SAndrey Smetanin static void on_each_cpu_async_wait(void (*func)(void *ctx), void *ctx)
318*69d4bf75SAndrey Smetanin {
319*69d4bf75SAndrey Smetanin     int i;
320*69d4bf75SAndrey Smetanin 
321*69d4bf75SAndrey Smetanin     atomic_set(&g_cpus_comp_count, 0);
322*69d4bf75SAndrey Smetanin     for (i = 0; i < g_cpus_count; i++) {
323*69d4bf75SAndrey Smetanin         on_cpu_async(i, func, ctx);
324*69d4bf75SAndrey Smetanin     }
325*69d4bf75SAndrey Smetanin     while (atomic_read(&g_cpus_comp_count) != g_cpus_count) {
326*69d4bf75SAndrey Smetanin         pause();
327*69d4bf75SAndrey Smetanin     }
328*69d4bf75SAndrey Smetanin }
329*69d4bf75SAndrey Smetanin 
330*69d4bf75SAndrey Smetanin static void stimer_test_all(void)
331*69d4bf75SAndrey Smetanin {
332*69d4bf75SAndrey Smetanin     int ncpus;
333*69d4bf75SAndrey Smetanin 
334*69d4bf75SAndrey Smetanin     setup_vm();
335*69d4bf75SAndrey Smetanin     smp_init();
336*69d4bf75SAndrey Smetanin     setup_idt();
337*69d4bf75SAndrey Smetanin     enable_apic();
338*69d4bf75SAndrey Smetanin 
339*69d4bf75SAndrey Smetanin     handle_irq(SINT1_VEC, stimer_isr);
340*69d4bf75SAndrey Smetanin     handle_irq(SINT2_VEC, stimer_isr_auto_eoi);
341*69d4bf75SAndrey Smetanin 
342*69d4bf75SAndrey Smetanin     ncpus = cpu_count();
343*69d4bf75SAndrey Smetanin     if (ncpus > MAX_CPUS) {
344*69d4bf75SAndrey Smetanin         ncpus = MAX_CPUS;
345*69d4bf75SAndrey Smetanin     }
346*69d4bf75SAndrey Smetanin 
347*69d4bf75SAndrey Smetanin     printf("cpus = %d\n", ncpus);
348*69d4bf75SAndrey Smetanin     g_cpus_count = ncpus;
349*69d4bf75SAndrey Smetanin 
350*69d4bf75SAndrey Smetanin     on_each_cpu_async_wait(stimer_test_prepare, (void *)read_cr3());
351*69d4bf75SAndrey Smetanin     on_each_cpu_async_wait(stimer_test, NULL);
352*69d4bf75SAndrey Smetanin     on_each_cpu_async_wait(stimer_test_cleanup, NULL);
353*69d4bf75SAndrey Smetanin }
354*69d4bf75SAndrey Smetanin 
355*69d4bf75SAndrey Smetanin int main(int ac, char **av)
356*69d4bf75SAndrey Smetanin {
357*69d4bf75SAndrey Smetanin 
358*69d4bf75SAndrey Smetanin     if (!synic_supported()) {
359*69d4bf75SAndrey Smetanin         report("Hyper-V SynIC is not supported", true);
360*69d4bf75SAndrey Smetanin         goto done;
361*69d4bf75SAndrey Smetanin     }
362*69d4bf75SAndrey Smetanin 
363*69d4bf75SAndrey Smetanin     if (!stimer_supported()) {
364*69d4bf75SAndrey Smetanin         report("Hyper-V SynIC timers are not supported", true);
365*69d4bf75SAndrey Smetanin         goto done;
366*69d4bf75SAndrey Smetanin     }
367*69d4bf75SAndrey Smetanin 
368*69d4bf75SAndrey Smetanin     if (!hv_time_ref_counter_supported()) {
369*69d4bf75SAndrey Smetanin         report("Hyper-V time reference counter is not supported", true);
370*69d4bf75SAndrey Smetanin         goto done;
371*69d4bf75SAndrey Smetanin     }
372*69d4bf75SAndrey Smetanin 
373*69d4bf75SAndrey Smetanin     stimer_test_all();
374*69d4bf75SAndrey Smetanin done:
375*69d4bf75SAndrey Smetanin     return report_summary();
376*69d4bf75SAndrey Smetanin }
377