- Implement FPU Exception Handler.

- We can now properly handle FPU faults (wrote a small test for invalid fpu precision).
- OpenGL probably still doesn't work, as there might be some bugs around the place. However, you should not see FPU Bugchecks anymore.

svn path=/trunk/; revision=24187
This commit is contained in:
Alex Ionescu 2006-09-18 02:33:21 +00:00
parent 03c36d1a35
commit 8b094bf093
2 changed files with 168 additions and 33 deletions

View file

@ -200,14 +200,29 @@ Author:
// //
// FPU Save Area Offsets // FPU Save Area Offsets
// //
#define FN_CONTROL_WORD 0x0 #define FP_CONTROL_WORD 0x0
#define FN_STATUS_WORD 0x4 #define FP_STATUS_WORD 0x4
#define FN_TAG_WORD 0x8 #define FP_TAG_WORD 0x8
#define FN_DATA_SELECTOR 0x18 #define FP_ERROR_OFFSET 0xC
#define FP_ERROR_SELECTOR 0x10
#define FP_DATA_OFFSET 0x14
#define FP_DATA_SELECTOR 0x18
#define FN_CR0_NPX_STATE 0x20C #define FN_CR0_NPX_STATE 0x20C
#define SIZEOF_FX_SAVE_AREA 528 #define SIZEOF_FX_SAVE_AREA 528
#define NPX_FRAME_LENGTH 0x210 #define NPX_FRAME_LENGTH 0x210
//
// FX Save Area Offsets
//
#define FX_CONTROL_WORD 0x0
#define FX_STATUS_WORD 0x2
#define FX_TAG_WORD 0x4
#define FX_ERROR_OPCODE 0x6
#define FX_ERROR_OFFSET 0x8
#define FX_ERROR_SELECTOR 0xC
#define FX_DATA_OFFSET 0x10
#define FX_DATA_SELECTOR 0x14
// //
// NPX States // NPX States
// //
@ -464,6 +479,15 @@ Author:
#define STATUS_SINGLE_STEP 0x80000004 #define STATUS_SINGLE_STEP 0x80000004
#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094 #define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094
#define STATUS_INTEGER_OVERFLOW 0xC0000095 #define STATUS_INTEGER_OVERFLOW 0xC0000095
#define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008D
#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008E
#define STATUS_FLOAT_INEXACT_RESULT 0xC000008F
#define STATUS_FLOAT_INVALID_OPERATION 0xC0000090
#define STATUS_FLOAT_OVERFLOW 0xC0000091
#define STATUS_FLOAT_STACK_CHECK 0xC0000092
#define STATUS_FLOAT_UNDERFLOW 0xC0000093
#define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4
#define STATUS_FLOAT_MULTIPLE_TRAPS 0xC00002B5
#define APC_INDEX_MISMATCH 0x01 #define APC_INDEX_MISMATCH 0x01
#define TRAP_CAUSE_UNKNOWN 0x12 #define TRAP_CAUSE_UNKNOWN 0x12
#define KMODE_EXCEPTION_NOT_HANDLED 0x13 #define KMODE_EXCEPTION_NOT_HANDLED 0x13

View file

