blob: 0248adcd43774950e11b83f089c6811be7ac88f7 [file] [log] [blame]
jaypit02ea3cd062018-10-05 12:22:38 +05301/** @file
2 * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved.
3 * SPDX-License-Identifier : Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16**/
17
18#include "val_framework.h"
19#include "val_interfaces.h"
20#include "val_dispatcher.h"
21#include "val_peripherals.h"
22#include "pal_interfaces_ns.h"
23#include "val_target.h"
24
25extern val_api_t val_api;
26extern psa_api_t psa_api;
27
28/* globals */
29test_status_buffer_t g_status_buffer;
30
31/**
32 * @brief Connect to given sid
33 @param -sid : RoT service id
34 @param -minor_version : minor_version of RoT service
35 @param -handle - return connection handle
36 * @return val_status_t
37 */
38val_status_t val_ipc_connect(uint32_t sid, uint32_t minor_version, psa_handle_t *handle )
39{
jaypit02ac23b5b2018-11-02 13:10:19 +053040 *handle = pal_ipc_connect(sid, minor_version);
jaypit02ea3cd062018-10-05 12:22:38 +053041
42 if (*handle < 0)
43 {
44 return VAL_STATUS_CONNECTION_FAILED;
45 }
46
47 return VAL_STATUS_SUCCESS;
48}
49
50/**
51 * @brief Call a connected Root of Trust Service.@n
52 * The caller must provide an array of ::psa_invec_t structures as the input payload.
53 *
54 * @param handle Handle for the connection.
55 * @param in_vec Array of psa_invec structures.
56 * @param in_len Number of psa_invec structures in in_vec.
57 * @param out_vec Array of psa_outvec structures for optional Root of Trust Service response.
58 * @param out_len Number of psa_outvec structures in out_vec.
59 * @return val_status_t
60 */
61val_status_t val_ipc_call(psa_handle_t handle, psa_invec *in_vec, size_t in_len,
62 psa_outvec *out_vec, size_t out_len)
63{
64 psa_status_t call_status = PSA_SUCCESS;
65
jaypit02ac23b5b2018-11-02 13:10:19 +053066 call_status = pal_ipc_call(handle, in_vec, in_len, out_vec, out_len);
jaypit02ea3cd062018-10-05 12:22:38 +053067
68 if (call_status != PSA_SUCCESS)
69 {
70 return VAL_STATUS_CALL_FAILED;
71 }
72
73 return VAL_STATUS_SUCCESS;
74}
75
76/**
77 * @brief Close a connection to a Root of Trust Service.
78 * Sends the PSA_IPC_DISCONNECT message to the Root of Trust Service so it can clean up resources.
79 *
80 * @param handle Handle for the connection.
81 * @return void
82 */
83void val_ipc_close(psa_handle_t handle)
84{
jaypit02ac23b5b2018-11-02 13:10:19 +053085 pal_ipc_close(handle);
jaypit02ea3cd062018-10-05 12:22:38 +053086}
87/**
88 @brief - This function executes given list of tests from non-secure sequentially
89 This covers non-secure to secure IPC API scenario
90 @param - test_num : Test_num
91 @param - tests_list : list of tests to be executed
92 @param - server_hs : Initiate a server handshake
93 @return - val_status_t
94**/
95val_status_t val_execute_non_secure_tests(uint32_t test_num, client_test_t *tests_list,
96 bool_t server_hs)
97{
98 val_status_t status = VAL_STATUS_SUCCESS;
99 val_status_t test_status = VAL_STATUS_SUCCESS;
100 boot_t boot;
101 psa_handle_t handle;
102 uint32_t i = 1;
103 test_info_t test_info;
104
105 test_info.test_num = test_num;
106
107 status = val_get_boot_flag(&boot.state);
108 if (VAL_ERROR(status))
109 {
110 val_set_status(RESULT_FAIL(status));
111 return status;
112 }
113
114 if (boot.state == BOOT_NOT_EXPECTED || boot.state == BOOT_EXPECTED_CRYPTO)
115 {
116 val_print(PRINT_TEST,"[Info] Executing tests form non-secure\n", 0);
117 while (tests_list[i] != NULL)
118 {
119 if (server_hs == TRUE)
120 {
121 /* Handshake with server tests */
122 test_info.block_num = i;
123 status = val_execute_secure_test_func(&handle, test_info,
124 SERVER_TEST_DISPATCHER_SID);
125 if (VAL_ERROR(status))
126 {
127 val_set_status(RESULT_FAIL(status));
128 val_print(PRINT_ERROR,"[Check%d] START\n", i);
129 return status;
130 }
131 else
132 {
133 val_print(PRINT_DEBUG,"[Check%d] START\n", i);
134 }
135 }
136
137 /* Execute client tests */
138 test_status = tests_list[i](NONSECURE);
139
140 if (server_hs == TRUE)
141 {
142 /* Retrive Server test status */
143 status = val_get_secure_test_result(&handle);
144 }
145
146 status = test_status ? test_status:status;
147 if (VAL_ERROR(status))
148 {
149 val_set_status(RESULT_FAIL(status));
jaypit02ac23b5b2018-11-02 13:10:19 +0530150 if (server_hs == TRUE)
jaypit02ea3cd062018-10-05 12:22:38 +0530151 val_print(PRINT_ERROR,"[Check%d] FAILED\n", i);
152 return status;
153 }
154 else
155 {
jaypit02ac23b5b2018-11-02 13:10:19 +0530156 if (server_hs == TRUE)
jaypit02ea3cd062018-10-05 12:22:38 +0530157 val_print(PRINT_DEBUG,"[Check%d] PASSED\n", i);
158 }
159 i++;
160 }
161 }
162 else
163 {
164 /* If we are here means, we are in second run of this test */
165 status = VAL_STATUS_SUCCESS;
166 if (boot.state != BOOT_EXPECTED_S)
167 {
168 val_print(PRINT_DEBUG,"[Check1] PASSED\n", 0);
169 }
170 }
171 return status;
172}
173/**
174 @brief - This function is used to switch to client_partition.c
175 where client tests will be executed to cover secure to secure
176 IPC scenario.
177 @param - test_num : Test_num
178 @return - val_status_t
179**/
180val_status_t val_switch_to_secure_client(uint32_t test_num)
181{
182 val_status_t status = VAL_STATUS_SUCCESS;
183 boot_t boot;
184 psa_handle_t handle;
185 test_info_t test_info;
186
187 test_info.test_num = test_num;
188 test_info.block_num = 1;
189
190 status = val_get_boot_flag(&boot.state);
191 if (VAL_ERROR(status))
192 {
193 goto exit;
194 }
195
196 if (boot.state != BOOT_EXPECTED_S)
197 {
198 status = val_set_boot_flag(BOOT_NOT_EXPECTED);
199 if (VAL_ERROR(status))
200 {
201 goto exit;
202 }
203
204 /* switch to secure client */
205 status = val_execute_secure_test_func(&handle, test_info, CLIENT_TEST_DISPATCHER_SID);
206 if (VAL_ERROR(status))
207 {
208 goto exit;
209 }
210
211 /* Retrive secure client test status */
212 status = val_get_secure_test_result(&handle);
213 if (VAL_ERROR(status))
214 {
215 goto exit;
216 }
217 return status;
218 }
219 else
220 {
221 /* If we are here means, we are in third run of this test */
222 val_print(PRINT_DEBUG,"[Check1] PASSED\n", 0);
223 return VAL_STATUS_SUCCESS;
224 }
225
226exit:
227 val_set_status(RESULT_FAIL(status));
228 return status;
229}
230
231/**
232 @brief - This function is used to handshake between:
233 - nonsecure client fn to server test fn
234 - secure client fn and server test fn
235 - nonsecure client fn to secure client test fn
236 @param - handle : handle returned while connecting given sid
237 @param - test_info : Test_num and block_num to be executed
238 @param - sid : RoT service to be connected. Partition dispatcher sid
239 @return - val_status_t
240**/
241val_status_t val_execute_secure_test_func(psa_handle_t *handle, test_info_t test_info, uint32_t sid)
242{
243 uint32_t test_data;
244 val_status_t status = VAL_STATUS_SUCCESS;
245 psa_status_t status_of_call = PSA_SUCCESS;
246
jaypit02ac23b5b2018-11-02 13:10:19 +0530247 *handle = pal_ipc_connect(sid, 0);
jaypit02ea3cd062018-10-05 12:22:38 +0530248
249 if (*handle < 0)
250 {
251 val_print(PRINT_ERROR, "Could not connect SID. Handle=%x\n", *handle);
252 return VAL_STATUS_CONNECTION_FAILED;
253 }
254
255 test_data = ((uint32_t)(test_info.test_num) |((uint32_t)(test_info.block_num) << BLOCK_NUM_POS)
256 | ((uint32_t)(TEST_EXECUTE_FUNC) << ACTION_POS));
257 psa_invec data[1] = {{&test_data, sizeof(test_data)}};
258
jaypit02ac23b5b2018-11-02 13:10:19 +0530259 status_of_call = pal_ipc_call(*handle, data, 1, NULL, 0);
jaypit02ea3cd062018-10-05 12:22:38 +0530260
261 if (status_of_call != PSA_SUCCESS)
262 {
263 status = VAL_STATUS_CALL_FAILED;
264 val_print(PRINT_ERROR, "Call to dispatch SF failed. Status=%x\n", status_of_call);
jaypit02ac23b5b2018-11-02 13:10:19 +0530265 pal_ipc_close(*handle);
jaypit02ea3cd062018-10-05 12:22:38 +0530266 }
267 return status;
268}
269
270/**
271 @brief - This function is used to retrive the status of previously connected test function
272 using val_execute_secure_test_func
273 @param - handle : handle of server function. Handle of Partition dispatcher sid
274 @return - The status of test functions
275**/
276val_status_t val_get_secure_test_result(psa_handle_t *handle)
277{
278 uint32_t test_data;
279 val_status_t status = VAL_STATUS_SUCCESS;
280 psa_status_t status_of_call = PSA_SUCCESS;
281
282 test_data = (TEST_RETURN_RESULT << ACTION_POS);
283
284 psa_outvec resp = {&status, sizeof(status)};
285 psa_invec data[1] = {{&test_data, sizeof(test_data)}};
286
jaypit02ac23b5b2018-11-02 13:10:19 +0530287 status_of_call = pal_ipc_call(*handle, data, 1, &resp, 1);
jaypit02ea3cd062018-10-05 12:22:38 +0530288 if (status_of_call != PSA_SUCCESS)
289 {
290 status = VAL_STATUS_CALL_FAILED;
291 val_print(PRINT_ERROR, "Call to dispatch SF failed. Status=%x\n", status_of_call);
292 }
293
jaypit02ac23b5b2018-11-02 13:10:19 +0530294 pal_ipc_close(*handle);
jaypit02ea3cd062018-10-05 12:22:38 +0530295 return status;
296}
297
298
299/**
300 @brief - Parses input status for a given test and
301 outputs appropriate information on the console
302 @return - Test state
303**/
304uint32_t val_report_status(void)
305{
306 uint32_t status, state;
307
308 status = val_get_status();
309
310 state = (status >> TEST_STATE_BIT) & TEST_STATE_MASK;
311 status = status & TEST_STATUS_MASK;
312
313 switch (state)
314 {
315 case TEST_START:
316 state = TEST_FAIL;
317 val_print(PRINT_ALWAYS, "TEST RESULT: FAILED (Error Code=0x%x)\n",
318 VAL_STATUS_INIT_FAILED);
319 break;
320
321 case TEST_END:
322 state = TEST_PASS;
323 val_print(PRINT_ALWAYS, "TEST RESULT: PASSED \n", 0);
324 break;
325
326 case TEST_FAIL:
327 val_print(PRINT_ALWAYS, "TEST RESULT: FAILED (Error Code=0x%x) \n", status);
328 break;
329
330 case TEST_SKIP:
331 val_print(PRINT_ALWAYS, "TEST RESULT: SKIPPED (Skip Code=0x%x)\n", status);
332 break;
333
334 case TEST_PENDING:
335 val_print(PRINT_ALWAYS, "TEST RESULT: SIM ERROR (Error Code=0x%x)\n", status);
336 break;
337
338 default:
339 state = TEST_FAIL;
340 val_print(PRINT_ALWAYS, "TEST RESULT: FAILED(Error Code=0x%x)\n", VAL_STATUS_INVALID);
341 break;
342
343 }
344
345 val_print(PRINT_ALWAYS, "\n******************************************\n", 0);
346 return state;
347}
348
349/**
350 @brief - Records the state and status of test
351 @return - val_status_t
352**/
353val_status_t val_set_status(uint32_t status)
354{
355 g_status_buffer.state = ((status >> TEST_STATE_BIT) & TEST_STATE_MASK);
356 g_status_buffer.status = (status & TEST_STATUS_MASK);
357
358 return VAL_STATUS_SUCCESS;
359}
360
361/**
362 @brief - Updates the state and status for a given test
363 @return - test status
364**/
365uint32_t val_get_status(void)
366{
367 return ((g_status_buffer.state) << TEST_STATE_BIT) | (g_status_buffer.status);
368}
369
370/*
371 @brief - This function checks if the input status argument is an error.
372 On error, we print the checkpoint value and set the status.
373 @param - checkpoint : Test debug checkpoint
374 - val_status_t : Test status
375 @return - returns the input status back to the program.
376*/
377
378val_status_t val_err_check_set(uint32_t checkpoint, val_status_t status)
379{
380 if (VAL_ERROR(status))
381 {
382 val_print(PRINT_ERROR, "\tCheckpoint %d : ", checkpoint);
383 val_print(PRINT_ERROR, "Error Code=0x%x \n", status);
384 val_set_status(RESULT_FAIL(status));
385 }
386 else
387 {
388 status = val_get_status();
389 if (VAL_ERROR(status))
390 {
391 val_print(PRINT_ERROR, "\tCheckpoint %d : ", checkpoint);
392 val_print(PRINT_ERROR, "Error Code=0x%x \n", status);
393 }
394 else
395 {
396 val_print(PRINT_DEBUG, "\tCheckpoint %d \n", checkpoint);
397 }
398 }
399 return status;
400}
401
402/**
403 @brief This API prints the test number, description and
404 sets the test state to TEST_START on successful execution.
405 @param test_num :unique number identifying this test
406 @param desc :brief description of the test
407 @param test_bitfield :Addition test info such as
408 - test isolation level requirement
409 - Watchdog timeout type
410 @return void
411**/
412
413void val_test_init(uint32_t test_num, char8_t *desc, uint32_t test_bitfield)
414{
415 val_status_t status = VAL_STATUS_SUCCESS;
416 miscellaneous_desc_t *misc_desc;
417
418 /*global init*/
419 g_status_buffer.state = 0;
420 g_status_buffer.status = VAL_STATUS_INVALID;
421
422 val_print(PRINT_ALWAYS, "\nTEST: %d | DESCRIPTION: ", test_num);
423 val_print(PRINT_ALWAYS, desc, 0);
424
425 /* common skip logic */
426 status = val_target_get_config(TARGET_CONFIG_CREATE_ID(GROUP_MISCELLANEOUS,
427 MISCELLANEOUS_DUT, 0),
428 (uint8_t **)&misc_desc,
429 (uint32_t *)sizeof(miscellaneous_desc_t));
430 if (VAL_ERROR(status))
431 {
432 return;
433 }
434
435 if (misc_desc->implemented_psa_firmware_isolation_level <
436 GET_TEST_ISOLATION_LEVEL(test_bitfield))
437 {
438 val_set_status(RESULT_SKIP(VAL_STATUS_ISOLATION_LEVEL_NOT_SUPP));
439 val_print(PRINT_ALWAYS, "Skipping test. Required isolation level is not supported\n", 0);
440 return;
441 }
442
443 /* Initialise watchdog */
444 status = val_wd_timer_init(GET_WD_TIMOUT_TYPE(test_bitfield));
445 if (VAL_ERROR(status))
446 {
447 val_print(PRINT_ERROR, "val_wd_timer_init failed Error=0x%x\n", status);
448 return;
449 }
450
451 /* Enable watchdog Timer */
452 status = val_wd_timer_enable();
453 if (VAL_ERROR(status))
454 {
455 val_print(PRINT_ERROR, "val_wd_timer_enable failed Error=0x%x\n", status);
456 return;
457 }
458
459 val_set_status(RESULT_START(VAL_STATUS_SUCCESS));
460 return;
461}
462
463/**
464 @brief This API sets the test state to TEST_END if test is successfuly passed.
465 @param none
466 @return none
467**/
468
469void val_test_exit(void)
470{
471 val_wd_timer_disable();
472
473 /* return if test skipped or failed */
474 if (IS_TEST_SKIP(val_get_status()) || IS_TEST_FAIL(val_get_status()))
475 {
476 return;
477 }
478 val_set_status(RESULT_END(VAL_STATUS_SUCCESS));
479}
480
481/**
482 @brief - This function returns the test ID of the last test that was run
483 @param - test_id address
484 @return - val_status_t
485**/
486val_status_t val_get_last_run_test_id(test_id_t *test_id)
487{
488 val_status_t status;
489 test_count_t test_count;
490 boot_t boot;
491 int i = 0, intermediate_boot = 0;
492 boot_state_t boot_state[] = {BOOT_NOT_EXPECTED, BOOT_EXPECTED_NS,
493 BOOT_EXPECTED_S, BOOT_EXPECTED_BUT_FAILED,
494 BOOT_EXPECTED_CRYPTO};
495
496 status = val_get_boot_flag(&boot.state);
497 if (VAL_ERROR(status))
498 {
499 return status;
500 }
501
502 for (i = 0; i < (sizeof(boot_state)/sizeof(boot_state[0])); i++)
503 {
504 if (boot.state == boot_state[i])
505 {
506 intermediate_boot = 1;
507 break;
508 }
509 }
510
511 if (!intermediate_boot)
512 {
513 /* First boot. Initiliase necessary data structure */
514 status = val_set_boot_flag(BOOT_UNKNOWN);
515 if (VAL_ERROR(status))
516 {
517 return status;
518 }
519
520 *test_id = VAL_INVALID_TEST_ID;
521 status = val_nvmem_write(VAL_NVMEM_OFFSET(NV_TEST_ID_PREVIOUS),
522 test_id, sizeof(test_id_t));
523 if (VAL_ERROR(status))
524 {
525 val_print(PRINT_ALWAYS, "\n\tNVMEM write error", 0);
526 return status;
527 }
528
529 test_count.pass_cnt = 0;
530 test_count.fail_cnt = 0;
531 test_count.skip_cnt = 0;
532 test_count.sim_error_cnt = 0;
533
534 status = val_nvmem_write(VAL_NVMEM_OFFSET(NV_TEST_CNT),
535 &test_count, sizeof(test_count_t));
536 if (VAL_ERROR(status))
537 {
538 val_print(PRINT_ERROR, "\n\tNVMEM write error", 0);
539 return status;
540 }
541 }
542
543 status = val_nvmem_read(VAL_NVMEM_OFFSET(NV_TEST_ID_PREVIOUS), test_id, sizeof(test_id_t));
544 if (VAL_ERROR(status))
545 {
546 val_print(PRINT_ERROR, "\n\tNVMEM read error", 0);
547 }
548
549 val_print(PRINT_INFO, "In val_get_last_run_test_id, test_id=%x\n", *test_id);
550 return status;
551}
552
553/**
554 @brief - This function sets the given boot.state value to corresponding
555 boot NVMEM location
556 @param - state: boot_state_t
557 @return - val_status_t
558**/
559val_status_t val_set_boot_flag(boot_state_t state)
560{
561 boot_t boot;
562 val_status_t status;
563
564 boot.state = state;
565 status = val_nvmem_write(VAL_NVMEM_OFFSET(NV_BOOT), &boot, sizeof(boot_t));
566 if (VAL_ERROR(status))
567 {
568 val_print(PRINT_ERROR, "val_nvmem_write failed. Error=0x%x\n", status);
569 return status;
570 }
571 return status;
572}
573
574/**
575 @brief - This function returns boot.state value available in boot NVMEM location
576 @param - state address
577 @return - val_status_t
578**/
579val_status_t val_get_boot_flag(boot_state_t *state)
580{
581 boot_t boot;
582 val_status_t status;
583
584 status = val_nvmem_read(VAL_NVMEM_OFFSET(NV_BOOT), &boot, sizeof(boot_t));
585 if (VAL_ERROR(status))
586 {
587 val_print(PRINT_ERROR, "val_nvmem_read failed. Error=0x%x\n", status);
588 return status;
589 }
590 *state = boot.state;
591 return status;
592}