Home | History | Annotate | Line # | Download | only in aarch64
trap.c revision 1.31
      1 /* $NetBSD: trap.c,v 1.31 2020/07/08 03:45:13 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.31 2020/07/08 03:45:13 ryo Exp $");
     35 
     36 #include "opt_arm_intr_impl.h"
     37 #include "opt_compat_netbsd32.h"
     38 #include "opt_dtrace.h"
     39 
     40 #include <sys/param.h>
     41 #include <sys/kauth.h>
     42 #include <sys/types.h>
     43 #include <sys/atomic.h>
     44 #include <sys/cpu.h>
     45 #include <sys/evcnt.h>
     46 #ifdef KDB
     47 #include <sys/kdb.h>
     48 #endif
     49 #include <sys/proc.h>
     50 #include <sys/systm.h>
     51 #include <sys/signal.h>
     52 #include <sys/signalvar.h>
     53 #include <sys/siginfo.h>
     54 #include <sys/xcall.h>
     55 
     56 #ifdef ARM_INTR_IMPL
     57 #include ARM_INTR_IMPL
     58 #else
     59 #error ARM_INTR_IMPL not defined
     60 #endif
     61 
     62 #ifndef ARM_IRQ_HANDLER
     63 #error ARM_IRQ_HANDLER not defined
     64 #endif
     65 
     66 #include <aarch64/userret.h>
     67 #include <aarch64/frame.h>
     68 #include <aarch64/machdep.h>
     69 #include <aarch64/armreg.h>
     70 #include <aarch64/locore.h>
     71 
     72 #ifdef KDB
     73 #include <machine/db_machdep.h>
     74 #endif
     75 #ifdef DDB
     76 #include <ddb/db_output.h>
     77 #include <machine/db_machdep.h>
     78 #endif
     79 #ifdef KDTRACE_HOOKS
     80 #include <sys/dtrace_bsd.h>
     81 #endif
     82 
     83 #ifdef DDB
     84 int sigill_debug = 0;
     85 #endif
     86 
     87 #ifdef KDTRACE_HOOKS
     88 dtrace_doubletrap_func_t	dtrace_doubletrap_func = NULL;
     89 dtrace_trap_func_t		dtrace_trap_func = NULL;
     90 int (*dtrace_invop_jump_addr)(struct trapframe *);
     91 #endif
     92 
     93 enum emul_arm_result {
     94 	EMUL_ARM_SUCCESS = 0,
     95 	EMUL_ARM_UNKNOWN,
     96 	EMUL_ARM_FAULT,
     97 };
     98 
     99 const char * const trap_names[] = {
    100 	[ESR_EC_UNKNOWN]	= "Unknown Reason (Illegal Instruction)",
    101 	[ESR_EC_SERROR]		= "SError Interrupt",
    102 	[ESR_EC_WFX]		= "WFI or WFE instruction execution",
    103 	[ESR_EC_ILL_STATE]	= "Illegal Execution State",
    104 
    105 	[ESR_EC_BTE_A64]	= "Branch Target Exception",
    106 
    107 	[ESR_EC_SYS_REG]	= "MSR/MRS/SYS instruction",
    108 	[ESR_EC_SVC_A64]	= "SVC Instruction Execution",
    109 	[ESR_EC_HVC_A64]	= "HVC Instruction Execution",
    110 	[ESR_EC_SMC_A64]	= "SMC Instruction Execution",
    111 
    112 	[ESR_EC_INSN_ABT_EL0]	= "Instruction Abort (EL0)",
    113 	[ESR_EC_INSN_ABT_EL1]	= "Instruction Abort (EL1)",
    114 	[ESR_EC_DATA_ABT_EL0]	= "Data Abort (EL0)",
    115 	[ESR_EC_DATA_ABT_EL1]	= "Data Abort (EL1)",
    116 
    117 	[ESR_EC_PC_ALIGNMENT]	= "Misaligned PC",
    118 	[ESR_EC_SP_ALIGNMENT]	= "Misaligned SP",
    119 
    120 	[ESR_EC_FP_ACCESS]	= "Access to SIMD/FP Registers",
    121 	[ESR_EC_FP_TRAP_A64]	= "FP Exception",
    122 
    123 	[ESR_EC_BRKPNT_EL0]	= "Breakpoint Exception (EL0)",
    124 	[ESR_EC_BRKPNT_EL1]	= "Breakpoint Exception (EL1)",
    125 	[ESR_EC_SW_STEP_EL0]	= "Software Step (EL0)",
    126 	[ESR_EC_SW_STEP_EL1]	= "Software Step (EL1)",
    127 	[ESR_EC_WTCHPNT_EL0]	= "Watchpoint (EL0)",
    128 	[ESR_EC_WTCHPNT_EL1]	= "Watchpoint (EL1)",
    129 	[ESR_EC_BKPT_INSN_A64]	= "BKPT Instruction Execution",
    130 
    131 	[ESR_EC_CP15_RT]	= "A32: MCR/MRC access to CP15",
    132 	[ESR_EC_CP15_RRT]	= "A32: MCRR/MRRC access to CP15",
    133 	[ESR_EC_CP14_RT]	= "A32: MCR/MRC access to CP14",
    134 	[ESR_EC_CP14_DT]	= "A32: LDC/STC access to CP14",
    135 	[ESR_EC_CP14_RRT]	= "A32: MRRC access to CP14",
    136 	[ESR_EC_SVC_A32]	= "A32: SVC Instruction Execution",
    137 	[ESR_EC_HVC_A32]	= "A32: HVC Instruction Execution",
    138 	[ESR_EC_SMC_A32]	= "A32: SMC Instruction Execution",
    139 	[ESR_EC_FPID]		= "A32: MCR/MRC access to CP10",
    140 	[ESR_EC_FP_TRAP_A32]	= "A32: FP Exception",
    141 	[ESR_EC_BKPT_INSN_A32]	= "A32: BKPT Instruction Execution",
    142 	[ESR_EC_VECTOR_CATCH]	= "A32: Vector Catch Exception"
    143 };
    144 
    145 const char *
    146 eclass_trapname(uint32_t eclass)
    147 {
    148 	static char trapnamebuf[sizeof("Unknown trap 0x????????")];
    149 
    150 	if (eclass >= __arraycount(trap_names) || trap_names[eclass] == NULL) {
    151 		snprintf(trapnamebuf, sizeof(trapnamebuf),
    152 		    "Unknown trap %#02x", eclass);
    153 		return trapnamebuf;
    154 	}
    155 	return trap_names[eclass];
    156 }
    157 
    158 void
    159 userret(struct lwp *l)
    160 {
    161 	mi_userret(l);
    162 }
    163 
    164 void
    165 trap_doast(struct trapframe *tf)
    166 {
    167 	struct lwp * const l = curlwp;
    168 
    169 	/*
    170 	 * allow to have a chance of context switch just prior to user
    171 	 * exception return.
    172 	 */
    173 #ifdef __HAVE_PREEMPTION
    174 	kpreempt_disable();
    175 #endif
    176 	struct cpu_info * const ci = curcpu();
    177 
    178 	ci->ci_data.cpu_ntrap++;
    179 
    180 	KDASSERT(ci->ci_cpl == IPL_NONE);
    181 #ifdef __HAVE_PREEMPTION
    182 	kpreempt_enable();
    183 #endif
    184 
    185 	if (l->l_pflag & LP_OWEUPC) {
    186 		l->l_pflag &= ~LP_OWEUPC;
    187 		ADDUPROF(l);
    188 	}
    189 
    190 	userret(l);
    191 }
    192 
    193 void
    194 trap_el1h_sync(struct trapframe *tf)
    195 {
    196 	const uint32_t esr = tf->tf_esr;
    197 	const uint32_t eclass = __SHIFTOUT(esr, ESR_EC); /* exception class */
    198 
    199 	/* re-enable traps and interrupts */
    200 	if (!(tf->tf_spsr & SPSR_I))
    201 		daif_enable(DAIF_D|DAIF_A|DAIF_I|DAIF_F);
    202 	else
    203 		daif_enable(DAIF_D|DAIF_A);
    204 
    205 #ifdef KDTRACE_HOOKS
    206 	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(tf, eclass))
    207 		return;
    208 #endif
    209 
    210 	switch (eclass) {
    211 	case ESR_EC_INSN_ABT_EL1:
    212 	case ESR_EC_DATA_ABT_EL1:
    213 		data_abort_handler(tf, eclass);
    214 		break;
    215 
    216 	case ESR_EC_BKPT_INSN_A64:
    217 #ifdef KDTRACE_HOOKS
    218 		if (__SHIFTOUT(esr, ESR_ISS) == 0x40d &&
    219 		    dtrace_invop_jump_addr != 0) {
    220 			(*dtrace_invop_jump_addr)(tf);
    221 			break;
    222 		}
    223 		/* FALLTHROUGH */
    224 #endif
    225 	case ESR_EC_BRKPNT_EL1:
    226 	case ESR_EC_SW_STEP_EL1:
    227 	case ESR_EC_WTCHPNT_EL1:
    228 #ifdef DDB
    229 		if (eclass == ESR_EC_BRKPNT_EL1)
    230 			kdb_trap(DB_TRAP_BREAKPOINT, tf);
    231 		else if (eclass == ESR_EC_BKPT_INSN_A64)
    232 			kdb_trap(DB_TRAP_BKPT_INSN, tf);
    233 		else if (eclass == ESR_EC_WTCHPNT_EL1)
    234 			kdb_trap(DB_TRAP_WATCHPOINT, tf);
    235 		else if (eclass == ESR_EC_SW_STEP_EL1)
    236 			kdb_trap(DB_TRAP_SW_STEP, tf);
    237 		else
    238 			kdb_trap(DB_TRAP_UNKNOWN, tf);
    239 #else
    240 		panic("No debugger in kernel");
    241 #endif
    242 		break;
    243 
    244 	case ESR_EC_FP_ACCESS:
    245 	case ESR_EC_FP_TRAP_A64:
    246 	case ESR_EC_PC_ALIGNMENT:
    247 	case ESR_EC_SP_ALIGNMENT:
    248 	case ESR_EC_ILL_STATE:
    249 	case ESR_EC_BTE_A64:
    250 	default:
    251 		panic("Trap: fatal %s: pc=%016" PRIx64 " sp=%016" PRIx64
    252 		    " esr=%08x", eclass_trapname(eclass), tf->tf_pc, tf->tf_sp,
    253 		    esr);
    254 		break;
    255 	}
    256 }
    257 
    258 /*
    259  * There are some systems with different cache line sizes for each cpu.
    260  * Userland programs can be preempted between CPUs at any time, so in such
    261  * a system, the minimum cache line size must be visible to userland.
    262  */
    263 #define CTR_EL0_USR_MASK	\
    264 	(CTR_EL0_DIC | CTR_EL0_IDC | CTR_EL0_DMIN_LINE | CTR_EL0_IMIN_LINE)
    265 uint64_t ctr_el0_usr __read_mostly;
    266 
    267 static xcfunc_t
    268 configure_cpu_traps0(void *arg1, void *arg2)
    269 {
    270 	struct cpu_info * const ci = curcpu();
    271 	uint64_t sctlr;
    272 	uint64_t ctr_el0_raw = reg_ctr_el0_read();
    273 
    274 #ifdef DEBUG_FORCE_TRAP_CTR_EL0
    275 	goto need_ctr_trap;
    276 #endif
    277 
    278 	if ((__SHIFTOUT(ctr_el0_raw, CTR_EL0_DMIN_LINE) >
    279 	     __SHIFTOUT(ctr_el0_usr, CTR_EL0_DMIN_LINE)) ||
    280 	    (__SHIFTOUT(ctr_el0_raw, CTR_EL0_IMIN_LINE) >
    281 	     __SHIFTOUT(ctr_el0_usr, CTR_EL0_IMIN_LINE)))
    282 		goto need_ctr_trap;
    283 
    284 	if ((__SHIFTOUT(ctr_el0_raw, CTR_EL0_DIC) == 1 &&
    285 	     __SHIFTOUT(ctr_el0_usr, CTR_EL0_DIC) == 0) ||
    286 	    (__SHIFTOUT(ctr_el0_raw, CTR_EL0_IDC) == 1 &&
    287 	     __SHIFTOUT(ctr_el0_usr, CTR_EL0_IDC) == 0))
    288 		goto need_ctr_trap;
    289 
    290 #if 0 /* XXX: To do or not to do */
    291 	/*
    292 	 * IDC==0, but (LoC==0 || LoUIS==LoUU==0)?
    293 	 * Would it be better to show IDC=1 to userland?
    294 	 */
    295 	if (__SHIFTOUT(ctr_el0_raw, CTR_EL0_IDC) == 0 &&
    296 	    __SHIFTOUT(ctr_el0_usr, CTR_EL0_IDC) == 1)
    297 		goto need_ctr_trap;
    298 #endif
    299 
    300 	return 0;
    301 
    302  need_ctr_trap:
    303 	evcnt_attach_dynamic(&ci->ci_uct_trap, EVCNT_TYPE_MISC, NULL,
    304 	    ci->ci_cpuname, "ctr_el0 trap");
    305 
    306 	/* trap CTR_EL0 access from EL0 on this cpu */
    307 	sctlr = reg_sctlr_el1_read();
    308 	sctlr &= ~SCTLR_UCT;
    309 	reg_sctlr_el1_write(sctlr);
    310 
    311 	return 0;
    312 }
    313 
    314 void
    315 configure_cpu_traps(void)
    316 {
    317 	CPU_INFO_ITERATOR cii;
    318 	struct cpu_info *ci;
    319 	uint64_t where;
    320 
    321 	/* remember minimum cache line size out of all CPUs */
    322 	for (CPU_INFO_FOREACH(cii, ci)) {
    323 		uint64_t ctr_el0_cpu = ci->ci_id.ac_ctr;
    324 		uint64_t clidr = ci->ci_id.ac_clidr;
    325 
    326 		if (__SHIFTOUT(clidr, CLIDR_LOC) == 0 ||
    327 		    (__SHIFTOUT(clidr, CLIDR_LOUIS) == 0 &&
    328 		     __SHIFTOUT(clidr, CLIDR_LOUU) == 0)) {
    329 			/* this means the same as IDC=1 */
    330 			ctr_el0_cpu |= CTR_EL0_IDC;
    331 		}
    332 
    333 		/*
    334 		 * if DIC==1, there is no need to icache sync. however,
    335 		 * to calculate the minimum cacheline, in this case
    336 		 * ICacheLine is treated as the maximum.
    337 		 */
    338 		if (__SHIFTOUT(ctr_el0_cpu, CTR_EL0_DIC) == 1)
    339 			ctr_el0_cpu |= CTR_EL0_IMIN_LINE;
    340 
    341 		/* Neoverse N1 erratum 1542419 */
    342 		if (CPU_ID_NEOVERSEN1_P(ci->ci_id.ac_midr) &&
    343 		    __SHIFTOUT(ctr_el0_cpu, CTR_EL0_DIC) == 1)
    344 			ctr_el0_cpu &= ~CTR_EL0_DIC;
    345 
    346 		if (cii == 0) {
    347 			ctr_el0_usr = ctr_el0_cpu;
    348 			continue;
    349 		}
    350 
    351 		/* keep minimum cache line size, and worst DIC/IDC */
    352 		ctr_el0_usr &= (ctr_el0_cpu & CTR_EL0_DIC) | ~CTR_EL0_DIC;
    353 		ctr_el0_usr &= (ctr_el0_cpu & CTR_EL0_IDC) | ~CTR_EL0_IDC;
    354 		if (__SHIFTOUT(ctr_el0_cpu, CTR_EL0_DMIN_LINE) <
    355 		    __SHIFTOUT(ctr_el0_usr, CTR_EL0_DMIN_LINE)) {
    356 			ctr_el0_usr &= ~CTR_EL0_DMIN_LINE;
    357 			ctr_el0_usr |= ctr_el0_cpu & CTR_EL0_DMIN_LINE;
    358 		}
    359 		if ((ctr_el0_cpu & CTR_EL0_DIC) == 0 &&
    360 		    (__SHIFTOUT(ctr_el0_cpu, CTR_EL0_IMIN_LINE) <
    361 		    __SHIFTOUT(ctr_el0_usr, CTR_EL0_IMIN_LINE))) {
    362 			ctr_el0_usr &= ~CTR_EL0_IMIN_LINE;
    363 			ctr_el0_usr |= ctr_el0_cpu & CTR_EL0_IMIN_LINE;
    364 		}
    365 	}
    366 
    367 	where = xc_broadcast(0,
    368 	    (xcfunc_t)configure_cpu_traps0, NULL, NULL);
    369 	xc_wait(where);
    370 }
    371 
    372 static enum emul_arm_result
    373 emul_aarch64_insn(struct trapframe *tf)
    374 {
    375 	uint32_t insn;
    376 
    377 	if (ufetch_32((uint32_t *)tf->tf_pc, &insn))
    378 		return EMUL_ARM_FAULT;
    379 
    380 	if ((insn & 0xffffffe0) == 0xd53b0020) {
    381 		/* mrs x?,ctr_el0 */
    382 		unsigned int Xt = insn & 31;
    383 		if (Xt != 31) {	/* !xzr */
    384 			uint64_t ctr_el0 = reg_ctr_el0_read();
    385 			ctr_el0 &= ~CTR_EL0_USR_MASK;
    386 			ctr_el0 |= (ctr_el0_usr & CTR_EL0_USR_MASK);
    387 			tf->tf_reg[Xt] = ctr_el0;
    388 		}
    389 		curcpu()->ci_uct_trap.ev_count++;
    390 
    391 	} else {
    392 		return EMUL_ARM_UNKNOWN;
    393 	}
    394 
    395 	tf->tf_pc += 4;
    396 	return EMUL_ARM_SUCCESS;
    397 }
    398 
    399 void
    400 trap_el0_sync(struct trapframe *tf)
    401 {
    402 	struct lwp * const l = curlwp;
    403 	const uint32_t esr = tf->tf_esr;
    404 	const uint32_t eclass = __SHIFTOUT(esr, ESR_EC); /* exception class */
    405 
    406 	/* disable trace */
    407 	reg_mdscr_el1_write(reg_mdscr_el1_read() & ~MDSCR_SS);
    408 	/* enable traps and interrupts */
    409 	daif_enable(DAIF_D|DAIF_A|DAIF_I|DAIF_F);
    410 
    411 	switch (eclass) {
    412 	case ESR_EC_INSN_ABT_EL0:
    413 	case ESR_EC_DATA_ABT_EL0:
    414 		data_abort_handler(tf, eclass);
    415 		userret(l);
    416 		break;
    417 
    418 	case ESR_EC_SVC_A64:
    419 		(*l->l_proc->p_md.md_syscall)(tf);
    420 		break;
    421 	case ESR_EC_FP_ACCESS:
    422 		fpu_load(l);
    423 		userret(l);
    424 		break;
    425 	case ESR_EC_FP_TRAP_A64:
    426 		do_trapsignal(l, SIGFPE, FPE_FLTUND, NULL, esr); /* XXX */
    427 		userret(l);
    428 		break;
    429 
    430 	case ESR_EC_PC_ALIGNMENT:
    431 		do_trapsignal(l, SIGBUS, BUS_ADRALN, (void *)tf->tf_pc, esr);
    432 		userret(l);
    433 		break;
    434 	case ESR_EC_SP_ALIGNMENT:
    435 		do_trapsignal(l, SIGBUS, BUS_ADRALN, (void *)tf->tf_sp, esr);
    436 		userret(l);
    437 		break;
    438 
    439 	case ESR_EC_BKPT_INSN_A64:
    440 	case ESR_EC_BRKPNT_EL0:
    441 	case ESR_EC_WTCHPNT_EL0:
    442 		do_trapsignal(l, SIGTRAP, TRAP_BRKPT, (void *)tf->tf_pc, esr);
    443 		userret(l);
    444 		break;
    445 	case ESR_EC_SW_STEP_EL0:
    446 		/* disable trace, and send trace trap */
    447 		tf->tf_spsr &= ~SPSR_SS;
    448 		do_trapsignal(l, SIGTRAP, TRAP_TRACE, (void *)tf->tf_pc, esr);
    449 		userret(l);
    450 		break;
    451 
    452 	case ESR_EC_SYS_REG:
    453 		switch (emul_aarch64_insn(tf)) {
    454 		case EMUL_ARM_SUCCESS:
    455 			break;
    456 		case EMUL_ARM_UNKNOWN:
    457 			goto unknown;
    458 		case EMUL_ARM_FAULT:
    459 			do_trapsignal(l, SIGSEGV, SEGV_MAPERR,
    460 			    (void *)tf->tf_pc, esr);
    461 			break;
    462 		}
    463 		userret(l);
    464 		break;
    465 
    466 	default:
    467 	case ESR_EC_UNKNOWN:
    468  unknown:
    469 #ifdef DDB
    470 		if (sigill_debug) {
    471 			/* show illegal instruction */
    472 			printf("TRAP: pid %d (%s), uid %d: %s:"
    473 			    " esr=0x%lx: pc=0x%lx: %s\n",
    474 			    curlwp->l_proc->p_pid, curlwp->l_proc->p_comm,
    475 			    l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1,
    476 			    eclass_trapname(eclass), tf->tf_esr, tf->tf_pc,
    477 			    strdisasm(tf->tf_pc, tf->tf_spsr));
    478 		}
    479 #endif
    480 		/* illegal or not implemented instruction */
    481 		do_trapsignal(l, SIGILL, ILL_ILLTRP, (void *)tf->tf_pc, esr);
    482 		userret(l);
    483 		break;
    484 	}
    485 }
    486 
    487 void
    488 interrupt(struct trapframe *tf)
    489 {
    490 	struct cpu_info * const ci = curcpu();
    491 
    492 #ifdef STACKCHECKS
    493 	struct lwp *l = curlwp;
    494 	void *sp = (void *)reg_sp_read();
    495 	if (l->l_addr >= sp) {
    496 		panic("lwp/interrupt stack overflow detected."
    497 		    " lwp=%p, sp=%p, l_addr=%p", l, sp, l->l_addr);
    498 	}
    499 #endif
    500 
    501 	/* disable trace */
    502 	reg_mdscr_el1_write(reg_mdscr_el1_read() & ~MDSCR_SS);
    503 
    504 	/* enable traps */
    505 	daif_enable(DAIF_D|DAIF_A);
    506 
    507 	ci->ci_intr_depth++;
    508 	ARM_IRQ_HANDLER(tf);
    509 	ci->ci_intr_depth--;
    510 
    511 	cpu_dosoftints();
    512 }
    513 
    514 #ifdef COMPAT_NETBSD32
    515 
    516 /*
    517  * 32-bit length Thumb instruction. See ARMv7 DDI0406A A6.3.
    518  */
    519 #define THUMB_32BIT(hi) (((hi) & 0xe000) == 0xe000 && ((hi) & 0x1800))
    520 
    521 int
    522 fetch_arm_insn(uint64_t pc, uint64_t spsr, uint32_t *insn)
    523 {
    524 
    525 	/* THUMB? */
    526 	if (spsr & SPSR_A32_T) {
    527 		uint16_t *p = (uint16_t *)(pc & ~1UL); /* XXX */
    528 		uint16_t hi, lo;
    529 
    530 		if (ufetch_16(p, &hi))
    531 			return -1;
    532 
    533 		if (!THUMB_32BIT(hi)) {
    534 			/* 16-bit Thumb instruction */
    535 			*insn = hi;
    536 			return 2;
    537 		}
    538 
    539 		/* 32-bit Thumb instruction */
    540 		if (ufetch_16(p + 1, &lo))
    541 			return -1;
    542 
    543 		*insn = ((uint32_t)hi << 16) | lo;
    544 		return 4;
    545 	}
    546 
    547 	if (ufetch_32((uint32_t *)pc, insn))
    548 		return -1;
    549 
    550 	return 4;
    551 }
    552 
    553 static enum emul_arm_result
    554 emul_arm_insn(struct trapframe *tf)
    555 {
    556 	struct lwp * const l = curlwp;
    557 	uint32_t insn;
    558 	int insn_size;
    559 
    560 	insn_size = fetch_arm_insn(tf->tf_pc, tf->tf_spsr, &insn);
    561 
    562 	switch (insn_size) {
    563 	case 2:
    564 		/* T32-16bit instruction */
    565 
    566 		/*
    567 		 * Breakpoint used by GDB.
    568 		 */
    569 		if (insn == 0xdefe)
    570 			goto trap;
    571 
    572 		/* XXX: some T32 IT instruction deprecated should be emulated */
    573 		break;
    574 	case 4:
    575 		/* T32-32bit instruction, or A32 instruction */
    576 
    577 		/*
    578 		 * Breakpoint used by GDB.
    579 		 */
    580 		if (insn == 0xe6000011 || insn == 0xe7ffdefe) {
    581  trap:
    582 			do_trapsignal(l, SIGTRAP, TRAP_BRKPT,
    583 			    (void *)tf->tf_pc, 0);
    584 			return 0;
    585 		}
    586 
    587 		/*
    588 		 * Emulate ARMv6 instructions with cache operations
    589 		 * register (c7), that can be used in user mode.
    590 		 */
    591 		switch (insn & 0x0fff0fff) {
    592 		case 0x0e070f95:
    593 			/*
    594 			 * mcr p15, 0, <Rd>, c7, c5, 4
    595 			 * (flush prefetch buffer)
    596 			 */
    597 			__asm __volatile("isb sy" ::: "memory");
    598 			goto emulated;
    599 		case 0x0e070f9a:
    600 			/*
    601 			 * mcr p15, 0, <Rd>, c7, c10, 4
    602 			 * (data synchronization barrier)
    603 			 */
    604 			__asm __volatile("dsb sy" ::: "memory");
    605 			goto emulated;
    606 		case 0x0e070fba:
    607 			/*
    608 			 * mcr p15, 0, <Rd>, c7, c10, 5
    609 			 * (data memory barrier)
    610 			 */
    611 			__asm __volatile("dmb sy" ::: "memory");
    612 			goto emulated;
    613 		default:
    614 			break;
    615 		}
    616 		break;
    617 	default:
    618 		return EMUL_ARM_FAULT;
    619 	}
    620 
    621 	/* unknown, or unsupported instruction */
    622 	return EMUL_ARM_UNKNOWN;
    623 
    624  emulated:
    625 	tf->tf_pc += insn_size;
    626 	return EMUL_ARM_SUCCESS;
    627 }
    628 #endif /* COMPAT_NETBSD32 */
    629 
    630 void
    631 trap_el0_32sync(struct trapframe *tf)
    632 {
    633 	struct lwp * const l = curlwp;
    634 	const uint32_t esr = tf->tf_esr;
    635 	const uint32_t eclass = __SHIFTOUT(esr, ESR_EC); /* exception class */
    636 
    637 	/* disable trace */
    638 	reg_mdscr_el1_write(reg_mdscr_el1_read() & ~MDSCR_SS);
    639 	/* enable traps and interrupts */
    640 	daif_enable(DAIF_D|DAIF_A|DAIF_I|DAIF_F);
    641 
    642 	switch (eclass) {
    643 #ifdef COMPAT_NETBSD32
    644 	case ESR_EC_INSN_ABT_EL0:
    645 	case ESR_EC_DATA_ABT_EL0:
    646 		data_abort_handler(tf, eclass);
    647 		userret(l);
    648 		break;
    649 
    650 	case ESR_EC_SVC_A32:
    651 		(*l->l_proc->p_md.md_syscall)(tf);
    652 		break;
    653 
    654 	case ESR_EC_FP_ACCESS:
    655 		fpu_load(l);
    656 		userret(l);
    657 		break;
    658 
    659 	case ESR_EC_FP_TRAP_A32:
    660 		do_trapsignal(l, SIGFPE, FPE_FLTUND, NULL, esr); /* XXX */
    661 		userret(l);
    662 		break;
    663 
    664 	case ESR_EC_PC_ALIGNMENT:
    665 		do_trapsignal(l, SIGBUS, BUS_ADRALN, (void *)tf->tf_pc, esr);
    666 		userret(l);
    667 		break;
    668 
    669 	case ESR_EC_SP_ALIGNMENT:
    670 		do_trapsignal(l, SIGBUS, BUS_ADRALN,
    671 		    (void *)tf->tf_reg[13], esr); /* sp is r13 on AArch32 */
    672 		userret(l);
    673 		break;
    674 
    675 	case ESR_EC_BKPT_INSN_A32:
    676 		do_trapsignal(l, SIGTRAP, TRAP_BRKPT, (void *)tf->tf_pc, esr);
    677 		userret(l);
    678 		break;
    679 
    680 	case ESR_EC_UNKNOWN:
    681 		switch (emul_arm_insn(tf)) {
    682 		case EMUL_ARM_SUCCESS:
    683 			break;
    684 		case EMUL_ARM_UNKNOWN:
    685 			goto unknown;
    686 		case EMUL_ARM_FAULT:
    687 			do_trapsignal(l, SIGSEGV, SEGV_MAPERR,
    688 			    (void *)tf->tf_pc, esr);
    689 			break;
    690 		}
    691 		userret(l);
    692 		break;
    693 
    694 	case ESR_EC_CP15_RT:
    695 	case ESR_EC_CP15_RRT:
    696 	case ESR_EC_CP14_RT:
    697 	case ESR_EC_CP14_DT:
    698 	case ESR_EC_CP14_RRT:
    699 unknown:
    700 #endif /* COMPAT_NETBSD32 */
    701 	default:
    702 #ifdef DDB
    703 		if (sigill_debug) {
    704 			/* show illegal instruction */
    705 			printf("TRAP: pid %d (%s), uid %d: %s:"
    706 			    " esr=0x%lx: pc=0x%lx: %s\n",
    707 			    curlwp->l_proc->p_pid, curlwp->l_proc->p_comm,
    708 			    l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1,
    709 			    eclass_trapname(eclass), tf->tf_esr, tf->tf_pc,
    710 			    strdisasm(tf->tf_pc, tf->tf_spsr));
    711 		}
    712 #endif
    713 		/* illegal or not implemented instruction */
    714 		do_trapsignal(l, SIGILL, ILL_ILLTRP, (void *)tf->tf_pc, esr);
    715 		userret(l);
    716 		break;
    717 	}
    718 }
    719 
    720 #define bad_trap_panic(trapfunc)	\
    721 void					\
    722 trapfunc(struct trapframe *tf)		\
    723 {					\
    724 	panic("%s", __func__);		\
    725 }
    726 bad_trap_panic(trap_el1t_sync)
    727 bad_trap_panic(trap_el1t_irq)
    728 bad_trap_panic(trap_el1t_fiq)
    729 bad_trap_panic(trap_el1t_error)
    730 bad_trap_panic(trap_el1h_fiq)
    731 bad_trap_panic(trap_el1h_error)
    732 bad_trap_panic(trap_el0_fiq)
    733 bad_trap_panic(trap_el0_error)
    734 bad_trap_panic(trap_el0_32fiq)
    735 bad_trap_panic(trap_el0_32error)
    736 
    737 void
    738 cpu_jump_onfault(struct trapframe *tf, const struct faultbuf *fb, int val)
    739 {
    740 	tf->tf_reg[19] = fb->fb_reg[FB_X19];
    741 	tf->tf_reg[20] = fb->fb_reg[FB_X20];
    742 	tf->tf_reg[21] = fb->fb_reg[FB_X21];
    743 	tf->tf_reg[22] = fb->fb_reg[FB_X22];
    744 	tf->tf_reg[23] = fb->fb_reg[FB_X23];
    745 	tf->tf_reg[24] = fb->fb_reg[FB_X24];
    746 	tf->tf_reg[25] = fb->fb_reg[FB_X25];
    747 	tf->tf_reg[26] = fb->fb_reg[FB_X26];
    748 	tf->tf_reg[27] = fb->fb_reg[FB_X27];
    749 	tf->tf_reg[28] = fb->fb_reg[FB_X28];
    750 	tf->tf_reg[29] = fb->fb_reg[FB_X29];
    751 	tf->tf_sp = fb->fb_reg[FB_SP];
    752 	tf->tf_pc = fb->fb_reg[FB_LR];
    753 	tf->tf_reg[0] = val;
    754 }
    755 
    756 #ifdef TRAP_SIGDEBUG
    757 static void
    758 frame_dump(const struct trapframe *tf)
    759 {
    760 	const struct reg *r = &tf->tf_regs;
    761 
    762 	printf("trapframe %p\n", tf);
    763 	for (size_t i = 0; i < __arraycount(r->r_reg); i++) {
    764 		printf(" r%.2zu %#018" PRIx64 "%c", i, r->r_reg[i],
    765 		    " \n"[i && (i & 1) == 0]);
    766 	}
    767 
    768 	printf("\n");
    769 	printf("   sp %#018" PRIx64 "    pc %#018" PRIx64 "\n",
    770 	    r->r_sp, r->r_pc);
    771 	printf(" spsr %#018" PRIx64 " tpidr %#018" PRIx64 "\n",
    772 	    r->r_spsr, r->r_tpidr);
    773 	printf("  esr %#018" PRIx64 "   far %#018" PRIx64 "\n",
    774 	    tf->tf_esr, tf->tf_far);
    775 
    776 	printf("\n");
    777 	hexdump(printf, "Stack dump", tf, 256);
    778 }
    779 
    780 static void
    781 sigdebug(const struct trapframe *tf, const ksiginfo_t *ksi)
    782 {
    783 	struct lwp *l = curlwp;
    784 	struct proc *p = l->l_proc;
    785 	const uint32_t eclass = __SHIFTOUT(ksi->ksi_trap, ESR_EC);
    786 
    787 	printf("pid %d.%d (%s): signal %d (trap %#x) "
    788 	    "@pc %#" PRIx64 ", addr %p, error=%s\n",
    789 	    p->p_pid, l->l_lid, p->p_comm, ksi->ksi_signo, ksi->ksi_trap,
    790 	    tf->tf_regs.r_pc, ksi->ksi_addr, eclass_trapname(eclass));
    791 	frame_dump(tf);
    792 }
    793 #endif
    794 
    795 void do_trapsignal1(
    796 #ifdef TRAP_SIGDEBUG
    797     const char *func,
    798     size_t line,
    799     struct trapframe *tf,
    800 #endif
    801     struct lwp *l, int signo, int code, void *addr, int trap)
    802 {
    803 	ksiginfo_t ksi;
    804 
    805 	KSI_INIT_TRAP(&ksi);
    806 	ksi.ksi_signo = signo;
    807 	ksi.ksi_code = code;
    808 	ksi.ksi_addr = addr;
    809 	ksi.ksi_trap = trap;
    810 #ifdef TRAP_SIGDEBUG
    811 	printf("%s, %zu: ", func, line);
    812 	sigdebug(tf, &ksi);
    813 #endif
    814 	(*l->l_proc->p_emul->e_trapsignal)(l, &ksi);
    815 }
    816 
    817 bool
    818 cpu_intr_p(void)
    819 {
    820 	uint64_t ncsw;
    821 	int idepth;
    822 	lwp_t *l;
    823 
    824 #ifdef __HAVE_PIC_FAST_SOFTINTS
    825 	/* XXX Copied from cpu.h.  Looks incomplete - needs fixing. */
    826 	if (ci->ci_cpl < IPL_VM)
    827 		return false;
    828 #endif
    829 
    830 	l = curlwp;
    831 	if (__predict_false(l->l_cpu == NULL)) {
    832 		KASSERT(l == &lwp0);
    833 		return false;
    834 	}
    835 	do {
    836 		ncsw = l->l_ncsw;
    837 		__insn_barrier();
    838 		idepth = l->l_cpu->ci_intr_depth;
    839 		__insn_barrier();
    840 	} while (__predict_false(ncsw != l->l_ncsw));
    841 
    842 	return idepth > 0;
    843 }
    844