xref: /kvm-unit-tests/x86/hyperv_synic.c (revision 17fdf23ec6d9e5c213da847d59f98e8c90d3ff34)
1*17fdf23eSAndrey Smetanin #include "libcflat.h"
2*17fdf23eSAndrey Smetanin #include "processor.h"
3*17fdf23eSAndrey Smetanin #include "msr.h"
4*17fdf23eSAndrey Smetanin #include "isr.h"
5*17fdf23eSAndrey Smetanin #include "vm.h"
6*17fdf23eSAndrey Smetanin #include "apic.h"
7*17fdf23eSAndrey Smetanin #include "desc.h"
8*17fdf23eSAndrey Smetanin #include "io.h"
9*17fdf23eSAndrey Smetanin #include "smp.h"
10*17fdf23eSAndrey Smetanin #include "atomic.h"
11*17fdf23eSAndrey Smetanin 
12*17fdf23eSAndrey Smetanin #define MAX_CPUS 4
13*17fdf23eSAndrey Smetanin #define HYPERV_CPUID_FEATURES                   0x40000003
14*17fdf23eSAndrey Smetanin #define HV_X64_MSR_SYNIC_AVAILABLE              (1 << 2)
15*17fdf23eSAndrey Smetanin #define HV_SYNIC_CONTROL_ENABLE                 (1ULL << 0)
16*17fdf23eSAndrey Smetanin #define HV_SYNIC_SIMP_ENABLE                    (1ULL << 0)
17*17fdf23eSAndrey Smetanin #define HV_SYNIC_SIEFP_ENABLE                   (1ULL << 0)
18*17fdf23eSAndrey Smetanin #define HV_SYNIC_SINT_MASKED                    (1ULL << 16)
19*17fdf23eSAndrey Smetanin #define HV_SYNIC_SINT_AUTO_EOI                  (1ULL << 17)
20*17fdf23eSAndrey Smetanin #define HV_SYNIC_SINT_VECTOR_MASK               (0xFF)
21*17fdf23eSAndrey Smetanin #define HV_SYNIC_SINT_COUNT                     16
22*17fdf23eSAndrey Smetanin 
23*17fdf23eSAndrey Smetanin enum {
24*17fdf23eSAndrey Smetanin     HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
25*17fdf23eSAndrey Smetanin     HV_TEST_DEV_SINT_ROUTE_DESTROY,
26*17fdf23eSAndrey Smetanin     HV_TEST_DEV_SINT_ROUTE_SET_SINT
27*17fdf23eSAndrey Smetanin };
28*17fdf23eSAndrey Smetanin 
29*17fdf23eSAndrey Smetanin static atomic_t isr_enter_count[MAX_CPUS];
30*17fdf23eSAndrey Smetanin static atomic_t cpus_comp_count;
31*17fdf23eSAndrey Smetanin 
32*17fdf23eSAndrey Smetanin static bool synic_supported(void)
33*17fdf23eSAndrey Smetanin {
34*17fdf23eSAndrey Smetanin    return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNIC_AVAILABLE;
35*17fdf23eSAndrey Smetanin }
36*17fdf23eSAndrey Smetanin 
37*17fdf23eSAndrey Smetanin static void synic_sint_auto_eoi_isr(isr_regs_t *regs)
38*17fdf23eSAndrey Smetanin {
39*17fdf23eSAndrey Smetanin     atomic_inc(&isr_enter_count[smp_id()]);
40*17fdf23eSAndrey Smetanin }
41*17fdf23eSAndrey Smetanin 
42*17fdf23eSAndrey Smetanin static void synic_sint_isr(isr_regs_t *regs)
43*17fdf23eSAndrey Smetanin {
44*17fdf23eSAndrey Smetanin     atomic_inc(&isr_enter_count[smp_id()]);
45*17fdf23eSAndrey Smetanin     eoi();
46*17fdf23eSAndrey Smetanin }
47*17fdf23eSAndrey Smetanin 
48*17fdf23eSAndrey Smetanin static void synic_ctl(u8 ctl, u8 vcpu_id, u8 sint)
49*17fdf23eSAndrey Smetanin {
50*17fdf23eSAndrey Smetanin     outl((ctl << 16)|((vcpu_id) << 8)|sint, 0x3000);
51*17fdf23eSAndrey Smetanin }
52*17fdf23eSAndrey Smetanin 
53*17fdf23eSAndrey Smetanin struct sint_vec_entry {
54*17fdf23eSAndrey Smetanin     int vec;
55*17fdf23eSAndrey Smetanin     bool auto_eoi;
56*17fdf23eSAndrey Smetanin };
57*17fdf23eSAndrey Smetanin 
58*17fdf23eSAndrey Smetanin struct sint_vec_entry sint_vecs[HV_SYNIC_SINT_COUNT] = {
59*17fdf23eSAndrey Smetanin     {0xB0, false},
60*17fdf23eSAndrey Smetanin     {0xB1, false},
61*17fdf23eSAndrey Smetanin     {0xB2, false},
62*17fdf23eSAndrey Smetanin     {0xB3, true},
63*17fdf23eSAndrey Smetanin     {0xB4, false},
64*17fdf23eSAndrey Smetanin     {0xB5, false},
65*17fdf23eSAndrey Smetanin     {0xB6, false},
66*17fdf23eSAndrey Smetanin     {0xB7, false},
67*17fdf23eSAndrey Smetanin     {0xB8, true},
68*17fdf23eSAndrey Smetanin     {0xB9, false},
69*17fdf23eSAndrey Smetanin     {0xBA, true},
70*17fdf23eSAndrey Smetanin     {0xBB, false},
71*17fdf23eSAndrey Smetanin     {0xBC, false},
72*17fdf23eSAndrey Smetanin     {0xBD, false},
73*17fdf23eSAndrey Smetanin     {0xBE, true},
74*17fdf23eSAndrey Smetanin     {0xBF, false},
75*17fdf23eSAndrey Smetanin };
76*17fdf23eSAndrey Smetanin 
77*17fdf23eSAndrey Smetanin static void synic_prepare_sint_vecs(void)
78*17fdf23eSAndrey Smetanin {
79*17fdf23eSAndrey Smetanin     bool auto_eoi;
80*17fdf23eSAndrey Smetanin     int i, vec;
81*17fdf23eSAndrey Smetanin 
82*17fdf23eSAndrey Smetanin     for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
83*17fdf23eSAndrey Smetanin         vec = sint_vecs[i].vec;
84*17fdf23eSAndrey Smetanin         auto_eoi = sint_vecs[i].auto_eoi;
85*17fdf23eSAndrey Smetanin         handle_irq(vec, (auto_eoi) ? synic_sint_auto_eoi_isr : synic_sint_isr);
86*17fdf23eSAndrey Smetanin     }
87*17fdf23eSAndrey Smetanin }
88*17fdf23eSAndrey Smetanin 
89*17fdf23eSAndrey Smetanin static void synic_sints_prepare(u8 vcpu)
90*17fdf23eSAndrey Smetanin {
91*17fdf23eSAndrey Smetanin     bool auto_eoi;
92*17fdf23eSAndrey Smetanin     int i, vec;
93*17fdf23eSAndrey Smetanin 
94*17fdf23eSAndrey Smetanin     for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
95*17fdf23eSAndrey Smetanin         vec = sint_vecs[i].vec;
96*17fdf23eSAndrey Smetanin         auto_eoi = sint_vecs[i].auto_eoi;
97*17fdf23eSAndrey Smetanin         wrmsr(HV_X64_MSR_SINT0 + i,
98*17fdf23eSAndrey Smetanin                 (u64)vec | ((auto_eoi) ? HV_SYNIC_SINT_AUTO_EOI : 0));
99*17fdf23eSAndrey Smetanin         synic_ctl(HV_TEST_DEV_SINT_ROUTE_CREATE, vcpu, i);
100*17fdf23eSAndrey Smetanin     }
101*17fdf23eSAndrey Smetanin }
102*17fdf23eSAndrey Smetanin 
103*17fdf23eSAndrey Smetanin static void synic_test_prepare(void *ctx)
104*17fdf23eSAndrey Smetanin {
105*17fdf23eSAndrey Smetanin     u64 r;
106*17fdf23eSAndrey Smetanin     int i = 0;
107*17fdf23eSAndrey Smetanin 
108*17fdf23eSAndrey Smetanin     write_cr3((ulong)ctx);
109*17fdf23eSAndrey Smetanin     irq_enable();
110*17fdf23eSAndrey Smetanin 
111*17fdf23eSAndrey Smetanin     rdmsr(HV_X64_MSR_SVERSION);
112*17fdf23eSAndrey Smetanin     rdmsr(HV_X64_MSR_SIMP);
113*17fdf23eSAndrey Smetanin     rdmsr(HV_X64_MSR_SIEFP);
114*17fdf23eSAndrey Smetanin     rdmsr(HV_X64_MSR_SCONTROL);
115*17fdf23eSAndrey Smetanin     for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
116*17fdf23eSAndrey Smetanin         rdmsr(HV_X64_MSR_SINT0 + i);
117*17fdf23eSAndrey Smetanin     }
118*17fdf23eSAndrey Smetanin     r = rdmsr(HV_X64_MSR_EOM);
119*17fdf23eSAndrey Smetanin     if (r != 0) {
120*17fdf23eSAndrey Smetanin         report("Hyper-V SynIC test, EOM read 0x%llx", false, r);
121*17fdf23eSAndrey Smetanin         goto ret;
122*17fdf23eSAndrey Smetanin     }
123*17fdf23eSAndrey Smetanin 
124*17fdf23eSAndrey Smetanin     wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(alloc_page()) |
125*17fdf23eSAndrey Smetanin             HV_SYNIC_SIMP_ENABLE);
126*17fdf23eSAndrey Smetanin     wrmsr(HV_X64_MSR_SIEFP, (u64)virt_to_phys(alloc_page())|
127*17fdf23eSAndrey Smetanin             HV_SYNIC_SIEFP_ENABLE);
128*17fdf23eSAndrey Smetanin     wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE);
129*17fdf23eSAndrey Smetanin 
130*17fdf23eSAndrey Smetanin     synic_sints_prepare(smp_id());
131*17fdf23eSAndrey Smetanin ret:
132*17fdf23eSAndrey Smetanin     atomic_inc(&cpus_comp_count);
133*17fdf23eSAndrey Smetanin }
134*17fdf23eSAndrey Smetanin 
135*17fdf23eSAndrey Smetanin static void synic_sints_test(u8 dst_vcpu)
136*17fdf23eSAndrey Smetanin {
137*17fdf23eSAndrey Smetanin     int i;
138*17fdf23eSAndrey Smetanin 
139*17fdf23eSAndrey Smetanin     atomic_set(&isr_enter_count[dst_vcpu], 0);
140*17fdf23eSAndrey Smetanin     for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
141*17fdf23eSAndrey Smetanin         synic_ctl(HV_TEST_DEV_SINT_ROUTE_SET_SINT, dst_vcpu, i);
142*17fdf23eSAndrey Smetanin     }
143*17fdf23eSAndrey Smetanin 
144*17fdf23eSAndrey Smetanin     while (atomic_read(&isr_enter_count[dst_vcpu]) != HV_SYNIC_SINT_COUNT) {
145*17fdf23eSAndrey Smetanin         pause();
146*17fdf23eSAndrey Smetanin     }
147*17fdf23eSAndrey Smetanin }
148*17fdf23eSAndrey Smetanin 
149*17fdf23eSAndrey Smetanin static void synic_test(void *ctx)
150*17fdf23eSAndrey Smetanin {
151*17fdf23eSAndrey Smetanin     u8 dst_vcpu = (ulong)ctx;
152*17fdf23eSAndrey Smetanin 
153*17fdf23eSAndrey Smetanin     irq_enable();
154*17fdf23eSAndrey Smetanin     synic_sints_test(dst_vcpu);
155*17fdf23eSAndrey Smetanin     atomic_inc(&cpus_comp_count);
156*17fdf23eSAndrey Smetanin }
157*17fdf23eSAndrey Smetanin 
158*17fdf23eSAndrey Smetanin static void synic_test_cleanup(void *ctx)
159*17fdf23eSAndrey Smetanin {
160*17fdf23eSAndrey Smetanin     u8 vcpu = smp_id();
161*17fdf23eSAndrey Smetanin     int i;
162*17fdf23eSAndrey Smetanin 
163*17fdf23eSAndrey Smetanin     irq_enable();
164*17fdf23eSAndrey Smetanin     for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
165*17fdf23eSAndrey Smetanin         synic_ctl(HV_TEST_DEV_SINT_ROUTE_DESTROY, vcpu, i);
166*17fdf23eSAndrey Smetanin         wrmsr(HV_X64_MSR_SINT0 + i, 0xFF|HV_SYNIC_SINT_MASKED);
167*17fdf23eSAndrey Smetanin     }
168*17fdf23eSAndrey Smetanin 
169*17fdf23eSAndrey Smetanin     wrmsr(HV_X64_MSR_SCONTROL, 0);
170*17fdf23eSAndrey Smetanin     wrmsr(HV_X64_MSR_SIMP, 0);
171*17fdf23eSAndrey Smetanin     wrmsr(HV_X64_MSR_SIEFP, 0);
172*17fdf23eSAndrey Smetanin     atomic_inc(&cpus_comp_count);
173*17fdf23eSAndrey Smetanin }
174*17fdf23eSAndrey Smetanin 
175*17fdf23eSAndrey Smetanin int main(int ac, char **av)
176*17fdf23eSAndrey Smetanin {
177*17fdf23eSAndrey Smetanin 
178*17fdf23eSAndrey Smetanin     if (synic_supported()) {
179*17fdf23eSAndrey Smetanin         int ncpus, i;
180*17fdf23eSAndrey Smetanin         bool ok;
181*17fdf23eSAndrey Smetanin 
182*17fdf23eSAndrey Smetanin         setup_vm();
183*17fdf23eSAndrey Smetanin         smp_init();
184*17fdf23eSAndrey Smetanin         setup_idt();
185*17fdf23eSAndrey Smetanin         enable_apic();
186*17fdf23eSAndrey Smetanin 
187*17fdf23eSAndrey Smetanin         synic_prepare_sint_vecs();
188*17fdf23eSAndrey Smetanin 
189*17fdf23eSAndrey Smetanin         ncpus = cpu_count();
190*17fdf23eSAndrey Smetanin         if (ncpus > MAX_CPUS) {
191*17fdf23eSAndrey Smetanin             ncpus = MAX_CPUS;
192*17fdf23eSAndrey Smetanin         }
193*17fdf23eSAndrey Smetanin         printf("ncpus = %d\n", ncpus);
194*17fdf23eSAndrey Smetanin 
195*17fdf23eSAndrey Smetanin         atomic_set(&cpus_comp_count, 0);
196*17fdf23eSAndrey Smetanin         for (i = 0; i < ncpus; i++) {
197*17fdf23eSAndrey Smetanin             on_cpu_async(i, synic_test_prepare, (void *)read_cr3());
198*17fdf23eSAndrey Smetanin         }
199*17fdf23eSAndrey Smetanin         printf("prepare\n");
200*17fdf23eSAndrey Smetanin         while (atomic_read(&cpus_comp_count) != ncpus) {
201*17fdf23eSAndrey Smetanin             pause();
202*17fdf23eSAndrey Smetanin         }
203*17fdf23eSAndrey Smetanin 
204*17fdf23eSAndrey Smetanin         atomic_set(&cpus_comp_count, 0);
205*17fdf23eSAndrey Smetanin         for (i = 0; i < ncpus; i++) {
206*17fdf23eSAndrey Smetanin             printf("test %d -> %d\n", i, ncpus - 1 - i);
207*17fdf23eSAndrey Smetanin             on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i));
208*17fdf23eSAndrey Smetanin         }
209*17fdf23eSAndrey Smetanin         while (atomic_read(&cpus_comp_count) != ncpus) {
210*17fdf23eSAndrey Smetanin             pause();
211*17fdf23eSAndrey Smetanin         }
212*17fdf23eSAndrey Smetanin 
213*17fdf23eSAndrey Smetanin         atomic_set(&cpus_comp_count, 0);
214*17fdf23eSAndrey Smetanin         for (i = 0; i < ncpus; i++) {
215*17fdf23eSAndrey Smetanin             on_cpu_async(i, synic_test_cleanup, NULL);
216*17fdf23eSAndrey Smetanin         }
217*17fdf23eSAndrey Smetanin         printf("cleanup\n");
218*17fdf23eSAndrey Smetanin         while (atomic_read(&cpus_comp_count) != ncpus) {
219*17fdf23eSAndrey Smetanin             pause();
220*17fdf23eSAndrey Smetanin         }
221*17fdf23eSAndrey Smetanin 
222*17fdf23eSAndrey Smetanin         ok = true;
223*17fdf23eSAndrey Smetanin         for (i = 0; i < ncpus; ++i) {
224*17fdf23eSAndrey Smetanin             printf("isr_enter_count[%d] = %d\n",
225*17fdf23eSAndrey Smetanin                    i, atomic_read(&isr_enter_count[i]));
226*17fdf23eSAndrey Smetanin             ok &= atomic_read(&isr_enter_count[i]) == 16;
227*17fdf23eSAndrey Smetanin         }
228*17fdf23eSAndrey Smetanin 
229*17fdf23eSAndrey Smetanin         report("Hyper-V SynIC test", ok);
230*17fdf23eSAndrey Smetanin     } else {
231*17fdf23eSAndrey Smetanin         report("Hyper-V SynIC is not supported", true);
232*17fdf23eSAndrey Smetanin     }
233*17fdf23eSAndrey Smetanin 
234*17fdf23eSAndrey Smetanin     return report_summary();
235*17fdf23eSAndrey Smetanin }
236