Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

trigger.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1993 Digital Equipment Corporation 00004 00005 Module Name: 00006 00007 trigger.c 00008 00009 Abstract: 00010 00011 This module implements functions that handle synchronous and asynchronous 00012 arithmetic exceptions. The Alpha SRM specifies certain code generation 00013 rules which if followed allow this code (in conjunction with internal 00014 processor register state) to effect a precise, synchronous exception 00015 given an imprecise, asynchronous exception. This capability is required 00016 for software emulation of the IEEE single and double floating operations. 00017 00018 Author: 00019 00020 Thomas Van Baak (tvb) 5-Mar-1993 00021 00022 Environment: 00023 00024 Kernel mode only. 00025 00026 Revision History: 00027 00028 --*/ 00029 00030 #include "ki.h" 00031 #pragma hdrstop 00032 #include "alphaops.h" 00033 00034 // 00035 // Define forward referenced function prototypes. 00036 // 00037 00038 BOOLEAN 00039 KiLocateTriggerPc ( 00040 IN OUT PEXCEPTION_RECORD ExceptionRecord, 00041 IN OUT PKTRAP_FRAME TrapFrame 00042 ); 00043 00044 // 00045 // Define debugging macros. 00046 // 00047 00048 #if DBG 00049 00050 extern ULONG RtlDebugFlags; 00051 #define DBGPRINT ((RtlDebugFlags & 0x4) != 0) && DbgPrint 00052 00053 #else 00054 00055 #define DBGPRINT 0 && DbgPrint 00056 00057 #endif 00058 00059 // 00060 // Define non-IEEE (a/k/a `high performance') arithmetic exception types. 00061 // The PALcode exception record is extended by one word and the 4th word 00062 // contains the reason the arithmetic exception is not an IEEE exception. 00063 // 00064 00065 #define NON_IEEE(ExceptionRecord, Reason) \ 00066 (ExceptionRecord)->NumberParameters = 4; \ 00067 (ExceptionRecord)->ExceptionInformation[3] = (Reason); 00068 00069 #define TRIGGER_FLOATING_REGISTER_MASK_CLEAR 1 00070 #define TRIGGER_INTEGER_REGISTER_MASK_SET 2 00071 #define TRIGGER_NO_SOFTWARE_COMPLETION 3 00072 #define TRIGGER_INVALID_INSTRUCTION_FOUND 4 00073 #define TRIGGER_INSTRUCTION_FETCH_ERROR 5 00074 #define TRIGGER_INSTRUCTION_NOT_FOUND 6 00075 #define TRIGGER_SOURCE_IS_DESTINATION 7 00076 #define TRIGGER_WRONG_INSTRUCTION 8 00077 00078 BOOLEAN 00079 KiFloatingException ( 00080 IN OUT PEXCEPTION_RECORD ExceptionRecord, 00081 IN OUT PKEXCEPTION_FRAME ExceptionFrame, 00082 IN OUT PKTRAP_FRAME TrapFrame, 00083 IN BOOLEAN ImpreciseTrap, 00084 IN OUT PULONG SoftFpcrCopy 00085 ) 00086 00087 /*++ 00088 00089 Routine Description: 00090 00091 This function is called to emulate a floating operation and convert the 00092 exception status to the proper value. If the exception is a fault, the 00093 faulting floating point instruction is emulated. If the exception is an 00094 imprecise trap, an attempt is made to locate and to emulate the original 00095 trapping floating point instruction. 00096 00097 Arguments: 00098 00099 ExceptionRecord - Supplies a pointer to an exception record. 00100 00101 ExceptionFrame - Supplies a pointer to an exception frame. 00102 00103 TrapFrame - Supplies a pointer to a trap frame. 00104 00105 ImpreciseTrap - Supplies a boolean value that specifies whether the 00106 exception is an imprecise trap. 00107 00108 SoftFpcrCopy - Supplies a pointer to a longword variable that receives 00109 a copy of the software FPCR. 00110 00111 Return Value: 00112 00113 A value of TRUE is returned if the floating exception is successfully 00114 emulated. Otherwise, a value of FALSE is returned. 00115 00116 --*/ 00117 00118 { 00119 00120 BOOLEAN Status; 00121 PSW_FPCR SoftwareFpcr; 00122 PTEB Teb; 00123 00124 try { 00125 00126 // 00127 // Obtain a copy of the software FPCR longword from the TEB. 00128 // 00129 00130 Teb = NtCurrentTeb(); 00131 *SoftFpcrCopy = Teb->FpSoftwareStatusRegister; 00132 SoftwareFpcr = (PSW_FPCR)SoftFpcrCopy; 00133 DBGPRINT("KiFloatingException: SoftFpcr = %.8lx\n", *SoftFpcrCopy); 00134 00135 #if DBG 00136 // 00137 // If the floating emulation inhibit flag is set, then bypass all 00138 // software emulation by the kernel and return FALSE to raise the 00139 // original PALcode exception. 00140 // 00141 // N.B. This is for user-mode development and testing and is not 00142 // part of the API. 00143 // 00144 00145 if (SoftwareFpcr->NoSoftwareEmulation != 0) { 00146 DBGPRINT("KiFloatingException: NoSoftwareEmulation\n"); 00147 return FALSE; 00148 } 00149 #endif 00150 00151 // 00152 // If the arithmetic exception is an imprecise trap, the address of 00153 // the trapping instruction is somewhere before the exception address. 00154 // 00155 // Otherwise the exception is a fault and the address of the faulting 00156 // instruction is the exception address. 00157 // 00158 00159 if (ImpreciseTrap != FALSE) { 00160 00161 // 00162 // If the arithmetic trap ignore mode is enabled, then do not 00163 // spend time to locate or to emulate the trapping instruction, 00164 // leave unpredictable results in the destination register, do 00165 // not set correct IEEE sticky bits in the software FPCR, leave 00166 // the hardware FPCR sticky status bits as they are, and return 00167 // TRUE to continue execution. It is assumed that user code will 00168 // check the hardware FPCR exception status bits to determine if 00169 // the instruction succeeded or not (Insignia SoftPc feature). 00170 // 00171 00172 if (SoftwareFpcr->ArithmeticTrapIgnore != 0) { 00173 return TRUE; 00174 } 00175 00176 // 00177 // Attempt to locate the trapping instruction. If the instruction 00178 // stream is such that this is not possible or was not intended, 00179 // then set an exception code that best reflects the exception 00180 // summary register bits and return FALSE to raise the exception. 00181 // 00182 // Otherwise emulate the trigger instruction in order to compute 00183 // the correct destination result value, the correct IEEE status 00184 // bits, and raise any enabled IEEE exceptions. 00185 // 00186 00187 if (KiLocateTriggerPc(ExceptionRecord, TrapFrame) == FALSE) { 00188 KiSetFloatingStatus(ExceptionRecord); 00189 return FALSE; 00190 } 00191 Status = KiEmulateFloating(ExceptionRecord, 00192 ExceptionFrame, 00193 TrapFrame, 00194 SoftwareFpcr); 00195 00196 } else { 00197 00198 // 00199 // Attempt to emulate the faulting instruction in order to perform 00200 // floating operations not supported by EV4, to compute the correct 00201 // destination result value, the correct IEEE status bits, and 00202 // raise any enabled IEEE exceptions. 00203 // 00204 00205 Status = KiEmulateFloating(ExceptionRecord, 00206 ExceptionFrame, 00207 TrapFrame, 00208 SoftwareFpcr); 00209 00210 // 00211 // If the emulation resulted in a floating point exception and 00212 // the arithmetic trap ignore mode is enabled, then set the return 00213 // value to TRUE to suppress the exception and continue execution. 00214 // 00215 00216 if ((Status == FALSE) && 00217 (SoftwareFpcr->ArithmeticTrapIgnore != 0) && 00218 (ExceptionRecord->ExceptionCode != STATUS_ILLEGAL_INSTRUCTION)) { 00219 Status = TRUE; 00220 } 00221 } 00222 00223 // 00224 // Store the updated software FPCR longword in the TEB. 00225 // 00226 00227 Teb->FpSoftwareStatusRegister = *SoftFpcrCopy; 00228 DBGPRINT("KiFloatingException: SoftFpcr = %.8lx\n", *SoftFpcrCopy); 00229 00230 } except (EXCEPTION_EXECUTE_HANDLER) { 00231 00232 // 00233 // An exception occurred accessing the TEB. 00234 // 00235 00236 ExceptionRecord->ExceptionCode = GetExceptionCode(); 00237 return FALSE; 00238 } 00239 00240 return Status; 00241 } 00242 00243 BOOLEAN 00244 KiLocateTriggerPc ( 00245 IN OUT PEXCEPTION_RECORD ExceptionRecord, 00246 IN OUT PKTRAP_FRAME TrapFrame 00247 ) 00248 00249 /*++ 00250 00251 Routine Description: 00252 00253 This function is called to try to determine the precise location of the 00254 instruction that caused an arithmetic exception. The instruction that 00255 caused the trap to occur is known as the trigger instruction. On entry, 00256 the actual address of the trigger instruction is unknown and the exception 00257 address is the continuation address. The continuation address is the 00258 address of the instruction that would have executed had the trap not 00259 occurred. The instructions following the trigger instruction up to the 00260 continuation address are known as the trap shadow of the trigger 00261 instruction. 00262 00263 Alpha AXP produces imprecise, asynchronous arithmetic exceptions. The 00264 exceptions are imprecise because the exception address when a trap is 00265 taken may be more than one instruction beyond the address of the 00266 instruction that actually caused the trap to occur. 00267 00268 The arithmetic exceptions are traps (rather than faults) because the 00269 exception address is not the address of the trapping instruction 00270 itself, but the address of the next instruction to execute, which is 00271 always (at least) one instruction beyond the address of the trapping 00272 instruction. 00273 00274 It is possible for multiple exceptions to occur and result in a single 00275 trap. This function only determines the address of the first trapping 00276 instruction. 00277 00278 Unpredictable values may have been stored in the destination register 00279 of trapping instructions. Thus to insure that the trigger instruction 00280 can be located, and that the trigger instruction and any instructions 00281 in the trap shadow can be re-executed, certain restrictions are placed 00282 on the type of instructions or the mix of operands in the trap shadow. 00283 00284 The code generation rules serve only to guarantee that the instruction 00285 backup algorithm and subsequent re-execution can always be successful. 00286 Hence the restrictions on such constructs as branches, jumps, and the 00287 re-use of source or destination operands within the trap shadow. 00288 00289 Arguments: 00290 00291 ExceptionRecord - Supplies a pointer to an exception record. 00292 00293 TrapFrame - Supplies a pointer to a trap frame. 00294 00295 Return Value: 00296 00297 If the trigger PC was precisely determined, the exception address in 00298 the exception record is set to the trigger PC, the continuation address 00299 in the trap frame is updated, and a value of TRUE is returned. Otherwise 00300 no values are stored and a value of FALSE is returned. 00301 00302 --*/ 00303 00304 { 00305 00306 PEXC_SUM ExceptionSummary; 00307 ULONG Fa; 00308 ULONG Fb; 00309 ULONG Fc; 00310 ULONG FloatRegisterTrashMask; 00311 ULONG FloatRegisterWriteMask; 00312 ALPHA_INSTRUCTION Instruction; 00313 ULONG IntegerRegisterWriteMask; 00314 ULONG Opcode; 00315 ULONG_PTR TrapShadowLowLimit; 00316 ULONG_PTR TriggerPc; 00317 KPROCESSOR_MODE PreviousMode; 00318 00319 // 00320 // Obtain a copy of the float and integer register write mask registers 00321 // and the exception summary register from the exception record built by 00322 // PALcode. 00323 // 00324 00325 FloatRegisterWriteMask = (ULONG)ExceptionRecord->ExceptionInformation[0]; 00326 IntegerRegisterWriteMask = (ULONG)ExceptionRecord->ExceptionInformation[1]; 00327 ExceptionSummary = (PEXC_SUM)&(ExceptionRecord->ExceptionInformation[2]); 00328 DBGPRINT("KiLocateTriggerPc: WriteMask %.8lx.%.8lx, ExceptionSummary %.8lx\n", 00329 FloatRegisterWriteMask, IntegerRegisterWriteMask, 00330 *(PULONG)ExceptionSummary); 00331 00332 // 00333 // Capture previous mode from trap frame not current thread. 00334 // 00335 00336 PreviousMode = (KPROCESSOR_MODE)(((PSR *)(&TrapFrame->Psr))->MODE); 00337 00338 if (FloatRegisterWriteMask == 0) { 00339 00340 // 00341 // It should not be possible to have a floating point exception without 00342 // at least one of the destination float register bits set. The trap 00343 // shadow is invalid. 00344 // 00345 00346 DBGPRINT("KiLocateTriggerPc: FloatRegisterWriteMask clear\n"); 00347 NON_IEEE(ExceptionRecord, TRIGGER_FLOATING_REGISTER_MASK_CLEAR); 00348 return FALSE; 00349 } 00350 if (IntegerRegisterWriteMask != 0) { 00351 00352 // 00353 // It is not possible to precisely locate the trigger instruction 00354 // when the integer overflow bit is set. The trap shadow is invalid. 00355 // 00356 00357 DBGPRINT("KiLocateTriggerPc: IntegerRegisterMask set.\n"); 00358 NON_IEEE(ExceptionRecord, TRIGGER_INTEGER_REGISTER_MASK_SET); 00359 return FALSE; 00360 } 00361 if (ExceptionSummary->SoftwareCompletion == 0) { 00362 00363 // 00364 // The exception summary software completion bit is the AND of the 00365 // /S bits of all trapping instructions in the trap shadow. Since 00366 // the software completion bit is not set, it can be assumed the 00367 // code that was executing does not want precise exceptions, or if 00368 // it does, the code does not comply with the Alpha AXP guidelines 00369 // for locating the trigger PC. The trap shadow is invalid. 00370 // 00371 00372 DBGPRINT("KiLocateTriggerPc: SoftwareCompletion clear\n"); 00373 NON_IEEE(ExceptionRecord, TRIGGER_NO_SOFTWARE_COMPLETION); 00374 return FALSE; 00375 } 00376 00377 // 00378 // Search for the trigger instruction starting with the instruction before 00379 // the continuation PC (the instruction pointed to by Fir either did not 00380 // complete or did not even start). Limit the search to the arbitrary 00381 // limit of N instructions back from the current PC to prevent unbounded 00382 // searches. The search is complete when all trapping destination register 00383 // bits in the float write mask register have been accounted for. 00384 // 00385 00386 FloatRegisterTrashMask = 0; 00387 TriggerPc = (ULONG_PTR)TrapFrame->Fir; 00388 TrapShadowLowLimit = TriggerPc - (500 * sizeof(ULONG)); 00389 00390 try { 00391 do { 00392 TriggerPc -= 4; 00393 if (TriggerPc < TrapShadowLowLimit) { 00394 00395 // 00396 // The trigger PC is too far away from the exception PC to 00397 // be reasonable. The trap shadow is invalid. 00398 // 00399 00400 DBGPRINT("KiLocateTriggerPc: Trap shadow too long\n"); 00401 NON_IEEE(ExceptionRecord, TRIGGER_INSTRUCTION_NOT_FOUND); 00402 return FALSE; 00403 } 00404 00405 if (PreviousMode != KernelMode) { 00406 Instruction.Long = ProbeAndReadUlong((PULONG)TriggerPc); 00407 } else { 00408 Instruction.Long = *((PULONG)TriggerPc); 00409 } 00410 00411 // 00412 // Examine the opcode of this instruction to determine if the 00413 // trap shadow is invalid. 00414 // 00415 00416 Opcode = Instruction.Memory.Opcode; 00417 if (Opcode == JMP_OP) { 00418 00419 // 00420 // This is one of the jump instructions: jump, return, or 00421 // either form of jsr. The trap shadow is invalid. 00422 // 00423 00424 DBGPRINT("KiLocateTriggerPc: Jump within Trap Shadow\n"); 00425 NON_IEEE(ExceptionRecord, TRIGGER_INVALID_INSTRUCTION_FOUND); 00426 return FALSE; 00427 00428 } else if ((Opcode >= BR_OP) && (Opcode <= BGT_OP)) { 00429 00430 // 00431 // The instruction is one of 16 branch opcodes that consists 00432 // of BR, the 6 floating point branch, BSR, and the 8 integer 00433 // branch instructions. The trap shadow is invalid. 00434 // 00435 00436 DBGPRINT("KiLocateTriggerPc: Branch within Trap Shadow\n"); 00437 NON_IEEE(ExceptionRecord, TRIGGER_INVALID_INSTRUCTION_FOUND); 00438 return FALSE; 00439 00440 } else if ((Instruction.Memory.Opcode == MEMSPC_OP) && 00441 ((Instruction.Memory.MemDisp == TRAPB_FUNC) || 00442 (Instruction.Memory.MemDisp == EXCB_FUNC))) { 00443 00444 // 00445 // The instruction is a type of TRAPB instruction. The trap 00446 // shadow is invalid. 00447 // 00448 00449 DBGPRINT("KiLocateTriggerPc: Trapb within Trap Shadow\n"); 00450 NON_IEEE(ExceptionRecord, TRIGGER_INVALID_INSTRUCTION_FOUND); 00451 return FALSE; 00452 00453 } else if (Opcode == CALLPAL_OP) { 00454 00455 // 00456 // The instruction is a Call PAL. The trap shadow is invalid. 00457 // 00458 00459 DBGPRINT("KiLocateTriggerPc: Call PAL within Trap Shadow\n"); 00460 NON_IEEE(ExceptionRecord, TRIGGER_INVALID_INSTRUCTION_FOUND); 00461 return FALSE; 00462 00463 } else if ((Opcode == IEEEFP_OP) || (Opcode == FPOP_OP)) { 00464 00465 // 00466 // The instruction is an IEEE floating point instruction. 00467 // Decode the destination register of the floating point 00468 // instruction in order to check against the register mask. 00469 // 00470 00471 Fc = Instruction.FpOp.Fc; 00472 if (Fc != FZERO_REG) { 00473 FloatRegisterTrashMask |= (1 << Fc); 00474 } 00475 FloatRegisterWriteMask &= ~(1 << Fc); 00476 } 00477 00478 } while (FloatRegisterWriteMask != 0); 00479 00480 // 00481 // If the instruction thought to be the trigger instruction does not 00482 // have the /S bit set, then the trap shadow is invalid (some other 00483 // instruction must have caused software completion bit to be set). 00484 // 00485 00486 if ((Instruction.FpOp.Function & FP_TRAP_ENABLE_S) == 0) { 00487 DBGPRINT("KiLocateTriggerPc: Trigger instruction missing /S\n"); 00488 NON_IEEE(ExceptionRecord, TRIGGER_WRONG_INSTRUCTION); 00489 return FALSE; 00490 } 00491 00492 // 00493 // If either of the operand registers of the trigger instruction is 00494 // also the destination register of the trigger instruction or any 00495 // instruction in the trap shadow, then the trap shadow in invalid. 00496 // This is because the original value of the operand register(s) may 00497 // have been destroyed making it impossible to re-execute the trigger 00498 // instruction. 00499 // 00500 00501 Fa = Instruction.FpOp.Fa; 00502 Fb = Instruction.FpOp.Fb; 00503 if ((FloatRegisterTrashMask & ((1 << Fa) | (1 << Fb))) != 0) { 00504 DBGPRINT("KiLocateTriggerPc: Source is destination\n"); 00505 NON_IEEE(ExceptionRecord, TRIGGER_SOURCE_IS_DESTINATION); 00506 return FALSE; 00507 } 00508 00509 } except (EXCEPTION_EXECUTE_HANDLER) { 00510 00511 // 00512 // An exception occurred while fetching the value of the 00513 // next previous instruction. The trap shadow is invalid. 00514 // 00515 00516 DBGPRINT("KiLocateTriggerPc: Instruction fetch error\n"); 00517 NON_IEEE(ExceptionRecord, TRIGGER_INSTRUCTION_FETCH_ERROR); 00518 return FALSE; 00519 } 00520 00521 // 00522 // The trigger instruction was successfully located. Set the precise 00523 // exception address in the exception record, set the new continuation 00524 // address in the trap frame, and return a value of TRUE. 00525 // 00526 00527 DBGPRINT("KiLocateTriggerPc: Exception PC = %p, Trigger PC = %p\n", 00528 ExceptionRecord->ExceptionAddress, TriggerPc); 00529 ExceptionRecord->ExceptionAddress = (PVOID)TriggerPc; 00530 TrapFrame->Fir = (ULONGLONG)(LONG_PTR)(TriggerPc + 4); 00531 return TRUE; 00532 } 00533 00534 VOID 00535 KiSetFloatingStatus ( 00536 IN OUT PEXCEPTION_RECORD ExceptionRecord 00537 ) 00538 00539 /*++ 00540 00541 Routine Description: 00542 00543 This function is called to convert the exception summary register bits 00544 into a status code value. 00545 00546 Arguments: 00547 00548 ExceptionRecord - Supplies a pointer to an exception record. 00549 00550 Return Value: 00551 00552 None. 00553 00554 --*/ 00555 00556 { 00557 00558 PEXC_SUM ExceptionSummary; 00559 00560 // 00561 // Perform the following triage on the exception summary register to 00562 // report the type of exception, even if though the PC reported is 00563 // imprecise. 00564 // 00565 00566 DBGPRINT("KiSetFloatingStatus: ExceptionSummary = %.8lx\n", 00567 ExceptionRecord->ExceptionInformation[2]); 00568 00569 ExceptionSummary = (PEXC_SUM)(&ExceptionRecord->ExceptionInformation[2]); 00570 if (ExceptionSummary->InvalidOperation != 0) { 00571 ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION; 00572 00573 } else if (ExceptionSummary->DivisionByZero != 0) { 00574 ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO; 00575 00576 } else if (ExceptionSummary->Overflow != 0) { 00577 ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW; 00578 00579 } else if (ExceptionSummary->Underflow != 0) { 00580 ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW; 00581 00582 } else if (ExceptionSummary->InexactResult != 0) { 00583 ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT; 00584 00585 } else if (ExceptionSummary->IntegerOverflow != 0) { 00586 ExceptionRecord->ExceptionCode = STATUS_INTEGER_OVERFLOW; 00587 00588 } else { 00589 ExceptionRecord->ExceptionCode = STATUS_FLOAT_STACK_CHECK; 00590 } 00591 }

Generated on Sat May 15 19:42:05 2004 for test by doxygen 1.3.7