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

trapc.c File Reference

#include "ki.h"

Go to the source code of this file.

Classes

struct  KMOD

Defines

#define REG(field)   ((ULONG)(&((KTRAP_FRAME *)0)->field))
#define GETREG(frame, reg)   ((PULONG) (((ULONG) frame)+reg))[0]

Typedefs

typedef * PKMOD

Functions

NTSTATUS Ki386CheckDivideByZeroTrap (IN PKTRAP_FRAME UserFrame)
UCHAR KiNextIStreamByte (IN PKTRAP_FRAME UserFrame, IN PUCHAR *istream)
BOOLEAN Ki386CheckDelayedNpxTrap (IN PKTRAP_FRAME UserFrame, IN PFX_SAVE_AREA NpxFrame)

Variables

UCHAR RM32 []
UCHAR RM8 []
KMOD MOD32 []
struct {
   UCHAR   Opcode1
   UCHAR   Opcode2
   UCHAR   ModRm
   UCHAR   type
NoWaitNpxInstructions []


Define Documentation

#define GETREG frame,
reg   )     ((PULONG) (((ULONG) frame)+reg))[0]
 

Definition at line 36 of file i386/trapc.c.

Referenced by Ki386CheckDelayedNpxTrap(), and Ki386CheckDivideByZeroTrap().

#define REG field   )     ((ULONG)(&((KTRAP_FRAME *)0)->field))
 

Definition at line 35 of file i386/trapc.c.


Typedef Documentation

typedef * PKMOD
 

Referenced by Ki386CheckDelayedNpxTrap(), and Ki386CheckDivideByZeroTrap().


Function Documentation

BOOLEAN Ki386CheckDelayedNpxTrap IN PKTRAP_FRAME  UserFrame,
IN PFX_SAVE_AREA  NpxFrame
 

Definition at line 309 of file i386/trapc.c.

References EXCEPTION_EXECUTE_HANDLER, FALSE, GETREG, KiCopyInformation(), KiDispatchException(), KiNextIStreamByte(), MOD32, NoWaitNpxInstructions, NULL, PKMOD, ProbeAndWriteUshort, PUSHORT, RM32, TRUE, UserMode, and USHORT.

