Home | History | Annotate | Line # | Download | only in aarch64
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