trap.c revision 1.20
1/* $OpenBSD: trap.c,v 1.20 2000/06/08 22:25:19 niklas Exp $ */ 2 3/* 4 * Copyright (c) 1998-2000 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#undef INTRDEBUG 34#undef TRAPDEBUG 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/kernel.h> 39#include <sys/syscall.h> 40#include <sys/ktrace.h> 41#include <sys/proc.h> 42#include <sys/signalvar.h> 43#include <sys/user.h> 44#include <sys/acct.h> 45#include <sys/signal.h> 46#include <sys/device.h> 47 48#include <net/netisr.h> 49 50#include <vm/vm.h> 51#include <vm/vm_kern.h> 52#include <uvm/uvm.h> 53 54#include <machine/iomod.h> 55#include <machine/cpufunc.h> 56#include <machine/reg.h> 57#include <machine/autoconf.h> 58 59#ifdef DDB 60#include <machine/db_machdep.h> 61#endif 62 63#if defined(INTRDEBUG) || defined(TRAPDEBUG) 64#include <ddb/db_output.h> 65#endif 66 67 68const char *trap_type[] = { 69 "invalid", 70 "HPMC", 71 "power failure", 72 "recovery counter", 73 "external interrupt", 74 "LPMC", 75 "ITLB miss fault", 76 "instruction protection", 77 "Illegal instruction", 78 "break instruction", 79 "privileged operation", 80 "privileged register", 81 "overflow", 82 "conditional", 83 "assist exception", 84 "DTLB miss", 85 "ITLB non-access miss", 86 "DTLB non-access miss", 87 "data protection/rights/alignment", 88 "data break", 89 "TLB dirty", 90 "page reference", 91 "assist emulation", 92 "higher-priv transfer", 93 "lower-priv transfer", 94 "taken branch", 95 "data access rights", 96 "data protection", 97 "unaligned data ref", 98}; 99int trap_types = sizeof(trap_type)/sizeof(trap_type[0]); 100 101u_int32_t sir; 102int want_resched; 103 104void pmap_hptdump __P((void)); 105void cpu_intr __P((struct trapframe *frame)); 106void syscall __P((struct trapframe *frame, int *args)); 107 108static __inline void 109userret (struct proc *p, register_t pc, u_quad_t oticks) 110{ 111 int sig; 112 113 /* take pending signals */ 114 while ((sig = CURSIG(p)) != 0) 115 postsig(sig); 116 117 p->p_priority = p->p_usrpri; 118 if (want_resched) { 119 register int s; 120 /* 121 * Since we are curproc, a clock interrupt could 122 * change our priority without changing run queues 123 * (the running process is not kept on a run queue). 124 * If this happened after we setrunqueue ourselves but 125 * before we switch()'ed, we might not be on the queue 126 * indicated by our priority. 127 */ 128 s = splstatclock(); 129 setrunqueue(p); 130 p->p_stats->p_ru.ru_nivcsw++; 131 mi_switch(); 132 splx(s); 133 while ((sig = CURSIG(p)) != 0) 134 postsig(sig); 135 } 136 137 /* 138 * If profiling, charge recent system time to the trapped pc. 139 */ 140 if (p->p_flag & P_PROFIL) { 141 extern int psratio; 142 143 addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio); 144 } 145 146 curpriority = p->p_priority; 147} 148 149void 150trap(type, frame) 151 int type; 152 struct trapframe *frame; 153{ 154 struct proc *p = curproc; 155 struct pcb *pcbp; 156 register vaddr_t va; 157 register vm_map_t map; 158 struct vmspace *vm; 159 register vm_prot_t vftype; 160 register pa_space_t space; 161 u_int opcode; 162 int ret; 163 union sigval sv; 164 int s, si; 165 const char *tts; 166extern db_regs_t ddb_regs; 167ddb_regs = *frame; 168 opcode = frame->tf_iir; 169 if (type == T_ITLBMISS || type == T_ITLBMISSNA) { 170 va = frame->tf_iioq_head; 171 space = frame->tf_iisq_head; 172 vftype = VM_PROT_READ; /* XXX VM_PROT_EXECUTE ??? */ 173 } else { 174 va = frame->tf_ior; 175 space = frame->tf_isr; 176 vftype = inst_store(opcode) ? VM_PROT_WRITE : VM_PROT_READ; 177 } 178 179 if (frame->tf_flags & TFF_LAST) 180 p->p_md.md_regs = frame; 181 182#ifdef TRAPDEBUG 183 if ((type & ~T_USER) > trap_types) 184 tts = "reserved"; 185 else 186 tts = trap_type[type & ~T_USER]; 187 188 if (type != T_INTERRUPT && (type & ~T_USER) != T_IBREAK) 189 db_printf("trap: %d, %s for %x:%x at %x:%x, fl=%x, fp=%p\n", 190 type, tts, space, va, frame->tf_iisq_head, 191 frame->tf_iioq_head, frame->tf_flags, frame); 192 else if ((type & ~T_USER) == T_IBREAK) 193 db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n", 194 break5(opcode), break13(opcode), 195 frame->tf_iisq_head, frame->tf_iioq_head, frame); 196 197 { 198 extern int etext; 199 if (frame < (struct trapframe *)&etext) { 200 printf("trap: bogus frame ptr %p\n", frame); 201 goto dead_end; 202 } 203 } 204#endif 205 switch (type) { 206 case T_NONEXIST: 207 case T_NONEXIST|T_USER: 208#ifndef DDB 209 /* we've got screwed up by the central scrutinizer */ 210 panic ("trap: elvis has just left the building!"); 211 break; 212#else 213 goto dead_end; 214#endif 215 case T_RECOVERY: 216 case T_RECOVERY|T_USER: 217#ifndef DDB 218 /* XXX will implement later */ 219 printf ("trap: handicapped"); 220 break; 221#else 222 goto dead_end; 223#endif 224 225#ifdef DIAGNOSTIC 226 case T_EXCEPTION: 227 panic("FPU/SFU emulation botch"); 228 229 /* these just can't happen ever */ 230 case T_PRIV_OP: 231 case T_PRIV_REG: 232 /* these just can't make it to the trap() ever */ 233 case T_HPMC: case T_HPMC | T_USER: 234 case T_EMULATION: case T_EMULATION | T_USER: 235 case T_TLB_DIRTY: case T_TLB_DIRTY | T_USER: 236#endif 237 case T_IBREAK: 238 case T_DATALIGN: 239 case T_DBREAK: 240 dead_end: 241#ifdef DDB 242 if (kdb_trap (type, va, frame)) { 243 if (type == T_IBREAK) { 244 /* skip break instruction */ 245 frame->tf_iioq_head = frame->tf_iioq_tail; 246 frame->tf_iioq_tail += 4; 247 } 248 return; 249 } 250#else 251 if (type == T_DATALIGN) 252 panic ("trap: %s at 0x%x", tts, va); 253 else 254 panic ("trap: no debugger for \"%s\" (%d)", tts, type); 255#endif 256 break; 257 258 case T_IBREAK | T_USER: 259 case T_DBREAK | T_USER: 260 /* pass to user debugger */ 261 break; 262 263 case T_EXCEPTION | T_USER: /* co-proc assist trap */ 264 sv.sival_int = va; 265 trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTINV, sv); 266 break; 267 268 case T_OVERFLOW | T_USER: 269 sv.sival_int = va; 270 trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 271 break; 272 273 case T_CONDITION | T_USER: 274 break; 275 276 case T_ILLEGAL | T_USER: 277 sv.sival_int = va; 278 trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 279 break; 280 281 case T_PRIV_OP | T_USER: 282 sv.sival_int = va; 283 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 284 break; 285 286 case T_PRIV_REG | T_USER: 287 sv.sival_int = va; 288 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 289 break; 290 291 /* these should never got here */ 292 case T_HIGHERPL | T_USER: 293 case T_LOWERPL | T_USER: 294 sv.sival_int = va; 295 trapsignal(p, SIGSEGV, type &~ T_USER, SEGV_ACCERR, sv); 296 break; 297 298 case T_IPROT | T_USER: 299 case T_DPROT | T_USER: 300 sv.sival_int = va; 301 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 302 break; 303 304 case T_DPROT: 305 case T_IPROT: 306 case T_DATACC: case T_DATACC | T_USER: 307 case T_ITLBMISS: case T_ITLBMISS | T_USER: 308 case T_DTLBMISS: case T_DTLBMISS | T_USER: 309 case T_ITLBMISSNA: case T_ITLBMISSNA | T_USER: 310 case T_DTLBMISSNA: case T_DTLBMISSNA | T_USER: 311 va = trunc_page(va); 312 vm = p->p_vmspace; 313 314 if (!vm) { 315#ifdef TRAPDEBUG 316 printf("trap: no vm, p=%p\n", p); 317#endif 318 goto dead_end; 319 } 320 321 /* 322 * it could be a kernel map for exec_map faults 323 */ 324 if (!(type & T_USER) && space == HPPA_SID_KERNEL) 325 map = kernel_map; 326 else 327 map = &vm->vm_map; 328 329 if (map->pmap->pmap_space != space) { 330#ifdef TRAPDEBUG 331 printf("trap: space missmatch %d != %d\n", 332 space, map->pmap->pmap_space); 333#endif 334 /* actually dump the user, crap the kernel */ 335 goto dead_end; 336 } 337 338 ret = uvm_fault(map, va, 0, vftype); 339 340#ifdef TRAPDEBUG 341 printf("uvm_fault(%p, %x, %d, %d)=%d\n", 342 map, va, 0, vftype, ret); 343#endif 344 345 /* 346 * If this was a stack access we keep track of the maximum 347 * accessed stack size. Also, if uvm_fault gets a protection 348 * failure it is due to accessing the stack region outside 349 * the current limit and we need to reflect that as an access 350 * error. 351 */ 352 if (va >= (vaddr_t)vm->vm_maxsaddr + vm->vm_ssize) { 353 if (ret == KERN_SUCCESS) { 354 vsize_t nss = clrnd(btoc(va - USRSTACK + NBPG)); 355 if (nss > vm->vm_ssize) 356 vm->vm_ssize = nss; 357 } else if (ret == KERN_PROTECTION_FAILURE) 358 ret = KERN_INVALID_ADDRESS; 359 } 360 361 if (ret != KERN_SUCCESS) { 362 if (type & T_USER) { 363printf("trapsignal: uvm_fault\n"); 364 sv.sival_int = frame->tf_ior; 365 trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 366 } else { 367 if (p && p->p_addr->u_pcb.pcb_onfault) { 368#ifdef PMAPDEBUG 369 printf("trap: copyin/out %d\n",ret); 370#endif 371 pcbp = &p->p_addr->u_pcb; 372 frame->tf_iioq_tail = 4 + 373 (frame->tf_iioq_head = 374 pcbp->pcb_onfault); 375 pcbp->pcb_onfault = 0; 376 break; 377 } 378#if 1 379if (kdb_trap (type, va, frame)) 380 return; 381#else 382 panic("trap: uvm_fault(%p, %x, %d, %d): %d", 383 map, va, 0, vftype, ret); 384#endif 385 } 386 } 387 break; 388 389 case T_DATALIGN | T_USER: 390 sv.sival_int = va; 391 trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 392 break; 393 394 case T_INTERRUPT: 395 case T_INTERRUPT|T_USER: 396 frame->tf_flags |= TFF_INTR; 397 cpu_intr(frame); 398#if 0 399if (kdb_trap (type, va, frame)) 400return; 401#endif 402 /* FALLTHROUGH */ 403 case T_LOWERPL: 404 __asm __volatile ("ldcws 0(%1), %0" 405 : "=r" (si) : "r" (&sir)); 406 s = spl0(); 407 if (si & SIR_CLOCK) { 408 splclock(); 409 softclock(); 410 spl0(); 411 } 412 413 if (si & SIR_NET) { 414 register int ni; 415 /* use atomic "load & clear" */ 416 __asm __volatile ("ldcws 0(%1), %0" 417 : "=r" (ni) : "r" (&netisr)); 418 splnet(); 419#define DONET(m,c) if (ni & (1 << (m))) c() 420#include "ether.h" 421#if NETHER > 0 422 DONET(NETISR_ARP, arpintr); 423#endif 424#ifdef INET 425 DONET(NETISR_IP, ipintr); 426#endif 427#ifdef INET6 428 DONET(NETISR_IPV6, ip6intr); 429#endif 430#ifdef NETATALK 431 DONET(NETISR_ATALK, atintr); 432#endif 433#ifdef IMP 434 DONET(NETISR_IMP, impintr); 435#endif 436#ifdef IPX 437 DONET(NETISR_IPX, ipxintr); 438#endif 439#ifdef NS 440 DONET(NETISR_NS, nsintr); 441#endif 442#ifdef ISO 443 DONET(NETISR_ISO, clnlintr); 444#endif 445#ifdef CCITT 446 DONET(NETISR_CCITT, ccittintr); 447#endif 448#ifdef NATM 449 DONET(NETISR_NATM, natmintr); 450#endif 451#include "ppp.h" 452#if NPPP > 0 453 DONET(NETISR_PPP, pppintr); 454#endif 455#include "bridge.h" 456#if NBRIDGE > 0 457 DONET(NETISR_BRIDGE, bridgeintr) 458#endif 459 } 460 splx(s); 461 break; 462 463 case T_OVERFLOW: 464 case T_CONDITION: 465 case T_ILLEGAL: 466 case T_HIGHERPL: 467 case T_TAKENBR: 468 case T_POWERFAIL: 469 case T_LPMC: 470 case T_PAGEREF: 471 case T_DATAPID: case T_DATAPID | T_USER: 472 if (0 /* T-chip */) { 473 break; 474 } 475 /* FALLTHROUGH to unimplemented */ 476 default: 477#if 1 478if (kdb_trap (type, va, frame)) 479 return; 480#endif 481 panic ("trap: unimplemented \'%s\' (%d)", tts, type); 482 } 483 484 if (type & T_USER) 485 userret(p, p->p_md.md_regs->tf_iioq_head, 0); 486} 487 488void 489child_return(p) 490 struct proc *p; 491{ 492 userret(p, p->p_md.md_regs->tf_iioq_head, 0); 493#ifdef KTRACE 494 if (KTRPOINT(p, KTR_SYSRET)) 495 ktrsysret(p->p_tracep, SYS_fork, 0, 0); 496#endif 497} 498 499/* 500 * call actual syscall routine 501 * from the low-level syscall handler: 502 * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto 503 * our stack, this wins compared to copyin just needed amount anyway 504 * - register args are copied onto stack too 505 */ 506void 507syscall(frame, args) 508 struct trapframe *frame; 509 int *args; 510{ 511 register struct proc *p; 512 register const struct sysent *callp; 513 int nsys, code, argsize, error; 514 int rval[2]; 515 516 uvmexp.syscalls++; 517 518 if (!USERMODE(frame->tf_iioq_head)) 519 panic("syscall"); 520 521 p = curproc; 522 p->p_md.md_regs = frame; 523 nsys = p->p_emul->e_nsysent; 524 callp = p->p_emul->e_sysent; 525 code = frame->tf_t1; 526 switch (code) { 527 case SYS_syscall: 528 code = *args; 529 args += 1; 530 break; 531 case SYS___syscall: 532 if (callp != sysent) 533 break; 534 code = *args; 535 args += 2; 536 } 537 538 if (code < 0 || code >= nsys) 539 callp += p->p_emul->e_nosys; /* bad syscall # */ 540 else 541 callp += code; 542 argsize = callp->sy_argsize; 543 544#ifdef SYSCALL_DEBUG 545 scdebug_call(p, code, args); 546#endif 547#ifdef KTRACE 548 if (KTRPOINT(p, KTR_SYSCALL)) 549 ktrsyscall(p->p_tracep, code, argsize, args); 550#endif 551 552 rval[0] = 0; 553 rval[1] = 0; 554 switch (error = (*callp->sy_call)(p, args, rval)) { 555 case 0: 556 p = curproc; /* changes on exec() */ 557 frame = p->p_md.md_regs; 558 frame->tf_ret0 = rval[0]; 559 frame->tf_ret1 = rval[1]; 560 frame->tf_t1 = 0; 561 break; 562 case ERESTART: 563 frame->tf_iioq_head -= 4; /* right? XXX */ 564 frame->tf_iioq_tail -= 4; /* right? XXX */ 565 break; 566 case EJUSTRETURN: 567 p = curproc; 568 break; 569 default: 570 if (p->p_emul->e_errno) 571 error = p->p_emul->e_errno[error]; 572 frame->tf_t1 = error; 573 break; 574 } 575#ifdef SYSCALL_DEBUG 576 scdebug_ret(p, code, error, rval); 577#endif 578 userret(p, frame->tf_iioq_head, 0); 579#ifdef KTRACE 580 if (KTRPOINT(p, KTR_SYSRET)) 581 ktrsysret(p->p_tracep, code, error, rval[0]); 582#endif 583} 584 585/* all the interrupts, minus cpu clock, which is the last */ 586struct cpu_intr_vector { 587 struct evcnt evcnt; 588 int pri; 589 int (*handler) __P((void *)); 590 void *arg; 591} cpu_intr_vectors[CPU_NINTS]; 592 593void * 594cpu_intr_establish(pri, irq, handler, arg, dv) 595 int pri, irq; 596 int (*handler) __P((void *)); 597 void *arg; 598 struct device *dv; 599{ 600 register struct cpu_intr_vector *iv; 601 602 if (0 <= irq && irq < CPU_NINTS && cpu_intr_vectors[irq].handler) 603 return NULL; 604 605 iv = &cpu_intr_vectors[irq]; 606 iv->pri = pri; 607 iv->handler = handler; 608 iv->arg = arg; 609 evcnt_attach(dv, dv->dv_xname, &iv->evcnt); 610 611 return iv; 612} 613 614void 615cpu_intr(frame) 616 struct trapframe *frame; 617{ 618 u_int32_t eirr; 619 register struct cpu_intr_vector *iv; 620 register int bit; 621 622 do { 623 mfctl(CR_EIRR, eirr); 624 eirr &= frame->tf_eiem; 625 bit = ffs(eirr) - 1; 626 if (bit >= 0) { 627 mtctl(1 << bit, CR_EIRR); 628 eirr &= ~(1 << bit); 629 /* ((struct iomod *)cpu_gethpa(0))->io_eir = 0; */ 630#ifdef INTRDEBUG 631 if (bit != 31) 632 db_printf ("cpu_intr: 0x%08x\n", (1 << bit)); 633#endif 634 iv = &cpu_intr_vectors[bit]; 635 if (iv->handler) { 636 register int s, r; 637 638 iv->evcnt.ev_count++; 639 s = splx(iv->pri); 640 /* no arg means pass the frame */ 641 r = (iv->handler)(iv->arg? iv->arg:frame); 642 splx(s); 643#ifdef INTRDEBUG 644 if (!r) 645 db_printf ("%s: can't handle interrupt\n", 646 iv->evcnt.ev_name); 647#endif 648 } 649#ifdef INTRDEBUG 650 else 651 db_printf ("cpu_intr: stray interrupt %d\n", bit); 652#endif 653 } 654 } while (eirr); 655} 656