blob: b4ea0678a43627706ce00bc468eaf6c2b83a4403 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
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
19void 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
29void 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 */
45u32 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 */
132int 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;
194out:
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 */
208int 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);
270out:
271 mutex_unlock(&supp->supp_mutex);
272 return rc;
273}