1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1992 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department, Ralph Campbell, Sony Corp. and Kazumasa Utashiro 9 * of Software Research Associates, Inc. 10 * 11 * %sccs.include.redist.c% 12 * 13 * from: Utah $Hdr: trap.c 1.32 91/04/06$ 14 * 15 * @(#)trap.c 7.8 (Berkeley) 04/08/93 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/proc.h> 21 #include <sys/kernel.h> 22 #include <sys/signalvar.h> 23 #include <sys/syscall.h> 24 #include <sys/user.h> 25 #include <sys/buf.h> 26 #ifdef KTRACE 27 #include <sys/ktrace.h> 28 #endif 29 #include <net/netisr.h> 30 31 #include <machine/trap.h> 32 #include <machine/psl.h> 33 #include <machine/reg.h> 34 #include <machine/cpu.h> 35 #include <machine/pte.h> 36 #include <machine/mips_opcode.h> 37 #include <machine/adrsmap.h> 38 39 #include <vm/vm.h> 40 #include <vm/vm_kern.h> 41 #include <vm/vm_page.h> 42 43 #include "lp.h" 44 #include "bm.h" 45 #include "ms.h" 46 #include "en.h" 47 #include <news3400/hbdev/dmac_0448.h> 48 #include <news3400/sio/scc.h> 49 50 struct proc *machFPCurProcPtr; /* pointer to last proc to use FP */ 51 52 extern void MachKernGenException(); 53 extern void MachUserGenException(); 54 extern void MachKernIntr(); 55 extern void MachUserIntr(); 56 extern void MachTLBModException(); 57 extern void MachTLBMissException(); 58 extern unsigned MachEmulateBranch(); 59 60 void (*machExceptionTable[])() = { 61 /* 62 * The kernel exception handlers. 63 */ 64 MachKernIntr, /* external interrupt */ 65 MachKernGenException, /* TLB modification */ 66 MachTLBMissException, /* TLB miss (load or instr. fetch) */ 67 MachTLBMissException, /* TLB miss (store) */ 68 MachKernGenException, /* address error (load or I-fetch) */ 69 MachKernGenException, /* address error (store) */ 70 MachKernGenException, /* bus error (I-fetch) */ 71 MachKernGenException, /* bus error (load or store) */ 72 MachKernGenException, /* system call */ 73 MachKernGenException, /* breakpoint */ 74 MachKernGenException, /* reserved instruction */ 75 MachKernGenException, /* coprocessor unusable */ 76 MachKernGenException, /* arithmetic overflow */ 77 MachKernGenException, /* reserved */ 78 MachKernGenException, /* reserved */ 79 MachKernGenException, /* reserved */ 80 /* 81 * The user exception handlers. 82 */ 83 MachUserIntr, 84 MachUserGenException, 85 MachUserGenException, 86 MachUserGenException, 87 MachUserGenException, 88 MachUserGenException, 89 MachUserGenException, 90 MachUserGenException, 91 MachUserGenException, 92 MachUserGenException, 93 MachUserGenException, 94 MachUserGenException, 95 MachUserGenException, 96 MachUserGenException, 97 MachUserGenException, 98 MachUserGenException, 99 }; 100 101 char *trap_type[] = { 102 "external interrupt", 103 "TLB modification", 104 "TLB miss (load or instr. fetch)", 105 "TLB miss (store)", 106 "address error (load or I-fetch)", 107 "address error (store)", 108 "bus error (I-fetch)", 109 "bus error (load or store)", 110 "system call", 111 "breakpoint", 112 "reserved instruction", 113 "coprocessor unusable", 114 "arithmetic overflow", 115 "reserved 13", 116 "reserved 14", 117 "reserved 15", 118 }; 119 120 #ifdef DEBUG 121 #define TRAPSIZE 10 122 struct trapdebug { /* trap history buffer for debugging */ 123 u_int status; 124 u_int cause; 125 u_int vadr; 126 u_int pc; 127 u_int ra; 128 u_int code; 129 } trapdebug[TRAPSIZE], *trp = trapdebug; 130 #endif 131 132 /* 133 * Handle an exception. 134 * Called from MachKernGenException() or MachUserGenException() 135 * when a processor trap occurs. 136 * In the case of a kernel trap, we return the pc where to resume if 137 * ((struct pcb *)UADDR)->pcb_onfault is set, otherwise, return old pc. 138 */ 139 unsigned 140 trap(statusReg, causeReg, vadr, pc, args) 141 unsigned statusReg; /* status register at time of the exception */ 142 unsigned causeReg; /* cause register at time of exception */ 143 unsigned vadr; /* address (if any) the fault occured on */ 144 unsigned pc; /* program counter where to continue */ 145 { 146 register int type, i; 147 unsigned ucode = 0; 148 register struct proc *p = curproc; 149 u_quad_t sticks; 150 vm_prot_t ftype; 151 extern unsigned onfault_table[]; 152 153 #ifdef DEBUG 154 trp->status = statusReg; 155 trp->cause = causeReg; 156 trp->vadr = vadr; 157 trp->pc = pc; 158 trp->ra = !USERMODE(statusReg) ? ((int *)&args)[19] : 159 p->p_md.md_regs[RA]; 160 trp->code = 0; 161 if (++trp == &trapdebug[TRAPSIZE]) 162 trp = trapdebug; 163 #endif 164 165 cnt.v_trap++; 166 type = (causeReg & MACH_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT; 167 if (USERMODE(statusReg)) { 168 type |= T_USER; 169 sticks = p->p_sticks; 170 } 171 172 /* 173 * Enable hardware interrupts if they were on before. 174 * We only respond to software interrupts when returning to user mode. 175 */ 176 if (statusReg & MACH_SR_INT_ENA_PREV) 177 splx((statusReg & MACH_HARD_INT_MASK) | MACH_SR_INT_ENA_CUR); 178 179 switch (type) { 180 case T_TLB_MOD: 181 /* check for kernel address */ 182 if ((int)vadr < 0) { 183 register pt_entry_t *pte; 184 register unsigned entry; 185 #ifndef ATTR 186 register vm_offset_t pa; 187 #endif 188 189 pte = kvtopte(vadr); 190 entry = pte->pt_entry; 191 if (entry & PG_RO) { 192 /* write to read only page in the kernel */ 193 ftype = VM_PROT_WRITE; 194 goto kernel_fault; 195 } 196 entry |= PG_M; 197 pte->pt_entry = entry; 198 vadr &= PG_FRAME; 199 printf("trap: TLBupdate hi %x lo %x i %x\n", vadr, 200 entry, MachTLBUpdate(vadr, entry)); /* XXX */ 201 #ifdef ATTR 202 pmap_attributes[atop(entry - KERNBASE)] |= PMAP_ATTR_MOD; 203 #else 204 pa = entry & PG_FRAME; 205 if (!IS_VM_PHYSADDR(pa)) 206 panic("trap: kmod"); 207 PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN; 208 #endif 209 return (pc); 210 } 211 /* FALLTHROUGH */ 212 213 case T_TLB_MOD+T_USER: 214 { 215 pmap_hash_t hp; 216 #ifndef ATTR 217 vm_offset_t pa; 218 #endif 219 #ifdef DIAGNOSTIC 220 extern pmap_hash_t zero_pmap_hash; 221 extern pmap_t cur_pmap; 222 223 if (cur_pmap->pm_hash == zero_pmap_hash || 224 cur_pmap->pm_hash == (pmap_hash_t)0) 225 panic("tlbmod"); 226 #endif 227 hp = &((pmap_hash_t)PMAP_HASH_UADDR)[PMAP_HASH(vadr)]; 228 if (((hp->pmh_pte[0].high ^ vadr) & ~PGOFSET) == 0) 229 i = 0; 230 else if (((hp->pmh_pte[1].high ^ vadr) & ~PGOFSET) == 0) 231 i = 1; 232 else 233 panic("trap: tlb umod not found"); 234 if (hp->pmh_pte[i].low & PG_RO) { 235 ftype = VM_PROT_WRITE; 236 goto dofault; 237 } 238 hp->pmh_pte[i].low |= PG_M; 239 printf("trap: TLBupdate hi %x lo %x i %x\n", 240 hp->pmh_pte[i].high, hp->pmh_pte[i].low, 241 MachTLBUpdate(hp->pmh_pte[i].high, hp->pmh_pte[i].low)); /* XXX */ 242 #ifdef ATTR 243 pmap_attributes[atop(hp->pmh_pte[i].low - KERNBASE)] |= 244 PMAP_ATTR_MOD; 245 #else 246 pa = hp->pmh_pte[i].low & PG_FRAME; 247 if (!IS_VM_PHYSADDR(pa)) 248 panic("trap: umod"); 249 PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN; 250 #endif 251 if (!USERMODE(statusReg)) 252 return (pc); 253 goto out; 254 } 255 256 case T_TLB_LD_MISS: 257 case T_TLB_ST_MISS: 258 ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ; 259 /* check for kernel address */ 260 if ((int)vadr < 0) { 261 register vm_offset_t va; 262 int rv; 263 264 kernel_fault: 265 va = trunc_page((vm_offset_t)vadr); 266 rv = vm_fault(kernel_map, va, ftype, FALSE); 267 if (rv == KERN_SUCCESS) 268 return (pc); 269 if (i = ((struct pcb *)UADDR)->pcb_onfault) { 270 ((struct pcb *)UADDR)->pcb_onfault = 0; 271 return (onfault_table[i]); 272 } 273 goto err; 274 } 275 /* 276 * It is an error for the kernel to access user space except 277 * through the copyin/copyout routines. 278 */ 279 if ((i = ((struct pcb *)UADDR)->pcb_onfault) == 0) 280 goto err; 281 /* check for fuswintr() or suswintr() getting a page fault */ 282 if (i == 4) 283 return (onfault_table[i]); 284 goto dofault; 285 286 case T_TLB_LD_MISS+T_USER: 287 ftype = VM_PROT_READ; 288 goto dofault; 289 290 case T_TLB_ST_MISS+T_USER: 291 ftype = VM_PROT_WRITE; 292 dofault: 293 { 294 register vm_offset_t va; 295 register struct vmspace *vm = p->p_vmspace; 296 register vm_map_t map = &vm->vm_map; 297 int rv; 298 299 va = trunc_page((vm_offset_t)vadr); 300 rv = vm_fault(map, va, ftype, FALSE); 301 if (rv != KERN_SUCCESS) { 302 printf("vm_fault(%x, %x, %x, 0) -> %x ADR %x PC %x RA %x\n", 303 map, va, ftype, rv, vadr, pc, 304 !USERMODE(statusReg) ? ((int *)&args)[19] : 305 p->p_md.md_regs[RA]); /* XXX */ 306 printf("\tpid %d %s PC %x RA %x\n", p->p_pid, 307 p->p_comm, p->p_md.md_regs[PC], 308 p->p_md.md_regs[RA]); /* XXX */ 309 #ifdef DEBUG 310 trapDump("vm_fault"); 311 #endif 312 } 313 /* 314 * If this was a stack access we keep track of the maximum 315 * accessed stack size. Also, if vm_fault gets a protection 316 * failure it is due to accessing the stack region outside 317 * the current limit and we need to reflect that as an access 318 * error. 319 */ 320 if ((caddr_t)va >= vm->vm_maxsaddr) { 321 if (rv == KERN_SUCCESS) { 322 unsigned nss; 323 324 nss = clrnd(btoc(USRSTACK-(unsigned)va)); 325 if (nss > vm->vm_ssize) 326 vm->vm_ssize = nss; 327 } else if (rv == KERN_PROTECTION_FAILURE) 328 rv = KERN_INVALID_ADDRESS; 329 } 330 if (rv == KERN_SUCCESS) { 331 if (!USERMODE(statusReg)) 332 return (pc); 333 goto out; 334 } 335 if (!USERMODE(statusReg)) { 336 if (i = ((struct pcb *)UADDR)->pcb_onfault) { 337 ((struct pcb *)UADDR)->pcb_onfault = 0; 338 return (onfault_table[i]); 339 } 340 goto err; 341 } 342 ucode = vadr; 343 i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; 344 break; 345 } 346 347 case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ 348 case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ 349 case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */ 350 case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */ 351 i = SIGSEGV; 352 break; 353 354 case T_SYSCALL+T_USER: 355 { 356 register int *locr0 = p->p_md.md_regs; 357 register struct sysent *callp; 358 unsigned int code; 359 int numsys; 360 struct args { 361 int i[8]; 362 } args; 363 int rval[2]; 364 struct sysent *systab; 365 extern int nsysent; 366 #ifdef COMPAT_NEWSOS 367 extern int nnewssys; 368 extern struct sysent newssys[]; 369 #endif 370 371 cnt.v_syscall++; 372 /* compute next PC after syscall instruction */ 373 if ((int)causeReg < 0) 374 locr0[PC] = MachEmulateBranch(locr0, pc, 0, 0); 375 else 376 locr0[PC] += 4; 377 systab = sysent; 378 numsys = nsysent; 379 code = locr0[V0]; 380 #ifdef COMPAT_NEWSOS 381 if (code >= 1000) { 382 code -= 1000; 383 systab = newssys; 384 numsys = nnewssys; 385 } 386 #endif 387 switch (code) { 388 case SYS_indir: 389 /* 390 * Code is first argument, followed by actual args. 391 */ 392 code = locr0[A0]; 393 #ifdef COMPAT_NEWSOS 394 if (code >= 1000) { 395 code -= 1000; 396 systab = newssys; 397 numsys = nnewssys; 398 } 399 #endif 400 if (code >= numsys) 401 callp = &systab[SYS_indir]; /* (illegal) */ 402 else 403 callp = &systab[code]; 404 i = callp->sy_narg; 405 args.i[0] = locr0[A1]; 406 args.i[1] = locr0[A2]; 407 args.i[2] = locr0[A3]; 408 if (i > 3) { 409 i = copyin((caddr_t)(locr0[SP] + 410 4 * sizeof(int)), 411 (caddr_t)&args.i[3], 412 (u_int)(i - 3) * sizeof(int)); 413 if (i) { 414 locr0[V0] = i; 415 locr0[A3] = 1; 416 #ifdef KTRACE 417 if (KTRPOINT(p, KTR_SYSCALL)) 418 ktrsyscall(p->p_tracep, code, 419 callp->sy_narg, args.i); 420 #endif 421 goto done; 422 } 423 } 424 break; 425 426 case SYS___indir: 427 /* 428 * Like indir, but code is a quad, so as to maintain 429 * quad alignment for the rest of the arguments. 430 */ 431 code = locr0[A0 + _QUAD_LOWWORD]; 432 if (code >= numsys) 433 callp = &systab[SYS_indir]; /* (illegal) */ 434 else 435 callp = &systab[code]; 436 i = callp->sy_narg; 437 args.i[0] = locr0[A2]; 438 args.i[1] = locr0[A3]; 439 if (i > 2) { 440 i = copyin((caddr_t)(locr0[SP] + 441 4 * sizeof(int)), 442 (caddr_t)&args.i[2], 443 (u_int)(i - 2) * sizeof(int)); 444 if (i) { 445 locr0[V0] = i; 446 locr0[A3] = 1; 447 #ifdef KTRACE 448 if (KTRPOINT(p, KTR_SYSCALL)) 449 ktrsyscall(p->p_tracep, code, 450 callp->sy_narg, args.i); 451 #endif 452 goto done; 453 } 454 } 455 break; 456 457 default: 458 if (code >= numsys) 459 callp = &systab[SYS_indir]; /* (illegal) */ 460 else 461 callp = &systab[code]; 462 i = callp->sy_narg; 463 args.i[0] = locr0[A0]; 464 args.i[1] = locr0[A1]; 465 args.i[2] = locr0[A2]; 466 args.i[3] = locr0[A3]; 467 if (i > 4) { 468 i = copyin((caddr_t)(locr0[SP] + 469 4 * sizeof(int)), 470 (caddr_t)&args.i[4], 471 (u_int)(i - 4) * sizeof(int)); 472 if (i) { 473 locr0[V0] = i; 474 locr0[A3] = 1; 475 #ifdef KTRACE 476 if (KTRPOINT(p, KTR_SYSCALL)) 477 ktrsyscall(p->p_tracep, code, 478 callp->sy_narg, args.i); 479 #endif 480 goto done; 481 } 482 } 483 } 484 #ifdef KTRACE 485 if (KTRPOINT(p, KTR_SYSCALL)) 486 ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); 487 #endif 488 rval[0] = 0; 489 rval[1] = locr0[V1]; 490 #ifdef DEBUG 491 if (trp == trapdebug) 492 trapdebug[TRAPSIZE - 1].code = code; 493 else 494 trp[-1].code = code; 495 #endif 496 i = (*callp->sy_call)(p, &args, rval); 497 /* 498 * Reinitialize proc pointer `p' as it may be different 499 * if this is a child returning from fork syscall. 500 */ 501 p = curproc; 502 locr0 = p->p_md.md_regs; 503 #ifdef DEBUG 504 { int s; 505 s = splhigh(); 506 trp->status = statusReg; 507 trp->cause = causeReg; 508 trp->vadr = locr0[SP]; 509 trp->pc = locr0[PC]; 510 trp->ra = locr0[RA]; 511 trp->code = -code; 512 if (++trp == &trapdebug[TRAPSIZE]) 513 trp = trapdebug; 514 splx(s); 515 } 516 #endif 517 switch (i) { 518 case 0: 519 locr0[V0] = rval[0]; 520 locr0[V1] = rval[1]; 521 locr0[A3] = 0; 522 break; 523 524 case ERESTART: 525 locr0[PC] = pc; 526 break; 527 528 case EJUSTRETURN: 529 break; /* nothing to do */ 530 531 default: 532 locr0[V0] = i; 533 locr0[A3] = 1; 534 } 535 done: 536 #ifdef KTRACE 537 if (KTRPOINT(p, KTR_SYSRET)) 538 ktrsysret(p->p_tracep, code, i, rval[0]); 539 #endif 540 541 goto out; 542 } 543 544 case T_BREAK+T_USER: 545 { 546 register unsigned va, instr; 547 548 /* compute address of break instruction */ 549 va = pc; 550 if ((int)causeReg < 0) 551 va += 4; 552 553 /* read break instruction */ 554 instr = fuiword((caddr_t)va); 555 #ifdef KADB 556 if (instr == MACH_BREAK_BRKPT || instr == MACH_BREAK_SSTEP) 557 goto err; 558 #endif 559 if (p->p_md.md_ss_addr != va || instr != MACH_BREAK_SSTEP) { 560 i = SIGTRAP; 561 break; 562 } 563 564 /* restore original instruction and clear BP */ 565 i = suiword((caddr_t)va, p->p_md.md_ss_instr); 566 if (i < 0) { 567 vm_offset_t sa, ea; 568 int rv; 569 570 sa = trunc_page((vm_offset_t)va); 571 ea = round_page((vm_offset_t)va+sizeof(int)-1); 572 rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, 573 VM_PROT_DEFAULT, FALSE); 574 if (rv == KERN_SUCCESS) { 575 i = suiword((caddr_t)va, p->p_md.md_ss_instr); 576 (void) vm_map_protect(&p->p_vmspace->vm_map, 577 sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 578 FALSE); 579 } 580 } 581 if (i < 0) { 582 i = SIGTRAP; 583 break; 584 } 585 p->p_md.md_ss_addr = 0; 586 goto out; 587 } 588 589 case T_RES_INST+T_USER: 590 i = SIGILL; 591 break; 592 593 case T_COP_UNUSABLE+T_USER: 594 if ((causeReg & MACH_CR_COP_ERR) != 0x10000000) { 595 i = SIGILL; /* only FPU instructions allowed */ 596 break; 597 } 598 MachSwitchFPState(machFPCurProcPtr, p->p_md.md_regs); 599 machFPCurProcPtr = p; 600 p->p_md.md_regs[PS] |= MACH_SR_COP_1_BIT; 601 p->p_md.md_flags |= MDP_FPUSED; 602 goto out; 603 604 case T_OVFLOW+T_USER: 605 i = SIGFPE; 606 break; 607 608 case T_ADDR_ERR_LD: /* misaligned access */ 609 case T_ADDR_ERR_ST: /* misaligned access */ 610 case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ 611 if (i = ((struct pcb *)UADDR)->pcb_onfault) { 612 ((struct pcb *)UADDR)->pcb_onfault = 0; 613 return (onfault_table[i]); 614 } 615 /* FALLTHROUGH */ 616 617 default: 618 err: 619 #ifdef KADB 620 { 621 extern struct pcb kdbpcb; 622 623 if (USERMODE(statusReg)) 624 kdbpcb = p->p_addr->u_pcb; 625 else { 626 kdbpcb.pcb_regs[ZERO] = 0; 627 kdbpcb.pcb_regs[AST] = ((int *)&args)[2]; 628 kdbpcb.pcb_regs[V0] = ((int *)&args)[3]; 629 kdbpcb.pcb_regs[V1] = ((int *)&args)[4]; 630 kdbpcb.pcb_regs[A0] = ((int *)&args)[5]; 631 kdbpcb.pcb_regs[A1] = ((int *)&args)[6]; 632 kdbpcb.pcb_regs[A2] = ((int *)&args)[7]; 633 kdbpcb.pcb_regs[A3] = ((int *)&args)[8]; 634 kdbpcb.pcb_regs[T0] = ((int *)&args)[9]; 635 kdbpcb.pcb_regs[T1] = ((int *)&args)[10]; 636 kdbpcb.pcb_regs[T2] = ((int *)&args)[11]; 637 kdbpcb.pcb_regs[T3] = ((int *)&args)[12]; 638 kdbpcb.pcb_regs[T4] = ((int *)&args)[13]; 639 kdbpcb.pcb_regs[T5] = ((int *)&args)[14]; 640 kdbpcb.pcb_regs[T6] = ((int *)&args)[15]; 641 kdbpcb.pcb_regs[T7] = ((int *)&args)[16]; 642 kdbpcb.pcb_regs[T8] = ((int *)&args)[17]; 643 kdbpcb.pcb_regs[T9] = ((int *)&args)[18]; 644 kdbpcb.pcb_regs[RA] = ((int *)&args)[19]; 645 kdbpcb.pcb_regs[MULLO] = ((int *)&args)[21]; 646 kdbpcb.pcb_regs[MULHI] = ((int *)&args)[22]; 647 kdbpcb.pcb_regs[PC] = pc; 648 kdbpcb.pcb_regs[SR] = statusReg; 649 bzero((caddr_t)&kdbpcb.pcb_regs[F0], 33 * sizeof(int)); 650 } 651 if (kdb(causeReg, vadr, p, !USERMODE(statusReg))) 652 return (kdbpcb.pcb_regs[PC]); 653 } 654 #else 655 #ifdef DEBUG 656 printf("trap: pid %d %s sig %d adr %x pc %x ra %x\n", p->p_pid, 657 p->p_comm, i, vadr, pc, p->p_md.md_regs[RA]); /* XXX */ 658 trapDump("trap"); 659 #endif 660 #endif 661 panic("trap"); 662 } 663 printf("trap: pid %d %s sig %d adr %x pc %x ra %x\n", p->p_pid, 664 p->p_comm, i, vadr, pc, p->p_md.md_regs[RA]); /* XXX */ 665 trapsignal(p, i, ucode); 666 out: 667 /* 668 * Note: we should only get here if returning to user mode. 669 */ 670 /* take pending signals */ 671 while ((i = CURSIG(p)) != 0) 672 psig(i); 673 p->p_pri = p->p_usrpri; 674 astpending = 0; 675 if (want_resched) { 676 int s; 677 678 /* 679 * Since we are curproc, clock will normally just change 680 * our priority without moving us from one queue to another 681 * (since the running process is not on a queue.) 682 * If that happened after we setrq ourselves but before we 683 * swtch()'ed, we might not be on the queue indicated by 684 * our priority. 685 */ 686 s = splstatclock(); 687 setrq(p); 688 p->p_stats->p_ru.ru_nivcsw++; 689 swtch(); 690 splx(s); 691 while ((i = CURSIG(p)) != 0) 692 psig(i); 693 } 694 /* 695 * If profiling, charge system time to the trapped pc. 696 */ 697 if (p->p_flag & SPROFIL) { 698 extern int psratio; 699 700 addupc_task(p, pc, (int)(p->p_sticks - sticks) * psratio); 701 } 702 curpri = p->p_pri; 703 return (pc); 704 } 705 706 int badaddr_flag; 707 708 /* 709 * Handle an interrupt. 710 * Called from MachKernIntr() or MachUserIntr() 711 * Note: curproc might be NULL. 712 */ 713 interrupt(statusReg, causeReg, pc) 714 unsigned statusReg; /* status register at time of the exception */ 715 unsigned causeReg; /* cause register at time of exception */ 716 unsigned pc; /* program counter where to continue */ 717 { 718 register unsigned mask; 719 struct clockframe cf; 720 int oonfault = ((struct pcb *)UADDR)->pcb_onfault; 721 722 #ifdef DEBUG 723 trp->status = statusReg; 724 trp->cause = causeReg; 725 trp->vadr = 0; 726 trp->pc = pc; 727 trp->ra = 0; 728 trp->code = 0; 729 if (++trp == &trapdebug[TRAPSIZE]) 730 trp = trapdebug; 731 #endif 732 733 mask = causeReg & statusReg; /* pending interrupts & enable mask */ 734 if (mask & MACH_INT_MASK_5) { /* level 5 interrupt */ 735 splx((MACH_SPL_MASK_8 & ~causeReg) | MACH_SR_INT_ENA_CUR); 736 printf("level 5 interrupt: PC %x CR %x SR %x\n", 737 pc, causeReg, statusReg); 738 causeReg &= ~MACH_INT_MASK_5; 739 } 740 if (mask & MACH_INT_MASK_4) { /* level 4 interrupt */ 741 /* 742 * asynchronous bus error 743 */ 744 splx((MACH_SPL_MASK_7 & ~causeReg) | MACH_SR_INT_ENA_CUR); 745 *(char *)INTCLR0 = INTCLR0_BERR; 746 causeReg &= ~MACH_INT_MASK_4; 747 #define BADADDR 1 748 if (oonfault == BADADDR) { /* XXX */ 749 badaddr_flag = 1; 750 } else { 751 printf("level 4 interrupt: PC %x CR %x SR %x\n", 752 pc, causeReg, statusReg); 753 } 754 } 755 if (mask & MACH_INT_MASK_3) { /* level 3 interrupt */ 756 /* 757 * fp error 758 */ 759 splx((MACH_SPL_MASK_6 & ~causeReg) | MACH_SR_INT_ENA_CUR); 760 if (!USERMODE(statusReg)) { 761 #ifdef DEBUG 762 trapDump("fpintr"); 763 #else 764 printf("FPU interrupt: PC %x CR %x SR %x\n", 765 pc, causeReg, statusReg); 766 #endif 767 } else 768 MachFPInterrupt(statusReg, causeReg, pc); 769 causeReg &= ~MACH_INT_MASK_3; 770 } 771 if (mask & MACH_INT_MASK_2) { /* level 2 interrupt */ 772 register int stat; 773 774 splx((MACH_SPL_MASK_5 & ~causeReg) | MACH_SR_INT_ENA_CUR); 775 stat = *(volatile u_char *)INTST0; 776 if (stat & INTST0_TIMINT) { /* timer */ 777 static int led_count = 0; 778 779 *(volatile u_char *)INTCLR0 = INTCLR0_TIMINT; 780 cf.pc = pc; 781 cf.sr = statusReg; 782 hardclock(&cf); 783 if (++led_count > hz) { 784 led_count = 0; 785 *(volatile u_char *)DEBUG_PORT ^= DP_LED1; 786 } 787 } 788 #if NBM > 0 789 if (stat & INTST0_KBDINT) /* keyboard */ 790 kbm_rint(SCC_KEYBOARD); 791 #endif 792 #if NMS > 0 793 if (stat & INTST0_MSINT) /* mouse */ 794 kbm_rint(SCC_MOUSE); 795 #endif 796 causeReg &= ~MACH_INT_MASK_2; 797 } 798 if (mask & MACH_INT_MASK_1) { /* level 1 interrupt */ 799 splx((MACH_SPL_MASK_4 & ~causeReg) | MACH_SR_INT_ENA_CUR); 800 level1_intr(); 801 causeReg &= ~MACH_INT_MASK_1; 802 } 803 if (mask & MACH_INT_MASK_0) { /* level 0 interrupt */ 804 splx((MACH_SPL_MASK_3 & ~causeReg) | MACH_SR_INT_ENA_CUR); 805 level0_intr(); 806 causeReg &= ~MACH_INT_MASK_0; 807 } 808 splx((MACH_SPL_MASK_3 & ~causeReg) | MACH_SR_INT_ENA_CUR); 809 810 if (mask & MACH_SOFT_INT_MASK_0) { 811 struct clockframe cf; 812 813 clearsoftclock(); 814 cnt.v_soft++; 815 cf.pc = pc; 816 cf.sr = statusReg; 817 softclock(); 818 } 819 /* process network interrupt if we trapped or will very soon */ 820 if ((mask & MACH_SOFT_INT_MASK_1) || 821 netisr && (statusReg & MACH_SOFT_INT_MASK_1)) { 822 clearsoftnet(); 823 cnt.v_soft++; 824 #ifdef INET 825 if (netisr & (1 << NETISR_ARP)) { 826 netisr &= ~(1 << NETISR_ARP); 827 arpintr(); 828 } 829 if (netisr & (1 << NETISR_IP)) { 830 netisr &= ~(1 << NETISR_IP); 831 ipintr(); 832 } 833 #endif 834 #ifdef NS 835 if (netisr & (1 << NETISR_NS)) { 836 netisr &= ~(1 << NETISR_NS); 837 nsintr(); 838 } 839 #endif 840 #ifdef ISO 841 if (netisr & (1 << NETISR_ISO)) { 842 netisr &= ~(1 << NETISR_ISO); 843 clnlintr(); 844 } 845 #endif 846 } 847 /* restore onfault flag */ 848 ((struct pcb *)UADDR)->pcb_onfault = oonfault; 849 } 850 851 /* 852 * This is called from MachUserIntr() if astpending is set. 853 * This is very similar to the tail of trap(). 854 */ 855 softintr(statusReg, pc) 856 unsigned statusReg; /* status register at time of the exception */ 857 unsigned pc; /* program counter where to continue */ 858 { 859 register struct proc *p = curproc; 860 int sig; 861 862 cnt.v_soft++; 863 /* take pending signals */ 864 while ((sig = CURSIG(p)) != 0) 865 psig(sig); 866 p->p_pri = p->p_usrpri; 867 astpending = 0; 868 if (p->p_flag & SOWEUPC) { 869 p->p_flag &= ~SOWEUPC; 870 ADDUPROF(p); 871 } 872 if (want_resched) { 873 int s; 874 875 /* 876 * Since we are curproc, clock will normally just change 877 * our priority without moving us from one queue to another 878 * (since the running process is not on a queue.) 879 * If that happened after we setrq ourselves but before we 880 * swtch()'ed, we might not be on the queue indicated by 881 * our priority. 882 */ 883 s = splstatclock(); 884 setrq(p); 885 p->p_stats->p_ru.ru_nivcsw++; 886 swtch(); 887 splx(s); 888 while ((sig = CURSIG(p)) != 0) 889 psig(sig); 890 } 891 curpri = p->p_pri; 892 } 893 894 #ifdef DEBUG 895 trapDump(msg) 896 char *msg; 897 { 898 register int i; 899 int s; 900 901 s = splhigh(); 902 printf("trapDump(%s)\n", msg); 903 for (i = 0; i < TRAPSIZE; i++) { 904 if (trp == trapdebug) 905 trp = &trapdebug[TRAPSIZE - 1]; 906 else 907 trp--; 908 if (trp->cause == 0) 909 break; 910 printf("%s: ADR %x PC %x CR %x SR %x\n", 911 trap_type[(trp->cause & MACH_CR_EXC_CODE) >> 912 MACH_CR_EXC_CODE_SHIFT], 913 trp->vadr, trp->pc, trp->cause, trp->status); 914 printf(" RA %x code %d\n", trp->ra, trp->code); 915 } 916 bzero(trapdebug, sizeof(trapdebug)); 917 trp = trapdebug; 918 splx(s); 919 } 920 #endif 921 922 /* 923 * Return the resulting PC as if the branch was executed. 924 */ 925 unsigned 926 MachEmulateBranch(regsPtr, instPC, fpcCSR, allowNonBranch) 927 unsigned *regsPtr; 928 unsigned instPC; 929 unsigned fpcCSR; 930 int allowNonBranch; 931 { 932 InstFmt inst; 933 unsigned retAddr; 934 int condition; 935 extern unsigned GetBranchDest(); 936 937 #if 0 938 printf("regsPtr=%x PC=%x Inst=%x fpcCsr=%x\n", regsPtr, instPC, 939 *(unsigned *)instPC, fpcCSR); 940 #endif 941 942 inst = *(InstFmt *)instPC; 943 switch ((int)inst.JType.op) { 944 case OP_SPECIAL: 945 switch ((int)inst.RType.func) { 946 case OP_JR: 947 case OP_JALR: 948 retAddr = regsPtr[inst.RType.rs]; 949 break; 950 951 default: 952 if (!allowNonBranch) 953 panic("MachEmulateBranch: Non-branch"); 954 retAddr = instPC + 4; 955 break; 956 } 957 break; 958 959 case OP_BCOND: 960 switch ((int)inst.IType.rt) { 961 case OP_BLTZ: 962 case OP_BLTZAL: 963 if ((int)(regsPtr[inst.RType.rs]) < 0) 964 retAddr = GetBranchDest((InstFmt *)instPC); 965 else 966 retAddr = instPC + 8; 967 break; 968 969 case OP_BGEZAL: 970 case OP_BGEZ: 971 if ((int)(regsPtr[inst.RType.rs]) >= 0) 972 retAddr = GetBranchDest((InstFmt *)instPC); 973 else 974 retAddr = instPC + 8; 975 break; 976 977 default: 978 panic("MachEmulateBranch: Bad branch cond"); 979 } 980 break; 981 982 case OP_J: 983 case OP_JAL: 984 retAddr = (inst.JType.target << 2) | 985 ((unsigned)instPC & 0xF0000000); 986 break; 987 988 case OP_BEQ: 989 if (regsPtr[inst.RType.rs] == regsPtr[inst.RType.rt]) 990 retAddr = GetBranchDest((InstFmt *)instPC); 991 else 992 retAddr = instPC + 8; 993 break; 994 995 case OP_BNE: 996 if (regsPtr[inst.RType.rs] != regsPtr[inst.RType.rt]) 997 retAddr = GetBranchDest((InstFmt *)instPC); 998 else 999 retAddr = instPC + 8; 1000 break; 1001 1002 case OP_BLEZ: 1003 if ((int)(regsPtr[inst.RType.rs]) <= 0) 1004 retAddr = GetBranchDest((InstFmt *)instPC); 1005 else 1006 retAddr = instPC + 8; 1007 break; 1008 1009 case OP_BGTZ: 1010 if ((int)(regsPtr[inst.RType.rs]) > 0) 1011 retAddr = GetBranchDest((InstFmt *)instPC); 1012 else 1013 retAddr = instPC + 8; 1014 break; 1015 1016 case OP_COP1: 1017 switch (inst.RType.rs) { 1018 case OP_BCx: 1019 case OP_BCy: 1020 if ((inst.RType.rt & COPz_BC_TF_MASK) == COPz_BC_TRUE) 1021 condition = fpcCSR & MACH_FPC_COND_BIT; 1022 else 1023 condition = !(fpcCSR & MACH_FPC_COND_BIT); 1024 if (condition) 1025 retAddr = GetBranchDest((InstFmt *)instPC); 1026 else 1027 retAddr = instPC + 8; 1028 break; 1029 1030 default: 1031 if (!allowNonBranch) 1032 panic("MachEmulateBranch: Bad coproc branch instruction"); 1033 retAddr = instPC + 4; 1034 } 1035 break; 1036 1037 default: 1038 if (!allowNonBranch) 1039 panic("MachEmulateBranch: Non-branch instruction"); 1040 retAddr = instPC + 4; 1041 } 1042 #if 0 1043 printf("Target addr=%x\n", retAddr); 1044 #endif 1045 return (retAddr); 1046 } 1047 1048 unsigned 1049 GetBranchDest(InstPtr) 1050 InstFmt *InstPtr; 1051 { 1052 return ((unsigned)InstPtr + 4 + ((short)InstPtr->IType.imm << 2)); 1053 } 1054 1055 /* 1056 * This routine is called by procxmt() to single step one instruction. 1057 * We do this by storing a break instruction after the current instruction, 1058 * resuming execution, and then restoring the old instruction. 1059 */ 1060 cpu_singlestep(p) 1061 register struct proc *p; 1062 { 1063 register unsigned va; 1064 register int *locr0 = p->p_md.md_regs; 1065 int i; 1066 1067 /* compute next address after current location */ 1068 va = MachEmulateBranch(locr0, locr0[PC], 0, 1); 1069 if (p->p_md.md_ss_addr || p->p_md.md_ss_addr == va || 1070 !useracc((caddr_t)va, 4, B_READ)) { 1071 printf("SS %s (%d): breakpoint already set at %x (va %x)\n", 1072 p->p_comm, p->p_pid, p->p_md.md_ss_addr, va); /* XXX */ 1073 return (EFAULT); 1074 } 1075 p->p_md.md_ss_addr = va; 1076 p->p_md.md_ss_instr = fuiword((caddr_t)va); 1077 i = suiword((caddr_t)va, MACH_BREAK_SSTEP); 1078 if (i < 0) { 1079 vm_offset_t sa, ea; 1080 int rv; 1081 1082 sa = trunc_page((vm_offset_t)va); 1083 ea = round_page((vm_offset_t)va+sizeof(int)-1); 1084 rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, 1085 VM_PROT_DEFAULT, FALSE); 1086 if (rv == KERN_SUCCESS) { 1087 i = suiword((caddr_t)va, MACH_BREAK_SSTEP); 1088 (void) vm_map_protect(&p->p_vmspace->vm_map, 1089 sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE); 1090 } 1091 } 1092 if (i < 0) 1093 return (EFAULT); 1094 printf("SS %s (%d): breakpoint set at %x: %x (pc %x)\n", 1095 p->p_comm, p->p_pid, p->p_md.md_ss_addr, 1096 p->p_md.md_ss_instr, locr0[PC]); /* XXX */ 1097 return (0); 1098 } 1099 1100 /* 1101 * news3400 - INT0 service routine. 1102 * 1103 * INTST0 bit 4: dma 1104 * 3: slot #1 1105 * 2: slot #3 1106 * 1: external #1 1107 * 0: external #3 1108 */ 1109 1110 #define LEVEL0_MASK \ 1111 (INTST1_DMA|INTST1_SLOT1|INTST1_SLOT3|INTST1_EXT1|INTST1_EXT3) 1112 1113 level0_intr() 1114 { 1115 register int stat; 1116 1117 stat = *(volatile u_char *)INTST1 & LEVEL0_MASK; 1118 *(u_char *)INTCLR1 = stat; 1119 1120 if (stat & INTST1_DMA) 1121 dma_intr(); 1122 if (stat & INTST1_SLOT1) 1123 exec_hb_intr2(); 1124 #if NEN > 0 1125 if (stat & INTST1_SLOT3) { 1126 int s, t; 1127 1128 s = splimp(); 1129 t = lance_intr(); 1130 (void) splx(s); 1131 if (t == 0) 1132 exec_hb_intr4(); 1133 } 1134 #endif 1135 #if NLE > 0 1136 if (stat & INTST1_SLOT3) { 1137 int s; 1138 1139 s = splimp(); 1140 leintr(0); 1141 (void) splx(s); 1142 } 1143 #endif 1144 if (stat & INTST1_EXT1) 1145 print_int_stat("EXT #1"); 1146 if (stat & INTST1_EXT3) 1147 print_int_stat("EXT #3"); 1148 } 1149 1150 /* 1151 * news3400 - INT1 service routine. 1152 * 1153 * INTST0 bit 1: centro fault 1154 * 0: centro busy 1155 * INTST1 bit 7: beep 1156 * 6: scc 1157 * 5: lance 1158 */ 1159 1160 #define LEVEL1_MASK2 (INTST0_CFLT|INTST0_CBSY) 1161 #define LEVEL1_MASK1 (INTST1_BEEP|INTST1_SCC|INTST1_LANCE) 1162 1163 level1_intr(pc) 1164 unsigned pc; 1165 { 1166 register int stat; 1167 register u_int saved_inten1 = *(u_char *)INTEN1; 1168 1169 *(u_char *)INTEN1 = 0; /* disable intr: beep, lance, scc */ 1170 1171 stat = *(volatile u_char *)INTST1 & LEVEL1_MASK1; 1172 *(u_char *)INTCLR1 = stat; 1173 1174 stat &= saved_inten1; 1175 1176 if (stat & INTST1_BEEP) { 1177 *(volatile u_char *)INTCLR1 = INTCLR1_BEEP; 1178 print_int_stat("BEEP"); 1179 } 1180 if (stat & INTST1_SCC) { 1181 scc_intr(); 1182 if (saved_inten1 & *(u_char *)INTST1 & INTST1_SCC) 1183 scc_intr(); 1184 } 1185 #if NEN > 0 1186 if (stat & INTST1_LANCE) 1187 lance_intr(); 1188 #endif 1189 #if NLE > 0 1190 if (stat & INTST1_LANCE) 1191 leintr(0); 1192 #endif 1193 1194 *(u_char *)INTEN1 = saved_inten1; 1195 1196 #if NLP > 0 1197 /* 1198 * The PARK2 cannot find centro interrupt correctly. 1199 * We must check it by reading the cause register of cpu 1200 * while other interrupts are disabled. 1201 */ 1202 { 1203 register int causereg; 1204 int s = splhigh(); 1205 1206 causereg = get_causereg(); 1207 (void) splx(s); 1208 1209 if ((causereg & CAUSE_IP4) == 0) 1210 return; 1211 } 1212 #endif 1213 1214 stat = (int)(*(u_char *)INTST0) & LEVEL1_MASK2; 1215 *(u_char *)INTCLR0 = stat; 1216 1217 if (stat & INTST0_CBSY) /* centro busy */ 1218 #if NLP > 0 1219 lpxint(0); 1220 #else 1221 printf("stray intr: CBSY\n"); 1222 #endif 1223 } 1224 1225 /* 1226 * DMA interrupt service routine. 1227 */ 1228 dma_intr() 1229 { 1230 register volatile u_char *gsp = (u_char *)DMAC_GSTAT; 1231 register u_int gstat = *gsp; 1232 register int mrqb, i; 1233 1234 /* 1235 * when DMA intrrupt occurs there remain some untransferred data. 1236 * wait data transfer completion. 1237 */ 1238 mrqb = (gstat & (CH0_INT|CH1_INT|CH2_INT|CH3_INT)) << 1; 1239 if (gstat & mrqb) { 1240 /* 1241 * SHOULD USE DELAY() 1242 */ 1243 for (i = 0; i < 50; i++) 1244 ; 1245 if (*gsp & mrqb) 1246 printf("dma_intr: MRQ\n"); 1247 } 1248 1249 /* SCSI Dispatch */ 1250 if (gstat & CH_INT(CH_SCSI)) 1251 scintr(); 1252 1253 #include "fd.h" 1254 #if NFD > 0 1255 /* FDC Interrupt Dispatch */ 1256 if (gstat & CH_INT(CH_FDC)) 1257 fdc_intr(0); 1258 #endif /* NFD > 0 */ 1259 1260 #include "sb.h" 1261 #if NSB > 0 1262 /* Audio Interface Dispatch */ 1263 sbintr(0); 1264 #endif /* NSB > 0 */ 1265 1266 /* Video I/F Dispatch */ 1267 if (gstat & CH_INT(CH_VIDEO)) 1268 ; 1269 } 1270 1271 /* 1272 * SCC vector interrupt service routine. 1273 */ 1274 scc_intr() 1275 { 1276 int vec; 1277 extern int scc_xint(), scc_sint(), scc_rint(), scc_cint(); 1278 static int (*func[])() = { 1279 scc_xint, 1280 scc_sint, 1281 scc_rint, 1282 scc_cint 1283 }; 1284 1285 vec = *(volatile u_char *)SCCVECT; 1286 (*func[(vec & SCC_INT_MASK) >> 1])(vec); 1287 } 1288 1289 print_int_stat(msg) 1290 char *msg; 1291 { 1292 int s0 = *(volatile u_char *)INTST0; 1293 int s1 = *(volatile u_char *)INTST1; 1294 1295 if (msg) 1296 printf("%s: ", msg); 1297 else 1298 printf("intr: "); 1299 printf("INTST0=0x%x, INTST1=0x%x.\n", s0, s1); 1300 } 1301 1302 traceback() 1303 { 1304 u_int pc, sp; 1305 1306 getpcsp(&pc, &sp); 1307 backtr(pc, sp); 1308 } 1309 1310 #define EF_RA 92 /* r31: return address */ 1311 #define KERN_REG_SIZE (18 * 4) 1312 #define STAND_FRAME_SIZE 24 1313 #define EF_SIZE STAND_FRAME_SIZE + KERN_REG_SIZE + 12 1314 1315 extern u_int MachKernGenExceptionEnd[]; 1316 extern u_int end[]; 1317 #define ENDOFTXT (end + 1) 1318 1319 #define VALID_TEXT(pc) \ 1320 ((u_int *)MACH_CODE_START <= (u_int *)MACH_UNCACHED_TO_CACHED(pc) && \ 1321 (u_int *)MACH_UNCACHED_TO_CACHED(pc) <= (u_int *)ENDOFTXT) 1322 1323 #define ExceptionHandler(x) \ 1324 ((u_int*)MachKernGenException < (u_int*)MACH_UNCACHED_TO_CACHED(x) && \ 1325 (u_int*)MACH_UNCACHED_TO_CACHED(x) < (u_int*)MachKernGenExceptionEnd) 1326 1327 backtr(pc, sp) 1328 register u_int *pc; 1329 register caddr_t sp; 1330 { 1331 int fsize; 1332 u_int *getra(); 1333 extern int _gp[]; 1334 1335 printf("start trace back pc=%x, sp=%x, pid=%d[%s]\n", 1336 pc, sp, curproc->p_pid, curproc->p_comm); 1337 1338 while (VALID_TEXT(pc)) { 1339 if (sp >= (caddr_t)KERNELSTACK || sp < (caddr_t)UADDR) { 1340 printf("stack exhausted (sp=0x%x)\n", sp); 1341 break; 1342 } 1343 if (ExceptionHandler(pc)) { 1344 pc = (u_int *)(*((u_int *)&sp[EF_RA])); 1345 sp += EF_SIZE; 1346 printf("trapped from pc=%x, sp=%x\n", pc, sp); 1347 } else { 1348 pc = getra(pc, sp, &fsize); 1349 sp += fsize; 1350 printf("called from pc=%x, sp=%x\n", pc, sp); 1351 } 1352 } 1353 printf("trace back END. pid=%d[%s]\n", curproc->p_pid, curproc->p_comm); 1354 } 1355 1356 #define NPCSTOCK 128 1357 1358 u_int * 1359 getra(pc, sp, fsize) 1360 register int *pc; 1361 register caddr_t sp; 1362 int *fsize; 1363 { 1364 u_int regs[32]; 1365 int *opcs[NPCSTOCK]; 1366 register int i, nbpc = 0; 1367 int printed = 0; 1368 InstFmt I; 1369 1370 *fsize = 0; 1371 for (i = 0; i < 32; i++) regs[i] = 0; 1372 for (; (u_int*)MACH_UNCACHED_TO_CACHED(pc) < (u_int*)ENDOFTXT; pc++) { 1373 I.word = *pc; 1374 switch (I.IType.op) { 1375 1376 case OP_ADDIU: 1377 /* sp += fsize */ 1378 if (I.IType.rs == SP && I.IType.rt == SP) 1379 *fsize = (u_short)I.IType.imm; 1380 break; 1381 1382 case OP_LW: 1383 if (I.IType.rs != SP) 1384 break; 1385 regs[I.IType.rt] = *(u_int *)&sp[(short)I.IType.imm]; 1386 break; 1387 1388 case OP_BEQ: 1389 if (I.IType.rs != ZERO || I.IType.rt != ZERO) 1390 break; 1391 for (i = 0; i < nbpc; i++) 1392 if (pc == opcs[i]) { 1393 /* 1394 * Brach constructs infinite loop. 1395 */ 1396 if (!printed) { 1397 printf("branch loop\n"); 1398 printed = 1; 1399 } 1400 break; 1401 } 1402 if (i == nbpc) { 1403 opcs[nbpc] = pc; 1404 nbpc = imin(nbpc + 1, NPCSTOCK); 1405 pc = pc + (short)I.IType.imm; 1406 } 1407 break; 1408 1409 default: 1410 break; 1411 } 1412 1413 I.word = *(pc - 1); 1414 if (I.RType.op == OP_SPECIAL && I.RType.func == OP_JR) 1415 return ((int *)regs[I.RType.rs]); 1416 } 1417 printf("pc run out of TEXT\n"); 1418 return (0); 1419 } 1420