472 lines
12 KiB
NASM
472 lines
12 KiB
NASM
page ,132
|
|
subttl emerror.asm - Emulator error handler
|
|
|
|
;emerror.asm - Emulator error handler
|
|
|
|
; Microsoft Confidential
|
|
|
|
; Copyright (c) Microsoft Corporation 1987, 1991
|
|
|
|
; All Rights Reserved
|
|
|
|
;Purpose:
|
|
; Emulator error handler
|
|
|
|
;Revision History: (also see emulator.hst)
|
|
|
|
; 10/30/89 WAJ Added this header.
|
|
; 11/15/89 WAJ Major changes for Dos32RaiseExcpetion().
|
|
; 12/01/89 WAJ Now set cbExceptionInfo correctly.
|
|
; 02/08/90 WAJ Fixed GP fault in 32 bit exception handler.
|
|
; 09/03/91 JWM Modified entry/exit sequence for DOSX32.
|
|
; 02/15/92 JWM Adapted for NT.
|
|
|
|
|
|
|
|
ifdef _DOS32EXT
|
|
include except32.inc
|
|
endif
|
|
|
|
;*** error_return - return to user code (regardless of error)
|
|
|
|
; This macro returns to user code. It goes to some lengths
|
|
; to restore the flags on the instruction immediately before
|
|
; the return so that any pending trace trap will be
|
|
; acknowledged immediately after the retfd (and before the
|
|
; next user instruction) instead of after the instruction
|
|
; following the return as would be the case if we returned
|
|
; using iretd.
|
|
|
|
; ENTRY ((SS:ESP)) = user's EAX
|
|
; ((SS:ESP)+4) = return EIP
|
|
; ((SS:ESP)+8) = return CS
|
|
; ((SS:ESP)+12) = user's EFLAGS
|
|
; EXIT return to user program, above arguments
|
|
; popped off stack, user's EAX and EFLAGS
|
|
; restored.
|
|
|
|
error_return macro noerror
|
|
ifdef _DOS32EXT
|
|
sti ; JWM, 9/3/91
|
|
push dword ptr [esp+8] ; JWM, 9/6/91
|
|
popfd ; JWM, 9/6/91
|
|
endif ; DOS32EXT
|
|
|
|
ifdef NT386
|
|
if DBG
|
|
push dword ptr [esp+8] ; On checked build, allow
|
|
popfd ; single step to work
|
|
endif
|
|
endif
|
|
iretd
|
|
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)
|
|
JSNZ signalerror
|
|
endm
|
|
|
|
EM_ENTRY eCommonExceptions
|
|
CommonExceptions:
|
|
mov ebx,[esp].[OldLongStatus]
|
|
and ebx,LongSavedFlags ;preserve condition codes, error flags
|
|
or EMSEG:[LongStatusWord],ebx ;merge saved status word, condition codes
|
|
pop eax
|
|
pop ecx
|
|
pop edx
|
|
pop ebx
|
|
add esp,4 ; toss esp value
|
|
pop ebp
|
|
pop esi
|
|
pop edi
|
|
add esp,8 ;toss old PrevCodeOff and StatusWord
|
|
pop ds
|
|
call Emexcept
|
|
error_return noerror
|
|
|
|
ifdef _DOS32EXT
|
|
|
|
EmExcept PROC C, OldEIP:DWORD, OldCS:DWORD, OldFlags:DWORD
|
|
|
|
LOCAL SSAR:DWORD
|
|
LOCAL ec:_DX32_CONTEXT
|
|
|
|
;*
|
|
;* Set up SS access rights.
|
|
;*
|
|
|
|
push ds
|
|
mov [ec.R_Eax], eax
|
|
GetEmData ds,ax
|
|
|
|
mov eax, ss
|
|
lar eax, eax
|
|
mov [SSAR], eax
|
|
|
|
;*
|
|
;* Fill in ExceptionContext structure.
|
|
;*
|
|
|
|
|
|
mov [ec.NPXContextFlags], NPX_CONTEXT_FULL
|
|
mov [ec.R_Edi], edi
|
|
mov [ec.R_Esi], esi
|
|
|
|
mov eax, [ebp]
|
|
mov [ec.R_Ebp], eax
|
|
|
|
lea eax, [OldFlags+4]
|
|
mov [ec.R_Esp], eax
|
|
|
|
mov [ec.R_Ebx], ebx
|
|
mov [ec.R_Edx], edx
|
|
mov [ec.R_Ecx], ecx
|
|
|
|
mov eax, EMSEG:[PrevCodeOff]
|
|
|
|
mov [ec.R_Eip], eax
|
|
mov eax, [OldFlags]
|
|
mov [ec.EFlags], eax
|
|
|
|
mov eax, [OldCS]
|
|
movzx eax,ax
|
|
mov [ec.SegCs], eax
|
|
mov ax,ss
|
|
movzx eax,ax
|
|
mov [ec.SegSs], eax
|
|
|
|
pop eax
|
|
movzx eax,ax
|
|
mov [ec.SegDs], eax ; ds was pushed on entry.
|
|
|
|
mov ax,es
|
|
movzx eax,ax
|
|
mov [ec.SegEs], eax
|
|
|
|
mov ax,fs
|
|
movzx eax,ax
|
|
mov [ec.SegFs], eax
|
|
|
|
mov ax,gs
|
|
movzx eax,ax
|
|
mov [ec.SegGs], eax
|
|
|
|
lea esi, [ec]
|
|
add esi, 4
|
|
|
|
push ebp
|
|
call SaveState
|
|
pop ebp
|
|
|
|
lea eax, [ec]
|
|
push ds
|
|
push es
|
|
|
|
mov bx, seg FLAT:CURstk
|
|
mov ds, ebx
|
|
mov es, ebx
|
|
push eax
|
|
|
|
call DOS32RAISEEXCEPTION
|
|
|
|
add esp, 4
|
|
|
|
pop es
|
|
pop ds
|
|
|
|
RaiseExceptRet:
|
|
or eax, eax
|
|
JZ ExceptNotHandled
|
|
|
|
;*
|
|
;* Copy new flags, cs, eip to new stack.
|
|
;*
|
|
|
|
mov ds, [ec.SegSs]
|
|
mov esi, [ec.R_Esp] ; ds:esi == new ss:esp
|
|
|
|
mov eax, [ec.Eflags] ; set up iretd frame
|
|
mov [esi-4], eax
|
|
|
|
mov eax, [ec.SegCs]
|
|
mov [esi-8], eax
|
|
|
|
mov eax, [ec.R_Eip]
|
|
mov [esi-12], eax
|
|
|
|
;*
|
|
;* Put new stack pointer on stack.
|
|
;*
|
|
|
|
push ds
|
|
sub esi, 12
|
|
push esi
|
|
|
|
;*
|
|
;* Reset other registers.
|
|
;*
|
|
|
|
mov edi, [ec.R_Edi]
|
|
mov esi, [ec.R_Esi]
|
|
mov ebx, [ec.R_Ebx]
|
|
mov edx, [ec.R_Edx]
|
|
mov ecx, [ec.R_Ecx]
|
|
mov eax, [ec.R_Eax]
|
|
mov ds, [ec.SegDs]
|
|
mov es, [ec.SegEs]
|
|
mov fs, [ec.SegFs]
|
|
mov gs, [ec.SegGs]
|
|
|
|
mov ebp, [ec.R_Ebp] ; must do this last.
|
|
|
|
lss esp, fword ptr [esp] ; reset ss:esp
|
|
|
|
sti ; JWM, 9/3/91
|
|
push [esp+8] ; JWM, 9/6/91
|
|
popfd ; JWM, 9/6/91
|
|
|
|
iretd ; reset flags, cs, eip
|
|
|
|
ExceptNotHandled:
|
|
EmExcept ENDP
|
|
|
|
endif ; ifdef _DOS32EXT
|
|
|
|
ifdef NT386
|
|
|
|
ISIZE equ 4
|
|
ISizeEC equ (ContextFrameLength + ISIZE - 1) and (not (ISIZE - 1))
|
|
ISizeExceptStruct equ (ExceptionRecordLength + ISIZE - 1) and (not (ISIZE - 1))
|
|
|
|
ec_off EQU 4+ISizeEc
|
|
estruct_off EQU ec_off+ISizeExceptStruct
|
|
|
|
SSAR EQU <[ebp][-4]>
|
|
ec EQU <[ebp][-ec_off]>
|
|
eStruct EQU <[ebp][-estruct_off]>
|
|
|
|
OldEIP EQU <ebp+8>
|
|
OldCS EQU <ebp+12>
|
|
OldFlags EQU <ebp+16>
|
|
|
|
|
|
EmExcept PROC NEAR
|
|
|
|
push ebp
|
|
mov ebp,esp
|
|
sub esp,estruct_off
|
|
|
|
|
|
;*
|
|
;* Set up SS access rights.
|
|
;*
|
|
|
|
push ds
|
|
mov [ec.ctx_RegEax], eax
|
|
GetEmData ds,ax
|
|
|
|
mov eax, ss
|
|
lar eax, eax
|
|
mov [SSAR], eax
|
|
|
|
;*
|
|
;* Fill in ExceptionContext structure.
|
|
;*
|
|
|
|
|
|
mov dword ptr [ec.ContextFlags], NPX_CONTEXT_FULL
|
|
mov dword ptr [ec.ctx_Cr0NpxState], CR0_EM
|
|
mov [ec.ctx_RegEdi], edi
|
|
mov [ec.ctx_RegEsi], esi
|
|
|
|
mov eax, [ebp]
|
|
mov [ec.ctx_RegEbp], eax
|
|
|
|
lea eax, [OldFlags+4]
|
|
mov [ec.ctx_RegEsp], eax
|
|
|
|
mov [ec.ctx_RegEbx], ebx
|
|
mov [ec.ctx_RegEdx], edx
|
|
mov [ec.ctx_RegEcx], ecx
|
|
|
|
mov eax, [OldEIP]
|
|
|
|
mov [ec.ctx_RegEip], eax
|
|
mov eax, [OldFlags]
|
|
mov [ec.ctx_EFlags], eax
|
|
|
|
mov eax, [OldCS]
|
|
movzx eax,ax
|
|
mov [ec.ctx_SegCs], eax
|
|
mov ax,ss
|
|
movzx eax,ax
|
|
mov [ec.ctx_SegSs], eax
|
|
|
|
pop eax
|
|
movzx eax,ax
|
|
mov [ec.ctx_SegDs], eax ; ds was pushed on entry.
|
|
|
|
mov ax,es
|
|
movzx eax,ax
|
|
mov [ec.ctx_SegEs], eax
|
|
|
|
mov ax,fs
|
|
movzx eax,ax
|
|
mov [ec.ctx_SegFs], eax
|
|
|
|
mov ax,gs
|
|
movzx eax,ax
|
|
mov [ec.ctx_SegGs], eax
|
|
|
|
lea esi, [ec]
|
|
add esi, ctx_env
|
|
|
|
or EMSEG:[StatusWord], 8000H ; set 'busy' bit
|
|
or EMSEG:[SWerr], Summary ; set Summary bit
|
|
or EMSEG:[CURerr], Summary
|
|
|
|
mov cl, EMSEG:[ErrMask]
|
|
push ecx
|
|
push ebp
|
|
call SaveState
|
|
pop ebp
|
|
pop ecx
|
|
|
|
call GetEMSEGStatusWord ; EAX = status word
|
|
test al, cl ; test status word against mask
|
|
jne short Err00
|
|
|
|
ifdef TRACENPX
|
|
mov edx, 0C1020304h ; Raise bogus exception code, to trace with
|
|
jmp short Err50
|
|
endif
|
|
mov al, Invalid
|
|
|
|
|
|
; According to the floating error priority, we test what is the cause of
|
|
; the NPX error and raise an appropriate exception.
|
|
|
|
|
|
Err00:
|
|
test al, Invalid ; Invalid Op?
|
|
jz short Err10 ; No, go check next
|
|
|
|
mov edx, XCPT_FLOAT_INVALID_OPERATION
|
|
test al, StackFlag ; Stack fault?
|
|
jz short Err50 ; No, go raise invalid op
|
|
mov edx, XCPT_FLOAT_STACK_CHECK
|
|
jmp short Err50 ; Go raise stack fault
|
|
|
|
Err10: mov edx, XCPT_FLOAT_DIVIDE_BY_ZERO
|
|
test al, ZeroDivide
|
|
jnz short Err50
|
|
mov edx, XCPT_FLOAT_DENORMAL_OPERAND
|
|
test al, Denormal
|
|
jnz short Err50
|
|
mov edx, XCPT_FLOAT_OVERFLOW
|
|
test al, Overflow
|
|
jnz short Err50
|
|
mov edx, XCPT_FLOAT_UNDERFLOW
|
|
test al, Underflow
|
|
jnz short Err50
|
|
mov edx, XCPT_FLOAT_INEXACT_RESULT
|
|
|
|
Err50: mov [eStruct.ExceptionNum], edx
|
|
|
|
xor eax,eax
|
|
mov [eStruct.fHandlerFlags], eax
|
|
mov [eStruct.NestedExceptionReportRecord], eax
|
|
mov dword ptr [eStruct.CParameters], 1 ; GeorgioP convention
|
|
mov [eStruct.ErExceptionInformation], eax ; GeorgioP convention
|
|
|
|
mov eax, EMSEG:[PrevCodeOff]
|
|
mov [eStruct.ExceptionAddress], eax
|
|
|
|
lea edx, [eStruct]
|
|
|
|
lea eax, [ec]
|
|
push ds
|
|
push es
|
|
|
|
|
|
;TRUE, this is a first-chance exception
|
|
|
|
stdCall _NtRaiseException,<edx, eax, 1>
|
|
stdCall _RtlRaiseStatus, <eax>
|
|
|
|
pop es
|
|
pop ds
|
|
|
|
RaiseExceptRet:
|
|
or eax, eax
|
|
JZ ExceptNotHandled
|
|
|
|
;*
|
|
;* Copy new flags, cs, eip to new stack.
|
|
;*
|
|
|
|
mov ds, [ec.ctx_SegSs]
|
|
mov esi, [ec.ctx_RegEsp] ; ds:esi == new ss:esp
|
|
|
|
mov eax, [ec.ctx_Eflags] ; set up iretd frame
|
|
mov [esi-4], eax
|
|
|
|
mov eax, [ec.ctx_SegCs]
|
|
mov [esi-8], eax
|
|
|
|
mov eax, [ec.ctx_RegEip]
|
|
mov [esi-12], eax
|
|
|
|
;*
|
|
;* Put new stack pointer on stack.
|
|
;*
|
|
|
|
push ds
|
|
sub esi, 12
|
|
push esi
|
|
|
|
;*
|
|
;* Reset other registers.
|
|
;*
|
|
|
|
mov edi, [ec.ctx_RegEdi]
|
|
mov esi, [ec.ctx_RegEsi]
|
|
mov ebx, [ec.ctx_RegEbx]
|
|
mov edx, [ec.ctx_RegEdx]
|
|
mov ecx, [ec.ctx_RegEcx]
|
|
mov eax, [ec.ctx_RegEax]
|
|
mov ds, [ec.ctx_SegDs]
|
|
mov es, [ec.ctx_SegEs]
|
|
mov fs, [ec.ctx_SegFs]
|
|
mov gs, [ec.ctx_SegGs]
|
|
|
|
mov ebp, [ec.ctx_RegEbp] ; must do this last.
|
|
|
|
lss esp, fword ptr [esp] ; reset ss:esp
|
|
|
|
sti ; JWM, 9/3/91
|
|
push [esp+8] ; JWM, 9/6/91
|
|
popfd ; JWM, 9/6/91
|
|
|
|
iretd ; reset flags, cs, eip
|
|
|
|
ExceptNotHandled:
|
|
EmExcept ENDP
|
|
|
|
endif ; ifdef NT386
|
|
|
|
int 3 ; Added For BBT, a return here is needed or BBT
|
|
ret ; has a flow problem.
|
|
ifdef DEBUG
|
|
|
|
lab PageFault
|
|
mov al, byte ptr cs:[iax]
|
|
ret
|
|
endif
|