@ -1220,32 +1220,135 @@ HandleUserNpx:
and ebx, ~(CR0_MP + CR0_EM + CR0_TS) and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
mov cr0, ebx mov cr0, ebx
/* FIXME: Implement the rest */ /* Check if we have FX support */
int 3 test byte ptr _KeI386FxsrPresent, 1
jmp $ jz FnSave2
/* Save the state */
fxsave [ecx]
jmp MakeCr0Dirty
FnSave2:
fnsave [ecx]
wait
MakeCr0Dirty:
/* Make CR0 state not loaded */
or ebx, NPX_STATE_NOT_LOADED
or ebx, [ecx+FN_CR0_NPX_STATE]
mov cr0, ebx
/* Update NPX state */
mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
mov dword ptr fs:[KPCR_NPX_THREAD], 0
NoSaveRestore: NoSaveRestore:
/* FIXME: Implement the rest */ /* Clear the TS bit and re-enable interrupts */
int 3 and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
jmp $ sti
EmulationEnabled: /* Check if we have FX support */
/* Did this come from kernel-mode? */ test byte ptr _KeI386FxsrPresent, 1
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE jz FnError
jz CheckState
/* It came from user-mode, so this would only be valid inside a VDM */ /* Get error offset, control and status words */
/* Since we don't actually have VDMs in ROS, bugcheck. */ mov ebx, [ecx+FX_ERROR_OFFSET]
jmp BogusTrap2 movzx eax, word ptr [ecx+FX_CONTROL_WORD]
movzx edx, word ptr [ecx+FX_STATUS_WORD]
TsSetOnLoadedState: /* Get the faulting opcode */
/* TS shouldn't be set, unless this we don't have a Math Processor */ mov esi, [ecx+FX_DATA_OFFSET]
test bl, CR0_MP jmp CheckError
jnz BogusTrap
/* Strange that we got a trap at all, but ignore and continue */ FnError:
clts /* Get error offset, control and status words */
jmp _Kei386EoiHelper@0 mov ebx, [ecx+FP_ERROR_OFFSET]
movzx eax, word ptr [ecx+FP_CONTROL_WORD]
movzx edx, word ptr [ecx+FP_STATUS_WORD]
/* Get the faulting opcode */
mov esi, [ecx+FP_DATA_OFFSET]
CheckError:
/* Mask exceptions */
and eax, 0x3F
not eax
and eax, edx
/* Check if what's left is invalid */
test al, 1
jz ValidNpxOpcode
/* Check if it was a stack fault */
test al, 64
jnz InvalidStack
/* Raise exception */
mov eax, STATUS_FLOAT_INVALID_OPERATION
jmp _DispatchOneParam
InvalidStack:
/* Raise exception */
mov eax, STATUS_FLOAT_STACK_CHECK
jmp _DispatchTwoParam
ValidNpxOpcode:
/* Check for divide by 0 */
test al, 4
jz 1f
/* Raise exception */
mov eax, STATUS_FLOAT_DIVIDE_BY_ZERO
jmp _DispatchOneParam
1:
/* Check for denormal */
test al, 2
jz 1f
/* Raise exception */
mov eax, STATUS_FLOAT_INVALID_OPERATION
jmp _DispatchOneParam
1:
/* Check for overflow */
test al, 8
jz 1f
/* Raise exception */
mov eax, STATUS_FLOAT_OVERFLOW
jmp _DispatchOneParam
1:
/* Check for underflow */
test al, 16
jz 1f
/* Raise exception */
mov eax, STATUS_FLOAT_UNDERFLOW
jmp _DispatchOneParam
1:
/* Check for precision fault */
test al, 32
jz UnexpectedNpx
/* Raise exception */
mov eax, STATUS_FLOAT_INEXACT_RESULT
jmp _DispatchOneParam
UnexpectedNpx:
/* Strange result, bugcheck the OS */
sti
push ebp
push 0
push 0
push eax
push 1
push TRAP_CAUSE_UNKNOWN
call _KeBugCheckWithTf@24
V86Npx: V86Npx:
/* Check if this is a VDM */ /* Check if this is a VDM */
@ -1258,15 +1361,23 @@ V86Npx:
int 3 int 3
jmp $ jmp $
BogusTrap2: EmulationEnabled:
/* Cause a bugcheck */ /* Did this come from kernel-mode? */
sti cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
push 0 jz CheckState
push 0
push eax /* It came from user-mode, so this would only be valid inside a VDM */
push 1 /* Since we don't actually have VDMs in ROS, bugcheck. */
push TRAP_CAUSE_UNKNOWN jmp UnexpectedNpx
call _KeBugCheckEx@20
TsSetOnLoadedState:
/* TS shouldn't be set, unless this we don't have a Math Processor */
test bl, CR0_MP
jnz BogusTrap
/* Strange that we got a trap at all, but ignore and continue */
clts
jmp _Kei386EoiHelper@0
BogusTrap: BogusTrap:
/* Cause a bugcheck */ /* Cause a bugcheck */