Merge remote-tracking branch 'torvalds/master' into perf/urgent
[linux-2.6-microblaze.git] / drivers / tee / optee / supp.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  */
5 #include <linux/device.h>
6 #include <linux/slab.h>
7 #include <linux/uaccess.h>
8 #include "optee_private.h"
9
10 struct optee_supp_req {
11         struct list_head link;
12
13         bool in_queue;
14         u32 func;
15         u32 ret;
16         size_t num_params;
17         struct tee_param *param;
18
19         struct completion c;
20 };
21
22 void optee_supp_init(struct optee_supp *supp)
23 {
24         memset(supp, 0, sizeof(*supp));
25         mutex_init(&supp->mutex);
26         init_completion(&supp->reqs_c);
27         idr_init(&supp->idr);
28         INIT_LIST_HEAD(&supp->reqs);
29         supp->req_id = -1;
30 }
31
32 void optee_supp_uninit(struct optee_supp *supp)
33 {
34         mutex_destroy(&supp->mutex);
35         idr_destroy(&supp->idr);
36 }
37
38 void optee_supp_release(struct optee_supp *supp)
39 {
40         int id;
41         struct optee_supp_req *req;
42         struct optee_supp_req *req_tmp;
43
44         mutex_lock(&supp->mutex);
45
46         /* Abort all request retrieved by supplicant */
47         idr_for_each_entry(&supp->idr, req, id) {
48                 idr_remove(&supp->idr, id);
49                 req->ret = TEEC_ERROR_COMMUNICATION;
50                 complete(&req->c);
51         }
52
53         /* Abort all queued requests */
54         list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) {
55                 list_del(&req->link);
56                 req->in_queue = false;
57                 req->ret = TEEC_ERROR_COMMUNICATION;
58                 complete(&req->c);
59         }
60
61         supp->ctx = NULL;
62         supp->req_id = -1;
63
64         mutex_unlock(&supp->mutex);
65 }
66
67 /**
68  * optee_supp_thrd_req() - request service from supplicant
69  * @ctx:        context doing the request
70  * @func:       function requested
71  * @num_params: number of elements in @param array
72  * @param:      parameters for function
73  *
74  * Returns result of operation to be passed to secure world
75  */
76 u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
77                         struct tee_param *param)
78
79 {
80         struct optee *optee = tee_get_drvdata(ctx->teedev);
81         struct optee_supp *supp = &optee->supp;
82         struct optee_supp_req *req;
83         bool interruptable;
84         u32 ret;
85
86         /*
87          * Return in case there is no supplicant available and
88          * non-blocking request.
89          */
90         if (!supp->ctx && ctx->supp_nowait)
91                 return TEEC_ERROR_COMMUNICATION;
92
93         req = kzalloc(sizeof(*req), GFP_KERNEL);
94         if (!req)
95                 return TEEC_ERROR_OUT_OF_MEMORY;
96
97         init_completion(&req->c);
98         req->func = func;
99         req->num_params = num_params;
100         req->param = param;
101
102         /* Insert the request in the request list */
103         mutex_lock(&supp->mutex);
104         list_add_tail(&req->link, &supp->reqs);
105         req->in_queue = true;
106         mutex_unlock(&supp->mutex);
107
108         /* Tell an eventual waiter there's a new request */
109         complete(&supp->reqs_c);
110
111         /*
112          * Wait for supplicant to process and return result, once we've
113          * returned from wait_for_completion(&req->c) successfully we have
114          * exclusive access again.
115          */
116         while (wait_for_completion_interruptible(&req->c)) {
117                 mutex_lock(&supp->mutex);
118                 interruptable = !supp->ctx;
119                 if (interruptable) {
120                         /*
121                          * There's no supplicant available and since the
122                          * supp->mutex currently is held none can
123                          * become available until the mutex released
124                          * again.
125                          *
126                          * Interrupting an RPC to supplicant is only
127                          * allowed as a way of slightly improving the user
128                          * experience in case the supplicant hasn't been
129                          * started yet. During normal operation the supplicant
130                          * will serve all requests in a timely manner and
131                          * interrupting then wouldn't make sense.
132                          */
133                         if (req->in_queue) {
134                                 list_del(&req->link);
135                                 req->in_queue = false;
136                         }
137                 }
138                 mutex_unlock(&supp->mutex);
139
140                 if (interruptable) {
141                         req->ret = TEEC_ERROR_COMMUNICATION;
142                         break;
143                 }
144         }
145
146         ret = req->ret;
147         kfree(req);
148
149         return ret;
150 }
151
152 static struct optee_supp_req  *supp_pop_entry(struct optee_supp *supp,
153                                               int num_params, int *id)
154 {
155         struct optee_supp_req *req;
156
157         if (supp->req_id != -1) {
158                 /*
159                  * Supplicant should not mix synchronous and asnynchronous
160                  * requests.
161                  */
162                 return ERR_PTR(-EINVAL);
163         }
164
165         if (list_empty(&supp->reqs))
166                 return NULL;
167
168         req = list_first_entry(&supp->reqs, struct optee_supp_req, link);
169
170         if (num_params < req->num_params) {
171                 /* Not enough room for parameters */
172                 return ERR_PTR(-EINVAL);
173         }
174
175         *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
176         if (*id < 0)
177                 return ERR_PTR(-ENOMEM);
178
179         list_del(&req->link);
180         req->in_queue = false;
181
182         return req;
183 }
184
185 static int supp_check_recv_params(size_t num_params, struct tee_param *params,
186                                   size_t *num_meta)
187 {
188         size_t n;
189
190         if (!num_params)
191                 return -EINVAL;
192
193         /*
194          * If there's memrefs we need to decrease those as they where
195          * increased earlier and we'll even refuse to accept any below.
196          */
197         for (n = 0; n < num_params; n++)
198                 if (tee_param_is_memref(params + n) && params[n].u.memref.shm)
199                         tee_shm_put(params[n].u.memref.shm);
200
201         /*
202          * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE with
203          * or without the TEE_IOCTL_PARAM_ATTR_META bit set.
204          */
205         for (n = 0; n < num_params; n++)
206                 if (params[n].attr &&
207                     params[n].attr != TEE_IOCTL_PARAM_ATTR_META)
208                         return -EINVAL;
209
210         /* At most we'll need one meta parameter so no need to check for more */
211         if (params->attr == TEE_IOCTL_PARAM_ATTR_META)
212                 *num_meta = 1;
213         else
214                 *num_meta = 0;
215
216         return 0;
217 }
218
219 /**
220  * optee_supp_recv() - receive request for supplicant
221  * @ctx:        context receiving the request
222  * @func:       requested function in supplicant
223  * @num_params: number of elements allocated in @param, updated with number
224  *              used elements
225  * @param:      space for parameters for @func
226  *
227  * Returns 0 on success or <0 on failure
228  */
229 int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
230                     struct tee_param *param)
231 {
232         struct tee_device *teedev = ctx->teedev;
233         struct optee *optee = tee_get_drvdata(teedev);
234         struct optee_supp *supp = &optee->supp;
235         struct optee_supp_req *req = NULL;
236         int id;
237         size_t num_meta;
238         int rc;
239
240         rc = supp_check_recv_params(*num_params, param, &num_meta);
241         if (rc)
242                 return rc;
243
244         while (true) {
245                 mutex_lock(&supp->mutex);
246                 req = supp_pop_entry(supp, *num_params - num_meta, &id);
247                 mutex_unlock(&supp->mutex);
248
249                 if (req) {
250                         if (IS_ERR(req))
251                                 return PTR_ERR(req);
252                         break;
253                 }
254
255                 /*
256                  * If we didn't get a request we'll block in
257                  * wait_for_completion() to avoid needless spinning.
258                  *
259                  * This is where supplicant will be hanging most of
260                  * the time, let's make this interruptable so we
261                  * can easily restart supplicant if needed.
262                  */
263                 if (wait_for_completion_interruptible(&supp->reqs_c))
264                         return -ERESTARTSYS;
265         }
266
267         if (num_meta) {
268                 /*
269                  * tee-supplicant support meta parameters -> requsts can be
270                  * processed asynchronously.
271                  */
272                 param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
273                               TEE_IOCTL_PARAM_ATTR_META;
274                 param->u.value.a = id;
275                 param->u.value.b = 0;
276                 param->u.value.c = 0;
277         } else {
278                 mutex_lock(&supp->mutex);
279                 supp->req_id = id;
280                 mutex_unlock(&supp->mutex);
281         }
282
283         *func = req->func;
284         *num_params = req->num_params + num_meta;
285         memcpy(param + num_meta, req->param,
286                sizeof(struct tee_param) * req->num_params);
287
288         return 0;
289 }
290
291 static struct optee_supp_req *supp_pop_req(struct optee_supp *supp,
292                                            size_t num_params,
293                                            struct tee_param *param,
294                                            size_t *num_meta)
295 {
296         struct optee_supp_req *req;
297         int id;
298         size_t nm;
299         const u32 attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
300                          TEE_IOCTL_PARAM_ATTR_META;
301
302         if (!num_params)
303                 return ERR_PTR(-EINVAL);
304
305         if (supp->req_id == -1) {
306                 if (param->attr != attr)
307                         return ERR_PTR(-EINVAL);
308                 id = param->u.value.a;
309                 nm = 1;
310         } else {
311                 id = supp->req_id;
312                 nm = 0;
313         }
314
315         req = idr_find(&supp->idr, id);
316         if (!req)
317                 return ERR_PTR(-ENOENT);
318
319         if ((num_params - nm) != req->num_params)
320                 return ERR_PTR(-EINVAL);
321
322         idr_remove(&supp->idr, id);
323         supp->req_id = -1;
324         *num_meta = nm;
325
326         return req;
327 }
328
329 /**
330  * optee_supp_send() - send result of request from supplicant
331  * @ctx:        context sending result
332  * @ret:        return value of request
333  * @num_params: number of parameters returned
334  * @param:      returned parameters
335  *
336  * Returns 0 on success or <0 on failure.
337  */
338 int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
339                     struct tee_param *param)
340 {
341         struct tee_device *teedev = ctx->teedev;
342         struct optee *optee = tee_get_drvdata(teedev);
343         struct optee_supp *supp = &optee->supp;
344         struct optee_supp_req *req;
345         size_t n;
346         size_t num_meta;
347
348         mutex_lock(&supp->mutex);
349         req = supp_pop_req(supp, num_params, param, &num_meta);
350         mutex_unlock(&supp->mutex);
351
352         if (IS_ERR(req)) {
353                 /* Something is wrong, let supplicant restart. */
354                 return PTR_ERR(req);
355         }
356
357         /* Update out and in/out parameters */
358         for (n = 0; n < req->num_params; n++) {
359                 struct tee_param *p = req->param + n;
360
361                 switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
362                 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
363                 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
364                         p->u.value.a = param[n + num_meta].u.value.a;
365                         p->u.value.b = param[n + num_meta].u.value.b;
366                         p->u.value.c = param[n + num_meta].u.value.c;
367                         break;
368                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
369                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
370                         p->u.memref.size = param[n + num_meta].u.memref.size;
371                         break;
372                 default:
373                         break;
374                 }
375         }
376         req->ret = ret;
377
378         /* Let the requesting thread continue */
379         complete(&req->c);
380
381         return 0;
382 }