xref: /inferno-os/os/js/trap.c (revision 9dc22068e29604f4b484e746112a9a4efe6fd57f)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"ureg.h"
7 #include	"io.h"
8 #include	"../port/error.h"
9 
10 void	noted(Ureg**, ulong);
11 void	rfnote(Ureg**);
12 int	domuldiv(ulong, Ureg*);
13 
14 extern	Label catch;
15 extern	void traplink(void);
16 extern	void syslink(void);
17 static	void faultsparc(Ureg *ur);
18 static	void faultasync(Ureg *ur);
19 
20 	long	ticks;
21 static	char	excbuf[64];	/* BUG: not reentrant! */
22 
23 char *trapname[]={
24 	"reset",
25 	"instruction access exception",
26 	"illegal instruction",
27 	"privileged instruction",
28 	"fp: disabled",
29 	"window overflow",
30 	"window underflow",
31 	"unaligned address",
32 	"fp: exception",
33 	"data access exception",
34 	"tag overflow",
35 	"watchpoint detected",
36 };
37 
38 char *fptrapname[]={
39 	"none",
40 	"IEEE 754 exception",
41 	"unfinished FP op",
42 	"unimplemented FP op",
43 	"sequence error",
44 	"hardware error",
45 	"invalid FP register",
46 	"reserved",
47 }
48 ;
49 
50 char*
51 excname(ulong tbr)
52 {
53 	char xx[64];
54 	char *t;
55 
56 	switch(tbr){
57 	case 8:
58 		if(up == 0)
59 			panic("fptrap in kernel\n");
60 		else{
61 panic("fptrap not implemented\n");
62 #ifdef notdef
63 			if(m->fpunsafe==0 && up->p->fpstate!=FPactive)
64 				panic("fptrap not active\n"); 							fsr = up->fpsave.env;
65 			sprint(excbuf, "fp: %s fppc=0x%lux",
66 				fptrapname[(fsr>>14)&7],
67 				up->fpsave.q[0].a, fsr);
68 #endif
69 		}
70 		return excbuf;
71 	case 36:
72 		return "trap: cp disabled";
73 	case 37:
74 		return "trap: unimplemented instruction";
75 	case 40:
76 		return "trap: cp exception";
77 	case 42:
78 		return "trap: divide by zero";
79 	case 128:
80 		return "syscall";
81 	case 129:
82 		return "breakpoint";
83 	}
84 	t = 0;
85 	if(tbr < sizeof trapname/sizeof(char*))
86 		t = trapname[tbr];
87 	if(t == 0){
88 		if(tbr >= 130)
89 			sprint(xx, "trap instruction %ld", tbr-128);
90 		else if(17<=tbr && tbr<=31)
91 			sprint(xx, "interrupt level %ld", tbr-16);
92 		else
93 			sprint(xx, "unknown trap %ld", tbr);
94 		t = xx;
95 	}
96 	if(strncmp(t, "fp: ", 4) == 0)
97 		strcpy(excbuf, t);
98 	else
99 		sprint(excbuf, "trap: %s", t);
100 	return excbuf;
101 
102 }
103 
104 void
105 trap(Ureg *ur)
106 {
107 	int user;
108 	ulong tbr, iw;
109 
110 	tbr = (ur->tbr&0xFFF)>>4;
111 	/*
112 	 * Hack to catch bootstrap fault during probe
113 	 */
114 	if(catch.pc)
115 		gotolabel(&catch);
116 
117 	if(up)
118 		up->dbgreg = ur;
119 
120 	user = !(ur->psr&PSRPSUPER);
121 	if(user) {
122 		panic("how did we get to user mode???");
123 	}
124 	if(tbr > 16){			/* interrupt */
125 		switch(tbr-16) {
126 		case 15:			/* asynch mem err */
127 			faultasync(ur);
128 			break;
129 		case 14:			/* processor counter */
130 			clock(ur);
131 			break;
132 		case 13:			/* keyboard/mouse */
133 			ns16552intr(0);
134 			kbdintr();
135 			break;
136 		case 6:				/* lance */
137 			lanceintr();
138 			break;
139 		default:
140 			print("unexp intr lev %ld\n", tbr-16);
141 			goto Error;
142 		}
143 	}else{
144 		switch(tbr){
145 		case 1:				/* instr. access */
146 		case 9:				/* data access */
147 			if(up && up->fpstate==FPACTIVE) {
148 				fpquiet();
149 				fpsave(&up->fpsave);
150 				up->fpstate = FPINACTIVE;
151 			}
152 			faultsparc(ur);
153 			goto Return;
154 		case 2:				/* illegal instr, maybe mul */
155 			iw = *(ulong*)ur->pc;
156 			if((iw&0xC1500000) == 0x80500000){
157 				if(domuldiv(iw, ur))
158 					goto Return;
159 				tbr = ur->tbr;
160 			}
161 			break;
162 		case 4:				/* floating point disabled */
163 panic("some more floating point crapola");
164 break;
165 #ifdef notdef
166 			if(u && u->p){
167 				if(up->p->fpstate == FPINIT)
168 					restfpregs(initfpp, up->fpsave.fsr);
169 				else if(u->p->fpstate == FPinactive)
170 					restfpregs(&u->fpsave, u->fpsave.fsr);
171 				else
172 					break;
173 				u->p->fpstate = FPactive;
174 				ur->psr |= PSREF;
175 				return;
176 			}
177 			break;
178 #endif
179 		case 8:				/* floating point exception */
180 panic("floating point crapola #3");
181 break;
182 #ifdef notdef
183 			/* if unsafe, trap happened shutting down FPU; just return */
184 			if(m->fpunsafe){
185 				m->fptrap = (fptrap()==0);
186 				return;
187 			}
188 			if(fptrap())
189 				goto Return;	/* handled the problem */
190 			break;
191 #endif
192 		default:
193 			break;
194 		}
195     Error:
196 		panic("kernel trap: %s pc=0x%lux\n", excname(tbr), ur->pc);
197 	}
198     Return:
199     	return;
200 }
201 
202 void
203 trapinit(void)
204 {
205 	int i;
206 	long t, a;
207 
208 	a = ((ulong)traplink-TRAPS)>>2;
209 	a += 0x40000000;			/* CALL traplink(SB) */
210 	t = TRAPS;
211 	for(i=0; i<256; i++){
212 		*(ulong*)(t+0) = a;		/* CALL traplink(SB) */
213 		*(ulong*)(t+4) = 0xa7480000;	/* MOVW PSR, R19 */
214 		a -= 16/4;
215 		t += 16;
216 	}
217 
218 #ifdef notdef
219 	flushpage(TRAPS);
220 #else
221 	flushicache();
222 #endif
223 
224 	puttbr(TRAPS);
225 	setpsr(getpsr()|PSRET|SPL(15));	/* enable traps, not interrupts */
226 }
227 
228 void
229 mulu(ulong u1, ulong u2, ulong *lop, ulong *hip)
230 {
231 	ulong lo1, lo2, hi1, hi2, lo, hi, t1, t2, t;
232 
233 	lo1 = u1 & 0xffff;
234 	lo2 = u2 & 0xffff;
235 	hi1 = u1 >> 16;
236 	hi2 = u2 >> 16;
237 
238 	lo = lo1 * lo2;
239 	t1 = lo1 * hi2;
240 	t2 = lo2 * hi1;
241 	hi = hi1 * hi2;
242 	t = lo;
243 	lo += t1 << 16;
244 	if(lo < t)
245 		hi++;
246 	t = lo;
247 	lo += t2 << 16;
248 	if(lo < t)
249 		hi++;
250 	hi += (t1 >> 16) + (t2 >> 16);
251 	*lop = lo;
252 	*hip = hi;
253 }
254 
255 void
256 muls(long l1, long l2, long *lop, long *hip)
257 {
258 	ulong t, lo, hi;
259 	ulong mlo, mhi;
260 	int sign;
261 
262 	sign = 0;
263 	if(l1 < 0){
264 		sign ^= 1;
265 		l1 = -l1;
266 	}
267 	if(l2 < 0){
268 		sign ^= 1;
269 		l2 = -l2;
270 	}
271 	mulu(l1, l2, &mlo, &mhi);
272 	lo = mlo;
273 	hi = mhi;
274 	if(sign){
275 		t = lo = ~lo;
276 		hi = ~hi;
277 		lo++;
278 		if(lo < t)
279 			hi++;
280 	}
281 	*lop = lo;
282 	*hip = hi;
283 }
284 
285 int
286 domuldiv(ulong iw, Ureg *ur)
287 {
288 	long op1, op2;
289 	long *regp;
290 	long *regs;
291 
292 	regs = (long*)ur;
293 	if(iw & (1<<13)){	/* signed immediate */
294 		op2 = iw & 0x1FFF;
295 		if(op2 & 0x1000)
296 			op2 |= ~0x1FFF;
297 	}else
298 		op2 = regs[iw&0x1F];
299 	op1 = regs[(iw>>14)&0x1F];
300 	regp = &regs[(iw>>25)&0x1F];
301 
302 	if(iw & (4<<19)){	/* divide */
303 		if(ur->y!=0 && ur->y!=~0){
304 	unimp:
305 			ur->tbr = 37;	/* "unimplemented instruction" */
306 			return 0;	/* complex Y is too hard */
307 		}
308 		if(op2 == 0){
309 			ur->tbr = 42;	/* "zero divide" */
310 			return 0;
311 		}
312 		if(iw & (1<<19)){
313 			if(ur->y && (op1&(1<<31))==0)
314 				goto unimp;	/* Y not sign extension */
315 			*regp = op1 / op2;
316 		}else{
317 			if(ur->y)
318 				goto unimp;
319 			*regp = (ulong)op1 / (ulong)op2;
320 		}
321 	}else{
322 		if(iw & (1<<19))
323 			muls(op1, op2, regp, (long*)&ur->y);
324 		else
325 			mulu(op1, op2, (ulong*)regp, &ur->y);
326 	}
327 	if(iw & (16<<19)){	/* set CC */
328 		ur->psr &= ~(0xF << 20);
329 		if(*regp & (1<<31))
330 			ur->psr |= 8 << 20;	/* N */
331 		if(*regp == 0)
332 			ur->psr |= 4 << 20;	/* Z */
333 		/* BUG: don't get overflow right on divide */
334 	}
335 	ur->pc += 4;
336 	ur->npc = ur->pc+4;
337 	return 1;
338 }
339 
340 void
341 dumpregs(Ureg *ur)
342 {
343 	int i;
344 	ulong *l;
345 
346 	if(up) {
347 		print("registers for %s %ld\n",up->text,up->pid);
348 		if(ur->usp < (ulong)up->kstack ||
349 		   ur->usp > (ulong)up->kstack+KSTACK-8)
350 			print("invalid stack pointer\n");
351 	} else
352 		print("registers for kernel\n");
353 
354 	print("PSR=%lux PC=%lux TBR=%lux\n", ur->psr, ur->pc, ur->tbr);
355 	l = &ur->r0;
356 	for(i=0; i<32; i+=2, l+=2)
357 		print("R%d\t%.8lux\tR%d\t%.8lux\n", i, l[0], i+1, l[1]);
358 }
359 
360 
361 /* This routine must save the values of registers the user is not permitted to
362  * write from devproc and the restore the saved values before returning
363  */
364 void
365 setregisters(Ureg *xp, char *pureg, char *uva, int n)
366 {
367 	ulong psr;
368 
369 	psr = xp->psr;
370 	memmove(pureg, uva, n);
371 	xp->psr = psr;
372 }
373 
374 void
375 dumpstack(void)
376 {
377 }
378 
379 /*
380  * Must only be called splhi() when it is safe to spllo().  Because the FP unit
381  * traps if you touch it when an exception is pending, and because if you
382  * trap with ET==0 you halt, this routine sets some global flags to enable
383  * the rest of the system to handle the trap that might occur here without
384  * upsetting the kernel.  Shouldn't be necessary, but safety first.
385  */
386 int
387 fpquiet(void)
388 {
389 	int i, notrap;
390 	ulong fsr;
391 	char buf[128];
392 
393 	i = 0;
394 	notrap = 1;
395 	up->fpstate = FPINACTIVE;
396 	for(;;){
397 		m->fptrap = 0;
398 		fsr = getfsr();
399 		if(m->fptrap){
400 			/* trap occurred and up->fpsave contains state */
401 			sprint(buf, "sys: %s", excname(8));
402 #ifdef notdef
403 			postnote(u->p, 1, buf, NDebug);
404 #else
405 			panic(buf);
406 #endif
407 			notrap = 0;
408 			break;
409 		}
410 		if((fsr&(1<<13)) == 0)
411 			break;
412 		if(++i > 1000){
413 			print("fp not quiescent\n");
414 			break;
415 		}
416 	}
417 	up->fpstate = FPACTIVE;
418 	return notrap;
419 }
420 
421 enum
422 {
423 	SE_WRITE	= 4<<5,
424 	SE_PROT		= 2<<2,
425 };
426 
427 static void
428 faultsparc(Ureg *ur)
429 {
430 	ulong addr;
431 	char buf[ERRMAX];
432 	int read;
433 	ulong tbr, ser;
434 
435 	tbr = (ur->tbr&0xFFF)>>4;
436 	addr = ur->pc;			/* assume instr. exception */
437 	read = 1;
438 	if(tbr == 9){			/* data access exception */
439 		addr = getrmmu(SFAR);
440 		ser = getrmmu(SFSR);
441 		if(ser&(SE_WRITE))	/* is SE_PROT needed? */
442 			read = 0;
443 	}
444 
445 	up->dbgreg = ur;		/* for remote acid */
446 	spllo();
447 	sprint(buf, "sys: trap: fault %s addr=0x%lux",
448 		read? "read" : "write", addr);
449 
450 	if(up->type == Interp)
451 		disfault(ur,buf);
452 	dumpregs(ur);
453 	panic("fault: %s", buf);
454 }
455 
456 static void
457 faultasync(Ureg *ur)
458 {
459 	int user;
460 
461 	print("interrupt 15 AFSR %lux AFAR %lux MFSR %lux MFAR %lux\n",
462 		getphys(AFSR), getphys(AFAR), getphys(MFSR), getphys(MFAR));
463 	dumpregs(ur);
464 	/*
465 	 * Clear interrupt
466 	 */
467 	putphys(PROCINTCLR, 1<<15);
468 	user = !(ur->psr&PSRPSUPER);
469 	if(user)
470 		pexit("Suicide", 0);
471 	panic("interrupt 15");
472 }
473