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

iafptrap.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 iafptrap.c 00008 00009 Abstract: 00010 00011 This is based on the i386 trapc.c module with very minor changes. 00012 It would be nice if there wasn't so much duplicate code so that 00013 fixes to that file would carry over to this one... 00014 00015 This module contains some trap handling code written in C. 00016 Only by the kernel. 00017 00018 Author: 00019 00020 Ken Reneris 6-9-93 00021 00022 Revision History: 00023 00024 --*/ 00025 00026 #include "ki.h" 00027 #include "ia32def.h" 00028 00029 NTSTATUS 00030 Ki386CheckDivideByZeroTrap ( 00031 IN PKTRAP_FRAME UserFrame 00032 ); 00033 00034 00035 #ifdef ALLOC_PRAGMA 00036 #pragma alloc_text(PAGE, Ki386CheckDivideByZeroTrap) 00037 #endif 00038 00039 00040 #define REG(field) ((ULONG_PTR)(&((KTRAP_FRAME *)0)->field)) 00041 #define GETREG(frame,reg) ((PULONG) (((ULONG_PTR) frame)+reg))[0] 00042 00043 typedef struct { 00044 UCHAR RmDisplaceOnly; // RM of displacment only, no base reg 00045 UCHAR RmSib; // RM of SIB 00046 UCHAR RmDisplace; // bit mask of RMs which have a displacement 00047 UCHAR Disp; // sizeof displacement (in bytes) 00048 } KMOD, *PKMOD; 00049 00050 static ULONG_PTR RM32[] = { 00051 /* 000 */ REG(IntV0), // EAX 00052 /* 001 */ REG(IntT2), // ECX 00053 /* 010 */ REG(IntT3), // EDX 00054 /* 011 */ REG(IntT4), // EBX 00055 /* 100 */ REG(IntSp), // ESP 00056 /* 101 */ REG(IntTeb), // EBP 00057 /* 110 */ REG(IntT5), // ESI 00058 /* 111 */ REG(IntT6) // EDI 00059 }; 00060 00061 static ULONG_PTR RM8[] = { 00062 /* 000 */ REG(IntV0), // al 00063 /* 001 */ REG(IntT2), // cl 00064 /* 010 */ REG(IntT3), // dl 00065 /* 011 */ REG(IntT4), // bl 00066 /* 100 */ REG(IntV0) + 1, // ah 00067 /* 101 */ REG(IntT2) + 1, // ch 00068 /* 110 */ REG(IntT3) + 1, // dh 00069 /* 111 */ REG(IntT4) + 1 // bh 00070 }; 00071 00072 static KMOD MOD32[] = { 00073 /* 00 */ 5, 4, 0x20, 4, 00074 /* 01 */ 0xff, 4, 0xff, 1, 00075 /* 10 */ 0xff, 4, 0xff, 4, 00076 /* 11 */ 0xff, 0xff, 0x00, 0 00077 } ; 00078 00079 static struct { 00080 UCHAR Opcode1, Opcode2; // instruction opcode 00081 UCHAR ModRm, type; // if 2nd part of opcode is encoded in ModRm 00082 } NoWaitNpxInstructions[] = { 00083 /* FNINIT */ 0xDB, 0xE3, 0, 1, 00084 /* FNCLEX */ 0xDB, 0xE2, 0, 1, 00085 /* FNSTENV */ 0xD9, 0x06, 1, 1, 00086 /* FNSAVE */ 0xDD, 0x06, 1, 1, 00087 /* FNSTCW */ 0xD9, 0x07, 1, 2, 00088 /* FNSTSW */ 0xDD, 0x07, 1, 3, 00089 /* FNSTSW AX*/ 0xDF, 0xE0, 0, 4, 00090 0x00, 0x00, 0, 1 00091 }; 00092 00093 00094 NTSTATUS 00095 Ki386CheckDivideByZeroTrap ( 00096 IN PKTRAP_FRAME UserFrame 00097 ) 00098 /*++ 00099 00100 Routine Description: 00101 00102 This function gains control when the x86 processor generates a 00103 divide by zero trap. The x86 design generates such a trap on 00104 divide by zero and on division overflows. In order to determine 00105 which expection code to dispatch, the divisor of the "div" or "idiv" 00106 instruction needs to be inspected. 00107 00108 Arguments: 00109 00110 UserFrame - Trap frame of the divide by zero trap 00111 00112 Return Value: 00113 00114 exception code dispatch 00115 00116 --*/ 00117 { 00118 ULONG operandsize, operandmask, i; 00119 ULONG_PTR accum; 00120 PUCHAR istream; 00121 ULONG_PTR *pRM; 00122 UCHAR ibyte, rm; 00123 PKMOD Mod; 00124 BOOLEAN fPrefix; 00125 NTSTATUS status; 00126 00127 status = STATUS_INTEGER_DIVIDE_BY_ZERO; 00128 00129 try { 00130 00131 // 00132 // read instruction prefixes 00133 // 00134 00135 fPrefix = TRUE; 00136 pRM = RM32; 00137 operandsize = 4; 00138 operandmask = 0xffffffff; 00139 istream = (PUCHAR) EIP(UserFrame); 00140 while (fPrefix) { 00141 ibyte = ProbeAndReadUchar(istream); 00142 istream++; 00143 switch (ibyte) { 00144 case 0x2e: // cs override 00145 case 0x36: // ss override 00146 case 0x3e: // ds override 00147 case 0x26: // es override 00148 case 0x64: // fs override 00149 case 0x65: // gs override 00150 case 0xF3: // rep 00151 case 0xF2: // rep 00152 case 0xF0: // lock 00153 break; 00154 00155 case 0x66: 00156 // 16 bit operand override 00157 operandsize = 2; 00158 operandmask = 0xffff; 00159 break; 00160 00161 case 0x67: 00162 // 16 bit address size override 00163 // this is some non-flat code 00164 goto try_exit; 00165 00166 default: 00167 fPrefix = FALSE; 00168 break; 00169 } 00170 } 00171 00172 // 00173 // Check instruction opcode 00174 // 00175 00176 if (ibyte != 0xf7 && ibyte != 0xf6) { 00177 // this is not a DIV or IDIV opcode 00178 goto try_exit; 00179 } 00180 00181 if (ibyte == 0xf6) { 00182 // this is a byte div or idiv 00183 operandsize = 1; 00184 operandmask = 0xff; 00185 } 00186 00187 // 00188 // Get Mod R/M 00189 // 00190 00191 ibyte = ProbeAndReadUchar (istream); 00192 istream++; 00193 Mod = MOD32 + (ibyte >> 6); 00194 rm = ibyte & 7; 00195 00196 // 00197 // put register values into accum 00198 // 00199 00200 if (operandsize == 1 && (ibyte & 0xc0) == 0xc0) { 00201 pRM = RM8; 00202 } 00203 00204 accum = 0; 00205 if (rm != Mod->RmDisplaceOnly) { 00206 if (rm == Mod->RmSib) { 00207 // get SIB 00208 ibyte = ProbeAndReadUchar(istream); 00209 istream++; 00210 i = (ibyte >> 3) & 7; 00211 if (i != 4) { 00212 accum = GETREG(UserFrame, RM32[i]); 00213 accum = accum << (ibyte >> 6); // apply scaler 00214 } 00215 i = ibyte & 7; 00216 accum = accum + GETREG(UserFrame, RM32[i]); 00217 } else { 00218 // get register's value 00219 // 00220 // BUGBUG: Seems like this could be a problem if rm points 00221 // to the 8 bit registers (see line 200 above (pRm = RM8)) 00222 // since the GETREG routine gets a ULONG's worth of data 00223 // 1) The rm8 means there is only 8 significant bits, not 32 00224 // 2) If grabbing from the high half, pointer is to an odd 00225 // address when grab 32-bits - a misalign fault... 00226 // 00227 accum = GETREG(UserFrame, pRM[rm]); 00228 } 00229 } 00230 00231 // 00232 // apply displacement to accum 00233 // 00234 00235 if (Mod->RmDisplace & (1 << rm)) { 00236 if (Mod->Disp == 4) { 00237 i = ProbeAndReadUlong ((PULONG) istream); 00238 } else { 00239 ibyte = ProbeAndReadChar (istream); 00240 i = (signed long) ((signed char) ibyte); // sign extend 00241 } 00242 accum += i; 00243 } 00244 00245 // 00246 // if this is an effective address, go get the data value 00247 // 00248 00249 if (Mod->Disp) { 00250 switch (operandsize) { 00251 case 1: accum = ProbeAndReadUchar((PUCHAR) accum); break; 00252 case 2: accum = ProbeAndReadUshort((PUSHORT) accum); break; 00253 case 4: accum = ProbeAndReadUlong((PULONG) accum); break; 00254 } 00255 } 00256 00257 // 00258 // accum now contains the instruction operand, see if the 00259 // operand was really a zero 00260 // 00261 00262 if (accum & operandmask) { 00263 // operand was non-zero, must be an overflow 00264 status = STATUS_INTEGER_OVERFLOW; 00265 } 00266 00267 try_exit: ; 00268 } except (EXCEPTION_EXECUTE_HANDLER) { 00269 // do nothing... 00270 } 00271 00272 return status; 00273 }

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