Prepares the ground for introducing new transports to the OP-TEE driver. "transports" as in alternatives to RPMsg and local network. Signed-off-by: George Poulios <gpoulios@census-labs.com>
284 lines
8.2 KiB
C
284 lines
8.2 KiB
C
/****************************************************************************
|
|
* drivers/misc/optee_socket.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/net/net.h>
|
|
#include <nuttx/kmalloc.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/param.h>
|
|
#include <sys/un.h>
|
|
#include <netpacket/rpmsg.h>
|
|
|
|
#include "optee.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#define OPTEE_SOCKET_MAX_IOVEC_NUM 7
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
struct optee_socket_priv_data
|
|
{
|
|
struct optee_priv_data base;
|
|
struct socket socket;
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
static int optee_socket_recv(FAR struct socket *psock, FAR void *msg,
|
|
size_t size)
|
|
{
|
|
while (size > 0)
|
|
{
|
|
ssize_t n = psock_recv(psock, msg, size, 0);
|
|
if (n <= 0)
|
|
{
|
|
return n < 0 ? n : -EIO;
|
|
}
|
|
|
|
size -= n;
|
|
msg = (FAR char *)msg + n;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: optee_transport_init
|
|
*
|
|
* Description:
|
|
* Perform any initialization actions specific to the transport used
|
|
* right before the driver is registered.
|
|
*
|
|
* Returned Values:
|
|
* 0 on success; A negated errno value is returned on any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int optee_transport_init(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: optee_transport_open
|
|
*
|
|
* Description:
|
|
* Perform any transport-specific actions upon driver character device
|
|
* open. In this case, open the socket and connect to it.
|
|
*
|
|
* Parameters:
|
|
* priv_ - the optee_priv_data struct to allocate and return by
|
|
* reference.
|
|
*
|
|
* Returned Values:
|
|
* 0 on success; A negated errno value is returned on any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int optee_transport_open(FAR struct optee_priv_data **priv_)
|
|
{
|
|
FAR struct optee_socket_priv_data *priv;
|
|
#ifdef CONFIG_DEV_OPTEE_LOCAL
|
|
struct sockaddr_un addr;
|
|
#else
|
|
struct sockaddr_rpmsg addr;
|
|
#endif
|
|
int ret;
|
|
|
|
priv = kmm_zalloc(sizeof(struct optee_socket_priv_data));
|
|
if (priv == NULL)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
#ifdef CONFIG_DEV_OPTEE_LOCAL
|
|
ret = psock_socket(AF_UNIX, SOCK_STREAM, 0, &priv->socket);
|
|
#else
|
|
ret = psock_socket(AF_RPMSG, SOCK_STREAM, 0, &priv->socket);
|
|
#endif
|
|
if (ret < 0)
|
|
{
|
|
kmm_free(priv);
|
|
return ret;
|
|
}
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
#ifdef CONFIG_DEV_OPTEE_LOCAL
|
|
addr.sun_family = AF_UNIX;
|
|
strlcpy(addr.sun_path, OPTEE_SERVER_PATH, sizeof(addr.sun_path));
|
|
#else
|
|
addr.rp_family = AF_RPMSG;
|
|
strlcpy(addr.rp_name, OPTEE_SERVER_PATH, sizeof(addr.rp_name));
|
|
strlcpy(addr.rp_cpu, CONFIG_OPTEE_REMOTE_CPU_NAME, sizeof(addr.rp_cpu));
|
|
#endif
|
|
|
|
ret = psock_connect(&priv->socket, (FAR const struct sockaddr *)&addr,
|
|
sizeof(addr));
|
|
if (ret < 0)
|
|
{
|
|
psock_close(&priv->socket);
|
|
kmm_free(priv);
|
|
return ret;
|
|
}
|
|
|
|
*priv_ = (FAR struct optee_priv_data *)priv;
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: optee_transport_close
|
|
*
|
|
* Description:
|
|
* Perform any transport-specific actions upon driver character device
|
|
* close.
|
|
*
|
|
* Parameters:
|
|
* priv_ - the optee_priv_data struct to close and de-allocate.
|
|
*
|
|
* Returned Values:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void optee_transport_close(FAR struct optee_priv_data *priv_)
|
|
{
|
|
FAR struct optee_socket_priv_data *priv =
|
|
(FAR struct optee_socket_priv_data *)priv_;
|
|
|
|
psock_close(&priv->socket);
|
|
kmm_free(priv);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: optee_transport_call
|
|
*
|
|
* Description:
|
|
* Call OP-TEE OS through the RPMsg/local socket.
|
|
*
|
|
* Parameters:
|
|
* priv_ - the optee_priv_data struct to use
|
|
*
|
|
* Returned Values:
|
|
* 0 on success; A negated errno value is returned on any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int optee_transport_call(FAR struct optee_priv_data *priv_,
|
|
FAR struct optee_msg_arg *arg)
|
|
{
|
|
/* iov[0]: struct opteee_msg_arg + struct optee_msg_param[n]
|
|
* iov[1 - n+1]: shm_mem
|
|
* 0 <= n <= 6
|
|
*/
|
|
|
|
FAR struct optee_socket_priv_data *priv =
|
|
(FAR struct optee_socket_priv_data *)priv_;
|
|
size_t arg_size = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
|
|
size_t shm_size[OPTEE_MAX_PARAM_NUM];
|
|
size_t shm_addr[OPTEE_MAX_PARAM_NUM];
|
|
struct iovec iov[OPTEE_SOCKET_MAX_IOVEC_NUM];
|
|
struct msghdr msghdr;
|
|
unsigned long iovlen = 1;
|
|
unsigned long i;
|
|
int ret;
|
|
|
|
memset(iov, 0, sizeof(iov));
|
|
memset(shm_size, 0, sizeof(shm_size));
|
|
|
|
iov[0].iov_base = arg;
|
|
iov[0].iov_len = arg_size;
|
|
|
|
for (i = 0; i < arg->num_params; i++)
|
|
{
|
|
if (arg->params[i].attr == OPTEE_MSG_ATTR_TYPE_RMEM_INPUT ||
|
|
arg->params[i].attr == OPTEE_MSG_ATTR_TYPE_RMEM_INOUT)
|
|
{
|
|
iov[iovlen].iov_base =
|
|
(FAR void *)(uintptr_t)arg->params[i].u.rmem.shm_ref;
|
|
iov[iovlen].iov_len = arg->params[i].u.rmem.size;
|
|
shm_size[i] = arg->params[i].u.rmem.size;
|
|
shm_addr[i] = arg->params[i].u.rmem.shm_ref;
|
|
iovlen++;
|
|
}
|
|
else if (arg->params[i].attr == OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT)
|
|
{
|
|
shm_size[i] = arg->params[i].u.rmem.size;
|
|
shm_addr[i] = arg->params[i].u.rmem.shm_ref;
|
|
}
|
|
}
|
|
|
|
memset(&msghdr, 0, sizeof(struct msghdr));
|
|
msghdr.msg_iov = iov;
|
|
msghdr.msg_iovlen = iovlen;
|
|
|
|
ret = psock_sendmsg(&priv->socket, &msghdr, 0);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = optee_socket_recv(&priv->socket, arg, arg_size);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
for (i = 0; i < arg->num_params; i++)
|
|
{
|
|
if (arg->params[i].attr == OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT ||
|
|
arg->params[i].attr == OPTEE_MSG_ATTR_TYPE_RMEM_INOUT)
|
|
{
|
|
size_t size = MIN(arg->params[i].u.rmem.size, shm_size[i]);
|
|
arg->params[i].u.rmem.shm_ref = shm_addr[i];
|
|
ret = optee_socket_recv(&priv->socket,
|
|
(FAR void *)(uintptr_t)
|
|
arg->params[i].u.rmem.shm_ref, size);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|