First version
[3rdparty/ote_partner/tlk.git] / arch / arm / arm / faults.c
1 /*
2  * Copyright (c) 2008 Travis Geiselbrecht
3  * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files
7  * (the "Software"), to deal in the Software without restriction,
8  * including without limitation the rights to use, copy, modify, merge,
9  * publish, distribute, sublicense, and/or sell copies of the Software,
10  * and to permit persons to whom the Software is furnished to do so,
11  * subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include <debug.h>
25 #include <platform.h>
26 #include <assert.h>
27 #include <arch.h>
28 #include <arch/arm.h>
29
30 #define MAX_FRAME_STRING_CHARS          64
31
32 static void dump_fault_frame(struct arm_fault_frame *frame)
33 {
34         char str[MAX_FRAME_STRING_CHARS];
35
36         sprintf(str, "r0  0x%08x r1  0x%08x r2  0x%08x r3  0x%08x\n", frame->r[0], frame->r[1], frame->r[2], frame->r[3]);
37         dputs(CRITICAL, str);
38         sprintf(str, "r4  0x%08x r5  0x%08x r6  0x%08x r7  0x%08x\n", frame->r[4], frame->r[5], frame->r[6], frame->r[7]);
39         dputs(CRITICAL, str);
40         sprintf(str, "r8  0x%08x r9  0x%08x r10 0x%08x r11 0x%08x\n", frame->r[8], frame->r[9], frame->r[10], frame->r[11]);
41         dputs(CRITICAL, str);
42         sprintf(str, "r12 0x%08x usp 0x%08x ulr 0x%08x pc  0x%08x\n", frame->r[12], frame->usp, frame->ulr, frame->pc);
43         dputs(CRITICAL, str);
44         sprintf(str, "spsr 0x%08x\n", frame->spsr);
45         dputs(CRITICAL, str);
46
47         struct arm_mode_regs regs;
48         arm_save_mode_regs(&regs);
49
50         sprintf(str, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_FIQ) ? '*' : ' ', "fiq", regs.fiq_r13, regs.fiq_r14);
51         dputs(CRITICAL, str);
52         sprintf(str, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_IRQ) ? '*' : ' ', "irq", regs.irq_r13, regs.irq_r14);
53         dputs(CRITICAL, str);
54         sprintf(str, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_SVC) ? '*' : ' ', "svc", regs.svc_r13, regs.svc_r14);
55         dputs(CRITICAL, str);
56         sprintf(str, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_UND) ? '*' : ' ', "und", regs.und_r13, regs.und_r14);
57         dputs(CRITICAL, str);
58         sprintf(str, "%c%s r13 0x%08x r14 0x%08x\n", ((frame->spsr & MODE_MASK) == MODE_SYS) ? '*' : ' ', "sys", regs.sys_r13, regs.sys_r14);
59         dputs(CRITICAL, str);
60
61         // dump the bottom of the current stack
62         addr_t stack;
63         switch (frame->spsr & MODE_MASK) {
64                 case MODE_FIQ: stack = regs.fiq_r13; break;
65                 case MODE_IRQ: stack = regs.irq_r13; break;
66                 case MODE_SVC: stack = regs.svc_r13; break;
67                 case MODE_UND: stack = regs.und_r13; break;
68                 case MODE_SYS: stack = regs.sys_r13; break;
69                 default:
70                         stack = 0;
71         }
72
73         if (stack != 0) {
74                 sprintf(str, "bottom of stack at 0x%08x:\n", (unsigned int)stack);
75                 dputs(CRITICAL, str);
76                 hexdump((void *)stack, 128);
77         }
78 }
79
80 static void exception_die(struct arm_fault_frame *frame, int pc_off, const char *msg)
81 {
82         inc_critical_section();
83         frame->pc += pc_off;
84         dputs(CRITICAL, msg);
85         dump_fault_frame(frame);
86
87         halt();
88         for(;;);
89 }
90
91 void arm_syscall_handler(struct arm_fault_frame *frame)
92 {
93         ASSERT(in_critical_section() == false);
94
95         /* should intrs be reenabled (svc exception disabled) */
96         if (platform_intr_ready())
97                 arch_enable_ints();
98
99         if (platform_syscall_handler((void *)frame->r))
100                 return;
101
102         exception_die(frame, -4, "unhandled syscall, halting\n");
103 }
104
105 /* Pointers to secure/normal world VFP contexts */
106 fpctx_t *s_vfp_hw_context = NULL;
107 fpctx_t *ns_vfp_hw_context = NULL;
108
109 void arm_undefined_handler(struct arm_fault_frame *frame)
110 {
111 #if ARM_WITH_NEON
112         if (arm_get_vfp_fpexc() & 0x40000000)
113                 goto fail;      /* already enabled? */
114
115         /*
116          * This vfp ctxsw exception should've been triggered by a user mode
117          * access. The current user mode thread should have a non-NULL fpctx
118          * setup during its task init. There also should be a single normal
119          * world vfp context buffer allocated to save/restore that context.
120          */
121         ASSERT((frame->spsr & MODE_MASK) == MODE_USR);
122         ASSERT(current_thread->arch.fpctx);
123         ASSERT(ns_vfp_hw_context);
124
125         /*
126          * First vfp context switch saves to NS world state. Any exceptions
127          * that follow are tasks context switching against each other where
128          * an outgoing context will need to be faulted back in.
129          */
130         if (ns_vfp_hw_context->valid == false) {
131                 /* save NS world state */
132                 arch_vfp_save(ns_vfp_hw_context);
133                 ns_vfp_hw_context->valid = true;
134
135                 s_vfp_hw_context = current_thread->arch.fpctx;
136
137                 /* restore S world state */
138                 arch_vfp_restore(s_vfp_hw_context);
139                 s_vfp_hw_context->fpexc = 0x40000000;
140                 s_vfp_hw_context->valid = true;
141         } else {
142                 ASSERT(s_vfp_hw_context);
143
144                 /* save previous S world state (faults when run again) */
145                 arch_vfp_save(s_vfp_hw_context);
146                 s_vfp_hw_context->fpexc = 0x0;
147
148                 s_vfp_hw_context = current_thread->arch.fpctx;
149
150                 /* restore next S world state */
151                 arch_vfp_restore(s_vfp_hw_context);
152                 s_vfp_hw_context->fpexc = 0x40000000;
153                 s_vfp_hw_context->valid = true;
154         }
155
156         /* retry instruction */
157         if (frame->spsr & EXC_THUMB)
158                 frame->pc -= 2;         // thumb
159         else
160                 frame->pc -= 4;         // arm
161         return;
162 #endif
163
164 fail:
165         /* unexpected exception */
166         exception_die(frame, -4, "undefined abort, halting\n");
167 }
168
169 void arm_data_abort_handler(struct arm_fault_frame *frame)
170 {
171         exception_die(frame, -8, "data abort, halting\n");
172 }
173
174 void arm_prefetch_abort_handler(struct arm_fault_frame *frame)
175 {
176         exception_die(frame, -4, "prefetch abort, halting\n");
177 }