1534 lines
31 KiB
NASM
1534 lines
31 KiB
NASM
TITLE LDINT - Loader interrupt procedure
|
|
|
|
.xlist
|
|
include kernel.inc
|
|
include newexe.inc
|
|
include tdb.inc
|
|
include protect.inc
|
|
include dbgsvc.inc
|
|
include bop.inc
|
|
include kdos.inc
|
|
include gpcont.inc ; SHERLOCK
|
|
ifdef WOW
|
|
include vint.inc
|
|
include softpc.inc
|
|
endif
|
|
|
|
NOTEXT = 1
|
|
NOGDICAPMASKS = 1
|
|
NOMB = 1
|
|
NOVK = 1
|
|
NOWH = 1
|
|
NOMST = 1
|
|
NORASTOPS = 1
|
|
NOMETAFILE = 1
|
|
NOMDI = 1
|
|
NOWINMESSAGES = 1
|
|
NOSYSMETRICS = 1
|
|
NOCOLOR = 1
|
|
NOCOMM = 1
|
|
NOKERNEL = 1
|
|
|
|
include windows.inc ; YIKES!!!
|
|
|
|
.list
|
|
|
|
FAULTSTACKFRAME struc
|
|
|
|
fsf_BP dw ? ; Saved BP
|
|
fsf_msg dw ? ; Near pointer to message describing fault
|
|
fsf_prev_IP dw ? ; IP of previous fault handler
|
|
fsf_prev_CS dw ? ; CS of previous fault handler
|
|
fsf_ret_IP dw ? ; DPMI fault handler frame follows
|
|
fsf_ret_CS dw ?
|
|
fsf_err_code dw ?
|
|
fsf_faulting_IP dw ?
|
|
fsf_faulting_CS dw ?
|
|
fsf_flags dw ?
|
|
fsf_SP dw ?
|
|
fsf_SS dw ?
|
|
|
|
FAULTSTACKFRAME ends
|
|
|
|
fsf_OFFSET = fsf_ret_IP - fsf_msg
|
|
|
|
UAE_STRING_LEN equ 192d
|
|
MIN_SP equ 256d
|
|
|
|
externFP ExitKernel
|
|
|
|
|
|
DataBegin
|
|
|
|
;externB syserr
|
|
externB szAbort
|
|
externB szAbortCaption
|
|
externB szNukeApp
|
|
externB szWillClose
|
|
externB szBlame
|
|
externB szSnoozer
|
|
externB szInModule
|
|
externB szAt
|
|
externB szII
|
|
externB szGP
|
|
externB szSF
|
|
externB szNP
|
|
externB szLoad
|
|
;externB szDiscard
|
|
externB szPF
|
|
externB Kernel_Flags
|
|
externB fBooting
|
|
externW curTDB
|
|
;externW pGlobalHeap
|
|
externW DemandLoadSel
|
|
externD pSErrProc
|
|
externD pUserGetFocus
|
|
externD pUserGetWinTask
|
|
externD pUserIsWindow
|
|
externD lpGPChain
|
|
|
|
if kdebug
|
|
globalw wFaultSegNo,0
|
|
endif
|
|
|
|
if ROM
|
|
externD prevIntx6proc
|
|
externD prevInt0Cproc
|
|
externD prevInt0Dproc
|
|
externD prevInt0Eproc
|
|
externD prevInt3Fproc
|
|
endif
|
|
|
|
if KDEBUG
|
|
staticW INT3Fcs,0
|
|
endif
|
|
|
|
globalW FaultHandler,<codeOffset HandleFault>
|
|
|
|
externD pPostMessage
|
|
|
|
ifdef WOW
|
|
externD FastBop
|
|
externD prevInt01proc
|
|
externD prevInt03proc
|
|
externD oldInt00proc
|
|
externW DebugWOW
|
|
externW gdtdsc
|
|
|
|
endif
|
|
|
|
DataEnd
|
|
|
|
sBegin DATA
|
|
externW gmove_stack
|
|
externW TraceOff
|
|
sEnd DATA
|
|
|
|
sBegin CODE
|
|
assumes CS,CODE
|
|
|
|
if SHERLOCK
|
|
externNP GPContinue
|
|
endif
|
|
|
|
ife ROM
|
|
externD prevIntx6proc
|
|
externD prevInt0Cproc
|
|
externD prevInt0Dproc
|
|
externD prevInt0Eproc
|
|
externD prevInt3Fproc
|
|
endif
|
|
|
|
externNP LoadSegment
|
|
;externNP MyLock
|
|
|
|
ifndef WOW
|
|
externNP htoa
|
|
endif
|
|
|
|
externNP GetOwner
|
|
externNP GetPureName
|
|
externNP TextMode
|
|
externNP Int21Handler
|
|
|
|
;externNP DebugPostLoadMessage
|
|
externFP GlobalLRUNewest
|
|
externFP GlobalHandleNorip
|
|
externFP HasGPHandler
|
|
externFP AllocSelector
|
|
externFP IFreeSelector
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
ifdef WOW
|
|
Entry macro name
|
|
public name
|
|
align 2
|
|
name&:
|
|
endm
|
|
endif
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Display_Box_of_Doom -- Display the Unrecoverable Application Error
|
|
; box that everyone seems to dislike so much.
|
|
;
|
|
; Entry:
|
|
; Action Reserved, must be zero
|
|
; lpText String to display, NULL for default
|
|
;
|
|
; Returns:
|
|
; AX = 1 Cancel
|
|
; AX = 2 OK
|
|
;
|
|
; Registers Destroyed:
|
|
; AX, BX, CX, DX, SI, DI
|
|
;
|
|
; History:
|
|
; Thu 16-May-1991 -by- Earle R. Horton
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc Display_Box_of_Doom,<PUBLIC,NEAR>
|
|
|
|
parmW action
|
|
parmD lpText
|
|
cBegin
|
|
SetKernelDS
|
|
if KDEBUG
|
|
xor bx,bx
|
|
or action,bx
|
|
jz @F
|
|
kerror 00FFh,<Action not 0 in FatalAppExit>,bx,bx
|
|
@@:
|
|
endif
|
|
push es ; added 10 feb 1990
|
|
mov es,curTDB ; did app disable exception
|
|
test es:[TDB_ErrMode],02h ; message box?
|
|
pop es
|
|
jnz nf_dont_ask
|
|
|
|
cmp pSErrProc.sel, 0 ; Can we put up message box?
|
|
jnz short nf_ask ; yes, do it
|
|
; no, have debugger?
|
|
nf_dont_ask:
|
|
mov ax,1
|
|
test Kernel_Flags[2],KF2_SYMDEB
|
|
jnz nf_ret ; yes, call debugger
|
|
inc ax
|
|
jmps nf_ret ; no, have to nuke the app
|
|
|
|
nf_ask:
|
|
push es
|
|
mov ax,lpText.sel
|
|
or ax,ax
|
|
jz nf_default_string
|
|
push ax
|
|
push lpText.off
|
|
jmps nf_pushed_string
|
|
|
|
nf_default_string:
|
|
push ds
|
|
mov ax,dataOffset szAbort ; lpText
|
|
push ax
|
|
|
|
nf_pushed_string:
|
|
push ds ; lpCaption
|
|
mov ax, dataOffset szAbortCaption
|
|
push ax
|
|
|
|
xor ax,ax ; Assume no debugger, blank first button
|
|
mov cx,ax
|
|
test Kernel_Flags[2],KF2_SYMDEB ; Debugger?
|
|
jz @F ; No
|
|
mov cx,SEB_CANCEL ; Yes, use Cancel button
|
|
@@:
|
|
push cx
|
|
; push SEB_OK+SEB_DEFBUTTON
|
|
push SEB_CLOSE + SEB_DEFBUTTON
|
|
push ax
|
|
|
|
call ds:[pSErrProc] ; Put up the system error message
|
|
pop es
|
|
|
|
nf_ret:
|
|
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; FatalAppExit -- Called by apps. to request an application error
|
|
; message box.
|
|
;
|
|
; Entry:
|
|
; Action Reserved, must be zero
|
|
; lpText String to display, NULL for default
|
|
;
|
|
; Returns:
|
|
; Returns to caller if Cancel button pressed
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Sun 22-Oct-1989 15:18:57 -by- David N. Weise [davidw]
|
|
; Tonyg wrote it!
|
|
; Fri 24-May-1991 EarleH totally rewrote it, so there!
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc IFatalAppExit,<PUBLIC,FAR>
|
|
|
|
parmW action
|
|
parmD lpText
|
|
cBegin
|
|
|
|
cmp seg_lpText,0
|
|
jne fae_string
|
|
mov off_lpText,offset szAbort
|
|
mov seg_lpText,seg szAbort
|
|
fae_string:
|
|
cCall Display_Box_of_Doom,<action,lpText>
|
|
cmp ax,1 ; Cancel pressed?
|
|
je fae_ret
|
|
jmp KillApp
|
|
fae_ret:
|
|
cEnd
|
|
|
|
; ------------------------------------------------------------------
|
|
;
|
|
; FormatFaultString -- Special purpose "sprintf()"
|
|
; Only used for the Box of Doom
|
|
;
|
|
; ------------------------------------------------------------------
|
|
|
|
cProc FormatFaultString,<PUBLIC,NEAR>,<si,di,ds,es>
|
|
parmD lpstr
|
|
parmW pStr ; Assumed in Kernel's DS
|
|
parmD csip
|
|
cBegin
|
|
SetKernelDS
|
|
cld
|
|
les di, lpstr ; Form string in ES:DI
|
|
call CurApName
|
|
lea si, szSnoozer ; " has caused an error in Windows"
|
|
call strcpy
|
|
mov si, pStr ; Copy the fault string
|
|
call strcpy
|
|
lea si, szInModule ; "in Module: <unknown>"
|
|
call strcpy
|
|
|
|
push es
|
|
push di
|
|
|
|
cCall GetOwner,<seg_csip> ; Can we find a module to blame?
|
|
or ax, ax
|
|
jz NoOwner
|
|
mov es, ax
|
|
cmp es:[ne_magic], NEMAGIC
|
|
jne NoOwner
|
|
|
|
mov bx, seg_csip ; Have the module, can we get the
|
|
and bl, not SEG_RING ; segment number?
|
|
mov di,es:[ne_segtab]
|
|
mov ax,1
|
|
mov cx, es:[ne_cseg]
|
|
getsegno:
|
|
mov dx, es:[di].ns_handle
|
|
and dl, not SEG_RING
|
|
cmp dx, bx
|
|
jz gotsegno
|
|
add di,SIZE NEW_SEG1
|
|
inc ax
|
|
loop getsegno
|
|
jmps nosegno ; No, report the selector instead
|
|
gotsegno:
|
|
mov seg_csip, ax ; Print Segment #
|
|
nosegno:
|
|
|
|
mov di, es:[ne_pfileinfo] ; Now blame the module
|
|
add di, opFile
|
|
call GetPureName
|
|
mov si, di
|
|
smov ds, es
|
|
UnSetKernelDS
|
|
pop di
|
|
pop es
|
|
ifdef FE_SB
|
|
find_space:
|
|
cmp byte ptr es:[di-1],' ' ; prepare space before mod name
|
|
jz copy_name
|
|
dec di
|
|
jmps find_space
|
|
copy_name:
|
|
else ; !FE_SB
|
|
sub di, 9 ; Get rid of <unknown>
|
|
endif ; !FE_SB
|
|
|
|
call strcpy
|
|
SetKernelDS
|
|
jmps GotOwner
|
|
|
|
NoOwner:
|
|
pop di
|
|
pop es
|
|
GotOwner:
|
|
lea si, szAt
|
|
call strcpy
|
|
ifdef WOW
|
|
cCall <far ptr Far_htoa>,<es,di,seg_csip>
|
|
else
|
|
cCall htoa,<es,di,seg_csip>
|
|
endif
|
|
mov di, ax
|
|
mov es, dx
|
|
mov byte ptr es:[di], ':'
|
|
inc di
|
|
ifdef WOW
|
|
cCall <far ptr Far_htoa>,<es,di,off_csip>
|
|
else
|
|
cCall htoa,<es,di,off_csip>
|
|
endif
|
|
mov es, dx
|
|
mov di, ax
|
|
lea si, szNukeApp
|
|
call strcpy
|
|
call CurApName
|
|
lea si, szWillClose
|
|
call strcpy
|
|
cEnd
|
|
|
|
CurApName proc near
|
|
SetKernelDS
|
|
lea si, szBlame ; Default task to blame
|
|
cmp curTDB, 0 ; Have a task to blame?
|
|
je DefaultCaption ; nope, use default
|
|
mov ds, curTDB
|
|
UnSetKernelDS
|
|
mov si, TDB_ModName
|
|
DefaultCaption:
|
|
mov cx, 8
|
|
copy_appname:
|
|
lodsb
|
|
stosb
|
|
or al, al ; Null padded in TDB
|
|
loopne copy_appname
|
|
jne no_null
|
|
dec di ; Toss extra space
|
|
no_null:
|
|
|
|
SetKernelDS
|
|
ret
|
|
CurApName endp
|
|
|
|
public strcpy
|
|
strcpy proc near
|
|
lodsb
|
|
stosb
|
|
or al, al
|
|
jnz strcpy
|
|
dec di ; Ignore Null
|
|
ret
|
|
strcpy endp
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; KillApp -- Calls USER to tell it that the application is going away,
|
|
; then tells DOS to kill it.
|
|
;
|
|
; ENTRY: None
|
|
; EXIT: None, doesn't
|
|
;
|
|
; Registers modified: Huh?
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
KillApp proc near
|
|
|
|
SetKernelDS
|
|
|
|
test fBooting, 1
|
|
jz @F
|
|
|
|
mov ax, 1
|
|
cCall ExitKernel,<ax>
|
|
|
|
@@: mov ax,4CFFH ; They said OK to Nuke app.
|
|
DOSCALL
|
|
|
|
UnSetKernelDS
|
|
KillApp endp
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; FaultFilter -- Called by HandleFault, NestedFault, and routines that
|
|
; use the same stack frame. Look at the faulting CS:IP on the exception
|
|
; handler frame, and make sure that CS is Ring 3, LDT. If it is not
|
|
; pop the near return address from the stack and chain the exception
|
|
; to the next handler. This will be the DPMI server, which will crash
|
|
; Windows back to DOS. We ought to try to close up a few things first.
|
|
;-----------------------------------------------------------------------;
|
|
ReSetKernelDS
|
|
|
|
public FaultFilter
|
|
FaultFilter proc near
|
|
|
|
|
|
mov al,byte ptr [bp].fsf_faulting_CS
|
|
and al, SEG_RING_MASK ; Check it was Ring 3, LDT
|
|
cmp al, SEG_RING
|
|
|
|
je @F
|
|
;
|
|
; The faulting CS's ring bits do not match up. We will not handle
|
|
; this fault, because we assume it happened in the DPMI provider,
|
|
; and is a Real Bad one. Since the default handler is going to
|
|
; abort here, it would be nice to let the user down real easy.
|
|
; Restoring the display to text mode would be nice, at the very
|
|
; minimum.
|
|
;
|
|
cCall TextMode
|
|
ret ; Hypocrite!
|
|
@@:
|
|
;
|
|
; Check for faults on POP FS and POP GS. If found, fix them up. We need to
|
|
; fix up faults in the register restoration of both KRNL386 (WOW16Return) and
|
|
; MMSYSTEM (MULTI_MEDIA_ISR386). Monty Pythons Complete Waste of Time is an app
|
|
; which frees selectors in FS across message boundries.
|
|
;
|
|
ifdef WOW
|
|
push ds
|
|
mov ax, word ptr [bp].fsf_faulting_CS
|
|
mov ds, ax
|
|
mov si, word ptr [bp].fsf_faulting_IP
|
|
cmp word ptr [si], 0A10Fh ; pop fs
|
|
je HandFSGSflt
|
|
cmp word ptr [si], 0A90Fh ; pop gs
|
|
je HandFSGSflt
|
|
jmp short NoFSGSflt
|
|
HandFSGSflt:
|
|
if KDEBUG
|
|
Trace_Out "POP GS/FS fault fixed up!"
|
|
endif
|
|
mov ds, [bp].fsf_SS
|
|
mov si, [bp].fsf_SP
|
|
mov word ptr [si], 0
|
|
pop ds ; restore kernel DS
|
|
pop ax ; don't do EH_Chain
|
|
push codeOffset EH_ret ; use "handled it" return instead
|
|
ret
|
|
NoFSGSflt:
|
|
pop ds
|
|
endif
|
|
|
|
pop ax ; toss chain return
|
|
push codeOffset EH_ret ; use "handled it" return
|
|
|
|
mov si,word ptr FaultHandler ; SI = Handler
|
|
push si
|
|
mov word ptr FaultHandler,codeOffset NestedFault
|
|
|
|
if KDEBUG
|
|
test byte ptr [bp].fsf_flags+1,2 ; IF set in faulting frame?
|
|
jnz @F
|
|
Trace_Out "Fault with interrupts disabled!"
|
|
@@:
|
|
endif
|
|
cmp [bp].fsf_SP,128d
|
|
jb ff_stack
|
|
|
|
cCall HasGPHandler, <[bp].fsf_faulting_CS, [bp].fsf_faulting_IP>
|
|
or ax, ax
|
|
jz ff_real_fault
|
|
mov ds, [bp].fsf_SS
|
|
mov bx, [bp].fsf_SP
|
|
sub [bp].fsf_SP, 4
|
|
mov cx, [bp].fsf_err_code ; put error code on stack
|
|
mov [bx-2],cx
|
|
mov dx, [bp].fsf_faulting_IP
|
|
mov [bx-4],dx ; and faulting IP
|
|
mov [bp].fsf_faulting_IP, ax ; continue at gp fault handler
|
|
jmps ff_ret
|
|
|
|
ff_real_fault:
|
|
|
|
ifdef WOW
|
|
test DebugWOW,DW_DEBUG
|
|
jz ff_no_wdebug
|
|
|
|
xor ax,ax ; 0 in AX defaults to not handled
|
|
push DBG_GPFAULT2
|
|
|
|
FBOP BOP_DEBUGGER,,FastBop
|
|
|
|
add sp,+2
|
|
or ax, ax
|
|
|
|
jnz ff_ret ; Alright! they handled the exception!
|
|
; Get us back to the app please!
|
|
|
|
; Otherwise, they chose to continue the exception
|
|
|
|
ff_no_wdebug:
|
|
|
|
endif
|
|
|
|
if SHERLOCK
|
|
cCall GPContinue ; We know BP points to
|
|
or ax, ax ; the fault frame!
|
|
jnz ff_ret
|
|
endif
|
|
|
|
ff_stack:
|
|
call si ; call our fault handler
|
|
|
|
ff_ret:
|
|
SetKernelDS
|
|
pop FaultHandler
|
|
ret
|
|
FaultFilter endp
|
|
|
|
ifdef WOW
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; single_step
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
Entry single_step
|
|
push ds
|
|
SetKernelDS ds
|
|
|
|
push ax
|
|
|
|
; QCWIN traces through code which it has no source code for. This means
|
|
; its ends up tracing through the 16-bit to 32-bit transition code and
|
|
; when it traces on the call fword instruction, it cause 32-bit trace
|
|
; interrupt which breaks into the kd> On a retail build with no
|
|
; debugger attached, it might work.
|
|
; To work around the problem we turn off the TraceFlag here if wow16cal
|
|
; has requested it.
|
|
|
|
test TraceOff,1h
|
|
jnz ss_turn_off_trace_flag
|
|
|
|
test DebugWOW,DW_DEBUG
|
|
jz ss_no_wdebug
|
|
|
|
xor ax,ax ; 0 in AX defaults to not handled
|
|
push DBG_SINGLESTEP
|
|
|
|
FBOP BOP_DEBUGGER,,FastBop
|
|
|
|
add sp,+2
|
|
or ax, ax
|
|
|
|
jnz ss_ret ; Alright! they handled the exception!
|
|
; Get us back to the app please!
|
|
|
|
ss_no_wdebug:
|
|
|
|
; Otherwise, they chose to continue the exception
|
|
pop ax
|
|
pop ds
|
|
jmp cs:[prevInt01proc]
|
|
|
|
|
|
; Tell api code (wow16cal) to turn on trace flag at end of next api
|
|
|
|
ss_turn_off_trace_flag:
|
|
sub sp,2 ; Make it look like "normalized" fault frame
|
|
push bp
|
|
mov bp,sp
|
|
or TraceOff,2h
|
|
and [bp].fsf_flags,NOT FLG_TRAP ; turn off the trap flag
|
|
pop bp
|
|
add sp,2
|
|
ss_ret:
|
|
pop ax
|
|
pop ds
|
|
UnSetKernelDS ds
|
|
retf
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; breakpoint
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
Entry breakpoint
|
|
push ds
|
|
SetKernelDS ds
|
|
push ax
|
|
|
|
test DebugWOW,DW_DEBUG
|
|
jz br_no_wdebug
|
|
|
|
xor ax,ax ; 0 in AX defaults to not handled
|
|
push DBG_BREAK
|
|
|
|
FBOP BOP_DEBUGGER,,FastBop
|
|
|
|
add sp,+2
|
|
or ax, ax
|
|
|
|
jnz bp_ret ; Alright! they handled the exception!
|
|
; Get us back to the app please!
|
|
|
|
br_no_wdebug:
|
|
|
|
; Otherwise, they chose to continue the exception
|
|
pop ax
|
|
pop ds
|
|
jmp cs:[prevInt03proc]
|
|
|
|
bp_ret:
|
|
pop ax
|
|
pop ds
|
|
UnSetKernelDS ds
|
|
retf
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; divide_overflow
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
Entry divide_overflow
|
|
push ds
|
|
SetKernelDS ds
|
|
push ax
|
|
|
|
test DebugWOW,DW_DEBUG
|
|
jz di_no_wdebug
|
|
|
|
xor ax,ax ; 0 in AX defaults to not handled
|
|
push DBG_DIVOVERFLOW
|
|
|
|
|
|
FBOP BOP_DEBUGGER,,FastBop
|
|
.286p
|
|
add sp,+2
|
|
or ax, ax
|
|
|
|
jnz do_ret ; Alright! they handled the exception!
|
|
; Get us back to the app please!
|
|
|
|
di_no_wdebug:
|
|
|
|
; Otherwise, they chose to continue the exception
|
|
pop ax
|
|
pop ds
|
|
jmp cs:[oldInt00proc]
|
|
|
|
do_ret:
|
|
pop ax
|
|
pop ds
|
|
UnSetKernelDS ds
|
|
retf
|
|
|
|
|
|
endif
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; Set_GO_BP
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
public Set_GO_BP
|
|
Set_GO_BP proc near
|
|
mov cx, [bp].fsf_faulting_CS ; Faulting CS
|
|
mov bx, [bp].fsf_faulting_IP ; Faulting IP
|
|
DebInt 40h
|
|
; mov ax, 40h ; 16 bit forced go command
|
|
; int 41h ; Call debugger
|
|
;ifdef JAPAN
|
|
; INT41SIGNATURE
|
|
;endif
|
|
ret
|
|
Set_GO_BP endp
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; ExitFault -- Fault at Exit Time!!!
|
|
;
|
|
; ENTRY: BP points to fault frame described above
|
|
;
|
|
; EXIT: Returns to DPMI.
|
|
;
|
|
; Registers Modified: None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
ReSetKernelDS
|
|
|
|
public ExitFault
|
|
ExitFault proc near
|
|
if KDEBUG
|
|
Trace_Out "Fault at Exit Time!!!"
|
|
endif
|
|
;
|
|
; If a kernel debugger is loaded, pop out at the nested fault, and
|
|
; take no prisoners.
|
|
;
|
|
test Kernel_Flags[2],KF2_SYMDEB ; Debugger?
|
|
jz @F
|
|
jmp Set_GO_BP
|
|
@@:
|
|
jmps HandleFault
|
|
ExitFault endp
|
|
|
|
public BUNNY_351
|
|
BUNNY_351 proc far
|
|
push ds
|
|
SetKernelDS
|
|
mov FaultHandler,codeOffset ExitFault
|
|
pop ds
|
|
ret
|
|
BUNNY_351 endp
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; MY_RETF -- Executes a far return.
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
MY_RETF proc near
|
|
retf
|
|
MY_RETF endp
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; NestedFault -- Called when a fault handler Faults!!!
|
|
;
|
|
; ENTRY: BP points to fault frame described above
|
|
;
|
|
; EXIT: Returns to DPMI.
|
|
;
|
|
; Registers Modified: None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
ReSetKernelDS
|
|
|
|
public NestedFault
|
|
NestedFault proc near
|
|
if KDEBUG
|
|
Trace_Out "Nested Fault!!!"
|
|
endif
|
|
;
|
|
; If a kernel debugger is loaded, pop out at the nested fault, and
|
|
; take no prisoners.
|
|
;
|
|
test Kernel_Flags[2],KF2_SYMDEB ; Debugger?
|
|
jz @F
|
|
jmp Set_GO_BP
|
|
@@:
|
|
jmps HandleFault
|
|
NestedFault endp
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; HandleFault -- Puts up the System Error box for a Fault. Terminates
|
|
; the application or enters the debugger.
|
|
;
|
|
; ENTRY: BP points to fault frame described above
|
|
;
|
|
; EXIT: Returns to DPMI. If Cancel is pressed, we tell
|
|
; WDEB to set a GO breakpoint at the faulting instruction
|
|
; first. If OK is pressed, then the CS:IP on the DPMI
|
|
; fault frame is modified to point to KillApp, and the
|
|
; SS:SP points to a temp. stack owned by Kernel.
|
|
;
|
|
; Registers Modified: None
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
ReSetKernelDS
|
|
|
|
public HandleFault
|
|
HandleFault proc near
|
|
|
|
mov ax, lpGPChain.sel ; Do we have a private GP handler?
|
|
mov lpGPChain.sel, 0 ; Prevent re-entrancy
|
|
cmp ax, [bp].fsf_SS
|
|
jnz We_Can_Handle_It
|
|
|
|
test Kernel_Flags[2],KF2_SYMDEB ; Debugger?
|
|
jz @F
|
|
mov lpGPChain.sel,ax
|
|
|
|
jmp Set_GO_BP
|
|
@@:
|
|
; If we want to chain back for any
|
|
mov bx, lpGPChain.off ; faults, then set up the stack of
|
|
mov [bp].fsf_SP, bx ; the handler, and continue execution
|
|
mov [bp].fsf_faulting_CS, cs ; at a RETF in Kernel
|
|
mov [bp].fsf_faulting_IP, offset MY_RETF
|
|
|
|
cmp [pPostMessage.sel],0 ; is there a USER around yet?
|
|
je @F
|
|
pusha
|
|
push es
|
|
cCall [pPostMessage],<-1,WM_SYSTEMERROR,1,0,0>
|
|
pop es
|
|
popa
|
|
@@:
|
|
|
|
if kdebug
|
|
mov es, ax
|
|
mov ax, es:[bx+2]
|
|
mov bx, es:[bx]
|
|
krDebugOut DEB_ERROR, "Fault detected - handled by %AX2 #AX:#BX"
|
|
endif
|
|
|
|
jmp HandleFault_Exit
|
|
|
|
We_Can_Handle_It:
|
|
sub sp, UAE_STRING_LEN ; Room for string
|
|
mov si, sp
|
|
|
|
cCall FormatFaultString,<ss,si,[bp].fsf_msg,[bp].fsf_faulting_CS,[bp].fsf_faulting_IP>
|
|
|
|
push bp
|
|
xor bp,bp ; Some people are picky...
|
|
cCall Display_Box_of_Doom,<0,ss,si>
|
|
pop bp
|
|
|
|
add sp, UAE_STRING_LEN
|
|
|
|
or ax, ax
|
|
jne @F
|
|
INT3_DEBUG ; Failed call - no USER
|
|
@@:
|
|
cmp ax, 1 ; Button 1 (Cancel) pressed?
|
|
jne @F
|
|
jmp Set_GO_BP
|
|
@@:
|
|
|
|
test fBooting, 1 ; No, they said to Nuke app.
|
|
jnz no_signal_proc
|
|
|
|
mov ds, curTDB
|
|
|
|
UnSetKernelDS
|
|
|
|
cmp ds:[TDB_USignalProc].sel,0
|
|
jz no_signal_proc
|
|
mov bx,0666h
|
|
mov di, -1
|
|
|
|
cCall ds:[TDB_USignalProc],<ds,bx,di,ds:[TDB_Module],ds:[TDB_Queue]>
|
|
|
|
;
|
|
; Since we are on a nice big fat juicy fault handler stack now, we can call
|
|
; Windows to clean up after the task.
|
|
;
|
|
mov bx,SG_EXIT
|
|
cCall ds:[TDB_USignalProc],<ds,bx,di,ds:[TDB_Module],ds:[TDB_Queue]>
|
|
mov ds:[TDB_USignalProc].sel,0
|
|
|
|
no_signal_proc:
|
|
|
|
mov [bp].fsf_SP,dataOffset gmove_stack
|
|
mov [bp].fsf_SS,seg gmove_stack
|
|
mov [bp].fsf_faulting_CS,cs
|
|
|
|
lea ax,KillApp
|
|
mov [bp].fsf_faulting_IP,ax
|
|
HandleFault_Exit:
|
|
ret
|
|
|
|
HandleFault endp
|
|
|
|
; ------------------------------------------------------------------
|
|
;
|
|
; ExceptionHandlerProc -- Common entry point for exception handlers
|
|
;
|
|
; ------------------------------------------------------------------
|
|
public ExceptionHandlerProc
|
|
ExceptionHandlerProc proc far
|
|
|
|
push bp
|
|
mov bp,sp
|
|
pusha
|
|
push ds
|
|
SetKernelDS
|
|
push es
|
|
EH_Popup:
|
|
call FaultFilter
|
|
EH_Chain:
|
|
pop es
|
|
pop ds
|
|
UnsetKernelDS
|
|
popa
|
|
pop bp
|
|
add sp,2 ; remove message from stack
|
|
retf ; chain to prev handler
|
|
EH_ret:
|
|
pop es
|
|
pop ds
|
|
popa
|
|
pop bp
|
|
add sp,fsf_OFFSET
|
|
retf
|
|
|
|
ExceptionHandlerProc endp
|
|
|
|
|
|
; ------------------------------------------------------------------
|
|
;
|
|
; This macro sets up the stack frame for entry to the generic
|
|
; exception handler.
|
|
;
|
|
; ------------------------------------------------------------------
|
|
ExceptionHandlerPrologue macro name,msg,chain
|
|
public name
|
|
name:
|
|
if ROM
|
|
sub sp,6
|
|
push bp
|
|
push ds
|
|
push ax
|
|
mov bp,sp
|
|
SetKernelDS
|
|
mov word ptr [bp+6],offset msg
|
|
mov ax, word ptr [chain][0]
|
|
mov [bp+8],ax
|
|
mov ax, word ptr [chain][2]
|
|
mov [bp+10],ax
|
|
UnsetKernelDS
|
|
pop ax
|
|
pop ds
|
|
pop bp
|
|
else
|
|
push word ptr chain + 2
|
|
push word ptr chain
|
|
push offset msg
|
|
endif
|
|
endm
|
|
|
|
; ------------------------------------------------------------------
|
|
;
|
|
; This macro sets up the stack frame, then jumps to the generic
|
|
; exception handler.
|
|
;
|
|
; ------------------------------------------------------------------
|
|
ExceptionHandler macro name,msg,chain
|
|
ExceptionHandlerPrologue name,msg,chain
|
|
jmp ExceptionHandlerProc
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
endm
|
|
|
|
; ------------------------------------------------------------------
|
|
;
|
|
; Four fatal ones.
|
|
;
|
|
; ------------------------------------------------------------------
|
|
ExceptionHandler StackFault,szSF,prevInt0Cproc
|
|
ExceptionHandler GPFault,szGP,prevInt0Dproc
|
|
ExceptionHandler invalid_op_code_exception,szII,prevIntx6proc
|
|
ExceptionHandler page_fault,szPF,prevInt0Eproc
|
|
ExceptionHandler LoadSegFailed,szLoad,prevInt3Fproc
|
|
|
|
; ------------------------------------------------------------------
|
|
;
|
|
; The not present fault is used to demand-load segments from newexe
|
|
; files. If we find out that something bogus has happened, then
|
|
; we just jump into the fault handler.
|
|
;
|
|
; ------------------------------------------------------------------
|
|
ExceptionHandlerPrologue SegmentNotPresentFault,szNP,prevInt3Fproc
|
|
|
|
push bp
|
|
mov bp,sp
|
|
pusha
|
|
push ds
|
|
SetKernelDS
|
|
push es
|
|
|
|
mov al,byte ptr [bp].fsf_faulting_CS
|
|
and al, SEG_RING_MASK ; Check it was Ring 1, LDT
|
|
cmp al, SEG_RING
|
|
|
|
je @F
|
|
jmp EH_Chain
|
|
@@:
|
|
mov al,byte ptr [bp].fsf_err_code
|
|
test al, SEL_LDT ; Check it was LDT
|
|
|
|
jne @F
|
|
jmp EH_Chain
|
|
@@:
|
|
|
|
if KDEBUG
|
|
test byte ptr [bp].fsf_flags+1,2 ; IF set in faulting frame?
|
|
jnz @F
|
|
Trace_Out "Segment not present fault with interrupts disabled!"
|
|
@@:
|
|
endif
|
|
FSTI
|
|
;
|
|
; Don't discard the segment that we have to return to!!!
|
|
;
|
|
cCall GlobalHandleNorip,<[bp].fsf_faulting_CS>
|
|
test cl,GA_DISCARDABLE
|
|
jz @F
|
|
cCall GlobalLRUNewest,<ax>
|
|
@@:
|
|
|
|
mov bx,[bp].fsf_err_code
|
|
seg_reload:
|
|
and bx, NOT 7h ; get the not present selector
|
|
or bl, SEG_RING ; Correct RING bits
|
|
if KDEBUG
|
|
mov INT3Fcs, bx ; Save in case of error
|
|
endif
|
|
|
|
if PMODE32
|
|
; On WOW we don't copy the owner to the real LDT since it is slow to call
|
|
; the NT Kernel, so we read our copy of it directly.
|
|
; see set_discarded_sel_owner mattfe mar 23 93
|
|
|
|
mov es,cs:gdtdsc
|
|
mov cx,bx ; save bx
|
|
and bl, not 7
|
|
mov es,es:[bx].dsc_owner
|
|
mov bx,cx ; restore
|
|
else
|
|
lsl cx, bx ; mov es,[bx].he_owner
|
|
mov es, cx
|
|
endif
|
|
StoH bl ; Need handle
|
|
|
|
cmp es:[ne_magic],NEMAGIC ; If owner is not a module
|
|
jnz bad_seg_load ; (i.e., an instance or garbage)
|
|
; get out of here.
|
|
mov di,es:[ne_segtab]
|
|
mov ax,1
|
|
mov cx, es:[ne_cseg]
|
|
jcxz bad_seg_load
|
|
dorten:
|
|
cmp es:[di].ns_handle,bx
|
|
jz got_seg_no
|
|
add di,SIZE NEW_SEG1
|
|
inc ax
|
|
loop dorten
|
|
|
|
; program has referenced garbage...
|
|
|
|
bad_seg_load:
|
|
jmp EH_Popup
|
|
|
|
got_seg_no:
|
|
|
|
;
|
|
; If we already are on the exception handler stack, then we want to make
|
|
; sure that we don't overwrite the original stack frame. Copy our
|
|
; stack frame variables down by the difference between SP and SP before
|
|
; we got called.
|
|
;
|
|
push ax
|
|
mov ax,ss
|
|
cmp ax,word ptr [bp].fsf_SS
|
|
pop ax
|
|
jne stack_OK
|
|
push ax
|
|
push bx
|
|
push bp
|
|
lea bp,word ptr [bp].fsf_SS
|
|
mov ax,sp
|
|
dec ax
|
|
dec ax
|
|
@@:
|
|
push word ptr [bp]
|
|
dec bp
|
|
dec bp
|
|
cmp bp,ax
|
|
jne @B
|
|
pop bp
|
|
pop bx
|
|
pop ax
|
|
;
|
|
; Figured out what this was supposed to be by tracing up to here
|
|
; in the debugger.
|
|
;
|
|
sub bp,32h
|
|
|
|
stack_OK:
|
|
push es
|
|
mov bx,ax
|
|
UnsetKernelDS
|
|
mov ax,ss
|
|
mov ds,ax
|
|
les di,dword ptr [bp].fsf_SP
|
|
dec di
|
|
dec di
|
|
std
|
|
;
|
|
; Push an IRET frame on the faulting stack.
|
|
;
|
|
lea si,[bp].fsf_flags
|
|
mov cx,3
|
|
rep movsw
|
|
;
|
|
; Push our saved registers on the faulting stack.
|
|
;
|
|
lea si,[bp]
|
|
mov cx,11 ; BP + PUSHA + ES + DS
|
|
rep movsw
|
|
|
|
pop ax
|
|
;
|
|
; Push arguments to LoadSegment on the faulting stack.
|
|
;
|
|
stosw ; hExe
|
|
mov ax,bx
|
|
stosw ; segno
|
|
mov ax,-1
|
|
stosw
|
|
stosw
|
|
inc di
|
|
inc di
|
|
;
|
|
; Point the faulting stack at the new location.
|
|
;
|
|
mov [bp].fsf_SP,di
|
|
;
|
|
; Tell DPMI to return to us instead of the faulting code.
|
|
;
|
|
mov [bp].fsf_faulting_CS,cs
|
|
mov [bp].fsf_faulting_IP,offset let_them_do_it
|
|
lea sp,[bp].fsf_ret_IP
|
|
|
|
if kdebug
|
|
SetKernelDS
|
|
mov wFaultSegNo, bx
|
|
UnSetKernelDS
|
|
endif
|
|
retf
|
|
let_them_do_it:
|
|
SetKernelDS
|
|
|
|
xor cx, cx ; we try to keep a selector reserved
|
|
xchg cx, DemandLoadSel ; for scratch use while demand
|
|
jcxz @f ; loading segments--free it to make
|
|
cCall IFreeSelector,<cx> ; it available now
|
|
@@:
|
|
cCall LoadSegment
|
|
|
|
push ax ; reserve a selector for the next
|
|
cCall AllocSelector,<0> ; time we demand load a segment
|
|
mov DemandLoadSel, ax
|
|
pop cx ; LoadSegment result
|
|
jcxz SegLoaderFailure
|
|
|
|
if kdebug
|
|
push bx
|
|
mov bx, wFaultSegNo
|
|
krDebugOut <DEB_TRACE or DEB_krLoadSeg>, "Demand load %CX2(#bx) on %SS2"
|
|
pop bx
|
|
endif
|
|
pop es
|
|
pop ds
|
|
UnsetKernelDS
|
|
popa
|
|
pop bp
|
|
|
|
;** Check to see if we're about to restart an instruction in
|
|
;** a not present segment. This would only occur if the
|
|
;** segment was discarded because of the segment load we
|
|
;** just did.
|
|
IF KDEBUG
|
|
push bp ;Make a stack frame
|
|
mov bp,sp
|
|
push ax
|
|
mov bp,[bp + 4] ;Get the CS
|
|
lar ax,bp ;See if the CS is valid
|
|
test ax,8000h ;Is it present?
|
|
jnz @F ;Yes, don't complain
|
|
mov ax,bp
|
|
Trace_Out <'LDINT: Trying to restart discarded caller (#AX)'>
|
|
@@:
|
|
pop ax
|
|
pop bp
|
|
ENDIF
|
|
iret
|
|
|
|
public SegLoaderFailure
|
|
SegLoaderFailure proc near
|
|
;
|
|
; segment loader was unable to load the segment!!!
|
|
; Restore all the registers, create a fake DPMI frame, then
|
|
; complain about the problem. Lets the user break into the
|
|
; debugger, if installed, on Cancel. Creating and destroying
|
|
; the fake DPMI frame is inconvenient and messy, but it lets
|
|
; us handle the problem in common fault code.
|
|
;
|
|
pop es
|
|
pop ds
|
|
UnsetKernelDS
|
|
popa
|
|
|
|
sub sp,4
|
|
mov bp,sp ; BP -> xx xx BP IP CS FL
|
|
push word ptr [bp+4] ; push app's BP
|
|
push ax ; get a temporary register
|
|
mov ax,[bp+6] ; IP
|
|
mov [bp+2],ax
|
|
mov ax,[bp+8] ; CS
|
|
mov [bp+4],ax
|
|
mov ax,[bp+10] ; Flags
|
|
mov [bp+6],ax
|
|
mov [bp+10],ss
|
|
lea ax,[bp+12]
|
|
mov [bp+8],ax
|
|
pop ax
|
|
pop bp
|
|
|
|
call far ptr LoadSegFailed ; BP -> RETIP RETCS EC IP CS FL SP SS
|
|
|
|
push bp
|
|
mov bp,sp ; BP -> BP EC IP CS FL SP SS
|
|
mov [bp+2],ax
|
|
mov ax,[bp+8] ; Flags
|
|
mov [bp+12],ax
|
|
mov ax,[bp+6] ; CS
|
|
mov [bp+10],ax
|
|
mov ax,[bp+4] ; IP
|
|
mov [bp+8],ax
|
|
pop bp
|
|
pop ax
|
|
add sp,4
|
|
iret
|
|
|
|
SegLoaderFailure endp
|
|
|
|
;ENDIF
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; default_sig_handler
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Wed 10-Jan-1990 22:32:34 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc default_sig_handler,<PUBLIC,FAR>
|
|
|
|
cBegin nogen
|
|
|
|
ret
|
|
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; Panic -- Called by ToolHelp when it gets a bad stack fault or any
|
|
; other fault with SP suspiciously low.
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc Panic,<PUBLIC,NEAR>
|
|
cBegin
|
|
if KDEBUG
|
|
Trace_Out "KERNEL: Panic called!!!"
|
|
endif
|
|
int 1
|
|
jmp KillApp
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; DoSignal
|
|
;
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Wed 10-Jan-1990 22:52:52 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc DoSignal,<PUBLIC,FAR>,<ax,bx,cx,dx,di,si,es>
|
|
cBegin
|
|
SetKernelDS
|
|
cmp pUserGetFocus.sel,0 ; is there a USER yet?
|
|
jz ds_exit
|
|
call pUserGetFocus
|
|
or ax,ax
|
|
jz ds_exit
|
|
mov si,ax
|
|
cCall pUserIsWindow,<ax>
|
|
or ax,ax
|
|
jz ds_exit
|
|
cCall pUserGetWinTask,<si>
|
|
mov ds,ax
|
|
TDB_check_DS
|
|
cmp ds:[TDB_SigAction],2 ; send it on?
|
|
jnz ds_exit
|
|
mov ax,1
|
|
xor bx,bx
|
|
cCall ds:[bx].TDB_ASignalProc,<bx,ax>
|
|
ds_exit:
|
|
|
|
cEnd
|
|
|
|
|
|
|
|
sEnd CODE
|
|
|
|
sBegin MISCCODE
|
|
assumes cs, misccode
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
externNP MISCMapDStoDATA
|
|
|
|
ifdef WOW
|
|
externFP htoa
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; allows htoa to be called from _TEXT code segment
|
|
cProc Far_htoa,<PUBLIC,FAR>
|
|
parmD lpstr
|
|
parmW val
|
|
cBegin
|
|
push [bp+10]
|
|
push [bp+8]
|
|
push [bp+6]
|
|
call far ptr htoa
|
|
cEnd
|
|
|
|
endif ;; WOW
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; SetSigHandler
|
|
;
|
|
; SetSigHandler notifies Windows of a handler for a signal.
|
|
; It may also be used to ignore a signal or install a default
|
|
; action for a signal.
|
|
;
|
|
; Entry:
|
|
; parmD lpprocRoutine Signal handler
|
|
; parmD lpDPrevAddress Previous handler (returned)
|
|
; parmD lpWPrevAction Previous action (returned)
|
|
; parmW Action Indicate request type
|
|
; parmW SigNumber Signal number of interest
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Mon 25-Dec-1989 00:36:01 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc SetSigHandler,<PUBLIC,FAR>,<di,si,ds>
|
|
|
|
parmD lpprocRoutine
|
|
parmD lpDPrevAddress
|
|
parmD lpWPrevAction
|
|
parmW Action
|
|
parmW SigNumber
|
|
cBegin
|
|
call MISCMapDStoDATA
|
|
ReSetKernelDS
|
|
cmp SigNumber,1 ; is it SIGINTR?
|
|
jnz dssh_return_success ; ignore if not
|
|
|
|
cmp Action,4 ; is it reset Signal?
|
|
jz @F
|
|
|
|
push ds
|
|
mov ds,curTDB
|
|
assumes ds,nothing
|
|
mov ax,Action
|
|
xchg ax,ds:[TDB_SigAction]
|
|
les bx,lpWPrevAction
|
|
mov cx,es
|
|
or cx,bx
|
|
jz @F
|
|
mov es:[bx],ax
|
|
@@:
|
|
mov dx,lpprocRoutine.sel
|
|
mov ax,lpprocRoutine.off
|
|
cmp Action,0 ; put in default handler?
|
|
jnz ssg_stick_it_in
|
|
mov dx,SEG default_sig_handler
|
|
mov ax,codeOffset default_sig_handler
|
|
ssg_stick_it_in:
|
|
xchg dx,ds:[TDB_ASignalProc].sel
|
|
xchg ax,ds:[TDB_ASignalProc].off
|
|
cmp Action,4 ; is it reset Signal?
|
|
jz @F
|
|
les bx,lpDPrevAddress
|
|
mov cx,es
|
|
or cx,bx
|
|
jz @F
|
|
mov es:[bx].sel,dx
|
|
mov es:[bx].off,ax
|
|
pop ds
|
|
@@:
|
|
|
|
dssh_return_success:
|
|
xor ax,ax ; return success
|
|
|
|
dssh_exit:
|
|
|
|
cEnd
|
|
|
|
;----------------------------------------------------------------------------
|
|
;
|
|
; SwapRecording(Flag)
|
|
;
|
|
; Flag = 0 => Stop recording
|
|
; = 1 => Start recording only Swaps, Discards and Returns
|
|
; = 2 => Start recording Calls in addition to Swaps, Discards and
|
|
; returns.
|
|
; Destroys AL register
|
|
;----------------------------------------------------------------------------
|
|
|
|
; Retail Version
|
|
|
|
cProc ISwapRecording,<PUBLIC, FAR>
|
|
; parmW Flag
|
|
cBegin nogen
|
|
retf 2
|
|
cEnd nogen
|
|
|
|
sEnd MISCCODE
|
|
|
|
end
|