1f380b77249977273715f02816fdc8627c3fc883
[linux-3.10.git] / security / tlk_driver / ote_comms.c
1 /*
2  * Copyright (c) 2012-2014 NVIDIA Corporation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18
19 #include <linux/atomic.h>
20 #include <linux/uaccess.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/fs.h>
24 #include <linux/printk.h>
25 #include <linux/ioctl.h>
26 #include <linux/sched.h>
27 #include <linux/mm.h>
28 #include <linux/pagemap.h>
29
30 #include "ote_protocol.h"
31
32 bool verbose_smc;
33 core_param(verbose_smc, verbose_smc, bool, 0644);
34
35 #define SET_RESULT(req, r, ro)  { req->result = r; req->result_origin = ro; }
36
37 static struct te_shmem_desc *te_add_shmem_desc(void *buffer, size_t size,
38                 struct tlk_context *context)
39 {
40         struct te_shmem_desc *shmem_desc = NULL;
41         shmem_desc = kzalloc(sizeof(struct te_shmem_desc), GFP_KERNEL);
42         if (shmem_desc) {
43                 INIT_LIST_HEAD(&(shmem_desc->list));
44                 shmem_desc->buffer = buffer;
45                 shmem_desc->size = size;
46                 list_add_tail(&shmem_desc->list, &(context->shmem_alloc_list));
47         }
48
49         return shmem_desc;
50 }
51
52 static int te_pin_mem_buffers(void *buffer, size_t size,
53                 struct tlk_context *context)
54 {
55         struct te_shmem_desc *shmem_desc = NULL;
56         int ret = 0;
57
58         shmem_desc = te_add_shmem_desc(buffer, size, context);
59         if (!shmem_desc) {
60                 pr_err("%s: te_add_shmem_desc Failed\n", __func__);
61                 ret = OTE_ERROR_OUT_OF_MEMORY;
62                 goto error;
63         }
64
65         return OTE_SUCCESS;
66 error:
67         return ret;
68 }
69
70 static int te_setup_temp_buffers(struct te_request *request,
71                 struct tlk_context *context)
72 {
73         uint32_t i;
74         int ret = OTE_SUCCESS;
75         struct te_oper_param *params = request->params;
76
77         for (i = 0; i < request->params_size; i++) {
78                 switch (params[i].type) {
79                 case TE_PARAM_TYPE_NONE:
80                 case TE_PARAM_TYPE_INT_RO:
81                 case TE_PARAM_TYPE_INT_RW:
82                         break;
83                 case TE_PARAM_TYPE_MEM_RO:
84                 case TE_PARAM_TYPE_MEM_RW:
85                         ret = te_pin_mem_buffers(
86                                 params[i].u.Mem.base,
87                                 params[i].u.Mem.len,
88                                 context);
89                         if (ret < 0) {
90                                 pr_err("%s failed with err (%d)\n",
91                                         __func__, ret);
92                                 ret = OTE_ERROR_BAD_PARAMETERS;
93                                 break;
94                         }
95                         break;
96                 default:
97                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
98                         ret = OTE_ERROR_BAD_PARAMETERS;
99                         break;
100                 }
101         }
102         return ret;
103 }
104
105 static int te_setup_temp_buffers_compat(struct te_request_compat *request,
106                 struct tlk_context *context)
107 {
108         uint32_t i;
109         int ret = OTE_SUCCESS;
110         struct te_oper_param_compat *params;
111
112         params = (struct te_oper_param_compat *)(uintptr_t)request->params;
113         for (i = 0; i < request->params_size; i++) {
114                 switch (params[i].type) {
115                 case TE_PARAM_TYPE_NONE:
116                 case TE_PARAM_TYPE_INT_RO:
117                 case TE_PARAM_TYPE_INT_RW:
118                         break;
119                 case TE_PARAM_TYPE_MEM_RO:
120                 case TE_PARAM_TYPE_MEM_RW:
121                         ret = te_pin_mem_buffers(
122                                 (void *)(uintptr_t)params[i].u.Mem.base,
123                                 params[i].u.Mem.len,
124                                 context);
125                         if (ret < 0) {
126                                 pr_err("%s failed with err (%d)\n",
127                                         __func__, ret);
128                                 ret = OTE_ERROR_BAD_PARAMETERS;
129                                 break;
130                         }
131                         break;
132                 default:
133                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
134                         ret = OTE_ERROR_BAD_PARAMETERS;
135                         break;
136                 }
137         }
138         return ret;
139 }
140
141 static void te_del_shmem_desc(void *buffer, struct tlk_context *context)
142 {
143         struct te_shmem_desc *shmem_desc, *tmp_shmem_desc;
144
145         list_for_each_entry_safe(shmem_desc, tmp_shmem_desc,
146                 &(context->shmem_alloc_list), list) {
147                 if (shmem_desc->buffer == buffer) {
148                         list_del(&shmem_desc->list);
149                         kfree(shmem_desc);
150                 }
151         }
152 }
153
154 /*
155  * Deregister previously initialized shared memory
156  */
157 void te_unregister_memory(void *buffer,
158         struct tlk_context *context)
159 {
160         if (!(list_empty(&(context->shmem_alloc_list))))
161                 te_del_shmem_desc(buffer, context);
162         else
163                 pr_err("No buffers to unpin\n");
164 }
165
166 static void te_unpin_temp_buffers(struct te_request *request,
167         struct tlk_context *context)
168 {
169         uint32_t i;
170         struct te_oper_param *params = request->params;
171
172         for (i = 0; i < request->params_size; i++) {
173                 switch (params[i].type) {
174                 case TE_PARAM_TYPE_NONE:
175                 case TE_PARAM_TYPE_INT_RO:
176                 case TE_PARAM_TYPE_INT_RW:
177                         break;
178                 case TE_PARAM_TYPE_MEM_RO:
179                 case TE_PARAM_TYPE_MEM_RW:
180                         te_unregister_memory(params[i].u.Mem.base, context);
181                         break;
182                 default:
183                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
184                         break;
185                 }
186         }
187 }
188
189 static void te_unpin_temp_buffers_compat(struct te_request_compat *request,
190         struct tlk_context *context)
191 {
192         uint32_t i;
193         struct te_oper_param_compat *params;
194
195         params = (struct te_oper_param_compat *)(uintptr_t)request->params;
196         for (i = 0; i < request->params_size; i++) {
197                 switch (params[i].type) {
198                 case TE_PARAM_TYPE_NONE:
199                 case TE_PARAM_TYPE_INT_RO:
200                 case TE_PARAM_TYPE_INT_RW:
201                         break;
202                 case TE_PARAM_TYPE_MEM_RO:
203                 case TE_PARAM_TYPE_MEM_RW:
204                         te_unregister_memory(
205                                 (void *)(uintptr_t)params[i].u.Mem.base,
206                                 context);
207                         break;
208                 default:
209                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
210                         break;
211                 }
212         }
213 }
214
215 #ifdef CONFIG_SMP
216 cpumask_t saved_cpu_mask;
217 static void switch_cpumask_to_cpu0(void)
218 {
219         long ret;
220         cpumask_t local_cpu_mask = CPU_MASK_NONE;
221
222         cpu_set(0, local_cpu_mask);
223         cpumask_copy(&saved_cpu_mask, tsk_cpus_allowed(current));
224         ret = sched_setaffinity(0, &local_cpu_mask);
225         if (ret)
226                 pr_err("sched_setaffinity #1 -> 0x%lX", ret);
227 }
228
229 static void restore_cpumask(void)
230 {
231         long ret = sched_setaffinity(0, &saved_cpu_mask);
232         if (ret)
233                 pr_err("sched_setaffinity #2 -> 0x%lX", ret);
234 }
235 #else
236 static inline void switch_cpumask_to_cpu0(void) {};
237 static inline void restore_cpumask(void) {};
238 #endif
239
240 uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2)
241 {
242         uint32_t retval;
243
244         switch_cpumask_to_cpu0();
245
246         retval = _tlk_generic_smc(arg0, arg1, arg2);
247         while (retval == 0xFFFFFFFD)
248                 retval = _tlk_generic_smc((60 << 24), 0, 0);
249
250         restore_cpumask();
251
252         return retval;
253 }
254
255 uint32_t tlk_extended_smc(uintptr_t *regs)
256 {
257         uint32_t retval;
258
259         switch_cpumask_to_cpu0();
260
261         retval = _tlk_extended_smc(regs);
262         while (retval == 0xFFFFFFFD)
263                 retval = _tlk_generic_smc((60 << 24), 0, 0);
264
265         restore_cpumask();
266
267         return retval;
268 }
269
270 /*
271  * Do an SMC call
272  */
273 static void do_smc(struct te_request *request, struct tlk_device *dev)
274 {
275         uint32_t smc_args;
276         uint32_t smc_params = 0;
277
278         if (dev->req_param_buf) {
279                 smc_args = (char *)request - dev->req_param_buf;
280                 if (request->params)
281                         smc_params = (char *)request->params -
282                                                 dev->req_param_buf;
283         } else {
284                 smc_args = (uint32_t)virt_to_phys(request);
285                 if (request->params)
286                         smc_params = (uint32_t)virt_to_phys(request->params);
287         }
288
289         tlk_generic_smc(request->type, smc_args, smc_params);
290
291         /*
292          * Check to see if there are any logs in written by TLK.
293          * If there are, print them out.
294          */
295         ote_print_logs();
296 }
297
298 /*
299  * Do an SMC call
300  */
301 static void do_smc_compat(struct te_request_compat *request,
302                           struct tlk_device *dev)
303 {
304         uint32_t smc_args;
305         uint32_t smc_params = 0;
306
307         smc_args = (char *)request - dev->req_param_buf;
308         if (request->params) {
309                 smc_params =
310                         (char *)(uintptr_t)request->params - dev->req_param_buf;
311         }
312
313         tlk_generic_smc(request->type, smc_args, smc_params);
314
315         /*
316          * Check to see if there are any logs in written by TLK.
317          * If there are, print them out.
318          */
319         ote_print_logs();
320 }
321
322 /*
323  * VPR programming SMC
324  */
325 int te_set_vpr_params(void *vpr_base, size_t vpr_size)
326 {
327         uint32_t retval;
328
329         /* Share the same lock used when request is send from user side */
330         mutex_lock(&smc_lock);
331
332         retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR, (uintptr_t)vpr_base,
333                         vpr_size);
334
335         mutex_unlock(&smc_lock);
336
337         if (retval != OTE_SUCCESS) {
338                 pr_err("te_set_vpr_params failed err (0x%x)\n", retval);
339                 return -EINVAL;
340         }
341         return 0;
342 }
343 EXPORT_SYMBOL(te_set_vpr_params);
344
345 /*
346  * Open session SMC (supporting client-based te_open_session() calls)
347  */
348 void te_open_session(struct te_opensession *cmd,
349                      struct te_request *request,
350                      struct tlk_context *context)
351 {
352         int ret;
353
354         ret = te_setup_temp_buffers(request, context);
355         if (ret != OTE_SUCCESS) {
356                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
357                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
358                 return;
359         }
360
361         memcpy(&request->dest_uuid,
362                &cmd->dest_uuid,
363                sizeof(struct te_service_id));
364
365         pr_info("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n",
366                 request->dest_uuid[0],
367                 request->dest_uuid[1],
368                 request->dest_uuid[2],
369                 request->dest_uuid[3]);
370
371         request->type = TE_SMC_OPEN_SESSION;
372
373         do_smc(request, context->dev);
374
375         te_unpin_temp_buffers(request, context);
376 }
377
378 /*
379  * Close session SMC (supporting client-based te_close_session() calls)
380  */
381 void te_close_session(struct te_closesession *cmd,
382                       struct te_request *request,
383                       struct tlk_context *context)
384 {
385         request->session_id = cmd->session_id;
386         request->type = TE_SMC_CLOSE_SESSION;
387
388         do_smc(request, context->dev);
389         if (request->result)
390                 pr_info("Error closing session: %08x\n", request->result);
391 }
392
393 /*
394  * Launch operation SMC (supporting client-based te_launch_operation() calls)
395  */
396 void te_launch_operation(struct te_launchop *cmd,
397                          struct te_request *request,
398                          struct tlk_context *context)
399 {
400         int ret;
401
402         ret = te_setup_temp_buffers(request, context);
403         if (ret != OTE_SUCCESS) {
404                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
405                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
406                 return;
407         }
408
409         request->session_id = cmd->session_id;
410         request->command_id = cmd->operation.command;
411         request->type = TE_SMC_LAUNCH_OPERATION;
412
413         do_smc(request, context->dev);
414
415         te_unpin_temp_buffers(request, context);
416 }
417
418 /*
419  * Open session SMC (supporting client-based te_open_session() calls)
420  */
421 void te_open_session_compat(struct te_opensession_compat *cmd,
422                             struct te_request_compat *request,
423                             struct tlk_context *context)
424 {
425         int ret;
426
427         ret = te_setup_temp_buffers_compat(request, context);
428         if (ret != OTE_SUCCESS) {
429                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
430                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
431                 return;
432         }
433
434         memcpy(&request->dest_uuid,
435                &cmd->dest_uuid,
436                sizeof(struct te_service_id));
437
438         pr_info("OPEN_CLIENT_SESSION_COMPAT: 0x%x 0x%x 0x%x 0x%x\n",
439                 request->dest_uuid[0],
440                 request->dest_uuid[1],
441                 request->dest_uuid[2],
442                 request->dest_uuid[3]);
443
444         request->type = TE_SMC_OPEN_SESSION;
445
446         do_smc_compat(request, context->dev);
447
448         te_unpin_temp_buffers_compat(request, context);
449 }
450
451 /*
452  * Close session SMC (supporting client-based te_close_session() calls)
453  */
454 void te_close_session_compat(struct te_closesession_compat *cmd,
455                              struct te_request_compat *request,
456                              struct tlk_context *context)
457 {
458         request->session_id = cmd->session_id;
459         request->type = TE_SMC_CLOSE_SESSION;
460
461         do_smc_compat(request, context->dev);
462         if (request->result)
463                 pr_info("Error closing session: %08x\n", request->result);
464 }
465
466 /*
467  * Launch operation SMC (supporting client-based te_launch_operation() calls)
468  */
469 void te_launch_operation_compat(struct te_launchop_compat *cmd,
470                                 struct te_request_compat *request,
471                                 struct tlk_context *context)
472 {
473         int ret;
474
475         ret = te_setup_temp_buffers_compat(request, context);
476         if (ret != OTE_SUCCESS) {
477                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
478                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
479                 return;
480         }
481
482         request->session_id = cmd->session_id;
483         request->command_id = cmd->operation.command;
484         request->type = TE_SMC_LAUNCH_OPERATION;
485
486         do_smc_compat(request, context->dev);
487
488         te_unpin_temp_buffers_compat(request, context);
489 }
490
491 static int __init tlk_register_irq_handler(void)
492 {
493         tlk_generic_smc(TE_SMC_REGISTER_IRQ_HANDLER,
494                 (uintptr_t)tlk_irq_handler, 0);
495         return 0;
496 }
497
498 arch_initcall(tlk_register_irq_handler);