[FOSS_TLK]platform: tegra: use arfuse registers
[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 #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                         mptr = task_find_mapping_by_id(taskp, args->id);
137                         if (mptr == NULL) {
138                                 return -EINVAL;
139                         }
140
141                         args->addr = (void *)((uint32_t)mptr->vaddr + mptr->offset);
142
143                         break;
144                 }
145                 case OTE_IOCTL_V_TO_P:
146                 {
147                         te_v_to_p_args_t *args = cmdbuf;
148                         paddr_t paddr;
149                         status_t retval;
150
151                         /* validate command buffer */
152                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
153                                 return -EFAULT;
154                         }
155
156                         retval = task_get_physaddr(taskp, (vaddr_t)args->vaddr, &paddr);
157                         if (retval != NO_ERROR)
158                                 return -EINVAL;
159
160                         args->paddr = paddr;
161                         break;
162                 }
163                 case OTE_IOCTL_CACHE_MAINT:
164                 {
165                         te_cache_maint_args_t *args = cmdbuf;
166 #if ARM_WITH_OUTER_CACHE
167                         vaddr_t vaddr;
168                         uint32_t nbytes;
169 #endif
170                         /* validate command buffer */
171                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
172                                 return -EFAULT;
173                         }
174
175                         /* operate on L1 (virtual addrs) */
176                         switch (args->op) {
177                         case OTE_EXT_NV_CM_OP_CLEAN:
178                                 arch_clean_cache_range((addr_t)args->vaddr, args->length);
179                                 break;
180                         case OTE_EXT_NV_CM_OP_INVALIDATE:
181                                 arch_invalidate_cache_range((addr_t)args->vaddr, args->length);
182                                 break;
183                         case OTE_EXT_NV_CM_OP_FLUSH:
184                                 arch_clean_invalidate_cache_range((addr_t)args->vaddr, args->length);
185                                 break;
186                         default:
187                                 return -EINVAL;
188                         }
189 #if ARM_WITH_OUTER_CACHE
190                         /* operate on L2 (physical addrs) */
191                         nbytes = args->length;
192                         vaddr = (vaddr_t)args->vaddr;
193
194                         while (nbytes) {
195                                 uint32_t len;
196                                 paddr_t paddr;
197                                 status_t retval;
198
199                                 retval = task_get_physaddr(taskp, vaddr, &paddr);
200                                 if (retval != NO_ERROR)
201                                         return -EFAULT;
202
203                                 /* careful in crossing page boundaries */
204                                 len = PAGE_SIZE - (paddr & PAGE_MASK);
205                                 len = MIN(nbytes, len);
206
207                                 switch (args->op) {
208                                 case OTE_EXT_NV_CM_OP_CLEAN:
209                                         outer_clean_range(paddr, len);
210                                         break;
211                                 case OTE_EXT_NV_CM_OP_INVALIDATE:
212                                         outer_inv_range(paddr, len);
213                                         break;
214                                 case OTE_EXT_NV_CM_OP_FLUSH:
215                                         outer_flush_range(paddr, len);
216                                         break;
217                                 }
218                                 vaddr  += len;
219                                 nbytes -= len;
220                         }
221 #endif
222                         break;
223                 }
224                 case OTE_IOCTL_TA_TO_TA_REQUEST:
225                 {
226                         te_ta_to_ta_request_args_t *args = cmdbuf;
227
228                         return platform_ta_to_ta_request_handler(args);
229                 }
230                 case OTE_IOCTL_GET_PROPERTY:
231                 {
232                         te_get_property_args_t *args = cmdbuf;
233
234                         return platform_get_property_handler(args);
235                 }
236                 case OTE_IOCTL_SS_REQUEST:
237                 {
238                         return platform_ss_request_handler();
239                 }
240                 case OTE_IOCTL_SS_GET_CONFIG:
241                 {
242                         uint32_t *ss_config = cmdbuf;
243
244                         /* validate command buffer */
245                         if (!task_valid_address((vaddr_t)ss_config,
246                                                         sizeof(uint32_t)))
247                                 return -EFAULT;
248
249                         return platform_ss_get_config(ss_config);
250                         break;
251                 }
252                 case OTE_IOCTL_GET_DEVICE_ID:
253                 {
254                         te_device_id_args_t *args = cmdbuf;
255
256                         /* validate command buffer */
257                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
258                                 return -EFAULT;
259                         }
260
261                         platform_get_device_id(args);
262                         break;
263                 }
264                 case OTE_IOCTL_GET_TIME_US:
265                 {
266                         uint32_t *args = cmdbuf;
267
268                         /* validate command buffer */
269                         if (!task_valid_address((vaddr_t)cmdbuf,
270                                                         sizeof(uint32_t)))
271                                 return -EFAULT;
272
273                         *args = platform_get_time_us();
274                         break;
275                 }
276                 case OTE_IOCTL_GET_RAND32:
277                 {
278                         uint32_t *args = cmdbuf;
279
280                         /* validate command buffer */
281                         if (!task_valid_address((vaddr_t)cmdbuf,
282                                                         sizeof(uint32_t)))
283                                 return -EFAULT;
284
285                         *args = platform_get_rand32();
286                         break;
287                 }
288                 case OTE_IOCTL_TASK_REQUEST:
289                 {
290                         te_task_request_args_t *args = cmdbuf;
291
292                         if (!task_valid_address((vaddr_t)args, sizeof(*args))) {
293                                 return -EFAULT;
294                         }
295
296                         return task_request_handler (args);
297                 }
298                 default:
299                 {
300                         dprintf(SPEW, "%s: invalid ioctl: cmd=0x%x\n",
301                                 __func__, cmd);
302                         return -EINVAL;
303                 }
304         }
305
306         return 0;
307 }
308
309 bool platform_syscall_handler(void *arg)
310 {
311         task_t *task = current_thread->arch.task;
312         uint32_t *r = arg;
313
314         if (r[12] == __NR_read) {       /* read */
315                 /* only expect reads of the TA pipe fd */
316                 r[0] = te_handle_ta_message(r[0],
317                                              (void *)(r[1]),
318                                              r[2],
319                                              true);
320                 return true;
321         }
322         if (r[12] == __NR_write) {      /* write */
323                 /* check buffer is in task's address space */
324                 if (task_valid_address(r[1], r[2]) == false) {
325                         r[0] = -EFAULT;
326                         return true;
327                 }
328                 if ((r[0] == 1) || (r[0] == 2)) {
329                         u_int i;
330                         /* handle stdout/stderr */
331                         for (i = 0; i < r[2]; i++) {
332                                 dprintf(CRITICAL, "%c", ((char *)r[1])[i]);
333                         }
334                         r[0] = r[2];
335                 } else {
336                         /* handle writes of one of the TA pipe fd's */
337                         r[0] = te_handle_ta_message(r[0],
338                                                      (void *)(r[1]),
339                                                      r[2],
340                                                      false);
341                 }
342                 return true;
343         }
344         if (r[12] == __NR_brk) {        /* brk */
345                 u_int brk = r[0];
346
347                 /* update brk, if within range */
348                 if ((brk >= task->start_brk) && (brk < task->end_brk)) {
349                         task->curr_brk = brk;
350                 } else {
351                         if (brk >= task->end_brk) {
352                                 dprintf(CRITICAL,
353                                         "%s: task %d: "
354                                         "no more heap (size 0x%lx bytes)\n",
355                                         __func__, task->task_index,
356                                         task->end_brk - task->start_brk);
357                         } else if ((brk < task->start_brk) && (brk != 0)) {
358                                 dprintf(CRITICAL,
359                                         "%s: task %d: "
360                                         "brk 0x%x < heap start 0x%lx\n",
361                                         __func__, task->task_index,
362                                         brk, task->start_brk);
363                         }
364                 }
365
366                 r[0] = task->curr_brk;
367                 return true;
368         }
369         if (r[12] == __NR_usleep) {     /* usleep */
370                 struct timespec *ts;
371
372                 /* check buffer is in task's address space */
373                 if (task_valid_address(r[0], sizeof(struct timespec)) == false) {
374                         r[0] = -EFAULT;
375                         return true;
376                 }
377
378                 ts = (struct timespec *)r[0];
379                 if (ts->tv_sec) {
380                         dprintf(SPEW, "ignoring seconds arg to usleep\n");
381                         ts->tv_sec = 0;
382                 }
383
384                 spin(ts->tv_nsec / 1000);
385
386                 r[0] = 0;
387                 return true;
388         }
389         if (r[12] == __NR_gettid) {     /* gettid */
390                 r[0] = (u_int)current_thread;
391                 return true;
392         }
393         if (r[12] == __NR_exit_group) { /* exit_group */
394                 /* terminate thread (and all task threads) */
395                 /* thread_exit(r[0]); */
396
397                 /* for now, just suspend the thread */
398                 thread_suspend();
399                 return true;
400         }
401         if (r[12] == __NR_ioctl) {      /* ioctl */
402                 r[0] = platform_ioctl_handler(r[1], (void *)r[2]);
403
404                 return true;
405         }
406
407         dprintf(CRITICAL, "%s: unhandled syscall: 0x%x\n", __func__, r[12]);
408
409         return true;
410 }