00316 : 00317 00318 This function gains control from the Trap07 handler. It examines 00319 the user mode instruction to see if it's a NoWait NPX instruction. 00320 Such instructions do not generate floating point exceptions - this 00321 check needs to be done due to the way 80386/80387 systems are 00322 implemented. Such machines will generate a floating point exception 00323 interrupt when the kernel performs an FRSTOR to reload the thread's 00324 NPX context. If the thread's next instruction is a NoWait style 00325 instruction, then we clear the exception or emulate the instruction. 00326 00327 AND... due to a different 80386/80387 "feature" the kernel needs 00328 to use FWAIT at times which can causes 80487's to generate delayed 00329 exceptions that can lead to the same problem described above. 00330 00331 Arguments: 00332 00333 UserFrame - Trap frame of the exception 00334 NpxFrame - Thread's NpxFrame (WARNING: does not have NpxState) 00335 00336 Interrupts are disabled 00337 00338 Return Value: 00339 00340 FALSE - Dispatch NPX exception to user mode 00341 TRUE - Exception handled, continue 00342 00343 --*/ 00344 00345 { 00346 EXCEPTION_RECORD ExceptionRecord; 00347 UCHAR ibyte1, ibyte2, inmodrm, status; 00348 USHORT StatusWord, ControlWord, UsersWord; 00349 PUCHAR istream; 00350 BOOLEAN fPrefix; 00351 UCHAR rm; 00352 PKMOD Mod; 00353 ULONG accum, i; 00354 00355 status = 0; 00356 try { 00357 00358 // 00359 // read instruction prefixes 00360 // 00361 00362 fPrefix = TRUE; 00363 istream = (PUCHAR) UserFrame->Eip; 00364 while (fPrefix) { 00365 ibyte1 = KiNextIStreamByte (UserFrame, &istream); 00366 switch (ibyte1) { 00367 case 0x2e: // cs override 00368 case 0x36: // ss override 00369 case 0x3e: // ds override 00370 case 0x26: // es override 00371 case 0x64: // fs override 00372 case 0x65: // gs override 00373 break; 00374 00375 default: 00376 fPrefix = FALSE; 00377 break; 00378 } 00379 } 00380 00381 // 00382 // Check for coprocessor NoWait NPX instruction 00383 // 00384 00385 ibyte2 = KiNextIStreamByte (UserFrame, &istream); 00386 inmodrm = (ibyte2 >> 3) & 0x7; 00387 00388 for (i=0; NoWaitNpxInstructions[i].Opcode1; i++) { 00389 if (NoWaitNpxInstructions[i].Opcode1 == ibyte1) { 00390 00391 // 00392 // first opcode byte matched - check second part of opcode 00393 // 00394 00395 if (NoWaitNpxInstructions[i].ModRm) { 00396 00397 // 00398 // modrm only applies for opcode in range 0-0xbf 00399 // 00400 00401 if (((ibyte2 & 0xc0) != 0xc0) && 00402 (NoWaitNpxInstructions[i].Opcode2 == inmodrm)) { 00403 00404 // 00405 // This is a no-wait NPX instruction 00406 // 00407 00408 status = NoWaitNpxInstructions[i].type; 00409 break; 00410 } 00411 00412 } else { 00413 if (NoWaitNpxInstructions[i].Opcode2 == ibyte2) { 00414 00415 // 00416 // This is a no-wait NPX instruction 00417 // 00418 00419 status = NoWaitNpxInstructions[i].type; 00420 break; 00421 } 00422 } 00423 } 00424 } 00425 00426 } except (EXCEPTION_EXECUTE_HANDLER) { 00427 // do nothing... 00428 } 00429 00430 if (status == 0) { 00431 // 00432 // Dispatch coprocessor exception to user mode 00433 // 00434 00435 return FALSE; 00436 } 00437 00438 if (status == 1) { 00439 // 00440 // Ignore pending exception, user mode instruction does not trap 00441 // on pending execptions and it will clear/mask the pending exceptions 00442 // 00443 00444 _asm { 00445 mov eax, cr0 00446 and eax, NOT (CR0_MP+CR0_EM+CR0_TS) 00447 mov cr0, eax 00448 } 00449 00450 NpxFrame->Cr0NpxState &= ~CR0_TS; 00451 return TRUE; 00452 } 00453 00454 // 00455 // This is either FNSTSW or FNSTCW. Both of these instructions get 00456 // a value from the coprocessor without effecting the pending exception 00457 // state. To do this we emulate the instructions. 00458 // 00459 00460 // 00461 // Read the coprocessors Status & Control word state, then re-enable 00462 // interrupts. (it's safe to context switch after that point) 00463 // 00464 00465 _asm { 00466 mov eax, cr0 00467 mov ecx, eax 00468 and eax, NOT (CR0_MP+CR0_EM+CR0_TS) 00469 mov cr0, eax 00470 00471 fnstsw StatusWord 00472 fnstcw ControlWord 00473 00474 mov cr0, ecx 00475 sti 00476 } 00477 00478 if (status == 4) { 00479 // 00480 // Emulate FNSTSW AX 00481 // 00482 00483 UserFrame->Eip = (ULONG)istream; 00484 UserFrame->Eax = (UserFrame->Eax & 0xFFFF0000) | StatusWord; 00485 return TRUE; 00486 } 00487 00488 if (status == 2) { 00489 UsersWord = ControlWord; 00490 } else { 00491 UsersWord = StatusWord; 00492 } 00493 00494 try { 00495 00496 // 00497 // (PERFNOTE: the operand decode code should really share code with 00498 // KiCheckDivideByZeroTrap, but this is a late change therefore the 00499 // code was copied to keep the impact of the change localized) 00500 // 00501 00502 // 00503 // decode Mod/RM byte 00504 // 00505 00506 Mod = MOD32 + (ibyte2 >> 6); 00507 rm = ibyte2 & 7; 00508 00509 // 00510 // Decode the instruction's word pointer into accum 00511 // 00512 00513 accum = 0; 00514 if (rm != Mod->RmDisplaceOnly) { 00515 if (rm == Mod->RmSib) { 00516 // get SIB 00517 ibyte1 = KiNextIStreamByte (UserFrame, &istream); 00518 i = (ibyte1 >> 3) & 7; 00519 if (i != 4) { 00520 accum = GETREG(UserFrame, RM32[i]); 00521 accum = accum << (ibyte1 >> 6); // apply scaler 00522 } 00523 i = ibyte1 & 7; 00524 accum = accum + GETREG(UserFrame, RM32[i]); 00525 } else { 00526 // get register's value 00527 accum = GETREG(UserFrame, RM32[rm]); 00528 } 00529 } 00530 00531 // 00532 // apply displacement to accum 00533 // 00534 00535 if (Mod->RmDisplace & (1 << rm)) { 00536 if (Mod->Disp == 4) { 00537 i = (KiNextIStreamByte (UserFrame, &istream) << 0) | 00538 (KiNextIStreamByte (UserFrame, &istream) << 8) | 00539 (KiNextIStreamByte (UserFrame, &istream) << 16) | 00540 (KiNextIStreamByte (UserFrame, &istream) << 24); 00541 } else { 00542 ibyte1 = KiNextIStreamByte (UserFrame, &istream); 00543 i = (signed long) ((signed char) ibyte1); // sign extend 00544 } 00545 accum += i; 00546 } 00547 00548 // 00549 // Set the word pointer 00550 // 00551 00552 if (UserFrame->SegCs == KGDT_R0_CODE) { 00553 *((PUSHORT) accum) = UsersWord; 00554 } else { 00555 ProbeAndWriteUshort ((PUSHORT) accum, UsersWord); 00556 } 00557 UserFrame->Eip = (ULONG)istream; 00558 00559 } except (KiCopyInformation(&ExceptionRecord, 00560 (GetExceptionInformation())->ExceptionRecord)) { 00561 // 00562 // Faulted addressing user's memory. 00563 // Set the address of the exception to the current program address 00564 // and raise the exception by calling the exception dispatcher. 00565 // 00566 00567 ExceptionRecord.ExceptionAddress = (PVOID)(UserFrame->Eip); 00568 KiDispatchException( 00569 &ExceptionRecord, 00570 NULL, // ExceptionFrame 00571 UserFrame, 00572 UserMode, 00573 TRUE 00574 ); 00575 } 00576 00577 return TRUE; 00578 } }

