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