;       SCCSID = @(#)tkmisc.asm 6.1 90/11/17
SCCSID  equ     "@(#)tkmisc.asm 13.39 90/09/24"
NAME TKMISC

;       Miscellaneous tasking routines.
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved



.xlist
include dosseg.inc
include basemaca.inc
include osmaca.inc
include fnotask.inc
include mi.inc
include pmode.inc
include tkexport.inc
include error.inc
include kmode.inc
include sicg.inc
include bseerr.inc      ;rjm
.list


        CpuMode         386
        ModName         , FNO_TKMISC_ASM

if RAS
        extrn           RASRST:far
;rjm
ReferGlobal     DUMP_ON,BYTE
ReferGlobal     DumpDevice,BYTE                     ;TrapDump device
endif

ifdef INTERRPRT
        extrn           _TKVSprintf:near
endif
        extrn           _tkPanic:near

        ReferFlat       _pTCBCur,DWORD
        ReferFlat       _pTSDCur,DWORD
        ReferFlat       _SELGDTLaddr,DWORD
        ReferFlat       _TKSSBase,DWORD

        ReferGDT        GDT_PTDA,WORD
        ReferGDT        GDT_TSS,QWORD

        ReferGlobal     RedirCallOut,DWORD
ifdef MISCSTRICT
        ReferGlobal     _tkPanicActive,byte
endif

        ReferInitGlobal pSICG,dword
        ReferInitGlobal sicg_packet_D,word
        ReferInitGlobal sicg_packet_D_d,byte



ifdef MISCSTRICT

PANICMSG segment
assertdsesfmt   db      "_AssertDSESFlat: ds=%04x, es=%04x", 0
PANICMSG ends


_DATA segment
        public  _cbTKMaxStackUsed       ; Largest amount of stack used
_cbTKMaxStackUsed dd    ?
_DATA ends

DATA segment
        public  _AssertAlignESP, _AssertAlignESPPanic
_AssertAlignESP      dd ?               ; flag to enable esp enforcement
_AssertAlignESPPanic dd ?               ; flag to enable Panic call
DATA ends

endif ; MISCSTRICT


ifdef INTERRPRT

_BSS segment
IEBUFLEN        equ     256             ; Internal error buffer length
fmsgbuf         db      ?               ; set when msgbuf filled in
msgbuf          db      IEBUFLEN dup(?) ; temporary sprintf buffer
_BSS ends

endif ; INTERRPRT


ifdef INCDEBUG
ThunkFar32 _DbgProcTerm,,DEBUGLOCK_TEXT
ThunkFar32 _DbgKillDebuggees,,DEBUGLOCK_TEXT
endif ;DEBUG

ThunkFar32 KMTHREADTERMINATE,,_TEXT
ThunkFar32 _SEMInitShrTbl,,_TEXT
ThunkFar32 _SEMCleanProcDying,,_TEXT
ThunkFar32 _semValidateName,,_TEXT
ThunkFar32 _SIGInitContextHook,,_TEXT
ThunkFar32 _TKPreInit,,CINIT_TEXT
ThunkFar32 _TKSchedInit,,CINIT_TEXT
ThunkFar32 _TKInit,,CINIT_TEXT
ThunkFar32 _KIEnableInit,,_TEXT                                 ; D159047
    
        FARCODE HIGH3                                                          ;#94979
HIGH3CODE segment                                                              ;#94979
Procedure __TKSetSSBase,<faronly>                                              ;#94979
        ASSUME  DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING        ;#94979
                                                                               ;#94979
        push    ds                                                             ;#94979
        pushad                                                                 ;#94979
	pushfd								; 97525
        FlatContext ds,ax                                                      ;#94979
                                                                               ;#94979
        mov     ax,ss                                                          ;#94979
        push    ds                                                             ;#94979
        GDTContext ds,edx               ; (DS) points to GDT                   ;#94979
        movzx   eax,ax                  ; (DS:EAX) = pointer to GDT selector   ;#94979
        mov     edx,dword ptr [eax].d_limit+1 ; Low 24 bits in high 24 bits    ;#94979
        mov     dl,[eax].d_extaddr      ; High 8 bits in low 8 bits            ;#94979
        ror     edx,8                   ; (EDX) = base of stack                ;#94979
        mov     ax,seg FLAT:DGROUP      ; (EAX) = Flat ring 0 DS selector      ;#94979
        movzx   eax,ax                                                         ;#94979
        mov     ecx,dword ptr [eax].d_limit+1 ; Low 24 bits in high 24 bits    ;#94979
        mov     cl,[eax].d_extaddr      ; High 8 bits in low 8 bits            ;#94979
        ror     ecx,8                   ; (ECX) = base of R0DS                 ;#94979
        sub     edx,ecx                 ; (EDX) = flat-relative stack base     ;#94979
        pop     ds                                                             ;#94979
    assume ds:FLAT                                                             ;#94979
                                                                               ;#94979
        mov     [_TKSSBase],edx         ; Save flat base of stack              ;#94979

	popfd								; 97525
        popad                                                                  ;#94979
        pop     ds                                                             ;#94979
                                                                               ;#94979
        RETC                                                                   ;#94979
EndProc __TKSetSSBase                                                          ;#94979
                                                                               ;#94979
HIGH3CODE ends                                                                 ;#94979

        FARCODE HIGH32
HIGH32CODE segment

ifdef MISCSTRICT
;***LP  tkCheckStackUsage - check (roughly) how much stack this thread used
;
;       This procedure scans from the base of the kernel stack looking
;       for a non-zero byte.  From the offset of this byte within the
;       stack, the procedure computes how much stack the thread used.
;       If this amount is larger than _cbTKMaxStackUsed, then this
;       global variable is updated.
;
;       tkCheckStackUsage (ptcb)
;
;       ENTRY   ptcb            - TCB pointer
;       RETURN  NONE
;
;       CALLS   NONE
;
;       WARNING This procedure follows C calling conventions.  You
;               should assume that it uses EAX, ECX, EDX, and the flags.
;
;       EFFECTS _cbTKMaxStackUsed may be updated.

Procedure _tkCheckStackUsage,near,,,esp
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

        ArgVar  csu_ptcb,DWORD          ; TCB pointer

        EnterProc
        mov     edx,csu_ptcb            ; (EDX) = TCB pointer
        mov     edx,[edx].TCBpTSD       ; (EDX) = TSD pointer
if TSDUserStack ne 0
        add     edx,TSDUserStack        ; (EDX) = base of kernel stack
endif
        push    edi                     ; csu_ptcb no longer valid
        mov     edi,edx                 ; (ES:EDI) = base of kernel stack
        mov     ecx,TSDStackSize/2      ; (ECX) = stack size in dwords
        .errnz  ((TSDUserESP - TSDUserStack) - TSDStackSize*2)
        lea     edx,[edx+ecx*4]         ; (EDX) = pointer past end of stack
        xor     eax,eax                 ; Look for non-zero dword
        repz scasd                      ; Scan until non-zero dword found
        jz      short csu0              ; Skip if last dword was zero
        sub     edi,4                   ; (EDI) = pointer to 1st non-zero dword
csu0:   sub     edx,edi                 ; (EDX) = number of bytes used on stack
        jc      short csuie             ; (should never happen)
        pop     edi                     ; csu_ptcb valid again
        cmp     edx,_cbTKMaxStackUsed   ; A new winner?
        jbe     short csu1              ;  no, exit
        mov     _cbTKMaxStackUsed,edx   ; Save new maximum
csu1:   LeaveProc
        RETC

csuie:  Panic   <"tkCheckStackUsage">   ; Should never happen

EndProc _tkCheckStackUsage
endif


;***EP  TKSetSSBase - set up stack base for SSToDS macro
;
;       This procedure sets up the global variable _TKSSBase
;       so that SSToDS() invocations will work correctly for
;       the current stack.
;
;       _TKSetSSBase must be called after all manual stack switches.
;
;       PGSwitchContext is optimized to do this in-line for speed
;
;       ENTRY   C-callable.
;               (DS) FLAT.  (ES) is not referenced, and need not be loaded
;
;       EXIT    void
;               _TKSSBase modified
;
;       USES    EAX, ECX, EDX, Flags

Procedure _TKSetSSBase,<near,far32>
        ASSUME  DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
ifdef MISCSTRICT
        mov     eax,ds
        cmp     ax,seg FLAT:DGROUP
        jz      short sss00
        Panic   <'_TKSetSSBase'>
sss00:
endif
        mov     ax,ss
        cmp     ax,GSEL GDT_PTDA        ; Normal TaskTime mapping?
        jnz     short sss10             ; no - do a linear mapping via SS

        mov     edx,[_pTCBCur]
        mov     edx,[edx].TCBBiasTSD    ; (EDX) = TaskTime TSD bias
        jmp     short sss20

sss10:  push    ds
        GDTContext ds,edx               ; (DS) points to GDT
        movzx   eax,ax                  ; (DS:EAX) = pointer to GDT selector
        mov     edx,dword ptr [eax].d_limit+1 ; Low 24 bits in high 24 bits
        mov     dl,[eax].d_extaddr      ; High 8 bits in low 8 bits
        ror     edx,8                   ; (EDX) = base of stack
        mov     ax,seg FLAT:DGROUP      ; (EAX) = Flat ring 0 DS selector
        movzx   eax,ax
        mov     ecx,dword ptr [eax].d_limit+1 ; Low 24 bits in high 24 bits
        mov     cl,[eax].d_extaddr      ; High 8 bits in low 8 bits
        ror     ecx,8                   ; (ECX) = base of R0DS
        sub     edx,ecx                 ; (EDX) = flat-relative stack base
        pop     ds
    assume ds:FLAT
sss20:  mov     [_TKSSBase],edx         ; Save flat base of stack
        RETC
EndProc _TKSetSSBase


ifdef PMDEBUG
;***LP  tkStop - break into debugger
;
;       This procedure loads its parameters into EAX and ECX,
;       executes an "int 3", then returns.
;
;       tkStop(rc, laddr)
;
;       ENTRY   rc - return code
;               laddr - linear address
;       RETURN  NONE
;       USES    EAX, ECX

Procedure _tkStop,near,,,esp
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING
        ArgVar ts_rc,DWORD              ; return code
        ArgVar ts_laddr,DWORD           ; linear address

        EnterProc
        mov     eax,[ts_rc]             ; (EAX) = return code
        mov     ecx,[ts_laddr]          ; (ECX) = linear address
        int     3                       ; Break into debugger
        LeaveProc
        RETC
EndProc _tkStop
endif


;***EP  TKTestPause - Pause a C procedure for testing
;
;       TKTestPause causes a single-step to occur in the calling
;       routine, just after the call to TKTestPause.  The debugger
;       will report an "unexpected trace interrupt" at that point.
;
;       TKTestPause should not exist in any checked-in code, unless
;       it is contained within private if-def'ed code.  No call to
;       TKTestPause should ever exist in a production system.  For
;       safety, if a call to TKTestPause IS made in a production system,
;       TKTestPause will simply return quietly.
;
;       ENTRY   NONE
;
;       RETURN  NONE
;
;       USES    NONE.

Procedure _TKTestPause
        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING

IFDEF   PMDEBUG
        pushf
        or      dword ptr ss:[esp],F_TRACE
        popf
ENDIF
        RETC

EndProc _TKTestPause


;***EP  TKGetProtTSS - return the protected mode task TSS selector
;
;       SEL TKGetProtTSS();
;
;       ENTRY   NONE
;
;       EXIT    EAX = protected mode TSS selector
;
;       USES    EAX, ECX, EDX, FS, GS, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure _TKGetProtTSS,near
        mov     eax,GSEL GDT_TSS
        RETC
EndProc   _TKGetProtTSS


;***EP  TKsetjmp - Set an intra-procedure jump target.
;
;       TKsetjmp emulates the _setjmp C runtime library call.
;
;       See the C runtime library call documentation for _setjmp.
;
;       TKsetjmp (struct ljmp_s pLJMP);
;
;       ENTRY
;               pLJMP   : Address of environment structure to use
;
;       EXIT
;               if Return Value == NO_ERROR
;                       The jump was not taken.  The target has been set
;
;               if Return Value != NO_ERROR
;                       The jump was just taken from elsewhere.
;
;       EFFECTS
;               Sets up a jump target for the _TKlongjmp call.
;
;       USES            EAX, ECX, EDX, EFlags

Procedure       _TKsetjmp,,,,esp
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:TASKAREA

        ArgVar  pLJMP,DWORD             ; pointer to an ljmp_s structure.

;       Stack looks like this on entry: (grows down, DWORDS shown)
;
;               |------------|
;               |     ??     |
;               |------------|
;               | pLJMP      |
;               |------------|  <---- resultant ESP from _TKlongjmp
;               | 0:32 ret   |
;       esp->   |------------|

        EnterProc
        mov     eax,pLJMP                       ; point to ljmp_s save buffer
        mov     [eax].ljmp_lEBX,ebx             ; save registers
        mov     [eax].ljmp_lESI,esi
        mov     [eax].ljmp_lEDI,edi
        mov     [eax].ljmp_lEBP,ebp
        LeaveProc
        mov     ecx,[esp]                       ; (ECX) = return address
        mov     [eax].ljmp_lESP,esp             ; Save ESP after popping EIP
        mov     [eax].ljmp_lEIP,ecx             ; Save return EIP
        xor     eax,eax                         ; NO_ERROR
        .errnz  NO_ERROR
        RETC                                    ; Return to caller

EndProc _TKsetjmp


;***EP  TKlongjmp - jump to previously set intra-procedure jump target
;***LP  tkLongJmp - jump to previously set intra-procedure jump target
;
;       _TKlongjmp emulates the _longjmp C runtime library call.
;
;       See the C runtime library call documentation for _longjmp.
;
;       _TKlongjmp reloads: EBX, ESI, EDI, EBP, ESP, EIP.
;
;       NO OTHER REGISTERS ARE RESTORED.
;
;       _TKlongjmp (struct ljmp_s pLJMP, ulong_t rt);
;
;       ENTRY   pLJMP           : Address of structure saved by _TKsetjmp
;               rt              : Return value (normally nonzero)
;
;       EXIT    if rt was nonzero,
;                       Return Value = rt
;               else
;                       Return Value = 1
;
;       EFFECTS
;               Reloads EBX, ESI, EDI, EBP, ESP, and EIP from
;               the image saved in pLJMP, then emulates a return
;               from _TKsetjmp.
;
;       NOTE:   Calling convention demands that the callee pops off parameters
;               off the stack. Since TKsetjmp and TKlongjmp have different # of
;               paramters, this is hacked as follows. We push the return address
;               on the stack and so a RETC.
;
;       USES
;               N/A - see _TKsetjmp
;
;       tkLongJmp:
;
;       ENTRY   (ECX) = pointer to ljmp_s pointer
;               (EAX) = value to return
;               (DS) = (ES) = FLAT
;       EXIT    NONE
;       USES    EAX, ECX, Flags
;
;       Pseudocode:
;               if (rt == 0)
;                       rt == 1;
;               store rt in EAX;
;               Reload all registers (except EIP);
;               Reload (EIP) via a jmp

Procedure _TKlongjmp,,,,ESP
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:TASKAREA

        ArgVar  pLJMP,DWORD             ; pointer to an ljmp_s structure.
        ArgVar  rt,DWORD                ; return code

        mov     ecx,pLJMP               ; point at environment structure
        mov     eax,rt                  ; (EAX) = proposed return code

Entry tkLongJmp,,local                  ; Entry for tkFaultHandler
        or      eax,eax                 ; is return code nonzero?
        .errnz  NO_ERROR
        jnz     short ljmp0             ; yes - accept it as is.
        inc     eax                     ; no - convert it to a 1.
ljmp0:  mov     ebx,[ecx].ljmp_lEBX     ; reload registers
        mov     esi,[ecx].ljmp_lESI
        mov     edi,[ecx].ljmp_lEDI
        mov     ebp,[ecx].ljmp_lEBP
        mov     esp,[ecx].ljmp_lESP     ; reload stack pointer
        mov     ecx,[ecx].ljmp_lEIP
        push    ecx
        RETC                            ; emulate return from _TKsetjmp

EndProc _TKlongjmp


;***EP  _TKCatchFault - set up local fault handler and longjmp buffer
;
;       Save the address of the ljmp_s in the TSD, set up
;       a local fault handler to do a longjmp if a fault occurs,
;       and jump to _TKsetjmp to finish setup and return.
;
;       ENTRY   (See _TKsetjmp)
;       EXIT    (EAX) = NO_ERROR if setting fault handler
;               (EAX) = error code if fault occurred
;       USES    (See _TKsetjmp)

Procedure _TKCatchFault,near,,,esp
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

        ArgVar  pLJMP,DWORD             ; pointer to an ljmp_s structure.

        EnterProc
ifdef   MISCSTRICT
        CCALL32 _AssertDSESFlat         ; Verify that DS and ES are flat
endif
        mov     eax,pLJMP               ; (EAX) = save area pointer
        mov     ecx,_pTSDCur            ; (ECX) = TSD pointer
        mov     edx,offset FLAT:tkFaultHandler
        xchg    edx,[ecx].TSDpfnFault   ; Install fault handler
        mov     [eax].ljmp_pfnFault,edx ; and save previous one in ljmp buffer
        mov     edx,eax                 ; EDX = pointer to ljmp buffer
        xchg    [ecx].TSDpljmp,edx      ; Save address of ljmp buffer in TSD
        mov     [eax].ljmp_pljmp,edx    ; and stash away previous one

ifdef   MISCSTRICT
;       ECX  =  TSDCur
;       EDX  =  Pointer to previous long jump buffer
;       EAX  =  Pointer to current long jump buffer
;
;       If both are on stack, then we verify that the current is at an address
;       lower than the previous one.

        add     ecx,TSDUserStack        ; Past TSDPad, check against lower bounds
        cmp     ecx,edx                 ; Is previous buffer on stack ?
        ja      short tkcf1             ; no, skip check
        cmp     ecx,eax                 ; Is current one on stack ?
        ja      short tkcf1             ; no skip check
        add     ecx,TSDStackSize * 2    ; Check against upper bound
        cmp     eax,ecx                 ; Is previous buffer on stack ?
        ja      short tkcf1             ; no, skip check
        cmp     edx,ecx                 ; Is current one on stack ?
        ja      short tkcf1             ; no skip check
        cmp     edx,eax                 ; Is old above new on stack?
        ja      short tkcf1             ; yes
        Panic   "TKCatchFault: Nesting Error"
tkcf1:
endif
        LeaveProc
        jmp     _TKsetjmp               ; Go finish the job

EndProc _TKCatchFault


;***LP  TKClrFault - Clear local fault handler and re-install previous one
;
;       This undoes the effect of TKCatchFault. Nesting of fault handlers
;       are allowed and so both TSDpfnFault and TSDpljmp are reset to the
;       previous values.
;
;       ENTRY   NONE
;
;       EXIT    NONE
;               TSDpfnFault and TSDpljmp are reset to the state prior to
;               the last TKCatchFault.

Procedure _TKClrFault,near
        mov     ecx,_pTSDCur
ifdef   MISCSTRICT
;       Check that the fault handler installed is tkFaultHandler - i.e.
;       this follows a earlier TKCatchFault.

        cmp     [ecx].TSDpfnFault,offset FLAT:tkFaultHandler
        jne     tkcfie
endif
        mov     edx,[ecx].TSDpljmp      ; EDX = pointer to current  ljmp buffer
        mov     eax,[edx].ljmp_pljmp    ; EAX = pointer to previous ljmp buffer
        mov     [ecx].TSDpljmp,eax      ; Install previous ljmp buffer
        mov     eax,[edx].ljmp_pfnFault ; EAX = previous fault handler
        mov     [ecx].TSDpfnFault,eax   ; Install previous fault handler
        RETC
ifdef   MISCSTRICT
tkcfie: Panic   <"TKClrFault: TKClrFault">
endif
EndProc _TKClrFault


;***LP  tkFaultHandler - do longjmp as set up by _TKCatchFault
;
;       Un-nest the fault handler with its assocaited long jump buffer and
;       do a long-jump
;
;       THIS PROCEDURE IS INVOKED ONLY AS A LOCAL FAULT HANDLER.
;
;       ENTRY   (AX) = error code
;       EXIT    (EAX) = error code
;       USES    EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP, DS, ES, Flags

Procedure tkFaultHandler,near,local
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

ifdef   MISCSTRICT
        CCALL32 _AssertDSESFlat         ; Verify that DS and ES are flat
endif
        mov     edx,_pTSDCur            ; (EDX) = TSD pointer
        mov     ecx,[edx].TSDpljmp      ; (ECX) = pointer to ljmp_s
        push    [ecx].ljmp_pfnFault     ; Get previous handlers address
        pop     [edx].TSDpfnFault       ; and install it
        mov     ecx,[ecx].ljmp_pljmp    ; Get previous long jump buffer
tkfh1:  xchg    ecx,[edx].TSDpljmp      ; (ECX) = pointer to current ljmp_s
        movzx   eax,ax                  ; (EAX) = error code
        jmp     tkLongJmp               ; Go do longjmp

EndProc tkFaultHandler


ifdef   MISCSTRICT
;***EP  _AssertDSESFlat - assert DS and ES are FLAT
;
;       Cause an InternalError if DS or ES isn't FLAT.
;
;       ENTRY   (DS) = seg FLAT:DGROUP
;               (ES) = seg FLAT:DGROUP
;       EXIT    NONE
;       USES    Flags

Procedure _AssertDSESFlat
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
ifdef INTERRPRT
    LocalVar    ade_es,dword
    LocalVar    ade_ds,dword
endif
        push    eax
        mov     eax,ds
        cmp     ax,seg FLAT:DGROUP
        jnz     short ade00
        mov     eax,es
        cmp     ax,seg FLAT:DGROUP
ade00:  pop     eax
        jnz     short adeie1
        test    esp,3
        jnz     short adeie2
adex:   RETC

;       DS or ES is not set up to the FLAT data selector:
;       Panic <"_AssertDSESFlat: ds=%04x, es=%04x">,<es,ds>

adeie1:
ifdef INTERRPRT
        EnterProc
        pushad
        push    ds
        push    es

        mov     ax,ds
        movzx   eax,ax
        mov     [ade_ds],eax
        mov     ax,es
        movzx   eax,ax
        mov     [ade_es],eax

;       TKVSprintf(&msgbuf, IEBUFLEN, assertdsesfmt, &args)

        FlatContext <ds,es>
        SSToDS  eax,[ade_ds]            ; setup pointer to args
        CCALL32 _TKVSprintf,<<offset FLAT:msgbuf>, \
                             IEBUFLEN, \
                             <offset FLAT:assertdsesfmt>, \
                             eax>
        pop     es
        pop     ds
    assume ds:nothing, es:nothing
        popad
        LeaveProc

        push    offset FLAT:msgbuf
        push    seg FLAT:DGROUP
        push    offset FLAT:__FILE__
        push    (-1 shl 16) or FNO_TKMISC_ASM
        push    [esp+16]                ; re-push caller's EIP
        mov     [esp+16].Segmt32,seg FLAT:DGROUP
        jmp     pfm40
else
        PUSHD   [esp]                   ; re-push caller's EIP
                                        ; set line, file numbers
        mov     dword ptr [esp+4],(-1 shl 16) or FNO_TKMISC_ASM
        jmp     __panic
endif

;       ESP is not dword aligned - Panic or allow breakpoint

    assume ds:FLAT, es:FLAT

adeie2: cmp     [_AssertAlignESP],0
        jz      short adex
        cmp     [_tkPanicActive],0      ; avoid recursion
        jz      short adex
        push    eax                     ; save eax
        mov     eax,[esp+4]             ; (eax) = return eip
        push    ebx                     ; save ebx
        push    [_AssertAlignESP]       ; save assert flag
        mov     [_AssertAlignESP],0     ; avoid recursion

        cmp     [_AssertAlignESPPanic],0
        jz      short ade80
        mov     ebx,esp
        Panic   <"_AssertDSESFlat: misaligned esp: %04x, eip=%08x">,<eax,ebx>
        mov     esp,ebx                 ; clean stack after Panic

Entry alignesp                          ; bp alignesp "ln eax;g"
ade80:  pop     [_AssertAlignESP]       ; restore assert flag
        pop     ebx                     ; restore ebx
        pop     eax                     ; restore eax
        RETC
EndProc _AssertDSESFlat
endif


ifdef INTERRPRT

;***EP  __panicsprintf - vsprintf a format string and args into a static buffer
;
;       This procedure is a C-callable stub to format a constant string into
;       a static buffer (using vsprintf) for later use by __panicfn.
;
;       ENTRY   ((ESP+4)) = args as needed by format string
;               ((ESP))   = FLAT-relative pointer to format string
;       EXIT    NONE
;       USES    NONE

Procedure __panicsprintf,cdecl
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
    ArgVar psf_pfmt,DWORD               ; format string
        EnterProc
        pushfd
        pushad
        push    ds
        push    es
        FlatContext <ds,es>,ax

;       TKVSprintf(&msgbuf, IEBUFLEN, pfmt, &args)

        SSToDS  eax,[psf_pfmt+4]        ; setup pointer to args
        CCALL32 _TKVSprintf,<<offset FLAT:msgbuf>,IEBUFLEN,[psf_pfmt],eax>
        inc     [fmsgbuf]               ; indicate buffer in use
        pop     es
        pop     ds
    assume ds:nothing, es:nothing
        popad
        popfd
        LeaveProc
        RETC
EndProc __panicsprintf

endif ;INTERRPRT


;***EP  __panicHIGH32 - panic with line,file number at retaddr
;***EP  __panicfnHIGH32 - panic with the above and file name
;***EP  __panicfnmsgHIGH32 - panic with all of the above and a message
;
;       Same as the procedures without the HIGH32 suffix, except that
;       the file and line numbers are stored at the return address instead
;       of passed on the stack.
;
;       ENTRY   ((ESP+8)) = offset FLAT:message     (__panicfnmsgHIGH32 only)
;               ((ESP+4)) = offset FLAT:filename    (__panicfn[msg]HIGH32 only)
;       EXIT    DOES NOT RETURN
;       USES    DOES NOT RETURN

Procedure __panicHIGH32
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        xchg    eax,[esp]               ; fetch ret address, save eax
        lea     eax,[eax+4]             ; point past file, line numbers
        push    eax                     ; re-push updated return address
        mov     eax,cs:[eax-4]          ; fetch file, line numbers
        xchg    eax,[esp+4]             ; store file, line numbers, restore eax
        jmp     short __panic                   ; jump to standard routine
EndProc __panicHIGH32

ifdef INTERRPRT
Procedure __panicfnHIGH32
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        xchg    eax,[esp]               ; fetch ret address, save eax
        lea     eax,[eax+4]             ; point past file, line numbers
        push    eax                     ; re-push updated return address
        mov     eax,cs:[eax-4]          ; fetch file, line numbers
        xchg    eax,[esp+4]             ; store file, line numbers, restore eax
        jmp     short __panicfn
EndProc __panicfnHIGH32

Procedure __panicfnmsgHIGH32
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        xchg    eax,[esp]               ; fetch ret address, save eax
        lea     eax,[eax+4]             ; point past file, line numbers
        push    eax                     ; re-push updated return address
        mov     eax,cs:[eax-4]          ; fetch file, line numbers
        xchg    eax,[esp+4]             ; store file, line numbers, restore eax
        jmp     short __panicfnmsg
EndProc __panicfnmsgHIGH32
endif ;INTERRPRT


;***EP  __panic - panic with line,file number
;***EP  __panicfn - panic with the above and file name
;***EP  __panicfnmsg - panic with all of the above and a message
;
;       This procedure is a C-callable stub to pass a constant set of
;       parameters to to the standard internal error interface.
;
;       ENTRY   ((ESP+12)) = offset FLAT:message     (__panicfnmsg only)
;               ((ESP+8))  = offset FLAT:filename    (__panicfn[msg] only)
;               ((ESP+4))  = (source line number << 16) | source file number
;       EXIT    DOES NOT RETURN
;       USES    DOES NOT RETURN

Procedure __panic
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

;       [ESP+4] = (source line number << 16) | source file number
;       [ESP]   = caller's EIP

        PUSHD   0                       ; push NULL segment of filename
        push    eax                     ; push garbage offset of filename
        PUSHD   [esp+12]                ; re-push line, file numbers
        PUSHD   [esp+12]                ; re-push EIP
        mov     [esp+16].Segmt32,0      ; set NULL segment of message

;       [ESP+16] = 16:32 pointer to message (NULL seg)
;       [ESP+8]  = 16:32 pointer to filename (NULL seg)
;       [ESP+4]  = (source line number << 16) | source file number
;       [ESP]    = caller's EIP

        jmp     short pfm40

ifdef INTERRPRT
Entry __panicfn
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

;       [ESP+8] = offset FLAT:filename
;       [ESP+4] = (source line number << 16) | source file number
;       [ESP]   = caller's EIP

        PUSHD   [esp+8]                 ; re-push offset of filename
        PUSHD   [esp+8]                 ; re-push line, file numbers
        PUSHD   [esp+8]                 ; re-push EIP
        mov     [esp+8].Segmt32,seg FLAT:DGROUP
        mov     [esp+16].Segmt32,seg FLAT:DGROUP
        mov     [esp+16].Offst32,offset FLAT:msgbuf

        push    ds
        pushfd
        FlatContext ds
        cmp     [fmsgbuf],0             ; has msgbuf been filled in?
        jnz     short pfm20             ; jmp if so
        mov     [esp+24].Segmt32,0      ; else set segment of msg to NULL
pfm20:  popfd
        pop     ds
    assume ds:nothing

;       [ESP+16] = 16:32 pointer to message (or NULL seg)
;       [ESP+8]  = 16:32 pointer to filename
;       [ESP+4]  = (source line number << 16) | source file number
;       [ESP]    = caller's EIP

        jmp     short pfm40

Entry __panicfnmsg
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

;       [ESP+12] = offset FLAT:message
;       [ESP+8]  = offset FLAT:filename
;       [ESP+4]  = (source line number << 16) | source file number
;       [ESP]    = caller's EIP

        PUSHD   [esp+4]                 ; re-push line, file numbers
        PUSHD   [esp+4]                 ; re-push EIP
        PUSHD   [esp+16]                ; move offset of filename down on stack
        POPD    [esp+8].Offst32         ;  "
        PUSHD   [esp+20]                ; move offset of message down on stack
        POPD    [esp+16].Offst32        ;  "
        mov     [esp+8].Segmt32,seg FLAT:DGROUP ; set segment of filename
        mov     [esp+16].Segmt32,seg FLAT:DGROUP ; set segment of message

;       [ESP+16] = 16:32 pointer to message (or NULL seg)
;       [ESP+8]  = 16:32 pointer to filename (or NULL seg)
;       [ESP+4]  = (source line number << 16) | source file number
;       [ESP]    = caller's EIP

        jmp     short pfm40

endif ;INTERRPRT

Entry __panicfmt
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

;       [ESP+4] = FLAT-relative pointer to message string
;       [ESP]   = caller's EIP

        PUSHD   0                       ; push NULL segment of filename
        push    eax                     ; push garbage offset of filename
        PUSHD   0                       ; push zero line, file numbers
        PUSHD   [esp+12]                ; re-push caller's EIP
        PUSHD   [esp+20]                ; move offset of message down on stack
        POPD    [esp+16].Offst32        ;  "
        mov     [esp+16].Segmt32,seg FLAT:DGROUP ; set segment of message

;       [ESP+16] = 16:32 pointer to message (or NULL seg)
;       [ESP+8]  = 16:32 pointer to filename (or NULL seg)
;       [ESP+4]  = (source line number << 16) | source file number
;       [ESP]    = caller's EIP

pfm40:  PUSHD   [esp]                   ; re-push caller's EIP
        mov     [esp].Segmt32,cs        ; make the frame look far

;       [ESP+20] = 16:32 pointer to message (or NULL seg)
;       [ESP+12] = 16:32 pointer to filename (or NULL seg)
;       [ESP+8]  = (source line number << 16) | source file number
;       [ESP]    = 16:32 caller's CS:EIP

        JMP16   __panic                 ; jmp far to Panic dispatch
EndProc __panic


;***EP  VR32Redir - worker for LANMAN's call gate
;
;       This function is the worker for the LANMAN call gate.
;       It sets EBP to point to the start of the parameters
;       on the kernel stack and makes a 16-bit far call to
;       the redirector through the far16 pointer, RedirCallOut.
;
;       ENTRY   sef             - stuff put on stack by EnterKmode
;               dummy1          - first dummy parameter
;               dummy2          - second dummy parameter
;               dummy3          - third dummy parameter
;               dummy4          - fourth dummy parameter
;               dummy5          - fifth dummy parameter
;       EXIT    ???
;       USES    ???

Procedure VR32Redir,cdecl,,,esp
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

        ArgVar rdr_sef,<SIZE sef_s>
        ArgVar dummy1,DWORD
        ArgVar dummy2,DWORD
        ArgVar dummy3,DWORD
        ArgVar dummy4,DWORD
        ArgVar dummy5,DWORD

        EnterProc
        lea     ebp,dummy1              ; (SS:EBP) = argument frame pointer
        jmp     far ptr CallRedir       ; Go call the redirector

Entry VR32RedirReturn,,local            ; CallRedir comes back here
        LeaveProc
        RETC

EndProc VR32Redir


;***EP  VR32ForceSystemDump - 32-bit worker routine to dump and reboot
;                             system
;
;       ENTRY   sef             - stuff put on stack by EnterKmode
;               reserved        - ulong reserved parameter for future Sears use
; RJM reserved now used privately to manipulate DumpDevice and DUMP_ON  
;
;       EXIT    never exits - system reboots
;
;       USES    not relevant

Procedure _VR32ForceSystemDump,cdecl,,,esp
            ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;@83241 SEM 5/20/94 above causes trap E, CS was setup as flat, needs to be doscode
;rjm        ASSUME  CS:DOSCODE, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

if RAS

;rjm        ArgVar sef,<SIZE sef_s>  this was a bug all along
        ArgVar sef,<SIZE thunksef_s>
        ArgVar reserved,DWORD

;       reserved parameter:
;       00000000  = force system dump
;       8000xxxx  = trapdump off
;       8001xxxx  = trapdump on
;       8002xxxx  = trapdump r0
;       xxxxxxdd  = trapdump ?,dd:



        EnterProc
        mov     eax,reserved
        or      eax,eax
        jz      sysd05
        test    eax,080000000h
        jz      sysd03
        cmp     eax,080010000h
        jnz     sysd01
        mov     DUMP_ON,001h
        jmp     sysd03
sysd01: cmp     eax,080020000h
        jnz     sysd02
        mov     DUMP_ON,002h
        jmp     sysd03
sysd02: mov     DUMP_ON,000h
sysd03: or      al,al
        jz      sysdx
        cmp     al,041h ;A
        jb      sysde
        cmp     al,05ah ;Z
        jb      sysd04 
        sub     al,020h ;convert from lower to upper case
        cmp     al,041h ;A
        jb      sysde
        cmp     al,05ah ;Z
        jb      sysd04 
sysde:  mov     eax,ERROR_INVALID_DRIVE
        jmp     sysdx1
sysd04: mov     DumpDevice,al
        jmp     short sysdx
sysd05: call    tkForceSystemDump
sysdx:  xor     eax,eax
sysdx1:
        LeaveProc

endif ;RAS

        RETC

EndProc _VR32ForceSystemDump

Procedure tkForceSystemDump
        ASSUME  CS:DOSCODE, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
        jmp     RASRST
        RETC
EndProc tkForceSystemDump


HIGH32CODE ends


        FARCODE LOW
CODE segment

;***LP  CallRedir - call LANMAN
;
;       This function should be called by VR32Redir only.  See
;       above.

Procedure CallRedir,far,local
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

        DosContext ds,cx
        call    dword ptr RedirCallOut
        FlatContext <ds,es>,cx
        JMP32   VR32RedirReturn

EndProc CallRedir


;***EP  __panic - panic with line,file number
;***EP  __panicfn - panic with the above and file name
;***EP  __panicfnmsg - panic with all of the above and a message
;
;       These procedures are 16 bit ASM-callable stubs to set up a 32 bit
;       return frame, then pass control to the common 32 bit panic code.
;
;       ENTRY   ((ESP+10)) = offset FLAT:message     (__panicfnmsg only)
;               ((ESP+6))  = offset FLAT:filename    (__panicfn[msg] only)
;               ((ESP+4))  = 16 bit return IP of real caller
;               ((ESP+2))  = 16 bit return CS of real caller
;               ((ESP))    = 16 bit return IP of thunk (garbage)
;               At real caller's return address:
;                   [retaddr]   = source file number (word)
;                   [retaddr+2] = source line number (word)
;       EXIT    DOES NOT RETURN
;       USES    DOES NOT RETURN

Procedure __panic,faronly,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

;       [ESP+4]     = 16 bit return IP of real caller
;       [ESP+2]     = 16 bit return CS of real caller
;       [ESP]       = 16 bit return IP of thunk (garbage)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

        lea     esp,[esp+2]             ; discard thunk IP

;       [ESP]       = 16:16 return IP:CS of real caller (backwards)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

        push    eax                     ; push garbage offset of message
        PUSHD   0                       ; push NULL segment of filename
        push    eax                     ; push garbage offset of filename
        PUSHD   [esp+12]                ; re-push IP:CS
        mov     [esp+12].Segmt32,0      ; set NULL segment of message

;       [ESP+12]    = 16:32 NULL pointer to message
;       [ESP+4]     = 16:32 NULL pointer to filename
;       [ESP]       = 16:16 return IP:CS of real caller (backwards)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

ifdef INTERRPRT
        jmp     short pff40

Entry __panicfn,faronly,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

;       [ESP+6]     = offset FLAT:filename
;       [ESP+4]     = 16 bit return IP of real caller
;       [ESP+2]     = 16 bit return CS of real caller
;       [ESP]       = 16 bit return IP of thunk (garbage)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

        lea     esp,[esp+2]             ; discard thunk IP

;       [ESP+4]     = offset FLAT:filename
;       [ESP]       = 16:16 return IP:CS of real caller (backwards)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

        push    ax                      ; push garbage high word of segment
        push    seg FLAT:DGROUP         ; push segment of filename
        PUSHD   [esp+8]                 ; move offset of filename down on stack
        PUSHD   [esp+8]                 ; move return IP:CS down on stack
        mov     [esp+12].Offst32,offset FLAT:msgbuf ; point to saved message
        mov     [esp+12].Segmt32,seg FLAT:DGROUP

        push    ds
        pushf
        FlatContext ds
        cmp     [fmsgbuf],0             ; has msgbuf been filled in?
        jnz     short pff20             ; jmp if so
        mov     [esp+16].Segmt32,0      ; else set segment of msg to NULL
pff20:  popf
        pop     ds
    assume ds:nothing

;       [ESP+12]    = 16:32 pointer to message (or NULL seg)
;       [ESP+4]     = 16:32 pointer to filename
;       [ESP]       = 16:16 return IP:CS of real caller (backwards)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

        jmp     short pff40

Entry __panicfnmsg,faronly,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

;       [ESP+10]    = offset FLAT:message
;       [ESP+6]     = offset FLAT:filename
;       [ESP+4]     = 16 bit return IP of real caller
;       [ESP+2]     = 16 bit return CS of real caller
;       [ESP]       = 16 bit return IP of thunk (garbage)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

        lea     esp,[esp+2]     ; discard thunk IP

;       [ESP+8]     = offset FLAT:message
;       [ESP+4]     = offset FLAT:filename
;       [ESP]       = 16:16 return IP:CS of real caller (backwards)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

        PUSHD   [esp+4]                 ; re-push offset FLAT:filename
        PUSHD   [esp+4]                 ; re-push 16:16 return IP:CS
        PUSHD   [esp+16]                ; move offset FLAT:message down
        POPD    [esp+12]                ;  "
        mov     [esp+4].Segmt32,seg FLAT:DGROUP ; set segment of filename
        mov     [esp+12].Segmt32,seg FLAT:DGROUP; set segment of message

;       [ESP+12]    = 16:32 pointer to message (or NULL seg)
;       [ESP+4]     = 16:32 pointer to filename (or NULL seg)
;       [ESP]       = 16:16 return IP:CS of real caller (backwards)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

endif ;INTERRPRT
pff40:  PUSHD   [esp]                   ; re-push caller's IP:CS
        PUSHD   [esp]                   ; duplicate IP:CS on stack
        push    eax                     ; push caller's eax
        pushf
        push    ds
        push    esi

        shr     [esp+12].Offst32,16     ; move IP to low word

        lds     esi,[esp+12]            ; fetch caller's return address
        add     [esp+12].Offst32,4      ; point return address past dword
        lods    dword ptr ds:[esi]      ; fetch line number and file number
        mov     [esp+20],eax            ; and store in stack frame

ifdef INTERRPRT
        whatmode ax
        jnc     short pff50
        FlatContext ds
        mov     [fmsgbuf],0             ; reset fmsgbuf for next call
pff50:
endif ;INTERRPRT

        pop     esi
        pop     ds
    assume ds:nothing
        popf
        pop     eax

;       [ESP+20] = 16:32 pointer to message (or NULL)   (fword)
;       [ESP+12] = 16:32 pointer to filename (or NULL)  (fword)
;       [ESP+10] = source line number                   (word)
;       [ESP+8]  = source file number                   (word)
;       [ESP]    = caller's CS:EIP                      (fword)

Entry __panic,far16,,NoCheck

        call    _tkPanic                ; no deposit, no return
EndProc __panic


ifdef INTERRPRT

;***EP  __panicfnmsgRM - panic with DOSGROUP relative message & filename
;
;       Same as the other 16-bit procedures with suffices, except that
;       the filename and message offsets are 16-bit DOSGROUP relative
;       offsets for possible real mode callers.
;
;       ENTRY   ((ESP+4)) = offset DOSGROUP:message
;               ((ESP+2)) = offset DOSGROUP:filename
;               [retaddr]   = source file number (word)
;               [retaddr+2] = source line number (word)
;       EXIT    DOES NOT RETURN
;       USES    DOES NOT RETURN

Procedure __panicfnmsgRM
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        push    cs
        push    ax                      ; push segment of filename
        push    DOSGROUP
        push    0                       ; push offset of filename
        push    word ptr [esp+10]
        PUSHD   [esp+8]                 ; re-push backwards IP:CS
        push    word ptr [esp+18]       ; move offset of message down on stack
        pop     [esp+12].Offst32.loword
        mov     [esp+12].Offst32.hiword,0 ; zero offset.hiword of message
        mov     [esp+12].Segmt32,DOSGROUP ; set segment of message

;       [ESP+12]    = 16:32 pointer to message
;       [ESP+4]     = 16:32 pointer to filename
;       [ESP]       = 16:16 return IP:CS of real caller (backwards)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

        jmp     short pff40
EndProc __panicfnmsgRM


;***EP  __panicsprintf - vsprintf a format string and args into a static buffer
;
;       This procedure is a C-callable stub to format a constant string into
;       a static buffer (using vsprintf) for later use by __panicfn.
;
;       ENTRY   ((ESP+4)) = args as needed by format string
;               ((ESP))   = FLAT-relative pointer to format string
;       EXIT    NONE
;       USES    NONE

Procedure __panicsprintf,<faronly,cdecl>
    ArgVar pff_pfmt,DWORD               ; format string
        EnterProc
        pushfd
        pushad
        push    ds
        push    es
        FlatContext <ds,es>,ax

;       TKVSprintf(&msgbuf, IEBUFLEN, pfmt, &args)

        SSToDS  eax,[pff_pfmt+4]        ; setup pointer to args
        CCALL32 _TKVSprintf,<<offset FLAT:msgbuf>,IEBUFLEN,[pff_pfmt],eax>
        inc     [fmsgbuf]               ; indicate buffer in use
        pop     es
        pop     ds
    assume ds:nothing, es:nothing
        popad
        popfd
        LeaveProc
        RETC
EndProc __panicsprintf
endif ;INTERRPRT


CODE ends


        FARCODE INIT
INITCODE segment


;***EP  _panicsicg - panic from ring 3 SICG call
;
;       The ring 3 code stored everything necessary in the sicg_pktD structure
;       then used a call gate to get to ring 0 and call this routine.
;
;       ENTRY   (DS:SI) -> sicg_pktD structure
;       EXIT    NONE
;       USES    Flags

Procedure _panicsicg
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        push    ax                        ; push caller's SS
        push    ds:[si].siD_ssesp.Segmt32
        push    ds:[si].siD_ssesp.Offst32 ; push caller's ESP
        push    ax                        ; push caller's 16:32 msg pointer
        push    ds:[si].siD_pmsg.Segmt32
        push    ds:[si].siD_pmsg.Offst32
        push    ax                        ; push caller's 16:32 filename ptr
        push    ds:[si].siD_pfn.Segmt32
        push    ds:[si].siD_pfn.Offst32
        push    ds:[si].siD_csip.Offst    ; push caller's IP:CS (backwards)
        push    ds:[si].siD_csip.Segmt

;       [ESP+16]    = 16:32 return SS:ESP
;       [ESP+12]    = 16:32 pointer to message
;       [ESP+4]     = 16:32 pointer to filename
;       [ESP]       = 16:16 return IP:CS of real caller (backwards)
;       [retaddr]   = source file number (word)
;       [retaddr+2] = source line number (word)

        jmp     pff40
EndProc _panicsicg


INITCODE ends


        FARCODE INITR3
INITR3CODE segment


Procedure __panicINITR3
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
    ArgVar dummy,byte                   ; to force EnterProc
        EnterProc

        push    ds
        push    si
        push    bx
        push    ax
        DosInitContext ds
        mov     si,offset sicg_packet_D_d

        mov     ds:[si].siD_ssesp.Segmt32,ss
        lea     bx,[bp+2]
        mov     ds:[si].siD_ssesp.Offst32.loword,bx
        mov     ds:[si].siD_pmsg.Segmt32,0
        mov     ds:[si].siD_pfn.Segmt32,0
        mov     ds:[si].siD_csip.Segmt,cs
        mov     ax,[bp+2]               ; fetch IP
        add     word ptr [bp+2],4       ; skip file, line numbers
        mov     ds:[si].siD_csip.Offst.loword,ax

        push    ds
        push    offset sicg_packet_D
        call    [pSICG]                 ; Call SICG to do the work.

        pop     ax
        pop     bx
        pop     si
        pop     ds
        LeaveProc
        ret
EndProc __panicINITR3

ifdef INTERRPRT

;***LP  __panicfnmsgINITR3 - call ring 0 Panic routine
;
;       ENTRY   ((ESP+6)) = offset FLAT:message
;               ((ESP+2)) = offset FLAT:filename
;               [retaddr]   = source file number (word)
;               [retaddr+2] = source line number (word)
;       EXIT    NONE
;       USES    NONE
;
;       call SICG to dispatch to ring 0 Panic routine

Procedure __panicfnmsgINITR3
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
    ArgVar pmi_pfn,dword
    ArgVar pmi_pmsg,dword
        EnterProc

        push    ds
        push    si
        push    bx
        push    eax
        DosInitContext ds
        mov     si,offset sicg_packet_D_d

        mov     ds:[si].siD_ssesp.Segmt32,ss
        lea     bx,[pmi_pmsg+4]
        mov     ds:[si].siD_ssesp.Offst32.loword,bx
        mov     ds:[si].siD_pmsg.Segmt32,seg FLAT:DGROUP
        mov     eax,[pmi_pmsg]
        mov     ds:[si].siD_pmsg.Offst32,eax
        mov     ds:[si].siD_pfn.Segmt32,seg FLAT:DGROUP
        mov     eax,[pmi_pfn]
        mov     ds:[si].siD_pfn.Offst32,eax
        mov     ds:[si].siD_csip.Segmt,cs
        mov     ax,[bp+2]               ; fetch IP
        add     word ptr [bp+2],4       ; skip file, line numbers
        mov     ds:[si].siD_csip.Offst.loword,ax

        push    ds
        push    offset sicg_packet_D
        call    [pSICG]                 ; Call SICG to do the work.

        pop     eax
        pop     bx
        pop     si
        pop     ds
        LeaveProc
        RETC
EndProc __panicfnmsgINITR3
endif


INITR3CODE ends


PanicThunk macro func, suffix, farcodename, codesegname
    FARCODE farcodename
    codesegname segment
    Procedure func&suffix
        CALLFAR  func
    EndProc func&suffix
    codesegname ends
endm


PanicThunk __panic,      LOW,   LOW,   CODE
PanicThunk __panic,      RM,    LOW,   CODE
PanicThunk __panic,      HIGH2, HIGH2, HIGH2CODE
PanicThunk __panic,      HIGH3, HIGH3, HIGH3CODE
PanicThunk __panic,      HIGH4, HIGH4, HIGH4CODE

ifdef INTERRPRT
PanicThunk __panicfn,    LOW,   LOW,   CODE
PanicThunk __panicfn,    HIGH2, HIGH2, HIGH2CODE
PanicThunk __panicfn,    HIGH3, HIGH3, HIGH3CODE
PanicThunk __panicfn,    HIGH4, HIGH4, HIGH4CODE

PanicThunk __panicfnmsg, LOW,   LOW,   CODE
PanicThunk __panicfnmsg, HIGH2, HIGH2, HIGH2CODE
PanicThunk __panicfnmsg, HIGH3, HIGH3, HIGH3CODE
PanicThunk __panicfnmsg, HIGH4, HIGH4, HIGH4CODE
endif


end
