;       SCCSID = @(#)trap286.asm        6.9 91/11/14
PAGE    ,132
NAME    trap286
TITLE   Exception and Interrupt Handlers for Protected Mode
.386
.287

SCCSID  equ     "@(#)trap286.asm        6.9 91/11/14"

;***    TRAP286 - OLD TRAP CODE SEE TRAP.ASM
;
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved

.xlist
        include dosseg.inc
        include dossymc.inc
        include basemaca.inc
        include fnotask.inc
        include osmaca.inc
        include osconst.inc
        include protmode.inc
        include seldesc.inc
        include except.inc
        include vmowner.inc
        include exec.inc
        include timer.inc
        include harderr.inc
        include proc.inc
        include mi.inc
        include error.inc
        include basemid.inc
        include kmode.inc
        include pgexport.inc
        include vmexport.inc
        include tkexport.inc
        include bsexcpt.inc
        include infoseg.inc
        include curdir.inc
        include dirent.inc
        include screen.inc
        include sem.inc
        include find.inc
        include sigdef.inc
        include tkptda.inc
.list

        ModName  , FNO_TRAP286_ASM
        CpuMode 386

        ReferGlobal     InDos,BYTE
        ReferGlobal     TaskNumber,WORD
        ReferGlobal     InterruptLevel
        ReferGlobal     ABIOS_present,BYTE

if RAS
        ReferGlobal     DUMP_ON,BYTE            ; DUMP
endif

        ReferGlobal     mathCop,BYTE
        ReferGlobal     NPX_Owner,WORD
        ReferGlobal     _SuppressPopUps,BYTE
        ReferGlobal     _PopUpLogDrive,BYTE     ; 157614
        ReferGlobal     _InitCodeInvalid

        ReferFlat       _pPTDACur,DWORD
        ReferFlat       _pTCBCur,DWORD
        ReferFlat       Int21Vec,QWORD


        EXTRN           Clear_Kernel_Sem:NEAR
        EXTRN           ChkHEDaemon:NEAR
        EXTRN           OutMessage:NEAR

if RAS
        EXTRN           RASRST:FAR                       ; DUMP
endif ;RAS

        EXTRN           Take_Kernel_Sem:NEAR
        EXTRN32         _TKUpdateLocalFPHandler
        EXTRN32         _XCPTBuildR3DispatcherStack
        EXTRN32         WaitNPX
        EXTRN32         SaveNPX

        EXTRNFAR        FuByteNF
        EXTRNFAR        FuWordNF
        EXTRNFAR        WrtToScrn
        EXTRNFAR        HexToAscii
        EXTRNFAR        ByteToAscii
        EXTRNFAR        StrLen
        EXTRNFAR        StrLen32
        EXTRNFAR        GetTempBuffer
        EXTRNFAR        FreeTempBuffer
        EXTRNFAR        HardError

        EXTRN32         KMQUERYCLIENTREGISTER
        EXTRN32         _TKDieSoonPTDA
        EXTRN32         _VMAllocKHB
        EXTRN32         _VMFreeKHB
        EXTRN32         _PDLogPopUp
        EXTRN32         _SELConvertToLaddr                 ;           86278
        EXTRN32         _SELVirtToLin
ifdef PMDEBUG
        EXTRN32         _TKDebugHardError
endif

DATA segment

;*   Register dump message

CrLfMsg         label   byte
        db      c_CR, c_LF
CrLfMsgLen      equ     $ - CrLfMsg

RegMsg2         label   byte

        db      'CS='
CSval   db      'XXXX '

        db      'IP='
IPval   db      'XXXX '

        db      'SS='
SSval   db      'XXXX '

        db      'SP='
SPval   db      'XXXX '

RegMsg2Len      equ     $ - RegMsg2

RegMsg3         label   byte

        db      'ERRCD='
ERRCval db      'XXXX '

        db      'ERLIM='
ERRClim db      'XXXX '

        db      'ERACC='
ERRCacc db      'XX'

RegMsg3Len      equ     $ - RegMsg3


;*   User argument fault dump format table


UsrArgFaultTable        label   word
        dw      TSDUserSS, offset DOSGROUP:SSval
        dw      TSDUserESP, offset DOSGROUP:SPval
        dw      TSDerrcFault, offset DOSGROUP:ERRCval
UsrArgFaultTableLen     equ     ($ - UsrArgFaultTable)/4

UsrArgFaultTable2       label   word
        dw      Segmt32, offset DOSGROUP:CSval
        dw      Offst32, offset DOSGROUP:IPval
UsrArgFaultTableLen2    equ     ($ - UsrArgFaultTable2)/4

UsrArgFaultLimAcc       label   word
        dw      TSDerrcFault
        dw      offset DOSGROUP:ERRCacc
        dw      offset DOSGROUP:ERRClim
UsrArgFaultLimAccLen    equ     ($ - UsrArgFaultLimAcc)/4


;*   Exc_Lookup look up table

ExcTable        label   byte
        .errnz  (($ - ExcTable) - EXCDIVZI)
        db      EXCDIVZ         ; Divide-by-zero exception
        .errnz  (($ - ExcTable) - EXCOVI)
        db      EXCOV           ; Overflow exception (INTO)
        .errnz  (($ - ExcTable) - EXCBOUNDI)
        db      EXCBOUND        ; Bound exception
        .errnz  (($ - ExcTable) - EXCOPI)
        db      EXCOP           ; Invalid opcode
        .errnz  (($ - ExcTable) - EXCNOFPI)
        db      EXCNOFP         ; Floating point processor not present
        .errnz  (($ - ExcTable) - EXCFPERRI)
        db      EXCFPERR        ; Processor extension error
        .errnz  (($ - ExcTable) - EXCDOSI)
        db      EXCDOS          ; DOS API interrupt
        .errnz  (($ - ExcTable) - EXCUSR)

DATA ends

          FARCODE HIGH3
HIGH3CODE SEGMENT

;***    w_SetVec - worker for DOSSETVEC
;
;       This function takes as its arguments an exception number
;       and a handler address.  It verifies that the exception
;       number is valid.  If the exception number is valid and
;       the exception handler address is non-zero, it causes
;       all such exceptions caused by the current process to be
;       routed to the handler.  If the exception number is valid
;       and the address is zero, it causes all such exceptions
;       to receive default processing, i.e., the process that
;       caused the exception is terminated.
;
;       If the exception handler that is being installed is for
;       numeric processor not present exceptions then we adjust
;       the MSW to make it look like we do not have a NPX. We do
;       this independant of what the hardware really is.
;
;       If we are deinstalling the NPX Not Present exception handler,
;       then we reset the MSW to reflect the true state of the machine.
;
;       ENTRY   (AX) = VecNum - exception number
;               (CX:BX) = RtnAddress - handler address
;
;       EXIT    Carry set
;                   (AX) = error_invalid_function
;               Carry clear
;                   (DX:AX) = previous exception handler
;
;       USES    EAX, BX, ECX, EDX, DI, SI, DS, ES, Flags

Procedure w_SetVec,faronly
        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA

        or      ah,ah                   ; Above 255?
        stc                             ;  (assume yes)
        jnz     wsv3                    ;  yes, return error
        mov     si,cx                   ; (SI:BX) = new handler address
        push    ax
        call    Exc_Lookup              ; (DX:AX) = old handler address
        pop     cx                      ; (CX) = exception number
        jc      wsv3                    ;  error if invalid exception number
        test    si,RPL_CLR              ; Null selector?
        jz      short wsv1              ;  yes, don't bother to check it

;       Check that we've been passed a ring 3 selector

        push    si                      ; save passed selctor
        and     si,RPL_MASK             ; mask down to rpl bits
        cmp     si,RPL_RING3            ; is it ring 3 selector?
        pop     si                      ; restore handler selector
        jne     short wsv2              ; If not ring 3, go to error

;       Update handler table and check for special cases

wsv1:   mov     es:[edi].Segmt,si       ; Set new handler address
        mov     es:[edi].Offst,bx
;d82549 cmp     cx,EXCNOFP              ; FP not present handler?
;       je      short wsv4              ;  yes, special case
        cmp     cx,EXCDOS               ; DOS API (int 21h)?
        je      wsv8                    ;  yes, special case
        clc                             ; No error
        ret

wsv2:   mov     ax,ERROR_PROTECTION_VIOLATION
        stc
        ret

wsv3:   mov     ax,ERROR_INVALID_FUNCTION
        ret

;       DosSetVec(7, ...) special case

;d82549
;wsv4:   push    dx                      ; Save old vector
;        push    ax
;
;        test    si,RPL_CLR              ; Installing a handler?
;        jz      short wsv6              ;  no, skip ahead
;
;;       Installing handler, turn MP off and EM on
;
;        FlatContext <ds,es>,ax
;        CCALL32 WaitNPX,,nocall         ; wait for NPX to finish
;        DosContext <ds,es>,ax
;        mov     ax,TaskNumber
;        cmp     ax,NPX_Owner            ; Current thread own NPX?
;        jne     short wsv5              ;  no, skip ahead
;        FlatContext <ds,es>,ax
;        CCALL32 SaveNPX,,nocall         ; save NPX context
;        DosContext <ds,es>,ax
;
;wsv5:   smsw    ax                      ; get MSW
;        and     ax,NOT MSW_MP           ; turn MP off
;        or      ax,MSW_EM               ; turn EM on
;        lmsw    ax                      ; load MSW
;        jmp     short wsv7
;
;;       Deinstalling handler, turn EM off and MP on if NPX exists
;
;wsv6:   DosContext ds
;        cmp     mathCop,0               ; Does NPX really exist?
;        je      short wsv7              ;  no, skip ahead
;        smsw    ax                      ; get MSW
;        and     ax,not MSW_EM           ; turn EM off
;        or      ax,MSW_MP+MSW_TS        ; turn MP, TS on
;        lmsw    ax                      ; load MSW
;
;;       Update emulator data area
;
;wsv7:   call    Take_Kernel_Sem         ; This operation must be serialized
;        jc      short wsv7              ; Don't take no for an answer!
;        FlatContext <ds,es>,ax
;        CCALL32 _TKUpdateLocalFPHandler,,nocall ; Update emulator data
;    ASSUME      DS:NOTHING, ES:NOTHING
;        pop     ax
;        pop     dx
;        call    Clear_Kernel_Sem        ; Release semaphore
;        clc
;        ret

;       DosSetVec(21, ...) special case

wsv8:   FlatContext ds,cx               ; Update IDT now
        mov     [Int21Vec].g_sel,si
        mov     [Int21Vec].g_lowoffset,bx
        ret                             ; carry is already clear
    ASSUME DS:nothing
EndProc w_SetVec


;***    Exc_Lookup - Look up a handler for a particular exception
;
;       Given an exception number, return the vector for that
;       exception for the current process.
;
;       ENTRY   (AL) = exception number
;               (SS) = PTDA of current task
;
;       EXIT    Direction flag clear
;               Carry set
;                   Invalid exception number
;               Carry clear
;                   (DX:AX) = handler address
;                   (ES:EDI) = pointer to slot in handler address table
;                   Zero set
;                       No handler
;
;       USES    AX, CX, DX, DI, ES, Flags
;
        ASSUME DS:NOTHING, ES:NOTHING, SS:TASKAREA

Procedure Exc_Lookup

        DosContext es
        mov     di,offset DOSGROUP:ExcTable ; Make ES:DI point to table
        mov     cx,EXCUSR               ; Put table length in CX
        cld                             ; To be safe
        repne scasb                     ; Search for match
        stc                             ; Assume no match
        jne     el0                     ; Exit if no match
        sub     di,offset DOSGROUP:ExcTable+1 ; Convert offset to index
        shl     di,2                    ; Scale to DWORD index
        movzx   edi,di
        add     edi,offset Exc_vec      ; SS:DI points into handler table
        FlatContext es
        SaveReg <esi>
        mov     esi,es:[_pPTDACur]
        mov     ax,es:[esi+edi].Offst   ; Put handler address in DX:AX
        mov     dx,es:[esi+edi].Segmt
        add     edi,esi
        RestoreReg <esi>
        mov     cx,ax                   ; Set ZF appropriately
        or      cx,dx                   ; (OR clears carry)
el0:    ret

EndProc Exc_Lookup


;***    UsrArgFault - handle GP fault caused by bad user argument
;***    UsrArgFaultMsg - handle GP fault caused by bad user argument
;
;       UsrArgFault gains control when a GP fault occurs in kernel mode
;       due to a faulty user argument.  (We're blaming the user process
;       for the fault.)
;
;       UsrArgFaultMsg is exactly like UsrArgFault exept the caller
;       passes in a messsage number in AX.
;
;       We print data to locate what system call died and with what
;       arguments.
;
;       ENTRY:  (TSDerrcFault) = error code to display
;               (TSDCSEIPPtr) = offset to user's CS:EIP
;               (TSDUserSS:TSDUserESP) = user's SS:ESP
;               (TSDParmBytes) = number of user arguments
;               if UsrArgFaultMsg
;                       AX = message number (Must be in EXACTLY same form
;                       as MSG_GEN_PROT_FAULT.)
;
;       EXIT:   NONE
;
;       USES:   AX, BX, CX, DX, SI, DI, DS, ES, Flags
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA

Procedure UsrArgFault,<hybrid,far16>
LocalVar uaf_exceptioninfo, 8

        EnterProc

        FlatContext <ds, es>, ax
        SSToDS  eax, [uaf_exceptioninfo]
        mov     dword ptr [eax], XCPT_UNKNOWN_ACCESS
        mov     dword ptr [eax + 4], XCPT_DATA_UNKNOWN
        CCALL32 _XCPTBuildR3DispatcherStack, <EXCGP, XCPT_ACCESS_VIOLATION, 2, eax, 0, 0>

        LeaveProc
        RETC

EndProc UsrArgFault

Procedure UsrArgFaultMsg,hybrid         ; second entry point AX == msg number
LocalVar  msgnum,WORD
LocalVar  uaf_cseip,QWORD
LocalVar  uaf_tempbuf,150

;       PMONLY

        EnterProc                       ; (BP) = stack frame pointer
        mov     msgnum,ax               ; save the message number

;       Format the user's CS:IP and SS:SP and the error code.
;       TCBUserEIPExcpt, TCBUserCSExcpt is also used by the SimulateFault
;       routine for other purposes.

        FlatContext <ds,es>,ax
        SSToDS  edi,[uaf_cseip.Offst32]
        CCALL32 KMQUERYCLIENTREGISTER,<_pTCBCur,KM_REG_EIP,edi>,,pascal
        or      eax,eax
        jnz     uaf4

        SSToDS  edi,[uaf_cseip.Segmt32]
        CCALL32 KMQUERYCLIENTREGISTER,<_pTCBCur,KM_REG_CS,edi>,,pascal
        or      eax,eax
        jnz     uaf4

        push    bp
        DosContext <ds,es>,ax

        lea     bp,[uaf_cseip]          ; (BP) = offset to CS:EIP
        mov     si,offset DOSGROUP:UsrArgFaultTable2
        mov     cx,UsrArgFaultTableLen2

;       (BP) = offset to variables used in format table in TSD
;       (ES) = segment that message being formated is in
;       (DS:SI) = register dump table
;       (CX) = length of table

        call    FormatRegDump           ; put register contents in buffer

        SaveReg <ds,esi>
        FlatContext ds
        mov     esi,_pPTDACur
        mov     bp,ds:[esi].CurrTSD     ; (BP) = current TSD pointer
        RestoreReg <esi,ds>
        DosContext ds

        mov     si,offset DOSGROUP:UsrArgFaultTable
        mov     cx,UsrArgFaultTableLen

;       (BP) = offset to variables used in format table in TCB
;       (ES) = segment that message being formated is in
;       (DS:SI) = register dump table
;       (CX) = length of table

        call    FormatRegDump           ; put register contents in buffer

        mov     si,offset DOSGROUP:UsrArgFaultLimAcc
        mov     cx,UsrArgFaultLimAccLen

;       (BP) = offset to variables used in format table in TSD
;       (ES) = segment that message being formated is in
;       (DS:SI) = limit/access dump table
;       (CX) = length of table

        call    FormatLimAccDump        ; put the limit/access byte values in
        pop     bp                      ; (BP) = stack frame pointer

        TaskContext es                  ; (ES:DI) = replacement string buffer
        lea     di,uaf_tempbuf
        mov     si,offset DOSGROUP:RegMsg2
        mov     cx,RegMsg2Len
B1EMac  rep movsb                       ; copy formated string into temp buffer

        mov     al,c_CR                 ; put a crlf into buffer
B1EMac  stosb
        mov     al,c_LF
B1EMac  stosb

        mov     si,offset DOSGROUP:RegMsg3
        mov     cx,RegMsg3Len
B1EMac  rep movsb                       ; copy formated string into temp buffer

        xor     al,al                   ; null terminate first string
B1EMac  stosb

;       Format the user's stack arguments from high to low

        SaveReg <ds,esi>
        FlatContext ds
        mov     esi,_pPTDACur
        mov     bx,ds:[esi].CurrTSD     ; *** install a local GP fault handler
        RestoreReg <esi,ds>
        mov     word ptr ss:[bx].TSDpfnFault,offset DOSHIGH3CODE:uaf3

        SaveReg <ds,es>                 ; Get Parambytes
        FlatContext <ds,es>,ecx
        SSToDS  ecx,[uaf_cseip]
        CCALL32 KMQUERYCLIENTREGISTER,<_pTCBCur,KM_REG_CBARGS,ecx>,,pascal
        or      eax,eax
        jnz     uaf4
        mov     ecx,dword ptr [uaf_cseip]
        RestoreReg  <es,ds>

        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA

        lds     esi,fword ptr ss:[bx].TSDUserESP

;       (DS:SI) = user's stack pointer

        add     si,cx                   ; start at high argument on stack
        dec     si
        dec     si
        shr     cx,1                    ; (CX) = words of parameters
        mov     dx,10

;       (DS:SI) = user's stack pointer - number of parameters bytes
;       (ES:DI) = temporary buffer to put the hex strings
;       (CX) = number of arguments to print
;       (DX) = arguments to print on first line because more
;              than 12 won't fit on the hard error screen.

        jcxz    uaf3                    ; (CX == 0) -> done

uaf1:   std
        lodsw                           ; (AX) = stack argument
        cld

        CALLFAR HexToAscii              ; format one argument word

        mov     al,' '
B1EMac  stosb                           ; put a space into buffer

        dec     dx                      ; do we need to print a crlf
        jnz     uaf2

        mov     al,c_CR                 ; put a crlf at the end
B1EMac  stosb
        mov     al,c_LF
B1EMac  stosb

uaf2:   loop    uaf1

;       We get here if:
;       (1) we exit the loop normally, or
;       (2) we fault while reading the user's stack.
;
;       (SS:BX) = pointer to current TSD

uaf3:   cld                             ; We could have faulted on LODSW above
        mov     word ptr ss:[bx].TSDpfnFault,0 ; Remove local GP fault handler

        TaskContext es                  ; (ES:DI) = replacement string buffer
        xor     al,al                   ; null terminate second string
B1EMac  stosb

        TaskContext ds
        lea     si,uaf_tempbuf          ; (DS:SI) = replacement strings

        mov     cx,2                    ; two argument strings in this message
        mov     dx,msgnum               ; message number
        mov     bx,EXCGP                ; GP fault number is the return code
        mov     ax,TC_GP_TRAP           ; exit type is GP fault
        xor     edi,edi                 ; No exception record

;       (AX) = exit type
;       (BX) = return code/fault number
;       (CX) = number of replacement strings
;       (DX) = message number
;       (DS:SI) = pointer to replacement strings

        call    DelayHardErr            ; generate harderr when process is dead
        LeaveProc
        ret
uaf4:   Panic   "UsrArgFault"
EndProc   UsrArgFaultMsg


;***    FormatRegDump - format the register dump string.
;
;       Formats the register dump string.
;
;       ENTRY:  BP = base pointer for offsets in the format table
;               CX = length of table
;               ES = segment that message being formatted is in
;               DS:SI = register dump table, in this format:
;
;               dw      offset relative to BP of data to be printed
;               dw      offset of the place to put hex string relative to ES
;
;       EXIT:   NONE
;
;       USES:   AX, CX, DX, SI, DI, Flags
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA

Procedure FormatRegDump,near,local

frd1:   lodsw                           ; (AX) = offset of value
        mov     di,ax
        mov     dx,[bp+di]              ; (DX) = register value
        lodsw                           ; (AX) = offset to put value
        mov     di,ax                   ; (ES:DI) = offset to put value
        mov     ax,dx                   ; (AX) = value to covert to hex
        CALLFAR HexToAscii
        loop    frd1
        ret

EndProc   FormatRegDump


;***    FormatLimAccDump - format the limit and access byte dump string.
;
;       Formats the limit and access byte dump string for the user's
;       segment.
;
;       ENTRY:  BP = base pointer for offsets in the format table
;               CX = length of table
;               ES = segment that message being formatted is in
;               DS:SI = segment limit/access dump table, in this format:
;
;               dw      offset relative to BP of segment
;               dw      offset of the place to put access byte hex string
;               dw      offset of the place to put limit hex string
;
;       EXIT:   NONE
;
;       USES:   AX, CX, DX, SI, DI, Flags
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA

Procedure FormatLimAccDump,near,local

fla1:   lodsw                           ; (AX) = offset of segment
        mov     di,ax
        mov     dx,[bp+di]              ; (DX) = segment value

        lodsw                           ; (AX) = offset to put access byte str
        mov     di,ax                   ; (ES:DI) = offset to put acc byte str

        xor     ax,ax                   ; if segment invalid, access byte == 0
        LOADAR  ax,dx                   ; (AH) = access byte of segment
        jnz     fla2

        mov     al,ah
        CALLFAR ByteToAscii             ; convert to hex and put in the string
        jmp     short fla3

fla2:   mov     ax,'**'                 ; "**" means bad segment
B1EMac  stosw

fla3:   lodsw                           ; (AX) = offset to put limit hex string
        mov     di,ax                   ; (ES:DI) = offset to put limit hex str
        LOADSL  ax,dx                   ; (AX) = limit of segment
        jnz     fla4                    ; jump if segment is invalid

        CALLFAR HexToAscii              ; convert to hex and put in the string
        jmp     short fla5

fla4:   mov     ax,'**'                 ; "****" means bad segment
        stosw
B1EMac  stosw

fla5:   loop    fla1
        ret

EndProc   FormatLimAccDump

;***    DelayHardErrTrap2 - Delay hard error until actual process death
;
;       See DelayHardErrSub Below

 Procedure DelayHardErrTrap2,<near,far16>
         push    edi
         xor     edi,edi                         ; No exception record
         call    DelayHardErrSub
         ret
 EndProc DelayHardErrTrap2

;***    DelayHardErr - Delay hard error until actual process death
;
;       See DelayHardErrSub Below

Procedure DelayHardErr,<near,far16>
        SaveReg <es>
        FlatContext ES
        push    dword ptr es:[_pPTDACur]
        call    DelayHardErrSub
        RestoreReg <es>
        ret
EndProc DelayHardErr

;***    DelayHardErrSub - Delay hard error until actual process death
;                         if SuppressPopUps is not enabled
;
;       1)  If SUPPRESSPOPUPS are ENABLED                              86278
;           Saves the hard error information in the popup log          86278
;           before the process's exit list routines are called         86278
;           and it's resources have gone away.                         86278
;
;           157614 changes SuppressPopUps in the following way:              
;           By default logging is active. SuppressPopUps now controls only   
;           the suppression of the PopUp. PopUpLogDrive controls the logging.
;           PopUpLogDrive is set to an initial value of 2 to indicate that   
;           PopUpLogDrive should be initialised to the Boot Drive. Having    
;           called the logging function once, PopUpLogDrive is converted to  
;           the boot drive. Thereafter DosSuppressPopUps controls these      
;           values. A special value of SUPPRESSPOPUPS=0 will force           
;           the original behaviour with logging disabled and popups enabled. 
;
;       2)  Saves the hard error information away until the process's
;           exit list routines are called and it's resources have gone
;           away.
;
;       This is done for the session manager/hard error daemon
;       because the process dieing because of an GP hard error may
;       own resources that are needed to display the hard error popup.
;       If another GP fault happens while there is a pending GP fault,
;       the second GP is ignored. This should only happen if a GP fault
;       happens in a exit list handler called because the process GP
;       faulted.
;
;       NOTE: It is up to the caller to make sure the replacement strings
;             will fit in a temporary buffer.
;
;       NOTE: If the TrapDump=yes command was used in config.sys,
;             the stand-alone dump is automatically given control.
;             This is due to the fact that the process is cleaned
;             up before the hard error is displayed.
;
;       NOTE: If there is not enough memory available to allocate the
;             packet buffer, SavedHardErr is set to -1.  This alerts
;             ChkDelayHardErr to display the MSG_NO_NEEDED_RESOURCES
;             message.
;
;       ENTRY   (AX) = Termination Type for TKDieSoonPTDA
;               (BX) = Return Code for TKDieSoonPTDA
;               (CX) = number of replacement strings
;               (DX) = message number
;               (EDI) = ptr to optional exception report record
;               (DS:SI) = pointer to replacement strings
;               (SS:ESP+2) = PTDA to use
;
;       EXIT    NONE
;
;       USES    EAX, EBX, CX, SI, EDI, DS, ES, Flags

