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.

390 lines
7.2 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. fpexception.c
  5. Abstract:
  6. This module contains code to test i386 floating point exceptions.
  7. Author:
  8. Environment:
  9. User mode only.
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. VOID
  14. FPxInit(
  15. OUT PFP_THREAD_DATA FpThreadData
  16. )
  17. /*++
  18. Routine Description:
  19. Initializes FPU state to known values.
  20. Arguments:
  21. FpThreadData - FP thread data.
  22. Return Value:
  23. None.
  24. --*/
  25. {
  26. USHORT cw = 0x27B;
  27. //
  28. // Fill in the initial thread values.
  29. //
  30. FpThreadData->FtagBad = 99.999;
  31. FpThreadData->ExpectedExceptionEIP = 0xbad;
  32. FpThreadData->ExceptionEIP = 0xbad;
  33. FpThreadData->BadEip = 1;
  34. FpThreadData->status = stOK;
  35. // unmask zero divide exception
  36. _asm {
  37. fninit
  38. fldcw [cw]
  39. }
  40. }
  41. VOID
  42. FPxLoadTag(
  43. IN OUT PFP_THREAD_DATA FpThreadData,
  44. IN UINT Tag
  45. )
  46. /*++
  47. Routine Description:
  48. Loads a semi-unique tag value into the Npx for later validation.
  49. Arguments:
  50. FpThreadData - FP thread data.
  51. Tag - Tag to load.
  52. Return Value:
  53. None.
  54. --*/
  55. {
  56. double localCopy;
  57. FpThreadData->Ftag = localCopy = Tag * 1.41415926e3;
  58. _asm fld [localCopy]
  59. }
  60. VOID
  61. FPxPendDivideByZero(
  62. VOID
  63. )
  64. /*++
  65. Routine Description:
  66. Loads a divide-by-zero pending exception into the Npx.
  67. Arguments:
  68. None.
  69. Return Value:
  70. None.
  71. --*/
  72. {
  73. _asm {
  74. fld1
  75. fldz
  76. fdiv
  77. }
  78. }
  79. VOID
  80. FPxDrain(
  81. IN OUT PFP_THREAD_DATA FpThreadData
  82. )
  83. /*++
  84. Routine Description:
  85. Drains any pending exceptions in the Npx.
  86. Arguments:
  87. FpThreadData - Updated with what should be the address of the pending
  88. exception.
  89. Return Value:
  90. None.
  91. --*/
  92. {
  93. UINT localExceptionEIP;
  94. _asm {
  95. mov localExceptionEIP, offset ExcAddr
  96. }
  97. FpThreadData->ExpectedExceptionEIP = localExceptionEIP;
  98. _asm {
  99. ExcAddr:
  100. fldpi
  101. }
  102. }
  103. FPXERR
  104. FPxCheckTag(
  105. IN OUT PFP_THREAD_DATA FpThreadData
  106. )
  107. /*++
  108. Routine Description:
  109. Makes sure the tag value that we loaded earlier is still present.
  110. Arguments:
  111. FpThreadData - Used to retrieve expected tag, updated with current Npx tag.
  112. Return Value:
  113. stOK if the tag is good, stBadTag if there's a mismatch.
  114. --*/
  115. {
  116. FPXERR rc = stOK;
  117. double localTagCopy, localBadTagCopy;
  118. //
  119. // We don't do an assignment here as we don't want to touch the FPU
  120. //
  121. memcpy(&localTagCopy, &FpThreadData->Ftag, sizeof(double));
  122. _asm {
  123. fnclex
  124. ffree st(0) ; move the tag to the top of stack
  125. ffree st(1)
  126. fincstp
  127. fincstp
  128. fcomp [localTagCopy] ; is it our tag?
  129. fnstsw ax
  130. sahf
  131. je Ex
  132. mov [rc], stBAD_TAG ; not our tag!
  133. fst [localBadTagCopy]
  134. fwait
  135. Ex:
  136. }
  137. //
  138. // We don't do an assignment here as we don't want to touch the FPU
  139. //
  140. memcpy(&FpThreadData->FtagBad, &localBadTagCopy, sizeof(double));
  141. return rc;
  142. }
  143. EXCEPTION_DISPOSITION
  144. FPxUnexpectedExceptionFilter(
  145. IN LPEXCEPTION_POINTERS ExcInfo,
  146. IN OUT PFP_THREAD_DATA FpThreadData
  147. )
  148. /*++
  149. Routine Description:
  150. This handler is called when an Npx exception we *don't* expect occurs.
  151. Arguments:
  152. ExcInfo - Exception record info.
  153. FpThreadData - Used to retrieve expected tag, updated with current Npx tag.
  154. Return Value:
  155. How to handle the exception.
  156. --*/
  157. {
  158. FpThreadData->ExceptionEIP = ExcInfo->ContextRecord->Eip;
  159. return EXCEPTION_EXECUTE_HANDLER;
  160. }
  161. EXCEPTION_DISPOSITION
  162. FPxExpectedExceptionFilter(
  163. IN LPEXCEPTION_POINTERS ExcInfo,
  164. IN OUT PFP_THREAD_DATA FpThreadData
  165. )
  166. /*++
  167. Routine Description:
  168. This handler is called when an Npx exception we *do* expect occurs.
  169. Arguments:
  170. ExcInfo - Exception record info.
  171. FpThreadData - Used to retrieve expected tag, updated with current Npx tag.
  172. Return Value:
  173. How to handle the exception.
  174. --*/
  175. {
  176. if (ExcInfo->ContextRecord->Eip != FpThreadData->ExpectedExceptionEIP) {
  177. FpThreadData->BadEip = ExcInfo->ContextRecord->Eip;
  178. FpThreadData->status = stBAD_EIP;
  179. } else {
  180. FpThreadData->status = stOK;
  181. }
  182. return EXCEPTION_EXECUTE_HANDLER;
  183. }
  184. FPXERR
  185. FPxTestExceptions(
  186. IN UINT Tag,
  187. IN PFN_FPX_CALLBACK_FUNC CallbackFunction,
  188. IN OUT PFP_THREAD_DATA FpThreadData,
  189. IN OUT PVOID Context
  190. )
  191. /*++
  192. Routine Description:
  193. This handler tests NPX exceptions.
  194. Arguments:
  195. Tag - Tag to test the FPU with.
  196. CallbackFunction - Called back between exception load and exception drains.
  197. Must *not* access FPU in user mode as this will trash
  198. loaded FPU state.
  199. FpThreadData - Cache of FPU information. Should be preinitialized with
  200. FPxInit before the first call to this function. Does not
  201. need to be preinited before subsequent invocations.
  202. Context - Context for callback func.
  203. Return Value:
  204. FPXERR result.
  205. --*/
  206. {
  207. __try {
  208. //
  209. // Tag the Npx
  210. //
  211. FPxLoadTag(FpThreadData, Tag);
  212. __try {
  213. //
  214. // generate pending exception
  215. //
  216. FPxPendDivideByZero();
  217. } __except(FPxUnexpectedExceptionFilter(GetExceptionInformation(),
  218. FpThreadData)) {
  219. FpThreadData->status = stSPURIOUS_EXCEPTION;
  220. }
  221. if (FpThreadData->status == stOK) {
  222. //
  223. // Invoke the callback function.
  224. //
  225. CallbackFunction(Context);
  226. //
  227. // Drain the exception that should still be pending.
  228. //
  229. FPxDrain(FpThreadData);
  230. //
  231. // We shouldn't get here.
  232. //
  233. FpThreadData->status = stMISSING_EXCEPTION;
  234. }
  235. } __except(FPxExpectedExceptionFilter(GetExceptionInformation(),
  236. FpThreadData)) {
  237. if (FpThreadData->status == stOK) {
  238. __try {
  239. //
  240. // ST(2) should still have our tag value
  241. //
  242. FpThreadData->status = FPxCheckTag(FpThreadData);
  243. } __except(FPxUnexpectedExceptionFilter(GetExceptionInformation(),
  244. FpThreadData)) {
  245. FpThreadData->status = stEXCEPTION_IN_HANDLER;
  246. }
  247. }
  248. }
  249. if (FpThreadData->status == stMISSING_EXCEPTION) {
  250. __try {
  251. FPxDrain(FpThreadData);
  252. FPxDrain(FpThreadData);
  253. } __except(EXCEPTION_EXECUTE_HANDLER) {
  254. FpThreadData->status = stMISSING_EXCEPTION_FOUND;
  255. }
  256. }
  257. return FpThreadData->status;
  258. }