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 #include "alloc_page.h"
12
13 #define MAX_CPUS 4
14
15 static atomic_t isr_enter_count[MAX_CPUS];
16
synic_sint_auto_eoi_isr(isr_regs_t * regs)17 static void synic_sint_auto_eoi_isr(isr_regs_t *regs)
18 {
19 atomic_inc(&isr_enter_count[smp_id()]);
20 }
21
synic_sint_isr(isr_regs_t * regs)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
synic_prepare_sint_vecs(void)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
synic_sints_prepare(int vcpu)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(i, vec, auto_eoi);
73 }
74 }
75
synic_test_prepare(void * ctx)76 static void synic_test_prepare(void *ctx)
77 {
78 u64 r;
79 int i = 0;
80
81 write_cr3((ulong)ctx);
82 sti();
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_fail("Hyper-V SynIC test, EOM read %#" PRIx64, r);
94 return;
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 }
105
synic_sints_test(int dst_vcpu)106 static void synic_sints_test(int dst_vcpu)
107 {
108 int i;
109
110 atomic_set(&isr_enter_count[dst_vcpu], 0);
111 for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
112 synic_sint_set(dst_vcpu, i);
113 }
114
115 while (atomic_read(&isr_enter_count[dst_vcpu]) != HV_SYNIC_SINT_COUNT) {
116 pause();
117 }
118 }
119
synic_test(void * ctx)120 static void synic_test(void *ctx)
121 {
122 int dst_vcpu = (ulong)ctx;
123
124 sti();
125 synic_sints_test(dst_vcpu);
126 }
127
synic_test_cleanup(void * ctx)128 static void synic_test_cleanup(void *ctx)
129 {
130 int i;
131
132 sti();
133 for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
134 synic_sint_destroy(i);
135 }
136
137 wrmsr(HV_X64_MSR_SCONTROL, 0);
138 wrmsr(HV_X64_MSR_SIMP, 0);
139 wrmsr(HV_X64_MSR_SIEFP, 0);
140 }
141
main(int ac,char ** av)142 int main(int ac, char **av)
143 {
144 int ncpus, i;
145 bool ok;
146
147 if (!hv_synic_supported()) {
148 report_skip("Hyper-V SynIC is not supported");
149 goto done;
150 }
151
152 setup_vm();
153 enable_apic();
154
155 ncpus = cpu_count();
156 if (ncpus > MAX_CPUS)
157 report_abort("number cpus exceeds %d", MAX_CPUS);
158 printf("ncpus = %d\n", ncpus);
159
160 synic_prepare_sint_vecs();
161
162 printf("prepare\n");
163 on_cpus(synic_test_prepare, (void *)read_cr3());
164
165 for (i = 0; i < ncpus; i++) {
166 printf("test %d -> %d\n", i, ncpus - 1 - i);
167 on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i));
168 }
169 while (cpus_active() > 1)
170 pause();
171
172 printf("cleanup\n");
173 on_cpus(synic_test_cleanup, NULL);
174
175 ok = true;
176 for (i = 0; i < ncpus; ++i) {
177 printf("isr_enter_count[%d] = %d\n",
178 i, atomic_read(&isr_enter_count[i]));
179 ok &= atomic_read(&isr_enter_count[i]) == 16;
180 }
181
182 report(ok, "Hyper-V SynIC test");
183
184 done:
185 return report_summary();
186 }
187