From 8b094bf09343774eea39aacda20402393cc14017 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Mon, 18 Sep 2006 02:33:21 +0000 Subject: [PATCH] - 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 --- reactos/include/ndk/asm.h | 32 +++++- reactos/ntoskrnl/ke/i386/trap.s | 169 ++++++++++++++++++++++++++------ 2 files changed, 168 insertions(+), 33 deletions(-) diff --git a/reactos/include/ndk/asm.h b/reactos/include/ndk/asm.h index 9ce3ef517d4..15cada7f0c7 100644 --- a/reactos/include/ndk/asm.h +++ b/reactos/include/ndk/asm.h @@ -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 diff --git a/reactos/ntoskrnl/ke/i386/trap.s b/reactos/ntoskrnl/ke/i386/trap.s index a8c449784f7..30a952d8499 100644 --- a/reactos/ntoskrnl/ke/i386/trap.s +++ b/reactos/ntoskrnl/ke/i386/trap.s @@ -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 */