xref: /OK3568_Linux_fs/kernel/drivers/tee/optee/rpc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2015-2016, Linaro Limited
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun #include <linux/device.h>
10*4882a593Smuzhiyun #include <linux/i2c.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/tee_drv.h>
13*4882a593Smuzhiyun #include "optee_private.h"
14*4882a593Smuzhiyun #include "optee_smc.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun struct wq_entry {
17*4882a593Smuzhiyun 	struct list_head link;
18*4882a593Smuzhiyun 	struct completion c;
19*4882a593Smuzhiyun 	u32 key;
20*4882a593Smuzhiyun };
21*4882a593Smuzhiyun 
optee_wait_queue_init(struct optee_wait_queue * priv)22*4882a593Smuzhiyun void optee_wait_queue_init(struct optee_wait_queue *priv)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun 	mutex_init(&priv->mu);
25*4882a593Smuzhiyun 	INIT_LIST_HEAD(&priv->db);
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun 
optee_wait_queue_exit(struct optee_wait_queue * priv)28*4882a593Smuzhiyun void optee_wait_queue_exit(struct optee_wait_queue *priv)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun 	mutex_destroy(&priv->mu);
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
handle_rpc_func_cmd_get_time(struct optee_msg_arg * arg)33*4882a593Smuzhiyun static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	struct timespec64 ts;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	if (arg->num_params != 1)
38*4882a593Smuzhiyun 		goto bad;
39*4882a593Smuzhiyun 	if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
40*4882a593Smuzhiyun 			OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT)
41*4882a593Smuzhiyun 		goto bad;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	ktime_get_real_ts64(&ts);
44*4882a593Smuzhiyun 	arg->params[0].u.value.a = ts.tv_sec;
45*4882a593Smuzhiyun 	arg->params[0].u.value.b = ts.tv_nsec;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	arg->ret = TEEC_SUCCESS;
48*4882a593Smuzhiyun 	return;
49*4882a593Smuzhiyun bad:
50*4882a593Smuzhiyun 	arg->ret = TEEC_ERROR_BAD_PARAMETERS;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #if IS_REACHABLE(CONFIG_I2C)
handle_rpc_func_cmd_i2c_transfer(struct tee_context * ctx,struct optee_msg_arg * arg)54*4882a593Smuzhiyun static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
55*4882a593Smuzhiyun 					     struct optee_msg_arg *arg)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	struct tee_param *params;
58*4882a593Smuzhiyun 	struct i2c_adapter *adapter;
59*4882a593Smuzhiyun 	struct i2c_msg msg = { };
60*4882a593Smuzhiyun 	size_t i;
61*4882a593Smuzhiyun 	int ret = -EOPNOTSUPP;
62*4882a593Smuzhiyun 	u8 attr[] = {
63*4882a593Smuzhiyun 		TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
64*4882a593Smuzhiyun 		TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
65*4882a593Smuzhiyun 		TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
66*4882a593Smuzhiyun 		TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT,
67*4882a593Smuzhiyun 	};
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	if (arg->num_params != ARRAY_SIZE(attr)) {
70*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
71*4882a593Smuzhiyun 		return;
72*4882a593Smuzhiyun 	}
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
75*4882a593Smuzhiyun 			       GFP_KERNEL);
76*4882a593Smuzhiyun 	if (!params) {
77*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
78*4882a593Smuzhiyun 		return;
79*4882a593Smuzhiyun 	}
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	if (optee_from_msg_param(params, arg->num_params, arg->params))
82*4882a593Smuzhiyun 		goto bad;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	for (i = 0; i < arg->num_params; i++) {
85*4882a593Smuzhiyun 		if (params[i].attr != attr[i])
86*4882a593Smuzhiyun 			goto bad;
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	adapter = i2c_get_adapter(params[0].u.value.b);
90*4882a593Smuzhiyun 	if (!adapter)
91*4882a593Smuzhiyun 		goto bad;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (params[1].u.value.a & OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT) {
94*4882a593Smuzhiyun 		if (!i2c_check_functionality(adapter,
95*4882a593Smuzhiyun 					     I2C_FUNC_10BIT_ADDR)) {
96*4882a593Smuzhiyun 			i2c_put_adapter(adapter);
97*4882a593Smuzhiyun 			goto bad;
98*4882a593Smuzhiyun 		}
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 		msg.flags = I2C_M_TEN;
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	msg.addr = params[0].u.value.c;
104*4882a593Smuzhiyun 	msg.buf  = params[2].u.memref.shm->kaddr;
105*4882a593Smuzhiyun 	msg.len  = params[2].u.memref.size;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	switch (params[0].u.value.a) {
108*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD:
109*4882a593Smuzhiyun 		msg.flags |= I2C_M_RD;
110*4882a593Smuzhiyun 		break;
111*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR:
112*4882a593Smuzhiyun 		break;
113*4882a593Smuzhiyun 	default:
114*4882a593Smuzhiyun 		i2c_put_adapter(adapter);
115*4882a593Smuzhiyun 		goto bad;
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	ret = i2c_transfer(adapter, &msg, 1);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (ret < 0) {
121*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_COMMUNICATION;
122*4882a593Smuzhiyun 	} else {
123*4882a593Smuzhiyun 		params[3].u.value.a = msg.len;
124*4882a593Smuzhiyun 		if (optee_to_msg_param(arg->params, arg->num_params, params))
125*4882a593Smuzhiyun 			arg->ret = TEEC_ERROR_BAD_PARAMETERS;
126*4882a593Smuzhiyun 		else
127*4882a593Smuzhiyun 			arg->ret = TEEC_SUCCESS;
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	i2c_put_adapter(adapter);
131*4882a593Smuzhiyun 	kfree(params);
132*4882a593Smuzhiyun 	return;
133*4882a593Smuzhiyun bad:
134*4882a593Smuzhiyun 	kfree(params);
135*4882a593Smuzhiyun 	arg->ret = TEEC_ERROR_BAD_PARAMETERS;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun #else
handle_rpc_func_cmd_i2c_transfer(struct tee_context * ctx,struct optee_msg_arg * arg)138*4882a593Smuzhiyun static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
139*4882a593Smuzhiyun 					     struct optee_msg_arg *arg)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	arg->ret = TEEC_ERROR_NOT_SUPPORTED;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun #endif
144*4882a593Smuzhiyun 
wq_entry_get(struct optee_wait_queue * wq,u32 key)145*4882a593Smuzhiyun static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	struct wq_entry *w;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	mutex_lock(&wq->mu);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	list_for_each_entry(w, &wq->db, link)
152*4882a593Smuzhiyun 		if (w->key == key)
153*4882a593Smuzhiyun 			goto out;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	w = kmalloc(sizeof(*w), GFP_KERNEL);
156*4882a593Smuzhiyun 	if (w) {
157*4882a593Smuzhiyun 		init_completion(&w->c);
158*4882a593Smuzhiyun 		w->key = key;
159*4882a593Smuzhiyun 		list_add_tail(&w->link, &wq->db);
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun out:
162*4882a593Smuzhiyun 	mutex_unlock(&wq->mu);
163*4882a593Smuzhiyun 	return w;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
wq_sleep(struct optee_wait_queue * wq,u32 key)166*4882a593Smuzhiyun static void wq_sleep(struct optee_wait_queue *wq, u32 key)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	struct wq_entry *w = wq_entry_get(wq, key);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (w) {
171*4882a593Smuzhiyun 		wait_for_completion(&w->c);
172*4882a593Smuzhiyun 		mutex_lock(&wq->mu);
173*4882a593Smuzhiyun 		list_del(&w->link);
174*4882a593Smuzhiyun 		mutex_unlock(&wq->mu);
175*4882a593Smuzhiyun 		kfree(w);
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
wq_wakeup(struct optee_wait_queue * wq,u32 key)179*4882a593Smuzhiyun static void wq_wakeup(struct optee_wait_queue *wq, u32 key)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	struct wq_entry *w = wq_entry_get(wq, key);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	if (w)
184*4882a593Smuzhiyun 		complete(&w->c);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
handle_rpc_func_cmd_wq(struct optee * optee,struct optee_msg_arg * arg)187*4882a593Smuzhiyun static void handle_rpc_func_cmd_wq(struct optee *optee,
188*4882a593Smuzhiyun 				   struct optee_msg_arg *arg)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	if (arg->num_params != 1)
191*4882a593Smuzhiyun 		goto bad;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
194*4882a593Smuzhiyun 			OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
195*4882a593Smuzhiyun 		goto bad;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	switch (arg->params[0].u.value.a) {
198*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP:
199*4882a593Smuzhiyun 		wq_sleep(&optee->wait_queue, arg->params[0].u.value.b);
200*4882a593Smuzhiyun 		break;
201*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP:
202*4882a593Smuzhiyun 		wq_wakeup(&optee->wait_queue, arg->params[0].u.value.b);
203*4882a593Smuzhiyun 		break;
204*4882a593Smuzhiyun 	default:
205*4882a593Smuzhiyun 		goto bad;
206*4882a593Smuzhiyun 	}
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	arg->ret = TEEC_SUCCESS;
209*4882a593Smuzhiyun 	return;
210*4882a593Smuzhiyun bad:
211*4882a593Smuzhiyun 	arg->ret = TEEC_ERROR_BAD_PARAMETERS;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
handle_rpc_func_cmd_wait(struct optee_msg_arg * arg)214*4882a593Smuzhiyun static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	u32 msec_to_wait;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	if (arg->num_params != 1)
219*4882a593Smuzhiyun 		goto bad;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
222*4882a593Smuzhiyun 			OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
223*4882a593Smuzhiyun 		goto bad;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	msec_to_wait = arg->params[0].u.value.a;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	/* Go to interruptible sleep */
228*4882a593Smuzhiyun 	msleep_interruptible(msec_to_wait);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	arg->ret = TEEC_SUCCESS;
231*4882a593Smuzhiyun 	return;
232*4882a593Smuzhiyun bad:
233*4882a593Smuzhiyun 	arg->ret = TEEC_ERROR_BAD_PARAMETERS;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
handle_rpc_supp_cmd(struct tee_context * ctx,struct optee_msg_arg * arg)236*4882a593Smuzhiyun static void handle_rpc_supp_cmd(struct tee_context *ctx,
237*4882a593Smuzhiyun 				struct optee_msg_arg *arg)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	struct tee_param *params;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	arg->ret_origin = TEEC_ORIGIN_COMMS;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
244*4882a593Smuzhiyun 			       GFP_KERNEL);
245*4882a593Smuzhiyun 	if (!params) {
246*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
247*4882a593Smuzhiyun 		return;
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	if (optee_from_msg_param(params, arg->num_params, arg->params)) {
251*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
252*4882a593Smuzhiyun 		goto out;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	arg->ret = optee_supp_thrd_req(ctx, arg->cmd, arg->num_params, params);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	if (optee_to_msg_param(arg->params, arg->num_params, params))
258*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
259*4882a593Smuzhiyun out:
260*4882a593Smuzhiyun 	kfree(params);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
cmd_alloc_suppl(struct tee_context * ctx,size_t sz)263*4882a593Smuzhiyun static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	u32 ret;
266*4882a593Smuzhiyun 	struct tee_param param;
267*4882a593Smuzhiyun 	struct optee *optee = tee_get_drvdata(ctx->teedev);
268*4882a593Smuzhiyun 	struct tee_shm *shm;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
271*4882a593Smuzhiyun 	param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
272*4882a593Smuzhiyun 	param.u.value.b = sz;
273*4882a593Smuzhiyun 	param.u.value.c = 0;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	ret = optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_ALLOC, 1, &param);
276*4882a593Smuzhiyun 	if (ret)
277*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	mutex_lock(&optee->supp.mutex);
280*4882a593Smuzhiyun 	/* Increases count as secure world doesn't have a reference */
281*4882a593Smuzhiyun 	shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c);
282*4882a593Smuzhiyun 	mutex_unlock(&optee->supp.mutex);
283*4882a593Smuzhiyun 	return shm;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun 
handle_rpc_func_cmd_shm_alloc(struct tee_context * ctx,struct optee * optee,struct optee_msg_arg * arg,struct optee_call_ctx * call_ctx)286*4882a593Smuzhiyun static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
287*4882a593Smuzhiyun 					  struct optee *optee,
288*4882a593Smuzhiyun 					  struct optee_msg_arg *arg,
289*4882a593Smuzhiyun 					  struct optee_call_ctx *call_ctx)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	phys_addr_t pa;
292*4882a593Smuzhiyun 	struct tee_shm *shm;
293*4882a593Smuzhiyun 	size_t sz;
294*4882a593Smuzhiyun 	size_t n;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	arg->ret_origin = TEEC_ORIGIN_COMMS;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (!arg->num_params ||
299*4882a593Smuzhiyun 	    arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
300*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
301*4882a593Smuzhiyun 		return;
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	for (n = 1; n < arg->num_params; n++) {
305*4882a593Smuzhiyun 		if (arg->params[n].attr != OPTEE_MSG_ATTR_TYPE_NONE) {
306*4882a593Smuzhiyun 			arg->ret = TEEC_ERROR_BAD_PARAMETERS;
307*4882a593Smuzhiyun 			return;
308*4882a593Smuzhiyun 		}
309*4882a593Smuzhiyun 	}
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	sz = arg->params[0].u.value.b;
312*4882a593Smuzhiyun 	switch (arg->params[0].u.value.a) {
313*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_SHM_TYPE_APPL:
314*4882a593Smuzhiyun 		shm = cmd_alloc_suppl(ctx, sz);
315*4882a593Smuzhiyun 		break;
316*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
317*4882a593Smuzhiyun 		shm = tee_shm_alloc(optee->ctx, sz,
318*4882a593Smuzhiyun 				    TEE_SHM_MAPPED | TEE_SHM_PRIV);
319*4882a593Smuzhiyun 		break;
320*4882a593Smuzhiyun 	default:
321*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
322*4882a593Smuzhiyun 		return;
323*4882a593Smuzhiyun 	}
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (IS_ERR(shm)) {
326*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
327*4882a593Smuzhiyun 		return;
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (tee_shm_get_pa(shm, 0, &pa)) {
331*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
332*4882a593Smuzhiyun 		goto bad;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	sz = tee_shm_get_size(shm);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	if (tee_shm_is_registered(shm)) {
338*4882a593Smuzhiyun 		struct page **pages;
339*4882a593Smuzhiyun 		u64 *pages_list;
340*4882a593Smuzhiyun 		size_t page_num;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 		pages = tee_shm_get_pages(shm, &page_num);
343*4882a593Smuzhiyun 		if (!pages || !page_num) {
344*4882a593Smuzhiyun 			arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
345*4882a593Smuzhiyun 			goto bad;
346*4882a593Smuzhiyun 		}
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 		pages_list = optee_allocate_pages_list(page_num);
349*4882a593Smuzhiyun 		if (!pages_list) {
350*4882a593Smuzhiyun 			arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
351*4882a593Smuzhiyun 			goto bad;
352*4882a593Smuzhiyun 		}
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 		call_ctx->pages_list = pages_list;
355*4882a593Smuzhiyun 		call_ctx->num_entries = page_num;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 		arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
358*4882a593Smuzhiyun 				      OPTEE_MSG_ATTR_NONCONTIG;
359*4882a593Smuzhiyun 		/*
360*4882a593Smuzhiyun 		 * In the least bits of u.tmem.buf_ptr we store buffer offset
361*4882a593Smuzhiyun 		 * from 4k page, as described in OP-TEE ABI.
362*4882a593Smuzhiyun 		 */
363*4882a593Smuzhiyun 		arg->params[0].u.tmem.buf_ptr = virt_to_phys(pages_list) |
364*4882a593Smuzhiyun 			(tee_shm_get_page_offset(shm) &
365*4882a593Smuzhiyun 			 (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
366*4882a593Smuzhiyun 		arg->params[0].u.tmem.size = tee_shm_get_size(shm);
367*4882a593Smuzhiyun 		arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 		optee_fill_pages_list(pages_list, pages, page_num,
370*4882a593Smuzhiyun 				      tee_shm_get_page_offset(shm));
371*4882a593Smuzhiyun 	} else {
372*4882a593Smuzhiyun 		arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
373*4882a593Smuzhiyun 		arg->params[0].u.tmem.buf_ptr = pa;
374*4882a593Smuzhiyun 		arg->params[0].u.tmem.size = sz;
375*4882a593Smuzhiyun 		arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	arg->ret = TEEC_SUCCESS;
379*4882a593Smuzhiyun 	return;
380*4882a593Smuzhiyun bad:
381*4882a593Smuzhiyun 	tee_shm_free(shm);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun 
cmd_free_suppl(struct tee_context * ctx,struct tee_shm * shm)384*4882a593Smuzhiyun static void cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	struct tee_param param;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
389*4882a593Smuzhiyun 	param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
390*4882a593Smuzhiyun 	param.u.value.b = tee_shm_get_id(shm);
391*4882a593Smuzhiyun 	param.u.value.c = 0;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	/*
394*4882a593Smuzhiyun 	 * Match the tee_shm_get_from_id() in cmd_alloc_suppl() as secure
395*4882a593Smuzhiyun 	 * world has released its reference.
396*4882a593Smuzhiyun 	 *
397*4882a593Smuzhiyun 	 * It's better to do this before sending the request to supplicant
398*4882a593Smuzhiyun 	 * as we'd like to let the process doing the initial allocation to
399*4882a593Smuzhiyun 	 * do release the last reference too in order to avoid stacking
400*4882a593Smuzhiyun 	 * many pending fput() on the client process. This could otherwise
401*4882a593Smuzhiyun 	 * happen if secure world does many allocate and free in a single
402*4882a593Smuzhiyun 	 * invoke.
403*4882a593Smuzhiyun 	 */
404*4882a593Smuzhiyun 	tee_shm_put(shm);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_FREE, 1, &param);
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
handle_rpc_func_cmd_shm_free(struct tee_context * ctx,struct optee_msg_arg * arg)409*4882a593Smuzhiyun static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
410*4882a593Smuzhiyun 					 struct optee_msg_arg *arg)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	struct tee_shm *shm;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	arg->ret_origin = TEEC_ORIGIN_COMMS;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	if (arg->num_params != 1 ||
417*4882a593Smuzhiyun 	    arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
418*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
419*4882a593Smuzhiyun 		return;
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	shm = (struct tee_shm *)(unsigned long)arg->params[0].u.value.b;
423*4882a593Smuzhiyun 	switch (arg->params[0].u.value.a) {
424*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_SHM_TYPE_APPL:
425*4882a593Smuzhiyun 		cmd_free_suppl(ctx, shm);
426*4882a593Smuzhiyun 		break;
427*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
428*4882a593Smuzhiyun 		tee_shm_free(shm);
429*4882a593Smuzhiyun 		break;
430*4882a593Smuzhiyun 	default:
431*4882a593Smuzhiyun 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun 	arg->ret = TEEC_SUCCESS;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
free_pages_list(struct optee_call_ctx * call_ctx)436*4882a593Smuzhiyun static void free_pages_list(struct optee_call_ctx *call_ctx)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	if (call_ctx->pages_list) {
439*4882a593Smuzhiyun 		optee_free_pages_list(call_ctx->pages_list,
440*4882a593Smuzhiyun 				      call_ctx->num_entries);
441*4882a593Smuzhiyun 		call_ctx->pages_list = NULL;
442*4882a593Smuzhiyun 		call_ctx->num_entries = 0;
443*4882a593Smuzhiyun 	}
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
optee_rpc_finalize_call(struct optee_call_ctx * call_ctx)446*4882a593Smuzhiyun void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun 	free_pages_list(call_ctx);
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
handle_rpc_func_cmd(struct tee_context * ctx,struct optee * optee,struct tee_shm * shm,struct optee_call_ctx * call_ctx)451*4882a593Smuzhiyun static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
452*4882a593Smuzhiyun 				struct tee_shm *shm,
453*4882a593Smuzhiyun 				struct optee_call_ctx *call_ctx)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun 	struct optee_msg_arg *arg;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	arg = tee_shm_get_va(shm, 0);
458*4882a593Smuzhiyun 	if (IS_ERR(arg)) {
459*4882a593Smuzhiyun 		pr_err("%s: tee_shm_get_va %p failed\n", __func__, shm);
460*4882a593Smuzhiyun 		return;
461*4882a593Smuzhiyun 	}
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	switch (arg->cmd) {
464*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_CMD_GET_TIME:
465*4882a593Smuzhiyun 		handle_rpc_func_cmd_get_time(arg);
466*4882a593Smuzhiyun 		break;
467*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_CMD_WAIT_QUEUE:
468*4882a593Smuzhiyun 		handle_rpc_func_cmd_wq(optee, arg);
469*4882a593Smuzhiyun 		break;
470*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_CMD_SUSPEND:
471*4882a593Smuzhiyun 		handle_rpc_func_cmd_wait(arg);
472*4882a593Smuzhiyun 		break;
473*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_CMD_SHM_ALLOC:
474*4882a593Smuzhiyun 		free_pages_list(call_ctx);
475*4882a593Smuzhiyun 		handle_rpc_func_cmd_shm_alloc(ctx, optee, arg, call_ctx);
476*4882a593Smuzhiyun 		break;
477*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_CMD_SHM_FREE:
478*4882a593Smuzhiyun 		handle_rpc_func_cmd_shm_free(ctx, arg);
479*4882a593Smuzhiyun 		break;
480*4882a593Smuzhiyun 	case OPTEE_MSG_RPC_CMD_I2C_TRANSFER:
481*4882a593Smuzhiyun 		handle_rpc_func_cmd_i2c_transfer(ctx, arg);
482*4882a593Smuzhiyun 		break;
483*4882a593Smuzhiyun 	default:
484*4882a593Smuzhiyun 		handle_rpc_supp_cmd(ctx, arg);
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun /**
489*4882a593Smuzhiyun  * optee_handle_rpc() - handle RPC from secure world
490*4882a593Smuzhiyun  * @ctx:	context doing the RPC
491*4882a593Smuzhiyun  * @param:	value of registers for the RPC
492*4882a593Smuzhiyun  * @call_ctx:	call context. Preserved during one OP-TEE invocation
493*4882a593Smuzhiyun  *
494*4882a593Smuzhiyun  * Result of RPC is written back into @param.
495*4882a593Smuzhiyun  */
optee_handle_rpc(struct tee_context * ctx,struct optee_rpc_param * param,struct optee_call_ctx * call_ctx)496*4882a593Smuzhiyun void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param,
497*4882a593Smuzhiyun 		      struct optee_call_ctx *call_ctx)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun 	struct tee_device *teedev = ctx->teedev;
500*4882a593Smuzhiyun 	struct optee *optee = tee_get_drvdata(teedev);
501*4882a593Smuzhiyun 	struct tee_shm *shm;
502*4882a593Smuzhiyun 	phys_addr_t pa;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
505*4882a593Smuzhiyun 	case OPTEE_SMC_RPC_FUNC_ALLOC:
506*4882a593Smuzhiyun 		shm = tee_shm_alloc(optee->ctx, param->a1,
507*4882a593Smuzhiyun 				    TEE_SHM_MAPPED | TEE_SHM_PRIV);
508*4882a593Smuzhiyun 		if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
509*4882a593Smuzhiyun 			reg_pair_from_64(&param->a1, &param->a2, pa);
510*4882a593Smuzhiyun 			reg_pair_from_64(&param->a4, &param->a5,
511*4882a593Smuzhiyun 					 (unsigned long)shm);
512*4882a593Smuzhiyun 		} else {
513*4882a593Smuzhiyun 			param->a1 = 0;
514*4882a593Smuzhiyun 			param->a2 = 0;
515*4882a593Smuzhiyun 			param->a4 = 0;
516*4882a593Smuzhiyun 			param->a5 = 0;
517*4882a593Smuzhiyun 		}
518*4882a593Smuzhiyun 		break;
519*4882a593Smuzhiyun 	case OPTEE_SMC_RPC_FUNC_FREE:
520*4882a593Smuzhiyun 		shm = reg_pair_to_ptr(param->a1, param->a2);
521*4882a593Smuzhiyun 		tee_shm_free(shm);
522*4882a593Smuzhiyun 		break;
523*4882a593Smuzhiyun 	case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
524*4882a593Smuzhiyun 		/*
525*4882a593Smuzhiyun 		 * A foreign interrupt was raised while secure world was
526*4882a593Smuzhiyun 		 * executing, since they are handled in Linux a dummy RPC is
527*4882a593Smuzhiyun 		 * performed to let Linux take the interrupt through the normal
528*4882a593Smuzhiyun 		 * vector.
529*4882a593Smuzhiyun 		 */
530*4882a593Smuzhiyun 		break;
531*4882a593Smuzhiyun 	case OPTEE_SMC_RPC_FUNC_CMD:
532*4882a593Smuzhiyun 		shm = reg_pair_to_ptr(param->a1, param->a2);
533*4882a593Smuzhiyun 		handle_rpc_func_cmd(ctx, optee, shm, call_ctx);
534*4882a593Smuzhiyun 		break;
535*4882a593Smuzhiyun 	default:
536*4882a593Smuzhiyun 		pr_warn("Unknown RPC func 0x%x\n",
537*4882a593Smuzhiyun 			(u32)OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0));
538*4882a593Smuzhiyun 		break;
539*4882a593Smuzhiyun 	}
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
542*4882a593Smuzhiyun }
543