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