blob: 1f9485e111e9adf6362bd47a98af9e891e267237 [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2016, Linaro Limited
* All rights reserved.
*/
#include <pta_invoke_tests.h>
#include <string.h>
#include <ta_sdp_basic.h>
#include <tee_api.h>
#include <tee_internal_api_extensions.h>
#include <tee_internal_api.h>
#include <tee_ta_api.h>
#include <trace.h>
/*
* Basic Secure Data Path access test commands:
* - command INJECT: copy from non secure input into secure output.
* - command TRANSFROM: read, transform and write from/to secure in/out.
* - command DUMP: copy from secure input into non secure output.
*/
static TEE_Result cmd_inject(uint32_t types,
TEE_Param params[TEE_NUM_PARAMS])
{
TEE_Result rc = TEE_ERROR_GENERIC;
const int sec_idx = 1; /* highlight secure buffer index */
const int ns_idx = 0; /* highlight nonsecure buffer index */
if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
TEE_PARAM_TYPE_MEMREF_OUTPUT,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE)) {
EMSG("bad parameters %x", (unsigned)types);
return TEE_ERROR_BAD_PARAMETERS;
}
if (params[sec_idx].memref.size < params[ns_idx].memref.size)
return TEE_ERROR_SHORT_BUFFER;
/*
* We could rely on the TEE to provide consistent buffer/size values
* to reference a buffer with a unique and consistent secure attribute
* value. Hence it is safe enough (and more optimal) to test only the
* secure attribute of a single byte of it. Yet, since the current
* test does not deal with performance, let check the secure attribute
* of each byte of the buffer.
*/
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
TEE_MEMORY_ACCESS_READ |
TEE_MEMORY_ACCESS_NONSECURE,
params[ns_idx].memref.buffer,
params[ns_idx].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CheckMemoryAccessRights(nsec) failed %x", rc);
return rc;
}
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
TEE_MEMORY_ACCESS_WRITE |
TEE_MEMORY_ACCESS_SECURE,
params[sec_idx].memref.buffer,
params[sec_idx].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CheckMemoryAccessRights(secure) failed %x", rc);
return rc;
}
#ifdef CFG_CACHE_API
/*
* we should invalidate cache (here we assume buffer were not
* filled through cpu core caches. We flush buffers so that
* cache is not corrupted in cache target buffer not aligned
* on cache line size.
*/
rc = TEE_CacheFlush(params[sec_idx].memref.buffer,
params[sec_idx].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
params[sec_idx].memref.buffer,
params[sec_idx].memref.size, rc);
return rc;
}
#endif /* CFG_CACHE_API */
/* inject data */
TEE_MemMove(params[sec_idx].memref.buffer,
params[ns_idx].memref.buffer,
params[sec_idx].memref.size);
#ifdef CFG_CACHE_API
rc = TEE_CacheFlush(params[sec_idx].memref.buffer,
params[sec_idx].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
params[sec_idx].memref.buffer,
params[sec_idx].memref.size, rc);
return rc;
}
#endif /* CFG_CACHE_API */
return rc;
}
static TEE_Result cmd_transform(uint32_t types,
TEE_Param params[TEE_NUM_PARAMS])
{
TEE_Result rc = TEE_ERROR_GENERIC;
unsigned char *p = NULL;
size_t sz = 0;
if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE))
return TEE_ERROR_BAD_PARAMETERS;
/*
* We could rely on the TEE to provide consistent buffer/size values
* to reference a buffer with a unique and consistent secure attribute
* value. Hence it is safe enough (and more optimal) to test only the
* secure attribute of a single byte of it. Yet, since the current
* test does not deal with performance, let check the secure attribute
* of each byte of the buffer.
*/
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
TEE_MEMORY_ACCESS_READ |
TEE_MEMORY_ACCESS_WRITE |
TEE_MEMORY_ACCESS_SECURE,
params[0].memref.buffer,
params[0].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CheckMemoryAccessRights(secure) failed %x", rc);
return rc;
}
#ifdef CFG_CACHE_API
/*
* we should invalidate cache (here we assume buffer were not
* filled through cpu core caches. We flush buffers so that
* cache is not corrupted in cache target buffer not aligned
* on cache line size.
*/
rc = TEE_CacheFlush(params[0].memref.buffer,
params[0].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
params[0].memref.buffer,
params[0].memref.size, rc);
return rc;
}
#endif /* CFG_CACHE_API */
/* transform the data */
p = (unsigned char *)params[0].memref.buffer;
sz = params[0].memref.size;
for (; sz; sz--, p++)
*p = ~(*p) + 1;
#ifdef CFG_CACHE_API
rc = TEE_CacheFlush(params[0].memref.buffer,
params[0].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
params[0].memref.buffer,
params[0].memref.size, rc);
return rc;
}
#endif /* CFG_CACHE_API */
return rc;
}
static TEE_Result cmd_dump(uint32_t types,
TEE_Param params[TEE_NUM_PARAMS])
{
TEE_Result rc = TEE_ERROR_GENERIC;
const int sec_idx = 0; /* highlight secure buffer index */
const int ns_idx = 1; /* highlight nonsecure buffer index */
if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
TEE_PARAM_TYPE_MEMREF_OUTPUT,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE))
return TEE_ERROR_BAD_PARAMETERS;
if (params[ns_idx].memref.size < params[sec_idx].memref.size)
return TEE_ERROR_SHORT_BUFFER;
/*
* We could rely on the TEE to provide consistent buffer/size values
* to reference a buffer with a unique and consistent secure attribute
* value. Hence it is safe enough (and more optimal) to test only the
* secure attribute of a single byte of it. Yet, since the current
* test does not deal with performance, let check the secure attribute
* of each byte of the buffer.
*/
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
TEE_MEMORY_ACCESS_WRITE |
TEE_MEMORY_ACCESS_NONSECURE,
params[ns_idx].memref.buffer,
params[ns_idx].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CheckMemoryAccessRights(nsec) failed %x", rc);
return rc;
}
rc = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
TEE_MEMORY_ACCESS_READ |
TEE_MEMORY_ACCESS_SECURE,
params[sec_idx].memref.buffer,
params[sec_idx].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CheckMemoryAccessRights(secure) failed %x", rc);
return rc;
}
#ifdef CFG_CACHE_API
/*
* we should invalidate cache (here we assume buffer were not
* filled through cpu core caches. We flush buffers so that
* cache is not corrupted in cache target buffer not aligned
* on cache line size.
*/
rc = TEE_CacheFlush(params[sec_idx].memref.buffer,
params[sec_idx].memref.size);
if (rc != TEE_SUCCESS) {
EMSG("TEE_CacheFlush(%p, %x) failed: 0x%x",
params[sec_idx].memref.buffer,
params[sec_idx].memref.size, rc);
return rc;
}
#endif /* CFG_CACHE_API */
/* dump the data */
TEE_MemMove(params[ns_idx].memref.buffer,
params[sec_idx].memref.buffer,
params[sec_idx].memref.size);
return rc;
}
static TEE_Result cmd_invoke(uint32_t nParamTypes,
TEE_Param pParams[TEE_NUM_PARAMS],
uint32_t nCommandID)
{
const TEE_UUID uuid = TA_SDP_BASIC_UUID;
static TEE_TASessionHandle sess = TEE_HANDLE_NULL;
uint32_t ret_orig = 0;
TEE_Result res = TEE_ERROR_GENERIC;
if (sess == TEE_HANDLE_NULL) {
res = TEE_OpenTASession(&uuid, TEE_TIMEOUT_INFINITE, 0, NULL,
&sess, &ret_orig);
if (res != TEE_SUCCESS) {
EMSG("SDP basic test TA: TEE_OpenTASession() FAILED \n");
goto cleanup_return;
}
}
res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE,
nCommandID, nParamTypes, pParams, &ret_orig);
if (res != TEE_SUCCESS) {
EMSG("SDP basic test TA: TEE_OpenTASession() FAILED %x/%d\n",
res, ret_orig);
}
cleanup_return:
if (res != TEE_SUCCESS) {
TEE_CloseTASession(sess);
sess = TEE_HANDLE_NULL;
}
return res;
}
static TEE_Result cmd_invoke_pta(uint32_t nParamTypes,
TEE_Param pParams[TEE_NUM_PARAMS],
uint32_t nCommandID)
{
const TEE_UUID uuid = PTA_INVOKE_TESTS_UUID;
static TEE_TASessionHandle sess = TEE_HANDLE_NULL;
uint32_t ret_orig = 0;
TEE_Result res = TEE_ERROR_GENERIC;
if (sess == TEE_HANDLE_NULL) {
res = TEE_OpenTASession(&uuid, TEE_TIMEOUT_INFINITE, 0, NULL,
&sess, &ret_orig);
if (res != TEE_SUCCESS) {
EMSG("SDP basic test TA: TEE_OpenTASession() FAILED \n");
goto cleanup_return;
}
}
res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE,
nCommandID, nParamTypes, pParams, &ret_orig);
if (res != TEE_SUCCESS) {
EMSG("SDP basic test TA: TEE_OpenTASession() FAILED %x/%d\n",
res, ret_orig);
}
cleanup_return:
if (res != TEE_SUCCESS) {
TEE_CloseTASession(sess);
sess = TEE_HANDLE_NULL;
}
return res;
}
TEE_Result TA_CreateEntryPoint(void)
{
return TEE_SUCCESS;
}
void TA_DestroyEntryPoint(void)
{
}
TEE_Result TA_OpenSessionEntryPoint(uint32_t nParamTypes,
TEE_Param pParams[TEE_NUM_PARAMS],
void **ppSessionContext)
{
(void)nParamTypes;
(void)pParams;
(void)ppSessionContext;
return TEE_SUCCESS;
}
void TA_CloseSessionEntryPoint(void *pSessionContext)
{
(void)pSessionContext;
}
TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext,
uint32_t nCommandID, uint32_t nParamTypes,
TEE_Param pParams[TEE_NUM_PARAMS])
{
(void)pSessionContext;
switch (nCommandID) {
case TA_SDP_BASIC_CMD_INJECT:
return cmd_inject(nParamTypes, pParams);
case TA_SDP_BASIC_CMD_TRANSFORM:
return cmd_transform(nParamTypes, pParams);
case TA_SDP_BASIC_CMD_DUMP:
return cmd_dump(nParamTypes, pParams);
case TA_SDP_BASIC_CMD_INVOKE_INJECT:
return cmd_invoke(nParamTypes, pParams, TA_SDP_BASIC_CMD_INJECT);
case TA_SDP_BASIC_CMD_INVOKE_TRANSFORM:
return cmd_invoke(nParamTypes, pParams, TA_SDP_BASIC_CMD_TRANSFORM);
case TA_SDP_BASIC_CMD_INVOKE_DUMP:
return cmd_invoke(nParamTypes, pParams, TA_SDP_BASIC_CMD_DUMP);
case TA_SDP_BASIC_CMD_PTA_INJECT:
return cmd_invoke_pta(nParamTypes, pParams, PTA_INVOKE_TESTS_CMD_COPY_NSEC_TO_SEC);
case TA_SDP_BASIC_CMD_PTA_TRANSFORM:
return cmd_invoke_pta(nParamTypes, pParams, PTA_INVOKE_TESTS_CMD_READ_MODIFY_SEC);
case TA_SDP_BASIC_CMD_PTA_DUMP:
return cmd_invoke_pta(nParamTypes, pParams, PTA_INVOKE_TESTS_CMD_COPY_SEC_TO_NSEC);
default:
return TEE_ERROR_BAD_PARAMETERS;
}
}