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