android13/u-boot/lib/optee_clientApi/OpteeClientSMC.c

359 lines
9.5 KiB
C

/*
* Copyright 2017, Rockchip Electronics Co., Ltd
* hisping lin, <hisping.lin@rock-chips.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <optee_include/OpteeClientMem.h>
#include <optee_include/OpteeClientSMC.h>
#include <optee_include/OpteeClientRPC.h>
#include <optee_include/teesmc.h>
#include <optee_include/teesmc_v2.h>
#define TEEC_SMC_DEFAULT_CACHE_ATTRIBUTES \
(TEESMC_ATTR_CACHE_DEFAULT << TEESMC_ATTR_CACHE_SHIFT);
static void SetTeeSmc32Params(TEEC_Operation *operation,
t_teesmc32_param *TeeSmc32Param);
static void GetTeeSmc32Params(t_teesmc32_param *TeeSmc32Param,
TEEC_Operation *operation);
static TEEC_Result OpteeSmcCall(t_teesmc32_arg *TeeSmc32Arg);
void tee_uuid_to_octets(uint8_t *d, const TEEC_UUID *s)
{
d[0] = s->timeLow >> 24;
d[1] = s->timeLow >> 16;
d[2] = s->timeLow >> 8;
d[3] = s->timeLow;
d[4] = s->timeMid >> 8;
d[5] = s->timeMid;
d[6] = s->timeHiAndVersion >> 8;
d[7] = s->timeHiAndVersion;
memcpy(d + 8, s->clockSeqAndNode, sizeof(s->clockSeqAndNode));
}
/*
* This function opens a new Session between the Client application and the
* specified TEE application.
*
* Only connection_method == TEEC_LOGIN_PUBLIC is supported connection_data and
* operation shall be set to NULL.
*/
TEEC_Result TEEC_SMC_OpenSession(TEEC_Context *context,
TEEC_Session *session,
const TEEC_UUID *destination,
TEEC_Operation *operation,
uint32_t *error_origin)
{
TEEC_Result TeecResult = TEEC_SUCCESS;
uint32_t TeeSmc32ArgLength;
uint32_t TeeSmcMetaSessionLength;
t_teesmc32_arg *TeeSmc32Arg = NULL;
t_teesmc32_param *TeeSmc32Param = NULL;
t_teesmc_meta_open_session *TeeSmcMetaSession = NULL;
uint32_t MetaNum = 2;
*error_origin = TEEC_ORIGIN_API;
TeeSmc32ArgLength =
TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum);
TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength);
if (TeeSmc32Arg == NULL) {
TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
goto Exit;
}
memset(TeeSmc32Arg, 0, TeeSmc32ArgLength);
TeeSmcMetaSessionLength = sizeof(*TeeSmcMetaSession);
TeeSmcMetaSession = (t_teesmc_meta_open_session *)
OpteeClientMemAlloc(TeeSmcMetaSessionLength);
if (TeeSmcMetaSession == NULL) {
TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
goto Exit;
}
memset(TeeSmcMetaSession, 0, TeeSmcMetaSessionLength);
TeeSmc32Arg->cmd = TEESMC_CMD_OPEN_SESSION;
TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum;
TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg);
memcpy(&TeeSmcMetaSession->uuid,
destination,
sizeof(TeeSmcMetaSession->uuid));
TeeSmcMetaSession->clnt_login = TEEC_LOGIN_PUBLIC;
TeeSmc32Param[0].u.memref.buf_ptr = (uint32_t) (size_t)TeeSmcMetaSession;
TeeSmc32Param[0].u.memref.size = sizeof(*TeeSmcMetaSession);
#ifdef CONFIG_OPTEE_V1
memcpy((void *)&TeeSmc32Param[0].u.value, &TeeSmcMetaSession->uuid, sizeof(TeeSmcMetaSession->uuid));
#endif
#ifdef CONFIG_OPTEE_V2
uint8_t * session_uuid = (uint8_t *)&TeeSmcMetaSession->uuid;
tee_uuid_to_octets(session_uuid, destination);
memcpy((void *)&TeeSmc32Param[0].u.value, &TeeSmcMetaSession->uuid, sizeof(TeeSmcMetaSession->uuid));
#endif
TeeSmc32Param[1].u.value.c = TeeSmcMetaSession->clnt_login;
TeeSmc32Param[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 |
OPTEE_MSG_ATTR_META_V2;
TeeSmc32Param[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 |
OPTEE_MSG_ATTR_META_V2;
SetTeeSmc32Params(operation, TeeSmc32Param + MetaNum);
*error_origin = TEEC_ORIGIN_COMMS;
TeecResult = OpteeSmcCall(TeeSmc32Arg);
if (TeecResult != TEEC_SUCCESS)
goto Exit;
session->id = TeeSmc32Arg->session;
TeecResult = TeeSmc32Arg->ret;
*error_origin = TeeSmc32Arg->ret_origin;
GetTeeSmc32Params(TeeSmc32Param + MetaNum, operation);
Exit:
if (TeeSmc32Arg != NULL)
OpteeClientMemFree(TeeSmc32Arg);
if (TeeSmcMetaSession != NULL)
OpteeClientMemFree(TeeSmcMetaSession);
return TeecResult;
}
/*
* This function closes a session which has been opened with a TEE
* application.
*
* Note that the GP specification does not allow for this API to fail and return
* a failure code however we'll support this at the SMC level so we can get
* see debug information about such failures.
*/
TEEC_Result TEEC_SMC_CloseSession(TEEC_Session *session,
uint32_t *error_origin)
{
TEEC_Result TeecResult = TEEC_SUCCESS;
uint32_t TeeSmc32ArgLength;
t_teesmc32_arg *TeeSmc32Arg = NULL;
*error_origin = TEEC_ORIGIN_API;
TeeSmc32ArgLength =
TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT);
TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength);
if (TeeSmc32Arg == NULL) {
TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
goto Exit;
}
memset(TeeSmc32Arg, 0, TeeSmc32ArgLength);
TeeSmc32Arg->cmd = TEESMC_CMD_CLOSE_SESSION;
TeeSmc32Arg->session = session->id;
*error_origin = TEEC_ORIGIN_COMMS;
TeecResult = OpteeSmcCall(TeeSmc32Arg);
if (TeecResult != TEEC_SUCCESS)
goto Exit;
TeecResult = TeeSmc32Arg->ret;
*error_origin = TeeSmc32Arg->ret_origin;
Exit:
if (TeeSmc32Arg != NULL)
OpteeClientMemFree(TeeSmc32Arg);
return TeecResult;
}
/*
* Invokes a TEE command (secure service, sub-PA or whatever).
*/
TEEC_Result TEEC_SMC_InvokeCommand(TEEC_Session *session,
uint32_t cmd_id,
TEEC_Operation *operation,
uint32_t *error_origin)
{
TEEC_Result TeecResult = TEEC_SUCCESS;
uint32_t TeeSmc32ArgLength;
t_teesmc32_arg *TeeSmc32Arg = NULL;
t_teesmc32_param *TeeSmc32Param = NULL;
*error_origin = TEEC_ORIGIN_API;
TeeSmc32ArgLength =
TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT);
TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength);
if (TeeSmc32Arg == NULL) {
TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
goto Exit;
}
memset(TeeSmc32Arg, 0, TeeSmc32ArgLength);
TeeSmc32Arg->cmd = TEESMC_CMD_INVOKE_COMMAND;
TeeSmc32Arg->ta_func = cmd_id;
TeeSmc32Arg->session = session->id;
TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg);
SetTeeSmc32Params(operation, TeeSmc32Param);
*error_origin = TEEC_ORIGIN_COMMS;
TeecResult = OpteeSmcCall(TeeSmc32Arg);
if (TeecResult != TEEC_SUCCESS)
goto Exit;
TeecResult = TeeSmc32Arg->ret;
*error_origin = TeeSmc32Arg->ret_origin;
GetTeeSmc32Params(TeeSmc32Param, operation);
Exit:
if (TeeSmc32Arg != NULL)
OpteeClientMemFree(TeeSmc32Arg);
return TeecResult;
}
/*
* Request a cancellation of a in-progress operation (best effort)
*
* Note that the GP specification does not allow for this API to fail and return
* a failure code however we'll support this at the SMC level so we can get
* see debug information about such failures.
*/
TEEC_Result TEEC_SMC_RequestCancellation(TEEC_Operation *operation,
uint32_t *error_origin)
{
return TEEC_ERROR_NOT_IMPLEMENTED;
}
/*
* Set the call parameter blocks in the
* SMC call based on the TEEC parameter supplied.
* This only handles the parameters supplied in
* the originating call and not those
* considered internal meta parameters and is
* thus constrained by the build
* constants exposed to callers.
*/
void SetTeeSmc32Params(TEEC_Operation *operation,
t_teesmc32_param *TeeSmc32Param)
{
uint32_t ParamCount;
for (ParamCount = 0;
ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT;
ParamCount++) {
uint32_t attr =
TEEC_PARAM_TYPE_GET(operation->paramTypes, ParamCount);
if (attr == TEEC_MEMREF_TEMP_INPUT ||
attr == TEEC_MEMREF_TEMP_OUTPUT ||
attr == TEEC_MEMREF_TEMP_INOUT) {
attr += (OPTEE_MSG_ATTR_TYPE_TMEM_INPUT_V2 - TEEC_MEMREF_TEMP_INPUT);
debug("TEEC: OPTEE_OS_V2 ARCH64 attr %x\n", attr);
TeeSmc32Param[ParamCount].attr = attr;
TeeSmc32Param[ParamCount].u.memref.buf_ptr =
(uint32_t)(size_t)operation->params[ParamCount].tmpref.buffer;
TeeSmc32Param[ParamCount].u.memref.size =
operation->params[ParamCount].tmpref.size;
} else {
TeeSmc32Param[ParamCount].attr = attr;
TeeSmc32Param[ParamCount].u.value.a =
operation->params[ParamCount].value.a;
TeeSmc32Param[ParamCount].u.value.b =
operation->params[ParamCount].value.b;
}
}
}
/*
* Get the return parameter blocks from
* the SMC call into the TEEC parameter supplied.
* This only handles the parameters supplied
* in the originating call and not those
* considered internal meta parameters and
* is thus constrained by the build
* constants exposed to callers.
*/
void GetTeeSmc32Params(t_teesmc32_param *TeeSmc32Param,
TEEC_Operation *operation)
{
uint32_t ParamCount;
for (ParamCount = 0;
ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT;
ParamCount++) {
operation->params[ParamCount].value.a =
TeeSmc32Param[ParamCount].u.value.a;
operation->params[ParamCount].value.b =
TeeSmc32Param[ParamCount].u.value.b;
}
}
/*
* Populate the SMC registers and make
* the call with OpTEE specific handling.
*/
TEEC_Result OpteeSmcCall(t_teesmc32_arg *TeeSmc32Arg)
{
TEEC_Result TeecResult = TEEC_SUCCESS;
ARM_SMC_ARGS ArmSmcArgs = {0};
ArmSmcArgs.Arg0 = OPTEE_SMC_CALL_WITH_ARG_V2;
ArmSmcArgs.Arg1 = 0;
ArmSmcArgs.Arg2 = (uint32_t) (size_t)TeeSmc32Arg;
while (1) {
tee_smc_call(&ArmSmcArgs);
debug("TEEC: arg0=0x%x arg1=0x%x arg2=0x%x arg3=0x%x \n",
ArmSmcArgs.Arg0, ArmSmcArgs.Arg1, ArmSmcArgs.Arg2, ArmSmcArgs.Arg3);
if (TEESMC_RETURN_IS_RPC(ArmSmcArgs.Arg0)) {
(void) OpteeRpcCallback(&ArmSmcArgs);
} else if (ArmSmcArgs.Arg0 == TEESMC_RETURN_UNKNOWN_FUNCTION) {
TeecResult = TEEC_ERROR_NOT_IMPLEMENTED;
break;
} else if (ArmSmcArgs.Arg0 != TEESMC_RETURN_OK) {
TeecResult = TEEC_ERROR_COMMUNICATION;
break;
} else {
TeecResult = TEEC_SUCCESS;
break;
}
}
return TeecResult;
}