xiaoxiang781216 commented on code in PR #16309:
URL: https://github.com/apache/nuttx/pull/16309#discussion_r2075950987


##########
drivers/misc/optee.c:
##########
@@ -154,6 +202,248 @@ static bool optee_is_valid_range(FAR void *va, size_t 
size)
 #  define optee_is_valid_range(addr, size) (true)
 #endif
 
+/****************************************************************************
+ * Name: optee_msg_alloc
+ *
+ * Description:
+ *   Allocate OP-TEE page-aligned memory for use as arguments to OP-TEE
+ *   calls, large enough to fit `num_params` parameters. Initialize the
+ *   buffer to 0, and set the `.num_params` field to the specified value.
+ *
+ *   Use `kmm_free()` to free the memory returned.
+ *
+ * Parameters:
+ *   priv       - the driver's private data structure
+ *   num_params - the number of arguments to allocate shared memory for.
+ *                Can be zero.
+ *
+ * Returned Values:
+ *   On success, pointer to OP-TEE message arguments struct initialized
+ *   to 0 except for `.num_params`, which is initialized to the specified.
+ *   On failure, NULL.
+ *
+ ****************************************************************************/
+
+static FAR struct optee_msg_arg *
+optee_msg_alloc(FAR struct optee_priv_data *priv, uint32_t num_params)
+{
+  FAR struct optee_msg_arg *msg;
+
+  if (priv->alignment)
+    {
+      msg = kmm_memalign(priv->alignment,
+                         OPTEE_MSG_GET_ARG_SIZE(num_params));
+    }
+  else
+    {
+      msg = kmm_malloc(OPTEE_MSG_GET_ARG_SIZE(num_params));
+    }
+
+  if (msg == NULL)
+    {
+      return NULL;
+    }
+
+  memset(msg, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
+  msg->num_params = num_params;
+
+  return msg;
+}
+
+/****************************************************************************
+ * Name: optee_shm_to_page_list
+ *
+ * Description:
+ *   Provide a page list of a shared memory buffer. Secure world doesn't
+ *   know about the address environment mapping of NuttX, so physical
+ *   pointers are needed when sharing memory. This implementation enables
+ *   sharing of physically non-contiguous buffers according to
+ *   optee_msg.h#OPTEE_MSG_ATTR_NONCONTIG.
+ *   Each entry in the generated page list is an array of the physical,
+ *   potentially non-contiguous pages making up the actual buffer to
+ *   represent. Note that this representation does not account for the page
+ *   offset of the shared memory buffer. The offset is encoded in the
+ *   physical address returned in `list_pa`.
+ *
+ * Parameters:
+ *   shme        - Shared memory entry to create a page list for.
+ *   list_pa     - If not NULL, will be set to the page list's physical
+ *                 address (which is aligned to
+ *                 OPTEE_MSG_NONCONTIG_PAGE_SIZE) added with shared memory
+ *                 page offset.
+ *
+ * Returned Values:
+ *   A pointer to the kernel virtual address of the page list on success.
+ *   NULL on failure. Caller responsible to free the returned list using
+ *   `kmm_free()`.
+ *
+ ****************************************************************************/
+
+FAR void *optee_shm_to_page_list(FAR struct optee_shm_entry *shme,
+                                 FAR uintptr_t *list_pa)
+{
+  size_t pgsize = OPTEE_MSG_NONCONTIG_PAGE_SIZE;
+  uintptr_t pgoff;
+  uintptr_t page;
+  uint32_t total_pages;
+  uint32_t list_size;
+  FAR void *list;
+  FAR struct optee_page_list_entry *list_entry;
+  uint32_t i = 0;
+
+  pgoff = shme->shm.addr & (pgsize - 1);
+  total_pages = (uint32_t)div_round_up(pgoff + shme->shm.length, pgsize);
+  list_size = div_round_up(total_pages, OPTEE_PAGES_ARRAY_LEN)
+              * sizeof(struct optee_page_list_entry);
+
+  /* Page list's address should be page aligned, conveniently leaving
+   * log2(<page size>) zero least-significant bits to use as the page
+   * offset of the shm buffer (added last before return below).
+   */
+
+  list = kmm_memalign(pgsize, list_size);
+  if (!list)
+    {
+      return NULL;
+    }
+
+  list_entry = (FAR struct optee_page_list_entry *)list;
+  page = ALIGN_DOWN(shme->shm.addr, pgsize);
+  while (total_pages)
+    {
+      list_entry->pages_array[i++] = optee_va_to_pa((FAR void *)page);
+      page += pgsize;
+      total_pages--;
+
+      if (i == OPTEE_PAGES_ARRAY_LEN)
+        {
+          list_entry->next_entry = optee_va_to_pa(list_entry + 1);
+          list_entry++;
+          i = 0;
+        }
+    }
+
+  if (list_pa)
+    {
+      *list_pa = optee_va_to_pa(list) | pgoff;
+    }
+
+  return list;
+}
+
+/****************************************************************************
+ * Name: optee_shm_sec_register
+ *
+ * Description:
+ *   Register specified shared memory entry with OP-TEE.
+ *
+ * Parameters:
+ *   priv  - The driver's private data structure
+ *   shme  - Pointer to shared memory entry to register. The entry, the
+ *           contained shared memory object, or the referenced shared buffer
+ *           cannot be NULL.
+ *
+ * Returned Values:
+ *   0 on success, negative error code otherwise.
+ *
+ ****************************************************************************/
+
+static int optee_shm_sec_register(FAR struct optee_priv_data *priv,
+                                  FAR struct optee_shm_entry *shme)
+{
+  FAR struct optee_msg_arg *msg;
+  FAR void *page_list;
+  uintptr_t page_list_pa;
+  int ret = 0;
+
+  msg = optee_msg_alloc(priv, 1);
+  if (msg == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  page_list = optee_shm_to_page_list(shme, &page_list_pa);
+  if (page_list == NULL)
+    {
+      ret = -ENOMEM;
+      goto errout_with_msg;
+    }
+
+  msg->cmd = OPTEE_MSG_CMD_REGISTER_SHM;
+  msg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
+                        OPTEE_MSG_ATTR_NONCONTIG;
+  msg->params[0].u.tmem.buf_ptr = page_list_pa;
+  msg->params[0].u.tmem.shm_ref = shme->shm.addr;
+  msg->params[0].u.tmem.size = shme->shm.length;
+
+  ret = optee_transport_call(priv, msg);
+  if (ret < 0)
+    {
+      goto errout_with_list;
+    }
+
+  if (msg->ret)
+    {
+      ret = optee_convert_error(msg->ret);
+    }
+
+errout_with_list:
+  kmm_free(page_list);
+

Review Comment:
   remove the blank line



##########
include/nuttx/tee.h:
##########
@@ -378,6 +378,13 @@ struct tee_iocl_supp_send_arg
 
 #define TEE_IOC_SUPPL_SEND _IOC(TEE_IOC_MAGIC << 8, TEE_IOC_BASE + 7)
 
+/* Shared memory specific defines */
+
+#define TEE_SHM_REGISTER        (1 << 0) /* In list of shared memory */
+#define TEE_SHM_SEC_REGISTER    (1 << 1) /* TEE notified of this memory */

Review Comment:
   remove the extra spaces



##########
drivers/misc/optee_smc.c:
##########
@@ -0,0 +1,322 @@
+/****************************************************************************
+ * drivers/misc/optee_smc.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/config.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <arch/syscall.h>
+
+#include "optee.h"
+#include "optee_smc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_ARM)
+#  define smccc_smc                  arm_smccc_smc
+#  define smccc_hvc                  arm_smccc_hvc
+#  define smccc_res_t                arm_smccc_res_t
+#elif defined(CONFIG_ARCH_ARM64)
+#  define smccc_smc                  arm64_smccc_smc
+#  define smccc_hvc                  arm64_smccc_hvc
+#  define smccc_res_t                arm64_smccc_res_t
+#else
+#  error "CONFIG_DEV_OPTEE_SMC is only supported on arm and arm64"
+#endif
+
+#ifdef CONFIG_DEV_OPTEE_SMC_CONDUIT_SMC
+#  define smc_conduit                smccc_smc
+#else
+#  define smc_conduit                smccc_hvc
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef void (*optee_smc_fn)(unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long,
+                             FAR smccc_res_t *);
+
+union optee_os_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_call_get_os_revision_result result;
+};
+
+union optee_calls_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_calls_revision_result result;
+};
+
+union optee_exchg_caps
+{
+  smccc_res_t smccc;
+  struct optee_smc_exchange_capabilities_result result;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static bool optee_smc_is_compatible(optee_smc_fn smc_fn)
+{
+  smccc_res_t callsuid;
+  union optee_os_revision osrev;
+  union optee_calls_revision callsrev;
+  union optee_exchg_caps xchgcaps;
+
+  /* Print the OS revision and build ID (if reported) */
+
+  osrev.result.build_id = 0;
+
+  smc_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0, &osrev.smccc);
+
+  if (osrev.result.build_id)
+    {
+      syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu (%08lx)\n",
+                       osrev.result.major, osrev.result.minor,
+                       osrev.result.build_id);
+    }
+  else
+    {
+      syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu\n",
+                       osrev.result.major, osrev.result.minor);
+    }
+
+  /* Check the API UID */
+
+  smc_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &callsuid);
+
+  if (callsuid.a0 != OPTEE_MSG_UID_0 || callsuid.a1 != OPTEE_MSG_UID_1 ||
+      callsuid.a2 != OPTEE_MSG_UID_2 || callsuid.a3 != OPTEE_MSG_UID_3)
+    {
+      syslog(LOG_ERR, "OP-TEE: API UID mismatch\n");
+      return false;
+    }
+
+  /* Check the API revision */
+
+  smc_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &callsrev.smccc);
+
+  if (callsrev.result.major != OPTEE_MSG_REVISION_MAJOR ||
+      (int)callsrev.result.minor < OPTEE_MSG_REVISION_MINOR)
+    {
+      syslog(LOG_ERR, "OP-TEE: API revision incompatible\n");
+      return false;
+    }
+
+  /* Check the capabilities */
+
+  smc_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, OPTEE_SMC_NSEC_CAP_UNIPROCESSOR,
+         0, 0, 0, 0, 0, 0, &xchgcaps.smccc);
+
+  if (xchgcaps.result.status != OPTEE_SMC_RETURN_OK)
+    {
+      syslog(LOG_ERR, "OP-TEE: Failed to exchange capabilities\n");
+      return false;
+    }
+
+  if (!(xchgcaps.result.capabilities & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM))
+    {
+      syslog(LOG_ERR, "OP-TEE: Does not support dynamic shared mem\n");
+      return false;
+    }
+
+  return true;
+}
+
+static void optee_smc_handle_rpc(FAR struct optee_priv_data *priv,
+                                 FAR smccc_res_t *par)
+{
+  FAR struct optee_shm_entry *shme;
+  uintptr_t shme_pa;
+  uint32_t rpc_func;
+  size_t shm_size;
+
+  rpc_func = OPTEE_SMC_RETURN_GET_RPC_FUNC(par->a0);
+  par->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
+
+  switch (rpc_func)
+    {
+      case OPTEE_SMC_RPC_FUNC_ALLOC:
+        {

Review Comment:
   remove ALL {} in each case



##########
drivers/misc/optee.c:
##########
@@ -608,6 +989,197 @@ static int optee_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
  * Public Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: optee_va_to_pa
+ *
+ * Description:
+ *   Convert the specified virtual address to a physical address. If the
+ *   virtual address does not belong to the user, it is assumed to be a
+ *   kernel virtual address with a 1-1 mapping and the VA is returned as-is.
+ *   The VA is also returned as-is if this is a build without
+ *   CONFIG_ARCH_ADDRENV.
+ *
+ * Parameters:
+ *   va    - The virtual address to convert.
+ *
+ * Returned Values:
+ *   The physical address corresponding to the specified VA.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_ADDRENV
+uintptr_t optee_va_to_pa(FAR void *va)
+{
+  FAR struct tcb_s *tcb;
+  FAR arch_addrenv_t *addrenv;
+  uintptr_t page;
+
+  tcb = nxsched_self();
+  addrenv = &tcb->addrenv_curr->addrenv;
+
+  page = up_addrenv_find_page(addrenv, (uintptr_t)va);
+  if (page == 0)
+    {
+      return (uintptr_t)va;
+    }
+
+  return page | ((uintptr_t)va & MM_PGMASK);
+}
+#endif
+
+/****************************************************************************
+ * Name: optee_shm_alloc
+ *
+ * Description:
+ *   Allocate, register and/or add shared memory for use with OP-TEE calls.
+ *   Shared memory entry suitable for use in shared memory linked list
+ *   returned in pass-by-reference `shmep` pointer. This function always
+ *   allocates a shared memory entry, regardless of flags. The rest of this
+ *   function's behaviour is largely determined by `flags`:
+ *   - If `TEE_SHM_ALLOC` is specified, then a buffer of length `size` will
+ *     be allocated. In this case `addr` will be ignored. If `align` is
+ *     true, the allocated buffer will be aligned to `priv->alignment`.
+ *     `TEE_SHM_ALLOC` flag is reserved for kernel use only.
+ *   - If `TEE_SHM_SEC_REGISTER` is specified, then the memory specified by
+ *     `addr` or allocated through `TEE_SHM_ALLOC`, will be registered with
+ *     OP-TEE as dynamic shared memory.
+ *   - If `TEE_SHM_REGISTER` is specified, then the memory specified by
+ *     `addr` or allocated through `TEE_SHM_ALLOC`, will be added to the
+ *     driver's private data structure linked list of shared memory chunks.
+ *
+ *   Use `optee_shm_free()` to undo this operation, i.e. to free,
+ *   unregister, and/or remove from the list the entry returned in `shmep`
+ *   and the contained buffer.
+ *
+ * Parameters:
+ *   priv  - The driver's private data structure
+ *   align - Align the allocated memory according to OP-TEE requirements.
+ *           Ignored when `flags` do not specify `TEE_SHM_ALLOC`.
+ *   addr  - The address of the shared memory to register with OP-TEE and/or
+ *           add to the driver's linked list of shared memory chunks.
+ *   size  - The size of the shared memory buffer to allocate/add/register.
+ *   flags - Flags specifying the behaviour of this function. Supports
+ *           combinations of `TEE_SHM_{ALLOC,REGISTER,SEC_REGISTER}`.
+ *   shmep - Pass-by-reference pointer to return the shared memory entry
+ *           allocated. Cannot be NULL.
+ *
+ * Returned Values:
+ *   0 on success, negative error code otherwise.
+ *
+ ****************************************************************************/
+
+int optee_shm_alloc(FAR struct optee_priv_data *priv, bool align,
+                    FAR void *addr, size_t size, uint32_t flags,
+                    FAR struct optee_shm_entry **shmep)
+{
+  FAR struct optee_shm_entry *shme;
+  FAR void *ptr;
+  int ret;
+
+  shme = (FAR struct optee_shm_entry *)
+            kmm_zalloc(sizeof(struct optee_shm_entry));
+  if (shme == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  if (flags & TEE_SHM_ALLOC)
+    {
+      if (align && priv->alignment)
+        {
+          ptr = kmm_memalign(priv->alignment, size);
+        }
+      else
+        {
+          ptr = kmm_malloc(size);
+        }
+    }
+  else
+    {
+      ptr = addr;
+    }
+
+  if (ptr == NULL)
+    {
+      ret = -ENOMEM;
+      goto err;
+    }
+
+  shme->shm.addr = (uintptr_t)ptr;
+  shme->shm.length = size;
+  shme->shm.flags = flags;
+
+  if (flags & TEE_SHM_SEC_REGISTER)
+    {
+      ret = optee_shm_sec_register(priv, shme);
+      if (ret < 0)
+        {
+          goto err;
+        }
+    }
+
+  if (flags & TEE_SHM_REGISTER)
+    {
+      list_add_head(&priv->shm_list, &shme->node);
+    }
+
+  *shmep = shme;
+

Review Comment:
   remove the blank line



##########
drivers/misc/optee.h:
##########
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * drivers/misc/optee.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_MISC_OPTEE_H
+#define __DRIVERS_MISC_OPTEE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/compiler.h>
+#include <nuttx/tee.h>
+
+#include "optee_msg.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define OPTEE_SERVER_PATH              "optee"
+#define OPTEE_MAX_PARAM_NUM            6
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct optee_priv_data;
+
+struct optee_priv_data

Review Comment:
   After more thinking, it may better to:
   ```
   // drivers/misc/optee.h
   struct optee_priv_data
   {
   };
   
   // drivers/misc/optee_socket.c
   struct optee_socket_priv_data
   {
     struct optee_priv_data base;
     struct psock socket;
   };
   
   int optee_transport_open(FAR struct optee_priv_data **priv_)
   {
     FAR struct optee_socket_priv_data *priv;
   
     priv = kmm_zalloc(sizeof(struct optee_socket_priv_data ));
     ...
   }
   ```
   so, we can do one allocation.



##########
drivers/misc/optee.h:
##########
@@ -64,6 +72,16 @@ extern "C"
 #define EXTERN extern
 #endif
 
+#ifdef CONFIG_ARCH_ADDRENV
+uintptr_t optee_va_to_pa(FAR void *va);
+#else
+#  define optee_va_to_pa(va)           ((uintptr_t)va)

Review Comment:
   remove the  extra spaces



##########
drivers/misc/optee.c:
##########
@@ -562,6 +892,55 @@ optee_ioctl_shm_alloc(FAR struct tee_ioctl_shm_alloc_data 
*data)
   return get_errno();
 }
 
+static int
+optee_ioctl_shm_register(FAR struct optee_priv_data *priv,
+                         FAR struct tee_ioctl_shm_register_data *rdata)
+{
+  FAR struct optee_shm_entry *shme;
+  int rc;

Review Comment:
   int ret



##########
drivers/misc/optee.h:
##########
@@ -64,6 +72,16 @@ extern "C"
 #define EXTERN extern
 #endif
 
+#ifdef CONFIG_ARCH_ADDRENV
+uintptr_t optee_va_to_pa(FAR void *va);
+#else
+#  define optee_va_to_pa(va)           ((uintptr_t)va)
+#endif
+int optee_shm_alloc(FAR struct optee_priv_data *priv, bool align,

Review Comment:
   why need align parameter



##########
drivers/misc/optee.c:
##########
@@ -207,10 +499,18 @@ static int optee_open(FAR struct file *filep)
 
 static int optee_close(FAR struct file *filep)
 {
+  FAR struct optee_shm_entry *shme;
+  FAR struct optee_shm_entry *tmp;
   FAR struct optee_priv_data *priv = filep->f_priv;

Review Comment:
   move before line 502



##########
drivers/misc/optee.c:
##########
@@ -99,6 +104,56 @@ static const struct file_operations g_optee_ops =
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: optee_is_valid_range
+ *
+ * Description:
+ *   Check whether provided virtual address is not NULL and the address
+ *   range belongs to user-owned memory. If this function is called from a
+ *   kernel thread, it returns true. If this function is called in a build
+ *   without CONFIG_ARCH_ADDRENV it always returns true.
+ *
+ * Parameters:
+ *   va    - Beginning of address range to check.
+ *   size  - Size of memory to check.
+ *
+ * Returned Values:
+ *   True if the provided address range is not NULL and belongs to the user
+ *   or the caller is a kernel thread. False otherwise.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_ADDRENV
+static bool optee_is_valid_range(FAR void *va, size_t size)

Review Comment:
   `static bool optee_is_valid_range(FAR const void *va, size_t size)`



##########
drivers/misc/optee_smc.c:
##########
@@ -0,0 +1,322 @@
+/****************************************************************************
+ * drivers/misc/optee_smc.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/config.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <arch/syscall.h>
+
+#include "optee.h"
+#include "optee_smc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_ARM)
+#  define smccc_smc                  arm_smccc_smc
+#  define smccc_hvc                  arm_smccc_hvc
+#  define smccc_res_t                arm_smccc_res_t
+#elif defined(CONFIG_ARCH_ARM64)
+#  define smccc_smc                  arm64_smccc_smc
+#  define smccc_hvc                  arm64_smccc_hvc
+#  define smccc_res_t                arm64_smccc_res_t
+#else
+#  error "CONFIG_DEV_OPTEE_SMC is only supported on arm and arm64"
+#endif
+
+#ifdef CONFIG_DEV_OPTEE_SMC_CONDUIT_SMC
+#  define smc_conduit                smccc_smc
+#else
+#  define smc_conduit                smccc_hvc
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef void (*optee_smc_fn)(unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long,
+                             FAR smccc_res_t *);
+
+union optee_os_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_call_get_os_revision_result result;
+};
+
+union optee_calls_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_calls_revision_result result;
+};
+
+union optee_exchg_caps
+{
+  smccc_res_t smccc;
+  struct optee_smc_exchange_capabilities_result result;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static bool optee_smc_is_compatible(optee_smc_fn smc_fn)
+{
+  smccc_res_t callsuid;

Review Comment:
   move after line 98



##########
drivers/misc/optee.c:
##########
@@ -154,6 +202,248 @@ static bool optee_is_valid_range(FAR void *va, size_t 
size)
 #  define optee_is_valid_range(addr, size) (true)
 #endif
 
+/****************************************************************************
+ * Name: optee_msg_alloc
+ *
+ * Description:
+ *   Allocate OP-TEE page-aligned memory for use as arguments to OP-TEE
+ *   calls, large enough to fit `num_params` parameters. Initialize the
+ *   buffer to 0, and set the `.num_params` field to the specified value.
+ *
+ *   Use `kmm_free()` to free the memory returned.
+ *
+ * Parameters:
+ *   priv       - the driver's private data structure
+ *   num_params - the number of arguments to allocate shared memory for.
+ *                Can be zero.
+ *
+ * Returned Values:
+ *   On success, pointer to OP-TEE message arguments struct initialized
+ *   to 0 except for `.num_params`, which is initialized to the specified.
+ *   On failure, NULL.
+ *
+ ****************************************************************************/
+
+static FAR struct optee_msg_arg *
+optee_msg_alloc(FAR struct optee_priv_data *priv, uint32_t num_params)
+{
+  FAR struct optee_msg_arg *msg;
+
+  if (priv->alignment)
+    {
+      msg = kmm_memalign(priv->alignment,
+                         OPTEE_MSG_GET_ARG_SIZE(num_params));
+    }
+  else
+    {
+      msg = kmm_malloc(OPTEE_MSG_GET_ARG_SIZE(num_params));
+    }
+
+  if (msg == NULL)
+    {
+      return NULL;
+    }
+
+  memset(msg, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
+  msg->num_params = num_params;
+
+  return msg;
+}
+
+/****************************************************************************
+ * Name: optee_shm_to_page_list
+ *
+ * Description:
+ *   Provide a page list of a shared memory buffer. Secure world doesn't
+ *   know about the address environment mapping of NuttX, so physical
+ *   pointers are needed when sharing memory. This implementation enables
+ *   sharing of physically non-contiguous buffers according to
+ *   optee_msg.h#OPTEE_MSG_ATTR_NONCONTIG.
+ *   Each entry in the generated page list is an array of the physical,
+ *   potentially non-contiguous pages making up the actual buffer to
+ *   represent. Note that this representation does not account for the page
+ *   offset of the shared memory buffer. The offset is encoded in the
+ *   physical address returned in `list_pa`.
+ *
+ * Parameters:
+ *   shme        - Shared memory entry to create a page list for.
+ *   list_pa     - If not NULL, will be set to the page list's physical
+ *                 address (which is aligned to
+ *                 OPTEE_MSG_NONCONTIG_PAGE_SIZE) added with shared memory
+ *                 page offset.
+ *
+ * Returned Values:
+ *   A pointer to the kernel virtual address of the page list on success.
+ *   NULL on failure. Caller responsible to free the returned list using
+ *   `kmm_free()`.
+ *
+ ****************************************************************************/
+
+FAR void *optee_shm_to_page_list(FAR struct optee_shm_entry *shme,
+                                 FAR uintptr_t *list_pa)
+{
+  size_t pgsize = OPTEE_MSG_NONCONTIG_PAGE_SIZE;
+  uintptr_t pgoff;
+  uintptr_t page;
+  uint32_t total_pages;
+  uint32_t list_size;
+  FAR void *list;
+  FAR struct optee_page_list_entry *list_entry;
+  uint32_t i = 0;

Review Comment:
   ```
     FAR struct optee_page_list_entry *list_entry;
     size_t pgsize = OPTEE_MSG_NONCONTIG_PAGE_SIZE;
     uintptr_t pgoff;
     uintptr_t page;
     FAR void *list;
     uint32_t total_pages;
     uint32_t list_size;
     uint32_t i = 0;
   ```



##########
drivers/misc/optee_smc.c:
##########
@@ -0,0 +1,322 @@
+/****************************************************************************
+ * drivers/misc/optee_smc.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/config.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <arch/syscall.h>
+
+#include "optee.h"
+#include "optee_smc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_ARM)
+#  define smccc_smc                  arm_smccc_smc
+#  define smccc_hvc                  arm_smccc_hvc
+#  define smccc_res_t                arm_smccc_res_t
+#elif defined(CONFIG_ARCH_ARM64)
+#  define smccc_smc                  arm64_smccc_smc
+#  define smccc_hvc                  arm64_smccc_hvc
+#  define smccc_res_t                arm64_smccc_res_t
+#else
+#  error "CONFIG_DEV_OPTEE_SMC is only supported on arm and arm64"
+#endif
+
+#ifdef CONFIG_DEV_OPTEE_SMC_CONDUIT_SMC
+#  define smc_conduit                smccc_smc
+#else
+#  define smc_conduit                smccc_hvc
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef void (*optee_smc_fn)(unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long,
+                             FAR smccc_res_t *);
+
+union optee_os_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_call_get_os_revision_result result;
+};
+
+union optee_calls_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_calls_revision_result result;
+};
+
+union optee_exchg_caps
+{
+  smccc_res_t smccc;
+  struct optee_smc_exchange_capabilities_result result;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static bool optee_smc_is_compatible(optee_smc_fn smc_fn)
+{
+  smccc_res_t callsuid;
+  union optee_os_revision osrev;
+  union optee_calls_revision callsrev;
+  union optee_exchg_caps xchgcaps;
+
+  /* Print the OS revision and build ID (if reported) */
+
+  osrev.result.build_id = 0;
+
+  smc_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0, &osrev.smccc);
+
+  if (osrev.result.build_id)
+    {
+      syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu (%08lx)\n",
+                       osrev.result.major, osrev.result.minor,
+                       osrev.result.build_id);
+    }
+  else
+    {
+      syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu\n",
+                       osrev.result.major, osrev.result.minor);
+    }
+
+  /* Check the API UID */
+
+  smc_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &callsuid);
+
+  if (callsuid.a0 != OPTEE_MSG_UID_0 || callsuid.a1 != OPTEE_MSG_UID_1 ||
+      callsuid.a2 != OPTEE_MSG_UID_2 || callsuid.a3 != OPTEE_MSG_UID_3)
+    {
+      syslog(LOG_ERR, "OP-TEE: API UID mismatch\n");
+      return false;
+    }
+
+  /* Check the API revision */
+
+  smc_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &callsrev.smccc);
+
+  if (callsrev.result.major != OPTEE_MSG_REVISION_MAJOR ||
+      (int)callsrev.result.minor < OPTEE_MSG_REVISION_MINOR)
+    {
+      syslog(LOG_ERR, "OP-TEE: API revision incompatible\n");
+      return false;
+    }
+
+  /* Check the capabilities */
+
+  smc_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, OPTEE_SMC_NSEC_CAP_UNIPROCESSOR,
+         0, 0, 0, 0, 0, 0, &xchgcaps.smccc);
+
+  if (xchgcaps.result.status != OPTEE_SMC_RETURN_OK)
+    {
+      syslog(LOG_ERR, "OP-TEE: Failed to exchange capabilities\n");
+      return false;
+    }
+
+  if (!(xchgcaps.result.capabilities & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM))
+    {
+      syslog(LOG_ERR, "OP-TEE: Does not support dynamic shared mem\n");
+      return false;
+    }
+
+  return true;
+}
+
+static void optee_smc_handle_rpc(FAR struct optee_priv_data *priv,
+                                 FAR smccc_res_t *par)
+{
+  FAR struct optee_shm_entry *shme;
+  uintptr_t shme_pa;
+  uint32_t rpc_func;
+  size_t shm_size;
+
+  rpc_func = OPTEE_SMC_RETURN_GET_RPC_FUNC(par->a0);
+  par->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
+
+  switch (rpc_func)
+    {
+      case OPTEE_SMC_RPC_FUNC_ALLOC:
+        {
+          shm_size = par->a1;
+          par->a1 = 0;
+          par->a2 = 0;
+          par->a4 = 0;
+          par->a5 = 0;
+
+          if (!optee_shm_alloc(priv, true, NULL, shm_size,
+                               TEE_SHM_ALLOC | TEE_SHM_REGISTER, &shme))
+            {
+              shme_pa = optee_va_to_pa(
+                          (FAR void *)(uintptr_t)shme->shm.addr);
+              par->a1 = shme_pa >> 32;
+              par->a2 = shme_pa & UINT32_MAX;
+              par->a4 = (uintptr_t)shme >> 32;
+              par->a5 = (uintptr_t)shme & UINT32_MAX;
+            }
+          break;
+        }
+
+      case OPTEE_SMC_RPC_FUNC_FREE:
+        {
+          shme = (FAR struct optee_shm_entry *)(uintptr_t)
+                  ((par->a1 << 32) | (par->a2 & UINT32_MAX));
+          optee_shm_free(priv, shme);
+          break;
+        }
+
+      case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
+        {
+          break;
+        }
+
+      default:
+        {
+          syslog(LOG_ERR, "OP-TEE: RPC 0x%04x not implemented\n", rpc_func);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * 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)
+{
+  if (!optee_smc_is_compatible(smc_conduit))
+    {
+      return -ENOENT;
+    }
+
+  syslog(LOG_INFO, "OP-TEE: compatibility check complete\n");
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: optee_transport_open
+ *
+ * Description:
+ *   Perform any transport-specific actions upon driver character device
+ *   open.
+ *
+ * Returned Values:
+ *   0 on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+int optee_transport_open(FAR struct optee_priv_data *priv)
+{
+  priv->transport = smc_conduit;
+  priv->alignment = OPTEE_MSG_NONCONTIG_PAGE_SIZE;
+  return 0;
+}
+
+/****************************************************************************
+ * Name: optee_transport_close
+ *
+ * Description:
+ *   Perform any transport-specific actions upon driver character device
+ *   close.
+ *
+ * Returned Values:
+ *  None
+ *
+ ****************************************************************************/
+
+void optee_transport_close(FAR struct optee_priv_data *priv)
+{
+}
+
+/****************************************************************************
+ * Name: optee_transport_call
+ *
+ * Description:
+ *   Call OP-TEE OS using SMCs.
+ *
+ * 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)
+{
+  smccc_res_t res;
+  smccc_res_t par;
+  uintptr_t arg_pa;
+  optee_smc_fn smc_fn = (optee_smc_fn)priv->transport;

Review Comment:
   move before line 292



##########
drivers/misc/optee_smc.c:
##########
@@ -0,0 +1,322 @@
+/****************************************************************************
+ * drivers/misc/optee_smc.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/config.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <arch/syscall.h>
+
+#include "optee.h"
+#include "optee_smc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_ARM)
+#  define smccc_smc                  arm_smccc_smc
+#  define smccc_hvc                  arm_smccc_hvc
+#  define smccc_res_t                arm_smccc_res_t
+#elif defined(CONFIG_ARCH_ARM64)
+#  define smccc_smc                  arm64_smccc_smc
+#  define smccc_hvc                  arm64_smccc_hvc
+#  define smccc_res_t                arm64_smccc_res_t
+#else
+#  error "CONFIG_DEV_OPTEE_SMC is only supported on arm and arm64"
+#endif
+
+#ifdef CONFIG_DEV_OPTEE_SMC_CONDUIT_SMC
+#  define smc_conduit                smccc_smc
+#else
+#  define smc_conduit                smccc_hvc
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef void (*optee_smc_fn)(unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long,
+                             FAR smccc_res_t *);
+
+union optee_os_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_call_get_os_revision_result result;
+};
+
+union optee_calls_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_calls_revision_result result;
+};
+
+union optee_exchg_caps
+{
+  smccc_res_t smccc;
+  struct optee_smc_exchange_capabilities_result result;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static bool optee_smc_is_compatible(optee_smc_fn smc_fn)
+{
+  smccc_res_t callsuid;
+  union optee_os_revision osrev;
+  union optee_calls_revision callsrev;
+  union optee_exchg_caps xchgcaps;
+
+  /* Print the OS revision and build ID (if reported) */
+
+  osrev.result.build_id = 0;
+
+  smc_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0, &osrev.smccc);
+
+  if (osrev.result.build_id)
+    {
+      syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu (%08lx)\n",
+                       osrev.result.major, osrev.result.minor,
+                       osrev.result.build_id);
+    }
+  else
+    {
+      syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu\n",
+                       osrev.result.major, osrev.result.minor);
+    }
+
+  /* Check the API UID */
+
+  smc_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &callsuid);
+
+  if (callsuid.a0 != OPTEE_MSG_UID_0 || callsuid.a1 != OPTEE_MSG_UID_1 ||
+      callsuid.a2 != OPTEE_MSG_UID_2 || callsuid.a3 != OPTEE_MSG_UID_3)
+    {
+      syslog(LOG_ERR, "OP-TEE: API UID mismatch\n");
+      return false;
+    }
+
+  /* Check the API revision */
+
+  smc_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &callsrev.smccc);
+
+  if (callsrev.result.major != OPTEE_MSG_REVISION_MAJOR ||
+      (int)callsrev.result.minor < OPTEE_MSG_REVISION_MINOR)
+    {
+      syslog(LOG_ERR, "OP-TEE: API revision incompatible\n");
+      return false;
+    }
+
+  /* Check the capabilities */
+
+  smc_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, OPTEE_SMC_NSEC_CAP_UNIPROCESSOR,
+         0, 0, 0, 0, 0, 0, &xchgcaps.smccc);
+
+  if (xchgcaps.result.status != OPTEE_SMC_RETURN_OK)
+    {
+      syslog(LOG_ERR, "OP-TEE: Failed to exchange capabilities\n");
+      return false;
+    }
+
+  if (!(xchgcaps.result.capabilities & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM))
+    {
+      syslog(LOG_ERR, "OP-TEE: Does not support dynamic shared mem\n");
+      return false;
+    }
+
+  return true;
+}
+
+static void optee_smc_handle_rpc(FAR struct optee_priv_data *priv,
+                                 FAR smccc_res_t *par)
+{
+  FAR struct optee_shm_entry *shme;
+  uintptr_t shme_pa;
+  uint32_t rpc_func;
+  size_t shm_size;
+
+  rpc_func = OPTEE_SMC_RETURN_GET_RPC_FUNC(par->a0);
+  par->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
+
+  switch (rpc_func)
+    {
+      case OPTEE_SMC_RPC_FUNC_ALLOC:
+        {
+          shm_size = par->a1;
+          par->a1 = 0;
+          par->a2 = 0;
+          par->a4 = 0;
+          par->a5 = 0;
+
+          if (!optee_shm_alloc(priv, true, NULL, shm_size,
+                               TEE_SHM_ALLOC | TEE_SHM_REGISTER, &shme))
+            {
+              shme_pa = optee_va_to_pa(
+                          (FAR void *)(uintptr_t)shme->shm.addr);
+              par->a1 = shme_pa >> 32;
+              par->a2 = shme_pa & UINT32_MAX;
+              par->a4 = (uintptr_t)shme >> 32;
+              par->a5 = (uintptr_t)shme & UINT32_MAX;
+            }
+          break;
+        }
+
+      case OPTEE_SMC_RPC_FUNC_FREE:
+        {
+          shme = (FAR struct optee_shm_entry *)(uintptr_t)
+                  ((par->a1 << 32) | (par->a2 & UINT32_MAX));
+          optee_shm_free(priv, shme);
+          break;
+        }
+
+      case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
+        {
+          break;
+        }
+
+      default:
+        {
+          syslog(LOG_ERR, "OP-TEE: RPC 0x%04x not implemented\n", rpc_func);
+          break;
+        }
+    }
+}
+
+/****************************************************************************
+ * 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)
+{
+  if (!optee_smc_is_compatible(smc_conduit))
+    {
+      return -ENOENT;
+    }
+
+  syslog(LOG_INFO, "OP-TEE: compatibility check complete\n");
+

Review Comment:
   remove



##########
drivers/misc/optee_smc.c:
##########
@@ -0,0 +1,322 @@
+/****************************************************************************
+ * drivers/misc/optee_smc.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/config.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <arch/syscall.h>

Review Comment:
   remove, done in optee_smc.h



##########
drivers/misc/optee.c:
##########
@@ -43,11 +43,11 @@
 #include "optee.h"
 
 /****************************************************************************
- *   The driver's main purpose is to support the porting of the open source
+ * The driver's main purpose is to support the porting of the open source
  * component optee_client (https://github.com/OP-TEE/optee_client) to NuttX.
- *   The basic function of the driver module is to convert
- * the REE application layer data and send it to the TEE through rpmsg.
- * TEE implementation is optee_os(https://github.com/OP-TEE/optee_os).
+ * The basic function of the driver module is to convert the REE application
+ * layer data and send it to the TEE through rpmsg or SMCs. TEE
+ * implementation is optee_os(https://github.com/OP-TEE/optee_os).

Review Comment:
   let's move all change in this file to the first patch



##########
drivers/misc/optee.c:
##########
@@ -154,6 +202,248 @@ static bool optee_is_valid_range(FAR void *va, size_t 
size)
 #  define optee_is_valid_range(addr, size) (true)
 #endif
 
+/****************************************************************************
+ * Name: optee_msg_alloc
+ *
+ * Description:
+ *   Allocate OP-TEE page-aligned memory for use as arguments to OP-TEE
+ *   calls, large enough to fit `num_params` parameters. Initialize the
+ *   buffer to 0, and set the `.num_params` field to the specified value.
+ *
+ *   Use `kmm_free()` to free the memory returned.
+ *
+ * Parameters:
+ *   priv       - the driver's private data structure
+ *   num_params - the number of arguments to allocate shared memory for.
+ *                Can be zero.
+ *
+ * Returned Values:
+ *   On success, pointer to OP-TEE message arguments struct initialized
+ *   to 0 except for `.num_params`, which is initialized to the specified.
+ *   On failure, NULL.
+ *
+ ****************************************************************************/
+
+static FAR struct optee_msg_arg *
+optee_msg_alloc(FAR struct optee_priv_data *priv, uint32_t num_params)
+{
+  FAR struct optee_msg_arg *msg;
+
+  if (priv->alignment)
+    {
+      msg = kmm_memalign(priv->alignment,
+                         OPTEE_MSG_GET_ARG_SIZE(num_params));
+    }
+  else
+    {
+      msg = kmm_malloc(OPTEE_MSG_GET_ARG_SIZE(num_params));
+    }
+
+  if (msg == NULL)
+    {
+      return NULL;
+    }
+
+  memset(msg, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
+  msg->num_params = num_params;
+
+  return msg;
+}
+
+/****************************************************************************
+ * Name: optee_shm_to_page_list
+ *
+ * Description:
+ *   Provide a page list of a shared memory buffer. Secure world doesn't
+ *   know about the address environment mapping of NuttX, so physical
+ *   pointers are needed when sharing memory. This implementation enables
+ *   sharing of physically non-contiguous buffers according to
+ *   optee_msg.h#OPTEE_MSG_ATTR_NONCONTIG.
+ *   Each entry in the generated page list is an array of the physical,
+ *   potentially non-contiguous pages making up the actual buffer to
+ *   represent. Note that this representation does not account for the page
+ *   offset of the shared memory buffer. The offset is encoded in the
+ *   physical address returned in `list_pa`.
+ *
+ * Parameters:
+ *   shme        - Shared memory entry to create a page list for.
+ *   list_pa     - If not NULL, will be set to the page list's physical
+ *                 address (which is aligned to
+ *                 OPTEE_MSG_NONCONTIG_PAGE_SIZE) added with shared memory
+ *                 page offset.
+ *
+ * Returned Values:
+ *   A pointer to the kernel virtual address of the page list on success.
+ *   NULL on failure. Caller responsible to free the returned list using
+ *   `kmm_free()`.
+ *
+ ****************************************************************************/
+
+FAR void *optee_shm_to_page_list(FAR struct optee_shm_entry *shme,
+                                 FAR uintptr_t *list_pa)
+{
+  size_t pgsize = OPTEE_MSG_NONCONTIG_PAGE_SIZE;
+  uintptr_t pgoff;
+  uintptr_t page;
+  uint32_t total_pages;
+  uint32_t list_size;
+  FAR void *list;
+  FAR struct optee_page_list_entry *list_entry;
+  uint32_t i = 0;
+
+  pgoff = shme->shm.addr & (pgsize - 1);
+  total_pages = (uint32_t)div_round_up(pgoff + shme->shm.length, pgsize);
+  list_size = div_round_up(total_pages, OPTEE_PAGES_ARRAY_LEN)
+              * sizeof(struct optee_page_list_entry);
+
+  /* Page list's address should be page aligned, conveniently leaving
+   * log2(<page size>) zero least-significant bits to use as the page
+   * offset of the shm buffer (added last before return below).
+   */
+
+  list = kmm_memalign(pgsize, list_size);
+  if (!list)
+    {
+      return NULL;
+    }
+
+  list_entry = (FAR struct optee_page_list_entry *)list;
+  page = ALIGN_DOWN(shme->shm.addr, pgsize);
+  while (total_pages)
+    {
+      list_entry->pages_array[i++] = optee_va_to_pa((FAR void *)page);
+      page += pgsize;
+      total_pages--;
+
+      if (i == OPTEE_PAGES_ARRAY_LEN)
+        {
+          list_entry->next_entry = optee_va_to_pa(list_entry + 1);
+          list_entry++;
+          i = 0;
+        }
+    }
+
+  if (list_pa)
+    {
+      *list_pa = optee_va_to_pa(list) | pgoff;
+    }
+
+  return list;
+}
+
+/****************************************************************************
+ * Name: optee_shm_sec_register
+ *
+ * Description:
+ *   Register specified shared memory entry with OP-TEE.
+ *
+ * Parameters:
+ *   priv  - The driver's private data structure
+ *   shme  - Pointer to shared memory entry to register. The entry, the
+ *           contained shared memory object, or the referenced shared buffer
+ *           cannot be NULL.
+ *
+ * Returned Values:
+ *   0 on success, negative error code otherwise.
+ *
+ ****************************************************************************/
+
+static int optee_shm_sec_register(FAR struct optee_priv_data *priv,
+                                  FAR struct optee_shm_entry *shme)
+{
+  FAR struct optee_msg_arg *msg;
+  FAR void *page_list;
+  uintptr_t page_list_pa;
+  int ret = 0;
+
+  msg = optee_msg_alloc(priv, 1);
+  if (msg == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  page_list = optee_shm_to_page_list(shme, &page_list_pa);
+  if (page_list == NULL)
+    {
+      ret = -ENOMEM;

Review Comment:
   merge to line 357



##########
drivers/misc/optee_smc.h:
##########
@@ -0,0 +1,448 @@
+/****************************************************************************
+ * drivers/misc/optee_smc.h
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ * Copyright (c) 2015-2018, Linaro Limited
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_MISC_OPTEE_SMC_H
+#define __DRIVERS_MISC_OPTEE_SMC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <arch/syscall.h>
+#include <nuttx/bits.h>
+
+/* This file is based on
+ * https://github.com
+ *    /OP-TEE/optee_os/blob/master/core/arch/arm/include/sm/optee_smc.h
+ * and may need to be updated when introducing new features.
+ */
+
+#define OPTEE_SMC_STD_CALL_VAL(func_num) \
+  ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_32, \
+         ARM_SMCCC_OWNER_TRUSTED_OS, (func_num))
+#define OPTEE_SMC_FAST_CALL_VAL(func_num) \
+  ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
+         ARM_SMCCC_OWNER_TRUSTED_OS, (func_num))
+
+/* Function specified by SMC Calling convention.
+ */
+#define OPTEE_SMC_FUNCID_CALLS_COUNT  0xFF00
+#define OPTEE_SMC_CALLS_COUNT \
+  ARM_SMCCC_CALL_VAL(OPTEE_SMC_FAST_CALL, SMCCC_SMC_32, \
+         SMCCC_OWNER_TRUSTED_OS_END, \
+         OPTEE_SMC_FUNCID_CALLS_COUNT)
+
+/* Normal cached memory (write-back), shareable for SMP systems and not
+ * shareable for UP systems.
+ */
+#define OPTEE_SMC_SHM_CACHED    1
+
+/* a0..a7 is used as register names in the descriptions below, on arm32
+ * that translates to r0..r7 and on arm64 to w0..w7. In both cases it's
+ * 32-bit registers.
+ */
+
+/* Function specified by SMC Calling convention
+ *
+ * Return one of the following UIDs if using API specified in this file
+ * without further extensions:
+ * 65cb6b93-af0c-4617-8ed6-644a8d1140f8
+ * see also OPTEE_SMC_UID_* in optee_msg.h
+ */
+#define OPTEE_SMC_FUNCID_CALLS_UID OPTEE_MSG_FUNCID_CALLS_UID
+#define OPTEE_SMC_CALLS_UID \
+  ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
+         ARM_SMCCC_OWNER_TRUSTED_OS_END, \
+         OPTEE_SMC_FUNCID_CALLS_UID)
+
+/* Function specified by SMC Calling convention
+ *
+ * Returns 2.0 if using API specified in this file without further
+ * extensions. See also OPTEE_MSG_REVISION_* in optee_msg.h
+ */
+#define OPTEE_SMC_FUNCID_CALLS_REVISION OPTEE_MSG_FUNCID_CALLS_REVISION
+#define OPTEE_SMC_CALLS_REVISION \
+  ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
+         ARM_SMCCC_OWNER_TRUSTED_OS_END, \
+         OPTEE_SMC_FUNCID_CALLS_REVISION)
+
+struct optee_smc_calls_revision_result
+{
+  unsigned long major;
+  unsigned long minor;
+  unsigned long reserved0;
+  unsigned long reserved1;
+};
+
+/* Get UUID of Trusted OS.
+ *
+ * Used by non-secure world to figure out which Trusted OS is installed.
+ * Note that returned UUID is the UUID of the Trusted OS, not of the API.
+ *
+ * Returns UUID in a0-4 in the same way as OPTEE_SMC_CALLS_UID
+ * described above.
+ */
+#define OPTEE_SMC_FUNCID_GET_OS_UUID OPTEE_MSG_FUNCID_GET_OS_UUID
+#define OPTEE_SMC_CALL_GET_OS_UUID \
+  OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_UUID)
+
+/* Get revision of Trusted OS.
+ *
+ * Used by non-secure world to figure out which version of the Trusted OS
+ * is installed. Note that the returned revision is the revision of the
+ * Trusted OS, not of the API.
+ *
+ * Returns revision in a0-1 in the same way as OPTEE_SMC_CALLS_REVISION
+ * described above. May optionally return a 32-bit build identifier in a2,
+ * with zero meaning unspecified.
+ */
+#define OPTEE_SMC_FUNCID_GET_OS_REVISION OPTEE_MSG_FUNCID_GET_OS_REVISION
+#define OPTEE_SMC_CALL_GET_OS_REVISION \
+  OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_REVISION)
+
+struct optee_smc_call_get_os_revision_result
+{
+  unsigned long major;
+  unsigned long minor;
+  unsigned long build_id;
+  unsigned long reserved1;
+};
+
+/* Call with struct optee_msg_arg as argument
+ *
+ * Call register usage:
+ * a0  SMC Function ID, OPTEE_SMC*CALL_WITH_ARG
+ * a1  Upper 32bit of a 64bit physical pointer to a struct optee_msg_arg
+ * a2  Lower 32bit of a 64bit physical pointer to a struct optee_msg_arg
+ * a3  Cache settings, not used if physical pointer is in a predefined shared
+ *  memory area else per OPTEE_SMC_SHM_*
+ * a4-6  Not used
+ * a7  Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0  Return value, OPTEE_SMC_RETURN_*
+ * a1-3  Not used
+ * a4-7  Preserved
+ *
+ * OPTEE_SMC_RETURN_ETHREAD_LIMIT return register usage:
+ * a0  Return value, OPTEE_SMC_RETURN_ETHREAD_LIMIT
+ * a1-3  Preserved
+ * a4-7  Preserved
+ *
+ * RPC return register usage:
+ * a0  Return value, OPTEE_SMC_RETURN_IS_RPC(val)
+ * a1-2  RPC parameters
+ * a3-7  Resume information, must be preserved
+ *
+ * Possible return values:
+ * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION  Trusted OS does not recognize this
+ *          function.
+ * OPTEE_SMC_RETURN_OK      Call completed, result updated in
+ *          the previously supplied struct
+ *          optee_msg_arg.
+ * OPTEE_SMC_RETURN_ETHREAD_LIMIT  Number of Trusted OS threads exceeded,
+ *          try again later.
+ * OPTEE_SMC_RETURN_EBADADDR    Bad physical pointer to struct
+ *          optee_msg_arg.
+ * OPTEE_SMC_RETURN_EBADCMD    Bad/unknown cmd in struct optee_msg_arg
+ * OPTEE_SMC_RETURN_IS_RPC()    Call suspended by RPC call to normal
+ *          world.
+ */
+#define OPTEE_SMC_FUNCID_CALL_WITH_ARG OPTEE_MSG_FUNCID_CALL_WITH_ARG
+#define OPTEE_SMC_CALL_WITH_ARG \
+  OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_WITH_ARG)
+
+/* Get Shared Memory Config
+ *
+ * Returns the Secure/Non-secure shared memory config.
+ *
+ * Call register usage:
+ * a0  SMC Function ID, OPTEE_SMC_GET_SHM_CONFIG
+ * a1-6  Not used
+ * a7  Hypervisor Client ID register
+ *
+ * Have config return register usage:
+ * a0  OPTEE_SMC_RETURN_OK
+ * a1  Physical address of start of SHM
+ * a2  Size of of SHM
+ * a3  Cache settings of memory, as defined by the
+ *  OPTEE_SMC_SHM_* values above
+ * a4-7  Preserved
+ *
+ * Not available register usage:
+ * a0  OPTEE_SMC_RETURN_ENOTAVAIL
+ * a1-3 Not used
+ * a4-7  Preserved
+ */
+#define OPTEE_SMC_FUNCID_GET_SHM_CONFIG  7
+#define OPTEE_SMC_GET_SHM_CONFIG \
+  OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_SHM_CONFIG)
+
+struct optee_smc_get_shm_config_result
+{
+  unsigned long status;
+  unsigned long start;
+  unsigned long size;
+  unsigned long settings;
+};
+
+/* Exchanges capabilities between normal world and secure world
+ *
+ * Call register usage:
+ * a0  SMC Function ID, OPTEE_SMC_EXCHANGE_CAPABILITIES
+ * a1  bitfield of normal world capabilities OPTEE_SMC_NSEC_CAP_*
+ * a2-6  Not used
+ * a7  Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0  OPTEE_SMC_RETURN_OK
+ * a1  bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_*
+ * a2-7  Preserved
+ *
+ * Error return register usage:
+ * a0  OPTEE_SMC_RETURN_ENOTAVAIL, can't use the capabilities from normal
+ *     world
+ * a1  bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_*
+ * a2-7 Preserved
+ */
+
+/* Normal world works as a uniprocessor system */
+#define OPTEE_SMC_NSEC_CAP_UNIPROCESSOR      BIT(0)
+/* Secure world has reserved shared memory for normal world to use */
+#define OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM  BIT(0)
+/* Secure world can communicate via previously unregistered shared memory */
+#define OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM   BIT(1)
+
+/* Secure world supports commands "register/unregister shared memory",
+ * secure world accepts command buffers located in any parts of non-secure
+ * RAM
+ */
+#define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM        BIT(2)
+
+#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
+#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
+  OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES)
+
+struct optee_smc_exchange_capabilities_result
+{
+  unsigned long status;
+  unsigned long capabilities;
+  unsigned long reserved0;
+  unsigned long reserved1;
+};
+
+/* Disable and empties cache of shared memory objects
+ *
+ * Secure world can cache frequently used shared memory objects, for
+ * example objects used as RPC arguments. When secure world is idle this
+ * function returns one shared memory reference to free. To disable the
+ * cache and free all cached objects this function has to be called until
+ * it returns OPTEE_SMC_RETURN_ENOTAVAIL.
+ *
+ * Call register usage:
+ * a0  SMC Function ID, OPTEE_SMC_DISABLE_SHM_CACHE
+ * a1-6  Not used
+ * a7  Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0  OPTEE_SMC_RETURN_OK
+ * a1  Upper 32bit of a 64bit Shared memory cookie
+ * a2  Lower 32bit of a 64bit Shared memory cookie
+ * a3-7  Preserved
+ *
+ * Cache empty return register usage:
+ * a0  OPTEE_SMC_RETURN_ENOTAVAIL
+ * a1-7  Preserved
+ *
+ * Not idle return register usage:
+ * a0  OPTEE_SMC_RETURN_EBUSY
+ * a1-7  Preserved
+ */
+#define OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE 10
+#define OPTEE_SMC_DISABLE_SHM_CACHE \
+  OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE)
+
+struct optee_smc_disable_shm_cache_result
+{
+  unsigned long status;
+  unsigned long shm_upper32;
+  unsigned long shm_lower32;
+  unsigned long reserved0;
+};
+
+/* Enable cache of shared memory objects
+ *
+ * Secure world can cache frequently used shared memory objects, for
+ * example objects used as RPC arguments. When secure world is idle this
+ * function returns OPTEE_SMC_RETURN_OK and the cache is enabled. If
+ * secure world isn't idle OPTEE_SMC_RETURN_EBUSY is returned.
+ *
+ * Call register usage:
+ * a0  SMC Function ID, OPTEE_SMC_ENABLE_SHM_CACHE
+ * a1-6  Not used
+ * a7  Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0  OPTEE_SMC_RETURN_OK
+ * a1-7  Preserved
+ *
+ * Not idle return register usage:
+ * a0  OPTEE_SMC_RETURN_EBUSY
+ * a1-7  Preserved
+ */
+#define OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE 11
+#define OPTEE_SMC_ENABLE_SHM_CACHE \
+  OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE)
+
+/* Resume from RPC (for example after processing a foreign interrupt)
+ *
+ * Call register usage:
+ * a0  SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC
+ * a1-3  Value of a1-3 when OPTEE_SMC_CALL_WITH_ARG returned
+ *  OPTEE_SMC_RETURN_RPC in a0
+ *
+ * Return register usage is the same as for OPTEE_SMC_*CALL_WITH_ARG above.
+ *
+ * Possible return values
+ * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION  Trusted OS does not recognize this
+ *          function.
+ * OPTEE_SMC_RETURN_OK      Original call completed, result
+ *          updated in the previously supplied.
+ *          struct optee_msg_arg
+ * OPTEE_SMC_RETURN_RPC      Call suspended by RPC call to normal
+ *          world.
+ * OPTEE_SMC_RETURN_ERESUME    Resume failed, the opaque resume
+ *          information was corrupt.
+ */
+#define OPTEE_SMC_FUNCID_RETURN_FROM_RPC  3
+#define OPTEE_SMC_CALL_RETURN_FROM_RPC \
+  OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_RETURN_FROM_RPC)
+
+#define OPTEE_SMC_RETURN_RPC_PREFIX_MASK  0xFFFF0000
+#define OPTEE_SMC_RETURN_RPC_PREFIX       0xFFFF0000
+#define OPTEE_SMC_RETURN_RPC_FUNC_MASK    0x0000FFFF
+
+#define OPTEE_SMC_RETURN_GET_RPC_FUNC(ret) \
+  ((ret) & OPTEE_SMC_RETURN_RPC_FUNC_MASK)
+
+#define OPTEE_SMC_RPC_VAL(func)    ((func) | OPTEE_SMC_RETURN_RPC_PREFIX)
+
+/* Allocate memory for RPC parameter passing. The memory is used to hold a
+ * struct optee_msg_arg.
+ *
+ * "Call" register usage:
+ * a0  This value, OPTEE_SMC_RETURN_RPC_ALLOC
+ * a1  Size in bytes of required argument memory
+ * a2  Not used
+ * a3  Resume information, must be preserved
+ * a4-5  Not used
+ * a6-7  Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0  SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1  Upper 32bits of 64bit physical pointer to allocated
+ *  memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't
+ *  be allocated.
+ * a2  Lower 32bits of 64bit physical pointer to allocated
+ *  memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't
+ *  be allocated
+ * a3  Preserved
+ * a4  Upper 32bits of 64bit Shared memory cookie used when freeing
+ *  the memory or doing an RPC
+ * a5  Lower 32bits of 64bit Shared memory cookie used when freeing
+ *  the memory or doing an RPC
+ * a6-7  Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_ALLOC          0
+#define OPTEE_SMC_RETURN_RPC_ALLOC \
+  OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_ALLOC)
+
+/* Free memory previously allocated by OPTEE_SMC_RETURN_RPC_ALLOC
+ *
+ * "Call" register usage:
+ * a0  This value, OPTEE_SMC_RETURN_RPC_FREE
+ * a1  Upper 32bits of 64bit shared memory cookie belonging to this
+ *  argument memory
+ * a2  Lower 32bits of 64bit shared memory cookie belonging to this
+ *  argument memory
+ * a3-7  Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0  SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1-2  Not used
+ * a3-7  Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_FREE           2
+#define OPTEE_SMC_RETURN_RPC_FREE \
+  OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FREE)
+
+/* Deliver foreign interrupt to normal world.
+ *
+ * "Call" register usage:
+ * a0  OPTEE_SMC_RETURN_RPC_FOREIGN_INTR
+ * a1-7  Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0  SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1-7  Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_FOREIGN_INTR   4
+#define OPTEE_SMC_RETURN_RPC_FOREIGN_INTR \
+  OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FOREIGN_INTR)
+
+/* Do an RPC request. The supplied struct optee_msg_arg tells which
+ * request to do and the parameters for the request. The following fields
+ * are used (the rest are unused):
+ * - cmd    the Request ID
+ * - ret    return value of the request, filled in by normal world
+ * - num_params    number of parameters for the request
+ * - params    the parameters
+ * - param_attrs  attributes of the parameters
+ *
+ * "Call" register usage:
+ * a0  OPTEE_SMC_RETURN_RPC_CMD
+ * a1  Upper 32bit of a 64bit Shared memory cookie holding a
+ *  struct optee_msg_arg, must be preserved, only the data should
+ *  be updated
+ * a2  Lower 32bit of a 64bit Shared memory cookie holding a
+ *  struct optee_msg_arg, must be preserved, only the data should
+ *  be updated
+ * a3-7  Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0  SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1-2  Not used
+ * a3-7  Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_CMD            5
+#define OPTEE_SMC_RETURN_RPC_CMD \
+  OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_CMD)
+
+/* Returned in a0 */
+#define OPTEE_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF
+
+/* Returned in a0 only from Trusted OS functions */
+#define OPTEE_SMC_RETURN_OK               0x0
+#define OPTEE_SMC_RETURN_ETHREAD_LIMIT    0x1
+#define OPTEE_SMC_RETURN_EBUSY            0x2
+#define OPTEE_SMC_RETURN_ERESUME          0x3
+#define OPTEE_SMC_RETURN_EBADADDR         0x4
+#define OPTEE_SMC_RETURN_EBADCMD          0x5
+#define OPTEE_SMC_RETURN_ENOMEM           0x6
+#define OPTEE_SMC_RETURN_ENOTAVAIL        0x7
+#define OPTEE_SMC_RETURN_IS_RPC(ret)      __optee_smc_return_is_rpc((ret))
+
+static inline bool __optee_smc_return_is_rpc(uint32_t ret)

