security: nv_tee_driver: add return origin & input/output param support
[linux-3.10.git] / security / nv_tee_driver / tee_comms.c
1 /*
2  * Copyright (c) 2013, NVIDIA Corporation.
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 "tee_types.h"
31 #include "tee_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 #define TEE_PARAM_COUNT 4
39
40 static int tee_device_set_request_params(struct tee_request *request,
41         struct TEEC_Operation *operation)
42 {
43         struct tee_cmd_param *param = &request->cmd_param;
44         uint32_t i, type;
45
46         param->param_types = operation->paramTypes;
47         for (i = 0; i < TEE_PARAM_COUNT; i++) {
48                 type = TEEC_PARAM_TYPE_GET(operation->paramTypes, i);
49                 switch (type) {
50                 case TEEC_PARAM_TYPE_NONE:
51                         break;
52                 case TEEC_PARAM_TYPE_VALUE_INPUT:
53                 case TEEC_PARAM_TYPE_VALUE_OUTPUT:
54                 case TEEC_PARAM_TYPE_VALUE_INOUT:
55                         memcpy(&param->params[i].value,
56                                 &operation->params[i].value,
57                                 sizeof(union tee_param));
58                 break;
59                 case TEEC_PARAM_TYPE_MEMREF_INPUT:
60                 case TEEC_PARAM_TYPE_MEMREF_OUTPUT:
61                 case TEEC_PARAM_TYPE_MEMREF_INOUT:
62                         memcpy(&param->params[i].memref,
63                                &operation->params[i].tmpref,
64                                sizeof(union tee_param));
65                 break;
66                 default:
67                         return TEEC_ERROR_BAD_PARAMETERS;
68                 }
69         }
70         return TEEC_SUCCESS;
71 }
72
73 static int tee_device_get_answer_params(struct TEEC_Operation *operation,
74         struct tee_request *request)
75 {
76         struct tee_cmd_param *param = &request->cmd_param;
77         uint32_t i, type;
78
79         param->param_types = operation->paramTypes;
80         for (i = 0; i < TEE_PARAM_COUNT; i++) {
81                 type = TEEC_PARAM_TYPE_GET(operation->paramTypes, i);
82                 switch (type) {
83                 case TEEC_PARAM_TYPE_NONE:
84                         break;
85                 case TEEC_PARAM_TYPE_VALUE_INPUT:
86                 case TEEC_PARAM_TYPE_VALUE_OUTPUT:
87                 case TEEC_PARAM_TYPE_VALUE_INOUT:
88                         memcpy(&operation->params[i].value,
89                                 &param->params[i].value,
90                                 sizeof(union tee_param));
91                 break;
92                 case TEEC_PARAM_TYPE_MEMREF_INPUT:
93                 case TEEC_PARAM_TYPE_MEMREF_OUTPUT:
94                 case TEEC_PARAM_TYPE_MEMREF_INOUT:
95                         memcpy(&operation->params[i].tmpref,
96                                &param->params[i].memref,
97                                sizeof(union tee_param));
98                 break;
99                 default:
100                         return TEEC_ERROR_BAD_PARAMETERS;
101                 }
102         }
103         return TEEC_SUCCESS;
104 }
105
106 static int tee_pin_user_pages(void *buffer, size_t size,
107         unsigned long *pages_ptr)
108 {
109         int ret = 0;
110         unsigned int nr_pages;
111         struct page **pages = NULL;
112
113         nr_pages = (((unsigned int)buffer & (PAGE_SIZE - 1)) +
114                         (size + PAGE_SIZE - 1)) >> PAGE_SHIFT;
115
116         pages = kzalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
117         if (!pages)
118                 return -ENOMEM;
119
120         down_read(&current->mm->mmap_sem);
121         ret = get_user_pages(current, current->mm, (unsigned long)buffer,
122                                 nr_pages, WRITE, 0, pages, NULL);
123         up_read(&current->mm->mmap_sem);
124
125         *pages_ptr = (unsigned long) pages;
126
127         return ret;
128 }
129
130 static struct nv_shmem_desc *tee_add_shmem_desc(void *buffer, size_t size,
131                         unsigned int nr_pages, struct page **pages,
132                         struct nv_tee_context *context)
133 {
134         struct nv_shmem_desc *shmem_desc = NULL;
135         shmem_desc = kzalloc(
136                                                 sizeof(struct nv_shmem_desc),
137                                                 GFP_KERNEL);
138         if (shmem_desc) {
139                 INIT_LIST_HEAD(&(shmem_desc->list));
140                 shmem_desc->buffer = buffer;
141                 shmem_desc->size = size;
142                 shmem_desc->nr_pages = nr_pages;
143                 shmem_desc->pages = pages;
144                 list_add_tail(&shmem_desc->list, &(context->shmem_alloc_list));
145         }
146
147         return shmem_desc;
148 }
149
150 static int tee_pin_mem_buffers(void *buffer, size_t size,
151         struct nv_tee_context *context)
152 {
153
154         unsigned long pages = 0;
155         struct nv_shmem_desc *shmem_desc = NULL;
156         int ret = 0, nr_pages = 0;
157
158         nr_pages = tee_pin_user_pages(buffer, size, &pages);
159         if (nr_pages <= 0) {
160                 pr_err("tee_pin_mem_buffers: tee_pin_user_pages Failed\n");
161                 ret = TEEC_ERROR_OUT_OF_MEMORY;
162                 goto error;
163         }
164
165         shmem_desc = tee_add_shmem_desc(buffer, size,
166                                 nr_pages, (struct page **)pages, context);
167         if (!shmem_desc) {
168                 pr_err("tee_pin_mem_buffers: tee_add_shmem_desc Failed\n");
169                 ret = TEEC_ERROR_OUT_OF_MEMORY;
170                 goto error;
171         }
172
173         return TEEC_SUCCESS;
174 error:
175         return ret;
176 }
177
178 static int tee_setup_temp_buffers(struct TEEC_Operation *oper,
179         struct nv_tee_context *context)
180 {
181         uint32_t i, type;
182         int ret = TEEC_SUCCESS;
183
184         for (i = 0; i < TEE_PARAM_COUNT; i++) {
185                 type = TEEC_PARAM_TYPE_GET(oper->paramTypes, i);
186                 switch (type) {
187                 case TEEC_PARAM_TYPE_NONE:
188                 case TEEC_PARAM_TYPE_VALUE_INPUT:
189                 case TEEC_PARAM_TYPE_VALUE_OUTPUT:
190                 case TEEC_PARAM_TYPE_VALUE_INOUT:
191                         break;
192                 case TEEC_PARAM_TYPE_MEMREF_INPUT:
193                 case TEEC_PARAM_TYPE_MEMREF_OUTPUT:
194                 case TEEC_PARAM_TYPE_MEMREF_INOUT:
195                         ret = tee_pin_mem_buffers(
196                                 oper->params[i].tmpref.buffer,
197                                 oper->params[i].tmpref.size,
198                                 context);
199                         if (ret < 0) {
200                                 pr_err("tee_pin_mem_buffers failed with err (%d)\n",
201                                                 ret);
202                                 ret = TEEC_ERROR_BAD_PARAMETERS;
203                                 break;
204                         }
205                         break;
206                 default:
207                         pr_err("tee_pin_mem_buffers: TEEC_ERROR_BAD_PARAMETERS\n");
208                         ret = TEEC_ERROR_BAD_PARAMETERS;
209                         break;
210                 }
211         }
212         return ret;
213 }
214
215 static void tee_del_shmem_desc(void *buffer, struct nv_tee_context *context)
216 {
217         struct nv_shmem_desc *shmem_desc, *tmp_shmem_desc;
218         int i;
219
220         list_for_each_entry_safe(shmem_desc, tmp_shmem_desc,
221                 &(context->shmem_alloc_list), list) {
222                 if (shmem_desc->buffer == buffer) {
223                         list_del(&shmem_desc->list);
224                         for (i = 0; i < shmem_desc->nr_pages; i++)
225                                 page_cache_release(shmem_desc->pages[i]);
226                         kfree(shmem_desc->pages);
227                         kfree(shmem_desc);
228                 }
229         }
230 }
231
232 /*
233  * Deregister previously initialized shared memory
234  */
235 void tee_unregister_memory(void *buffer,
236         struct nv_tee_context *context)
237 {
238         if (!(list_empty(&(context->shmem_alloc_list))))
239                 tee_del_shmem_desc(buffer, context);
240         else
241                 pr_err("No buffers to unpin\n");
242 }
243
244 static void tee_unpin_temp_buffers(struct TEEC_Operation *oper,
245         struct nv_tee_context *context)
246 {
247         uint32_t i, type;
248
249         for (i = 0; i < TEE_PARAM_COUNT; i++) {
250                 type = TEEC_PARAM_TYPE_GET(oper->paramTypes, i);
251                 switch (type) {
252                 case TEEC_PARAM_TYPE_NONE:
253                 case TEEC_PARAM_TYPE_VALUE_INPUT:
254                 case TEEC_PARAM_TYPE_VALUE_OUTPUT:
255                 case TEEC_PARAM_TYPE_VALUE_INOUT:
256                         break;
257                 case TEEC_PARAM_TYPE_MEMREF_INPUT:
258                 case TEEC_PARAM_TYPE_MEMREF_OUTPUT:
259                 case TEEC_PARAM_TYPE_MEMREF_INOUT:
260                         tee_unregister_memory(oper->params[i].tmpref.buffer,
261                                 context);
262                         break;
263                 default:
264                         pr_err("tee_unpin_mem_buffers: TEEC_ERROR_BAD_PARAMETERS\n");
265                         break;
266                 }
267         }
268 }
269
270 /*
271  * Do an SMC call
272  */
273 static void do_smc(struct tee_request *request)
274 {
275         phys_addr_t smc_args = virt_to_phys(request);
276
277 #ifdef CONFIG_SMP
278         long ret;
279         cpumask_t saved_cpu_mask;
280         cpumask_t local_cpu_mask = CPU_MASK_NONE;
281
282         cpu_set(0, local_cpu_mask);
283         sched_getaffinity(0, &saved_cpu_mask);
284         ret = sched_setaffinity(0, &local_cpu_mask);
285         if (ret != 0)
286                 pr_err("sched_setaffinity #1 -> 0x%lX", ret);
287 #endif
288
289         asm volatile (
290                 "stmdb  sp!, {r4-r12}\n"
291                 "mov    r0,  %0\n"
292                 "mov    r1,  %1\n"
293 #ifdef REQUIRES_SEC
294                 ".arch_extension sec\n"
295 #endif
296                 "smc    #0\n"
297                 "ldmia  sp!, {r4-r12}\n"
298                 : : "r" (request->type), "r" (smc_args)
299                 : "r0", "r1"
300         );
301
302 #ifdef CONFIG_SMP
303         ret = sched_setaffinity(0, &saved_cpu_mask);
304         if (ret != 0)
305                 pr_err("sched_setaffinity #2 -> 0x%lX", ret);
306 #endif
307 }
308
309 /*
310  * Do an 'empty' request just to get more pending answers.
311  */
312 static void get_more_answers(struct tee_request *request)
313 {
314         request->type = TMK_SMC_GET_MORE;
315         /* rest of request ignored */
316         do_smc(request);
317 }
318
319 /*
320  * Open session SMC (TEEC_OpenSession)
321  */
322 void tee_open_session(struct tee_opensession *cmd,
323                       struct tee_request *request,
324                       struct nv_tee_context *context)
325 {
326         int ret;
327
328         ret = tee_device_set_request_params(request, &cmd->operation);
329         if (ret != TEEC_SUCCESS) {
330                 pr_err("tee_device_set_request_params failed\n");
331                 SET_RESULT(request, ret, TEEC_ORIGIN_API);
332                 return;
333         }
334
335         ret = tee_setup_temp_buffers(&cmd->operation, context);
336         if (ret != TEEC_SUCCESS) {
337                 pr_err("tee_setup_temp_buffers failed err (0x%x)\n", ret);
338                 SET_RESULT(request, ret, TEEC_ORIGIN_API);
339                 return;
340         }
341
342         memcpy(&request->cmd_param.dest_uuid,
343                &cmd->dest_uuid,
344                sizeof(struct TEEC_UUID));
345
346         pr_info("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n",
347                 request->cmd_param.dest_uuid[0],
348                 request->cmd_param.dest_uuid[1],
349                 request->cmd_param.dest_uuid[2],
350                 request->cmd_param.dest_uuid[3]);
351
352         request->type = TMK_SMC_OPEN_SESSION;
353
354         do_smc(request);
355
356         tee_device_get_answer_params(&cmd->operation, request);
357
358         tee_unpin_temp_buffers(&cmd->operation, context);
359 }
360
361 /*
362  * Close session SMC (TEEC_CloseSession)
363  */
364 void tee_close_session(struct tee_closesession *cmd,
365                        struct tee_request *request)
366 {
367         request->type = TMK_SMC_CLOSE_SESSION;
368         request->session_id = cmd->session_id;
369
370         do_smc(request);
371         if (request->result)
372                 pr_info("Error closing session: %08x\n", request->result);
373 }
374
375 /*
376  * Register Shared Memory SMC (TEEC_RegisterSharedMemory)
377  */
378 void tee_register_memory(struct tee_sharedmem *cmd, struct tee_request *request,
379                         struct nv_tee_context *context)
380 {
381         int ret = 0;
382
383         request->type = TMK_SMC_REG_SHARED_MEM;
384         request->session_id = cmd->session_id;
385
386         request->cmd_param.param_types = cmd->memref.flags;
387         request->cmd_param.params[0].memref.buffer = cmd->memref.buffer;
388         request->cmd_param.params[0].memref.size = cmd->memref.size;
389
390         ret = tee_pin_mem_buffers(cmd->memref.buffer, cmd->memref.size,
391                 context);
392         if (ret != TEEC_SUCCESS) {
393                 SET_RESULT(request, ret, TEEC_ORIGIN_API);
394                 return;
395         }
396
397         do_smc(request);
398 }
399
400 /*
401  * Invoke Command SMC (TEEC_InvokeCommand)
402  */
403 void tee_invoke_command(struct tee_invokecmd *cmd,
404                         struct tee_request *request,
405                         struct nv_tee_context *context)
406 {
407         int ret = TEEC_SUCCESS;
408
409         ret = tee_device_set_request_params(request, &cmd->operation);
410         if (ret != TEEC_SUCCESS) {
411                 pr_err("tee_device_set_request_params failed\n");
412                 SET_RESULT(request, ret, TEEC_ORIGIN_API);
413                 return;
414         }
415
416         ret = tee_setup_temp_buffers(&cmd->operation, context);
417         if (ret != TEEC_SUCCESS) {
418                 pr_err("tee_setup_temp_buffers failed err (0x%x)\n", ret);
419                 SET_RESULT(request, ret, TEEC_ORIGIN_API);
420                 return;
421         }
422
423         request->type = TMK_SMC_INVOKE_CMD;
424         request->session_id = cmd->session_id;
425         request->command_id = cmd->command_id;
426
427         do_smc(request);
428
429         tee_device_get_answer_params(&cmd->operation, request);
430
431         tee_unpin_temp_buffers(&cmd->operation, context);
432 }
433
434 static int __init nv_tee_register_irq_handler(void)
435 {
436         asm volatile (
437                 "mov    r1, %0\n"
438                 "movw   r0, #0x1FF0\n"
439                 "movt   r0, #0xFFFF\n"
440 #ifdef REQUIRES_SEC
441                 ".arch_extension sec\n"
442 #endif
443                 "smc    #0\n"
444                 "cpsie  i\n"
445                 : : "r" (nv_tee_irq_handler)
446                 : "r0", "r1", "r13", "r14"
447         );
448
449         return 0;
450 }
451
452 arch_initcall(nv_tee_register_irq_handler);