xref: /kvm-unit-tests/x86/hyperv_connections.c (revision 1472a3843b122481866e805d40460f96819ade9d)
1*1472a384SRoman Kagan #include "libcflat.h"
2*1472a384SRoman Kagan #include "vm.h"
3*1472a384SRoman Kagan #include "smp.h"
4*1472a384SRoman Kagan #include "isr.h"
5*1472a384SRoman Kagan #include "atomic.h"
6*1472a384SRoman Kagan #include "hyperv.h"
7*1472a384SRoman Kagan #include "bitops.h"
8*1472a384SRoman Kagan 
9*1472a384SRoman Kagan #define MAX_CPUS 64
10*1472a384SRoman Kagan 
11*1472a384SRoman Kagan #define MSG_VEC 0xb0
12*1472a384SRoman Kagan #define EVT_VEC 0xb1
13*1472a384SRoman Kagan #define MSG_SINT 0x8
14*1472a384SRoman Kagan #define EVT_SINT 0x9
15*1472a384SRoman Kagan #define MSG_CONN_BASE 0x10
16*1472a384SRoman Kagan #define EVT_CONN_BASE 0x20
17*1472a384SRoman Kagan #define MSG_TYPE 0x12345678
18*1472a384SRoman Kagan 
19*1472a384SRoman Kagan #define WAIT_CYCLES 10000000
20*1472a384SRoman Kagan 
21*1472a384SRoman Kagan static atomic_t ncpus_done;
22*1472a384SRoman Kagan 
23*1472a384SRoman Kagan struct hv_vcpu {
24*1472a384SRoman Kagan 	struct hv_message_page *msg_page;
25*1472a384SRoman Kagan 	struct hv_event_flags_page *evt_page;
26*1472a384SRoman Kagan 	struct hv_input_post_message *post_msg;
27*1472a384SRoman Kagan 	u8 msg_conn;
28*1472a384SRoman Kagan 	u8 evt_conn;
29*1472a384SRoman Kagan 	u64 hvcall_status;
30*1472a384SRoman Kagan 	atomic_t sint_received;
31*1472a384SRoman Kagan };
32*1472a384SRoman Kagan 
33*1472a384SRoman Kagan static struct hv_vcpu hv_vcpus[MAX_CPUS];
34*1472a384SRoman Kagan 
35*1472a384SRoman Kagan static void sint_isr(isr_regs_t *regs)
36*1472a384SRoman Kagan {
37*1472a384SRoman Kagan 	atomic_inc(&hv_vcpus[smp_id()].sint_received);
38*1472a384SRoman Kagan }
39*1472a384SRoman Kagan 
40*1472a384SRoman Kagan static void *hypercall_page;
41*1472a384SRoman Kagan 
42*1472a384SRoman Kagan static void setup_hypercall(void)
43*1472a384SRoman Kagan {
44*1472a384SRoman Kagan 	u64 guestid = (0x8f00ull << 48);
45*1472a384SRoman Kagan 
46*1472a384SRoman Kagan 	hypercall_page = alloc_page();
47*1472a384SRoman Kagan 	if (!hypercall_page)
48*1472a384SRoman Kagan 		report_abort("failed to allocate hypercall page");
49*1472a384SRoman Kagan 	memset(hypercall_page, 0, PAGE_SIZE);
50*1472a384SRoman Kagan 
51*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_GUEST_OS_ID, guestid);
52*1472a384SRoman Kagan 
53*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_HYPERCALL,
54*1472a384SRoman Kagan 	      (u64)virt_to_phys(hypercall_page) | HV_X64_MSR_HYPERCALL_ENABLE);
55*1472a384SRoman Kagan }
56*1472a384SRoman Kagan 
57*1472a384SRoman Kagan static void teardown_hypercall(void)
58*1472a384SRoman Kagan {
59*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_HYPERCALL, 0);
60*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_GUEST_OS_ID, 0);
61*1472a384SRoman Kagan 	free_page(hypercall_page);
62*1472a384SRoman Kagan }
63*1472a384SRoman Kagan 
64*1472a384SRoman Kagan static u64 do_hypercall(u16 code, u64 arg, bool fast)
65*1472a384SRoman Kagan {
66*1472a384SRoman Kagan 	u64 ret;
67*1472a384SRoman Kagan 	u64 ctl = code;
68*1472a384SRoman Kagan 	if (fast)
69*1472a384SRoman Kagan 		ctl |= HV_HYPERCALL_FAST;
70*1472a384SRoman Kagan 
71*1472a384SRoman Kagan 	asm volatile ("call *%[hcall_page]"
72*1472a384SRoman Kagan #ifdef __x86_64__
73*1472a384SRoman Kagan 		      "\n mov $0,%%r8"
74*1472a384SRoman Kagan 		      : "=a"(ret)
75*1472a384SRoman Kagan 		      : "c"(ctl), "d"(arg),
76*1472a384SRoman Kagan #else
77*1472a384SRoman Kagan 		      : "=A"(ret)
78*1472a384SRoman Kagan 		      : "A"(ctl),
79*1472a384SRoman Kagan 			"b" ((u32)(arg >> 32)), "c" ((u32)arg),
80*1472a384SRoman Kagan 			"D"(0), "S"(0),
81*1472a384SRoman Kagan #endif
82*1472a384SRoman Kagan 		      [hcall_page] "m" (hypercall_page)
83*1472a384SRoman Kagan #ifdef __x86_64__
84*1472a384SRoman Kagan 		      : "r8"
85*1472a384SRoman Kagan #endif
86*1472a384SRoman Kagan 		     );
87*1472a384SRoman Kagan 
88*1472a384SRoman Kagan 	return ret;
89*1472a384SRoman Kagan }
90*1472a384SRoman Kagan 
91*1472a384SRoman Kagan static void setup_cpu(void *ctx)
92*1472a384SRoman Kagan {
93*1472a384SRoman Kagan 	int vcpu;
94*1472a384SRoman Kagan 	struct hv_vcpu *hv;
95*1472a384SRoman Kagan 
96*1472a384SRoman Kagan 	write_cr3((ulong)ctx);
97*1472a384SRoman Kagan 	irq_enable();
98*1472a384SRoman Kagan 
99*1472a384SRoman Kagan 	vcpu = smp_id();
100*1472a384SRoman Kagan 	hv = &hv_vcpus[vcpu];
101*1472a384SRoman Kagan 
102*1472a384SRoman Kagan 	hv->msg_page = alloc_page();
103*1472a384SRoman Kagan 	hv->evt_page = alloc_page();
104*1472a384SRoman Kagan 	hv->post_msg = alloc_page();
105*1472a384SRoman Kagan 	if (!hv->msg_page || !hv->evt_page || !hv->post_msg)
106*1472a384SRoman Kagan 		report_abort("failed to allocate synic pages for vcpu");
107*1472a384SRoman Kagan 	memset(hv->msg_page, 0, sizeof(*hv->msg_page));
108*1472a384SRoman Kagan 	memset(hv->evt_page, 0, sizeof(*hv->evt_page));
109*1472a384SRoman Kagan 	memset(hv->post_msg, 0, sizeof(*hv->post_msg));
110*1472a384SRoman Kagan 	hv->msg_conn = MSG_CONN_BASE + vcpu;
111*1472a384SRoman Kagan 	hv->evt_conn = EVT_CONN_BASE + vcpu;
112*1472a384SRoman Kagan 
113*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_SIMP,
114*1472a384SRoman Kagan 	      (u64)virt_to_phys(hv->msg_page) | HV_SYNIC_SIMP_ENABLE);
115*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_SIEFP,
116*1472a384SRoman Kagan 	      (u64)virt_to_phys(hv->evt_page) | HV_SYNIC_SIEFP_ENABLE);
117*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE);
118*1472a384SRoman Kagan 
119*1472a384SRoman Kagan 	msg_conn_create(MSG_SINT, MSG_VEC, hv->msg_conn);
120*1472a384SRoman Kagan 	evt_conn_create(EVT_SINT, EVT_VEC, hv->evt_conn);
121*1472a384SRoman Kagan 
122*1472a384SRoman Kagan 	hv->post_msg->connectionid = hv->msg_conn;
123*1472a384SRoman Kagan 	hv->post_msg->message_type = MSG_TYPE;
124*1472a384SRoman Kagan 	hv->post_msg->payload_size = 8;
125*1472a384SRoman Kagan 	hv->post_msg->payload[0] = (u64)vcpu << 16;
126*1472a384SRoman Kagan }
127*1472a384SRoman Kagan 
128*1472a384SRoman Kagan static void teardown_cpu(void *ctx)
129*1472a384SRoman Kagan {
130*1472a384SRoman Kagan 	int vcpu = smp_id();
131*1472a384SRoman Kagan 	struct hv_vcpu *hv = &hv_vcpus[vcpu];
132*1472a384SRoman Kagan 
133*1472a384SRoman Kagan 	evt_conn_destroy(EVT_SINT, hv->evt_conn);
134*1472a384SRoman Kagan 	msg_conn_destroy(MSG_SINT, hv->msg_conn);
135*1472a384SRoman Kagan 
136*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_SCONTROL, 0);
137*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_SIEFP, 0);
138*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_SIMP, 0);
139*1472a384SRoman Kagan 
140*1472a384SRoman Kagan 	free_page(hv->post_msg);
141*1472a384SRoman Kagan 	free_page(hv->evt_page);
142*1472a384SRoman Kagan 	free_page(hv->msg_page);
143*1472a384SRoman Kagan }
144*1472a384SRoman Kagan 
145*1472a384SRoman Kagan static void do_msg(void *ctx)
146*1472a384SRoman Kagan {
147*1472a384SRoman Kagan 	int vcpu = (ulong)ctx;
148*1472a384SRoman Kagan 	struct hv_vcpu *hv = &hv_vcpus[vcpu];
149*1472a384SRoman Kagan 	struct hv_input_post_message *msg = hv->post_msg;
150*1472a384SRoman Kagan 
151*1472a384SRoman Kagan 	msg->payload[0]++;
152*1472a384SRoman Kagan 	atomic_set(&hv->sint_received, 0);
153*1472a384SRoman Kagan 	hv->hvcall_status = do_hypercall(HVCALL_POST_MESSAGE,
154*1472a384SRoman Kagan 					 virt_to_phys(msg), 0);
155*1472a384SRoman Kagan 	atomic_inc(&ncpus_done);
156*1472a384SRoman Kagan }
157*1472a384SRoman Kagan 
158*1472a384SRoman Kagan static void clear_msg(void *ctx)
159*1472a384SRoman Kagan {
160*1472a384SRoman Kagan 	/* should only be done on the current vcpu */
161*1472a384SRoman Kagan 	int vcpu = smp_id();
162*1472a384SRoman Kagan 	struct hv_vcpu *hv = &hv_vcpus[vcpu];
163*1472a384SRoman Kagan 	struct hv_message *msg = &hv->msg_page->sint_message[MSG_SINT];
164*1472a384SRoman Kagan 
165*1472a384SRoman Kagan 	atomic_set(&hv->sint_received, 0);
166*1472a384SRoman Kagan 	msg->header.message_type = 0;
167*1472a384SRoman Kagan 	barrier();
168*1472a384SRoman Kagan 	wrmsr(HV_X64_MSR_EOM, 0);
169*1472a384SRoman Kagan 	atomic_inc(&ncpus_done);
170*1472a384SRoman Kagan }
171*1472a384SRoman Kagan 
172*1472a384SRoman Kagan static bool msg_ok(int vcpu)
173*1472a384SRoman Kagan {
174*1472a384SRoman Kagan 	struct hv_vcpu *hv = &hv_vcpus[vcpu];
175*1472a384SRoman Kagan 	struct hv_input_post_message *post_msg = hv->post_msg;
176*1472a384SRoman Kagan 	struct hv_message *msg = &hv->msg_page->sint_message[MSG_SINT];
177*1472a384SRoman Kagan 
178*1472a384SRoman Kagan 	return msg->header.message_type == post_msg->message_type &&
179*1472a384SRoman Kagan 		msg->header.payload_size == post_msg->payload_size &&
180*1472a384SRoman Kagan 		msg->header.message_flags.msg_pending == 0 &&
181*1472a384SRoman Kagan 		msg->u.payload[0] == post_msg->payload[0] &&
182*1472a384SRoman Kagan 		hv->hvcall_status == 0 &&
183*1472a384SRoman Kagan 		atomic_read(&hv->sint_received) == 1;
184*1472a384SRoman Kagan }
185*1472a384SRoman Kagan 
186*1472a384SRoman Kagan static bool msg_busy(int vcpu)
187*1472a384SRoman Kagan {
188*1472a384SRoman Kagan 	struct hv_vcpu *hv = &hv_vcpus[vcpu];
189*1472a384SRoman Kagan 	struct hv_input_post_message *post_msg = hv->post_msg;
190*1472a384SRoman Kagan 	struct hv_message *msg = &hv->msg_page->sint_message[MSG_SINT];
191*1472a384SRoman Kagan 
192*1472a384SRoman Kagan 	return msg->header.message_type == post_msg->message_type &&
193*1472a384SRoman Kagan 		msg->header.payload_size == post_msg->payload_size &&
194*1472a384SRoman Kagan 		msg->header.message_flags.msg_pending == 1 &&
195*1472a384SRoman Kagan 		msg->u.payload[0] == post_msg->payload[0] - 1 &&
196*1472a384SRoman Kagan 		hv->hvcall_status == 0 &&
197*1472a384SRoman Kagan 		atomic_read(&hv->sint_received) == 0;
198*1472a384SRoman Kagan }
199*1472a384SRoman Kagan 
200*1472a384SRoman Kagan static void do_evt(void *ctx)
201*1472a384SRoman Kagan {
202*1472a384SRoman Kagan 	int vcpu = (ulong)ctx;
203*1472a384SRoman Kagan 	struct hv_vcpu *hv = &hv_vcpus[vcpu];
204*1472a384SRoman Kagan 
205*1472a384SRoman Kagan 	atomic_set(&hv->sint_received, 0);
206*1472a384SRoman Kagan 	hv->hvcall_status = do_hypercall(HVCALL_SIGNAL_EVENT,
207*1472a384SRoman Kagan 					 hv->evt_conn, 1);
208*1472a384SRoman Kagan 	atomic_inc(&ncpus_done);
209*1472a384SRoman Kagan }
210*1472a384SRoman Kagan 
211*1472a384SRoman Kagan static void clear_evt(void *ctx)
212*1472a384SRoman Kagan {
213*1472a384SRoman Kagan 	/* should only be done on the current vcpu */
214*1472a384SRoman Kagan 	int vcpu = smp_id();
215*1472a384SRoman Kagan 	struct hv_vcpu *hv = &hv_vcpus[vcpu];
216*1472a384SRoman Kagan 	ulong *flags = hv->evt_page->slot[EVT_SINT].flags;
217*1472a384SRoman Kagan 
218*1472a384SRoman Kagan 	atomic_set(&hv->sint_received, 0);
219*1472a384SRoman Kagan 	flags[BIT_WORD(hv->evt_conn)] &= ~BIT_MASK(hv->evt_conn);
220*1472a384SRoman Kagan 	barrier();
221*1472a384SRoman Kagan 	atomic_inc(&ncpus_done);
222*1472a384SRoman Kagan }
223*1472a384SRoman Kagan 
224*1472a384SRoman Kagan static bool evt_ok(int vcpu)
225*1472a384SRoman Kagan {
226*1472a384SRoman Kagan 	struct hv_vcpu *hv = &hv_vcpus[vcpu];
227*1472a384SRoman Kagan 	ulong *flags = hv->evt_page->slot[EVT_SINT].flags;
228*1472a384SRoman Kagan 
229*1472a384SRoman Kagan 	return flags[BIT_WORD(hv->evt_conn)] == BIT_MASK(hv->evt_conn) &&
230*1472a384SRoman Kagan 		hv->hvcall_status == 0 &&
231*1472a384SRoman Kagan 		atomic_read(&hv->sint_received) == 1;
232*1472a384SRoman Kagan }
233*1472a384SRoman Kagan 
234*1472a384SRoman Kagan static bool evt_busy(int vcpu)
235*1472a384SRoman Kagan {
236*1472a384SRoman Kagan 	struct hv_vcpu *hv = &hv_vcpus[vcpu];
237*1472a384SRoman Kagan 	ulong *flags = hv->evt_page->slot[EVT_SINT].flags;
238*1472a384SRoman Kagan 
239*1472a384SRoman Kagan 	return flags[BIT_WORD(hv->evt_conn)] == BIT_MASK(hv->evt_conn) &&
240*1472a384SRoman Kagan 		hv->hvcall_status == 0 &&
241*1472a384SRoman Kagan 		atomic_read(&hv->sint_received) == 0;
242*1472a384SRoman Kagan }
243*1472a384SRoman Kagan 
244*1472a384SRoman Kagan static int run_test(int ncpus, int dst_add, ulong wait_cycles,
245*1472a384SRoman Kagan 		    void (*func)(void *), bool (*is_ok)(int))
246*1472a384SRoman Kagan {
247*1472a384SRoman Kagan 	int i, ret = 0;
248*1472a384SRoman Kagan 
249*1472a384SRoman Kagan 	atomic_set(&ncpus_done, 0);
250*1472a384SRoman Kagan 	for (i = 0; i < ncpus; i++) {
251*1472a384SRoman Kagan 		ulong dst = (i + dst_add) % ncpus;
252*1472a384SRoman Kagan 		on_cpu_async(i, func, (void *)dst);
253*1472a384SRoman Kagan 	}
254*1472a384SRoman Kagan 	while (atomic_read(&ncpus_done) != ncpus)
255*1472a384SRoman Kagan 		pause();
256*1472a384SRoman Kagan 
257*1472a384SRoman Kagan 	while (wait_cycles--)
258*1472a384SRoman Kagan 		pause();
259*1472a384SRoman Kagan 
260*1472a384SRoman Kagan 	if (is_ok)
261*1472a384SRoman Kagan 		for (i = 0; i < ncpus; i++)
262*1472a384SRoman Kagan 			ret += is_ok(i);
263*1472a384SRoman Kagan 	return ret;
264*1472a384SRoman Kagan }
265*1472a384SRoman Kagan 
266*1472a384SRoman Kagan #define HV_STATUS_INVALID_HYPERCALL_CODE        2
267*1472a384SRoman Kagan 
268*1472a384SRoman Kagan int main(int ac, char **av)
269*1472a384SRoman Kagan {
270*1472a384SRoman Kagan 	int ncpus, ncpus_ok, i;
271*1472a384SRoman Kagan 
272*1472a384SRoman Kagan 	if (!synic_supported()) {
273*1472a384SRoman Kagan 		report_skip("Hyper-V SynIC is not supported");
274*1472a384SRoman Kagan 		goto summary;
275*1472a384SRoman Kagan 	}
276*1472a384SRoman Kagan 
277*1472a384SRoman Kagan 	setup_vm();
278*1472a384SRoman Kagan 	smp_init();
279*1472a384SRoman Kagan 	ncpus = cpu_count();
280*1472a384SRoman Kagan 	if (ncpus > MAX_CPUS)
281*1472a384SRoman Kagan 		report_abort("# cpus: %d > %d", ncpus, MAX_CPUS);
282*1472a384SRoman Kagan 
283*1472a384SRoman Kagan 	handle_irq(MSG_VEC, sint_isr);
284*1472a384SRoman Kagan 	handle_irq(EVT_VEC, sint_isr);
285*1472a384SRoman Kagan 
286*1472a384SRoman Kagan 	setup_hypercall();
287*1472a384SRoman Kagan 
288*1472a384SRoman Kagan 	if (do_hypercall(HVCALL_SIGNAL_EVENT, 0x1234, 1) ==
289*1472a384SRoman Kagan 	    HV_STATUS_INVALID_HYPERCALL_CODE) {
290*1472a384SRoman Kagan 		report_skip("Hyper-V SynIC connections are not supported");
291*1472a384SRoman Kagan 		goto summary;
292*1472a384SRoman Kagan 	}
293*1472a384SRoman Kagan 
294*1472a384SRoman Kagan 	for (i = 0; i < ncpus; i++)
295*1472a384SRoman Kagan 		on_cpu(i, setup_cpu, (void *)read_cr3());
296*1472a384SRoman Kagan 
297*1472a384SRoman Kagan 	ncpus_ok = run_test(ncpus, 0, WAIT_CYCLES, do_msg, msg_ok);
298*1472a384SRoman Kagan 	report("send message to self: %d/%d",
299*1472a384SRoman Kagan 	       ncpus_ok == ncpus, ncpus_ok, ncpus);
300*1472a384SRoman Kagan 
301*1472a384SRoman Kagan 	run_test(ncpus, 0, 0, clear_msg, NULL);
302*1472a384SRoman Kagan 
303*1472a384SRoman Kagan 	ncpus_ok = run_test(ncpus, 1, WAIT_CYCLES, do_msg, msg_ok);
304*1472a384SRoman Kagan 	report("send message to another cpu: %d/%d",
305*1472a384SRoman Kagan 	       ncpus_ok == ncpus, ncpus_ok, ncpus);
306*1472a384SRoman Kagan 
307*1472a384SRoman Kagan 	ncpus_ok = run_test(ncpus, 1, WAIT_CYCLES, do_msg, msg_busy);
308*1472a384SRoman Kagan 	report("send message to busy slot: %d/%d",
309*1472a384SRoman Kagan 	       ncpus_ok == ncpus, ncpus_ok, ncpus);
310*1472a384SRoman Kagan 
311*1472a384SRoman Kagan 	ncpus_ok = run_test(ncpus, 0, WAIT_CYCLES, clear_msg, msg_ok);
312*1472a384SRoman Kagan 	report("receive pending message: %d/%d",
313*1472a384SRoman Kagan 	       ncpus_ok == ncpus, ncpus_ok, ncpus);
314*1472a384SRoman Kagan 
315*1472a384SRoman Kagan 	ncpus_ok = run_test(ncpus, 0, WAIT_CYCLES, do_evt, evt_ok);
316*1472a384SRoman Kagan 	report("signal event on self: %d/%d",
317*1472a384SRoman Kagan 	       ncpus_ok == ncpus, ncpus_ok, ncpus);
318*1472a384SRoman Kagan 
319*1472a384SRoman Kagan 	run_test(ncpus, 0, 0, clear_evt, NULL);
320*1472a384SRoman Kagan 
321*1472a384SRoman Kagan 	ncpus_ok = run_test(ncpus, 1, WAIT_CYCLES, do_evt, evt_ok);
322*1472a384SRoman Kagan 	report("signal event on another cpu: %d/%d",
323*1472a384SRoman Kagan 	       ncpus_ok == ncpus, ncpus_ok, ncpus);
324*1472a384SRoman Kagan 
325*1472a384SRoman Kagan 	ncpus_ok = run_test(ncpus, 1, WAIT_CYCLES, do_evt, evt_busy);
326*1472a384SRoman Kagan 	report("signal event already set: %d/%d",
327*1472a384SRoman Kagan 	       ncpus_ok == ncpus, ncpus_ok, ncpus);
328*1472a384SRoman Kagan 
329*1472a384SRoman Kagan 	for (i = 0; i < ncpus; i++)
330*1472a384SRoman Kagan 		on_cpu(i, teardown_cpu, NULL);
331*1472a384SRoman Kagan 
332*1472a384SRoman Kagan 	teardown_hypercall();
333*1472a384SRoman Kagan 
334*1472a384SRoman Kagan summary:
335*1472a384SRoman Kagan 	return report_summary();
336*1472a384SRoman Kagan }
337