security: tlk_driver: ensure VPR SMC occurs on CPU0
[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 struct te_shmem_desc *te_add_shmem_desc(void *buffer, size_t size,
39                 struct tlk_context *context)
40 {
41         struct te_shmem_desc *shmem_desc = NULL;
42         shmem_desc = kzalloc(sizeof(struct te_shmem_desc), GFP_KERNEL);
43         if (shmem_desc) {
44                 INIT_LIST_HEAD(&(shmem_desc->list));
45                 shmem_desc->buffer = buffer;
46                 shmem_desc->size = size;
47                 list_add_tail(&shmem_desc->list, &(context->shmem_alloc_list));
48         }
49
50         return shmem_desc;
51 }
52
53 static int te_pin_mem_buffers(void *buffer, size_t size,
54                 struct tlk_context *context)
55 {
56         struct te_shmem_desc *shmem_desc = NULL;
57         int ret = 0;
58
59         shmem_desc = te_add_shmem_desc(buffer, size, context);
60         if (!shmem_desc) {
61                 pr_err("%s: te_add_shmem_desc Failed\n", __func__);
62                 ret = OTE_ERROR_OUT_OF_MEMORY;
63                 goto error;
64         }
65
66         return OTE_SUCCESS;
67 error:
68         return ret;
69 }
70
71 static int te_setup_temp_buffers(struct te_request *request,
72                 struct tlk_context *context)
73 {
74         uint32_t i;
75         int ret = OTE_SUCCESS;
76         struct te_oper_param *params = request->params;
77
78         for (i = 0; i < request->params_size; i++) {
79                 switch (params[i].type) {
80                 case TE_PARAM_TYPE_NONE:
81                 case TE_PARAM_TYPE_INT_RO:
82                 case TE_PARAM_TYPE_INT_RW:
83                         break;
84                 case TE_PARAM_TYPE_MEM_RO:
85                 case TE_PARAM_TYPE_MEM_RW:
86                         ret = te_pin_mem_buffers(
87                                 params[i].u.Mem.base,
88                                 params[i].u.Mem.len,
89                                 context);
90                         if (ret < 0) {
91                                 pr_err("%s failed with err (%d)\n",
92                                         __func__, ret);
93                                 ret = OTE_ERROR_BAD_PARAMETERS;
94                                 break;
95                         }
96                         break;
97                 default:
98                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
99                         ret = OTE_ERROR_BAD_PARAMETERS;
100                         break;
101                 }
102         }
103         return ret;
104 }
105
106 static int te_setup_temp_buffers_compat(struct te_request_compat *request,
107                 struct tlk_context *context)
108 {
109         uint32_t i;
110         int ret = OTE_SUCCESS;
111         struct te_oper_param_compat *params;
112
113         params = (struct te_oper_param_compat *)(uintptr_t)request->params;
114         for (i = 0; i < request->params_size; i++) {
115                 switch (params[i].type) {
116                 case TE_PARAM_TYPE_NONE:
117                 case TE_PARAM_TYPE_INT_RO:
118                 case TE_PARAM_TYPE_INT_RW:
119                         break;
120                 case TE_PARAM_TYPE_MEM_RO:
121                 case TE_PARAM_TYPE_MEM_RW:
122                         ret = te_pin_mem_buffers(
123                                 (void *)(uintptr_t)params[i].u.Mem.base,
124                                 params[i].u.Mem.len,
125                                 context);
126                         if (ret < 0) {
127                                 pr_err("%s failed with err (%d)\n",
128                                         __func__, ret);
129                                 ret = OTE_ERROR_BAD_PARAMETERS;
130                                 break;
131                         }
132                         break;
133                 default:
134                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
135                         ret = OTE_ERROR_BAD_PARAMETERS;
136                         break;
137                 }
138         }
139         return ret;
140 }
141
142 static void te_del_shmem_desc(void *buffer, struct tlk_context *context)
143 {
144         struct te_shmem_desc *shmem_desc, *tmp_shmem_desc;
145
146         list_for_each_entry_safe(shmem_desc, tmp_shmem_desc,
147                 &(context->shmem_alloc_list), list) {
148                 if (shmem_desc->buffer == buffer) {
149                         list_del(&shmem_desc->list);
150                         kfree(shmem_desc);
151                 }
152         }
153 }
154
155 /*
156  * Deregister previously initialized shared memory
157  */
158 void te_unregister_memory(void *buffer,
159         struct tlk_context *context)
160 {
161         if (!(list_empty(&(context->shmem_alloc_list))))
162                 te_del_shmem_desc(buffer, context);
163         else
164                 pr_err("No buffers to unpin\n");
165 }
166
167 static void te_unpin_temp_buffers(struct te_request *request,
168         struct tlk_context *context)
169 {
170         uint32_t i;
171         struct te_oper_param *params = request->params;
172
173         for (i = 0; i < request->params_size; i++) {
174                 switch (params[i].type) {
175                 case TE_PARAM_TYPE_NONE:
176                 case TE_PARAM_TYPE_INT_RO:
177                 case TE_PARAM_TYPE_INT_RW:
178                         break;
179                 case TE_PARAM_TYPE_MEM_RO:
180                 case TE_PARAM_TYPE_MEM_RW:
181                         te_unregister_memory(params[i].u.Mem.base, context);
182                         break;
183                 default:
184                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
185                         break;
186                 }
187         }
188 }
189
190 static void te_unpin_temp_buffers_compat(struct te_request_compat *request,
191         struct tlk_context *context)
192 {
193         uint32_t i;
194         struct te_oper_param_compat *params;
195
196         params = (struct te_oper_param_compat *)(uintptr_t)request->params;
197         for (i = 0; i < request->params_size; i++) {
198                 switch (params[i].type) {
199                 case TE_PARAM_TYPE_NONE:
200                 case TE_PARAM_TYPE_INT_RO:
201                 case TE_PARAM_TYPE_INT_RW:
202                         break;
203                 case TE_PARAM_TYPE_MEM_RO:
204                 case TE_PARAM_TYPE_MEM_RW:
205                         te_unregister_memory(
206                                 (void *)(uintptr_t)params[i].u.Mem.base,
207                                 context);
208                         break;
209                 default:
210                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
211                         break;
212                 }
213         }
214 }
215
216 #ifdef CONFIG_SMP
217 cpumask_t saved_cpu_mask;
218 static void switch_cpumask_to_cpu0(void)
219 {
220         long ret;
221         cpumask_t local_cpu_mask = CPU_MASK_NONE;
222         unsigned long flags;
223
224         flags = current->flags;
225         current->flags &= ~PF_NO_SETAFFINITY;
226
227         cpu_set(0, local_cpu_mask);
228         cpumask_copy(&saved_cpu_mask, tsk_cpus_allowed(current));
229         ret = sched_setaffinity(0, &local_cpu_mask);
230         if (ret)
231                 pr_err("sched_setaffinity #1 -> 0x%lX", ret);
232
233         current->flags = flags;
234 }
235
236 static void restore_cpumask(void)
237 {
238         unsigned long flags;
239         long ret;
240
241         flags = current->flags;
242         current->flags &= ~PF_NO_SETAFFINITY;
243
244         ret = sched_setaffinity(0, &saved_cpu_mask);
245         if (ret)
246                 pr_err("sched_setaffinity #2 -> 0x%lX", ret);
247
248         current->flags = flags;
249 }
250 #else
251 static inline void switch_cpumask_to_cpu0(void) {};
252 static inline void restore_cpumask(void) {};
253 #endif
254
255 uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2)
256 {
257         uint32_t retval;
258
259         switch_cpumask_to_cpu0();
260
261         retval = _tlk_generic_smc(arg0, arg1, arg2);
262         while (retval == 0xFFFFFFFD)
263                 retval = _tlk_generic_smc((60 << 24), 0, 0);
264
265         restore_cpumask();
266
267         /* Print TLK logs if any */
268         ote_print_logs();
269
270         return retval;
271 }
272
273 uint32_t tlk_extended_smc(uintptr_t *regs)
274 {
275         uint32_t retval;
276
277         switch_cpumask_to_cpu0();
278
279         retval = _tlk_extended_smc(regs);
280         while (retval == 0xFFFFFFFD)
281                 retval = _tlk_generic_smc((60 << 24), 0, 0);
282
283         restore_cpumask();
284
285         /* Print TLK logs if any */
286         ote_print_logs();
287
288         return retval;
289 }
290
291 /*
292  * Do an SMC call
293  */
294 static void do_smc(struct te_request *request, struct tlk_device *dev)
295 {
296         uint32_t smc_args;
297         uint32_t smc_params = 0;
298
299         if (dev->req_param_buf) {
300                 smc_args = (char *)request - dev->req_param_buf;
301                 if (request->params)
302                         smc_params = (char *)request->params -
303                                                 dev->req_param_buf;
304         } else {
305                 smc_args = (uint32_t)virt_to_phys(request);
306                 if (request->params)
307                         smc_params = (uint32_t)virt_to_phys(request->params);
308         }
309
310         tlk_generic_smc(request->type, smc_args, smc_params);
311 }
312
313 /*
314  * Do an SMC call
315  */
316 static void do_smc_compat(struct te_request_compat *request,
317                           struct tlk_device *dev)
318 {
319         uint32_t smc_args;
320         uint32_t smc_params = 0;
321
322         smc_args = (char *)request - dev->req_param_buf;
323         if (request->params) {
324                 smc_params =
325                         (char *)(uintptr_t)request->params - dev->req_param_buf;
326         }
327
328         tlk_generic_smc(request->type, smc_args, smc_params);
329 }
330
331 struct tlk_smc_work_args {
332         uint32_t arg0;
333         uint32_t arg1;
334         uint32_t arg2;
335 };
336
337 static long tlk_generic_smc_on_cpu0(void *args)
338 {
339         struct tlk_smc_work_args *work;
340         int cpu = cpu_logical_map(smp_processor_id());
341         uint32_t retval;
342
343         BUG_ON(cpu != 0);
344
345         work = (struct tlk_smc_work_args *)args;
346         retval = _tlk_generic_smc(work->arg0, work->arg1, work->arg2);
347         while (retval == 0xFFFFFFFD)
348                 retval = _tlk_generic_smc((60 << 24), 0, 0);
349         return retval;
350 }
351
352 /*
353  * VPR programming SMC
354  *
355  * This routine is called both from normal threads and worker threads.
356  * The worker threads are per-cpu and have PF_NO_SETAFFINITY set, so
357  * any calls to sched_setaffinity will fail.
358  *
359  * If it's a worker thread on CPU0, just invoke the SMC directly. If
360  * it's running on a non-CPU0, use work_on_cpu() to schedule the SMC
361  * on CPU0.
362  */
363 int te_set_vpr_params(void *vpr_base, size_t vpr_size)
364 {
365         uint32_t retval;
366
367         /* Share the same lock used when request is send from user side */
368         mutex_lock(&smc_lock);
369
370         if (current->flags & PF_WQ_WORKER) {
371                 struct tlk_smc_work_args work_args;
372                 int cpu = cpu_logical_map(smp_processor_id());
373
374                 work_args.arg0 = TE_SMC_PROGRAM_VPR;
375                 work_args.arg1 = (uint32_t)vpr_base;
376                 work_args.arg2 = vpr_size;
377
378                 /* depending on the CPU, execute directly or sched work */
379                 if (cpu == 0)
380                         retval = tlk_generic_smc_on_cpu0(&work_args);
381                 else
382                         retval = work_on_cpu(0,
383                                         tlk_generic_smc_on_cpu0, &work_args);
384         } else {
385                 retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR,
386                                         (uintptr_t)vpr_base, vpr_size);
387         }
388
389         mutex_unlock(&smc_lock);
390
391         if (retval != OTE_SUCCESS) {
392                 pr_err("te_set_vpr_params failed err (0x%x)\n", retval);
393                 return -EINVAL;
394         }
395         return 0;
396 }
397 EXPORT_SYMBOL(te_set_vpr_params);
398
399 /*
400  * Open session SMC (supporting client-based te_open_session() calls)
401  */
402 void te_open_session(struct te_opensession *cmd,
403                      struct te_request *request,
404                      struct tlk_context *context)
405 {
406         int ret;
407
408         ret = te_setup_temp_buffers(request, context);
409         if (ret != OTE_SUCCESS) {
410                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
411                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
412                 return;
413         }
414
415         memcpy(&request->dest_uuid,
416                &cmd->dest_uuid,
417                sizeof(struct te_service_id));
418
419         pr_info("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n",
420                 request->dest_uuid[0],
421                 request->dest_uuid[1],
422                 request->dest_uuid[2],
423                 request->dest_uuid[3]);
424
425         request->type = TE_SMC_OPEN_SESSION;
426
427         do_smc(request, context->dev);
428
429         te_unpin_temp_buffers(request, context);
430 }
431
432 /*
433  * Close session SMC (supporting client-based te_close_session() calls)
434  */
435 void te_close_session(struct te_closesession *cmd,
436                       struct te_request *request,
437                       struct tlk_context *context)
438 {
439         request->session_id = cmd->session_id;
440         request->type = TE_SMC_CLOSE_SESSION;
441
442         do_smc(request, context->dev);
443         if (request->result)
444                 pr_info("Error closing session: %08x\n", request->result);
445 }
446
447 /*
448  * Launch operation SMC (supporting client-based te_launch_operation() calls)
449  */
450 void te_launch_operation(struct te_launchop *cmd,
451                          struct te_request *request,
452                          struct tlk_context *context)
453 {
454         int ret;
455
456         ret = te_setup_temp_buffers(request, context);
457         if (ret != OTE_SUCCESS) {
458                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
459                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
460                 return;
461         }
462
463         request->session_id = cmd->session_id;
464         request->command_id = cmd->operation.command;
465         request->type = TE_SMC_LAUNCH_OPERATION;
466
467         do_smc(request, context->dev);
468
469         te_unpin_temp_buffers(request, context);
470 }
471
472 /*
473  * Open session SMC (supporting client-based te_open_session() calls)
474  */
475 void te_open_session_compat(struct te_opensession_compat *cmd,
476                             struct te_request_compat *request,
477                             struct tlk_context *context)
478 {
479         int ret;
480
481         ret = te_setup_temp_buffers_compat(request, context);
482         if (ret != OTE_SUCCESS) {
483                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
484                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
485                 return;
486         }
487
488         memcpy(&request->dest_uuid,
489                &cmd->dest_uuid,
490                sizeof(struct te_service_id));
491
492         pr_info("OPEN_CLIENT_SESSION_COMPAT: 0x%x 0x%x 0x%x 0x%x\n",
493                 request->dest_uuid[0],
494                 request->dest_uuid[1],
495                 request->dest_uuid[2],
496                 request->dest_uuid[3]);
497
498         request->type = TE_SMC_OPEN_SESSION;
499
500         do_smc_compat(request, context->dev);
501
502         te_unpin_temp_buffers_compat(request, context);
503 }
504
505 /*
506  * Close session SMC (supporting client-based te_close_session() calls)
507  */
508 void te_close_session_compat(struct te_closesession_compat *cmd,
509                              struct te_request_compat *request,
510                              struct tlk_context *context)
511 {
512         request->session_id = cmd->session_id;
513         request->type = TE_SMC_CLOSE_SESSION;
514
515         do_smc_compat(request, context->dev);
516         if (request->result)
517                 pr_info("Error closing session: %08x\n", request->result);
518 }
519
520 /*
521  * Launch operation SMC (supporting client-based te_launch_operation() calls)
522  */
523 void te_launch_operation_compat(struct te_launchop_compat *cmd,
524                                 struct te_request_compat *request,
525                                 struct tlk_context *context)
526 {
527         int ret;
528
529         ret = te_setup_temp_buffers_compat(request, context);
530         if (ret != OTE_SUCCESS) {
531                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
532                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
533                 return;
534         }
535
536         request->session_id = cmd->session_id;
537         request->command_id = cmd->operation.command;
538         request->type = TE_SMC_LAUNCH_OPERATION;
539
540         do_smc_compat(request, context->dev);
541
542         te_unpin_temp_buffers_compat(request, context);
543 }
544
545 static int __init tlk_register_irq_handler(void)
546 {
547         tlk_generic_smc(TE_SMC_REGISTER_IRQ_HANDLER,
548                 (uintptr_t)tlk_irq_handler, 0);
549         return 0;
550 }
551
552 arch_initcall(tlk_register_irq_handler);