tlk: 6/19 update
[3rdparty/ote_partner/tlk.git] / platform / tegra / common / platform.c
1 /*
2  * Copyright (c) 2012-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
24 #include <assert.h>
25 #include <errno.h>
26 #include <err.h>
27 #include <debug.h>
28 #include <rand.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <lib/heap.h>
32 #include <arch/arm/mmu.h>
33 #include <arch/ops.h>
34 #include <arch/arm.h>
35 #include <platform.h>
36 #include <platform/memmap.h>
37 #include <platform/irqs.h>
38 #include <kernel/task.h>
39 #include <target/debugconfig.h>
40 #include <lib/monitor/monitor_vector.h>
41 #if ARM_WITH_OUTER_CACHE
42 #include <arch/outercache.h>
43 #endif
44 #include <platform/platform_p.h>
45
46 #define MB              (1024 * 1024)
47
48 extern unsigned long boot_secondary_cpu_addr;
49 extern unsigned int coldboot_normal_os;
50 extern unsigned int normal_os_coldboot_fn;
51 extern uint32_t device_uid[4];
52
53 #if !defined(WITH_MONITOR_BIN)
54 extern uint32_t __save_boot_regs[9];
55 extern uint32_t __save_boot_cpsr;
56 extern uint32_t __jumpback_addr;
57 #endif
58
59 uint32_t debug_uart_id = DEFAULT_DEBUG_PORT;
60
61 static te_ss_op_t *ss_op_shmem;
62 static te_ss_op_t *ns_ss_op_shmem;
63
64 /* track available kernel VA space */
65 vaddr_t platform_vaspace_ptr;
66 vaddr_t platform_vaspace_end;
67
68 extern unsigned long cbstruct_addr;
69 extern unsigned long cbuf_addr;
70
71 static addr_t user_vector_page;
72
73 void platform_early_init(void)
74 {
75         platform_init_debug_port(debug_uart_id);
76 }
77
78 void platform_idle(void)
79 {
80         struct tz_monitor_frame frame, *smc_frame;
81 #if ARM_CPU_CORTEX_A9
82         uint32_t val;
83 #endif
84
85 #if !defined(WITH_MONITOR_BIN)
86         /* mark the entire TLK carveout as secure in the MC */
87         platform_secure_dram_aperture();
88 #endif
89
90 #if !defined(WITH_MONITOR_BIN)
91         memset(&frame, 0, sizeof(frame));
92
93         ASSERT(__jumpback_addr);
94         frame.pc = __jumpback_addr;
95         frame.spsr = __save_boot_cpsr;  /* interrupts disabled, in svc */
96         memcpy(&frame.r[4], __save_boot_regs, sizeof(__save_boot_regs));
97 #endif
98
99 #if ARM_CPU_CORTEX_A9
100         /*
101          * Before going to the NS world for the first time, set ACTLR.FW.
102          * The NSACR.NS_SMP setting granted it the capability to set ACTLR.SMP,
103          * but it doesn't cover NS writing ACTLR.FW.
104          */
105         val = arm_read_actlr();
106         val |= 0x1;
107         arm_write_actlr(val);
108 #endif
109
110         dputs(CRITICAL, "TLK initialization complete. Jumping to non-secure world\n");
111
112         smc_frame = tz_switch_to_ns(SMC_TOS_INITIAL_NS_RETURN, &frame);
113         while (smc_frame) {
114                 tz_stdcall_handler(smc_frame);
115                 smc_frame = tz_switch_to_ns(SMC_TOS_COMPLETION, smc_frame);
116         }
117 }
118
119 void platform_init(void)
120 {
121         task_map_t mptr;
122         arm_phys_attrs_t attrs;
123         uint32_t reg = 0;
124
125         platform_init_cpu();
126
127         /* map read-only user vector page in kernel */
128         arm_mmu_desc_set_default_kernel(&attrs);
129
130         mptr.map_attrs = &attrs;
131         mptr.size = PAGE_SIZE;
132         mptr.flags = TM_UR;
133
134         arm_mmu_map_kpage(0xFFFF0000, virtual_to_physical(user_vector_page), &mptr);
135         arm_invalidate_tlb();
136
137         memset((void *)user_vector_page, 0, mptr.size);
138
139         /* load user vectors (used by libc to get tls) */
140         memcpy((char *)user_vector_page + 0xFE0, arm_get_tls, 0x8);
141         memcpy((char *)user_vector_page + 0xFE8, arm_get_tls, 0x8);
142
143         platform_clean_invalidate_cache_range(user_vector_page, mptr.size);
144
145         platform_setup_keys();
146
147         /*
148          * Set SE_TZRAM_SECURITY sticky bit to respect secure TZRAM accesses.
149          * Note: No need to reprogram it after LP0 exit as it's part of SE's
150          * sticky bits HW LP0 context, so will be restored by the BR.
151          */
152         reg = *(volatile uint32_t *)(TEGRA_SE_BASE + 0x4);
153         reg &= ~(0x1);
154         *(volatile uint32_t *)(TEGRA_SE_BASE + 0x4) = reg;
155 }
156
157 void platform_init_mmu_mappings(void)
158 {
159         extern int _heap_end;
160         extern uint32_t __load_phys_size, __early_heap_allocs;
161
162         /*
163          * End of the kernel's heap is the carveout size, reduced by
164          * any early allocations (e.g. pages used for pagetables).
165          */
166         _heap_end = (VMEMBASE + __load_phys_size) - __early_heap_allocs;
167         _heap_end &= ~PAGE_MASK;
168
169         /* reserve user vector page (before heap is initialized) */
170         _heap_end -= PAGE_SIZE;
171         user_vector_page = _heap_end;
172
173         /* setup available vaspace (starts at end of carveout memory) */
174         platform_vaspace_ptr = VMEMBASE + __load_phys_size;
175         platform_vaspace_end = platform_vaspace_ptr + (VMEMSIZE - __load_phys_size);
176 }
177
178 uint64_t platform_translate_nsaddr(nsaddr_t vaddr, uint32_t type)
179 {
180 #if defined(WITH_MONITOR_BIN)
181         struct tz_monitor_frame frame;
182         frame.r[0] = vaddr;
183         frame.r[1] = type;
184         monitor_send_receive(SMC_TOS_ADDR_TRANSLATE, &frame);
185         return frame.r[0];
186 #else
187         arm_write_v2p(vaddr, type);
188         return arm_read_par();
189 #endif
190 }
191
192 uint32_t platform_get_rand32(void)
193 {
194         return rand();
195 }
196
197 uint32_t platform_get_time_us(void)
198 {
199         return *(volatile uint32_t *)(TEGRA_TMRUS_BASE);
200 }
201
202 status_t platform_ss_register_handler(struct tz_monitor_frame *frame)
203 {
204         /* r[1] -> address of shared fs operation buffer */
205         ns_ss_op_shmem = (te_ss_op_t *)(uintptr_t)frame->r[1];
206
207         ss_op_shmem = (te_ss_op_t *)tz_map_shared_mem((nsaddr_t)frame->r[1],
208                                                 sizeof(*ss_op_shmem));
209         if (!ss_op_shmem)
210                 return ERR_GENERIC;
211
212         return NO_ERROR;
213 }
214
215 /*
216  * Calculate the physical address of the shared buffer that we have got for
217  * logging from the linux kernel. All references to the shared buffer from
218  * within tlk are made directly to the physical address.
219  */
220 status_t set_log_phy_addr(nsaddr_t _ns_cb_struct_addr)
221 {
222         struct circular_buffer *cbstruct;
223         nsaddr_t cbuf;
224
225         cbstruct = (struct circular_buffer *)
226                         tz_map_shared_mem(_ns_cb_struct_addr, PAGE_SIZE);
227         if (cbstruct == NULL) {
228                 dprintf(CRITICAL, "%s: failed to map cbstruct\n", __func__);
229                 return ERR_NO_MEMORY;
230         }
231
232         cbuf = tz_map_shared_mem(cbstruct->buf, cbstruct->size);
233         if (cbuf == NULL) {
234                 dprintf(CRITICAL, "%s: failed to map cbuf\n", __func__);
235                 return ERR_NO_MEMORY;
236         }
237
238         cbstruct_addr = (unsigned long)cbstruct;
239         cbuf_addr = (unsigned long)cbuf;
240
241         return NO_ERROR;
242 }
243
244 static int validate_rpmb_frame_arg(te_storage_param_t *arg)
245 {
246         /* validate frame length */
247         if (arg->mem.len != RPMB_FRAME_SIZE)
248                 return -EINVAL;
249
250         /* validate frame memory range */
251         if (!task_valid_address((vaddr_t)arg->mem.base, arg->mem.len))
252                 return -EFAULT;
253
254         return 0;
255 }
256
257 int platform_ss_request_handler(te_storage_request_t *req)
258 {
259         struct tz_monitor_frame frame, *smc_frame;
260         int result;
261
262         ss_op_shmem->type = req->type;
263         ss_op_shmem->result = 0;
264
265         dprintf(INFO, "%s: type 0x%x\n", __func__, req->type);
266
267         switch (ss_op_shmem->type) {
268         case OTE_FILE_REQ_TYPE_CREATE:
269                 /* input args: dirname, filename, flags */
270                 strncpy(ss_op_shmem->params.f_create.dname,
271                         req->args[0].mem.base,
272                         sizeof(ss_op_shmem->params.f_create.dname));
273                 strncpy(ss_op_shmem->params.f_create.fname,
274                         req->args[1].mem.base,
275                         sizeof(ss_op_shmem->params.f_create.fname));
276                 ss_op_shmem->params.f_create.flags = req->args[2].val.a;
277
278                 ss_op_shmem->params_size =
279                         sizeof(ss_op_shmem->params.f_create);
280                 break;
281         case OTE_FILE_REQ_TYPE_DELETE:
282                 /* input args: dirname, filename */
283                 strncpy((char *)ss_op_shmem->params.f_delete.dname,
284                         req->args[0].mem.base,
285                         sizeof(ss_op_shmem->params.f_delete.dname));
286                 strncpy((char *)ss_op_shmem->params.f_delete.fname,
287                         req->args[1].mem.base,
288                         sizeof(ss_op_shmem->params.f_delete.fname));
289
290                 ss_op_shmem->params_size =
291                         sizeof(ss_op_shmem->params.f_delete);
292                 break;
293         case OTE_FILE_REQ_TYPE_OPEN:
294                 /* input args: dirname, filename, flags */
295                 strncpy((char *)ss_op_shmem->params.f_open.dname,
296                         req->args[0].mem.base,
297                         sizeof(ss_op_shmem->params.f_open.dname));
298                 strncpy((char *)ss_op_shmem->params.f_open.fname,
299                         req->args[1].mem.base,
300                         sizeof(ss_op_shmem->params.f_open.fname));
301                 ss_op_shmem->params.f_open.flags = req->args[2].val.a;
302
303                 ss_op_shmem->params_size = sizeof(ss_op_shmem->params.f_open);
304                 break;
305         case OTE_FILE_REQ_TYPE_CLOSE:
306                 /* input args: file handle */
307                 ss_op_shmem->params.f_close.handle = req->args[0].val.a;
308
309                 ss_op_shmem->params_size = sizeof(ss_op_shmem->params.f_close);
310                 break;
311         case OTE_FILE_REQ_TYPE_READ:
312                 /* validate read buffer */
313                 if (!task_valid_address((vaddr_t)req->args[1].mem.base,
314                                         req->args[1].mem.len)) {
315                         return -EFAULT;
316                 }
317
318                 /* validate read buffer size */
319                 if (req->args[1].mem.len >
320                         sizeof(ss_op_shmem->params.f_read.data)) {
321                         return -EINVAL;
322                 }
323
324                 /* input args: file_handle, read buffer */
325                 ss_op_shmem->params.f_close.handle = req->args[0].val.a;
326                 ss_op_shmem->params.f_read.data_size = req->args[1].mem.len;
327
328                 ss_op_shmem->params_size = sizeof(ss_op_shmem->params.f_read);
329                 break;
330         case OTE_FILE_REQ_TYPE_WRITE:
331                 /* validate write buffer */
332                 if (!task_valid_address((vaddr_t)req->args[1].mem.base,
333                                         req->args[1].mem.len)) {
334                         return -EFAULT;
335                 }
336
337                 /* validate write buffer size */
338                 if (req->args[1].mem.len >
339                         sizeof(ss_op_shmem->params.f_write.data)) {
340                         return -EINVAL;
341                 }
342
343                 /* input args: file_handle, write buffer */
344                 ss_op_shmem->params.f_write.handle = req->args[0].val.a;
345                 ss_op_shmem->params.f_write.data_size = req->args[1].mem.len;
346                 memcpy((void*)ss_op_shmem->params.f_write.data,
347                         req->args[1].mem.base,
348                         ss_op_shmem->params.f_write.data_size);
349
350                 ss_op_shmem->params_size = sizeof(ss_op_shmem->params.f_write);
351                 break;
352         case OTE_FILE_REQ_TYPE_GET_SIZE:
353                 /* input arg: file_handle */
354                 ss_op_shmem->params.f_getsize.handle = req->args[0].val.a;
355
356                 ss_op_shmem->params_size =
357                         sizeof(ss_op_shmem->params.f_getsize);
358                 break;
359         case OTE_FILE_REQ_TYPE_SEEK:
360                 /* input args: file_handle, offset, whence */
361                 ss_op_shmem->params.f_seek.handle = req->args[0].val.a;
362                 ss_op_shmem->params.f_seek.offset = req->args[1].val.a;
363                 ss_op_shmem->params.f_seek.whence = req->args[2].val.a;
364
365                 ss_op_shmem->params_size = sizeof(ss_op_shmem->params.f_seek);
366                 break;
367         case OTE_FILE_REQ_TYPE_TRUNC:
368                 /* input args: file_handle, length */
369                 ss_op_shmem->params.f_trunc.handle = req->args[0].val.a;
370                 ss_op_shmem->params.f_trunc.length = req->args[1].val.a;
371
372                 ss_op_shmem->params_size = sizeof(ss_op_shmem->params.f_trunc);
373                 break;
374         case OTE_FILE_REQ_TYPE_RPMB_WRITE:
375                 /* validate request frame */
376                 result = validate_rpmb_frame_arg(&req->args[0]);
377                 if (result) {
378                         dprintf(CRITICAL, "%s: write req frame invalid\n",
379                                 __func__);
380                         return result;
381                 }
382
383                 /* validate request-response frame */
384                 result = validate_rpmb_frame_arg(&req->args[1]);
385                 if (result) {
386                         dprintf(CRITICAL, "%s: write req-resp frame invalid\n",
387                                 __func__);
388                         return result;
389                 }
390
391                 /* validate response frame */
392                 result = validate_rpmb_frame_arg(&req->args[2]);
393                 if (result) {
394                         dprintf(CRITICAL, "%s: write resp frame invalid\n",
395                                 __func__);
396                         return result;
397                 }
398
399                 /* input args: request frame, request-response frame */
400                 memcpy((void*)ss_op_shmem->params.f_rpmb_write.req_frame,
401                         req->args[0].mem.base, req->args[0].mem.len);
402                 memcpy((void*)ss_op_shmem->params.f_rpmb_write.req_resp_frame,
403                         req->args[1].mem.base, req->args[1].mem.len);
404
405                 ss_op_shmem->params_size =
406                         sizeof(ss_op_shmem->params.f_rpmb_write);
407                 break;
408         case OTE_FILE_REQ_TYPE_RPMB_READ:
409                 /* validate request frame */
410                 result = validate_rpmb_frame_arg(&req->args[0]);
411                 if (result) {
412                         dprintf(CRITICAL, "%s: read req frame invalid\n",
413                                 __func__);
414                         return result;
415                 }
416
417                 /* validate response frame */
418                 result = validate_rpmb_frame_arg(&req->args[1]);
419                 if (result) {
420                         dprintf(CRITICAL, "%s: read resp frame invalid\n",
421                                 __func__);
422                         return result;
423                 }
424
425                 /* input arg: request frame */
426                 memcpy((void*)ss_op_shmem->params.f_rpmb_read.req_frame,
427                         req->args[0].mem.base, req->args[0].mem.len);
428
429                 ss_op_shmem->params_size =
430                         sizeof(ss_op_shmem->params.f_rpmb_read);
431                 break;
432         default:
433                 return -EINVAL;
434         }
435
436         /* adjust size down to only include required parameters */
437         ss_op_shmem->req_size = (sizeof(te_ss_op_t) - sizeof(uint32_t) -
438                 sizeof(te_ss_req_params_t)) + ss_op_shmem->params_size;
439
440 #if defined(WITH_MONITOR_BIN)
441         memset(&frame, 0, sizeof(struct tz_monitor_frame));
442         frame.r[0] = SMC_ERR_PREEMPT_BY_FS;
443
444         smc_frame = tz_switch_to_ns(SMC_TOS_COMPLETION, &frame);
445         while (smc_frame->r[0] != SMC_TOS_RESTART) {
446                 frame.r[0] = SMC_ERR_PREEMPT_BY_IRQ;
447                 smc_frame = tz_switch_to_ns(SMC_TOS_COMPLETION, &frame);
448         }
449 #else
450         smc_frame = tz_switch_to_ns(SMC_TOS_PREEMPT_BY_FS, NULL);
451         while (smc_frame)
452                 smc_frame = tz_switch_to_ns(SMC_TOS_PREEMPT_BY_IRQ, NULL);
453 #endif
454
455         req->result = ss_op_shmem->result;
456         if (req->result != 0) {
457                 dprintf(CRITICAL, "%s: call to non-secure world failed 0x%x\n",
458                         __func__, req->result);
459                 return req->result;
460         }
461
462         /* move any expected return data into request structure */
463         switch (ss_op_shmem->type) {
464         case OTE_FILE_REQ_TYPE_OPEN:
465                 /* output arg: file_handle */
466                 req->args[3].val.a = ss_op_shmem->params.f_open.handle;
467                 break;
468         case OTE_FILE_REQ_TYPE_READ:
469                 /* output args: amount of data read, data */
470                 req->args[1].mem.len = ss_op_shmem->params.f_read.data_size;
471                 memcpy(req->args[1].mem.base,
472                         (void *)ss_op_shmem->params.f_read.data,
473                         req->args[1].mem.len);
474                 break;
475         case OTE_FILE_REQ_TYPE_GET_SIZE:
476                 /* output arg: file size */
477                 req->args[1].val.a = ss_op_shmem->params.f_getsize.size;
478                 break;
479         case OTE_FILE_REQ_TYPE_RPMB_WRITE:
480                 /* output arg: response frame */
481                 memcpy(req->args[2].mem.base,
482                         (void *)ss_op_shmem->params.f_rpmb_write.resp_frame,
483                         req->args[2].mem.len);
484                 break;
485         case OTE_FILE_REQ_TYPE_RPMB_READ:
486                 /* output arg: response frame */
487                 memcpy(req->args[1].mem.base,
488                         (void *)ss_op_shmem->params.f_rpmb_read.resp_frame,
489                         req->args[1].mem.len);
490                 break;
491         default:
492                 break;
493         }
494
495         return 0;
496 }
497
498 void platform_get_device_id(te_device_id_args_t *out)
499 {
500         if (out)
501                 memcpy(out, device_uid, sizeof(te_device_id_args_t));
502 }
503
504 void platform_clean_invalidate_cache_range(vaddr_t range, uint32_t length)
505 {
506 #if defined(ARM_USE_CPU_CACHING)
507         arch_clean_invalidate_cache_range(range, length);
508
509 #if ARM_WITH_OUTER_CACHE
510         outer_clean_range(virtual_to_physical(range), length);
511         outer_inv_range(virtual_to_physical(range), length);
512 #endif
513 #endif
514 }