Thread (11 messages) 11 messages, 4 authors, 2015-06-18

[PATCH V3 2/2] tee: add OP-TEE driver

From: mark.rutland@arm.com (Mark Rutland)
Date: 2015-05-18 13:19:14
Also in: linux-devicetree, lkml

Hi,

On Fri, May 15, 2015 at 07:34:27AM +0100, Jens Wiklander wrote:
Adds a OP-TEE driver which also can be compiled as a loadable module.

* Targets ARM and ARM64
* Supports using reserved memory from OP-TEE as shared memory
* CMA as shared memory is optional and only tried if OP-TEE doesn't
  supply a reserved shared memory region
How does OP-TEE provide that reserved memory? How is that described in
DT/UEFI to the OS (e.g. is there a memreserve, or is the memory not
described at all)?
* Probes OP-TEE version using SMCs
* Accepts requests on privileged and unprivileged device
* Uses OPTEE message protocol version 2

Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
---
 Documentation/devicetree/bindings/optee/optee.txt  |  17 +
I'm concerned that there's no documentation regarding the interface
exposed to userspace, for neither rationale nor usage.

I'm also very concerned that the interface exposed to userspace is
hideously low-level. Surely we'd expect kernel-side drivers to be doing
the bulk of direct communication to the OP-TEE instance? In the lack of
a provided rationale I don't see why the current messaging interface
would make sense.
quoted hunk ↗ jump to hunk
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 MAINTAINERS                                        |   6 +
 drivers/tee/Kconfig                                |  10 +
 drivers/tee/Makefile                               |   1 +
 drivers/tee/optee/Kconfig                          |  19 +
 drivers/tee/optee/Makefile                         |  13 +
 drivers/tee/optee/call.c                           | 294 ++++++++++++
 drivers/tee/optee/core.c                           | 509 ++++++++++++++++++++
 drivers/tee/optee/optee_private.h                  | 138 ++++++
 drivers/tee/optee/optee_smc.h                      | 510 +++++++++++++++++++++
 drivers/tee/optee/rpc.c                            | 282 ++++++++++++
 drivers/tee/optee/smc_a32.S                        |  30 ++
 drivers/tee/optee/smc_a64.S                        |  37 ++
 drivers/tee/optee/supp.c                           | 327 +++++++++++++
 include/uapi/linux/optee_msg.h                     | 368 +++++++++++++++
 16 files changed, 2562 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/optee/optee.txt
 create mode 100644 drivers/tee/optee/Kconfig
 create mode 100644 drivers/tee/optee/Makefile
 create mode 100644 drivers/tee/optee/call.c
 create mode 100644 drivers/tee/optee/core.c
 create mode 100644 drivers/tee/optee/optee_private.h
 create mode 100644 drivers/tee/optee/optee_smc.h
 create mode 100644 drivers/tee/optee/rpc.c
 create mode 100644 drivers/tee/optee/smc_a32.S
 create mode 100644 drivers/tee/optee/smc_a64.S
 create mode 100644 drivers/tee/optee/supp.c
 create mode 100644 include/uapi/linux/optee_msg.h
diff --git a/Documentation/devicetree/bindings/optee/optee.txt b/Documentation/devicetree/bindings/optee/optee.txt
new file mode 100644
index 0000000..8cea829
--- /dev/null
+++ b/Documentation/devicetree/bindings/optee/optee.txt
@@ -0,0 +1,17 @@
+OP-TEE Device Tree Bindings
+
+OP-TEE is a piece of software using hardware features to provide a Trusted
+Execution Environment. The security can be provided with ARM TrustZone, but
+also by virtualization or a separate chip. As there's no single OP-TEE
+vendor we're using "optee" as the first part of compatible propterty,
s/propterty/property/
+indicating the OP-TEE protocol is used when communicating with the secure
+world.
+
+* OP-TEE based on ARM TrustZone required properties:
+
+- compatible="optee,optee-tz"
+
+Example:
+       optee {
+               compatible="optee,optee-tz";
+       };
What does the OP-TEE protocol give in the way of discoverability? Is it
expected that the specific implementation and/or features will be
detected dynamically?

Where can I find documentation on the protocol?
quoted hunk ↗ jump to hunk
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 8033919..17c2a7e 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -141,6 +141,7 @@ nvidia      NVIDIA
 nxp    NXP Semiconductors
 onnn   ON Semiconductor Corp.
 opencores      OpenCores.org
