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 <[email protected]>
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 <[email protected]>
---
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;
+}