Review Comment:
   optee_smc_return_is_rpc



##########
drivers/misc/optee.c:
##########
@@ -259,16 +314,14 @@ static int optee_from_msg_param(FAR struct 
tee_ioctl_param *params,
   return 0;
 }
 
-static int
-optee_ioctl_close_session(FAR struct optee_priv_data *priv,
-                          FAR struct tee_ioctl_close_session_arg *arg)
+static int optee_close_session(FAR struct optee_priv_data *priv,
+                               uint32_t session)

Review Comment:
   merge to previous line. Let's move the new prototype function to previous 
patch to avoid the big change in this patch.



##########
drivers/misc/optee.c:
##########
@@ -608,6 +989,197 @@ static int optee_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
  * Public Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: optee_va_to_pa
+ *
+ * Description:
+ *   Convert the specified virtual address to a physical address. If the
+ *   virtual address does not belong to the user, it is assumed to be a
+ *   kernel virtual address with a 1-1 mapping and the VA is returned as-is.
+ *   The VA is also returned as-is if this is a build without
+ *   CONFIG_ARCH_ADDRENV.
+ *
+ * Parameters:
+ *   va    - The virtual address to convert.
+ *
+ * Returned Values:
+ *   The physical address corresponding to the specified VA.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_ADDRENV
+uintptr_t optee_va_to_pa(FAR void *va)
+{
+  FAR struct tcb_s *tcb;
+  FAR arch_addrenv_t *addrenv;

Review Comment:
   move before line 1013



##########
drivers/misc/optee.c:
##########
@@ -154,6 +202,248 @@ static bool optee_is_valid_range(FAR void *va, size_t 
size)
 #  define optee_is_valid_range(addr, size) (true)
 #endif
 
+/****************************************************************************
+ * Name: optee_msg_alloc
+ *
+ * Description:
+ *   Allocate OP-TEE page-aligned memory for use as arguments to OP-TEE
+ *   calls, large enough to fit `num_params` parameters. Initialize the
+ *   buffer to 0, and set the `.num_params` field to the specified value.
+ *
+ *   Use `kmm_free()` to free the memory returned.
+ *
+ * Parameters:
+ *   priv       - the driver's private data structure
+ *   num_params - the number of arguments to allocate shared memory for.
+ *                Can be zero.
+ *
+ * Returned Values:
+ *   On success, pointer to OP-TEE message arguments struct initialized
+ *   to 0 except for `.num_params`, which is initialized to the specified.
+ *   On failure, NULL.
+ *
+ ****************************************************************************/
+
+static FAR struct optee_msg_arg *
+optee_msg_alloc(FAR struct optee_priv_data *priv, uint32_t num_params)
+{
+  FAR struct optee_msg_arg *msg;
+
+  if (priv->alignment)
+    {
+      msg = kmm_memalign(priv->alignment,
+                         OPTEE_MSG_GET_ARG_SIZE(num_params));
+    }
+  else
+    {
+      msg = kmm_malloc(OPTEE_MSG_GET_ARG_SIZE(num_params));
+    }
+
+  if (msg == NULL)
+    {
+      return NULL;
+    }
+
+  memset(msg, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
+  msg->num_params = num_params;
+
+  return msg;
+}
+
+/****************************************************************************
+ * Name: optee_shm_to_page_list
+ *
+ * Description:
+ *   Provide a page list of a shared memory buffer. Secure world doesn't
+ *   know about the address environment mapping of NuttX, so physical
+ *   pointers are needed when sharing memory. This implementation enables
+ *   sharing of physically non-contiguous buffers according to
+ *   optee_msg.h#OPTEE_MSG_ATTR_NONCONTIG.
+ *   Each entry in the generated page list is an array of the physical,
+ *   potentially non-contiguous pages making up the actual buffer to
+ *   represent. Note that this representation does not account for the page
+ *   offset of the shared memory buffer. The offset is encoded in the
+ *   physical address returned in `list_pa`.
+ *
+ * Parameters:
+ *   shme        - Shared memory entry to create a page list for.
+ *   list_pa     - If not NULL, will be set to the page list's physical
+ *                 address (which is aligned to
+ *                 OPTEE_MSG_NONCONTIG_PAGE_SIZE) added with shared memory
+ *                 page offset.
+ *
+ * Returned Values:
+ *   A pointer to the kernel virtual address of the page list on success.
+ *   NULL on failure. Caller responsible to free the returned list using
+ *   `kmm_free()`.
+ *
+ ****************************************************************************/
+
+FAR void *optee_shm_to_page_list(FAR struct optee_shm_entry *shme,
+                                 FAR uintptr_t *list_pa)
+{
+  size_t pgsize = OPTEE_MSG_NONCONTIG_PAGE_SIZE;
+  uintptr_t pgoff;
+  uintptr_t page;
+  uint32_t total_pages;
+  uint32_t list_size;
+  FAR void *list;
+  FAR struct optee_page_list_entry *list_entry;
+  uint32_t i = 0;
+
+  pgoff = shme->shm.addr & (pgsize - 1);
+  total_pages = (uint32_t)div_round_up(pgoff + shme->shm.length, pgsize);
+  list_size = div_round_up(total_pages, OPTEE_PAGES_ARRAY_LEN)
+              * sizeof(struct optee_page_list_entry);
+
+  /* Page list's address should be page aligned, conveniently leaving
+   * log2(<page size>) zero least-significant bits to use as the page
+   * offset of the shm buffer (added last before return below).
+   */
+
+  list = kmm_memalign(pgsize, list_size);
+  if (!list)
+    {
+      return NULL;
+    }
+
+  list_entry = (FAR struct optee_page_list_entry *)list;
+  page = ALIGN_DOWN(shme->shm.addr, pgsize);
+  while (total_pages)
+    {
+      list_entry->pages_array[i++] = optee_va_to_pa((FAR void *)page);
+      page += pgsize;
+      total_pages--;
+
+      if (i == OPTEE_PAGES_ARRAY_LEN)
+        {
+          list_entry->next_entry = optee_va_to_pa(list_entry + 1);
+          list_entry++;
+          i = 0;
+        }
+    }
+
+  if (list_pa)
+    {
+      *list_pa = optee_va_to_pa(list) | pgoff;
+    }
+
+  return list;
+}
+
+/****************************************************************************
+ * Name: optee_shm_sec_register
+ *
+ * Description:
+ *   Register specified shared memory entry with OP-TEE.
+ *
+ * Parameters:
+ *   priv  - The driver's private data structure
+ *   shme  - Pointer to shared memory entry to register. The entry, the
+ *           contained shared memory object, or the referenced shared buffer
+ *           cannot be NULL.
+ *
+ * Returned Values:
+ *   0 on success, negative error code otherwise.
+ *
+ ****************************************************************************/
+
+static int optee_shm_sec_register(FAR struct optee_priv_data *priv,
+                                  FAR struct optee_shm_entry *shme)
+{
+  FAR struct optee_msg_arg *msg;
+  FAR void *page_list;
+  uintptr_t page_list_pa;

Review Comment:
   move before line 355



##########
drivers/misc/optee_smc.c:
##########
@@ -0,0 +1,322 @@
+/****************************************************************************
+ * drivers/misc/optee_smc.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/config.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <arch/syscall.h>
+
+#include "optee.h"
+#include "optee_smc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_ARM)
+#  define smccc_smc                  arm_smccc_smc
+#  define smccc_hvc                  arm_smccc_hvc
+#  define smccc_res_t                arm_smccc_res_t
+#elif defined(CONFIG_ARCH_ARM64)
+#  define smccc_smc                  arm64_smccc_smc
+#  define smccc_hvc                  arm64_smccc_hvc
+#  define smccc_res_t                arm64_smccc_res_t
+#else
+#  error "CONFIG_DEV_OPTEE_SMC is only supported on arm and arm64"
+#endif
+
+#ifdef CONFIG_DEV_OPTEE_SMC_CONDUIT_SMC
+#  define smc_conduit                smccc_smc
+#else
+#  define smc_conduit                smccc_hvc
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef void (*optee_smc_fn)(unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long, unsigned long,
+                             unsigned long, unsigned long,
+                             FAR smccc_res_t *);
+
+union optee_os_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_call_get_os_revision_result result;
+};
+
+union optee_calls_revision
+{
+  smccc_res_t smccc;
+  struct optee_smc_calls_revision_result result;
+};
+
+union optee_exchg_caps
+{
+  smccc_res_t smccc;
+  struct optee_smc_exchange_capabilities_result result;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static bool optee_smc_is_compatible(optee_smc_fn smc_fn)
+{
+  smccc_res_t callsuid;
+  union optee_os_revision osrev;
+  union optee_calls_revision callsrev;
+  union optee_exchg_caps xchgcaps;
+
+  /* Print the OS revision and build ID (if reported) */
+
+  osrev.result.build_id = 0;
+
+  smc_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0, &osrev.smccc);
+
+  if (osrev.result.build_id)
+    {
+      syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu (%08lx)\n",
+                       osrev.result.major, osrev.result.minor,
+                       osrev.result.build_id);
+    }
+  else
+    {
+      syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu\n",
+                       osrev.result.major, osrev.result.minor);
+    }
+
+  /* Check the API UID */
+
+  smc_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &callsuid);
+
+  if (callsuid.a0 != OPTEE_MSG_UID_0 || callsuid.a1 != OPTEE_MSG_UID_1 ||
+      callsuid.a2 != OPTEE_MSG_UID_2 || callsuid.a3 != OPTEE_MSG_UID_3)
+    {
+      syslog(LOG_ERR, "OP-TEE: API UID mismatch\n");
+      return false;
+    }
+
+  /* Check the API revision */
+
+  smc_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &callsrev.smccc);
+
+  if (callsrev.result.major != OPTEE_MSG_REVISION_MAJOR ||
+      (int)callsrev.result.minor < OPTEE_MSG_REVISION_MINOR)

