Fix for FPU generated exception as interrupt 0x10, contributed by Max Nazhalov

git-svn-id: trunk@36813 -
This commit is contained in:
pierre 2017-07-29 11:50:21 +00:00
parent 301fc9af70
commit ba7586a5c8
2 changed files with 64 additions and 53 deletions

View File

@ -73,7 +73,6 @@
extern __SaveInt75
extern __fpu_status
extern __fpu_control
extern FPC_HANDLE_I8086_ERROR
@ -283,7 +282,8 @@ error_msg:
global FPC_INT00_HANDLER
FPC_INT00_HANDLER:
sub sp, 4 ; reserve space on the stack for the retf
pushf
sub sp, 4 ; reserve space on the stack for the iret
push cx
push ds
@ -310,7 +310,7 @@ FPC_INT00_HANDLER:
%ifndef __FAR_CODE__
; check whether we're coming from the same code segment
mov bp, sp
mov cx, [bp + 3*2 + 6] ; get caller segment
mov cx, [bp + 3*2 + 6 + 2] ; get caller segment
mov bp, cs
cmp bp, cx
jne .call_previous_handler00
@ -318,12 +318,12 @@ FPC_INT00_HANDLER:
; Call Fpc_Handle_I8086_Error, with err=0
mov bp, sp
mov cx, [bp + 3*2 + 4] ; get caller offset
mov cx, [bp + 3*2 + 6] ; get caller offset
%ifdef __FAR_CODE__
mov dx, [bp + 3*2 + 6] ; get caller segment
mov dx, [bp + 3*2 + 6 + 2] ; get caller segment
%endif
pop bp
add sp, 2*2 + 4 + 6
add sp, 2*2 + 6 + 6
xor ax, ax
push ax
mov ax, 0
@ -333,6 +333,7 @@ FPC_INT00_HANDLER:
%endif
push cx
cld
sti
%ifdef __FAR_CODE__
jmp far FPC_HANDLE_I8086_ERROR
%else
@ -348,11 +349,12 @@ FPC_INT00_HANDLER:
pop bp
pop ds
pop cx
retf ; jumps to the previous handler with all registers and stack intact
iret ; jumps to the previous handler with all registers and stack intact
global FPC_INT10_HANDLER
FPC_INT10_HANDLER:
sub sp, 4 ; reserve space on the stack for the retf
pushf
sub sp, 4 ; reserve space on the stack for the iret
push cx
push ds
@ -368,21 +370,8 @@ FPC_INT10_HANDLER:
%endif
mov ds, bp
; Check that an unmasked exception is indeed set
; First load FPU control register to __fpu_control
fnstcw word [__fpu_control]
; Move control register value to bx register
mov bx,word [__fpu_control]
; Now load status register to ax
fnstsw word [__fpu_status]
; Only the exception part is useful, clear other parts
and bx,3fh
; at least one same bit must also be set in bx
; in that case with a bit set in status register
; which means an exception has been generated by the FPU
; and the exeception is not masked, as the same
; bit is set in control register
mov ax,word [__fpu_status]
and ax,bx
test byte [__fpu_status], 80h ; really just this bit is enough, see i8087 datasheet
je .call_previous_handler10
%ifdef __NEAR_DATA__
@ -396,7 +385,7 @@ FPC_INT10_HANDLER:
%ifndef __FAR_CODE__
; check whether we're coming from the same code segment
mov bp, sp
mov cx, [bp + 3*2 + 6] ; get caller segment
mov cx, [bp + 3*2 + 6 + 2] ; get caller segment
mov bp, cs
cmp bp, cx
jne .call_previous_handler10
@ -404,12 +393,12 @@ FPC_INT10_HANDLER:
; Call Fpc_Handle_I8086_Error, with err=$10
mov bp, sp
mov cx, [bp + 3*2 + 4] ; get caller offset
mov cx, [bp + 3*2 + 6] ; get caller offset
%ifdef __FAR_CODE__
mov dx, [bp + 3*2 + 6] ; get caller segment
mov dx, [bp + 3*2 + 6 + 2] ; get caller segment
%endif
pop bp
add sp, 2*2 + 4 + 6
add sp, 2*2 + 6 + 6
xor ax, ax
push ax
mov ax, 10h
@ -419,6 +408,7 @@ FPC_INT10_HANDLER:
%endif
push cx
cld
sti
%ifdef __FAR_CODE__
jmp far FPC_HANDLE_I8086_ERROR
%else
@ -434,11 +424,12 @@ FPC_INT10_HANDLER:
pop bp
pop ds
pop cx
retf ; jumps to the previous handler with all registers and stack intact
iret ; jumps to the previous handler with all registers and stack intact
global FPC_INT75_HANDLER
FPC_INT75_HANDLER:
sub sp, 4 ; reserve space on the stack for the retf
pushf
sub sp, 4 ; reserve space on the stack for the iret
push cx
push ds
@ -465,7 +456,7 @@ FPC_INT75_HANDLER:
%ifndef __FAR_CODE__
; check whether we're coming from the same code segment
mov bp, sp
mov cx, [bp + 3*2 + 6] ; get caller segment
mov cx, [bp + 3*2 + 6 + 2] ; get caller segment
mov bp, cs
cmp bp, cx
jne .call_previous_handler75
@ -473,12 +464,12 @@ FPC_INT75_HANDLER:
; Call Fpc_Handle_I8086_Error, with err=$75
mov bp, sp
mov cx, [bp + 3*2 + 4] ; get caller offset
mov cx, [bp + 3*2 + 6] ; get caller offset
%ifdef __FAR_CODE__
mov dx, [bp + 3*2 + 6] ; get caller segment
mov dx, [bp + 3*2 + 6 + 2] ; get caller segment
%endif
pop bp
add sp, 2*2 + 4 + 6
add sp, 2*2 + 6 + 6
xor ax, ax
push ax
mov ax, 75h
@ -488,6 +479,14 @@ FPC_INT75_HANDLER:
%endif
push cx
cld
; Reset IRQ/#IGNNE latch; signal EOI; enable interrupts
mov al,20h
out 0F0h,al ; al=any
out 0A0h,al
out 020h,al
sti
%ifdef __FAR_CODE__
jmp far FPC_HANDLE_I8086_ERROR
%else
@ -509,9 +508,9 @@ FPC_INT75_HANDLER:
global FPC_INSTALL_INTERRUPT_HANDLERS
FPC_INSTALL_INTERRUPT_HANDLERS:
push ds
%ifdef __HUGE__
push ds
mov ax, SYSTEM_DATA
mov ds, ax
%endif
@ -525,14 +524,16 @@ FPC_INSTALL_INTERRUPT_HANDLERS:
; install the new int 00 handler
%ifndef __TINY__
push ds
push cs
pop ds
%endif
mov dx, FPC_INT00_HANDLER
pop ds
push ds
mov ax, 2500h
int 21h
%ifndef __TINY__
pop ds
%endif
; save old int $10 handler
mov ax, 3510h
@ -543,14 +544,16 @@ FPC_INSTALL_INTERRUPT_HANDLERS:
; install the new int $10 handler
%ifndef __TINY__
push ds
push cs
pop ds
%endif
mov dx, FPC_INT10_HANDLER
mov ax, 2510h
int 21h
%ifndef __TINY__
pop ds
push ds
%endif
; save old int $75 handler
mov ax, 3575h
@ -561,15 +564,21 @@ FPC_INSTALL_INTERRUPT_HANDLERS:
; install the new int $75 handler
%ifndef __TINY__
push ds
push cs
pop ds
%endif
mov dx, FPC_INT75_HANDLER
mov ax, 2575h
int 21h
%ifndef __TINY__
pop ds
%endif
%ifdef __HUGE__
pop ds
%endif
%ifdef __FAR_CODE__
retf
%else
@ -579,26 +588,33 @@ FPC_INSTALL_INTERRUPT_HANDLERS:
global FPC_RESTORE_INTERRUPT_HANDLERS
FPC_RESTORE_INTERRUPT_HANDLERS:
push ds
%ifdef __HUGE__
push ds
mov ax, SYSTEM_DATA
mov ds, ax
%endif
push ds
mov ax, 2500h
lds dx, [__SaveInt00]
int 21h
pop ds
push ds
mov ax, 2510h
lds dx, [__SaveInt10]
int 21h
pop ds
push ds
mov ax, 2575h
lds dx, [__SaveInt75]
int 21h
pop ds
%ifdef __HUGE__
pop ds
%endif
%ifdef __FAR_CODE__
retf
%else

