1 /* $NetBSD: trap.c,v 1.56 2000/06/29 07:14:34 mrg 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed at Ludd, University of Lule}. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* All bugs are subject to removal without further notice */ 34 35 #include "opt_ddb.h" 36 #include "opt_ktrace.h" 37 #include "opt_multiprocessor.h" 38 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <sys/proc.h> 42 #include <sys/user.h> 43 #include <sys/syscall.h> 44 #include <sys/systm.h> 45 #include <sys/signalvar.h> 46 #include <sys/exec.h> 47 48 #include <uvm/uvm_extern.h> 49 50 #include <machine/mtpr.h> 51 #include <machine/pte.h> 52 #include <machine/pcb.h> 53 #include <machine/trap.h> 54 #include <machine/pmap.h> 55 #include <machine/cpu.h> 56 57 #ifdef DDB 58 #include <machine/db_machdep.h> 59 #endif 60 #include <kern/syscalls.c> 61 #ifdef KTRACE 62 #include <sys/ktrace.h> 63 #endif 64 65 #ifdef TRAPDEBUG 66 volatile int startsysc = 0, faultdebug = 0; 67 #endif 68 69 static __inline void userret __P((struct proc *, struct trapframe *, u_quad_t)); 70 71 void arithflt __P((struct trapframe *)); 72 void syscall __P((struct trapframe *)); 73 74 char *traptypes[]={ 75 "reserved addressing", 76 "privileged instruction", 77 "reserved operand", 78 "breakpoint instruction", 79 "XFC instruction", 80 "system call ", 81 "arithmetic trap", 82 "asynchronous system trap", 83 "page table length fault", 84 "translation violation fault", 85 "trace trap", 86 "compatibility mode fault", 87 "access violation fault", 88 "", 89 "", 90 "KSP invalid", 91 "", 92 "kernel debugger trap" 93 }; 94 int no_traps = 18; 95 96 #define USERMODE(framep) ((((framep)->psl) & (PSL_U)) == PSL_U) 97 #define FAULTCHK \ 98 if (p->p_addr->u_pcb.iftrap) { \ 99 frame->pc = (unsigned)p->p_addr->u_pcb.iftrap; \ 100 frame->psl &= ~PSL_FPD; \ 101 frame->r0 = EFAULT;/* for copyin/out */ \ 102 frame->r1 = -1; /* for fetch/store */ \ 103 return; \ 104 } 105 106 /* 107 * userret: 108 * 109 * Common code used by various execption handlers to 110 * return to usermode. 111 */ 112 static __inline void 113 userret(p, frame, oticks) 114 struct proc *p; 115 struct trapframe *frame; 116 u_quad_t oticks; 117 { 118 int sig; 119 120 /* Take pending signals. */ 121 while ((sig = CURSIG(p)) != 0) 122 postsig(sig); 123 p->p_priority = p->p_usrpri; 124 if (curcpu()->ci_want_resched) { 125 /* 126 * We are being preempted. 127 */ 128 preempt(NULL); 129 while ((sig = CURSIG(p)) != 0) 130 postsig(sig); 131 } 132 133 /* 134 * If profiling, charge system time to the trapped pc. 135 */ 136 if (p->p_flag & P_PROFIL) { 137 extern int psratio; 138 139 addupc_task(p, frame->pc, 140 (int)(p->p_sticks - oticks) * psratio); 141 } 142 curcpu()->ci_schedstate.spc_curpriority = p->p_priority; 143 } 144 145 void 146 arithflt(frame) 147 struct trapframe *frame; 148 { 149 u_int sig = 0, type = frame->trap, trapsig = 1; 150 u_int rv, addr, umode; 151 struct proc *p = curproc; 152 u_quad_t oticks = 0; 153 vm_map_t map; 154 vm_prot_t ftype; 155 156 uvmexp.traps++; 157 if ((umode = USERMODE(frame))) { 158 type |= T_USER; 159 oticks = p->p_sticks; 160 p->p_addr->u_pcb.framep = frame; 161 } 162 163 type&=~(T_WRITE|T_PTEFETCH); 164 165 166 #ifdef TRAPDEBUG 167 if(frame->trap==7) goto fram; 168 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n", 169 frame->trap, frame->code, frame->pc, frame->psl); 170 fram: 171 #endif 172 switch(type){ 173 174 default: 175 #ifdef DDB 176 kdb_trap(frame); 177 #endif 178 printf("Trap: type %x, code %x, pc %x, psl %x\n", 179 (u_int)frame->trap, (u_int)frame->code, 180 (u_int)frame->pc, (u_int)frame->psl); 181 panic("trap"); 182 183 case T_KSPNOTVAL: 184 panic("kernel stack invalid"); 185 186 case T_TRANSFLT|T_USER: 187 case T_TRANSFLT: 188 /* 189 * BUG! BUG! BUG! BUG! BUG! 190 * Due to a hardware bug (at in least KA65x CPUs) a double 191 * page table fetch trap will cause a translation fault 192 * even if access in the SPT PTE entry specifies 'no access'. 193 * In for example section 6.4.2 in VAX Architecture 194 * Reference Manual it states that if a page both are invalid 195 * and have no access set, a 'access violation fault' occurs. 196 * Therefore, we must fall through here... 197 */ 198 #ifdef nohwbug 199 panic("translation fault"); 200 #endif 201 case T_ACCFLT|T_USER: 202 if (frame->code < 0) { /* Check for kernel space */ 203 sig = SIGSEGV; 204 break; 205 } 206 case T_ACCFLT: 207 #ifdef TRAPDEBUG 208 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", 209 frame->trap, frame->code, frame->pc, frame->psl); 210 #endif 211 #ifdef DIAGNOSTIC 212 if (p == 0) 213 panic("trap: access fault: addr %lx code %lx", 214 frame->pc, frame->code); 215 #endif 216 217 /* 218 * Page tables are allocated in pmap_enter(). We get 219 * info from below if it is a page table fault, but 220 * UVM may want to map in pages without faults, so 221 * because we must check for PTE pages anyway we don't 222 * bother doing it here. 223 */ 224 addr = trunc_page(frame->code); 225 if ((umode == 0) && (frame->code < 0)) 226 map = kernel_map; 227 else 228 map = &p->p_vmspace->vm_map; 229 230 if (frame->trap & T_WRITE) 231 ftype = VM_PROT_WRITE|VM_PROT_READ; 232 else 233 ftype = VM_PROT_READ; 234 235 rv = uvm_fault(map, addr, 0, ftype); 236 if (rv != KERN_SUCCESS) { 237 if (umode == 0) { 238 FAULTCHK; 239 panic("Segv in kernel mode: pc %x addr %x", 240 (u_int)frame->pc, (u_int)frame->code); 241 } 242 if (rv == KERN_RESOURCE_SHORTAGE) { 243 printf("UVM: pid %d (%s), uid %d killed: " 244 "out of swap\n", 245 p->p_pid, p->p_comm, 246 p->p_cred && p->p_ucred ? 247 p->p_ucred->cr_uid : -1); 248 sig = SIGKILL; 249 } else { 250 sig = SIGSEGV; 251 } 252 } else 253 trapsig = 0; 254 break; 255 256 case T_PTELEN: 257 if (p && p->p_addr) 258 FAULTCHK; 259 panic("ptelen fault in system space: addr %lx pc %lx", 260 frame->code, frame->pc); 261 262 case T_PTELEN|T_USER: /* Page table length exceeded */ 263 sig = SIGSEGV; 264 break; 265 266 case T_BPTFLT|T_USER: 267 case T_TRCTRAP|T_USER: 268 sig = SIGTRAP; 269 frame->psl &= ~PSL_T; 270 break; 271 272 case T_PRIVINFLT|T_USER: 273 case T_RESADFLT|T_USER: 274 case T_RESOPFLT|T_USER: 275 sig = SIGILL; 276 break; 277 278 case T_XFCFLT|T_USER: 279 sig = SIGEMT; 280 break; 281 282 case T_ARITHFLT|T_USER: 283 sig = SIGFPE; 284 break; 285 286 case T_ASTFLT|T_USER: 287 mtpr(AST_NO,PR_ASTLVL); 288 trapsig = 0; 289 break; 290 291 #ifdef DDB 292 case T_BPTFLT: /* Kernel breakpoint */ 293 case T_KDBTRAP: 294 case T_KDBTRAP|T_USER: 295 case T_TRCTRAP: 296 kdb_trap(frame); 297 return; 298 #endif 299 } 300 301 if (trapsig) 302 trapsignal(p, sig, frame->code); 303 304 if (umode == 0) 305 return; 306 307 userret(p, frame, oticks); 308 } 309 310 void 311 setregs(p, pack, stack) 312 struct proc *p; 313 struct exec_package *pack; 314 u_long stack; 315 { 316 struct trapframe *exptr; 317 318 exptr = p->p_addr->u_pcb.framep; 319 exptr->pc = pack->ep_entry + 2; 320 exptr->sp = stack; 321 exptr->r6 = stack; /* for ELF */ 322 exptr->r7 = 0; /* for ELF */ 323 exptr->r8 = 0; /* for ELF */ 324 exptr->r9 = (u_long) PS_STRINGS; /* for ELF */ 325 } 326 327 void 328 syscall(frame) 329 struct trapframe *frame; 330 { 331 struct sysent *callp; 332 u_quad_t oticks; 333 int nsys; 334 int err, rval[2], args[8]; 335 struct trapframe *exptr; 336 struct proc *p = curproc; 337 338 #ifdef TRAPDEBUG 339 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n", 340 syscallnames[frame->code], frame->pc, frame->psl,frame->sp, 341 curproc->p_pid,frame); 342 #endif 343 uvmexp.syscalls++; 344 345 exptr = p->p_addr->u_pcb.framep = frame; 346 callp = p->p_emul->e_sysent; 347 nsys = p->p_emul->e_nsysent; 348 oticks = p->p_sticks; 349 350 if(frame->code == SYS___syscall){ 351 int g = *(int *)(frame->ap); 352 353 frame->code = *(int *)(frame->ap + 4); 354 frame->ap += 8; 355 *(int *)(frame->ap) = g - 2; 356 } 357 358 if(frame->code < 0 || frame->code >= nsys) 359 callp += p->p_emul->e_nosys; 360 else 361 callp += frame->code; 362 363 rval[0] = 0; 364 rval[1] = frame->r1; 365 if(callp->sy_narg) { 366 err = copyin((char*)frame->ap + 4, args, callp->sy_argsize); 367 if (err) { 368 #ifdef KTRACE 369 if (KTRPOINT(p, KTR_SYSCALL)) 370 ktrsyscall(p, frame->code, 371 callp->sy_argsize, args); 372 #endif 373 goto bad; 374 } 375 } 376 #ifdef KTRACE 377 if (KTRPOINT(p, KTR_SYSCALL)) 378 ktrsyscall(p, frame->code, callp->sy_argsize, args); 379 #endif 380 err = (*callp->sy_call)(curproc, args, rval); 381 exptr = curproc->p_addr->u_pcb.framep; 382 383 #ifdef TRAPDEBUG 384 if(startsysc) 385 printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, v{rde %d r0 %d, r1 %d, frame %p\n", 386 syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp, 387 p->p_pid,err,rval[0],rval[1],exptr); /* } */ 388 #endif 389 390 bad: 391 switch (err) { 392 case 0: 393 exptr->r1 = rval[1]; 394 exptr->r0 = rval[0]; 395 exptr->psl &= ~PSL_C; 396 break; 397 398 case EJUSTRETURN: 399 return; 400 401 case ERESTART: 402 exptr->pc -= (exptr->code > 63 ? 4 : 2); 403 break; 404 405 default: 406 exptr->r0 = err; 407 exptr->psl |= PSL_C; 408 break; 409 } 410 411 userret(p, frame, oticks); 412 413 #ifdef KTRACE 414 if (KTRPOINT(p, KTR_SYSRET)) 415 ktrsysret(p, frame->code, err, rval[0]); 416 #endif 417 } 418 419 void 420 child_return(void *arg) 421 { 422 struct proc *p = arg; 423 424 userret(p, p->p_addr->u_pcb.framep, 0); 425 426 #ifdef KTRACE 427 if (KTRPOINT(p, KTR_SYSRET)) 428 ktrsysret(p, SYS_fork, 0, 0); 429 #endif 430 } 431 432