diff options
author | Jens Wiklander <jens.wiklander@linaro.org> | 2016-12-23 07:13:39 -0500 |
---|---|---|
committer | Jens Wiklander <jens.wiklander@linaro.org> | 2017-11-29 04:37:13 -0500 |
commit | 1647a5ac175490d7dac2e74532e85b6197fc74e9 (patch) | |
tree | 9883ff54c1d697ddd0cd77c2c2dea7160ff4fdd7 | |
parent | f2aa97240c84b8f258710e297ba60048bd9c153e (diff) |
optee: support asynchronous supplicant requests
Adds support for asynchronous supplicant requests, meaning that the
supplicant can process several requests in parallel or block in a
request for some time.
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Tested-by: Etienne Carriere <etienne.carriere@linaro.org> (b2260 pager=y/n)
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r-- | drivers/tee/optee/core.c | 11 | ||||
-rw-r--r-- | drivers/tee/optee/optee_private.h | 43 | ||||
-rw-r--r-- | drivers/tee/optee/rpc.c | 4 | ||||
-rw-r--r-- | drivers/tee/optee/supp.c | 358 |
4 files changed, 243 insertions, 173 deletions
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 7952357df9c8..b7492da92567 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c | |||
@@ -187,12 +187,12 @@ static int optee_open(struct tee_context *ctx) | |||
187 | if (teedev == optee->supp_teedev) { | 187 | if (teedev == optee->supp_teedev) { |
188 | bool busy = true; | 188 | bool busy = true; |
189 | 189 | ||
190 | mutex_lock(&optee->supp.ctx_mutex); | 190 | mutex_lock(&optee->supp.mutex); |
191 | if (!optee->supp.ctx) { | 191 | if (!optee->supp.ctx) { |
192 | busy = false; | 192 | busy = false; |
193 | optee->supp.ctx = ctx; | 193 | optee->supp.ctx = ctx; |
194 | } | 194 | } |
195 | mutex_unlock(&optee->supp.ctx_mutex); | 195 | mutex_unlock(&optee->supp.mutex); |
196 | if (busy) { | 196 | if (busy) { |
197 | kfree(ctxdata); | 197 | kfree(ctxdata); |
198 | return -EBUSY; | 198 | return -EBUSY; |
@@ -252,11 +252,8 @@ static void optee_release(struct tee_context *ctx) | |||
252 | 252 | ||
253 | ctx->data = NULL; | 253 | ctx->data = NULL; |
254 | 254 | ||
255 | if (teedev == optee->supp_teedev) { | 255 | if (teedev == optee->supp_teedev) |
256 | mutex_lock(&optee->supp.ctx_mutex); | 256 | optee_supp_release(&optee->supp); |
257 | optee->supp.ctx = NULL; | ||
258 | mutex_unlock(&optee->supp.ctx_mutex); | ||
259 | } | ||
260 | } | 257 | } |
261 | 258 | ||
262 | static const struct tee_driver_ops optee_ops = { | 259 | static const struct tee_driver_ops optee_ops = { |
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index c374cd594314..3e7da187acbe 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h | |||
@@ -53,36 +53,24 @@ struct optee_wait_queue { | |||
53 | * @ctx the context of current connected supplicant. | 53 | * @ctx the context of current connected supplicant. |
54 | * if !NULL the supplicant device is available for use, | 54 | * if !NULL the supplicant device is available for use, |
55 | * else busy | 55 | * else busy |
56 | * @ctx_mutex: held while accessing @ctx | 56 | * @mutex: held while accessing content of this struct |
57 | * @func: supplicant function id to call | 57 | * @req_id: current request id if supplicant is doing synchronous |
58 | * @ret: call return value | 58 | * communication, else -1 |
59 | * @num_params: number of elements in @param | 59 | * @reqs: queued request not yet retrieved by supplicant |
60 | * @param: parameters for @func | 60 | * @idr: IDR holding all requests currently being processed |
61 | * @req_posted: if true, a request has been posted to the supplicant | 61 | * by supplicant |
62 | * @supp_next_send: if true, next step is for supplicant to send response | 62 | * @reqs_c: completion used by supplicant when waiting for a |
63 | * @thrd_mutex: held by the thread doing a request to supplicant | 63 | * request to be queued. |
64 | * @supp_mutex: held by supplicant while operating on this struct | ||
65 | * @data_to_supp: supplicant is waiting on this for next request | ||
66 | * @data_from_supp: requesting thread is waiting on this to get the result | ||
67 | */ | 64 | */ |
68 | struct optee_supp { | 65 | struct optee_supp { |
66 | /* Serializes access to this struct */ | ||
67 | struct mutex mutex; | ||
69 | struct tee_context *ctx; | 68 | struct tee_context *ctx; |
70 | /* Serializes access of ctx */ | 69 | |
71 | struct mutex ctx_mutex; | 70 | int req_id; |
72 | 71 | struct list_head reqs; | |
73 | u32 func; | 72 | struct idr idr; |
74 | u32 ret; | 73 | struct completion reqs_c; |
75 | size_t num_params; | ||
76 | struct tee_param *param; | ||
77 | |||
78 | bool req_posted; | ||
79 | bool supp_next_send; | ||
80 | /* Serializes access to this struct for requesting thread */ | ||
81 | struct mutex thrd_mutex; | ||
82 | /* Serializes access to this struct for supplicant threads */ | ||
83 | struct mutex supp_mutex; | ||
84 | struct completion data_to_supp; | ||
85 | struct completion data_from_supp; | ||
86 | }; | 74 | }; |
87 | 75 | ||
88 | /** | 76 | /** |
@@ -142,6 +130,7 @@ int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len); | |||
142 | int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len); | 130 | int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len); |
143 | void optee_supp_init(struct optee_supp *supp); | 131 | void optee_supp_init(struct optee_supp *supp); |
144 | void optee_supp_uninit(struct optee_supp *supp); | 132 | void optee_supp_uninit(struct optee_supp *supp); |
133 | void optee_supp_release(struct optee_supp *supp); | ||
145 | 134 | ||
146 | int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, | 135 | int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, |
147 | struct tee_param *param); | 136 | struct tee_param *param); |
diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c index cef417f4f4d2..c6df4317ca9f 100644 --- a/drivers/tee/optee/rpc.c +++ b/drivers/tee/optee/rpc.c | |||
@@ -192,10 +192,10 @@ static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz) | |||
192 | if (ret) | 192 | if (ret) |
193 | return ERR_PTR(-ENOMEM); | 193 | return ERR_PTR(-ENOMEM); |
194 | 194 | ||
195 | mutex_lock(&optee->supp.ctx_mutex); | 195 | mutex_lock(&optee->supp.mutex); |
196 | /* Increases count as secure world doesn't have a reference */ | 196 | /* Increases count as secure world doesn't have a reference */ |
197 | shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c); | 197 | shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c); |
198 | mutex_unlock(&optee->supp.ctx_mutex); | 198 | mutex_unlock(&optee->supp.mutex); |
199 | return shm; | 199 | return shm; |
200 | } | 200 | } |
201 | 201 | ||
diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c index 56aa8b929b8c..df35fc01fd3e 100644 --- a/drivers/tee/optee/supp.c +++ b/drivers/tee/optee/supp.c | |||
@@ -16,21 +16,61 @@ | |||
16 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
17 | #include "optee_private.h" | 17 | #include "optee_private.h" |
18 | 18 | ||
19 | struct optee_supp_req { | ||
20 | struct list_head link; | ||
21 | |||
22 | bool busy; | ||
23 | u32 func; | ||
24 | u32 ret; | ||
25 | size_t num_params; | ||
26 | struct tee_param *param; | ||
27 | |||
28 | struct completion c; | ||
29 | }; | ||
30 | |||
19 | void optee_supp_init(struct optee_supp *supp) | 31 | void optee_supp_init(struct optee_supp *supp) |
20 | { | 32 | { |
21 | memset(supp, 0, sizeof(*supp)); | 33 | memset(supp, 0, sizeof(*supp)); |
22 | mutex_init(&supp->ctx_mutex); | 34 | mutex_init(&supp->mutex); |
23 | mutex_init(&supp->thrd_mutex); | 35 | init_completion(&supp->reqs_c); |
24 | mutex_init(&supp->supp_mutex); | 36 | idr_init(&supp->idr); |
25 | init_completion(&supp->data_to_supp); | 37 | INIT_LIST_HEAD(&supp->reqs); |
26 | init_completion(&supp->data_from_supp); | 38 | supp->req_id = -1; |
27 | } | 39 | } |
28 | 40 | ||
29 | void optee_supp_uninit(struct optee_supp *supp) | 41 | void optee_supp_uninit(struct optee_supp *supp) |
30 | { | 42 | { |
31 | mutex_destroy(&supp->ctx_mutex); | 43 | mutex_destroy(&supp->mutex); |
32 | mutex_destroy(&supp->thrd_mutex); | 44 | idr_destroy(&supp->idr); |
33 | mutex_destroy(&supp->supp_mutex); | 45 | } |
46 | |||
47 | void optee_supp_release(struct optee_supp *supp) | ||
48 | { | ||
49 | int id; | ||
50 | struct optee_supp_req *req; | ||
51 | struct optee_supp_req *req_tmp; | ||
52 | |||
53 | mutex_lock(&supp->mutex); | ||
54 | |||
55 | /* Abort all request retrieved by supplicant */ | ||
56 | idr_for_each_entry(&supp->idr, req, id) { | ||
57 | req->busy = false; | ||
58 | idr_remove(&supp->idr, id); | ||
59 | req->ret = TEEC_ERROR_COMMUNICATION; | ||
60 | complete(&req->c); | ||
61 | } | ||
62 | |||
63 | /* Abort all queued requests */ | ||
64 | list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { | ||
65 | list_del(&req->link); | ||
66 | req->ret = TEEC_ERROR_COMMUNICATION; | ||
67 | complete(&req->c); | ||
68 | } | ||
69 | |||
70 | supp->ctx = NULL; | ||
71 | supp->req_id = -1; | ||
72 | |||
73 | mutex_unlock(&supp->mutex); | ||
34 | } | 74 | } |
35 | 75 | ||
36 | /** | 76 | /** |
@@ -44,53 +84,42 @@ void optee_supp_uninit(struct optee_supp *supp) | |||
44 | */ | 84 | */ |
45 | u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, | 85 | u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, |
46 | struct tee_param *param) | 86 | struct tee_param *param) |
87 | |||
47 | { | 88 | { |
48 | bool interruptable; | ||
49 | struct optee *optee = tee_get_drvdata(ctx->teedev); | 89 | struct optee *optee = tee_get_drvdata(ctx->teedev); |
50 | struct optee_supp *supp = &optee->supp; | 90 | struct optee_supp *supp = &optee->supp; |
91 | struct optee_supp_req *req = kzalloc(sizeof(*req), GFP_KERNEL); | ||
92 | bool interruptable; | ||
51 | u32 ret; | 93 | u32 ret; |
52 | 94 | ||
53 | /* | 95 | if (!req) |
54 | * Other threads blocks here until we've copied our answer from | 96 | return TEEC_ERROR_OUT_OF_MEMORY; |
55 | * supplicant. | ||
56 | */ | ||
57 | while (mutex_lock_interruptible(&supp->thrd_mutex)) { | ||
58 | /* See comment below on when the RPC can be interrupted. */ | ||
59 | mutex_lock(&supp->ctx_mutex); | ||
60 | interruptable = !supp->ctx; | ||
61 | mutex_unlock(&supp->ctx_mutex); | ||
62 | if (interruptable) | ||
63 | return TEEC_ERROR_COMMUNICATION; | ||
64 | } | ||
65 | 97 | ||
66 | /* | 98 | init_completion(&req->c); |
67 | * We have exclusive access now since the supplicant at this | 99 | req->func = func; |
68 | * point is either doing a | 100 | req->num_params = num_params; |
69 | * wait_for_completion_interruptible(&supp->data_to_supp) or is in | 101 | req->param = param; |
70 | * userspace still about to do the ioctl() to enter | ||
71 | * optee_supp_recv() below. | ||
72 | */ | ||
73 | 102 | ||
74 | supp->func = func; | 103 | /* Insert the request in the request list */ |
75 | supp->num_params = num_params; | 104 | mutex_lock(&supp->mutex); |
76 | supp->param = param; | 105 | list_add_tail(&req->link, &supp->reqs); |
77 | supp->req_posted = true; | 106 | mutex_unlock(&supp->mutex); |
78 | 107 | ||
79 | /* Let supplicant get the data */ | 108 | /* Tell an eventual waiter there's a new request */ |
80 | complete(&supp->data_to_supp); | 109 | complete(&supp->reqs_c); |
81 | 110 | ||
82 | /* | 111 | /* |
83 | * Wait for supplicant to process and return result, once we've | 112 | * Wait for supplicant to process and return result, once we've |
84 | * returned from wait_for_completion(data_from_supp) we have | 113 | * returned from wait_for_completion(&req->c) successfully we have |
85 | * exclusive access again. | 114 | * exclusive access again. |
86 | */ | 115 | */ |
87 | while (wait_for_completion_interruptible(&supp->data_from_supp)) { | 116 | while (wait_for_completion_interruptible(&req->c)) { |
88 | mutex_lock(&supp->ctx_mutex); | 117 | mutex_lock(&supp->mutex); |
89 | interruptable = !supp->ctx; | 118 | interruptable = !supp->ctx; |
90 | if (interruptable) { | 119 | if (interruptable) { |
91 | /* | 120 | /* |
92 | * There's no supplicant available and since the | 121 | * There's no supplicant available and since the |
93 | * supp->ctx_mutex currently is held none can | 122 | * supp->mutex currently is held none can |
94 | * become available until the mutex released | 123 | * become available until the mutex released |
95 | * again. | 124 | * again. |
96 | * | 125 | * |
@@ -101,28 +130,65 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, | |||
101 | * will serve all requests in a timely manner and | 130 | * will serve all requests in a timely manner and |
102 | * interrupting then wouldn't make sense. | 131 | * interrupting then wouldn't make sense. |
103 | */ | 132 | */ |
104 | supp->ret = TEEC_ERROR_COMMUNICATION; | 133 | interruptable = !req->busy; |
105 | init_completion(&supp->data_to_supp); | 134 | if (!req->busy) |
135 | list_del(&req->link); | ||
106 | } | 136 | } |
107 | mutex_unlock(&supp->ctx_mutex); | 137 | mutex_unlock(&supp->mutex); |
108 | if (interruptable) | 138 | |
139 | if (interruptable) { | ||
140 | req->ret = TEEC_ERROR_COMMUNICATION; | ||
109 | break; | 141 | break; |
142 | } | ||
110 | } | 143 | } |
111 | 144 | ||
112 | ret = supp->ret; | 145 | ret = req->ret; |
113 | supp->param = NULL; | 146 | kfree(req); |
114 | supp->req_posted = false; | ||
115 | |||
116 | /* We're done, let someone else talk to the supplicant now. */ | ||
117 | mutex_unlock(&supp->thrd_mutex); | ||
118 | 147 | ||
119 | return ret; | 148 | return ret; |
120 | } | 149 | } |
121 | 150 | ||
122 | static int supp_check_recv_params(size_t num_params, struct tee_param *params) | 151 | static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, |
152 | int num_params, int *id) | ||
153 | { | ||
154 | struct optee_supp_req *req; | ||
155 | |||
156 | if (supp->req_id != -1) { | ||
157 | /* | ||
158 | * Supplicant should not mix synchronous and asnynchronous | ||
159 | * requests. | ||
160 | */ | ||
161 | return ERR_PTR(-EINVAL); | ||
162 | } | ||
163 | |||
164 | if (list_empty(&supp->reqs)) | ||
165 | return NULL; | ||
166 | |||
167 | req = list_first_entry(&supp->reqs, struct optee_supp_req, link); | ||
168 | |||
169 | if (num_params < req->num_params) { | ||
170 | /* Not enough room for parameters */ | ||
171 | return ERR_PTR(-EINVAL); | ||
172 | } | ||
173 | |||
174 | *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); | ||
175 | if (*id < 0) | ||
176 | return ERR_PTR(-ENOMEM); | ||
177 | |||
178 | list_del(&req->link); | ||
179 | req->busy = true; | ||
180 | |||
181 | return req; | ||
182 | } | ||
183 | |||
184 | static int supp_check_recv_params(size_t num_params, struct tee_param *params, | ||
185 | size_t *num_meta) | ||
123 | { | 186 | { |
124 | size_t n; | 187 | size_t n; |
125 | 188 | ||
189 | if (!num_params) | ||
190 | return -EINVAL; | ||
191 | |||
126 | /* | 192 | /* |
127 | * If there's memrefs we need to decrease those as they where | 193 | * If there's memrefs we need to decrease those as they where |
128 | * increased earlier and we'll even refuse to accept any below. | 194 | * increased earlier and we'll even refuse to accept any below. |
@@ -132,11 +198,20 @@ static int supp_check_recv_params(size_t num_params, struct tee_param *params) | |||
132 | tee_shm_put(params[n].u.memref.shm); | 198 | tee_shm_put(params[n].u.memref.shm); |
133 | 199 | ||
134 | /* | 200 | /* |
135 | * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE (0). | 201 | * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE with |
202 | * or without the TEE_IOCTL_PARAM_ATTR_META bit set. | ||
136 | */ | 203 | */ |
137 | for (n = 0; n < num_params; n++) | 204 | for (n = 0; n < num_params; n++) |
138 | if (params[n].attr) | 205 | if (params[n].attr && |
206 | params[n].attr != TEE_IOCTL_PARAM_ATTR_META) | ||
139 | return -EINVAL; | 207 | return -EINVAL; |
208 | |||
209 | /* At most we'll need one meta parameter so no need to check for more */ | ||
210 | if (params->attr == TEE_IOCTL_PARAM_ATTR_META) | ||
211 | *num_meta = 1; | ||
212 | else | ||
213 | *num_meta = 0; | ||
214 | |||
140 | return 0; | 215 | return 0; |
141 | } | 216 | } |
142 | 217 | ||
@@ -156,69 +231,99 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, | |||
156 | struct tee_device *teedev = ctx->teedev; | 231 | struct tee_device *teedev = ctx->teedev; |
157 | struct optee *optee = tee_get_drvdata(teedev); | 232 | struct optee *optee = tee_get_drvdata(teedev); |
158 | struct optee_supp *supp = &optee->supp; | 233 | struct optee_supp *supp = &optee->supp; |
234 | struct optee_supp_req *req = NULL; | ||
235 | int id; | ||
236 | size_t num_meta; | ||
159 | int rc; | 237 | int rc; |
160 | 238 | ||
161 | rc = supp_check_recv_params(*num_params, param); | 239 | rc = supp_check_recv_params(*num_params, param, &num_meta); |
162 | if (rc) | 240 | if (rc) |
163 | return rc; | 241 | return rc; |
164 | 242 | ||
165 | /* | 243 | while (true) { |
166 | * In case two threads in one supplicant is calling this function | 244 | mutex_lock(&supp->mutex); |
167 | * simultaneously we need to protect the data with a mutex which | 245 | req = supp_pop_entry(supp, *num_params - num_meta, &id); |
168 | * we'll release before returning. | 246 | mutex_unlock(&supp->mutex); |
169 | */ | 247 | |
170 | mutex_lock(&supp->supp_mutex); | 248 | if (req) { |
249 | if (IS_ERR(req)) | ||
250 | return PTR_ERR(req); | ||
251 | break; | ||
252 | } | ||
171 | 253 | ||
172 | if (supp->supp_next_send) { | ||
173 | /* | 254 | /* |
174 | * optee_supp_recv() has been called again without | 255 | * If we didn't get a request we'll block in |
175 | * a optee_supp_send() in between. Supplicant has | 256 | * wait_for_completion() to avoid needless spinning. |
176 | * probably been restarted before it was able to | 257 | * |
177 | * write back last result. Abort last request and | 258 | * This is where supplicant will be hanging most of |
178 | * wait for a new. | 259 | * the time, let's make this interruptable so we |
260 | * can easily restart supplicant if needed. | ||
179 | */ | 261 | */ |
180 | if (supp->req_posted) { | 262 | if (wait_for_completion_interruptible(&supp->reqs_c)) |
181 | supp->ret = TEEC_ERROR_COMMUNICATION; | 263 | return -ERESTARTSYS; |
182 | supp->supp_next_send = false; | ||
183 | complete(&supp->data_from_supp); | ||
184 | } | ||
185 | } | 264 | } |
186 | 265 | ||
187 | /* | 266 | if (num_meta) { |
188 | * This is where supplicant will be hanging most of the | 267 | /* |
189 | * time, let's make this interruptable so we can easily | 268 | * tee-supplicant support meta parameters -> requsts can be |
190 | * restart supplicant if needed. | 269 | * processed asynchronously. |
191 | */ | 270 | */ |
192 | if (wait_for_completion_interruptible(&supp->data_to_supp)) { | 271 | param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | |
193 | rc = -ERESTARTSYS; | 272 | TEE_IOCTL_PARAM_ATTR_META; |
194 | goto out; | 273 | param->u.value.a = id; |
274 | param->u.value.b = 0; | ||
275 | param->u.value.c = 0; | ||
276 | } else { | ||
277 | mutex_lock(&supp->mutex); | ||
278 | supp->req_id = id; | ||
279 | mutex_unlock(&supp->mutex); | ||
195 | } | 280 | } |
196 | 281 | ||
197 | /* We have exlusive access to the data */ | 282 | *func = req->func; |
283 | *num_params = req->num_params + num_meta; | ||
284 | memcpy(param + num_meta, req->param, | ||
285 | sizeof(struct tee_param) * req->num_params); | ||
198 | 286 | ||
199 | if (*num_params < supp->num_params) { | 287 | return 0; |
200 | /* | 288 | } |
201 | * Not enough room for parameters, tell supplicant | 289 | |
202 | * it failed and abort last request. | 290 | static struct optee_supp_req *supp_pop_req(struct optee_supp *supp, |
203 | */ | 291 | size_t num_params, |
204 | supp->ret = TEEC_ERROR_COMMUNICATION; | 292 | struct tee_param *param, |
205 | rc = -EINVAL; | 293 | size_t *num_meta) |
206 | complete(&supp->data_from_supp); | 294 | { |
207 | goto out; | 295 | struct optee_supp_req *req; |
296 | int id; | ||
297 | size_t nm; | ||
298 | const u32 attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | | ||
299 | TEE_IOCTL_PARAM_ATTR_META; | ||
300 | |||
301 | if (!num_params) | ||
302 | return ERR_PTR(-EINVAL); | ||
303 | |||
304 | if (supp->req_id == -1) { | ||
305 | if (param->attr != attr) | ||
306 | return ERR_PTR(-EINVAL); | ||
307 | id = param->u.value.a; | ||
308 | nm = 1; | ||
309 | } else { | ||
310 | id = supp->req_id; | ||
311 | nm = 0; | ||
208 | } | 312 | } |
209 | 313 | ||
210 | *func = supp->func; | 314 | req = idr_find(&supp->idr, id); |
211 | *num_params = supp->num_params; | 315 | if (!req) |
212 | memcpy(param, supp->param, | 316 | return ERR_PTR(-ENOENT); |
213 | sizeof(struct tee_param) * supp->num_params); | 317 | |
318 | if ((num_params - nm) != req->num_params) | ||
319 | return ERR_PTR(-EINVAL); | ||
214 | 320 | ||
215 | /* Allow optee_supp_send() below to do its work */ | 321 | req->busy = false; |
216 | supp->supp_next_send = true; | 322 | idr_remove(&supp->idr, id); |
323 | supp->req_id = -1; | ||
324 | *num_meta = nm; | ||
217 | 325 | ||
218 | rc = 0; | 326 | return req; |
219 | out: | ||
220 | mutex_unlock(&supp->supp_mutex); | ||
221 | return rc; | ||
222 | } | 327 | } |
223 | 328 | ||
224 | /** | 329 | /** |
@@ -236,63 +341,42 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, | |||
236 | struct tee_device *teedev = ctx->teedev; | 341 | struct tee_device *teedev = ctx->teedev; |
237 | struct optee *optee = tee_get_drvdata(teedev); | 342 | struct optee *optee = tee_get_drvdata(teedev); |
238 | struct optee_supp *supp = &optee->supp; | 343 | struct optee_supp *supp = &optee->supp; |
344 | struct optee_supp_req *req; | ||
239 | size_t n; | 345 | size_t n; |
240 | int rc = 0; | 346 | size_t num_meta; |
241 | 347 | ||
242 | /* | 348 | mutex_lock(&supp->mutex); |
243 | * We still have exclusive access to the data since that's how we | 349 | req = supp_pop_req(supp, num_params, param, &num_meta); |
244 | * left it when returning from optee_supp_read(). | 350 | mutex_unlock(&supp->mutex); |
245 | */ | ||
246 | 351 | ||
247 | /* See comment on mutex in optee_supp_read() above */ | 352 | if (IS_ERR(req)) { |
248 | mutex_lock(&supp->supp_mutex); | 353 | /* Something is wrong, let supplicant restart. */ |
249 | 354 | return PTR_ERR(req); | |
250 | if (!supp->supp_next_send) { | ||
251 | /* | ||
252 | * Something strange is going on, supplicant shouldn't | ||
253 | * enter optee_supp_send() in this state | ||
254 | */ | ||
255 | rc = -ENOENT; | ||
256 | goto out; | ||
257 | } | ||
258 | |||
259 | if (num_params != supp->num_params) { | ||
260 | /* | ||
261 | * Something is wrong, let supplicant restart. Next call to | ||
262 | * optee_supp_recv() will give an error to the requesting | ||
263 | * thread and release it. | ||
264 | */ | ||
265 | rc = -EINVAL; | ||
266 | goto out; | ||
267 | } | 355 | } |
268 | 356 | ||
269 | /* Update out and in/out parameters */ | 357 | /* Update out and in/out parameters */ |
270 | for (n = 0; n < num_params; n++) { | 358 | for (n = 0; n < req->num_params; n++) { |
271 | struct tee_param *p = supp->param + n; | 359 | struct tee_param *p = req->param + n; |
272 | 360 | ||
273 | switch (p->attr) { | 361 | switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { |
274 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: | 362 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: |
275 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: | 363 | case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: |
276 | p->u.value.a = param[n].u.value.a; | 364 | p->u.value.a = param[n + num_meta].u.value.a; |
277 | p->u.value.b = param[n].u.value.b; | 365 | p->u.value.b = param[n + num_meta].u.value.b; |
278 | p->u.value.c = param[n].u.value.c; | 366 | p->u.value.c = param[n + num_meta].u.value.c; |
279 | break; | 367 | break; |
280 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | 368 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: |
281 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | 369 | case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: |
282 | p->u.memref.size = param[n].u.memref.size; | 370 | p->u.memref.size = param[n + num_meta].u.memref.size; |
283 | break; | 371 | break; |
284 | default: | 372 | default: |
285 | break; | 373 | break; |
286 | } | 374 | } |
287 | } | 375 | } |
288 | supp->ret = ret; | 376 | req->ret = ret; |
289 | |||
290 | /* Allow optee_supp_recv() above to do its work */ | ||
291 | supp->supp_next_send = false; | ||
292 | 377 | ||
293 | /* Let the requesting thread continue */ | 378 | /* Let the requesting thread continue */ |
294 | complete(&supp->data_from_supp); | 379 | complete(&req->c); |
295 | out: | 380 | |
296 | mutex_unlock(&supp->supp_mutex); | 381 | return 0; |
297 | return rc; | ||
298 | } | 382 | } |