- 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
//
#define FN_CONTROL_WORD 0x0
#define FN_STATUS_WORD 0x4
#define FN_TAG_WORD 0x8
#define FN_DATA_SELECTOR 0x18
#define FP_CONTROL_WORD 0x0
#define FP_STATUS_WORD 0x4
#define FP_TAG_WORD 0x8
#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 SIZEOF_FX_SAVE_AREA 528
#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
//
@ -464,6 +479,15 @@ Author:
#define STATUS_SINGLE_STEP 0x80000004
#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094
#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 TRAP_CAUSE_UNKNOWN 0x12
#define KMODE_EXCEPTION_NOT_HANDLED 0x13

View file

@ -1220,32 +1220,135 @@ HandleUserNpx:
and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
mov cr0, ebx
/* FIXME: Implement the rest */
int 3
jmp $
/* Check if we have FX support */
test byte ptr _KeI386FxsrPresent, 1
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:
/* FIXME: Implement the rest */
int 3
jmp $
/* Clear the TS bit and re-enable interrupts */
and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
sti
EmulationEnabled:
/* Did this come from kernel-mode? */
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
jz CheckState
/* Check if we have FX support */
test byte ptr _KeI386FxsrPresent, 1
jz FnError
/* It came from user-mode, so this would only be valid inside a VDM */
/* Since we don't actually have VDMs in ROS, bugcheck. */
jmp BogusTrap2
/* Get error offset, control and status words */
mov ebx, [ecx+FX_ERROR_OFFSET]
movzx eax, word ptr [ecx+FX_CONTROL_WORD]
movzx edx, word ptr [ecx+FX_STATUS_WORD]
TsSetOnLoadedState:
/* TS shouldn't be set, unless this we don't have a Math Processor */
test bl, CR0_MP
jnz BogusTrap
/* Get the faulting opcode */
mov esi, [ecx+FX_DATA_OFFSET]
jmp CheckError
/* Strange that we got a trap at all, but ignore and continue */
clts
jmp _Kei386EoiHelper@0
FnError:
/* Get error offset, control and status words */
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:
/* Check if this is a VDM */
@ -1258,15 +1361,23 @@ V86Npx:
int 3
jmp $
BogusTrap2:
/* Cause a bugcheck */
sti
push 0
push 0
push eax
push 1
push TRAP_CAUSE_UNKNOWN
call _KeBugCheckEx@20
EmulationEnabled:
/* Did this come from kernel-mode? */
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
jz CheckState
/* It came from user-mode, so this would only be valid inside a VDM */
/* Since we don't actually have VDMs in ROS, bugcheck. */
jmp UnexpectedNpx
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:
/* Cause a bugcheck */