trap.c revision 1.17
1/* $OpenBSD: trap.c,v 1.17 2000/01/17 00:30:17 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#define 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#define FAULT_TYPE(op) (VM_PROT_READ|(inst_store(op) ? VM_PROT_WRITE : 0)) 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; 166 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_EXECUTE; 172 } else { 173 va = frame->tf_ior; 174 space = frame->tf_isr; 175 vftype = FAULT_TYPE(opcode); 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 goto dead_end; 200 } 201#endif 202 switch (type) { 203 case T_NONEXIST: 204 case T_NONEXIST|T_USER: 205#ifndef DDB 206 /* we've got screwed up by the central scrutinizer */ 207 panic ("trap: elvis has just left the building!"); 208 break; 209#endif 210 case T_RECOVERY: 211 case T_RECOVERY|T_USER: 212#ifndef DDB 213 /* XXX will implement later */ 214 printf ("trap: handicapped"); 215 break; 216#endif 217 218#ifdef DIAGNOSTIC 219 case T_EXCEPTION: 220 panic("FPU/SFU emulation botch"); 221 222 /* these just can't happen ever */ 223 case T_PRIV_OP: 224 case T_PRIV_REG: 225 /* these just can't make it to the trap() ever */ 226 case T_HPMC: case T_HPMC | T_USER: 227 case T_EMULATION: case T_EMULATION | T_USER: 228 case T_TLB_DIRTY: case T_TLB_DIRTY | T_USER: 229#endif 230 case T_IBREAK: 231 case T_DATALIGN: 232 case T_DBREAK: 233 dead_end: 234#ifdef DDB 235 if (kdb_trap (type, 0, frame)) { 236 if (type == T_IBREAK) { 237 /* skip break instruction */ 238 frame->tf_iioq_head = frame->tf_iioq_tail; 239 frame->tf_iioq_tail += 4; 240 } 241 return; 242 } 243#else 244 if (type == T_DATALIGN) 245 panic ("trap: %s at 0x%x", tts, va); 246 else 247 panic ("trap: no debugger for \"%s\" (%d)", tts, type); 248#endif 249 break; 250 251 case T_IBREAK | T_USER: 252 case T_DBREAK | T_USER: 253 /* pass to user debugger */ 254 break; 255 256 case T_EXCEPTION | T_USER: /* co-proc assist trap */ 257 sv.sival_int = va; 258 trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTINV, sv); 259 break; 260 261 case T_OVERFLOW | T_USER: 262 sv.sival_int = va; 263 trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 264 break; 265 266 case T_CONDITION | T_USER: 267 break; 268 269 case T_ILLEGAL | T_USER: 270 sv.sival_int = va; 271 trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 272 break; 273 274 case T_PRIV_OP | T_USER: 275 sv.sival_int = va; 276 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 277 break; 278 279 case T_PRIV_REG | T_USER: 280 sv.sival_int = va; 281 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 282 break; 283 284 /* these should never got here */ 285 case T_HIGHERPL | T_USER: 286 case T_LOWERPL | T_USER: 287 sv.sival_int = va; 288 trapsignal(p, SIGSEGV, type &~ T_USER, SEGV_ACCERR, sv); 289 break; 290 291 case T_IPROT | T_USER: 292 case T_DPROT | T_USER: 293 sv.sival_int = va; 294 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 295 break; 296 297 case T_DPROT: 298 case T_IPROT: 299 case T_DATACC: case T_DATACC | T_USER: 300 case T_ITLBMISS: case T_ITLBMISS | T_USER: 301 case T_DTLBMISS: case T_DTLBMISS | T_USER: 302 case T_ITLBMISSNA: case T_ITLBMISSNA | T_USER: 303 case T_DTLBMISSNA: case T_DTLBMISSNA | T_USER: 304 va = trunc_page(va); 305 vm = p->p_vmspace; 306 307 if (!vm) 308 goto dead_end; 309 310 /* 311 * it could be a kernel map for exec_map faults 312 */ 313 if (!(type & T_USER) && space == HPPA_SID_KERNEL) 314 map = kernel_map; 315 else 316 map = &vm->vm_map; 317 318 ret = uvm_fault(map, va, 0, vftype); 319 320 /* 321 * If this was a stack access we keep track of the maximum 322 * accessed stack size. Also, if uvm_fault gets a protection 323 * failure it is due to accessing the stack region outside 324 * the current limit and we need to reflect that as an access 325 * error. 326 */ 327 if (va >= (vaddr_t)vm->vm_maxsaddr + vm->vm_ssize) { 328 if (ret == KERN_SUCCESS) { 329 vsize_t nss = clrnd(btoc(va - USRSTACK + NBPG)); 330 if (nss > vm->vm_ssize) 331 vm->vm_ssize = nss; 332 } else if (ret == KERN_PROTECTION_FAILURE) 333 ret = KERN_INVALID_ADDRESS; 334 } 335 336 if (ret != KERN_SUCCESS) { 337 if (type & T_USER) { 338printf("trapsignal: uvm_fault\n"); 339 sv.sival_int = frame->tf_ior; 340 trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 341 } else { 342 if (p && p->p_addr->u_pcb.pcb_onfault) { 343#ifdef PMAPDEBUG 344 printf("trap: copyin/out %d\n",ret); 345#endif 346 pcbp = &p->p_addr->u_pcb; 347 frame->tf_iioq_tail = 4 + 348 (frame->tf_iioq_head = 349 pcbp->pcb_onfault); 350 pcbp->pcb_onfault = 0; 351 break; 352 } 353#if 1 354if (kdb_trap (type, 0, frame)) 355 return; 356#else 357 panic("trap: uvm_fault(%p, %x, %d, %d): %d", 358 map, va, 0, vftype, ret); 359#endif 360 } 361 } 362if (type == (T_DATACC|T_USER) && kdb_trap (type, 0, frame)) 363 return; 364 break; 365 366 case T_DATALIGN | T_USER: 367 sv.sival_int = va; 368 trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 369 break; 370 371 case T_INTERRUPT: 372 case T_INTERRUPT|T_USER: 373 cpu_intr(frame); 374#if 0 375if (kdb_trap (type, 0, frame)) 376return; 377#endif 378 /* FALLTHROUGH */ 379 case T_LOWERPL: 380 __asm __volatile ("ldcws 0(%1), %0" 381 : "=r" (si) : "r" (&sir)); 382 s = spl0(); 383 if (si & SIR_CLOCK) { 384 splclock(); 385 softclock(); 386 spl0(); 387 } 388 389 if (si & SIR_NET) { 390 register int ni; 391 /* use atomic "load & clear" */ 392 __asm __volatile ("ldcws 0(%1), %0" 393 : "=r" (ni) : "r" (&netisr)); 394 splnet(); 395#define DONET(m,c) if (ni & (1 << (m))) c() 396#include "ether.h" 397#if NETHER > 0 398 DONET(NETISR_ARP, arpintr); 399#endif 400#ifdef INET 401 DONET(NETISR_IP, ipintr); 402#endif 403#ifdef INET6 404 DONET(NETISR_IPV6, ip6intr); 405#endif 406#ifdef NETATALK 407 DONET(NETISR_ATALK, atintr); 408#endif 409#ifdef IMP 410 DONET(NETISR_IMP, impintr); 411#endif 412#ifdef IPX 413 DONET(NETISR_IPX, ipxintr); 414#endif 415#ifdef NS 416 DONET(NETISR_NS, nsintr); 417#endif 418#ifdef ISO 419 DONET(NETISR_ISO, clnlintr); 420#endif 421#ifdef CCITT 422 DONET(NETISR_CCITT, ccittintr); 423#endif 424#ifdef NATM 425 DONET(NETISR_NATM, natmintr); 426#endif 427#include "ppp.h" 428#if NPPP > 0 429 DONET(NETISR_PPP, pppintr); 430#endif 431#include "bridge.h" 432#if NBRIDGE > 0 433 DONET(NETISR_BRIDGE, bridgeintr) 434#endif 435 } 436 splx(s); 437 break; 438 439 case T_OVERFLOW: 440 case T_CONDITION: 441 case T_ILLEGAL: 442 case T_HIGHERPL: 443 case T_TAKENBR: 444 case T_POWERFAIL: 445 case T_LPMC: 446 case T_PAGEREF: 447 case T_DATAPID: case T_DATAPID | T_USER: 448 if (0 /* T-chip */) { 449 break; 450 } 451 /* FALLTHROUGH to unimplemented */ 452 default: 453#if 1 454if (kdb_trap (type, 0, frame)) 455 return; 456#endif 457 panic ("trap: unimplemented \'%s\' (%d)", tts, type); 458 } 459 460 if (type & T_USER) 461 userret(p, p->p_md.md_regs->tf_iioq_head, 0); 462} 463 464void 465child_return(p) 466 struct proc *p; 467{ 468 userret(p, p->p_md.md_regs->tf_iioq_head, 0); 469#ifdef KTRACE 470 if (KTRPOINT(p, KTR_SYSRET)) 471 ktrsysret(p->p_tracep, SYS_fork, 0, 0); 472#endif 473} 474 475/* 476 * call actual syscall routine 477 * from the low-level syscall handler: 478 * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto 479 * our stack, this wins compared to copyin just needed amount anyway 480 * - register args are copied onto stack too 481 */ 482void 483syscall(frame, args) 484 struct trapframe *frame; 485 int *args; 486{ 487 register struct proc *p; 488 register const struct sysent *callp; 489 int nsys, code, argsize, error; 490 int rval[2]; 491 492 uvmexp.syscalls++; 493 494 if (!USERMODE(frame->tf_iioq_head)) 495 panic("syscall"); 496 497 p = curproc; 498 p->p_md.md_regs = frame; 499 nsys = p->p_emul->e_nsysent; 500 callp = p->p_emul->e_sysent; 501 code = frame->tf_t1; 502 switch (code) { 503 case SYS_syscall: 504 code = frame->tf_arg0; 505 args += 1; 506 break; 507 case SYS___syscall: 508 if (callp != sysent) 509 break; 510 code = frame->tf_arg0; /* XXX or arg1? */ 511 args += 2; 512 } 513 514 if (code < 0 || code >= nsys) 515 callp += p->p_emul->e_nosys; /* bad syscall # */ 516 else 517 callp += code; 518 argsize = callp->sy_argsize; 519 520#ifdef SYSCALL_DEBUG 521 scdebug_call(p, code, args); 522#endif 523#ifdef KTRACE 524 if (KTRPOINT(p, KTR_SYSCALL)) 525 ktrsyscall(p->p_tracep, code, argsize, args); 526#endif 527 528 rval[0] = 0; 529 rval[1] = 0; 530 switch (error = (*callp->sy_call)(p, args, rval)) { 531 case 0: 532 /* curproc may change inside the fork() */ 533 frame->tf_ret0 = rval[0]; 534 frame->tf_ret1 = rval[1]; 535 frame->tf_t1 = 0; 536 break; 537 case ERESTART: 538 frame->tf_iioq_head -= 4; /* right? XXX */ 539 break; 540 case EJUSTRETURN: 541 break; 542 default: 543 if (p->p_emul->e_errno) 544 error = p->p_emul->e_errno[error]; 545 frame->tf_t1 = error; 546 break; 547 } 548 p = curproc; 549#ifdef SYSCALL_DEBUG 550 scdebug_ret(p, code, error, rval); 551#endif 552 userret(p, p->p_md.md_regs->tf_iioq_head, 0); 553#ifdef KTRACE 554 if (KTRPOINT(p, KTR_SYSRET)) 555 ktrsysret(p->p_tracep, code, error, rval[0]); 556#endif 557} 558 559/* all the interrupts, minus cpu clock, which is the last */ 560struct cpu_intr_vector { 561 struct evcnt evcnt; 562 int pri; 563 int (*handler) __P((void *)); 564 void *arg; 565} cpu_intr_vectors[CPU_NINTS]; 566 567void * 568cpu_intr_establish(pri, irq, handler, arg, dv) 569 int pri, irq; 570 int (*handler) __P((void *)); 571 void *arg; 572 struct device *dv; 573{ 574 register struct cpu_intr_vector *iv; 575 576 if (0 <= irq && irq < CPU_NINTS && cpu_intr_vectors[irq].handler) 577 return NULL; 578 579 iv = &cpu_intr_vectors[irq]; 580 iv->pri = pri; 581 iv->handler = handler; 582 iv->arg = arg; 583 evcnt_attach(dv, dv->dv_xname, &iv->evcnt); 584 585 return iv; 586} 587 588void 589cpu_intr(frame) 590 struct trapframe *frame; 591{ 592 u_int32_t eirr; 593 register struct cpu_intr_vector *iv; 594 register int bit; 595 596 do { 597 mfctl(CR_EIRR, eirr); 598 eirr &= frame->tf_eiem; 599 bit = ffs(eirr) - 1; 600 if (bit >= 0) { 601 mtctl(1 << bit, CR_EIRR); 602 eirr &= ~(1 << bit); 603 /* ((struct iomod *)cpu_gethpa(0))->io_eir = 0; */ 604#ifdef INTRDEBUG 605 if (bit != 31) 606 db_printf ("cpu_intr: 0x%08x\n", (1 << bit)); 607#endif 608 iv = &cpu_intr_vectors[bit]; 609 if (iv->handler) { 610 register int s, r; 611 612 iv->evcnt.ev_count++; 613 s = splx(iv->pri); 614 /* no arg means pass the frame */ 615 r = (iv->handler)(iv->arg? iv->arg:frame); 616 splx(s); 617#ifdef DEBUG 618 if (!r) 619 db_printf ("%s: can't handle interrupt\n", 620 iv->evcnt.ev_name); 621#endif 622 } else 623 db_printf ("cpu_intr: stray interrupt %d\n", bit); 624 } 625 } while (eirr); 626} 627