+optee  OP-TEE, Open Portable Trusted Execution Environment
 ortustech      Ortus Technology Co., Ltd.
 ovti   OmniVision Technologies
 panasonic      Panasonic Corporation
diff --git a/MAINTAINERS b/MAINTAINERS
index dfcc9cc..1234695 100644
Please split the DT binding parts into a separate patch, at the start of
the series.
quoted hunk ↗ jump to hunk
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
new file mode 100644
index 0000000..096651d
--- /dev/null
+++ b/drivers/tee/optee/Makefile
@@ -0,0 +1,13 @@
+obj-$(CONFIG_OPTEE) += optee.o
+optee-objs += core.o
+optee-objs += call.o
+ifdef CONFIG_ARM
+plus_sec := $(call as-instr,.arch_extension sec,+sec)
+AFLAGS_smc_a32.o := -Wa,-march=armv7-a$(plus_sec)
+optee-objs += smc_a32.o
+endif
+ifdef CONFIG_ARM64
+optee-objs += smc_a64.o
+endif
The assembly objects should probably live under the relevant arch/
folders, and can probably be shared with clients for other services
compliant with the SMC Calling Conventions.
+static void optee_call_lock(struct optee_call_sync *callsync)
+{
+       mutex_lock(&callsync->mutex);
+}
+
+static void optee_call_lock_wait_completion(struct optee_call_sync *callsync)
+{
+       /*
+        * Release the lock until "something happens" and then reacquire it
+        * again.
When you say you're waiting until "something happens", you really are
waiting until something happens. The quotes aren't helpful, please drop
them.
+        *
+        * This is needed when TEE returns "busy" and we need to try again
+        * later.
+        */
+       callsync->c_waiters++;
+       mutex_unlock(&callsync->mutex);
+       /*
+        * Wait at most one second. Secure world is normally never busy
+        * more than that so we should normally never timeout.
+        */
+       wait_for_completion_timeout(&callsync->c, HZ);
+       mutex_lock(&callsync->mutex);
+       callsync->c_waiters--;
+}
+
+static void optee_call_unlock(struct optee_call_sync *callsync)
+{
+       /*
+        * If at least one thread is waiting for "something to happen" let
+        * one thread know that "something has happened".
+        */
+       if (callsync->c_waiters)
+               complete(&callsync->c);
+       mutex_unlock(&callsync->mutex);
+}
+
You can get rid of the c_waiters variable entirely, as complete() is
safe to call when the completion has an empty waiters list (and the
manipulation of c_waiters is racy anyway...).

