1 /*
2 * processor control and status functions
3 *
4 * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
5 *
6 * This work is licensed under the terms of the GNU LGPL, version 2.
7 */
8 #include <libcflat.h>
9 #include <asm/ptrace.h>
10 #include <asm/processor.h>
11 #include <asm/thread_info.h>
12
13 static const char *vector_names[] = {
14 "el1t_sync",
15 "el1t_irq",
16 "el1t_fiq",
17 "el1t_error",
18 "el1h_sync",
19 "el1h_irq",
20 "el1h_fiq",
21 "el1h_error",
22 "el0_sync_64",
23 "el0_irq_64",
24 "el0_fiq_64",
25 "el0_error_64",
26 "el0_sync_32",
27 "el0_irq_32",
28 "el0_fiq_32",
29 "el0_error_32",
30 };
31
32 static const char *ec_names[EC_MAX] = {
33 [ESR_EL1_EC_UNKNOWN] = "UNKNOWN",
34 [ESR_EL1_EC_WFI] = "WFI",
35 [ESR_EL1_EC_CP15_32] = "CP15_32",
36 [ESR_EL1_EC_CP15_64] = "CP15_64",
37 [ESR_EL1_EC_CP14_MR] = "CP14_MR",
38 [ESR_EL1_EC_CP14_LS] = "CP14_LS",
39 [ESR_EL1_EC_FP_ASIMD] = "FP_ASMID",
40 [ESR_EL1_EC_CP10_ID] = "CP10_ID",
41 [ESR_EL1_EC_CP14_64] = "CP14_64",
42 [ESR_EL1_EC_ILL_ISS] = "ILL_ISS",
43 [ESR_EL1_EC_SVC32] = "SVC32",
44 [ESR_EL1_EC_SVC64] = "SVC64",
45 [ESR_EL1_EC_SYS64] = "SYS64",
46 [ESR_EL1_EC_SVE] = "SVE",
47 [ESR_EL1_EC_IABT_EL0] = "IABT_EL0",
48 [ESR_EL1_EC_IABT_EL1] = "IABT_EL1",
49 [ESR_EL1_EC_PC_ALIGN] = "PC_ALIGN",
50 [ESR_EL1_EC_DABT_EL0] = "DABT_EL0",
51 [ESR_EL1_EC_DABT_EL1] = "DABT_EL1",
52 [ESR_EL1_EC_SP_ALIGN] = "SP_ALIGN",
53 [ESR_EL1_EC_FP_EXC32] = "FP_EXC32",
54 [ESR_EL1_EC_FP_EXC64] = "FP_EXC64",
55 [ESR_EL1_EC_SERROR] = "SERROR",
56 [ESR_EL1_EC_BREAKPT_EL0] = "BREAKPT_EL0",
57 [ESR_EL1_EC_BREAKPT_EL1] = "BREAKPT_EL1",
58 [ESR_EL1_EC_SOFTSTP_EL0] = "SOFTSTP_EL0",
59 [ESR_EL1_EC_SOFTSTP_EL1] = "SOFTSTP_EL1",
60 [ESR_EL1_EC_WATCHPT_EL0] = "WATCHPT_EL0",
61 [ESR_EL1_EC_WATCHPT_EL1] = "WATCHPT_EL1",
62 [ESR_EL1_EC_BKPT32] = "BKPT32",
63 [ESR_EL1_EC_BRK64] = "BRK64",
64 };
65
show_regs(struct pt_regs * regs)66 void show_regs(struct pt_regs *regs)
67 {
68 int i;
69
70 printf("pc : [<%016lx>] lr : [<%016lx>] pstate: %08lx\n",
71 regs->pc, regs->regs[30], regs->pstate);
72 printf("sp : %016lx\n", regs->sp);
73
74 for (i = 29; i >= 0; --i) {
75 printf("x%-2d: %016lx ", i, regs->regs[i]);
76 if (i % 2 == 0)
77 printf("\n");
78 }
79 printf("\n");
80 }
81
get_far(unsigned int esr,unsigned long * far)82 bool get_far(unsigned int esr, unsigned long *far)
83 {
84 unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
85
86 asm volatile("mrs %0, far_el1": "=r" (*far));
87
88 switch (ec) {
89 case ESR_EL1_EC_IABT_EL0:
90 case ESR_EL1_EC_IABT_EL1:
91 case ESR_EL1_EC_PC_ALIGN:
92 case ESR_EL1_EC_DABT_EL0:
93 case ESR_EL1_EC_DABT_EL1:
94 case ESR_EL1_EC_WATCHPT_EL0:
95 case ESR_EL1_EC_WATCHPT_EL1:
96 if ((esr & 0x3f /* DFSC */) != 0x10
97 || !(esr & 0x400 /* FnV */))
98 return true;
99 }
100 return false;
101 }
102
103 extern unsigned long _text;
104
bad_exception(enum vector v,struct pt_regs * regs,unsigned int esr,bool esr_valid,bool bad_vector)105 static void bad_exception(enum vector v, struct pt_regs *regs,
106 unsigned int esr, bool esr_valid, bool bad_vector)
107 {
108 unsigned long far;
109 bool far_valid = get_far(esr, &far);
110 unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
111 uintptr_t text = (uintptr_t)&_text;
112
113 printf("Load address: %" PRIxPTR "\n", text);
114 printf("PC: %" PRIxPTR " PC offset: %" PRIxPTR "\n",
115 (uintptr_t)regs->pc, (uintptr_t)regs->pc - text);
116
117 if (bad_vector) {
118 if (v < VECTOR_MAX)
119 printf("Unhandled vector %d (%s)\n", v,
120 vector_names[v]);
121 else
122 printf("Got bad vector=%d\n", v);
123 } else if (esr_valid) {
124 if (ec_names[ec])
125 printf("Unhandled exception ec=%#x (%s)\n", ec,
126 ec_names[ec]);
127 else
128 printf("Got bad ec=%#x\n", ec);
129 }
130
131 printf("Vector: %d (%s)\n", v, vector_names[v]);
132 printf("ESR_EL1: %8s%08x, ec=%#x (%s)\n", "", esr, ec, ec_names[ec]);
133 printf("FAR_EL1: %016lx (%svalid)\n", far, far_valid ? "" : "not ");
134 printf("Exception frame registers:\n");
135 show_regs(regs);
136 dump_frame_stack((void *)regs->pc, (void *)regs->regs[29]);
137 abort();
138 }
139
install_exception_handler(enum vector v,unsigned int ec,exception_fn fn)140 void install_exception_handler(enum vector v, unsigned int ec, exception_fn fn)
141 {
142 struct thread_info *ti = current_thread_info();
143
144 if (v < VECTOR_MAX && ec < EC_MAX)
145 ti->exception_handlers[v][ec] = fn;
146 }
147
install_irq_handler(enum vector v,irq_handler_fn fn)148 void install_irq_handler(enum vector v, irq_handler_fn fn)
149 {
150 struct thread_info *ti = current_thread_info();
151
152 if (v < VECTOR_MAX)
153 ti->exception_handlers[v][0] = (exception_fn)fn;
154 }
155
default_vector_sync_handler(enum vector v,struct pt_regs * regs,unsigned int esr)156 void default_vector_sync_handler(enum vector v, struct pt_regs *regs,
157 unsigned int esr)
158 {
159 struct thread_info *ti = thread_info_sp(regs->sp);
160 unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
161
162 if (ti->flags & TIF_USER_MODE) {
163 if (ec < EC_MAX && ti->exception_handlers[v][ec]) {
164 ti->exception_handlers[v][ec](regs, esr);
165 return;
166 }
167 ti = current_thread_info();
168 }
169
170 if (ec < EC_MAX && ti->exception_handlers[v][ec])
171 ti->exception_handlers[v][ec](regs, esr);
172 else
173 bad_exception(v, regs, esr, true, false);
174 }
175
default_vector_irq_handler(enum vector v,struct pt_regs * regs,unsigned int esr)176 void default_vector_irq_handler(enum vector v, struct pt_regs *regs,
177 unsigned int esr)
178 {
179 struct thread_info *ti = thread_info_sp(regs->sp);
180 irq_handler_fn irq_handler =
181 (irq_handler_fn)ti->exception_handlers[v][0];
182
183 if (ti->flags & TIF_USER_MODE) {
184 if (irq_handler) {
185 irq_handler(regs);
186 return;
187 }
188 ti = current_thread_info();
189 irq_handler = (irq_handler_fn)ti->exception_handlers[v][0];
190 }
191
192 if (irq_handler)
193 irq_handler(regs);
194 else
195 bad_exception(v, regs, esr, false, false);
196 }
197
vector_handlers_default_init(vector_fn * handlers)198 void vector_handlers_default_init(vector_fn *handlers)
199 {
200 handlers[EL1H_SYNC] = default_vector_sync_handler;
201 handlers[EL1H_IRQ] = default_vector_irq_handler;
202 handlers[EL0_SYNC_64] = default_vector_sync_handler;
203 handlers[EL0_IRQ_64] = default_vector_irq_handler;
204 }
205
206 /* Needed to compile with -Wmissing-prototypes */
207 void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr);
208
do_handle_exception(enum vector v,struct pt_regs * regs,unsigned int esr)209 void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr)
210 {
211 struct thread_info *ti = thread_info_sp(regs->sp);
212
213 if (ti->flags & TIF_USER_MODE) {
214 if (v < VECTOR_MAX && ti->vector_handlers[v]) {
215 ti->vector_handlers[v](v, regs, esr);
216 return;
217 }
218 ti = current_thread_info();
219 }
220
221 if (v < VECTOR_MAX && ti->vector_handlers[v])
222 ti->vector_handlers[v](v, regs, esr);
223 else
224 bad_exception(v, regs, esr, true, true);
225 }
226
install_vector_handler(enum vector v,vector_fn fn)227 void install_vector_handler(enum vector v, vector_fn fn)
228 {
229 struct thread_info *ti = current_thread_info();
230
231 if (v < VECTOR_MAX)
232 ti->vector_handlers[v] = fn;
233 }
234
__thread_info_init(struct thread_info * ti,unsigned int flags)235 static void __thread_info_init(struct thread_info *ti, unsigned int flags)
236 {
237 memset(ti, 0, sizeof(struct thread_info));
238 ti->cpu = mpidr_to_cpu(get_mpidr());
239 ti->flags = flags;
240 }
241
thread_info_init(struct thread_info * ti,unsigned int flags)242 void thread_info_init(struct thread_info *ti, unsigned int flags)
243 {
244 __thread_info_init(ti, flags);
245 vector_handlers_default_init(ti->vector_handlers);
246 }
247
start_usr(void (* func)(void * arg),void * arg,unsigned long sp_usr)248 void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr)
249 {
250 sp_usr &= (~15UL); /* stack ptr needs 16-byte alignment */
251
252 __thread_info_init(thread_info_sp(sp_usr), TIF_USER_MODE);
253 thread_info_sp(sp_usr)->pgtable = current_thread_info()->pgtable;
254
255 asm volatile(
256 "mov x0, %0\n"
257 "msr sp_el0, %1\n"
258 "msr elr_el1, %2\n"
259 "mov x3, xzr\n" /* clear and "set" PSR_MODE_EL0t */
260 "msr spsr_el1, x3\n"
261 "eret\n"
262 :: "r" (arg), "r" (sp_usr), "r" (func) : "x0", "x3");
263 }
264
is_user(void)265 bool is_user(void)
266 {
267 return current_thread_info()->flags & TIF_USER_MODE;
268 }
269
__mmu_enabled(void)270 bool __mmu_enabled(void)
271 {
272 return read_sysreg(sctlr_el1) & SCTLR_EL1_M;
273 }
274