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