diff options
author | Varun Wadekar <vwadekar@nvidia.com> | 2014-04-23 10:34:00 +0530 |
---|---|---|
committer | Riham Haidar <rhaidar@nvidia.com> | 2014-05-14 14:05:46 -0700 |
commit | dfc98274759500dffa41d90b08c5019630612812 (patch) | |
tree | 865a4a1ae3a45e8ef8092d95ba45f596e6c4f7aa /security | |
parent | c644396e53d0100431ea5e4e06528d967581f812 (diff) |
security: tlk_driver: modify secure storage glue
The secure world now sends a PREEMPT_BY_FS error code as a result
of OpenSession/LaunchOp call. This indicates a pending FS request
from the secure world which we need to handle and send the
FS_COMPLETION SMC on completion.
Until the secure firmware and the linux driver get in sync, we keep
legacy SS handling alive to avoid incomaptibility issues. Once the
secure firmware switches to the new handling, we would remove the
legacy support from the linux driver as well.
Bug 1500621
Change-Id: I9e84cd5a87d820107b1c2279c9d89dcd5c31b44b
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Reviewed-on: http://git-master/r/375994
(cherry picked from commit 433d8d1687725ab7db23eef27e5a073e8d88e862)
Reviewed-on: http://git-master/r/406769
Reviewed-by: Riham Haidar <rhaidar@nvidia.com>
Tested-by: Riham Haidar <rhaidar@nvidia.com>
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 |