blob: 0b1d6be36c56eeeb62f2d9ee86545a691acf0219 [file] [log] [blame]
/** @file
* Copyright (c) 2018-2019, Arm Limited or its affiliates. All rights reserved.
* SPDX-License-Identifier : Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/* Note- This file contains the functions and variables definition which are common to
all partitions defined by test suite. These functions and variables are declared with static
keyword because some fully isolated system may not allow to share code and data segment
between partitions and static will help each partition to have its own copy of code and data.
Moreover it can prevents symbol names conflict if these functions are separately compiled and
linked with each of partitions in fully isolated environment.
*/
#ifndef _VAL_COMMON_SP_APIS_H_
#define _VAL_COMMON_SP_APIS_H_
#include "val.h"
#include "val_target.c"
#include "val_service_defs.h"
__UNUSED STATIC_DECLARE val_status_t val_print
(print_verbosity_t verbosity, char *string, int32_t data);
__UNUSED STATIC_DECLARE val_status_t val_ipc_connect
(uint32_t sid, uint32_t version, psa_handle_t *handle );
__UNUSED STATIC_DECLARE val_status_t val_ipc_call(psa_handle_t handle,
int32_t type,
const psa_invec *in_vec,
size_t in_len,
psa_outvec *out_vec,
size_t out_len);
__UNUSED STATIC_DECLARE void val_ipc_close
(psa_handle_t handle);
__UNUSED STATIC_DECLARE val_status_t val_process_connect_request(psa_signal_t sig, psa_msg_t *msg);
__UNUSED STATIC_DECLARE val_status_t val_process_call_request(psa_signal_t sig, psa_msg_t *msg);
__UNUSED STATIC_DECLARE val_status_t val_process_disconnect_request
(psa_signal_t sig, psa_msg_t *msg);
__UNUSED STATIC_DECLARE val_status_t val_execute_secure_tests
(test_info_t test_info, client_test_t *tests_list);
__UNUSED STATIC_DECLARE val_status_t val_execute_secure_test_func
(psa_handle_t *handle, test_info_t test_info, uint32_t sid);
__UNUSED STATIC_DECLARE val_status_t val_get_secure_test_result(psa_handle_t *handle);
__UNUSED STATIC_DECLARE val_status_t val_err_check_set(uint32_t checkpoint, val_status_t status);
__UNUSED STATIC_DECLARE val_status_t val_nvmem_write(uint32_t offset, void *buffer, int size);
__UNUSED STATIC_DECLARE val_status_t val_set_boot_flag(boot_state_t state);
__UNUSED static val_api_t val_api = {
.print = val_print,
.err_check_set = val_err_check_set,
.execute_secure_test_func = val_execute_secure_test_func,
.get_secure_test_result = val_get_secure_test_result,
.ipc_connect = val_ipc_connect,
.ipc_call = val_ipc_call,
.ipc_close = val_ipc_close,
.set_boot_flag = val_set_boot_flag,
.target_get_config = val_target_get_config,
.process_connect_request = val_process_connect_request,
.process_call_request = val_process_call_request,
.process_disconnect_request= val_process_disconnect_request,
};
__UNUSED static psa_api_t psa_api = {
.framework_version = psa_framework_version,
.version = psa_version,
.connect = psa_connect,
.call = psa_call,
.close = psa_close,
.wait = psa_wait,
.set_rhandle = psa_set_rhandle,
.get = psa_get,
.read = psa_read,
.skip = psa_skip,
.write = psa_write,
.reply = psa_reply,
.notify = psa_notify,
.clear = psa_clear,
.eoi = psa_eoi,
.rot_lifecycle_state = psa_rot_lifecycle_state,
.panic = psa_panic,
};
/**
@brief - Print module. This is client interface API of secure partition
val_print_sf API for spe world
@param - verbosity: Print verbosity level
- string : Input string
- data : Value for format specifier
@return - val_status_t
**/
STATIC_DECLARE val_status_t val_print(print_verbosity_t verbosity, char *string, int32_t data)
{
int string_len = 0;
char *p = string;
psa_handle_t print_handle = 0;
psa_status_t status_of_call = PSA_SUCCESS;
val_status_t status = VAL_STATUS_SUCCESS;
uart_fn_type_t uart_fn = UART_PRINT;
if (verbosity < VERBOSE)
{
return VAL_STATUS_SUCCESS;
}
while (*p != '\0')
{
string_len++;
p++;
}
psa_invec data1[3] = {{&uart_fn, sizeof(uart_fn)}, {string, string_len+1}, {&data, sizeof(data)}};
print_handle = psa_connect(DRIVER_UART_SID, DRIVER_UART_VERSION);
if (PSA_HANDLE_IS_VALID(print_handle))
{
status_of_call = psa_call(print_handle, 0, data1, 3, NULL, 0);
if (status_of_call != PSA_SUCCESS)
{
status = VAL_STATUS_CALL_FAILED;
}
}
else
{
return VAL_STATUS_CONNECTION_FAILED;
}
psa_close(print_handle);
return status;
}
/**
* @brief Connect to given sid
@param -sid : RoT service id
@param -version : version of RoT service
@param -handle - return connection handle
* @return val_status_t
*/
STATIC_DECLARE val_status_t val_ipc_connect(uint32_t sid, uint32_t version,
psa_handle_t *handle )
{
*handle = psa_connect(sid, version);
if (PSA_HANDLE_IS_VALID(*handle))
return VAL_STATUS_SUCCESS;
return VAL_STATUS_CONNECTION_FAILED;
}
/**
* @brief Call a connected Root of Trust Service.@n
* The caller must provide an array of ::psa_invec_t structures as the input payload.
* @param handle: Handle for the connection.
* @param type: Request type.
* @param in_vec: Array of psa_invec structures.
* @param in_len: Number of psa_invec structures in in_vec.
* @param out_vec: Array of psa_outvec structures for optional Root of Trust Service response.
* @param out_len: Number of psa_outvec structures in out_vec.
* @return val_status_t
*/
STATIC_DECLARE val_status_t val_ipc_call(psa_handle_t handle,
int32_t type,
const psa_invec *in_vec,
size_t in_len,
psa_outvec *out_vec,
size_t out_len)
{
psa_status_t call_status = PSA_SUCCESS;
call_status = psa_call(handle, type, in_vec, in_len, out_vec, out_len);
if (call_status != PSA_SUCCESS)
{
return(VAL_STATUS_CALL_FAILED);
}
return VAL_STATUS_SUCCESS;
}
/**
* @brief Close a connection to a Root of Trust Service.
* Sends the PSA_IPC_DISCONNECT message to the Root of Trust Service so
it can clean up resources.
* @param handle: Handle for the connection.
* @return void
*/
STATIC_DECLARE void val_ipc_close(psa_handle_t handle)
{
psa_close(handle);
}
/**
* @brief Proccess a generic connect message to given rot signal.
@param -sig : signal to be processed
@param -msg : return msg info of given signal
* @return val_status_t.
*/
STATIC_DECLARE val_status_t val_process_connect_request(psa_signal_t sig, psa_msg_t *msg)
{
val_status_t res = VAL_STATUS_ERROR;
psa_signal_t signals;
wait1:
signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
if (signals & sig)
{
if (psa_get(sig, msg) != PSA_SUCCESS)
{
goto wait1;
}
if ((msg->type != PSA_IPC_CONNECT) || (msg->handle <= 0))
{
val_print(PRINT_ERROR, "\tpsa_get failed for connect message\n", 0);
res = VAL_STATUS_ERROR;
}
else
{
res = VAL_STATUS_SUCCESS;
}
}
else
{
val_print(PRINT_ERROR, "\tpsa_wait returned with invalid signal value = 0x%x\n", signals);
res = VAL_STATUS_ERROR;
}
return res;
}
/**
* @brief Proccess a generic call message to given rot signal.
@param -sig : signal to be processed
@param -msg : return msg info of given signal
* @return val_status_t
*/
STATIC_DECLARE val_status_t val_process_call_request(psa_signal_t sig, psa_msg_t *msg)
{
val_status_t res = VAL_STATUS_ERROR;
psa_signal_t signals;
wait2:
signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
if (signals & sig)
{
if (psa_get(sig, msg) != PSA_SUCCESS)
{
goto wait2;
}
if ((msg->type < PSA_IPC_CALL) || (msg->handle <= 0))
{
val_print(PRINT_ERROR, "\tpsa_get failed for request message\n", 0);
res = VAL_STATUS_ERROR;
}
else
{
res = VAL_STATUS_SUCCESS;
}
}
else
{
val_print(PRINT_ERROR, "\tpsa_wait returned with invalid signal value = 0x%x\n", signals);
res = VAL_STATUS_ERROR;
}
return res;
}
/**
* @brief Proccess a generic disconnect message to given rot signal.
@param -sig : signal to be processed
@param -msg : return msg info of given signal
* @return val_status_t
*/
STATIC_DECLARE val_status_t val_process_disconnect_request(psa_signal_t sig, psa_msg_t *msg)
{
val_status_t res = VAL_STATUS_ERROR;
psa_signal_t signals;
wait3:
signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
if (signals & sig)
{
if (psa_get(sig, msg) != PSA_SUCCESS)
{
goto wait3;
}
if ((msg->type != PSA_IPC_DISCONNECT) || (msg->handle <= 0))
{
val_print(PRINT_ERROR, "\tpsa_get failed for disconnect massage\n", 0);
res = VAL_STATUS_ERROR;
}
else
{
res = VAL_STATUS_SUCCESS;
}
}
else
{
val_print(PRINT_ERROR, "\tpsa_wait returned with invalid signal value = 0x%x\n", signals);
res = VAL_STATUS_ERROR;
}
return res;
}
/**
@brief - This function executes given list of tests from secure sequentially
This covers secure to secure IPC API scenario
@param - test_info_t : test_num and block_num
@param - tests_list : list of tests to be executed
@return - val_status_t
**/
STATIC_DECLARE val_status_t val_execute_secure_tests(test_info_t test_info, client_test_t *tests_list)
{
val_status_t status = VAL_STATUS_SUCCESS;
val_status_t test_status = VAL_STATUS_SUCCESS;
psa_handle_t handle;
int i = test_info.block_num;
while (tests_list[i] != NULL)
{
if (i == 1)
val_print(PRINT_TEST, "[Info] Executing tests from secure\n", 0);
/* Handshake with server tests */
test_info.block_num = i;
status = val_execute_secure_test_func(&handle, test_info, SERVER_TEST_DISPATCHER_SID);
if (VAL_ERROR(status))
{
val_print(PRINT_ERROR, "[Check %d] START\n", i);
return status;
}
else
{
val_print(PRINT_DEBUG, "[Check %d] START\n", i);
}
/* Execute client tests */
test_status = tests_list[i](CALLER_SECURE);
/* Retrive Server test status */
status = val_get_secure_test_result(&handle);
status = test_status ? test_status:status;
if (IS_TEST_SKIP(status))
{
val_print(PRINT_DEBUG, "[Check %d] SKIPPED\n", i);
return status;
}
if (VAL_ERROR(status))
{
val_print(PRINT_DEBUG, "[Check %d] FAILED\n", i);
return status;
}
else
{
val_print(PRINT_DEBUG, "[Check %d] PASSED\n", i);
}
i++;
}
return status;
}
/**
@brief - This function is used to handshake between:
- nonsecure client to server test fn
- secure client and server test fn
- nonsecure client to secure client test fn
@param - handle : handle returned while connecting given sid
@param - test_info : Test_num and block_num to be executed
@param - sid : RoT service to be connected. Partition dispatcher sid
@return - val_status_t
**/
STATIC_DECLARE val_status_t val_execute_secure_test_func(psa_handle_t *handle,
test_info_t test_info,
uint32_t sid)
{
uint32_t test_data;
val_status_t status = VAL_STATUS_SUCCESS;
psa_status_t status_of_call = PSA_SUCCESS;
*handle = psa_connect(sid, 1);
if (*handle < 0)
{
val_print(PRINT_ERROR, "Could not connect SID. Handle=%x\n", *handle);
status = VAL_STATUS_CONNECTION_FAILED;
}
test_data = ((uint32_t)(test_info.test_num) | ((uint32_t)(test_info.block_num) << BLOCK_NUM_POS)
| ((uint32_t)(TEST_EXECUTE_FUNC) << ACTION_POS));
psa_invec data[1] = {{&test_data, sizeof(test_data)}};
status_of_call = psa_call(*handle, 0, data, 1, NULL, 0);
if (status_of_call != PSA_SUCCESS)
{
status = VAL_STATUS_CALL_FAILED;
val_print(PRINT_ERROR, "Call to dispatch SF failed. Status=%x\n", status_of_call);
psa_close(*handle);
}
return status;
}
/**
@brief - This function is used to retrive the status of previously connected test function
using val_execute_secure_test_func
@param - handle : handle of server function. Handle of Partition dispatcher sid
@return - The status of test functions
**/
STATIC_DECLARE val_status_t val_get_secure_test_result(psa_handle_t *handle)
{
uint32_t test_data;
val_status_t status = VAL_STATUS_SUCCESS;
psa_status_t status_of_call = PSA_SUCCESS;
test_data = (TEST_RETURN_RESULT << ACTION_POS);
psa_outvec resp = {&status, sizeof(status)};
psa_invec data[1] = {{&test_data, sizeof(test_data)}};
status_of_call = psa_call(*handle, 0, data, 1, &resp, 1);
if (status_of_call != PSA_SUCCESS)
{
status = VAL_STATUS_CALL_FAILED;
val_print(PRINT_ERROR, "Call to dispatch SF failed. Status=%x\n", status_of_call);
}
psa_close(*handle);
return status;
}
/*
@brief - This function checks if the input status argument is an error.
On error, print the checkpoint value
@param - checkpoint : Test debug checkpoint
- val_status_t : Test status
@return - returns the input status back to the program.
*/
STATIC_DECLARE val_status_t val_err_check_set(uint32_t checkpoint, val_status_t status)
{
if (VAL_ERROR(status))
{
val_print(PRINT_ERROR, "\tCheckpoint %d : ", checkpoint);
val_print(PRINT_ERROR, "Error Code=0x%x \n", status);
}
else
{
val_print(PRINT_DEBUG, "\tCheckpoint %d \n", checkpoint);
}
return status;
}
/*
@brief - Writes 'size' bytes from buffer into non-volatile memory at a given
'base + offset'. This is client interface API of secure partition
val_nvmem_write_sf API for spe world
- offset : Offset
- buffer : Pointer to source address
- size : Number of bytes
@return - val_status_t
*/
STATIC_DECLARE val_status_t val_nvmem_write(uint32_t offset, void *buffer, int size)
{
nvmem_param_t nvmem_param;
psa_handle_t handle = 0;
psa_status_t status_of_call = PSA_SUCCESS;
val_status_t status = VAL_STATUS_SUCCESS;
memory_desc_t *memory_desc;
status = val_target_get_config(TARGET_CONFIG_CREATE_ID(GROUP_MEMORY, MEMORY_NVMEM, 0),
(uint8_t **)&memory_desc,
(uint32_t *)sizeof(memory_desc_t));
if (VAL_ERROR(status))
{
return status;
}
nvmem_param.nvmem_fn_type = NVMEM_WRITE;
nvmem_param.base = memory_desc->start;
nvmem_param.offset = offset;
nvmem_param.size = size;
psa_invec invec[2] = {{&nvmem_param, sizeof(nvmem_param)}, {buffer, size}};
handle = psa_connect(DRIVER_NVMEM_SID, DRIVER_NVMEM_VERSION);
if (PSA_HANDLE_IS_VALID(handle))
{
status_of_call = psa_call(handle, 0, invec, 2, NULL, 0);
if (status_of_call != PSA_SUCCESS)
{
psa_close(handle);
return VAL_STATUS_CALL_FAILED;
}
}
else
{
return VAL_STATUS_CONNECTION_FAILED;
}
psa_close(handle);
return VAL_STATUS_SUCCESS;
}
/**
@brief - This function sets the given boot.state value to corresponding
boot NVMEM location
@param - state: boot_state_t
@return - val_status_t
**/
STATIC_DECLARE val_status_t val_set_boot_flag(boot_state_t state)
{
boot_t boot;
val_status_t status;
boot.state = state;
status = val_nvmem_write(VAL_NVMEM_OFFSET(NV_BOOT), &boot, sizeof(boot_t));
if (VAL_ERROR(status))
{
val_print(PRINT_ERROR, "\tval_nvmem_write failed Error=0x%x\n", status);
return status;
}
return status;
}
#endif