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