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
11 #include <stdint.h>
12
13 #include "hf/arch/irq.h"
14 #include "hf/arch/vm/interrupts.h"
15 #include "hf/arch/vm/timer.h"
16
17 #include "hf/std.h"
18
19 #include "vmapi/hf/call.h"
20
21 #include "primary_with_secondary.h"
22 #include "test/hftest.h"
23 #include "test/vmapi/ffa.h"
24
TEAR_DOWN(ffa)25 TEAR_DOWN(ffa)
26 {
27 EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
28 }
29
30 /**
31 * Send a message to a secondary VM which checks the validity of the received
32 * header.
33 */
TEST(ffa,msg_send)34 TEST(ffa, msg_send)
35 {
36 const char message[] = "ffa_msg_send";
37 struct ffa_value run_res;
38 struct mailbox_buffers mb = set_up_mailbox();
39
40 SERVICE_SELECT(SERVICE_VM1, "ffa_check", mb.send);
41
42 /* Set the payload, init the message header and send the message. */
43 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
44 EXPECT_EQ(
45 ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
46 .func,
47 FFA_SUCCESS_32);
48
49 run_res = ffa_run(SERVICE_VM1, 0);
50 EXPECT_EQ(run_res.func, FFA_YIELD_32);
51 }
52
53 /**
54 * Send a message to a secondary VM spoofing the source VM id.
55 */
TEST(ffa,msg_send_spoof)56 TEST(ffa, msg_send_spoof)
57 {
58 const char message[] = "ffa_msg_send";
59 struct mailbox_buffers mb = set_up_mailbox();
60
61 SERVICE_SELECT(SERVICE_VM1, "ffa_check", mb.send);
62
63 /* Set the payload, init the message header and send the message. */
64 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
65 EXPECT_FFA_ERROR(
66 ffa_msg_send(SERVICE_VM2, SERVICE_VM1, sizeof(message), 0),
67 FFA_INVALID_PARAMETERS);
68 }
69
70 /**
71 * Send a message to a secondary VM with incorrect destination id.
72 */
TEST(ffa,ffa_invalid_destination_id)73 TEST(ffa, ffa_invalid_destination_id)
74 {
75 const char message[] = "fail to send";
76 struct mailbox_buffers mb = set_up_mailbox();
77
78 SERVICE_SELECT(SERVICE_VM1, "ffa_check", mb.send);
79 /* Set the payload, init the message header and send the message. */
80 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
81 EXPECT_FFA_ERROR(ffa_msg_send(HF_PRIMARY_VM_ID, -1, sizeof(message), 0),
82 FFA_INVALID_PARAMETERS);
83 }
84
85 /**
86 * Ensure that the length parameter is respected when sending messages.
87 */
TEST(ffa,ffa_incorrect_length)88 TEST(ffa, ffa_incorrect_length)
89 {
90 const char message[] = "this should be truncated";
91 struct ffa_value run_res;
92 struct mailbox_buffers mb = set_up_mailbox();
93
94 SERVICE_SELECT(SERVICE_VM1, "ffa_length", mb.send);
95
96 /* Send the message and compare if truncated. */
97 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
98 /* Hard code incorrect length. */
99 EXPECT_EQ(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, 16, 0).func,
100 FFA_SUCCESS_32);
101 run_res = ffa_run(SERVICE_VM1, 0);
102 EXPECT_EQ(run_res.func, FFA_YIELD_32);
103 }
104
105 /**
106 * Attempt to send a message larger than what is supported.
107 */
TEST(ffa,ffa_large_message)108 TEST(ffa, ffa_large_message)
109 {
110 const char message[] = "fail to send";
111 struct mailbox_buffers mb = set_up_mailbox();
112
113 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
114 /* Send a message that is larger than the mailbox supports (4KB). */
115 EXPECT_FFA_ERROR(
116 ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, 4 * 1024 + 1, 0),
117 FFA_INVALID_PARAMETERS);
118 }
119
120 /**
121 * Verify secondary VM non blocking recv.
122 */
TEST(ffa,ffa_recv_non_blocking)123 TEST(ffa, ffa_recv_non_blocking)
124 {
125 struct mailbox_buffers mb = set_up_mailbox();
126 struct ffa_value run_res;
127
128 /* Check is performed in secondary VM. */
129 SERVICE_SELECT(SERVICE_VM1, "ffa_recv_non_blocking", mb.send);
130 run_res = ffa_run(SERVICE_VM1, 0);
131 EXPECT_EQ(run_res.func, FFA_YIELD_32);
132 }
133
134 /**
135 * Verify that FFA_MSG_WAIT responds correctly to wrong parameters.
136 */
TEST(ffa,ffa_msg_wait_fail)137 TEST(ffa, ffa_msg_wait_fail)
138 {
139 struct ffa_value ret;
140 ret = ffa_call((struct ffa_value){.func = FFA_MSG_WAIT_32,
141 .arg1 = 1,
142 .arg2 = 2,
143 .arg3 = 3,
144 .arg4 = 4,
145 .arg5 = 5,
146 .arg6 = 6,
147 .arg7 = 7});
148 EXPECT_FFA_ERROR(ret, FFA_INVALID_PARAMETERS);
149 }
150
151 /**
152 * Verify that partition discovery via the FFA_PARTITION_INFO interface
153 * returns the expected information on the VMs in the system.
154 */
TEST(ffa,ffa_partition_info)155 TEST(ffa, ffa_partition_info)
156 {
157 struct mailbox_buffers mb = set_up_mailbox();
158 struct ffa_value ret;
159 const struct ffa_partition_info *partitions = mb.recv;
160 struct ffa_uuid uuid;
161 ffa_vm_count_t vm_count;
162
163 /* A Null UUID requests information for all partitions. */
164 ffa_uuid_init(0, 0, 0, 0, &uuid);
165
166 ret = ffa_partition_info_get(&uuid, 0);
167 EXPECT_EQ(ret.func, FFA_SUCCESS_32);
168 vm_count = ret.arg2;
169 EXPECT_EQ(vm_count, 4);
170
171 for (uint16_t index = 0; index < vm_count; ++index) {
172 ffa_vm_id_t vm_id = partitions[index].vm_id;
173 EXPECT_GE(vm_id, (ffa_vm_id_t)HF_PRIMARY_VM_ID);
174 EXPECT_LE(vm_id, (ffa_vm_id_t)SERVICE_VM3);
175
176 /*
177 * NOTE: The ordering is NOT specified by the spec, but is an
178 * artifact of how it's implemented in Hafnium. If that changes
179 * the following EXPECT could fail.
180 */
181 EXPECT_EQ(vm_id, index + 1);
182
183 EXPECT_GE(partitions[index].vcpu_count, 1);
184 }
185
186 ret = ffa_rx_release();
187 EXPECT_EQ(ret.func, FFA_SUCCESS_32);
188 }
189
190 /**
191 * Trying to run a partition which is waiting for a message should not actually
192 * run it, but return FFA_MSG_WAIT again.
193 */
TEST(ffa,run_waiting)194 TEST(ffa, run_waiting)
195 {
196 struct mailbox_buffers mb = set_up_mailbox();
197 struct ffa_value run_res;
198
199 SERVICE_SELECT(SERVICE_VM1, "run_waiting", mb.send);
200
201 /* Let the secondary get started and wait for a message. */
202 run_res = ffa_run(SERVICE_VM1, 0);
203 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
204 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
205
206 /*
207 * Trying to run it again should return the same value, and not actually
208 * run it.
209 */
210 run_res = ffa_run(SERVICE_VM1, 0);
211 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
212 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
213 }
214
215 /**
216 * Send direct message, verify that sent info is echoed back.
217 */
TEST(ffa,ffa_send_direct_message_req_echo)218 TEST(ffa, ffa_send_direct_message_req_echo)
219 {
220 const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
221 0x88889999};
222 struct mailbox_buffers mb = set_up_mailbox();
223 struct ffa_value res;
224
225 SERVICE_SELECT(SERVICE_VM1, "ffa_direct_message_resp_echo", mb.send);
226 ffa_run(SERVICE_VM1, 0);
227
228 res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, msg[0],
229 msg[1], msg[2], msg[3], msg[4]);
230
231 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
232
233 EXPECT_EQ(res.arg3, msg[0]);
234 EXPECT_EQ(res.arg4, msg[1]);
235 EXPECT_EQ(res.arg5, msg[2]);
236 EXPECT_EQ(res.arg6, msg[3]);
237 EXPECT_EQ(res.arg7, msg[4]);
238 }
239
240 /**
241 * Send direct message, secondary verifies disallowed SMC invocations while
242 * ffa_msg_send_direct_req is being serviced.
243 */
TEST(ffa,ffa_send_direct_message_req_disallowed_smc)244 TEST(ffa, ffa_send_direct_message_req_disallowed_smc)
245 {
246 const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
247 0x88889999};
248 struct mailbox_buffers mb = set_up_mailbox();
249 struct ffa_value res;
250
251 SERVICE_SELECT(SERVICE_VM1, "ffa_direct_msg_req_disallowed_smc",
252 mb.send);
253 ffa_run(SERVICE_VM1, 0);
254
255 res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, msg[0],
256 msg[1], msg[2], msg[3], msg[4]);
257
258 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
259 }
260
261 /**
262 * Send direct message to invalid destination.
263 */
TEST(ffa,ffa_send_direct_message_req_invalid_dst)264 TEST(ffa, ffa_send_direct_message_req_invalid_dst)
265 {
266 const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
267 0x88889999};
268 struct ffa_value res;
269
270 res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, HF_PRIMARY_VM_ID,
271 msg[0], msg[1], msg[2], msg[3], msg[4]);
272
273 EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
274 }
275
276 /**
277 * Verify that the primary VM can't send direct message responses.
278 */
TEST(ffa,ffa_send_direct_message_resp_invalid)279 TEST(ffa, ffa_send_direct_message_resp_invalid)
280 {
281 struct ffa_value res;
282 struct mailbox_buffers mb = set_up_mailbox();
283
284 SERVICE_SELECT(SERVICE_VM1, "ffa_direct_message_resp_echo", mb.send);
285 ffa_run(SERVICE_VM1, 0);
286
287 res = ffa_msg_send_direct_resp(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0, 0,
288 0, 0);
289 EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
290 }
291
292 /**
293 * Run secondary VM through ffa_run and check it cannot invoke
294 * a direct message request.
295 */
TEST(ffa,ffa_secondary_direct_msg_req_invalid)296 TEST(ffa, ffa_secondary_direct_msg_req_invalid)
297 {
298 struct mailbox_buffers mb = set_up_mailbox();
299 struct ffa_value res;
300
301 SERVICE_SELECT(SERVICE_VM1, "ffa_disallowed_direct_msg_req", mb.send);
302 ffa_run(SERVICE_VM1, 0);
303
304 res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0, 0, 0,
305 0);
306 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
307 }
308
309 /**
310 * Run secondary VM without sending a direct message request beforehand.
311 * Secondary VM must fail sending a direct message response.
312 */
TEST(ffa,ffa_secondary_direct_msg_resp_invalid)313 TEST(ffa, ffa_secondary_direct_msg_resp_invalid)
314 {
315 struct mailbox_buffers mb = set_up_mailbox();
316 struct ffa_value res;
317
318 SERVICE_SELECT(SERVICE_VM1, "ffa_disallowed_direct_msg_resp", mb.send);
319 ffa_run(SERVICE_VM1, 0);
320
321 res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0, 0, 0,
322 0);
323 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
324 }
325
326 /**
327 * Run secondary VM and send a direct message request. Secondary VM attempts
328 * altering the sender and receiver in its direct message responses, and must
329 * fail to do so.
330 */
TEST(ffa,ffa_secondary_spoofed_response)331 TEST(ffa, ffa_secondary_spoofed_response)
332 {
333 struct mailbox_buffers mb = set_up_mailbox();
334 struct ffa_value res;
335
336 SERVICE_SELECT(SERVICE_VM1,
337 "ffa_direct_msg_resp_invalid_sender_receiver", mb.send);
338 ffa_run(SERVICE_VM1, 0);
339
340 res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0, 0, 0,
341 0);
342 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
343 }
344
345 /*
346 * The secondary vCPU is waiting for a direct request, but the primary instead
347 * calls `FFA_RUN`. This should return immediately to the primary without the
348 * secondary ever actually being run.
349 */
TEST(ffa,ffa_secondary_run)350 TEST(ffa, ffa_secondary_run)
351 {
352 struct mailbox_buffers mb = set_up_mailbox();
353 struct ffa_value res;
354
355 SERVICE_SELECT(SERVICE_VM1, "ffa_direct_msg_run", mb.send);
356 res = ffa_run(SERVICE_VM1, 0);
357 EXPECT_EQ(res.func, FFA_MSG_WAIT_32);
358 EXPECT_EQ(res.arg2, FFA_SLEEP_INDEFINITE);
359
360 res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, 1, 0, 0, 0,
361 0);
362 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
363 EXPECT_EQ(res.arg3, 2);
364
365 res = ffa_run(SERVICE_VM1, 0);
366 EXPECT_EQ(res.func, FFA_MSG_WAIT_32);
367 EXPECT_EQ(res.arg2, FFA_SLEEP_INDEFINITE);
368
369 res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, 3, 0, 0, 0,
370 0);
371 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
372 EXPECT_EQ(res.arg3, 4);
373 }
374