blob: 1b12fb7cfc3f457597fe90ad9b826276004fd640 [file] [log] [blame]
J-Alves9f6f0142020-06-17 15:37:59 +01001/*
2 * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#include <assert.h>
J-Alves9f6f0142020-06-17 15:37:59 +01007#include <debug.h>
Max Shvetsov40eb6a22020-06-08 11:15:30 +01008#include <errno.h>
Arunachalam Ganapathy51be1fe2020-09-22 13:25:21 +01009#include <cactus_platform_def.h>
Max Shvetsovc32f4782020-06-23 09:41:15 +010010#include <cactus_def.h>
J-Alves5aecd982020-06-11 10:25:33 +010011#include <ffa_helpers.h>
J-Alves9f6f0142020-06-17 15:37:59 +010012#include <sp_helpers.h>
13
J-Alves63cdaa72020-10-08 17:22:45 +010014#include <lib/libc/string.h>
15#include <lib/xlat_tables/xlat_tables_v2.h>
16
J-Alves9f6f0142020-06-17 15:37:59 +010017/* FFA version test helpers */
18#define FFA_MAJOR 1U
19#define FFA_MINOR 0U
20
Max Shvetsovc32f4782020-06-23 09:41:15 +010021static const uint32_t primary_uuid[4] = PRIMARY_UUID;
22static const uint32_t secondary_uuid[4] = SECONDARY_UUID;
Ruari Phippsd75596a2020-07-17 16:41:34 +010023static const uint32_t tertiary_uuid[4] = TERTIARY_UUID;
Max Shvetsovc32f4782020-06-23 09:41:15 +010024static const uint32_t null_uuid[4] = {0};
25
Max Shvetsov40eb6a22020-06-08 11:15:30 +010026struct feature_test {
27 const char *test_name;
28 unsigned int feature;
29 unsigned int expected_ret;
30};
31
32static const struct feature_test test_target[] = {
33 {"FFA_ERROR_32 check", FFA_ERROR, FFA_SUCCESS_SMC32},
34 {"FFA_SUCCESS_32 check", FFA_SUCCESS_SMC32, FFA_SUCCESS_SMC32},
35 {"FFA_INTERRUPT_32 check", FFA_INTERRUPT, FFA_SUCCESS_SMC32},
36 {"FFA_VERSION_32 check", FFA_VERSION, FFA_SUCCESS_SMC32},
37 {"FFA_FEATURES_32 check", FFA_FEATURES, FFA_SUCCESS_SMC32},
38 {"FFA_RX_RELEASE_32 check", FFA_RX_RELEASE, FFA_SUCCESS_SMC32},
39 {"FFA_RXTX_MAP_32 check", FFA_RXTX_MAP_SMC32, FFA_ERROR},
40 {"FFA_RXTX_MAP_64 check", FFA_RXTX_MAP_SMC64, FFA_SUCCESS_SMC32},
41 {"FFA_RXTX_UNMAP_32 check", FFA_RXTX_UNMAP, FFA_ERROR},
42 {"FFA_PARTITION_INFO_GET_32 check", FFA_PARTITION_INFO_GET, FFA_SUCCESS_SMC32},
43 {"FFA_ID_GET_32 check", FFA_ID_GET, FFA_SUCCESS_SMC32},
44 {"FFA_MSG_POLL_32 check", FFA_MSG_POLL, FFA_SUCCESS_SMC32},
45 {"FFA_MSG_WAIT_32 check", FFA_MSG_WAIT, FFA_SUCCESS_SMC32},
46 {"FFA_YIELD_32 check", FFA_MSG_YIELD, FFA_SUCCESS_SMC32},
47 {"FFA_RUN_32 check", FFA_MSG_RUN, FFA_SUCCESS_SMC32},
48 {"FFA_MSG_SEND_32 check", FFA_MSG_SEND, FFA_SUCCESS_SMC32},
49 {"FFA_MEM_DONATE_32 check", FFA_MEM_DONATE_SMC32, FFA_SUCCESS_SMC32},
50 {"FFA_MEM_LEND_32 check", FFA_MEM_LEND_SMC32, FFA_SUCCESS_SMC32},
51 {"FFA_MEM_SHARE_32 check", FFA_MEM_SHARE_SMC32, FFA_SUCCESS_SMC32},
52 {"FFA_MEM_RETRIEVE_REQ_32 check", FFA_MEM_RETRIEVE_REQ_SMC32, FFA_SUCCESS_SMC32},
53 {"FFA_MEM_RETRIEVE_RESP_32 check", FFA_MEM_RETRIEVE_RESP, FFA_SUCCESS_SMC32},
54 {"FFA_MEM_RELINQUISH_32 check", FFA_MEM_RELINQUISH, FFA_SUCCESS_SMC32},
55 {"FFA_MEM_RECLAIM_32 check", FFA_MEM_RECLAIM, FFA_SUCCESS_SMC32},
56 {"Check non-existent command", 0xFFFF, FFA_ERROR}
57};
58
59/*
60 * Test FFA_FEATURES interface.
61 */
62static void ffa_features_test(void)
63{
64 const char *test_features = "FFA Features interface";
65 smc_ret_values ffa_ret;
66 unsigned int i, test_target_size =
67 sizeof(test_target) / sizeof(struct feature_test);
68
69 announce_test_section_start(test_features);
70
71 for (i = 0U; i < test_target_size; i++) {
72 announce_test_start(test_target[i].test_name);
73
74 ffa_ret = ffa_features(test_target[i].feature);
75 expect(ffa_ret.ret0, test_target[i].expected_ret);
76 if (test_target[i].expected_ret == FFA_ERROR) {
77 expect(ffa_ret.ret2, FFA_ERROR_NOT_SUPPORTED);
78 }
79
80 announce_test_end(test_target[i].test_name);
81 }
82
83 announce_test_section_end(test_features);
84}
85
Max Shvetsovc32f4782020-06-23 09:41:15 +010086static void ffa_partition_info_helper(struct mailbox_buffers *mb, const uint32_t uuid[4],
87 const struct ffa_partition_info *expected,
88 const uint16_t expected_size)
89{
90 smc_ret_values ret = ffa_partition_info_get(uuid);
91 unsigned int i;
92 expect(ret.ret0, FFA_SUCCESS_SMC32);
93
94 struct ffa_partition_info *info = (struct ffa_partition_info *)(mb->recv);
95 for (i = 0U; i < expected_size; i++) {
96 expect(info[i].id, expected[i].id);
97 expect(info[i].exec_context, expected[i].exec_context);
98 expect(info[i].properties, expected[i].properties);
99 }
100
101 ret = ffa_rx_release();
102 expect(ret.ret0, FFA_SUCCESS_SMC32);
103}
104
105static void ffa_partition_info_wrong_test(void)
106{
107 const char *test_wrong_uuid = "Request wrong UUID";
108 uint32_t uuid[4] = {1};
109
110 announce_test_start(test_wrong_uuid);
111
112 smc_ret_values ret = ffa_partition_info_get(uuid);
113 expect(ret.ret0, FFA_ERROR);
114 expect(ret.ret2, FFA_ERROR_INVALID_PARAMETER);
115
116 announce_test_end(test_wrong_uuid);
117}
118
119static void ffa_partition_info_get_test(struct mailbox_buffers *mb)
120{
121 const char *test_partition_info = "FFA Partition info interface";
122 const char *test_primary = "Get primary partition info";
123 const char *test_secondary = "Get secondary partition info";
Ruari Phippsd75596a2020-07-17 16:41:34 +0100124 const char *test_tertiary = "Get tertiary partition info";
Max Shvetsovc32f4782020-06-23 09:41:15 +0100125 const char *test_all = "Get all partitions info";
126
127 const struct ffa_partition_info expected_info[] = {
Arunachalam Ganapathy51be1fe2020-09-22 13:25:21 +0100128 /* Primary partition info */
129 {
130 .id = SPM_VM_ID_FIRST,
131 .exec_context = CACTUS_PRIMARY_EC_COUNT,
Olivier Deprez6d274a42020-10-23 09:12:27 +0200132 /* Supports receipt of direct message requests. */
133 .properties = 1U
Arunachalam Ganapathy51be1fe2020-09-22 13:25:21 +0100134 },
135 /* Secondary partition info */
136 {
137 .id = SPM_VM_ID_FIRST + 1U,
138 .exec_context = CACTUS_SECONDARY_EC_COUNT,
Olivier Deprez6d274a42020-10-23 09:12:27 +0200139 .properties = 1U
Arunachalam Ganapathy51be1fe2020-09-22 13:25:21 +0100140 },
141 /* Tertiary partition info */
142 {
143 .id = SPM_VM_ID_FIRST + 2U,
144 .exec_context = CACTUS_TERTIARY_EC_COUNT,
Olivier Deprez6d274a42020-10-23 09:12:27 +0200145 .properties = 1U
Arunachalam Ganapathy51be1fe2020-09-22 13:25:21 +0100146 }
Max Shvetsovc32f4782020-06-23 09:41:15 +0100147 };
148
149 announce_test_section_start(test_partition_info);
150
Ruari Phippsd75596a2020-07-17 16:41:34 +0100151 announce_test_start(test_tertiary);
152 ffa_partition_info_helper(mb, tertiary_uuid, &expected_info[2], 1);
153 announce_test_end(test_tertiary);
154
Max Shvetsovc32f4782020-06-23 09:41:15 +0100155 announce_test_start(test_secondary);
156 ffa_partition_info_helper(mb, secondary_uuid, &expected_info[1], 1);
157 announce_test_end(test_secondary);
158
159 announce_test_start(test_primary);
160 ffa_partition_info_helper(mb, primary_uuid, &expected_info[0], 1);
161 announce_test_end(test_primary);
162
163 announce_test_start(test_all);
Ruari Phippsd75596a2020-07-17 16:41:34 +0100164 ffa_partition_info_helper(mb, null_uuid, expected_info, 3);
Max Shvetsovc32f4782020-06-23 09:41:15 +0100165 announce_test_end(test_all);
166
167 ffa_partition_info_wrong_test();
168
169 announce_test_section_end(test_partition_info);
170}
171
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100172void ffa_version_test(void)
J-Alves9f6f0142020-06-17 15:37:59 +0100173{
J-Alves9f6f0142020-06-17 15:37:59 +0100174 const char *test_ffa_version = "FFA Version interface";
175
J-Alves9f6f0142020-06-17 15:37:59 +0100176 announce_test_start(test_ffa_version);
177
178 smc_ret_values ret = ffa_version(MAKE_FFA_VERSION(FFA_MAJOR, FFA_MINOR));
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100179 uint32_t spm_version = (uint32_t)ret.ret0;
J-Alves9f6f0142020-06-17 15:37:59 +0100180
Max Shvetsov40eb6a22020-06-08 11:15:30 +0100181 bool ffa_version_compatible =
182 ((spm_version >> FFA_VERSION_MAJOR_SHIFT) == FFA_MAJOR &&
183 (spm_version & FFA_VERSION_MINOR_MASK) >= FFA_MINOR);
J-Alves9f6f0142020-06-17 15:37:59 +0100184
185 NOTICE("FFA_VERSION returned %u.%u; Compatible: %i\n",
186 spm_version >> FFA_VERSION_MAJOR_SHIFT,
187 spm_version & FFA_VERSION_MINOR_MASK,
188 (int)ffa_version_compatible);
189
190 expect((int)ffa_version_compatible, (int)true);
191
192 announce_test_end(test_ffa_version);
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100193}
194
J-Alves63cdaa72020-10-08 17:22:45 +0100195bool ffa_memory_retrieve_test(struct mailbox_buffers *mb,
196 struct ffa_memory_region *retrieved,
197 uint64_t handle, ffa_vm_id_t sender,
198 ffa_vm_id_t receiver, uint32_t mem_func)
199{
200 smc_ret_values ret;
201 uint32_t fragment_size;
202 uint32_t total_size;
203 uint32_t descriptor_size;
204
205 if (retrieved == NULL || mb == NULL) {
206 ERROR("Invalid parameters!\n");
207 return false;
208 }
209
210
211 /*
212 * TODO: Revise shareability attribute in function call
213 * below.
214 * https://lists.trustedfirmware.org/pipermail/hafnium/2020-June/000023.html
215 */
216 descriptor_size = ffa_memory_retrieve_request_init(
217 mb->send, handle, sender, receiver, 0, 0,
218 FFA_DATA_ACCESS_RW,
219 FFA_INSTRUCTION_ACCESS_NX,
220 FFA_MEMORY_NORMAL_MEM,
221 FFA_MEMORY_CACHE_WRITE_BACK,
222 FFA_MEMORY_OUTER_SHAREABLE);
223
224 ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
225
226 if (ret.ret0 != FFA_MEM_RETRIEVE_RESP) {
227 ERROR("Couldn't retrieve the memory page!\n");
228 return false;
229 }
230
231 /*
232 * Following total_size and fragment_size are useful to keep track
233 * of the state of transaction. When the sum of all fragment_size of all
234 * fragments is equal to total_size, the memory transaction has been
235 * completed.
236 * This is a simple test with only one segment. As such, upon
237 * successful ffa_mem_retrieve_req, total_size must be equal to
238 * fragment_size.
239 */
240 total_size = ret.ret1;
241 fragment_size = ret.ret2;
242
243 if (total_size != fragment_size) {
244 ERROR("Only expect one memory segment to be sent!\n");
245 return false;
246 }
247
248 if (fragment_size > PAGE_SIZE) {
249 ERROR("Fragment should be smaller than RX buffer!\n");
250 return false;
251 }
252
253 memcpy((void *)retrieved, mb->recv, fragment_size);
254
255 if (ffa_rx_release().ret0 != FFA_SUCCESS_SMC32) {
256 ERROR("Failed to release Rx buffer!\n");
257 return false;
258 }
259
260 if (retrieved->receiver_count != 1) {
261 VERBOSE("This memory has been shared with multiple"
262 " receivers!\n");
263 }
264
265 NOTICE("Memory Retrieved!\n");
266
267 return true;
268}
269
270bool ffa_memory_relinquish_test(struct ffa_mem_relinquish *m,
271 uint64_t handle,
272 ffa_vm_id_t id)
273{
274 ffa_mem_relinquish_init(m, handle, 0, id);
275
276 if (ffa_mem_relinquish().ret0 != FFA_SUCCESS_SMC32) {
277 ERROR("%s failed to relinquish memory!\n", __func__);
278 return false;
279 }
280
281 NOTICE("Memory Relinquished!\n");
282 return true;
283}
284
285void ffa_memory_management_test(struct mailbox_buffers *mb, ffa_vm_id_t vm_id,
286 ffa_vm_id_t sender, uint32_t mem_func,
287 uint64_t handle)
288{
289 const char *test_ffa = "Memory Management";
290 struct ffa_memory_region m;
291 struct ffa_composite_memory_region *composite;
292 int ret;
293 unsigned int mem_attrs;
294 uint32_t *ptr;
295
296 announce_test_section_start(test_ffa);
297
298 expect(ffa_memory_retrieve_test(
299 mb, &m, handle, sender, vm_id, mem_func),
300 true);
301
302 composite = ffa_memory_region_get_composite(&m, 0);
303
304 NOTICE("Address: %p; page_count: %x %x\n",
305 composite->constituents[0].address,
306 composite->constituents[0].page_count, PAGE_SIZE);
307
308 /* This test is only concerned with RW permissions. */
309 expect(ffa_get_data_access_attr(
310 m.receivers[0].receiver_permissions.permissions),
311 FFA_DATA_ACCESS_RW);
312
313 mem_attrs = MT_RW_DATA | MT_NS | MT_EXECUTE_NEVER;
314
315 ret = mmap_add_dynamic_region(
316 (uint64_t)composite->constituents[0].address,
317 (uint64_t)composite->constituents[0].address,
318 composite->constituents[0].page_count * PAGE_SIZE,
319 mem_attrs);
320 expect(ret, 0);
321
322 VERBOSE("Memory has been mapped\n");
323
324 ptr = (uint32_t *) composite->constituents[0].address;
325
326 /* Write mem_func to retrieved memory region for validation purposes. */
327 VERBOSE("Writing: %x\n", mem_func);
328 for (unsigned int i = 0U; i < 5U; i++)
329 ptr[i] = mem_func;
330
331 /*
332 * A FFA_MEM_DONATE changes the ownership of the page, as such no
333 * relinquish is needed.
334 */
335 if (mem_func != FFA_MEM_DONATE_SMC32) {
336 ret = mmap_remove_dynamic_region(
337 (uint64_t)composite->constituents[0].address,
338 composite->constituents[0].page_count * PAGE_SIZE);
339 expect(ret, 0);
340
341 expect(ffa_memory_relinquish_test(
342 (struct ffa_mem_relinquish *)mb->send,
343 m.handle, vm_id),
344 true);
345 }
346
347 announce_test_section_end(test_ffa);
348}
349
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100350void ffa_tests(struct mailbox_buffers *mb)
351{
352 const char *test_ffa = "FFA Interfaces";
353
354 announce_test_section_start(test_ffa);
J-Alves9f6f0142020-06-17 15:37:59 +0100355
Max Shvetsov40eb6a22020-06-08 11:15:30 +0100356 ffa_features_test();
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100357 ffa_version_test();
Max Shvetsovc32f4782020-06-23 09:41:15 +0100358 ffa_partition_info_get_test(mb);
Max Shvetsov40eb6a22020-06-08 11:15:30 +0100359
J-Alves9f6f0142020-06-17 15:37:59 +0100360 announce_test_section_end(test_ffa);
361}