xref: /original-bsd/sys/vax/vax/trap.c (revision cd18b70b)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)trap.c	7.2 (Berkeley) 02/21/87
7  */
8 
9 #include "psl.h"
10 #include "reg.h"
11 #include "pte.h"
12 
13 #include "param.h"
14 #include "systm.h"
15 #include "dir.h"
16 #include "user.h"
17 #include "assym.s"
18 #include "proc.h"
19 #include "seg.h"
20 #include "trap.h"
21 #include "acct.h"
22 #include "kernel.h"
23 #ifdef SYSCALLTRACE
24 #include "../sys/syscalls.c"
25 #endif
26 
27 #include "mtpr.h"
28 
29 #define	USER	040		/* user-mode flag added to type */
30 
31 struct	sysent	sysent[];
32 int	nsysent;
33 
34 char	*trap_type[] = {
35 	"Reserved addressing mode",
36 	"Privileged instruction",
37 	"Reserved operand",
38 	"Breakpoint",
39 	"Xfc trap",
40 	"Syscall trap",
41 	"Arithmetic fault",
42 	"Ast trap",
43 	"Segmentation fault",
44 	"Protection fault",
45 	"Trace trap",
46 	"Compatibility mode trap",
47 	"Page fault",
48 	"Page table fault",
49 	"Kernel debugger trap",
50 };
51 int	TRAP_TYPES = (sizeof trap_type / sizeof trap_type[0]);
52 
53 /*
54  * Called from the trap handler when a processor trap occurs.
55  */
56 /*ARGSUSED*/
57 trap(sp, type, code, pc, psl)
58 	int sp, type;
59 	unsigned code;
60 	int pc, psl;
61 {
62 	register int *locr0 = ((int *)&psl)-PS;
63 	register int i;
64 	register struct proc *p;
65 	struct timeval syst;
66 
67 	syst = u.u_ru.ru_stime;
68 	if (USERMODE(locr0[PS])) {
69 		type |= USER;
70 		u.u_ar0 = locr0;
71 	}
72 	switch (type) {
73 
74 	default:
75 #ifdef KDB
76 		if (kdb_trap(&psl))
77 			return;
78 #endif
79 		printf("trap type %d, code = %x, pc = %x\n", type, code, pc);
80 		type &= ~USER;
81 		if ((unsigned)type < TRAP_TYPES)
82 			panic(trap_type[type]);
83 		panic("trap");
84 
85 	case T_PROTFLT+USER:	/* protection fault */
86 		i = SIGBUS;
87 		break;
88 
89 	case T_PRIVINFLT+USER:	/* privileged instruction fault */
90 	case T_RESADFLT+USER:	/* reserved addressing fault */
91 	case T_RESOPFLT+USER:	/* resereved operand fault */
92 		u.u_code = type &~ USER;
93 		i = SIGILL;
94 		break;
95 
96 	case T_ASTFLT+USER:
97 		astoff();
98 		if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) {
99 			addupc(pc, &u.u_prof, 1);
100 			u.u_procp->p_flag &= ~SOWEUPC;
101 		}
102 		goto out;
103 
104 	case T_ARITHTRAP+USER:
105 		u.u_code = code;
106 		i = SIGFPE;
107 		break;
108 
109 	/*
110 	 * If the user SP is above the stack segment,
111 	 * grow the stack automatically.
112 	 */
113 	case T_SEGFLT+USER:
114 		if (grow((unsigned)locr0[SP]) || grow(code))
115 			goto out;
116 		i = SIGSEGV;
117 		break;
118 
119 	case T_TABLEFLT:	/* allow page table faults in kernel mode */
120 	case T_TABLEFLT+USER:   /* page table fault */
121 		panic("ptable fault");
122 
123 	case T_PAGEFLT:		/* allow page faults in kernel mode */
124 	case T_PAGEFLT+USER:	/* page fault */
125 		i = u.u_error;
126 		pagein(code, 0);
127 		u.u_error = i;
128 		if (type == T_PAGEFLT)
129 			return;
130 		goto out;
131 
132 	case T_BPTFLT+USER:	/* bpt instruction fault */
133 	case T_TRCTRAP+USER:	/* trace trap */
134 		locr0[PS] &= ~PSL_T;
135 		i = SIGTRAP;
136 		break;
137 
138 	case T_XFCFLT+USER:	/* xfc instruction fault */
139 		i = SIGEMT;
140 		break;
141 
142 	case T_COMPATFLT+USER:	/* compatibility mode fault */
143 		u.u_acflag |= ACOMPAT;
144 		u.u_code = code;
145 		i = SIGILL;
146 		break;
147 	}
148 	psignal(u.u_procp, i);
149 out:
150 	p = u.u_procp;
151 	if (p->p_cursig || ISSIG(p))
152 		psig();
153 	p->p_pri = p->p_usrpri;
154 	if (runrun) {
155 		/*
156 		 * Since we are u.u_procp, clock will normally just change
157 		 * our priority without moving us from one queue to another
158 		 * (since the running process is not on a queue.)
159 		 * If that happened after we setrq ourselves but before we
160 		 * swtch()'ed, we might not be on the queue indicated by
161 		 * our priority.
162 		 */
163 		(void) splclock();
164 		setrq(p);
165 		u.u_ru.ru_nivcsw++;
166 		swtch();
167 	}
168 	if (u.u_prof.pr_scale) {
169 		int ticks;
170 		struct timeval *tv = &u.u_ru.ru_stime;
171 
172 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
173 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
174 		if (ticks)
175 			addupc(locr0[PC], &u.u_prof, ticks);
176 	}
177 	curpri = p->p_pri;
178 }
179 
180 #ifdef SYSCALLTRACE
181 int syscalltrace = 0;
182 #endif
183 /*
184  * Called from the trap handler when a system call occurs
185  */
186 /*ARGSUSED*/
187 syscall(sp, type, code, pc, psl)
188 	unsigned code;
189 {
190 	register int *locr0 = ((int *)&psl)-PS;
191 	register caddr_t params;		/* known to be r10 below */
192 	register int i;				/* known to be r9 below */
193 	register struct sysent *callp;
194 	register struct proc *p;
195 	int opc;
196 	struct timeval syst;
197 
198 	syst = u.u_ru.ru_stime;
199 	if (!USERMODE(locr0[PS]))
200 		panic("syscall");
201 	u.u_ar0 = locr0;
202 	if (code == 139) {			/* XXX 4.2 COMPATIBILITY */
203 		osigcleanup();			/* XXX 4.2 COMPATIBILITY */
204 		goto done;			/* XXX 4.2 COMPATIBILITY */
205 	}					/* XXX 4.2 COMPATIBILITY */
206 	params = (caddr_t)locr0[AP] + NBPW;
207 	u.u_error = 0;
208 	opc = pc - 2;
209 	if (code > 63)
210 		opc -= 2;
211 	if (code >= nsysent)
212 		callp = &sysent[0];		/* indir (illegal) */
213 	else {
214 		callp = &sysent[code];
215 		if (callp == sysent) {		/* indir */
216 			i = fuword(params);
217 			params += NBPW;
218 			if ((unsigned)i >= nsysent)
219 				callp = &sysent[0];
220 			else
221 				callp = &sysent[i];
222 		}
223 	}
224 	if ((i = callp->sy_narg * sizeof (int)) &&
225 	    (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) {
226 		locr0[R0] = u.u_error;
227 		locr0[PS] |= PSL_C;	/* carry bit */
228 		goto done;
229 	}
230 	u.u_r.r_val1 = 0;
231 	u.u_r.r_val2 = locr0[R1];
232 	if (setjmp(&u.u_qsave)) {
233 		if (u.u_error == 0 && u.u_eosys != RESTARTSYS)
234 			u.u_error = EINTR;
235 	} else {
236 		u.u_eosys = NORMALRETURN;
237 #ifdef SYSCALLTRACE
238 		if (syscalltrace) {
239 			register int i;
240 			char *cp;
241 
242 			if (code >= nsysent)
243 				printf("0x%x", code);
244 			else
245 				printf("%s", syscallnames[code]);
246 			cp = "(";
247 			for (i= 0; i < callp->sy_narg; i++) {
248 				printf("%s%x", cp, u.u_arg[i]);
249 				cp = ", ";
250 			}
251 			if (i)
252 				putchar(')', 0);
253 			putchar('\n', 0);
254 		}
255 #endif
256 		(*(callp->sy_call))();
257 	}
258 	if (u.u_eosys == NORMALRETURN) {
259 		if (u.u_error) {
260 			locr0[R0] = u.u_error;
261 			locr0[PS] |= PSL_C;	/* carry bit */
262 		} else {
263 			locr0[R0] = u.u_r.r_val1;
264 			locr0[R1] = u.u_r.r_val2;
265 			locr0[PS] &= ~PSL_C;
266 		}
267 	} else if (u.u_eosys == RESTARTSYS)
268 		pc = opc;
269 	/* else if (u.u_eosys == JUSTRETURN) */
270 		/* nothing to do */
271 done:
272 	p = u.u_procp;
273 	if (p->p_cursig || ISSIG(p))
274 		psig();
275 	p->p_pri = p->p_usrpri;
276 	if (runrun) {
277 		/*
278 		 * Since we are u.u_procp, clock will normally just change
279 		 * our priority without moving us from one queue to another
280 		 * (since the running process is not on a queue.)
281 		 * If that happened after we setrq ourselves but before we
282 		 * swtch()'ed, we might not be on the queue indicated by
283 		 * our priority.
284 		 */
285 		(void) splclock();
286 		setrq(p);
287 		u.u_ru.ru_nivcsw++;
288 		swtch();
289 	}
290 	if (u.u_prof.pr_scale) {
291 		int ticks;
292 		struct timeval *tv = &u.u_ru.ru_stime;
293 
294 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
295 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
296 		if (ticks)
297 			addupc(locr0[PC], &u.u_prof, ticks);
298 	}
299 	curpri = p->p_pri;
300 }
301 
302 /*
303  * nonexistent system call-- signal process (may want to handle it)
304  * flag error if process won't see signal immediately
305  * Q: should we do that all the time ??
306  */
307 nosys()
308 {
309 	if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD)
310 		u.u_error = EINVAL;
311 	psignal(u.u_procp, SIGSYS);
312 }
313