tlk: 6/19 update
[3rdparty/ote_partner/tlk.git] / kernel / syscall.c
1 /*
2  * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include <debug.h>
24 #include <errno.h>
25 #include <err.h>
26 #include <assert.h>
27 #include <string.h>
28 #include <arch/arm.h>
29 #include <arch/outercache.h>
30 #include <kernel/thread.h>
31 #include <stdlib.h>
32 #include <platform/memmap.h>
33 #include <lib/ote/ote_protocol.h>
34 #include <ote_intf.h>
35 #include <platform/platform_p.h>
36 #include <kernel/task_load.h>
37
38 struct timespec {
39         long tv_sec;    /* seconds */
40         long tv_nsec;   /* nanoseconds */
41 };
42
43 #define MAP_SHARED              0x01    /* Share changes.  */
44 #define MAP_PRIVATE             0x02    /* Changes are private.  */
45 #define MAP_ANONYMOUS           0x20    /* Don't use a file.  */
46
47 static int platform_ta_to_ta_request_handler(te_ta_to_ta_request_args_t *args)
48 {
49         te_error_t result;
50
51         /* validate command buffer */
52         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
53                 return -EFAULT;
54         }
55
56         dprintf(SPEW, "%s: %d\n", __func__, args->request.type);
57
58         switch (args->request.type) {
59                 case OPEN_SESSION:
60                         result = te_handle_open_session(&args->request, true);
61                         break;
62                 case CLOSE_SESSION:
63                         result = te_handle_close_session(&args->request, true);
64                         break;
65                 case LAUNCH_OPERATION:
66                         result = te_handle_launch_op(&args->request, true);
67                         break;
68                 default:
69                         dprintf(SPEW, "%s: unknown cmd=0x%x\n",
70                                 __func__, args->request.type);
71                         return -EINVAL;
72         }
73
74         args->request.result = result;
75
76         /* consider any failure here to have occured in common TEE code */
77         if (args->request.result != OTE_SUCCESS) {
78                 args->request.result_origin = OTE_RESULT_ORIGIN_KERNEL;
79         }
80
81         te_get_completed_cmd(&args->request, true);
82
83         return 0;
84 }
85
86 static int platform_get_property_handler(te_get_property_args_t *args)
87 {
88         int retval = 0;
89
90         /* validate command buffer */
91         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
92                 return -EFAULT;
93         }
94
95         dprintf(SPEW, "%s: propset 0x%x\n", __func__, args->prop);
96
97         switch (args->prop) {
98                 case TE_PROPERTY_CURRENT_TA:
99                         retval = te_get_current_ta_property(args);
100                         break;
101                 case TE_PROPERTY_CURRENT_CLIENT:
102                         retval = te_get_current_client_property(args);
103                         break;
104                 case TE_PROPERTY_TE_IMPLEMENTATION:
105                         retval = te_get_implementation_property(args);
106                         break;
107                 default:
108                         args->result = OTE_ERROR_BAD_PARAMETERS;
109                         retval = -EINVAL;
110                         break;
111         }
112
113         return retval;
114 }
115
116 static int platform_ioctl_handler(u_int cmd, void *cmdbuf)
117 {
118         task_t *taskp = current_thread->arch.task;
119
120         dprintf(SPEW, "%s: cmd 0x%x cmdbuf 0x%p\n",
121                 __func__, cmd, cmdbuf);
122
123         switch (cmd) {
124                 case OTE_IOCTL_GET_MAP_MEM_ADDR:
125                 {
126                         te_map_mem_addr_args_t *args = cmdbuf;
127                         task_map_t *mptr;
128
129                         /* validate command buffer */
130                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
131                                 return -EFAULT;
132                         }
133
134                         mptr = task_find_mapping_by_id(taskp, args->id);
135                         if (mptr == NULL) {
136                                 return -EINVAL;
137                         }
138
139                         args->addr = (void *)((uint32_t)mptr->vaddr + mptr->offset);
140
141                         break;
142                 }
143                 case OTE_IOCTL_V_TO_P:
144                 {
145                         te_v_to_p_args_t *args = cmdbuf;
146                         paddr_t paddr;
147                         status_t retval;
148
149                         /* validate command buffer */
150                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
151                                 return -EFAULT;
152                         }
153
154                         retval = task_get_physaddr(taskp, (vaddr_t)args->vaddr, &paddr);
155                         if (retval != NO_ERROR)
156                                 return -EINVAL;
157
158                         args->paddr = paddr;
159                         break;
160                 }
161                 case OTE_IOCTL_CACHE_MAINT:
162                 {
163                         te_cache_maint_args_t *args = cmdbuf;
164 #if ARM_WITH_OUTER_CACHE
165                         vaddr_t vaddr;
166                         uint32_t nbytes;
167 #endif
168                         /* validate command buffer */
169                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
170                                 return -EFAULT;
171                         }
172
173                         /* operate on L1 (virtual addrs) */
174                         switch (args->op) {
175                         case OTE_EXT_NV_CM_OP_CLEAN:
176                                 arch_clean_cache_range((addr_t)args->vaddr, args->length);
177                                 break;
178                         case OTE_EXT_NV_CM_OP_INVALIDATE:
179                                 arch_invalidate_cache_range((addr_t)args->vaddr, args->length);
180                                 break;
181                         case OTE_EXT_NV_CM_OP_FLUSH:
182                                 arch_clean_invalidate_cache_range((addr_t)args->vaddr, args->length);
183                                 break;
184                         default:
185                                 return -EINVAL;
186                         }
187 #if ARM_WITH_OUTER_CACHE
188                         /* operate on L2 (physical addrs) */
189                         nbytes = args->length;
190                         vaddr = (vaddr_t)args->vaddr;
191
192                         while (nbytes) {
193                                 uint32_t len;
194                                 paddr_t paddr;
195                                 status_t retval;
196
197                                 retval = task_get_physaddr(taskp, vaddr, &paddr);
198                                 if (retval != NO_ERROR)
199                                         return -EFAULT;
200
201                                 /* careful in crossing page boundaries */
202                                 len = PAGE_SIZE - (paddr & PAGE_MASK);
203                                 len = MIN(nbytes, len);
204
205                                 switch (args->op) {
206                                 case OTE_EXT_NV_CM_OP_CLEAN:
207                                         outer_clean_range(paddr, len);
208                                         break;
209                                 case OTE_EXT_NV_CM_OP_INVALIDATE:
210                                         outer_inv_range(paddr, len);
211                                         break;
212                                 case OTE_EXT_NV_CM_OP_FLUSH:
213                                         outer_flush_range(paddr, len);
214                                         break;
215                                 }
216                                 vaddr  += len;
217                                 nbytes -= len;
218                         }
219 #endif
220                         break;
221                 }
222                 case OTE_IOCTL_TA_TO_TA_REQUEST:
223                 {
224                         te_ta_to_ta_request_args_t *args = cmdbuf;
225
226                         return platform_ta_to_ta_request_handler(args);
227                 }
228                 case OTE_IOCTL_GET_PROPERTY:
229                 {
230                         te_get_property_args_t *args = cmdbuf;
231
232                         return platform_get_property_handler(args);
233                 }
234                 case OTE_IOCTL_SS_REQUEST:
235                 {
236                         te_storage_request_t *args = cmdbuf;
237
238                         /* validate command buffer */
239                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
240                                 return -EFAULT;
241                         }
242
243                         return platform_ss_request_handler(args);
244                 }
245                 case OTE_IOCTL_GET_DEVICE_ID:
246                 {
247                         te_device_id_args_t *args = cmdbuf;
248
249                         /* validate command buffer */
250                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
251                                 return -EFAULT;
252                         }
253
254                         platform_get_device_id(args);
255                         break;
256                 }
257                 case OTE_IOCTL_GET_TIME_US:
258                 {
259                         uint32_t *args = cmdbuf;
260
261                         /* validate command buffer */
262                         if (!task_valid_address((vaddr_t)cmdbuf,
263                                                         sizeof(uint32_t)))
264                                 return -EFAULT;
265
266                         *args = platform_get_time_us();
267                         break;
268                 }
269                 case OTE_IOCTL_GET_RAND32:
270                 {
271                         uint32_t *args = cmdbuf;
272
273                         /* validate command buffer */
274                         if (!task_valid_address((vaddr_t)cmdbuf,
275                                                         sizeof(uint32_t)))
276                                 return -EFAULT;
277
278                         *args = platform_get_rand32();
279                         break;
280                 }
281                 case OTE_IOCTL_TASK_REQUEST:
282                 {
283                         te_task_request_args_t *args = cmdbuf;
284
285                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
286                                 return -EFAULT;
287                         }
288
289                         return task_request_handler (args);
290                 }
291                 default:
292                 {
293                         dprintf(SPEW, "%s: invalid ioctl: cmd=0x%x\n",
294                                 __func__, cmd);
295                         return -EINVAL;
296                 }
297         }
298
299         return 0;
300 }
301
302 bool platform_syscall_handler(void *arg)
303 {
304         task_t *task = current_thread->arch.task;
305         uint32_t *r = arg;
306
307         if (r[7] == 0x3) {      /* read */
308                 /* only expect reads of the TA pipe fd */
309                 r[0] = te_handle_ta_message(r[0],
310                                              (void *)(r[1]),
311                                              r[2],
312                                              true);
313                 return true;
314         }
315         if (r[7] == 0x4) {      /* write */
316                 /* check buffer is in task's address space */
317                 if (task_valid_address(r[1], r[2]) == false) {
318                         r[0] = -EFAULT;
319                         return true;
320                 }
321                 if ((r[0] == 1) || (r[0] == 2)) {
322                         u_int i;
323                         /* handle stdout/stderr */
324                         for (i = 0; i < r[2]; i++) {
325                                 dprintf(CRITICAL, "%c", ((char *)r[1])[i]);
326                         }
327                         r[0] = r[2];
328                 } else {
329                         /* handle writes of one of the TA pipe fd's */
330                         r[0] = te_handle_ta_message(r[0],
331                                                      (void *)(r[1]),
332                                                      r[2],
333                                                      false);
334                 }
335                 return true;
336         }
337         if (r[7] == 0x5) {      /* open */
338                 /* for now, fail all open() attempts */
339                 r[0] = -ENXIO;
340                 return true;
341         }
342         if (r[7] == 0x2d) {     /* brk */
343                 u_int brk = r[0];
344
345                 /* update brk, if within range */
346                 if ((brk >= task->start_brk) && (brk < task->end_brk)) {
347                         task->curr_brk = brk;
348                 } else {
349                         if (brk >= task->end_brk) {
350                                 dprintf(CRITICAL,
351                                         "%s: task %d: "
352                                         "no more heap (size 0x%lx bytes)\n",
353                                         __func__, task->task_index,
354                                         task->end_brk - task->start_brk);
355                         } else if ((brk < task->start_brk) && (brk != 0)) {
356                                 dprintf(CRITICAL,
357                                         "%s: task %d: "
358                                         "brk 0x%x < heap start 0x%lx\n",
359                                         __func__, task->task_index,
360                                         brk, task->start_brk);
361                         }
362                 }
363
364                 r[0] = task->curr_brk;
365                 return true;
366         }
367         if (r[7] == 0x4e) {     /* sys_gettimeofday */
368                 r[0] = 0;
369                 return true;
370         }
371         if (r[7] == 0x5b) {     /* munmap */
372                 /* attempt to reclaim most recent alloc */
373                 if ((r[0] + r[1]) == task->curr_brk) {
374                         task->curr_brk = r[0];
375                 }
376                 r[0] = 0;
377                 return true;
378         }
379         if (r[7] == 0x7d) {     /* mprotect */
380                 r[0] = 0;
381                 return true;
382         }
383         if (r[7] == 0xa2) {     /* usleep */
384                 struct timespec *ts;
385
386                 /* check buffer is in task's address space */
387                 if (task_valid_address(r[0], sizeof(struct timespec)) == false) {
388                         r[0] = -EFAULT;
389                         return true;
390                 }
391
392                 ts = (struct timespec *)r[0];
393                 if (ts->tv_sec) {
394                         dprintf(SPEW, "ignoring seconds arg to usleep\n");
395                         ts->tv_sec = 0;
396                 }
397
398                 spin(ts->tv_nsec / 1000);
399
400                 r[0] = 0;
401                 return true;
402         }
403         if (r[7] == 0xc0) {     /* mmap2 */
404                 u_int brk;
405
406                 if (r[3] != (MAP_ANONYMOUS | MAP_PRIVATE)) {
407                         r[0] = -EINVAL;
408                         return true;
409                 }
410
411                 r[0] = ROUNDUP(task->curr_brk, PAGE_SIZE);
412                 brk = r[0] + ROUNDUP(r[1], PAGE_SIZE);
413
414                 /* update brk, if within range */
415                 if ((brk >= task->start_brk) && (brk < task->end_brk)) {
416                         task->curr_brk = brk;
417                         return true;
418                 } else {
419                         if (brk >= task->end_brk) {
420                                 dprintf(CRITICAL,
421                                         "%s: task %d: mmap2: "
422                                         "no more heap (size 0x%lx bytes)\n",
423                                         __func__, task->task_index,
424                                         task->end_brk - task->start_brk);
425                         } else if (brk < task->start_brk) {
426                                 dprintf(CRITICAL,
427                                         "%s: task %d: mmap2: "
428                                         "brk 0x%x < heap start 0x%lx\n",
429                                         __func__, task->task_index,
430                                         brk, task->start_brk);
431                         }
432                 }
433                 r[0] = -ENOMEM;
434                 return true;
435         }
436         if (r[7] == 0xc5) {     /* fstat */
437                 r[0] = -ENOENT;
438                 return true;
439         }
440         if (r[7] == 0xdc) {     /* madvise */
441                 r[0] = 0;
442                 return true;
443         }
444         if (r[7] == 0xe0) {     /* gettid */
445                 r[0] = (u_int)current_thread;
446                 return true;
447         }
448         if (r[7] == 0x14) {     /* getpid */
449                 r[0] = -ENOENT;
450                 return true;
451         }
452         if (r[7] == 0xc7) {     /* getuid */
453                 r[0] = -ENOENT;
454                 return true;
455         }
456         if (r[7] == 0xf8) {     /* exit_group */
457                 /* terminate thread (and all task threads) */
458                 /* thread_exit(r[0]); */
459
460                 /* for now, just suspend the thread */
461                 thread_suspend();
462                 return true;
463         }
464         if (r[7] == 0x107) {    /* sys_clock_gettime */
465                 r[0] = -EFAULT;
466                 return true;
467         }
468         if (r[7] == 0x119){     /* socket */
469                 r[0] = -ENOENT;
470                 return true;
471         }
472         if (r[7] == 0xF0005) {  /* set_tls */
473                 current_thread->arch.tp_value = r[0];
474                 arch_set_tls(r[0]);
475
476                 r[0] = 0x0;
477                 return true;
478         }
479         if (r[7] == 0x36) {     /* ioctl */
480                 r[0] = platform_ioctl_handler(r[1], (void *)r[2]);
481
482                 return true;
483         }
484
485         dprintf(CRITICAL, "%s: unhandled syscall: 0x%x\n", __func__, r[7]);
486
487         return true;
488 }