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