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 <stdint.h>
10
11 #include "hf/ffa.h"
12 #include "hf/std.h"
13
14 #include "vmapi/hf/call.h"
15
16 #include "primary_with_secondary.h"
17 #include "test/hftest.h"
18 #include "test/vmapi/ffa.h"
19
20 /**
21 * Reverses the order of the elements in the given array.
22 */
reverse(char * s,size_t len)23 static void reverse(char *s, size_t len)
24 {
25 size_t i;
26
27 for (i = 0; i < len / 2; i++) {
28 char t = s[i];
29 s[i] = s[len - 1 - i];
30 s[len - 1 - i] = t;
31 }
32 }
33
34 /**
35 * Finds the next lexicographic permutation of the given array, if there is one.
36 */
next_permutation(char * s,size_t len)37 static void next_permutation(char *s, size_t len)
38 {
39 size_t i;
40 size_t j;
41
42 for (i = len - 2; i < len; i--) {
43 const char t = s[i];
44 if (t >= s[i + 1]) {
45 continue;
46 }
47
48 for (j = len - 1; t >= s[j]; j--) {
49 }
50
51 s[i] = s[j];
52 s[j] = t;
53 reverse(s + i + 1, len - i - 1);
54 return;
55 }
56 }
57
TEAR_DOWN(mailbox)58 TEAR_DOWN(mailbox)
59 {
60 EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
61 }
62
63 /**
64 * Clearing an empty mailbox is an error.
65 */
TEST(mailbox,clear_empty)66 TEST(mailbox, clear_empty)
67 {
68 EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
69 EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
70 EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
71 }
72
73 /**
74 * Send and receive the same message from the echo VM.
75 */
TEST(mailbox,echo)76 TEST(mailbox, echo)
77 {
78 const char message[] = "Echo this back to me!";
79 struct ffa_value run_res;
80 struct mailbox_buffers mb = set_up_mailbox();
81
82 SERVICE_SELECT(SERVICE_VM1, "echo", mb.send);
83
84 run_res = ffa_run(SERVICE_VM1, 0);
85 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
86 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
87
88 /* Set the message, echo it and check it didn't change. */
89 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
90 EXPECT_EQ(
91 ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
92 .func,
93 FFA_SUCCESS_32);
94 run_res = ffa_run(SERVICE_VM1, 0);
95 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
96 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(message));
97 EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
98 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
99 }
100
101 /**
102 * Repeatedly send a message and receive it back from the echo VM.
103 */
TEST(mailbox,repeated_echo)104 TEST(mailbox, repeated_echo)
105 {
106 char message[] = "Echo this back to me!";
107 struct ffa_value run_res;
108 uint8_t i;
109 struct mailbox_buffers mb = set_up_mailbox();
110
111 SERVICE_SELECT(SERVICE_VM1, "echo", mb.send);
112
113 for (i = 0; i < 100; i++) {
114 /* Run secondary until it reaches the wait for messages. */
115 run_res = ffa_run(SERVICE_VM1, 0);
116 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
117 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
118
119 /* Set the message, echo it and check it didn't change. */
120 next_permutation(message, sizeof(message) - 1);
121 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message,
122 sizeof(message));
123 EXPECT_EQ(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1,
124 sizeof(message), 0)
125 .func,
126 FFA_SUCCESS_32);
127 run_res = ffa_run(SERVICE_VM1, 0);
128 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
129 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(message));
130 EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
131 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
132 }
133 }
134
135 /**
136 * Send a message to relay_a which will forward it to relay_b where it will be
137 * sent back here.
138 */
TEST(mailbox,relay)139 TEST(mailbox, relay)
140 {
141 const char message[] = "Send this round the relay!";
142 struct ffa_value run_res;
143 struct mailbox_buffers mb = set_up_mailbox();
144
145 SERVICE_SELECT(SERVICE_VM1, "relay", mb.send);
146 SERVICE_SELECT(SERVICE_VM2, "relay", mb.send);
147
148 run_res = ffa_run(SERVICE_VM1, 0);
149 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
150 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
151 run_res = ffa_run(SERVICE_VM2, 0);
152 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
153 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
154
155 /*
156 * Build the message chain so the message is sent from here to
157 * SERVICE_VM1, then to SERVICE_VM2 and finally back to here.
158 */
159 {
160 ffa_vm_id_t *chain = (ffa_vm_id_t *)mb.send;
161 *chain++ = htole32(SERVICE_VM2);
162 *chain++ = htole32(HF_PRIMARY_VM_ID);
163 memcpy_s(chain, FFA_MSG_PAYLOAD_MAX - (2 * sizeof(ffa_vm_id_t)),
164 message, sizeof(message));
165
166 EXPECT_EQ(
167 ffa_msg_send(
168 HF_PRIMARY_VM_ID, SERVICE_VM1,
169 sizeof(message) + (2 * sizeof(ffa_vm_id_t)), 0)
170 .func,
171 FFA_SUCCESS_32);
172 }
173
174 /* Let SERVICE_VM1 forward the message. */
175 run_res = ffa_run(SERVICE_VM1, 0);
176 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
177 EXPECT_EQ(ffa_receiver(run_res), SERVICE_VM2);
178 EXPECT_EQ(ffa_msg_send_size(run_res), 0);
179
180 /* Let SERVICE_VM2 forward the message. */
181 run_res = ffa_run(SERVICE_VM2, 0);
182 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
183
184 /* Ensure the message is intact. */
185 EXPECT_EQ(ffa_receiver(run_res), HF_PRIMARY_VM_ID);
186 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(message));
187 EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
188 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
189 }
190
191 /**
192 * Send a message before the secondary VM is configured, but do not register
193 * for notification. Ensure we're not notified.
194 */
TEST(mailbox,no_primary_to_secondary_notification_on_configure)195 TEST(mailbox, no_primary_to_secondary_notification_on_configure)
196 {
197 struct ffa_value run_res;
198
199 set_up_mailbox();
200
201 EXPECT_FFA_ERROR(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0),
202 FFA_BUSY);
203
204 run_res = ffa_run(SERVICE_VM1, 0);
205 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
206 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
207
208 EXPECT_EQ(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0).func,
209 FFA_SUCCESS_32);
210 }
211