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, ¶m);
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, ¶m);
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(¶m->a1, ¶m->a2, pa);
510*4882a593Smuzhiyun reg_pair_from_64(¶m->a4, ¶m->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