View File

@ -84,7 +84,6 @@ var
SaveInt10: FarPointer;public name '__SaveInt10';
SaveInt75: FarPointer;public name '__SaveInt75';
fpu_status: word;public name '__fpu_status';
fpu_control: word;public name '__fpu_control';
AllFilesMask: string [3];
@ -182,7 +181,7 @@ Procedure SysInitFPU;
fldcw localfpucw
fwait
end;
if Test8087 < 2 then
if Test8087 < 3 then { i8087/i80287 do not have "native" exception mode (CR0:NE) }
begin
restore_old_int10:=true;
end
@ -239,13 +238,11 @@ Procedure SysInitFPU;
end;
{ Restore previous interrupt 06 handler }
asm
push es
mov bx,word [prevInt06]
mov dx,word [prevInt06+2]
mov es,dx
push ds
mov ax, $2506
lds dx,[prevInt06]
int $21
pop es
pop ds
end;
end;
{ Special handler of interrupt $10
@ -254,13 +251,11 @@ Procedure SysInitFPU;
{$ifndef TEST_FPU_INT10}
if restore_old_int10 then
asm
push es
mov bx,word [SaveInt10]
mov dx,word [SaveInt10+2]
mov es,dx
push ds
mov ax, $2510
lds dx,[SaveInt10]
int $21
pop es
pop ds
end;
{$endif ndef TEST_FPU_INT10}
end;