trap.c revision 1.13 1 /* $NetBSD: trap.c,v 1.13 2018/12/12 18:11:00 ryo Exp $ */
2
3 /*-
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas of 3am Software Foundry.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33
34 __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.13 2018/12/12 18:11:00 ryo Exp $");
35
36 #include "opt_arm_intr_impl.h"
37 #include "opt_compat_netbsd32.h"
38
39 #include <sys/param.h>
40 #include <sys/kauth.h>
41 #include <sys/types.h>
42 #include <sys/atomic.h>
43 #include <sys/cpu.h>
44 #ifdef KDB
45 #include <sys/kdb.h>
46 #endif
47 #include <sys/proc.h>
48 #include <sys/systm.h>
49 #include <sys/signal.h>
50 #include <sys/signalvar.h>
51 #include <sys/siginfo.h>
52
53 #ifdef ARM_INTR_IMPL
54 #include ARM_INTR_IMPL
55 #else
56 #error ARM_INTR_IMPL not defined
57 #endif
58
59 #ifndef ARM_IRQ_HANDLER
60 #error ARM_IRQ_HANDLER not defined
61 #endif
62
63 #include <aarch64/userret.h>
64 #include <aarch64/frame.h>
65 #include <aarch64/machdep.h>
66 #include <aarch64/armreg.h>
67 #include <aarch64/locore.h>
68
69 #ifdef KDB
70 #include <machine/db_machdep.h>
71 #endif
72 #ifdef DDB
73 #include <ddb/db_output.h>
74 #include <machine/db_machdep.h>
75 #endif
76
77 #ifdef DDB
78 int sigill_debug = 0;
79 #endif
80
81 const char * const trap_names[] = {
82 [ESR_EC_UNKNOWN] = "Unknown Reason (Illegal Instruction)",
83 [ESR_EC_SERROR] = "SError Interrupt",
84 [ESR_EC_WFX] = "WFI or WFE instruction execution",
85 [ESR_EC_ILL_STATE] = "Illegal Execution State",
86
87 [ESR_EC_SYS_REG] = "MSR/MRS/SYS instruction",
88 [ESR_EC_SVC_A64] = "SVC Instruction Execution",
89 [ESR_EC_HVC_A64] = "HVC Instruction Execution",
90 [ESR_EC_SMC_A64] = "SMC Instruction Execution",
91
92 [ESR_EC_INSN_ABT_EL0] = "Instruction Abort (EL0)",
93 [ESR_EC_INSN_ABT_EL1] = "Instruction Abort (EL1)",
94 [ESR_EC_DATA_ABT_EL0] = "Data Abort (EL0)",
95 [ESR_EC_DATA_ABT_EL1] = "Data Abort (EL1)",
96
97 [ESR_EC_PC_ALIGNMENT] = "Misaligned PC",
98 [ESR_EC_SP_ALIGNMENT] = "Misaligned SP",
99
100 [ESR_EC_FP_ACCESS] = "Access to SIMD/FP Registers",
101 [ESR_EC_FP_TRAP_A64] = "FP Exception",
102
103 [ESR_EC_BRKPNT_EL0] = "Breakpoint Exception (EL0)",
104 [ESR_EC_BRKPNT_EL1] = "Breakpoint Exception (EL1)",
105 [ESR_EC_SW_STEP_EL0] = "Software Step (EL0)",
106 [ESR_EC_SW_STEP_EL1] = "Software Step (EL1)",
107 [ESR_EC_WTCHPNT_EL0] = "Watchpoint (EL0)",
108 [ESR_EC_WTCHPNT_EL1] = "Watchpoint (EL1)",
109 [ESR_EC_BKPT_INSN_A64] = "BKPT Instruction Execution",
110
111 [ESR_EC_CP15_RT] = "A32: MCR/MRC access to CP15",
112 [ESR_EC_CP15_RRT] = "A32: MCRR/MRRC access to CP15",
113 [ESR_EC_CP14_RT] = "A32: MCR/MRC access to CP14",
114 [ESR_EC_CP14_DT] = "A32: LDC/STC access to CP14",
115 [ESR_EC_CP14_RRT] = "A32: MRRC access to CP14",
116 [ESR_EC_SVC_A32] = "A32: SVC Instruction Execution",
117 [ESR_EC_HVC_A32] = "A32: HVC Instruction Execution",
118 [ESR_EC_SMC_A32] = "A32: SMC Instruction Execution",
119 [ESR_EC_FPID] = "A32: MCR/MRC access to CP10",
120 [ESR_EC_FP_TRAP_A32] = "A32: FP Exception",
121 [ESR_EC_BKPT_INSN_A32] = "A32: BKPT Instruction Execution",
122 [ESR_EC_VECTOR_CATCH] = "A32: Vector Catch Exception"
123 };
124
125 const char *
126 eclass_trapname(uint32_t eclass)
127 {
128 static char trapnamebuf[sizeof("Unknown trap 0x????????")];
129
130 if (eclass >= __arraycount(trap_names) || trap_names[eclass] == NULL) {
131 snprintf(trapnamebuf, sizeof(trapnamebuf),
132 "Unknown trap %#02x", eclass);
133 return trapnamebuf;
134 }
135 return trap_names[eclass];
136 }
137
138 void
139 userret(struct lwp *l)
140 {
141 mi_userret(l);
142 }
143
144 void
145 trap_doast(struct trapframe *tf)
146 {
147 struct lwp * const l = curlwp;
148
149 /*
150 * allow to have a chance of context switch just prior to user
151 * exception return.
152 */
153 #ifdef __HAVE_PREEMPTION
154 kpreempt_disable();
155 #endif
156 struct cpu_info * const ci = curcpu();
157
158 ci->ci_data.cpu_ntrap++;
159
160 KDASSERT(ci->ci_cpl == IPL_NONE);
161 const int want_resched = ci->ci_want_resched;
162 #ifdef __HAVE_PREEMPTION
163 kpreempt_enable();
164 #endif
165
166 if (l->l_pflag & LP_OWEUPC) {
167 l->l_pflag &= ~LP_OWEUPC;
168 ADDUPROF(l);
169 }
170
171 /* Allow a forced task switch. */
172 if (want_resched)
173 preempt();
174 userret(l);
175 }
176
177 void
178 trap_el1h_sync(struct trapframe *tf)
179 {
180 const uint32_t esr = tf->tf_esr;
181 const uint32_t eclass = __SHIFTOUT(esr, ESR_EC); /* exception class */
182
183 /* re-enable traps and interrupts */
184 if (!(tf->tf_spsr & SPSR_I))
185 daif_enable(DAIF_D|DAIF_A|DAIF_I|DAIF_F);
186 else
187 daif_enable(DAIF_D|DAIF_A);
188
189 switch (eclass) {
190 case ESR_EC_INSN_ABT_EL1:
191 case ESR_EC_DATA_ABT_EL1:
192 data_abort_handler(tf, eclass);
193 break;
194
195 case ESR_EC_BRKPNT_EL1:
196 case ESR_EC_SW_STEP_EL1:
197 case ESR_EC_WTCHPNT_EL1:
198 case ESR_EC_BKPT_INSN_A64:
199 #ifdef DDB
200 if (eclass == ESR_EC_BRKPNT_EL1)
201 kdb_trap(DB_TRAP_BREAKPOINT, tf);
202 else if (eclass == ESR_EC_BKPT_INSN_A64)
203 kdb_trap(DB_TRAP_BKPT_INSN, tf);
204 else if (eclass == ESR_EC_WTCHPNT_EL1)
205 kdb_trap(DB_TRAP_WATCHPOINT, tf);
206 else if (eclass == ESR_EC_SW_STEP_EL1)
207 kdb_trap(DB_TRAP_SW_STEP, tf);
208 else
209 kdb_trap(DB_TRAP_UNKNOWN, tf);
210 #else
211 panic("No debugger in kernel");
212 #endif
213 break;
214
215 case ESR_EC_FP_ACCESS:
216 case ESR_EC_FP_TRAP_A64:
217 case ESR_EC_PC_ALIGNMENT:
218 case ESR_EC_SP_ALIGNMENT:
219 case ESR_EC_ILL_STATE:
220 default:
221 panic("Trap: fatal %s: pc=%016" PRIx64 " sp=%016" PRIx64
222 " esr=%08x", eclass_trapname(eclass), tf->tf_pc, tf->tf_sp,
223 esr);
224 break;
225 }
226 }
227
228 void
229 trap_el0_sync(struct trapframe *tf)
230 {
231 struct lwp * const l = curlwp;
232 const uint32_t esr = tf->tf_esr;
233 const uint32_t eclass = __SHIFTOUT(esr, ESR_EC); /* exception class */
234
235 /* enable traps and interrupts */
236 daif_enable(DAIF_D|DAIF_A|DAIF_I|DAIF_F);
237
238 switch (eclass) {
239 case ESR_EC_INSN_ABT_EL0:
240 case ESR_EC_DATA_ABT_EL0:
241 data_abort_handler(tf, eclass);
242 userret(l);
243 break;
244
245 case ESR_EC_SVC_A64:
246 (*l->l_proc->p_md.md_syscall)(tf);
247 break;
248 case ESR_EC_FP_ACCESS:
249 fpu_load(l);
250 userret(l);
251 break;
252 case ESR_EC_FP_TRAP_A64:
253 do_trapsignal(l, SIGFPE, FPE_FLTUND, NULL, esr); /* XXX */
254 userret(l);
255 break;
256
257 case ESR_EC_PC_ALIGNMENT:
258 do_trapsignal(l, SIGBUS, BUS_ADRALN, (void *)tf->tf_pc, esr);
259 userret(l);
260 break;
261 case ESR_EC_SP_ALIGNMENT:
262 do_trapsignal(l, SIGBUS, BUS_ADRALN, (void *)tf->tf_sp, esr);
263 userret(l);
264 break;
265
266 case ESR_EC_BKPT_INSN_A64:
267 case ESR_EC_BRKPNT_EL0:
268 case ESR_EC_SW_STEP_EL0:
269 case ESR_EC_WTCHPNT_EL0:
270 do_trapsignal(l, SIGTRAP, TRAP_BRKPT, (void *)tf->tf_pc, esr);
271 userret(l);
272 break;
273
274 default:
275 case ESR_EC_UNKNOWN:
276 #ifdef DDB
277 if (sigill_debug) {
278 /* show illegal instruction */
279 printf("TRAP: pid %d (%s), uid %d: %s:"
280 " esr=0x%lx: pc=0x%lx: %s\n",
281 curlwp->l_proc->p_pid, curlwp->l_proc->p_comm,
282 l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1,
283 eclass_trapname(eclass), tf->tf_esr, tf->tf_pc,
284 strdisasm(tf->tf_pc));
285 }
286 #endif
287 /* illegal or not implemented instruction */
288 do_trapsignal(l, SIGILL, ILL_ILLTRP, (void *)tf->tf_pc, esr);
289 userret(l);
290 break;
291 }
292 }
293
294 void
295 interrupt(struct trapframe *tf)
296 {
297 struct cpu_info * const ci = curcpu();
298
299 #ifdef STACKCHECKS
300 struct lwp *l = curlwp;
301 void *sp = (void *)reg_sp_read();
302 if (l->l_addr >= sp) {
303 panic("lwp/interrupt stack overflow detected."
304 " lwp=%p, sp=%p, l_addr=%p", l, sp, l->l_addr);
305 }
306 #endif
307
308 /* enable traps */
309 daif_enable(DAIF_D|DAIF_A);
310
311 ci->ci_intr_depth++;
312 ARM_IRQ_HANDLER(tf);
313 ci->ci_intr_depth--;
314
315 cpu_dosoftints();
316 }
317
318 void
319 trap_el0_32sync(struct trapframe *tf)
320 {
321 struct lwp * const l = curlwp;
322 const uint32_t esr = tf->tf_esr;
323 const uint32_t eclass = __SHIFTOUT(esr, ESR_EC); /* exception class */
324
325 /* enable traps and interrupts */
326 daif_enable(DAIF_D|DAIF_A|DAIF_I|DAIF_F);
327
328 switch (eclass) {
329 #ifdef COMPAT_NETBSD32
330 case ESR_EC_INSN_ABT_EL0:
331 case ESR_EC_DATA_ABT_EL0:
332 data_abort_handler(tf, eclass);
333 userret(l);
334 break;
335
336 case ESR_EC_SVC_A32:
337 (*l->l_proc->p_md.md_syscall)(tf);
338 break;
339 case ESR_EC_FP_ACCESS:
340 fpu_load(l);
341 userret(l);
342 break;
343 case ESR_EC_FP_TRAP_A32:
344 do_trapsignal(l, SIGFPE, FPE_FLTUND, NULL, esr); /* XXX */
345 userret(l);
346
347 case ESR_EC_PC_ALIGNMENT:
348 do_trapsignal(l, SIGBUS, BUS_ADRALN, (void *)tf->tf_pc, esr);
349 userret(l);
350 break;
351 case ESR_EC_SP_ALIGNMENT:
352 do_trapsignal(l, SIGBUS, BUS_ADRALN,
353 (void *)tf->tf_reg[13], esr); /* sp is r13 on AArch32 */
354 userret(l);
355 break;
356
357 case ESR_EC_BKPT_INSN_A32:
358 do_trapsignal(l, SIGTRAP, TRAP_BRKPT, (void *)tf->tf_pc, esr);
359 userret(l);
360 break;
361
362 case ESR_EC_CP15_RT:
363 case ESR_EC_CP15_RRT:
364 case ESR_EC_CP14_RT:
365 case ESR_EC_CP14_DT:
366 case ESR_EC_CP14_RRT:
367 #endif /* COMPAT_NETBSD32 */
368 default:
369 #ifdef DDB
370 if (sigill_debug) {
371 /* show illegal instruction */
372 printf("TRAP: pid %d (%s), uid %d: %s:"
373 " esr=0x%lx: pc=0x%lx: %s\n",
374 curlwp->l_proc->p_pid, curlwp->l_proc->p_comm,
375 l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1,
376 eclass_trapname(eclass), tf->tf_esr, tf->tf_pc,
377 strdisasm_aarch32(tf->tf_pc));
378 }
379 #endif
380 /* illegal or not implemented instruction */
381 do_trapsignal(l, SIGILL, ILL_ILLTRP, (void *)tf->tf_pc, esr);
382 userret(l);
383 break;
384 }
385 }
386
387 #define bad_trap_panic(trapfunc) \
388 void \
389 trapfunc(struct trapframe *tf) \
390 { \
391 panic("%s", __func__); \
392 }
393 bad_trap_panic(trap_el1t_sync)
394 bad_trap_panic(trap_el1t_irq)
395 bad_trap_panic(trap_el1t_fiq)
396 bad_trap_panic(trap_el1t_error)
397 bad_trap_panic(trap_el1h_fiq)
398 bad_trap_panic(trap_el1h_error)
399 bad_trap_panic(trap_el0_fiq)
400 bad_trap_panic(trap_el0_error)
401 bad_trap_panic(trap_el0_32fiq)
402 bad_trap_panic(trap_el0_32error)
403
404 void
405 cpu_jump_onfault(struct trapframe *tf, const struct faultbuf *fb, int val)
406 {
407 tf->tf_reg[19] = fb->fb_reg[FB_X19];
408 tf->tf_reg[20] = fb->fb_reg[FB_X20];
409 tf->tf_reg[21] = fb->fb_reg[FB_X21];
410 tf->tf_reg[22] = fb->fb_reg[FB_X22];
411 tf->tf_reg[23] = fb->fb_reg[FB_X23];
412 tf->tf_reg[24] = fb->fb_reg[FB_X24];
413 tf->tf_reg[25] = fb->fb_reg[FB_X25];
414 tf->tf_reg[26] = fb->fb_reg[FB_X26];
415 tf->tf_reg[27] = fb->fb_reg[FB_X27];
416 tf->tf_reg[28] = fb->fb_reg[FB_X28];
417 tf->tf_reg[29] = fb->fb_reg[FB_X29];
418 tf->tf_sp = fb->fb_reg[FB_SP];
419 tf->tf_pc = fb->fb_reg[FB_LR];
420 tf->tf_reg[0] = val;
421 }
422
423 void
424 ucas_ras_check(struct trapframe *tf)
425 {
426 #if 0 /* XXX notyet */
427 extern char ucas_32_ras_start[];
428 extern char ucas_32_ras_end[];
429 extern char ucas_64_ras_start[];
430 extern char ucas_64_ras_end[];
431
432 if (tf->tf_pc > (vaddr_t)ucas_32_ras_start &&
433 tf->tf_pc < (vaddr_t)ucas_32_ras_end) {
434 tf->tf_pc = (vaddr_t)ucas_32_ras_start;
435 } else if (tf->tf_pc > (vaddr_t)ucas_64_ras_start &&
436 tf->tf_pc < (vaddr_t)ucas_64_ras_end) {
437 tf->tf_pc = (vaddr_t)ucas_64_ras_start;
438 }
439 #endif
440 }
441
442 #ifdef TRAP_SIGDEBUG
443 static void
444 frame_dump(const struct trapframe *tf)
445 {
446 const struct reg *r = &tf->tf_regs;
447
448 printf("trapframe %p\n", tf);
449 for (size_t i = 0; i < __arraycount(r->r_reg); i++) {
450 printf(" r%.2zu %#018" PRIx64 "%c", i, r->r_reg[i],
451 " \n"[i && (i & 1) == 0]);
452 }
453
454 printf("\n");
455 printf(" sp %#018" PRIx64 " pc %#018" PRIx64 "\n",
456 r->r_sp, r->r_pc);
457 printf(" spsr %#018" PRIx64 " tpidr %#018" PRIx64 "\n",
458 r->r_spsr, r->r_tpidr);
459 printf(" esr %#018" PRIx64 " far %#018" PRIx64 "\n",
460 tf->tf_esr, tf->tf_far);
461
462 printf("\n");
463 hexdump(printf, "Stack dump", tf, 256);
464 }
465
466 static void
467 sigdebug(const struct trapframe *tf, const ksiginfo_t *ksi)
468 {
469 struct lwp *l = curlwp;
470 struct proc *p = l->l_proc;
471 const uint32_t eclass = __SHIFTOUT(ksi->ksi_trap, ESR_EC);
472
473 printf("pid %d.%d (%s): signal %d (trap %#x) "
474 "@pc %#" PRIx64 ", addr %p, error=%s\n",
475 p->p_pid, l->l_lid, p->p_comm, ksi->ksi_signo, ksi->ksi_trap,
476 tf->tf_regs.r_pc, ksi->ksi_addr, eclass_trapname(eclass));
477 frame_dump(tf);
478 }
479 #endif
480
481 void do_trapsignal1(
482 #ifdef TRAP_SIGDEBUG
483 const char *func,
484 size_t line,
485 struct trapframe *tf,
486 #endif
487 struct lwp *l, int signo, int code, void *addr, int trap)
488 {
489 ksiginfo_t ksi;
490
491 KSI_INIT_TRAP(&ksi);
492 ksi.ksi_signo = signo;
493 ksi.ksi_code = code;
494 ksi.ksi_addr = addr;
495 ksi.ksi_trap = trap;
496 #ifdef TRAP_SIGDEBUG
497 printf("%s, %zu: ", func, line);
498 sigdebug(tf, &ksi);
499 #endif
500 (*l->l_proc->p_emul->e_trapsignal)(l, &ksi);
501 }
502