Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
7.0 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. iafptrap.c
  5. Abstract:
  6. This is based on the i386 trapc.c module with very minor changes.
  7. It would be nice if there wasn't so much duplicate code so that
  8. fixes to that file would carry over to this one...
  9. This module contains some trap handling code written in C.
  10. Only by the kernel.
  11. Author:
  12. Ken Reneris 6-9-93
  13. Revision History:
  14. --*/
  15. #include "ki.h"
  16. #include "ia32def.h"
  17. NTSTATUS
  18. Ki386CheckDivideByZeroTrap (
  19. IN PKTRAP_FRAME UserFrame
  20. );
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE, Ki386CheckDivideByZeroTrap)
  23. #endif
  24. #define REG(field) ((ULONG_PTR)(&((KTRAP_FRAME *)0)->field))
  25. #define GETREG(frame,reg) ((PULONG) (((ULONG_PTR) frame)+reg))[0]
  26. typedef struct {
  27. UCHAR RmDisplaceOnly; // RM of displacment only, no base reg
  28. UCHAR RmSib; // RM of SIB
  29. UCHAR RmDisplace; // bit mask of RMs which have a displacement
  30. UCHAR Disp; // sizeof displacement (in bytes)
  31. } KMOD, *PKMOD;
  32. static ULONG_PTR RM32[] = {
  33. /* 000 */ REG(IntV0), // EAX
  34. /* 001 */ REG(IntT2), // ECX
  35. /* 010 */ REG(IntT3), // EDX
  36. /* 011 */ REG(IntT4), // EBX
  37. /* 100 */ REG(IntSp), // ESP
  38. /* 101 */ REG(IntTeb), // EBP
  39. /* 110 */ REG(IntT5), // ESI
  40. /* 111 */ REG(IntT6) // EDI
  41. };
  42. static KMOD MOD32[] = {
  43. /* 00 */ 5, 4, 0x20, 4,
  44. /* 01 */ 0xff, 4, 0xff, 1,
  45. /* 10 */ 0xff, 4, 0xff, 4,
  46. /* 11 */ 0xff, 0xff, 0x00, 0
  47. } ;
  48. static struct {
  49. UCHAR Opcode1, Opcode2; // instruction opcode
  50. UCHAR ModRm, type; // if 2nd part of opcode is encoded in ModRm
  51. } NoWaitNpxInstructions[] = {
  52. /* FNINIT */ 0xDB, 0xE3, 0, 1,
  53. /* FNCLEX */ 0xDB, 0xE2, 0, 1,
  54. /* FNSTENV */ 0xD9, 0x06, 1, 1,
  55. /* FNSAVE */ 0xDD, 0x06, 1, 1,
  56. /* FNSTCW */ 0xD9, 0x07, 1, 2,
  57. /* FNSTSW */ 0xDD, 0x07, 1, 3,
  58. /* FNSTSW AX*/ 0xDF, 0xE0, 0, 4,
  59. 0x00, 0x00, 0, 1
  60. };
  61. NTSTATUS
  62. Ki386CheckDivideByZeroTrap (
  63. IN PKTRAP_FRAME UserFrame
  64. )
  65. /*++
  66. Routine Description:
  67. This function gains control when the x86 processor generates a
  68. divide by zero trap. The x86 design generates such a trap on
  69. divide by zero and on division overflows. In order to determine
  70. which expection code to dispatch, the divisor of the "div" or "idiv"
  71. instruction needs to be inspected.
  72. Arguments:
  73. UserFrame - Trap frame of the divide by zero trap
  74. Return Value:
  75. exception code dispatch
  76. --*/
  77. {
  78. ULONG operandsize, operandmask, i;
  79. ULONG_PTR accum;
  80. PUCHAR istream;
  81. UCHAR ibyte, rm;
  82. PKMOD Mod;
  83. BOOLEAN fPrefix;
  84. NTSTATUS status;
  85. BOOLEAN fHighRm8;
  86. status = STATUS_INTEGER_DIVIDE_BY_ZERO;
  87. fHighRm8 = FALSE;
  88. try {
  89. //
  90. // read instruction prefixes
  91. //
  92. fPrefix = TRUE;
  93. operandsize = 4;
  94. operandmask = 0xffffffff;
  95. istream = (PUCHAR) (ULONG_PTR) EIP(UserFrame);
  96. do {
  97. ibyte = ProbeAndReadUchar(istream);
  98. istream++;
  99. switch (ibyte) {
  100. case 0x2e: // cs override
  101. case 0x36: // ss override
  102. case 0x3e: // ds override
  103. case 0x26: // es override
  104. case 0x64: // fs override
  105. case 0x65: // gs override
  106. case 0xF3: // rep
  107. case 0xF2: // rep
  108. case 0xF0: // lock
  109. break;
  110. case 0x66:
  111. // 16 bit operand override
  112. operandsize = 2;
  113. operandmask = 0xffff;
  114. break;
  115. case 0x67:
  116. // 16 bit address size override
  117. // this is some non-flat code
  118. goto try_exit;
  119. default:
  120. fPrefix = FALSE;
  121. break;
  122. }
  123. } while (fPrefix);
  124. //
  125. // Check instruction opcode
  126. //
  127. if (ibyte != 0xf7 && ibyte != 0xf6) {
  128. // this is not a DIV or IDIV opcode
  129. goto try_exit;
  130. }
  131. if (ibyte == 0xf6) {
  132. // this is a byte div or idiv
  133. operandsize = 1;
  134. operandmask = 0xff;
  135. }
  136. //
  137. // Get Mod R/M
  138. //
  139. ibyte = ProbeAndReadUchar (istream);
  140. istream++;
  141. Mod = MOD32 + (ibyte >> 6);
  142. rm = ibyte & 7;
  143. //
  144. // put register values into accum
  145. //
  146. if (operandsize == 1 && (ibyte & 0xc0) == 0xc0) {
  147. if ((rm & 4) != 0) {
  148. fHighRm8 = TRUE;
  149. }
  150. }
  151. accum = 0;
  152. if (rm != Mod->RmDisplaceOnly) {
  153. if (rm == Mod->RmSib) {
  154. // get SIB
  155. ibyte = ProbeAndReadUchar(istream);
  156. istream++;
  157. i = (ibyte >> 3) & 7;
  158. if (i != 4) {
  159. accum = GETREG(UserFrame, RM32[i]);
  160. accum = accum << (ibyte >> 6); // apply scaler
  161. }
  162. i = ibyte & 7;
  163. accum = accum + GETREG(UserFrame, RM32[i]);
  164. } else {
  165. //
  166. // get register's value
  167. //
  168. if (fHighRm8 == TRUE) {
  169. accum = GETREG(UserFrame, RM32[rm & 3]);
  170. accum = accum >> 8;
  171. } else {
  172. accum = GETREG(UserFrame, RM32[rm]);
  173. }
  174. }
  175. }
  176. //
  177. // apply displacement to accum
  178. //
  179. if (Mod->RmDisplace & (1 << rm)) {
  180. if (Mod->Disp == 4) {
  181. i = ProbeAndReadUlong ((PULONG) istream);
  182. } else {
  183. ibyte = ProbeAndReadChar ((PCHAR)istream);
  184. i = (signed long) ((signed char) ibyte); // sign extend
  185. }
  186. accum += i;
  187. }
  188. //
  189. // if this is an effective address, go get the data value
  190. //
  191. if (Mod->Disp) {
  192. switch (operandsize) {
  193. case 1: accum = ProbeAndReadUchar((PUCHAR) accum); break;
  194. case 2: accum = ProbeAndReadUshort((PUSHORT) accum); break;
  195. case 4: accum = ProbeAndReadUlong((PULONG) accum); break;
  196. }
  197. }
  198. //
  199. // accum now contains the instruction operand, see if the
  200. // operand was really a zero
  201. //
  202. if (accum & operandmask) {
  203. // operand was non-zero, must be an overflow
  204. status = STATUS_INTEGER_OVERFLOW;
  205. }
  206. try_exit: ;
  207. } except (EXCEPTION_EXECUTE_HANDLER) {
  208. // do nothing...
  209. }
  210. return status;
  211. }