First version
[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
37 struct timespec {
38         long tv_sec;    /* seconds */
39         long tv_nsec;   /* nanoseconds */
40 };
41
42 #define MAP_SHARED              0x01    /* Share changes.  */
43 #define MAP_PRIVATE             0x02    /* Changes are private.  */
44 #define MAP_ANONYMOUS           0x20    /* Don't use a file.  */
45
46 int tee_handle_ta_message(uint32_t fd, void *msg, uint32_t msgsize, bool isread);
47
48 static int platform_ta_to_ta_request_handler(te_ta_to_ta_request_args_t *args)
49 {
50         te_error_t result;
51
52         /* validate command buffer */
53         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
54                 return -EFAULT;
55         }
56
57         dprintf(SPEW, "%s: %d\n", __func__, args->request.type);
58
59         switch (args->request.type) {
60                 case OPEN_SESSION:
61                         result = te_handle_open_session(&args->request, true);
62                         break;
63                 case CLOSE_SESSION:
64                         result = te_handle_close_session(&args->request, true);
65                         break;
66                 case LAUNCH_OPERATION:
67                         result = te_handle_launch_op(&args->request, true);
68                         break;
69                 default:
70                         dprintf(SPEW, "%s: unknown cmd=0x%x\n",
71                                 __func__, args->request.type);
72                         return -EINVAL;
73         }
74
75         args->request.result = result;
76
77         /* consider any failure here to have occured in common TEE code */
78         if (args->request.result != OTE_SUCCESS) {
79                 args->request.result_origin = OTE_RESULT_ORIGIN_KERNEL;
80         }
81
82         te_get_completed_cmd(&args->request, true);
83
84         return 0;
85 }
86
87 static int platform_get_property_handler(te_get_property_args_t *args)
88 {
89         int retval = 0;
90
91         /* validate command buffer */
92         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
93                 return -EFAULT;
94         }
95
96         dprintf(SPEW, "%s: propset 0x%x\n", __func__, args->prop);
97
98         switch (args->prop) {
99                 case TE_PROPERTY_CURRENT_TA:
100                         retval = te_get_current_ta_property(args);
101                         break;
102                 case TE_PROPERTY_CURRENT_CLIENT:
103                         retval = te_get_current_client_property(args);
104                         break;
105                 case TE_PROPERTY_TE_IMPLEMENTATION:
106                         retval = te_get_implementation_property(args);
107                         break;
108                 default:
109                         args->result = OTE_ERROR_BAD_PARAMETERS;
110                         retval = -EINVAL;
111                         break;
112         }
113
114         return retval;
115 }
116
117 static int platform_ioctl_handler(u_int cmd, void *cmdbuf)
118 {
119         task_t *taskp = current_thread->arch.task;
120
121         dprintf(SPEW, "%s: cmd 0x%x cmdbuf 0x%p\n",
122                 __func__, cmd, cmdbuf);
123
124         switch (cmd) {
125                 case OTE_IOCTL_GET_MAP_MEM_ADDR:
126                 {
127                         te_map_mem_addr_args_t *args = cmdbuf;
128                         task_map_t *mptr;
129
130                         /* validate command buffer */
131                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
132                                 return -EFAULT;
133                         }
134
135                         mptr = task_find_mapping_by_id(taskp, args->id);
136                         if (mptr == NULL) {
137                                 return -EINVAL;
138                         }
139
140                         args->addr = (void *)((uint32_t)mptr->vaddr + mptr->offset);
141
142                         break;
143                 }
144                 case OTE_IOCTL_V_TO_P:
145                 {
146                         te_v_to_p_args_t *args = cmdbuf;
147                         paddr_t paddr;
148                         status_t retval;
149
150                         /* validate command buffer */
151                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
152                                 return -EFAULT;
153                         }
154
155                         retval = task_get_physaddr(taskp, (vaddr_t)args->vaddr, &paddr);
156                         if (retval != NO_ERROR)
157                                 return -EINVAL;
158
159                         args->paddr = paddr;
160                         break;
161                 }
162                 case OTE_IOCTL_CACHE_MAINT:
163                 {
164                         te_cache_maint_args_t *args = cmdbuf;
165 #if ARM_WITH_OUTER_CACHE
166                         vaddr_t vaddr;
167                         uint32_t nbytes;
168 #endif
169                         /* validate command buffer */
170                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
171                                 return -EFAULT;
172                         }
173
174                         /* operate on L1 (virtual addrs) */
175                         switch (args->op) {
176                         case OTE_EXT_NV_CM_OP_CLEAN:
177                                 arch_clean_cache_range((addr_t)args->vaddr, args->length);
178                                 break;
179                         case OTE_EXT_NV_CM_OP_INVALIDATE:
180                                 arch_invalidate_cache_range((addr_t)args->vaddr, args->length);
181                                 break;
182                         case OTE_EXT_NV_CM_OP_FLUSH:
183                                 arch_clean_invalidate_cache_range((addr_t)args->vaddr, args->length);
184                                 break;
185                         default:
186                                 return -EINVAL;
187                         }
188 #if ARM_WITH_OUTER_CACHE
189                         /* operate on L2 (physical addrs) */
190                         nbytes = args->length;
191                         vaddr = (vaddr_t)args->vaddr;
192
193                         while (nbytes) {
194                                 uint32_t len;
195                                 paddr_t paddr;
196                                 status_t retval;
197
198                                 retval = task_get_physaddr(taskp, vaddr, &paddr);
199                                 if (retval != NO_ERROR)
200                                         return -EFAULT;
201
202                                 /* careful in crossing page boundaries */
203                                 len = PAGE_SIZE - (paddr & PAGE_MASK);
204                                 len = MIN(nbytes, len);
205
206                                 switch (args->op) {
207                                 case OTE_EXT_NV_CM_OP_CLEAN:
208                                         outer_clean_range(paddr, len);
209                                         break;
210                                 case OTE_EXT_NV_CM_OP_INVALIDATE:
211                                         outer_inv_range(paddr, len);
212                                         break;
213                                 case OTE_EXT_NV_CM_OP_FLUSH:
214                                         outer_flush_range(paddr, len);
215                                         break;
216                                 }
217                                 vaddr  += len;
218                                 nbytes -= len;
219                         }
220 #endif
221                         break;
222                 }
223                 case OTE_IOCTL_TA_TO_TA_REQUEST:
224                 {
225                         te_ta_to_ta_request_args_t *args = cmdbuf;
226
227                         return platform_ta_to_ta_request_handler(args);
228                 }
229                 case OTE_IOCTL_GET_PROPERTY:
230                 {
231                         te_get_property_args_t *args = cmdbuf;
232
233                         return platform_get_property_handler(args);
234                 }
235                 case OTE_IOCTL_SS_REQUEST:
236                 {
237                         te_storage_request_t *args = cmdbuf;
238
239                         /* validate command buffer */
240                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
241                                 return -EFAULT;
242                         }
243
244                         return platform_ss_request_handler(args);
245                 }
246                 case OTE_IOCTL_GET_DEVICE_ID:
247                 {
248                         te_device_id_args_t *args = cmdbuf;
249
250                         /* validate command buffer */
251                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
252                                 return -EFAULT;
253                         }
254
255                         platform_get_device_id(args);
256                         break;
257                 }
258                 case OTE_IOCTL_GET_TIME_US:
259                 {
260                         uint32_t *args = cmdbuf;
261
262                         /* validate command buffer */
263                         if (!task_valid_address((vaddr_t)cmdbuf,
264                                                         sizeof(uint32_t)))
265                                 return -EFAULT;
266
267                         *args = platform_get_time_us();
268                         break;
269                 }
270                 case OTE_IOCTL_GET_RAND32:
271                 {
272                         uint32_t *args = cmdbuf;
273
274                         /* validate command buffer */
275                         if (!task_valid_address((vaddr_t)cmdbuf,
276                                                         sizeof(uint32_t)))
277                                 return -EFAULT;
278
279                         *args = platform_get_rand32();
280                         break;
281                 }
282                 default:
283                 {
284                         dprintf(SPEW, "%s: invalid ioctl: cmd=0x%x\n",
285                                 __func__, cmd);
286                         return -EINVAL;
287                 }
288         }
289
290         return 0;
291 }
292
293 bool platform_syscall_handler(void *arg)
294 {
295         task_t *task = current_thread->arch.task;
296         uint32_t *r = arg;
297
298         if (r[7] == 0x3) {      /* read */
299                 /* only expect reads of the TA pipe fd */
300                 r[0] = te_handle_ta_message(r[0],
301                                              (void *)(r[1]),
302                                              r[2],
303                                              true);
304                 return true;
305         }
306         if (r[7] == 0x4) {      /* write */
307                 /* check buffer is in task's address space */
308                 if (task_valid_address(r[1], r[2]) == false) {
309                         r[0] = -EFAULT;
310                         return true;
311                 }
312                 if ((r[0] == 1) || (r[0] == 2)) {
313                         u_int i;
314                         /* handle stdout/stderr */
315                         for (i = 0; i < r[2]; i++) {
316                                 dprintf(CRITICAL, "%c", ((char *)r[1])[i]);
317                         }
318                         r[0] = r[2];
319                 } else {
320                         /* handle writes of one of the TA pipe fd's */
321                         r[0] = te_handle_ta_message(r[0],
322                                                      (void *)(r[1]),
323                                                      r[2],
324                                                      false);
325                 }
326                 return true;
327         }
328         if (r[7] == 0x5) {      /* open */
329                 /* for now, fail all open() attempts */
330                 r[0] = -ENXIO;
331                 return true;
332         }
333         if (r[7] == 0x2d) {     /* brk */
334                 u_int brk = r[0];
335
336                 /* update brk, if within range */
337                 if ((brk >= task->start_brk) && (brk < task->end_brk)) {
338                         task->curr_brk = brk;
339                 }
340                 r[0] = task->curr_brk;
341                 return true;
342         }
343         if (r[7] == 0x4e) {     /* sys_gettimeofday */
344                 r[0] = 0;
345                 return true;
346         }
347         if (r[7] == 0x5b) {     /* munmap */
348                 /* attempt to reclaim most recent alloc */
349                 if ((r[0] + r[1]) == task->curr_brk) {
350                         task->curr_brk = r[0];
351                 }
352                 r[0] = 0;
353                 return true;
354         }
355         if (r[7] == 0x7d) {     /* mprotect */
356                 r[0] = 0;
357                 return true;
358         }
359         if (r[7] == 0xa2) {     /* usleep */
360                 struct timespec *ts;
361
362                 /* check buffer is in task's address space */
363                 if (task_valid_address(r[0], sizeof(struct timespec)) == false) {
364                         r[0] = -EFAULT;
365                         return true;
366                 }
367
368                 ts = (struct timespec *)r[0];
369                 if (ts->tv_sec) {
370                         dprintf(SPEW, "ignoring seconds arg to usleep\n");
371                         ts->tv_sec = 0;
372                 }
373
374                 spin(ts->tv_nsec / 1000);
375
376                 r[0] = 0;
377                 return true;
378         }
379         if (r[7] == 0xc0) {     /* mmap2 */
380                 u_int brk;
381
382                 if (r[3] != (MAP_ANONYMOUS | MAP_PRIVATE)) {
383                         r[0] = -EINVAL;
384                         return true;
385                 }
386
387                 r[0] = ROUNDUP(task->curr_brk, PAGE_SIZE);
388                 brk = r[0] + ROUNDUP(r[1], PAGE_SIZE);
389
390                 /* update brk, if within range */
391                 if ((brk >= task->start_brk) && (brk < task->end_brk)) {
392                         task->curr_brk = brk;
393                         return true;
394                 }
395                 r[0] = -ENOMEM;
396                 return true;
397         }
398         if (r[7] == 0xc5) {     /* fstat */
399                 r[0] = -ENOENT;
400                 return true;
401         }
402         if (r[7] == 0xdc) {     /* madvise */
403                 r[0] = 0;
404                 return true;
405         }
406         if (r[7] == 0xe0) {     /* gettid */
407                 r[0] = (u_int)current_thread;
408                 return true;
409         }
410         if (r[7] == 0x14) {     /* getpid */
411                 r[0] = -ENOENT;
412                 return true;
413         }
414         if (r[7] == 0xc7) {     /* getuid */
415                 r[0] = -ENOENT;
416                 return true;
417         }
418         if (r[7] == 0xf8) {     /* exit_group */
419                 /* terminate thread (and all task threads) */
420                 /* thread_exit(r[0]); */
421
422                 /* for now, just suspend the thread */
423                 thread_suspend();
424                 return true;
425         }
426         if (r[7] == 0x107) {    /* sys_clock_gettime */
427                 r[0] = -EFAULT;
428                 return true;
429         }
430         if (r[7] == 0x119){     /* socket */
431                 r[0] = -ENOENT;
432                 return true;
433         }
434         if (r[7] == 0xF0005) {  /* set_tls */
435                 current_thread->arch.tp_value = r[0];
436                 arch_set_tls(r[0]);
437
438                 r[0] = 0x0;
439                 return true;
440         }
441         if (r[7] == 0x36) {     /* ioctl */
442                 r[0] = platform_ioctl_handler(r[1], (void *)r[2]);
443
444                 return true;
445         }
446
447         dprintf(CRITICAL, "%s: unhandled syscall: 0x%x\n", __func__, r[7]);
448
449         return true;
450 }