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