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 OldCS EQU OldFlags EQU 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, stdCall _RtlRaiseStatus, 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 ifdef DEBUG lab PageFault mov al, byte ptr cs:[iax] ret endif