security: nv_tee_driver: kernel driver for tlk
Vandana Salve [Mon, 10 Dec 2012 23:29:06 +0000 (15:29 -0800)]
Added basic driver support, ioctl interface
Added support to lock the temporary and the shared memory buffers
Added command parameter descriptor free and used lists
Added shmem descriptor to keep track of pinned buffer
Added support to unpin temp buffers

Change-Id: I048c72bcf98ce0e75264144e66a1f8759b0ba0fe
Reviewed-on: http://git-master/r/169837
Reviewed-on: http://git-master/r/190658
Signed-off-by: Vandana Salve <vsalve@nvidia.com>
Reviewed-on: http://git-master/r/212074
Reviewed-by: Varun Wadekar <vwadekar@nvidia.com>
Tested-by: Varun Wadekar <vwadekar@nvidia.com>

security/Kconfig
security/Makefile
security/nv_tee_driver/Kconfig [new file with mode: 0644]
security/nv_tee_driver/Makefile [new file with mode: 0644]
security/nv_tee_driver/tee_client_api.h [new file with mode: 0644]
security/nv_tee_driver/tee_comms.c [new file with mode: 0644]
security/nv_tee_driver/tee_device.c [new file with mode: 0644]
security/nv_tee_driver/tee_irq.S [new file with mode: 0644]
security/nv_tee_driver/tee_protocol.h [new file with mode: 0644]
security/nv_tee_driver/tee_types.h [new file with mode: 0644]

index 7eaaed2..48c3820 100644 (file)
@@ -122,6 +122,7 @@ source security/smack/Kconfig
 source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 source security/tf_driver/Kconfig
+source security/nv_tee_driver/Kconfig
 source security/yama/Kconfig
 
 source security/integrity/Kconfig
index 3312cc3..219dc9e 100644 (file)
@@ -9,6 +9,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)     += apparmor
 subdir-$(CONFIG_TRUSTED_FOUNDATIONS)   += tf_driver
 subdir-$(CONFIG_SECURITY_YAMA)         += yama
+subdir-$(CONFIG_TRUSTED_LITTLE_KERNEL) += nv_tee_driver
 
 # always enable default capabilities
 obj-y                                  += commoncap.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_SECURITY_APPARMOR)               += apparmor/built-in.o
 obj-$(CONFIG_SECURITY_YAMA)            += yama/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
 obj-$(CONFIG_TRUSTED_FOUNDATIONS)      += tf_driver/built-in.o
+obj-$(CONFIG_TRUSTED_LITTLE_KERNEL)    += nv_tee_driver/built-in.o
 
 # Object integrity file lists
 subdir-$(CONFIG_INTEGRITY)             += integrity
