Commit | Line | Data |
---|---|---|
430f81c3 MK |
1 | /* |
2 | * Copyright (c) 1988 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
ca67e7b4 | 6 | * @(#)trap.c 7.1 (Berkeley) 5/21/88 |
430f81c3 | 7 | */ |
a55e280b SL |
8 | |
9 | #include "param.h" | |
10 | #include "systm.h" | |
11 | #include "dir.h" | |
12 | #include "user.h" | |
13 | #include "proc.h" | |
14 | #include "seg.h" | |
15 | #include "acct.h" | |
16 | #include "kernel.h" | |
430f81c3 MK |
17 | |
18 | #include "psl.h" | |
19 | #include "reg.h" | |
20 | #include "pte.h" | |
21 | #include "mtpr.h" | |
22 | ||
a55e280b | 23 | #define SYSCALLTRACE |
2a120284 SL |
24 | #ifdef SYSCALLTRACE |
25 | #include "../sys/syscalls.c" | |
26 | #endif | |
a55e280b SL |
27 | |
28 | #include "../tahoe/trap.h" | |
2a120284 SL |
29 | |
30 | #define USER 040 /* user-mode flag added to type */ | |
31 | ||
a55e280b SL |
32 | struct sysent sysent[]; |
33 | int nsysent; | |
34 | ||
35 | char *trap_type[] = { | |
36 | "Reserved addressing mode", /* T_RESADFLT */ | |
37 | "Privileged instruction", /* T_PRIVINFLT */ | |
38 | "Reserved operand", /* T_RESOPFLT */ | |
39 | "Breakpoint", /* T_BPTFLT */ | |
40 | 0, | |
41 | "Kernel call", /* T_SYSCALL */ | |
42 | "Arithmetic trap", /* T_ARITHTRAP */ | |
43 | "System forced exception", /* T_ASTFLT */ | |
44 | "Segmentation fault", /* T_SEGFLT */ | |
45 | "Protection fault", /* T_PROTFLT */ | |
46 | "Trace trap", /* T_TRCTRAP */ | |
47 | 0, | |
48 | "Page fault", /* T_PAGEFLT */ | |
49 | "Page table fault", /* T_TABLEFLT */ | |
50 | "Alignment fault", /* T_ALIGNFLT */ | |
51 | "Kernel stack not valid", /* T_KSPNOTVAL */ | |
52 | "Bus error", /* T_BUSERR */ | |
c5747722 | 53 | "Kernel debugger trap", /* T_KDBTRAP */ |
a55e280b | 54 | }; |
c5747722 | 55 | int TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]); |
2a120284 SL |
56 | |
57 | /* | |
58 | * Called from the trap handler when a processor trap occurs. | |
59 | */ | |
a55e280b | 60 | /*ARGSUSED*/ |
2a120284 | 61 | trap(sp, type, hfs, accmst, acclst, dbl, code, pc, psl) |
a55e280b | 62 | unsigned type, code; |
2a120284 | 63 | { |
a55e280b | 64 | int r0, r1; /* must reserve space */ |
2a120284 SL |
65 | register int *locr0 = ((int *)&psl)-PS; |
66 | register int i; | |
67 | register struct proc *p; | |
68 | struct timeval syst; | |
2a120284 | 69 | |
a55e280b SL |
70 | #ifdef lint |
71 | r0 = 0; r0 = r0; r1 = 0; r1 = r1; | |
72 | #endif | |
2a120284 SL |
73 | syst = u.u_ru.ru_stime; |
74 | if (USERMODE(locr0[PS])) { | |
75 | type |= USER; | |
76 | u.u_ar0 = locr0; | |
77 | } | |
78 | switch (type) { | |
79 | ||
a55e280b | 80 | default: |
8b58ff19 | 81 | #ifdef KADB |
c5747722 SL |
82 | if (kdb_trap(&psl)) |
83 | return; | |
84 | #endif | |
a55e280b SL |
85 | printf("trap type %d, code = %x, pc = %x\n", type, code, pc); |
86 | type &= ~USER; | |
87 | if (type < TRAP_TYPES && trap_type[type]) | |
88 | panic(trap_type[type]); | |
89 | else | |
90 | panic("trap"); | |
91 | /*NOTREACHED*/ | |
2a120284 | 92 | |
a55e280b | 93 | case T_PROTFLT + USER: /* protection fault */ |
2a120284 SL |
94 | i = SIGBUS; |
95 | break; | |
96 | ||
97 | case T_PRIVINFLT + USER: /* privileged instruction fault */ | |
a55e280b SL |
98 | case T_RESADFLT + USER: /* reserved addressing fault */ |
99 | case T_RESOPFLT + USER: /* resereved operand fault */ | |
100 | case T_ALIGNFLT + USER: /* unaligned data fault */ | |
2a120284 SL |
101 | u.u_code = type &~ USER; |
102 | i = SIGILL; | |
103 | break; | |
104 | ||
a55e280b | 105 | case T_ASTFLT + USER: /* Allow process switch */ |
2a120284 SL |
106 | case T_ASTFLT: |
107 | astoff(); | |
108 | if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) { | |
109 | addupc(pc, &u.u_prof, 1); | |
110 | u.u_procp->p_flag &= ~SOWEUPC; | |
111 | } | |
112 | goto out; | |
113 | ||
114 | case T_ARITHTRAP + USER: | |
115 | u.u_code = code; | |
116 | i = SIGFPE; | |
117 | break; | |
118 | ||
119 | /* | |
120 | * If the user SP is above the stack segment, | |
121 | * grow the stack automatically. | |
122 | */ | |
123 | case T_SEGFLT + USER: | |
124 | if (grow((unsigned)locr0[SP]) || grow(code)) | |
125 | goto out; | |
126 | i = SIGSEGV; | |
127 | break; | |
128 | ||
a55e280b SL |
129 | case T_TABLEFLT: /* allow page table faults in kernel */ |
130 | case T_TABLEFLT + USER: /* page table fault */ | |
2a120284 SL |
131 | panic("ptable fault"); |
132 | ||
a55e280b SL |
133 | case T_PAGEFLT: /* allow page faults in kernel mode */ |
134 | case T_PAGEFLT + USER: /* page fault */ | |
2a120284 | 135 | i = u.u_error; |
a55e280b | 136 | pagein(code, 0); |
2a120284 SL |
137 | u.u_error = i; |
138 | if (type == T_PAGEFLT) | |
139 | return; | |
140 | goto out; | |
141 | ||
a55e280b SL |
142 | case T_BPTFLT + USER: /* bpt instruction fault */ |
143 | case T_TRCTRAP + USER: /* trace trap */ | |
2a120284 SL |
144 | locr0[PS] &= ~PSL_T; |
145 | i = SIGTRAP; | |
146 | break; | |
a55e280b | 147 | |
2f63ec38 SL |
148 | /* |
149 | * For T_KSPNOTVAL and T_BUSERR, can not allow spl to | |
150 | * drop to 0 as clock could go off and we would end up | |
151 | * doing an rei to the interrupt stack at ipl 0 (a | |
152 | * reserved operand fault). Instead, we allow psignal | |
153 | * to post an ast, then return to user mode where we | |
154 | * will reenter the kernel on the kernel's stack and | |
155 | * can then service the signal. | |
156 | */ | |
2a120284 | 157 | case T_KSPNOTVAL: |
2f63ec38 SL |
158 | if (noproc) |
159 | panic("ksp not valid"); | |
160 | /* fall thru... */ | |
2a120284 | 161 | case T_KSPNOTVAL + USER: |
c05010e2 | 162 | printf("pid %d: ksp not valid\n", u.u_procp->p_pid); |
2f63ec38 SL |
163 | /* must insure valid kernel stack pointer? */ |
164 | psignal(u.u_procp, SIGKILL); | |
165 | return; | |
2a120284 | 166 | |
a55e280b | 167 | case T_BUSERR + USER: |
a55e280b | 168 | u.u_code = code; |
2f63ec38 SL |
169 | psignal(u.u_procp, SIGBUS); |
170 | return; | |
2a120284 SL |
171 | } |
172 | psignal(u.u_procp, i); | |
173 | out: | |
174 | p = u.u_procp; | |
175 | if (p->p_cursig || ISSIG(p)) | |
176 | psig(); | |
177 | p->p_pri = p->p_usrpri; | |
178 | if (runrun) { | |
179 | /* | |
180 | * Since we are u.u_procp, clock will normally just change | |
181 | * our priority without moving us from one queue to another | |
182 | * (since the running process is not on a queue.) | |
183 | * If that happened after we setrq ourselves but before we | |
184 | * swtch()'ed, we might not be on the queue indicated by | |
185 | * our priority. | |
186 | */ | |
b1cd91d1 | 187 | (void) splclock(); |
2a120284 SL |
188 | setrq(p); |
189 | u.u_ru.ru_nivcsw++; | |
190 | swtch(); | |
191 | } | |
192 | if (u.u_prof.pr_scale) { | |
193 | int ticks; | |
194 | struct timeval *tv = &u.u_ru.ru_stime; | |
195 | ||
196 | ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + | |
197 | (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); | |
198 | if (ticks) | |
199 | addupc(locr0[PC], &u.u_prof, ticks); | |
200 | } | |
201 | curpri = p->p_pri; | |
202 | } | |
203 | ||
204 | #ifdef SYSCALLTRACE | |
a55e280b | 205 | int syscalltrace = 0; |
2a120284 SL |
206 | #endif |
207 | ||
208 | /* | |
a55e280b | 209 | * Called from locore when a system call occurs |
2a120284 | 210 | */ |
a55e280b | 211 | /*ARGSUSED*/ |
2a120284 | 212 | syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl) |
a55e280b | 213 | unsigned code; |
2a120284 | 214 | { |
a55e280b | 215 | int r0, r1; /* must reserve space */ |
2a120284 | 216 | register int *locr0 = ((int *)&psl)-PS; |
a55e280b SL |
217 | register caddr_t params; |
218 | register int i; | |
2a120284 SL |
219 | register struct sysent *callp; |
220 | register struct proc *p; | |
a55e280b | 221 | struct timeval syst; |
2a120284 SL |
222 | int opc; |
223 | ||
a55e280b SL |
224 | #ifdef lint |
225 | r0 = 0; r0 = r0; r1 = 0; r1 = r1; | |
226 | #endif | |
2a120284 SL |
227 | syst = u.u_ru.ru_stime; |
228 | if (!USERMODE(locr0[PS])) | |
229 | panic("syscall"); | |
230 | u.u_ar0 = locr0; | |
a55e280b SL |
231 | if (code == 139) { /* 4.2 COMPATIBILTY XXX */ |
232 | osigcleanup(); /* 4.2 COMPATIBILTY XXX */ | |
233 | goto done; /* 4.2 COMPATIBILTY XXX */ | |
2a120284 SL |
234 | } |
235 | params = (caddr_t)locr0[FP] + NBPW; | |
236 | u.u_error = 0; | |
a55e280b SL |
237 | /* BEGIN GROT */ |
238 | /* | |
239 | * Try to reconstruct pc, assuming code | |
240 | * is an immediate constant | |
241 | */ | |
2a120284 SL |
242 | opc = pc - 2; /* short literal */ |
243 | if (code > 0x3f) { | |
a55e280b | 244 | opc--; /* byte immediate */ |
2a120284 | 245 | if (code > 0x7f) { |
a55e280b | 246 | opc--; /* word immediate */ |
2a120284 SL |
247 | if (code > 0x7fff) |
248 | opc -= 2; /* long immediate */ | |
249 | } | |
250 | } | |
a55e280b | 251 | /* END GROT */ |
2a120284 SL |
252 | callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; |
253 | if (callp == sysent) { | |
254 | i = fuword(params); | |
255 | params += NBPW; | |
a55e280b | 256 | callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; |
2a120284 | 257 | } |
a55e280b SL |
258 | if ((i = callp->sy_narg * sizeof (int)) && |
259 | (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) { | |
260 | locr0[R0] = u.u_error; | |
261 | locr0[PS] |= PSL_C; /* carry bit */ | |
262 | goto done; | |
2a120284 | 263 | } |
2a120284 | 264 | u.u_r.r_val1 = 0; |
a55e280b | 265 | u.u_r.r_val2 = locr0[R1]; |
2a120284 | 266 | if (setjmp(&u.u_qsave)) { |
a55e280b | 267 | if (u.u_error == 0 && u.u_eosys != RESTARTSYS) |
2a120284 SL |
268 | u.u_error = EINTR; |
269 | } else { | |
a55e280b | 270 | u.u_eosys = NORMALRETURN; |
2a120284 SL |
271 | #ifdef SYSCALLTRACE |
272 | if (syscalltrace) { | |
9d61b7ff | 273 | register int a; |
2a120284 SL |
274 | char *cp; |
275 | ||
276 | if (code >= nsysent) | |
277 | printf("0x%x", code); | |
278 | else | |
279 | printf("%s", syscallnames[code]); | |
280 | cp = "("; | |
9d61b7ff SL |
281 | for (a = 0; a < callp->sy_narg; a++) { |
282 | printf("%s%x", cp, u.u_arg[a]); | |
2a120284 SL |
283 | cp = ", "; |
284 | } | |
9d61b7ff SL |
285 | if (a) |
286 | printf(")"); | |
287 | printf("\n"); | |
2a120284 SL |
288 | } |
289 | #endif | |
a55e280b | 290 | (*callp->sy_call)(); |
2a120284 | 291 | } |
a55e280b SL |
292 | if (u.u_eosys == NORMALRETURN) { |
293 | if (u.u_error) { | |
294 | locr0[R0] = u.u_error; | |
295 | locr0[PS] |= PSL_C; /* carry bit */ | |
296 | } else { | |
297 | locr0[PS] &= ~PSL_C; /* clear carry bit */ | |
298 | locr0[R0] = u.u_r.r_val1; | |
299 | locr0[R1] = u.u_r.r_val2; | |
300 | } | |
301 | } else if (u.u_eosys == RESTARTSYS) | |
2a120284 | 302 | pc = opc; |
a55e280b SL |
303 | /* else if (u.u_eosys == JUSTRETURN) */ |
304 | /* nothing to do */ | |
2a120284 SL |
305 | done: |
306 | p = u.u_procp; | |
307 | if (p->p_cursig || ISSIG(p)) | |
308 | psig(); | |
309 | p->p_pri = p->p_usrpri; | |
310 | if (runrun) { | |
311 | /* | |
312 | * Since we are u.u_procp, clock will normally just change | |
313 | * our priority without moving us from one queue to another | |
314 | * (since the running process is not on a queue.) | |
315 | * If that happened after we setrq ourselves but before we | |
316 | * swtch()'ed, we might not be on the queue indicated by | |
317 | * our priority. | |
318 | */ | |
b1cd91d1 | 319 | (void) splclock(); |
2a120284 SL |
320 | setrq(p); |
321 | u.u_ru.ru_nivcsw++; | |
322 | swtch(); | |
323 | } | |
324 | if (u.u_prof.pr_scale) { | |
325 | int ticks; | |
326 | struct timeval *tv = &u.u_ru.ru_stime; | |
327 | ||
328 | ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + | |
329 | (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); | |
330 | if (ticks) | |
331 | addupc(locr0[PC], &u.u_prof, ticks); | |
332 | } | |
333 | curpri = p->p_pri; | |
334 | } | |
335 | ||
336 | /* | |
337 | * nonexistent system call-- signal process (may want to handle it) | |
338 | * flag error if process won't see signal immediately | |
339 | * Q: should we do that all the time ?? | |
340 | */ | |
341 | nosys() | |
342 | { | |
a55e280b | 343 | |
2a120284 SL |
344 | if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD) |
345 | u.u_error = EINVAL; | |
346 | psignal(u.u_procp, SIGSYS); | |
347 | } | |
348 | ||
a55e280b | 349 | #ifdef notdef |
2a120284 SL |
350 | /* |
351 | * Ignored system call | |
352 | */ | |
353 | nullsys() | |
354 | { | |
355 | ||
356 | } | |
a55e280b | 357 | #endif |