Procedure DelayHardErrSub
        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA

        ArgVar   dhe_pptda,DWORD

        LocalVar dhe_bufptr,DWORD       ; FLAT address of packet buffer
        LocalVar dhe_termtype, DWORD    ; Termination Type
        LocalVar dhe_retcode, DWORD     ; Return Code
        LocalVar dhe_pERepRec, DWORD    ; Exception Report Record
        LocalVar dhe_msgstring,WORD     ; message string offset

        EnterProc

        movzx   eax, ax
        mov     [dhe_termtype], eax
        movzx   ebx, bx
        mov     [dhe_retcode], ebx
        mov     [dhe_pERepRec], edi

; If popup logging is enabled, log the popup information.  157614
;                                                                      86278
pop00:  pushad                          ; push all registers           86278
        push    ds                      ; push selector register       86278
        DosContext ds                   ;                              86278


        mov     al,_PopUpLogDrive       ; Has the user left every thing 157614
        cmp     al,2                    ; to default ?                  157614
        jz      pop01                   ;                               157614

        mov     al,_PopUpLogDrive       ; drive letter for log file     157614
        cmp     al,0                    ; popup logging enabled?        157614
        je      pop20                   ; No, skip logging to a file   86278


pop01:  pop     ds                      ; Get DS value back from stack 86278
        push    ds                      ; put it back on stack so      86278
    assume ds:nothing                   ;   POP DS works below         86278
                                        ;                              86278
        push    edx                     ; save edx                     86278
        push    ecx                     ; save ecx                     86278
        mov     ax,ds                   ; to convert to linear address 86278
        movzx   eax,ax                  ; zero out high word of eax    86278
        FlatContext <ds,es>             ; 32-bit context               86278

;105043 - modified/rearranged next few lines starting here
        movzx   esi,si                  ; Offset of repacement string  86278
        CCALL32 _SELVirtToLin <esi, eax>; eax = laddr = SELVirtToLin(offset,sel)
        pop     ecx                     ; restore ecx                  86278
        pop     edx                     ; restore edx                  86278
IFDEF MISCSTRICT                        ;                              86278
        cmp     eax,-1                  ;       ; error ?              86278
        jne     pop05                   ;                              86278
        InternalError   <DelayHardErrSub: invalid message pointer?>
ENDIF                                   ;                              86278
pop05:                                  ; eax=base address of selector 86278
        movzx   edx, dx                 ; Message Number for Trap      86278
        movzx   ecx, cx                 ; Num of replacement Strings   86278
                                        ;                              86278
        FlatContext <ds,es>             ; FlatSelectors for calling    86278
        CCALL32 _PDLogPopUp <edx,ecx,eax> ; Log Popup to a file        86278
;105043 - end of modifications
                                        ;                              86278
    assume ds:nothing                   ;                              86278
    assume es:nothing                   ;                              86278
                                        ;                              86278
pop20:                                  ;                              86278
        pop     ds                      ; pop  selector register       86278
        popad                           ; pop all registers            86278
                                        ;                              86278
; End popup suppression code                                           86278

;       Stand-alone Dump check in case of a Trap

IF RAS
        push    ds                      ; save DS
        DosContext ds                   ; DUMP check
        cmp     DUMP_ON,1               ; Ring 3 DUMP wanted?    ##F78693
        jne     dhe00                   ; No DUMP                ##F78693
        call    RASRST                  ; Dump it
dhe00:  pop     ds                      ; Restore ds
    assume ds:nothing

ENDIF
ifdef PMDEBUG
        push    ds
        push    es
        pushad
        mov     di,ds
        FlatContext <ds,es>,ax
        jcxz    short dhe04

;       eax=laddr = _SELVirtToLin(offset, selector)

        push    cx
        push    dx
        movzx   esi,si
        CCALL32 _SELVirtToLin <esi, edi>
        pop     dx
        pop     cx
        cmp     eax,-1
        jz      short dhe05

;       _TKDebugHardError(# of strings, msg #, pointer to strings)

dhe04:  movzx   ecx,cx
        movzx   edx,dx
        CCALL32 _TKDebugHardError <ecx, edx, eax>
dhe05:  popad
        pop     es
        pop     ds
    assume ds:nothing, es:nothing
endif

        SaveReg <esi,ds>
        FlatContext DS
        mov     esi,dhe_pptda
        cmp     [esi].SavedHardErr,0    ; Is there a delayed harderr pending?
        RestoreReg <ds,esi>
    assume ds:nothing
        jne     short dhe50             ;  yes, skip ahead

;       Determine size of buffer needed

        push    si
        jcxz    short dhe20             ; Skip ahead if no strings
        push    cx
dhe10:  lodsb                           ; (AL) = string byte
        or      al,al                   ; End of string?
        jne     short dhe10             ;  no, keep looking
        loop    dhe10                   ; Loop if there are more strings
        pop     cx
dhe20:  mov     ax,si                   ; (DS:AX) = byte after last string
        pop     si
        sub     ax,si                   ; (AX) = size of strings
        add     ax,4                    ; Add in size of header (BUGBUG: struc)

;       Allocate buffer for hard error packet
;
;       (AX) = size of packet needed
;       (CX) = number of message strings
;       (DX) = message number
;       (DS:SI) = pointer to message strings

        SaveReg <cx, dx>
        push    ds
        FlatContext <ds,es>,cx          ; (DS) = (ES) = R0DS
        lea     ecx,dhe_bufptr
        SSToDS  ecx                     ; (ECX) = offset of loc for pointer
        movzx   eax,ax                  ; (EAX) = size of buffer
        CCALL32 _VMAllocKHB <VM_HKH_PUB_RESRW, eax, TRAPHEOWNER, 0, ecx>
                                        ; Allocate buffer
        mov     dhe_msgstring,si
        mov     esi,dhe_pptda
        or      eax,eax                 ; Successful?
        .errnz  NO_ERROR
        jz      short dhe30             ;  yes, skip ahead
        mov     ds:[esi].SavedHardErr,-1   ; Save indication of no memory for buf
        jmp     short dhe50
dhe30:  mov     edi,dhe_bufptr          ; (ES:EDI) = buffer
        mov     ds:[esi].SavedHardErr,edi  ; Save pointer to buffer
        pop     ds
    ASSUME      DS:NOTHING
        RestoreReg <dx, cx>

;       Format hard error packet
;
;       (CX) = number of message strings
;       (DX) = message number
;       (DS:SI) = pointer to message strings
;       (ES:EDI) = pointer to hard error packet

        mov     si,dhe_msgstring
        mov     ax,dx                   ; save message number
B1EMac  stos    word ptr es:[edi]
        mov     ax,cx                   ; save number of replacement strings
B1EMac  stos    word ptr es:[edi]
        jcxz    dhe50                   ; copy argument strings
dhe40:  lodsb
B1EMac  stos    byte ptr es:[edi]       ; copy each argument string
        or      al,al
        jnz     short dhe40
        loop    dhe40                   ; next argument string

;       Set a bit in the PTDA's AutoFail field to indicate whether extended
;       information (register dump, module name, etc.) is available.

dhe50:  FlatContext <ds,es>
        mov     edi,[dhe_pptda]         ; (EDI) = pointer to PTDA
        and     ds:[edi].AutoFail,NOT DOSERR_EXTENDEDERR ; assume no reg dump
        mov     eax,[dhe_pERepRec]      ; (EAX) = pointer to xcpt report rec
        or      eax,eax                 ; does xcpt report rec exist?
        jz      short dhe60             ; no, leave bit clear
        or      ds:[edi].AutoFail,DOSERR_EXTENDEDERR ; yes, set bit

;       Kill all the threads in the process by setting force flags to kill
;       in Exit_Kmode

dhe60:  CCALL32 _TKDieSoonPTDA, <[dhe_pptda], [dhe_retcode], [dhe_termtype], [dhe_pERepRec]>

       ; If there is no hard error daemon and we are at init time,
       ; Then go ahead and processess the hard error
        call    ChkHEDaemon             ; is there a hard error daemon?
        jnc     short dhe80             ; jump if there is a hard error daemon

        DosContext ds
        cmp     _InitCodeInvalid,0      ; And initcode is valid,
        assume  ds:nothing
        jne     short dhe80             ; (nope, jump)

        call    ChkDelayHardErr         ; Go ahead and call ChkDelayhardErr
                                        ; to avoid endless blinking logo

dhe80:
        LeaveProc
        RETC
EndProc DelayHardErrSub


;***    ChkDelayHardErr
;
;       Checks if there are any delayed hard errors. If popup
;       suppression is enabled, the trap information is written
;       to the appropriate log file by _PDLogPopUp. If an hard
;       daemon exists and exception hard errors are enabled the
;       hard error routine is called with the information saved
;       away in the PTDA. If the hard daemon doesn't exists, the
;       trap information is printed with OutMessage.
;
;       NOTE: If SavedHardErr is -1, then there was not enough memory
;             available to allocate the packet buffer.  In this case,
;             simply display the MSG_NO_NEEDED_RESOURCES message.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX, BX, CX, DX, SI, DI, DS, Flags
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA

Procedure ChkDelayHardErr,<faronly,near>

        LocalVar cdh_freebuf, DWORD     ; Free buffer flag

        xor     esi,esi
        FlatContext DS
        mov     edi,_pPTDACur
        xchg    esi,[edi].SavedHardErr  ; (ESI) = flat buffer pointer or null
    assume ds:nothing
        or      esi,esi                 ; Is there a hard error?
        jz      cdh50                   ;  no, return
        cmp     esi,-1                  ; Out of resources?
        jne     short cdh10             ;  no, handle normally
        mov     [cdh_freebuf],0         ; Do not free buffer
        mov     dx,MSG_NO_NEEDED_RESOURCES ; (DX) = message number
        xor     cx,cx                   ; (CX) = number of replacement strings
        jmp     short cdh20

cdh10:  mov     [cdh_freebuf],1         ; Free buffer
        push    esi                     ; Push on stack for _VMFreeKHB call
        FlatContext ds                  ; (DS:ESI) = address of hard err info
        mov     edi,esi                 ; (EDI) = buffer to free
        lods    word ptr ds:[esi]
        movzx   edx,ax                  ; (DX) = message number
        lods    word ptr ds:[esi]
        movzx   ecx,ax                  ; (CX) = number of replacement strings

cdh20:                                  ;                               86278
 ;   This section will check to see if SUPPRESSPOPUP are ENABLED        86278
 ;   If they are enabled we do not want to display the popup on         86278
 ;   the screen                                                         86278

        DosContext ds
        mov     al,_SuppressPopUps      ; (AL) = drive letter for log file
        FlatContext ds
        cmp     al,0                    ; Is popup suppression enabled?
        je      short cdh25             ; No, check for hard error daemon

 ;      Yes, we logged the popup in DELAYHARDERRSUB, ONLY possible      86278
 ;      at this point is a timing window, we can not control            86278
 ;      CCALL32 _PDLogPopUp <edx,ecx,esi> removed this line of code     86278

        jmp     cdh40                   ;   and free buffer

cdh25:  call    ChkHEDaemon             ; is there a hard error daemon?
        jc      short cdh30             ; jump if there is no hard error daemon

        SaveReg <ds>
        FlatContext DS
        mov     edi,_pPTDACur
        mov     bx,ds:[edi].CurrTCB
        test    ds:[edi].AutoFail,DOSERR_EXCEPTION_FLAG
        RestoreReg <ds>
        Assume  ds:nothing
        jnz     cdh40                   ; jump if we don't do hard error popups

;       Allow only abort from the hard error daemon

        mov     ss:[bx].TCBAllowed,(ALLOWED_ABORT OR ALLOWED_REGDUMP)

;       (DX) = message number
;       (CX) = number of replacement strings
;       (DS:ESI) = pointer to replacement strings
;       (dword ptr (SS:SP)) = flat address of buffer to free

        mov     ax,HEMessage            ; generate an hard error
        CALLFAR HardError
        jmp     cdh40

;       When the hard error daemon doesn't exists, we still need to
;       print the hard error message. OutMessage prints message with
;       replacement strings inserted directly to the console.

cdh30:  mov     ax,ds
        mov     es,ax
        mov     edi,esi                 ; (ES:EDI) = replacement strings addr
        mov     bx,cx                   ; (BX) = number of replacement strings
        mov     ax,dx                   ; (AX) = message number

;       (ES:EDI) = replacement strings
;       (BX) = number of replacement strings
;       (AX) = message number
;       (dword ptr (SS:SP)) = flat address of buffer to free

        SaveReg <bx,es,edi>
        call    OutMessage              ; print message directly to console
        RestoreReg <edx,es,bx>          ; ES:DX -> replacement strings to print
        jc      short cdh35             ; Error, go print replacement strings

        SaveReg <ds,edi>
        FlatContext ds
        mov     edi,_pPTDACur           ; (EDI) = pointer to PTDA
        test    ds:[edi].AutoFail,DOSERR_EXTENDEDERR ; hard err have extended info?
        RestoreReg <edi,ds>
        jz      cdh40                 ; jump if hard err not have extended info


;       If message not in the boot loader, print the first replacement
;       string.  If the DOSERR_EXTENDEDERR bit in the PTDA's AutoFail
;       field is set, the hard error resulted from an exception so print
;       the fourth (module name, object:offset) and third (register dump)
;       replacement strings as well.
cdh35:
        or      bx,bx
        jz      cdh40                   ; jump if no replacement strings

        SaveReg <edx>
        DosContext ds
        mov     edx,offset DOSGROUP:CrLfMsg                             ;b719413
        mov     cx,CrLfMsgLen
        CALLFAR WrtToScrn
        RestoreReg <edx>                ; (DS:EDX) = replacement string to print
        mov     edi,edx
        CALLFAR StrLen32                ; (CX) = string length first insert
        dec     cx                      ; minus null byte
        mov     ax,es
        mov     ds,ax
        CALLFAR WrtToScrn               ; print string directly to console
        inc     cx                      ; skip back over null byte

        SaveReg <ecx>
        DosContext ds
        mov     edx,offset DOSGROUP:CrLfMsg
        mov     cx,CrLfMsgLen
        CALLFAR WrtToScrn
        RestoreReg <ecx>
        SaveReg <ds,edi>
        FlatContext ds
        mov     edi,_pPTDACur           ; (EDI) = pointer to PTDA
        test    ds:[edi].AutoFail,DOSERR_EXTENDEDERR ; hard err have extended info?
        RestoreReg <edi,ds>
        jz      short cdh40             ; jump if hard err not have extended info
        add     edi,ecx                 ; skip first insert
        CALLFAR StrLen32                ; (CX) = string length second insert
        add     edi,ecx                 ; skip second insert
        mov     edx,edi                 ; (DS:EDX) = third replacement string
        CALLFAR StrLen32                ; (CX) = string length third insert
        SaveReg <ecx,edx>
        add     edi,ecx                 ; skip third insert
        mov     edx,edi                 ; (DS:EDX) = fourth replacement string
        CALLFAR StrLen32                ; (CX) = string length fourth insert
        dec     cx                      ; minus null byte
        mov     ax,es
        mov     ds,ax
        CALLFAR WrtToScrn               ; print string directly to console
        RestoreReg <edx,ecx>
        dec     cx                      ; minus null byte
        CALLFAR WrtToScrn               ; print string directly to console

;       (dword ptr (SS:SP)) = flat address of buffer to free

cdh40:  cmp     [cdh_freebuf],0
        je      short cdh50
        pop     eax
        FlatContext <ds,es>,cx
        CCALL32 _VMFreeKHB, <VM_HKH_PUB_RESRW, eax>
cdh50:  ret

EndProc ChkDelayHardErr

HIGH3CODE ENDS

        END
