xref: /csrg-svn/sys/tahoe/align/exception.c (revision 45699)
1*45699Sbostic /*	exception.c	1.2	90/12/04	*/
229647Ssam 
3*45699Sbostic #include "align.h"
429647Ssam 
529647Ssam /*
629647Ssam  * Signal an exception. It will be handled by 'locore.s'. Here, I:
729647Ssam  *	1) Put the exception code where it belongs on the stack.
829647Ssam  *	2) Restore pc and sp to show that the current opcode
929647Ssam  *		'was not executed'.
1029647Ssam  *	3) Execute one big non-local-goto. In the process we take care
1129647Ssam  *		to reset the current HW fp such that 'alignment' will
1229647Ssam  *		indeed return to 'locore.s'.
1329647Ssam  *		IMPORTANT NOTE : the process I use will NOT restore
1429647Ssam  *		all registers (like normal returns) so the call to the
1529647Ssam  *		handling routine HAS TO BE the last thing in 'alignment'.
1629647Ssam  *		Otherwise, all its own register variables will be a mess !!
1729647Ssam  *		I also know that 'alignment' itself WILL restore all
1829647Ssam  *		registers for 'locore.s' since its entry mask is all-1.
1929647Ssam  */
2029647Ssam exception(infop, type, param1, param2)
2129647Ssam process_info *infop;
2229647Ssam int	type, param1, param2;
2329647Ssam {
2429647Ssam 	register long *my_fp;
2529647Ssam 	register long *current_fp, *prev_fp;
2629647Ssam 
2729647Ssam 	my_fp = (long *)&infop-1 ;
2829647Ssam 	infop->ret_exception = type;
2929647Ssam 	switch (type) {
3029647Ssam 	case ARITHMETIC:
3129647Ssam 		infop->ret_code = param1;
3229647Ssam 		break;
3329647Ssam 	case ILL_ACCESS:
3429647Ssam 		infop->ret_addr = param1;
3529647Ssam 		infop->ret_code = param2;
3629647Ssam 		break;
3729647Ssam 	case ALIGNMENT:
3829647Ssam 	case ILL_ADDRMOD:
3929647Ssam 	case ILL_OPRND:
4029647Ssam 		break;
4129647Ssam 	default :
4229647Ssam 		printf ("Bad exception type %d (alignment code)\n", type);
4329647Ssam 		break;
4429647Ssam 	}
4529647Ssam /*
4629647Ssam  * Now the big trick. Look up the stack until the frame of
4729647Ssam  * 'alignment' is found. prev_fp will point to it and current_fp
4829647Ssam  * will then point to the frame of whoever 'alignment' called.
4929647Ssam  * This should better work ...
5029647Ssam  */
5129647Ssam 	prev_fp = my_fp;
5229647Ssam 	while (prev_fp != &fp) {
5329647Ssam 		current_fp = prev_fp;
5429647Ssam 		prev_fp = (long *) *prev_fp;
5529647Ssam 	}
5629647Ssam /*
5729647Ssam  * Found it. Now fool the HW into thinking that 'alignment' called
5829647Ssam  * us directly here, so this routine's 'return' will go back
5929647Ssam  * all the way to 'alignment', stopping any further emulation
6029647Ssam  * for the current offending opcode.
6129647Ssam  *  "fool the HW..." ha ha, am I realy fooling myself ?
6229647Ssam  */
6329647Ssam 	*my_fp = *current_fp;
6429647Ssam 	*(my_fp - 2) = *(current_fp -2);	/* Alter program counter */
6529647Ssam /*
6629647Ssam  * Without further ado, just go back now !!!!
6729647Ssam  */
6829647Ssam }
6929647Ssam 
7029647Ssam not_needed (infop)
7129647Ssam process_info *infop;
7229647Ssam {
7329647Ssam /*
7429647Ssam  * Shouldn't ever come to this routine.
7529647Ssam  */
7629647Ssam 
7729647Ssam 	printf ("Opcode 0x%x should not trap to alignment code.",
7829647Ssam 		opCODE);
7929647Ssam 	printf (" OS or machine problem!! \n");
8029647Ssam }
8129647Ssam 
8229647Ssam 
8329647Ssam cannot_do (infop)
8429647Ssam process_info *infop;
8529647Ssam {
8629647Ssam /*
8729647Ssam  * Some opcode-caused alignments cannot be emulated. See table.c for
8829647Ssam  * specific reasons. Reflect this back to the process as alignment
8929647Ssam  * exception.
9029647Ssam  */
9129647Ssam 	exception (infop, ALIGNMENT);
9229647Ssam }
93