diff options
author | James Zhao <jamesz@nvidia.com> | 2013-06-07 15:51:20 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 13:34:23 -0700 |
commit | 09745b57d5f9b4cc57a9bc6ca0e428ec6e918446 (patch) | |
tree | 4a578eee4d62bb9947fa3e938e881cc969fe4ef2 /security | |
parent | dac6c1c7844bdfbf901a1af37c6de467130dbfca (diff) |
tlk: New API changes for tlk
- add new parameter passing support for variable number of parameter
- some clean up of naming conventions
Bug 1310292
Change-Id: Ie9669456682fe2b85eb79a3d9cb4cbac9eba8d54
Signed-off-by: James Zhao <jamesz@nvidia.com>
Reviewed-on: http://git-master/r/239104
(cherry picked from commit da4ee985be76b4f02284510d2eb7e851fb50bc0b)
Reviewed-on: http://git-master/r/249870
Reviewed-by: Varun Wadekar <vwadekar@nvidia.com>
Tested-by: Varun Wadekar <vwadekar@nvidia.com>
Tested-by: Aaron Gamble <jgamble@nvidia.com>
Diffstat (limited to 'security')
-rw-r--r-- | security/Kconfig | 2 | ||||
-rw-r--r-- | security/Makefile | 4 | ||||
-rw-r--r-- | security/nv_tee_driver/Kconfig | 8 | ||||
-rw-r--r-- | security/nv_tee_driver/tee_client_api.h | 115 | ||||
-rw-r--r-- | security/nv_tee_driver/tee_comms.c | 455 | ||||
-rw-r--r-- | security/nv_tee_driver/tee_device.c | 364 | ||||
-rw-r--r-- | security/nv_tee_driver/tee_protocol.h | 216 | ||||
-rw-r--r-- | security/nv_tee_driver/tee_types.h | 109 | ||||
-rw-r--r-- | security/tlk_driver/Kconfig | 7 | ||||
-rw-r--r-- | security/tlk_driver/Makefile (renamed from security/nv_tee_driver/Makefile) | 18 | ||||
-rw-r--r-- | security/tlk_driver/ote_comms.c | 372 | ||||
-rw-r--r-- | security/tlk_driver/ote_device.c | 456 | ||||
-rw-r--r-- | security/tlk_driver/ote_fs.c (renamed from security/nv_tee_driver/tee_fs.c) | 139 | ||||
-rw-r--r-- | security/tlk_driver/ote_irq.S (renamed from security/nv_tee_driver/tee_irq.S) | 6 | ||||
-rw-r--r-- | security/tlk_driver/ote_protocol.h | 202 | ||||
-rw-r--r-- | security/tlk_driver/ote_types.h | 79 |
16 files changed, 1194 insertions, 1358 deletions
diff --git a/security/Kconfig b/security/Kconfig index 48c38202d998..60738cb04caa 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -122,7 +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/tlk_driver/Kconfig source security/yama/Kconfig source security/integrity/Kconfig diff --git a/security/Makefile b/security/Makefile index 219dc9e71e9c..6e5b56784cf7 100644 --- a/security/Makefile +++ b/security/Makefile @@ -9,7 +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 +subdir-$(CONFIG_TRUSTED_LITTLE_KERNEL) += tlk_driver # always enable default capabilities obj-y += commoncap.o @@ -27,7 +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 +obj-$(CONFIG_TRUSTED_LITTLE_KERNEL) += tlk_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 deleted file mode 100644 index ad74e591062b..000000000000 --- a/security/nv_tee_driver/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -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/tee_client_api.h b/security/nv_tee_driver/tee_client_api.h deleted file mode 100644 index 0f0eed2275db..000000000000 --- a/security/nv_tee_driver/tee_client_api.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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]; -}; - -#define TEEC_MAX_FILE_NAME_LEN 64 - -typedef enum { - TEEC_FILE_REQ_READ = 0, - TEEC_FILE_REQ_WRITE = 1, - TEEC_FILE_REQ_DELETE = 2, - TEEC_FILE_REQ_SIZE = 3, -} TEEC_FileReqType; - -typedef struct { - char name[TEEC_MAX_FILE_NAME_LEN]; - TEEC_FileReqType type; - void *user_data_buf; - void *kern_data_buf; - unsigned long data_len; - unsigned long result; - int error; -} TEEC_FileReq; - -struct tee_file_req_node { - struct list_head node; - TEEC_FileReq *req; -}; - -#endif diff --git a/security/nv_tee_driver/tee_comms.c b/security/nv_tee_driver/tee_comms.c deleted file mode 100644 index 81013894028d..000000000000 --- a/security/nv_tee_driver/tee_comms.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * 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); - -#define SET_RESULT(req, r, ro) { req->result = r; req->result_origin = ro; } - -#define TEE_PARAM_COUNT 4 - -static int tee_device_set_request_params(struct tee_request *request, - struct TEEC_Operation *operation) -{ - struct tee_cmd_param *param = &request->cmd_param; - uint32_t i, type; - - param->param_types = operation->paramTypes; - for (i = 0; i < TEE_PARAM_COUNT; 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(¶m->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(¶m->params[i].memref, - &operation->params[i].tmpref, - sizeof(union tee_param)); - break; - default: - return TEEC_ERROR_BAD_PARAMETERS; - } - } - return TEEC_SUCCESS; -} - -static int tee_device_get_answer_params(struct TEEC_Operation *operation, - struct tee_request *request) -{ - struct tee_cmd_param *param = &request->cmd_param; - uint32_t i, type; - - param->param_types = operation->paramTypes; - for (i = 0; i < TEE_PARAM_COUNT; 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(&operation->params[i].value, - ¶m->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(&operation->params[i].tmpref, - ¶m->params[i].memref, - sizeof(union tee_param)); - break; - default: - return TEEC_ERROR_BAD_PARAMETERS; - } - } - return TEEC_SUCCESS; -} - -static int tee_pin_user_pages(void *buffer, size_t size, - unsigned long *pages_ptr) -{ - int ret = 0; - unsigned int nr_pages; - struct page **pages = NULL; - - nr_pages = (((unsigned int)buffer & (PAGE_SIZE - 1)) + - (size + PAGE_SIZE - 1)) >> PAGE_SHIFT; - - pages = kzalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); - if (!pages) - return -ENOMEM; - - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, (unsigned long)buffer, - nr_pages, WRITE, 0, pages, NULL); - up_read(¤t->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 int tee_pin_mem_buffers(void *buffer, size_t size, - struct nv_tee_context *context) -{ - - unsigned long pages = 0; - 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 = TEEC_ERROR_OUT_OF_MEMORY; - 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 = TEEC_ERROR_OUT_OF_MEMORY; - goto error; - } - - return TEEC_SUCCESS; -error: - return ret; -} - -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 < TEE_PARAM_COUNT; 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("tee_pin_mem_buffers failed with err (%d)\n", - ret); - ret = TEEC_ERROR_BAD_PARAMETERS; - break; - } - break; - default: - pr_err("tee_pin_mem_buffers: TEEC_ERROR_BAD_PARAMETERS\n"); - ret = TEEC_ERROR_BAD_PARAMETERS; - break; - } - } - return ret; -} - -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); - } - } -} - -/* - * 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"); -} - -static void tee_unpin_temp_buffers(struct TEEC_Operation *oper, - struct nv_tee_context *context) -{ - uint32_t i, type; - - for (i = 0; i < TEE_PARAM_COUNT; 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_unpin_mem_buffers: TEEC_ERROR_BAD_PARAMETERS\n"); - break; - } - } -} - -/* - * Do an SMC call - */ -static void do_smc(struct tee_request *request) -{ - phys_addr_t smc_args = virt_to_phys(request); - unsigned long regs[15]; - -#ifdef CONFIG_SMP - long ret; - cpumask_t saved_cpu_mask; - cpumask_t local_cpu_mask = CPU_MASK_NONE; - - cpu_set(0, local_cpu_mask); - cpumask_copy(&saved_cpu_mask, tsk_cpus_allowed(current)); - ret = sched_setaffinity(0, &local_cpu_mask); - if (ret != 0) - pr_err("sched_setaffinity #1 -> 0x%lX", ret); -#endif - - asm volatile ( - "mov r0, %0 \n" - "stmia r0, {r4-r12} \n" - "mov r0, %1 \n" - "mov r1, %2 \n" -#ifdef REQUIRES_SEC - ".arch_extension sec \n" -#endif - "smc #0 \n" - "mov r1, %0 \n" - "ldmia r1, {r4-r12} \n" - : : "r" (regs), "r" (request->type), "r" (smc_args) - : "r0", "r1" - ); - -#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(struct tee_request *request) -{ - request->type = TMK_SMC_GET_MORE; - /* rest of request ignored */ - do_smc(request); -} - -/* - * Open session SMC (TEEC_OpenSession) - */ -void tee_open_session(struct tee_opensession *cmd, - struct tee_request *request, - struct nv_tee_context *context) -{ - int ret; - - ret = tee_device_set_request_params(request, &cmd->operation); - if (ret != TEEC_SUCCESS) { - pr_err("tee_device_set_request_params failed\n"); - SET_RESULT(request, ret, TEEC_ORIGIN_API); - return; - } - - ret = tee_setup_temp_buffers(&cmd->operation, context); - if (ret != TEEC_SUCCESS) { - pr_err("tee_setup_temp_buffers failed err (0x%x)\n", ret); - SET_RESULT(request, ret, TEEC_ORIGIN_API); - return; - } - - memcpy(&request->cmd_param.dest_uuid, - &cmd->dest_uuid, - sizeof(struct TEEC_UUID)); - - pr_info("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n", - request->cmd_param.dest_uuid[0], - request->cmd_param.dest_uuid[1], - request->cmd_param.dest_uuid[2], - request->cmd_param.dest_uuid[3]); - - request->type = TMK_SMC_OPEN_SESSION; - - do_smc(request); - - tee_device_get_answer_params(&cmd->operation, request); - - tee_unpin_temp_buffers(&cmd->operation, context); -} - -/* - * Close session SMC (TEEC_CloseSession) - */ -void tee_close_session(struct tee_closesession *cmd, - struct tee_request *request) -{ - request->type = TMK_SMC_CLOSE_SESSION; - request->session_id = cmd->session_id; - - do_smc(request); - if (request->result) - pr_info("Error closing session: %08x\n", request->result); -} - -/* - * Register Shared Memory SMC (TEEC_RegisterSharedMemory) - */ -void tee_register_memory(struct tee_sharedmem *cmd, struct tee_request *request, - struct nv_tee_context *context) -{ - int ret = 0; - - request->type = TMK_SMC_REG_SHARED_MEM; - request->session_id = cmd->session_id; - - request->cmd_param.param_types = cmd->memref.flags; - request->cmd_param.params[0].memref.buffer = cmd->memref.buffer; - request->cmd_param.params[0].memref.size = cmd->memref.size; - - ret = tee_pin_mem_buffers(cmd->memref.buffer, cmd->memref.size, - context); - if (ret != TEEC_SUCCESS) { - SET_RESULT(request, ret, TEEC_ORIGIN_API); - return; - } - - do_smc(request); -} - -/* - * Invoke Command SMC (TEEC_InvokeCommand) - */ -void tee_invoke_command(struct tee_invokecmd *cmd, - struct tee_request *request, - struct nv_tee_context *context) -{ - int ret = TEEC_SUCCESS; - - ret = tee_device_set_request_params(request, &cmd->operation); - if (ret != TEEC_SUCCESS) { - pr_err("tee_device_set_request_params failed\n"); - SET_RESULT(request, ret, TEEC_ORIGIN_API); - return; - } - - ret = tee_setup_temp_buffers(&cmd->operation, context); - if (ret != TEEC_SUCCESS) { - pr_err("tee_setup_temp_buffers failed err (0x%x)\n", ret); - SET_RESULT(request, ret, TEEC_ORIGIN_API); - return; - } - - request->type = TMK_SMC_INVOKE_CMD; - request->session_id = cmd->session_id; - request->command_id = cmd->command_id; - - do_smc(request); - - tee_device_get_answer_params(&cmd->operation, request); - - tee_unpin_temp_buffers(&cmd->operation, context); -} - -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 deleted file mode 100644 index 57a5f5fa0c3e..000000000000 --- a/security/nv_tee_driver/tee_device.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * 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 SET_ANSWER(a, r, ro) { a.result = r; a.return_origin = ro; } - -#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; - -/* - * The maximum number of outstanding command requests. - */ -#define NV_CMD_DESC_MAX (PAGE_SIZE / sizeof(struct tee_request)) - -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 tee_request) * cmd_desc_count; - INIT_LIST_HEAD(&(param_desc->list)); - - /*Add the cmd param descriptor to free list*/ - list_add_tail(¶m_desc->list, &(dev->free_cmd_list)); - } -error: - 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(¶m_desc->list); - list_add_tail(¶m_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 int tee_device_open(struct inode *inode, struct file *file) -{ - struct nv_tee_context *context; - int ret = 0; - - 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) -{ - kfree(file->private_data); - file->private_data = NULL; - return 0; -} - -static long tee_handle_trustedapp_ioctl(struct file *file, unsigned int ioctl_num, - unsigned long ioctl_param) -{ - long err = 0; - union tee_cmd cmd; - void *ptr_user_answer = NULL; - struct tee_answer answer; - struct tee_request *request; - 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(&cmd, (void __user *)ioctl_param, - sizeof(union tee_cmd))) { - pr_err("Failed to copy command request\n"); - err = -EFAULT; - goto error; - } - - memset(&answer, 0, sizeof(struct tee_answer)); - switch (ioctl_num) { - case TEE_IOCTL_OPEN_CLIENT_SESSION: - ptr_user_answer = (void *)cmd.opensession.answer; - - cmd_desc = tee_get_free_cmd_desc(nv_dev); - if (!cmd_desc) { - SET_ANSWER(answer, - TEEC_ERROR_OUT_OF_MEMORY, - TEEC_ORIGIN_COMMS); - pr_err("failed to get cmd_desc\n"); - goto error; - } - - request = (struct tee_request *)cmd_desc->param_addr; - memset(request, 0, sizeof(struct tee_request)); - - tee_open_session(&cmd.opensession, request, context); - - memcpy(answer.params, cmd.opensession.operation.params, - sizeof(answer.params)); - - SET_ANSWER(answer, request->result, request->result_origin); - answer.session_id = request->session_id; - break; - - case TEE_IOCTL_CLOSE_CLIENT_SESSION: - ptr_user_answer = (void *)cmd.closesession.answer; - cmd_desc = tee_get_free_cmd_desc(nv_dev); - if (!cmd_desc) { - SET_ANSWER(answer, - TEEC_ERROR_OUT_OF_MEMORY, - TEEC_ORIGIN_COMMS); - pr_err("failed to get cmd_desc\n"); - goto error; - } - - request = (struct tee_request *)cmd_desc->param_addr; - memset(request, 0, sizeof(struct tee_request)); - - /* close session cannot fail */ - tee_close_session(&cmd.closesession, request); - break; - - case TEE_IOCTL_REGISTER_MEMORY: - ptr_user_answer = (void *)cmd.sharedmem.answer; - cmd_desc = tee_get_free_cmd_desc(nv_dev); - if (!cmd_desc) { - SET_ANSWER(answer, - TEEC_ERROR_OUT_OF_MEMORY, - TEEC_ORIGIN_COMMS); - pr_err("failed to get cmd_desc\n"); - goto error; - } - - request = (struct tee_request *)cmd_desc->param_addr; - memset(request, 0, sizeof(request)); - - tee_register_memory(&cmd.sharedmem, request, context); - - SET_ANSWER(answer, request->result, request->result_origin); - - break; - - case TEE_IOCTL_RELEASE_SHARED_MEM: - tee_unregister_memory(cmd.release_shared_mem.buffer, - context); - break; - - case TEE_IOCTL_INVOKE_COMMAND: - ptr_user_answer = (void *)cmd.invokecmd.answer; - cmd_desc = tee_get_free_cmd_desc(nv_dev); - - if (!cmd_desc) { - SET_ANSWER(answer, - TEEC_ERROR_OUT_OF_MEMORY, - TEEC_ORIGIN_COMMS); - pr_err("failed to get cmd_desc\n"); - goto error; - } - - request = (struct tee_request *)cmd_desc->param_addr; - memset(request, 0, sizeof(struct tee_request)); - - tee_invoke_command(&cmd.invokecmd, request, context); - - memcpy(answer.params, cmd.invokecmd.operation.params, - sizeof(answer.params)); - - SET_ANSWER(answer, request->result, request->result_origin); - 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 long tee_device_ioctl(struct file *file, unsigned int ioctl_num, - unsigned long ioctl_param) -{ - int err; - - switch (ioctl_num) { - case TEE_IOCTL_OPEN_CLIENT_SESSION: - case TEE_IOCTL_CLOSE_CLIENT_SESSION: - case TEE_IOCTL_REGISTER_MEMORY: - case TEE_IOCTL_RELEASE_SHARED_MEM: - case TEE_IOCTL_INVOKE_COMMAND: - err = tee_handle_trustedapp_ioctl(file, ioctl_num, ioctl_param); - break; - - case TEE_IOCTL_FILE_NEW_REQ: - case TEE_IOCTL_FILE_FILL_BUF: - case TEE_IOCTL_FILE_REQ_COMPLETE: - err = tee_handle_fs_ioctl(file, ioctl_num, ioctl_param); - break; - - default: - pr_err("%s: Invalid IOCTL (0x%lx) 0x%lx, %d\n", __func__, - ioctl_num, TEE_IOCTL_FILE_NEW_REQ, - sizeof(TEEC_FileReq)); - err = -EINVAL; - } - - return err; -} - -/* - * 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_protocol.h b/security/nv_tee_driver/tee_protocol.h deleted file mode 100644 index 2c6e71e3d7f3..000000000000 --- a/security/nv_tee_driver/tee_protocol.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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_FILE_NEW_REQ \ - _IOR(TEE_IOCTL_MAGIC_NUMBER, 0x16, TEEC_FileReq) -#define TEE_IOCTL_FILE_FILL_BUF \ - _IOR(TEE_IOCTL_MAGIC_NUMBER, 0x17, TEEC_FileReq) -#define TEE_IOCTL_FILE_REQ_COMPLETE \ - _IOWR(TEE_IOCTL_MAGIC_NUMBER, 0x18, TEEC_FileReq) - -#define TEE_IOCTL_MIN_NR _IOC_NR(TEE_IOCTL_OPEN_CLIENT_SESSION) -#define TEE_IOCTL_MAX_NR _IOC_NR(TEE_IOCTL_FILE_REQ_COMPLETE) - -#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; -}; - -/* - * 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]; -}; - -struct tee_request { - uint32_t type; - uint32_t session_id; - uint32_t command_id; - struct tee_cmd_param cmd_param; - uint32_t result; - uint32_t result_origin; -}; - -struct tee_answer { - uint32_t type; - uint32_t result; - uint32_t return_origin; - uint32_t session_id; - union TEEC_Param params[4]; -}; - -void tee_open_session(struct tee_opensession *cmd, - struct tee_request *request, - struct nv_tee_context *context); - -void tee_close_session(struct tee_closesession *cmd, - struct tee_request *request); - -void tee_register_memory(struct tee_sharedmem *cmd, - struct tee_request *request, - struct nv_tee_context *context); - -void tee_invoke_command(struct tee_invokecmd *cmd, - struct tee_request *request, - struct nv_tee_context *context); - -void tee_unregister_memory(void *buffer, - struct nv_tee_context *context); - -int tee_handle_fs_ioctl(struct file * file, unsigned int ioctl_num, - unsigned long ioctl_param); - -#endif diff --git a/security/nv_tee_driver/tee_types.h b/security/nv_tee_driver/tee_types.h deleted file mode 100644 index c1233f4eb47a..000000000000 --- a/security/nv_tee_driver/tee_types.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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 diff --git a/security/tlk_driver/Kconfig b/security/tlk_driver/Kconfig new file mode 100644 index 000000000000..240a3180d7a0 --- /dev/null +++ b/security/tlk_driver/Kconfig @@ -0,0 +1,7 @@ +config TRUSTED_LITTLE_KERNEL + bool "Enable Open Trusted Execution driver" + select TEGRA_USE_SECURE_KERNEL + help + This option adds kernel support for communication with the + Trusted LK secure OS monitor/runtime support. + If you are unsure how to answer this question, answer N. diff --git a/security/nv_tee_driver/Makefile b/security/tlk_driver/Makefile index 00b65f1eb0de..2fb6a24acc24 100644 --- a/security/nv_tee_driver/Makefile +++ b/security/tlk_driver/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, NVIDIA Corporation. +# Copyright (c) 2013 NVIDIA Corporation. All rights reserved. # # 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 @@ -17,13 +17,13 @@ # 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) -CFLAGS_tee_fs.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) +AFLAGS_ote_irq.o :=-Wa,-march=armv7-a$(plus_sec) +CFLAGS_ote_comms.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) +CFLAGS_ote_fs.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_fs.o -nv_tee_driver-objs += tee_irq.o +tlk_driver-objs += ote_device.o +tlk_driver-objs += ote_comms.o +tlk_driver-objs += ote_fs.o +tlk_driver-objs += ote_irq.o -obj-$(CONFIG_TRUSTED_LITTLE_KERNEL) += nv_tee_driver.o +obj-$(CONFIG_TRUSTED_LITTLE_KERNEL) += tlk_driver.o diff --git a/security/tlk_driver/ote_comms.c b/security/tlk_driver/ote_comms.c new file mode 100644 index 000000000000..fc9744ad3766 --- /dev/null +++ b/security/tlk_driver/ote_comms.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. + * + * 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 "ote_protocol.h" + +bool verbose_smc; +core_param(verbose_smc, verbose_smc, bool, 0644); + +#define SET_RESULT(req, r, ro) { req->result = r; req->result_origin = ro; } + +static int te_pin_user_pages(void *buffer, size_t size, + unsigned long *pages_ptr) +{ + int ret = 0; + unsigned int nr_pages; + struct page **pages = NULL; + + nr_pages = (((unsigned int)buffer & (PAGE_SIZE - 1)) + + (size + PAGE_SIZE - 1)) >> PAGE_SHIFT; + + pages = kzalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); + if (!pages) + return -ENOMEM; + + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, (unsigned long)buffer, + nr_pages, WRITE, 0, pages, NULL); + up_read(¤t->mm->mmap_sem); + + *pages_ptr = (unsigned long) pages; + + return ret; +} + +static struct te_shmem_desc *te_add_shmem_desc(void *buffer, size_t size, + unsigned int nr_pages, struct page **pages, + struct tlk_context *context) +{ + struct te_shmem_desc *shmem_desc = NULL; + shmem_desc = kzalloc(sizeof(struct te_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 int te_pin_mem_buffers(void *buffer, size_t size, + struct tlk_context *context) +{ + + unsigned long pages = 0; + struct te_shmem_desc *shmem_desc = NULL; + int ret = 0, nr_pages = 0; + + nr_pages = te_pin_user_pages(buffer, size, &pages); + if (nr_pages <= 0) { + pr_err("%s: te_pin_user_pages Failed\n", __func__); + ret = OTE_ERROR_OUT_OF_MEMORY; + goto error; + } + + shmem_desc = te_add_shmem_desc(buffer, size, + nr_pages, (struct page **)pages, context); + if (!shmem_desc) { + pr_err("%s: te_add_shmem_desc Failed\n", __func__); + ret = OTE_ERROR_OUT_OF_MEMORY; + goto error; + } + + return OTE_SUCCESS; +error: + return ret; +} + +static int te_setup_temp_buffers(struct te_request *request, + struct tlk_context *context) +{ + uint32_t i; + int ret = OTE_SUCCESS; + struct te_oper_param *params = request->params; + + for (i = 0; i < request->params_size; i++) { + switch (params[i].type) { + case TE_PARAM_TYPE_NONE: + case TE_PARAM_TYPE_INT_RO: + case TE_PARAM_TYPE_INT_RW: + break; + case TE_PARAM_TYPE_MEM_RO: + case TE_PARAM_TYPE_MEM_RW: + ret = te_pin_mem_buffers( + params[i].u.Mem.base, + params[i].u.Mem.len, + context); + if (ret < 0) { + pr_err("%s failed with err (%d)\n", + __func__, ret); + ret = OTE_ERROR_BAD_PARAMETERS; + break; + } + break; + default: + pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__); + ret = OTE_ERROR_BAD_PARAMETERS; + break; + } + } + return ret; +} + +static void te_del_shmem_desc(void *buffer, struct tlk_context *context) +{ + struct te_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); + } + } +} + +/* + * Deregister previously initialized shared memory + */ +void te_unregister_memory(void *buffer, + struct tlk_context *context) +{ + if (!(list_empty(&(context->shmem_alloc_list)))) + te_del_shmem_desc(buffer, context); + else + pr_err("No buffers to unpin\n"); +} + +static void te_unpin_temp_buffers(struct te_request *request, + struct tlk_context *context) +{ + uint32_t i; + struct te_oper_param *params = request->params; + + for (i = 0; i < request->params_size; i++) { + switch (params[i].type) { + case TE_PARAM_TYPE_NONE: + case TE_PARAM_TYPE_INT_RO: + case TE_PARAM_TYPE_INT_RW: + break; + case TE_PARAM_TYPE_MEM_RO: + case TE_PARAM_TYPE_MEM_RW: + te_unregister_memory(params[i].u.Mem.base, context); + break; + default: + pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__); + break; + } + } +} + +uint32_t __naked tlk_generic_smc(uint32_t arg0, uint32_t arg1, uint32_t arg2) +{ + register uint32_t r0 asm("r0") = arg0; + register uint32_t r1 asm("r1") = arg1; + register uint32_t r2 asm("r2") = arg2; + + asm volatile( + __asmeq("%0", "r0") + __asmeq("%1", "r0") + __asmeq("%2", "r1") + __asmeq("%3", "r2") + "stmfd sp!, {r4-r12} @ save reg state\n" +#ifdef REQUIRES_SEC + ".arch_extension sec\n" +#endif + "smc #0 @ switch to secure world\n" + "ldmfd sp!, {r4-r12} @ restore saved regs\n" + "bx lr" + : "=r" (r0) + : "r" (r0), "r" (r1), "r" (r2) + ); + return r0; +} + +uint32_t __naked tlk_extended_smc(uint32_t *regs) +{ + register uint32_t r0 asm("r0") = (uint32_t)regs; + + /* allows MAX_EXT_SMC_ARGS (r0-r11) to be passed in registers */ + asm volatile( + __asmeq("%0", "r0") + "stmfd sp!, {r4-r12} @ save reg state\n" + "mov r12, r0 @ reg ptr to r12\n" + "ldmia r12, {r0-r11} @ load arg regs\n" +#ifdef REQUIRES_SEC + ".arch_extension sec\n" +#endif + "smc #0 @ switch to secure world\n" + "ldmfd sp!, {r4-r12} @ restore saved regs\n" + "bx lr" + : "=r" (r0) + : "r" (r0) + ); + return r0; +} + +/* + * Do an SMC call + */ +static void do_smc(struct te_request *request) +{ +#ifdef CONFIG_SMP + cpumask_t saved_cpu_mask; +#endif + phys_addr_t smc_args = virt_to_phys(request); + phys_addr_t smc_params = 0; + + if (request->params) + smc_params = virt_to_phys(request->params); + +#ifdef CONFIG_SMP +{ + long ret; + cpumask_t local_cpu_mask = CPU_MASK_NONE; + + cpu_set(0, local_cpu_mask); + cpumask_copy(&saved_cpu_mask, tsk_cpus_allowed(current)); + ret = sched_setaffinity(0, &local_cpu_mask); + if (ret) + pr_err("sched_setaffinity #1 -> 0x%lX", ret); +} +#endif + + tlk_generic_smc(request->type, smc_args, smc_params); + +#ifdef CONFIG_SMP +{ + long ret = sched_setaffinity(0, &saved_cpu_mask); + if (ret) + pr_err("sched_setaffinity #2 -> 0x%lX", ret); +} +#endif +} + +/* + * Open session SMC (supporting client-based te_open_session() calls) + */ +void te_open_session(struct te_opensession *cmd, + struct te_request *request, + struct tlk_context *context) +{ + int ret; + + ret = te_setup_temp_buffers(request, context); + if (ret != OTE_SUCCESS) { + pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret); + SET_RESULT(request, ret, OTE_ERROR_ORIGIN_API); + return; + } + + memcpy(&request->dest_uuid, + &cmd->dest_uuid, + sizeof(struct te_service_id)); + + pr_info("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n", + request->dest_uuid[0], + request->dest_uuid[1], + request->dest_uuid[2], + request->dest_uuid[3]); + + request->type = TE_SMC_OPEN_SESSION; + + do_smc(request); + + te_unpin_temp_buffers(request, context); +} + +/* + * Close session SMC (supporting client-based te_close_session() calls) + */ +void te_close_session(struct te_closesession *cmd, + struct te_request *request) +{ + request->session_id = cmd->session_id; + request->type = TE_SMC_CLOSE_SESSION; + + do_smc(request); + if (request->result) + pr_info("Error closing session: %08x\n", request->result); +} + +/* + * Launch operation SMC (supporting client-based te_launch_operation() calls) + */ +void te_launch_operation(struct te_launchop *cmd, + struct te_request *request, + struct tlk_context *context) +{ + int ret; + + ret = te_setup_temp_buffers(request, context); + if (ret != OTE_SUCCESS) { + pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret); + SET_RESULT(request, ret, OTE_ERROR_ORIGIN_API); + return; + } + + request->session_id = cmd->session_id; + request->command_id = cmd->operation.command; + request->type = TE_SMC_LAUNCH_OPERATION; + + do_smc(request); + + te_unpin_temp_buffers(request, context); +} + +static int __init tlk_register_irq_handler(void) +{ + tlk_generic_smc(0xFFFF1FF0, (unsigned int)tlk_irq_handler, 0); + +#if 0 + 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" (tlk_irq_handler) + : "r0", "r1", "r13", "r14" + ); +#endif + + return 0; +} + +arch_initcall(tlk_register_irq_handler); diff --git a/security/tlk_driver/ote_device.c b/security/tlk_driver/ote_device.c new file mode 100644 index 000000000000..44d8a09971d0 --- /dev/null +++ b/security/tlk_driver/ote_device.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. + * + * 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 "ote_protocol.h" + +#define SET_ANSWER(a, r, ro) { a.result = r; a.return_origin = ro; } + +#define CREATE_TRACE_POINTS +#include <trace/events/nvsecurity.h> + +struct tlk_device tlk_dev; + +u32 notrace tegra_read_cycle(void) +{ + u32 cycle_count; + + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(cycle_count)); + + return cycle_count; +} + +/* + * The maximum number of outstanding command requests. + */ +#define TE_CMD_DESC_MAX (PAGE_SIZE / sizeof(struct te_request)) +#define TE_PARAM_MAX (PAGE_SIZE / sizeof(struct te_oper_param)) + +static int te_create_free_cmd_list(struct tlk_device *dev) +{ + struct page *te_cmd_pages; + int cmd_desc_count = 0, ret = 0; + struct te_cmd_req_desc *req_desc; + int bitmap_size; + + te_cmd_pages = alloc_pages(GFP_KERNEL, get_count_order(2)); + if (!te_cmd_pages) { + ret = -ENOMEM; + goto error; + } + + /* first 4KB page is request freelist, second is param freelist */ + dev->req_addr = (unsigned long) page_address(te_cmd_pages); + dev->param_addr = (struct te_oper_param *)(dev->req_addr + PAGE_SIZE); + set_memory_uc(dev->req_addr, 2); + + /* alloc param bitmap allocator */ + bitmap_size = BITS_TO_LONGS(TE_PARAM_MAX) * sizeof(long); + dev->param_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + + for (cmd_desc_count = 0; + cmd_desc_count < TE_CMD_DESC_MAX; cmd_desc_count++) { + + req_desc = kzalloc(sizeof(struct te_cmd_req_desc), GFP_KERNEL); + if (req_desc == NULL) { + pr_err("Failed to allocate cmd req descriptor\n"); + ret = -ENOMEM; + goto error; + } + req_desc->req_addr = dev->req_addr + + sizeof(struct te_request) * cmd_desc_count; + INIT_LIST_HEAD(&(req_desc->list)); + + /* Add the cmd param descriptor to free list */ + list_add_tail(&req_desc->list, &(dev->free_cmd_list)); + } +error: + return ret; + +} + +static struct te_oper_param *te_get_free_params(struct tlk_device *dev, + unsigned int nparams) +{ + struct te_oper_param *params = NULL; + int idx, nbits; + + if (nparams) { + nbits = get_count_order(nparams); + idx = bitmap_find_free_region(dev->param_bitmap, + TE_PARAM_MAX, nbits); + if (idx >= 0) + params = dev->param_addr + idx; + } + return params; +} + +static void te_put_free_params(struct tlk_device *dev, + struct te_oper_param *params, uint32_t nparams) +{ + int idx, nbits; + + idx = (params - dev->param_addr); + nbits = get_count_order(nparams); + bitmap_release_region(dev->param_bitmap, idx, nbits); +} + +static struct te_cmd_req_desc *te_get_free_cmd_desc(struct tlk_device *dev) +{ + struct te_cmd_req_desc *cmd_desc = NULL; + + if (!(list_empty(&(dev->free_cmd_list)))) { + cmd_desc = list_first_entry(&(dev->free_cmd_list), + struct te_cmd_req_desc, list); + list_del(&(cmd_desc->list)); + list_add_tail(&cmd_desc->list, &(dev->used_cmd_list)); + } + return cmd_desc; +} + +static void te_put_used_cmd_desc(struct tlk_device *dev, + struct te_cmd_req_desc *cmd_desc) +{ + struct te_cmd_req_desc *param_desc, *tmp_param_desc; + + if (cmd_desc) { + list_for_each_entry_safe(param_desc, tmp_param_desc, + &(dev->used_cmd_list), list) { + if (cmd_desc->req_addr == param_desc->req_addr) { + list_del(¶m_desc->list); + list_add_tail(¶m_desc->list, + &(dev->free_cmd_list)); + } + } + } +} + +static void __attribute__((unused)) te_print_cmd_list( + struct tlk_device *dev, int used_list) +{ + struct te_cmd_req_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 req desc (%lx)\n", + param_desc->req_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 req desc (%lx)\n", + param_desc->req_addr); + } + } +} + +static int tlk_device_open(struct inode *inode, struct file *file) +{ + struct tlk_context *context; + int ret = 0; + + context = kzalloc(sizeof(struct tlk_context), GFP_KERNEL); + if (!context) { + ret = -ENOMEM; + goto error; + } + context->dev = &tlk_dev; + INIT_LIST_HEAD(&(context->shmem_alloc_list)); + + file->private_data = context; + return 0; +error: + return ret; +} + +static int tlk_device_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + file->private_data = NULL; + return 0; +} + +static int copy_params_from_user(struct te_request *req, + struct te_operation *operation) +{ + struct te_oper_param *param_array; + struct te_oper_param *user_param; + uint32_t i; + + if (operation->list_count == 0) + return 0; + + param_array = req->params; + if (param_array == NULL) { + pr_err("param_array empty\n"); + return 1; + } + + user_param = operation->list_head; + for (i = 0; i < operation->list_count && user_param != NULL; i++) { + if (copy_from_user(param_array + i, user_param, + sizeof(struct te_oper_param))) { + pr_err("Failed to copy operation parameter:%d, %p, " \ + "list_count: %d\n", + i, user_param, operation->list_count); + return 1; + } + user_param = param_array[i].next_ptr_user; + } + return 0; +} + +static int copy_params_to_user(struct te_request *req, + struct te_operation *operation) +{ + struct te_oper_param *param_array; + struct te_oper_param *user_param; + uint32_t i; + + if (operation->list_count == 0) + return 0; + + param_array = req->params; + if (param_array == NULL) { + pr_err("param_array empty\n"); + return 1; + } + + user_param = operation->list_head; + for (i = 0; i < req->params_size; i++) { + if (copy_to_user(user_param, param_array + i, + sizeof(struct te_oper_param))) { + pr_err("Failed to copy back parameter:%d %p\n", i, + user_param); + return 1; + } + user_param = param_array[i].next_ptr_user; + } + return 0; +} + +static long te_handle_trustedapp_ioctl(struct file *file, + unsigned int ioctl_num, unsigned long ioctl_param) +{ + long err = 0; + union te_cmd cmd; + void *ptr_user_answer = NULL; + struct te_operation *operation = NULL; + struct te_oper_param *params = NULL; + struct te_answer answer; + struct te_request *request; + + struct te_cmd_req_desc *cmd_desc = NULL; + struct tlk_context *context = file->private_data; + struct tlk_device *dev = context->dev; + + if (copy_from_user(&cmd, (void __user *)ioctl_param, + sizeof(union te_cmd))) { + pr_err("Failed to copy command request\n"); + err = -EFAULT; + goto error; + } + + memset(&answer, 0, sizeof(struct te_answer)); + + switch (ioctl_num) { + case TE_IOCTL_OPEN_CLIENT_SESSION: + operation = &cmd.opensession.operation; + ptr_user_answer = (void *)cmd.opensession.answer; + + cmd_desc = te_get_free_cmd_desc(dev); + params = te_get_free_params(dev, operation->list_count); + + if (!cmd_desc || (operation->list_count && !params)) { + SET_ANSWER(answer, + OTE_ERROR_OUT_OF_MEMORY, + OTE_ERROR_ORIGIN_COMMS); + pr_err("failed to get cmd_desc/params\n"); + goto error; + } + + request = (struct te_request *)cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request)); + + request->params = params; + request->params_size = operation->list_count; + + if (copy_params_from_user(request, operation)) { + err = -EFAULT; + pr_info("failed to copy params from user\n"); + goto error; + } + + te_open_session(&cmd.opensession, request, context); + + SET_ANSWER(answer, request->result, request->result_origin); + answer.session_id = request->session_id; + break; + + case TE_IOCTL_CLOSE_CLIENT_SESSION: + ptr_user_answer = (void *)cmd.closesession.answer; + cmd_desc = te_get_free_cmd_desc(dev); + if (!cmd_desc) { + SET_ANSWER(answer, + OTE_ERROR_OUT_OF_MEMORY, + OTE_ERROR_ORIGIN_COMMS); + pr_err("failed to get cmd_desc\n"); + goto error; + } + + request = (struct te_request *)cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request)); + + /* close session cannot fail */ + te_close_session(&cmd.closesession, request); + break; + + case TE_IOCTL_LAUNCH_OPERATION: + operation = &cmd.launchop.operation; + ptr_user_answer = (void *)cmd.launchop.answer; + + cmd_desc = te_get_free_cmd_desc(dev); + params = te_get_free_params(dev, operation->list_count); + + if (!cmd_desc || (operation->list_count && !params)) { + SET_ANSWER(answer, + OTE_ERROR_OUT_OF_MEMORY, + OTE_ERROR_ORIGIN_COMMS); + pr_err("failed to get cmd_desc/params\n"); + goto error; + } + + request = (struct te_request *)cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request)); + + request->params = params; + request->params_size = operation->list_count; + + if (copy_params_from_user(request, operation)) { + err = -EFAULT; + pr_info("failed to copy params from user\n"); + goto error; + } + + te_launch_operation(&cmd.launchop, request, context); + + SET_ANSWER(answer, request->result, request->result_origin); + 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 te_answer))) { + pr_err("Failed to copy answer\n"); + err = -EFAULT; + } + } + if (request->params && !err) { + if (copy_params_to_user(request, operation)) { + pr_err("Failed to copy return params\n"); + err = -EFAULT; + } + } + +error: + if (cmd_desc) + te_put_used_cmd_desc(dev, cmd_desc); + if (params) + te_put_free_params(dev, params, operation->list_count); + return err; +} + +static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num, + unsigned long ioctl_param) +{ + int err; + + switch (ioctl_num) { + case TE_IOCTL_OPEN_CLIENT_SESSION: + case TE_IOCTL_CLOSE_CLIENT_SESSION: + case TE_IOCTL_LAUNCH_OPERATION: + err = te_handle_trustedapp_ioctl(file, ioctl_num, ioctl_param); + break; + + case TE_IOCTL_FILE_NEW_REQ: + case TE_IOCTL_FILE_FILL_BUF: + case TE_IOCTL_FILE_REQ_COMPLETE: + err = te_handle_fs_ioctl(file, ioctl_num, ioctl_param); + break; + + default: + pr_err("%s: Invalid IOCTL (0x%x) id 0x%x max 0x%x\n", __func__, + ioctl_num, _IOC_NR(ioctl_num), TE_IOCTL_MAX_NR); + err = -EINVAL; + } + + return err; +} + +/* + * tlk_driver function definitions. + */ +static const struct file_operations tlk_device_fops = { + .owner = THIS_MODULE, + .open = tlk_device_open, + .release = tlk_device_release, + .unlocked_ioctl = tlk_device_ioctl, +}; + +struct miscdevice tlk_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "tlk_device", + .fops = &tlk_device_fops, +}; + +static int __init tlk_init(void) +{ + int ret; + + INIT_LIST_HEAD(&(tlk_dev.used_cmd_list)); + INIT_LIST_HEAD(&(tlk_dev.free_cmd_list)); + + ret = te_create_free_cmd_list(&tlk_dev); + if (ret != 0) + return ret; + + return misc_register(&tlk_misc_device); +} + +module_init(tlk_init); diff --git a/security/nv_tee_driver/tee_fs.c b/security/tlk_driver/ote_fs.c index a5dbdfdf6102..716d004f68bb 100644 --- a/security/nv_tee_driver/tee_fs.c +++ b/security/tlk_driver/ote_fs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, NVIDIA Corporation. + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. * * 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 @@ -23,69 +23,62 @@ #include <linux/workqueue.h> #include <linux/freezer.h> #include <linux/bitops.h> +#include <linux/uaccess.h> -#include <asm/uaccess.h> +#include "ote_protocol.h" -#include "tee_protocol.h" +#define TE_SHMEM_FNAME_SZ SZ_64 +#define TE_SHMEM_DATA_SZ SZ_128K +#define TE_FS_READY_BIT 1 -#define TEE_SHMEM_FNAME_SZ SZ_64 -#define TEE_SHMEM_DATA_SZ SZ_128K - -#define TEE_FS_READY_BIT 1 +struct te_file_req_shmem { + char file_name[TE_SHMEM_FNAME_SZ]; + char file_data[TE_SHMEM_DATA_SZ]; +}; -struct tee_shmem { - char file_name[TEE_SHMEM_FNAME_SZ]; - char file_data[TEE_SHMEM_DATA_SZ]; +struct te_file_req_node { + struct list_head node; + struct te_file_req *req; }; -struct list_head req_list; -DECLARE_COMPLETION(req_ready); -DECLARE_COMPLETION(req_complete); +static struct list_head req_list; +static DECLARE_COMPLETION(req_ready); +static DECLARE_COMPLETION(req_complete); static unsigned long secure_error; static unsigned long fs_ready; static void indicate_complete(unsigned long ret) { - asm volatile ( - "mov r1, %0 \n" - "movw r0, #0x1FFF \n" - "movt r0, #0xFFFF \n" -#ifdef REQUIRES_SEC - ".arch_extension sec \n" -#endif - "smc #0 \n" - : : "r" (ret) - : "r0", "r1" - ); + tlk_generic_smc(0xFFFF1FFF, ret, 0); } -int tee_handle_fs_ioctl(struct file *file, unsigned int ioctl_num, +int te_handle_fs_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { - TEEC_FileReq new_req, *ptr_user_req = NULL; - struct tee_file_req_node *req_node; + struct te_file_req new_req, *ptr_user_req = NULL; + struct te_file_req_node *req_node; switch (ioctl_num) { - case TEE_IOCTL_FILE_NEW_REQ: /* new request */ + case TE_IOCTL_FILE_NEW_REQ: /* new request */ - ptr_user_req = (TEEC_FileReq *)ioctl_param; + ptr_user_req = (struct te_file_req *)ioctl_param; set_freezable(); - set_bit(TEE_FS_READY_BIT, &fs_ready); + set_bit(TE_FS_READY_BIT, &fs_ready); /* wait for a new request */ while (wait_for_completion_interruptible(&req_ready)) try_to_freeze(); /* dequeue new request from the secure world */ - req_node = list_first_entry(&req_list, struct tee_file_req_node, + req_node = list_first_entry(&req_list, struct te_file_req_node, node); /* populate request for the non-secure client */ if (req_node) { if (copy_to_user(ptr_user_req, req_node->req, - sizeof(TEEC_FileReq))) { + sizeof(struct te_file_req))) { pr_err("copy_to_user failed for new request\n"); return -EFAULT; } @@ -99,15 +92,15 @@ int tee_handle_fs_ioctl(struct file *file, unsigned int ioctl_num, break; - case TEE_IOCTL_FILE_FILL_BUF: /* pass data to be written to the file */ + case TE_IOCTL_FILE_FILL_BUF: /* pass data to be written to the file */ if (copy_from_user(&new_req, (void __user *)ioctl_param, - sizeof(TEEC_FileReq))) { + sizeof(struct te_file_req))) { pr_err("copy_from_user failed for request\n"); return -EFAULT; } - if (new_req.type != TEEC_FILE_REQ_WRITE) + if (new_req.type != OTE_FILE_REQ_WRITE) return -EINVAL; if (!new_req.kern_data_buf || !new_req.user_data_buf) @@ -120,15 +113,15 @@ int tee_handle_fs_ioctl(struct file *file, unsigned int ioctl_num, } break; - case TEE_IOCTL_FILE_REQ_COMPLETE: /* request complete */ + case TE_IOCTL_FILE_REQ_COMPLETE: /* request complete */ if (copy_from_user(&new_req, (void __user *)ioctl_param, - sizeof(TEEC_FileReq))) { + sizeof(struct te_file_req))) { pr_err("copy_from_user failed for request\n"); return -EFAULT; } - if (new_req.type == TEEC_FILE_REQ_READ && !new_req.error) { + if (new_req.type == OTE_FILE_REQ_READ && !new_req.error) { if (copy_from_user(new_req.kern_data_buf, (void __user *)new_req.user_data_buf, new_req.data_len)) { @@ -138,7 +131,8 @@ int tee_handle_fs_ioctl(struct file *file, unsigned int ioctl_num, } /* get error code */ - secure_error = (new_req.error) ? TEEC_ERROR_NO_DATA : new_req.result; + secure_error = (new_req.error) ? OTE_ERROR_NO_DATA + : new_req.result; /* signal the producer */ complete(&req_complete); @@ -148,25 +142,25 @@ int tee_handle_fs_ioctl(struct file *file, unsigned int ioctl_num, return 0; } -static void _tee_fs_file_operation(const char *name, void *buf, int len, - TEEC_FileReqType type) +static void _te_fs_file_operation(const char *name, void *buf, int len, + enum te_file_req_type type) { - TEEC_FileReq *new_req; - struct tee_file_req_node *req_node; + struct te_file_req *new_req; + struct te_file_req_node *req_node; - if (!test_and_clear_bit(TEE_FS_READY_BIT, &fs_ready)) { + if (!test_and_clear_bit(TE_FS_READY_BIT, &fs_ready)) { pr_err("%s: daemon not loaded yet\n", __func__); - secure_error = TEEC_ERROR_NO_DATA; + secure_error = OTE_ERROR_NO_DATA; goto fail; } BUG_ON(!name); - if (type == TEEC_FILE_REQ_READ || type == TEEC_FILE_REQ_WRITE) + if (type == OTE_FILE_REQ_READ || type == OTE_FILE_REQ_WRITE) BUG_ON(!buf); - /* allocate TEEC_FileReq structure */ - new_req = kzalloc(sizeof(TEEC_FileReq), GFP_KERNEL); + /* allocate te_file_req structure */ + new_req = kzalloc(sizeof(struct te_file_req), GFP_KERNEL); BUG_ON(!new_req); /* prepare a new request */ @@ -177,7 +171,7 @@ static void _tee_fs_file_operation(const char *name, void *buf, int len, new_req->kern_data_buf = buf; new_req->error = 0; - req_node = kzalloc(sizeof(struct tee_file_req_node), GFP_KERNEL); + req_node = kzalloc(sizeof(struct te_file_req_node), GFP_KERNEL); BUG_ON(!req_node); req_node->req = new_req; @@ -200,29 +194,30 @@ fail: indicate_complete(secure_error); } -void nv_tee_fread(const char *name, void *buf, int len) +void tlk_fread(const char *name, void *buf, int len) { if (!buf) - _tee_fs_file_operation(name, buf, len, TEEC_FILE_REQ_SIZE); + _te_fs_file_operation(name, buf, len, OTE_FILE_REQ_SIZE); else - _tee_fs_file_operation(name, buf, len, TEEC_FILE_REQ_READ); + _te_fs_file_operation(name, buf, len, OTE_FILE_REQ_READ); } -void nv_tee_fwrite(const char *name, void *buf, int len) +void tlk_fwrite(const char *name, void *buf, int len) { - _tee_fs_file_operation(name, buf, len, TEEC_FILE_REQ_WRITE); + _te_fs_file_operation(name, buf, len, OTE_FILE_REQ_WRITE); } -void nv_tee_fdelete(const char *name) +void tlk_fdelete(const char *name) { - _tee_fs_file_operation(name, NULL, 0, TEEC_FILE_REQ_DELETE); + _te_fs_file_operation(name, NULL, 0, OTE_FILE_REQ_DELETE); } -static int __init nv_tee_fs_register_handlers(void) +static int __init tlk_fs_register_handlers(void) { - struct tee_shmem *shmem_ptr; + struct te_file_req_shmem *shmem_ptr; + uint32_t smc_args[MAX_EXT_SMC_ARGS]; - shmem_ptr = kzalloc(sizeof(struct tee_shmem), GFP_KERNEL); + shmem_ptr = kzalloc(sizeof(struct te_file_req_shmem), GFP_KERNEL); if (!shmem_ptr) { pr_err("%s: no memory available for fs operations\n", __func__); return -ENOMEM; @@ -232,24 +227,16 @@ static int __init nv_tee_fs_register_handlers(void) init_completion(&req_ready); init_completion(&req_complete); - asm volatile ( - "movw r0, #0x1FF2 \n" - "movt r0, #0xFFFF \n" - "mov r1, %0 \n" - "mov r2, %1 \n" - "mov r3, %2 \n" - "mov r4, %3 \n" - "mov r5, %4 \n" -#ifdef REQUIRES_SEC - ".arch_extension sec \n" -#endif - "smc #0 \n" - : : "r" (nv_tee_fread), "r" (nv_tee_fwrite), "r" (nv_tee_fdelete), - "r" (shmem_ptr->file_name), "r" (shmem_ptr->file_data) - : "r0", "r1", "r2", "r3", "r4", "r13", "r14" - ); + smc_args[0] = 0xFFFF1FF2; + smc_args[1] = (uint32_t)tlk_fread; + smc_args[2] = (uint32_t)tlk_fwrite; + smc_args[3] = (uint32_t)tlk_fdelete; + smc_args[4] = (uint32_t)shmem_ptr->file_name; + smc_args[5] = (uint32_t)shmem_ptr->file_data; + + tlk_extended_smc(smc_args); return 0; } -arch_initcall(nv_tee_fs_register_handlers); +arch_initcall(tlk_fs_register_handlers); diff --git a/security/nv_tee_driver/tee_irq.S b/security/tlk_driver/ote_irq.S index 4e913cb24c03..7bfda8861108 100644 --- a/security/nv_tee_driver/tee_irq.S +++ b/security/tlk_driver/ote_irq.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, NVIDIA Corporation. + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. * * 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 @@ -14,8 +14,8 @@ #include <linux/linkage.h> #include <linux/init.h> -ENTRY(nv_tee_irq_handler) +ENTRY(tlk_irq_handler) movw r0, #0x1FF1 movt r0, #0xFFFF smc #0 -ENDPROC(nv_tee_irq_handler) +ENDPROC(tlk_irq_handler) diff --git a/security/tlk_driver/ote_protocol.h b/security/tlk_driver/ote_protocol.h new file mode 100644 index 000000000000..79224e1c3669 --- /dev/null +++ b/security/tlk_driver/ote_protocol.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. + * + * 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 __OTE_PROTOCOL_H__ +#define __OTE_PROTOCOL_H__ + +#include "ote_types.h" + +#define TE_IOCTL_MAGIC_NUMBER ('t') +#define TE_IOCTL_OPEN_CLIENT_SESSION \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x10, union te_cmd) +#define TE_IOCTL_CLOSE_CLIENT_SESSION \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x11, union te_cmd) +#define TE_IOCTL_LAUNCH_OPERATION \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x14, union te_cmd) +#define TE_IOCTL_FILE_NEW_REQ \ + _IOR(TE_IOCTL_MAGIC_NUMBER, 0x16, struct te_file_req) +#define TE_IOCTL_FILE_FILL_BUF \ + _IOR(TE_IOCTL_MAGIC_NUMBER, 0x17, struct te_file_req) +#define TE_IOCTL_FILE_REQ_COMPLETE \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x18, struct te_file_req) + +#define TE_IOCTL_MIN_NR _IOC_NR(TE_IOCTL_OPEN_CLIENT_SESSION) +#define TE_IOCTL_MAX_NR _IOC_NR(TE_IOCTL_FILE_REQ_COMPLETE) + +#define MAX_EXT_SMC_ARGS 12 + +extern uint32_t tlk_generic_smc(uint32_t arg0, uint32_t arg1, uint32_t arg2); +extern uint32_t tlk_extended_smc(uint32_t *args); +extern void tlk_irq_handler(void); + +struct tlk_device { + unsigned long req_addr; + struct te_oper_param *param_addr; + unsigned long *param_bitmap; + + struct list_head used_cmd_list; + struct list_head free_cmd_list; +}; + +struct te_cmd_req_desc { + unsigned long req_addr; + struct list_head list; +}; + +struct te_shmem_desc { + struct list_head list; + void *buffer; + size_t size; + unsigned int mem_type; + struct page **pages; + unsigned int nr_pages; +}; + +struct tlk_context { + struct tlk_device *dev; + struct list_head shmem_alloc_list; +}; + +enum { + TE_SMC_OPEN_SESSION = 0xFFFF1004, + TE_SMC_CLOSE_SESSION = 0xFFFF1005, + TE_SMC_LAUNCH_OPERATION = 0xFFFF1000, +}; + +enum { + TE_PARAM_TYPE_NONE = 0, + TE_PARAM_TYPE_INT_RO = 1, + TE_PARAM_TYPE_INT_RW = 2, + TE_PARAM_TYPE_MEM_RO = 3, + TE_PARAM_TYPE_MEM_RW = 4, +}; + +struct te_oper_param { + uint32_t index; + uint32_t type; + union { + struct { + uint32_t val; + } Int; + struct { + void *base; + uint32_t len; + } Mem; + } u; + void *next_ptr_user; +}; + +struct te_operation { + uint32_t command; + struct te_oper_param *list_head; + /* Maintain a pointer to tail of list to easily add new param node */ + struct te_oper_param *list_tail; + uint32_t list_count; + uint32_t status; + uint32_t iterface_side; +}; + +struct te_service_id { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_and_node[8]; +}; + +/* + * OpenSession + */ +struct te_opensession { + struct te_service_id dest_uuid; + struct te_operation operation; + uint32_t answer; +}; + +/* + * CloseSession + */ +struct te_closesession { + uint32_t session_id; + uint32_t answer; +}; + +/* + * LaunchOperation + */ +struct te_launchop { + uint32_t session_id; + struct te_operation operation; + uint32_t answer; +}; + +union te_cmd { + struct te_opensession opensession; + struct te_closesession closesession; + struct te_launchop launchop; +}; + +struct te_request { + uint32_t type; + uint32_t session_id; + uint32_t command_id; + struct te_oper_param *params; + uint32_t params_size; + uint32_t dest_uuid[4]; + uint32_t result; + uint32_t result_origin; +}; + +struct te_answer { + uint32_t result; + uint32_t session_id; + uint32_t return_origin; +}; + +void te_open_session(struct te_opensession *cmd, + struct te_request *request, + struct tlk_context *context); + +void te_close_session(struct te_closesession *cmd, + struct te_request *request); + +void te_launch_operation(struct te_launchop *cmd, + struct te_request *request, + struct tlk_context *context); + +#define TE_MAX_FILE_NAME_LEN 64 + +enum te_file_req_type { + OTE_FILE_REQ_READ = 0, + OTE_FILE_REQ_WRITE = 1, + OTE_FILE_REQ_DELETE = 2, + OTE_FILE_REQ_SIZE = 3, +}; + +struct te_file_req { + char name[TE_MAX_FILE_NAME_LEN]; + enum te_file_req_type type; + void *user_data_buf; + void *kern_data_buf; + unsigned long data_len; + unsigned long result; + int error; +}; + +int te_handle_fs_ioctl(struct file *file, unsigned int ioctl_num, + unsigned long ioctl_param); +#endif diff --git a/security/tlk_driver/ote_types.h b/security/tlk_driver/ote_types.h new file mode 100644 index 000000000000..ef82d4ffec9d --- /dev/null +++ b/security/tlk_driver/ote_types.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. + * + * 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 __OTE_TYPES_H__ +#define __OTE_TYPES_H__ + +/* + * Return Codes + */ +enum { + /* Success */ + OTE_SUCCESS = 0x00000000, + OTE_ERROR_NO_ERROR = OTE_SUCCESS, + /* Non-specific cause */ + OTE_ERROR_GENERIC = 0xFFFF0000, + /* Access priviledge not sufficient */ + OTE_ERROR_ACCESS_DENIED = 0xFFFF0001, + /* The operation was cancelled */ + OTE_ERROR_CANCEL = 0xFFFF0002, + /* Concurrent accesses conflict */ + OTE_ERROR_ACCESS_CONFLICT = 0xFFFF0003, + /* Too much data for req was passed */ + OTE_ERROR_EXCESS_DATA = 0xFFFF0004, + /* Input data was of invalid format */ + OTE_ERROR_BAD_FORMAT = 0xFFFF0005, + /* Input parameters were invalid */ + OTE_ERROR_BAD_PARAMETERS = 0xFFFF0006, + /* Oper invalid in current state */ + OTE_ERROR_BAD_STATE = 0xFFFF0007, + /* The req data item not found */ + OTE_ERROR_ITEM_NOT_FOUND = 0xFFFF0008, + /* The req oper not implemented */ + OTE_ERROR_NOT_IMPLEMENTED = 0xFFFF0009, + /* The req oper not supported */ + OTE_ERROR_NOT_SUPPORTED = 0xFFFF000A, + /* Expected data was missing */ + OTE_ERROR_NO_DATA = 0xFFFF000B, + /* System ran out of resources */ + OTE_ERROR_OUT_OF_MEMORY = 0xFFFF000C, + /* The system is busy */ + OTE_ERROR_BUSY = 0xFFFF000D, + /* Communication failed */ + OTE_ERROR_COMMUNICATION = 0xFFFF000E, + /* A security fault was detected */ + OTE_ERROR_SECURITY = 0xFFFF000F, + /* The supplied buffer is too short */ + OTE_ERROR_SHORT_BUFFER = 0xFFFF0010, +}; + +/* + * Return Code origins + */ +enum { + /* Originated from OTE Client API */ + OTE_ERROR_ORIGIN_API = 1, + /* Originated from Underlying Communication Stack */ + OTE_ERROR_ORIGIN_COMMS = 2, + /* Originated from Common OTE Code */ + OTE_ERROR_ORIGIN_KERNEL = 3, + /* Originated from Trusted APP Code */ + OTE_ERROR_ORIGIN_TRUSTED_APP = 4, +}; + +#endif |