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