1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2015, Linaro Limited
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/arm-smccc.h>
9*4882a593Smuzhiyun #include <linux/crash_dump.h>
10*4882a593Smuzhiyun #include <linux/errno.h>
11*4882a593Smuzhiyun #include <linux/io.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/of.h>
14*4882a593Smuzhiyun #include <linux/of_platform.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/string.h>
18*4882a593Smuzhiyun #include <linux/tee_drv.h>
19*4882a593Smuzhiyun #include <linux/types.h>
20*4882a593Smuzhiyun #include <linux/uaccess.h>
21*4882a593Smuzhiyun #include <linux/workqueue.h>
22*4882a593Smuzhiyun #include "optee_private.h"
23*4882a593Smuzhiyun #include "optee_smc.h"
24*4882a593Smuzhiyun #include "shm_pool.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define DRIVER_NAME "optee"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #define OPTEE_SHM_NUM_PRIV_PAGES CONFIG_OPTEE_SHM_NUM_PRIV_PAGES
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /**
31*4882a593Smuzhiyun * optee_from_msg_param() - convert from OPTEE_MSG parameters to
32*4882a593Smuzhiyun * struct tee_param
33*4882a593Smuzhiyun * @params: subsystem internal parameter representation
34*4882a593Smuzhiyun * @num_params: number of elements in the parameter arrays
35*4882a593Smuzhiyun * @msg_params: OPTEE_MSG parameters
36*4882a593Smuzhiyun * Returns 0 on success or <0 on failure
37*4882a593Smuzhiyun */
optee_from_msg_param(struct tee_param * params,size_t num_params,const struct optee_msg_param * msg_params)38*4882a593Smuzhiyun int optee_from_msg_param(struct tee_param *params, size_t num_params,
39*4882a593Smuzhiyun const struct optee_msg_param *msg_params)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun int rc;
42*4882a593Smuzhiyun size_t n;
43*4882a593Smuzhiyun struct tee_shm *shm;
44*4882a593Smuzhiyun phys_addr_t pa;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun for (n = 0; n < num_params; n++) {
47*4882a593Smuzhiyun struct tee_param *p = params + n;
48*4882a593Smuzhiyun const struct optee_msg_param *mp = msg_params + n;
49*4882a593Smuzhiyun u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun switch (attr) {
52*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_NONE:
53*4882a593Smuzhiyun p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
54*4882a593Smuzhiyun memset(&p->u, 0, sizeof(p->u));
55*4882a593Smuzhiyun break;
56*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
57*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
58*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
59*4882a593Smuzhiyun p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT +
60*4882a593Smuzhiyun attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
61*4882a593Smuzhiyun p->u.value.a = mp->u.value.a;
62*4882a593Smuzhiyun p->u.value.b = mp->u.value.b;
63*4882a593Smuzhiyun p->u.value.c = mp->u.value.c;
64*4882a593Smuzhiyun break;
65*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
66*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
67*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
68*4882a593Smuzhiyun p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
69*4882a593Smuzhiyun attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
70*4882a593Smuzhiyun p->u.memref.size = mp->u.tmem.size;
71*4882a593Smuzhiyun shm = (struct tee_shm *)(unsigned long)
72*4882a593Smuzhiyun mp->u.tmem.shm_ref;
73*4882a593Smuzhiyun if (!shm) {
74*4882a593Smuzhiyun p->u.memref.shm_offs = 0;
75*4882a593Smuzhiyun p->u.memref.shm = NULL;
76*4882a593Smuzhiyun break;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun rc = tee_shm_get_pa(shm, 0, &pa);
79*4882a593Smuzhiyun if (rc)
80*4882a593Smuzhiyun return rc;
81*4882a593Smuzhiyun p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
82*4882a593Smuzhiyun p->u.memref.shm = shm;
83*4882a593Smuzhiyun break;
84*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
85*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
86*4882a593Smuzhiyun case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
87*4882a593Smuzhiyun p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
88*4882a593Smuzhiyun attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
89*4882a593Smuzhiyun p->u.memref.size = mp->u.rmem.size;
90*4882a593Smuzhiyun shm = (struct tee_shm *)(unsigned long)
91*4882a593Smuzhiyun mp->u.rmem.shm_ref;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun if (!shm) {
94*4882a593Smuzhiyun p->u.memref.shm_offs = 0;
95*4882a593Smuzhiyun p->u.memref.shm = NULL;
96*4882a593Smuzhiyun break;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun p->u.memref.shm_offs = mp->u.rmem.offs;
99*4882a593Smuzhiyun p->u.memref.shm = shm;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun break;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun default:
104*4882a593Smuzhiyun return -EINVAL;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
to_msg_param_tmp_mem(struct optee_msg_param * mp,const struct tee_param * p)110*4882a593Smuzhiyun static int to_msg_param_tmp_mem(struct optee_msg_param *mp,
111*4882a593Smuzhiyun const struct tee_param *p)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun int rc;
114*4882a593Smuzhiyun phys_addr_t pa;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + p->attr -
117*4882a593Smuzhiyun TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm;
120*4882a593Smuzhiyun mp->u.tmem.size = p->u.memref.size;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (!p->u.memref.shm) {
123*4882a593Smuzhiyun mp->u.tmem.buf_ptr = 0;
124*4882a593Smuzhiyun return 0;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun rc = tee_shm_get_pa(p->u.memref.shm, p->u.memref.shm_offs, &pa);
128*4882a593Smuzhiyun if (rc)
129*4882a593Smuzhiyun return rc;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun mp->u.tmem.buf_ptr = pa;
132*4882a593Smuzhiyun mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED <<
133*4882a593Smuzhiyun OPTEE_MSG_ATTR_CACHE_SHIFT;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
to_msg_param_reg_mem(struct optee_msg_param * mp,const struct tee_param * p)138*4882a593Smuzhiyun static int to_msg_param_reg_mem(struct optee_msg_param *mp,
139*4882a593Smuzhiyun const struct tee_param *p)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun mp->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + p->attr -
142*4882a593Smuzhiyun TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun mp->u.rmem.shm_ref = (unsigned long)p->u.memref.shm;
145*4882a593Smuzhiyun mp->u.rmem.size = p->u.memref.size;
146*4882a593Smuzhiyun mp->u.rmem.offs = p->u.memref.shm_offs;
147*4882a593Smuzhiyun return 0;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /**
151*4882a593Smuzhiyun * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters
152*4882a593Smuzhiyun * @msg_params: OPTEE_MSG parameters
153*4882a593Smuzhiyun * @num_params: number of elements in the parameter arrays
154*4882a593Smuzhiyun * @params: subsystem itnernal parameter representation
155*4882a593Smuzhiyun * Returns 0 on success or <0 on failure
156*4882a593Smuzhiyun */
optee_to_msg_param(struct optee_msg_param * msg_params,size_t num_params,const struct tee_param * params)157*4882a593Smuzhiyun int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
158*4882a593Smuzhiyun const struct tee_param *params)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun int rc;
161*4882a593Smuzhiyun size_t n;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun for (n = 0; n < num_params; n++) {
164*4882a593Smuzhiyun const struct tee_param *p = params + n;
165*4882a593Smuzhiyun struct optee_msg_param *mp = msg_params + n;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun switch (p->attr) {
168*4882a593Smuzhiyun case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
169*4882a593Smuzhiyun mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
170*4882a593Smuzhiyun memset(&mp->u, 0, sizeof(mp->u));
171*4882a593Smuzhiyun break;
172*4882a593Smuzhiyun case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
173*4882a593Smuzhiyun case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
174*4882a593Smuzhiyun case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
175*4882a593Smuzhiyun mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr -
176*4882a593Smuzhiyun TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
177*4882a593Smuzhiyun mp->u.value.a = p->u.value.a;
178*4882a593Smuzhiyun mp->u.value.b = p->u.value.b;
179*4882a593Smuzhiyun mp->u.value.c = p->u.value.c;
180*4882a593Smuzhiyun break;
181*4882a593Smuzhiyun case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
182*4882a593Smuzhiyun case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
183*4882a593Smuzhiyun case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
184*4882a593Smuzhiyun if (tee_shm_is_registered(p->u.memref.shm))
185*4882a593Smuzhiyun rc = to_msg_param_reg_mem(mp, p);
186*4882a593Smuzhiyun else
187*4882a593Smuzhiyun rc = to_msg_param_tmp_mem(mp, p);
188*4882a593Smuzhiyun if (rc)
189*4882a593Smuzhiyun return rc;
190*4882a593Smuzhiyun break;
191*4882a593Smuzhiyun default:
192*4882a593Smuzhiyun return -EINVAL;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun return 0;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
optee_get_version(struct tee_device * teedev,struct tee_ioctl_version_data * vers)198*4882a593Smuzhiyun static void optee_get_version(struct tee_device *teedev,
199*4882a593Smuzhiyun struct tee_ioctl_version_data *vers)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun struct tee_ioctl_version_data v = {
202*4882a593Smuzhiyun .impl_id = TEE_IMPL_ID_OPTEE,
203*4882a593Smuzhiyun .impl_caps = TEE_OPTEE_CAP_TZ,
204*4882a593Smuzhiyun .gen_caps = TEE_GEN_CAP_GP,
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun struct optee *optee = tee_get_drvdata(teedev);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
209*4882a593Smuzhiyun v.gen_caps |= TEE_GEN_CAP_REG_MEM;
210*4882a593Smuzhiyun if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
211*4882a593Smuzhiyun v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL;
212*4882a593Smuzhiyun *vers = v;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
optee_bus_scan(struct work_struct * work)215*4882a593Smuzhiyun static void optee_bus_scan(struct work_struct *work)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
optee_open(struct tee_context * ctx)220*4882a593Smuzhiyun static int optee_open(struct tee_context *ctx)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun struct optee_context_data *ctxdata;
223*4882a593Smuzhiyun struct tee_device *teedev = ctx->teedev;
224*4882a593Smuzhiyun struct optee *optee = tee_get_drvdata(teedev);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
227*4882a593Smuzhiyun if (!ctxdata)
228*4882a593Smuzhiyun return -ENOMEM;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun if (teedev == optee->supp_teedev) {
231*4882a593Smuzhiyun bool busy = true;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun mutex_lock(&optee->supp.mutex);
234*4882a593Smuzhiyun if (!optee->supp.ctx) {
235*4882a593Smuzhiyun busy = false;
236*4882a593Smuzhiyun optee->supp.ctx = ctx;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun mutex_unlock(&optee->supp.mutex);
239*4882a593Smuzhiyun if (busy) {
240*4882a593Smuzhiyun kfree(ctxdata);
241*4882a593Smuzhiyun return -EBUSY;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (!optee->scan_bus_done) {
245*4882a593Smuzhiyun INIT_WORK(&optee->scan_bus_work, optee_bus_scan);
246*4882a593Smuzhiyun optee->scan_bus_wq = create_workqueue("optee_bus_scan");
247*4882a593Smuzhiyun if (!optee->scan_bus_wq) {
248*4882a593Smuzhiyun kfree(ctxdata);
249*4882a593Smuzhiyun return -ECHILD;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun queue_work(optee->scan_bus_wq, &optee->scan_bus_work);
252*4882a593Smuzhiyun optee->scan_bus_done = true;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun mutex_init(&ctxdata->mutex);
256*4882a593Smuzhiyun INIT_LIST_HEAD(&ctxdata->sess_list);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
259*4882a593Smuzhiyun ctx->cap_memref_null = true;
260*4882a593Smuzhiyun else
261*4882a593Smuzhiyun ctx->cap_memref_null = false;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun ctx->data = ctxdata;
264*4882a593Smuzhiyun return 0;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
optee_release(struct tee_context * ctx)267*4882a593Smuzhiyun static void optee_release(struct tee_context *ctx)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun struct optee_context_data *ctxdata = ctx->data;
270*4882a593Smuzhiyun struct tee_device *teedev = ctx->teedev;
271*4882a593Smuzhiyun struct optee *optee = tee_get_drvdata(teedev);
272*4882a593Smuzhiyun struct tee_shm *shm;
273*4882a593Smuzhiyun struct optee_msg_arg *arg = NULL;
274*4882a593Smuzhiyun phys_addr_t parg;
275*4882a593Smuzhiyun struct optee_session *sess;
276*4882a593Smuzhiyun struct optee_session *sess_tmp;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (!ctxdata)
279*4882a593Smuzhiyun return;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg),
282*4882a593Smuzhiyun TEE_SHM_MAPPED | TEE_SHM_PRIV);
283*4882a593Smuzhiyun if (!IS_ERR(shm)) {
284*4882a593Smuzhiyun arg = tee_shm_get_va(shm, 0);
285*4882a593Smuzhiyun /*
286*4882a593Smuzhiyun * If va2pa fails for some reason, we can't call into
287*4882a593Smuzhiyun * secure world, only free the memory. Secure OS will leak
288*4882a593Smuzhiyun * sessions and finally refuse more sessions, but we will
289*4882a593Smuzhiyun * at least let normal world reclaim its memory.
290*4882a593Smuzhiyun */
291*4882a593Smuzhiyun if (!IS_ERR(arg))
292*4882a593Smuzhiyun if (tee_shm_va2pa(shm, arg, &parg))
293*4882a593Smuzhiyun arg = NULL; /* prevent usage of parg below */
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
297*4882a593Smuzhiyun list_node) {
298*4882a593Smuzhiyun list_del(&sess->list_node);
299*4882a593Smuzhiyun if (!IS_ERR_OR_NULL(arg)) {
300*4882a593Smuzhiyun memset(arg, 0, sizeof(*arg));
301*4882a593Smuzhiyun arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
302*4882a593Smuzhiyun arg->session = sess->session_id;
303*4882a593Smuzhiyun optee_do_call_with_arg(ctx, parg);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun kfree(sess);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun kfree(ctxdata);
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun if (!IS_ERR(shm))
310*4882a593Smuzhiyun tee_shm_free(shm);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun ctx->data = NULL;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun if (teedev == optee->supp_teedev) {
315*4882a593Smuzhiyun if (optee->scan_bus_wq) {
316*4882a593Smuzhiyun destroy_workqueue(optee->scan_bus_wq);
317*4882a593Smuzhiyun optee->scan_bus_wq = NULL;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun optee_supp_release(&optee->supp);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun static const struct tee_driver_ops optee_ops = {
324*4882a593Smuzhiyun .get_version = optee_get_version,
325*4882a593Smuzhiyun .open = optee_open,
326*4882a593Smuzhiyun .release = optee_release,
327*4882a593Smuzhiyun .open_session = optee_open_session,
328*4882a593Smuzhiyun .close_session = optee_close_session,
329*4882a593Smuzhiyun .invoke_func = optee_invoke_func,
330*4882a593Smuzhiyun .cancel_req = optee_cancel_req,
331*4882a593Smuzhiyun .shm_register = optee_shm_register,
332*4882a593Smuzhiyun .shm_unregister = optee_shm_unregister,
333*4882a593Smuzhiyun };
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun static const struct tee_desc optee_desc = {
336*4882a593Smuzhiyun .name = DRIVER_NAME "-clnt",
337*4882a593Smuzhiyun .ops = &optee_ops,
338*4882a593Smuzhiyun .owner = THIS_MODULE,
339*4882a593Smuzhiyun };
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun static const struct tee_driver_ops optee_supp_ops = {
342*4882a593Smuzhiyun .get_version = optee_get_version,
343*4882a593Smuzhiyun .open = optee_open,
344*4882a593Smuzhiyun .release = optee_release,
345*4882a593Smuzhiyun .supp_recv = optee_supp_recv,
346*4882a593Smuzhiyun .supp_send = optee_supp_send,
347*4882a593Smuzhiyun .shm_register = optee_shm_register_supp,
348*4882a593Smuzhiyun .shm_unregister = optee_shm_unregister_supp,
349*4882a593Smuzhiyun };
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun static const struct tee_desc optee_supp_desc = {
352*4882a593Smuzhiyun .name = DRIVER_NAME "-supp",
353*4882a593Smuzhiyun .ops = &optee_supp_ops,
354*4882a593Smuzhiyun .owner = THIS_MODULE,
355*4882a593Smuzhiyun .flags = TEE_DESC_PRIVILEGED,
356*4882a593Smuzhiyun };
357*4882a593Smuzhiyun
optee_msg_api_uid_is_optee_api(optee_invoke_fn * invoke_fn)358*4882a593Smuzhiyun static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun struct arm_smccc_res res;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun if (res.a0 == OPTEE_MSG_UID_0 && res.a1 == OPTEE_MSG_UID_1 &&
365*4882a593Smuzhiyun res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3)
366*4882a593Smuzhiyun return true;
367*4882a593Smuzhiyun return false;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
optee_msg_get_os_revision(optee_invoke_fn * invoke_fn)370*4882a593Smuzhiyun static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun union {
373*4882a593Smuzhiyun struct arm_smccc_res smccc;
374*4882a593Smuzhiyun struct optee_smc_call_get_os_revision_result result;
375*4882a593Smuzhiyun } res = {
376*4882a593Smuzhiyun .result = {
377*4882a593Smuzhiyun .build_id = 0
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun };
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
382*4882a593Smuzhiyun &res.smccc);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun if (res.result.build_id)
385*4882a593Smuzhiyun pr_info("revision %lu.%lu (%08lx)", res.result.major,
386*4882a593Smuzhiyun res.result.minor, res.result.build_id);
387*4882a593Smuzhiyun else
388*4882a593Smuzhiyun pr_info("revision %lu.%lu", res.result.major, res.result.minor);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
optee_msg_api_revision_is_compatible(optee_invoke_fn * invoke_fn)391*4882a593Smuzhiyun static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun union {
394*4882a593Smuzhiyun struct arm_smccc_res smccc;
395*4882a593Smuzhiyun struct optee_smc_calls_revision_result result;
396*4882a593Smuzhiyun } res;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun if (res.result.major == OPTEE_MSG_REVISION_MAJOR &&
401*4882a593Smuzhiyun (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR)
402*4882a593Smuzhiyun return true;
403*4882a593Smuzhiyun return false;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
optee_msg_exchange_capabilities(optee_invoke_fn * invoke_fn,u32 * sec_caps)406*4882a593Smuzhiyun static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
407*4882a593Smuzhiyun u32 *sec_caps)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun union {
410*4882a593Smuzhiyun struct arm_smccc_res smccc;
411*4882a593Smuzhiyun struct optee_smc_exchange_capabilities_result result;
412*4882a593Smuzhiyun } res;
413*4882a593Smuzhiyun u32 a1 = 0;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun /*
416*4882a593Smuzhiyun * TODO This isn't enough to tell if it's UP system (from kernel
417*4882a593Smuzhiyun * point of view) or not, is_smp() returns the the information
418*4882a593Smuzhiyun * needed, but can't be called directly from here.
419*4882a593Smuzhiyun */
420*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_SMP) || nr_cpu_ids == 1)
421*4882a593Smuzhiyun a1 |= OPTEE_SMC_NSEC_CAP_UNIPROCESSOR;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0,
424*4882a593Smuzhiyun &res.smccc);
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun if (res.result.status != OPTEE_SMC_RETURN_OK)
427*4882a593Smuzhiyun return false;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun *sec_caps = res.result.capabilities;
430*4882a593Smuzhiyun return true;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
optee_config_dyn_shm(void)433*4882a593Smuzhiyun static struct tee_shm_pool *optee_config_dyn_shm(void)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun struct tee_shm_pool_mgr *priv_mgr;
436*4882a593Smuzhiyun struct tee_shm_pool_mgr *dmabuf_mgr;
437*4882a593Smuzhiyun void *rc;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun rc = optee_shm_pool_alloc_pages();
440*4882a593Smuzhiyun if (IS_ERR(rc))
441*4882a593Smuzhiyun return rc;
442*4882a593Smuzhiyun priv_mgr = rc;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun rc = optee_shm_pool_alloc_pages();
445*4882a593Smuzhiyun if (IS_ERR(rc)) {
446*4882a593Smuzhiyun tee_shm_pool_mgr_destroy(priv_mgr);
447*4882a593Smuzhiyun return rc;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun dmabuf_mgr = rc;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
452*4882a593Smuzhiyun if (IS_ERR(rc)) {
453*4882a593Smuzhiyun tee_shm_pool_mgr_destroy(priv_mgr);
454*4882a593Smuzhiyun tee_shm_pool_mgr_destroy(dmabuf_mgr);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun return rc;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun static struct tee_shm_pool *
optee_config_shm_memremap(optee_invoke_fn * invoke_fn,void ** memremaped_shm)461*4882a593Smuzhiyun optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun union {
464*4882a593Smuzhiyun struct arm_smccc_res smccc;
465*4882a593Smuzhiyun struct optee_smc_get_shm_config_result result;
466*4882a593Smuzhiyun } res;
467*4882a593Smuzhiyun unsigned long vaddr;
468*4882a593Smuzhiyun phys_addr_t paddr;
469*4882a593Smuzhiyun size_t size;
470*4882a593Smuzhiyun phys_addr_t begin;
471*4882a593Smuzhiyun phys_addr_t end;
472*4882a593Smuzhiyun void *va;
473*4882a593Smuzhiyun struct tee_shm_pool_mgr *priv_mgr;
474*4882a593Smuzhiyun struct tee_shm_pool_mgr *dmabuf_mgr;
475*4882a593Smuzhiyun void *rc;
476*4882a593Smuzhiyun const int sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
479*4882a593Smuzhiyun if (res.result.status != OPTEE_SMC_RETURN_OK) {
480*4882a593Smuzhiyun pr_err("static shm service not available\n");
481*4882a593Smuzhiyun return ERR_PTR(-ENOENT);
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun if (res.result.settings != OPTEE_SMC_SHM_CACHED) {
485*4882a593Smuzhiyun pr_err("only normal cached shared memory supported\n");
486*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun begin = roundup(res.result.start, PAGE_SIZE);
490*4882a593Smuzhiyun end = rounddown(res.result.start + res.result.size, PAGE_SIZE);
491*4882a593Smuzhiyun paddr = begin;
492*4882a593Smuzhiyun size = end - begin;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun if (size < 2 * OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE) {
495*4882a593Smuzhiyun pr_err("too small shared memory area\n");
496*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun va = memremap(paddr, size, MEMREMAP_WB);
500*4882a593Smuzhiyun if (!va) {
501*4882a593Smuzhiyun pr_err("shared memory ioremap failed\n");
502*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun vaddr = (unsigned long)va;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
507*4882a593Smuzhiyun 3 /* 8 bytes aligned */);
508*4882a593Smuzhiyun if (IS_ERR(rc))
509*4882a593Smuzhiyun goto err_memunmap;
510*4882a593Smuzhiyun priv_mgr = rc;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun vaddr += sz;
513*4882a593Smuzhiyun paddr += sz;
514*4882a593Smuzhiyun size -= sz;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT);
517*4882a593Smuzhiyun if (IS_ERR(rc))
518*4882a593Smuzhiyun goto err_free_priv_mgr;
519*4882a593Smuzhiyun dmabuf_mgr = rc;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
522*4882a593Smuzhiyun if (IS_ERR(rc))
523*4882a593Smuzhiyun goto err_free_dmabuf_mgr;
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun *memremaped_shm = va;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun return rc;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun err_free_dmabuf_mgr:
530*4882a593Smuzhiyun tee_shm_pool_mgr_destroy(dmabuf_mgr);
531*4882a593Smuzhiyun err_free_priv_mgr:
532*4882a593Smuzhiyun tee_shm_pool_mgr_destroy(priv_mgr);
533*4882a593Smuzhiyun err_memunmap:
534*4882a593Smuzhiyun memunmap(va);
535*4882a593Smuzhiyun return rc;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun /* Simple wrapper functions to be able to use a function pointer */
optee_smccc_smc(unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long a4,unsigned long a5,unsigned long a6,unsigned long a7,struct arm_smccc_res * res)539*4882a593Smuzhiyun static void optee_smccc_smc(unsigned long a0, unsigned long a1,
540*4882a593Smuzhiyun unsigned long a2, unsigned long a3,
541*4882a593Smuzhiyun unsigned long a4, unsigned long a5,
542*4882a593Smuzhiyun unsigned long a6, unsigned long a7,
543*4882a593Smuzhiyun struct arm_smccc_res *res)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
optee_smccc_hvc(unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long a4,unsigned long a5,unsigned long a6,unsigned long a7,struct arm_smccc_res * res)548*4882a593Smuzhiyun static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
549*4882a593Smuzhiyun unsigned long a2, unsigned long a3,
550*4882a593Smuzhiyun unsigned long a4, unsigned long a5,
551*4882a593Smuzhiyun unsigned long a6, unsigned long a7,
552*4882a593Smuzhiyun struct arm_smccc_res *res)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
get_invoke_func(struct device * dev)557*4882a593Smuzhiyun static optee_invoke_fn *get_invoke_func(struct device *dev)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun const char *method;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun pr_info("probing for conduit method.\n");
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun if (device_property_read_string(dev, "method", &method)) {
564*4882a593Smuzhiyun pr_warn("missing \"method\" property\n");
565*4882a593Smuzhiyun return ERR_PTR(-ENXIO);
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (!strcmp("hvc", method))
569*4882a593Smuzhiyun return optee_smccc_hvc;
570*4882a593Smuzhiyun else if (!strcmp("smc", method))
571*4882a593Smuzhiyun return optee_smccc_smc;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun pr_warn("invalid \"method\" property: %s\n", method);
574*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun /* optee_remove - Device Removal Routine
578*4882a593Smuzhiyun * @pdev: platform device information struct
579*4882a593Smuzhiyun *
580*4882a593Smuzhiyun * optee_remove is called by platform subsystem to alert the driver
581*4882a593Smuzhiyun * that it should release the device
582*4882a593Smuzhiyun */
583*4882a593Smuzhiyun
optee_remove(struct platform_device * pdev)584*4882a593Smuzhiyun static int optee_remove(struct platform_device *pdev)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun struct optee *optee = platform_get_drvdata(pdev);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun /* Unregister OP-TEE specific client devices on TEE bus */
589*4882a593Smuzhiyun optee_unregister_devices();
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun teedev_close_context(optee->ctx);
592*4882a593Smuzhiyun /*
593*4882a593Smuzhiyun * Ask OP-TEE to free all cached shared memory objects to decrease
594*4882a593Smuzhiyun * reference counters and also avoid wild pointers in secure world
595*4882a593Smuzhiyun * into the old shared memory range.
596*4882a593Smuzhiyun */
597*4882a593Smuzhiyun optee_disable_shm_cache(optee);
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun /*
600*4882a593Smuzhiyun * The two devices have to be unregistered before we can free the
601*4882a593Smuzhiyun * other resources.
602*4882a593Smuzhiyun */
603*4882a593Smuzhiyun tee_device_unregister(optee->supp_teedev);
604*4882a593Smuzhiyun tee_device_unregister(optee->teedev);
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun tee_shm_pool_free(optee->pool);
607*4882a593Smuzhiyun if (optee->memremaped_shm)
608*4882a593Smuzhiyun memunmap(optee->memremaped_shm);
609*4882a593Smuzhiyun optee_wait_queue_exit(&optee->wait_queue);
610*4882a593Smuzhiyun optee_supp_uninit(&optee->supp);
611*4882a593Smuzhiyun mutex_destroy(&optee->call_queue.mutex);
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun kfree(optee);
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun return 0;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun /* optee_shutdown - Device Removal Routine
619*4882a593Smuzhiyun * @pdev: platform device information struct
620*4882a593Smuzhiyun *
621*4882a593Smuzhiyun * platform_shutdown is called by the platform subsystem to alert
622*4882a593Smuzhiyun * the driver that a shutdown, reboot, or kexec is happening and
623*4882a593Smuzhiyun * device must be disabled.
624*4882a593Smuzhiyun */
optee_shutdown(struct platform_device * pdev)625*4882a593Smuzhiyun static void optee_shutdown(struct platform_device *pdev)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun optee_disable_shm_cache(platform_get_drvdata(pdev));
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun
optee_probe(struct platform_device * pdev)630*4882a593Smuzhiyun static int optee_probe(struct platform_device *pdev)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun optee_invoke_fn *invoke_fn;
633*4882a593Smuzhiyun struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
634*4882a593Smuzhiyun struct optee *optee = NULL;
635*4882a593Smuzhiyun void *memremaped_shm = NULL;
636*4882a593Smuzhiyun struct tee_device *teedev;
637*4882a593Smuzhiyun struct tee_context *ctx;
638*4882a593Smuzhiyun u32 sec_caps;
639*4882a593Smuzhiyun int rc;
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun /*
642*4882a593Smuzhiyun * The kernel may have crashed at the same time that all available
643*4882a593Smuzhiyun * secure world threads were suspended and we cannot reschedule the
644*4882a593Smuzhiyun * suspended threads without access to the crashed kernel's wait_queue.
645*4882a593Smuzhiyun * Therefore, we cannot reliably initialize the OP-TEE driver in the
646*4882a593Smuzhiyun * kdump kernel.
647*4882a593Smuzhiyun */
648*4882a593Smuzhiyun if (is_kdump_kernel())
649*4882a593Smuzhiyun return -ENODEV;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun invoke_fn = get_invoke_func(&pdev->dev);
652*4882a593Smuzhiyun if (IS_ERR(invoke_fn))
653*4882a593Smuzhiyun return PTR_ERR(invoke_fn);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun if (!optee_msg_api_uid_is_optee_api(invoke_fn)) {
656*4882a593Smuzhiyun pr_warn("api uid mismatch\n");
657*4882a593Smuzhiyun return -EINVAL;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun optee_msg_get_os_revision(invoke_fn);
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
663*4882a593Smuzhiyun pr_warn("api revision mismatch\n");
664*4882a593Smuzhiyun return -EINVAL;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) {
668*4882a593Smuzhiyun pr_warn("capabilities mismatch\n");
669*4882a593Smuzhiyun return -EINVAL;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun /*
673*4882a593Smuzhiyun * Try to use dynamic shared memory if possible
674*4882a593Smuzhiyun */
675*4882a593Smuzhiyun if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
676*4882a593Smuzhiyun pool = optee_config_dyn_shm();
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun /*
679*4882a593Smuzhiyun * If dynamic shared memory is not available or failed - try static one
680*4882a593Smuzhiyun */
681*4882a593Smuzhiyun if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
682*4882a593Smuzhiyun pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun if (IS_ERR(pool))
685*4882a593Smuzhiyun return PTR_ERR(pool);
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun optee = kzalloc(sizeof(*optee), GFP_KERNEL);
688*4882a593Smuzhiyun if (!optee) {
689*4882a593Smuzhiyun rc = -ENOMEM;
690*4882a593Smuzhiyun goto err;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun optee->invoke_fn = invoke_fn;
694*4882a593Smuzhiyun optee->sec_caps = sec_caps;
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun teedev = tee_device_alloc(&optee_desc, NULL, pool, optee);
697*4882a593Smuzhiyun if (IS_ERR(teedev)) {
698*4882a593Smuzhiyun rc = PTR_ERR(teedev);
699*4882a593Smuzhiyun goto err;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun optee->teedev = teedev;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee);
704*4882a593Smuzhiyun if (IS_ERR(teedev)) {
705*4882a593Smuzhiyun rc = PTR_ERR(teedev);
706*4882a593Smuzhiyun goto err;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun optee->supp_teedev = teedev;
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun rc = tee_device_register(optee->teedev);
711*4882a593Smuzhiyun if (rc)
712*4882a593Smuzhiyun goto err;
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun rc = tee_device_register(optee->supp_teedev);
715*4882a593Smuzhiyun if (rc)
716*4882a593Smuzhiyun goto err;
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun mutex_init(&optee->call_queue.mutex);
719*4882a593Smuzhiyun INIT_LIST_HEAD(&optee->call_queue.waiters);
720*4882a593Smuzhiyun optee_wait_queue_init(&optee->wait_queue);
721*4882a593Smuzhiyun optee_supp_init(&optee->supp);
722*4882a593Smuzhiyun optee->memremaped_shm = memremaped_shm;
723*4882a593Smuzhiyun optee->pool = pool;
724*4882a593Smuzhiyun ctx = teedev_open(optee->teedev);
725*4882a593Smuzhiyun if (IS_ERR(ctx)) {
726*4882a593Smuzhiyun rc = PTR_ERR(ctx);
727*4882a593Smuzhiyun goto err;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun optee->ctx = ctx;
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun /*
732*4882a593Smuzhiyun * Ensure that there are no pre-existing shm objects before enabling
733*4882a593Smuzhiyun * the shm cache so that there's no chance of receiving an invalid
734*4882a593Smuzhiyun * address during shutdown. This could occur, for example, if we're
735*4882a593Smuzhiyun * kexec booting from an older kernel that did not properly cleanup the
736*4882a593Smuzhiyun * shm cache.
737*4882a593Smuzhiyun */
738*4882a593Smuzhiyun optee_disable_unmapped_shm_cache(optee);
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun optee_enable_shm_cache(optee);
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
743*4882a593Smuzhiyun pr_info("dynamic shared memory is enabled\n");
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun platform_set_drvdata(pdev, optee);
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
748*4882a593Smuzhiyun if (rc) {
749*4882a593Smuzhiyun optee_remove(pdev);
750*4882a593Smuzhiyun return rc;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun pr_info("initialized driver\n");
754*4882a593Smuzhiyun return 0;
755*4882a593Smuzhiyun err:
756*4882a593Smuzhiyun if (optee) {
757*4882a593Smuzhiyun /*
758*4882a593Smuzhiyun * tee_device_unregister() is safe to call even if the
759*4882a593Smuzhiyun * devices hasn't been registered with
760*4882a593Smuzhiyun * tee_device_register() yet.
761*4882a593Smuzhiyun */
762*4882a593Smuzhiyun tee_device_unregister(optee->supp_teedev);
763*4882a593Smuzhiyun tee_device_unregister(optee->teedev);
764*4882a593Smuzhiyun kfree(optee);
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun if (pool)
767*4882a593Smuzhiyun tee_shm_pool_free(pool);
768*4882a593Smuzhiyun if (memremaped_shm)
769*4882a593Smuzhiyun memunmap(memremaped_shm);
770*4882a593Smuzhiyun return rc;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun static const struct of_device_id optee_dt_match[] = {
774*4882a593Smuzhiyun { .compatible = "linaro,optee-tz" },
775*4882a593Smuzhiyun {},
776*4882a593Smuzhiyun };
777*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, optee_dt_match);
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun static struct platform_driver optee_driver = {
780*4882a593Smuzhiyun .probe = optee_probe,
781*4882a593Smuzhiyun .remove = optee_remove,
782*4882a593Smuzhiyun .shutdown = optee_shutdown,
783*4882a593Smuzhiyun .driver = {
784*4882a593Smuzhiyun .name = "optee",
785*4882a593Smuzhiyun .of_match_table = optee_dt_match,
786*4882a593Smuzhiyun },
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun module_platform_driver(optee_driver);
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun MODULE_AUTHOR("Linaro");
791*4882a593Smuzhiyun MODULE_DESCRIPTION("OP-TEE driver");
792*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("");
793*4882a593Smuzhiyun MODULE_VERSION("1.0");
794*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
795*4882a593Smuzhiyun MODULE_ALIAS("platform:optee");
796