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