xref: /openbmc/linux/drivers/tee/optee/supp.c (revision b78412b8)
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 }
274