]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - security/tlk_driver/ote_comms.c
8a0c4ece66b63f7af4fecbcb243e728b3da6f5ec
[sojka/nv-tegra/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 #include <asm/smp_plat.h>
30
31 #include "ote_protocol.h"
32
33 bool verbose_smc;
34 core_param(verbose_smc, verbose_smc, bool, 0644);
35
36 #define SET_RESULT(req, r, ro)  { req->result = r; req->result_origin = ro; }
37
38 static int te_pin_user_pages(void *buffer, size_t size,
39                 unsigned long *pages_ptr, uint32_t buf_type)
40 {
41         int ret = 0;
42         unsigned int nr_pages;
43         struct page **pages = NULL;
44         bool writable;
45
46         nr_pages = (((uintptr_t)buffer & (PAGE_SIZE - 1)) +
47                         (size + PAGE_SIZE - 1)) >> PAGE_SHIFT;
48
49         pages = kzalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
50         if (!pages)
51                 return -ENOMEM;
52
53         writable = (buf_type == TE_PARAM_TYPE_MEM_RW ||
54                 buf_type == TE_PARAM_TYPE_PERSIST_MEM_RW);
55
56         down_read(&current->mm->mmap_sem);
57         ret = get_user_pages(current, current->mm, (unsigned long)buffer,
58                         nr_pages, writable,
59                         0, pages, NULL);
60
61         up_read(&current->mm->mmap_sem);
62
63         *pages_ptr = (unsigned long) pages;
64
65         return ret;
66 }
67
68 static int te_prep_mem_buffer(uint32_t session_id,
69                 void *buffer, size_t size, uint32_t buf_type,
70                 struct tlk_context *context)
71 {
72         unsigned long pages = 0;
73         struct te_shmem_desc *shmem_desc = NULL;
74         int ret = 0, nr_pages = 0;
75
76         /* allocate new shmem descriptor */
77         shmem_desc = kzalloc(sizeof(struct te_shmem_desc), GFP_KERNEL);
78         if (!shmem_desc) {
79                 pr_err("%s: te_add_shmem_desc failed\n", __func__);
80                 ret = OTE_ERROR_OUT_OF_MEMORY;
81                 goto error;
82         }
83
84         /* pin pages */
85         nr_pages = te_pin_user_pages(buffer, size, &pages, buf_type);
86         if (nr_pages <= 0) {
87                 pr_err("%s: te_pin_user_pages failed (%d)\n", __func__,
88                         nr_pages);
89                 ret = OTE_ERROR_OUT_OF_MEMORY;
90                 kfree(shmem_desc);
91                 goto error;
92         }
93
94         /* initialize shmem descriptor */
95         INIT_LIST_HEAD(&(shmem_desc->list));
96         shmem_desc->active = false;
97         shmem_desc->buffer = buffer;
98         shmem_desc->size = size;
99         shmem_desc->nr_pages = nr_pages;
100         shmem_desc->pages = (struct page **)(uintptr_t)pages;
101
102         /* add shmem descriptor to proper list */
103         if ((buf_type == TE_PARAM_TYPE_MEM_RO) ||
104                 (buf_type == TE_PARAM_TYPE_MEM_RW))
105                 list_add_tail(&shmem_desc->list, &context->temp_shmem_list);
106         else {
107                 list_add_tail(&shmem_desc->list, &context->persist_shmem_list);
108         }
109
110         return OTE_SUCCESS;
111 error:
112         return ret;
113 }
114
115 static int te_prep_mem_buffers(struct te_request *request,
116                         struct tlk_context *context)
117 {
118         uint32_t i;
119         int ret = OTE_SUCCESS;
120         struct te_oper_param *params = request->params;
121
122         for (i = 0; i < request->params_size; i++) {
123                 switch (params[i].type) {
124                 case TE_PARAM_TYPE_NONE:
125                 case TE_PARAM_TYPE_INT_RO:
126                 case TE_PARAM_TYPE_INT_RW:
127                         break;
128                 case TE_PARAM_TYPE_MEM_RO:
129                 case TE_PARAM_TYPE_MEM_RW:
130                 case TE_PARAM_TYPE_PERSIST_MEM_RO:
131                 case TE_PARAM_TYPE_PERSIST_MEM_RW:
132                         ret = te_prep_mem_buffer(request->session_id,
133                                 params[i].u.Mem.base,
134                                 params[i].u.Mem.len,
135                                 params[i].type,
136                                 context);
137                         if (ret < 0) {
138                                 pr_err("%s failed with err (%d)\n",
139                                         __func__, ret);
140                                 ret = OTE_ERROR_BAD_PARAMETERS;
141                                 break;
142                         }
143                         break;
144                 default:
145                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
146                         ret = OTE_ERROR_BAD_PARAMETERS;
147                         break;
148                 }
149         }
150         return ret;
151 }
152
153 static int te_prep_mem_buffers_compat(struct te_request_compat *request,
154                         struct tlk_context *context)
155 {
156         uint32_t i;
157         int ret = OTE_SUCCESS;
158         struct te_oper_param_compat *params;
159
160         params = (struct te_oper_param_compat *)(uintptr_t)request->params;
161         for (i = 0; i < request->params_size; i++) {
162                 switch (params[i].type) {
163                 case TE_PARAM_TYPE_NONE:
164                 case TE_PARAM_TYPE_INT_RO:
165                 case TE_PARAM_TYPE_INT_RW:
166                         break;
167                 case TE_PARAM_TYPE_MEM_RO:
168                 case TE_PARAM_TYPE_MEM_RW:
169                 case TE_PARAM_TYPE_PERSIST_MEM_RO:
170                 case TE_PARAM_TYPE_PERSIST_MEM_RW:
171                         ret = te_prep_mem_buffer(request->session_id,
172                                 (void *)(uintptr_t)params[i].u.Mem.base,
173                                 params[i].u.Mem.len,
174                                 params[i].type,
175                                 context);
176                         if (ret < 0) {
177                                 pr_err("%s failed with err (%d)\n",
178                                         __func__, ret);
179                                 ret = OTE_ERROR_BAD_PARAMETERS;
180                                 break;
181                         }
182                         break;
183                 default:
184                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
185                         ret = OTE_ERROR_BAD_PARAMETERS;
186                         break;
187                 }
188         }
189         return ret;
190 }
191
192 static void te_release_mem_buffer(struct te_shmem_desc *shmem_desc)
193 {
194         uint32_t i;
195
196         list_del(&shmem_desc->list);
197         for (i = 0; i < shmem_desc->nr_pages; i++) {
198                 if ((shmem_desc->type == TE_PARAM_TYPE_MEM_RW) ||
199                         (shmem_desc->type == TE_PARAM_TYPE_PERSIST_MEM_RW))
200                         set_page_dirty_lock(shmem_desc->pages[i]);
201                 page_cache_release(shmem_desc->pages[i]);
202         }
203         kfree(shmem_desc->pages);
204         kfree(shmem_desc);
205 }
206
207 static void te_release_temp_mem_buffers(struct tlk_context *context)
208 {
209         struct te_shmem_desc *shmem_desc, *tmp_shmem_desc;
210
211         if (list_empty(&context->temp_shmem_list))
212                 return;
213
214         list_for_each_entry_safe(shmem_desc, tmp_shmem_desc,
215                 &context->temp_shmem_list, list) {
216                 te_release_mem_buffer(shmem_desc);
217         }
218 }
219
220 static void te_release_persist_mem_buffers(uint32_t session_id,
221         struct tlk_context *context)
222 {
223         struct te_shmem_desc *shmem_desc, *tmp_shmem_desc;
224
225         if (list_empty(&context->persist_shmem_list))
226                 return;
227
228         /*
229          * Release any persistent mem buffers that either belong to
230          * the specified session_id or are not currently marked active
231          * (i.e. because the associated open_session or launch_operation
232          * failed).
233          */
234         list_for_each_entry_safe(shmem_desc, tmp_shmem_desc,
235                 &context->persist_shmem_list, list) {
236                 if ((shmem_desc->session_id == session_id) ||
237                         (!shmem_desc->active))
238                         te_release_mem_buffer(shmem_desc);
239         }
240 }
241
242 static void te_update_persist_mem_buffers(uint32_t session_id,
243         struct tlk_context *context)
244 {
245         struct te_shmem_desc *shmem_desc, *tmp_shmem_desc;
246
247         /*
248          * Assumes any entries that have yet to be marked active belong
249          * to the session associated with the session_id that has been
250          * passed in.
251          */
252         list_for_each_entry_safe(shmem_desc, tmp_shmem_desc,
253                 &context->persist_shmem_list, list) {
254
255                 if (!shmem_desc->active) {
256                         shmem_desc->session_id = session_id;
257                         shmem_desc->active = true;
258                 }
259         }
260 }
261
262 #ifdef CONFIG_SMP
263 cpumask_t saved_cpu_mask;
264 static void switch_cpumask_to_cpu0(void)
265 {
266         long ret;
267         cpumask_t local_cpu_mask = CPU_MASK_NONE;
268
269         cpu_set(0, local_cpu_mask);
270         cpumask_copy(&saved_cpu_mask, tsk_cpus_allowed(current));
271         ret = sched_setaffinity(0, &local_cpu_mask);
272         if (ret)
273                 pr_err("%s: sched_setaffinity #1 -> 0x%lX", __func__, ret);
274 }
275
276 static void restore_cpumask(void)
277 {
278         long ret = sched_setaffinity(0, &saved_cpu_mask);
279         if (ret)
280                 pr_err("%s: sched_setaffinity #2 -> 0x%lX", __func__, ret);
281 }
282 #else
283 static inline void switch_cpumask_to_cpu0(void) {};
284 static inline void restore_cpumask(void) {};
285 #endif
286
287 uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2)
288 {
289         uint32_t retval;
290
291         switch_cpumask_to_cpu0();
292
293         retval = _tlk_generic_smc(arg0, arg1, arg2);
294         while (retval == TE_ERROR_PREEMPT_BY_IRQ ||
295                retval == TE_ERROR_PREEMPT_BY_FS) {
296                 if (retval == TE_ERROR_PREEMPT_BY_FS)
297                         tlk_ss_op();
298                 retval = _tlk_generic_smc(TE_SMC_RESTART, 0, 0);
299         }
300
301         restore_cpumask();
302
303         return retval;
304 }
305
306 uint32_t tlk_extended_smc(uintptr_t *regs)
307 {
308         uint32_t retval;
309
310         switch_cpumask_to_cpu0();
311
312         retval = _tlk_extended_smc(regs);
313         while (retval == TE_ERROR_PREEMPT_BY_IRQ)
314                 retval = _tlk_generic_smc(TE_SMC_RESTART, 0, 0);
315
316         restore_cpumask();
317
318         return retval;
319 }
320
321 /*
322  * Do an SMC call
323  */
324 static void do_smc(struct te_request *request, struct tlk_device *dev)
325 {
326         uint32_t smc_args;
327         uint32_t smc_params = 0;
328
329         if (dev->req_param_buf) {
330                 smc_args = (char *)request - dev->req_param_buf;
331                 if (request->params)
332                         smc_params = (char *)request->params -
333                                                 dev->req_param_buf;
334         } else {
335                 smc_args = (uint32_t)virt_to_phys(request);
336                 if (request->params)
337                         smc_params = (uint32_t)virt_to_phys(request->params);
338         }
339
340         tlk_generic_smc(request->type, smc_args, smc_params);
341
342         /*
343          * Check to see if there are any logs in written by TLK.
344          * If there are, print them out.
345          */
346         ote_print_logs();
347 }
348
349 struct tlk_smc_work_args {
350         uint32_t arg0;
351         uintptr_t arg1;
352         uint32_t arg2;
353 };
354
355 static long tlk_generic_smc_on_cpu0(void *args)
356 {
357         struct tlk_smc_work_args *work;
358         int cpu = cpu_logical_map(smp_processor_id());
359         uint32_t retval;
360
361         BUG_ON(cpu != 0);
362
363         work = (struct tlk_smc_work_args *)args;
364         retval = _tlk_generic_smc(work->arg0, work->arg1, work->arg2);
365         while (retval == TE_ERROR_PREEMPT_BY_IRQ)
366                 retval = _tlk_generic_smc(TE_SMC_RESTART, 0, 0);
367         return retval;
368 }
369
370 /*
371  * Do an SMC call
372  */
373 static void do_smc_compat(struct te_request_compat *request,
374                           struct tlk_device *dev)
375 {
376         uint32_t smc_args;
377         uint32_t smc_params = 0;
378
379         smc_args = (char *)request - dev->req_param_buf;
380         if (request->params) {
381                 smc_params =
382                         (char *)(uintptr_t)request->params - dev->req_param_buf;
383         }
384
385         tlk_generic_smc(request->type, smc_args, smc_params);
386
387         /*
388          * Check to see if there are any logs in written by TLK.
389          * If there are, print them out.
390          */
391         ote_print_logs();
392 }
393
394 /*
395  * VPR programming SMC
396  *
397  * This routine is called both from normal threads and worker threads.
398  * The worker threads are per-cpu and have PF_NO_SETAFFINITY set, so
399  * any calls to sched_setaffinity will fail.
400  *
401  * If it's a worker thread on CPU0, just invoke the SMC directly. If
402  * it's running on a non-CPU0, use work_on_cpu() to schedule the SMC
403  * on CPU0.
404  */
405 int te_set_vpr_params(void *vpr_base, size_t vpr_size)
406 {
407         uint32_t retval;
408
409         /* Share the same lock used when request is send from user side */
410         mutex_lock(&smc_lock);
411
412         if (current->flags &
413             (PF_WQ_WORKER | PF_NO_SETAFFINITY | PF_KTHREAD)) {
414                 struct tlk_smc_work_args work_args;
415                 int cpu = cpu_logical_map(smp_processor_id());
416
417                 work_args.arg0 = TE_SMC_PROGRAM_VPR;
418                 work_args.arg1 = (uintptr_t)vpr_base;
419                 work_args.arg2 = vpr_size;
420
421                 /* workers don't change CPU. depending on the CPU, execute
422                  * directly or sched work */
423                 if (cpu == 0 && (current->flags & PF_WQ_WORKER))
424                         retval = tlk_generic_smc_on_cpu0(&work_args);
425                 else
426                         retval = work_on_cpu(0,
427                                         tlk_generic_smc_on_cpu0, &work_args);
428         } else {
429                 retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR,
430                                         (uintptr_t)vpr_base, vpr_size);
431         }
432
433         mutex_unlock(&smc_lock);
434
435         if (retval != OTE_SUCCESS) {
436                 pr_err("%s: smc failed err (0x%x)\n", __func__, retval);
437                 return -EINVAL;
438         }
439         return 0;
440 }
441 EXPORT_SYMBOL(te_set_vpr_params);
442
443
444 /*
445  * Open session SMC (supporting client-based te_open_session() calls)
446  */
447 void te_open_session(struct te_opensession *cmd,
448                      struct te_request *request,
449                      struct tlk_context *context)
450 {
451         int ret;
452
453         request->type = TE_SMC_OPEN_SESSION;
454
455         ret = te_prep_mem_buffers(request, context);
456         if (ret != OTE_SUCCESS) {
457                 pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n",
458                         __func__, ret);
459                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
460                 return;
461         }
462
463         memcpy(&request->dest_uuid,
464                &cmd->dest_uuid,
465                sizeof(struct te_service_id));
466
467         pr_info("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n",
468                 request->dest_uuid[0],
469                 request->dest_uuid[1],
470                 request->dest_uuid[2],
471                 request->dest_uuid[3]);
472
473         do_smc(request, context->dev);
474
475         if (request->result) {
476                 /* release any persistent mem buffers if we failed */
477                 te_release_persist_mem_buffers(request->session_id, context);
478         } else {
479                 /* mark active any persistent mem buffers */
480                 te_update_persist_mem_buffers(request->session_id, context);
481         }
482
483         te_release_temp_mem_buffers(context);
484 }
485
486 /*
487  * Close session SMC (supporting client-based te_close_session() calls)
488  */
489 void te_close_session(struct te_closesession *cmd,
490                       struct te_request *request,
491                       struct tlk_context *context)
492 {
493         request->session_id = cmd->session_id;
494         request->type = TE_SMC_CLOSE_SESSION;
495
496         do_smc(request, context->dev);
497         if (request->result)
498                 pr_info("%s: error closing session: %08x\n",
499                         __func__, request->result);
500
501         /* release any peristent mem buffers */
502         te_release_persist_mem_buffers(request->session_id, context);
503 }
504
505 /*
506  * Launch operation SMC (supporting client-based te_launch_operation() calls)
507  */
508 void te_launch_operation(struct te_launchop *cmd,
509                          struct te_request *request,
510                          struct tlk_context *context)
511 {
512         int ret;
513
514         request->session_id = cmd->session_id;
515         request->command_id = cmd->operation.command;
516         request->type = TE_SMC_LAUNCH_OPERATION;
517
518         ret = te_prep_mem_buffers(request, context);
519         if (ret != OTE_SUCCESS) {
520                 pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n",
521                         __func__, ret);
522                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
523                 return;
524         }
525
526         do_smc(request, context->dev);
527
528         if (request->result) {
529                 /* release any persistent mem buffers if we failed */
530                 te_release_persist_mem_buffers(request->session_id, context);
531         } else {
532                 /* mark active any persistent mem buffers */
533                 te_update_persist_mem_buffers(request->session_id, context);
534         }
535
536         te_release_temp_mem_buffers(context);
537 }
538
539 /*
540  * Open session SMC (supporting client-based te_open_session() calls)
541  */
542 void te_open_session_compat(struct te_opensession_compat *cmd,
543                             struct te_request_compat *request,
544                             struct tlk_context *context)
545 {
546         int ret;
547
548         request->type = TE_SMC_OPEN_SESSION;
549
550         ret = te_prep_mem_buffers_compat(request, context);
551         if (ret != OTE_SUCCESS) {
552                 pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n",
553                         __func__, ret);
554                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
555                 return;
556         }
557
558         memcpy(&request->dest_uuid,
559                &cmd->dest_uuid,
560                sizeof(struct te_service_id));
561
562         pr_info("OPEN_CLIENT_SESSION_COMPAT: 0x%x 0x%x 0x%x 0x%x\n",
563                 request->dest_uuid[0],
564                 request->dest_uuid[1],
565                 request->dest_uuid[2],
566                 request->dest_uuid[3]);
567
568         do_smc_compat(request, context->dev);
569
570         if (request->result) {
571                 /* release any persistent mem buffers if we failed */
572                 te_release_persist_mem_buffers(request->session_id, context);
573         } else {
574                 /* mark active any persistent mem buffers */
575                 te_update_persist_mem_buffers(request->session_id, context);
576         }
577
578         te_release_temp_mem_buffers(context);
579 }
580
581 /*
582  * Close session SMC (supporting client-based te_close_session() calls)
583  */
584 void te_close_session_compat(struct te_closesession_compat *cmd,
585                              struct te_request_compat *request,
586                              struct tlk_context *context)
587 {
588         request->session_id = cmd->session_id;
589         request->type = TE_SMC_CLOSE_SESSION;
590
591         do_smc_compat(request, context->dev);
592         if (request->result)
593                 pr_info("%s: error closing session: %08x\n",
594                         __func__, request->result);
595
596         /* release any peristent mem buffers */
597         te_release_persist_mem_buffers(request->session_id, context);
598 }
599
600 /*
601  * Launch operation SMC (supporting client-based te_launch_operation() calls)
602  */
603 void te_launch_operation_compat(struct te_launchop_compat *cmd,
604                                 struct te_request_compat *request,
605                                 struct tlk_context *context)
606 {
607         int ret;
608
609         request->session_id = cmd->session_id;
610         request->command_id = cmd->operation.command;
611         request->type = TE_SMC_LAUNCH_OPERATION;
612
613         ret = te_prep_mem_buffers_compat(request, context);
614         if (ret != OTE_SUCCESS) {
615                 pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n",
616                         __func__, ret);
617                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
618                 return;
619         }
620
621         do_smc_compat(request, context->dev);
622
623         if (request->result) {
624                 /* release any persistent mem buffers if we failed */
625                 te_release_persist_mem_buffers(request->session_id, context);
626         } else {
627                 /* mark active any persistent mem buffers */
628                 te_update_persist_mem_buffers(request->session_id, context);
629         }
630
631         te_release_temp_mem_buffers(context);
632 }