1 /* $Id: fpu.c,v 1.18 2004/11/27 16:12:26 hbirr Exp $
4 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/i386/fpu.c
23 * PURPOSE: Handles the FPU
24 * PROGRAMMER: David Welch (welch@mcmail.com)
29 /* INCLUDES *****************************************************************/
34 #include <internal/debug.h>
36 /* DEFINES *******************************************************************/
38 #define EXCEPTION_FLT_DENORMAL_OPERAND (0xc000008dL)
39 #define EXCEPTION_FLT_DIVIDE_BY_ZERO (0xc000008eL)
40 #define EXCEPTION_FLT_INEXACT_RESULT (0xc000008fL)
41 #define EXCEPTION_FLT_INVALID_OPERATION (0xc0000090L)
42 #define EXCEPTION_FLT_OVERFLOW (0xc0000091L)
43 #define EXCEPTION_FLT_STACK_CHECK (0xc0000092L)
44 #define EXCEPTION_FLT_UNDERFLOW (0xc0000093L)
45 #define EXCEPTION_FLT_MULTIPLE_FAULTS (0xC00002B4L)
46 #define EXCEPTION_FLT_MULTIPLE_TRAPS (0xC00002B5L)
48 /* x87 Status Word exception flags */
49 #define X87_SW_IE (1<<0) /* Invalid Operation */
50 #define X87_SW_DE (1<<1) /* Denormalized Operand */
51 #define X87_SW_ZE (1<<2) /* Zero Devide */
52 #define X87_SW_OE (1<<3) /* Overflow */
53 #define X87_SW_UE (1<<4) /* Underflow */
54 #define X87_SW_PE (1<<5) /* Precision */
55 #define X87_SW_SE (1<<6) /* Stack Fault */
57 #define X87_SW_ES (1<<7) /* Error Summary */
59 /* MXCSR exception flags */
60 #define MXCSR_IE (1<<0) /* Invalid Operation */
61 #define MXCSR_DE (1<<1) /* Denormalized Operand */
62 #define MXCSR_ZE (1<<2) /* Zero Devide */
63 #define MXCSR_OE (1<<3) /* Overflow */
64 #define MXCSR_UE (1<<4) /* Underflow */
65 #define MXCSR_PE (1<<5) /* Precision */
66 #define MXCSR_DAZ (1<<6) /* Denormals Are Zeros (P4 only) */
68 /* GLOBALS *******************************************************************/
70 ULONG HardwareMathSupport
= 0;
71 static ULONG MxcsrFeatureMask
= 0, XmmSupport
= 0;
72 ULONG FxsrSupport
= 0; /* used by Ki386ContextSwitch for MP */
74 /* FUNCTIONS *****************************************************************/
77 KiTagWordFnsaveToFxsave(USHORT TagWord
)
82 * Converts the tag-word. 11 (Empty) is converted into 0, everything else into 1
84 tmp
= ~TagWord
; /* Empty is now 00, any 2 bits containing 1 mean valid */
85 tmp
= (tmp
| (tmp
>> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
86 tmp
= (tmp
| (tmp
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
87 tmp
= (tmp
| (tmp
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
88 tmp
= (tmp
| (tmp
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
94 KiTagWordFxsaveToFnsave(PFXSAVE_FORMAT FxSave
)
99 struct FPREG
{ USHORT Significand
[4]; USHORT Exponent
; } *FpReg
;
101 for (i
= 0; i
< 8; i
++)
103 if (FxSave
->TagWord
& (1 << i
)) /* valid */
105 FpReg
= (struct FPREG
*)(FxSave
->RegisterArea
+ (i
* 16));
106 switch (FpReg
->Exponent
& 0x00007fff)
109 if (FpReg
->Significand
[0] == 0 && FpReg
->Significand
[1] == 0 &&
110 FpReg
->Significand
[2] == 0 && FpReg
->Significand
[3] == 0)
116 Tag
= 2; /* Special */
121 Tag
= 2; /* Special */
125 if (FpReg
->Significand
[3] & 0x00008000)
131 Tag
= 2; /* Special */
140 TagWord
|= Tag
<< (i
* 2);
147 KiFnsaveToFxsaveFormat(PFXSAVE_FORMAT FxSave
, CONST PFNSAVE_FORMAT FnSave
)
151 FxSave
->ControlWord
= (USHORT
)FnSave
->ControlWord
;
152 FxSave
->StatusWord
= (USHORT
)FnSave
->StatusWord
;
153 FxSave
->TagWord
= KiTagWordFnsaveToFxsave((USHORT
)FnSave
->TagWord
);
154 FxSave
->ErrorOpcode
= (USHORT
)(FnSave
->ErrorSelector
>> 16);
155 FxSave
->ErrorOffset
= FnSave
->ErrorOffset
;
156 FxSave
->ErrorSelector
= FnSave
->ErrorSelector
& 0x0000ffff;
157 FxSave
->DataOffset
= FnSave
->DataOffset
;
158 FxSave
->DataSelector
= FnSave
->DataSelector
& 0x0000ffff;
160 FxSave
->MXCsr
= 0x00001f80 & MxcsrFeatureMask
;
163 FxSave
->MXCsrMask
= MxcsrFeatureMask
;
164 memset(FxSave
->Reserved3
, 0, sizeof(FxSave
->Reserved3
) +
165 sizeof(FxSave
->Reserved4
)); /* XXX - doesnt zero Align16Byte because
166 Context->ExtendedRegisters is only 512 bytes, not 520 */
167 for (i
= 0; i
< 8; i
++)
169 memcpy(FxSave
->RegisterArea
+ (i
* 16), FnSave
->RegisterArea
+ (i
* 10), 10);
170 memset(FxSave
->RegisterArea
+ (i
* 16) + 10, 0, 6);
175 KiFxsaveToFnsaveFormat(PFNSAVE_FORMAT FnSave
, CONST PFXSAVE_FORMAT FxSave
)
179 FnSave
->ControlWord
= 0xffff0000 | FxSave
->ControlWord
;
180 FnSave
->StatusWord
= 0xffff0000 | FxSave
->StatusWord
;
181 FnSave
->TagWord
= 0xffff0000 | KiTagWordFxsaveToFnsave(FxSave
);
182 FnSave
->ErrorOffset
= FxSave
->ErrorOffset
;
183 FnSave
->ErrorSelector
= FxSave
->ErrorSelector
& 0x0000ffff;
184 FnSave
->ErrorSelector
|= FxSave
->ErrorOpcode
<< 16;
185 FnSave
->DataOffset
= FxSave
->DataOffset
;
186 FnSave
->DataSelector
= FxSave
->DataSelector
| 0xffff0000;
187 for (i
= 0; i
< 8; i
++)
189 memcpy(FnSave
->RegisterArea
+ (i
* 10), FxSave
->RegisterArea
+ (i
* 16), 10);
194 KiFloatingSaveAreaToFxSaveArea(PFX_SAVE_AREA FxSaveArea
, CONST FLOATING_SAVE_AREA
*FloatingSaveArea
)
198 KiFnsaveToFxsaveFormat(&FxSaveArea
->U
.FxArea
, (PFNSAVE_FORMAT
)FloatingSaveArea
);
202 memcpy(&FxSaveArea
->U
.FnArea
, FloatingSaveArea
, sizeof(FxSaveArea
->U
.FnArea
));
204 FxSaveArea
->NpxSavedCpu
= 0;
205 FxSaveArea
->Cr0NpxState
= FloatingSaveArea
->Cr0NpxState
;
209 KiContextToFxSaveArea(PFX_SAVE_AREA FxSaveArea
, PCONTEXT Context
)
211 BOOL FpuContextChanged
= FALSE
;
213 /* First of all convert the FLOATING_SAVE_AREA into the FX_SAVE_AREA */
214 if ((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) == CONTEXT_FLOATING_POINT
)
216 KiFloatingSaveAreaToFxSaveArea(FxSaveArea
, &Context
->FloatSave
);
217 FpuContextChanged
= TRUE
;
220 /* Now merge the FX_SAVE_AREA from the context with the destination area */
221 if ((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) == CONTEXT_EXTENDED_REGISTERS
)
225 PFXSAVE_FORMAT src
= (PFXSAVE_FORMAT
)Context
->ExtendedRegisters
;
226 PFXSAVE_FORMAT dst
= &FxSaveArea
->U
.FxArea
;
227 dst
->MXCsr
= src
->MXCsr
& MxcsrFeatureMask
;
228 memcpy(dst
->Reserved3
, src
->Reserved3
,
229 sizeof(src
->Reserved3
) + sizeof(src
->Reserved4
));
231 if ((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) != CONTEXT_FLOATING_POINT
)
233 dst
->ControlWord
= src
->ControlWord
;
234 dst
->StatusWord
= src
->StatusWord
;
235 dst
->TagWord
= src
->TagWord
;
236 dst
->ErrorOpcode
= src
->ErrorOpcode
;
237 dst
->ErrorOffset
= src
->ErrorOffset
;
238 dst
->ErrorSelector
= src
->ErrorSelector
;
239 dst
->DataOffset
= src
->DataOffset
;
240 dst
->DataSelector
= src
->DataSelector
;
241 memcpy(dst
->RegisterArea
, src
->RegisterArea
, sizeof(src
->RegisterArea
));
243 FxSaveArea
->NpxSavedCpu
= 0;
244 FxSaveArea
->Cr0NpxState
= 0;
246 FpuContextChanged
= TRUE
;
250 return FpuContextChanged
;
256 unsigned short int status
;
259 PKPCR Pcr
= KeGetCurrentKPCR();
261 Ke386SaveFlags(Flags
);
262 Ke386DisableInterrupts();
264 HardwareMathSupport
= 0;
269 cr0
|= X86_CR0_NE
| X86_CR0_MP
;
270 cr0
&= ~(X86_CR0_EM
| X86_CR0_TS
);
273 #if defined(__GNUC__)
274 asm volatile("fninit\n\t");
275 asm volatile("fstsw %0\n\t" : "=a" (status
));
276 #elif defined(_MSC_VER)
283 #error Unknown compiler for inline assembler
288 /* Set the EM flag in CR0 so any FPU instructions cause a trap. */
289 Ke386SetCr0(Ke386GetCr0() | X86_CR0_EM
);
290 Ke386RestoreFlags(Flags
);
294 /* fsetpm for i287, ignored by i387 */
295 #if defined(__GNUC__)
296 asm volatile(".byte 0xDB, 0xE4\n\t");
297 #elif defined(_MSC_VER)
298 __asm _emit
0xDB __asm _emit
0xe4
300 #error Unknown compiler for inline assembler
303 HardwareMathSupport
= 1;
305 /* check for and enable MMX/SSE support if possible */
306 if ((Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_FXSR
) != 0)
308 BYTE DummyArea
[sizeof(FX_SAVE_AREA
) + 15];
309 PFX_SAVE_AREA FxSaveArea
;
314 /* we need a 16 byte aligned FX_SAVE_AREA */
315 FxSaveArea
= (PFX_SAVE_AREA
)DummyArea
;
316 if ((ULONG_PTR
)FxSaveArea
& 0x0f)
318 FxSaveArea
= (PFX_SAVE_AREA
)(((ULONG_PTR
)FxSaveArea
+ 0x10) & (~0x0f));
321 Ke386SetCr4(Ke386GetCr4() | X86_CR4_OSFXSR
);
322 memset(&FxSaveArea
->U
.FxArea
, 0, sizeof(FxSaveArea
->U
.FxArea
));
323 asm volatile("fxsave %0" : : "m"(FxSaveArea
->U
.FxArea
));
324 MxcsrFeatureMask
= FxSaveArea
->U
.FxArea
.MXCsrMask
;
325 if (MxcsrFeatureMask
== 0)
327 MxcsrFeatureMask
= 0x0000ffbf;
330 /* FIXME: Check for SSE3 in Ke386CpuidFlags2! */
331 if (Pcr
->PrcbData
.FeatureBits
& (X86_FEATURE_SSE
| X86_FEATURE_SSE2
))
333 Ke386SetCr4(Ke386GetCr4() | X86_CR4_OSXMMEXCPT
);
339 Ke386SetCr0(Ke386GetCr0() | X86_CR0_TS
);
340 Ke386RestoreFlags(Flags
);
343 /* This is a rather naive implementation of Ke(Save/Restore)FloatingPointState
344 which will not work for WDM drivers. Please feel free to improve */
346 #define FPU_STATE_SIZE 108
349 KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save
)
353 ASSERT_IRQL(DISPATCH_LEVEL
); /* FIXME: is this removed for non-debug builds? I hope not! */
355 /* check if we are doing software emulation */
356 if (!HardwareMathSupport
)
358 return STATUS_ILLEGAL_FLOAT_CONTEXT
;
361 FpState
= ExAllocatePool(PagedPool
, FPU_STATE_SIZE
);
364 return STATUS_INSUFFICIENT_RESOURCES
;
366 *((PVOID
*) Save
) = FpState
;
368 #if defined(__GNUC__)
369 asm volatile("fsave %0\n\t" : "=m" (*FpState
));
370 #elif defined(_MSC_VER)
371 __asm mov eax
, FpState
;
374 #error Unknown compiler for inline assembler
377 KeGetCurrentThread()->NpxIrql
= KeGetCurrentIrql();
379 return STATUS_SUCCESS
;
383 KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save
)
385 char *FpState
= *((PVOID
*) Save
);
387 if (KeGetCurrentThread()->NpxIrql
!= KeGetCurrentIrql())
389 KEBUGCHECK(UNDEFINED_BUG_CODE
);
392 #if defined(__GNUC__)
393 __asm__("frstor %0\n\t" : "=m" (*FpState
));
394 #elif defined(_MSC_VER)
395 __asm mov eax
, FpState
;
398 #error Unknown compiler for inline assembler
403 return STATUS_SUCCESS
;
407 KiClearFloatingPointState(BOOLEAN Save
)
409 PKTHREAD CurrentThread
;
410 PFX_SAVE_AREA FxSaveArea
;
412 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
414 CurrentThread
= KeGetCurrentThread();
416 if (CurrentThread
->NpxState
& NPX_STATE_DIRTY
)
420 FxSaveArea
= (PFX_SAVE_AREA
)((char *)CurrentThread
->InitialStack
- sizeof (FX_SAVE_AREA
));
423 asm volatile("fxsave %0" : : "m"(FxSaveArea
->U
.FxArea
));
427 asm volatile("fnsave %0" : : "m"(FxSaveArea
->U
.FnArea
));
429 CurrentThread
->NpxState
= NPX_STATE_VALID
;
433 CurrentThread
->NpxState
= NPX_STATE_INVALID
;
435 Ke386SetCr0(Ke386GetCr0() | X86_CR0_TS
);
437 if (KeGetCurrentKPCR()->PrcbData
.NpxThread
== CurrentThread
)
439 KeGetCurrentKPCR()->PrcbData
.NpxThread
= NULL
;
445 KiHandleFpuFault(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
447 if (ExceptionNr
== 7) /* device not present */
449 BOOL FpuInitialized
= FALSE
;
450 unsigned int cr0
= Ke386GetCr0();
451 PKTHREAD CurrentThread
;
452 PFX_SAVE_AREA FxSaveArea
;
459 ASSERT((cr0
& X86_CR0_TS
) == X86_CR0_TS
);
460 ASSERT((Tf
->Eflags
& X86_EFLAGS_VM
) == 0);
461 ASSERT((cr0
& X86_CR0_EM
) == 0);
463 /* disable scheduler, clear TS in cr0 */
464 ASSERT_IRQL(DISPATCH_LEVEL
);
465 KeRaiseIrql(DISPATCH_LEVEL
, &oldIrql
);
466 asm volatile("clts");
468 CurrentThread
= KeGetCurrentThread();
470 NpxThread
= KeGetCurrentKPCR()->PrcbData
.NpxThread
;
473 ASSERT(CurrentThread
!= NULL
);
474 DPRINT("Device not present exception happened! (Cr0 = 0x%x, NpxState = 0x%x)\n", cr0
, CurrentThread
->NpxState
);
477 /* check if the current thread already owns the FPU */
478 if (NpxThread
!= CurrentThread
) /* FIXME: maybe this could be an assertation */
480 /* save the FPU state into the owner's save area */
481 if (NpxThread
!= NULL
)
483 KeGetCurrentKPCR()->PrcbData
.NpxThread
= NULL
;
484 FxSaveArea
= (PFX_SAVE_AREA
)((char *)NpxThread
->InitialStack
- sizeof (FX_SAVE_AREA
));
485 /* the fnsave might raise a delayed #MF exception */
488 asm volatile("fxsave %0" : : "m"(FxSaveArea
->U
.FxArea
));
492 asm volatile("fnsave %0" : : "m"(FxSaveArea
->U
.FnArea
));
493 FpuInitialized
= TRUE
;
495 NpxThread
->NpxState
= NPX_STATE_VALID
;
499 /* restore the state of the current thread */
500 ASSERT((CurrentThread
->NpxState
& NPX_STATE_DIRTY
) == 0);
501 FxSaveArea
= (PFX_SAVE_AREA
)((char *)CurrentThread
->InitialStack
- sizeof (FX_SAVE_AREA
));
502 if (CurrentThread
->NpxState
& NPX_STATE_VALID
)
506 FxSaveArea
->U
.FxArea
.MXCsr
&= MxcsrFeatureMask
;
507 asm volatile("fxrstor %0" : : "m"(FxSaveArea
->U
.FxArea
));
511 asm volatile("frstor %0" : : "m"(FxSaveArea
->U
.FnArea
));
514 else /* NpxState & NPX_STATE_INVALID */
516 DPRINT("Setting up clean FPU state\n");
519 memset(&FxSaveArea
->U
.FxArea
, 0, sizeof(FxSaveArea
->U
.FxArea
));
520 FxSaveArea
->U
.FxArea
.ControlWord
= 0x037f;
523 FxSaveArea
->U
.FxArea
.MXCsr
= 0x00001f80 & MxcsrFeatureMask
;
525 asm volatile("fxrstor %0" : : "m"(FxSaveArea
->U
.FxArea
));
527 else if (!FpuInitialized
)
529 asm volatile("finit");
532 KeGetCurrentKPCR()->PrcbData
.NpxThread
= CurrentThread
;
537 CurrentThread
->NpxState
|= NPX_STATE_DIRTY
;
538 KeLowerIrql(oldIrql
);
539 DPRINT("Device not present exception handled!\n");
541 return STATUS_SUCCESS
;
543 else /* ExceptionNr == 16 || ExceptionNr == 19 */
546 UCHAR DummyContext
[sizeof(CONTEXT
) + 16];
548 KPROCESSOR_MODE PreviousMode
;
549 PKTHREAD CurrentThread
, NpxThread
;
552 ASSERT(ExceptionNr
== 16 || ExceptionNr
== 19); /* math fault or XMM fault*/
554 KeRaiseIrql(DISPATCH_LEVEL
, &oldIrql
);
556 NpxThread
= KeGetCurrentKPCR()->PrcbData
.NpxThread
;
557 CurrentThread
= KeGetCurrentThread();
558 if (NpxThread
== NULL
)
560 KeLowerIrql(oldIrql
);
561 DPRINT1("!!! Math/Xmm fault ignored! (NpxThread == NULL)\n");
562 return STATUS_SUCCESS
;
565 PreviousMode
= ((Tf
->Cs
& 0xffff) == USER_CS
) ? (UserMode
) : (KernelMode
);
566 DPRINT("Math/Xmm fault happened! (PreviousMode = %s)\n",
567 (PreviousMode
== UserMode
) ? ("UserMode") : ("KernelMode"));
569 ASSERT(NpxThread
== CurrentThread
); /* FIXME: Is not always true I think */
571 /* For fxsave we have to align Context->ExtendedRegisters on 16 bytes */
572 Context
= (PCONTEXT
)DummyContext
;
573 Context
= (PCONTEXT
)((ULONG_PTR
)Context
+ 0x10 - ((ULONG_PTR
)Context
->ExtendedRegisters
& 0x0f));
575 /* Get FPU/XMM state */
576 Context
->FloatSave
.Cr0NpxState
= 0;
579 PFXSAVE_FORMAT FxSave
= (PFXSAVE_FORMAT
)Context
->ExtendedRegisters
;
580 FxSave
->MXCsrMask
= MxcsrFeatureMask
;
581 memset(FxSave
->RegisterArea
, 0, sizeof(FxSave
->RegisterArea
) +
582 sizeof(FxSave
->Reserved3
) + sizeof(FxSave
->Reserved4
));
583 asm volatile("fxsave %0" : : "m"(*FxSave
));
584 KeLowerIrql(oldIrql
);
585 KiFxsaveToFnsaveFormat((PFNSAVE_FORMAT
)&Context
->FloatSave
, FxSave
);
589 PFNSAVE_FORMAT FnSave
= (PFNSAVE_FORMAT
)&Context
->FloatSave
;
590 asm volatile("fnsave %0" : : "m"(*FnSave
));
591 KeLowerIrql(oldIrql
);
592 KiFnsaveToFxsaveFormat((PFXSAVE_FORMAT
)Context
->ExtendedRegisters
, FnSave
);
595 /* Fill the rest of the context */
596 Context
->ContextFlags
= CONTEXT_FULL
;
597 KeTrapFrameToContext(Tf
, Context
);
598 Context
->ContextFlags
|= CONTEXT_FLOATING_POINT
| CONTEXT_EXTENDED_REGISTERS
;
600 /* Determine exception code */
601 if (ExceptionNr
== 16)
603 USHORT FpuStatusWord
= Context
->FloatSave
.StatusWord
& 0xffff;
604 DPRINT("FpuStatusWord = 0x%04x\n", FpuStatusWord
);
606 if (FpuStatusWord
& X87_SW_IE
)
607 Er
.ExceptionCode
= EXCEPTION_FLT_INVALID_OPERATION
;
608 else if (FpuStatusWord
& X87_SW_DE
)
609 Er
.ExceptionCode
= EXCEPTION_FLT_DENORMAL_OPERAND
;
610 else if (FpuStatusWord
& X87_SW_ZE
)
611 Er
.ExceptionCode
= EXCEPTION_FLT_DIVIDE_BY_ZERO
;
612 else if (FpuStatusWord
& X87_SW_OE
)
613 Er
.ExceptionCode
= EXCEPTION_FLT_OVERFLOW
;
614 else if (FpuStatusWord
& X87_SW_UE
)
615 Er
.ExceptionCode
= EXCEPTION_FLT_UNDERFLOW
;
616 else if (FpuStatusWord
& X87_SW_PE
)
617 Er
.ExceptionCode
= EXCEPTION_FLT_INEXACT_RESULT
;
618 else if (FpuStatusWord
& X87_SW_SE
)
619 Er
.ExceptionCode
= EXCEPTION_FLT_STACK_CHECK
;
621 ASSERT(0); /* not reached */
622 /* FIXME: is this the right way to get the correct EIP of the faulting instruction? */
623 Er
.ExceptionAddress
= (PVOID
)Context
->FloatSave
.ErrorOffset
;
625 else /* ExceptionNr == 19 */
627 /* FIXME: When should we use EXCEPTION_FLT_MULTIPLE_FAULTS? */
628 Er
.ExceptionCode
= EXCEPTION_FLT_MULTIPLE_TRAPS
;
629 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
632 Er
.ExceptionFlags
= 0;
633 Er
.ExceptionRecord
= NULL
;
634 Er
.NumberParameters
= 0;
636 /* Dispatch exception */
637 DPRINT("Dispatching exception (ExceptionCode = 0x%08x)\n", Er
.ExceptionCode
);
638 KiDispatchException(&Er
, Context
, Tf
, PreviousMode
, TRUE
);
640 DPRINT("Math-fault handled!\n");
641 return STATUS_SUCCESS
;
644 return STATUS_UNSUCCESSFUL
;