1 /* $NetBSD: trap.c,v 1.60 2000/12/31 19:41:41 matt 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 (struct proc *, struct trapframe *, u_quad_t); 70 71 void trap (struct trapframe *); 72 void syscall (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(struct proc *p, struct trapframe *frame, u_quad_t oticks) 114 { 115 int sig; 116 117 /* Take pending signals. */ 118 while ((sig = CURSIG(p)) != 0) 119 postsig(sig); 120 p->p_priority = p->p_usrpri; 121 if (curcpu()->ci_want_resched) { 122 /* 123 * We are being preempted. 124 */ 125 preempt(NULL); 126 while ((sig = CURSIG(p)) != 0) 127 postsig(sig); 128 } 129 130 /* 131 * If profiling, charge system time to the trapped pc. 132 */ 133 if (p->p_flag & P_PROFIL) { 134 extern int psratio; 135 136 addupc_task(p, frame->pc, 137 (int)(p->p_sticks - oticks) * psratio); 138 } 139 curcpu()->ci_schedstate.spc_curpriority = p->p_priority; 140 } 141 142 void 143 trap(struct trapframe *frame) 144 { 145 u_int sig = 0, type = frame->trap, trapsig = 1; 146 u_int rv, addr, umode; 147 struct proc *p = curproc; 148 u_quad_t oticks = 0; 149 vm_map_t map; 150 vm_prot_t ftype; 151 152 uvmexp.traps++; 153 if ((umode = USERMODE(frame))) { 154 type |= T_USER; 155 oticks = p->p_sticks; 156 p->p_addr->u_pcb.framep = frame; 157 } 158 159 type&=~(T_WRITE|T_PTEFETCH); 160 161 162 #ifdef TRAPDEBUG 163 if(frame->trap==7) goto fram; 164 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n", 165 frame->trap, frame->code, frame->pc, frame->psl); 166 fram: 167 #endif 168 switch(type){ 169 170 default: 171 #ifdef DDB 172 kdb_trap(frame); 173 #endif 174 printf("Trap: type %x, code %x, pc %x, psl %x\n", 175 (u_int)frame->trap, (u_int)frame->code, 176 (u_int)frame->pc, (u_int)frame->psl); 177 panic("trap"); 178 179 case T_KSPNOTVAL: 180 panic("kernel stack invalid"); 181 182 case T_TRANSFLT|T_USER: 183 case T_TRANSFLT: 184 /* 185 * BUG! BUG! BUG! BUG! BUG! 186 * Due to a hardware bug (at in least KA65x CPUs) a double 187 * page table fetch trap will cause a translation fault 188 * even if access in the SPT PTE entry specifies 'no access'. 189 * In for example section 6.4.2 in VAX Architecture 190 * Reference Manual it states that if a page both are invalid 191 * and have no access set, a 'access violation fault' occurs. 192 * Therefore, we must fall through here... 193 */ 194 #ifdef nohwbug 195 panic("translation fault"); 196 #endif 197 case T_ACCFLT|T_USER: 198 if (frame->code < 0) { /* Check for kernel space */ 199 sig = SIGSEGV; 200 break; 201 } 202 case T_ACCFLT: 203 #ifdef TRAPDEBUG 204 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", 205 frame->trap, frame->code, frame->pc, frame->psl); 206 #endif 207 #ifdef DIAGNOSTIC 208 if (p == 0) 209 panic("trap: access fault: addr %lx code %lx", 210 frame->pc, frame->code); 211 #endif 212 213 /* 214 * Page tables are allocated in pmap_enter(). We get 215 * info from below if it is a page table fault, but 216 * UVM may want to map in pages without faults, so 217 * because we must check for PTE pages anyway we don't 218 * bother doing it here. 219 */ 220 addr = trunc_page(frame->code); 221 if ((umode == 0) && (frame->code < 0)) 222 map = kernel_map; 223 else 224 map = &p->p_vmspace->vm_map; 225 226 if (frame->trap & T_WRITE) 227 ftype = VM_PROT_WRITE|VM_PROT_READ; 228 else 229 ftype = VM_PROT_READ; 230 231 rv = uvm_fault(map, addr, 0, ftype); 232 if (rv != KERN_SUCCESS) { 233 if (umode == 0) { 234 FAULTCHK; 235 panic("Segv in kernel mode: pc %x addr %x", 236 (u_int)frame->pc, (u_int)frame->code); 237 } 238 if (rv == KERN_RESOURCE_SHORTAGE) { 239 printf("UVM: pid %d (%s), uid %d killed: " 240 "out of swap\n", 241 p->p_pid, p->p_comm, 242 p->p_cred && p->p_ucred ? 243 p->p_ucred->cr_uid : -1); 244 sig = SIGKILL; 245 } else { 246 sig = SIGSEGV; 247 } 248 } else 249 trapsig = 0; 250 break; 251 252 case T_PTELEN: 253 if (p && p->p_addr) 254 FAULTCHK; 255 panic("ptelen fault in system space: addr %lx pc %lx", 256 frame->code, frame->pc); 257 258 case T_PTELEN|T_USER: /* Page table length exceeded */ 259 sig = SIGSEGV; 260 break; 261 262 case T_BPTFLT|T_USER: 263 case T_TRCTRAP|T_USER: 264 sig = SIGTRAP; 265 frame->psl &= ~PSL_T; 266 break; 267 268 case T_PRIVINFLT|T_USER: 269 case T_RESADFLT|T_USER: 270 case T_RESOPFLT|T_USER: 271 sig = SIGILL; 272 break; 273 274 case T_XFCFLT|T_USER: 275 sig = SIGEMT; 276 break; 277 278 case T_ARITHFLT|T_USER: 279 sig = SIGFPE; 280 break; 281 282 case T_ASTFLT|T_USER: 283 mtpr(AST_NO,PR_ASTLVL); 284 trapsig = 0; 285 break; 286 287 #ifdef DDB 288 case T_BPTFLT: /* Kernel breakpoint */ 289 case T_KDBTRAP: 290 case T_KDBTRAP|T_USER: 291 case T_TRCTRAP: 292 kdb_trap(frame); 293 return; 294 #endif 295 } 296 if (trapsig) { 297 if (sig == SIGSEGV || sig == SIGILL) 298 printf("pid %d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n", 299 p->p_pid, p->p_comm, sig, frame->trap, 300 frame->code, frame->pc, frame->psl); 301 trapsignal(p, sig, frame->code); 302 } 303 304 if (umode == 0) 305 return; 306 307 userret(p, frame, oticks); 308 } 309 310 void 311 setregs(struct proc *p, struct exec_package *pack, u_long stack) 312 { 313 struct trapframe *exptr; 314 315 exptr = p->p_addr->u_pcb.framep; 316 exptr->pc = pack->ep_entry + 2; 317 exptr->sp = stack; 318 exptr->r6 = stack; /* for ELF */ 319 exptr->r7 = 0; /* for ELF */ 320 exptr->r8 = 0; /* for ELF */ 321 exptr->r9 = (u_long) PS_STRINGS; /* for ELF */ 322 } 323 324 void 325 syscall(struct trapframe *frame) 326 { 327 const struct sysent *callp; 328 u_quad_t oticks; 329 int nsys; 330 int err, rval[2], args[8]; 331 struct trapframe *exptr; 332 struct proc *p = curproc; 333 334 #ifdef TRAPDEBUG 335 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n", 336 syscallnames[frame->code], frame->pc, frame->psl,frame->sp, 337 curproc->p_pid,frame); 338 #endif 339 uvmexp.syscalls++; 340 341 exptr = p->p_addr->u_pcb.framep = frame; 342 callp = p->p_emul->e_sysent; 343 nsys = p->p_emul->e_nsysent; 344 oticks = p->p_sticks; 345 346 if (frame->code == SYS___syscall) { 347 int g = *(int *)(frame->ap); 348 349 frame->code = *(int *)(frame->ap + 4); 350 frame->ap += 8; 351 *(int *)(frame->ap) = g - 2; 352 } 353 354 if ((unsigned long) frame->code >= nsys) 355 callp += p->p_emul->e_nosys; 356 else 357 callp += frame->code; 358 359 rval[0] = 0; 360 rval[1] = frame->r1; 361 if (callp->sy_narg) { 362 err = copyin((char*)frame->ap + 4, args, callp->sy_argsize); 363 if (err) { 364 #ifdef KTRACE 365 if (KTRPOINT(p, KTR_SYSCALL)) 366 ktrsyscall(p, frame->code, 367 callp->sy_argsize, args); 368 #endif 369 goto bad; 370 } 371 } 372 #ifdef KTRACE 373 if (KTRPOINT(p, KTR_SYSCALL)) 374 ktrsyscall(p, frame->code, callp->sy_argsize, args); 375 #endif 376 err = (*callp->sy_call)(curproc, args, rval); 377 exptr = curproc->p_addr->u_pcb.framep; 378 379 #ifdef TRAPDEBUG 380 if(startsysc) 381 printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, err %d r0 %d, r1 %d, frame %p\n", 382 syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp, 383 p->p_pid,err,rval[0],rval[1],exptr); /* } */ 384 #endif 385 386 bad: 387 switch (err) { 388 case 0: 389 exptr->r1 = rval[1]; 390 exptr->r0 = rval[0]; 391 exptr->psl &= ~PSL_C; 392 break; 393 394 case EJUSTRETURN: 395 return; 396 397 case ERESTART: 398 exptr->pc -= (exptr->code > 63 ? 4 : 2); 399 break; 400 401 default: 402 exptr->r0 = err; 403 exptr->psl |= PSL_C; 404 break; 405 } 406 407 userret(p, frame, oticks); 408 409 #ifdef KTRACE 410 if (KTRPOINT(p, KTR_SYSRET)) 411 ktrsysret(p, frame->code, err, rval[0]); 412 #endif 413 } 414 415 void 416 child_return(void *arg) 417 { 418 struct proc *p = arg; 419 420 userret(p, p->p_addr->u_pcb.framep, 0); 421 422 #ifdef KTRACE 423 if (KTRPOINT(p, KTR_SYSRET)) 424 ktrsysret(p, SYS_fork, 0, 0); 425 #endif 426 } 427