Review Comment:
   why need `(int)` cast



##########
drivers/misc/optee.c:
##########
@@ -125,52 +115,24 @@ static const struct file_operations g_optee_ops =
 
 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
+  FAR struct optee_priv_data *priv;
   int ret;
 
-  psock = (FAR struct socket *)kmm_zalloc(sizeof(struct socket));
-  if (psock == NULL)
+  priv = (FAR struct optee_priv_data *)
+            kmm_zalloc(sizeof(struct optee_priv_data));
+  if (priv == 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
+  ret = optee_transport_open(priv);
   if (ret < 0)
     {
-      kmm_free(psock);

Review Comment:
   but we need kmm_free(priv)



##########
drivers/misc/optee.c:
##########
@@ -608,6 +989,197 @@ static int optee_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
  * Public Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: optee_va_to_pa
+ *
+ * Description:
+ *   Convert the specified virtual address to a physical address. If the
+ *   virtual address does not belong to the user, it is assumed to be a
+ *   kernel virtual address with a 1-1 mapping and the VA is returned as-is.
+ *   The VA is also returned as-is if this is a build without
+ *   CONFIG_ARCH_ADDRENV.
+ *
+ * Parameters:
+ *   va    - The virtual address to convert.
+ *
+ * Returned Values:
+ *   The physical address corresponding to the specified VA.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_ADDRENV
+uintptr_t optee_va_to_pa(FAR void *va)
+{
+  FAR struct tcb_s *tcb;
+  FAR arch_addrenv_t *addrenv;
+  uintptr_t page;
+
+  tcb = nxsched_self();
+  addrenv = &tcb->addrenv_curr->addrenv;
+
+  page = up_addrenv_find_page(addrenv, (uintptr_t)va);
+  if (page == 0)
+    {
+      return (uintptr_t)va;
+    }
+
+  return page | ((uintptr_t)va & MM_PGMASK);
+}
+#endif
+
+/****************************************************************************
+ * Name: optee_shm_alloc
+ *
+ * Description:
+ *   Allocate, register and/or add shared memory for use with OP-TEE calls.
+ *   Shared memory entry suitable for use in shared memory linked list
+ *   returned in pass-by-reference `shmep` pointer. This function always
+ *   allocates a shared memory entry, regardless of flags. The rest of this
+ *   function's behaviour is largely determined by `flags`:
+ *   - If `TEE_SHM_ALLOC` is specified, then a buffer of length `size` will
+ *     be allocated. In this case `addr` will be ignored. If `align` is
+ *     true, the allocated buffer will be aligned to `priv->alignment`.
+ *     `TEE_SHM_ALLOC` flag is reserved for kernel use only.
+ *   - If `TEE_SHM_SEC_REGISTER` is specified, then the memory specified by
+ *     `addr` or allocated through `TEE_SHM_ALLOC`, will be registered with
+ *     OP-TEE as dynamic shared memory.
+ *   - If `TEE_SHM_REGISTER` is specified, then the memory specified by
+ *     `addr` or allocated through `TEE_SHM_ALLOC`, will be added to the
+ *     driver's private data structure linked list of shared memory chunks.
+ *
+ *   Use `optee_shm_free()` to undo this operation, i.e. to free,
+ *   unregister, and/or remove from the list the entry returned in `shmep`
+ *   and the contained buffer.
+ *
+ * Parameters:
+ *   priv  - The driver's private data structure
+ *   align - Align the allocated memory according to OP-TEE requirements.
+ *           Ignored when `flags` do not specify `TEE_SHM_ALLOC`.
+ *   addr  - The address of the shared memory to register with OP-TEE and/or
+ *           add to the driver's linked list of shared memory chunks.
+ *   size  - The size of the shared memory buffer to allocate/add/register.
+ *   flags - Flags specifying the behaviour of this function. Supports
+ *           combinations of `TEE_SHM_{ALLOC,REGISTER,SEC_REGISTER}`.
+ *   shmep - Pass-by-reference pointer to return the shared memory entry
+ *           allocated. Cannot be NULL.
+ *
+ * Returned Values:
+ *   0 on success, negative error code otherwise.
+ *
+ ****************************************************************************/
+
+int optee_shm_alloc(FAR struct optee_priv_data *priv, bool align,
+                    FAR void *addr, size_t size, uint32_t flags,
+                    FAR struct optee_shm_entry **shmep)
+{
+  FAR struct optee_shm_entry *shme;
+  FAR void *ptr;
+  int ret;
+
+  shme = (FAR struct optee_shm_entry *)
+            kmm_zalloc(sizeof(struct optee_shm_entry));
+  if (shme == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  if (flags & TEE_SHM_ALLOC)
+    {
+      if (align && priv->alignment)
+        {
+          ptr = kmm_memalign(priv->alignment, size);
+        }
+      else
+        {
+          ptr = kmm_malloc(size);
+        }
+    }
+  else
+    {
+      ptr = addr;
+    }
+
+  if (ptr == NULL)
+    {
+      ret = -ENOMEM;
+      goto err;
+    }
+
+  shme->shm.addr = (uintptr_t)ptr;
+  shme->shm.length = size;
+  shme->shm.flags = flags;
+
+  if (flags & TEE_SHM_SEC_REGISTER)
+    {
+      ret = optee_shm_sec_register(priv, shme);
+      if (ret < 0)
+        {
+          goto err;
+        }
+    }
+
+  if (flags & TEE_SHM_REGISTER)
+    {
+      list_add_head(&priv->shm_list, &shme->node);
+    }
+
+  *shmep = shme;
+
+  return 0;
+
+err:
+  kmm_free(shme);
+

Review Comment:
   ditto



##########
drivers/misc/optee.h:
##########
@@ -64,6 +72,16 @@ extern "C"
 #define EXTERN extern
 #endif
 
+#ifdef CONFIG_ARCH_ADDRENV
+uintptr_t optee_va_to_pa(FAR void *va);

Review Comment:
   add consts



##########
drivers/misc/optee.h:
##########
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * drivers/misc/optee.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_MISC_OPTEE_H
+#define __DRIVERS_MISC_OPTEE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/compiler.h>
+#include <nuttx/tee.h>
+
+#include "optee_msg.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define OPTEE_SERVER_PATH              "optee"
+#define OPTEE_MAX_PARAM_NUM            6
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct optee_priv_data;

Review Comment:
   remove



-- 
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


Reply via email to