NTSTATUS Ki386CheckDivideByZeroTrap IN PKTRAP_FRAME  UserFrame  ) 
 

Definition at line 90 of file i386/trapc.c.

References EXCEPTION_EXECUTE_HANDLER, FALSE, GETREG, KeBugCheck(), MOD32, NTSTATUS(), PKMOD, ProbeAndReadChar, ProbeAndReadUchar, ProbeAndReadUlong, ProbeAndReadUshort, PUSHORT, RM32, RM8, TRUE, and UNEXPECTED_KERNEL_MODE_TRAP.

00095 : 00096 00097 This function gains control when the x86 processor generates a 00098 divide by zero trap. The x86 design generates such a trap on 00099 divide by zero and on division overflows. In order to determine 00100 which expection code to dispatch, the divisor of the "div" or "idiv" 00101 instruction needs to be inspected. 00102 00103 Arguments: 00104 00105 UserFrame - Trap frame of the divide by zero trap 00106 00107 Return Value: 00108 00109 exception code dispatch 00110 00111 --*/ 00112 { 00113 ULONG operandsize, operandmask, i, accum; 00114 PUCHAR istream, pRM; 00115 UCHAR ibyte, rm; 00116 PKMOD Mod; 00117 BOOLEAN fPrefix; 00118 NTSTATUS status; 00119 00120 status = STATUS_INTEGER_DIVIDE_BY_ZERO; 00121 00122 if (UserFrame->SegCs == KGDT_R0_CODE) { 00123 // 00124 // Divide by zero exception from Kernel Mode? 00125 // Likely bad hardware interrupt and the device or vector table is corrupt. 00126 // Bugcheck NOW so we can figure out what went wrong. If we try and 00127 // proceed, then we'll likely fault in reading the top of user space, and then 00128 // double fault (page fault in the div zero handler.) -- This is a debugging 00129 // consideration. You can't put breakpoints on the trap labels so this is hard to debug. 00130 // We cannot recover 00131 // 00132 // 00133 KeBugCheck (UNEXPECTED_KERNEL_MODE_TRAP); 00134 00135 } 00136 00137 00138 try { 00139 00140 // 00141 // read instruction prefixes 00142 // 00143 00144 fPrefix = TRUE; 00145 pRM = RM32; 00146 operandsize = 4; 00147 operandmask = 0xffffffff; 00148 istream = (PUCHAR) UserFrame->Eip; 00149 while (fPrefix) { 00150 ibyte = ProbeAndReadUchar(istream); 00151 istream++; 00152 switch (ibyte) { 00153 case 0x2e: // cs override 00154 case 0x36: // ss override 00155 case 0x3e: // ds override 00156 case 0x26: // es override 00157 case 0x64: // fs override 00158 case 0x65: // gs override 00159 case 0xF3: // rep 00160 case 0xF2: // rep 00161 case 0xF0: // lock 00162 break; 00163 00164 case 0x66: 00165 // 16 bit operand override 00166 operandsize = 2; 00167 operandmask = 0xffff; 00168 break; 00169 00170 case 0x67: 00171 // 16 bit address size override 00172 // this is some non-flat code 00173 goto try_exit; 00174 00175 default: 00176 fPrefix = FALSE; 00177 break; 00178 } 00179 } 00180 00181 // 00182 // Check instruction opcode 00183 // 00184 00185 if (ibyte != 0xf7 && ibyte != 0xf6) { 00186 // this is not a DIV or IDIV opcode 00187 goto try_exit; 00188 } 00189 00190 if (ibyte == 0xf6) { 00191 // this is a byte div or idiv 00192 operandsize = 1; 00193 operandmask = 0xff; 00194 } 00195 00196 // 00197 // Get Mod R/M 00198 // 00199 00200 ibyte = ProbeAndReadUchar (istream); 00201 istream++; 00202 Mod = MOD32 + (ibyte >> 6); 00203 rm = ibyte & 7; 00204 00205 // 00206 // put register values into accum 00207 // 00208 00209 if (operandsize == 1 && (ibyte & 0xc0) == 0xc0) { 00210 pRM = RM8; 00211 } 00212 00213 accum = 0; 00214 if (rm != Mod->RmDisplaceOnly) { 00215 if (rm == Mod->RmSib) { 00216 // get SIB 00217 ibyte = ProbeAndReadUchar(istream); 00218 istream++; 00219 i = (ibyte >> 3) & 7; 00220 if (i != 4) { 00221 accum = GETREG(UserFrame, RM32[i]); 00222 accum = accum << (ibyte >> 6); // apply scaler 00223 } 00224 i = ibyte & 7; 00225 accum = accum + GETREG(UserFrame, RM32[i]); 00226 } else { 00227 // get register's value 00228 accum = GETREG(UserFrame, pRM[rm]); 00229 } 00230 } 00231 00232 // 00233 // apply displacement to accum 00234 // 00235 00236 if (Mod->RmDisplace & (1 << rm)) { 00237 if (Mod->Disp == 4) { 00238 i = ProbeAndReadUlong ((PULONG) istream); 00239 } else { 00240 ibyte = ProbeAndReadChar (istream); 00241 i = (signed long) ((signed char) ibyte); // sign extend 00242 } 00243 accum += i; 00244 } 00245 00246 // 00247 // if this is an effective address, go get the data value 00248 // 00249 00250 if (Mod->Disp) { 00251 switch (operandsize) { 00252 case 1: accum = ProbeAndReadUchar((PUCHAR) accum); break; 00253 case 2: accum = ProbeAndReadUshort((PUSHORT) accum); break; 00254 case 4: accum = ProbeAndReadUlong((PULONG) accum); break; 00255 } 00256 } 00257 00258 // 00259 // accum now contains the instruction operand, see if the 00260 // operand was really a zero 00261 // 00262 00263 if (accum & operandmask) { 00264 // operand was non-zero, must be an overflow 00265 status = STATUS_INTEGER_OVERFLOW; 00266 } 00267 00268 try_exit: ; 00269 } except (EXCEPTION_EXECUTE_HANDLER) { 00270 // do nothing... 00271 } 00272 00273 return status; 00274 }

UCHAR KiNextIStreamByte IN PKTRAP_FRAME  UserFrame,
IN PUCHAR *  istream
 

Definition at line 277 of file i386/trapc.c.

References ProbeAndReadUchar.

Referenced by Ki386CheckDelayedNpxTrap().

00283 : 00284 00285 Reads the next byte from the istream pointed to by the UserFrame, and 00286 advances the EIP. 00287 00288 00289 Note: this function works for 32 bit code only 00290 00291 --*/ 00292 { 00293 UCHAR ibyte; 00294 00295 if (UserFrame->SegCs == KGDT_R0_CODE) { 00296 ibyte = **istream; 00297 } else { 00298 ibyte = ProbeAndReadUchar (*istream); 00299 } 00300 00301 *istream += 1; 00302 return ibyte; 00303 }


Variable Documentation

KMOD MOD32[] [static]
 

Initial value:

{ 5, 4, 0x20, 4, 0xff, 4, 0xff, 1, 0xff, 4, 0xff, 4, 0xff, 0xff, 0x00, 0 }

Definition at line 67 of file i386/trapc.c.

Referenced by Ki386CheckDelayedNpxTrap(), and Ki386CheckDivideByZeroTrap().

UCHAR ModRm
 

Definition at line 76 of file i386/trapc.c.

struct { ... } NoWaitNpxInstructions[] [static]
 

Referenced by Ki386CheckDelayedNpxTrap().

UCHAR Opcode1
 

Definition at line 75 of file i386/trapc.c.

UCHAR Opcode2
 

Definition at line 75 of file i386/trapc.c.

UCHAR RM32[] [static]
 

Initial value:

{ REG(Eax), REG(Ecx), REG(Edx), REG(Ebx), REG(HardwareEsp), REG(Ebp), REG(Esi), REG(Edi) }

Definition at line 45 of file i386/trapc.c.

Referenced by Ki386CheckDelayedNpxTrap(), and Ki386CheckDivideByZeroTrap().

UCHAR RM8[] [static]
 

Initial value:

{ REG(Eax), REG(Ecx), REG(Edx), REG(Ebx), REG(Eax) + 1, REG(Ecx) + 1, REG(Edx) + 1, REG(Ebx) + 1 }

Definition at line 56 of file i386/trapc.c.

Referenced by Ki386CheckDivideByZeroTrap().

UCHAR type
 

Definition at line 76 of file i386/trapc.c.

Referenced by CmpAppendSection(), CmpGetInfData(), CreateHandle(), LdrpMapDll(), List(), LoadDIB(), LoadIcoCur(), LoadImageA(), main(), ObjectFromDIBResource(), OpenUserPerformanceData(), RtlLoadObjectFromDIBFile(), UserGetDesktopDC(), WowServerLoadCreateCursorIcon(), and xxxDrawDragRect().


Generated on Sat May 15 19:45:49 2004 for test by doxygen 1.3.7