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

/*++
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;
}