trap.c revision 1.44
1/* $OpenBSD: trap.c,v 1.44 2002/07/21 11:47:39 mickey Exp $ */ 2 3/* 4 * Copyright (c) 1998-2001 Michael Shalayeff 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 by Michael Shalayeff. 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/* #define TRAPDEBUG */ 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/syscall.h> 38#include <sys/ktrace.h> 39#include <sys/proc.h> 40#include <sys/signalvar.h> 41#include <sys/user.h> 42 43#include <net/netisr.h> 44 45#include "systrace.h" 46#include <dev/systrace.h> 47 48#include <uvm/uvm.h> 49 50#include <machine/autoconf.h> 51 52#ifdef DDB 53#include <machine/db_machdep.h> 54#ifdef TRAPDEBUG 55#include <ddb/db_output.h> 56#endif 57#endif 58 59const char *trap_type[] = { 60 "invalid", 61 "HPMC", 62 "power failure", 63 "recovery counter", 64 "external interrupt", 65 "LPMC", 66 "ITLB miss fault", 67 "instruction protection", 68 "Illegal instruction", 69 "break instruction", 70 "privileged operation", 71 "privileged register", 72 "overflow", 73 "conditional", 74 "assist exception", 75 "DTLB miss", 76 "ITLB non-access miss", 77 "DTLB non-access miss", 78 "data protection/rights/alignment", 79 "data break", 80 "TLB dirty", 81 "page reference", 82 "assist emulation", 83 "higher-priv transfer", 84 "lower-priv transfer", 85 "taken branch", 86 "data access rights", 87 "data protection", 88 "unaligned data ref", 89}; 90int trap_types = sizeof(trap_type)/sizeof(trap_type[0]); 91 92int want_resched, astpending; 93 94void syscall(struct trapframe *frame, int *args); 95 96static __inline void 97userret (struct proc *p, register_t pc, u_quad_t oticks) 98{ 99 int sig; 100 101 /* take pending signals */ 102 while ((sig = CURSIG(p)) != 0) 103 postsig(sig); 104 105 p->p_priority = p->p_usrpri; 106 if (want_resched) { 107 /* 108 * We're being preempted. 109 */ 110 preempt(NULL); 111 while ((sig = CURSIG(p)) != 0) 112 postsig(sig); 113 } 114 115 /* 116 * If profiling, charge recent system time to the trapped pc. 117 */ 118 if (p->p_flag & P_PROFIL) { 119 extern int psratio; 120 121 addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio); 122 } 123 124 curpriority = p->p_priority; 125} 126 127void 128trap(type, frame) 129 int type; 130 struct trapframe *frame; 131{ 132 extern u_int32_t sir; 133 struct proc *p = curproc; 134 struct pcb *pcbp; 135 vaddr_t va; 136 struct vm_map *map; 137 struct vmspace *vm; 138 register vm_prot_t vftype; 139 register pa_space_t space; 140 union sigval sv; 141 u_int opcode; 142 int ret, s, si, trapnum; 143 const char *tts; 144 145 trapnum = type & ~T_USER; 146 opcode = frame->tf_iir; 147 if (trapnum == T_ITLBMISS || trapnum == T_ITLBMISSNA) { 148 va = frame->tf_iioq_head; 149 space = frame->tf_iisq_head; 150 vftype = VM_PROT_EXECUTE; 151 } else { 152 va = frame->tf_ior; 153 space = frame->tf_isr; 154 vftype = inst_store(opcode) ? VM_PROT_WRITE : VM_PROT_READ; 155 } 156 157 if (frame->tf_flags & TFF_LAST) 158 p->p_md.md_regs = frame; 159 160#ifdef TRAPDEBUG 161 if (trapnum > trap_types) 162 tts = "reserved"; 163 else 164 tts = trap_type[trapnum]; 165 166 if (trapnum != T_INTERRUPT && trapnum != T_IBREAK) 167 db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n", 168 type, tts, space, va, frame->tf_iisq_head, 169 frame->tf_iioq_head, frame->tf_flags, frame); 170 else if (trapnum == T_IBREAK) 171 db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n", 172 break5(opcode), break13(opcode), 173 frame->tf_iisq_head, frame->tf_iioq_head, frame); 174 175 { 176 extern int etext; 177 if (frame < (struct trapframe *)&etext) { 178 printf("trap: bogus frame ptr %p\n", frame); 179 goto dead_end; 180 } 181 } 182#endif 183 switch (type) { 184 case T_NONEXIST: 185 case T_NONEXIST|T_USER: 186#ifndef DDB 187 /* we've got screwed up by the central scrutinizer */ 188 panic ("trap: elvis has just left the building!"); 189 break; 190#else 191 goto dead_end; 192#endif 193 case T_RECOVERY: 194 case T_RECOVERY|T_USER: 195#ifndef DDB 196 /* XXX will implement later */ 197 printf ("trap: handicapped"); 198 break; 199#else 200 goto dead_end; 201#endif 202 203#ifdef DIAGNOSTIC 204 case T_EXCEPTION: 205 panic("FPU/SFU emulation botch"); 206 207 /* these just can't happen ever */ 208 case T_PRIV_OP: 209 case T_PRIV_REG: 210 /* these just can't make it to the trap() ever */ 211 case T_HPMC: case T_HPMC | T_USER: 212 case T_EMULATION: case T_EMULATION | T_USER: 213#endif 214 case T_IBREAK: 215 case T_DATALIGN: 216 case T_DBREAK: 217 dead_end: 218#ifdef DDB 219 if (kdb_trap (type, va, frame)) { 220 if (type == T_IBREAK) { 221 /* skip break instruction */ 222 frame->tf_iioq_head = frame->tf_iioq_tail; 223 frame->tf_iioq_tail += 4; 224 } 225 return; 226 } 227#else 228 if (type == T_DATALIGN) 229 panic ("trap: %s at 0x%x", tts, va); 230 else 231 panic ("trap: no debugger for \"%s\" (%d)", tts, type); 232#endif 233 break; 234 235 case T_IBREAK | T_USER: 236 case T_DBREAK | T_USER: 237 /* pass to user debugger */ 238 break; 239 240 case T_EXCEPTION | T_USER: /* co-proc assist trap */ 241 sv.sival_int = va; 242 trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTINV, sv); 243 break; 244 245 case T_OVERFLOW | T_USER: 246 sv.sival_int = va; 247 trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 248 break; 249 250 case T_CONDITION | T_USER: 251 break; 252 253 case T_ILLEGAL | T_USER: 254 sv.sival_int = va; 255 trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 256 break; 257 258 case T_PRIV_OP | T_USER: 259 sv.sival_int = va; 260 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 261 break; 262 263 case T_PRIV_REG | T_USER: 264 sv.sival_int = va; 265 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 266 break; 267 268 /* these should never got here */ 269 case T_HIGHERPL | T_USER: 270 case T_LOWERPL | T_USER: 271 sv.sival_int = va; 272 trapsignal(p, SIGSEGV, type &~ T_USER, SEGV_ACCERR, sv); 273 break; 274 275 case T_IPROT | T_USER: 276 case T_DPROT | T_USER: 277 sv.sival_int = va; 278 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 279 break; 280 281 case T_DATACC: case T_USER | T_DATACC: 282 case T_ITLBMISS: case T_USER | T_ITLBMISS: 283 case T_DTLBMISS: case T_USER | T_DTLBMISS: 284 case T_ITLBMISSNA: case T_USER | T_ITLBMISSNA: 285 case T_DTLBMISSNA: case T_USER | T_DTLBMISSNA: 286 case T_TLB_DIRTY: case T_USER | T_TLB_DIRTY: 287 va = hppa_trunc_page(va); 288 vm = p->p_vmspace; 289 290 if (!vm) { 291#ifdef TRAPDEBUG 292 printf("trap: no vm, p=%p\n", p); 293#endif 294 goto dead_end; 295 } 296 297 /* 298 * it could be a kernel map for exec_map faults 299 */ 300 if (!(type & T_USER) && space == HPPA_SID_KERNEL) 301 map = kernel_map; 302 else 303 map = &vm->vm_map; 304 305 if (map->pmap->pm_space != space) { 306#ifdef TRAPDEBUG 307 printf("trap: space missmatch %d != %d\n", 308 space, map->pmap->pm_space); 309#endif 310 /* actually dump the user, crap the kernel */ 311 goto dead_end; 312 } 313 314#ifdef TRAPDEBUG 315 if (space == -1) { 316 extern int pmapdebug; 317 pmapdebug = 0xffffff; 318 } 319#endif 320 321 ret = uvm_fault(map, va, 0, vftype); 322 323#ifdef TRAPDEBUG 324 if (space == -1) { 325 extern int pmapdebug; 326 pmapdebug = 0; 327 } 328 329 printf("uvm_fault(%p, %x, %d, %d)=%d\n", 330 map, va, 0, vftype, ret); 331#endif 332 333 /* 334 * If this was a stack access we keep track of the maximum 335 * accessed stack size. Also, if uvm_fault gets a protection 336 * failure it is due to accessing the stack region outside 337 * the current limit and we need to reflect that as an access 338 * error. 339 */ 340 if (va >= (vaddr_t)vm->vm_maxsaddr + vm->vm_ssize) { 341 if (ret == 0) { 342 vsize_t nss = btoc(va - USRSTACK + NBPG); 343 if (nss > vm->vm_ssize) 344 vm->vm_ssize = nss; 345 } else if (ret == EACCES) 346 ret = EFAULT; 347 } 348 349 if (ret != 0) { 350 if (type & T_USER) { 351 sv.sival_int = frame->tf_ior; 352 trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 353 } else { 354 if (p && p->p_addr->u_pcb.pcb_onfault) { 355 pcbp = &p->p_addr->u_pcb; 356 frame->tf_iioq_tail = 4 + 357 (frame->tf_iioq_head = 358 pcbp->pcb_onfault); 359 break; 360 } 361#if 0 362if (kdb_trap (type, va, frame)) 363 return; 364#else 365 panic("trap: uvm_fault(%p, %x, %d, %d): %d", 366 map, va, 0, vftype, ret); 367#endif 368 } 369 } 370 break; 371 372 case T_DATALIGN | T_USER: 373 sv.sival_int = va; 374 trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 375 break; 376 377 case T_INTERRUPT: 378 case T_INTERRUPT|T_USER: 379 frame->tf_flags |= TFF_INTR; 380 cpu_intr(frame); 381#if 0 382if (kdb_trap (type, va, frame)) 383return; 384#endif 385 /* FALLTHROUGH */ 386 case T_LOWERPL: 387 __asm __volatile ( 388 "ldcws 0(%1), %0" : "=&r" (si) : "r" (&sir) : "memory"); 389 if (si & SIR_CLOCK) { 390 s = splsoftclock(); 391 softclock(); 392 splx(s); 393 } 394 395 if (si & SIR_NET) { 396 register int ni; 397 /* use atomic "load & clear" */ 398 __asm __volatile ( 399 "ldcws 0(%1), %0" 400 : "=&r" (ni) : "r" (&netisr) : "memory"); 401 s = splnet(); 402#define DONETISR(m,c) if (ni & (1 << (m))) c() 403#include <net/netisr_dispatch.h> 404 splx(s); 405 } 406 break; 407 408 case T_DPROT: 409 case T_IPROT: 410 case T_OVERFLOW: 411 case T_CONDITION: 412 case T_ILLEGAL: 413 case T_HIGHERPL: 414 case T_TAKENBR: 415 case T_POWERFAIL: 416 case T_LPMC: 417 case T_PAGEREF: 418 case T_DATAPID: case T_DATAPID | T_USER: 419 if (0 /* T-chip */) { 420 break; 421 } 422 /* FALLTHROUGH to unimplemented */ 423 default: 424#if 0 425if (kdb_trap (type, va, frame)) 426 return; 427#endif 428 panic ("trap: unimplemented \'%s\' (%d)", tts, type); 429 } 430 431 if (type & T_USER) 432 userret(p, p->p_md.md_regs->tf_iioq_head, 0); 433} 434 435void 436child_return(arg) 437 void *arg; 438{ 439 struct proc *p = (struct proc *)arg; 440 userret(p, p->p_md.md_regs->tf_iioq_head, 0); 441#ifdef KTRACE 442 if (KTRPOINT(p, KTR_SYSRET)) 443 ktrsysret(p, SYS_fork, 0, 0); 444#endif 445} 446 447/* 448 * call actual syscall routine 449 * from the low-level syscall handler: 450 * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto 451 * our stack, this wins compared to copyin just needed amount anyway 452 * - register args are copied onto stack too 453 */ 454void 455syscall(frame, args) 456 struct trapframe *frame; 457 int *args; 458{ 459 register struct proc *p; 460 register const struct sysent *callp; 461 int nsys, code, argsize, error; 462 int rval[2]; 463 464 uvmexp.syscalls++; 465 466 if (!USERMODE(frame->tf_iioq_head)) 467 panic("syscall"); 468 469 p = curproc; 470 p->p_md.md_regs = frame; 471 nsys = p->p_emul->e_nsysent; 472 callp = p->p_emul->e_sysent; 473 code = frame->tf_t1; 474 switch (code) { 475 case SYS_syscall: 476 code = *args; 477 args += 1; 478 break; 479 case SYS___syscall: 480 if (callp != sysent) 481 break; 482 code = *args; 483 args += 2; 484 } 485 486 if (code < 0 || code >= nsys) 487 callp += p->p_emul->e_nosys; /* bad syscall # */ 488 else 489 callp += code; 490 argsize = callp->sy_argsize; 491 492#ifdef SYSCALL_DEBUG 493 scdebug_call(p, code, args); 494#endif 495#ifdef KTRACE 496 if (KTRPOINT(p, KTR_SYSCALL)) 497 ktrsyscall(p, code, argsize, args); 498#endif 499 500 rval[0] = 0; 501 rval[1] = 0; 502#if NSYSTRACE > 0 503 if (ISSET(p->p_flag, P_SYSTRACE)) 504 error = systrace_redirect(code, p, args, rval); 505 else 506#endif 507 error = (*callp->sy_call)(p, args, rval); 508 switch (error) { 509 case 0: 510 p = curproc; /* changes on exec() */ 511 frame = p->p_md.md_regs; 512 frame->tf_ret0 = rval[0]; 513 frame->tf_ret1 = rval[1]; 514 frame->tf_t1 = 0; 515 break; 516 case ERESTART: 517 frame->tf_iioq_head -= 12; 518 frame->tf_iioq_tail -= 12; 519 break; 520 case EJUSTRETURN: 521 p = curproc; 522 break; 523 default: 524 if (p->p_emul->e_errno) 525 error = p->p_emul->e_errno[error]; 526 frame->tf_t1 = error; 527 break; 528 } 529#ifdef SYSCALL_DEBUG 530 scdebug_ret(p, code, error, rval); 531#endif 532 userret(p, frame->tf_iioq_head, 0); 533#ifdef KTRACE 534 if (KTRPOINT(p, KTR_SYSRET)) 535 ktrsysret(p, code, error, rval[0]); 536#endif 537} 538