diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/tlk_driver/ote_comms.c | 11 | ||||
-rw-r--r-- | security/tlk_driver/ote_device.c | 5 | ||||
-rw-r--r-- | security/tlk_driver/ote_fs.c | 87 | ||||
-rw-r--r-- | security/tlk_driver/ote_protocol.h | 23 |
4 files changed, 114 insertions, 12 deletions
diff --git a/security/tlk_driver/ote_comms.c b/security/tlk_driver/ote_comms.c index 2facb386c7a7..cf5f87e31807 100644 --- a/security/tlk_driver/ote_comms.c +++ b/security/tlk_driver/ote_comms.c @@ -259,8 +259,15 @@ uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2) switch_cpumask_to_cpu0(); retval = _tlk_generic_smc(arg0, arg1, arg2); - while (retval == 0xFFFFFFFD) - retval = _tlk_generic_smc((60 << 24), 0, 0); + while (retval == TE_ERROR_PREEMPT_BY_IRQ || + retval == TE_ERROR_PREEMPT_BY_FS) { + if (retval == TE_ERROR_PREEMPT_BY_IRQ) { + retval = _tlk_generic_smc((60 << 24), 0, 0); + } else { + tlk_ss_op(); + retval = _tlk_generic_smc(TE_SMC_SS_REQ_COMPLETE, 0, 0); + } + } restore_cpumask(); diff --git a/security/tlk_driver/ote_device.c b/security/tlk_driver/ote_device.c index d7dfd7a94d6f..32a2b65bf36e 100644 --- a/security/tlk_driver/ote_device.c +++ b/security/tlk_driver/ote_device.c @@ -712,6 +712,11 @@ static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num, mutex_unlock(&smc_lock); break; + case TE_IOCTL_SS_NEW_REQ_LEGACY: + case TE_IOCTL_SS_REQ_COMPLETE_LEGACY: + err = te_handle_ss_ioctl_legacy(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); diff --git a/security/tlk_driver/ote_fs.c b/security/tlk_driver/ote_fs.c index e3d427ae9a2f..f58bdd64aecb 100644 --- a/security/tlk_driver/ote_fs.c +++ b/security/tlk_driver/ote_fs.c @@ -30,6 +30,7 @@ static DECLARE_COMPLETION(req_ready); static DECLARE_COMPLETION(req_complete); +static struct te_ss_op_legacy *ss_op_shmem_legacy; static struct te_ss_op *ss_op_shmem; static uint32_t ss_op_size; @@ -38,26 +39,26 @@ static void indicate_ss_op_complete(void) tlk_generic_smc(TE_SMC_SS_REQ_COMPLETE, 0, 0); } -int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num, +int te_handle_ss_ioctl_legacy(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { switch (ioctl_num) { - case TE_IOCTL_SS_NEW_REQ: + case TE_IOCTL_SS_NEW_REQ_LEGACY: /* wait for a new request */ if (wait_for_completion_interruptible(&req_ready)) return -ENODATA; /* transfer pending request to daemon's buffer */ - if (copy_to_user((void __user *)ioctl_param, ss_op_shmem, + if (copy_to_user((void __user *)ioctl_param, ss_op_shmem_legacy, ss_op_size)) { pr_err("copy_to_user failed for new request\n"); return -EFAULT; } break; - case TE_IOCTL_SS_REQ_COMPLETE: /* request complete */ - if (copy_from_user(ss_op_shmem, (void __user *)ioctl_param, - ss_op_size)) { + case TE_IOCTL_SS_REQ_COMPLETE_LEGACY: /* request complete */ + if (copy_from_user(ss_op_shmem_legacy, + (void __user *)ioctl_param, ss_op_size)) { pr_err("copy_from_user failed for request\n"); return -EFAULT; } @@ -70,7 +71,7 @@ int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num, return 0; } -void tlk_ss_op(uint32_t size) +void tlk_ss_op_legacy(uint32_t size) { /* store size of request */ ss_op_size = size; @@ -85,9 +86,71 @@ void tlk_ss_op(uint32_t size) indicate_ss_op_complete(); } +static int __init tlk_ss_init_legacy(void) +{ + dma_addr_t ss_op_shmem_dma; + + /* allocate shared memory buffer */ + ss_op_shmem_legacy = dma_alloc_coherent(NULL, + sizeof(struct te_ss_op_legacy), &ss_op_shmem_dma, GFP_KERNEL); + if (!ss_op_shmem_legacy) { + pr_err("%s: no memory available for fs operations\n", __func__); + return -ENOMEM; + } + + tlk_generic_smc(TE_SMC_SS_REGISTER_HANDLER_LEGACY, + (uintptr_t)tlk_ss_op_legacy, (uintptr_t)ss_op_shmem_legacy); + + return 0; +} + +arch_initcall(tlk_ss_init_legacy); + +int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num, + unsigned long ioctl_param) +{ + switch (ioctl_num) { + case TE_IOCTL_SS_NEW_REQ: + /* wait for a new request */ + if (wait_for_completion_interruptible(&req_ready)) + return -ENODATA; + + /* transfer pending request to daemon's buffer */ + if (copy_to_user((void __user *)ioctl_param, ss_op_shmem->data, + ss_op_shmem->req_size)) { + pr_err("copy_to_user failed for new request\n"); + return -EFAULT; + } + break; + + case TE_IOCTL_SS_REQ_COMPLETE: /* request complete */ + if (copy_from_user(ss_op_shmem->data, + (void __user *)ioctl_param, ss_op_shmem->req_size)) { + pr_err("copy_from_user failed for request\n"); + return -EFAULT; + } + + /* signal the producer */ + complete(&req_complete); + break; + } + + return 0; +} + +void tlk_ss_op(void) +{ + /* signal consumer */ + complete(&req_ready); + + /* wait for the consumer's signal */ + wait_for_completion(&req_complete); +} + static int __init tlk_ss_init(void) { dma_addr_t ss_op_shmem_dma; + int32_t ret; /* allocate shared memory buffer */ ss_op_shmem = dma_alloc_coherent(NULL, sizeof(struct te_ss_op), @@ -97,8 +160,14 @@ static int __init tlk_ss_init(void) return -ENOMEM; } - tlk_generic_smc(TE_SMC_SS_REGISTER_HANDLER, - (uintptr_t)tlk_ss_op, (uintptr_t)ss_op_shmem); + ret = tlk_generic_smc(TE_SMC_SS_REGISTER_HANDLER, + (uintptr_t)ss_op_shmem, 0); + if (ret != 0) { + dma_free_coherent(NULL, sizeof(struct te_ss_op), + (void *)ss_op_shmem, ss_op_shmem_dma); + ss_op_shmem = NULL; + return -ENOTSUPP; + } return 0; } diff --git a/security/tlk_driver/ote_protocol.h b/security/tlk_driver/ote_protocol.h index c5aea3d234e3..608ee8981e7c 100644 --- a/security/tlk_driver/ote_protocol.h +++ b/security/tlk_driver/ote_protocol.h @@ -37,6 +37,12 @@ #define TE_IOCTL_LAUNCH_OPERATION_COMPAT \ _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x14, union te_cmd_compat) +#define TE_IOCTL_SS_NEW_REQ_LEGACY \ + _IOR(TE_IOCTL_MAGIC_NUMBER, 0x20, struct te_ss_op_legacy) +#define TE_IOCTL_SS_REQ_COMPLETE_LEGACY \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x21, struct te_ss_op_legacy) + +/* ioctls using new SS structs (eventually to replace current SS ioctls) */ #define TE_IOCTL_SS_NEW_REQ \ _IOR(TE_IOCTL_MAGIC_NUMBER, 0x20, struct te_ss_op) #define TE_IOCTL_SS_REQ_COMPLETE \ @@ -65,6 +71,12 @@ uint32_t _tlk_extended_smc(uintptr_t *args); uint32_t tlk_extended_smc(uintptr_t *args); void tlk_irq_handler(void); +/* errors returned by secure world in reponse to SMC calls */ +enum { + TE_ERROR_PREEMPT_BY_IRQ = 0xFFFFFFFD, + TE_ERROR_PREEMPT_BY_FS = 0xFFFFFFFE, +}; + struct tlk_device { struct te_request *req_addr; dma_addr_t req_addr_phys; @@ -115,8 +127,9 @@ enum { TE_SMC_REGISTER_IRQ_HANDLER = 0x32000004, TE_SMC_NS_IRQ_DONE = 0x32000005, TE_SMC_INIT_LOGGER = 0x32000007, - TE_SMC_SS_REGISTER_HANDLER = 0x32000008, + TE_SMC_SS_REGISTER_HANDLER_LEGACY = 0x32000008, TE_SMC_SS_REQ_COMPLETE = 0x32000009, + TE_SMC_SS_REGISTER_HANDLER = 0x32000010, /* SIP (SOC specific) calls. */ TE_SMC_PROGRAM_VPR = 0x82000003, @@ -308,13 +321,21 @@ void te_launch_operation_compat(struct te_launchop_compat *cmd, #define SS_OP_MAX_DATA_SIZE 0x1000 struct te_ss_op { + uint32_t req_size; uint8_t data[SS_OP_MAX_DATA_SIZE]; }; +struct te_ss_op_legacy { + uint8_t data[SS_OP_MAX_DATA_SIZE]; +}; + +int te_handle_ss_ioctl_legacy(struct file *file, unsigned int ioctl_num, + unsigned long ioctl_param); int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param); int te_handle_fs_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param); void ote_print_logs(void); +void tlk_ss_op(void); #endif |