diff options
Diffstat (limited to 'core/arch/arm/tee/pta_socket.c')
-rw-r--r-- | core/arch/arm/tee/pta_socket.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/core/arch/arm/tee/pta_socket.c b/core/arch/arm/tee/pta_socket.c new file mode 100644 index 0000000..d696773 --- /dev/null +++ b/core/arch/arm/tee/pta_socket.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2016-2017, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <kernel/pseudo_ta.h> +#include <optee_msg.h> +#include <optee_msg_supplicant.h> +#include <pta_socket.h> +#include <string.h> +#include <tee/tee_fs_rpc.h> + +static uint32_t get_instance_id(struct tee_ta_session *sess) +{ + return sess->ctx->ops->get_instance_id(sess->ctx); +} + +static TEE_Result socket_open(struct tee_ta_session *sess, uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + TEE_Result res; + paddr_t pa; + uint64_t cookie; + void *va; + struct optee_msg_param msg_params[4]; + uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT); + + if (exp_pt != param_types) { + DMSG("got param_types 0x%x, expected 0x%x", + param_types, exp_pt); + return TEE_ERROR_BAD_PARAMETERS; + } + + memset(msg_params, 0, sizeof(msg_params)); + + va = tee_fs_rpc_cache_alloc(params[1].memref.size, &pa, &cookie); + if (!va) + return TEE_ERROR_OUT_OF_MEMORY; + + msg_params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_params[0].u.value.a = OPTEE_MRC_SOCKET_OPEN; + msg_params[0].u.value.b = get_instance_id(sess); + + msg_params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_params[1].u.value.a = params[0].value.b; /* server port number */ + msg_params[1].u.value.b = params[2].value.a; /* protocol */ + msg_params[1].u.value.c = params[0].value.a; /* ip version */ + + /* server address */ + msg_params[2].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; + msg_params[2].u.tmem.buf_ptr = pa; + msg_params[2].u.tmem.size = params[1].memref.size; + msg_params[2].u.tmem.shm_ref = cookie; + memcpy(va, params[1].memref.buffer, params[1].memref.size); + + /* socket handle */ + msg_params[3].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT; + + res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_SOCKET, 4, msg_params); + + if (res == TEE_SUCCESS) + params[3].value.a = msg_params[3].u.value.a; + + return res; +} + +static TEE_Result socket_close(struct tee_ta_session *sess, + uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + struct optee_msg_param msg_params[1]; + uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (exp_pt != param_types) { + DMSG("got param_types 0x%x, expected 0x%x", + param_types, exp_pt); + return TEE_ERROR_BAD_PARAMETERS; + } + + memset(msg_params, 0, sizeof(msg_params)); + + msg_params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_params[0].u.value.a = OPTEE_MRC_SOCKET_CLOSE; + msg_params[0].u.value.b = get_instance_id(sess); + msg_params[0].u.value.c = params[0].value.a; + + return thread_rpc_cmd(OPTEE_MSG_RPC_CMD_SOCKET, 1, msg_params); +} + +static TEE_Result socket_send(struct tee_ta_session *sess, uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + TEE_Result res; + paddr_t pa; + uint64_t cookie; + void *va; + struct optee_msg_param msg_params[3]; + uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT, + TEE_PARAM_TYPE_NONE); + + if (exp_pt != param_types) { + DMSG("got param_types 0x%x, expected 0x%x", + param_types, exp_pt); + return TEE_ERROR_BAD_PARAMETERS; + } + + memset(msg_params, 0, sizeof(msg_params)); + + va = tee_fs_rpc_cache_alloc(params[1].memref.size, &pa, &cookie); + if (!va) + return TEE_ERROR_OUT_OF_MEMORY; + + msg_params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_params[0].u.value.a = OPTEE_MRC_SOCKET_SEND; + msg_params[0].u.value.b = get_instance_id(sess); + msg_params[0].u.value.c = params[0].value.a; /* handle */ + + /* buffer */ + msg_params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; + msg_params[1].u.tmem.buf_ptr = pa; + msg_params[1].u.tmem.size = params[1].memref.size; + msg_params[1].u.tmem.shm_ref = cookie; + memcpy(va, params[1].memref.buffer, params[1].memref.size); + + msg_params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INOUT; + msg_params[2].u.value.a = params[0].value.b /* timeout */; + + + res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_SOCKET, 3, msg_params); + params[2].value.a = msg_params[2].u.value.b; /* transmitted bytes */ + return res; +} + +static TEE_Result socket_recv(struct tee_ta_session *sess, uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + TEE_Result res; + paddr_t pa; + uint64_t cookie; + void *va; + struct optee_msg_param msg_params[3]; + uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (exp_pt != param_types) { + DMSG("got param_types 0x%x, expected 0x%x", + param_types, exp_pt); + return TEE_ERROR_BAD_PARAMETERS; + } + + memset(msg_params, 0, sizeof(msg_params)); + + va = tee_fs_rpc_cache_alloc(params[1].memref.size, &pa, &cookie); + if (!va) + return TEE_ERROR_OUT_OF_MEMORY; + + msg_params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_params[0].u.value.a = OPTEE_MRC_SOCKET_RECV; + msg_params[0].u.value.b = get_instance_id(sess); + msg_params[0].u.value.c = params[0].value.a; /* handle */ + + /* buffer */ + msg_params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; + msg_params[1].u.tmem.buf_ptr = pa; + msg_params[1].u.tmem.size = params[1].memref.size; + msg_params[1].u.tmem.shm_ref = cookie; + + msg_params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_params[2].u.value.a = params[0].value.b /* timeout */; + + + res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_SOCKET, 3, msg_params); + params[1].memref.size = msg_params[1].u.tmem.size; + if (msg_params[1].u.tmem.size) + memcpy(params[1].memref.buffer, va, msg_params[1].u.tmem.size); + return res; +} + +static TEE_Result socket_ioctl(struct tee_ta_session *sess, + uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + TEE_Result res; + paddr_t pa; + uint64_t cookie; + void *va; + struct optee_msg_param msg_params[3]; + uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (exp_pt != param_types) { + DMSG("got param_types 0x%x, expected 0x%x", + param_types, exp_pt); + return TEE_ERROR_BAD_PARAMETERS; + } + + memset(msg_params, 0, sizeof(msg_params)); + + va = tee_fs_rpc_cache_alloc(params[1].memref.size, &pa, &cookie); + if (!va) + return TEE_ERROR_OUT_OF_MEMORY; + + msg_params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_params[0].u.value.a = OPTEE_MRC_SOCKET_IOCTL; + msg_params[0].u.value.b = get_instance_id(sess); + msg_params[0].u.value.c = params[0].value.a; /* handle */ + + /* buffer */ + msg_params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT; + msg_params[1].u.tmem.buf_ptr = pa; + msg_params[1].u.tmem.size = params[1].memref.size; + msg_params[1].u.tmem.shm_ref = cookie; + memcpy(va, params[1].memref.buffer, params[1].memref.size); + + msg_params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_params[2].u.value.a = params[0].value.b; /* ioctl command */ + + res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_SOCKET, 3, msg_params); + if (msg_params[1].u.tmem.size <= params[1].memref.size) + memcpy(params[1].memref.buffer, va, msg_params[1].u.tmem.size); + params[1].memref.size = msg_params[1].u.tmem.size; + return res; +} + +typedef TEE_Result (*ta_func)(struct tee_ta_session *sess, uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]); + +static const ta_func ta_funcs[] = { + [PTA_SOCKET_OPEN] = socket_open, + [PTA_SOCKET_CLOSE] = socket_close, + [PTA_SOCKET_SEND] = socket_send, + [PTA_SOCKET_RECV] = socket_recv, + [PTA_SOCKET_IOCTL] = socket_ioctl, +}; + +/* + * Trusted Application Entry Points + */ + +static TEE_Result pta_socket_open_session(uint32_t param_types __unused, + TEE_Param pParams[TEE_NUM_PARAMS] __unused, + void **sess_ctx __unused) +{ + struct tee_ta_session *s; + + /* Check that we're called from a TA */ + s = tee_ta_get_calling_session(); + if (!s) + return TEE_ERROR_ACCESS_DENIED; + + *sess_ctx = s; + + return TEE_SUCCESS; +} + +static void pta_socket_close_session(void *sess_ctx) +{ + TEE_Result res; + struct optee_msg_param msg_params[1]; + + memset(msg_params, 0, sizeof(msg_params)); + + msg_params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_params[0].u.value.a = OPTEE_MRC_SOCKET_CLOSE_ALL; + msg_params[0].u.value.b = get_instance_id(sess_ctx); + + res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_SOCKET, 1, msg_params); + if (res != TEE_SUCCESS) + DMSG("OPTEE_MRC_SOCKET_CLOSE_ALL failed: %#" PRIx32, res); +} + +static TEE_Result pta_socket_invoke_command(void *sess_ctx, uint32_t cmd_id, + uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS]) +{ + if (cmd_id < ARRAY_SIZE(ta_funcs) && ta_funcs[cmd_id]) + return ta_funcs[cmd_id](sess_ctx, param_types, params); + + return TEE_ERROR_NOT_IMPLEMENTED; +} + +pseudo_ta_register(.uuid = PTA_SOCKET_UUID, .name = "socket", + .flags = PTA_DEFAULT_FLAGS, + .open_session_entry_point = pta_socket_open_session, + .close_session_entry_point = pta_socket_close_session, + .invoke_command_entry_point = pta_socket_invoke_command); |