1 /*
2  * Copyright 2021 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #include "hf/ffa.h"
10 #include "hf/std.h"
11 
12 #include "vmapi/hf/call.h"
13 
14 #include "test/hftest.h"
15 
wait_for_vm(uint32_t vmid)16 static void wait_for_vm(uint32_t vmid)
17 {
18 	uint16_t retry_count = 0;
19 	for (;;) {
20 		retry_count++;
21 		int64_t w = hf_mailbox_writable_get();
22 		if (w == vmid) {
23 			return;
24 		}
25 
26 		if (w == -1) {
27 			__asm__ volatile("wfe");
28 		}
29 		/*
30 		 * On FVP, WFI/WFE done trap to EL2 even though SCTLR_EL2 is
31 		 * setup to trap these instructions. The architecture does not
32 		 * guarantee that these instructions will be trapped, only that
33 		 * it may be trapped if it does not complete in finite time. To
34 		 * work around this, if there are more than a threshold number
35 		 * of retries, simply call yield to allow primary VM to get back
36 		 * control. Note that on QEMU, WFI/WFE trap just fine.
37 		 */
38 		if (retry_count > 1000) {
39 			ffa_yield();
40 			retry_count = 0;
41 		}
42 	}
43 }
44 
TEST_SERVICE(echo_with_notification)45 TEST_SERVICE(echo_with_notification)
46 {
47 	/* Loop, echo messages back to the sender. */
48 	for (;;) {
49 		void *send_buf = SERVICE_SEND_BUFFER();
50 		void *recv_buf = SERVICE_RECV_BUFFER();
51 		struct ffa_value ret = ffa_msg_wait();
52 		ffa_vm_id_t target_vm_id = ffa_receiver(ret);
53 		ffa_vm_id_t source_vm_id = ffa_sender(ret);
54 
55 		memcpy_s(send_buf, FFA_MSG_PAYLOAD_MAX, recv_buf,
56 			 ffa_msg_send_size(ret));
57 
58 		while (ffa_msg_send(target_vm_id, source_vm_id,
59 				    ffa_msg_send_size(ret), FFA_MSG_SEND_NOTIFY)
60 			       .func != FFA_SUCCESS_32) {
61 			wait_for_vm(source_vm_id);
62 		}
63 
64 		EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
65 	}
66 }
67