1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3 * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
4 */
5 #include <fcntl.h>
6 #include <ffa.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/ioctl.h>
10 #include <unistd.h>
11 #include "include/uapi/linux/arm_ffa_user.h"
12 #include "xtest_helpers.h"
13 #include "xtest_test.h"
14
15 #define FFA_DRIVER_FS_PATH "/sys/kernel/debug/arm_ffa_user"
16 #define SPMC_TEST_OK 0xaa
17 #define INCORRECT_ENDPOINT_ID 0xffff
18 #define NORMAL_WORLD_ENDPOINT_ID 0
19
20 /* Get the 32 least significant bits of a handle.*/
21 #define MEM_SHARE_HANDLE_LOW(x) ((x) & 0xffffffff)
22 /* Get the 32 most significant bits of a handle.*/
23 #define MEM_SHARE_HANDLE_HIGH(x) (((x) >> 32) & 0xffffffff)
24
25 #define MEM_SHARE_HANDLE_LOW_INDEX 1
26 #define MEM_SHARE_HANDLE_HIGH_INDEX 2
27 #define MEM_SHARE_HANDLE_ENDPOINT_INDEX 3
28
29 enum sp_tests {
30 EP_TEST_SP,
31 EP_TEST_SP_COMMUNICATION,
32 EP_TEST_SP_INCREASE,
33 EP_TRY_R_ACCESS,
34 EP_TRY_W_ACCESS,
35 EP_RETRIEVE,
36 EP_RELINQUISH,
37 EP_SP_MEM_SHARING,
38 EP_SP_MEM_SHARING_MULTI,
39 EP_SP_MEM_SHARING_EXC,
40 EP_SP_MEM_INCORRECT_ACCESS,
41 EP_SP_NOP
42 };
43
44 static int ffa_fd = -1;
45
46 static const char test_endpoint1_uuid[] =
47 "5c9edbc3-7b3a-4367-9f83-7c191ae86a37";
48 static const char test_endpoint2_uuid[] =
49 "7817164c-c40c-4d1a-867a-9bb2278cf41a";
50 static const char test_endpoint3_uuid[] =
51 "23eb0100-e32a-4497-9052-2f11e584afa6";
52
53 static struct ffa_ioctl_ep_desc test_endpoint1 = {
54 .uuid_ptr = (uint64_t)test_endpoint1_uuid,
55 };
56
57 static struct ffa_ioctl_ep_desc test_endpoint2 = {
58 .uuid_ptr = (uint64_t)test_endpoint2_uuid,
59 };
60
61 static struct ffa_ioctl_ep_desc test_endpoint3 = {
62 .uuid_ptr = (uint64_t)test_endpoint3_uuid,
63 };
64
close_debugfs(void)65 static void close_debugfs(void)
66 {
67 int err = 0;
68
69 if (ffa_fd >= 0) {
70 err = close(ffa_fd);
71 if (err < 0)
72 Do_ADBG_Log("Error: Could not close the FF-A driver");
73 }
74 ffa_fd = -1;
75 }
76
init_sp_xtest(ADBG_Case_t * c)77 static bool init_sp_xtest(ADBG_Case_t *c)
78 {
79 if (ffa_fd < 0) {
80 ffa_fd = open(FFA_DRIVER_FS_PATH, O_RDWR);
81 if (ffa_fd < 0) {
82 Do_ADBG_Log("Error: Could not open the FF-A driver");
83 return false;
84 }
85 }
86 return true;
87 }
88
start_sp_test(uint16_t endpoint,enum sp_tests test,struct ffa_ioctl_msg_args * args)89 static int start_sp_test(uint16_t endpoint, enum sp_tests test,
90 struct ffa_ioctl_msg_args *args)
91 {
92 args->dst_id = endpoint;
93 args->args[0] = test;
94 return ioctl(ffa_fd, FFA_IOC_MSG_SEND, args);
95 }
96
get_endpoint_id(uint64_t endp)97 static uint16_t get_endpoint_id(uint64_t endp)
98 {
99 struct ffa_ioctl_ep_desc sid = { .uuid_ptr = endp };
100
101 /* Get ID of destination SP based on UUID */
102 if(ioctl(ffa_fd, FFA_IOC_GET_PART_ID, &sid))
103 return INCORRECT_ENDPOINT_ID;
104
105 return sid.id;
106 }
107
xtest_ffa_spmc_test_1001(ADBG_Case_t * c)108 static void xtest_ffa_spmc_test_1001(ADBG_Case_t *c)
109 {
110 struct ffa_ioctl_msg_args args = { 0 };
111 uint16_t endpoint1_id = 0;
112 uint16_t endpoint2_id = 0;
113 int rc = 0;
114
115 Do_ADBG_BeginSubCase(c, "SP1 comms check");
116 if (!init_sp_xtest(c)) {
117 Do_ADBG_Log("Failed to initialise test, skipping SP test");
118 goto out;
119 }
120
121 endpoint1_id = get_endpoint_id(test_endpoint1.uuid_ptr);
122 if (endpoint1_id == INCORRECT_ENDPOINT_ID) {
123 Do_ADBG_Log("Could not contact xtest_1 sp, skipping SP test");
124 Do_ADBG_Log("Add xtest_1 sp to the image to enable tests");
125 goto out;
126 }
127
128 memset(&args, 0, sizeof(args));
129 rc = start_sp_test(endpoint1_id, EP_TEST_SP, &args);
130 if (!ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0))
131 goto out;
132
133 if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK))
134 goto out;
135 Do_ADBG_EndSubCase(c, "SP1 comms check");
136
137 Do_ADBG_BeginSubCase(c, "Sp2 comms check");
138 endpoint2_id = get_endpoint_id(test_endpoint2.uuid_ptr);
139 if (endpoint2_id == INCORRECT_ENDPOINT_ID) {
140 Do_ADBG_Log("Could not contact xtest_2 sp, skipping SP test");
141 Do_ADBG_Log("Add xtest_2 sp to the image to enable tests");
142 goto out;
143 }
144
145 memset(&args, 0, sizeof(args));
146 rc = start_sp_test(endpoint2_id, EP_TEST_SP, &args);
147 if (!ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0))
148 goto out;
149
150 if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK))
151 goto out;
152 Do_ADBG_EndSubCase(c, "Sp2 comms check");
153
154 /* Test SP to SP messaging. */
155 Do_ADBG_BeginSubCase(c, "SP to SP messaging check");
156 memset(&args, 0, sizeof(args));
157 args.args[1] = endpoint2_id;
158
159 rc = start_sp_test(endpoint1_id, EP_TEST_SP_COMMUNICATION, &args);
160 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
161 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
162
163 memset(&args, 0, sizeof(args));
164 args.args[1] = endpoint1_id;
165
166 rc = start_sp_test(endpoint2_id, EP_TEST_SP_COMMUNICATION, &args);
167 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
168 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
169
170 out:
171 Do_ADBG_EndSubCase(c, NULL);
172 close_debugfs();
173 }
174
175 ADBG_CASE_DEFINE(ffa_spmc, 1001, xtest_ffa_spmc_test_1001,
176 "Test FF-A communication");
177
check_alive(ADBG_Case_t * c,uint16_t endpoint)178 static void check_alive(ADBG_Case_t *c, uint16_t endpoint)
179 {
180 struct ffa_ioctl_msg_args args = {};
181 int rc = 0;
182
183 args.dst_id = endpoint;
184 rc = start_sp_test(endpoint, EP_SP_NOP, &args);
185 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
186 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
187 }
188
share_mem(uint16_t endpoint,uint64_t * handle)189 static int share_mem(uint16_t endpoint, uint64_t *handle)
190 {
191 int status = false;
192 struct ffa_ioctl_shm_desc shm_desc = { .dst_id = endpoint,
193 .size = 0x1000 };
194
195 status = ioctl(ffa_fd, FFA_IOC_SHM_INIT, &shm_desc);
196
197 if (!status)
198 *handle = shm_desc.handle;
199
200 return status;
201 }
202
set_up_mem(struct ffa_ioctl_ep_desc * endp,struct ffa_ioctl_msg_args * args,uint64_t * handle,ADBG_Case_t * c)203 static int set_up_mem(struct ffa_ioctl_ep_desc *endp,
204 struct ffa_ioctl_msg_args *args,
205 uint64_t *handle, ADBG_Case_t *c)
206 {
207 uint16_t endpoint = 0;
208 int rc = 0;
209
210 endpoint = get_endpoint_id(endp->uuid_ptr);
211 *handle = 0;
212 /* Share memory with SP*/
213 rc = share_mem(endpoint, handle);
214 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
215
216 if (!ADBG_EXPECT_TRUE(c, handle != NULL))
217 return TEEC_ERROR_GENERIC;
218
219 /* SP will retrieve the memory region. */
220 memset(args, 0, sizeof(*args));
221 args->dst_id = endpoint;
222 args->args[MEM_SHARE_HANDLE_LOW_INDEX] = MEM_SHARE_HANDLE_LOW(*handle);
223 args->args[MEM_SHARE_HANDLE_HIGH_INDEX] = MEM_SHARE_HANDLE_HIGH(*handle);
224 args->args[MEM_SHARE_HANDLE_ENDPOINT_INDEX] = NORMAL_WORLD_ENDPOINT_ID;
225
226 rc = start_sp_test(endpoint, EP_RETRIEVE, args);
227 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
228 ADBG_EXPECT_COMPARE_UNSIGNED(c, args->args[0], ==, SPMC_TEST_OK);
229
230 return TEEC_SUCCESS;
231 }
232
xtest_ffa_spmc_test_1002(ADBG_Case_t * c)233 static void xtest_ffa_spmc_test_1002(ADBG_Case_t *c)
234 {
235 struct ffa_ioctl_msg_args args = { 0 };
236 uint64_t handle = 0;
237 uint16_t endpoint1_id = 0;
238 int rc = 0;
239 struct ffa_ioctl_shm_desc shm_desc = { 0 };
240
241 if (!init_sp_xtest(c)) {
242 Do_ADBG_Log("Failed to initialise test, skipping SP test");
243 goto out;
244 }
245
246 endpoint1_id = get_endpoint_id(test_endpoint1.uuid_ptr);
247 if (endpoint1_id == INCORRECT_ENDPOINT_ID) {
248 Do_ADBG_Log("Could not contact xtest_1 sp, skipping SP test");
249 Do_ADBG_Log("Add xtest_1 sp to the image to enable tests");
250 goto out;
251 }
252
253 memset(&args, 0, sizeof(args));
254 rc = start_sp_test(endpoint1_id, EP_TEST_SP, &args);
255 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
256 if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK))
257 goto out;
258
259 /* Set up memory and have the SP retrieve it. */
260 Do_ADBG_BeginSubCase(c, "Test memory set-up");
261 memset(&args, 0, sizeof(args));
262 if (set_up_mem(&test_endpoint1, &args, &handle, c)) {
263 Do_ADBG_EndSubCase(c, "Test memory set-up");
264 goto out;
265 }
266 Do_ADBG_EndSubCase(c, "Test memory set-up");
267
268 /* Retrieve it again. */
269 Do_ADBG_BeginSubCase(c, "Test retrieve memory second time");
270 memset(&args, 0, sizeof(args));
271 args.dst_id = endpoint1_id;
272 args.args[MEM_SHARE_HANDLE_LOW_INDEX] = MEM_SHARE_HANDLE_LOW(handle);
273 args.args[MEM_SHARE_HANDLE_HIGH_INDEX] = MEM_SHARE_HANDLE_HIGH(handle);
274 args.args[MEM_SHARE_HANDLE_ENDPOINT_INDEX] = NORMAL_WORLD_ENDPOINT_ID;
275 rc = start_sp_test(endpoint1_id, EP_RETRIEVE, &args);
276 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
277 Do_ADBG_EndSubCase(c, "Test retrieve memory second time");
278
279 /*Access it. */
280 Do_ADBG_BeginSubCase(c, "Test accessing memory");
281 memset(&args, 0, sizeof(args));
282 rc = start_sp_test(endpoint1_id, EP_TRY_R_ACCESS, &args);
283 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
284 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
285 Do_ADBG_EndSubCase(c, "Test accessing memory");
286
287 /*RELINQUISH the memory area.*/
288 Do_ADBG_BeginSubCase(c, "Test relinquish memory");
289 memset(&args, 0, sizeof(args));
290 args.args[MEM_SHARE_HANDLE_LOW_INDEX] = MEM_SHARE_HANDLE_LOW(handle);
291 args.args[MEM_SHARE_HANDLE_HIGH_INDEX] = MEM_SHARE_HANDLE_HIGH(handle);
292 rc = start_sp_test(endpoint1_id, EP_RELINQUISH, &args);
293 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
294 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
295 check_alive(c, endpoint1_id);
296 Do_ADBG_EndSubCase(c, "Test relinquish memory");
297
298 /* Try to reclaim the mem with the SP still having access to it. */
299 Do_ADBG_BeginSubCase(c, "Test incorrect reclaim");
300 shm_desc.handle = handle;
301 shm_desc.dst_id = endpoint1_id;
302 rc = ioctl(ffa_fd, FFA_IOC_SHM_DEINIT, &shm_desc);
303 ADBG_EXPECT_COMPARE_SIGNED(c, rc, <, 0);
304 Do_ADBG_EndSubCase(c, "Test incorrect reclaim");
305
306 /*RELINQUISH the memory area.*/
307 Do_ADBG_BeginSubCase(c, "Test relinquish memory second time");
308 memset(&args, 0, sizeof(args));
309 args.args[MEM_SHARE_HANDLE_LOW_INDEX] = MEM_SHARE_HANDLE_LOW(handle);
310 args.args[MEM_SHARE_HANDLE_HIGH_INDEX] = MEM_SHARE_HANDLE_HIGH(handle);
311 rc = start_sp_test(endpoint1_id, EP_RELINQUISH, &args);
312 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
313 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
314 check_alive(c, endpoint1_id);
315 Do_ADBG_EndSubCase(c, "Test relinquish memory second time");
316
317 /* Try to reclaim again this time it should work. */
318 Do_ADBG_BeginSubCase(c, "Test correct reclaim");
319 shm_desc.handle = handle;
320 shm_desc.dst_id = endpoint1_id;
321 rc = ioctl(ffa_fd, FFA_IOC_SHM_DEINIT, &shm_desc);
322 ADBG_EXPECT_COMPARE_SIGNED(c, rc, >=, 0);
323 check_alive(c, endpoint1_id);
324 Do_ADBG_EndSubCase(c, "Test correct reclaim");
325
326 /* SP will try to retrieve invalid memory region. */
327 Do_ADBG_BeginSubCase(c, "Test retrieve invalid memory region");
328 memset(&args, 0, sizeof(args));
329 args.args[MEM_SHARE_HANDLE_LOW_INDEX] = MEM_SHARE_HANDLE_LOW(handle);
330 args.args[MEM_SHARE_HANDLE_HIGH_INDEX] = MEM_SHARE_HANDLE_HIGH(handle);
331 args.args[MEM_SHARE_HANDLE_ENDPOINT_INDEX] = NORMAL_WORLD_ENDPOINT_ID;
332 rc = start_sp_test(endpoint1_id, EP_RETRIEVE, &args);
333 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
334 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], !=, SPMC_TEST_OK);
335 check_alive(c, endpoint1_id);
336
337 Do_ADBG_EndSubCase(c, "Test retrieve invalid memory region");
338 out:
339 close_debugfs();
340 }
341
342 ADBG_CASE_DEFINE(ffa_spmc, 1002, xtest_ffa_spmc_test_1002,
343 "Test FF-A memory: share memory from Normal World to SP");
344
xtest_ffa_spmc_test_1003(ADBG_Case_t * c)345 static void xtest_ffa_spmc_test_1003(ADBG_Case_t *c)
346 {
347 struct ffa_ioctl_msg_args args = { 0 };
348 uint16_t endpoint1 = 0;
349 uint16_t endpoint2 = 0;
350 int rc = 0;
351
352 if (!init_sp_xtest(c)) {
353 Do_ADBG_Log("Failed to initialise test, skipping SP test");
354 goto out;
355 }
356
357 endpoint1 = get_endpoint_id(test_endpoint1.uuid_ptr);
358 if (endpoint1 == INCORRECT_ENDPOINT_ID) {
359 Do_ADBG_Log("Could not contact xtest_1 sp, skipping SP test");
360 Do_ADBG_Log("Add xtest_1 sp to the image to enable tests");
361 goto out;
362 }
363
364 /* Test SP to SP memory sharing. */
365 endpoint2 = get_endpoint_id(test_endpoint2.uuid_ptr);
366 if (endpoint2 == INCORRECT_ENDPOINT_ID) {
367 Do_ADBG_Log("Could not contact xtest_2 sp, skipping SP test");
368 Do_ADBG_Log("Add xtest_2 sp to the image to enable tests");
369 goto out;
370 }
371
372 memset(&args, 0, sizeof(args));
373 args.args[1] = endpoint2;
374 rc = start_sp_test(endpoint1, EP_SP_MEM_SHARING, &args);
375 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
376 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
377
378 out:
379 close_debugfs();
380 }
381
382 ADBG_CASE_DEFINE(ffa_spmc, 1003, xtest_ffa_spmc_test_1003,
383 "Test FF-A memory: SP to SP");
384
xtest_ffa_spmc_test_1004(ADBG_Case_t * c)385 static void xtest_ffa_spmc_test_1004(ADBG_Case_t *c)
386 {
387 struct ffa_ioctl_msg_args args = { 0 };
388 uint16_t endpoint1 = 0;
389 uint16_t endpoint2 = 0;
390 int rc = 0;
391
392 if (!init_sp_xtest(c)) {
393 Do_ADBG_Log("Failed to initialise test, skipping SP test");
394 goto out;
395 }
396
397 endpoint1 = get_endpoint_id(test_endpoint1.uuid_ptr);
398 if (endpoint1 == INCORRECT_ENDPOINT_ID) {
399 Do_ADBG_Log("Could not contact xtest_1 sp, skipping SP test");
400 Do_ADBG_Log("Add xtest_1 sp to the image to enable tests");
401 goto out;
402 }
403
404 /* Test SP to SP memory sharing. */
405 endpoint2 = get_endpoint_id(test_endpoint2.uuid_ptr);
406 if (endpoint2 == INCORRECT_ENDPOINT_ID) {
407 Do_ADBG_Log("Could not contact xtest_2 sp, skipping SP test");
408 Do_ADBG_Log("Add xtest_2 sp to the image to enable tests");
409 goto out;
410 }
411
412 Do_ADBG_BeginSubCase(c, "Test sharing with exc access");
413 memset(&args, 0, sizeof(args));
414 args.args[1] = endpoint2;
415 rc = start_sp_test(endpoint1, EP_SP_MEM_SHARING_EXC, &args);
416 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
417 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
418 Do_ADBG_EndSubCase(c, "Test sharing with exc access");
419
420 Do_ADBG_BeginSubCase(c, "Test sharing with incorrect access");
421 memset(&args, 0, sizeof(args));
422 args.args[1] = endpoint2;
423 rc = start_sp_test(endpoint1, EP_SP_MEM_INCORRECT_ACCESS, &args);
424 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
425 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
426 Do_ADBG_EndSubCase(c, "Test sharing with incorrect access");
427
428 out:
429 close_debugfs();
430 }
431
432 ADBG_CASE_DEFINE(ffa_spmc, 1004, xtest_ffa_spmc_test_1004,
433 "Test FF-A memory: Access and flags");
434
xtest_ffa_spmc_test_1005(ADBG_Case_t * c)435 static void xtest_ffa_spmc_test_1005(ADBG_Case_t *c)
436 {
437 struct ffa_ioctl_msg_args args = { 0 };
438 uint16_t endpoint1 = 0;
439 uint16_t endpoint2 = 0;
440 uint16_t endpoint3 = 0;
441 int rc = 0;
442
443 if (!init_sp_xtest(c)) {
444 Do_ADBG_Log("Failed to initialise test, skipping SP test");
445 goto out;
446 }
447
448 endpoint1 = get_endpoint_id(test_endpoint1.uuid_ptr);
449 if (endpoint1 == INCORRECT_ENDPOINT_ID) {
450 Do_ADBG_Log("Could not contact xtest_1 sp, skipping SP test");
451 Do_ADBG_Log("Add xtest_1 sp to the image to enable tests");
452 goto out;
453 }
454
455 endpoint2 = get_endpoint_id(test_endpoint2.uuid_ptr);
456 if (endpoint2 == INCORRECT_ENDPOINT_ID) {
457 Do_ADBG_Log("Could not contact xtest_2 sp, skipping SP test");
458 Do_ADBG_Log("Add xtest_2 sp to the image to enable tests");
459 goto out;
460 }
461
462 endpoint3 = get_endpoint_id(test_endpoint3.uuid_ptr);
463 if (endpoint3 == INCORRECT_ENDPOINT_ID) {
464 Do_ADBG_Log("Could not contact xtest_3 sp, skipping SP test");
465 Do_ADBG_Log("Add xtest_3 sp to the image to enable tests");
466 goto out;
467 }
468
469 memset(&args, 0, sizeof(args));
470 args.args[1] = endpoint2;
471 args.args[2] = endpoint3;
472 rc = start_sp_test(endpoint1, EP_SP_MEM_SHARING_MULTI,&args);
473 ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
474 ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
475
476 out:
477 close_debugfs();
478 }
479
480 ADBG_CASE_DEFINE(regression, 1005, xtest_ffa_spmc_test_1005,
481 "Test FF-A memory: multiple receiver");
482