This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new 30ef8ff84 examples/optee: Introduce an OP-TEE client example
30ef8ff84 is described below

commit 30ef8ff845b219220aa635660d570a673907e9e8
Author: George Poulios <gpoul...@census-labs.com>
AuthorDate: Sat May 3 19:38:58 2025 +0300

    examples/optee: Introduce an OP-TEE client example
    
    Add an example app that opens a session with the devices pseudo-TA
    and enumerates the available devices (prints their UUIDs only).
    
    The example showcases:
     - opening the OP-TEE client driver
     - printing its version
     - opening a session
     - allocating shared memory
     - registering shared memory
     - invoking a function to the TA referencing the shared memory
     - closing the session
    
    Enabled with CONFIG_EXAMPLES_OPTEE.
    
    Signed-off-by: George Poulios <gpoul...@census-labs.com>
---
 examples/optee/CMakeLists.txt |  33 ++++
 examples/optee/Kconfig        |  29 +++
 examples/optee/Make.defs      |  25 +++
 examples/optee/Makefile       |  34 ++++
 examples/optee/optee_main.c   | 410 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 531 insertions(+)

diff --git a/examples/optee/CMakeLists.txt b/examples/optee/CMakeLists.txt
new file mode 100644
index 000000000..e843d6717
--- /dev/null
+++ b/examples/optee/CMakeLists.txt
@@ -0,0 +1,33 @@
+# 
##############################################################################
+# apps/examples/optee/CMakeLists.txt
+#
+# 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.
+#
+# 
##############################################################################
+
+if(CONFIG_EXAMPLES_OPTEE)
+  nuttx_add_application(
+    NAME
+    ${CONFIG_EXAMPLES_OPTEE_PROGNAME}
+    SRCS
+    optee_main.c
+    STACKSIZE
+    ${CONFIG_EXAMPLES_OPTEE_STACKSIZE}
+    PRIORITY
+    ${CONFIG_EXAMPLES_OPTEE_PRIORITY})
+endif()
diff --git a/examples/optee/Kconfig b/examples/optee/Kconfig
new file mode 100644
index 000000000..9e91beff6
--- /dev/null
+++ b/examples/optee/Kconfig
@@ -0,0 +1,29 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config EXAMPLES_OPTEE
+       tristate "OP-TEE client example"
+       default n
+       ---help---
+               Enable the OP-TEE client example
+
+if EXAMPLES_OPTEE
+
+config EXAMPLES_OPTEE_PROGNAME
+       string "Program name"
+       default "optee"
+       ---help---
+               This is the name of the program that will be used when the NSH 
ELF
+               program is installed.
+
+config EXAMPLES_OPTEE_PRIORITY
+       int "OP-TEE task priority"
+       default 100
+
+config EXAMPLES_OPTEE_STACKSIZE
+       int "OP-TEE stack size"
+       default DEFAULT_TASK_STACKSIZE
+
+endif
diff --git a/examples/optee/Make.defs b/examples/optee/Make.defs
new file mode 100644
index 000000000..8da4df36e
--- /dev/null
+++ b/examples/optee/Make.defs
@@ -0,0 +1,25 @@
+############################################################################
+# apps/examples/optee/Make.defs
+#
+# 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.
+#
+############################################################################
+
+ifneq ($(CONFIG_EXAMPLES_OPTEE),)
+CONFIGURED_APPS += $(APPDIR)/examples/optee
+endif
diff --git a/examples/optee/Makefile b/examples/optee/Makefile
new file mode 100644
index 000000000..f60644cd7
--- /dev/null
+++ b/examples/optee/Makefile
@@ -0,0 +1,34 @@
+############################################################################
+# apps/examples/optee/Makefile
+#
+# 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.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+# OP-TEE client built-in application info
+
+PROGNAME  = $(CONFIG_EXAMPLES_OPTEE_PROGNAME)
+PRIORITY  = $(CONFIG_EXAMPLES_OPTEE_PRIORITY)
+STACKSIZE = $(CONFIG_EXAMPLES_OPTEE_STACKSIZE)
+MODULE    = $(CONFIG_EXAMPLES_OPTEE)
+
+MAINSRC = optee_main.c
+
+include $(APPDIR)/Application.mk
diff --git a/examples/optee/optee_main.c b/examples/optee/optee_main.c
new file mode 100644
index 000000000..9fd474f53
--- /dev/null
+++ b/examples/optee/optee_main.c
@@ -0,0 +1,410 @@
+/****************************************************************************
+ * apps/examples/optee/optee_main.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 <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <nuttx/tee.h>
+#include <uuid.h>
+
+/****************************************************************************
+ * Pre-processor definitions
+ ****************************************************************************/
+
+#define OPTEE_DEV                 "/dev/tee0"
+
+#define PTA_DEVICE_ENUM           { 0x7011a688, 0xddde, 0x4053, \
+                                    0xa5, 0xa9, \
+                                    { 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8 } }
+
+#define PTA_CMD_GET_DEVICES       0x0
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef struct tee_shm
+{
+  int fd;
+  size_t size;
+  void *ptr;
+  int32_t id;
+} tee_shm_t;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int tee_check_version_and_caps(int fd, uint32_t *caps)
+{
+  struct tee_ioctl_version_data ioc_ver;
+  int ret;
+
+  ret = ioctl(fd, TEE_IOC_VERSION, (unsigned long)&ioc_ver);
+  if (ret < 0)
+    {
+      printf("Failed to query TEE driver version and caps: %d, %s\n",
+             ret, strerror(errno));
+      return ret;
+    }
+
+  if (ioc_ver.impl_id != TEE_IMPL_ID_OPTEE)
+    {
+      printf("Not an OP-TEE implementation\n");
+      return -ENOTSUP;
+    }
+
+  if (!(ioc_ver.impl_caps & TEE_OPTEE_CAP_TZ))
+    {
+      printf("OP-TEE TrustZone not supported\n");
+      return -ENOTSUP;
+    }
+
+  if (((TEE_GEN_CAP_GP | TEE_GEN_CAP_MEMREF_NULL) & ioc_ver.gen_caps) !=
+       (TEE_GEN_CAP_GP | TEE_GEN_CAP_MEMREF_NULL))
+    {
+      printf("CAP_GP or MEMREF_NULL not supported\n");
+      return -ENOTSUP;
+    }
+
+  printf("impl id: %u, impl caps: %u, gen caps: %u\n",
+         ioc_ver.impl_id, ioc_ver.impl_caps, ioc_ver.gen_caps);
+
+  if (caps)
+    {
+      *caps = ioc_ver.gen_caps;
+    }
+
+  return ret;
+}
+
+static int tee_open_session(int fd, const uuid_t *uuid, uint32_t *session)
+{
+  struct tee_ioctl_open_session_arg ioc_opn;
+  struct tee_ioctl_buf_data ioc_buf;
+  int ret;
+
+  memset(&ioc_opn, 0, sizeof(struct tee_ioctl_open_session_arg));
+
+  uuid_enc_be(&ioc_opn.uuid, uuid);
+
+  ioc_buf.buf_ptr = (uintptr_t)&ioc_opn;
+  ioc_buf.buf_len = sizeof(struct tee_ioctl_open_session_arg);
+
+  ret = ioctl(fd, TEE_IOC_OPEN_SESSION, (unsigned long)&ioc_buf);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (session)
+    {
+      *session = ioc_opn.session;
+    }
+
+  return ret;
+}
+
+static int tee_invoke(int fd, uint32_t session, uint32_t func,
+                      struct tee_ioctl_param *params, size_t num_params)
+{
+  struct tee_ioctl_invoke_arg *ioc_args;
+  struct tee_ioctl_buf_data ioc_buf;
+  size_t ioc_args_len;
+  int ret;
+
+  ioc_args_len = sizeof(struct tee_ioctl_invoke_arg) +
+                 TEE_IOCTL_PARAM_SIZE(num_params);
+
+  ioc_args = (struct tee_ioctl_invoke_arg *)calloc(1, ioc_args_len);
+  if (!ioc_args)
+    {
+      return -ENOMEM;
+    }
+
+  ioc_args->func = func;
+  ioc_args->session = session;
+  ioc_args->num_params = num_params;
+  memcpy(&ioc_args->params, params, TEE_IOCTL_PARAM_SIZE(num_params));
+
+  ioc_buf.buf_ptr = (uintptr_t)ioc_args;
+  ioc_buf.buf_len = ioc_args_len;
+
+  ret = ioctl(fd, TEE_IOC_INVOKE, (unsigned long)&ioc_buf);
+  if (ret < 0)
+    {
+      goto err_with_args;
+    }
+
+  memcpy(params, &ioc_args->params, TEE_IOCTL_PARAM_SIZE(num_params));
+
+err_with_args:
+  free(ioc_args);
+
+  return ret;
+}
+
+static int tee_shm_register(int fd, tee_shm_t *shm)
+{
+  struct tee_ioctl_shm_register_data ioc_reg;
+
+  memset(&ioc_reg, 0, sizeof(struct tee_ioctl_shm_register_data));
+
+  if (!shm)
+    {
+      return -EINVAL;
+    }
+
+  shm->id = (int32_t)(uintptr_t)shm->ptr;
+
+  ioc_reg.addr = (uintptr_t)shm->ptr;
+  ioc_reg.length = shm->size;
+  ioc_reg.flags = TEE_SHM_REGISTER | TEE_SHM_SEC_REGISTER;
+  ioc_reg.id = shm->id;
+
+  return ioctl(fd, TEE_IOC_SHM_REGISTER, (unsigned long)&ioc_reg);
+}
+
+#if 0 /* Not used */
+static int tee_shm_mmap(int fd, tee_shm_t *shm, bool reg)
+{
+  struct tee_ioctl_shm_alloc_data ioc_alloc;
+  int ret = 0;
+
+  memset(&ioc_alloc, 0, sizeof(struct tee_ioctl_shm_alloc_data));
+
+  if (!shm)
+    {
+      return -EINVAL;
+    }
+
+  ioc_alloc.size = shm->size;
+
+  shm->fd = ioctl(fd, TEE_IOC_SHM_ALLOC, (unsigned long)&ioc_alloc);
+  if (shm->fd < 0)
+    {
+      return shm->fd;
+    }
+
+  shm->ptr = mmap(NULL, shm->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                  shm->fd, 0);
+  if (shm->ptr == MAP_FAILED)
+    {
+      close(shm->fd);
+      return -ENOMEM;
+    }
+
+  if (reg)
+    {
+      ret = tee_shm_register(fd, shm);
+      if (ret < 0)
+        {
+          munmap(shm->ptr, shm->size);
+          close(shm->fd);
+          return ret;
+        }
+    }
+
+  return ret;
+}
+#endif
+
+static int tee_shm_alloc(int fd, tee_shm_t *shm, bool reg)
+{
+  int ret = 0;
+
+  if (!shm)
+    {
+      return -EINVAL;
+    }
+
+  shm->ptr = malloc(shm->size);
+  if (!shm->ptr)
+    {
+      return -ENOMEM;
+    }
+
+  shm->fd = -1;
+
+  if (reg)
+    {
+      ret = tee_shm_register(fd, shm);
+      if (ret < 0)
+        {
+          free(shm->ptr);
+        }
+    }
+
+  return ret;
+}
+
+static void tee_shm_free(tee_shm_t *shm)
+{
+  if (!shm)
+    {
+      return;
+    }
+
+  if (shm->fd > 0)
+    {
+      /* Allocated via tee_shm_mmap() */
+
+      munmap(shm->ptr, shm->size);
+      close(shm->fd);
+    }
+  else
+    {
+      /* Allocated via tee_shm_alloc() */
+
+      free(shm->ptr);
+    }
+
+  shm->ptr = NULL;
+  shm->fd = -1;
+}
+
+static int tee_close_session(int fd, uint32_t session)
+{
+  struct tee_ioctl_close_session_arg ioc_close;
+  int ret;
+
+  ioc_close.session = session;
+
+  ret = ioctl(fd, TEE_IOC_CLOSE_SESSION, (unsigned long)&ioc_close);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * optee_main
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  int fd;
+  uint32_t caps;
+  const uuid_t pta_dvc_uuid = PTA_DEVICE_ENUM;
+  uint32_t session;
+  struct tee_ioctl_param par0;
+  tee_shm_t shm;
+  unsigned int count;
+  const uuid_t *raw_ta_uuid;
+  uuid_t ta_uuid;
+  char *ta_uuid_s;
+  int ret;
+
+  memset(&par0, 0, sizeof(struct tee_ioctl_param));
+  memset(&shm, 0, sizeof(tee_shm_t));
+
+  fd = open(OPTEE_DEV, O_RDONLY | O_NONBLOCK);
+  if (fd < 0)
+    {
+      printf("Failed to open " OPTEE_DEV ": %s\n", strerror(errno));
+      return -errno;
+    }
+
+  ret = tee_check_version_and_caps(fd, &caps);
+  if (ret < 0)
+    {
+      goto err;
+    }
+
+  ret = tee_open_session(fd, &pta_dvc_uuid, &session);
+  if (ret < 0)
+    {
+      printf("Failed to open session with devices.pta: %d, %s\n",
+             ret, strerror(errno));
+      goto err;
+    }
+
+  par0.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+
+  ret = tee_invoke(fd, session, PTA_CMD_GET_DEVICES, &par0, 1);
+  if (ret < 0)
+    {
+      printf("Failed to get size needed for device enumeration: %d, %s\n",
+             ret, strerror(errno));
+      goto err_with_session;
+    }
+
+  shm.size = par0.b;
+
+  ret = tee_shm_alloc(fd, &shm, caps & TEE_GEN_CAP_REG_MEM);
+  if (ret < 0)
+    {
+      printf("Failed to allocate shared memory: %d, %s\n",
+             ret, strerror(errno));
+      goto err_with_session;
+    }
+
+  par0.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+  par0.a = 0;
+  par0.b = shm.size;
+  par0.c = (uintptr_t)shm.ptr;
+
+  ret = tee_invoke(fd, session, PTA_CMD_GET_DEVICES, &par0, 1);
+  if (ret < 0)
+    {
+      printf("Failed to enumerate devices: %d, %s\n", ret, strerror(errno));
+      goto err_with_shm;
+    }
+
+  printf("Available devices:\n");
+
+  count = par0.b / sizeof(uuid_t);
+  raw_ta_uuid = (uuid_t *)shm.ptr;
+
+  while (count--)
+    {
+      uuid_dec_be(raw_ta_uuid, &ta_uuid);
+      uuid_to_string(&ta_uuid, &ta_uuid_s, NULL);
+
+      printf("  %s\n", ta_uuid_s);
+
+      free(ta_uuid_s);
+      raw_ta_uuid++;
+    }
+
+err_with_shm:
+  tee_shm_free(&shm);
+
+err_with_session:
+  tee_close_session(fd, session);
+
+err:
+  close(fd);
+
+  return ret;
+}

Reply via email to