windows-nt/Source/XPSP1/NT/base/mvdm/wow16/kernel31/gpcont.asm
2020-09-26 16:20:57 +08:00

306 lines
6 KiB
NASM

; GPCont.asm - code to allow continuation after GP faults
.xlist
include kernel.inc
include newexe.inc ; ne_restab
include gpcont.inc
.list
if SHERLOCK
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_DS equ word ptr -10
fsf_ES equ word ptr -10
fsf_FS equ word ptr -10
fsf_GS equ word ptr -10
;flag bits set in gpRegs
strCX = 1
strSI = 2
strDI = 4
segDS = 8
segES = 16
segFS = 32
segGS = 64
ifdef WOW
sBegin MISCCODE
externFP DisAsm86
assumes ds,nothing
assumes es,nothing
;-----------------------------------------------------------------------;
; allows DisAsm86 to be called from _TEXT code segment
cProc Far_DisAsm86,<PUBLIC,FAR>,<dx>
parmD cp
cBegin
mov ax,cp.off
mov dx,cp.sel
cCall <far ptr DisAsm86>,<dx,ax>
cEnd
sEnd MISCCODE
endif ;; WOW
DataBegin
externB szGPCont
szKernel db 6,'KERNEL'
szUser db 4,'USER'
szDrWatson db 'DRWATSON'
externW gpTrying ; retrying current operation
externW gpEnable ; user has enabled GP continue
externW gpSafe ; current instruction is safe
externW gpInsLen ; length of faulting instruction
externW gpRegs ; bit field of modified regs
externD pSErrProc ; pointer to SysErrBox in USER
DataEnd
externFP IsBadCodePtr
externFP FarFindExeInfo
sBegin CODE
assumes CS,CODE
ifndef WOW
externNP DisAsm86
endif
externNP GetOwner
;extern int far pascal SysErrorBox(char far *text, char far *caption,
; int b1, int b2, int b3);
SEB_OK = 1 ; Button with "OK".
SEB_CANCEL = 2 ; Button with "Cancel"
SEB_YES = 3 ; Button with "&Yes"
SEB_NO = 4 ; Button with "&No"
SEB_RETRY = 5 ; Button with "&Retry"
SEB_ABORT = 6 ; Button with "&Abort"
SEB_IGNORE = 7 ; Button with "&Ignore"
SEB_CLOSE = 8 ; Button with "Close"
SEB_DEFBUTTON = 8000h ; Mask to make this button default
SEB_BTN1 = 1 ; Button 1 was selected
SEB_BTN2 = 2 ; Button 1 was selected
SEB_BTN3 = 3 ; Button 1 was selected
;Name: int PrepareToParty(char *modName)
;Desc: Checks whether we can continue the current app by skipping an
; instruction. If so, it performs the side effects of the
; instruction. This must be called after a call to DisAsm86() has
; set the gpXxxx global vars.
;Bugs: Should do more checking, should check for within a device driver,
cProc PrepareToParty,<PUBLIC,NEAR>,<si,di>
parmD modName
parmD appName
cBegin
ReSetKernelDS
mov ax, [gpEnable] ; User enabled continue
test ax, 1 ; We know how to continue
jz ptp_poop
cld
dec [modName.off] ; include length byte in compare
les di, [modName]
test ax, 4 ; can continue in KERNEL?
jnz @F
lea si, szKernel
mov cx, 7
repe cmpsb
jz ptp_poop ; fault in Kernel is fatal
@@: test ax, 8 ; can continue in USER?
jnz @F
mov di, modName.off
lea si, szUser
mov cx, 5
repe cmpsb
jz ptp_poop ; fault in User is fatal
@@: cmp [gpTrying], 0
jne ptp_exit ; AX != 0 - do it again
cmp pSErrProc.sel, 0 ; Is USER loaded?
je ptp_poop
mov ax, dataoffset szGPCont
mov bx, SEB_CLOSE or SEB_DEFBUTTON ; dumb cmacros
cCall [pSErrProc],<ds, ax, appName, bx, 0, SEB_IGNORE>
cmp ax, SEB_BTN3
jne ptp_poop
; mov [gpTrying], 100
jmps ptp_exit ; AX != 0
ptp_poop: ; every party needs a pooper
xor ax, ax
ptp_exit:
cEnd
UnSetKernelDS
cProc SafeDisAsm86,<NEAR,PUBLIC>
parmD cp
cBegin
ReSetKernelDS
mov [gpSafe], 0 ; assume unsafe
mov bx, cp.off ; make sure we can disassemble
add bx, 10 ; at least a 10-byte instruction
jc sda_exit ; offset wrap-around - failed
cCall IsBadCodePtr,<seg_cp, bx>
or ax, ax
jnz sda_exit
ifdef WOW
cCall <far ptr Far_DisAsm86>,<cp>
else
cCall DisAsm86,<cp>
endif
mov [gpInsLen], ax
sda_exit:
cEnd
; return value in DX:AX and ES:AX (your choice), sets Z flag if failure
cProc FindSegName,<NEAR,PUBLIC>,<ds>
parmW segval
cBegin
cCall GetOwner,<segval>
mov dx, ax
or ax, ax
jz fsn_exit
mov es, ax
mov ax, es:[ne_restab]
inc ax
fsn_exit:
cEnd
public GPContinue
GPContinue proc near
push si ; instruction length
test [gpEnable], 1
jz s_fail
cCall SafeDisAsm86,<[bp].fsf_faulting_CS,[bp].fsf_faulting_IP>
test [gpSafe], 1
jz s_fail
push ds
push dataoffset szDrWatson
push 8
Call FarFindExeInfo
or ax, ax
jnz s_fail
cCall FindSegName,<[bp].fsf_faulting_CS>
jz s_fail
push dx
push ax
cCall FindSegName,<[bp].fsf_SS>
jz s_fail4
push dx
push ax
cCall PrepareToParty
or ax, ax
jz s_fail
; Perform side-effects
mov ax, [gpRegs] ; Invalid value to DS?
test ax, segDS
jz @F
mov [bp].fsf_DS, 0
@@: test ax, segES ; Invalid value to ES?
jz @F
mov [bp].fsf_ES, 0
if PMODE32
.386p
@@: xor bx, bx ; Invalid value to FS?
test ax, segFS
jz short @F
mov fs, bx
@@: test ax, segGS ; Invalid value to GS?
jz short @F
mov gs, bx
.286p
endif
@@:
test ax, 0
; check other reg side effects
mov bx, [gpInsLen] ; Fixup IP for instruction length
add [bp].fsf_faulting_IP, bx
mov ax, 1
jmps s_end
s_fail4:
add sp, 4
s_fail:
xor ax, ax
s_end:
pop si
ret
GPContinue endp
sEnd CODE
endif ; SHERLOCK
end
regs.ip += faultlen; /* set at top of func - don't reuse
if ((int)gpStack < 0) {
for (i=0; i<8; i++) stack[i+gpStack] = stack[i];
} else if (gpStack) {
for (i=7; i>=0; i--) stack[i+gpStack] = stack[i];
}
regs.sp += gpStack << 1;
if (gpRegs & strCX) {
len = regs.cx * memSize;
regs.cx = 0;
} else len = memSize;
if (gpRegs & strSI) { /* doesn't handle 32 bit regs
regs.si += len;
if (regs.si < (word)len) /* if overflow, set to big value
regs.si = 0xfff0; /* so global vars in heap don't get
} /* trashed when we continue
if (gpRegs & strDI) {
regs.di += len;
if (regs.di < (word)len) regs.di = 0xfff0;
}
}
return party;
} /* Sherlock