trap.c revision 1.65
1/* $OpenBSD: trap.c,v 1.65 2003/04/11 00:25:40 mickey Exp $ */ 2 3/* 4 * Copyright (c) 1998-2003 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 MIND, 27 * USE, 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#include <machine/db_machdep.h> /* XXX always needed for inst_store() */ 53#ifdef DDB 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 95userret(struct proc *p, register_t pc, u_quad_t oticks) 96{ 97 int sig; 98 99 /* take pending signals */ 100 while ((sig = CURSIG(p)) != 0) 101 postsig(sig); 102 103 p->p_priority = p->p_usrpri; 104 if (astpending) { 105 astpending = 0; 106 if (p->p_flag & P_OWEUPC) { 107 p->p_flag &= ~P_OWEUPC; 108 ADDUPROF(p); 109 } 110 } 111 if (want_resched) { 112 /* 113 * We're being preempted. 114 */ 115 preempt(NULL); 116 while ((sig = CURSIG(p)) != 0) 117 postsig(sig); 118 } 119 120 /* 121 * If profiling, charge recent system time to the trapped pc. 122 */ 123 if (p->p_flag & P_PROFIL) { 124 extern int psratio; 125 126 addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio); 127 } 128 129 curpriority = p->p_priority; 130} 131 132void 133trap(type, frame) 134 int type; 135 struct trapframe *frame; 136{ 137 struct proc *p = curproc; 138 vaddr_t va; 139 struct vm_map *map; 140 struct vmspace *vm; 141 register vm_prot_t vftype; 142 register pa_space_t space; 143 union sigval sv; 144 u_int opcode; 145 int ret, trapnum; 146 const char *tts; 147 vm_fault_t fault = VM_FAULT_INVALID; 148#ifdef DIAGNOSTIC 149 int oldcpl = cpl; 150#endif 151 152 trapnum = type & ~T_USER; 153 opcode = frame->tf_iir; 154 if (trapnum == T_ITLBMISS || 155 trapnum == T_EXCEPTION || trapnum == T_EMULATION) { 156 va = frame->tf_iioq_head; 157 space = frame->tf_iisq_head; 158 vftype = UVM_PROT_EXEC; 159 } else { 160 va = frame->tf_ior; 161 space = frame->tf_isr; 162 /* what is the vftype for the T_ITLBMISSNA ??? XXX */ 163 if (va == frame->tf_iioq_head) 164 vftype = UVM_PROT_EXEC; 165 else if (inst_store(opcode)) 166 vftype = UVM_PROT_WRITE; 167 else 168 vftype = UVM_PROT_READ; 169 } 170 171 if (frame->tf_flags & TFF_LAST) 172 p->p_md.md_regs = frame; 173 174 if (trapnum > trap_types) 175 tts = "reserved"; 176 else 177 tts = trap_type[trapnum]; 178 179#ifdef TRAPDEBUG 180 if (trapnum != T_INTERRUPT && trapnum != T_IBREAK) 181 db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n", 182 type, tts, space, va, frame->tf_iisq_head, 183 frame->tf_iioq_head, frame->tf_flags, frame); 184 else if (trapnum == T_IBREAK) 185 db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n", 186 break5(opcode), break13(opcode), 187 frame->tf_iisq_head, frame->tf_iioq_head, frame); 188 189 { 190 extern int etext; 191 if (frame < (struct trapframe *)&etext) { 192 printf("trap: bogus frame ptr %p\n", frame); 193 goto dead_end; 194 } 195 } 196#endif 197 if (trapnum != T_INTERRUPT) { 198 uvmexp.traps++; 199 mtctl(frame->tf_eiem, CR_EIEM); 200 } else 201 uvmexp.intrs++; 202 203 switch (type) { 204 case T_NONEXIST: 205 case T_NONEXIST | T_USER: 206 /* we've got screwed up by the central scrutinizer */ 207 printf("trap: elvis has just left the building!\n"); 208 goto dead_end; 209 210 case T_RECOVERY: 211 case T_RECOVERY | T_USER: 212 /* XXX will implement later */ 213 printf("trap: handicapped"); 214 goto dead_end; 215 216#ifdef DIAGNOSTIC 217 case T_EXCEPTION: 218 panic("FPU/SFU emulation botch"); 219 220 /* these just can't happen ever */ 221 case T_PRIV_OP: 222 case T_PRIV_REG: 223 /* these just can't make it to the trap() ever */ 224 case T_HPMC: 225 case T_HPMC | T_USER: 226#endif 227 case T_IBREAK: 228 case T_DATALIGN: 229 case T_DBREAK: 230 dead_end: 231#ifdef DDB 232 if (kdb_trap (type, va, frame)) { 233 if (type == T_IBREAK) { 234 /* skip break instruction */ 235 frame->tf_iioq_head = frame->tf_iioq_tail; 236 frame->tf_iioq_tail += 4; 237 } 238 return; 239 } 240#else 241 if (type == T_DATALIGN) 242 panic ("trap: %s at 0x%x", tts, va); 243 else 244 panic ("trap: no debugger for \"%s\" (%d)", tts, type); 245#endif 246 break; 247 248 case T_IBREAK | T_USER: 249 /* XXX */ 250 frame->tf_iioq_head = frame->tf_iioq_tail; 251 frame->tf_iioq_tail += 4; 252 case T_DBREAK | T_USER: 253 /* pass to user debugger */ 254 break; 255 256 case T_EXCEPTION | T_USER: { 257 u_int64_t *fpp = (u_int64_t *)frame->tf_cr30; 258 u_int32_t *pex; 259 int i, flt; 260 261 pex = (u_int32_t *)&fpp[0]; 262 for (i = 0, pex++; i < 7 && !*pex; i++, pex++); 263 flt = 0; 264 if (i < 7) { 265 u_int32_t stat = HPPA_FPU_OP(*pex); 266 if (stat == HPPA_FPU_UNMPL) 267 flt = FPE_FLTINV; 268 else if (stat & HPPA_FPU_V) 269 flt = FPE_FLTINV; 270 else if (stat & HPPA_FPU_Z) 271 flt = FPE_FLTDIV; 272 else if (stat & HPPA_FPU_I) 273 flt = FPE_FLTRES; 274 else if (stat & HPPA_FPU_O) 275 flt = FPE_FLTOVF; 276 else if (stat & HPPA_FPU_U) 277 flt = FPE_FLTUND; 278 /* still left: under/over-flow w/ inexact */ 279 *pex = 0; 280 } 281 /* reset the trap flag, as if there was none */ 282 fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32); 283 /* flush out, since load is done from phys, only 4 regs */ 284 fdcache(HPPA_SID_KERNEL, (vaddr_t)fpp, 8 * 4); 285 286 sv.sival_int = va; 287 trapsignal(p, SIGFPE, type &~ T_USER, flt, sv); 288 } 289 break; 290 291 case T_EMULATION: 292 panic("trap: emulation trap in the kernel"); 293 break; 294 295 case T_EMULATION | T_USER: 296 sv.sival_int = va; 297 trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 298 break; 299 300 case T_OVERFLOW | T_USER: 301 sv.sival_int = va; 302 trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 303 break; 304 305 case T_CONDITION | T_USER: 306 break; 307 308 case T_ILLEGAL | T_USER: 309 sv.sival_int = va; 310 trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 311 break; 312 313 case T_PRIV_OP | T_USER: 314 sv.sival_int = va; 315 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 316 break; 317 318 case T_PRIV_REG | T_USER: 319 sv.sival_int = va; 320 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 321 break; 322 323 /* these should never got here */ 324 case T_HIGHERPL | T_USER: 325 case T_LOWERPL | T_USER: 326 sv.sival_int = va; 327 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 328 break; 329 330 case T_IPROT | T_USER: 331 case T_DPROT | T_USER: 332 sv.sival_int = va; 333 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 334 break; 335 336 case T_DATACC: 337 case T_DATACC | T_USER: 338 fault = VM_FAULT_PROTECT; 339 case T_ITLBMISS: 340 case T_ITLBMISS | T_USER: 341 case T_DTLBMISS: 342 case T_DTLBMISS | T_USER: 343 case T_ITLBMISSNA: 344 case T_ITLBMISSNA | T_USER: 345 case T_DTLBMISSNA: 346 case T_DTLBMISSNA | T_USER: 347 case T_TLB_DIRTY: 348 case T_TLB_DIRTY | T_USER: 349 /* 350 * user faults out of user addr space are always a fail, 351 * this happens on va >= VM_MAXUSER_ADDRESS, where 352 * space id will be zero and therefore cause 353 * a misbehave lower in the code. 354 */ 355 if (type & T_USER && va >= VM_MAXUSER_ADDRESS) { 356 sv.sival_int = va; 357 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 358 break; 359 } 360 361 /* 362 * it could be a kernel map for exec_map faults 363 */ 364 if (space == HPPA_SID_KERNEL) 365 map = kernel_map; 366 else { 367 vm = p->p_vmspace; 368 map = &vm->vm_map; 369 } 370 371 if (type & T_USER && map->pmap->pm_space != space) { 372 sv.sival_int = va; 373 trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 374 break; 375 } 376 377 ret = uvm_fault(map, hppa_trunc_page(va), fault, vftype); 378 379 /* 380 * If this was a stack access we keep track of the maximum 381 * accessed stack size. Also, if uvm_fault gets a protection 382 * failure it is due to accessing the stack region outside 383 * the current limit and we need to reflect that as an access 384 * error. 385 */ 386 if (space != 0 && va < (vaddr_t)vm->vm_minsaddr && 387 va >= (vaddr_t)vm->vm_maxsaddr + ctob(vm->vm_ssize)) { 388 if (ret == 0) { 389 vsize_t nss = btoc(va - USRSTACK + NBPG - 1); 390 if (nss > vm->vm_ssize) 391 vm->vm_ssize = nss; 392 } else if (ret == EACCES) 393 ret = EFAULT; 394 } 395 396 if (ret != 0) { 397 if (type & T_USER) { 398 sv.sival_int = va; 399 trapsignal(p, SIGSEGV, vftype, 400 ret == EACCES? SEGV_ACCERR : SEGV_MAPERR, 401 sv); 402 } else { 403 if (p && p->p_addr->u_pcb.pcb_onfault) { 404 frame->tf_iioq_tail = 4 + 405 (frame->tf_iioq_head = 406 p->p_addr->u_pcb.pcb_onfault); 407#ifdef DDB 408 frame->tf_iir = 0; 409#endif 410 } else { 411 panic("trap: " 412 "uvm_fault(%p, %x, %d, %d): %d", 413 map, va, 0, vftype, ret); 414 } 415 } 416 } 417 break; 418 419 case T_DATALIGN | T_USER: 420 sv.sival_int = va; 421 trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 422 break; 423 424 case T_INTERRUPT: 425 case T_INTERRUPT | T_USER: 426 cpu_intr(frame); 427 break; 428 429 case T_CONDITION: 430 panic("trap: divide by zero in the kernel"); 431 break; 432 433 case T_LOWERPL: 434 case T_DPROT: 435 case T_IPROT: 436 case T_OVERFLOW: 437 case T_ILLEGAL: 438 case T_HIGHERPL: 439 case T_TAKENBR: 440 case T_POWERFAIL: 441 case T_LPMC: 442 case T_PAGEREF: 443 case T_DATAPID: 444 case T_DATAPID | T_USER: 445 if (0 /* T-chip */) { 446 break; 447 } 448 /* FALLTHROUGH to unimplemented */ 449 default: 450#if 0 451if (kdb_trap (type, va, frame)) 452 return; 453#endif 454 panic("trap: unimplemented \'%s\' (%d)", tts, trapnum); 455 } 456 457#ifdef DIAGNOSTIC 458 if (cpl != oldcpl) 459 printf("WARNING: SPL (%d) NOT LOWERED ON " 460 "TRAP (%d) EXIT\n", cpl, trapnum); 461#endif 462 463 if (trapnum != T_INTERRUPT) 464 splx(cpl); /* process softints */ 465 466 if (type & T_USER) 467 userret(p, frame->tf_iioq_head, 0); 468} 469 470void 471child_return(arg) 472 void *arg; 473{ 474 struct proc *p = (struct proc *)arg; 475 userret(p, p->p_md.md_regs->tf_iioq_head, 0); 476#ifdef KTRACE 477 if (KTRPOINT(p, KTR_SYSRET)) 478 ktrsysret(p, SYS_fork, 0, 0); 479#endif 480} 481 482 483/* 484 * call actual syscall routine 485 */ 486void 487syscall(struct trapframe *frame) 488{ 489 register struct proc *p = curproc; 490 register const struct sysent *callp; 491 int retq, nsys, code, argsize, argoff, oerror, error; 492 register_t args[8], rval[2]; 493#ifdef DIAGNOSTIC 494 int oldcpl = cpl; 495#endif 496 497 uvmexp.syscalls++; 498 499 if (!USERMODE(frame->tf_iioq_head)) 500 panic("syscall"); 501 502 p->p_md.md_regs = frame; 503 nsys = p->p_emul->e_nsysent; 504 callp = p->p_emul->e_sysent; 505 506 argoff = 4; retq = 0; 507 switch (code = frame->tf_t1) { 508 case SYS_syscall: 509 code = frame->tf_arg0; 510 args[0] = frame->tf_arg1; 511 args[1] = frame->tf_arg2; 512 args[2] = frame->tf_arg3; 513 argoff = 3; 514 break; 515 case SYS___syscall: 516 if (callp != sysent) 517 break; 518 /* 519 * this works, because quads get magically swapped 520 * due to the args being layed backwards on the stack 521 * and then copied in words 522 */ 523 code = frame->tf_arg0; 524 args[0] = frame->tf_arg2; 525 args[1] = frame->tf_arg3; 526 argoff = 2; 527 retq = 1; 528 break; 529 default: 530 args[0] = frame->tf_arg0; 531 args[1] = frame->tf_arg1; 532 args[2] = frame->tf_arg2; 533 args[3] = frame->tf_arg3; 534 break; 535 } 536 537 if (code < 0 || code >= nsys) 538 callp += p->p_emul->e_nosys; /* bad syscall # */ 539 else 540 callp += code; 541 542 oerror = error = 0; 543 if ((argsize = callp->sy_argsize)) { 544 int i; 545 546 for (i = 0, argsize -= argoff * 4; 547 argsize > 0; i++, argsize -= 4) { 548 error = copyin((void *)(frame->tf_sp + 549 HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4); 550 551 if (error) 552 break; 553 } 554 555 /* 556 * coming from syscall() or __syscall we must be 557 * having one of those w/ a 64 bit arguments, 558 * which needs a word swap due to the order 559 * of the arguments on the stack. 560 * this assumes that none of 'em are called 561 * by their normal syscall number, maybe a regress 562 * test should be used, to whatch the behaviour. 563 */ 564 if (!error && argoff < 4) { 565 int t; 566 567 i = 0; 568 switch (code) { 569 case SYS_lseek: retq = 0; 570 case SYS_truncate: 571 case SYS_ftruncate: i = 2; break; 572 case SYS_preadv: 573 case SYS_pwritev: 574 case SYS_pread: 575 case SYS_pwrite: i = 4; break; 576 case SYS_mmap: i = 6; break; 577 } 578 579 if (i) { 580 t = args[i]; 581 args[i] = args[i + 1]; 582 args[i + 1] = t; 583 } 584 } 585 } 586 587#ifdef SYSCALL_DEBUG 588 scdebug_call(p, code, args); 589#endif 590#ifdef KTRACE 591 if (KTRPOINT(p, KTR_SYSCALL)) 592 ktrsyscall(p, code, callp->sy_argsize, args); 593#endif 594 if (error) 595 goto bad; 596 597 rval[0] = 0; 598 rval[1] = frame->tf_ret1; 599#if NSYSTRACE > 0 600 if (ISSET(p->p_flag, P_SYSTRACE)) 601 oerror = error = systrace_redirect(code, p, args, rval); 602 else 603#endif 604 oerror = error = (*callp->sy_call)(p, args, rval); 605 p = curproc; 606 frame = p->p_md.md_regs; 607 switch (error) { 608 case 0: 609 frame->tf_ret0 = rval[0]; 610 frame->tf_ret1 = rval[!retq]; 611 frame->tf_t1 = 0; 612 break; 613 case ERESTART: 614 frame->tf_iioq_head -= 12; 615 frame->tf_iioq_tail -= 12; 616 case EJUSTRETURN: 617 break; 618 default: 619 bad: 620 if (p->p_emul->e_errno) 621 error = p->p_emul->e_errno[error]; 622 frame->tf_t1 = error; 623 break; 624 } 625#ifdef SYSCALL_DEBUG 626 scdebug_ret(p, code, oerror, rval); 627#endif 628 userret(p, frame->tf_iioq_head, 0); 629 splx(cpl); /* process softints */ 630#ifdef KTRACE 631 if (KTRPOINT(p, KTR_SYSRET)) 632 ktrsysret(p, code, oerror, rval[0]); 633#endif 634#ifdef DIAGNOSTIC 635 if (cpl != oldcpl) 636 printf("WARNING: SPL (0x%x) NOT LOWERED ON " 637 "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n", 638 cpl, code, args[0], args[1], args[2], p->p_pid); 639#endif 640} 641