diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/tlk_driver/Makefile | 14 | ||||
-rw-r--r-- | security/tlk_driver/ote_asm.S | 74 | ||||
-rw-r--r-- | security/tlk_driver/ote_comms.c | 52 | ||||
-rw-r--r-- | security/tlk_driver/ote_device.c | 13 | ||||
-rw-r--r-- | security/tlk_driver/ote_fs.c | 207 | ||||
-rw-r--r-- | security/tlk_driver/ote_irq.S | 23 | ||||
-rw-r--r-- | security/tlk_driver/ote_log.c | 4 | ||||
-rw-r--r-- | security/tlk_driver/ote_protocol.h | 34 |
8 files changed, 97 insertions, 324 deletions
diff --git a/security/tlk_driver/Makefile b/security/tlk_driver/Makefile index 86a293d2f009..9ab4168f7e11 100644 --- a/security/tlk_driver/Makefile +++ b/security/tlk_driver/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2013 NVIDIA Corporation. All rights reserved. +# Copyright (c) 2013-2014, 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 @@ -16,15 +16,15 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -plus_sec := $(call as-instr,.arch_extension sec,+sec) -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) - tlk_driver-objs += ote_device.o tlk_driver-objs += ote_comms.o tlk_driver-objs += ote_fs.o -tlk_driver-objs += ote_irq.o +tlk_driver-objs += ote_asm.o tlk_driver-objs += ote_log.o +ifeq ($(CONFIG_ARM),y) +plus_sec := $(call as-instr,.arch_extension sec,+sec) +AFLAGS_ote_asm.o :=-Wa,-march=armv7-a$(plus_sec) +endif + obj-$(CONFIG_TRUSTED_LITTLE_KERNEL) += tlk_driver.o diff --git a/security/tlk_driver/ote_asm.S b/security/tlk_driver/ote_asm.S new file mode 100644 index 000000000000..2c5563ba7ed8 --- /dev/null +++ b/security/tlk_driver/ote_asm.S @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014, 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. + * + * 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> + +#ifdef CONFIG_ARM64 + +ENTRY(tlk_irq_handler) + mov x0, #0x5 + movk x0, #0x3200, lsl #16 // TE_SMC_NS_IRQ_DONE + smc #0 + ret +ENDPROC(tlk_irq_handler) + +/* uint32_t tlk_generic_smc(uint32_t arg0, uint32_t arg1, uint32_t arg2) */ +ENTRY(_tlk_generic_smc) + smc #0 + ret +ENDPROC(_tlk_generic_smc) + + /* allows MAX_EXT_SMC_ARGS (r0-r11) to be passed in registers */ + +/* uint32_t tlk_extended_smc(uint32_t *regs) */ +ENTRY(_tlk_extended_smc) + /* + * Allows MAX_EXT_SMC_ARGS (r0-r11) to be passed in registers + * (for aarch64, these are scratch, so no need to save them) + */ + mov x12, x0 + ldp x0, x1, [x12], #16 + ldp x2, x3, [x12], #16 + ldp x4, x5, [x12], #16 + ldp x6, x7, [x12], #16 + ldp x8, x9, [x12], #16 + ldp x10, x11, [x12], #16 + smc #0 + ret +ENDPROC(_tlk_extended_smc) + +#else + +ENTRY(tlk_irq_handler) + movw r0, #0x5 + movt r0, #0x3200 @ TE_SMC_NS_IRQ_DONE + mov r1, #0 + mov r2, #0 + smc #0 +ENDPROC(tlk_irq_handler) + +ENTRY(_tlk_generic_smc) + smc #0 + mov pc, lr +ENDPROC(_tlk_generic_smc) + +ENTRY(_tlk_extended_smc) + stmfd sp!, {r4-r12} @ save reg state + mov r12, r0 @ reg ptr to r12 + ldmia r12, {r0-r11} @ load arg regs + smc #0 + ldmfd sp!, {r4-r12} @ restore saved regs +ENDPROC(_tlk_extended_smc) + +#endif diff --git a/security/tlk_driver/ote_comms.c b/security/tlk_driver/ote_comms.c index 46d7fc679b78..1f380b772499 100644 --- a/security/tlk_driver/ote_comms.c +++ b/security/tlk_driver/ote_comms.c @@ -237,29 +237,7 @@ static inline void switch_cpumask_to_cpu0(void) {}; static inline void restore_cpumask(void) {}; #endif -static uint32_t _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") -#ifdef REQUIRES_SEC - ".arch_extension sec \n" -#endif - "smc #0 @ switch to secure world\n" - : "=r" (r0) - : "r" (r0), "r" (r1), "r" (r2) - ); - - return r0; -} - -uint32_t tlk_generic_smc(uint32_t arg0, uint32_t arg1, uint32_t arg2) +uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2) { uint32_t retval; @@ -274,29 +252,7 @@ uint32_t tlk_generic_smc(uint32_t arg0, uint32_t arg1, uint32_t arg2) return retval; } -static uint32_t _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" - : "=r" (r0) - : "r" (r0) - ); - - return r0; -} - -uint32_t tlk_extended_smc(uint32_t *regs) +uint32_t tlk_extended_smc(uintptr_t *regs) { uint32_t retval; @@ -373,7 +329,7 @@ int te_set_vpr_params(void *vpr_base, size_t vpr_size) /* Share the same lock used when request is send from user side */ mutex_lock(&smc_lock); - retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR, (uint32_t)vpr_base, + retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR, (uintptr_t)vpr_base, vpr_size); mutex_unlock(&smc_lock); @@ -535,7 +491,7 @@ void te_launch_operation_compat(struct te_launchop_compat *cmd, static int __init tlk_register_irq_handler(void) { tlk_generic_smc(TE_SMC_REGISTER_IRQ_HANDLER, - (unsigned int)tlk_irq_handler, 0); + (uintptr_t)tlk_irq_handler, 0); return 0; } diff --git a/security/tlk_driver/ote_device.c b/security/tlk_driver/ote_device.c index 170f46c06e14..bfc59d3cb94c 100644 --- a/security/tlk_driver/ote_device.c +++ b/security/tlk_driver/ote_device.c @@ -68,7 +68,7 @@ static int te_create_free_cmd_list(struct tlk_device *dev) (dev->req_param_buf + PAGE_SIZE); tlk_generic_smc(TE_SMC_REGISTER_REQ_BUF, - (uint32_t)dev->req_addr, (2 * PAGE_SIZE)); + (uintptr_t)dev->req_addr, (2 * PAGE_SIZE)); } else { dev->req_addr = dma_alloc_coherent(NULL, PAGE_SIZE, &dev->req_addr_phys, GFP_KERNEL); @@ -712,20 +712,15 @@ static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num, mutex_unlock(&smc_lock); 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; - case TE_IOCTL_SS_NEW_REQ: case TE_IOCTL_SS_REQ_COMPLETE: err = te_handle_ss_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); + pr_err("%s: Invalid IOCTL (0x%x) id 0x%x max 0x%lx\n", + __func__, ioctl_num, _IOC_NR(ioctl_num), + (unsigned long)TE_IOCTL_MAX_NR); err = -EINVAL; break; } diff --git a/security/tlk_driver/ote_fs.c b/security/tlk_driver/ote_fs.c index d398bebed9d2..e3d427ae9a2f 100644 --- a/security/tlk_driver/ote_fs.c +++ b/security/tlk_driver/ote_fs.c @@ -27,188 +27,17 @@ #include "ote_protocol.h" -#define TE_SHMEM_FNAME_SZ SZ_64 -#define TE_SHMEM_DATA_SZ SZ_128K - -struct te_file_req_shmem { - char file_name[TE_SHMEM_FNAME_SZ]; - char file_data[TE_SHMEM_DATA_SZ]; -}; - -struct te_file_req_node { - struct list_head node; - struct te_file_req *req; -}; - -static struct list_head req_list; static DECLARE_COMPLETION(req_ready); static DECLARE_COMPLETION(req_complete); -static unsigned long secure_error; static struct te_ss_op *ss_op_shmem; static uint32_t ss_op_size; -static void indicate_complete(unsigned long ret) -{ - tlk_generic_smc(TE_SMC_FS_OP_DONE, ret, 0); -} - static void indicate_ss_op_complete(void) { tlk_generic_smc(TE_SMC_SS_REQ_COMPLETE, 0, 0); } -int te_handle_fs_ioctl(struct file *file, unsigned int ioctl_num, - unsigned long ioctl_param) -{ - struct te_file_req new_req, *ptr_user_req = NULL; - struct te_file_req_node *req_node; - - switch (ioctl_num) { - case TE_IOCTL_FILE_NEW_REQ: /* new request */ - - ptr_user_req = (struct te_file_req *)ioctl_param; - - /* wait for a new request */ - if (wait_for_completion_interruptible(&req_ready)) { - return -ENODATA; - } - - /* dequeue new request from the secure world */ - 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(struct te_file_req))) { - pr_err("copy_to_user failed for new request\n"); - return -EFAULT; - } - - list_del(&req_node->node); - kfree(req_node); - } else { - pr_err("no request available\n"); - return -ENOMEM; - } - - break; - - 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(struct te_file_req))) { - pr_err("copy_from_user failed for request\n"); - return -EFAULT; - } - - if (new_req.type != OTE_FILE_REQ_WRITE) - return -EINVAL; - - if (!new_req.kern_data_buf || !new_req.user_data_buf) - return -EINVAL; - - if (copy_to_user(new_req.user_data_buf, new_req.kern_data_buf, - new_req.data_len)) { - pr_err("copy_to_user failed for fill buffer\n"); - return -EFAULT; - } - break; - - case TE_IOCTL_FILE_REQ_COMPLETE: /* request complete */ - - if (copy_from_user(&new_req, (void __user *)ioctl_param, - sizeof(struct te_file_req))) { - pr_err("copy_from_user failed for request\n"); - return -EFAULT; - } - - 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)) { - pr_err("copy_from_user failed for request\n"); - return -EFAULT; - } - } - - /* get error code */ - secure_error = (new_req.error) ? OTE_ERROR_NO_DATA - : new_req.result; - - /* signal the producer */ - complete(&req_complete); - break; - - default: - pr_err("copy_from_user failed for request\n"); - return -EINVAL; - } - - return 0; -} - -static void _te_fs_file_operation(const char *name, void *buf, int len, - enum te_file_req_type type) -{ - struct te_file_req *new_req; - struct te_file_req_node *req_node; - - BUG_ON(!name); - - if (type == OTE_FILE_REQ_READ || type == OTE_FILE_REQ_WRITE) - BUG_ON(!buf); - - /* allocate te_file_req structure */ - new_req = kzalloc(sizeof(struct te_file_req), GFP_KERNEL); - BUG_ON(!new_req); - - /* prepare a new request */ - strncpy(new_req->name, name, strlen(name)); - new_req->type = type; - new_req->data_len = len; - new_req->result = 0; - new_req->kern_data_buf = buf; - new_req->error = 0; - - req_node = kzalloc(sizeof(struct te_file_req_node), GFP_KERNEL); - BUG_ON(!req_node); - - req_node->req = new_req; - INIT_LIST_HEAD(&req_node->node); - - /* add it to the pending queue and signal the consumer */ - list_add_tail(&req_list, &req_node->node); - complete(&req_ready); - - /* wait for the consumer's signal */ - wait_for_completion(&req_complete); - - kfree(new_req); - - /* signal completion to the secure world */ - indicate_complete(secure_error); -} - -void tlk_fread(const char *name, void *buf, int len) -{ - if (!buf) - _te_fs_file_operation(name, buf, len, OTE_FILE_REQ_SIZE); - else - _te_fs_file_operation(name, buf, len, OTE_FILE_REQ_READ); -} - -void tlk_fwrite(const char *name, void *buf, int len) -{ - _te_fs_file_operation(name, buf, len, OTE_FILE_REQ_WRITE); -} - -void tlk_fdelete(const char *name) -{ - _te_fs_file_operation(name, NULL, 0, OTE_FILE_REQ_DELETE); -} - int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { @@ -256,44 +85,10 @@ void tlk_ss_op(uint32_t size) indicate_ss_op_complete(); } -static int tlk_fs_register_handlers(void) -{ - struct te_file_req_shmem *shmem_ptr; - uint32_t smc_args[MAX_EXT_SMC_ARGS]; - dma_addr_t shmem_dma; - - shmem_ptr = dma_alloc_coherent(NULL, sizeof(struct te_file_req_shmem), - &shmem_dma, GFP_KERNEL); - if (!shmem_ptr) { - pr_err("%s: no memory available for fs operations\n", __func__); - return -ENOMEM; - } - - memset(shmem_ptr, 0, sizeof(struct te_file_req_shmem)); - - INIT_LIST_HEAD(&req_list); - init_completion(&req_ready); - init_completion(&req_complete); - - smc_args[0] = TE_SMC_REGISTER_FS_HANDLERS; - 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; -} - static int __init tlk_ss_init(void) { dma_addr_t ss_op_shmem_dma; - /* register legacy support */ - tlk_fs_register_handlers(); - /* allocate shared memory buffer */ ss_op_shmem = dma_alloc_coherent(NULL, sizeof(struct te_ss_op), &ss_op_shmem_dma, GFP_KERNEL); @@ -303,7 +98,7 @@ static int __init tlk_ss_init(void) } tlk_generic_smc(TE_SMC_SS_REGISTER_HANDLER, - (uint32_t)tlk_ss_op, (uint32_t)ss_op_shmem); + (uintptr_t)tlk_ss_op, (uintptr_t)ss_op_shmem); return 0; } diff --git a/security/tlk_driver/ote_irq.S b/security/tlk_driver/ote_irq.S deleted file mode 100644 index 3a4ca6875801..000000000000 --- a/security/tlk_driver/ote_irq.S +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - * - * 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(tlk_irq_handler) - movw r0, #0x5 - movt r0, #0x3200 @ TE_SMC_NS_IRQ_DONE - mov r1, #0 - mov r2, #0 - smc #0 -ENDPROC(tlk_irq_handler) diff --git a/security/tlk_driver/ote_log.c b/security/tlk_driver/ote_log.c index 0cd4412d1470..0a1fbd79b617 100644 --- a/security/tlk_driver/ote_log.c +++ b/security/tlk_driver/ote_log.c @@ -172,14 +172,14 @@ void ote_print_logs(void) {} */ static int __init ote_logger_init(void) { - uint32_t smc_args[MAX_EXT_SMC_ARGS]; + uintptr_t smc_args[MAX_EXT_SMC_ARGS]; #if defined(CONFIG_OTE_ENABLE_LOGGER) if (circ_buf_init(&cb) != 0) return -1; smc_args[0] = TE_SMC_INIT_LOGGER; - smc_args[1] = (uint32_t)cb; + smc_args[1] = (uintptr_t)cb; tlk_generic_smc(smc_args[0], smc_args[1], 0); ote_logging_enabled = 1; diff --git a/security/tlk_driver/ote_protocol.h b/security/tlk_driver/ote_protocol.h index 66228e4a9eaa..7e10feed5233 100644 --- a/security/tlk_driver/ote_protocol.h +++ b/security/tlk_driver/ote_protocol.h @@ -37,12 +37,6 @@ #define TE_IOCTL_LAUNCH_OPERATION_COMPAT \ _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x14, union te_cmd_compat) -#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_SS_NEW_REQ \ _IOR(TE_IOCTL_MAGIC_NUMBER, 0x20, struct te_ss_op) #define TE_IOCTL_SS_REQ_COMPLETE \ @@ -63,9 +57,12 @@ #define MAX_EXT_SMC_ARGS 12 extern struct mutex smc_lock; +extern struct tlk_device tlk_dev; -uint32_t tlk_generic_smc(uint32_t arg0, uint32_t arg1, uint32_t arg2); -uint32_t tlk_extended_smc(uint32_t *args); +uint32_t _tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2); +uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2); +uint32_t _tlk_extended_smc(uintptr_t *args); +uint32_t tlk_extended_smc(uintptr_t *args); void tlk_irq_handler(void); struct tlk_device { @@ -114,12 +111,10 @@ enum { TE_SMC_LAUNCH_OPERATION = 0x30000003, /* Trusted OS calls */ - TE_SMC_REGISTER_FS_HANDLERS = 0x32000001, TE_SMC_REGISTER_REQ_BUF = 0x32000002, TE_SMC_PROGRAM_VPR = 0x32000003, TE_SMC_REGISTER_IRQ_HANDLER = 0x32000004, TE_SMC_NS_IRQ_DONE = 0x32000005, - TE_SMC_FS_OP_DONE = 0x32000006, TE_SMC_INIT_LOGGER = 0x32000007, TE_SMC_SS_REGISTER_HANDLER = 0x32000008, TE_SMC_SS_REQ_COMPLETE = 0x32000009, @@ -309,25 +304,6 @@ void te_launch_operation_compat(struct te_launchop_compat *cmd, struct te_request_compat *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; -}; - #define SS_OP_MAX_DATA_SIZE 0x1000 struct te_ss_op { uint8_t data[SS_OP_MAX_DATA_SIZE]; |