Home | History | Annotate | Line # | Download | only in vax
      1 /*	$NetBSD: trap.c,v 1.143 2025/04/05 11:20:30 riastradh Exp $     */
      2 
      3 /*
      4  * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28  /* All bugs are subject to removal without further notice */
     29 
     30 #include <sys/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.143 2025/04/05 11:20:30 riastradh Exp $");
     32 
     33 #include "opt_ddb.h"
     34 #include "opt_multiprocessor.h"
     35 
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/cpu.h>
     39 #include <sys/exec.h>
     40 #include <sys/kauth.h>
     41 #include <sys/proc.h>
     42 #include <sys/signalvar.h>
     43 
     44 #include <uvm/uvm_extern.h>
     45 
     46 #include <machine/trap.h>
     47 #include <machine/userret.h>
     48 
     49 #ifdef DDB
     50 #include <machine/db_machdep.h>
     51 #endif
     52 #include <vax/vax/db_disasm.h>
     53 #include <kern/syscalls.c>
     54 #include <sys/ktrace.h>
     55 
     56 #ifdef TRAPDEBUG
     57 volatile int faultdebug = 0;
     58 #endif
     59 
     60 int	cpu_printfataltraps = 0;
     61 
     62 void	trap (struct trapframe *);
     63 
     64 const char * const traptypes[]={
     65 	"reserved addressing",
     66 	"privileged instruction",
     67 	"reserved operand",
     68 	"breakpoint instruction",
     69 	"XFC instruction",
     70 	"system call ",
     71 	"arithmetic trap",
     72 	"asynchronous system trap",
     73 	"page table length fault",
     74 	"translation violation fault",
     75 	"trace trap",
     76 	"compatibility mode fault",
     77 	"access violation fault",
     78 	"",
     79 	"",
     80 	"KSP invalid",
     81 	"",
     82 	"kernel debugger trap"
     83 };
     84 int no_traps = 18;
     85 
     86 #define USERMODE_P(tf)   ((((tf)->tf_psl) & (PSL_U)) == PSL_U)
     87 
     88 void
     89 trap(struct trapframe *tf)
     90 {
     91 	u_int	sig = 0, type = tf->tf_trap, code = 0;
     92 	u_int	rv, addr;
     93 	bool trapsig = true;
     94 	const bool usermode = USERMODE_P(tf);
     95 	struct lwp * const l = curlwp;
     96 	struct proc * const p = l->l_proc;
     97 	struct pcb * const pcb = lwp_getpcb(l);
     98 	u_quad_t oticks = 0;
     99 	struct vmspace *vm;
    100 	struct vm_map *map;
    101 	vm_prot_t ftype;
    102 	void *onfault = pcb->pcb_onfault;
    103 
    104 	KASSERT(p != NULL);
    105 	curcpu()->ci_data.cpu_ntrap++;
    106 	if (usermode) {
    107 		type |= T_USER;
    108 		oticks = p->p_sticks;
    109 		l->l_md.md_utf = tf;
    110 	}
    111 
    112 	type &= ~(T_WRITE|T_PTEFETCH);
    113 
    114 
    115 #ifdef TRAPDEBUG
    116 if(tf->tf_trap==7) goto fram;
    117 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
    118 		tf->tf_trap, tf->tf_code, tf->tf_pc, tf->tf_psl);
    119 fram:
    120 #endif
    121 	switch (type) {
    122 
    123 	default:
    124 #ifdef DDB
    125 		kdb_trap(tf);
    126 #endif
    127 		panic("trap: type %x, code %x, pc %x, psl %x",
    128 		    (u_int)tf->tf_trap, (u_int)tf->tf_code,
    129 		    (u_int)tf->tf_pc, (u_int)tf->tf_psl);
    130 
    131 	case T_KSPNOTVAL:
    132 		panic("%d.%d (%s): KSP invalid %#x@%#x pcb %p fp %#x psl %#x)",
    133 		    p->p_pid, l->l_lid, l->l_name ? l->l_name : "??",
    134 		    mfpr(PR_KSP), (u_int)tf->tf_pc, pcb,
    135 		    (u_int)tf->tf_fp, (u_int)tf->tf_psl);
    136 
    137 	case T_TRANSFLT|T_USER:
    138 	case T_TRANSFLT:
    139 		/*
    140 		 * BUG! BUG! BUG! BUG! BUG!
    141 		 * Due to a hardware bug (at in least KA65x CPUs) a double
    142 		 * page table fetch trap will cause a translation fault
    143 		 * even if access in the SPT PTE entry specifies 'no access'.
    144 		 * In for example section 6.4.2 in VAX Architecture
    145 		 * Reference Manual it states that if a page both are invalid
    146 		 * and have no access set, a 'access violation fault' occurs.
    147 		 * Therefore, we must fall through here...
    148 		 */
    149 #ifdef nohwbug
    150 		panic("translation fault");
    151 #endif
    152 
    153 	case T_PTELEN|T_USER:	/* Page table length exceeded */
    154 	case T_ACCFLT|T_USER:
    155 		if (tf->tf_code < 0) { /* Check for kernel space */
    156 			sig = SIGSEGV;
    157 			code = SEGV_ACCERR;
    158 			break;
    159 		}
    160 
    161 	case T_PTELEN:
    162 #ifndef MULTIPROCESSOR
    163 		/*
    164 		 * If we referred to an address beyond the end of the system
    165 		 * page table, it may be due to a failed CAS
    166 		 * restartable-atomic-sequence.  If it is, restart it at the
    167 		 * beginning and restart.
    168 		 */
    169 		{
    170 			extern const uint8_t cas32_ras_start[], cas32_ras_end[];
    171 			if (tf->tf_code == CASMAGIC
    172 			    && tf->tf_pc >= (uintptr_t) cas32_ras_start
    173 			    && tf->tf_pc < (uintptr_t) cas32_ras_end) {
    174 				tf->tf_pc = (uintptr_t) cas32_ras_start;
    175 				trapsig = false;
    176 				break;
    177 			}
    178 		}
    179 		/* FALLTHROUGH */
    180 #endif
    181 	case T_ACCFLT:
    182 #ifdef TRAPDEBUG
    183 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
    184 			tf->tf_trap, tf->tf_code, tf->tf_pc, tf->tf_psl);
    185 #endif
    186 #ifdef DIAGNOSTIC
    187 		if (p == 0)
    188 			panic("trap: access fault: addr %lx code %lx",
    189 			    tf->tf_pc, tf->tf_code);
    190 		if (tf->tf_psl & PSL_IS)
    191 			panic("trap: pflt on IS");
    192 #endif
    193 
    194 		/*
    195 		 * Page tables are allocated in pmap_enter(). We get
    196 		 * info from below if it is a page table fault, but
    197 		 * UVM may want to map in pages without faults, so
    198 		 * because we must check for PTE pages anyway we don't
    199 		 * bother doing it here.
    200 		 */
    201 		addr = trunc_page(tf->tf_code);
    202 		if (!usermode && (tf->tf_code < 0)) {
    203 			vm = NULL;
    204 			map = kernel_map;
    205 
    206 		} else {
    207 			vm = p->p_vmspace;
    208 			map = &vm->vm_map;
    209 		}
    210 
    211 		if (tf->tf_trap & T_WRITE)
    212 			ftype = VM_PROT_WRITE;
    213 		else
    214 			ftype = VM_PROT_READ;
    215 
    216 		pcb->pcb_onfault = NULL;
    217 		rv = uvm_fault(map, addr, ftype);
    218 		pcb->pcb_onfault = onfault;
    219 		if (rv != 0) {
    220 			if (!usermode) {
    221 				if (onfault) {
    222 					pcb->pcb_onfault = NULL;
    223 					tf->tf_pc = (unsigned)onfault;
    224 					tf->tf_psl &= ~PSL_FPD;
    225 					tf->tf_r0 = rv;
    226 					return;
    227 				}
    228 				printf("r0=%08lx r1=%08lx r2=%08lx r3=%08lx\n",
    229 				    tf->tf_r0, tf->tf_r1, tf->tf_r2, tf->tf_r3);
    230 				printf("r4=%08lx r5=%08lx r6=%08lx r7=%08lx\n",
    231 				    tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7);
    232 				printf(
    233 				    "r8=%08lx r9=%08lx r10=%08lx r11=%08lx\n",
    234 				    tf->tf_r8, tf->tf_r9, tf->tf_r10,
    235 				    tf->tf_r11);
    236 				printf("ap=%08lx fp=%08lx sp=%08lx pc=%08lx\n",
    237 				    tf->tf_ap, tf->tf_fp, tf->tf_sp, tf->tf_pc);
    238 				panic("SEGV in kernel mode: pc %#lx addr %#lx",
    239 				    tf->tf_pc, tf->tf_code);
    240 			}
    241 			switch (rv) {
    242 			case ENOMEM:
    243 				printf("UVM: pid %d (%s), uid %d killed: "
    244 				       "out of swap\n",
    245 				       p->p_pid, p->p_comm,
    246 				       l->l_cred ?
    247 				       kauth_cred_geteuid(l->l_cred) : -1);
    248 				sig = SIGKILL;
    249 				code = SI_NOINFO;
    250 				break;
    251 			case EINVAL:
    252 				code = BUS_ADRERR;
    253 				sig = SIGBUS;
    254 				break;
    255 			case EACCES:
    256 				code = SEGV_ACCERR;
    257 				sig = SIGSEGV;
    258 				break;
    259 			default:
    260 				code = SEGV_MAPERR;
    261 				sig = SIGSEGV;
    262 				break;
    263 			}
    264 		} else {
    265 			trapsig = false;
    266 			if (map != kernel_map && addr > 0
    267 			    && (void *)addr >= vm->vm_maxsaddr)
    268 				uvm_grow(p, addr);
    269 		}
    270 		break;
    271 
    272 	case T_BPTFLT|T_USER:
    273 		sig = SIGTRAP;
    274 		code = TRAP_BRKPT;
    275 		break;
    276 	case T_TRCTRAP|T_USER:
    277 		sig = SIGTRAP;
    278 		code = TRAP_TRACE;
    279 		tf->tf_psl &= ~PSL_T;
    280 		break;
    281 
    282 	case T_PRIVINFLT|T_USER:
    283 		sig = SIGILL;
    284 		code = ILL_PRVOPC;
    285 		break;
    286 	case T_RESADFLT|T_USER:
    287 		sig = SIGILL;
    288 		code = ILL_ILLADR;
    289 		break;
    290 	case T_RESOPFLT|T_USER:
    291 		sig = SIGILL;
    292 		code = ILL_ILLOPC;
    293 		break;
    294 
    295 	case T_XFCFLT|T_USER:
    296 		sig = SIGEMT;
    297 		break;
    298 
    299 	case T_ARITHFLT|T_USER:
    300 		sig = SIGFPE;
    301 		switch (tf->tf_code) {
    302 		case ATRP_INTOVF: code = FPE_INTOVF; break;
    303 		case ATRP_INTDIV: code = FPE_INTDIV; break;
    304 		case ATRP_FLTOVF: code = FPE_FLTOVF; break;
    305 		case ATRP_FLTDIV: code = FPE_FLTDIV; break;
    306 		case ATRP_FLTUND: code = FPE_FLTUND; break;
    307 		case ATRP_DECOVF: code = FPE_INTOVF; break;
    308 		case ATRP_FLTSUB: code = FPE_FLTSUB; break;
    309 		case AFLT_FLTDIV: code = FPE_FLTDIV; break;
    310 		case AFLT_FLTUND: code = FPE_FLTUND; break;
    311 		case AFLT_FLTOVF: code = FPE_FLTOVF; break;
    312 		default:	  code = FPE_FLTINV; break;
    313 		}
    314 		break;
    315 
    316 	case T_ASTFLT|T_USER:
    317 		pcb->P0LR = (pcb->P0LR & ~AST_MASK) | AST_PCB;
    318 		mtpr(AST_NO,PR_ASTLVL);
    319 		trapsig = false;
    320 		break;
    321 
    322 #ifdef DDB
    323 	case T_BPTFLT: /* Kernel breakpoint */
    324 	case T_KDBTRAP:
    325 	case T_KDBTRAP|T_USER:
    326 	case T_TRCTRAP:
    327 		kdb_trap(tf);
    328 		return;
    329 #endif
    330 	}
    331 	if (trapsig) {
    332 		ksiginfo_t ksi;
    333 		if ((sig == SIGSEGV || sig == SIGILL)
    334 		    && cpu_printfataltraps
    335 		    && (p->p_slflag & PSL_TRACED) == 0
    336 		    && !sigismember(&p->p_sigctx.ps_sigcatch, sig))
    337 			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
    338 			       p->p_pid, l->l_lid, p->p_comm, sig, tf->tf_trap,
    339 			       tf->tf_code, tf->tf_pc, tf->tf_psl);
    340 		KSI_INIT_TRAP(&ksi);
    341 		ksi.ksi_signo = sig;
    342 		ksi.ksi_trap = tf->tf_trap;
    343 		ksi.ksi_addr = (void *)tf->tf_code;
    344 		ksi.ksi_code = code;
    345 
    346 		/*
    347 		 * Arithmetic exceptions can be of two kinds:
    348 		 * - traps (codes 1..7), where pc points to the
    349 		 *   next instruction to execute.
    350 		 * - faults (codes 8..10), where pc points to the
    351 		 *   faulting instruction.
    352 		 * In the latter case, we need to advance pc by ourselves
    353 		 * to prevent a signal loop.
    354 		 *
    355 		 * XXX this is gross -- miod
    356 		 */
    357 		if (type == (T_ARITHFLT | T_USER) && (tf->tf_code & 8))
    358 			tf->tf_pc = skip_opcode(tf->tf_pc);
    359 
    360 		trapsignal(l, &ksi);
    361 	}
    362 
    363 	if (!usermode)
    364 		return;
    365 
    366 	userret(l, tf, oticks);
    367 }
    368 
    369 void
    370 setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
    371 {
    372 	struct trapframe * const tf = l->l_md.md_utf;
    373 
    374 	memset(tf, 0, sizeof(*tf));
    375 
    376 	tf->tf_pc = pack->ep_entry + 2;
    377 	tf->tf_sp = stack;
    378 	tf->tf_r6 = stack;				/* for ELF */
    379 	tf->tf_r7 = 0;				/* for ELF */
    380 	tf->tf_r8 = 0;				/* for ELF */
    381 	tf->tf_r9 = l->l_proc->p_psstrp;		/* for ELF */
    382 	tf->tf_psl = PSL_U|PSL_PREVU;
    383 }
    384 
    385 
    386 /*
    387  * Start a new LWP
    388  */
    389 void
    390 startlwp(void *arg)
    391 {
    392 	ucontext_t * const uc = arg;
    393 	lwp_t * const l = curlwp;
    394 	int error __diagused;
    395 
    396 	error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
    397 	KASSERT(error == 0);
    398 
    399 	kmem_free(uc, sizeof(ucontext_t));
    400 	/* XXX - profiling spoiled here */
    401 	userret(l, l->l_md.md_utf, l->l_proc->p_sticks);
    402 }
    403