#include "../h/local.h" #ifdef SCCS_ID static char SCCS_ID [] = "@(#)trap.c 3.1 13:54:10 - 81/09/04 "; #endif SCCS_ID #include "../h/param.h" #include "../h/systm.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/proc.h" #include "../h/reg.h" #include "../h/seg.h" #define EBIT 0x08 /* user err bit in psw: C-bit */ #define SYS 0xe1 /* svc (trap) instruction */ #define USER 0x10 /* user-mode flag added to dev */ /* * Offsets of the user's registers relative to * the saved r0. See reg.h */ int regloc[NREGS] = { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, PC, RPS }; /* * Called from low.s when a processor trap occurs. * The arguments are the words saved on the system stack * by the software during the trap processing. * Their order is dictated by the details * of C's calling sequence. They are peculiar in that * this call is not 'by value' and changed user registers * get copied back on return. * dev is the kind of trap that occurred. */ trap(dev, stat, r0, r1, r2, r3, r4, r5, r6, asp, rf, ps, pc, nps) int *pc; { register i; register *a; register struct sysent *callp; time_t syst; extern char *panicstr; trace(0x02, "trap", dev); trace(0x02, "loc", pc); syst = u.u_stime; u.u_fpsaved = 0; if (USERMODE(ps)) dev |= USER; u.u_ar0 = &r0; switch(dev) { /* * Trap not expected. * Usually a kernel mode address error. */ default: panicstr = 1; printf("Useg = %x\n", useg); printf("PSW = %x %x\n", ps, pc); printf("ar0 = %x\n", &r0); printf("trap type %d\n", dev); panic("trap"); case 0+USER: /* memory error */ i = SIGBUS; break; case 1+USER: /* illegal instruction */ /* * Assume emulated floating-point instruction. * Nonzero return from fptrap means illegal instruction or * floating point error. */ if (i = fptrap(&r0, &u.u_fps)) break; goto out; case 2+USER: /* bpt or trace */ i = SIGTRC; break; case 3+USER: /* iot */ i = SIGIOT; break; case 5+USER: /* emt */ i = SIGEMT; break; case 6+USER: /* sys call */ u.u_error = 0; ps &= ~EBIT; #ifdef SVC6 u.u_svc6 = stat&0x100; /* old style system call */ #endif callp = &sysent[stat&077]; /* stat is svc no. */ if (callp == sysent) { /* indirect */ a = (int *)fuiword((caddr_t)pc); pc++; i = fuword((caddr_t)a); a++; if ((i >> 24) != SYS) i = 077; /* illegal */ callp = &sysent[i&077]; } else { a = pc; pc += callp->sy_narg - callp->sy_nrarg; } trace(0x04, "svc", callp-sysent); for (i=0; isy_nrarg; i++) u.u_arg[i] = u.u_ar0[regloc[i]]; for(; isy_narg; i++) u.u_arg[i] = fuword((caddr_t)a++); u.u_dirp = (caddr_t)u.u_arg[0]; u.u_r.r_val1 = u.u_ar0[R0]; u.u_r.r_val2 = u.u_ar0[R1]; u.u_ap = u.u_arg; if (save(u.u_qsav)) { if (u.u_error==0) u.u_error = EINTR; } else { (*callp->sy_call)(); } if(u.u_error) { ps |= EBIT; u.u_ar0[R0] = u.u_error; } else { u.u_ar0[R0] = u.u_r.r_val1; u.u_ar0[R1] = u.u_r.r_val2; } goto out; case 8+USER: /* arithmetic fault */ i = SIGFPT; break; /* * If the user SP is below the stack segment, * grow the stack automatically. * This relies on the ability of the hardware * to restart a half executed instruction. * At the moment this is unimplemented (and possibly * unimplementable) on the Interdata. */ case 9+USER: /* segmentation exception */ { /*** register int osp; osp = sp; if(backup(u.u_ar0) == 0) if(grow((unsigned)osp)) goto out; ***/ i = SIGSEG; break; } case 10+USER: /* illegal svc number */ i = SIGSYS; break; case 12+USER: /* allow cpu switch */ goto out; case 13+USER: /* data format or alignment fault */ i = SIGBUS; break; } psignal(u.u_procp, i); out: if(issig()) psig(); curpri = setpri(u.u_procp); if (runrun) qswtch(); if(u.u_prof.pr_scale) addupc((caddr_t)pc, &u.u_prof, (int)(u.u_stime-syst)); if (u.u_fpsaved) restfp(&u.u_fps); } /* * nonexistent system call-- set fatal error code. */ nosys() { u.u_error = EINVAL; } /* * Ignored system call */ nullsys() { }