mirror of
https://github.com/apache/nuttx.git
synced 2025-12-08 19:02:43 +08:00
Adds support for SHM_REGISTER IOCTL. Registration can
be requested both against the driver (for automatic cleanup)
and against the secure OS (for sharing).
Introduces also `optee_{msg,free}_alloc()` to allocate
aligned memory for message arguments depending on the
`alignment` specified in the driver's private data. For
alignment greater than word size, memory is allocated on the
heap, otherwise it's allocated on the stack (similar to the
previous implementation but using `alloca()` instead).
Signed-off-by: George Poulios <gpoulios@census-labs.com>
286 lines
8.2 KiB
C
286 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->base.alignment = 0;
|
|
*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;
|
|
}
|