pkarashchenko commented on code in PR #11228: URL: https://github.com/apache/nuttx/pull/11228#discussion_r1399560883
########## drivers/misc/optee.c: ########## @@ -0,0 +1,648 @@ +/**************************************************************************** + * drivers/misc/optee.c + * + * 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/tee.h> + +#include <fcntl.h> +#include <netpacket/rpmsg.h> +#include <nuttx/drivers/optee.h> +#include <nuttx/kmalloc.h> +#include <nuttx/mutex.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/un.h> + +#include "optee_msg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Some GlobalPlatform error codes used in this driver */ + +#define TEE_SUCCESS 0x00000000 +#define TEE_ERROR_BAD_PARAMETERS 0xFFFF0006 +#define TEE_ERROR_NOT_SUPPORTED 0xFFFF000A +#define TEE_ERROR_COMMUNICATION 0xFFFF000E +#define TEE_ERROR_OUT_OF_MEMORY 0xFFFF000C +#define TEE_ERROR_BUSY 0xFFFF000D Review Comment: There is 1 space diff in alignment. Could you please unify it? ########## drivers/misc/optee.c: ########## @@ -0,0 +1,648 @@ +/**************************************************************************** + * drivers/misc/optee.c + * + * 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/tee.h> + +#include <fcntl.h> +#include <netpacket/rpmsg.h> +#include <nuttx/drivers/optee.h> +#include <nuttx/kmalloc.h> +#include <nuttx/mutex.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/un.h> + +#include "optee_msg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Some GlobalPlatform error codes used in this driver */ + +#define TEE_SUCCESS 0x00000000 +#define TEE_ERROR_BAD_PARAMETERS 0xFFFF0006 +#define TEE_ERROR_NOT_SUPPORTED 0xFFFF000A +#define TEE_ERROR_COMMUNICATION 0xFFFF000E +#define TEE_ERROR_OUT_OF_MEMORY 0xFFFF000C +#define TEE_ERROR_BUSY 0xFFFF000D +#define TEE_ERROR_SHORT_BUFFER 0xFFFF0010 + +#define TEE_ORIGIN_COMMS 0x00000002 + +#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_ioctl_param) * (x)) + +#define OPTEE_MAX_IOVEC_NUM 7 +#define OPTEE_MAX_PARAM_NUM 6 + +#define OPTEE_SERVER_PATH "optee" +#define OPTEE_DEV_PATH "/dev/tee0" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* The file operation functions */ + +static int optee_open(FAR struct file *filep); +static int optee_close(FAR struct file *filep); +static int optee_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); Review Comment: ```suggestion static int optee_ioctl(FAR struct file *filep, int cmd, unsigned long arg); ``` ########## drivers/misc/optee.c: ########## @@ -0,0 +1,648 @@ +/**************************************************************************** + * drivers/misc/optee.c + * + * 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/tee.h> + +#include <fcntl.h> +#include <netpacket/rpmsg.h> +#include <nuttx/drivers/optee.h> +#include <nuttx/kmalloc.h> +#include <nuttx/mutex.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/un.h> + +#include "optee_msg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Some GlobalPlatform error codes used in this driver */ + +#define TEE_SUCCESS 0x00000000 +#define TEE_ERROR_BAD_PARAMETERS 0xFFFF0006 +#define TEE_ERROR_NOT_SUPPORTED 0xFFFF000A +#define TEE_ERROR_COMMUNICATION 0xFFFF000E +#define TEE_ERROR_OUT_OF_MEMORY 0xFFFF000C +#define TEE_ERROR_BUSY 0xFFFF000D +#define TEE_ERROR_SHORT_BUFFER 0xFFFF0010 + +#define TEE_ORIGIN_COMMS 0x00000002 + +#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_ioctl_param) * (x)) + +#define OPTEE_MAX_IOVEC_NUM 7 +#define OPTEE_MAX_PARAM_NUM 6 + +#define OPTEE_SERVER_PATH "optee" +#define OPTEE_DEV_PATH "/dev/tee0" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* The file operation functions */ + +static int optee_open(FAR struct file *filep); +static int optee_close(FAR struct file *filep); +static int optee_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* File operations */ + +static const struct file_operations g_optee_ops = +{ + optee_open, /* open */ + optee_close, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + optee_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + NULL /* poll */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: optee_open + * + * Description: + * optee open operation + * + * Parameters: + * filep - the file instance + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int optee_open(FAR struct file *filep) +{ + FAR struct socket *psock; +#ifdef CONFIG_DEV_OPTEE_LOCAL + struct sockaddr_un addr; +#else + struct sockaddr_rpmsg addr; +#endif + int ret; + + psock = (FAR struct socket *)kmm_zalloc(sizeof(struct socket)); + if (psock == NULL) + { + return -ENOMEM; + } + +#ifdef CONFIG_DEV_OPTEE_LOCAL + ret = psock_socket(AF_UNIX, SOCK_STREAM, 0, psock); +#else + ret = psock_socket(AF_RPMSG, SOCK_STREAM, 0, psock); +#endif + if (ret < 0) + { + kmm_free(psock); + 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(psock, (FAR const struct sockaddr *)&addr, + sizeof(addr)); + if (ret < 0) + { + psock_close(psock); + kmm_free(psock); + return ret; + } + + filep->f_priv = psock; + return 0; +} + +/**************************************************************************** + * Name: optee_close + * + * Description: + * optee close operation + * + * Parameters: + * filep - the file instance + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int optee_close(FAR struct file *filep) +{ + FAR struct socket *psock = filep->f_priv; + + psock_close(psock); + kmm_free(psock); + return 0; +} + +static int optee_to_msg_param(FAR struct optee_msg_param *mparams, + size_t num_params, + FAR const struct tee_ioctl_param *params) +{ + size_t n; + + for (n = 0; n < num_params; n++) + { + FAR const struct tee_ioctl_param *p = params + n; + FAR struct optee_msg_param *mp = mparams + n; + + if (p->attr & ~TEE_IOCTL_PARAM_ATTR_MASK) + { + return -EINVAL; + } + + switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) + { + case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: + mp->attr = OPTEE_MSG_ATTR_TYPE_NONE; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr - + TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + mp->u.value.a = p->a; + mp->u.value.b = p->b; + mp->u.value.c = p->c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + mp->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + p->attr - + TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + if (p->c != TEE_MEMREF_NULL) + { + mp->u.rmem.shm_ref = p->c; + } + else + { + mp->u.rmem.shm_ref = 0; + } + + mp->u.rmem.size = p->b; + mp->u.rmem.offs = p->a; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static int optee_from_msg_param(FAR struct tee_ioctl_param *params, + size_t num_params, + FAR const struct optee_msg_param *mparams) +{ + size_t n; + + for (n = 0; n < num_params; n++) + { + FAR const struct optee_msg_param *mp = mparams + n; + FAR struct tee_ioctl_param *p = params + n; + + switch (mp->attr & OPTEE_MSG_ATTR_TYPE_MASK) + { + case OPTEE_MSG_ATTR_TYPE_NONE: + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + p->a = 0; + p->b = 0; + p->c = 0; + break; + case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT: + case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT: + case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT: + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT + + mp->attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + p->a = mp->u.value.a; + p->b = mp->u.value.b; + p->c = mp->u.value.c; + break; + case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT: + case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT: + case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT: + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT + + mp->attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; + p->b = mp->u.rmem.size; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static ssize_t optee_recv(FAR struct socket *psock, FAR void *msg, + size_t size) +{ + size_t remain = size; + + while (remain) + { + ssize_t n = psock_recv(psock, msg, remain, 0); + if (n <= 0) + { + return remain == size ? n : size - remain; + } + + remain -= n; + msg = (FAR char *)msg + n; + } + + return size; +} + +static int optee_send_recv(FAR struct socket *psocket, + 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 + */ + + 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_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(psocket, &msghdr, 0); + if (ret < 0) + { + return ret; + } + + ret = optee_recv(psocket, 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_recv(psocket, + (FAR void *)(uintptr_t) + arg->params[i].u.rmem.shm_ref, size); + if (ret < 0) + { + return ret; + } + } + } + + return 0; +} + +static int optee_ioctl_open_session(FAR struct socket *psocket, + FAR struct tee_ioctl_buf_data *buf) +{ + char msg_buf[OPTEE_MSG_GET_ARG_SIZE(OPTEE_MAX_PARAM_NUM)]; + FAR struct tee_ioctl_open_session_arg *arg; + FAR struct optee_msg_arg *msg; + int ret; + + if (buf->buf_len > TEE_MAX_ARG_SIZE || + buf->buf_len < sizeof(struct tee_ioctl_open_session_arg)) + { + return -EINVAL; + } + + arg = (FAR struct tee_ioctl_open_session_arg *)(uintptr_t)buf->buf_ptr; + + if (sizeof(*arg) + TEE_IOCTL_PARAM_SIZE(arg->num_params) != + buf->buf_len) + { + return -EINVAL; + } + + if (arg->num_params + 2 > OPTEE_MAX_PARAM_NUM) + { + return -EINVAL; + } + + if (arg->clnt_login >= TEE_IOCTL_LOGIN_REE_KERNEL_MIN && + arg->clnt_login <= TEE_IOCTL_LOGIN_REE_KERNEL_MAX) + { + return -EPERM; + } + + arg->ret = TEE_ERROR_COMMUNICATION; + arg->ret_origin = TEE_ORIGIN_COMMS; + + memset(msg_buf, 0, sizeof(msg_buf)); + msg = (FAR struct optee_msg_arg *)&msg_buf[0]; + + msg->cmd = OPTEE_MSG_CMD_OPEN_SESSION; + msg->cancel_id = arg->cancel_id; + msg->num_params = arg->num_params + 2; + + /* Initialize and add the meta parameters needed when opening a + * session. + */ + + msg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT | + OPTEE_MSG_ATTR_META; + msg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT | + OPTEE_MSG_ATTR_META; + memcpy(&msg->params[0].u.value, arg->uuid, sizeof(arg->uuid)); + msg->params[1].u.value.c = arg->clnt_login; + + ret = optee_to_msg_param(msg->params + 2, arg->num_params, arg->params); + if (ret < 0) + { + return ret; + } + + ret = optee_send_recv(psocket, msg); + if (ret < 0) + { + return ret; + } + + ret = optee_from_msg_param(arg->params, arg->num_params, + msg->params + 2); + if (ret < 0) + { + return ret; + } + + arg->session = msg->session; + arg->ret = msg->ret; + arg->ret_origin = msg->ret_origin; + + return ret; +} + +static int optee_ioctl_invoke(FAR struct socket *psocket, + FAR struct tee_ioctl_buf_data *buf) +{ + char msg_buf[OPTEE_MSG_GET_ARG_SIZE(OPTEE_MAX_PARAM_NUM)]; + FAR struct tee_ioctl_invoke_arg *arg; + FAR struct optee_msg_arg *msg; + int ret; + + if (buf->buf_len > TEE_MAX_ARG_SIZE || + buf->buf_len < sizeof(struct tee_ioctl_invoke_arg)) + { + return -EINVAL; + } + + arg = (FAR struct tee_ioctl_invoke_arg *)(uintptr_t)buf->buf_ptr; + + if (sizeof(*arg) + TEE_IOCTL_PARAM_SIZE(arg->num_params) != + buf->buf_len) + { + return -EINVAL; + } + + if (arg->num_params > OPTEE_MAX_PARAM_NUM) + { + return -EINVAL; + } + + arg->ret = TEE_ERROR_COMMUNICATION; + arg->ret_origin = TEE_ORIGIN_COMMS; + + memset(msg_buf, 0, sizeof(msg_buf)); + msg = (FAR struct optee_msg_arg *)&msg_buf[0]; + + msg->cmd = OPTEE_MSG_CMD_INVOKE_COMMAND; + msg->func = arg->func; + msg->session = arg->session; + msg->cancel_id = arg->cancel_id; + msg->num_params = arg->num_params; + + ret = optee_to_msg_param(msg->params, arg->num_params, arg->params); + if (ret < 0) + { + return ret; + } + + ret = optee_send_recv(psocket, msg); + if (ret < 0) + { + return ret; + } + + ret = optee_from_msg_param(arg->params, arg->num_params, msg->params); + if (ret < 0) + { + return ret; + } + + arg->ret = msg->ret; + arg->ret_origin = msg->ret_origin; + + return ret; +} + +static int +optee_ioctl_close_session(FAR struct socket *psocket, + FAR struct tee_ioctl_close_session_arg *arg) +{ + struct optee_msg_arg msg; + + memset(&msg, 0, sizeof(struct optee_msg_arg)); + msg.cmd = OPTEE_MSG_CMD_CLOSE_SESSION; + msg.session = arg->session; + msg.num_params = 0; + + return optee_send_recv(psocket, &msg); +} + +static int optee_ioctl_version(FAR struct tee_ioctl_version_data *vers) +{ + vers->impl_id = TEE_IMPL_ID_OPTEE; + vers->impl_caps = TEE_OPTEE_CAP_TZ; + vers->gen_caps = TEE_GEN_CAP_GP | TEE_GEN_CAP_MEMREF_NULL; + return 0; +} + +static int optee_ioctl_cancel(FAR struct socket *psocket, + FAR struct tee_ioctl_cancel_arg *arg) +{ + struct optee_msg_arg msg; + + memset(&msg, 0, sizeof(struct optee_msg_arg)); + msg.cmd = OPTEE_MSG_CMD_CANCEL; + msg.session = arg->session; + msg.cancel_id = arg->cancel_id; + return optee_send_recv(psocket, &msg); +} + +static int +optee_ioctl_shm_alloc(FAR struct tee_ioctl_shm_alloc_data *data) +{ + int memfd = memfd_create(OPTEE_SERVER_PATH, O_CREAT); Review Comment: I have a mixed feeling about this driver. It seems to be registered from the kernel, but uses user space API and access `errno`. Maybe be acceptable for FLAT builds, but not sure about the kernel separated mode. ########## drivers/misc/optee.c: ########## @@ -0,0 +1,648 @@ +/**************************************************************************** + * drivers/misc/optee.c + * + * 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/tee.h> + +#include <fcntl.h> +#include <netpacket/rpmsg.h> +#include <nuttx/drivers/optee.h> +#include <nuttx/kmalloc.h> +#include <nuttx/mutex.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/un.h> + +#include "optee_msg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Some GlobalPlatform error codes used in this driver */ + +#define TEE_SUCCESS 0x00000000 +#define TEE_ERROR_BAD_PARAMETERS 0xFFFF0006 +#define TEE_ERROR_NOT_SUPPORTED 0xFFFF000A +#define TEE_ERROR_COMMUNICATION 0xFFFF000E +#define TEE_ERROR_OUT_OF_MEMORY 0xFFFF000C +#define TEE_ERROR_BUSY 0xFFFF000D +#define TEE_ERROR_SHORT_BUFFER 0xFFFF0010 + +#define TEE_ORIGIN_COMMS 0x00000002 + +#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_ioctl_param) * (x)) + +#define OPTEE_MAX_IOVEC_NUM 7 +#define OPTEE_MAX_PARAM_NUM 6 + +#define OPTEE_SERVER_PATH "optee" +#define OPTEE_DEV_PATH "/dev/tee0" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* The file operation functions */ + +static int optee_open(FAR struct file *filep); +static int optee_close(FAR struct file *filep); +static int optee_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* File operations */ + +static const struct file_operations g_optee_ops = +{ + optee_open, /* open */ + optee_close, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + optee_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + NULL /* poll */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: optee_open + * + * Description: + * optee open operation + * + * Parameters: + * filep - the file instance + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int optee_open(FAR struct file *filep) +{ + FAR struct socket *psock; +#ifdef CONFIG_DEV_OPTEE_LOCAL + struct sockaddr_un addr; +#else + struct sockaddr_rpmsg addr; +#endif + int ret; + + psock = (FAR struct socket *)kmm_zalloc(sizeof(struct socket)); + if (psock == NULL) + { + return -ENOMEM; + } + +#ifdef CONFIG_DEV_OPTEE_LOCAL + ret = psock_socket(AF_UNIX, SOCK_STREAM, 0, psock); +#else + ret = psock_socket(AF_RPMSG, SOCK_STREAM, 0, psock); +#endif + if (ret < 0) + { + kmm_free(psock); + 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(psock, (FAR const struct sockaddr *)&addr, + sizeof(addr)); + if (ret < 0) + { + psock_close(psock); + kmm_free(psock); + return ret; + } + + filep->f_priv = psock; + return 0; +} + +/**************************************************************************** + * Name: optee_close + * + * Description: + * optee close operation + * + * Parameters: + * filep - the file instance + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int optee_close(FAR struct file *filep) +{ + FAR struct socket *psock = filep->f_priv; + + psock_close(psock); + kmm_free(psock); + return 0; +} + +static int optee_to_msg_param(FAR struct optee_msg_param *mparams, + size_t num_params, + FAR const struct tee_ioctl_param *params) +{ + size_t n; + + for (n = 0; n < num_params; n++) + { + FAR const struct tee_ioctl_param *p = params + n; + FAR struct optee_msg_param *mp = mparams + n; + + if (p->attr & ~TEE_IOCTL_PARAM_ATTR_MASK) + { + return -EINVAL; + } + + switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) + { + case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: + mp->attr = OPTEE_MSG_ATTR_TYPE_NONE; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: + mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr - + TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + mp->u.value.a = p->a; + mp->u.value.b = p->b; + mp->u.value.c = p->c; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: + mp->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + p->attr - + TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + if (p->c != TEE_MEMREF_NULL) + { + mp->u.rmem.shm_ref = p->c; + } + else + { + mp->u.rmem.shm_ref = 0; + } + + mp->u.rmem.size = p->b; + mp->u.rmem.offs = p->a; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static int optee_from_msg_param(FAR struct tee_ioctl_param *params, + size_t num_params, + FAR const struct optee_msg_param *mparams) +{ + size_t n; + + for (n = 0; n < num_params; n++) + { + FAR const struct optee_msg_param *mp = mparams + n; + FAR struct tee_ioctl_param *p = params + n; + + switch (mp->attr & OPTEE_MSG_ATTR_TYPE_MASK) + { + case OPTEE_MSG_ATTR_TYPE_NONE: + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + p->a = 0; + p->b = 0; + p->c = 0; + break; + case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT: + case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT: + case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT: + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT + + mp->attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + p->a = mp->u.value.a; + p->b = mp->u.value.b; + p->c = mp->u.value.c; + break; + case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT: + case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT: + case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT: + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT + + mp->attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; + p->b = mp->u.rmem.size; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static ssize_t optee_recv(FAR struct socket *psock, FAR void *msg, + size_t size) +{ + size_t remain = size; + + while (remain) + { + ssize_t n = psock_recv(psock, msg, remain, 0); + if (n <= 0) + { + return remain == size ? n : size - remain; + } + + remain -= n; + msg = (FAR char *)msg + n; + } + + return size; +} + +static int optee_send_recv(FAR struct socket *psocket, + 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 + */ + + 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_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(psocket, &msghdr, 0); + if (ret < 0) + { + return ret; + } + + ret = optee_recv(psocket, 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_recv(psocket, + (FAR void *)(uintptr_t) + arg->params[i].u.rmem.shm_ref, size); + if (ret < 0) + { + return ret; + } + } + } + + return 0; +} + +static int optee_ioctl_open_session(FAR struct socket *psocket, + FAR struct tee_ioctl_buf_data *buf) +{ + char msg_buf[OPTEE_MSG_GET_ARG_SIZE(OPTEE_MAX_PARAM_NUM)]; + FAR struct tee_ioctl_open_session_arg *arg; + FAR struct optee_msg_arg *msg; + int ret; + + if (buf->buf_len > TEE_MAX_ARG_SIZE || + buf->buf_len < sizeof(struct tee_ioctl_open_session_arg)) + { + return -EINVAL; + } + + arg = (FAR struct tee_ioctl_open_session_arg *)(uintptr_t)buf->buf_ptr; + + if (sizeof(*arg) + TEE_IOCTL_PARAM_SIZE(arg->num_params) != + buf->buf_len) + { + return -EINVAL; + } + + if (arg->num_params + 2 > OPTEE_MAX_PARAM_NUM) + { + return -EINVAL; + } + + if (arg->clnt_login >= TEE_IOCTL_LOGIN_REE_KERNEL_MIN && + arg->clnt_login <= TEE_IOCTL_LOGIN_REE_KERNEL_MAX) + { + return -EPERM; + } + + arg->ret = TEE_ERROR_COMMUNICATION; + arg->ret_origin = TEE_ORIGIN_COMMS; + + memset(msg_buf, 0, sizeof(msg_buf)); + msg = (FAR struct optee_msg_arg *)&msg_buf[0]; + + msg->cmd = OPTEE_MSG_CMD_OPEN_SESSION; + msg->cancel_id = arg->cancel_id; + msg->num_params = arg->num_params + 2; + + /* Initialize and add the meta parameters needed when opening a + * session. + */ + + msg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT | + OPTEE_MSG_ATTR_META; + msg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT | + OPTEE_MSG_ATTR_META; + memcpy(&msg->params[0].u.value, arg->uuid, sizeof(arg->uuid)); + msg->params[1].u.value.c = arg->clnt_login; + + ret = optee_to_msg_param(msg->params + 2, arg->num_params, arg->params); + if (ret < 0) + { + return ret; + } + + ret = optee_send_recv(psocket, msg); + if (ret < 0) + { + return ret; + } + + ret = optee_from_msg_param(arg->params, arg->num_params, + msg->params + 2); Review Comment: ```suggestion ret = optee_from_msg_param(arg->params, arg->num_params, msg->params + 2); ``` ########## include/nuttx/tee.h: ########## @@ -0,0 +1,479 @@ +/**************************************************************************** + * include/nuttx/tee.h + * + * Copyright (c) 2015-2016, 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_TEE_H +#define __INCLUDE_NUTTX_TEE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/fs/ioctl.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/** + * This file describes the API provided by a TEE driver to user space. + * + * Each TEE driver defines a TEE specific protocol which is used for the + * data passed back and forth using TEE_IOC_CMD. + */ + +/* Helpers to make the ioctl defines */ + +#define TEE_IOC_MAGIC 0xa4 +#define TEE_IOC_BASE 0 + +#define TEE_MAX_ARG_SIZE 1024 + +#define TEE_GEN_CAP_GP (1 << 0) /* GlobalPlatform compliant TEE */ +#define TEE_GEN_CAP_PRIVILEGED (1 << 1) /* Privileged device (for supplicant) */ +#define TEE_GEN_CAP_REG_MEM (1 << 2) /* Supports registering shared memory */ +#define TEE_GEN_CAP_MEMREF_NULL (1 << 3) /* NULL MemRef support */ + +#define TEE_MEMREF_NULL ((uint64_t)-1) /* NULL MemRef Buffer */ + +/** + * TEE Implementation ID + */ + +#define TEE_IMPL_ID_OPTEE 1 +#define TEE_IMPL_ID_AMDTEE 2 + +/** + * OP-TEE specific capabilities + */ + +#define TEE_OPTEE_CAP_TZ (1 << 0) + +/** + * struct tee_ioctl_version_data - TEE version + * @impl_id: [out] TEE implementation id + * @impl_caps: [out] Implementation specific capabilities + * @gen_caps: [out] Generic capabilities, defined by TEE_GEN_CAPS_* above + * + * Identifies the TEE implementation, @impl_id is one of TEE_IMPL_ID_* above. + * @impl_caps is implementation specific, for example TEE_OPTEE_CAP_* + * is valid when @impl_id == TEE_IMPL_ID_OPTEE. + */ + +struct tee_ioctl_version_data +{ + uint32_t impl_id; + uint32_t impl_caps; + uint32_t gen_caps; +}; + +/** + * TEE_IOC_VERSION - query version of TEE + * + * Takes a tee_ioctl_version_data struct and returns with the TEE version + * data filled in. + */ +#define TEE_IOC_VERSION _IOC(TEE_IOC_MAGIC << 8, TEE_IOC_BASE + 0) + +/** + * struct tee_ioctl_shm_alloc_data - Shared memory allocate argument + * @size: [in/out] Size of shared memory to allocate + * @flags: [in/out] Flags to/from allocation. + * @id: [out] Identifier of the shared memory + * + * The flags field should currently be zero as input. Updated by the call + * with actual flags as defined by TEE_IOCTL_SHM_* above. + * This structure is used as argument for TEE_IOC_SHM_ALLOC below. + */ + +struct tee_ioctl_shm_alloc_data +{ + uint64_t size; + uint32_t flags; + int32_t id; +}; + +/** + * TEE_IOC_SHM_ALLOC - allocate shared memory + * + * Allocates shared memory between the user space process and secure OS. + * + * Returns a file descriptor on success or < 0 on failure + * + * The returned file descriptor is used to map the shared memory into user + * space. The shared memory is freed when the descriptor is closed and the + * memory is unmapped. + */ + +#define TEE_IOC_SHM_ALLOC _IOC(TEE_IOC_MAGIC << 8, TEE_IOC_BASE + 1) + +/** + * struct tee_ioctl_shm_register_fd_data - Shared memory registering argument + * @fd: [in] file descriptor identifying the shared memory + * @size: [out] Size of shared memory to allocate + * @flags: [in] Flags to/from allocation. + * @id: [out] Identifier of the shared memory + * + * The flags field should currently be zero as input. Updated by the call + * with actual flags as defined by TEE_IOCTL_SHM_* above. + * This structure is used as argument for TEE_IOC_SHM_ALLOC below. + */ + +struct tee_ioctl_shm_register_fd_data +{ + int64_t fd; + uint64_t size; + uint32_t flags; + int32_t id; +}; + +/** + * Attributes for struct tee_ioctl_param, selects field in the union + */ + +#define TEE_IOCTL_PARAM_ATTR_TYPE_NONE 0 /* parameter not used */ + +/** + * These defines value parameters (struct tee_ioctl_param_value) + */ + +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT 1 +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT 2 +#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT 3 /* input and output */ + +/** + * These defines shared memory reference parameters (struct + * tee_ioctl_param_memref) + */ + +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT 5 +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6 +#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */ + +/** + * Mask for the type part of the attribute, leaves room for more types + */ + +#define TEE_IOCTL_PARAM_ATTR_TYPE_MASK 0xff + +/* Meta parameter carrying extra information about the message. */ + +#define TEE_IOCTL_PARAM_ATTR_META 0x100 + +/* Mask of all known attr bits */ +#define TEE_IOCTL_PARAM_ATTR_MASK \ + (TEE_IOCTL_PARAM_ATTR_TYPE_MASK | TEE_IOCTL_PARAM_ATTR_META) + +/** + * Matches TEEC_LOGIN_* in GP TEE Client API + * Are only defined for GP compliant TEEs + */ + +#define TEE_IOCTL_LOGIN_PUBLIC 0 +#define TEE_IOCTL_LOGIN_USER 1 +#define TEE_IOCTL_LOGIN_GROUP 2 +#define TEE_IOCTL_LOGIN_APPLICATION 4 +#define TEE_IOCTL_LOGIN_USER_APPLICATION 5 +#define TEE_IOCTL_LOGIN_GROUP_APPLICATION 6 + +/** + * Disallow user-space to use GP implementation specific login + * method range (0x80000000 - 0xBFFFFFFF). This range is rather + * being reserved for REE kernel clients or TEE implementation. + */ + +#define TEE_IOCTL_LOGIN_REE_KERNEL_MIN 0x80000000 +#define TEE_IOCTL_LOGIN_REE_KERNEL_MAX 0xBFFFFFFF + +/* Private login method for REE kernel clients */ + +#define TEE_IOCTL_LOGIN_REE_KERNEL 0x80000000 + +/** + * struct tee_ioctl_param - parameter + * @attr: attributes + * @a: if a memref, offset into the shared memory object, else a value + * parameter + * @b: if a memref, size of the buffer, else a value parameter + * @c: if a memref, shared memory identifier, else a value parameter + * + * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in + * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and + * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE + * indicates that none of the members are used. + * + * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an + * identifier representing the shared memory object. A memref can reference + * a part of a shared memory by specifying an offset (@a) and size (@b) of + * the object. To supply the entire shared memory object set the offset + * (@a) to 0 and size (@b) to the previously returned size of the object. + */ + +struct tee_ioctl_param +{ + uint64_t attr; + uint64_t a; + uint64_t b; + uint64_t c; +}; + +#define TEE_IOCTL_UUID_LEN 16 + +/** + * struct tee_ioctl_open_session_arg - Open session argument + * @uuid: [in] UUID of the Trusted Application + * @clnt_uuid: [in] UUID of client + * @clnt_login: [in] Login class of client, TEE_IOCTL_LOGIN_* above + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @session: [out] Session id + * @ret: [out] return value + * @ret_origin [out] origin of the return value + * @num_params [in] number of parameters following this struct + */ + +struct tee_ioctl_open_session_arg +{ + uint8_t uuid[TEE_IOCTL_UUID_LEN]; + uint8_t clnt_uuid[TEE_IOCTL_UUID_LEN]; + uint32_t clnt_login; + uint32_t cancel_id; + uint32_t session; + uint32_t ret; + uint32_t ret_origin; + uint32_t num_params; + + /* num_params tells the actual number of element in params */ + + struct tee_ioctl_param params[]; +}; + +/** + * TEE_IOC_OPEN_SESSION - opens a session to a Trusted Application + * + * Takes a struct tee_ioctl_buf_data which contains a struct + * tee_ioctl_open_session_arg followed by any array of struct + * tee_ioctl_param + */ + +#define TEE_IOC_OPEN_SESSION _IOC(TEE_IOC_MAGIC << 8, TEE_IOC_BASE + 2) + +/** + * struct tee_ioctl_invoke_func_arg - Invokes a function in a Trusted + * Application + * @func: [in] Trusted Application function, specific to the TA + * @session: [in] Session id + * @cancel_id: [in] Cancellation id, a unique value to identify this request + * @ret: [out] return value + * @ret_origin [out] origin of the return value + * @num_params [in] number of parameters following this struct + */ + +struct tee_ioctl_invoke_arg +{ + uint32_t func; + uint32_t session; + uint32_t cancel_id; + uint32_t ret; + uint32_t ret_origin; + uint32_t num_params; + + /* num_params tells the actual number of element in params */ + + struct tee_ioctl_param params[]; Review Comment: C89 incompatible -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org