134408Skarels /*
234408Skarels * Copyright (c) 1988 Regents of the University of California.
334408Skarels * All rights reserved. The Berkeley software License Agreement
434408Skarels * specifies the terms and conditions for redistribution.
534408Skarels *
6*64622Sbostic * @(#)trap.c 7.14 (Berkeley) 09/23/93
734408Skarels */
824012Ssam
945798Sbostic #include "sys/param.h"
1045798Sbostic #include "sys/systm.h"
1145798Sbostic #include "sys/user.h"
1245798Sbostic #include "sys/proc.h"
1345798Sbostic #include "sys/seg.h"
1445798Sbostic #include "sys/acct.h"
1545798Sbostic #include "sys/kernel.h"
1634408Skarels
1745798Sbostic #include "../include/psl.h"
1845798Sbostic #include "../include/reg.h"
1945798Sbostic #include "../include/pte.h"
2045798Sbostic #include "../include/mtpr.h"
2138404Smarc #ifdef KTRACE
2245798Sbostic #include "sys/ktrace.h"
2324012Ssam #endif
2424012Ssam
2545798Sbostic #include "../include/trap.h"
2625678Ssam
2724012Ssam #define USER 040 /* user-mode flag added to type */
2824012Ssam
2925678Ssam struct sysent sysent[];
3025678Ssam int nsysent;
3124012Ssam
3225678Ssam char *trap_type[] = {
3325678Ssam "Reserved addressing mode", /* T_RESADFLT */
3425678Ssam "Privileged instruction", /* T_PRIVINFLT */
3525678Ssam "Reserved operand", /* T_RESOPFLT */
3625678Ssam "Breakpoint", /* T_BPTFLT */
3725678Ssam 0,
3825678Ssam "Kernel call", /* T_SYSCALL */
3925678Ssam "Arithmetic trap", /* T_ARITHTRAP */
4025678Ssam "System forced exception", /* T_ASTFLT */
4125678Ssam "Segmentation fault", /* T_SEGFLT */
4225678Ssam "Protection fault", /* T_PROTFLT */
4325678Ssam "Trace trap", /* T_TRCTRAP */
4425678Ssam 0,
4525678Ssam "Page fault", /* T_PAGEFLT */
4625678Ssam "Page table fault", /* T_TABLEFLT */
4725678Ssam "Alignment fault", /* T_ALIGNFLT */
4825678Ssam "Kernel stack not valid", /* T_KSPNOTVAL */
4925678Ssam "Bus error", /* T_BUSERR */
5038935Skarels "Kernel debugger request", /* T_KDBTRAP */
5125678Ssam };
5230176Ssam int TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]);
5325678Ssam
5424012Ssam /*
5524012Ssam * Called from the trap handler when a processor trap occurs.
5624012Ssam */
5725678Ssam /*ARGSUSED*/
trap(sp,type,hfs,accmst,acclst,dbl,code,pc,psl)5824012Ssam trap(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
5938935Skarels unsigned type, code; /* kdb assumes these are *not* registers */
6024012Ssam {
6125678Ssam int r0, r1; /* must reserve space */
6224012Ssam register int *locr0 = ((int *)&psl)-PS;
6324012Ssam register int i;
6438935Skarels unsigned ucode = code;
6524012Ssam register struct proc *p;
6624012Ssam struct timeval syst;
6724012Ssam
6825678Ssam #ifdef lint
6925678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1;
7025678Ssam #endif
7124012Ssam syst = u.u_ru.ru_stime;
7224012Ssam if (USERMODE(locr0[PS])) {
7324012Ssam type |= USER;
7424012Ssam u.u_ar0 = locr0;
7524012Ssam }
7624012Ssam switch (type) {
7724012Ssam
7825678Ssam default:
7934402Skarels #ifdef KADB
8030176Ssam if (kdb_trap(&psl))
8130176Ssam return;
8230176Ssam #endif
8325678Ssam printf("trap type %d, code = %x, pc = %x\n", type, code, pc);
8425678Ssam type &= ~USER;
8525678Ssam if (type < TRAP_TYPES && trap_type[type])
8625678Ssam panic(trap_type[type]);
8725678Ssam else
8825678Ssam panic("trap");
8925678Ssam /*NOTREACHED*/
9024012Ssam
9125678Ssam case T_PROTFLT + USER: /* protection fault */
9224012Ssam i = SIGBUS;
9324012Ssam break;
9424012Ssam
9524012Ssam case T_PRIVINFLT + USER: /* privileged instruction fault */
9625678Ssam case T_RESADFLT + USER: /* reserved addressing fault */
9725678Ssam case T_RESOPFLT + USER: /* resereved operand fault */
9825678Ssam case T_ALIGNFLT + USER: /* unaligned data fault */
9938935Skarels ucode = type &~ USER;
10024012Ssam i = SIGILL;
10124012Ssam break;
10224012Ssam
10325678Ssam case T_ASTFLT + USER: /* Allow process switch */
10424012Ssam case T_ASTFLT:
10524012Ssam astoff();
106*64622Sbostic if ((u.u_procp->p_flag & P_OWEUPC) && u.u_prof.pr_scale) {
10724012Ssam addupc(pc, &u.u_prof, 1);
108*64622Sbostic u.u_procp->p_flag &= ~P_OWEUPC;
10924012Ssam }
11024012Ssam goto out;
11124012Ssam
11224012Ssam case T_ARITHTRAP + USER:
11324012Ssam i = SIGFPE;
11424012Ssam break;
11524012Ssam
11624012Ssam /*
11724012Ssam * If the user SP is above the stack segment,
11824012Ssam * grow the stack automatically.
11924012Ssam */
12024012Ssam case T_SEGFLT + USER:
12124012Ssam if (grow((unsigned)locr0[SP]) || grow(code))
12224012Ssam goto out;
12324012Ssam i = SIGSEGV;
12424012Ssam break;
12524012Ssam
12625678Ssam case T_TABLEFLT: /* allow page table faults in kernel */
12725678Ssam case T_TABLEFLT + USER: /* page table fault */
12824012Ssam panic("ptable fault");
12924012Ssam
13025678Ssam case T_PAGEFLT: /* allow page faults in kernel mode */
13125678Ssam case T_PAGEFLT + USER: /* page fault */
13225678Ssam pagein(code, 0);
13324012Ssam if (type == T_PAGEFLT)
13424012Ssam return;
13524012Ssam goto out;
13624012Ssam
13725678Ssam case T_BPTFLT + USER: /* bpt instruction fault */
13825678Ssam case T_TRCTRAP + USER: /* trace trap */
13924012Ssam locr0[PS] &= ~PSL_T;
14024012Ssam i = SIGTRAP;
14124012Ssam break;
14225678Ssam
14338935Skarels #ifdef notdef
14438935Skarels /* THIS CODE IS BOGUS- delete? (KSP not valid is unrecoverable)
14538935Skarels And what does KSPNOTVAL in user-mode mean? */
14625746Ssam /*
14725746Ssam * For T_KSPNOTVAL and T_BUSERR, can not allow spl to
14825746Ssam * drop to 0 as clock could go off and we would end up
14925746Ssam * doing an rei to the interrupt stack at ipl 0 (a
15025746Ssam * reserved operand fault). Instead, we allow psignal
15125746Ssam * to post an ast, then return to user mode where we
15225746Ssam * will reenter the kernel on the kernel's stack and
15325746Ssam * can then service the signal.
15425746Ssam */
15524012Ssam case T_KSPNOTVAL:
15625746Ssam if (noproc)
15725746Ssam panic("ksp not valid");
15825746Ssam /* fall thru... */
15924012Ssam case T_KSPNOTVAL + USER:
16025772Ssam printf("pid %d: ksp not valid\n", u.u_procp->p_pid);
16138935Skarels panic("ksp not valid - 2");
16225746Ssam /* must insure valid kernel stack pointer? */
16325746Ssam psignal(u.u_procp, SIGKILL);
16425746Ssam return;
16538935Skarels #endif
16624012Ssam
16725678Ssam case T_BUSERR + USER:
16838935Skarels i = SIGBUS;
16938935Skarels break;
17024012Ssam }
17138935Skarels trapsignal(i, ucode);
17224012Ssam out:
17324012Ssam p = u.u_procp;
17440716Skarels if (i = CURSIG(p))
175*64622Sbostic postsig(i);
176*64622Sbostic p->p_priority = p->p_usrpri;
17724012Ssam if (runrun) {
17824012Ssam /*
17924012Ssam * Since we are u.u_procp, clock will normally just change
18024012Ssam * our priority without moving us from one queue to another
18124012Ssam * (since the running process is not on a queue.)
18264549Sbostic * If that happened after we put ourselves on the run queue
183*64622Sbostic * but before we Xswitch()'ed, we might not be on the queue
18464549Sbostic * indicated by our priority.
18524012Ssam */
18629561Ssam (void) splclock();
18764549Sbostic setrunqueue(p);
18824012Ssam u.u_ru.ru_nivcsw++;
189*64622Sbostic Xswitch();
19040716Skarels if (i = CURSIG(p))
191*64622Sbostic postsig(i);
19224012Ssam }
19324012Ssam if (u.u_prof.pr_scale) {
19424012Ssam int ticks;
19524012Ssam struct timeval *tv = &u.u_ru.ru_stime;
19624012Ssam
19724012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
19824012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
19924012Ssam if (ticks)
20024012Ssam addupc(locr0[PC], &u.u_prof, ticks);
20124012Ssam }
202*64622Sbostic curpriority = p->p_priority;
20324012Ssam }
20424012Ssam
20524012Ssam /*
20625678Ssam * Called from locore when a system call occurs
20724012Ssam */
20825678Ssam /*ARGSUSED*/
syscall(sp,type,hfs,accmst,acclst,dbl,code,pc,psl)20924012Ssam syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
21025678Ssam unsigned code;
21124012Ssam {
21225678Ssam int r0, r1; /* must reserve space */
21324012Ssam register int *locr0 = ((int *)&psl)-PS;
21425678Ssam register caddr_t params;
21525678Ssam register int i;
21624012Ssam register struct sysent *callp;
21738404Smarc register struct proc *p = u.u_procp;
21825678Ssam struct timeval syst;
21940716Skarels int error, opc;
22044019Skarels struct args {
22144019Skarels int i[8];
22244019Skarels } args;
22344019Skarels int rval[2];
22424012Ssam
22525678Ssam #ifdef lint
22625678Ssam r0 = 0; r0 = r0; r1 = 0; r1 = r1;
22725678Ssam #endif
22824012Ssam syst = u.u_ru.ru_stime;
22924012Ssam if (!USERMODE(locr0[PS]))
23024012Ssam panic("syscall");
23124012Ssam u.u_ar0 = locr0;
23224012Ssam params = (caddr_t)locr0[FP] + NBPW;
23325678Ssam /* BEGIN GROT */
23425678Ssam /*
23525678Ssam * Try to reconstruct pc, assuming code
23625678Ssam * is an immediate constant
23725678Ssam */
23824012Ssam opc = pc - 2; /* short literal */
23924012Ssam if (code > 0x3f) {
24025678Ssam opc--; /* byte immediate */
24124012Ssam if (code > 0x7f) {
24225678Ssam opc--; /* word immediate */
24324012Ssam if (code > 0x7fff)
24424012Ssam opc -= 2; /* long immediate */
24524012Ssam }
24624012Ssam }
24725678Ssam /* END GROT */
24843643Skarels if (code == 0) { /* indir */
24943643Skarels code = fuword(params);
25024012Ssam params += NBPW;
25124012Ssam }
25243643Skarels if (code >= nsysent)
25343643Skarels callp = &sysent[0]; /* indir (illegal) */
25443643Skarels else
25543643Skarels callp = &sysent[code];
25625678Ssam if ((i = callp->sy_narg * sizeof (int)) &&
25744019Skarels (error = copyin(params, (caddr_t)&args, (u_int)i)) != 0) {
25840716Skarels locr0[R0] = error;
25925678Ssam locr0[PS] |= PSL_C; /* carry bit */
26040669Smarc #ifdef KTRACE
26140669Smarc if (KTRPOINT(p, KTR_SYSCALL))
26244019Skarels ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);
26340669Smarc #endif
26425678Ssam goto done;
26524012Ssam }
26640669Smarc #ifdef KTRACE
26740669Smarc if (KTRPOINT(p, KTR_SYSCALL))
26844019Skarels ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);
26940669Smarc #endif
27043643Skarels rval[0] = 0;
27143643Skarels rval[1] = locr0[R1];
27244019Skarels error = (*callp->sy_call)(u.u_procp, &args, rval);
27340716Skarels if (error == ERESTART)
27440716Skarels pc = opc;
27540716Skarels else if (error != EJUSTRETURN) {
27640716Skarels if (error) {
27740716Skarels locr0[R0] = error;
27825678Ssam locr0[PS] |= PSL_C; /* carry bit */
27925678Ssam } else {
28025678Ssam locr0[PS] &= ~PSL_C; /* clear carry bit */
28143643Skarels locr0[R0] = rval[0];
28243643Skarels locr0[R1] = rval[1];
28325678Ssam }
28440716Skarels }
28540716Skarels /* else if (error == EJUSTRETURN) */
28625678Ssam /* nothing to do */
28724012Ssam done:
28840669Smarc /*
28940669Smarc * Reinitialize proc pointer `p' as it may be different
29040669Smarc * if this is a child returning from fork syscall.
29140669Smarc */
29224012Ssam p = u.u_procp;
29340716Skarels if (i = CURSIG(p))
294*64622Sbostic postsig(i);
295*64622Sbostic p->p_priority = p->p_usrpri;
29624012Ssam if (runrun) {
29724012Ssam /*
29824012Ssam * Since we are u.u_procp, clock will normally just change
29924012Ssam * our priority without moving us from one queue to another
30024012Ssam * (since the running process is not on a queue.)
30164549Sbostic * If that happened after we put ourselves on the run queue
302*64622Sbostic * but before we Xswitch()'ed, we might not be on the queue
30364549Sbostic * indicated by our priority.
30424012Ssam */
30529561Ssam (void) splclock();
30664549Sbostic setrunqueue(p);
30724012Ssam u.u_ru.ru_nivcsw++;
308*64622Sbostic Xswitch();
30940716Skarels if (i = CURSIG(p))
310*64622Sbostic postsig(i);
31124012Ssam }
31224012Ssam if (u.u_prof.pr_scale) {
31324012Ssam int ticks;
31424012Ssam struct timeval *tv = &u.u_ru.ru_stime;
31524012Ssam
31624012Ssam ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
31724012Ssam (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
31824012Ssam if (ticks)
31924012Ssam addupc(locr0[PC], &u.u_prof, ticks);
32024012Ssam }
321*64622Sbostic curpriority = p->p_priority;
32240669Smarc #ifdef KTRACE
32340669Smarc if (KTRPOINT(p, KTR_SYSRET))
32443643Skarels ktrsysret(p->p_tracep, code, error, rval[0]);
32540669Smarc #endif
32624012Ssam }
327