mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
399 lines
8.0 KiB
399 lines
8.0 KiB
page ,132
|
|
subttl emerror.asm - Emulator error handler
|
|
;***
|
|
;emerror.asm - Emulator error handler
|
|
;
|
|
; Copyright (c) 1987-89, Microsoft Corporation
|
|
;
|
|
;Purpose:
|
|
; Emulator error handler
|
|
;
|
|
; This Module contains Proprietary Information of Microsoft
|
|
; Corporation and should be treated as Confidential.
|
|
;
|
|
;Revision History:
|
|
; See emulator.hst
|
|
;
|
|
;*******************************************************************************
|
|
|
|
|
|
ProfBegin ERROR
|
|
|
|
; error entry to check for unmasked errors
|
|
|
|
|
|
error_return macro noerror
|
|
pop eax ; common exit code
|
|
ifdef XENIX
|
|
ifdef i386
|
|
pop ss ; pop stack selector
|
|
endif
|
|
ifnb <noerror>
|
|
iretd ; normal return
|
|
else
|
|
int 0FFh ; special XENIX int for error
|
|
endif
|
|
else
|
|
iretd
|
|
endif ;XENIX
|
|
endm
|
|
|
|
|
|
TESTif macro nam
|
|
mov bl,err&nam ; default error number
|
|
IF (nam GE 100H)
|
|
test ah,nam/256
|
|
ELSE ;not (nam GE 100H)
|
|
test al,nam
|
|
ENDIF ;(nam GE 100H)
|
|
jnz short signalerror
|
|
endm
|
|
|
|
pub CommonExceptions
|
|
|
|
ifdef QB3
|
|
|
|
jmp $EM_INT ; jump to QB3 error handler
|
|
|
|
else ;not QB3
|
|
|
|
push ds ; get address from task DS
|
|
push ebx
|
|
|
|
TESTif StackUnderflow ; Stack underflow
|
|
TESTif StackOverflow ; Stack overflow
|
|
TESTif SquareRootNeg ; Square root of negative number?
|
|
TESTif IntegerOverflow ; Would number not fit in integer?
|
|
TESTif Invalid ; indefinite error ?
|
|
TESTif ZeroDivide ; zero divide error ?
|
|
TESTif Overflow ; overflow error ?
|
|
TESTif Underflow ; underflow error ?
|
|
; TESTif Denormal ; denormal error ? not yet implemented
|
|
TESTif Precision ; Precision error ?
|
|
TESTif Unemulated ; unemulated error ?
|
|
|
|
; BL = error code value
|
|
|
|
pub signalerror
|
|
|
|
ifndef XENIX
|
|
|
|
ifdef MTHREAD
|
|
LOADthreadDS ; macro in emthread.asm
|
|
; load thread's DS; trash AX
|
|
elseifdef standalone
|
|
xor ax,ax
|
|
mov ds,ax
|
|
mov ds,ds:[4*TSKINT+2]
|
|
|
|
elseifdef _COM_
|
|
mov ds, [__EmDataSeg]
|
|
|
|
else ;Default
|
|
mov ax, edataBASE
|
|
mov ds,ax
|
|
endif ;Default
|
|
|
|
|
|
ifdef MTHREAD
|
|
; lock _SIGNAL_LOCK to guard SignalAddress (also used by signal func.)
|
|
mov ax,DGROUP
|
|
mov ds,ax ; establish DS == DGROUP for __lock
|
|
push _SIGNAL_LOCK
|
|
call __lockf
|
|
add sp,2
|
|
mov ax,EMULATOR_DATA ; use thread 1's data segment
|
|
mov ds,ax ; establish DS == EMULATOR_DATA
|
|
mov ax,word ptr [SignalAddress] ; check for nonzero address
|
|
or ax,word ptr [SignalAddress+2]
|
|
jnz short havehandler
|
|
; go straight to DOSEXIT call below ...
|
|
; don't bother cleaning up the stack or unlocking _SIGNAL_LOCK
|
|
|
|
;pop bx ; don't bother tossing
|
|
;pop ebx ; don't bother tossing
|
|
;pop ds ; don't bother tossing
|
|
mov ax,1
|
|
push ax
|
|
; BL = error code value
|
|
xchg ax,bx ; al = return code
|
|
xor ah,ah
|
|
push ax
|
|
os2call DOSEXIT ; DOSEXIT(1,return code) to terminate process
|
|
|
|
elseifdef WINDOWS
|
|
push es
|
|
push bx
|
|
|
|
mov ax, DOS_getvector*256 + TSKINT
|
|
IntDOS
|
|
|
|
mov ax, es
|
|
or ax, bx
|
|
|
|
pop bx
|
|
pop es
|
|
jnz short havehandler
|
|
|
|
else ;not MTHREAD or WINDOWS
|
|
mov ax,word ptr [SignalAddress]
|
|
or ax,word ptr [SignalAddress+2]
|
|
jnz short havehandler
|
|
; UNDONE - why no "os2call DOSEXIT" for the DOS5 case?
|
|
;pop bx ; don't bother tossing
|
|
;pop ds ; don't bother tossing
|
|
xchg ax,bx ; al = return code
|
|
mov ah,04Ch
|
|
int 21h ; terminate process with fp error code
|
|
|
|
endif ;not MTHREAD or WINDOWS
|
|
|
|
pub havehandler
|
|
|
|
ifdef MTHREAD
|
|
; DS == EMULATOR_DATA ; Use thread 1's DS for SignalAddress.
|
|
; BL = return code
|
|
xchg ax,bx ; al = return code
|
|
push word ptr [SignalAddress+2]
|
|
push word ptr [SignalAddress]
|
|
|
|
mov bx,DGROUP
|
|
mov ds,bx ; establish DS == DGROUP for __unlock
|
|
|
|
push _SIGNAL_LOCK ; unlock _SIGNAL_LOCK
|
|
call __unlockf
|
|
add sp,2
|
|
|
|
mov bx,sp ; SS:BX points to a copy of SignalAddress on the stack
|
|
|
|
else ;not MTHREAD
|
|
; bl = return code
|
|
xchg ax,bx ; al = return code
|
|
|
|
; other error return info for recovery
|
|
pop ebx
|
|
endif ;not MTHREAD
|
|
|
|
; all registers are the original values except AX and DS
|
|
;
|
|
; al = error code (81h and up)
|
|
;
|
|
; if the signal routine is going to return to the user program, it can
|
|
; just do a long ret. The users DS is sitting above the far return address
|
|
|
|
|
|
ifdef POLLING ; new exception handling code
|
|
ifndef frontend
|
|
|
|
ifdef DOS3and5
|
|
cmp [protmode],0 ; check for protect mode
|
|
jne callsig ; yes - call signal now
|
|
endif ;DOS3and5
|
|
|
|
ifdef DOS3
|
|
cmp [have8087],0 ; check if emulating
|
|
je callsig ; yes - call signal now
|
|
cmp [errorcode],0 ; check if pending error
|
|
ifdef WF
|
|
je ncs1
|
|
jmp nocallsig
|
|
ncs1:
|
|
else
|
|
jne nocallsig ; yes - just return
|
|
endif
|
|
|
|
mov [errorcode],al ; save error code for later
|
|
|
|
|
|
;*
|
|
;* Set 80x87 exception occured flag.
|
|
;*
|
|
|
|
ifdef USE_IRET
|
|
mov byte ptr cs:[FWAITiret], iNOP ; nop out "iret"
|
|
|
|
elseifdef WINDOWS
|
|
ifdef WF
|
|
cmp [wfGoFast], 0
|
|
je WinSlow2
|
|
|
|
.286p
|
|
; int 3
|
|
push bp ; bp[0], ds[2], ax[4], retip[6], retcs[8], retfl[10]
|
|
mov bp, sp ; faultip[12], faultcs[14]
|
|
push es
|
|
pusha
|
|
mov ax, REMLSW
|
|
mov [wfErr], ax
|
|
|
|
push cs ; if fault CS:IP == our int 3d handler
|
|
pop ax ; then we don't want to patch it, we just want
|
|
cmp [bp+14], ax ; to set the flag as if we had
|
|
jnz wfPatch
|
|
mov ax, offset wfFaultHere
|
|
cmp [bp+12], ax
|
|
jnz wfPatch
|
|
mov [wfInsn], 3dcdh
|
|
jmp short wfNoPatch
|
|
wfPatch:
|
|
|
|
push [bp+14] ; copy faulting CS to data selector
|
|
push [wfSel]
|
|
call ChangeSelector
|
|
|
|
mov es, [wfSel] ; es:bx points to faulting insn
|
|
mov bx, [bp+12]
|
|
|
|
mov ax, es:[bx] ; save old insn value
|
|
mov [wfInsn], ax
|
|
mov es:[bx], 3dcdh ; put INT 3D at fault location
|
|
wfNoPatch:
|
|
popa
|
|
pop es
|
|
pop bp
|
|
pop ds
|
|
pop ax
|
|
iret
|
|
; fall through to old code
|
|
WinSlow2:
|
|
endif
|
|
mov [ExceptFlag], 1
|
|
|
|
else ;DEFAULT
|
|
mov byte ptr cs:[FWAITRetF], iNOP ; nop out "retf 2"
|
|
mov word ptr cs:[FWAITRetF2], wNOP
|
|
endif ;DEFAULT
|
|
|
|
jmp short nocallsig ; just return
|
|
endif ;DOS3
|
|
|
|
endif ;not frontend
|
|
endif ;POLLING
|
|
|
|
|
|
callsig:
|
|
|
|
ifdef MTHREAD
|
|
call dword ptr ss:[bx] ; call thru thread 1's signal address
|
|
add sp, 4 ; remove address of signal handler from stack
|
|
pop ebx ; note that bx is restored after the call to the
|
|
; SIGFPE signal handler, but the SIG_DFL, SIG_IGN, or
|
|
; user-handler shouldn't care; in the event of SIG_IGN
|
|
; or a user handler that actually returns instead of
|
|
; doing longjump(), this pop instruction will restore bx
|
|
|
|
elseifdef WINDOWS
|
|
mov REMLSW, ax ; save error code
|
|
|
|
pop ds
|
|
pop ax ; stack is now just an int stack frame
|
|
|
|
ifdef WF0
|
|
.286p
|
|
; int 3
|
|
push bp ; bp[0], retip[2], retcs[4], retfl[6]
|
|
mov bp, sp ; faultip[8], faultcs[10]
|
|
push ds
|
|
push es
|
|
pusha
|
|
mov ax, EMULATOR_DATA
|
|
mov ds, ax
|
|
cmp [wfGoFast], 1 ; if running Std Mode
|
|
jnz WinSlow2
|
|
mov ax, REMLSW
|
|
mov [wfErr], ax
|
|
push [bp+10] ; copy faulting CS to data selector
|
|
push [wfSel]
|
|
call ChangeSelector
|
|
|
|
mov es, [wfSel] ; es:bx points to faulting insn
|
|
mov bx, [bp+8]
|
|
|
|
mov ax, es:[bx] ; save old insn value
|
|
mov [wfInsn], ax
|
|
|
|
mov es:[bx], 3dcdh ; put INT 3D at fault location
|
|
|
|
popa
|
|
pop es
|
|
pop ds
|
|
pop bp
|
|
iret
|
|
WinSlow2: ; can't do fast (non-poll) fp, so
|
|
popa ; restore stack and use old method
|
|
pop es
|
|
pop ds
|
|
pop bp
|
|
; fall through to old code
|
|
endif
|
|
|
|
inc bp
|
|
push bp
|
|
mov bp, sp
|
|
push ds
|
|
|
|
push ax ; save user's ax
|
|
|
|
push cs ; must set up another stack frame
|
|
mov ax, offset DummyReturn
|
|
push ax
|
|
DummyReturn:
|
|
|
|
mov word ptr [bp-2], EMULATOR_DATA ; emulator's ds goes on first frame
|
|
|
|
inc bp
|
|
push bp
|
|
mov bp, sp
|
|
push ds ; push user's ds onto dummy stack frame
|
|
|
|
mov ax, EMULATOR_DATA
|
|
mov ds, ax
|
|
|
|
push es ; if windows => setup SignalAddress for
|
|
push bx ; far call
|
|
|
|
mov ax, DOS_getvector*256 + TSKINT
|
|
IntDOS
|
|
|
|
mov word ptr [SignalAddress], bx
|
|
mov word ptr [SignalAddress+2], es
|
|
|
|
pop bx
|
|
pop es
|
|
|
|
mov ax, REMLSW ; al = error code
|
|
|
|
call [SignalAddress] ; execute signal routine
|
|
|
|
pop ds ; restore user's ds
|
|
add sp, 6 ; get rid of dummy stack frame
|
|
pop ax ; restore user's ax
|
|
|
|
add sp, 2 ; get rid of emulator ds on stack
|
|
|
|
pop bp
|
|
dec bp
|
|
|
|
iret ; return
|
|
|
|
|
|
else ;not MTHREAD or WINDOWS
|
|
call [SignalAddress] ; execute signal routine
|
|
endif ;not MTHREAD or WINDOWS
|
|
|
|
nocallsig:
|
|
|
|
pop ds ; restore user DS
|
|
error_return noerror ; treat as if nothing happened
|
|
|
|
else ;XENIX
|
|
pop ebx ; restore EBX and DS
|
|
pop ds
|
|
error_return ; error exit for XENIX
|
|
|
|
endif ;XENIX
|
|
|
|
|
|
endif ;not QB3
|
|
|
|
ProfEnd ERROR
|