diff --git a/security/nv_tee_driver/Kconfig b/security/nv_tee_driver/Kconfig
new file mode 100644 (file)
index 0000000..ad74e59
--- /dev/null
@@ -0,0 +1,8 @@
+config TRUSTED_LITTLE_KERNEL
+       bool "Enable NVIDIA Trusted Execution Environment driver"
+       select TEGRA_USE_SECURE_KERNEL
+       help
+         This option adds kernel support for communication with the NVIDIA
+         secure kernel.
+         If you are unsure how to answer this question, answer N.
+
diff --git a/security/nv_tee_driver/Makefile b/security/nv_tee_driver/Makefile
new file mode 100644 (file)
index 0000000..96761c6
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Copyright (c) 2013, NVIDIA Corporation.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+plus_sec := $(call as-instr,.arch_extension sec,+sec)
+AFLAGS_tee_irq.o :=-Wa,-march=armv7-a$(plus_sec)
+CFLAGS_tee_comms.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
+
+nv_tee_driver-objs += tee_device.o
+nv_tee_driver-objs += tee_comms.o
+nv_tee_driver-objs += tee_irq.o
+
+obj-$(CONFIG_TRUSTED_LITTLE_KERNEL) += nv_tee_driver.o
diff --git a/security/nv_tee_driver/tee_client_api.h b/security/nv_tee_driver/tee_client_api.h
new file mode 100644 (file)
index 0000000..d7b00e1
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ */
+
+/*
+ * This header file corresponds to V1.0_c of the GlobalPlatform
+ * TEE Client API Specification
+ */
+
+#ifndef __TEE_CLIENT_API_H__
+#define __TEE_CLIENT_API_H__
+
+#define TEEC_Result            uint32_t;
+
+#define TEEC_PARAM_TYPES(t0, t1, t2, t3) \
+        ((t0) | ((t1) << 4) | ((t2) << 8) | ((t3) << 12))
+#define TEEC_PARAM_TYPE_GET(t, i) (((t) >> (i*4)) & 0xF)
+
+/*
+ * Implementation dependent data types
+ */
+
+struct TEEC_Context_Imp {
+       uint32_t context_id;
+};
+
+struct TEEC_Session_Imp {
+       uint32_t context_id;
+       uint32_t session_id;
+};
+
+struct TEEC_Operation_Imp {
+       uint32_t context_id;
+       uint32_t session_id;
+};
+
+struct TEEC_SharedMemory_Imp {
+       uint32_t context_id;
+       uint32_t session_id;
+       uint32_t alloc_state;
+};
+
+/*
+ * Type definitions
+ */
+
+struct TEEC_Context {
+       struct TEEC_Context_Imp imp;
+};
+
+struct TEEC_Session {
+       struct TEEC_Session_Imp imp;
+};
+
+struct TEEC_SharedMemory {
+       void *buffer;
+       size_t size;
+       uint32_t flags;
+       struct TEEC_SharedMemory_Imp imp;
+};
+
+union TEEC_Param {
+       struct {
+               void *buffer;
+               size_t size;
+       } tmpref;
+       struct {
+               struct TEEC_SharedMemory *parent;
+               size_t size;
+               size_t offset;
+       } memref;
+       struct {
+               uint32_t a;
+               uint32_t b;
+       } value;
+};
+
+struct TEEC_Operation {
+       uint32_t started;
+       uint32_t paramTypes;
+       union TEEC_Param params[4];
+};
+
+struct TEEC_UUID {
+       uint32_t time_low;
+       uint16_t time_mid;
+       uint16_t time_hi_and_version;
+       uint8_t clock_seq_and_node[8];
+};
+
+#endif
diff --git a/security/nv_tee_driver/tee_comms.c b/security/nv_tee_driver/tee_comms.c
new file mode 100644 (file)
index 0000000..f9a5f6e
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/atomic.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/printk.h>
+#include <linux/ioctl.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#include "tee_types.h"
+#include "tee_protocol.h"
+
+bool verbose_smc;
+core_param(verbose_smc, verbose_smc, bool, 0644);
+
+static int tee_pin_user_pages(void *buffer, size_t size,
+       unsigned long *pages_ptr)
+{
+       int ret = 0, i;
+       unsigned int nr_pages;
+       struct page **pages = NULL;
+
+       nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+       pages = kzalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
+       if (!pages)
+               return -ENOMEM;
+
+       down_read(&current->mm->mmap_sem);
+       ret = get_user_pages(current, current->mm, (unsigned long)buffer,
+                               nr_pages, WRITE, 0, pages, NULL);
+       up_read(&current->mm->mmap_sem);
+
+       *pages_ptr = (unsigned long) pages;
+
+       return ret;
+}
+
+static struct nv_shmem_desc *tee_add_shmem_desc(void *buffer, size_t size,
+                       unsigned int nr_pages, struct page **pages,
+                       struct nv_tee_context *context)
+{
+       struct nv_shmem_desc *shmem_desc = NULL;
+       shmem_desc = kzalloc(
+                                               sizeof(struct nv_shmem_desc),
+                                               GFP_KERNEL);
+       if (shmem_desc) {
+               INIT_LIST_HEAD(&(shmem_desc->list));
+               shmem_desc->buffer = buffer;
+               shmem_desc->size = size;
+               shmem_desc->nr_pages = nr_pages;
+               shmem_desc->pages = pages;
+               list_add_tail(&shmem_desc->list, &(context->shmem_alloc_list));
+       }
+
+       return shmem_desc;
+}
+
+static void tee_del_shmem_desc(void *buffer, struct nv_tee_context *context)
+{
+       struct nv_shmem_desc *shmem_desc, *tmp_shmem_desc;
+       int i;
+
+       list_for_each_entry_safe(shmem_desc, tmp_shmem_desc,
+               &(context->shmem_alloc_list), list) {
+               if (shmem_desc->buffer == buffer) {
+                       list_del(&shmem_desc->list);
+                       for (i = 0; i < shmem_desc->nr_pages; i++)
+                               page_cache_release(shmem_desc->pages[i]);
+                       kfree(shmem_desc->pages);
+                       kfree(shmem_desc);
+               }
+       }
+}
+
+/*
+ * Do an SMC call
+ */
+static void do_smc(union smc_args_t *smc_args, void *data)
+{
+       unsigned int *args = smc_args->smc;
+
+#ifdef CONFIG_SMP
+       long ret;
+       cpumask_t saved_cpu_mask;
+       cpumask_t local_cpu_mask = CPU_MASK_NONE;
+
+       cpu_set(0, local_cpu_mask);
+       sched_getaffinity(0, &saved_cpu_mask);
+       ret = sched_setaffinity(0, &local_cpu_mask);
+       if (ret != 0)
+               pr_err("sched_setaffinity #1 -> 0x%lX", ret);
+#endif
+
+       if (verbose_smc) {
+               pr_info("SMC call:\n");
+               pr_info(" %08x %08x\n", args[0], args[1]);
+               pr_info(" %08x %08x\n", args[2], args[3]);
+               pr_info(" %08x %08x\n", args[4], args[5]);
+               pr_info(" %08x %08x\n", args[6], args[7]);
+       }
+
+       asm volatile (
+               "stmdb  sp!, {r4-r12}\n"
+               "mov    r12, %2\n"
+               "ldmia  r12, {r0-r7}\n"
+#ifdef REQUIRES_SEC
+               ".arch_extension sec\n"
+#endif
+               "smc    #0\n"
+               "ldmia  sp!, {r4-r12}\n"
+               "mov    r2, %0\n"
+               "str    r0, [r2]\n"
+               "mov    r2, %1\n"
+               "cmp    r2, #0\n"
+               "strne  r1, [r2]\n"
+               : : "r" (&smc_args->answer.result), "r" (data), "r" (args)
+               : "r0", "r1", "r2", "r3"
+       );
+
+       if (verbose_smc) {
+               pr_info("SMC result:\n");
+               pr_info(" %08x %08x\n", args[0], args[1]);
+               pr_info(" %08x %08x\n", args[2], args[3]);
+               pr_info(" %08x %08x\n", args[4], args[5]);
+               pr_info(" %08x %08x\n", args[6], args[7]);
+       }
+
+#ifdef CONFIG_SMP
+       ret = sched_setaffinity(0, &saved_cpu_mask);
+       if (ret != 0)
+               pr_err("sched_setaffinity #2 -> 0x%lX", ret);
+#endif
+}
+
+/*
+ * Do an 'empty' request just to get more pending answers.
+ */
+static void get_more_answers(union smc_args_t *smc_buf)
+{
+       smc_buf->request.type = TMK_SMC_GET_MORE;
+       /* rest of smc_buf ignored */
+       do_smc(smc_buf, NULL);
+}
+
+/*
+ * Handle an answer from the secure side.
+ * This should unblock the waiting client (according to session_id number)
+ * and give it back results from smc_buf->answer union field.
+ */
+static void interpret_single_answer(union smc_args_t *smc_buf)
+{
+       pr_info("UNBLOCK client of session %d\n", smc_buf->answer.session_id);
+       pr_info(" result=%08x origin=%08x\n",
+               smc_buf->answer.result, smc_buf->answer.return_origin);
+}
+
+/*
+ * Fetch all pending answers from the secure side.
+ */
+static void interpret_answers(union smc_args_t *smc_buf)
+{
+       /*
+        * Future improvement would be to signal the number
+        * of pending answers from secure side
+        */
+       while (smc_buf->answer.type == TMK_SMC_ANSWER) {
+               interpret_single_answer(smc_buf);
+               get_more_answers(smc_buf);
+       }
+
+       if (smc_buf->answer.type != TMK_SMC_NO_ANSWER)
+               pr_info("Protocol error: expected NO_ANSWER\n");
+}
+
+static void tee_setup_smc_buf(union smc_args_t *smc_buf,
+       uint32_t type, uint32_t session_id,
+       uint32_t command_id, phys_addr_t phy_cmd_page)
+{
+       smc_buf->request.type = type;
+       smc_buf->request.session_id = session_id;
+       smc_buf->request.command_id = command_id;
+       smc_buf->request.cmd_param = phy_cmd_page;
+}
+
+
+/*
+ * Open session SMC (TEEC_OpenSession)
+ */
+int tee_open_session(struct tee_opensession *cmd,
+               phys_addr_t phy_cmd_page,
+               struct tee_answer *answer)
+{
+       union smc_args_t smc_buf;
+       unsigned int id;
+
+       tee_setup_smc_buf(&smc_buf, TMK_SMC_OPEN_SESSION, cmd->login_types,
+               cmd->login_data, phy_cmd_page);
+
+       do_smc(&smc_buf, &id);
+       if (smc_buf.answer.result) {
+               pr_err("Error opening session: %08x %08x\n",
+                       smc_buf.answer.result,
+                       smc_buf.answer.return_origin);
+               return -1;
+       }
+
+       answer->session_id = id;
+       return 0;
+}
+
+/*
+ * Close session SMC (TEEC_CloseSession)
+ */
+int tee_close_session(uint32_t session_id)
+{
+       union smc_args_t smc_buf;
+
+       tee_setup_smc_buf(&smc_buf, TMK_SMC_CLOSE_SESSION, session_id,
+               0, 0);
+       do_smc(&smc_buf, NULL);
+       if (smc_buf.answer.result) {
+               pr_info("Error closing session: %08x\n", smc_buf.answer.result);
+               return -1;
+       }
+
+       return 0;
+}
+
+int tee_pin_mem_buffers(void *buffer, size_t size,
+       struct nv_tee_context *context)
+{
+
+       unsigned long pages = NULL;
+       struct nv_shmem_desc *shmem_desc = NULL;
+       int ret = 0, nr_pages = 0;
+
+       nr_pages = tee_pin_user_pages(buffer, size, &pages);
+       if (nr_pages <= 0) {
+               pr_err("tee_pin_mem_buffers: tee_pin_user_pages Failed\n");
+               ret = -EFAULT;
+               goto error;
+       }
+
+       shmem_desc = tee_add_shmem_desc(buffer, size,
+                               nr_pages, (struct page **)pages, context);
+       if (!shmem_desc) {
+               pr_err("tee_pin_mem_buffers: tee_add_shmem_desc Failed\n");
+               ret = -EFAULT;
+               goto error;
+       }
+
+       return 0;
+error:
+       return ret;
+}
+
+/*
+ * Register Shared Memory SMC (TEEC_RegisterSharedMemory)
+ */
+int tee_register_memory(struct tee_sharedmem *cmd, phys_addr_t phy_cmd_page,
+       struct tee_answer *answer, struct nv_tee_context *context)
+{
+       int ret = 0;
+       union smc_args_t smc_buf;
+
+       ret = tee_pin_mem_buffers(cmd->memref.buffer, cmd->memref.size,
+               context);
+       if (ret < 0) {
+               ret = -EFAULT;
+               goto error;
+       }
+
+       tee_setup_smc_buf(&smc_buf, TMK_SMC_REG_SHARED_MEM, cmd->session_id,
+               0, phy_cmd_page);
+
+       do_smc(&smc_buf, NULL);
+
+       return 0;
+error:
+       return ret;
+}
+
+/*
+ * Deregister previously initialized shared memory
+ */
+void tee_unregister_memory(void *buffer,
+       struct nv_tee_context *context)
+{
+       if (!(list_empty(&(context->shmem_alloc_list))))
+               tee_del_shmem_desc(buffer, context);
+       else
+               pr_err("No buffers to unpin\n");
+}
+
+/*
+ * Invoke Command SMC (TEEC_InvokeCommand)
+ */
+
+int tee_invoke_command(struct tee_invokecmd *cmd, phys_addr_t phy_cmd_page,
+       struct tee_answer *answer)
+{
+       union smc_args_t smc_buf;
+
+       pr_info("tee_invoke_command: session_id (%d) command_id(%d)\n",
+               cmd->session_id, cmd->command_id);
+
+       tee_setup_smc_buf(&smc_buf, TMK_SMC_INVOKE_CMD, cmd->session_id,
+               cmd->command_id, phy_cmd_page);
+
+       do_smc(&smc_buf, NULL);
+
+       if (smc_buf.answer.result) {
+               pr_err("Error opening session: %08x %08x\n",
+                       smc_buf.answer.result,
+                       smc_buf.answer.return_origin);
+               return -1;
+       }
+       return 0;
+}
+
+static int __init nv_tee_register_irq_handler(void)
+{
+       asm volatile (
+               "mov    r1, %0\n"
+               "movw   r0, #0x1FF0\n"
+               "movt   r0, #0xFFFF\n"
+#ifdef REQUIRES_SEC
+               ".arch_extension sec\n"
+#endif
+               "smc    #0\n"
+               "cpsie  i\n"
+               : : "r" (nv_tee_irq_handler)
+               : "r0", "r1", "r13", "r14"
+       );
+
+       return 0;
+}
+
+arch_initcall(nv_tee_register_irq_handler);
diff --git a/security/nv_tee_driver/tee_device.c b/security/nv_tee_driver/tee_device.c
new file mode 100644 (file)
index 0000000..8270b32
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/atomic.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/printk.h>
+#include <linux/ioctl.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include <asm/outercache.h>
+#include <linux/list.h>
+
+#include "tee_protocol.h"
+#include "tee_types.h"
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/nvsecurity.h>
+
+u32 notrace tegra_read_cycle(void)
+{
+       u32 cycle_count;
+
+       asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(cycle_count));
+
+       return cycle_count;
+}
+
+struct nv_device tee_nv_dev;
+
+static int tee_device_setup_operation_params(struct tee_cmd_param *param,
+       struct TEEC_Operation *operation)
+{
+       uint32_t i, type;
+       int ret = TEEC_SUCCESS;
+
+       param->param_types = operation->paramTypes;
+       for (i = 0; i < 4; i++) {
+               type = TEEC_PARAM_TYPE_GET(operation->paramTypes, i);
+               switch (type) {
+               case TEEC_PARAM_TYPE_NONE:
+                       break;
+               case TEEC_PARAM_TYPE_VALUE_INPUT:
+               case TEEC_PARAM_TYPE_VALUE_OUTPUT:
+               case TEEC_PARAM_TYPE_VALUE_INOUT:
+                       memcpy(&param->params[i].value,
+                               &operation->params[i].value,
+                               sizeof(union tee_param));
+               break;
+               case TEEC_PARAM_TYPE_MEMREF_INPUT:
+               case TEEC_PARAM_TYPE_MEMREF_OUTPUT:
+               case TEEC_PARAM_TYPE_MEMREF_INOUT:
+                       memcpy(&param->params[i].memref,
+                               &operation->params[i].tmpref,
+                               sizeof(union tee_param));
+               break;
+#if 0
+               /* XXX support for these requires some work */
+               case TEEC_PARAM_TYPE_MEMREF_WHOLE:
+               case TEEC_PARAM_TYPE_MEMREF_PARTIAL_INPUT:
+               case TEEC_PARAM_TYPE_MEMREF_PARTIAL_OUTPUT:
+               case TEEC_PARAM_TYPE_MEMREF_PARTIAL_INOUT:
+               break;
+#endif
+               default:
+                       return TEEC_ERROR_BAD_PARAMETERS;
+               }
+       }
+       return 0;
+}
+
+static int tee_setup_temp_buffers(struct TEEC_Operation *oper,
+       struct nv_tee_context *context)
+{
+       uint32_t i, type;
+       int ret = TEEC_SUCCESS;
+
+       for (i = 0; i < 4; i++) {
+               type = TEEC_PARAM_TYPE_GET(oper->paramTypes, i);
+               switch (type) {
+               case TEEC_PARAM_TYPE_NONE:
+               case TEEC_PARAM_TYPE_VALUE_INPUT:
+               case TEEC_PARAM_TYPE_VALUE_OUTPUT:
+               case TEEC_PARAM_TYPE_VALUE_INOUT:
+                       break;
+               case TEEC_PARAM_TYPE_MEMREF_INPUT:
+               case TEEC_PARAM_TYPE_MEMREF_OUTPUT:
+               case TEEC_PARAM_TYPE_MEMREF_INOUT:
+                       ret = tee_pin_mem_buffers(
+                               oper->params[i].tmpref.buffer,
+                               oper->params[i].tmpref.size,
+                               context);
+                       if (ret < 0) {
+                               pr_err("Pin buffer failed err (%d)\n", ret);
+                               break;
+                       }
+                       break;
+               default:
+                       pr_err("Pin buffer TEEC_ERROR_BAD_PARAMETERS\n");
+                       ret = TEEC_ERROR_BAD_PARAMETERS;
+               }
+       }
+       return ret;
+}
+
+static int tee_unpin_temp_buffers(struct TEEC_Operation *oper,
+       struct nv_tee_context *context)
+{
+       uint32_t i, type;
+       int ret = TEEC_SUCCESS;
+
+       for (i = 0; i < 4; i++) {
+               type = TEEC_PARAM_TYPE_GET(oper->paramTypes, i);
+               switch (type) {
+               case TEEC_PARAM_TYPE_NONE:
+               case TEEC_PARAM_TYPE_VALUE_INPUT:
+               case TEEC_PARAM_TYPE_VALUE_OUTPUT:
+               case TEEC_PARAM_TYPE_VALUE_INOUT:
+                       break;
+               case TEEC_PARAM_TYPE_MEMREF_INPUT:
+               case TEEC_PARAM_TYPE_MEMREF_OUTPUT:
+               case TEEC_PARAM_TYPE_MEMREF_INOUT:
+                       tee_unregister_memory(oper->params[i].tmpref.buffer,
+                               context);
+                       break;
+               default:
+                       pr_err("tee_pin_mem_buffers: TEEC_ERROR_BAD_PARAMETERS\n");
+                       ret = TEEC_ERROR_BAD_PARAMETERS;
+               }
+       }
+       return ret;
+
+}
+
+static struct nv_cmd_param_desc *tee_get_free_cmd_desc(struct nv_device *nv_dev)
+{
+       struct nv_cmd_param_desc *cmd_desc = NULL;
+
+       if (!(list_empty(&(nv_dev->free_cmd_list)))) {
+               cmd_desc = list_first_entry(&(nv_dev->free_cmd_list),
+                               struct nv_cmd_param_desc, list);
+               list_del(&(cmd_desc->list));
+               list_add_tail(&cmd_desc->list, &(nv_dev->used_cmd_list));
+       }
+       return cmd_desc;
+}
+
+static void tee_put_used_cmd_desc(struct nv_device *nv_dev,
+       struct nv_cmd_param_desc *cmd_desc)
+{
+       struct nv_cmd_param_desc *param_desc, *tmp_param_desc;
+
+       if (cmd_desc) {
+               list_for_each_entry_safe(param_desc, tmp_param_desc,
+                               &(nv_dev->used_cmd_list), list) {
+                       if (cmd_desc->param_addr ==
+                                       param_desc->param_addr) {
+                               list_del(&param_desc->list);
+                               list_add_tail(&param_desc->list,
+                                       &(nv_dev->free_cmd_list));
+                       }
+               }
+       }
+}
+
+static void tee_print_cmd_list(struct nv_device *dev, int used_list)
+{
+       struct nv_cmd_param_desc *param_desc;
+
+       if (!used_list) {
+               pr_info("Printing free cmd list\n");
+               if (!(list_empty(&(dev->free_cmd_list)))) {
+                       list_for_each_entry(param_desc, &(dev->free_cmd_list),
+                                       list)
+                               pr_info("Phys addr for cmd param desc (%X)\n",
+                                       param_desc->param_addr);
+               }
+       } else {
+               pr_info("Printing used cmd list\n");
+               if (!(list_empty(&(dev->used_cmd_list)))) {
+                       list_for_each_entry(param_desc, &(dev->used_cmd_list),
+                                       list)
+                               pr_info("Phys addr for cmd param desc (%X)\n",
+                                       param_desc->param_addr);
+               }
+       }
+}
+
+static void tee_print_opensession_cmd(struct tee_opensession *opensession)
+{
+       int i;
+       pr_info("UUID time low (%x)\n", opensession->dest_uuid.time_low);
+       pr_info("UUID time low (%x)\n", opensession->dest_uuid.time_mid);
+       pr_info("UUID time_hi_and_version (%x)\n",
+               opensession->dest_uuid.time_hi_and_version);
+       pr_info("login type (%d)\n", opensession->login_types);
+       if (opensession->login_data)
+               pr_info("login data (%d)\n", opensession->login_data);
+       for (i = 0; i < 4; i++)
+                       pr_info("Param#(%d) : param_type (%d)\n", i,
+                               TEEC_PARAM_TYPE_GET(
+                                       (opensession->operation.paramTypes),
+                                       i));
+}
+
+static int tee_device_open(struct inode *inode, struct file *file)
+{
+       struct nv_tee_context *context;
+       int ret = 0;
+
+       pr_info("tee_device_open\n");
+       context = kzalloc(
+                       sizeof(struct nv_tee_context), GFP_KERNEL);
+       if (!context) {
+               ret = -ENOMEM;
+               goto error;
+       }
+       context->dev = &tee_nv_dev;
+       INIT_LIST_HEAD(&(context->shmem_alloc_list));
+
+       file->private_data = context;
+       return 0;
+error:
+       return ret;
+}
+
+static int tee_device_release(struct inode *inode, struct file *file)
+{
+       pr_info("tee_device_release\n");
+       kfree(file->private_data);
+       file->private_data = NULL;
+       return 0;
+}
+
+static long tee_device_ioctl(struct file *file, unsigned int ioctl_num,
+       unsigned long ioctl_param)
+{
+       int err = TEEC_SUCCESS;
+       union tee_cmd command;
+       void *ptr_user_answer = NULL;
+       struct tee_answer answer;
+       struct tee_cmd_param *param;
+       struct nv_cmd_param_desc *cmd_desc = NULL;
+
+       struct nv_tee_context *context = file->private_data;
+       struct nv_device *nv_dev = context->dev;
+
+       if (copy_from_user(&command, (void __user *)ioctl_param,
+                               sizeof(union tee_cmd))) {
+               pr_err("Failed to copy command request\n");
+               goto error;
+       }
+
+       memset(&answer, 0, sizeof(struct tee_answer));
+       switch (ioctl_num) {
+       case TEE_IOCTL_OPEN_CLIENT_SESSION:
+               ptr_user_answer = (void *)command.opensession.answer;
+
+               cmd_desc = tee_get_free_cmd_desc(nv_dev);
+               if (cmd_desc) {
+                       param = (struct tee_cmd_param *)
+                               cmd_desc->param_addr;
+
+                       err = tee_device_setup_operation_params(param,
+                               &command.opensession.operation);
+                       if (err != TEEC_SUCCESS) {
+                               pr_err("setup operation params failed\n");
+                               goto error;
+                       }
+
+                       err = tee_setup_temp_buffers(
+                               &command.opensession.operation, context);
+                       if (err != TEEC_SUCCESS) {
+                               pr_err("setup temp buf failed err (%d)\n", err);
+                               goto error;
+                       }
+
+                       memcpy(&param->dest_uuid,
+                               &command.opensession.dest_uuid,
+                               sizeof(struct TEEC_UUID));
+
+                       err = tee_open_session(&command.opensession,
+                               virt_to_phys((void *)cmd_desc->param_addr),
+                               &answer);
+                       if (err)
+                               pr_err("open session failed with err (%d)\n",
+                                               err);
+                       err = tee_unpin_temp_buffers(
+                               &command.opensession.operation, context);
+               } else {
+                       pr_err("failed to get cmd_desc\n");
+                       goto error;
+               }
+               break;
+
+       case TEE_IOCTL_CLOSE_CLIENT_SESSION:
+               ptr_user_answer = (void *)command.closesession.answer;
+               err = tee_close_session(command.closesession.session_id);
+               if (err)
+                       pr_err("close session failed with error %d\n", err);
+               break;
+
+       case TEE_IOCTL_REGISTER_MEMORY:
+               ptr_user_answer = (void *)command.sharedmem.answer;
+               cmd_desc = tee_get_free_cmd_desc(nv_dev);
+               if (cmd_desc) {
+                       param = (struct tee_cmd_param *)
+                                cmd_desc->param_addr;
+                       param->param_types = command.sharedmem.memref.flags;
+                       param->params[0].memref.buffer =
+                               command.sharedmem.memref.buffer;
+                       param->params[0].memref.size =
+                               command.sharedmem.memref.size;
+               }
+
+               err = tee_register_memory(&(command.sharedmem),
+                       virt_to_phys((void *)cmd_desc->param_addr),
+                       &answer,
+                       context);
+               if (err)
+                       pr_err("memory registor failed with error %d\n", err);
+               break;
+
+       case TEE_IOCTL_RELEASE_SHARED_MEM:
+               tee_unregister_memory(command.release_shared_mem.buffer,
+                       context);
+               break;
+
+       case TEE_IOCTL_INVOKE_COMMAND:
+               ptr_user_answer = (void *)command.invokecmd.answer;
+               cmd_desc = tee_get_free_cmd_desc(nv_dev);
+               if (cmd_desc) {
+                       param = (struct tee_cmd_param *)
+                               cmd_desc->param_addr;
+                       err = tee_device_setup_operation_params(param,
+                               &command.invokecmd.operation);
+                       if (err != TEEC_SUCCESS) {
+                               pr_err("tee_device_setup_operation_params failed\n");
+                               goto error;
+                       }
+
+                       err = tee_setup_temp_buffers(
+                               &command.invokecmd.operation, context);
+                       if (err != TEEC_SUCCESS) {
+                               pr_err("setup temp buffers failed err (%d)\n",
+                                               err);
+                               goto error;
+                       }
+
+                       err = tee_invoke_command(&(command.invokecmd),
+                               virt_to_phys((void *)cmd_desc->param_addr),
+                                &answer);
+                       if (err) {
+                               pr_err("Invoke cmd id (%u) failed err (%d)\n",
+                                       command.invokecmd.command_id, err);
+                       }
+                       err = tee_unpin_temp_buffers(
+                               &command.invokecmd.operation, context);
+               } else {
+                       pr_err("failed to get cmd_desc\n");
+               }
+               break;
+
+       default:
+               pr_err("Invalid IOCTL Cmd\n");
+               err = -EINVAL;
+               goto error;
+       }
+       if (ptr_user_answer && !err)
+               if (copy_to_user(ptr_user_answer, &answer,
+                       sizeof(struct tee_answer))) {
+                       pr_err("Failed to copy answer\n");
+                       err = -EFAULT;
+               }
+error:
+       if (cmd_desc)
+               tee_put_used_cmd_desc(nv_dev, cmd_desc);
+       return err;
+}
+
+static int tee_create_free_cmd_list(struct nv_device *dev)
+{
+       struct page *tee_cmd_page;
+       int cmd_desc_count = 0, ret = 0;
+       struct nv_cmd_param_desc *param_desc;
+
+       tee_cmd_page =  alloc_pages(GFP_KERNEL, 1);
+       if (!tee_cmd_page) {
+               ret = -ENOMEM;
+               goto error;
+       }
+       set_pages_array_uc(&tee_cmd_page, 1);
+       dev->param_addr = (unsigned long) page_address(tee_cmd_page);
+
+       for (cmd_desc_count = 0;
+               cmd_desc_count < NV_CMD_DESC_MAX; cmd_desc_count++) {
+
+               param_desc = kzalloc(
+                                       sizeof(struct nv_cmd_param_desc),
+                                       GFP_KERNEL);
+               if (param_desc == NULL) {
+                       pr_err("Failed to allocate cmd param descriptor\n");
+                       ret = -ENOMEM;
+                       goto error;
+               }
+               param_desc->param_addr =
+                       dev->param_addr +
+                       sizeof(struct nv_cmd_param_desc) * cmd_desc_count;
+               INIT_LIST_HEAD(&(param_desc->list));
+
+               /*Add the cmd param descriptor to free list*/
+               list_add_tail(&param_desc->list, &(dev->free_cmd_list));
+       }
+error:
+       return ret;
+
+}
+
+/*
+ * tee_driver function definitions.
+ */
+static const struct file_operations tegra_tee_device_fops = {
+       .owner = THIS_MODULE,
+       .open = tee_device_open,
+       .release = tee_device_release,
+       .unlocked_ioctl = tee_device_ioctl,
+};
+
+struct miscdevice tegra_tee_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "tee_device",
+       .fops = &tegra_tee_device_fops,
+};
+
+static int __init nv_tee_init(void)
+{
+       int ret;
+
+       INIT_LIST_HEAD(&(tee_nv_dev.used_cmd_list));
+       INIT_LIST_HEAD(&(tee_nv_dev.free_cmd_list));
+
+       ret = tee_create_free_cmd_list(&tee_nv_dev);
+       if (ret != 0)
+               return ret;
+
+       return misc_register(&tegra_tee_device);
+}
+
+module_init(nv_tee_init);
diff --git a/security/nv_tee_driver/tee_irq.S b/security/nv_tee_driver/tee_irq.S
new file mode 100644 (file)
index 0000000..4e913cb
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * 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/linkage.h>
+#include <linux/init.h>
+
+ENTRY(nv_tee_irq_handler)
+       movw    r0, #0x1FF1
+       movt    r0, #0xFFFF
+       smc     #0
+ENDPROC(nv_tee_irq_handler)
diff --git a/security/nv_tee_driver/tee_protocol.h b/security/nv_tee_driver/tee_protocol.h
new file mode 100644 (file)
index 0000000..8983cad
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __NV_TEE_PROTOCOL_H
+#define __NV_TEE_PROTOCOL_H
+
+#include "tee_types.h"
+#include "tee_client_api.h"
+
+#define TEE_IOCTL_MAGIC_NUMBER ('t')
+#define TEE_IOCTL_OPEN_CLIENT_SESSION \
+       _IOWR(TEE_IOCTL_MAGIC_NUMBER, 0x10, union tee_cmd)
+#define TEE_IOCTL_CLOSE_CLIENT_SESSION \
+       _IOWR(TEE_IOCTL_MAGIC_NUMBER, 0x11, union tee_cmd)
+#define TEE_IOCTL_REGISTER_MEMORY \
+       _IOWR(TEE_IOCTL_MAGIC_NUMBER, 0x12, union tee_cmd)
+#define TEE_IOCTL_RELEASE_SHARED_MEM \
+       _IOWR(TEE_IOCTL_MAGIC_NUMBER, 0x13, struct TEEC_SharedMemory)
+#define TEE_IOCTL_INVOKE_COMMAND \
+       _IOWR(TEE_IOCTL_MAGIC_NUMBER, 0x14, union tee_cmd)
+#define TEE_IOCTL_REQ_CANCELLATION \
+       _IOR(TEE_IOCTL_MAGIC_NUMBER, 0x15, union tee_cmd)
+
+#define TEE_IOCTL_MIN_NR       _IOC_NR(TEE_IOCTL_OPEN_CLIENT_SESSION)
+#define TEE_IOCTL_MAX_NR       _IOC_NR(TEE_IOCTL_REQ_CANCELLATION)
+
+#define NV_CMD_DESC_MAX        120
+
+extern void nv_tee_irq_handler(void);
+
+struct nv_device {
+       unsigned long param_addr;
+       struct list_head used_cmd_list;
+       struct list_head free_cmd_list;
+};
+
+struct nv_cmd_param_desc {
+       unsigned long param_addr;
+       struct list_head list;
+};
+
+struct nv_shmem_desc {
+       struct list_head list;
+       void *buffer;
+       size_t size;
+       unsigned int mem_type;
+       struct page **pages;
+       unsigned int nr_pages;
+};
+
+struct nv_tee_context {
+       struct nv_device *dev;
+       struct list_head shmem_alloc_list;
+};
+
+enum {
+       /* Do a tee invoke */
+       TMK_SMC_INVOKE_CMD = 0xFFFF1000,
+       /* Get a pending answer without making new invokes */
+       TMK_SMC_GET_MORE = 0xFFFF1001,
+       /* Answer from secure side */
+       TMK_SMC_ANSWER = 0xFFFF1002,
+       /* No answers for now (secure side idle) */
+       TMK_SMC_NO_ANSWER = 0xFFFF1003,
+       /* Open Session */
+       TMK_SMC_OPEN_SESSION = 0xFFFF1004,
+       /* Close Session */
+       TMK_SMC_CLOSE_SESSION = 0xFFFF1005,
+       /* Alloc Shared Memory*/
+       TMK_SMC_ALLOC_SHARED_MEM = 0xFFFF1006,
+       /* Register Shared Memory*/
+       TMK_SMC_REG_SHARED_MEM = 0xFFFF1007,
+       /* Release Shared Memory*/
+       TMK_SMC_RELEASE_SHARED_MEM = 0xFFFF1008,
+};
+
+union tee_param {
+       struct {
+               void    *buffer;
+               size_t  size;
+       } memref;
+       struct {
+               uint32_t        a;
+               uint32_t        b;
+       } value;
+};
+
+struct tee_request {
+       uint32_t        type;
+       uint32_t        session_id;
+       uint32_t        command_id;
+       phys_addr_t     cmd_param;
+};
+
+struct tee_answer {
+       uint32_t        type;
+       uint32_t        result;
+       uint32_t        return_origin;
+       uint32_t        session_id;
+       union TEEC_Param        params[4];
+};
+
+/*
+ * structures for user app communication
+ */
+
+/*
+ * OpenSession
+ */
+
+struct tee_opensession {
+       struct TEEC_UUID dest_uuid;
+       uint32_t login_types;
+       uint32_t login_data;
+       struct TEEC_Operation operation;
+       uint32_t answer;
+};
+
+/*
+ * CloseSession
+ */
+struct tee_closesession {
+       uint32_t        session_id;
+       uint32_t        answer;
+};
+
+/*
+ * Shared Memory request
+ */
+struct tee_sharedmem {
+       uint32_t                session_id;
+       uint32_t                command_id;
+       struct TEEC_SharedMemory        memref;
+       uint32_t                answer;
+};
+
+/*
+ * Invoke Command request
+ */
+struct tee_invokecmd {
+       uint32_t        session_id;
+       uint32_t        command_id;
+       struct TEEC_Operation   operation;
+       uint32_t        answer;
+};
+
+/*
+ * Request Cancellation request
+ */
+struct tee_req_cancellation {
+       uint32_t        session_id;
+       uint32_t        command_id;
+       struct TEEC_Operation   operation;
+       uint32_t        answer;
+};
+
+union tee_cmd {
+       struct tee_opensession          opensession;
+       struct tee_closesession         closesession;
+       struct tee_sharedmem            sharedmem;
+       struct TEEC_SharedMemory                release_shared_mem;
+       struct tee_invokecmd            invokecmd;
+       struct tee_req_cancellation     cancellation;
+};
+
+struct tee_cmd_param {
+       uint32_t        param_types;
+       union tee_param params[4];
+       uint32_t        dest_uuid[4];
+};
+
+/*
+ * SMC protocol union
+ */
+union smc_args_t {
+       struct tee_request      request;
+       struct tee_answer       answer;
+       unsigned int            smc[8];
+};
+
+int tee_open_session(struct tee_opensession *cmd,
+       phys_addr_t phy_cmd_page,
+       struct tee_answer *answer);
+
+int tee_close_session(uint32_t session_id);
+
+int tee_register_memory(struct tee_sharedmem *cmd,
+       phys_addr_t phy_cmd_page,
+       struct tee_answer *answer,
+       struct nv_tee_context *context);
+
+void tee_unregister_memory(void *buffer,
+       struct nv_tee_context *context);
+
+int tee_invoke_command(struct tee_invokecmd *cmd,
+       phys_addr_t phy_cmd_page,
+       struct tee_answer *answer);
+
+int tee_pin_mem_buffers(void *buffer, size_t size,
+       struct nv_tee_context *context);
+#endif
diff --git a/security/nv_tee_driver/tee_types.h b/security/nv_tee_driver/tee_types.h
new file mode 100644 (file)
index 0000000..c1233f4
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __NV_TEE_TYPES_H__
+#define __NV_TEE_TYPES_H__
+
+/*
+ * Return Codes
+ */
+enum {
+       TEEC_SUCCESS                    = 0,
+       /* Non-specific cause */
+       TEEC_ERROR_GENERIC              = 0xFFFF0000,
+       /* Access priviledge not sufficient */
+       TEEC_ERROR_ACCESS_DENIED        = 0xFFFF0001,
+       /* The operation was cancelled */
+       TEEC_ERROR_CANCEL               = 0xFFFF0002,
+       /* Concurrent accesses conflict */
+       TEEC_ERROR_ACCESS_CONFLICT      = 0xFFFF0003,
+       /* Too much data for req was passed */
+       TEEC_ERROR_EXCESS_DATA          = 0xFFFF0004,
+       /* Input data was of invalid format */
+       TEEC_ERROR_BAD_FORMAT           = 0xFFFF0005,
+       /* Input parameters were invalid */
+       TEEC_ERROR_BAD_PARAMETERS       = 0xFFFF0006,
+       /* Oper invalid in current state */
+       TEEC_ERROR_BAD_STATE            = 0xFFFF0007,
+       /* The req data item not found */
+       TEEC_ERROR_ITEM_NOT_FOUND       = 0xFFFF0008,
+       /* The req oper not implemented */
+       TEEC_ERROR_NOT_IMPLEMENTED      = 0xFFFF0009,
+       /* The req oper not supported */
+       TEEC_ERROR_NOT_SUPPORTED        = 0xFFFF000A,
+       /* Expected data was missing */
+       TEEC_ERROR_NO_DATA              = 0xFFFF000B,
+       /* System ran out of resources */
+       TEEC_ERROR_OUT_OF_MEMORY        = 0xFFFF000C,
+       /* The system is busy */
+       TEEC_ERROR_BUSY                 = 0xFFFF000D,
+       /* Communication failed */
+       TEEC_ERROR_COMMUNICATION        = 0xFFFF000E,
+       /* A security fault was detected */
+       TEEC_ERROR_SECURITY             = 0xFFFF000F,
+       /* The supplied buffer is too short */
+       TEEC_ERROR_SHORT_BUFFER         = 0xFFFF0010,
+};
+
+/*
+ * Return Code origins
+ */
+enum {
+       TEEC_ORIGIN_API         = 1,
+       TEEC_ORIGIN_COMMS       = 2,
+       TEEC_ORIGIN_TEE         = 3,
+       TEEC_ORIGIN_TRUSTED_APP = 4,
+};
+
+/*
+ * Shared Memory control flags
+ */
+enum {
+       TEEC_MEM_INPUT  = 1,
+       TEEC_MEM_OUTPUT = 2,
+};
+
+/*
+ * Parameter types
+ */
+enum {
+       TEEC_PARAM_TYPE_NONE            = 0x0,
+       TEEC_PARAM_TYPE_VALUE_INPUT     = 0x1,
+       TEEC_PARAM_TYPE_VALUE_OUTPUT    = 0x2,
+       TEEC_PARAM_TYPE_VALUE_INOUT     = 0x3,
+       TEEC_PARAM_TYPE_MEMREF_INPUT    = 0x5,
+       TEEC_PARAM_TYPE_MEMREF_OUTPUT   = 0x6,
+       TEEC_PARAM_TYPE_MEMREF_INOUT    = 0x7,
+       TEEC_MEMREF_WHOLE               = 0xC,
+       TEEC_MEMREF_PARTIAL_INPUT       = 0xD,
+       TEEC_MEMREF_PARTIAL_OUTPUT      = 0xE,
+       TEEC_MEMREF_PARTIAL_INOUT       = 0xF,
+};
+
+/*
+ * Session Login Methods
+ */
+enum {
+       TEEC_LOGIN_PUBLIC               = 0x0,
+       TEEC_LOGIN_USER                 = 0x1,
+       TEEC_LOGIC_GROUP                = 0x2,
+       TEEC_LOGIC_APPLICATION          = 0x4,
+       TEEC_LOGIC_USER_APPLICATION     = 0x5,
+       TEEC_LOGIC_GROUP_APPLICATION    = 0x6,
+};
+#endif