diff options
author | Jens Wiklander <jens.wiklander@linaro.org> | 2016-09-16 13:29:15 +0200 |
---|---|---|
committer | Jens Wiklander <jens.wiklander@linaro.org> | 2016-09-16 13:33:14 +0200 |
commit | 9cb0453666a2119af85dafb47caa0ae4e43b1f9d (patch) | |
tree | 71e3dc5471c1bda49054e1b6ea724a5cf7e5e167 | |
parent | 3754ffde90a494025925f487d430a525905aac28 (diff) |
tee: apply v12 delta
Applies the v12 of the generic TEE subsystem patch set.
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r-- | drivers/tee/optee/call.c | 29 | ||||
-rw-r--r-- | drivers/tee/optee/core.c | 101 | ||||
-rw-r--r-- | drivers/tee/optee/optee_msg.h | 28 | ||||
-rw-r--r-- | drivers/tee/optee/optee_smc.h | 28 | ||||
-rw-r--r-- | drivers/tee/optee/rpc.c | 2 | ||||
-rw-r--r-- | drivers/tee/tee_core.c | 6 | ||||
-rw-r--r-- | drivers/tee/tee_shm.c | 8 | ||||
-rw-r--r-- | include/linux/tee_drv.h | 2 | ||||
-rw-r--r-- | include/uapi/linux/tee.h | 6 |
9 files changed, 143 insertions, 67 deletions
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index 040c2a7c9482..97fad0e2f90a 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -32,15 +32,17 @@ static void optee_cq_wait_init(struct optee_call_queue *cq, struct optee_call_waiter *w) { mutex_lock(&cq->mutex); + /* * We add ourselves to the queue, but we don't wait. This - * guarentees that we don't lose a completion if secure world + * guarantees that we don't lose a completion if secure world * returns busy and another thread just exited and try to complete * someone. */ w->completed = false; init_completion(&w->c); list_add_tail(&w->list_node, &cq->waiters); + mutex_unlock(&cq->mutex); } @@ -101,6 +103,7 @@ static struct optee_session *find_session(struct optee_context_data *ctxdata, list_for_each_entry(sess, &ctxdata->sess_list, list_node) if (sess->session_id == session_id) return sess; + return NULL; } @@ -149,11 +152,13 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg) break; } } + /* * We're done with our thread in secure world, if there's any * thread waiters wake up one. */ optee_cq_wait_final(&optee->call_queue, &w); + return ret; } @@ -169,11 +174,13 @@ static struct tee_shm *get_msg_arg(struct tee_context *ctx, size_t num_params, TEE_SHM_MAPPED); if (IS_ERR(shm)) return shm; + ma = tee_shm_get_va(shm, 0); if (IS_ERR(ma)) { rc = PTR_ERR(ma); goto out; } + rc = tee_shm_get_pa(shm, 0, msg_parg); if (rc) goto out; @@ -186,6 +193,7 @@ out: tee_shm_free(shm); return ERR_PTR(rc); } + return shm; } @@ -243,7 +251,8 @@ int optee_open_session(struct tee_context *ctx, mutex_lock(&ctxdata->mutex); list_add(&sess->list_node, &ctxdata->sess_list); mutex_unlock(&ctxdata->mutex); - sess = NULL; + } else { + kfree(sess); } if (optee_from_msg_param(param, arg->num_params, msg_param + 2)) { @@ -257,8 +266,8 @@ int optee_open_session(struct tee_context *ctx, arg->ret_origin = msg_arg->ret_origin; } out: - kfree(sess); tee_shm_free(shm); + return rc; } @@ -403,16 +412,20 @@ void optee_disable_shm_cache(struct optee *optee) /* We need to retry until secure world isn't busy. */ optee_cq_wait_init(&optee->call_queue, &w); while (true) { - struct arm_smccc_res res; + union { + struct arm_smccc_res smccc; + struct optee_smc_disable_shm_cache_result result; + } res; optee->invoke_fn(OPTEE_SMC_DISABLE_SHM_CACHE, 0, 0, 0, 0, 0, 0, - 0, &res); - if (res.a0 == OPTEE_SMC_RETURN_ENOTAVAIL) + 0, &res.smccc); + if (res.result.status == OPTEE_SMC_RETURN_ENOTAVAIL) break; /* All shm's freed */ - if (res.a0 == OPTEE_SMC_RETURN_OK) { + if (res.result.status == OPTEE_SMC_RETURN_OK) { struct tee_shm *shm; - shm = reg_pair_to_ptr(res.a1, res.a2); + shm = reg_pair_to_ptr(res.result.shm_upper32, + res.result.shm_lower32); tee_shm_free(shm); } else { optee_cq_wait_for_completion(&optee->call_queue, &w); diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index b61eb1d017fc..b4fe7713b2fb 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -80,7 +80,7 @@ int optee_from_msg_param(struct tee_param *params, size_t num_params, rc = tee_shm_get_pa(shm, 0, &pa); if (rc) return rc; - p->u.memref.shm_offs = pa - mp->u.tmem.buf_ptr; + p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa; p->u.memref.shm = shm; /* Check that the memref is covered by the shm object */ @@ -210,6 +210,8 @@ static void optee_release(struct tee_context *ctx) struct tee_shm *shm; struct optee_msg_arg *arg = NULL; phys_addr_t parg; + struct optee_session *sess; + struct optee_session *sess_tmp; if (!ctxdata) return; @@ -220,21 +222,15 @@ static void optee_release(struct tee_context *ctx) /* * If va2pa fails for some reason, we can't call * optee_close_session(), only free the memory. Secure OS - * will leak sessions and finally refuse more session, but + * will leak sessions and finally refuse more sessions, but * we will at least let normal world reclaim its memory. */ if (!IS_ERR(arg)) tee_shm_va2pa(shm, arg, &parg); } - while (true) { - struct optee_session *sess; - - sess = list_first_entry_or_null(&ctxdata->sess_list, - struct optee_session, - list_node); - if (!sess) - break; + list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list, + list_node) { list_del(&sess->list_node); if (!IS_ERR_OR_NULL(arg)) { memset(arg, 0, sizeof(*arg)); @@ -303,12 +299,15 @@ static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn) static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn) { - struct arm_smccc_res res; + union { + struct arm_smccc_res smccc; + struct optee_smc_calls_revision_result result; + } res; - invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res); + invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc); - if (res.a0 == OPTEE_MSG_REVISION_MAJOR && - (int)res.a1 >= OPTEE_MSG_REVISION_MINOR) + if (res.result.major == OPTEE_MSG_REVISION_MAJOR && + (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR) return true; return false; } @@ -316,7 +315,10 @@ static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn) static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn, u32 *sec_caps) { - struct arm_smccc_res res; + union { + struct arm_smccc_res smccc; + struct optee_smc_exchange_capabilities_result result; + } res; u32 a1 = 0; /* @@ -328,12 +330,13 @@ static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn, a1 |= OPTEE_SMC_NSEC_CAP_UNIPROCESSOR; #endif - invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0, &res); + invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0, + &res.smccc); - if (res.a0 != OPTEE_SMC_RETURN_OK) + if (res.result.status != OPTEE_SMC_RETURN_OK) return false; - *sec_caps = res.a1; + *sec_caps = res.result.capabilities; return true; } @@ -341,7 +344,10 @@ static struct tee_shm_pool * optee_config_shm_ioremap(struct device *dev, optee_invoke_fn *invoke_fn, void __iomem **ioremaped_shm) { - struct arm_smccc_res res; + union { + struct arm_smccc_res smccc; + struct optee_smc_get_shm_config_result result; + } res; struct tee_shm_pool *pool; unsigned long vaddr; phys_addr_t paddr; @@ -352,19 +358,19 @@ optee_config_shm_ioremap(struct device *dev, optee_invoke_fn *invoke_fn, struct tee_shm_pool_mem_info priv_info; struct tee_shm_pool_mem_info dmabuf_info; - invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res); - if (res.a0 != OPTEE_SMC_RETURN_OK) { + invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc); + if (res.result.status != OPTEE_SMC_RETURN_OK) { dev_info(dev, "shm service not available\n"); return ERR_PTR(-ENOENT); } - if (res.a3 != OPTEE_SMC_SHM_CACHED) { + if (res.result.settings != OPTEE_SMC_SHM_CACHED) { dev_err(dev, "only normal cached shared memory supported\n"); return ERR_PTR(-EINVAL); } - begin = roundup(res.a1, PAGE_SIZE); - end = rounddown(res.a1 + res.a2, PAGE_SIZE); + begin = roundup(res.result.start, PAGE_SIZE); + end = rounddown(res.result.start + res.result.size, PAGE_SIZE); paddr = begin; size = end - begin; @@ -388,10 +394,13 @@ optee_config_shm_ioremap(struct device *dev, optee_invoke_fn *invoke_fn, dmabuf_info.size = size - OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; pool = tee_shm_pool_alloc_res_mem(dev, &priv_info, &dmabuf_info); - if (IS_ERR(pool)) + if (IS_ERR(pool)) { iounmap(va); - else - *ioremaped_shm = va; + goto out; + } + + *ioremaped_shm = va; +out: return pool; } @@ -432,10 +441,20 @@ static int optee_probe(struct platform_device *pdev) if (rc) return rc; - if (!optee_msg_api_uid_is_optee_api(invoke_fn) || - !optee_msg_api_revision_is_compatible(invoke_fn) || - !optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) + if (!optee_msg_api_uid_is_optee_api(invoke_fn)) { + dev_warn(&pdev->dev, "api uid mismatch\n"); + return -EINVAL; + } + + if (!optee_msg_api_revision_is_compatible(invoke_fn)) { + dev_warn(&pdev->dev, "api revision mismatch\n"); + return -EINVAL; + } + + if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) { + dev_warn(&pdev->dev, "capabilities mismatch\n"); return -EINVAL; + } /* * We have no other option for shared memory, if secure world @@ -494,13 +513,18 @@ static int optee_probe(struct platform_device *pdev) return 0; err: if (optee) { - tee_device_unregister(optee->teedev); + /* + * tee_device_unregister() is safe to call even if the + * devices hasn't been registered with + * tee_device_register() yet. + */ tee_device_unregister(optee->supp_teedev); + tee_device_unregister(optee->teedev); } if (pool) tee_shm_pool_free(pool); if (ioremaped_shm) - iounmap(optee->ioremaped_shm); + iounmap(ioremaped_shm); return rc; } @@ -508,16 +532,27 @@ static int optee_remove(struct platform_device *pdev) { struct optee *optee = platform_get_drvdata(pdev); + /* + * Ask OP-TEE to free all cached shared memory objects to decrease + * reference counters and also avoid wild pointers in secure world + * into the old shared memory range. + */ optee_disable_shm_cache(optee); - tee_device_unregister(optee->teedev); + /* + * The two devices has to be unregistered before we can free the + * other resources. + */ tee_device_unregister(optee->supp_teedev); + tee_device_unregister(optee->teedev); + tee_shm_pool_free(optee->pool); if (optee->ioremaped_shm) iounmap(optee->ioremaped_shm); optee_wait_queue_exit(&optee->wait_queue); optee_supp_uninit(&optee->supp); mutex_destroy(&optee->call_queue.mutex); + return 0; } diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h index 19377c77ccda..3c0a91213610 100644 --- a/drivers/tee/optee/optee_msg.h +++ b/drivers/tee/optee/optee_msg.h @@ -56,7 +56,7 @@ #define OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT 0xa #define OPTEE_MSG_ATTR_TYPE_TMEM_INOUT 0xb -#define OPTEE_MSG_ATTR_TYPE_MASK 0xff +#define OPTEE_MSG_ATTR_TYPE_MASK GENMASK(7, 0) /* * Meta parameter to be absorbed by the Secure OS and not passed @@ -81,7 +81,7 @@ * bearer of this protocol OPTEE_SMC_SHM_* is used for values. */ #define OPTEE_MSG_ATTR_CACHE_SHIFT 16 -#define OPTEE_MSG_ATTR_CACHE_MASK 0x7 +#define OPTEE_MSG_ATTR_CACHE_MASK GENMASK(2, 0) #define OPTEE_MSG_ATTR_CACHE_PREDEFINED 0 /* @@ -95,7 +95,7 @@ #define OPTEE_MSG_LOGIN_APPLICATION_GROUP 0x00000006 /** - * struct optee_msg_param_tmem - temporary memory reference + * struct optee_msg_param_tmem - temporary memory reference parameter * @buf_ptr: Address of the buffer * @size: Size of the buffer * @shm_ref: Temporary shared memory reference, pointer to a struct tee_shm @@ -114,7 +114,7 @@ struct optee_msg_param_tmem { }; /** - * struct optee_msg_param_rmem - registered memory reference + * struct optee_msg_param_rmem - registered memory reference parameter * @offs: Offset into shared memory reference * @size: Size of the buffer * @shm_ref: Shared memory reference, pointer to a struct tee_shm @@ -126,10 +126,9 @@ struct optee_msg_param_rmem { }; /** - * struct optee_msg_param_value - values - * @a: first value - * @b: second value - * @c: third value + * struct optee_msg_param_value - opaque value parameter + * + * Value parameters are passed unchecked between normal and secure world. */ struct optee_msg_param_value { u64 a; @@ -138,10 +137,11 @@ struct optee_msg_param_value { }; /** - * struct optee_msg_param - parameter - * @attr: attributes - * @memref: a memory reference - * @value: a value + * struct optee_msg_param - parameter used together with struct optee_msg_arg + * @attr: attributes + * @tmem: parameter by temporary memory reference + * @rmem: parameter by registered memory reference + * @value: parameter by opaque value * * @attr & OPTEE_MSG_ATTR_TYPE_MASK indicates if tmem, rmem or value is used in * the union. OPTEE_MSG_ATTR_TYPE_VALUE_* indicates value, @@ -236,7 +236,7 @@ struct optee_msg_arg { /* * Return the following UID if using API specified in this file without - * further extentions: + * further extensions: * 384fb3e0-e7f8-11e3-af63-0002a5d5c51b. * Represented in 4 32-bit words in OPTEE_MSG_UID_0, OPTEE_MSG_UID_1, * OPTEE_MSG_UID_2, OPTEE_MSG_UID_3. @@ -249,7 +249,7 @@ struct optee_msg_arg { /* * Returns 2.0 if using API specified in this file without further - * extentions. Represented in 2 32-bit words in OPTEE_MSG_REVISION_MAJOR + * extensions. Represented in 2 32-bit words in OPTEE_MSG_REVISION_MAJOR * and OPTEE_MSG_REVISION_MINOR */ #define OPTEE_MSG_REVISION_MAJOR 2 diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h index 2a1722984a0b..ff98cb7e83c9 100644 --- a/drivers/tee/optee/optee_smc.h +++ b/drivers/tee/optee/optee_smc.h @@ -84,6 +84,13 @@ ARM_SMCCC_OWNER_TRUSTED_OS_END, \ OPTEE_SMC_FUNCID_CALLS_REVISION) +struct optee_smc_calls_revision_result { + unsigned long major; + unsigned long minor; + unsigned long reserved0; + unsigned long reserved1; +}; + /* * Get UUID of Trusted OS. * @@ -183,6 +190,13 @@ #define OPTEE_SMC_GET_SHM_CONFIG \ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_SHM_CONFIG) +struct optee_smc_get_shm_config_result { + unsigned long status; + unsigned long start; + unsigned long size; + unsigned long settings; +}; + /* * Exchanges capabilities between normal world and secure world * @@ -212,6 +226,13 @@ #define OPTEE_SMC_EXCHANGE_CAPABILITIES \ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES) +struct optee_smc_exchange_capabilities_result { + unsigned long status; + unsigned long capabilities; + unsigned long reserved0; + unsigned long reserved1; +}; + /* * Disable and empties cache of shared memory objects * @@ -244,6 +265,13 @@ #define OPTEE_SMC_DISABLE_SHM_CACHE \ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE) +struct optee_smc_disable_shm_cache_result { + unsigned long status; + unsigned long shm_upper32; + unsigned long shm_lower32; + unsigned long reserved0; +}; + /* * Enable cache of shared memory objects * diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c index 3e6fca10afd8..0b9c1a2accd0 100644 --- a/drivers/tee/optee/rpc.c +++ b/drivers/tee/optee/rpc.c @@ -385,7 +385,7 @@ void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param) case OPTEE_SMC_RPC_FUNC_IRQ: /* * An IRQ was raised while secure world was executing, - * since all IRQs a handled in Linux a dummy RPC is + * since all IRQs are handled in Linux a dummy RPC is * performed to let Linux take the IRQ through the normal * vector. */ diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index d30d9347b79c..204521003350 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -29,8 +29,8 @@ #define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x)) /* - * Unprivileged devices in the in the lower half range and privileged - * devices in the upper half range. + * Unprivileged devices in the lower half range and privileged devices in + * the upper half range. */ static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES); static DEFINE_SPINLOCK(driver_lock); @@ -876,7 +876,7 @@ static int __init tee_init(void) } rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee"); - if (rc < 0) { + if (rc) { pr_err("failed to allocate char dev region\n"); class_destroy(tee_class); tee_class = NULL; diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index 157f76dad7c6..c2c90a8249be 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -97,11 +97,9 @@ static struct dma_buf_ops tee_shm_dma_buf_ops = { * * Memory allocated as global shared memory is automatically freed when the * TEE file pointer is closed. The @flags field uses the bits defined by - * TEE_SHM_* above. TEE_SHM_MAPPED must currently always be set. If - * TEE_SHM_DMA_BUF global shared memory will be allocated and associated - * with a dma-buf handle, else driver private memory. - * - * @returns a pointer to 'struct tee_shm' + * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be + * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and + * associated with a dma-buf handle, else driver private memory. */ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) { diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h index 9641878a69be..f5d5f455660c 100644 --- a/include/linux/tee_drv.h +++ b/include/linux/tee_drv.h @@ -157,7 +157,7 @@ void tee_device_unregister(struct tee_device *teedev); */ struct tee_shm_pool_mem_info { unsigned long vaddr; - unsigned long paddr; + phys_addr_t paddr; size_t size; }; diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h index 3d1ed516b00d..ddc476e3c16b 100644 --- a/include/uapi/linux/tee.h +++ b/include/uapi/linux/tee.h @@ -155,7 +155,7 @@ struct tee_ioctl_buf_data { /* * Matches TEEC_LOGIN_* in GP TEE Client API - * Is only defined for GP compliant TEEs + * Are only defined for GP compliant TEEs */ #define TEE_IOCTL_LOGIN_PUBLIC 0 #define TEE_IOCTL_LOGIN_USER 1 @@ -187,6 +187,8 @@ struct tee_ioctl_param_memref { * @a: first value * @b: second value * @c: third value + * + * Value parameters are passed unchecked to the destination */ struct tee_ioctl_param_value { __u64 a; @@ -219,7 +221,7 @@ struct tee_ioctl_param { * struct tee_ioctl_open_session_arg - Open session argument * @uuid: [in] UUID of the Trusted Application * @clnt_uuid: [in] UUID of client - * @clnt_login: [in] Login class of client, TEE_LOGIN_* above + * @clnt_login: [in] Login class of client, TEE_IOCTL_LOGIN_* above * @cancel_id: [in] Cancellation id, a unique value to identify this request * @session: [out] Session id * @ret: [out] return value |