1c51a564aSJens Wiklander // SPDX-License-Identifier: GPL-2.0-only
2c51a564aSJens Wiklander /*
3c51a564aSJens Wiklander * Copyright (c) 2015-2021, Linaro Limited
4c51a564aSJens Wiklander * Copyright (c) 2016, EPAM Systems
5c51a564aSJens Wiklander */
6c51a564aSJens Wiklander
7c51a564aSJens Wiklander #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8c51a564aSJens Wiklander
9c51a564aSJens Wiklander #include <linux/arm-smccc.h>
10f3040daaSJeffrey Kardatzke #include <linux/cpuhotplug.h>
11c51a564aSJens Wiklander #include <linux/errno.h>
12f3040daaSJeffrey Kardatzke #include <linux/firmware.h>
136749e69cSJens Wiklander #include <linux/interrupt.h>
14c51a564aSJens Wiklander #include <linux/io.h>
156749e69cSJens Wiklander #include <linux/irqdomain.h>
16f3040daaSJeffrey Kardatzke #include <linux/kernel.h>
1734f3c67bSJens Wiklander #include <linux/mm.h>
18c51a564aSJens Wiklander #include <linux/module.h>
19c51a564aSJens Wiklander #include <linux/of.h>
206749e69cSJens Wiklander #include <linux/of_irq.h>
21c51a564aSJens Wiklander #include <linux/of_platform.h>
22c51a564aSJens Wiklander #include <linux/platform_device.h>
236749e69cSJens Wiklander #include <linux/sched.h>
24c51a564aSJens Wiklander #include <linux/slab.h>
25c51a564aSJens Wiklander #include <linux/string.h>
26c51a564aSJens Wiklander #include <linux/tee_drv.h>
27c51a564aSJens Wiklander #include <linux/types.h>
28c51a564aSJens Wiklander #include <linux/workqueue.h>
29c51a564aSJens Wiklander #include "optee_private.h"
30c51a564aSJens Wiklander #include "optee_smc.h"
31c51a564aSJens Wiklander #include "optee_rpc_cmd.h"
326add87fdSXiaolei Wang #include <linux/kmemleak.h>
33c51a564aSJens Wiklander #define CREATE_TRACE_POINTS
34c51a564aSJens Wiklander #include "optee_trace.h"
35c51a564aSJens Wiklander
36c51a564aSJens Wiklander /*
37c51a564aSJens Wiklander * This file implement the SMC ABI used when communicating with secure world
38c51a564aSJens Wiklander * OP-TEE OS via raw SMCs.
39c51a564aSJens Wiklander * This file is divided into the following sections:
40c51a564aSJens Wiklander * 1. Convert between struct tee_param and struct optee_msg_param
41c51a564aSJens Wiklander * 2. Low level support functions to register shared memory in secure world
42c51a564aSJens Wiklander * 3. Dynamic shared memory pool based on alloc_pages()
43c51a564aSJens Wiklander * 4. Do a normal scheduled call into secure world
446749e69cSJens Wiklander * 5. Asynchronous notification
456749e69cSJens Wiklander * 6. Driver initialization.
46c51a564aSJens Wiklander */
47c51a564aSJens Wiklander
48d88e0493SJens Wiklander /*
49d88e0493SJens Wiklander * A typical OP-TEE private shm allocation is 224 bytes (argument struct
50d88e0493SJens Wiklander * with 6 parameters, needed for open session). So with an alignment of 512
51d88e0493SJens Wiklander * we'll waste a bit more than 50%. However, it's only expected that we'll
52d88e0493SJens Wiklander * have a handful of these structs allocated at a time. Most memory will
53d88e0493SJens Wiklander * be allocated aligned to the page size, So all in all this should scale
54d88e0493SJens Wiklander * up and down quite well.
55d88e0493SJens Wiklander */
56d88e0493SJens Wiklander #define OPTEE_MIN_STATIC_POOL_ALIGN 9 /* 512 bytes aligned */
57c51a564aSJens Wiklander
58b3b4ced1SEtienne Carriere /* SMC ABI considers at most a single TEE firmware */
59b3b4ced1SEtienne Carriere static unsigned int pcpu_irq_num;
60b3b4ced1SEtienne Carriere
optee_cpuhp_enable_pcpu_irq(unsigned int cpu)61b3b4ced1SEtienne Carriere static int optee_cpuhp_enable_pcpu_irq(unsigned int cpu)
62b3b4ced1SEtienne Carriere {
63b3b4ced1SEtienne Carriere enable_percpu_irq(pcpu_irq_num, IRQ_TYPE_NONE);
64b3b4ced1SEtienne Carriere
65b3b4ced1SEtienne Carriere return 0;
66b3b4ced1SEtienne Carriere }
67b3b4ced1SEtienne Carriere
optee_cpuhp_disable_pcpu_irq(unsigned int cpu)68b3b4ced1SEtienne Carriere static int optee_cpuhp_disable_pcpu_irq(unsigned int cpu)
69b3b4ced1SEtienne Carriere {
70b3b4ced1SEtienne Carriere disable_percpu_irq(pcpu_irq_num);
71b3b4ced1SEtienne Carriere
72b3b4ced1SEtienne Carriere return 0;
73b3b4ced1SEtienne Carriere }
74b3b4ced1SEtienne Carriere
75c51a564aSJens Wiklander /*
76c51a564aSJens Wiklander * 1. Convert between struct tee_param and struct optee_msg_param
77c51a564aSJens Wiklander *
78c51a564aSJens Wiklander * optee_from_msg_param() and optee_to_msg_param() are the main
79c51a564aSJens Wiklander * functions.
80c51a564aSJens Wiklander */
81c51a564aSJens Wiklander
from_msg_param_tmp_mem(struct tee_param * p,u32 attr,const struct optee_msg_param * mp)82c51a564aSJens Wiklander static int from_msg_param_tmp_mem(struct tee_param *p, u32 attr,
83c51a564aSJens Wiklander const struct optee_msg_param *mp)
84c51a564aSJens Wiklander {
85c51a564aSJens Wiklander struct tee_shm *shm;
86c51a564aSJens Wiklander phys_addr_t pa;
87c51a564aSJens Wiklander int rc;
88c51a564aSJens Wiklander
89c51a564aSJens Wiklander p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
90c51a564aSJens Wiklander attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
91c51a564aSJens Wiklander p->u.memref.size = mp->u.tmem.size;
92c51a564aSJens Wiklander shm = (struct tee_shm *)(unsigned long)mp->u.tmem.shm_ref;
93c51a564aSJens Wiklander if (!shm) {
94c51a564aSJens Wiklander p->u.memref.shm_offs = 0;
95c51a564aSJens Wiklander p->u.memref.shm = NULL;
96c51a564aSJens Wiklander return 0;
97c51a564aSJens Wiklander }
98c51a564aSJens Wiklander
99c51a564aSJens Wiklander rc = tee_shm_get_pa(shm, 0, &pa);
100c51a564aSJens Wiklander if (rc)
101c51a564aSJens Wiklander return rc;
102c51a564aSJens Wiklander
103c51a564aSJens Wiklander p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
104c51a564aSJens Wiklander p->u.memref.shm = shm;
105c51a564aSJens Wiklander
106c51a564aSJens Wiklander return 0;
107c51a564aSJens Wiklander }
108c51a564aSJens Wiklander
from_msg_param_reg_mem(struct tee_param * p,u32 attr,const struct optee_msg_param * mp)109c51a564aSJens Wiklander static void from_msg_param_reg_mem(struct tee_param *p, u32 attr,
110c51a564aSJens Wiklander const struct optee_msg_param *mp)
111c51a564aSJens Wiklander {
112c51a564aSJens Wiklander struct tee_shm *shm;
113c51a564aSJens Wiklander
114c51a564aSJens Wiklander p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
115c51a564aSJens Wiklander attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
116c51a564aSJens Wiklander p->u.memref.size = mp->u.rmem.size;
117c51a564aSJens Wiklander shm = (struct tee_shm *)(unsigned long)mp->u.rmem.shm_ref;
118c51a564aSJens Wiklander
119c51a564aSJens Wiklander if (shm) {
120c51a564aSJens Wiklander p->u.memref.shm_offs = mp->u.rmem.offs;
121c51a564aSJens Wiklander p->u.memref.shm = shm;
122c51a564aSJens Wiklander } else {
123c51a564aSJens Wiklander p->u.memref.shm_offs = 0;
124c51a564aSJens Wiklander p->u.memref.shm = NULL;
125c51a564aSJens Wiklander }
126c51a564aSJens Wiklander }
127c51a564aSJens Wiklander
128c51a564aSJens Wiklander /**
129c51a564aSJens Wiklander * optee_from_msg_param() - convert from OPTEE_MSG parameters to
130c51a564aSJens Wiklander * struct tee_param
131c51a564aSJens Wiklander * @optee: main service struct
132c51a564aSJens Wiklander * @params: subsystem internal parameter representation
133c51a564aSJens Wiklander * @num_params: number of elements in the parameter arrays
134c51a564aSJens Wiklander * @msg_params: OPTEE_MSG parameters
135c51a564aSJens Wiklander * Returns 0 on success or <0 on failure
136c51a564aSJens Wiklander */
optee_from_msg_param(struct optee * optee,struct tee_param * params,size_t num_params,const struct optee_msg_param * msg_params)137c51a564aSJens Wiklander static int optee_from_msg_param(struct optee *optee, struct tee_param *params,
138c51a564aSJens Wiklander size_t num_params,
139c51a564aSJens Wiklander const struct optee_msg_param *msg_params)
140c51a564aSJens Wiklander {
141c51a564aSJens Wiklander int rc;
142c51a564aSJens Wiklander size_t n;
143c51a564aSJens Wiklander
144c51a564aSJens Wiklander for (n = 0; n < num_params; n++) {
145c51a564aSJens Wiklander struct tee_param *p = params + n;
146c51a564aSJens Wiklander const struct optee_msg_param *mp = msg_params + n;
147c51a564aSJens Wiklander u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK;
148c51a564aSJens Wiklander
149c51a564aSJens Wiklander switch (attr) {
150c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_NONE:
151c51a564aSJens Wiklander p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
152c51a564aSJens Wiklander memset(&p->u, 0, sizeof(p->u));
153c51a564aSJens Wiklander break;
154c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
155c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
156c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
157c51a564aSJens Wiklander optee_from_msg_param_value(p, attr, mp);
158c51a564aSJens Wiklander break;
159c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
160c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
161c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
162c51a564aSJens Wiklander rc = from_msg_param_tmp_mem(p, attr, mp);
163c51a564aSJens Wiklander if (rc)
164c51a564aSJens Wiklander return rc;
165c51a564aSJens Wiklander break;
166c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
167c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
168c51a564aSJens Wiklander case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
169c51a564aSJens Wiklander from_msg_param_reg_mem(p, attr, mp);
170c51a564aSJens Wiklander break;
171c51a564aSJens Wiklander
172c51a564aSJens Wiklander default:
173c51a564aSJens Wiklander return -EINVAL;
174c51a564aSJens Wiklander }
175c51a564aSJens Wiklander }
176c51a564aSJens Wiklander return 0;
177c51a564aSJens Wiklander }
178c51a564aSJens Wiklander
to_msg_param_tmp_mem(struct optee_msg_param * mp,const struct tee_param * p)179c51a564aSJens Wiklander static int to_msg_param_tmp_mem(struct optee_msg_param *mp,
180c51a564aSJens Wiklander const struct tee_param *p)
181c51a564aSJens Wiklander {
182c51a564aSJens Wiklander int rc;
183c51a564aSJens Wiklander phys_addr_t pa;
184c51a564aSJens Wiklander
185c51a564aSJens Wiklander mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + p->attr -
186c51a564aSJens Wiklander TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
187c51a564aSJens Wiklander
188c51a564aSJens Wiklander mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm;
189c51a564aSJens Wiklander mp->u.tmem.size = p->u.memref.size;
190c51a564aSJens Wiklander
191c51a564aSJens Wiklander if (!p->u.memref.shm) {
192c51a564aSJens Wiklander mp->u.tmem.buf_ptr = 0;
193c51a564aSJens Wiklander return 0;
194c51a564aSJens Wiklander }
195c51a564aSJens Wiklander
196c51a564aSJens Wiklander rc = tee_shm_get_pa(p->u.memref.shm, p->u.memref.shm_offs, &pa);
197c51a564aSJens Wiklander if (rc)
198c51a564aSJens Wiklander return rc;
199c51a564aSJens Wiklander
200c51a564aSJens Wiklander mp->u.tmem.buf_ptr = pa;
201c51a564aSJens Wiklander mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED <<
202c51a564aSJens Wiklander OPTEE_MSG_ATTR_CACHE_SHIFT;
203c51a564aSJens Wiklander
204c51a564aSJens Wiklander return 0;
205c51a564aSJens Wiklander }
206c51a564aSJens Wiklander
to_msg_param_reg_mem(struct optee_msg_param * mp,const struct tee_param * p)207c51a564aSJens Wiklander static int to_msg_param_reg_mem(struct optee_msg_param *mp,
208c51a564aSJens Wiklander const struct tee_param *p)
209c51a564aSJens Wiklander {
210c51a564aSJens Wiklander mp->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + p->attr -
211c51a564aSJens Wiklander TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
212c51a564aSJens Wiklander
213c51a564aSJens Wiklander mp->u.rmem.shm_ref = (unsigned long)p->u.memref.shm;
214c51a564aSJens Wiklander mp->u.rmem.size = p->u.memref.size;
215c51a564aSJens Wiklander mp->u.rmem.offs = p->u.memref.shm_offs;
216c51a564aSJens Wiklander return 0;
217c51a564aSJens Wiklander }
218c51a564aSJens Wiklander
219c51a564aSJens Wiklander /**
220c51a564aSJens Wiklander * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters
221c51a564aSJens Wiklander * @optee: main service struct
222c51a564aSJens Wiklander * @msg_params: OPTEE_MSG parameters
223c51a564aSJens Wiklander * @num_params: number of elements in the parameter arrays
224c51a564aSJens Wiklander * @params: subsystem itnernal parameter representation
225c51a564aSJens Wiklander * Returns 0 on success or <0 on failure
226c51a564aSJens Wiklander */
optee_to_msg_param(struct optee * optee,struct optee_msg_param * msg_params,size_t num_params,const struct tee_param * params)227c51a564aSJens Wiklander static int optee_to_msg_param(struct optee *optee,
228c51a564aSJens Wiklander struct optee_msg_param *msg_params,
229c51a564aSJens Wiklander size_t num_params, const struct tee_param *params)
230c51a564aSJens Wiklander {
231c51a564aSJens Wiklander int rc;
232c51a564aSJens Wiklander size_t n;
233c51a564aSJens Wiklander
234c51a564aSJens Wiklander for (n = 0; n < num_params; n++) {
235c51a564aSJens Wiklander const struct tee_param *p = params + n;
236c51a564aSJens Wiklander struct optee_msg_param *mp = msg_params + n;
237c51a564aSJens Wiklander
238c51a564aSJens Wiklander switch (p->attr) {
239c51a564aSJens Wiklander case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
240c51a564aSJens Wiklander mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
241c51a564aSJens Wiklander memset(&mp->u, 0, sizeof(mp->u));
242c51a564aSJens Wiklander break;
243c51a564aSJens Wiklander case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
244c51a564aSJens Wiklander case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
245c51a564aSJens Wiklander case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
246c51a564aSJens Wiklander optee_to_msg_param_value(mp, p);
247c51a564aSJens Wiklander break;
248c51a564aSJens Wiklander case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
249c51a564aSJens Wiklander case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
250c51a564aSJens Wiklander case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
251a45ea4efSJens Wiklander if (tee_shm_is_dynamic(p->u.memref.shm))
252c51a564aSJens Wiklander rc = to_msg_param_reg_mem(mp, p);
253c51a564aSJens Wiklander else
254c51a564aSJens Wiklander rc = to_msg_param_tmp_mem(mp, p);
255c51a564aSJens Wiklander if (rc)
256c51a564aSJens Wiklander return rc;
257c51a564aSJens Wiklander break;
258c51a564aSJens Wiklander default:
259c51a564aSJens Wiklander return -EINVAL;
260c51a564aSJens Wiklander }
261c51a564aSJens Wiklander }
262c51a564aSJens Wiklander return 0;
263c51a564aSJens Wiklander }
264c51a564aSJens Wiklander
265c51a564aSJens Wiklander /*
266c51a564aSJens Wiklander * 2. Low level support functions to register shared memory in secure world
267c51a564aSJens Wiklander *
268c51a564aSJens Wiklander * Functions to enable/disable shared memory caching in secure world, that
269c51a564aSJens Wiklander * is, lazy freeing of previously allocated shared memory. Freeing is
270c51a564aSJens Wiklander * performed when a request has been compled.
271c51a564aSJens Wiklander *
272c51a564aSJens Wiklander * Functions to register and unregister shared memory both for normal
273c51a564aSJens Wiklander * clients and for tee-supplicant.
274c51a564aSJens Wiklander */
275c51a564aSJens Wiklander
276c51a564aSJens Wiklander /**
277c51a564aSJens Wiklander * optee_enable_shm_cache() - Enables caching of some shared memory allocation
278c51a564aSJens Wiklander * in OP-TEE
279c51a564aSJens Wiklander * @optee: main service struct
280c51a564aSJens Wiklander */
optee_enable_shm_cache(struct optee * optee)281c51a564aSJens Wiklander static void optee_enable_shm_cache(struct optee *optee)
282c51a564aSJens Wiklander {
283c51a564aSJens Wiklander struct optee_call_waiter w;
284c51a564aSJens Wiklander
285c51a564aSJens Wiklander /* We need to retry until secure world isn't busy. */
286c51a564aSJens Wiklander optee_cq_wait_init(&optee->call_queue, &w);
287c51a564aSJens Wiklander while (true) {
288c51a564aSJens Wiklander struct arm_smccc_res res;
289c51a564aSJens Wiklander
290c51a564aSJens Wiklander optee->smc.invoke_fn(OPTEE_SMC_ENABLE_SHM_CACHE,
291c51a564aSJens Wiklander 0, 0, 0, 0, 0, 0, 0, &res);
292c51a564aSJens Wiklander if (res.a0 == OPTEE_SMC_RETURN_OK)
293c51a564aSJens Wiklander break;
294c51a564aSJens Wiklander optee_cq_wait_for_completion(&optee->call_queue, &w);
295c51a564aSJens Wiklander }
296c51a564aSJens Wiklander optee_cq_wait_final(&optee->call_queue, &w);
297c51a564aSJens Wiklander }
298c51a564aSJens Wiklander
299c51a564aSJens Wiklander /**
300c51a564aSJens Wiklander * __optee_disable_shm_cache() - Disables caching of some shared memory
301c51a564aSJens Wiklander * allocation in OP-TEE
302c51a564aSJens Wiklander * @optee: main service struct
303c51a564aSJens Wiklander * @is_mapped: true if the cached shared memory addresses were mapped by this
304c51a564aSJens Wiklander * kernel, are safe to dereference, and should be freed
305c51a564aSJens Wiklander */
__optee_disable_shm_cache(struct optee * optee,bool is_mapped)306c51a564aSJens Wiklander static void __optee_disable_shm_cache(struct optee *optee, bool is_mapped)
307c51a564aSJens Wiklander {
308c51a564aSJens Wiklander struct optee_call_waiter w;
309c51a564aSJens Wiklander
310c51a564aSJens Wiklander /* We need to retry until secure world isn't busy. */
311c51a564aSJens Wiklander optee_cq_wait_init(&optee->call_queue, &w);
312c51a564aSJens Wiklander while (true) {
313c51a564aSJens Wiklander union {
314c51a564aSJens Wiklander struct arm_smccc_res smccc;
315c51a564aSJens Wiklander struct optee_smc_disable_shm_cache_result result;
316c51a564aSJens Wiklander } res;
317c51a564aSJens Wiklander
318c51a564aSJens Wiklander optee->smc.invoke_fn(OPTEE_SMC_DISABLE_SHM_CACHE,
319c51a564aSJens Wiklander 0, 0, 0, 0, 0, 0, 0, &res.smccc);
320c51a564aSJens Wiklander if (res.result.status == OPTEE_SMC_RETURN_ENOTAVAIL)
321c51a564aSJens Wiklander break; /* All shm's freed */
322c51a564aSJens Wiklander if (res.result.status == OPTEE_SMC_RETURN_OK) {
323c51a564aSJens Wiklander struct tee_shm *shm;
324c51a564aSJens Wiklander
325c51a564aSJens Wiklander /*
326c51a564aSJens Wiklander * Shared memory references that were not mapped by
327c51a564aSJens Wiklander * this kernel must be ignored to prevent a crash.
328c51a564aSJens Wiklander */
329c51a564aSJens Wiklander if (!is_mapped)
330c51a564aSJens Wiklander continue;
331c51a564aSJens Wiklander
332c51a564aSJens Wiklander shm = reg_pair_to_ptr(res.result.shm_upper32,
333c51a564aSJens Wiklander res.result.shm_lower32);
334c51a564aSJens Wiklander tee_shm_free(shm);
335c51a564aSJens Wiklander } else {
336c51a564aSJens Wiklander optee_cq_wait_for_completion(&optee->call_queue, &w);
337c51a564aSJens Wiklander }
338c51a564aSJens Wiklander }
339c51a564aSJens Wiklander optee_cq_wait_final(&optee->call_queue, &w);
340c51a564aSJens Wiklander }
341c51a564aSJens Wiklander
342c51a564aSJens Wiklander /**
343c51a564aSJens Wiklander * optee_disable_shm_cache() - Disables caching of mapped shared memory
344c51a564aSJens Wiklander * allocations in OP-TEE
345c51a564aSJens Wiklander * @optee: main service struct
346c51a564aSJens Wiklander */
optee_disable_shm_cache(struct optee * optee)347c51a564aSJens Wiklander static void optee_disable_shm_cache(struct optee *optee)
348c51a564aSJens Wiklander {
349c51a564aSJens Wiklander return __optee_disable_shm_cache(optee, true);
350c51a564aSJens Wiklander }
351c51a564aSJens Wiklander
352c51a564aSJens Wiklander /**
353c51a564aSJens Wiklander * optee_disable_unmapped_shm_cache() - Disables caching of shared memory
354c51a564aSJens Wiklander * allocations in OP-TEE which are not
355c51a564aSJens Wiklander * currently mapped
356c51a564aSJens Wiklander * @optee: main service struct
357c51a564aSJens Wiklander */
optee_disable_unmapped_shm_cache(struct optee * optee)358c51a564aSJens Wiklander static void optee_disable_unmapped_shm_cache(struct optee *optee)
359c51a564aSJens Wiklander {
360c51a564aSJens Wiklander return __optee_disable_shm_cache(optee, false);
361c51a564aSJens Wiklander }
362c51a564aSJens Wiklander
363c51a564aSJens Wiklander #define PAGELIST_ENTRIES_PER_PAGE \
364c51a564aSJens Wiklander ((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1)
365c51a564aSJens Wiklander
366c51a564aSJens Wiklander /*
367c51a564aSJens Wiklander * The final entry in each pagelist page is a pointer to the next
368c51a564aSJens Wiklander * pagelist page.
369c51a564aSJens Wiklander */
get_pages_list_size(size_t num_entries)370c51a564aSJens Wiklander static size_t get_pages_list_size(size_t num_entries)
371c51a564aSJens Wiklander {
372c51a564aSJens Wiklander int pages = DIV_ROUND_UP(num_entries, PAGELIST_ENTRIES_PER_PAGE);
373c51a564aSJens Wiklander
374c51a564aSJens Wiklander return pages * OPTEE_MSG_NONCONTIG_PAGE_SIZE;
375c51a564aSJens Wiklander }
376c51a564aSJens Wiklander
optee_allocate_pages_list(size_t num_entries)377c51a564aSJens Wiklander static u64 *optee_allocate_pages_list(size_t num_entries)
378c51a564aSJens Wiklander {
379c51a564aSJens Wiklander return alloc_pages_exact(get_pages_list_size(num_entries), GFP_KERNEL);
380c51a564aSJens Wiklander }
381c51a564aSJens Wiklander
optee_free_pages_list(void * list,size_t num_entries)382c51a564aSJens Wiklander static void optee_free_pages_list(void *list, size_t num_entries)
383c51a564aSJens Wiklander {
384c51a564aSJens Wiklander free_pages_exact(list, get_pages_list_size(num_entries));
385c51a564aSJens Wiklander }
386c51a564aSJens Wiklander
387c51a564aSJens Wiklander /**
388c51a564aSJens Wiklander * optee_fill_pages_list() - write list of user pages to given shared
389c51a564aSJens Wiklander * buffer.
390c51a564aSJens Wiklander *
391c51a564aSJens Wiklander * @dst: page-aligned buffer where list of pages will be stored
392c51a564aSJens Wiklander * @pages: array of pages that represents shared buffer
393c51a564aSJens Wiklander * @num_pages: number of entries in @pages
394c51a564aSJens Wiklander * @page_offset: offset of user buffer from page start
395c51a564aSJens Wiklander *
396c51a564aSJens Wiklander * @dst should be big enough to hold list of user page addresses and
397c51a564aSJens Wiklander * links to the next pages of buffer
398c51a564aSJens Wiklander */
optee_fill_pages_list(u64 * dst,struct page ** pages,int num_pages,size_t page_offset)399c51a564aSJens Wiklander static void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
400c51a564aSJens Wiklander size_t page_offset)
401c51a564aSJens Wiklander {
402c51a564aSJens Wiklander int n = 0;
403c51a564aSJens Wiklander phys_addr_t optee_page;
404c51a564aSJens Wiklander /*
405c51a564aSJens Wiklander * Refer to OPTEE_MSG_ATTR_NONCONTIG description in optee_msg.h
406c51a564aSJens Wiklander * for details.
407c51a564aSJens Wiklander */
408c51a564aSJens Wiklander struct {
409c51a564aSJens Wiklander u64 pages_list[PAGELIST_ENTRIES_PER_PAGE];
410c51a564aSJens Wiklander u64 next_page_data;
411c51a564aSJens Wiklander } *pages_data;
412c51a564aSJens Wiklander
413c51a564aSJens Wiklander /*
414c51a564aSJens Wiklander * Currently OP-TEE uses 4k page size and it does not looks
415c51a564aSJens Wiklander * like this will change in the future. On other hand, there are
416c51a564aSJens Wiklander * no know ARM architectures with page size < 4k.
417c51a564aSJens Wiklander * Thus the next built assert looks redundant. But the following
418c51a564aSJens Wiklander * code heavily relies on this assumption, so it is better be
419c51a564aSJens Wiklander * safe than sorry.
420c51a564aSJens Wiklander */
421c51a564aSJens Wiklander BUILD_BUG_ON(PAGE_SIZE < OPTEE_MSG_NONCONTIG_PAGE_SIZE);
422c51a564aSJens Wiklander
423c51a564aSJens Wiklander pages_data = (void *)dst;
424c51a564aSJens Wiklander /*
425c51a564aSJens Wiklander * If linux page is bigger than 4k, and user buffer offset is
426c51a564aSJens Wiklander * larger than 4k/8k/12k/etc this will skip first 4k pages,
427c51a564aSJens Wiklander * because they bear no value data for OP-TEE.
428c51a564aSJens Wiklander */
429c51a564aSJens Wiklander optee_page = page_to_phys(*pages) +
430c51a564aSJens Wiklander round_down(page_offset, OPTEE_MSG_NONCONTIG_PAGE_SIZE);
431c51a564aSJens Wiklander
432c51a564aSJens Wiklander while (true) {
433c51a564aSJens Wiklander pages_data->pages_list[n++] = optee_page;
434c51a564aSJens Wiklander
435c51a564aSJens Wiklander if (n == PAGELIST_ENTRIES_PER_PAGE) {
436c51a564aSJens Wiklander pages_data->next_page_data =
437c51a564aSJens Wiklander virt_to_phys(pages_data + 1);
438c51a564aSJens Wiklander pages_data++;
439c51a564aSJens Wiklander n = 0;
440c51a564aSJens Wiklander }
441c51a564aSJens Wiklander
442c51a564aSJens Wiklander optee_page += OPTEE_MSG_NONCONTIG_PAGE_SIZE;
443c51a564aSJens Wiklander if (!(optee_page & ~PAGE_MASK)) {
444c51a564aSJens Wiklander if (!--num_pages)
445c51a564aSJens Wiklander break;
446c51a564aSJens Wiklander pages++;
447c51a564aSJens Wiklander optee_page = page_to_phys(*pages);
448c51a564aSJens Wiklander }
449c51a564aSJens Wiklander }
450c51a564aSJens Wiklander }
451c51a564aSJens Wiklander
optee_shm_register(struct tee_context * ctx,struct tee_shm * shm,struct page ** pages,size_t num_pages,unsigned long start)452c51a564aSJens Wiklander static int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
453c51a564aSJens Wiklander struct page **pages, size_t num_pages,
454c51a564aSJens Wiklander unsigned long start)
455c51a564aSJens Wiklander {
456c51a564aSJens Wiklander struct optee *optee = tee_get_drvdata(ctx->teedev);
457c51a564aSJens Wiklander struct optee_msg_arg *msg_arg;
458c51a564aSJens Wiklander struct tee_shm *shm_arg;
459c51a564aSJens Wiklander u64 *pages_list;
4605b4018b9SJens Wiklander size_t sz;
461c51a564aSJens Wiklander int rc;
462c51a564aSJens Wiklander
463c51a564aSJens Wiklander if (!num_pages)
464c51a564aSJens Wiklander return -EINVAL;
465c51a564aSJens Wiklander
466c51a564aSJens Wiklander rc = optee_check_mem_type(start, num_pages);
467c51a564aSJens Wiklander if (rc)
468c51a564aSJens Wiklander return rc;
469c51a564aSJens Wiklander
470c51a564aSJens Wiklander pages_list = optee_allocate_pages_list(num_pages);
471c51a564aSJens Wiklander if (!pages_list)
472c51a564aSJens Wiklander return -ENOMEM;
473c51a564aSJens Wiklander
4745b4018b9SJens Wiklander /*
4755b4018b9SJens Wiklander * We're about to register shared memory we can't register shared
4765b4018b9SJens Wiklander * memory for this request or there's a catch-22.
4775b4018b9SJens Wiklander *
4785b4018b9SJens Wiklander * So in this we'll have to do the good old temporary private
4795b4018b9SJens Wiklander * allocation instead of using optee_get_msg_arg().
4805b4018b9SJens Wiklander */
4815b4018b9SJens Wiklander sz = optee_msg_arg_size(optee->rpc_param_count);
4825b4018b9SJens Wiklander shm_arg = tee_shm_alloc_priv_buf(ctx, sz);
483c51a564aSJens Wiklander if (IS_ERR(shm_arg)) {
484c51a564aSJens Wiklander rc = PTR_ERR(shm_arg);
485c51a564aSJens Wiklander goto out;
486c51a564aSJens Wiklander }
4875b4018b9SJens Wiklander msg_arg = tee_shm_get_va(shm_arg, 0);
4885b4018b9SJens Wiklander if (IS_ERR(msg_arg)) {
4895b4018b9SJens Wiklander rc = PTR_ERR(msg_arg);
4905b4018b9SJens Wiklander goto out;
4915b4018b9SJens Wiklander }
492c51a564aSJens Wiklander
493c51a564aSJens Wiklander optee_fill_pages_list(pages_list, pages, num_pages,
494c51a564aSJens Wiklander tee_shm_get_page_offset(shm));
495c51a564aSJens Wiklander
4965b4018b9SJens Wiklander memset(msg_arg, 0, OPTEE_MSG_GET_ARG_SIZE(1));
4975b4018b9SJens Wiklander msg_arg->num_params = 1;
498c51a564aSJens Wiklander msg_arg->cmd = OPTEE_MSG_CMD_REGISTER_SHM;
499c51a564aSJens Wiklander msg_arg->params->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
500c51a564aSJens Wiklander OPTEE_MSG_ATTR_NONCONTIG;
501c51a564aSJens Wiklander msg_arg->params->u.tmem.shm_ref = (unsigned long)shm;
502c51a564aSJens Wiklander msg_arg->params->u.tmem.size = tee_shm_get_size(shm);
503c51a564aSJens Wiklander /*
504c51a564aSJens Wiklander * In the least bits of msg_arg->params->u.tmem.buf_ptr we
505c51a564aSJens Wiklander * store buffer offset from 4k page, as described in OP-TEE ABI.
506c51a564aSJens Wiklander */
507c51a564aSJens Wiklander msg_arg->params->u.tmem.buf_ptr = virt_to_phys(pages_list) |
508c51a564aSJens Wiklander (tee_shm_get_page_offset(shm) & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
509c51a564aSJens Wiklander
5105b4018b9SJens Wiklander if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) ||
511c51a564aSJens Wiklander msg_arg->ret != TEEC_SUCCESS)
512c51a564aSJens Wiklander rc = -EINVAL;
513c51a564aSJens Wiklander
514c51a564aSJens Wiklander tee_shm_free(shm_arg);
515c51a564aSJens Wiklander out:
516c51a564aSJens Wiklander optee_free_pages_list(pages_list, num_pages);
517c51a564aSJens Wiklander return rc;
518c51a564aSJens Wiklander }
519c51a564aSJens Wiklander
optee_shm_unregister(struct tee_context * ctx,struct tee_shm * shm)520c51a564aSJens Wiklander static int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
521c51a564aSJens Wiklander {
522c51a564aSJens Wiklander struct optee *optee = tee_get_drvdata(ctx->teedev);
523c51a564aSJens Wiklander struct optee_msg_arg *msg_arg;
524c51a564aSJens Wiklander struct tee_shm *shm_arg;
525c51a564aSJens Wiklander int rc = 0;
5265b4018b9SJens Wiklander size_t sz;
527c51a564aSJens Wiklander
5285b4018b9SJens Wiklander /*
5295b4018b9SJens Wiklander * We're about to unregister shared memory and we may not be able
5305b4018b9SJens Wiklander * register shared memory for this request in case we're called
5315b4018b9SJens Wiklander * from optee_shm_arg_cache_uninit().
5325b4018b9SJens Wiklander *
5335b4018b9SJens Wiklander * So in order to keep things simple in this function just as in
5345b4018b9SJens Wiklander * optee_shm_register() we'll use temporary private allocation
5355b4018b9SJens Wiklander * instead of using optee_get_msg_arg().
5365b4018b9SJens Wiklander */
5375b4018b9SJens Wiklander sz = optee_msg_arg_size(optee->rpc_param_count);
5385b4018b9SJens Wiklander shm_arg = tee_shm_alloc_priv_buf(ctx, sz);
539c51a564aSJens Wiklander if (IS_ERR(shm_arg))
540c51a564aSJens Wiklander return PTR_ERR(shm_arg);
5415b4018b9SJens Wiklander msg_arg = tee_shm_get_va(shm_arg, 0);
5425b4018b9SJens Wiklander if (IS_ERR(msg_arg)) {
5435b4018b9SJens Wiklander rc = PTR_ERR(msg_arg);
5445b4018b9SJens Wiklander goto out;
5455b4018b9SJens Wiklander }
546c51a564aSJens Wiklander
5475b4018b9SJens Wiklander memset(msg_arg, 0, sz);
5485b4018b9SJens Wiklander msg_arg->num_params = 1;
549c51a564aSJens Wiklander msg_arg->cmd = OPTEE_MSG_CMD_UNREGISTER_SHM;
550c51a564aSJens Wiklander msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
551c51a564aSJens Wiklander msg_arg->params[0].u.rmem.shm_ref = (unsigned long)shm;
552c51a564aSJens Wiklander
5535b4018b9SJens Wiklander if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) ||
554c51a564aSJens Wiklander msg_arg->ret != TEEC_SUCCESS)
555c51a564aSJens Wiklander rc = -EINVAL;
5565b4018b9SJens Wiklander out:
557c51a564aSJens Wiklander tee_shm_free(shm_arg);
558c51a564aSJens Wiklander return rc;
559c51a564aSJens Wiklander }
560c51a564aSJens Wiklander
optee_shm_register_supp(struct tee_context * ctx,struct tee_shm * shm,struct page ** pages,size_t num_pages,unsigned long start)561c51a564aSJens Wiklander static int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
562c51a564aSJens Wiklander struct page **pages, size_t num_pages,
563c51a564aSJens Wiklander unsigned long start)
564c51a564aSJens Wiklander {
565c51a564aSJens Wiklander /*
566c51a564aSJens Wiklander * We don't want to register supplicant memory in OP-TEE.
567c51a564aSJens Wiklander * Instead information about it will be passed in RPC code.
568c51a564aSJens Wiklander */
569c51a564aSJens Wiklander return optee_check_mem_type(start, num_pages);
570c51a564aSJens Wiklander }
571c51a564aSJens Wiklander
optee_shm_unregister_supp(struct tee_context * ctx,struct tee_shm * shm)572c51a564aSJens Wiklander static int optee_shm_unregister_supp(struct tee_context *ctx,
573c51a564aSJens Wiklander struct tee_shm *shm)
574c51a564aSJens Wiklander {
575c51a564aSJens Wiklander return 0;
576c51a564aSJens Wiklander }
577c51a564aSJens Wiklander
578c51a564aSJens Wiklander /*
579c51a564aSJens Wiklander * 3. Dynamic shared memory pool based on alloc_pages()
580c51a564aSJens Wiklander *
581c51a564aSJens Wiklander * Implements an OP-TEE specific shared memory pool which is used
582c51a564aSJens Wiklander * when dynamic shared memory is supported by secure world.
583c51a564aSJens Wiklander *
584c51a564aSJens Wiklander * The main function is optee_shm_pool_alloc_pages().
585c51a564aSJens Wiklander */
586c51a564aSJens Wiklander
pool_op_alloc(struct tee_shm_pool * pool,struct tee_shm * shm,size_t size,size_t align)587d88e0493SJens Wiklander static int pool_op_alloc(struct tee_shm_pool *pool,
588d88e0493SJens Wiklander struct tee_shm *shm, size_t size, size_t align)
589c51a564aSJens Wiklander {
590c51a564aSJens Wiklander /*
591c51a564aSJens Wiklander * Shared memory private to the OP-TEE driver doesn't need
592c51a564aSJens Wiklander * to be registered with OP-TEE.
593c51a564aSJens Wiklander */
594c51a564aSJens Wiklander if (shm->flags & TEE_SHM_PRIV)
595d88e0493SJens Wiklander return optee_pool_op_alloc_helper(pool, shm, size, align, NULL);
596c51a564aSJens Wiklander
597d88e0493SJens Wiklander return optee_pool_op_alloc_helper(pool, shm, size, align,
598d88e0493SJens Wiklander optee_shm_register);
599c51a564aSJens Wiklander }
600c51a564aSJens Wiklander
pool_op_free(struct tee_shm_pool * pool,struct tee_shm * shm)601d88e0493SJens Wiklander static void pool_op_free(struct tee_shm_pool *pool,
602c51a564aSJens Wiklander struct tee_shm *shm)
603c51a564aSJens Wiklander {
604c51a564aSJens Wiklander if (!(shm->flags & TEE_SHM_PRIV))
605924e3226SJens Wiklander optee_pool_op_free_helper(pool, shm, optee_shm_unregister);
606924e3226SJens Wiklander else
607924e3226SJens Wiklander optee_pool_op_free_helper(pool, shm, NULL);
608c51a564aSJens Wiklander }
609c51a564aSJens Wiklander
pool_op_destroy_pool(struct tee_shm_pool * pool)610d88e0493SJens Wiklander static void pool_op_destroy_pool(struct tee_shm_pool *pool)
611c51a564aSJens Wiklander {
612d88e0493SJens Wiklander kfree(pool);
613c51a564aSJens Wiklander }
614c51a564aSJens Wiklander
615d88e0493SJens Wiklander static const struct tee_shm_pool_ops pool_ops = {
616c51a564aSJens Wiklander .alloc = pool_op_alloc,
617c51a564aSJens Wiklander .free = pool_op_free,
618d88e0493SJens Wiklander .destroy_pool = pool_op_destroy_pool,
619c51a564aSJens Wiklander };
620c51a564aSJens Wiklander
621c51a564aSJens Wiklander /**
622c51a564aSJens Wiklander * optee_shm_pool_alloc_pages() - create page-based allocator pool
623c51a564aSJens Wiklander *
624c51a564aSJens Wiklander * This pool is used when OP-TEE supports dymanic SHM. In this case
625c51a564aSJens Wiklander * command buffers and such are allocated from kernel's own memory.
626c51a564aSJens Wiklander */
optee_shm_pool_alloc_pages(void)627d88e0493SJens Wiklander static struct tee_shm_pool *optee_shm_pool_alloc_pages(void)
628c51a564aSJens Wiklander {
629d88e0493SJens Wiklander struct tee_shm_pool *pool = kzalloc(sizeof(*pool), GFP_KERNEL);
630c51a564aSJens Wiklander
631d88e0493SJens Wiklander if (!pool)
632c51a564aSJens Wiklander return ERR_PTR(-ENOMEM);
633c51a564aSJens Wiklander
634d88e0493SJens Wiklander pool->ops = &pool_ops;
635c51a564aSJens Wiklander
636d88e0493SJens Wiklander return pool;
637c51a564aSJens Wiklander }
638c51a564aSJens Wiklander
639c51a564aSJens Wiklander /*
640c51a564aSJens Wiklander * 4. Do a normal scheduled call into secure world
641c51a564aSJens Wiklander *
642c51a564aSJens Wiklander * The function optee_smc_do_call_with_arg() performs a normal scheduled
643c51a564aSJens Wiklander * call into secure world. During this call may normal world request help
644c51a564aSJens Wiklander * from normal world using RPCs, Remote Procedure Calls. This includes
645c51a564aSJens Wiklander * delivery of non-secure interrupts to for instance allow rescheduling of
646c51a564aSJens Wiklander * the current task.
647c51a564aSJens Wiklander */
648c51a564aSJens Wiklander
handle_rpc_func_cmd_shm_free(struct tee_context * ctx,struct optee_msg_arg * arg)649c51a564aSJens Wiklander static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
650c51a564aSJens Wiklander struct optee_msg_arg *arg)
651c51a564aSJens Wiklander {
652c51a564aSJens Wiklander struct tee_shm *shm;
653c51a564aSJens Wiklander
654c51a564aSJens Wiklander arg->ret_origin = TEEC_ORIGIN_COMMS;
655c51a564aSJens Wiklander
656c51a564aSJens Wiklander if (arg->num_params != 1 ||
657c51a564aSJens Wiklander arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
658c51a564aSJens Wiklander arg->ret = TEEC_ERROR_BAD_PARAMETERS;
659c51a564aSJens Wiklander return;
660c51a564aSJens Wiklander }
661c51a564aSJens Wiklander
662c51a564aSJens Wiklander shm = (struct tee_shm *)(unsigned long)arg->params[0].u.value.b;
663c51a564aSJens Wiklander switch (arg->params[0].u.value.a) {
664c51a564aSJens Wiklander case OPTEE_RPC_SHM_TYPE_APPL:
665c51a564aSJens Wiklander optee_rpc_cmd_free_suppl(ctx, shm);
666c51a564aSJens Wiklander break;
667c51a564aSJens Wiklander case OPTEE_RPC_SHM_TYPE_KERNEL:
668c51a564aSJens Wiklander tee_shm_free(shm);
669c51a564aSJens Wiklander break;
670c51a564aSJens Wiklander default:
671c51a564aSJens Wiklander arg->ret = TEEC_ERROR_BAD_PARAMETERS;
672c51a564aSJens Wiklander }
673c51a564aSJens Wiklander arg->ret = TEEC_SUCCESS;
674c51a564aSJens Wiklander }
675c51a564aSJens Wiklander
handle_rpc_func_cmd_shm_alloc(struct tee_context * ctx,struct optee * optee,struct optee_msg_arg * arg,struct optee_call_ctx * call_ctx)676c51a564aSJens Wiklander static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
677aceeafefSJens Wiklander struct optee *optee,
678c51a564aSJens Wiklander struct optee_msg_arg *arg,
679c51a564aSJens Wiklander struct optee_call_ctx *call_ctx)
680c51a564aSJens Wiklander {
681c51a564aSJens Wiklander phys_addr_t pa;
682c51a564aSJens Wiklander struct tee_shm *shm;
683c51a564aSJens Wiklander size_t sz;
684c51a564aSJens Wiklander size_t n;
685c51a564aSJens Wiklander
686c51a564aSJens Wiklander arg->ret_origin = TEEC_ORIGIN_COMMS;
687c51a564aSJens Wiklander
688c51a564aSJens Wiklander if (!arg->num_params ||
689c51a564aSJens Wiklander arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
690c51a564aSJens Wiklander arg->ret = TEEC_ERROR_BAD_PARAMETERS;
691c51a564aSJens Wiklander return;
692c51a564aSJens Wiklander }
693c51a564aSJens Wiklander
694c51a564aSJens Wiklander for (n = 1; n < arg->num_params; n++) {
695c51a564aSJens Wiklander if (arg->params[n].attr != OPTEE_MSG_ATTR_TYPE_NONE) {
696c51a564aSJens Wiklander arg->ret = TEEC_ERROR_BAD_PARAMETERS;
697c51a564aSJens Wiklander return;
698c51a564aSJens Wiklander }
699c51a564aSJens Wiklander }
700c51a564aSJens Wiklander
701c51a564aSJens Wiklander sz = arg->params[0].u.value.b;
702c51a564aSJens Wiklander switch (arg->params[0].u.value.a) {
703c51a564aSJens Wiklander case OPTEE_RPC_SHM_TYPE_APPL:
704c51a564aSJens Wiklander shm = optee_rpc_cmd_alloc_suppl(ctx, sz);
705c51a564aSJens Wiklander break;
706c51a564aSJens Wiklander case OPTEE_RPC_SHM_TYPE_KERNEL:
7075d41f1b3SJens Wiklander shm = tee_shm_alloc_priv_buf(optee->ctx, sz);
708c51a564aSJens Wiklander break;
709c51a564aSJens Wiklander default:
710c51a564aSJens Wiklander arg->ret = TEEC_ERROR_BAD_PARAMETERS;
711c51a564aSJens Wiklander return;
712c51a564aSJens Wiklander }
713c51a564aSJens Wiklander
714c51a564aSJens Wiklander if (IS_ERR(shm)) {
715c51a564aSJens Wiklander arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
716c51a564aSJens Wiklander return;
717c51a564aSJens Wiklander }
718c51a564aSJens Wiklander
719c51a564aSJens Wiklander if (tee_shm_get_pa(shm, 0, &pa)) {
720c51a564aSJens Wiklander arg->ret = TEEC_ERROR_BAD_PARAMETERS;
721c51a564aSJens Wiklander goto bad;
722c51a564aSJens Wiklander }
723c51a564aSJens Wiklander
724c51a564aSJens Wiklander sz = tee_shm_get_size(shm);
725c51a564aSJens Wiklander
726a45ea4efSJens Wiklander if (tee_shm_is_dynamic(shm)) {
727c51a564aSJens Wiklander struct page **pages;
728c51a564aSJens Wiklander u64 *pages_list;
729c51a564aSJens Wiklander size_t page_num;
730c51a564aSJens Wiklander
731c51a564aSJens Wiklander pages = tee_shm_get_pages(shm, &page_num);
732c51a564aSJens Wiklander if (!pages || !page_num) {
733c51a564aSJens Wiklander arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
734c51a564aSJens Wiklander goto bad;
735c51a564aSJens Wiklander }
736c51a564aSJens Wiklander
737c51a564aSJens Wiklander pages_list = optee_allocate_pages_list(page_num);
738c51a564aSJens Wiklander if (!pages_list) {
739c51a564aSJens Wiklander arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
740c51a564aSJens Wiklander goto bad;
741c51a564aSJens Wiklander }
742c51a564aSJens Wiklander
743c51a564aSJens Wiklander call_ctx->pages_list = pages_list;
744c51a564aSJens Wiklander call_ctx->num_entries = page_num;
745c51a564aSJens Wiklander
746c51a564aSJens Wiklander arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
747c51a564aSJens Wiklander OPTEE_MSG_ATTR_NONCONTIG;
748c51a564aSJens Wiklander /*
749c51a564aSJens Wiklander * In the least bits of u.tmem.buf_ptr we store buffer offset
750c51a564aSJens Wiklander * from 4k page, as described in OP-TEE ABI.
751c51a564aSJens Wiklander */
752c51a564aSJens Wiklander arg->params[0].u.tmem.buf_ptr = virt_to_phys(pages_list) |
753c51a564aSJens Wiklander (tee_shm_get_page_offset(shm) &
754c51a564aSJens Wiklander (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
755c51a564aSJens Wiklander arg->params[0].u.tmem.size = tee_shm_get_size(shm);
756c51a564aSJens Wiklander arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
757c51a564aSJens Wiklander
758c51a564aSJens Wiklander optee_fill_pages_list(pages_list, pages, page_num,
759c51a564aSJens Wiklander tee_shm_get_page_offset(shm));
760c51a564aSJens Wiklander } else {
761c51a564aSJens Wiklander arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
762c51a564aSJens Wiklander arg->params[0].u.tmem.buf_ptr = pa;
763c51a564aSJens Wiklander arg->params[0].u.tmem.size = sz;
764c51a564aSJens Wiklander arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
765c51a564aSJens Wiklander }
766c51a564aSJens Wiklander
767c51a564aSJens Wiklander arg->ret = TEEC_SUCCESS;
768c51a564aSJens Wiklander return;
769c51a564aSJens Wiklander bad:
770c51a564aSJens Wiklander tee_shm_free(shm);
771c51a564aSJens Wiklander }
772c51a564aSJens Wiklander
free_pages_list(struct optee_call_ctx * call_ctx)773c51a564aSJens Wiklander static void free_pages_list(struct optee_call_ctx *call_ctx)
774c51a564aSJens Wiklander {
775c51a564aSJens Wiklander if (call_ctx->pages_list) {
776c51a564aSJens Wiklander optee_free_pages_list(call_ctx->pages_list,
777c51a564aSJens Wiklander call_ctx->num_entries);
778c51a564aSJens Wiklander call_ctx->pages_list = NULL;
779c51a564aSJens Wiklander call_ctx->num_entries = 0;
780c51a564aSJens Wiklander }
781c51a564aSJens Wiklander }
782c51a564aSJens Wiklander
optee_rpc_finalize_call(struct optee_call_ctx * call_ctx)783c51a564aSJens Wiklander static void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx)
784c51a564aSJens Wiklander {
785c51a564aSJens Wiklander free_pages_list(call_ctx);
786c51a564aSJens Wiklander }
787c51a564aSJens Wiklander
handle_rpc_func_cmd(struct tee_context * ctx,struct optee * optee,struct optee_msg_arg * arg,struct optee_call_ctx * call_ctx)788c51a564aSJens Wiklander static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
789ed8faf6cSJens Wiklander struct optee_msg_arg *arg,
790c51a564aSJens Wiklander struct optee_call_ctx *call_ctx)
791c51a564aSJens Wiklander {
792c51a564aSJens Wiklander
793c51a564aSJens Wiklander switch (arg->cmd) {
794c51a564aSJens Wiklander case OPTEE_RPC_CMD_SHM_ALLOC:
795c51a564aSJens Wiklander free_pages_list(call_ctx);
796aceeafefSJens Wiklander handle_rpc_func_cmd_shm_alloc(ctx, optee, arg, call_ctx);
797c51a564aSJens Wiklander break;
798c51a564aSJens Wiklander case OPTEE_RPC_CMD_SHM_FREE:
799c51a564aSJens Wiklander handle_rpc_func_cmd_shm_free(ctx, arg);
800c51a564aSJens Wiklander break;
801c51a564aSJens Wiklander default:
802c51a564aSJens Wiklander optee_rpc_cmd(ctx, optee, arg);
803c51a564aSJens Wiklander }
804c51a564aSJens Wiklander }
805c51a564aSJens Wiklander
806c51a564aSJens Wiklander /**
807c51a564aSJens Wiklander * optee_handle_rpc() - handle RPC from secure world
808c51a564aSJens Wiklander * @ctx: context doing the RPC
809c51a564aSJens Wiklander * @param: value of registers for the RPC
810c51a564aSJens Wiklander * @call_ctx: call context. Preserved during one OP-TEE invocation
811c51a564aSJens Wiklander *
812c51a564aSJens Wiklander * Result of RPC is written back into @param.
813c51a564aSJens Wiklander */
optee_handle_rpc(struct tee_context * ctx,struct optee_msg_arg * rpc_arg,struct optee_rpc_param * param,struct optee_call_ctx * call_ctx)814c51a564aSJens Wiklander static void optee_handle_rpc(struct tee_context *ctx,
815ed8faf6cSJens Wiklander struct optee_msg_arg *rpc_arg,
816c51a564aSJens Wiklander struct optee_rpc_param *param,
817c51a564aSJens Wiklander struct optee_call_ctx *call_ctx)
818c51a564aSJens Wiklander {
819c51a564aSJens Wiklander struct tee_device *teedev = ctx->teedev;
820c51a564aSJens Wiklander struct optee *optee = tee_get_drvdata(teedev);
821ed8faf6cSJens Wiklander struct optee_msg_arg *arg;
822c51a564aSJens Wiklander struct tee_shm *shm;
823c51a564aSJens Wiklander phys_addr_t pa;
824c51a564aSJens Wiklander
825c51a564aSJens Wiklander switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
826c51a564aSJens Wiklander case OPTEE_SMC_RPC_FUNC_ALLOC:
8275d41f1b3SJens Wiklander shm = tee_shm_alloc_priv_buf(optee->ctx, param->a1);
828c51a564aSJens Wiklander if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
829c51a564aSJens Wiklander reg_pair_from_64(¶m->a1, ¶m->a2, pa);
830c51a564aSJens Wiklander reg_pair_from_64(¶m->a4, ¶m->a5,
831c51a564aSJens Wiklander (unsigned long)shm);
832c51a564aSJens Wiklander } else {
833c51a564aSJens Wiklander param->a1 = 0;
834c51a564aSJens Wiklander param->a2 = 0;
835c51a564aSJens Wiklander param->a4 = 0;
836c51a564aSJens Wiklander param->a5 = 0;
837c51a564aSJens Wiklander }
8386add87fdSXiaolei Wang kmemleak_not_leak(shm);
839c51a564aSJens Wiklander break;
840c51a564aSJens Wiklander case OPTEE_SMC_RPC_FUNC_FREE:
841c51a564aSJens Wiklander shm = reg_pair_to_ptr(param->a1, param->a2);
842c51a564aSJens Wiklander tee_shm_free(shm);
843c51a564aSJens Wiklander break;
844c51a564aSJens Wiklander case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
845c51a564aSJens Wiklander /*
846c51a564aSJens Wiklander * A foreign interrupt was raised while secure world was
847c51a564aSJens Wiklander * executing, since they are handled in Linux a dummy RPC is
848c51a564aSJens Wiklander * performed to let Linux take the interrupt through the normal
849c51a564aSJens Wiklander * vector.
850c51a564aSJens Wiklander */
851c51a564aSJens Wiklander break;
852c51a564aSJens Wiklander case OPTEE_SMC_RPC_FUNC_CMD:
853ed8faf6cSJens Wiklander if (rpc_arg) {
854ed8faf6cSJens Wiklander arg = rpc_arg;
855ed8faf6cSJens Wiklander } else {
856c51a564aSJens Wiklander shm = reg_pair_to_ptr(param->a1, param->a2);
857ed8faf6cSJens Wiklander arg = tee_shm_get_va(shm, 0);
858ed8faf6cSJens Wiklander if (IS_ERR(arg)) {
859ed8faf6cSJens Wiklander pr_err("%s: tee_shm_get_va %p failed\n",
860ed8faf6cSJens Wiklander __func__, shm);
861ed8faf6cSJens Wiklander break;
862ed8faf6cSJens Wiklander }
863ed8faf6cSJens Wiklander }
864ed8faf6cSJens Wiklander
865ed8faf6cSJens Wiklander handle_rpc_func_cmd(ctx, optee, arg, call_ctx);
866c51a564aSJens Wiklander break;
867c51a564aSJens Wiklander default:
868c51a564aSJens Wiklander pr_warn("Unknown RPC func 0x%x\n",
869c51a564aSJens Wiklander (u32)OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0));
870c51a564aSJens Wiklander break;
871c51a564aSJens Wiklander }
872c51a564aSJens Wiklander
873c51a564aSJens Wiklander param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
874c51a564aSJens Wiklander }
875c51a564aSJens Wiklander
876c51a564aSJens Wiklander /**
877c51a564aSJens Wiklander * optee_smc_do_call_with_arg() - Do an SMC to OP-TEE in secure world
878c51a564aSJens Wiklander * @ctx: calling context
879ed8faf6cSJens Wiklander * @shm: shared memory holding the message to pass to secure world
8805b4018b9SJens Wiklander * @offs: offset of the message in @shm
881c51a564aSJens Wiklander *
882c51a564aSJens Wiklander * Does and SMC to OP-TEE in secure world and handles eventual resulting
883c51a564aSJens Wiklander * Remote Procedure Calls (RPC) from OP-TEE.
884c51a564aSJens Wiklander *
885c51a564aSJens Wiklander * Returns return code from secure world, 0 is OK
886c51a564aSJens Wiklander */
optee_smc_do_call_with_arg(struct tee_context * ctx,struct tee_shm * shm,u_int offs)887c51a564aSJens Wiklander static int optee_smc_do_call_with_arg(struct tee_context *ctx,
8885b4018b9SJens Wiklander struct tee_shm *shm, u_int offs)
889c51a564aSJens Wiklander {
890c51a564aSJens Wiklander struct optee *optee = tee_get_drvdata(ctx->teedev);
891c51a564aSJens Wiklander struct optee_call_waiter w;
892c51a564aSJens Wiklander struct optee_rpc_param param = { };
893c51a564aSJens Wiklander struct optee_call_ctx call_ctx = { };
894ed8faf6cSJens Wiklander struct optee_msg_arg *rpc_arg = NULL;
895c51a564aSJens Wiklander int rc;
896c51a564aSJens Wiklander
897ed8faf6cSJens Wiklander if (optee->rpc_param_count) {
898ed8faf6cSJens Wiklander struct optee_msg_arg *arg;
899ed8faf6cSJens Wiklander unsigned int rpc_arg_offs;
900ed8faf6cSJens Wiklander
9015b4018b9SJens Wiklander arg = tee_shm_get_va(shm, offs);
902ed8faf6cSJens Wiklander if (IS_ERR(arg))
903ed8faf6cSJens Wiklander return PTR_ERR(arg);
904ed8faf6cSJens Wiklander
905ed8faf6cSJens Wiklander rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
9065b4018b9SJens Wiklander rpc_arg = tee_shm_get_va(shm, offs + rpc_arg_offs);
907d4fac258SYang Yingliang if (IS_ERR(rpc_arg))
908d4fac258SYang Yingliang return PTR_ERR(rpc_arg);
909ed8faf6cSJens Wiklander }
910ed8faf6cSJens Wiklander
911ed8faf6cSJens Wiklander if (rpc_arg && tee_shm_is_dynamic(shm)) {
912ed8faf6cSJens Wiklander param.a0 = OPTEE_SMC_CALL_WITH_REGD_ARG;
913ed8faf6cSJens Wiklander reg_pair_from_64(¶m.a1, ¶m.a2, (u_long)shm);
9145b4018b9SJens Wiklander param.a3 = offs;
915ed8faf6cSJens Wiklander } else {
916ed8faf6cSJens Wiklander phys_addr_t parg;
917ed8faf6cSJens Wiklander
9185b4018b9SJens Wiklander rc = tee_shm_get_pa(shm, offs, &parg);
919c51a564aSJens Wiklander if (rc)
920c51a564aSJens Wiklander return rc;
921c51a564aSJens Wiklander
922ed8faf6cSJens Wiklander if (rpc_arg)
923ed8faf6cSJens Wiklander param.a0 = OPTEE_SMC_CALL_WITH_RPC_ARG;
924ed8faf6cSJens Wiklander else
925c51a564aSJens Wiklander param.a0 = OPTEE_SMC_CALL_WITH_ARG;
926c51a564aSJens Wiklander reg_pair_from_64(¶m.a1, ¶m.a2, parg);
927ed8faf6cSJens Wiklander }
928c51a564aSJens Wiklander /* Initialize waiter */
929c51a564aSJens Wiklander optee_cq_wait_init(&optee->call_queue, &w);
930c51a564aSJens Wiklander while (true) {
931c51a564aSJens Wiklander struct arm_smccc_res res;
932c51a564aSJens Wiklander
933c51a564aSJens Wiklander trace_optee_invoke_fn_begin(¶m);
934c51a564aSJens Wiklander optee->smc.invoke_fn(param.a0, param.a1, param.a2, param.a3,
935c51a564aSJens Wiklander param.a4, param.a5, param.a6, param.a7,
936c51a564aSJens Wiklander &res);
937c51a564aSJens Wiklander trace_optee_invoke_fn_end(¶m, &res);
938c51a564aSJens Wiklander
939c51a564aSJens Wiklander if (res.a0 == OPTEE_SMC_RETURN_ETHREAD_LIMIT) {
940c51a564aSJens Wiklander /*
941c51a564aSJens Wiklander * Out of threads in secure world, wait for a thread
942c51a564aSJens Wiklander * become available.
943c51a564aSJens Wiklander */
944c51a564aSJens Wiklander optee_cq_wait_for_completion(&optee->call_queue, &w);
945c51a564aSJens Wiklander } else if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
946c51a564aSJens Wiklander cond_resched();
947c51a564aSJens Wiklander param.a0 = res.a0;
948c51a564aSJens Wiklander param.a1 = res.a1;
949c51a564aSJens Wiklander param.a2 = res.a2;
950c51a564aSJens Wiklander param.a3 = res.a3;
951ed8faf6cSJens Wiklander optee_handle_rpc(ctx, rpc_arg, ¶m, &call_ctx);
952c51a564aSJens Wiklander } else {
953c51a564aSJens Wiklander rc = res.a0;
954c51a564aSJens Wiklander break;
955c51a564aSJens Wiklander }
956c51a564aSJens Wiklander }
957c51a564aSJens Wiklander
958c51a564aSJens Wiklander optee_rpc_finalize_call(&call_ctx);
959c51a564aSJens Wiklander /*
960c51a564aSJens Wiklander * We're done with our thread in secure world, if there's any
961c51a564aSJens Wiklander * thread waiters wake up one.
962c51a564aSJens Wiklander */
963c51a564aSJens Wiklander optee_cq_wait_final(&optee->call_queue, &w);
964c51a564aSJens Wiklander
965c51a564aSJens Wiklander return rc;
966c51a564aSJens Wiklander }
967c51a564aSJens Wiklander
simple_call_with_arg(struct tee_context * ctx,u32 cmd)9686749e69cSJens Wiklander static int simple_call_with_arg(struct tee_context *ctx, u32 cmd)
9696749e69cSJens Wiklander {
9705b4018b9SJens Wiklander struct optee_shm_arg_entry *entry;
9716749e69cSJens Wiklander struct optee_msg_arg *msg_arg;
9726749e69cSJens Wiklander struct tee_shm *shm;
9735b4018b9SJens Wiklander u_int offs;
9746749e69cSJens Wiklander
9755b4018b9SJens Wiklander msg_arg = optee_get_msg_arg(ctx, 0, &entry, &shm, &offs);
9765b4018b9SJens Wiklander if (IS_ERR(msg_arg))
9775b4018b9SJens Wiklander return PTR_ERR(msg_arg);
9786749e69cSJens Wiklander
9796749e69cSJens Wiklander msg_arg->cmd = cmd;
9805b4018b9SJens Wiklander optee_smc_do_call_with_arg(ctx, shm, offs);
9816749e69cSJens Wiklander
9825b4018b9SJens Wiklander optee_free_msg_arg(ctx, entry, offs);
9836749e69cSJens Wiklander return 0;
9846749e69cSJens Wiklander }
9856749e69cSJens Wiklander
optee_smc_do_bottom_half(struct tee_context * ctx)9866749e69cSJens Wiklander static int optee_smc_do_bottom_half(struct tee_context *ctx)
9876749e69cSJens Wiklander {
9886749e69cSJens Wiklander return simple_call_with_arg(ctx, OPTEE_MSG_CMD_DO_BOTTOM_HALF);
9896749e69cSJens Wiklander }
9906749e69cSJens Wiklander
optee_smc_stop_async_notif(struct tee_context * ctx)9916749e69cSJens Wiklander static int optee_smc_stop_async_notif(struct tee_context *ctx)
9926749e69cSJens Wiklander {
9936749e69cSJens Wiklander return simple_call_with_arg(ctx, OPTEE_MSG_CMD_STOP_ASYNC_NOTIF);
9946749e69cSJens Wiklander }
9956749e69cSJens Wiklander
996c51a564aSJens Wiklander /*
9976749e69cSJens Wiklander * 5. Asynchronous notification
9986749e69cSJens Wiklander */
9996749e69cSJens Wiklander
get_async_notif_value(optee_invoke_fn * invoke_fn,bool * value_valid,bool * value_pending)10006749e69cSJens Wiklander static u32 get_async_notif_value(optee_invoke_fn *invoke_fn, bool *value_valid,
10016749e69cSJens Wiklander bool *value_pending)
10026749e69cSJens Wiklander {
10036749e69cSJens Wiklander struct arm_smccc_res res;
10046749e69cSJens Wiklander
10056749e69cSJens Wiklander invoke_fn(OPTEE_SMC_GET_ASYNC_NOTIF_VALUE, 0, 0, 0, 0, 0, 0, 0, &res);
10066749e69cSJens Wiklander
1007*654d0310SEtienne Carriere if (res.a0) {
1008*654d0310SEtienne Carriere *value_valid = false;
10096749e69cSJens Wiklander return 0;
1010*654d0310SEtienne Carriere }
10116749e69cSJens Wiklander *value_valid = (res.a2 & OPTEE_SMC_ASYNC_NOTIF_VALUE_VALID);
10126749e69cSJens Wiklander *value_pending = (res.a2 & OPTEE_SMC_ASYNC_NOTIF_VALUE_PENDING);
10136749e69cSJens Wiklander return res.a1;
10146749e69cSJens Wiklander }
10156749e69cSJens Wiklander
irq_handler(struct optee * optee)1016b3b4ced1SEtienne Carriere static irqreturn_t irq_handler(struct optee *optee)
10176749e69cSJens Wiklander {
10186749e69cSJens Wiklander bool do_bottom_half = false;
10196749e69cSJens Wiklander bool value_valid;
10206749e69cSJens Wiklander bool value_pending;
10216749e69cSJens Wiklander u32 value;
10226749e69cSJens Wiklander
10236749e69cSJens Wiklander do {
10246749e69cSJens Wiklander value = get_async_notif_value(optee->smc.invoke_fn,
10256749e69cSJens Wiklander &value_valid, &value_pending);
10266749e69cSJens Wiklander if (!value_valid)
10276749e69cSJens Wiklander break;
10286749e69cSJens Wiklander
10296749e69cSJens Wiklander if (value == OPTEE_SMC_ASYNC_NOTIF_VALUE_DO_BOTTOM_HALF)
10306749e69cSJens Wiklander do_bottom_half = true;
10316749e69cSJens Wiklander else
10326749e69cSJens Wiklander optee_notif_send(optee, value);
10336749e69cSJens Wiklander } while (value_pending);
10346749e69cSJens Wiklander
10356749e69cSJens Wiklander if (do_bottom_half)
10366749e69cSJens Wiklander return IRQ_WAKE_THREAD;
10376749e69cSJens Wiklander return IRQ_HANDLED;
10386749e69cSJens Wiklander }
10396749e69cSJens Wiklander
notif_irq_handler(int irq,void * dev_id)1040b3b4ced1SEtienne Carriere static irqreturn_t notif_irq_handler(int irq, void *dev_id)
1041b3b4ced1SEtienne Carriere {
1042b3b4ced1SEtienne Carriere struct optee *optee = dev_id;
1043b3b4ced1SEtienne Carriere
1044b3b4ced1SEtienne Carriere return irq_handler(optee);
1045b3b4ced1SEtienne Carriere }
1046b3b4ced1SEtienne Carriere
notif_irq_thread_fn(int irq,void * dev_id)10476749e69cSJens Wiklander static irqreturn_t notif_irq_thread_fn(int irq, void *dev_id)
10486749e69cSJens Wiklander {
10496749e69cSJens Wiklander struct optee *optee = dev_id;
10506749e69cSJens Wiklander
1051aceeafefSJens Wiklander optee_smc_do_bottom_half(optee->ctx);
10526749e69cSJens Wiklander
10536749e69cSJens Wiklander return IRQ_HANDLED;
10546749e69cSJens Wiklander }
10556749e69cSJens Wiklander
init_irq(struct optee * optee,u_int irq)1056b3b4ced1SEtienne Carriere static int init_irq(struct optee *optee, u_int irq)
10576749e69cSJens Wiklander {
10586749e69cSJens Wiklander int rc;
10596749e69cSJens Wiklander
10606749e69cSJens Wiklander rc = request_threaded_irq(irq, notif_irq_handler,
10616749e69cSJens Wiklander notif_irq_thread_fn,
10626749e69cSJens Wiklander 0, "optee_notification", optee);
10636749e69cSJens Wiklander if (rc)
1064aceeafefSJens Wiklander return rc;
10656749e69cSJens Wiklander
10666749e69cSJens Wiklander optee->smc.notif_irq = irq;
10676749e69cSJens Wiklander
10686749e69cSJens Wiklander return 0;
10696749e69cSJens Wiklander }
10706749e69cSJens Wiklander
notif_pcpu_irq_handler(int irq,void * dev_id)1071b3b4ced1SEtienne Carriere static irqreturn_t notif_pcpu_irq_handler(int irq, void *dev_id)
1072b3b4ced1SEtienne Carriere {
1073b3b4ced1SEtienne Carriere struct optee_pcpu *pcpu = dev_id;
1074b3b4ced1SEtienne Carriere struct optee *optee = pcpu->optee;
1075b3b4ced1SEtienne Carriere
1076b3b4ced1SEtienne Carriere if (irq_handler(optee) == IRQ_WAKE_THREAD)
1077b3b4ced1SEtienne Carriere queue_work(optee->smc.notif_pcpu_wq,
1078b3b4ced1SEtienne Carriere &optee->smc.notif_pcpu_work);
1079b3b4ced1SEtienne Carriere
1080b3b4ced1SEtienne Carriere return IRQ_HANDLED;
1081b3b4ced1SEtienne Carriere }
1082b3b4ced1SEtienne Carriere
notif_pcpu_irq_work_fn(struct work_struct * work)1083b3b4ced1SEtienne Carriere static void notif_pcpu_irq_work_fn(struct work_struct *work)
1084b3b4ced1SEtienne Carriere {
1085b3b4ced1SEtienne Carriere struct optee_smc *optee_smc = container_of(work, struct optee_smc,
1086b3b4ced1SEtienne Carriere notif_pcpu_work);
1087b3b4ced1SEtienne Carriere struct optee *optee = container_of(optee_smc, struct optee, smc);
1088b3b4ced1SEtienne Carriere
1089b3b4ced1SEtienne Carriere optee_smc_do_bottom_half(optee->ctx);
1090b3b4ced1SEtienne Carriere }
1091b3b4ced1SEtienne Carriere
init_pcpu_irq(struct optee * optee,u_int irq)1092b3b4ced1SEtienne Carriere static int init_pcpu_irq(struct optee *optee, u_int irq)
1093b3b4ced1SEtienne Carriere {
1094b3b4ced1SEtienne Carriere struct optee_pcpu __percpu *optee_pcpu;
1095b3b4ced1SEtienne Carriere int cpu, rc;
1096b3b4ced1SEtienne Carriere
1097b3b4ced1SEtienne Carriere optee_pcpu = alloc_percpu(struct optee_pcpu);
1098b3b4ced1SEtienne Carriere if (!optee_pcpu)
1099b3b4ced1SEtienne Carriere return -ENOMEM;
1100b3b4ced1SEtienne Carriere
1101b3b4ced1SEtienne Carriere for_each_present_cpu(cpu)
1102b3b4ced1SEtienne Carriere per_cpu_ptr(optee_pcpu, cpu)->optee = optee;
1103b3b4ced1SEtienne Carriere
1104b3b4ced1SEtienne Carriere rc = request_percpu_irq(irq, notif_pcpu_irq_handler,
1105b3b4ced1SEtienne Carriere "optee_pcpu_notification", optee_pcpu);
1106b3b4ced1SEtienne Carriere if (rc)
1107b3b4ced1SEtienne Carriere goto err_free_pcpu;
1108b3b4ced1SEtienne Carriere
1109b3b4ced1SEtienne Carriere INIT_WORK(&optee->smc.notif_pcpu_work, notif_pcpu_irq_work_fn);
1110b3b4ced1SEtienne Carriere optee->smc.notif_pcpu_wq = create_workqueue("optee_pcpu_notification");
1111b3b4ced1SEtienne Carriere if (!optee->smc.notif_pcpu_wq) {
1112b3b4ced1SEtienne Carriere rc = -EINVAL;
1113b3b4ced1SEtienne Carriere goto err_free_pcpu_irq;
1114b3b4ced1SEtienne Carriere }
1115b3b4ced1SEtienne Carriere
1116b3b4ced1SEtienne Carriere optee->smc.optee_pcpu = optee_pcpu;
1117b3b4ced1SEtienne Carriere optee->smc.notif_irq = irq;
1118b3b4ced1SEtienne Carriere
1119b3b4ced1SEtienne Carriere pcpu_irq_num = irq;
1120b3b4ced1SEtienne Carriere rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "optee/pcpu-notif:starting",
1121b3b4ced1SEtienne Carriere optee_cpuhp_enable_pcpu_irq,
1122b3b4ced1SEtienne Carriere optee_cpuhp_disable_pcpu_irq);
1123b3b4ced1SEtienne Carriere if (!rc)
1124b3b4ced1SEtienne Carriere rc = -EINVAL;
1125b3b4ced1SEtienne Carriere if (rc < 0)
1126b3b4ced1SEtienne Carriere goto err_free_pcpu_irq;
1127b3b4ced1SEtienne Carriere
1128b3b4ced1SEtienne Carriere optee->smc.notif_cpuhp_state = rc;
1129b3b4ced1SEtienne Carriere
1130b3b4ced1SEtienne Carriere return 0;
1131b3b4ced1SEtienne Carriere
1132b3b4ced1SEtienne Carriere err_free_pcpu_irq:
1133b3b4ced1SEtienne Carriere free_percpu_irq(irq, optee_pcpu);
1134b3b4ced1SEtienne Carriere err_free_pcpu:
1135b3b4ced1SEtienne Carriere free_percpu(optee_pcpu);
1136b3b4ced1SEtienne Carriere
1137b3b4ced1SEtienne Carriere return rc;
1138b3b4ced1SEtienne Carriere }
1139b3b4ced1SEtienne Carriere
optee_smc_notif_init_irq(struct optee * optee,u_int irq)1140b3b4ced1SEtienne Carriere static int optee_smc_notif_init_irq(struct optee *optee, u_int irq)
1141b3b4ced1SEtienne Carriere {
1142b3b4ced1SEtienne Carriere if (irq_is_percpu_devid(irq))
1143b3b4ced1SEtienne Carriere return init_pcpu_irq(optee, irq);
1144b3b4ced1SEtienne Carriere else
1145b3b4ced1SEtienne Carriere return init_irq(optee, irq);
1146b3b4ced1SEtienne Carriere }
1147b3b4ced1SEtienne Carriere
uninit_pcpu_irq(struct optee * optee)1148b3b4ced1SEtienne Carriere static void uninit_pcpu_irq(struct optee *optee)
1149b3b4ced1SEtienne Carriere {
1150b3b4ced1SEtienne Carriere cpuhp_remove_state(optee->smc.notif_cpuhp_state);
1151b3b4ced1SEtienne Carriere
1152b3b4ced1SEtienne Carriere destroy_workqueue(optee->smc.notif_pcpu_wq);
1153b3b4ced1SEtienne Carriere
1154b3b4ced1SEtienne Carriere free_percpu_irq(optee->smc.notif_irq, optee->smc.optee_pcpu);
1155b3b4ced1SEtienne Carriere free_percpu(optee->smc.optee_pcpu);
1156b3b4ced1SEtienne Carriere }
1157b3b4ced1SEtienne Carriere
optee_smc_notif_uninit_irq(struct optee * optee)11586749e69cSJens Wiklander static void optee_smc_notif_uninit_irq(struct optee *optee)
11596749e69cSJens Wiklander {
1160aceeafefSJens Wiklander if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
1161aceeafefSJens Wiklander optee_smc_stop_async_notif(optee->ctx);
11626749e69cSJens Wiklander if (optee->smc.notif_irq) {
1163b3b4ced1SEtienne Carriere if (irq_is_percpu_devid(optee->smc.notif_irq))
1164b3b4ced1SEtienne Carriere uninit_pcpu_irq(optee);
1165b3b4ced1SEtienne Carriere else
11666749e69cSJens Wiklander free_irq(optee->smc.notif_irq, optee);
1167b3b4ced1SEtienne Carriere
11686749e69cSJens Wiklander irq_dispose_mapping(optee->smc.notif_irq);
11696749e69cSJens Wiklander }
11706749e69cSJens Wiklander }
11716749e69cSJens Wiklander }
11726749e69cSJens Wiklander
11736749e69cSJens Wiklander /*
11746749e69cSJens Wiklander * 6. Driver initialization
11756749e69cSJens Wiklander *
11766749e69cSJens Wiklander * During driver initialization is secure world probed to find out which
1177c51a564aSJens Wiklander * features it supports so the driver can be initialized with a matching
1178c51a564aSJens Wiklander * configuration. This involves for instance support for dynamic shared
1179c51a564aSJens Wiklander * memory instead of a static memory carvout.
1180c51a564aSJens Wiklander */
1181c51a564aSJens Wiklander
optee_get_version(struct tee_device * teedev,struct tee_ioctl_version_data * vers)1182c51a564aSJens Wiklander static void optee_get_version(struct tee_device *teedev,
1183c51a564aSJens Wiklander struct tee_ioctl_version_data *vers)
1184c51a564aSJens Wiklander {
1185c51a564aSJens Wiklander struct tee_ioctl_version_data v = {
1186c51a564aSJens Wiklander .impl_id = TEE_IMPL_ID_OPTEE,
1187c51a564aSJens Wiklander .impl_caps = TEE_OPTEE_CAP_TZ,
1188c51a564aSJens Wiklander .gen_caps = TEE_GEN_CAP_GP,
1189c51a564aSJens Wiklander };
1190c51a564aSJens Wiklander struct optee *optee = tee_get_drvdata(teedev);
1191c51a564aSJens Wiklander
1192c51a564aSJens Wiklander if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
1193c51a564aSJens Wiklander v.gen_caps |= TEE_GEN_CAP_REG_MEM;
1194c51a564aSJens Wiklander if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
1195c51a564aSJens Wiklander v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL;
1196c51a564aSJens Wiklander *vers = v;
1197c51a564aSJens Wiklander }
1198c51a564aSJens Wiklander
optee_smc_open(struct tee_context * ctx)1199c51a564aSJens Wiklander static int optee_smc_open(struct tee_context *ctx)
1200c51a564aSJens Wiklander {
1201c51a564aSJens Wiklander struct optee *optee = tee_get_drvdata(ctx->teedev);
1202c51a564aSJens Wiklander u32 sec_caps = optee->smc.sec_caps;
1203c51a564aSJens Wiklander
1204c51a564aSJens Wiklander return optee_open(ctx, sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL);
1205c51a564aSJens Wiklander }
1206c51a564aSJens Wiklander
1207c51a564aSJens Wiklander static const struct tee_driver_ops optee_clnt_ops = {
1208c51a564aSJens Wiklander .get_version = optee_get_version,
1209c51a564aSJens Wiklander .open = optee_smc_open,
1210c51a564aSJens Wiklander .release = optee_release,
1211c51a564aSJens Wiklander .open_session = optee_open_session,
1212c51a564aSJens Wiklander .close_session = optee_close_session,
1213c51a564aSJens Wiklander .invoke_func = optee_invoke_func,
1214c51a564aSJens Wiklander .cancel_req = optee_cancel_req,
1215c51a564aSJens Wiklander .shm_register = optee_shm_register,
1216c51a564aSJens Wiklander .shm_unregister = optee_shm_unregister,
1217c51a564aSJens Wiklander };
1218c51a564aSJens Wiklander
1219c51a564aSJens Wiklander static const struct tee_desc optee_clnt_desc = {
1220c51a564aSJens Wiklander .name = DRIVER_NAME "-clnt",
1221c51a564aSJens Wiklander .ops = &optee_clnt_ops,
1222c51a564aSJens Wiklander .owner = THIS_MODULE,
1223c51a564aSJens Wiklander };
1224c51a564aSJens Wiklander
1225c51a564aSJens Wiklander static const struct tee_driver_ops optee_supp_ops = {
1226c51a564aSJens Wiklander .get_version = optee_get_version,
1227c51a564aSJens Wiklander .open = optee_smc_open,
1228c51a564aSJens Wiklander .release = optee_release_supp,
1229c51a564aSJens Wiklander .supp_recv = optee_supp_recv,
1230c51a564aSJens Wiklander .supp_send = optee_supp_send,
1231c51a564aSJens Wiklander .shm_register = optee_shm_register_supp,
1232c51a564aSJens Wiklander .shm_unregister = optee_shm_unregister_supp,
1233c51a564aSJens Wiklander };
1234c51a564aSJens Wiklander
1235c51a564aSJens Wiklander static const struct tee_desc optee_supp_desc = {
1236c51a564aSJens Wiklander .name = DRIVER_NAME "-supp",
1237c51a564aSJens Wiklander .ops = &optee_supp_ops,
1238c51a564aSJens Wiklander .owner = THIS_MODULE,
1239c51a564aSJens Wiklander .flags = TEE_DESC_PRIVILEGED,
1240c51a564aSJens Wiklander };
1241c51a564aSJens Wiklander
1242c51a564aSJens Wiklander static const struct optee_ops optee_ops = {
1243c51a564aSJens Wiklander .do_call_with_arg = optee_smc_do_call_with_arg,
1244c51a564aSJens Wiklander .to_msg_param = optee_to_msg_param,
1245c51a564aSJens Wiklander .from_msg_param = optee_from_msg_param,
1246c51a564aSJens Wiklander };
1247c51a564aSJens Wiklander
enable_async_notif(optee_invoke_fn * invoke_fn)12486749e69cSJens Wiklander static int enable_async_notif(optee_invoke_fn *invoke_fn)
12496749e69cSJens Wiklander {
12506749e69cSJens Wiklander struct arm_smccc_res res;
12516749e69cSJens Wiklander
12526749e69cSJens Wiklander invoke_fn(OPTEE_SMC_ENABLE_ASYNC_NOTIF, 0, 0, 0, 0, 0, 0, 0, &res);
12536749e69cSJens Wiklander
12546749e69cSJens Wiklander if (res.a0)
12556749e69cSJens Wiklander return -EINVAL;
12566749e69cSJens Wiklander return 0;
12576749e69cSJens Wiklander }
12586749e69cSJens Wiklander
optee_msg_api_uid_is_optee_api(optee_invoke_fn * invoke_fn)1259c51a564aSJens Wiklander static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn)
1260c51a564aSJens Wiklander {
1261c51a564aSJens Wiklander struct arm_smccc_res res;
1262c51a564aSJens Wiklander
1263c51a564aSJens Wiklander invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
1264c51a564aSJens Wiklander
1265c51a564aSJens Wiklander if (res.a0 == OPTEE_MSG_UID_0 && res.a1 == OPTEE_MSG_UID_1 &&
1266c51a564aSJens Wiklander res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3)
1267c51a564aSJens Wiklander return true;
1268c51a564aSJens Wiklander return false;
1269c51a564aSJens Wiklander }
1270c51a564aSJens Wiklander
1271f3040daaSJeffrey Kardatzke #ifdef CONFIG_OPTEE_INSECURE_LOAD_IMAGE
optee_msg_api_uid_is_optee_image_load(optee_invoke_fn * invoke_fn)1272f3040daaSJeffrey Kardatzke static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
1273f3040daaSJeffrey Kardatzke {
1274f3040daaSJeffrey Kardatzke struct arm_smccc_res res;
1275f3040daaSJeffrey Kardatzke
1276f3040daaSJeffrey Kardatzke invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
1277f3040daaSJeffrey Kardatzke
1278f3040daaSJeffrey Kardatzke if (res.a0 == OPTEE_MSG_IMAGE_LOAD_UID_0 &&
1279f3040daaSJeffrey Kardatzke res.a1 == OPTEE_MSG_IMAGE_LOAD_UID_1 &&
1280f3040daaSJeffrey Kardatzke res.a2 == OPTEE_MSG_IMAGE_LOAD_UID_2 &&
1281f3040daaSJeffrey Kardatzke res.a3 == OPTEE_MSG_IMAGE_LOAD_UID_3)
1282f3040daaSJeffrey Kardatzke return true;
1283f3040daaSJeffrey Kardatzke return false;
1284f3040daaSJeffrey Kardatzke }
1285f3040daaSJeffrey Kardatzke #endif
1286f3040daaSJeffrey Kardatzke
optee_msg_get_os_revision(optee_invoke_fn * invoke_fn)1287c51a564aSJens Wiklander static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
1288c51a564aSJens Wiklander {
1289c51a564aSJens Wiklander union {
1290c51a564aSJens Wiklander struct arm_smccc_res smccc;
1291c51a564aSJens Wiklander struct optee_smc_call_get_os_revision_result result;
1292c51a564aSJens Wiklander } res = {
1293c51a564aSJens Wiklander .result = {
1294c51a564aSJens Wiklander .build_id = 0
1295c51a564aSJens Wiklander }
1296c51a564aSJens Wiklander };
1297c51a564aSJens Wiklander
1298c51a564aSJens Wiklander invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
1299c51a564aSJens Wiklander &res.smccc);
1300c51a564aSJens Wiklander
1301c51a564aSJens Wiklander if (res.result.build_id)
1302c51a564aSJens Wiklander pr_info("revision %lu.%lu (%08lx)", res.result.major,
1303c51a564aSJens Wiklander res.result.minor, res.result.build_id);
1304c51a564aSJens Wiklander else
1305c51a564aSJens Wiklander pr_info("revision %lu.%lu", res.result.major, res.result.minor);
1306c51a564aSJens Wiklander }
1307c51a564aSJens Wiklander
optee_msg_api_revision_is_compatible(optee_invoke_fn * invoke_fn)1308c51a564aSJens Wiklander static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn)
1309c51a564aSJens Wiklander {
1310c51a564aSJens Wiklander union {
1311c51a564aSJens Wiklander struct arm_smccc_res smccc;
1312c51a564aSJens Wiklander struct optee_smc_calls_revision_result result;
1313c51a564aSJens Wiklander } res;
1314c51a564aSJens Wiklander
1315c51a564aSJens Wiklander invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
1316c51a564aSJens Wiklander
1317c51a564aSJens Wiklander if (res.result.major == OPTEE_MSG_REVISION_MAJOR &&
1318c51a564aSJens Wiklander (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR)
1319c51a564aSJens Wiklander return true;
1320c51a564aSJens Wiklander return false;
1321c51a564aSJens Wiklander }
1322c51a564aSJens Wiklander
optee_msg_exchange_capabilities(optee_invoke_fn * invoke_fn,u32 * sec_caps,u32 * max_notif_value,unsigned int * rpc_param_count)1323c51a564aSJens Wiklander static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
1324ed8faf6cSJens Wiklander u32 *sec_caps, u32 *max_notif_value,
1325ed8faf6cSJens Wiklander unsigned int *rpc_param_count)
1326c51a564aSJens Wiklander {
1327c51a564aSJens Wiklander union {
1328c51a564aSJens Wiklander struct arm_smccc_res smccc;
1329c51a564aSJens Wiklander struct optee_smc_exchange_capabilities_result result;
1330c51a564aSJens Wiklander } res;
1331c51a564aSJens Wiklander u32 a1 = 0;
1332c51a564aSJens Wiklander
1333c51a564aSJens Wiklander /*
1334c51a564aSJens Wiklander * TODO This isn't enough to tell if it's UP system (from kernel
1335c51a564aSJens Wiklander * point of view) or not, is_smp() returns the information
1336c51a564aSJens Wiklander * needed, but can't be called directly from here.
1337c51a564aSJens Wiklander */
1338c51a564aSJens Wiklander if (!IS_ENABLED(CONFIG_SMP) || nr_cpu_ids == 1)
1339c51a564aSJens Wiklander a1 |= OPTEE_SMC_NSEC_CAP_UNIPROCESSOR;
1340c51a564aSJens Wiklander
1341c51a564aSJens Wiklander invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0,
1342c51a564aSJens Wiklander &res.smccc);
1343c51a564aSJens Wiklander
1344c51a564aSJens Wiklander if (res.result.status != OPTEE_SMC_RETURN_OK)
1345c51a564aSJens Wiklander return false;
1346c51a564aSJens Wiklander
1347c51a564aSJens Wiklander *sec_caps = res.result.capabilities;
13486749e69cSJens Wiklander if (*sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF)
13496749e69cSJens Wiklander *max_notif_value = res.result.max_notif_value;
13506749e69cSJens Wiklander else
13516749e69cSJens Wiklander *max_notif_value = OPTEE_DEFAULT_MAX_NOTIF_VALUE;
1352ed8faf6cSJens Wiklander if (*sec_caps & OPTEE_SMC_SEC_CAP_RPC_ARG)
1353ed8faf6cSJens Wiklander *rpc_param_count = (u8)res.result.data;
1354ed8faf6cSJens Wiklander else
1355ed8faf6cSJens Wiklander *rpc_param_count = 0;
13566749e69cSJens Wiklander
1357c51a564aSJens Wiklander return true;
1358c51a564aSJens Wiklander }
1359c51a564aSJens Wiklander
1360c51a564aSJens Wiklander static struct tee_shm_pool *
optee_config_shm_memremap(optee_invoke_fn * invoke_fn,void ** memremaped_shm)1361c51a564aSJens Wiklander optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
1362c51a564aSJens Wiklander {
1363c51a564aSJens Wiklander union {
1364c51a564aSJens Wiklander struct arm_smccc_res smccc;
1365c51a564aSJens Wiklander struct optee_smc_get_shm_config_result result;
1366c51a564aSJens Wiklander } res;
1367c51a564aSJens Wiklander unsigned long vaddr;
1368c51a564aSJens Wiklander phys_addr_t paddr;
1369c51a564aSJens Wiklander size_t size;
1370c51a564aSJens Wiklander phys_addr_t begin;
1371c51a564aSJens Wiklander phys_addr_t end;
1372c51a564aSJens Wiklander void *va;
1373c51a564aSJens Wiklander void *rc;
1374c51a564aSJens Wiklander
1375c51a564aSJens Wiklander invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
1376c51a564aSJens Wiklander if (res.result.status != OPTEE_SMC_RETURN_OK) {
1377c51a564aSJens Wiklander pr_err("static shm service not available\n");
1378c51a564aSJens Wiklander return ERR_PTR(-ENOENT);
1379c51a564aSJens Wiklander }
1380c51a564aSJens Wiklander
1381c51a564aSJens Wiklander if (res.result.settings != OPTEE_SMC_SHM_CACHED) {
1382c51a564aSJens Wiklander pr_err("only normal cached shared memory supported\n");
1383c51a564aSJens Wiklander return ERR_PTR(-EINVAL);
1384c51a564aSJens Wiklander }
1385c51a564aSJens Wiklander
1386c51a564aSJens Wiklander begin = roundup(res.result.start, PAGE_SIZE);
1387c51a564aSJens Wiklander end = rounddown(res.result.start + res.result.size, PAGE_SIZE);
1388c51a564aSJens Wiklander paddr = begin;
1389c51a564aSJens Wiklander size = end - begin;
1390c51a564aSJens Wiklander
1391c51a564aSJens Wiklander va = memremap(paddr, size, MEMREMAP_WB);
1392c51a564aSJens Wiklander if (!va) {
1393c51a564aSJens Wiklander pr_err("shared memory ioremap failed\n");
1394c51a564aSJens Wiklander return ERR_PTR(-EINVAL);
1395c51a564aSJens Wiklander }
1396c51a564aSJens Wiklander vaddr = (unsigned long)va;
1397c51a564aSJens Wiklander
1398d88e0493SJens Wiklander rc = tee_shm_pool_alloc_res_mem(vaddr, paddr, size,
1399d88e0493SJens Wiklander OPTEE_MIN_STATIC_POOL_ALIGN);
1400c51a564aSJens Wiklander if (IS_ERR(rc))
1401d88e0493SJens Wiklander memunmap(va);
1402d88e0493SJens Wiklander else
1403c51a564aSJens Wiklander *memremaped_shm = va;
1404c51a564aSJens Wiklander
1405c51a564aSJens Wiklander return rc;
1406c51a564aSJens Wiklander }
1407c51a564aSJens Wiklander
1408c51a564aSJens Wiklander /* 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)1409c51a564aSJens Wiklander static void optee_smccc_smc(unsigned long a0, unsigned long a1,
1410c51a564aSJens Wiklander unsigned long a2, unsigned long a3,
1411c51a564aSJens Wiklander unsigned long a4, unsigned long a5,
1412c51a564aSJens Wiklander unsigned long a6, unsigned long a7,
1413c51a564aSJens Wiklander struct arm_smccc_res *res)
1414c51a564aSJens Wiklander {
1415c51a564aSJens Wiklander arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
1416c51a564aSJens Wiklander }
1417c51a564aSJens Wiklander
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)1418c51a564aSJens Wiklander static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
1419c51a564aSJens Wiklander unsigned long a2, unsigned long a3,
1420c51a564aSJens Wiklander unsigned long a4, unsigned long a5,
1421c51a564aSJens Wiklander unsigned long a6, unsigned long a7,
1422c51a564aSJens Wiklander struct arm_smccc_res *res)
1423c51a564aSJens Wiklander {
1424c51a564aSJens Wiklander arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
1425c51a564aSJens Wiklander }
1426c51a564aSJens Wiklander
get_invoke_func(struct device * dev)1427c51a564aSJens Wiklander static optee_invoke_fn *get_invoke_func(struct device *dev)
1428c51a564aSJens Wiklander {
1429c51a564aSJens Wiklander const char *method;
1430c51a564aSJens Wiklander
1431c51a564aSJens Wiklander pr_info("probing for conduit method.\n");
1432c51a564aSJens Wiklander
1433c51a564aSJens Wiklander if (device_property_read_string(dev, "method", &method)) {
1434c51a564aSJens Wiklander pr_warn("missing \"method\" property\n");
1435c51a564aSJens Wiklander return ERR_PTR(-ENXIO);
1436c51a564aSJens Wiklander }
1437c51a564aSJens Wiklander
1438c51a564aSJens Wiklander if (!strcmp("hvc", method))
1439c51a564aSJens Wiklander return optee_smccc_hvc;
1440c51a564aSJens Wiklander else if (!strcmp("smc", method))
1441c51a564aSJens Wiklander return optee_smccc_smc;
1442c51a564aSJens Wiklander
1443c51a564aSJens Wiklander pr_warn("invalid \"method\" property: %s\n", method);
1444c51a564aSJens Wiklander return ERR_PTR(-EINVAL);
1445c51a564aSJens Wiklander }
1446c51a564aSJens Wiklander
1447c51a564aSJens Wiklander /* optee_remove - Device Removal Routine
1448c51a564aSJens Wiklander * @pdev: platform device information struct
1449c51a564aSJens Wiklander *
1450c51a564aSJens Wiklander * optee_remove is called by platform subsystem to alert the driver
1451c51a564aSJens Wiklander * that it should release the device
1452c51a564aSJens Wiklander */
optee_smc_remove(struct platform_device * pdev)1453c51a564aSJens Wiklander static int optee_smc_remove(struct platform_device *pdev)
1454c51a564aSJens Wiklander {
1455c51a564aSJens Wiklander struct optee *optee = platform_get_drvdata(pdev);
1456c51a564aSJens Wiklander
1457c51a564aSJens Wiklander /*
1458c51a564aSJens Wiklander * Ask OP-TEE to free all cached shared memory objects to decrease
1459c51a564aSJens Wiklander * reference counters and also avoid wild pointers in secure world
1460c51a564aSJens Wiklander * into the old shared memory range.
1461c51a564aSJens Wiklander */
1462ed8faf6cSJens Wiklander if (!optee->rpc_param_count)
1463c51a564aSJens Wiklander optee_disable_shm_cache(optee);
1464c51a564aSJens Wiklander
14656749e69cSJens Wiklander optee_smc_notif_uninit_irq(optee);
14666749e69cSJens Wiklander
1467c51a564aSJens Wiklander optee_remove_common(optee);
1468c51a564aSJens Wiklander
1469c51a564aSJens Wiklander if (optee->smc.memremaped_shm)
1470c51a564aSJens Wiklander memunmap(optee->smc.memremaped_shm);
1471c51a564aSJens Wiklander
1472c51a564aSJens Wiklander kfree(optee);
1473c51a564aSJens Wiklander
1474c51a564aSJens Wiklander return 0;
1475c51a564aSJens Wiklander }
1476c51a564aSJens Wiklander
1477c51a564aSJens Wiklander /* optee_shutdown - Device Removal Routine
1478c51a564aSJens Wiklander * @pdev: platform device information struct
1479c51a564aSJens Wiklander *
1480c51a564aSJens Wiklander * platform_shutdown is called by the platform subsystem to alert
1481c51a564aSJens Wiklander * the driver that a shutdown, reboot, or kexec is happening and
1482c51a564aSJens Wiklander * device must be disabled.
1483c51a564aSJens Wiklander */
optee_shutdown(struct platform_device * pdev)1484c51a564aSJens Wiklander static void optee_shutdown(struct platform_device *pdev)
1485c51a564aSJens Wiklander {
1486ed8faf6cSJens Wiklander struct optee *optee = platform_get_drvdata(pdev);
1487ed8faf6cSJens Wiklander
1488ed8faf6cSJens Wiklander if (!optee->rpc_param_count)
1489ed8faf6cSJens Wiklander optee_disable_shm_cache(optee);
1490c51a564aSJens Wiklander }
1491c51a564aSJens Wiklander
1492f3040daaSJeffrey Kardatzke #ifdef CONFIG_OPTEE_INSECURE_LOAD_IMAGE
1493f3040daaSJeffrey Kardatzke
1494f3040daaSJeffrey Kardatzke #define OPTEE_FW_IMAGE "optee/tee.bin"
1495f3040daaSJeffrey Kardatzke
1496f3040daaSJeffrey Kardatzke static optee_invoke_fn *cpuhp_invoke_fn;
1497f3040daaSJeffrey Kardatzke
optee_cpuhp_probe(unsigned int cpu)1498f3040daaSJeffrey Kardatzke static int optee_cpuhp_probe(unsigned int cpu)
1499f3040daaSJeffrey Kardatzke {
1500f3040daaSJeffrey Kardatzke /*
1501f3040daaSJeffrey Kardatzke * Invoking a call on a CPU will cause OP-TEE to perform the required
1502f3040daaSJeffrey Kardatzke * setup for that CPU. Just invoke the call to get the UID since that
1503f3040daaSJeffrey Kardatzke * has no side effects.
1504f3040daaSJeffrey Kardatzke */
1505f3040daaSJeffrey Kardatzke if (optee_msg_api_uid_is_optee_api(cpuhp_invoke_fn))
1506f3040daaSJeffrey Kardatzke return 0;
1507f3040daaSJeffrey Kardatzke else
1508f3040daaSJeffrey Kardatzke return -EINVAL;
1509f3040daaSJeffrey Kardatzke }
1510f3040daaSJeffrey Kardatzke
optee_load_fw(struct platform_device * pdev,optee_invoke_fn * invoke_fn)1511f3040daaSJeffrey Kardatzke static int optee_load_fw(struct platform_device *pdev,
1512f3040daaSJeffrey Kardatzke optee_invoke_fn *invoke_fn)
1513f3040daaSJeffrey Kardatzke {
1514f3040daaSJeffrey Kardatzke const struct firmware *fw = NULL;
1515f3040daaSJeffrey Kardatzke struct arm_smccc_res res;
1516f3040daaSJeffrey Kardatzke phys_addr_t data_pa;
1517f3040daaSJeffrey Kardatzke u8 *data_buf = NULL;
1518f3040daaSJeffrey Kardatzke u64 data_size;
1519f3040daaSJeffrey Kardatzke u32 data_pa_high, data_pa_low;
1520f3040daaSJeffrey Kardatzke u32 data_size_high, data_size_low;
1521f3040daaSJeffrey Kardatzke int rc;
1522f3040daaSJeffrey Kardatzke int hp_state;
1523f3040daaSJeffrey Kardatzke
1524f3040daaSJeffrey Kardatzke if (!optee_msg_api_uid_is_optee_image_load(invoke_fn))
1525f3040daaSJeffrey Kardatzke return 0;
1526f3040daaSJeffrey Kardatzke
1527f3040daaSJeffrey Kardatzke rc = request_firmware(&fw, OPTEE_FW_IMAGE, &pdev->dev);
1528f3040daaSJeffrey Kardatzke if (rc) {
1529f3040daaSJeffrey Kardatzke /*
1530f3040daaSJeffrey Kardatzke * The firmware in the rootfs will not be accessible until we
1531f3040daaSJeffrey Kardatzke * are in the SYSTEM_RUNNING state, so return EPROBE_DEFER until
1532f3040daaSJeffrey Kardatzke * that point.
1533f3040daaSJeffrey Kardatzke */
1534f3040daaSJeffrey Kardatzke if (system_state < SYSTEM_RUNNING)
1535f3040daaSJeffrey Kardatzke return -EPROBE_DEFER;
1536f3040daaSJeffrey Kardatzke goto fw_err;
1537f3040daaSJeffrey Kardatzke }
1538f3040daaSJeffrey Kardatzke
1539f3040daaSJeffrey Kardatzke data_size = fw->size;
1540f3040daaSJeffrey Kardatzke /*
1541f3040daaSJeffrey Kardatzke * This uses the GFP_DMA flag to ensure we are allocated memory in the
1542f3040daaSJeffrey Kardatzke * 32-bit space since TF-A cannot map memory beyond the 32-bit boundary.
1543f3040daaSJeffrey Kardatzke */
1544f3040daaSJeffrey Kardatzke data_buf = kmemdup(fw->data, fw->size, GFP_KERNEL | GFP_DMA);
1545f3040daaSJeffrey Kardatzke if (!data_buf) {
1546f3040daaSJeffrey Kardatzke rc = -ENOMEM;
1547f3040daaSJeffrey Kardatzke goto fw_err;
1548f3040daaSJeffrey Kardatzke }
1549f3040daaSJeffrey Kardatzke data_pa = virt_to_phys(data_buf);
1550f3040daaSJeffrey Kardatzke reg_pair_from_64(&data_pa_high, &data_pa_low, data_pa);
1551f3040daaSJeffrey Kardatzke reg_pair_from_64(&data_size_high, &data_size_low, data_size);
1552f3040daaSJeffrey Kardatzke goto fw_load;
1553f3040daaSJeffrey Kardatzke
1554f3040daaSJeffrey Kardatzke fw_err:
1555f3040daaSJeffrey Kardatzke pr_warn("image loading failed\n");
1556f3040daaSJeffrey Kardatzke data_pa_high = 0;
1557f3040daaSJeffrey Kardatzke data_pa_low = 0;
1558f3040daaSJeffrey Kardatzke data_size_high = 0;
1559f3040daaSJeffrey Kardatzke data_size_low = 0;
1560f3040daaSJeffrey Kardatzke
1561f3040daaSJeffrey Kardatzke fw_load:
1562f3040daaSJeffrey Kardatzke /*
1563f3040daaSJeffrey Kardatzke * Always invoke the SMC, even if loading the image fails, to indicate
1564f3040daaSJeffrey Kardatzke * to EL3 that we have passed the point where it should allow invoking
1565f3040daaSJeffrey Kardatzke * this SMC.
1566f3040daaSJeffrey Kardatzke */
1567f3040daaSJeffrey Kardatzke pr_warn("OP-TEE image loaded from kernel, this can be insecure");
1568f3040daaSJeffrey Kardatzke invoke_fn(OPTEE_SMC_CALL_LOAD_IMAGE, data_size_high, data_size_low,
1569f3040daaSJeffrey Kardatzke data_pa_high, data_pa_low, 0, 0, 0, &res);
1570f3040daaSJeffrey Kardatzke if (!rc)
1571f3040daaSJeffrey Kardatzke rc = res.a0;
1572f3040daaSJeffrey Kardatzke if (fw)
1573f3040daaSJeffrey Kardatzke release_firmware(fw);
1574f3040daaSJeffrey Kardatzke kfree(data_buf);
1575f3040daaSJeffrey Kardatzke
1576f3040daaSJeffrey Kardatzke if (!rc) {
1577f3040daaSJeffrey Kardatzke /*
1578f3040daaSJeffrey Kardatzke * We need to initialize OP-TEE on all other running cores as
1579f3040daaSJeffrey Kardatzke * well. Any cores that aren't running yet will get initialized
1580f3040daaSJeffrey Kardatzke * when they are brought up by the power management functions in
1581f3040daaSJeffrey Kardatzke * TF-A which are registered by the OP-TEE SPD. Due to that we
1582f3040daaSJeffrey Kardatzke * can un-register the callback right after registering it.
1583f3040daaSJeffrey Kardatzke */
1584f3040daaSJeffrey Kardatzke cpuhp_invoke_fn = invoke_fn;
1585f3040daaSJeffrey Kardatzke hp_state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "optee:probe",
1586f3040daaSJeffrey Kardatzke optee_cpuhp_probe, NULL);
1587f3040daaSJeffrey Kardatzke if (hp_state < 0) {
1588f3040daaSJeffrey Kardatzke pr_warn("Failed with CPU hotplug setup for OP-TEE");
1589f3040daaSJeffrey Kardatzke return -EINVAL;
1590f3040daaSJeffrey Kardatzke }
1591f3040daaSJeffrey Kardatzke cpuhp_remove_state(hp_state);
1592f3040daaSJeffrey Kardatzke cpuhp_invoke_fn = NULL;
1593f3040daaSJeffrey Kardatzke }
1594f3040daaSJeffrey Kardatzke
1595f3040daaSJeffrey Kardatzke return rc;
1596f3040daaSJeffrey Kardatzke }
1597f3040daaSJeffrey Kardatzke #else
optee_load_fw(struct platform_device * pdev,optee_invoke_fn * invoke_fn)1598f3040daaSJeffrey Kardatzke static inline int optee_load_fw(struct platform_device *pdev,
1599f3040daaSJeffrey Kardatzke optee_invoke_fn *invoke_fn)
1600f3040daaSJeffrey Kardatzke {
1601f3040daaSJeffrey Kardatzke return 0;
1602f3040daaSJeffrey Kardatzke }
1603f3040daaSJeffrey Kardatzke #endif
1604f3040daaSJeffrey Kardatzke
optee_probe(struct platform_device * pdev)1605f3040daaSJeffrey Kardatzke static int optee_probe(struct platform_device *pdev)
1606c51a564aSJens Wiklander {
1607c51a564aSJens Wiklander optee_invoke_fn *invoke_fn;
1608c51a564aSJens Wiklander struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
1609c51a564aSJens Wiklander struct optee *optee = NULL;
1610c51a564aSJens Wiklander void *memremaped_shm = NULL;
1611c51a564aSJens Wiklander unsigned int rpc_param_count;
1612ed8faf6cSJens Wiklander struct tee_device *teedev;
1613c51a564aSJens Wiklander struct tee_context *ctx;
1614aceeafefSJens Wiklander u32 max_notif_value;
16156749e69cSJens Wiklander u32 arg_cache_flags;
16165b4018b9SJens Wiklander u32 sec_caps;
1617c51a564aSJens Wiklander int rc;
1618c51a564aSJens Wiklander
1619c51a564aSJens Wiklander invoke_fn = get_invoke_func(&pdev->dev);
1620c51a564aSJens Wiklander if (IS_ERR(invoke_fn))
1621c51a564aSJens Wiklander return PTR_ERR(invoke_fn);
1622c51a564aSJens Wiklander
1623c51a564aSJens Wiklander rc = optee_load_fw(pdev, invoke_fn);
1624f3040daaSJeffrey Kardatzke if (rc)
1625f3040daaSJeffrey Kardatzke return rc;
1626f3040daaSJeffrey Kardatzke
1627f3040daaSJeffrey Kardatzke if (!optee_msg_api_uid_is_optee_api(invoke_fn)) {
1628c51a564aSJens Wiklander pr_warn("api uid mismatch\n");
1629c51a564aSJens Wiklander return -EINVAL;
1630c51a564aSJens Wiklander }
1631c51a564aSJens Wiklander
1632c51a564aSJens Wiklander optee_msg_get_os_revision(invoke_fn);
1633c51a564aSJens Wiklander
1634c51a564aSJens Wiklander if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
1635c51a564aSJens Wiklander pr_warn("api revision mismatch\n");
1636c51a564aSJens Wiklander return -EINVAL;
1637c51a564aSJens Wiklander }
1638c51a564aSJens Wiklander
1639c51a564aSJens Wiklander if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps,
16406749e69cSJens Wiklander &max_notif_value,
1641ed8faf6cSJens Wiklander &rpc_param_count)) {
1642ed8faf6cSJens Wiklander pr_warn("capabilities mismatch\n");
1643c51a564aSJens Wiklander return -EINVAL;
1644c51a564aSJens Wiklander }
1645c51a564aSJens Wiklander
1646c51a564aSJens Wiklander /*
1647c51a564aSJens Wiklander * Try to use dynamic shared memory if possible
1648c51a564aSJens Wiklander */
1649c51a564aSJens Wiklander if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) {
16505b4018b9SJens Wiklander /*
16515b4018b9SJens Wiklander * If we have OPTEE_SMC_SEC_CAP_RPC_ARG we can ask
16525b4018b9SJens Wiklander * optee_get_msg_arg() to pre-register (by having
16535b4018b9SJens Wiklander * OPTEE_SHM_ARG_ALLOC_PRIV cleared) the page used to pass
16545b4018b9SJens Wiklander * an argument struct.
16555b4018b9SJens Wiklander *
16565b4018b9SJens Wiklander * With the page is pre-registered we can use a non-zero
16575b4018b9SJens Wiklander * offset for argument struct, this is indicated with
16585b4018b9SJens Wiklander * OPTEE_SHM_ARG_SHARED.
16595b4018b9SJens Wiklander *
16605b4018b9SJens Wiklander * This means that optee_smc_do_call_with_arg() will use
16615b4018b9SJens Wiklander * OPTEE_SMC_CALL_WITH_REGD_ARG for pre-registered pages.
16625b4018b9SJens Wiklander */
16635b4018b9SJens Wiklander if (sec_caps & OPTEE_SMC_SEC_CAP_RPC_ARG)
16645b4018b9SJens Wiklander arg_cache_flags = OPTEE_SHM_ARG_SHARED;
16655b4018b9SJens Wiklander else
16665b4018b9SJens Wiklander arg_cache_flags = OPTEE_SHM_ARG_ALLOC_PRIV;
16675b4018b9SJens Wiklander
16685b4018b9SJens Wiklander pool = optee_shm_pool_alloc_pages();
1669d88e0493SJens Wiklander }
16705b4018b9SJens Wiklander
1671c51a564aSJens Wiklander /*
1672c51a564aSJens Wiklander * If dynamic shared memory is not available or failed - try static one
1673c51a564aSJens Wiklander */
1674c51a564aSJens Wiklander if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) {
16755b4018b9SJens Wiklander /*
16765b4018b9SJens Wiklander * The static memory pool can use non-zero page offsets so
16775b4018b9SJens Wiklander * let optee_get_msg_arg() know that with OPTEE_SHM_ARG_SHARED.
16785b4018b9SJens Wiklander *
16795b4018b9SJens Wiklander * optee_get_msg_arg() should not pre-register the
16805b4018b9SJens Wiklander * allocated page used to pass an argument struct, this is
16815b4018b9SJens Wiklander * indicated with OPTEE_SHM_ARG_ALLOC_PRIV.
16825b4018b9SJens Wiklander *
16835b4018b9SJens Wiklander * This means that optee_smc_do_call_with_arg() will use
16845b4018b9SJens Wiklander * OPTEE_SMC_CALL_WITH_ARG if rpc_param_count is 0, else
16855b4018b9SJens Wiklander * OPTEE_SMC_CALL_WITH_RPC_ARG.
16865b4018b9SJens Wiklander */
16875b4018b9SJens Wiklander arg_cache_flags = OPTEE_SHM_ARG_SHARED |
16885b4018b9SJens Wiklander OPTEE_SHM_ARG_ALLOC_PRIV;
16895b4018b9SJens Wiklander pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
1690c51a564aSJens Wiklander }
16915b4018b9SJens Wiklander
1692c51a564aSJens Wiklander if (IS_ERR(pool))
1693c51a564aSJens Wiklander return PTR_ERR(pool);
1694c51a564aSJens Wiklander
1695c51a564aSJens Wiklander optee = kzalloc(sizeof(*optee), GFP_KERNEL);
1696c51a564aSJens Wiklander if (!optee) {
1697c51a564aSJens Wiklander rc = -ENOMEM;
1698c51a564aSJens Wiklander goto err_free_pool;
16996749e69cSJens Wiklander }
1700c51a564aSJens Wiklander
1701c51a564aSJens Wiklander optee->ops = &optee_ops;
1702c51a564aSJens Wiklander optee->smc.invoke_fn = invoke_fn;
1703c51a564aSJens Wiklander optee->smc.sec_caps = sec_caps;
1704c51a564aSJens Wiklander optee->rpc_param_count = rpc_param_count;
1705ed8faf6cSJens Wiklander
1706c51a564aSJens Wiklander teedev = tee_device_alloc(&optee_clnt_desc, NULL, pool, optee);
1707c51a564aSJens Wiklander if (IS_ERR(teedev)) {
1708c51a564aSJens Wiklander rc = PTR_ERR(teedev);
1709c51a564aSJens Wiklander goto err_free_optee;
17106749e69cSJens Wiklander }
1711c51a564aSJens Wiklander optee->teedev = teedev;
1712c51a564aSJens Wiklander
1713c51a564aSJens Wiklander teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee);
1714c51a564aSJens Wiklander if (IS_ERR(teedev)) {
1715c51a564aSJens Wiklander rc = PTR_ERR(teedev);
1716c51a564aSJens Wiklander goto err_unreg_teedev;
17176749e69cSJens Wiklander }
1718c51a564aSJens Wiklander optee->supp_teedev = teedev;
1719c51a564aSJens Wiklander
1720c51a564aSJens Wiklander rc = tee_device_register(optee->teedev);
1721c51a564aSJens Wiklander if (rc)
1722c51a564aSJens Wiklander goto err_unreg_supp_teedev;
17236749e69cSJens Wiklander
1724c51a564aSJens Wiklander rc = tee_device_register(optee->supp_teedev);
1725c51a564aSJens Wiklander if (rc)
1726c51a564aSJens Wiklander goto err_unreg_supp_teedev;
17276749e69cSJens Wiklander
1728c51a564aSJens Wiklander mutex_init(&optee->call_queue.mutex);
1729c51a564aSJens Wiklander INIT_LIST_HEAD(&optee->call_queue.waiters);
1730c51a564aSJens Wiklander optee_supp_init(&optee->supp);
1731c51a564aSJens Wiklander optee->smc.memremaped_shm = memremaped_shm;
1732c51a564aSJens Wiklander optee->pool = pool;
1733c51a564aSJens Wiklander optee_shm_arg_cache_init(optee, arg_cache_flags);
17345b4018b9SJens Wiklander
1735c51a564aSJens Wiklander platform_set_drvdata(pdev, optee);
1736787c80ccSJens Wiklander ctx = teedev_open(optee->teedev);
1737aceeafefSJens Wiklander if (IS_ERR(ctx)) {
173840eb0dcfSYang Yingliang rc = PTR_ERR(ctx);
173940eb0dcfSYang Yingliang goto err_supp_uninit;
1740aceeafefSJens Wiklander }
174140eb0dcfSYang Yingliang optee->ctx = ctx;
1742aceeafefSJens Wiklander rc = optee_notif_init(optee, max_notif_value);
17436749e69cSJens Wiklander if (rc)
17446749e69cSJens Wiklander goto err_close_ctx;
1745aceeafefSJens Wiklander
17466749e69cSJens Wiklander if (sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
17476749e69cSJens Wiklander unsigned int irq;
17486749e69cSJens Wiklander
17496749e69cSJens Wiklander rc = platform_get_irq(pdev, 0);
17506749e69cSJens Wiklander if (rc < 0) {
17516749e69cSJens Wiklander pr_err("platform_get_irq: ret %d\n", rc);
17526749e69cSJens Wiklander goto err_notif_uninit;
17536749e69cSJens Wiklander }
17546749e69cSJens Wiklander irq = rc;
17556749e69cSJens Wiklander
17566749e69cSJens Wiklander rc = optee_smc_notif_init_irq(optee, irq);
17576749e69cSJens Wiklander if (rc) {
1758787c80ccSJens Wiklander irq_dispose_mapping(irq);
17596749e69cSJens Wiklander goto err_notif_uninit;
17606749e69cSJens Wiklander }
17616749e69cSJens Wiklander enable_async_notif(optee->smc.invoke_fn);
17626749e69cSJens Wiklander pr_info("Asynchronous notifications enabled\n");
17636749e69cSJens Wiklander }
1764787c80ccSJens Wiklander
1765787c80ccSJens Wiklander /*
1766c51a564aSJens Wiklander * Ensure that there are no pre-existing shm objects before enabling
1767c51a564aSJens Wiklander * the shm cache so that there's no chance of receiving an invalid
1768c51a564aSJens Wiklander * address during shutdown. This could occur, for example, if we're
1769c51a564aSJens Wiklander * kexec booting from an older kernel that did not properly cleanup the
1770c51a564aSJens Wiklander * shm cache.
1771c51a564aSJens Wiklander */
1772c51a564aSJens Wiklander optee_disable_unmapped_shm_cache(optee);
1773c51a564aSJens Wiklander
1774c51a564aSJens Wiklander /*
1775ed8faf6cSJens Wiklander * Only enable the shm cache in case we're not able to pass the RPC
1776ed8faf6cSJens Wiklander * arg struct right after the normal arg struct.
1777ed8faf6cSJens Wiklander */
1778ed8faf6cSJens Wiklander if (!optee->rpc_param_count)
1779ed8faf6cSJens Wiklander optee_enable_shm_cache(optee);
1780c51a564aSJens Wiklander
1781c51a564aSJens Wiklander if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
1782c51a564aSJens Wiklander pr_info("dynamic shared memory is enabled\n");
1783c51a564aSJens Wiklander
1784c51a564aSJens Wiklander rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
1785c51a564aSJens Wiklander if (rc)
17866749e69cSJens Wiklander goto err_disable_shm_cache;
17876749e69cSJens Wiklander
1788c51a564aSJens Wiklander pr_info("initialized driver\n");
1789c51a564aSJens Wiklander return 0;
1790c51a564aSJens Wiklander
17916749e69cSJens Wiklander err_disable_shm_cache:
17926749e69cSJens Wiklander if (!optee->rpc_param_count)
1793ed8faf6cSJens Wiklander optee_disable_shm_cache(optee);
17946749e69cSJens Wiklander optee_smc_notif_uninit_irq(optee);
17956749e69cSJens Wiklander optee_unregister_devices();
17966749e69cSJens Wiklander err_notif_uninit:
17976749e69cSJens Wiklander optee_notif_uninit(optee);
17986749e69cSJens Wiklander err_close_ctx:
1799aceeafefSJens Wiklander teedev_close_context(ctx);
1800aceeafefSJens Wiklander err_supp_uninit:
18016749e69cSJens Wiklander optee_shm_arg_cache_uninit(optee);
18025b4018b9SJens Wiklander optee_supp_uninit(&optee->supp);
18036749e69cSJens Wiklander mutex_destroy(&optee->call_queue.mutex);
18046749e69cSJens Wiklander err_unreg_supp_teedev:
18056749e69cSJens Wiklander tee_device_unregister(optee->supp_teedev);
1806c51a564aSJens Wiklander err_unreg_teedev:
18076749e69cSJens Wiklander tee_device_unregister(optee->teedev);
1808c51a564aSJens Wiklander err_free_optee:
18096749e69cSJens Wiklander kfree(optee);
1810c51a564aSJens Wiklander err_free_pool:
18116749e69cSJens Wiklander tee_shm_pool_free(pool);
1812c51a564aSJens Wiklander if (memremaped_shm)
1813c51a564aSJens Wiklander memunmap(memremaped_shm);
1814c51a564aSJens Wiklander return rc;
1815c51a564aSJens Wiklander }
1816c51a564aSJens Wiklander
1817c51a564aSJens Wiklander static const struct of_device_id optee_dt_match[] = {
1818c51a564aSJens Wiklander { .compatible = "linaro,optee-tz" },
1819c51a564aSJens Wiklander {},
1820c51a564aSJens Wiklander };
1821c51a564aSJens Wiklander MODULE_DEVICE_TABLE(of, optee_dt_match);
1822c51a564aSJens Wiklander
1823c51a564aSJens Wiklander static struct platform_driver optee_driver = {
1824c51a564aSJens Wiklander .probe = optee_probe,
1825c51a564aSJens Wiklander .remove = optee_smc_remove,
1826c51a564aSJens Wiklander .shutdown = optee_shutdown,
1827c51a564aSJens Wiklander .driver = {
1828c51a564aSJens Wiklander .name = "optee",
1829c51a564aSJens Wiklander .of_match_table = optee_dt_match,
1830c51a564aSJens Wiklander },
1831c51a564aSJens Wiklander };
1832c51a564aSJens Wiklander
optee_smc_abi_register(void)1833c51a564aSJens Wiklander int optee_smc_abi_register(void)
1834c51a564aSJens Wiklander {
1835c51a564aSJens Wiklander return platform_driver_register(&optee_driver);
1836c51a564aSJens Wiklander }
1837c51a564aSJens Wiklander
optee_smc_abi_unregister(void)1838c51a564aSJens Wiklander void optee_smc_abi_unregister(void)
1839c51a564aSJens Wiklander {
1840c51a564aSJens Wiklander platform_driver_unregister(&optee_driver);
1841c51a564aSJens Wiklander }
1842c51a564aSJens Wiklander