xref: /csrg-svn/sys/tahoe/align/exception.c (revision 29647)
1*29647Ssam /*	exception.c	1.1	86/07/20	*/
2*29647Ssam 
3*29647Ssam #include "../tahoealign/align.h"
4*29647Ssam 
5*29647Ssam /*
6*29647Ssam  * Signal an exception. It will be handled by 'locore.s'. Here, I:
7*29647Ssam  *	1) Put the exception code where it belongs on the stack.
8*29647Ssam  *	2) Restore pc and sp to show that the current opcode
9*29647Ssam  *		'was not executed'.
10*29647Ssam  *	3) Execute one big non-local-goto. In the process we take care
11*29647Ssam  *		to reset the current HW fp such that 'alignment' will
12*29647Ssam  *		indeed return to 'locore.s'.
13*29647Ssam  *		IMPORTANT NOTE : the process I use will NOT restore
14*29647Ssam  *		all registers (like normal returns) so the call to the
15*29647Ssam  *		handling routine HAS TO BE the last thing in 'alignment'.
16*29647Ssam  *		Otherwise, all its own register variables will be a mess !!
17*29647Ssam  *		I also know that 'alignment' itself WILL restore all
18*29647Ssam  *		registers for 'locore.s' since its entry mask is all-1.
19*29647Ssam  */
20*29647Ssam exception(infop, type, param1, param2)
21*29647Ssam process_info *infop;
22*29647Ssam int	type, param1, param2;
23*29647Ssam {
24*29647Ssam 	register long *my_fp;
25*29647Ssam 	register long *current_fp, *prev_fp;
26*29647Ssam 
27*29647Ssam 	my_fp = (long *)&infop-1 ;
28*29647Ssam 	infop->ret_exception = type;
29*29647Ssam 	switch (type) {
30*29647Ssam 	case ARITHMETIC:
31*29647Ssam 		infop->ret_code = param1;
32*29647Ssam 		break;
33*29647Ssam 	case ILL_ACCESS:
34*29647Ssam 		infop->ret_addr = param1;
35*29647Ssam 		infop->ret_code = param2;
36*29647Ssam 		break;
37*29647Ssam 	case ALIGNMENT:
38*29647Ssam 	case ILL_ADDRMOD:
39*29647Ssam 	case ILL_OPRND:
40*29647Ssam 		break;
41*29647Ssam 	default :
42*29647Ssam 		printf ("Bad exception type %d (alignment code)\n", type);
43*29647Ssam 		break;
44*29647Ssam 	}
45*29647Ssam /*
46*29647Ssam  * Now the big trick. Look up the stack until the frame of
47*29647Ssam  * 'alignment' is found. prev_fp will point to it and current_fp
48*29647Ssam  * will then point to the frame of whoever 'alignment' called.
49*29647Ssam  * This should better work ...
50*29647Ssam  */
51*29647Ssam 	prev_fp = my_fp;
52*29647Ssam 	while (prev_fp != &fp) {
53*29647Ssam 		current_fp = prev_fp;
54*29647Ssam 		prev_fp = (long *) *prev_fp;
55*29647Ssam 	}
56*29647Ssam /*
57*29647Ssam  * Found it. Now fool the HW into thinking that 'alignment' called
58*29647Ssam  * us directly here, so this routine's 'return' will go back
59*29647Ssam  * all the way to 'alignment', stopping any further emulation
60*29647Ssam  * for the current offending opcode.
61*29647Ssam  *  "fool the HW..." ha ha, am I realy fooling myself ?
62*29647Ssam  */
63*29647Ssam 	*my_fp = *current_fp;
64*29647Ssam 	*(my_fp - 2) = *(current_fp -2);	/* Alter program counter */
65*29647Ssam /*
66*29647Ssam  * Without further ado, just go back now !!!!
67*29647Ssam  */
68*29647Ssam }
69*29647Ssam 
70*29647Ssam not_needed (infop)
71*29647Ssam process_info *infop;
72*29647Ssam {
73*29647Ssam /*
74*29647Ssam  * Shouldn't ever come to this routine.
75*29647Ssam  */
76*29647Ssam 
77*29647Ssam 	printf ("Opcode 0x%x should not trap to alignment code.",
78*29647Ssam 		opCODE);
79*29647Ssam 	printf (" OS or machine problem!! \n");
80*29647Ssam }
81*29647Ssam 
82*29647Ssam 
83*29647Ssam cannot_do (infop)
84*29647Ssam process_info *infop;
85*29647Ssam {
86*29647Ssam /*
87*29647Ssam  * Some opcode-caused alignments cannot be emulated. See table.c for
88*29647Ssam  * specific reasons. Reflect this back to the process as alignment
89*29647Ssam  * exception.
90*29647Ssam  */
91*29647Ssam 	exception (infop, ALIGNMENT);
92*29647Ssam }
93