blob: 2ef08e1a3f7b590d322e2a4fb3abb4599be1d4c1 [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-Alves8f4a56f2020-10-28 10:29:05 +000011#include <ffa_endpoints.h>
J-Alves5aecd982020-06-11 10:25:33 +010012#include <ffa_helpers.h>
J-Alves9f6f0142020-06-17 15:37:59 +010013#include <sp_helpers.h>
14
J-Alves63cdaa72020-10-08 17:22:45 +010015#include <lib/libc/string.h>
16#include <lib/xlat_tables/xlat_tables_v2.h>
17
J-Alves9f6f0142020-06-17 15:37:59 +010018/* FFA version test helpers */
19#define FFA_MAJOR 1U
20#define FFA_MINOR 0U
21
Max Shvetsovc32f4782020-06-23 09:41:15 +010022static const uint32_t primary_uuid[4] = PRIMARY_UUID;
23static const uint32_t secondary_uuid[4] = SECONDARY_UUID;
Ruari Phippsd75596a2020-07-17 16:41:34 +010024static const uint32_t tertiary_uuid[4] = TERTIARY_UUID;
Max Shvetsovc32f4782020-06-23 09:41:15 +010025static const uint32_t null_uuid[4] = {0};
26
Max Shvetsov40eb6a22020-06-08 11:15:30 +010027struct feature_test {
28 const char *test_name;
29 unsigned int feature;
30 unsigned int expected_ret;
31};
32
33static const struct feature_test test_target[] = {
34 {"FFA_ERROR_32 check", FFA_ERROR, FFA_SUCCESS_SMC32},
35 {"FFA_SUCCESS_32 check", FFA_SUCCESS_SMC32, FFA_SUCCESS_SMC32},
36 {"FFA_INTERRUPT_32 check", FFA_INTERRUPT, FFA_SUCCESS_SMC32},
37 {"FFA_VERSION_32 check", FFA_VERSION, FFA_SUCCESS_SMC32},
38 {"FFA_FEATURES_32 check", FFA_FEATURES, FFA_SUCCESS_SMC32},
39 {"FFA_RX_RELEASE_32 check", FFA_RX_RELEASE, FFA_SUCCESS_SMC32},
40 {"FFA_RXTX_MAP_32 check", FFA_RXTX_MAP_SMC32, FFA_ERROR},
41 {"FFA_RXTX_MAP_64 check", FFA_RXTX_MAP_SMC64, FFA_SUCCESS_SMC32},
42 {"FFA_RXTX_UNMAP_32 check", FFA_RXTX_UNMAP, FFA_ERROR},
43 {"FFA_PARTITION_INFO_GET_32 check", FFA_PARTITION_INFO_GET, FFA_SUCCESS_SMC32},
44 {"FFA_ID_GET_32 check", FFA_ID_GET, FFA_SUCCESS_SMC32},
45 {"FFA_MSG_POLL_32 check", FFA_MSG_POLL, FFA_SUCCESS_SMC32},
46 {"FFA_MSG_WAIT_32 check", FFA_MSG_WAIT, FFA_SUCCESS_SMC32},
47 {"FFA_YIELD_32 check", FFA_MSG_YIELD, FFA_SUCCESS_SMC32},
48 {"FFA_RUN_32 check", FFA_MSG_RUN, FFA_SUCCESS_SMC32},
49 {"FFA_MSG_SEND_32 check", FFA_MSG_SEND, FFA_SUCCESS_SMC32},
50 {"FFA_MEM_DONATE_32 check", FFA_MEM_DONATE_SMC32, FFA_SUCCESS_SMC32},
51 {"FFA_MEM_LEND_32 check", FFA_MEM_LEND_SMC32, FFA_SUCCESS_SMC32},
52 {"FFA_MEM_SHARE_32 check", FFA_MEM_SHARE_SMC32, FFA_SUCCESS_SMC32},
53 {"FFA_MEM_RETRIEVE_REQ_32 check", FFA_MEM_RETRIEVE_REQ_SMC32, FFA_SUCCESS_SMC32},
54 {"FFA_MEM_RETRIEVE_RESP_32 check", FFA_MEM_RETRIEVE_RESP, FFA_SUCCESS_SMC32},
55 {"FFA_MEM_RELINQUISH_32 check", FFA_MEM_RELINQUISH, FFA_SUCCESS_SMC32},
56 {"FFA_MEM_RECLAIM_32 check", FFA_MEM_RECLAIM, FFA_SUCCESS_SMC32},
57 {"Check non-existent command", 0xFFFF, FFA_ERROR}
58};
59
60/*
61 * Test FFA_FEATURES interface.
62 */
63static void ffa_features_test(void)
64{
65 const char *test_features = "FFA Features interface";
66 smc_ret_values ffa_ret;
67 unsigned int i, test_target_size =
68 sizeof(test_target) / sizeof(struct feature_test);
69
70 announce_test_section_start(test_features);
71
72 for (i = 0U; i < test_target_size; i++) {
73 announce_test_start(test_target[i].test_name);
74
75 ffa_ret = ffa_features(test_target[i].feature);
76 expect(ffa_ret.ret0, test_target[i].expected_ret);
77 if (test_target[i].expected_ret == FFA_ERROR) {
78 expect(ffa_ret.ret2, FFA_ERROR_NOT_SUPPORTED);
79 }
80
81 announce_test_end(test_target[i].test_name);
82 }
83
84 announce_test_section_end(test_features);
85}
86
Max Shvetsovc32f4782020-06-23 09:41:15 +010087static void ffa_partition_info_helper(struct mailbox_buffers *mb, const uint32_t uuid[4],
88 const struct ffa_partition_info *expected,
89 const uint16_t expected_size)
90{
91 smc_ret_values ret = ffa_partition_info_get(uuid);
92 unsigned int i;
93 expect(ret.ret0, FFA_SUCCESS_SMC32);
94
95 struct ffa_partition_info *info = (struct ffa_partition_info *)(mb->recv);
96 for (i = 0U; i < expected_size; i++) {
97 expect(info[i].id, expected[i].id);
98 expect(info[i].exec_context, expected[i].exec_context);
99 expect(info[i].properties, expected[i].properties);
100 }
101
102 ret = ffa_rx_release();
103 expect(ret.ret0, FFA_SUCCESS_SMC32);
104}
105
106static void ffa_partition_info_wrong_test(void)
107{
108 const char *test_wrong_uuid = "Request wrong UUID";
109 uint32_t uuid[4] = {1};
110
111 announce_test_start(test_wrong_uuid);
112
113 smc_ret_values ret = ffa_partition_info_get(uuid);
114 expect(ret.ret0, FFA_ERROR);
115 expect(ret.ret2, FFA_ERROR_INVALID_PARAMETER);
116
117 announce_test_end(test_wrong_uuid);
118}
119
120static void ffa_partition_info_get_test(struct mailbox_buffers *mb)
121{
122 const char *test_partition_info = "FFA Partition info interface";
123 const char *test_primary = "Get primary partition info";
124 const char *test_secondary = "Get secondary partition info";
Ruari Phippsd75596a2020-07-17 16:41:34 +0100125 const char *test_tertiary = "Get tertiary partition info";
Max Shvetsovc32f4782020-06-23 09:41:15 +0100126 const char *test_all = "Get all partitions info";
127
128 const struct ffa_partition_info expected_info[] = {
Arunachalam Ganapathy51be1fe2020-09-22 13:25:21 +0100129 /* Primary partition info */
130 {
131 .id = SPM_VM_ID_FIRST,
132 .exec_context = CACTUS_PRIMARY_EC_COUNT,
Olivier Deprez6d274a42020-10-23 09:12:27 +0200133 /* Supports receipt of direct message requests. */
134 .properties = 1U
Arunachalam Ganapathy51be1fe2020-09-22 13:25:21 +0100135 },
136 /* Secondary partition info */
137 {
138 .id = SPM_VM_ID_FIRST + 1U,
139 .exec_context = CACTUS_SECONDARY_EC_COUNT,
Olivier Deprez6d274a42020-10-23 09:12:27 +0200140 .properties = 1U
Arunachalam Ganapathy51be1fe2020-09-22 13:25:21 +0100141 },
142 /* Tertiary partition info */
143 {
144 .id = SPM_VM_ID_FIRST + 2U,
145 .exec_context = CACTUS_TERTIARY_EC_COUNT,
Olivier Deprez6d274a42020-10-23 09:12:27 +0200146 .properties = 1U
Arunachalam Ganapathy51be1fe2020-09-22 13:25:21 +0100147 }
Max Shvetsovc32f4782020-06-23 09:41:15 +0100148 };
149
150 announce_test_section_start(test_partition_info);
151
Ruari Phippsd75596a2020-07-17 16:41:34 +0100152 announce_test_start(test_tertiary);
153 ffa_partition_info_helper(mb, tertiary_uuid, &expected_info[2], 1);
154 announce_test_end(test_tertiary);
155
Max Shvetsovc32f4782020-06-23 09:41:15 +0100156 announce_test_start(test_secondary);
157 ffa_partition_info_helper(mb, secondary_uuid, &expected_info[1], 1);
158 announce_test_end(test_secondary);
159
160 announce_test_start(test_primary);
161 ffa_partition_info_helper(mb, primary_uuid, &expected_info[0], 1);
162 announce_test_end(test_primary);
163
164 announce_test_start(test_all);
Ruari Phippsd75596a2020-07-17 16:41:34 +0100165 ffa_partition_info_helper(mb, null_uuid, expected_info, 3);
Max Shvetsovc32f4782020-06-23 09:41:15 +0100166 announce_test_end(test_all);
167
168 ffa_partition_info_wrong_test();
169
170 announce_test_section_end(test_partition_info);
171}
172
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100173void ffa_version_test(void)
J-Alves9f6f0142020-06-17 15:37:59 +0100174{
J-Alves9f6f0142020-06-17 15:37:59 +0100175 const char *test_ffa_version = "FFA Version interface";
176
J-Alves9f6f0142020-06-17 15:37:59 +0100177 announce_test_start(test_ffa_version);
178
179 smc_ret_values ret = ffa_version(MAKE_FFA_VERSION(FFA_MAJOR, FFA_MINOR));
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100180 uint32_t spm_version = (uint32_t)ret.ret0;
J-Alves9f6f0142020-06-17 15:37:59 +0100181
Max Shvetsov40eb6a22020-06-08 11:15:30 +0100182 bool ffa_version_compatible =
183 ((spm_version >> FFA_VERSION_MAJOR_SHIFT) == FFA_MAJOR &&
184 (spm_version & FFA_VERSION_MINOR_MASK) >= FFA_MINOR);
J-Alves9f6f0142020-06-17 15:37:59 +0100185
186 NOTICE("FFA_VERSION returned %u.%u; Compatible: %i\n",
187 spm_version >> FFA_VERSION_MAJOR_SHIFT,
188 spm_version & FFA_VERSION_MINOR_MASK,
189 (int)ffa_version_compatible);
190
191 expect((int)ffa_version_compatible, (int)true);
192
193 announce_test_end(test_ffa_version);
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100194}
195
J-Alves63cdaa72020-10-08 17:22:45 +0100196bool ffa_memory_retrieve_test(struct mailbox_buffers *mb,
J-Alves0435cae2020-11-06 10:49:56 +0000197 struct ffa_memory_region **retrieved,
J-Alves63cdaa72020-10-08 17:22:45 +0100198 uint64_t handle, ffa_vm_id_t sender,
199 ffa_vm_id_t receiver, uint32_t mem_func)
200{
201 smc_ret_values ret;
202 uint32_t fragment_size;
203 uint32_t total_size;
204 uint32_t descriptor_size;
205
206 if (retrieved == NULL || mb == NULL) {
207 ERROR("Invalid parameters!\n");
208 return false;
209 }
210
J-Alves63cdaa72020-10-08 17:22:45 +0100211 /*
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(
J-Alves0435cae2020-11-06 10:49:56 +0000217 mb->send, handle, sender, receiver, 0, 0,
J-Alves63cdaa72020-10-08 17:22:45 +0100218 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) {
J-Alves0435cae2020-11-06 10:49:56 +0000227 ERROR("Couldn't retrieve the memory page. Error: %lx\n",
228 ret.ret2);
J-Alves63cdaa72020-10-08 17:22:45 +0100229 return false;
230 }
231
232 /*
233 * Following total_size and fragment_size are useful to keep track
234 * of the state of transaction. When the sum of all fragment_size of all
235 * fragments is equal to total_size, the memory transaction has been
236 * completed.
237 * This is a simple test with only one segment. As such, upon
238 * successful ffa_mem_retrieve_req, total_size must be equal to
239 * fragment_size.
240 */
241 total_size = ret.ret1;
242 fragment_size = ret.ret2;
243
244 if (total_size != fragment_size) {
245 ERROR("Only expect one memory segment to be sent!\n");
246 return false;
247 }
248
249 if (fragment_size > PAGE_SIZE) {
250 ERROR("Fragment should be smaller than RX buffer!\n");
251 return false;
252 }
253
J-Alves0435cae2020-11-06 10:49:56 +0000254 *retrieved = (struct ffa_memory_region *)mb->recv;
J-Alves63cdaa72020-10-08 17:22:45 +0100255
J-Alves0435cae2020-11-06 10:49:56 +0000256 if ((*retrieved)->receiver_count > MAX_MEM_SHARE_RECIPIENTS) {
257 VERBOSE("SPMC memory sharing operations support max of %u "
258 "receivers!\n", MAX_MEM_SHARE_RECIPIENTS);
J-Alves63cdaa72020-10-08 17:22:45 +0100259 return false;
260 }
261
J-Alves63cdaa72020-10-08 17:22:45 +0100262 NOTICE("Memory Retrieved!\n");
263
264 return true;
265}
266
267bool ffa_memory_relinquish_test(struct ffa_mem_relinquish *m,
268 uint64_t handle,
269 ffa_vm_id_t id)
270{
271 ffa_mem_relinquish_init(m, handle, 0, id);
272
273 if (ffa_mem_relinquish().ret0 != FFA_SUCCESS_SMC32) {
274 ERROR("%s failed to relinquish memory!\n", __func__);
275 return false;
276 }
277
278 NOTICE("Memory Relinquished!\n");
279 return true;
280}
281
282void ffa_memory_management_test(struct mailbox_buffers *mb, ffa_vm_id_t vm_id,
283 ffa_vm_id_t sender, uint32_t mem_func,
284 uint64_t handle)
285{
286 const char *test_ffa = "Memory Management";
J-Alves0435cae2020-11-06 10:49:56 +0000287 struct ffa_memory_region *m;
J-Alves63cdaa72020-10-08 17:22:45 +0100288 struct ffa_composite_memory_region *composite;
289 int ret;
290 unsigned int mem_attrs;
291 uint32_t *ptr;
292
293 announce_test_section_start(test_ffa);
294
295 expect(ffa_memory_retrieve_test(
296 mb, &m, handle, sender, vm_id, mem_func),
297 true);
298
J-Alves0435cae2020-11-06 10:49:56 +0000299 composite = ffa_memory_region_get_composite(m, 0);
J-Alves63cdaa72020-10-08 17:22:45 +0100300
301 NOTICE("Address: %p; page_count: %x %x\n",
302 composite->constituents[0].address,
303 composite->constituents[0].page_count, PAGE_SIZE);
304
305 /* This test is only concerned with RW permissions. */
306 expect(ffa_get_data_access_attr(
J-Alves0435cae2020-11-06 10:49:56 +0000307 m->receivers[0].receiver_permissions.permissions),
J-Alves63cdaa72020-10-08 17:22:45 +0100308 FFA_DATA_ACCESS_RW);
309
310 mem_attrs = MT_RW_DATA | MT_NS | MT_EXECUTE_NEVER;
311
312 ret = mmap_add_dynamic_region(
313 (uint64_t)composite->constituents[0].address,
314 (uint64_t)composite->constituents[0].address,
315 composite->constituents[0].page_count * PAGE_SIZE,
316 mem_attrs);
317 expect(ret, 0);
318
319 VERBOSE("Memory has been mapped\n");
320
321 ptr = (uint32_t *) composite->constituents[0].address;
322
323 /* Write mem_func to retrieved memory region for validation purposes. */
324 VERBOSE("Writing: %x\n", mem_func);
325 for (unsigned int i = 0U; i < 5U; i++)
326 ptr[i] = mem_func;
327
328 /*
329 * A FFA_MEM_DONATE changes the ownership of the page, as such no
330 * relinquish is needed.
331 */
332 if (mem_func != FFA_MEM_DONATE_SMC32) {
333 ret = mmap_remove_dynamic_region(
334 (uint64_t)composite->constituents[0].address,
335 composite->constituents[0].page_count * PAGE_SIZE);
336 expect(ret, 0);
337
338 expect(ffa_memory_relinquish_test(
339 (struct ffa_mem_relinquish *)mb->send,
J-Alves0435cae2020-11-06 10:49:56 +0000340 m->handle, vm_id),
J-Alves63cdaa72020-10-08 17:22:45 +0100341 true);
342 }
343
J-Alves0435cae2020-11-06 10:49:56 +0000344 expect(ffa_rx_release().ret0, FFA_SUCCESS_SMC32);
345
J-Alves63cdaa72020-10-08 17:22:45 +0100346 announce_test_section_end(test_ffa);
347}
348
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100349void ffa_tests(struct mailbox_buffers *mb)
350{
351 const char *test_ffa = "FFA Interfaces";
352
353 announce_test_section_start(test_ffa);
J-Alves9f6f0142020-06-17 15:37:59 +0100354
Max Shvetsov40eb6a22020-06-08 11:15:30 +0100355 ffa_features_test();
Max Shvetsov57c6ddb2020-07-01 14:09:48 +0100356 ffa_version_test();
Max Shvetsovc32f4782020-06-23 09:41:15 +0100357 ffa_partition_info_get_test(mb);
Max Shvetsov40eb6a22020-06-08 11:15:30 +0100358
J-Alves9f6f0142020-06-17 15:37:59 +0100359 announce_test_section_end(test_ffa);
360}