Commit a8e9f5f6 authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'tee-drv-async-supplicant-for-v4.16' of...

Merge tag 'tee-drv-async-supplicant-for-v4.16' of https://git.linaro.org/people/jens.wiklander/linux-tee into next/drivers

Pull "Enable async communication with tee supplicant" from Jens Wiklander:

This pull request enables asynchronous communication with TEE supplicant
by introducing meta parameters in the user space API. The meta
parameters can be used to tag requests with an id that can be matched
against an asynchronous response as is done here in the OP-TEE driver.

Asynchronous supplicant communication is needed by OP-TEE to implement
GlobalPlatforms TEE Sockets API Specification v1.0.1. The specification
is available at https://www.globalplatform.org/specificationsdevice.asp.

This change is backwards compatible allowing older supplicants to work
with newer kernels and vice versa.

* tag 'tee-drv-async-supplicant-for-v4.16' of https://git.linaro.org/people/jens.wiklander/linux-tee:
  optee: support asynchronous supplicant requests
  tee: add TEE_IOCTL_PARAM_ATTR_META
  tee: add tee_param_is_memref() for driver use
parents 1291a0d5 1647a5ac
...@@ -187,12 +187,12 @@ static int optee_open(struct tee_context *ctx) ...@@ -187,12 +187,12 @@ static int optee_open(struct tee_context *ctx)
if (teedev == optee->supp_teedev) { if (teedev == optee->supp_teedev) {
bool busy = true; bool busy = true;
mutex_lock(&optee->supp.ctx_mutex); mutex_lock(&optee->supp.mutex);
if (!optee->supp.ctx) { if (!optee->supp.ctx) {
busy = false; busy = false;
optee->supp.ctx = ctx; optee->supp.ctx = ctx;
} }
mutex_unlock(&optee->supp.ctx_mutex); mutex_unlock(&optee->supp.mutex);
if (busy) { if (busy) {
kfree(ctxdata); kfree(ctxdata);
return -EBUSY; return -EBUSY;
...@@ -252,11 +252,8 @@ static void optee_release(struct tee_context *ctx) ...@@ -252,11 +252,8 @@ static void optee_release(struct tee_context *ctx)
ctx->data = NULL; ctx->data = NULL;
if (teedev == optee->supp_teedev) { if (teedev == optee->supp_teedev)
mutex_lock(&optee->supp.ctx_mutex); optee_supp_release(&optee->supp);
optee->supp.ctx = NULL;
mutex_unlock(&optee->supp.ctx_mutex);
}
} }
static const struct tee_driver_ops optee_ops = { static const struct tee_driver_ops optee_ops = {
......
...@@ -53,36 +53,24 @@ struct optee_wait_queue { ...@@ -53,36 +53,24 @@ struct optee_wait_queue {
* @ctx the context of current connected supplicant. * @ctx the context of current connected supplicant.
* if !NULL the supplicant device is available for use, * if !NULL the supplicant device is available for use,
* else busy * else busy
* @ctx_mutex: held while accessing @ctx * @mutex: held while accessing content of this struct
* @func: supplicant function id to call * @req_id: current request id if supplicant is doing synchronous
* @ret: call return value * communication, else -1
* @num_params: number of elements in @param * @reqs: queued request not yet retrieved by supplicant
* @param: parameters for @func * @idr: IDR holding all requests currently being processed
* @req_posted: if true, a request has been posted to the supplicant * by supplicant
* @supp_next_send: if true, next step is for supplicant to send response * @reqs_c: completion used by supplicant when waiting for a
* @thrd_mutex: held by the thread doing a request to supplicant * request to be queued.
* @supp_mutex: held by supplicant while operating on this struct
* @data_to_supp: supplicant is waiting on this for next request
* @data_from_supp: requesting thread is waiting on this to get the result
*/ */
struct optee_supp { struct optee_supp {
/* Serializes access to this struct */
struct mutex mutex;
struct tee_context *ctx; struct tee_context *ctx;
/* Serializes access of ctx */
struct mutex ctx_mutex; int req_id;
struct list_head reqs;
u32 func; struct idr idr;
u32 ret; struct completion reqs_c;
size_t num_params;
struct tee_param *param;
bool req_posted;
bool supp_next_send;
/* Serializes access to this struct for requesting thread */
struct mutex thrd_mutex;
/* Serializes access to this struct for supplicant threads */
struct mutex supp_mutex;
struct completion data_to_supp;
struct completion data_from_supp;
}; };
/** /**
...@@ -142,6 +130,7 @@ int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len); ...@@ -142,6 +130,7 @@ int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len);
int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len); int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len);
void optee_supp_init(struct optee_supp *supp); void optee_supp_init(struct optee_supp *supp);
void optee_supp_uninit(struct optee_supp *supp); void optee_supp_uninit(struct optee_supp *supp);
void optee_supp_release(struct optee_supp *supp);
int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
struct tee_param *param); struct tee_param *param);
......
...@@ -192,10 +192,10 @@ static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz) ...@@ -192,10 +192,10 @@ static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
if (ret) if (ret)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
mutex_lock(&optee->supp.ctx_mutex); mutex_lock(&optee->supp.mutex);
/* Increases count as secure world doesn't have a reference */ /* Increases count as secure world doesn't have a reference */
shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c); shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c);
mutex_unlock(&optee->supp.ctx_mutex); mutex_unlock(&optee->supp.mutex);
return shm; return shm;
} }
......
This diff is collapsed.
...@@ -152,11 +152,11 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params, ...@@ -152,11 +152,11 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
return -EFAULT; return -EFAULT;
/* All unused attribute bits has to be zero */ /* All unused attribute bits has to be zero */
if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK)
return -EINVAL; return -EINVAL;
params[n].attr = ip.attr; params[n].attr = ip.attr;
switch (ip.attr) { switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
break; break;
...@@ -221,18 +221,6 @@ static int params_to_user(struct tee_ioctl_param __user *uparams, ...@@ -221,18 +221,6 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
return 0; return 0;
} }
static bool param_is_memref(struct tee_param *param)
{
switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
return true;
default:
return false;
}
}
static int tee_ioctl_open_session(struct tee_context *ctx, static int tee_ioctl_open_session(struct tee_context *ctx,
struct tee_ioctl_buf_data __user *ubuf) struct tee_ioctl_buf_data __user *ubuf)
{ {
...@@ -296,7 +284,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx, ...@@ -296,7 +284,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx,
if (params) { if (params) {
/* Decrease ref count for all valid shared memory pointers */ /* Decrease ref count for all valid shared memory pointers */
for (n = 0; n < arg.num_params; n++) for (n = 0; n < arg.num_params; n++)
if (param_is_memref(params + n) && if (tee_param_is_memref(params + n) &&
params[n].u.memref.shm) params[n].u.memref.shm)
tee_shm_put(params[n].u.memref.shm); tee_shm_put(params[n].u.memref.shm);
kfree(params); kfree(params);
...@@ -358,7 +346,7 @@ static int tee_ioctl_invoke(struct tee_context *ctx, ...@@ -358,7 +346,7 @@ static int tee_ioctl_invoke(struct tee_context *ctx,
if (params) { if (params) {
/* Decrease ref count for all valid shared memory pointers */ /* Decrease ref count for all valid shared memory pointers */
for (n = 0; n < arg.num_params; n++) for (n = 0; n < arg.num_params; n++)
if (param_is_memref(params + n) && if (tee_param_is_memref(params + n) &&
params[n].u.memref.shm) params[n].u.memref.shm)
tee_shm_put(params[n].u.memref.shm); tee_shm_put(params[n].u.memref.shm);
kfree(params); kfree(params);
...@@ -406,8 +394,8 @@ static int params_to_supp(struct tee_context *ctx, ...@@ -406,8 +394,8 @@ static int params_to_supp(struct tee_context *ctx,
struct tee_ioctl_param ip; struct tee_ioctl_param ip;
struct tee_param *p = params + n; struct tee_param *p = params + n;
ip.attr = p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK; ip.attr = p->attr;
switch (p->attr) { switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
ip.a = p->u.value.a; ip.a = p->u.value.a;
...@@ -471,6 +459,10 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx, ...@@ -471,6 +459,10 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
if (!params) if (!params)
return -ENOMEM; return -ENOMEM;
rc = params_from_user(ctx, params, num_params, uarg->params);
if (rc)
goto out;
rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params); rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
if (rc) if (rc)
goto out; goto out;
...@@ -500,11 +492,11 @@ static int params_from_supp(struct tee_param *params, size_t num_params, ...@@ -500,11 +492,11 @@ static int params_from_supp(struct tee_param *params, size_t num_params,
return -EFAULT; return -EFAULT;
/* All unused attribute bits has to be zero */ /* All unused attribute bits has to be zero */
if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK)
return -EINVAL; return -EINVAL;
p->attr = ip.attr; p->attr = ip.attr;
switch (ip.attr) { switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
/* Only out and in/out values can be updated */ /* Only out and in/out values can be updated */
......
...@@ -275,4 +275,16 @@ int tee_shm_get_id(struct tee_shm *shm); ...@@ -275,4 +275,16 @@ int tee_shm_get_id(struct tee_shm *shm);
*/ */
struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id); struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id);
static inline bool tee_param_is_memref(struct tee_param *param)
{
switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
return true;
default:
return false;
}
}
#endif /*__TEE_DRV_H*/ #endif /*__TEE_DRV_H*/
...@@ -154,6 +154,13 @@ struct tee_ioctl_buf_data { ...@@ -154,6 +154,13 @@ struct tee_ioctl_buf_data {
*/ */
#define TEE_IOCTL_PARAM_ATTR_TYPE_MASK 0xff #define TEE_IOCTL_PARAM_ATTR_TYPE_MASK 0xff
/* Meta parameter carrying extra information about the message. */
#define TEE_IOCTL_PARAM_ATTR_META 0x100
/* Mask of all known attr bits */
#define TEE_IOCTL_PARAM_ATTR_MASK \
(TEE_IOCTL_PARAM_ATTR_TYPE_MASK | TEE_IOCTL_PARAM_ATTR_META)
/* /*
* Matches TEEC_LOGIN_* in GP TEE Client API * Matches TEEC_LOGIN_* in GP TEE Client API
* Are only defined for GP compliant TEEs * Are only defined for GP compliant TEEs
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment