;       SCCSID = @(#)xcptmisc.asm       6.8 92/02/29
SCCSID  equ "@(#)xcptmisc.asm   6.8 92/02/29"


;***  Change History
;***   noto  11/18/93  Define which segment for Page Tuning DLL   ***
;***                                                              ***


.xlist
INCL_DOSERRORS  equ     1
include bseerr.inc

include mi.inc
include basemaca.inc
include selxport.inc
include infoseg.inc
include dc1segs.inc
include osmaca.inc
include bsexcpt.inc
include bsetib.inc
include dc1mmpha.inc
.list

.386
.387
CpuMode 386

EXTRN32 DOS32IRAISEEXCEPTION
EXTRN32 DOS32IEXITMUSTCOMPLETE
EXTRN32 _xcptUnwindDispatcher
EXTRN   DOS32TIB:ABS


CODE32_TUNE1 SEGMENT DWORD USE32 PUBLIC 'CODE'
CODE32_TUNE1 ENDS
CODE32       SEGMENT DWORD USE32 PUBLIC 'CODE'
CODE32       ENDS



CODE32_TUNE1 segment

        assume  cs:FLAT

?cstype  = ?CS_32bit                            ; Make ArgVar work right

;***EP  Dos32SetExceptionHandler - Register an exception handler
;
;       This API registers the specified exception handler at the
;       beginning of the thread's list of exception handlers.
;
;       INVOKE  push    @dword PEXCEPTIONREGISTRATIONRECORD
;               call    Dos32SetExceptionHandler
;               add     esp,4
;
;       USES    EAX, ECX

;***DT  preDOS32SETEXCEPTIONHANDLER - Dos32SetExceptionHandler pre-invocation trace point
;
;    TRACE MINOR = <RAS_DC1_PRE_DOS32SETEXCEPTIONHANDLER>,
;          TP    = .DOS32SETEXCEPTIONHANDLER,
;          TYPE  = (PRE,API),
;          GROUP = EXMG,
;          DESC  = "(OS) Dos32SetExceptionHandler Pre-Invocation",
;          MEM32 = (FESP+0x04+<C_PARM1>,D,4),
;          FMT   = "ExcHandlerStructAddress = <FMT_C_DWORD>"

;***DT  postDOS32SETEXCEPTIONHANDLER - Dos32SetExceptionHandler post-invocation trace point
;
;    TRACE MINOR = <RAS_DC1_POST_DOS32SETEXCEPTIONHANDLER>,
;          TP    = .postDOS32SETEXCEPTIONHANDLER,
;          TYPE  = (POST,API),
;          GROUP = EXMG,
;          DESC  = "(OS) Dos32SetExceptionHandler Post-Invocation",

Procedure DOS32SETEXCEPTIONHANDLER
        ASSUME  DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING

ArgVar  seh_pERegRec,DWORD      ; Pointer to exception registration record

        EnterProc
        MMPHPreDOSSetExceptionHandler   ; Performance Hook (1C0Bh)
        mov     eax, DOS32TIB           ; Load FS in case user left it
        mov     fs, eax                 ;  in corrupted state

        mov     eax, fs:[tib_pexchain]  ; (EAX) = head of chain
        mov     ecx, seh_pERegRec       ; (ECX) = reg rec
        mov     DWORD PTR [ecx], eax    ; fix reg rec's prev_structure pointer
        mov     fs:[tib_pexchain], ecx  ; fix head of chain
        sub     eax, eax                ; (EAX) = NO_ERROR

        PUBLIC  postDOS32SETEXCEPTIONHANDLER
postDOS32SETEXCEPTIONHANDLER:           ; RAS post-invocation trace
        MMPHPostDOSSetExceptionHandler  ; Performance Hook (1C8Bh)

        LeaveProc
        RETP

EndProc DOS32SETEXCEPTIONHANDLER

;***EP  Dos32UnsetExceptionHandler - Unregister an exception handler
;
;       This API unregisters the specified exception handler from
;       the thread's list of exception handlers.
;
;       INVOKE  push    @dword PEXCEPTIONREGISTRATIONRECORD
;               call    Dos32UnsetExceptionHandler
;               add     esp,4
;
;       USES    EAX, ECX

;***DT  preDOS32UNSETEXCEPTIONHANDLER - Dos32UnsetExceptionHandler pre-invocation trace point
;
;    TRACE MINOR = <RAS_DC1_PRE_DOS32UNSETEXCEPTIONHANDLER>,
;          TP    = .DOS32UNSETEXCEPTIONHANDLER,
;          TYPE  = (PRE,API),
;          GROUP = EXMG,
;          DESC  = "(OS) Dos32UnsetExceptionHandler Pre-Invocation",
;          MEM32 = (FESP+0x04+<C_PARM1>,D,4),
;          FMT   = "ExcHandlerStructAddress = <FMT_C_DWORD>"

;***DT  postDOS32UNSETEXCEPTIONHANDLER - Dos32UnsetExceptionHandler post-invocation trace point
;
;    TRACE MINOR = <RAS_DC1_POST_DOS32UNSETEXCEPTIONHANDLER>,
;          TP    = .postDOS32UNSETEXCEPTIONHANDLER,
;          TYPE  = (POST,API),
;          GROUP = EXMG,
;          DESC  = "(OS) Dos32UnsetExceptionHandler Post-Invocation",
;          <LOG_C_RETVAL>,
;          FMT   = "Return Code = <FMT_C_RETVAL>"

Procedure DOS32UNSETEXCEPTIONHANDLER
        ASSUME  DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING

ArgVar  ueh_pERegRec,DWORD      ; Pointer to exception registration record

        EnterProc
        MMPHPreDOSUnsetExceptionHandler ; Performance Hook (1C0Ch)
        mov     eax, DOS32TIB           ; Load FS in case user left it
        mov     fs, eax                 ;  in corrupted state

        mov     ecx, ueh_pERegRec       ; (ECX) = reg rec
        cmp     ecx, END_OF_CHAIN       ; is reg rec end of chain?
        je      short ueh10             ; yes, return error code

        mov     eax, fs:[tib_pexchain]  ; (EAX) = head of chain
        cmp     eax, END_OF_CHAIN       ; is chain empty?
        je      short ueh10             ; yes, return error code

        cmp     ecx, eax                ; is reg rec head of chain?
        je      short ueh15             ; yes, remove head of chain

ueh5:   cmp     ecx, DWORD PTR [eax]    ; is reg rec next in chain?
        je      short ueh20             ; yes, remove from chain
        mov     eax, DWORD PTR [eax]    ; (EAX) = next reg rec in chain
        cmp     eax, END_OF_CHAIN       ; are we out of reg recs?
        jne     short ueh5              ; no, check next reg rec

ueh10:  mov     eax, ERROR_INVALID_PARAMETER
        jmp     ueh30

ueh15:  call    _xcptRemoveRegistrationHead ; yes, remove head of chain
        jmp     ueh25

ueh20:  mov     ecx, DWORD PTR [ecx]    ; (ECX) = reg rec after next in chain
        mov     DWORD PTR [eax], ecx    ; remove next in chain from chain

ueh25:  sub     eax, eax                ; (EAX) = NO_ERROR

        PUBLIC  postDOS32UNSETEXCEPTIONHANDLER
postDOS32UNSETEXCEPTIONHANDLER:         ; RAS post-invocation trace
ueh30:  MMPHPostDOSUnsetExceptionHandler; Performance Hook (1C8Ch)

        LeaveProc
        RETP

EndProc DOS32UNSETEXCEPTIONHANDLER

CODE32_TUNE1 ends





CODE32 segment

        assume  cs:FLAT


;***EP  Dos32RaiseException - Raise an exception
;
;       This API raises the specified exception.
;
;       INVOKE  push    @dword PEXCEPTIONREPORTRECORD
;               call    Dos32RaiseException
;               add     esp,4
;
;       USES    EAX, ECX, EDX, Flags

;***DT  preDOS32RAISEEXCEPTION - Dos32RaiseException pre-invocation trace point
;
;    TRACE MINOR = <RAS_DC1_PRE_DOS32RAISEEXCEPTION>,
;          TP    = .DOS32RAISEEXCEPTION,
;          TYPE  = (PRE,API),
;          GROUP = EXMG,
;          DESC  = "(OS) Dos32RaiseException Pre-Invocation",

Procedure DOS32RAISEEXCEPTION
        ASSUME  DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING

ArgVar  rex_pERepRec,DWORD      ; Pointer to exception report record

LocalVar rex_Context, <size CONTEXTRECORD>      ; Context record

        EnterProc
        MMPHPreDOSRaiseException        ; Performance Hook (1C0Ah)
;
; Capture the context. The following is assumed:
;       1) Old EBP = [EBP]
;       2) Return address is at [EBP + 4]
;       3) Arguments are cleaned up by the caller

        pushfd
        pop     [rex_Context].ctx_EFlags

        mov     [rex_Context].ContextFlags, CONTEXT_CONTROL or CONTEXT_SEGMENTS or CONTEXT_INTEGER

        mov     [rex_Context].ctx_SegGs, gs
        mov     [rex_Context].ctx_SegFs, fs
        mov     [rex_Context].ctx_SegEs, es
        mov     [rex_Context].ctx_SegDs, ds

        mov     [rex_Context].ctx_RegEax, NO_ERROR
        mov     [rex_Context].ctx_RegEbx, ebx
        mov     [rex_Context].ctx_RegEcx, ecx
        mov     [rex_Context].ctx_RegEdx, edx
        mov     [rex_Context].ctx_RegEsi, esi
        mov     [rex_Context].ctx_RegEdi, edi

        mov     eax, [ebp]
        mov     [rex_Context].ctx_RegEbp, eax
        lea     eax, [ebp + 8]
        mov     [rex_Context].ctx_RegEsp, eax
        mov     eax, [ebp + 4]
        mov     [rex_Context].ctx_RegEip, eax
        mov     [rex_Context].ctx_SegCs, cs
        mov     [rex_Context].ctx_SegSs, ss

        mov     ecx, rex_pERepRec
        mov     eax, [ebp + 4]
        mov     [ecx].ExceptionAddress, eax     ; Fill in exception address
if 1                                                                      ;@SEC
        and     [ecx].fHandlerFlags, EH_NONCONTINUABLE or EH_STACK_INVALID or EH_SIGFTERM ; Mask flags @SEC
else                                                                      ;@SEC
        and     [ecx].fHandlerFlags, EH_NONCONTINUABLE OR EH_STACK_INVALID
endif                                                                     ;@SEC

        lea     eax, [rex_Context]
        CCALL32 DOS32IRAISEEXCEPTION, <ecx, eax>
;
; We'll never actually get here.
;

        LeaveProc
        RETP

EndProc DOS32RAISEEXCEPTION

;***EP  Dos32UnwindException - Unwind exception handlers
;
;       This API unwinds exception handlers
;
;       INVOKE  push    @dword ExceptionReportRecord
;               push    @dword TargetIP
;               push    @dword ExceptionRegistrationRecord
;               call    Dos32UnwindException
;               add     esp,4
;
;       USES    EAX, ECX, EDX, Flags

;***DT  preDOS32UNWINDEXCEPTION - Dos32UnwindException pre-invocation trace point
;
;    TRACE MINOR = <RAS_DC1_PRE_DOS32UNWINDEXCEPTION>,
;          TP    = .DOS32UNWINDEXCEPTION,
;          TYPE  = (PRE,API),
;          GROUP = EXMG,
;          DESC  = "(OS) Dos32UnwindException Pre-Invocation",
;          MEM32 = (FESP+0x04+<C_PARM1>,D,4),
;          FMT   = "ExcHandlerStructAddress = <FMT_C_DWORD>"

Procedure DOS32UNWINDEXCEPTION
        ASSUME  DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING

ArgVar  unx_pERegRec, DWORD
ArgVar  unx_TargetIP, DWORD
ArgVar  unx_pERepRec, DWORD

LocalVar unx_Context, <size CONTEXTRECORD>      ; Context record

        EnterProc
        MMPHPreDOSUnwindException       ; Performance Hook (1C0Dh)
;
; Capture the context. The following is assumed:
;       1) Old EBP = [EBP]
;       2) Return address is at [EBP + 4]
;       3) Arguments are cleaned up by the caller

        pushfd
        pop     [unx_Context].ctx_EFlags

        mov     [unx_Context].ContextFlags, CONTEXT_CONTROL or CONTEXT_INTEGER

        mov     [rex_Context].ctx_RegEax, NO_ERROR
        mov     [rex_Context].ctx_RegEbx, ebx
        mov     [rex_Context].ctx_RegEcx, ecx
        mov     [rex_Context].ctx_RegEdx, edx
        mov     [rex_Context].ctx_RegEsi, esi
        mov     [rex_Context].ctx_RegEdi, edi

        mov     eax, [ebp]
        mov     [unx_Context].ctx_RegEbp, eax
        lea     eax, [ebp + 8]
        mov     [unx_Context].ctx_RegEsp, eax
        mov     eax, [ebp + 4]
        mov     [unx_Context].ctx_RegEip, eax
        mov     [unx_Context].ctx_SegCs, cs
        mov     [unx_Context].ctx_SegSs, ss

        lea     eax, [unx_Context]
        CCALL32 _xcptUnwindDispatcher, <[unx_pERegRec], [unx_TargetIP], [unx_pERepRec], eax>

; If we get here, then EH_STACK_INVALID was set in unx_pERepRec upon entry,
; so return ERROR_INVALID_FUNCTION since we cannot perform an unwind if the
; stack is invalid.

        mov     eax, ERROR_INVALID_FUNCTION

        LeaveProc
        RETP

EndProc DOS32UNWINDEXCEPTION

CODE32 ends





CODE32_TUNE1 segment

        assume  cs:FLAT


;***EP  DOS32ENTERMUSTCOMPLETE - Enter a must complete section
;
;       DOS32ENTERMUSTCOMPLETE is called to enter a must complete section.
;       While in a mustcomplete section, all asyncronous exceptions,
;       signals, and flags will be held. Optimized for NO_ERROR entry.
;
;       ENTRY   pulNesting - Nesting level of MC calls
;
;       EXIT    Success - NO_ERROR
;               Failure - ERROR_NESTING_TOO_DEEP
;
;       USES    EAX, ECX, FLAGS

Procedure DOS32ENTERMUSTCOMPLETE
        ASSUME  DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING

ArgVar  emc_pulNesting, DWORD

        EnterProc
        mov     eax, DOS32TIB           ; Load FS in case user left it
        mov     fs, eax                 ;  in corrupted state

        mov     eax, fs:[tib_ptib2]             ; EAX = pTIB2
        inc     [eax].tib2_usMCCount
        jz      short emc60                     ; Z --> counter wrapped
        mov     ecx, [emc_pulNesting]
        movzx   eax, [eax].tib2_usMCCount
        mov     [ecx], eax                      ; [ECX] = new nesting
        .errnz  (NO_ERROR)
        xor     eax,eax
emc50:  LeaveProc
        RETP

emc60:  dec     [eax].tib2_usMCCount
        mov     eax, ERROR_NESTING_TOO_DEEP
        jmp     short emc50

EndProc DOS32ENTERMUSTCOMPLETE

;***EP  DOS32EXITMUSTCOMPLETE - Exit a must complete section
;
;       DOS32EXITMUSTCOMPLETE is called to leave a must complete section.
;       While in a mustcomplete section, all asyncronous exceptions,
;       signals, and flags will be held. Optimized for exiting must complete
;       section (e.g. MC count going in was 1 and no signals pending).
;
;       ENTRY   pulNesting - Nesting level of MC calls
;
;       EXIT    Success - NO_ERROR
;               Failure - ERROR_ALREADY_RESET
;
;       USES    EAX, ECX, EDX, FLAGS

Procedure DOS32EXITMUSTCOMPLETE

ArgVar  xmc_pulNesting, DWORD

        EnterProc
        mov     eax, DOS32TIB           ; Load FS in case user left it
        mov     fs, eax                 ;  in corrupted state

        mov     ecx, fs:[tib_ptib2]
        sub     [ecx].tib2_usMCCount, 1
        jnz     short xmc50                     ; Z --> exiting MC
        xor     edx,edx
        xchg    dx, [ecx].tib2_fMCForceFlag
        or      edx,edx                         ; NZ --> Signal was sent
        jnz     short xmc40

