1
2
3
4
5
6
7
8
9
10
11
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
38
39
40
41
42
43
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
55
56
57 while (mutex_lock_interruptible(&supp->thrd_mutex)) {
58
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
68
69
70
71
72
73
74 supp->func = func;
75 supp->num_params = num_params;
76 supp->param = param;
77 supp->req_posted = true;
78
79
80 complete(&supp->data_to_supp);
81
82
83
84
85
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
93
94
95
96
97
98
99
100
101
102
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
117 mutex_unlock(&supp->thrd_mutex);
118
119 return ret;
120}
121
122
123
124
125
126
127
128
129
130
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
142
143
144
145 mutex_lock(&supp->supp_mutex);
146
147 if (supp->supp_next_send) {
148
149
150
151
152
153
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
164
165
166
167 if (wait_for_completion_interruptible(&supp->data_to_supp)) {
168 rc = -ERESTARTSYS;
169 goto out;
170 }
171
172
173
174 if (*num_params < supp->num_params) {
175
176
177
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
191 supp->supp_next_send = true;
192
193 rc = 0;
194out:
195 mutex_unlock(&supp->supp_mutex);
196 return rc;
197}
198
199
200
201
202
203
204
205
206
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
219
220
221
222
223 mutex_lock(&supp->supp_mutex);
224
225 if (!supp->supp_next_send) {
226
227
228
229
230 rc = -ENOENT;
231 goto out;
232 }
233
234 if (num_params != supp->num_params) {
235
236
237
238
239
240 rc = -EINVAL;
241 goto out;
242 }
243
244
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
266 supp->supp_next_send = false;
267
268
269 complete(&supp->data_from_supp);
270out:
271 mutex_unlock(&supp->supp_mutex);
272 return rc;
273}
274