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