GNU Linux-libre 4.14.266-gnu1
[releases.git] / drivers / tee / optee / supp.c
1 /*
2  * Copyright (c) 2015, Linaro Limited
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14 #include <linux/device.h>
15 #include <linux/slab.h>
16 #include <linux/uaccess.h>
17 #include "optee_private.h"
18
19 void optee_supp_init(struct optee_supp *supp)
20 {
21         memset(supp, 0, sizeof(*supp));
22         mutex_init(&supp->ctx_mutex);
23         mutex_init(&supp->thrd_mutex);
24         mutex_init(&supp->supp_mutex);
25         init_completion(&supp->data_to_supp);
26         init_completion(&supp->data_from_supp);
27 }
28
29 void optee_supp_uninit(struct optee_supp *supp)
30 {
31         mutex_destroy(&supp->ctx_mutex);
32         mutex_destroy(&supp->thrd_mutex);
33         mutex_destroy(&supp->supp_mutex);
34 }
35
36 /**
37  * optee_supp_thrd_req() - request service from supplicant
38  * @ctx:        context doing the request
39  * @func:       function requested
40  * @num_params: number of elements in @param array
41  * @param:      parameters for function
42  *
43  * Returns result of operation to be passed to secure world
44  */
45 u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
46                         struct tee_param *param)
47 {
48         bool interruptable;
49         struct optee *optee = tee_get_drvdata(ctx->teedev);
50         struct optee_supp *supp = &optee->supp;
51         u32 ret;
52
53         /*
54          * Other threads blocks here until we've copied our answer from
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
66         /*
67          * We have exclusive access now since the supplicant at this
68          * point is either doing a
69          * wait_for_completion_interruptible(&supp->data_to_supp) or is in
70          * userspace still about to do the ioctl() to enter
71          * optee_supp_recv() below.
72          */
73
74         supp->func = func;
75         supp->num_params = num_params;
76         supp->param = param;
77         supp->req_posted = true;
78
79         /* Let supplicant get the data */
80         complete(&supp->data_to_supp);
81
82         /*
83          * Wait for supplicant to process and return result, once we've
84          * returned from wait_for_completion(data_from_supp) we have
85          * exclusive access again.
86          */
87         while (wait_for_completion_interruptible(&supp->data_from_supp)) {
88                 mutex_lock(&supp->ctx_mutex);
89                 interruptable = !supp->ctx;
90                 if (interruptable) {
91                         /*
92                          * There's no supplicant available and since the
93                          * supp->ctx_mutex currently is held none can
94                          * become available until the mutex released
95                          * again.
96                          *
97                          * Interrupting an RPC to supplicant is only
98                          * allowed as a way of slightly improving the user
99                          * experience in case the supplicant hasn't been
100                          * started yet. During normal operation the supplicant
101                          * will serve all requests in a timely manner and
102                          * interrupting then wouldn't make sense.
103                          */
104                         supp->ret = TEEC_ERROR_COMMUNICATION;
105                         init_completion(&supp->data_to_supp);
106                 }
107                 mutex_unlock(&supp->ctx_mutex);
108                 if (interruptable)
109                         break;
110         }
111
112         ret = supp->ret;
113         supp->param = NULL;
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
119         return ret;
120 }
121
122 /**
123  * optee_supp_recv() - receive request for supplicant
124  * @ctx:        context receiving the request
125  * @func:       requested function in supplicant
126  * @num_params: number of elements allocated in @param, updated with number
127  *              used elements
128  * @param:      space for parameters for @func
129  *
130  * Returns 0 on success or <0 on failure
131  */
132 int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
133                     struct tee_param *param)
134 {
135         struct tee_device *teedev = ctx->teedev;
136         struct optee *optee = tee_get_drvdata(teedev);
137         struct optee_supp *supp = &optee->supp;
138         int rc;
139
140         /*
141          * In case two threads in one supplicant is calling this function
142          * simultaneously we need to protect the data with a mutex which
143          * we'll release before returning.
144          */
145         mutex_lock(&supp->supp_mutex);
146
147         if (supp->supp_next_send) {
148                 /*
149                  * optee_supp_recv() has been called again without
150                  * a optee_supp_send() in between. Supplicant has
151                  * probably been restarted before it was able to
152                  * write back last result. Abort last request and
153                  * wait for a new.
154                  */
155                 if (supp->req_posted) {
156                         supp->ret = TEEC_ERROR_COMMUNICATION;
157                         supp->supp_next_send = false;
158                         complete(&supp->data_from_supp);
159                 }
160         }
161
162         /*
163          * This is where supplicant will be hanging most of the
164          * time, let's make this interruptable so we can easily
165          * restart supplicant if needed.
166          */
167         if (wait_for_completion_interruptible(&supp->data_to_supp)) {
168                 rc = -ERESTARTSYS;
169                 goto out;
170         }
171
172         /* We have exlusive access to the data */
173
174         if (*num_params < supp->num_params) {
175                 /*
176                  * Not enough room for parameters, tell supplicant
177                  * it failed and abort last request.
178                  */
179                 supp->ret = TEEC_ERROR_COMMUNICATION;
180                 rc = -EINVAL;
181                 complete(&supp->data_from_supp);
182                 goto out;
183         }
184
185         *func = supp->func;
186         *num_params = supp->num_params;
187         memcpy(param, supp->param,
188                sizeof(struct tee_param) * supp->num_params);
189
190         /* Allow optee_supp_send() below to do its work */
191         supp->supp_next_send = true;
192
193         rc = 0;
194 out:
195         mutex_unlock(&supp->supp_mutex);
196         return rc;
197 }
198
199 /**
200  * optee_supp_send() - send result of request from supplicant
201  * @ctx:        context sending result
202  * @ret:        return value of request
203  * @num_params: number of parameters returned
204  * @param:      returned parameters
205  *
206  * Returns 0 on success or <0 on failure.
207  */
208 int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
209                     struct tee_param *param)
210 {
211         struct tee_device *teedev = ctx->teedev;
212         struct optee *optee = tee_get_drvdata(teedev);
213         struct optee_supp *supp = &optee->supp;
214         size_t n;
215         int rc = 0;
216
217         /*
218          * We still have exclusive access to the data since that's how we
219          * left it when returning from optee_supp_read().
220          */
221
222         /* See comment on mutex in optee_supp_read() above */
223         mutex_lock(&supp->supp_mutex);
224
225         if (!supp->supp_next_send) {
226                 /*
227                  * Something strange is going on, supplicant shouldn't
228                  * enter optee_supp_send() in this state
229                  */
230                 rc = -ENOENT;
231                 goto out;
232         }
233
234         if (num_params != supp->num_params) {
235                 /*
236                  * Something is wrong, let supplicant restart. Next call to
237                  * optee_supp_recv() will give an error to the requesting
238                  * thread and release it.
239                  */
240                 rc = -EINVAL;
241                 goto out;
242         }
243
244         /* Update out and in/out parameters */
245         for (n = 0; n < num_params; n++) {
246                 struct tee_param *p = supp->param + n;
247
248                 switch (p->attr) {
249                 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
250                 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
251                         p->u.value.a = param[n].u.value.a;
252                         p->u.value.b = param[n].u.value.b;
253                         p->u.value.c = param[n].u.value.c;
254                         break;
255                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
256                 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
257                         p->u.memref.size = param[n].u.memref.size;
258                         break;
259                 default:
260                         break;
261                 }
262         }
263         supp->ret = ret;
264
265         /* Allow optee_supp_recv() above to do its work */
266         supp->supp_next_send = false;
267
268         /* Let the requesting thread continue */
269         complete(&supp->data_from_supp);
270 out:
271         mutex_unlock(&supp->supp_mutex);
272         return rc;
273 }