Also, I think you need complete_all(&callsync->c) if more than two
concurrent calls are possible. Otherwise one call might block another
indefinitely.
+static int optee_arg_from_user(struct opteem_arg *arg, size_t size,
+                       struct tee_shm **put_shm)
+{
+       struct opteem_param *param;
+       size_t n;
+
+       if (!arg->num_params || !put_shm)
+               return -EINVAL;
+
+       param = OPTEEM_GET_PARAMS(arg);
OPTEEM is a little opaque. OPTEE_MSG would be easier to grasp.

[...]
quoted hunk ↗ jump to hunk
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
new file mode 100644
index 0000000..b3f8b92d
--- /dev/null
+++ b/drivers/tee/optee/core.c
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/dma-contiguous.h>
+#ifdef CONFIG_OPTEE_USE_CMA
+#include <linux/cma.h>
+#endif
Surely this ifdeffery isn't necessary?

[...]
+static struct tee_shm_pool *optee_config_shm_ioremap(struct device *dev,
+                       void __iomem **ioremaped_shm)
+{
+       struct optee_smc_param param = { .a0 = OPTEE_SMC_GET_SHM_CONFIG };
+       struct tee_shm_pool *pool;
+       u_long vaddr;
Why not plain unsigned long?

[...]
+/*
+ * This file is exported by OP-TEE and is in kept in sync between secure
+ * world and normal world kernel driver. We're following ARM SMC Calling
+ * Convention as specified in
+ * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
The values defined in the SMC Calling Conventions (which have nothing to
do with OP-TEE as such), we should probably prefix with SMCCC_, and have
in a shared file.
+ *
+ * This file depends on optee_msg.h being included to expand the SMC id
+ * macros below.
+ */
+
+#define OPTEE_SMC_32                   0
+#define OPTEE_SMC_64                   0x40000000
+#define OPTEE_SMC_FAST_CALL            0x80000000
+#define OPTEE_SMC_STD_CALL             0
The zero cases look a bit odd here. They might be better-documented if
you defined them with shifts, e.g.

#define SMCCC_SMC_32                    (0 << 30)
#define SMCCC_SMC_64                    (1 << 30)
#define SMCCC_FAST_CALL                 (1 << 31)
#define SMCCC_STD_CALL                  (0 << 31)

[...]
+/*
+ * Cache settings for shared memory
+ */
+#define OPTEE_SMC_SHM_NONCACHED                0ULL
+#define OPTEE_SMC_SHM_CACHED           1ULL
What precise set of memory attributes do these imply?

[...]
+/*
+ * Same values as TEE_PARAM_* from TEE Internal API
+ */
+#define OPTEEM_ATTR_TYPE_NONE          0
+#define OPTEEM_ATTR_TYPE_VALUE_INPUT   1
+#define OPTEEM_ATTR_TYPE_VALUE_OUTPUT  2
+#define OPTEEM_ATTR_TYPE_VALUE_INOUT   3
+#define OPTEEM_ATTR_TYPE_MEMREF_INPUT  5
+#define OPTEEM_ATTR_TYPE_MEMREF_OUTPUT 6
+#define OPTEEM_ATTR_TYPE_MEMREF_INOUT  7
Are these well-defined ABI values?

As mentioned previously, OPTEEM_* is opaque, and OPTEE_MSG_* would be
far clearer.
+/**
+ * struct opteem_param_memref - memory reference
+ * @buf_ptr:   Address of the buffer
+ * @size:      Size of the buffer
+ * @shm_ref:   Shared memory reference only used by normal world
+ *
+ * Secure and normal world communicates pointers as physical address
+ * instead of the virtual address. This is because secure and normal world
+ * have completely independent memory mapping. Normal world can even have a
+ * hypervisor which need to translate the guest physical address (AKA IPA
+ * in ARM documentation) to a real physical address before passing the
+ * structure to secure world.
+ */
+struct opteem_param_memref {
+       __u64 buf_ptr;
+       __u64 size;
+       __u64 shm_ref;
+};
Why does this mention physical addresses at all? What does that have to
do with userspace?

What is the shm_ref, and who allocates it?

There should really be some documentation for this.
+/**
+ * struct opteem_param_value - values
+ * @a: first value
+ * @b: second value
+ * @c: third value
+ */
+struct opteem_param_value {
+       __u64 a;
+       __u64 b;
+       __u64 c;
+};
Are OP-TEE messages defined to only ever take three parameters?

[...]
+/**
+ * struct optee_cmd_prefix - initial header for all user space buffers
+ * @func_id:   Function Id OPTEEM_FUNCID_* below
+ * @pad:       padding to make the struct size a multiple of 8 bytes
+ *
+ * This struct is 8 byte aligned since it's always followed by a struct
+ * opteem_arg which requires 8 byte alignment.
+ */
+struct opteem_cmd_prefix {
+       __u32 func_id;
+       __u32 pad __aligned(8);
+};
Shouldn't the alignment be applied to the struct as a whole rather than
the final field?
+/*
+ * Sleep mutex, helper for secure world to implement a sleeping mutex.
+ * struct opteem_arg::func     one of OPTEEM_RPC_SLEEP_MUTEX_* below
+ *
+ * OPTEEM_RPC_SLEEP_MUTEX_WAIT
+ * [in] param[0].value .a sleep mutex key
+ *                     .b wait tick
+ * [not used] param[1]
+ *
+ * OPTEEM_RPC_SLEEP_MUTEX_WAKEUP
+ * [in] param[0].value .a sleep mutex key
+ *                     .b wait after
+ * [not used] param[1]
+ *
+ * OPTEEM_RPC_SLEEP_MUTEX_DELETE
+ * [in] param[0].value .a sleep mutex key
+ * [not used] param[1]
+ */
+#define OPTEEM_RPC_SLEEP_MUTEX_WAIT    0
+#define OPTEEM_RPC_SLEEP_MUTEX_WAKEUP  1
+#define OPTEEM_RPC_SLEEP_MUTEX_DELETE  2
+#define OPTEEM_RPC_CMD_SLEEP_MUTEX     4
I'm lost. Why are mutexes exposed to userspace or the secure world in
such a manner?

Thanks,
Mark.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help