xmc20:  mov     edx, [xmc_pulNesting]
        movzx   eax, [ecx].tib2_usMCCount
        mov     [edx], eax                      ; [edx] = New MC Count
        .errnz  (NO_ERROR)
        xor     eax, eax

xmc30:  LeaveProc
        RETP

xmc40:  CCALL32 DOS32IEXITMUSTCOMPLETE
        jmp     short xmc20

xmc50:  jnc     short xmc20                     ; NC --> Prev value > 0
        inc     [ecx].tib2_usMCCount
        mov     eax, ERROR_ALREADY_RESET
        jmp     short xmc30

EndProc DOS32EXITMUSTCOMPLETE

CODE32_TUNE1 ends




CODE32 segment

        assume  cs:FLAT

;***LP  _xcptGetRegistrationHead - Get first registration record from TIB.
;
;       _xcptGetRegistrationHead looks at FS:[tib_pexchain] to find
;       the first exception registration record.
;
;       ENTRY   none
;
;       EXIT    Success - EAX = FS:[tib_pexchain]
;
;       USES    EAX
;
;       NOTES   Loads FS before using it just in case exception occurred
;               while user had something other than base of TIB in it.

Procedure _xcptGetRegistrationHead

        mov     eax, DOS32TIB           ; Load FS in case user left it
        mov     fs, eax                 ;  in corrupted state

        mov     eax, fs:[tib_pexchain]
        RETC

EndProc _xcptGetRegistrationHead

;***LP  _xcptGetStackLimits - Retrieve stack limits from the TIB
;
;       ENTRY   gsl_pHigh - Pointer to store High limit in
;               gsl_pLow  - Pointer to store Low limit in
;
;       EXIT    none
;
;       USES    EAX, EBX
;
;       NOTES   Loads FS before using it just in case exception occurred
;               while user had something other than base of TIB in it.

Procedure _xcptGetStackLimits

ArgVar gsl_pHigh, DWORD
ArgVar gsl_pLow, DWORD

        EnterProc
        mov     eax, DOS32TIB           ; Load FS in case user left it
        mov     fs, eax                 ;  in corrupted state

        mov     eax, [gsl_pHigh]
        mov     ebx, fs:[tib_pstacklimit]
        mov     [eax], ebx
        mov     eax, [gsl_pLow]
        mov     ebx, fs:[tib_pstack]
        mov     [eax], ebx

        LeaveProc
        RETC

EndProc _xcptGetStackLimits

CODE32 ends





CODE32_TUNE1 segment

        assume  cs:FLAT

;***LP  _xcptRemoveRegistrationHead - Remove 1 Exception Handler
;
;       _xcptRemoveRegistrationHead removes the first exception handler.
;       No checking is done to verify there is an EH to remove.
;
;       ENTRY   none
;
;       EXIT    Success - Pointer to the next registration head
;
;       USES    eax

Procedure _xcptRemoveRegistrationHead

        mov     eax, DOS32TIB           ; Load FS in case user left it
        mov     fs, eax                 ;  in corrupted state

        mov     eax, fs:[tib_pexchain]
        mov     eax, [eax].prev_structure
        mov     fs:[tib_pexchain], eax
        RETC

EndProc _xcptRemoveRegistrationHead

CODE32_TUNE1 ends




CODE32 segment

        assume  cs:FLAT

;***EP  DOS32R3FRESTOR - Trampoline code for doing an FRESTOR
;
;       We have to do this from R3 because of the emulator.
;
;       ENTRY   iret frame
;               frs_env    - The floating point environment/stack (108 bytes)

Procedure DOS32R3FRESTOR

ArgVar frs_env, 108                             ; The full FP Environment

        SaveReg <eax>

        lea     eax, [esp + 4]
        frstor  [eax]

        RestoreReg <eax>

        add     esp, 108                        ; Remove argument
        pop     gs                              ; Restore selectors
        pop     fs
        pop     es
        pop     ds
        lss     esp, [esp]                      ; Switch stacks?

        iretd

EndProc DOS32R3FRESTOR

CODE32 ends


END
