d7fa733a6aa0aa09fe5b3d455988f58cc94ad9d8
[tegra/ote_partner/tlk_driver.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         /* Print TLK logs if any */
304         ote_print_logs();
305
306         return retval;
307 }
308
309 uint32_t tlk_extended_smc(uintptr_t *regs)
310 {
311         uint32_t retval;
312
313         switch_cpumask_to_cpu0();
314
315         retval = _tlk_extended_smc(regs);
316         while (retval == TE_ERROR_PREEMPT_BY_IRQ)
317                 retval = _tlk_generic_smc(TE_SMC_RESTART, 0, 0);
318
319         restore_cpumask();
320
321         /* Print TLK logs if any */
322         ote_print_logs();
323
324         return retval;
325 }
326
327 /*
328  * Do an SMC call
329  */
330 static void do_smc(struct te_request *request, struct tlk_device *dev)
331 {
332         uint32_t smc_args;
333         uint32_t smc_params = 0;
334
335         if (dev->req_param_buf) {
336                 smc_args = (char *)request - dev->req_param_buf;
337                 if (request->params)
338                         smc_params = (char *)request->params -
339                                                 dev->req_param_buf;
340         } else {
341                 smc_args = (uint32_t)virt_to_phys(request);
342                 if (request->params)
343                         smc_params = (uint32_t)virt_to_phys(request->params);
344         }
345
346         tlk_generic_smc(request->type, smc_args, smc_params);
347 }
348
349 /*
350  * Do an SMC call
351  */
352 static void do_smc_compat(struct te_request_compat *request,
353                           struct tlk_device *dev)
354 {
355         uint32_t smc_args;
356         uint32_t smc_params = 0;
357
358         smc_args = (char *)request - dev->req_param_buf;
359         if (request->params) {
360                 smc_params =
361                         (char *)(uintptr_t)request->params - dev->req_param_buf;
362         }
363
364         tlk_generic_smc(request->type, smc_args, smc_params);
365 }
366
367 struct tlk_smc_work_args {
368         uint32_t arg0;
369         uintptr_t arg1;
370         uint32_t arg2;
371 };
372
373 static long tlk_generic_smc_on_cpu0(void *args)
374 {
375         struct tlk_smc_work_args *work;
376         int cpu = cpu_logical_map(smp_processor_id());
377         uint32_t retval;
378
379         BUG_ON(cpu != 0);
380
381         work = (struct tlk_smc_work_args *)args;
382         retval = _tlk_generic_smc(work->arg0, work->arg1, work->arg2);
383         while (retval == TE_ERROR_PREEMPT_BY_IRQ)
384                 retval = _tlk_generic_smc(TE_SMC_RESTART, 0, 0);
385         return retval;
386 }
387
388 /*
389  * VPR programming SMC
390  *
391  * This routine is called both from normal threads and worker threads.
392  * The worker threads are per-cpu and have PF_NO_SETAFFINITY set, so
393  * any calls to sched_setaffinity will fail.
394  *
395  * If it's a worker thread on CPU0, just invoke the SMC directly. If
396  * it's running on a non-CPU0, use work_on_cpu() to schedule the SMC
397  * on CPU0.
398  */
399 int te_set_vpr_params(void *vpr_base, size_t vpr_size)
400 {
401         uint32_t retval;
402
403         /* Share the same lock used when request is send from user side */
404         mutex_lock(&smc_lock);
405
406         if (current->flags &
407             (PF_WQ_WORKER | PF_NO_SETAFFINITY | PF_KTHREAD)) {
408                 struct tlk_smc_work_args work_args;
409                 int cpu = cpu_logical_map(smp_processor_id());
410
411                 work_args.arg0 = TE_SMC_PROGRAM_VPR;
412                 work_args.arg1 = (uintptr_t)vpr_base;
413                 work_args.arg2 = vpr_size;
414
415                 /* workers don't change CPU. depending on the CPU, execute
416                  * directly or sched work */
417                 if (cpu == 0 && (current->flags & PF_WQ_WORKER))
418                         retval = tlk_generic_smc_on_cpu0(&work_args);
419                 else
420                         retval = work_on_cpu(0,
421                                         tlk_generic_smc_on_cpu0, &work_args);
422         } else {
423                 retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR,
424                                         (uintptr_t)vpr_base, vpr_size);
425         }
426
427         mutex_unlock(&smc_lock);
428
429         if (retval != OTE_SUCCESS) {
430                 pr_err("%s: smc failed err (0x%x)\n", __func__, retval);
431                 return -EINVAL;
432         }
433         return 0;
434 }
435 EXPORT_SYMBOL(te_set_vpr_params);
436
437
438 /*
439  * Open session SMC (supporting client-based te_open_session() calls)
440  */
441 void te_open_session(struct te_opensession *cmd,
442                      struct te_request *request,
443                      struct tlk_context *context)
444 {
445         int ret;
446
447         request->type = TE_SMC_OPEN_SESSION;
448
449         ret = te_prep_mem_buffers(request, context);
450         if (ret != OTE_SUCCESS) {
451                 pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n",
452                         __func__, ret);
453                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
454                 return;
455         }
456
457         memcpy(&request->dest_uuid,
458                &cmd->dest_uuid,
459                sizeof(struct te_service_id));
460
461         pr_info("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n",
462                 request->dest_uuid[0],
463                 request->dest_uuid[1],
464                 request->dest_uuid[2],
465                 request->dest_uuid[3]);
466
467         do_smc(request, context->dev);
468
469         if (request->result) {
470                 /* release any persistent mem buffers if we failed */
471                 te_release_persist_mem_buffers(request->session_id, context);
472         } else {
473                 /* mark active any persistent mem buffers */
474                 te_update_persist_mem_buffers(request->session_id, context);
475         }
476
477         te_release_temp_mem_buffers(context);
478 }
479
480 /*
481  * Close session SMC (supporting client-based te_close_session() calls)
482  */
483 void te_close_session(struct te_closesession *cmd,
484                       struct te_request *request,
485                       struct tlk_context *context)
486 {
487         request->session_id = cmd->session_id;
488         request->type = TE_SMC_CLOSE_SESSION;
489
490         do_smc(request, context->dev);
491         if (request->result)
492                 pr_info("%s: error closing session: %08x\n",
493                         __func__, request->result);
494
495         /* release any peristent mem buffers */
496         te_release_persist_mem_buffers(request->session_id, context);
497 }
498
499 /*
500  * Launch operation SMC (supporting client-based te_launch_operation() calls)
501  */
502 void te_launch_operation(struct te_launchop *cmd,
503                          struct te_request *request,
504                          struct tlk_context *context)
505 {
506         int ret;
507
508         request->session_id = cmd->session_id;
509         request->command_id = cmd->operation.command;
510         request->type = TE_SMC_LAUNCH_OPERATION;
511
512         ret = te_prep_mem_buffers(request, context);
513         if (ret != OTE_SUCCESS) {
514                 pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n",
515                         __func__, ret);
516                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
517                 return;
518         }
519
520         do_smc(request, context->dev);
521
522         if (request->result) {
523                 /* release any persistent mem buffers if we failed */
524                 te_release_persist_mem_buffers(request->session_id, context);
525         } else {
526                 /* mark active any persistent mem buffers */
527                 te_update_persist_mem_buffers(request->session_id, context);
528         }
529
530         te_release_temp_mem_buffers(context);
531 }
532
533 /*
534  * Open session SMC (supporting client-based te_open_session() calls)
535  */
536 void te_open_session_compat(struct te_opensession_compat *cmd,
537                             struct te_request_compat *request,
538                             struct tlk_context *context)
539 {
540         int ret;
541
542         request->type = TE_SMC_OPEN_SESSION;
543
544         ret = te_prep_mem_buffers_compat(request, context);
545         if (ret != OTE_SUCCESS) {
546                 pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n",
547                         __func__, ret);
548                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
549                 return;
550         }
551
552         memcpy(&request->dest_uuid,
553                &cmd->dest_uuid,
554                sizeof(struct te_service_id));
555
556         pr_info("OPEN_CLIENT_SESSION_COMPAT: 0x%x 0x%x 0x%x 0x%x\n",
557                 request->dest_uuid[0],
558                 request->dest_uuid[1],
559                 request->dest_uuid[2],
560                 request->dest_uuid[3]);
561
562         do_smc_compat(request, context->dev);
563
564         if (request->result) {
565                 /* release any persistent mem buffers if we failed */
566                 te_release_persist_mem_buffers(request->session_id, context);
567         } else {
568                 /* mark active any persistent mem buffers */
569                 te_update_persist_mem_buffers(request->session_id, context);
570         }
571
572         te_release_temp_mem_buffers(context);
573 }
574
575 /*
576  * Close session SMC (supporting client-based te_close_session() calls)
577  */
578 void te_close_session_compat(struct te_closesession_compat *cmd,
579                              struct te_request_compat *request,
580                              struct tlk_context *context)
581 {
582         request->session_id = cmd->session_id;
583         request->type = TE_SMC_CLOSE_SESSION;
584
585         do_smc_compat(request, context->dev);
586         if (request->result)
587                 pr_info("%s: error closing session: %08x\n",
588                         __func__, request->result);
589
590         /* release any peristent mem buffers */
591         te_release_persist_mem_buffers(request->session_id, context);
592 }
593
594 /*
595  * Launch operation SMC (supporting client-based te_launch_operation() calls)
596  */
597 void te_launch_operation_compat(struct te_launchop_compat *cmd,
598                                 struct te_request_compat *request,
599                                 struct tlk_context *context)
600 {
601         int ret;
602
603         request->session_id = cmd->session_id;
604         request->command_id = cmd->operation.command;
605         request->type = TE_SMC_LAUNCH_OPERATION;
606
607         ret = te_prep_mem_buffers_compat(request, context);
608         if (ret != OTE_SUCCESS) {
609                 pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n",
610                         __func__, ret);
611                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
612                 return;
613         }
614
615         do_smc_compat(request, context->dev);
616
617         if (request->result) {
618                 /* release any persistent mem buffers if we failed */
619                 te_release_persist_mem_buffers(request->session_id, context);
620         } else {
621                 /* mark active any persistent mem buffers */
622                 te_update_persist_mem_buffers(request->session_id, context);
623         }
624 }