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.
|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
fpexception.c
Abstract:
This module contains code to test i386 floating point exceptions.
Author:
Environment:
User mode only.
Revision History:
--*/
#include "pch.h"
VOID FPxInit( OUT PFP_THREAD_DATA FpThreadData ) /*++
Routine Description:
Initializes FPU state to known values.
Arguments:
FpThreadData - FP thread data.
Return Value:
None.
--*/ { USHORT cw = 0x27B;
//
// Fill in the initial thread values.
//
FpThreadData->FtagBad = 99.999; FpThreadData->ExpectedExceptionEIP = 0xbad; FpThreadData->ExceptionEIP = 0xbad; FpThreadData->BadEip = 1; FpThreadData->status = stOK;
// unmask zero divide exception
_asm { fninit fldcw [cw] } }
VOID FPxLoadTag( IN OUT PFP_THREAD_DATA FpThreadData, IN UINT Tag ) /*++
Routine Description:
Loads a semi-unique tag value into the Npx for later validation.
Arguments:
FpThreadData - FP thread data.
Tag - Tag to load.
Return Value:
None.
--*/ { double localCopy;
FpThreadData->Ftag = localCopy = Tag * 1.41415926e3;
_asm fld [localCopy] }
VOID FPxPendDivideByZero( VOID ) /*++
Routine Description:
Loads a divide-by-zero pending exception into the Npx.
Arguments:
None.
Return Value:
None.
--*/ { _asm {
fld1 fldz fdiv } }
VOID FPxDrain( IN OUT PFP_THREAD_DATA FpThreadData ) /*++
Routine Description:
Drains any pending exceptions in the Npx.
Arguments:
FpThreadData - Updated with what should be the address of the pending exception.
Return Value:
None.
--*/ { UINT localExceptionEIP;
_asm { mov localExceptionEIP, offset ExcAddr }
FpThreadData->ExpectedExceptionEIP = localExceptionEIP;
_asm {
ExcAddr: fldpi } }
FPXERR FPxCheckTag( IN OUT PFP_THREAD_DATA FpThreadData ) /*++
Routine Description:
Makes sure the tag value that we loaded earlier is still present.
Arguments:
FpThreadData - Used to retrieve expected tag, updated with current Npx tag.
Return Value:
stOK if the tag is good, stBadTag if there's a mismatch.
--*/ { FPXERR rc = stOK; double localTagCopy, localBadTagCopy;
//
// We don't do an assignment here as we don't want to touch the FPU
//
memcpy(&localTagCopy, &FpThreadData->Ftag, sizeof(double));
_asm {
fnclex ffree st(0) ; move the tag to the top of stack ffree st(1) fincstp fincstp fcomp [localTagCopy] ; is it our tag? fnstsw ax sahf je Ex
mov [rc], stBAD_TAG ; not our tag! fst [localBadTagCopy] fwait Ex: }
//
// We don't do an assignment here as we don't want to touch the FPU
//
memcpy(&FpThreadData->FtagBad, &localBadTagCopy, sizeof(double));
return rc; }
EXCEPTION_DISPOSITION FPxUnexpectedExceptionFilter( IN LPEXCEPTION_POINTERS ExcInfo, IN OUT PFP_THREAD_DATA FpThreadData ) /*++
Routine Description:
This handler is called when an Npx exception we *don't* expect occurs.
Arguments:
ExcInfo - Exception record info.
FpThreadData - Used to retrieve expected tag, updated with current Npx tag.
Return Value:
How to handle the exception.
--*/ { FpThreadData->ExceptionEIP = ExcInfo->ContextRecord->Eip; return EXCEPTION_EXECUTE_HANDLER; }
EXCEPTION_DISPOSITION FPxExpectedExceptionFilter( IN LPEXCEPTION_POINTERS ExcInfo, IN OUT PFP_THREAD_DATA FpThreadData ) /*++
Routine Description:
This handler is called when an Npx exception we *do* expect occurs.
Arguments:
ExcInfo - Exception record info.
FpThreadData - Used to retrieve expected tag, updated with current Npx tag.
Return Value:
How to handle the exception.
--*/ { if (ExcInfo->ContextRecord->Eip != FpThreadData->ExpectedExceptionEIP) {
FpThreadData->BadEip = ExcInfo->ContextRecord->Eip; FpThreadData->status = stBAD_EIP;
} else {
FpThreadData->status = stOK;
}
return EXCEPTION_EXECUTE_HANDLER; }
FPXERR FPxTestExceptions( IN UINT Tag, IN PFN_FPX_CALLBACK_FUNC CallbackFunction, IN OUT PFP_THREAD_DATA FpThreadData, IN OUT PVOID Context ) /*++
Routine Description:
This handler tests NPX exceptions.
Arguments:
Tag - Tag to test the FPU with.
CallbackFunction - Called back between exception load and exception drains. Must *not* access FPU in user mode as this will trash loaded FPU state.
FpThreadData - Cache of FPU information. Should be preinitialized with FPxInit before the first call to this function. Does not need to be preinited before subsequent invocations.
Context - Context for callback func.
Return Value:
FPXERR result.
--*/ { __try {
//
// Tag the Npx
//
FPxLoadTag(FpThreadData, Tag);
__try {
//
// generate pending exception
//
FPxPendDivideByZero();
} __except(FPxUnexpectedExceptionFilter(GetExceptionInformation(), FpThreadData)) {
FpThreadData->status = stSPURIOUS_EXCEPTION; }
if (FpThreadData->status == stOK) {
//
// Invoke the callback function.
//
CallbackFunction(Context);
//
// Drain the exception that should still be pending.
//
FPxDrain(FpThreadData);
//
// We shouldn't get here.
//
FpThreadData->status = stMISSING_EXCEPTION; }
} __except(FPxExpectedExceptionFilter(GetExceptionInformation(), FpThreadData)) {
if (FpThreadData->status == stOK) {
__try {
//
// ST(2) should still have our tag value
//
FpThreadData->status = FPxCheckTag(FpThreadData);
} __except(FPxUnexpectedExceptionFilter(GetExceptionInformation(), FpThreadData)) {
FpThreadData->status = stEXCEPTION_IN_HANDLER; } } }
if (FpThreadData->status == stMISSING_EXCEPTION) {
__try {
FPxDrain(FpThreadData); FPxDrain(FpThreadData);
} __except(EXCEPTION_EXECUTE_HANDLER) {
FpThreadData->status = stMISSING_EXCEPTION_FOUND; } }
return FpThreadData->status; }
|