aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Wiklander <jens.wiklander@linaro.org>2016-09-16 13:29:15 +0200
committerJens Wiklander <jens.wiklander@linaro.org>2016-09-16 13:33:14 +0200
commit9cb0453666a2119af85dafb47caa0ae4e43b1f9d (patch)
tree71e3dc5471c1bda49054e1b6ea724a5cf7e5e167
parent3754ffde90a494025925f487d430a525905aac28 (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.c29
-rw-r--r--drivers/tee/optee/core.c101
-rw-r--r--drivers/tee/optee/optee_msg.h28
-rw-r--r--drivers/tee/optee/optee_smc.h28
-rw-r--r--drivers/tee/optee/rpc.c2
-rw-r--r--drivers/tee/tee_core.c6
-rw-r--r--drivers/tee/tee_shm.c8
-rw-r--r--include/linux/tee_drv.h2
-rw-r--r--include/uapi/linux/tee.h6
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