;       SCCSID = @(#)dynci.asm	6.1 90/11/17
SCCSID	equ	"@(#)dynci.asm		13.11 90/10/11"
PAGE	,132
TITLE	DYNCI.ASM - Dynamic Trace Command Interpreter
NAME	DYNCI

;***	DYNCI.ASM -- Dynamic Trace Command Interpreter
;
;	IBM/Microsoft Confidential
;
;	Copyright (c) IBM Corporation 1987, 1989
;	Copyright (c) Microsoft Corporation 1987, 1989
;
;	All Rights Reserved
;
;	This file implements the Dynamic Trace Command Interpreter
;
;	This function is called from _DYNTrap3, to gather information
;	to log a DynamicTrace tracepoint.
;
;	Note: Any DynamicTrace tracepoints set in this file will
;	be automaticly and silently removed if hit.
;
;  Change Activity:
;
;  19th Mar 96 RJM Implement new RPN OPs for Merlin
;
.xlist
	include dosseg.inc
	include basemaca.inc
	include osmaca.inc
	include fnotask.inc
	include dossymc.inc
	include sigdef.inc
	include except.inc
	include osconst.inc
	include infoseg.inc
	include pgexport.inc
	include vmexport.inc
	include selxport.inc
	include seldesc.inc
	include tkexport.inc
	include mi.inc
	include systrace.inc
	include dynxport.inc
	include dynapi.inc
	include dynlocal.inc
        include sem.inc              ; RJM2 included for tkptda.inc
        include screen.inc           ; RJM2 included for tkptda.inc
        include curdir.inc           ; RJM2 included for tkptda.inc
        include dirent.inc           ; RJM2 included for tkptda.inc
        include find.inc             ; RJM2 included for tkptda.inc
	include tkptda.inc   ;rjm2
.list

if	RAS

	CpuMode 386
	ModName ,FNO_DYNCI_ASM

	ReferFlat	IDT,DWORD

	ReferFlat	tci_Fault0,byte
	ReferFlat	tci_Fault1,byte

	ReferFlat	_pPTDACur,dword
	EXTRN32 _SELSelToLa
	EXTRN32 _SELLaToSel
        EXTRN32 _PLD32ApiDump ;rjm2
   EXTRN RASRST:FAR ;RJM

;***LM	FAULTLABEL - Emit a label for fault detection
;
;	All instructions inside the dynamic trace interpreter which
;	can cause a GP fault or a Page fault on access to user memory
;	MUST be preceeded by an invocation of FAULTLABEL.  FAULTLABEL
;	emits a label which is used to discern expected vs. unexpected
;	faults in the interpreter, and to ascertain whether the fault
;	was due to a user-space access or a log buffer overflow.
;
;	Failre to preceed faulting instructions with OVERFLOWLABEL
;	or FAULTLABEL will result in a Panic on a GP fault at that
;	address.
;
;	The 'kind' of fault tells the GP fault handler how to
;	manage the fault.  It is required, and can be one of :
;
;	FAULT_FROMTOS	= Fault due to segment load from TOS (TOS:0 logged)
;	FAULT_DS_SI	= Fault at DS:SI due to lodsb (DS:SI logged)
;	FAULT_FS_AX	= Fault at FS:AX due to mov (FS:AX logged)
;	FAULT_FS_SI	= Fault at FS:SI due to mov (FS:SI logged)
;	FAULT_PAGE	= GP fault not expected here, page faults only

FAULT_PAGE	EQU	0
FAULT_FROMTOS	EQU	1
FAULT_DS_SI	EQU	2
FAULT_FS_AX	EQU	3
FAULT_FS_SI	EQU	4

MakeFLab	macro n
	tci_Fault&n:
endm

?faults = 2			; start at 2 for statically initialized entries
				;   for SELSelToLa and SELLaToSel
FAULTLABEL	macro	kind
if1
    ifdef   FAULTTABLEBUILT
	%out	<FAULTLABEL : Fault Table Already Generated>
	.err
    endif
endif
	mov	ss:[ebp].dt_FaultKind,kind	; Store fault kind.
	MakeFLab %?faults			; Make fault label
	?faults = ?faults + 1
endm


;***LM	OVERFLOWLABEL - Emit a label for log overflow detection
;
;	All instructions inside the dynamic trace interpreter which
;	access new parts of the log buffer MUST be preceeded by an
;	invocation of OVERFLOWLABEL.  OVERFLOWLABEL emits a label
;	which is used to discern log overflows from other faults in
;	the interpreter

MakeOLab	macro n
	tci_Overflow&n:
endm

?overflows = 0
OVERFLOWLABEL	macro
if1
    ifdef   OVERFLOWTABLEBUILT
	%out	<OVERFLOWLABEL : Overflow Table Already Generated>
	.err
    endif
endif
	MakeOLab %?overflows			; Make Overflow Label
	?overflows = ?overflows + 1
endm


;***LM	FAULTTABLE - Build table of fault labels
;
;	FAULTTABLE creates a table of flat offsets to all of the
;	FAULTLABEL labels.  Note that this macro only knows about the
;	labels defined which are textually above it's invocation, so
;	the fault table must appear near the end of this file.

MakeFTabEntry	macro n
	dd	offset FLAT:tci_Fault&n
endm

FAULTTABLE	macro
	FAULTTABLEBUILT		EQU	1

	?i = 0
	rept ?faults
		MakeFTabEntry %?i
		?i = ?i + 1
	endm
endm


;***LM	OVERFLOWTABLE - Build table of overflow labels
;
;	OVERFLOWTABLE creates a table of flat offsets to all of the
;	OVERFLOWTABLE labels.  Note that this macro only knows about
;	the labels defined which are textually above it's invocation,
;	so the overflow table must appear near the end of this file.
;

MakeOTabEntry	macro n
	dd	offset FLAT:tci_Overflow&n
endm

OVERFLOWTABLE	macro
	OVERFLOWTABLEBUILT	EQU	1

	?i = 0
	rept ?overflows
		MakeOTabEntry %?i
		?i = ?i + 1
	endm
endm


;***LM	RPNPush - increment top of RPN stack pointer.
;
;	RPNPush increments the top of stack pointer held in EDX.
;	No data transfer to the RPN stack occurs.

RPNPush macro
	inc	edx
	and	edx,15
endm


;***LM	RPNPop - decrement top of RPN stack pointer.
;
;	RPNPop decrement the top of stack pointer held in EDX.
;	No data transfer to the RPN stack occurs.

RPNPop	macro
	dec	edx
	and	edx,15
endm


;***LM	RPNGetTOSzx - Move top element of RPN stack to a register
;
;	RPNGetTOSzx <dword reg>
;
;	RPNGetTOSzx moves the top word element of the RPN stack
;	into a register.  The high word of the register is zeroed.
;	No motion of the RPN stack occurs.

RPNGetTOSzx macro reg
	movzx	reg,WORD PTR es:dtb_RPNStack[edx*4]
endm


;***LM	RPNGetTOS - Move top element of RPN stack to a register
;
;	RPNGetTOS <reg>
;
;	RPNGetTOS moves the top element of the RPN stack into a register.
;	No motion of the RPN stack occurs.

RPNGetTOS macro reg
	mov	reg,es:dtb_RPNStack[edx*4]
endm


;***LM	RPNPutTOS - Move top element of RPN stack to a register
;
;	RPNPutTOS <reg>
;
;	RPNPutTOS moves a register to the top element of the RPN stack.
;	No motion of the RPN stack occurs.

RPNPutTOS macro reg
	mov	es:dtb_RPNStack[edx*4],reg
endm

	FARCODE HIGH32
DYNLOCK_TEXT	segment

;***LP	_dynInterpreter - DynamicTrace Command Interpreter
;
;	_dynInterpreter interprets the DynamicTrace code stored
;	in the DTR when a tracepoint is taken.
;
;	ENTRY	(EBX) = pdto
;		(ECX) = pdtr
;		(DS) = Flat
;		(ES) = DTB selector.  Limit adjusted to max log length.
;		(SS:EBP) -> dtci_s structure
;
;	EXIT	Dynamic Tracepoint Interpreted.
;		Data to log stored in dtb_Log
;		dtb_fAbort = FALSE
;			Data is to be saved in STDA after Single Step
;
;		dtb_fAbort = TRUE
;			Do not save data in STDA after Single Step.
;
;	USES	EAX, EBX, ECX, EDX, EDI, ESI, EFlags

Procedure _dynInterpreter
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	es:[dtb_fAbort],0	; No abort selected yet
	mov	ax,[ecx].dtr_MinCode
	mov	es:[dtb_MinCode],ax	; Record minor code
	mov	ax,[ecx].dtr_MajCode
	mov	es:[dtb_MajCode],ax	; Record major code

;	Set default RAS flags (no error) to be used in the RAS log header.

	mov	es:[dtb_bfRas],RF_DYNLINK + RF_PROTECT + RF_DYNTRC

;	*** BEGIN IDT EDIT.  BE SURE THAT DEBUG VECTORS D AND E ARE CLEAR. ***
;	Edit the IDT to set up private GP fault and Page fault trap gates.
;	This allows us to trace the trap manager code for GP faults and
;	page faults, and avoids blocking problems when taking a page
;	fault.  It does not slow down the standard page fault code path.

	mov	esi,(offset FLAT:IDT)+8*0dh	; (DS:ESI)-> GP fault gate
	push	[esi+0*4]		; Save GP fault gate low DWORD
	push	[esi+1*4]		; Save GP fault gate high DWORD
	push	[esi+2*4]		; Save Page fault gate low DWORD
	push	[esi+3*4]		; Save Page fault gate high DWORD
	mov	edx,cr2
	push	edx			; Save CR2 for nested page faults

	; Setup GP Fault and Page Fault gates.

	mov	eax,D_TRAP032 SHL 24	; Trap gate.
	mov	ax,cs			; Current CS.
	mov	edx,offset FLAT:tci_GPFault
	mov	[esi+0*8+0],dx		; GP fault low offset
	mov	[esi+0*8+2],eax		; GP fault CS and atr. byte
	shr	edx,16
	mov	[esi+0*8+6],dx		; GP fault high offset

	mov	edx,offset FLAT:tci_PageFault
	mov	[esi+1*8+0],dx		; Page fault low offset
	mov	[esi+1*8+2],eax		; Page fault CS and atr. byte
	shr	edx,16
	mov	[esi+1*8+6],dx		; Page fault high offset

;	End IDT Edit.

	xor	edx,edx			; (EDX) -> Index of top of RPN stack
	lea	esi,[ecx].size dtr_s	; (DS:ESI) -> Instruction Stream
	movzx	ebx,[ecx].dtr_cbDTCODE	; (EBX) = length of instruction stream
	add	ebx,esi			; (EBX) -> End of Instruction Stream
	mov	ss:[ebp].dt_pLog,offset dtb_Log ; Set initial log offset
	mov	ss:[ebp].dt_ESP,esp	; return ESP stored for fault handlers

;	Interpreter main loop :
;
;	Standard Interpreter Routine Entry Conditions :
;
;	ENTRY:
;		(AL)  = Opcode byte
;		(EBX) = End of instruction stream pointer
;		(ECX) = Undefined
;		(EDX) = Top of RPN stack
;		(ESI) = Operand Pointer
;		(EDI) = Undefined
;		(EBP) = dtci_frame pointer (stack relative)
;		(DS)  = Flat
;		(ES)  = DTB selector.  (ES:0)-> dtb_s
;		(FS)  = Undefined.  Available.
;		(GS)  = Undefined.  DO NOT MODIFY !!!
;
;	EXIT:
;		(AL)  = Undefined
;		(EBX) = End of instruction stream pointer	(unchanged)
;		(ECX) = Undefined
;		(EDX) = Top of RPN stack			(modified)
;		(ESI) = Operand Pointer				(modified)
;		(EDI) = Undefined
;		(EBP) = dtci_frame pointer			(unchanged)
;		(DS)  = Flat					(unchanged)
;		(ES)  = DTB selector.				(unchanged)
;		(FS)  = Undefined.  Available.
;		(GS)  = Undefined.  DO NOT MODIFY !!!

tci_Return:
	cmp	esi,ebx
	je	short tci_Exit		; Exit if interpreter complete

	lodsb
	movzx	eax,al
	push	offset FLAT:tci_Return	; push return address. (return above)
	jmp	DWORD PTR FLAT:tci_apfn[4*eax]	; 'call' interpreter routine

tci_Exit:
	add	esp,4			; Don't restore CR2 in normal case

;	(CR2) has been restored at this point (in error path only)

tci_ExitError:
;	Find final log length. This is the delta to ss:[ebp].dt_pLog.

	mov	esi,ss:[ebp].dt_pLog	; get final log offset
	sub	esi,offset dtb_Log	; Adjust relative to original value
	mov	es:[dtb_cbLog],esi	; store log length in dtb.

;	*** BEGIN IDT EDIT.  BE SURE THAT DEBUG VECTORS D AND E ARE CLEAR. ***

	mov	esi,(offset FLAT:IDT)+8*0dh	; (DS:ESI)-> GP fault gate
	pop	[esi+3*4]		; Restore Page fault gate high DWORD
	pop	[esi+2*4]		; Restore Page fault gate low DWORD
	pop	[esi+1*4]		; Restore GP fault gate high DWORD
	pop	[esi+0*4]		; Restore GP fault gate low DWORD

;	End IDT Edit.

	RETC				; INTERPRETER EXIT POINT

;***	tci_ExitFault - jump label for tci_PageFault and tci_GPFault
;
;	tci_ExitFault retores the stack and CR2 contents, as they are
;	modified in the case of a fault.  It then falls into tci_Error.
;
;	ENTRY:	NONE.

tci_ExitFault:
	mov	esp,ss:[ebp].dt_ESP	; restore ESP
	pop	esi			; (ESI) = CR2 value to restore
	mov	cr2,esi			; restore CR2 in error case only
	sub	esp,8			; emulate 2 pushes.
;;	FallInto tci_Error

;***	tci_Error - jump label for tci_ routines which detect an error.
;
;	ENTRY:	(ESP) = return address to _dynInterpreter loop.
;
;	If a tci routine discovers an error, it jumps to this label to
;	indicate that error.  This eliminates the need to check a flag in
;	the main dispatching loop.

tci_Error:
	add	esp,8			; pop return address and CR2 contents.
	or	es:[dtb_bfRas],RF_DYNERR; Set error flag.
	jmp	short tci_ExitError
EndProc	  _dynInterpreter


;***	tci_apfn - jump table to Trace Command Interpreter routines.
;

tci_apfn:
	dd	offset FLAT:tci_PushEAX		; 00
	dd	offset FLAT:tci_PushECX		; 01
	dd	offset FLAT:tci_PushEDX		; 02
	dd	offset FLAT:tci_PushEBX		; 03
	dd	offset FLAT:tci_PushESP		; 04
	dd	offset FLAT:tci_PushEBP		; 05
	dd	offset FLAT:tci_PushESI		; 06
	dd	offset FLAT:tci_PushEDI		; 07
	dd	offset FLAT:tci_PushES		; 08
	dd	offset FLAT:tci_PushCS		; 09
	dd	offset FLAT:tci_PushSS		; 0a
	dd	offset FLAT:tci_PushDS		; 0b
	dd	offset FLAT:tci_PushEFlags	; 0c
	dd	offset FLAT:tci_PushEIP		; 0d
	dd	offset FLAT:tci_PushFS		; 0e
	dd	offset FLAT:tci_PushGS		; 0f
	dd	offset FLAT:tci_PushW		; 10
	dd	offset FLAT:tci_PushOXS		; 11
	dd	offset FLAT:tci_PushWIS		; 12
	dd	offset FLAT:tci_PushSIS		; 13
	dd	offset FLAT:tci_LogWN		; 14
	dd	offset FLAT:tci_LogMRS		; 15
	dd	offset FLAT:tci_Add		; 16
	dd	offset FLAT:tci_POP1W		; 17
	dd	offset FLAT:tci_POP1W		; 18
	dd	offset FLAT:tci_LogARS		; 19
	dd	offset FLAT:tci_PushD		; 1a
	dd	offset FLAT:tci_PushOXF		; 1b
	dd	offset FLAT:tci_PushFIF		; 1c
	dd	offset FLAT:tci_CnvrtFXS	; 1d
	dd	offset FLAT:tci_CnvrtSXF	; 1e
	dd	offset FLAT:tci_CnvrtDXS	; 1f
	dd	offset FLAT:tci_CnvrtSXD	; 20
	dd	offset FLAT:tci_LogDN		; 21
	dd	offset FLAT:tci_LogMRF		; 22
	dd	offset FLAT:tci_LogARF		; 23
	dd	offset FLAT:tci_Sub		; 24
	dd	offset FLAT:tci_Mul		; 25
	dd	offset FLAT:tci_PopN		; 26
	dd	offset FLAT:tci_MoveV		; 27
	dd	offset FLAT:tci_PushV		; 28
	dd	offset FLAT:tci_IncV		; 29
	dd	offset FLAT:tci_MoveVIi		; 2a
	dd	offset FLAT:tci_PushVIi		; 2b
	dd	offset FLAT:tci_IncVIi		; 2c
	dd	offset FLAT:tci_JmpN		; 2d
	dd	offset FLAT:tci_JmpZN		; 2e
	dd	offset FLAT:tci_JmpNN		; 2f
	dd	offset FLAT:tci_JmpPN		; 30
	dd	offset FLAT:tci_Abort		; 31
	dd	offset FLAT:tci_OrV		; 32
	dd	offset FLAT:tci_Remove		; 33
;RJM
	dd	offset FLAT:tci_SysDump ; 34
	dd	offset FLAT:tci_And     ; 35
	dd	offset FLAT:tci_Or      ; 36
	dd	offset FLAT:tci_Xor     ; 37
	dd	offset FLAT:tci_Not     ; 38
	dd	offset FLAT:tci_ExitOk  ; 39
	dd	offset FLAT:tci_ProcDump; 3a
;RJM2
	dd	offset FLAT:tci_SetMinW ; 3b
	dd	offset FLAT:tci_SetMajW ; 3c
	dd	offset FLAT:tci_SetMin  ; 3d
	dd	offset FLAT:tci_SetMaj  ; 3e
	dd	offset FLAT:tci_Xchg    ; 3f


.errnz	($- offset tci_apfn- 4*(DYN_MAXOPCODE+1))


;***	tci_PushEAX - Push value of EAX onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushEAX
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[ebp].dt_pad.pads_eax	; Fetch EAX from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushEAX


;***	tci_PushECX - Push value of ECX onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushECX
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[ebp].dt_pad.pads_ecx	; Fetch ECX from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushECX


;***	tci_PushEDX - Push value of EDX onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushEDX
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[ebp].dt_pad.pads_edx	; Fetch EDX from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushEDX


;***	tci_PushEBX - Push value of EBX onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushEBX
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[ebp].dt_pad.pads_ebx	; Fetch EBX from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushEBX


;***	tci_PushESP - Push value of ESP onto the RPN stack.
;
;	Note: The value of ESP is dependent on whether the tracepoint
;	occurred at ring 0 or not.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushESP
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lea	eax,[ebp].dt_iret.pltiret32_esp ; Calculate ESP if at Ring 0
	test	ss:[ebp].dt_iret.pltiret32_cs,RPL_MASK ; Trap from ring 0?
	jz	short psp1			; yes.  (EAX) = ESP at trap

	mov	eax,ss:[eax]			; Fetch ESP from iret frame.

;	(EAX) = ESP value to push, corrected for ring level.

psp1:	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushESP


;***	tci_PushEBP - Push value of EBP onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushEBP
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[ebp].dt_pad.pads_ebp	; Fetch EBP from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushEBP


;***	tci_PushESI - Push value of ESI onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushESI
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[ebp].dt_pad.pads_esi	; Fetch ESI from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushESI


;***	tci_PushEDI - Push value of EDI onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushEDI
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[ebp].dt_pad.pads_edi	; Fetch EDI from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushEDI


;***	tci_PushCS - Push value of CS onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushCS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	movzx	eax,ss:[ebp].dt_iret.pltiret32_cs	; Fetch CS from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushCS


;***	tci_PushSS - Push value of SS onto the RPN stack.
;
;	Note: The value of SS is dependent on whether the tracepoint
;	occurred at ring 0 or not.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushSS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	ax,ss				; Assume ring 0 SS
	test	ss:[ebp].dt_iret.pltiret32_cs,RPL_MASK	; Trap from ring 0?
	jz	short pss1			; Yes.  (AX) = SS at trap.

	movzx	eax,[ebp].dt_iret.pltiret32_ss	; Fetch SS from iret frame.

;	(AX) = SS value to push, corrected for ring level.

pss1:	movzx	eax,ax
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushSS


;***	tci_PushEFlags - Push value of EFlags onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushEFlags
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[ebp].dt_iret.pltiret32_eflag	; Fetch EFlags
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushEFlags


;***	tci_PushEIP - Push value of EIP onto the RPN stack.
;
;	Note: The EIP on the stack is one too large, due to the INT3.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushEIP
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[ebp].dt_iret.pltiret32_eip	; Fetch EIP
	dec	eax			; Adjust EIP for Trap 3
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushEIP


;***	tci_PushDS - Push value of DS onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushDS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	movzx	eax,WORD PTR ss:[ebp].dt_ds	; Fetch DS from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushDS


;***	tci_PushES - Push value of ES onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushES
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	movzx	eax,WORD PTR ss:[ebp].dt_es	; Fetch ES from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushES


;***	tci_PushFS - Push value of FS onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushFS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	movzx	eax,WORD PTR ss:[ebp].dt_fs	; Fetch FS from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushFS


;***	tci_PushGS - Push value of GS onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushGS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	movzx	eax,WORD PTR ss:[ebp].dt_gs	; Fetch GS from stack.
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushGS


;***	tci_PushW - Push a word operand onto the RPN stack.
;
;	tci_PushW takes a word operand, zero extends it, and pushes
;	it onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushW
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsw				; Grab word operand
	movzx	eax,ax
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushW


;***	tci_PushOXS - Push Object number converted to a Selector
;
;	tci_PushOXS converts it's byte operand into a selector,
;	zero extends that value, and pushes it onto the stack.
;
;	Because MTEs may eventually become nonresident, the selectors
;	(up to 256) are stored in an array in the DTO when the tracepoints
;	were inserted.  The word operand indexes this array to get the sel.
;
;	Invalid selectors are stored as a zero in dti_aSel.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushOXS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsb				; Grab byte operand (known correct)
	movzx	eax,al			; (EAX) = segment number.

;	Translate the byte operand into a selector.

.errnz	(size dtl_s - 12)		; verify that size (dtl_s) is 12.

	mov	edi,[ebp].dt_pdto	; (EDI) = pdto
	mov	edi,[edi].dto_dti.dti_padtl	; (EDI) = padtl
	lea	eax,[eax+eax*2]		; (EAX) = EAX * 3
	movzx	eax,WORD PTR [edi+eax*4+dtl_sel-size dtl_s]; (EAX) = selector
	or	eax,eax
	jz	tci_Error		; Error if selector is Zero

	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushOXS


;***	tci_PushWIS - Push a word, indirect, segmented.
;
;	tci_PushWIS pops an offset, then a selector, from the RPN stack,
;	fetches the user word at that 16:16 address, zero extends it,
;	and pushes that onto the RPN stack.
;
;	If the address is invalid or not present, a GP fault or Page
;	fault record will be logged in the buffer, and the interpreter
;	will exit.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushWIS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOSzx	eax		; (EAX) = Offset (trimmed to 16-bits)
	RPNPop
    FAULTLABEL	FAULT_FROMTOS
	RPNGetTOS	fs		; (FS) = User Selector
    FAULTLABEL	FAULT_FS_AX
	movzx	eax,WORD PTR fs:[eax]	; Grab User Word
	RPNPutTOS	eax
	RETC
EndProc tci_PushWIS


;***	tci_PushSIS - Push a segmented address, indirect, segmented.
;
;	tci_PushSIS pops an offset, then a selector, from the RPN stack,
;	fetches the user dword at that 16:16 address and pushes that onto
;	the RPN stack in the segmented address format.	 That is,
;	the high word (selector) is zero extended and pushed, and then
;	the low word (offset) is zero extended and pushed.
;
;	If the address is invalid or not present, a GP fault or Page
;	fault record will be logged in the buffer, and the interpreter
;	will exit.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushSIS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOSzx	eax		; (EAX) = Offset
	RPNPop
    FAULTLABEL	FAULT_FROMTOS
	RPNGetTOS	fs		; (FS) = User Selector
    FAULTLABEL	FAULT_FS_AX
	mov	eax,fs:[eax]		; (EAX) = User DWORD (16:16 address)
	movzx	edi,ax			; (EDI) = Offset
	shr	eax,16			; (EAX) = Selector
	RPNPutTOS	eax		; place Selector on TOS
	RPNPush
	RPNPutTOS	edi		; place Offset on TOS
	RETC
EndProc tci_PushSIS


;***	tci_LogWN - Log N words into the buffer.
;
;	tci_LogWN takes a byte operand, and repeats the following operation
;	that many times:
;		Pop the value from the top of the RPN stack
;		Log the low word of that value, ignoring the high word.
;
;	If the log overflows, the interpreter will exit without continuing,
;	but will record as much as it can.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_LogWN
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsb				; (AL) = byte operand
	movzx	ecx,al			; (ECX) = number of words to move
	jecxz	short lwn2		; Zero words to log.

	mov	edi,ss:[ebp].dt_pLog	; (EDI) = current log location
lwn1:	RPNGetTOSzx	eax		; (AX) = Word from TOS
   OVERFLOWLABEL
	stosw				; store word in log (No B1EMac)

;	WARNING: Do not add a new instruction here without
;	understanding the B1EMac macro.  (80386 B1 errata workaround)

	RPNPop
	add	ss:[ebp].dt_pLog,2	; update current log location
	loop	short lwn1		; Loop until all desired words logged.

lwn2:	RETC
EndProc tci_LogWN


;***	tci_LogMRS - Log a Memory Range, via a Segmented address
;
;	tci_LogMRS pops the following from the RPN stack:
;		Offset
;		Selector
;		Length
;
;	tci_LogMRS then zero extends all these values, and attempts to
;	move Length number of bytes from the given 16:16 address into
;	the log buffer.
;
;	The logged memory is prefixed by 3 bytes :
;		Token byte of 0 (DYN_LF_VALIDMEMORY)
;		Length word (length of logged information, in bytes)
;
;	If an address is invalid or not present, a GP fault or Page
;	fault record will be logged in the buffer, and the interpreter
;	will exit.
;
;	If the log overflows, the interpreter will exit without continuing,
;	and without logging the memory.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_LogMRS
	ASSUME DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	push	esi
	RPNGetTOSzx	esi		; (ESI) = 16-bit Offset
	RPNPop
    FAULTLABEL	FAULT_FROMTOS
	RPNGetTOS	fs		; (FS) = User Selector
	RPNPop
	RPNGetTOSzx	ecx		; (ECX) = Memory Length (max 64K)
	RPNPop
	mov	edi,ss:[ebp].dt_pLog	; (EDI) = current log location
	add	edi,3			; Memory Log Header Length = 3 bytes
	jecxz	short lmrs2		; length = 0 - exit

	; Warning:  To save time, FAULTLABEL is outside of the loop.
	; This only works if FAULTLABEL is at the top of the loop, and
	; there are no other FAULTLABELs inside the loop.

    FAULTLABEL	FAULT_FS_SI
lmrs1:	mov	al,fs:[esi]		; (AL) = memory byte
	inc	esi
    OVERFLOWLABEL
	stosb				; Log Memory Byte (No B1EMac)

;	WARNING: Do not add a new instruction here without
;	understanding the B1EMac macro.  (80386 B1 errata workaround)

	loop	short lmrs1

;	Successful memory log.  Save token byte and length.

lmrs2:	xchg	ss:[ebp].dt_pLog,edi	; update current log location
					; (EDI) = old log location
    OVERFLOWLABEL
	mov	BYTE PTR es:[edi],DYN_LF_VALIDMEMORY ; Store memory token byte
	mov	eax,ss:[ebp].dt_pLog
	sub	eax,edi
	sub	eax,3			; 3 bytes for length and token
    OVERFLOWLABEL
	mov	es:[edi]+1,ax		; Store length of memory log
	pop	esi
	RETC
EndProc tci_LogMRS


;***	tci_Add - Add the top two stack elements
;
;	tci_Add pops two DWORDs from the RPN stack, and pushes their sum.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_Add
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax		; (EAX) = DWORD from TOS
	RPNPop
	add	es:dtb_RPNStack[edx*4],eax	; Add (EAX) to TOS
	RETC
EndProc tci_Add


;***	tci_POP1W - POP stack once, taking a word operand.
;
;	tci_POP1W does nothing but eat up a word operand, and pop the
;	stack once.
;
;	This is used for compatability with the 16-bit version of
;	DOSDYNAMICTRACE.  The SetErrorE and SetErrorNE functions
;	were never implemented in previous OS/2 versions.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_POP1W
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	inc	esi
	inc	esi			; eat word operand
	RPNPop				; pop stack once
	RETC
EndProc tci_POP1W


;***	tci_LogARS - Log ASCIIZ string, in a range of memory, segmented.
;
;	tci_LogARS pops the following from the RPN stack:
;		Offset
;		Selector
;		Length
;
;	tci_LogARS then zero extends all these values, and attempts to
;	move Length number of bytes from the given 16:16 address into
;	the log buffer.  The data transfer will be discontinued if a
;	null byte is fetched.  The null byte will not be logged.
;
;	The logged string is prefixed by 3 bytes :
;		Token byte of 1 (DYN_LF_VALIDASCIIZ)
;		Length word (length of logged information, in bytes)
;
;	If an address is invalid or not present, a GP fault or Page
;	fault record will be logged in the buffer, and the interpreter
;	will exit.
;
;	If the log overflows, the interpreter will exit without continuing,
;	and without logging the string.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_LogARS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	push	esi
	RPNGetTOSzx	esi		; (ESI) = 16-bit Offset
	RPNPop
    FAULTLABEL	FAULT_FROMTOS
	RPNGetTOS	fs		; (FS) = User Selector
	RPNPop
	RPNGetTOSzx	ecx		; (EAX) = String Length
	RPNPop
	mov	edi,ss:[ebp].dt_pLog	; (EDI) = current log location
	add	edi,3			; Asciiz Log Header Length = 3 bytes
	jecxz	short lars2

	; Warning:  To save time, FAULTLABEL is outside of the loop.
	; This only works if FAULTLABEL is at the top of the loop, and
	; there are no other FAULTLABELs inside the loop.

    FAULTLABEL	FAULT_FS_SI
lars1:	mov	al,fs:[esi]		; (AL) = memory byte
	inc	esi
	or	al,al			; End of string?
	jz	short lars2		; yes - exit.  (NULL byte not logged)
    OVERFLOWLABEL
	stosb				; Log Asciiz Byte (No B1EMac)

;	WARNING: Do not add a new instruction here without
;	understanding the B1EMac macro.  (80386 B1 errata workaround)

	loop	short lars1

;	Successful Asciiz log.  Save token byte and length.

lars2:	xchg	ss:[ebp].dt_pLog,edi	; update current log location
					; (EDI) = old log location
    OVERFLOWLABEL
	mov	BYTE PTR es:[edi],DYN_LF_VALIDASCIIZ ; Store asciiz token byte
	mov	eax,ss:[ebp].dt_pLog
	sub	eax,edi
	sub	eax,3			; 3 bytes for length and token
    OVERFLOWLABEL
	mov	es:[edi]+1,ax		; Store string length
	pop	esi
	RETC
EndProc tci_LogARS


;***	tci_PushD - push immediate DWORD
;
;	tci_PushD takes a DWORD operand, and pushes it onto the RPN stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushD
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsd				; Grab DWord operand
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushD


;***	tci_PushOXF - Push object number converted to a flat address
;
;	tci_PushOXF converts it's dword operand into a flat address,
;	and pushes it onto the stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure	tci_PushOXF
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsd				; Grab DWord operand (known correct)

.errnz	(size dtl_s - 12)		; verify that size (dtl_s) is 12.

	mov	edi,[ebp].dt_pdto	; (EDI) = pdto
	mov	edi,[edi].dto_dti.dti_padtl	; (EDI) = padtl
	lea	eax,[eax+eax*2]		; (EAX) = EAX * 3
	mov	eax,[edi+eax*4+dtl_pBase-size dtl_s]	; (EAX) = base address
	cmp	eax,-1
	jz	tci_Error		; Error if object base is -1

	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushOXF


;***	tci_PushFIF - Push Flat address, indirect, flat
;
;	tci_PushFIF pops a Dword from the RPN stack, and then
;	pushes the dword at that flat address onto the stack.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushFIF
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax		; (EAX) = Flat offset from stack
    FAULTLABEL	FAULT_PAGE
	mov	eax,ds:[eax]		; (EAX) = User DWORD
	RPNPutTOS	eax		; Replace DWORD on stack.
	RETC
EndProc tci_PushFIF


;***	tci_CnvrtFXS - Convert flat address to a segmented address
;
;	tci_CnvrtFXS pops a dword from the RPN stack, uses CRMA
;	to translate that flat pointer to a 16:16 segmented pointer.
;	It then pushes the selector (zero extended) and then the
;	offset (zero extended) onto the stack.
;
;	If the flat address does not lie within the compatability
;	region, the interpreter will exit immediately.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

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

;	Get flat pointer from TOS, Perform CRMA, and push result on stack.

	RPNGetTOS	eax		; (EAX) = Flat Addr
	mov	edi,eax			; (EDI) = (EAX) = Flat Addr
	cmp	edi, SEL_512MEG		; outside compatibility region?
	ja	tci_Error

	mov	ss:[ebp].dt_FaultKind,FAULT_PAGE ; Store fault kind.

	CCALL32 _SELLaToSel <eax, [_pPTDACur]>	       ; (EAX) = Selector

;	We assume that SelToLa will work because LaToSel just succeeded.

	RPNPutTOS	eax		; Store selector on TOS

	mov	ss:[ebp].dt_FaultKind,FAULT_PAGE; Store fault kind.

	CCALL32 _SELSelToLa <eax, [_pPTDACur]>	; (EAX) = Selector Base
	sub	edi,eax			; (EDI) = 16:16 offset

	RPNPush
	RPNPutTOS	edi		; Store offset on TOS
	RETC
EndProc tci_CnvrtFXS


;***	tci_CnvrtSXF - Convert segmented address to a flat address
;
;	tci_CnvrtSXF pops a selector, then an offset from the RPN stack,
;	uses CRMA to translate that 16:16 pointer to a flat address,
;	and pushes that flat address onto the stack.
;
;	If the segmented address does not lie within the compatability
;	region (GDT selector), the interpreter will exit immediately.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_CnvrtSXF
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOSzx	edi		; (EDI) = 16-bit Offset
	RPNPop
	RPNGetTOSzx	eax		; (EAX) = Selector
	test	ax, SEL_LDTBIT
	jz	tci_Error		; go to error if GDT

	mov	ss:[ebp].dt_FaultKind,FAULT_PAGE; Store fault kind.

	CCALL32 _SELSelToLa <eax, [_pPTDACur]>	; (EAX) = Selector Base

	add	eax,edi			; (EAX) = Flat Addr
	RPNPutTOS	eax		; Store Flat Address on TOS
	RETC
EndProc tci_CnvrtSXF


;***	tci_CnvrtDXS - Convert Dword to Segmeted
;
;	tci_CnvrtDXS pops a DWORD, then pushes the high word (zero
;	extended) and then the low word (zero extended).  No CRMA is
;	applied.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_CnvrtDXS
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	edi		; (EDI) = DWORD from TOS
	mov	eax,edi			; (EDI) = (EAX) = DWORD from TOS
	movzx	eax,ax			; (EAX) = Low 16 bits
	shr	edi,16			; (EDI) = High 16 bits
	RPNPutTOS	edi		; Store high word on TOS
	RPNPush
	RPNPutTOS	eax		; Store low word on TOS
	RETC
EndProc tci_CnvrtDXS


;***	tci_CnvrtSXD - Convert Segmeted to Dword
;
;	tci_CnvrtDXS pops a low word, then a high word, then
;	concatenates them into a DWORD, and pushes the result.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_CnvrtSXD
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax		; (EAX) = DWORD from TOS
	shl	eax,16			; (EAX) = low word << 16
	RPNPop
	mov	ax,WORD PTR es:dtb_RPNStack[edx*4]	; (EAX) = (low:high)
	ror	eax,16			; (EAX) = DWORD = (high:low)
	RPNPutTOS	eax		; Store DWORD to TOS
	RETC
EndProc tci_CnvrtSXD


;***	tci_LogDN - Log N Dwords into the buffer.
;
;	tci_LogDN takes a byte operand, and repeats the following operation
;	that many times:
;		Pop the value from the top of the RPN stack
;		Log the value (as a DWORD)
;
;	If the log overflows, the interpreter will exit without continuing,
;	but will record as much as it can.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_LogDN
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsb				; (AL) = byte operand
	movzx	ecx,al			; (ECX) = number of dwords to move
	jecxz	short ldn2		; Zero dwords to log.

	mov	edi,ss:[ebp].dt_pLog	; (EDI) = current log location
ldn1:	RPNGetTOS	eax		; (EAX) = DWORD from TOS
   OVERFLOWLABEL
	stosd				; store dword in log (No B1EMac)

;	WARNING: Do not add a new instruction here without
;	understanding the B1EMac macro.  (80386 B1 errata workaround)

	RPNPop
	add	ss:[ebp].dt_pLog,4	; update current log location
	loop	short ldn1		; Loop until all desired dwords logged.

ldn2:	RETC
EndProc tci_LogDN


;***	tci_LogMRF - Log a Memory Range, via a Flat address
;
;	tci_LogMRF pops the following from the RPN stack:
;		Flat Address
;		Length
;
;	tci_LogMRS then zero extends the length, and attempts to move
;	Length number of bytes from the given flat address into
;	the log buffer.
;
;	The logged memory is prefixed by 3 bytes :
;		Token byte of 0 (DYN_LF_VALIDMEMORY)
;		Length word (length of logged information, in bytes)
;
;	If an address is not present, a Page fault record will be
;	logged in the buffer, and the interpreter will exit.
;
;	If the log overflows, the interpreter will exit without continuing,
;	and without logging the memory.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_LogMRF
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	push	esi
	RPNGetTOS	esi		; (ESI) = Flat Offset
	RPNPop
	RPNGetTOSzx	ecx		; (ECX) = Memory Length (max 64K)
	RPNPop
	mov	edi,ss:[ebp].dt_pLog	; (EDI) = current log location
	add	edi,3			; Memory Log Header Length = 3 bytes
	jecxz	short lmrf2		; no memory bytes to log

	; Warning:  To save time, FAULTLABEL is outside of the loop.
	; This only works if FAULTLABEL is at the top of the loop, and
	; there are no other FAULTLABELs inside the loop.

    FAULTLABEL	FAULT_PAGE
lmrf1:	lodsb				; (AL) = memory byte
    OVERFLOWLABEL
	stosb				; Log Memory Byte (No B1EMac)

;	WARNING: Do not add a new instruction here without
;	understanding the B1EMac macro.  (80386 B1 errata workaround)

	loop	short lmrf1

;	Successful memory log.  Save token byte and length.

lmrf2:	xchg	ss:[ebp].dt_pLog,edi	; update current log location
					; (EDI) = old log location
    OVERFLOWLABEL
	mov	BYTE PTR es:[edi],DYN_LF_VALIDMEMORY ; Store memory token byte
	mov	eax,ss:[ebp].dt_pLog
	sub	eax,edi
	sub	eax,3			; 3 bytes for length and token
    OVERFLOWLABEL
	mov	es:[edi]+1,ax		; Store length of memory log
	pop	esi
	RETC
EndProc tci_LogMRF


;***	tci_LogARF - Log ASCIIZ string, in a range of memory, flat.
;
;	tci_LogARF pops the following from the RPN stack:
;		Flat Address
;		Length
;
;	tci_LogARF then zero extends the length, and attempts to move
;	Length number of bytes from the given flat address into
;	the log buffer.  The data transfer will be discontinued if a
;	null byte is fetched.  The null byte will not be logged.
;
;	The logged string is prefixed by 3 bytes :
;		Token byte of 1 (DYN_LF_VALIDASCIIZ)
;		Length word (length of logged information, in bytes)
;
;	If an address is not present, a Page fault record will be
;	logged in the buffer, and the interpreter will exit.
;
;	If the log overflows, the interpreter will exit without continuing,
;	and without logging the string.
;
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_LogARF
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	push	esi
	RPNGetTOS	esi		; (ESI) = Flat Offset
	RPNPop
	RPNGetTOS	ecx		; (ECX) = String Length (max 64K)
	RPNPop
	mov	edi,ss:[ebp].dt_pLog	; (EDI) = current log location
	add	edi,3			; Asciiz Log Header Length = 3 bytes
	jecxz	short larf2		; no string

	; Warning:  To save time, FAULTLABEL is outside of the loop.
	; This only works if FAULTLABEL is at the top of the loop, and
	; there are no other FAULTLABELs inside the loop.

    FAULTLABEL	FAULT_PAGE
larf1:	lodsb				; (AL) = asciiz byte
	or	al,al			; End of string?
	jz	short larf2		; yes - exit.  (NULL byte not logged)
    OVERFLOWLABEL
	stosb				; Log Asciiz Byte (No B1EMac)

;	WARNING: Do not add a new instruction here without
;	understanding the B1EMac macro.  (80386 B1 errata workaround)

	loop	short larf1

;	Successful Asciiz log.  Save token byte and length.

larf2:	xchg	ss:[ebp].dt_pLog,edi	; update current log location
					; (EDI) = old log location
    OVERFLOWLABEL
	mov	BYTE PTR es:[edi],DYN_LF_VALIDASCIIZ ; Store asciiz token byte
	mov	eax,ss:[ebp].dt_pLog
	sub	eax,edi
	sub	eax,3			; 3 bytes for length and token
    OVERFLOWLABEL
	mov	es:[edi]+1,ax		; Store string length
	pop	esi
	RETC
EndProc tci_LogARF


;***	tci_Sub - Subtract the top two stack elements
;
;	tci_Sub pops two DWORDs from the RPN stack, and pushes their
;	difference.   The first value poped is subtracted from the second.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_Sub
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax		; (EAX) = DWORD from TOS
	RPNPop
	sub	es:dtb_RPNStack[edx*4],eax	; Sub (EAX) from TOS
	RETC
EndProc tci_Sub


;***	tci_Mul - Multiply the top two stack elements
;
;	tci_Mul pops two DWORDs from the RPN stack, and pushes their
;	product.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_Mul
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax		; (EAX) = DWORD from TOS
	RPNPop

;	Design Note: The RPN stack can't handle QWORDs, so we simply
;	ignore the possible high DWORD from the multiply.  As this
;	instruction is really designed for array addressing, this
;	is no big deal.

	push	edx
	mul	es:dtb_RPNStack[edx*4]	; multiply into (EDX:EAX)
	pop	edx			; Ignore EDX from mul
	RPNPutTOS	eax		; (EAX) = DWORD from TOS
	RETC
EndProc tci_Mul


;***	tci_PopN - Pop N stack elements
;
;	tci_PopN takes a byte operand, and pops that many operands
;	from the stack.  As the values are not actually removed from
;	the 16-element circular stack, tci_PopN effectively rotates
;	the stack down.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PopN
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsb				; Fetch byte operand
	sub	dl,al			; Pop N times
	and	edx,15			; Mask EDX for 16-element stack.
	RETC
EndProc tci_PopN


;***	tci_MoveV - Move the top of stack to a DynTrc variable
;
;	tci_MoveV takes a word operand.  tci_MoveV then moves
;	the value on the top of the stack to the DynTrc variable
;	in the current DTO at that index.  The top of stack pointer
;	is not changed.
;
;	The variable's index has already been validated in _dtrCompile,
;	so it is trusted here.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_MoveV
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsw				; Fetch word operand
	movzx	eax,ax
	mov	edi,[ebp].dt_pdto	; (EDI) = pdto
	RPNGetTOS	ecx		; get value from TOS
	mov	DWORD PTR [edi+4*eax].dto_dth+size dth_s,ecx ; store variable
	RETC
EndProc tci_MoveV


;***	tci_PushV - Push a DynTrc variable onto the stack
;
;	tci_PushV takes a word operand.	  tci_PushV uses that to index
;	to the DynTrc variable in the current DTO, and pushes the value
;	it finds there.
;
;	The variable's index has already been validated in _dtrCompile,
;	so it is trusted here.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushV
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsw				; Fetch word operand
	movzx	eax,ax
	mov	edi,[ebp].dt_pdto	; (EDI) = pdto
	mov	eax,DWORD PTR [edi+4*eax].dto_dth+size dth_s ; (EAX) = Variable
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushV


;***	tci_IncV - Increment a DynTrc variable
;
;	tci_IncV takes a word operand, and increments the value in the
;	DynTrc variable in the current DTO at that index.
;
;	The variable's index has already been validated in _dtrCompile,
;	so it is trusted here.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_IncV
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsw				; Fetch word operand
	movzx	eax,ax
	mov	edi,[ebp].dt_pdto	; (EDI) = pdto
	inc	DWORD PTR [edi+4*eax].dto_dth + size dth_s ; inc variable
	RETC
EndProc tci_IncV


;***	tci_MoveVIi - Move the top of stack to a DynTrc variable, indirect.
;
;	tci_MoveVIi pops a variable index off the top of the stack,
;	and then pops a value off the top of the stack.  The value is moved
;	into the Dyntrc variable in the current DTO at that index.
;	The variable and the index are then pushed back onto the stack,
;	so that there is no net change on the stack at all.
;
;	If the index is too large, the interpreter will exit with an error.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_MoveVIi
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax			; variable index = TOS
	mov	edi,[ebp].dt_pdto		; (EDI) = pdto
	cmp	eax,[edi].dto_dth.dth_clVar	; index in range?
	jnb	tci_Error			; no - error

	RPNPop
	RPNGetTOS	ecx			; value = new TOS
	RPNPush					; restore stack (unchanged!)
	mov	DWORD PTR [edi+4*eax].dto_dth+size dth_s,ecx ; store variable
	RETC
EndProc tci_MoveVIi


;***	tci_PushVIi - Push a DynTrc variable, indirect
;
;	tci_PushVIi fetches an index of a DynTrc variable from
;	the top of the stack, (without doing a pop), and then
;	pushes the value of that variable onto the stack.
;
;	If the index is too large, the interpreter will exit with an error.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_PushVIi
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax			; variable index = TOS
	mov	edi,[ebp].dt_pdto		; (EDI) = pdto
	cmp	eax,[edi].dto_dth.dth_clVar	; index in range?
	jnb	tci_Error			; no - error

;	The index stays unchanged and in-place on the stack.

	mov	eax,DWORD PTR [edi+4*eax].dto_dth+size dth_s ; (EAX) = Variable
	RPNPush
	RPNPutTOS	eax
	RETC
EndProc tci_PushVIi


;***	tci_IncVIi - Increment a DynTrc variable, indirect
;
;	tci_IncVIi fetches an index of a DynTrc variable from
;	the top of the stack, (without doing a pop), and then
;	increments the value of that variable.
;
;	If the index is too large, the interpreter will exit with an error.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_IncVIi
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax			; variable index = TOS
	mov	edi,[ebp].dt_pdto		; (EDI) = pdto
	cmp	eax,[edi].dto_dth.dth_clVar	; index in range?
	jnb	tci_Error			; no - error

	inc	DWORD PTR [edi+4*eax].dto_dth + size dth_s ; inc variable
	RETC
EndProc tci_IncVIi


;***	tci_Jmp - Jump forward by N bytes
;
;	tci_Jmp takes a word operand.  tci_Jmp causes an
;	unconditional jump forward in the instruction stream by
;	that number of bytes, relative to the end of the instruction.
;
;	Therefore, tci_Jmp by 0 bytes is a NOP.
;
;	The operand has been checked by _dynCompile to be sure that it
;	will fall on an opcode boundary, assuming no jumps were taken.
;
;	To prevent loops, no backward jumps are permitted.  Also, it is
;	illegal to jump into the code stream for another DTR.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_JmpN
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsw
	movzx	eax,ax
	add	esi,eax
	RETC
EndProc tci_JmpN


;***	tci_JmpZN - Jump forward by N if TOS is Zero
;
;	tci_JmpZN takes a word operand.  tci_JmpZN causes an
;	unconditional jump forward in the instruction stream by
;	that number of bytes, relative to the end of the instruction,
;	but only if the value on the top of the stack is zero.
;
;	The operand has been checked by _dynCompile to be sure that it
;	will fall on an opcode boundary, assuming no jumps were taken.
;
;	To prevent loops, no backward jumps are permitted.  Also, it is
;	illegal to jump into the code stream for another DTR.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_JmpZN
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsw
	cmp	DWORD PTR es:dtb_RPNStack[edx*4],0
	jne	short jzn1		; Not Zero - no jump

	movzx	eax,ax			; Zero - perform jump
	add	esi,eax
jzn1:	RETC
EndProc tci_JmpZN


;***	tci_JmpNN - Jump forward by N if TOS is Negative
;
;	tci_JmpZN takes a word operand.  tci_JmpZN causes an
;	unconditional jump forward in the instruction stream by
;	that number of bytes, relative to the end of the instruction,
;	but only if the value on the top of the stack is negative.
;
;	The operand has been checked by _dynCompile to be sure that it
;	will fall on an opcode boundary, assuming no jumps were taken.
;
;	To prevent loops, no backward jumps are permitted.  Also, it is
;	illegal to jump into the code stream for another DTR.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_JmpNN
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsw
	cmp	DWORD PTR es:dtb_RPNStack[edx*4],0
	jge	short jnn1		; not Negative - no jump

	movzx	eax,ax			; Negative - perform jump
	add	esi,eax
jnn1:	RETC
EndProc tci_JmpNN


;***	tci_JmpPN - Jump forward by N if TOS is Positive
;
;	tci_JmpPN takes a word operand.  tci_JmpPN causes an
;	unconditional jump forward in the instruction stream by
;	that number of bytes, relative to the end of the instruction,
;	but only if the value on the top of the stack is positive.
;
;	The operand has been checked by _dynCompile to be sure that it
;	will fall on an opcode boundary, assuming no jumps were taken.
;
;	To prevent loops, no backward jumps are permitted.  Also, it is
;	illegal to jump into the code stream for another DTR.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_JmpPN
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsw
	cmp	DWORD PTR es:dtb_RPNStack[edx*4],0
	jle	short jpn1		; Not Positive - no jump

	movzx	eax,ax			; Positive - perform jump
	add	esi,eax
jpn1:	RETC
EndProc tci_JmpPN


;***	tci_Remove - Remove and Abort the current tracepoint.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_Remove
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	ecx,ss:[ebp].dt_pdtr		; (ECX) = pdtr
	or	[ecx].dtr_Reserved,DTR_REMOVED	; mark tracepoint 'need removal'
;;	FallInto tci_Abort

EndProc tci_Remove


;***	tci_Abort - Abort the tracepoint.
;
;	tci_Abort aborts the tracepoint entirely.  The interpreter
;	exits, but does not log any information.  The data logged
;	by this tracepoint is lost.
;
;	However, alterations to the variables remain.
;
;	By using tci_Abort in combination with the tci_Jmp??
;	instructions, unnecessary tracepoints can be filtered
;	at runtime, without crowding or overflowing the log buffer.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_Abort
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
;;	FallFrom tci_Remove
	mov	es:[dtb_fAbort],TRUE	; Abort selected
	mov	esi,ebx			; force interpreter completion.
	RETC
EndProc tci_Abort


;***	tci_OrV - OR a dyntrc variable with TOS.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_OrV
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	lodsw				; (EAX) = word variable index operand
	movzx	eax,ax
	RPNGetTOS ecx			; (ECX) = dword bitmask from TOS
	mov	edi,[ebp].dt_pdto	; (EDI) = pdto
	or	DWORD PTR [edi+4*eax].dto_dth + size dth_s,ecx ; OR variable
	RETC
EndProc tci_OrV

;RJM
;***	tci_And - And the top two stack elements
;
;	tci_And pops two DWORDs from the RPN stack, and pushes their
;	bitwise AND.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_And
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax		; (EAX) = DWORD from TOS
	RPNPop
	and	es:dtb_RPNStack[edx*4],eax	; And (EAX) with TOS
	RETC
EndProc tci_And

;RJM
;***	tci_Or  - Or the top two stack elements
;
;	tci_Or pops two DWORDs from the RPN stack, and pushes their
;	bitwise OR.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_Or
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax		; (EAX) = DWORD from TOS
	RPNPop
	or 	es:dtb_RPNStack[edx*4],eax	; Or (EAX) with TOS
	RETC
EndProc tci_Or

;RJM
;***	tci_Xor - Xor the top two stack elements
;
;	tci_Xor pops two DWORDs from the RPN stack, and pushes their
;	bitwise XOR.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_Xor
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	RPNGetTOS	eax		; (EAX) = DWORD from TOS
	RPNPop
	xor 	es:dtb_RPNStack[edx*4],eax	; Xor (EAX) with TOS
	RETC
EndProc tci_Xor

;RJM
;***	tci_Not - 1s complement the TOS
;
;	tci_Neg 1s complements TOS. The RPN Stack pointer is not altered.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_Not
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	not 	es:dtb_RPNStack[edx*4]     ; Not TOS
	RETC
EndProc tci_Not

;RJM2
;***	tci_ProcDump - Force Process Dump
;
;	tci_ProcDump forces a process dump to the Pid at TOS.
;	If PID is zero then the current process is dumped.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_ProcDump
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
        RPNGetTOS	eax		; (EAX) = DWORD from TOS (=PID)
        RPNPop
;
; Unfortunately I haven't been able to make this code work, the problems are:
; 1) _PLD32ApiDump is in swappable code and may cause a page fault
; 2) The data dumpped by process dump may be swapped and therefore cause a page fault
; 3) This code runs disabled and can't service page faults, even if I restore the IDT
;    entries for faults D and E.
; 4) There seems to be a restriction in the page fault handler that prohibits a page 
;    fault from being serviced from the trap 3 handler. Hence even if we re-enable for
;    interrupts we don't seem to be able to handle page faults.
; Consequently I'm leaving the code commented out until thses problems can be resolved.

;
;; Now prepare to exit the interpreter
;	add	esp,8			; Don't restore CR2 and swallow the ret addr
;
;;	*** BEGIN IDT EDIT.  BE SURE THAT DEBUG VECTORS D AND E ARE CLEAR. ***
;
;	mov	esi,(offset FLAT:IDT)+8*0dh	; (DS:ESI)-> GP fault gate
;	pop	[esi+3*4]		; Restore Page fault gate high DWORD
;	pop	[esi+2*4]		; Restore Page fault gate low DWORD
;	pop	[esi+1*4]		; Restore GP fault gate high DWORD
;	pop	[esi+0*4]		; Restore GP fault gate low DWORD
;
;;	End IDT Edit.
;; we can't make the following calls until normal page fault handling has resumed.
;        sti        or eax,eax
;        jnz tci_pdump
;;       CCALL32 _SELSelToLa <eax, [_pPTDACur]>	; (EAX) = Selector Base
;        mov  eax,_pPTDACur
;        movzx eax,[eax].ptda_Pid
;tci_pdump:
;        CCALL32 _PLD32ApiDump <eax,-1>;
        RETC                            ; exit interpreter without logging data
EndProc tci_ProcDump



;RJM
;***	tci_ExitOk - Exit tracepoint. Trace data logged so far.
;
;	tci_Exit teminates tracepoint, saving logged data.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_ExitOk
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov esi,ebx ; simulate end of intruction stream
	RETC
EndProc tci_ExitOk


;RJM2
;***	tci_SetMinW - Override Minor Code
;
;	tci_SetMinW overrides the minor code with a word operand when the
;  data for this trace point is logged into the System Trace Buffer.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_SetMinW
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
        lodsw				; Fetch word operand
	     mov	es:[dtb_MinCode],ax	; Record minor code
        RETC
EndProc tci_SetMinW


;RJM2
;***	tci_SetMajW - Override Major Code
;
;	tci_SetMajW overrides the major code with a word operand when the
;  data for this trace point is logged into the System Trace Buffer.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_SetMajW
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
        lodsw				; Fetch word operand
	     mov	es:[dtb_MajCode],ax	; Record major code
        RETC
EndProc tci_SetMajW

;RJM2
;***	tci_SetMin - Override Minor Code
;
;	tci_SetMin overrides the minor code with a TOS when
;  data for this trace point is logged into the System Trace Buffer.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_SetMin
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
        RPNGetTOS	eax		; (EAX) = DWORD from TOS
	     RPNPop
	     mov	es:[dtb_MinCode],ax	; Record minor code
        RETC
EndProc tci_SetMin


;RJM2
;***	tci_SetMaj - Override Major Code
;
;	tci_SetMaj overrides the major code with the TOS when
;  data for this trace point is logged into the System Trace Buffer.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_SetMaj
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
        RPNGetTOS	eax		; (EAX) = DWORD from TOS
	     RPNPop
	     mov	es:[dtb_MajCode],ax	; Record major code
        RETC
EndProc tci_SetMaj


;RJM2
;***	tci_Xchg - Exchange two elements on TOS
;
;	tci_Xchg pops the top two elements from the stack and pushes
;	them in reverse order.
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	Standard tci exit.  See comment inside _dynInterpreter.
;

Procedure tci_Xchg
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
        RPNGetTOS	edi		; (EDI) = DWORD from TOS
        RPNPop
        RPNGetTOS	eax		; (EAX) = DWORD from TOS
        RPNPutTOS edi      ; TOS = EDI
        RPNPush
        RPNPutTOS eax      ; TOS = EAX
        RETC
EndProc tci_Xchg


;***	tci_LogFault - Log a fault.
;
;	tci_LogFault places a fault log in the buffer.  The format for
;	a fault log is as follows :
;
;	GP Fault:
;		Token byte  : DYN_LF_INVALIDSEL
;		Length Word : 4
;		DWORD data  : Selector:Offset of fault.
;
;	Page Fault:
;		Token byte  : DYN_LF_NOTPRESPAGE
;		Length Word : 4
;		DWORD data  : Linear Address of page fault
;
;	ENTRY	(AL) = Fault Token
;			DYN_LF_INVALIDSEL
;				(ECX) = Selector:Offset of fault.
;			DYN_LF_NOTPRESPAGE
;				(ECX) = Linear Address of page fault
;		(ES) = FAult Log Selector
;
;	EXIT	NONE
;

Procedure tci_LogFault
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	edi,ss:[ebp].dt_pLog	; (ES:EDI) = current log location
    OVERFLOWLABEL
	stosb				; Store fault log token byte (No B1EMac)

;	WARNING: Do not add a new instruction here without
;	understanding the B1EMac macro.  (80386 B1 errata workaround)

	mov	ax,4			; data length is always 4 bytes
    OVERFLOWLABEL
	stosw				; Store data length (No B1EMac)

;	WARNING: Do not add a new instruction here without
;	understanding the B1EMac macro.  (80386 B1 errata workaround)

	mov	eax,ecx
    OVERFLOWLABEL
	stosd				; Log Fault data (No B1EMac)

;	WARNING: Do not add a new instruction here without
;	understanding the B1EMac macro.  (80386 B1 errata workaround)

	add	ss:[ebp].dt_pLog,7
	jmp	tci_ExitFault		; force an error and exit (restore CR2)
EndProc tci_LogFault


;***	tci_FaultLabels:
;
;	This is a table of the possible locations in the code where
;	we can take either a Page or GP fault due to an access to
;	user-space memory.  When a fault occurs, we look up the EIP
;	in this table and use that information to determine if the
;	fault was as expected.
;
;	The fault table size is given by cbFaultTable.  Immediately
;	following the fault labels is the table of overflow labels.
;	This is a table of the possible locations in the code where
;	we can take GP fault due to an overflowing log buffer.
;	If this occurs, we force an interpreter exit.

tci_FaultLabels:
	FAULTTABLE

cbFaultTable = ($-tci_FaultLabels)

tci_LogOverflows:
	OVERFLOWTABLE

cbOverflowTable = ($-tci_LogOverflows)

;	These two tables must be contiguous.

.errnz	($ - offset FLAT:tci_FaultLabels - cbFaultTable - cbOverflowTable)


;***LP	tci_GPFault - Handle Trace Command Interpreter GP Fault
;
;	tci_GPFault is entered if the Trace Command Interpreter generates
;	a GP fault.  The fault could have occurred in these cases:
;
;	1) Fault trying to access an invalid Selector and Offset.
;		Log a GP fault record and exit the interpreter.
;
;		In this case (only) we look at ss:[ebp].dt_lFaultKind to
;		determine in what registers the address to log is stored.
;
;	2) Fault trying to log too much information.
;		Halt the tracepoint interpreter.
;
;	3) An unexpected GP fault in the interpreter
;		Panic.
;
;	NOTE: ESP varies here.  Restore it before returning.
;
;	ENTRY
;
;	EXIT

fault_s struc
	fault_errcd	dd	?
	fault_iret	db	size iret32_s	DUP	(?)
fault_s ends

;	Jump table based on ss:[ebp].dt_FaultKind.

tci_FaultKindTable:
.errnz	($ - tci_FaultKindTable - 4*FAULT_PAGE)
	dd	offset	FLAT:gpfie
.errnz	($ - tci_FaultKindTable - 4*FAULT_FROMTOS)
	dd	offset	FLAT:gpf1
.errnz	($ - tci_FaultKindTable - 4*FAULT_DS_SI)
	dd	offset	FLAT:gpf2
.errnz	($ - tci_FaultKindTable - 4*FAULT_FS_AX)
	dd	offset	FLAT:gpf3
.errnz	($ - tci_FaultKindTable - 4*FAULT_FS_SI)
	dd	offset	FLAT:gpf4
FaultKindTable = ($-tci_FaultKindTable)

Procedure tci_GPFault
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	push	eax			; save (EAX)
	push	es			; save DTB selector (ES)
	push	ds
	pop	es			; (ES) = Flat
	mov	eax,ss:[esp].fault_iret.iret32_eip+8	; get fault address
	mov	edi,offset FLAT:tci_FaultLabels ; Table address
	mov	ecx,cbFaultTable/4	; Fault label count
	repne	scasd			; Look for label
	je	short gpf0		; label found - log a GP fault.

	mov	ecx,cbOverflowTable/4	; Overflow label count
	repne	scasd			; Look for label
	pop	es			; (ES) = DTB selector.
	pop	eax			; discard (EAX) from stack (unused)
	je	tci_ExitFault		; overflow - no panic, no log.

;	Unexpected GP fault.  (EAX) = flat address of fault.
;	FAULT_PANIC

gpfie:	Panic <"tci_GPFault">

;	Here, we have detected a fault due to loading a user's invalid
;	selector, or by referencing invalid user's memory.  We use the
;	contents of ss:[ebp].dt_FaultKind (which was set up by FAULTLABEL)
;	as an index into a jump table, that will take us to gpf(ie,1,2,3,4)
;	to gather exact information as to where the fault occurred.

gpf0:	pop	es			; (ES) = DTB selector.
	pop	eax			; (EAX) = (EAX) at fault
	mov	edi,ss:[ebp].dt_FaultKind	; Get fault kind = table index
	jmp	DWORD PTR cs:tci_FaultKindTable[edi*4]	; Dispatch via table

;	FAULT_FROMTOS
gpf1:	RPNGetTOS	ecx		; Fault due to selector load from TOS.
	shl	ecx,16			; Use offset 0 to avoid confusion.
	jmp	short gpf8

;	FAULT_DS_SI
gpf2:	mov	cx,ds			; Fault due to reference at (DS:SI)
	shl	ecx,16
	mov	cx,si
	jmp	short gpf8

;	FAULT_FS_AX
gpf3:	mov	cx,fs			; Fault due to reference at (FS:AX)
	shl	ecx,16
	mov	cx,ax
	jmp	short gpf8

;	FAULT_FS_SI
gpf4:	mov	cx,fs			; Fault due to reference at (FS:SI)
	shl	ecx,16
	mov	cx,si

;	(ECX) = Sel:Off of GP fault.

gpf8:	mov	al,DYN_LF_INVALIDSEL
	jmp	tci_LogFault		; Log fault, force an error and exit

EndProc tci_GPFault


;***LP	tci_PageFault - Handle Trace Command Interpreter Page Fault
;
;	tci_PageFault is entered if the Trace Command Interpreter generates
;	a Page fault.  The fault could have occurred in these cases:
;
;	1) The interpreter tried to access an invalid user page.
;		Log a Page fault record and exit the interpreter.
;
;	2) The interpreter tried to load a user selector into a segment
;	   register, but the LDT page was not present.
;
;	3) An unexpected Page fault in the interpreter.
;		Panic.
;
;	NOTE: ESP varies here.  Restore it before returning.
;
;	ENTRY	INTEL Page fault trap frame.  (direct from the IDT)
;		Interrupts enabled (Trap Gate)
;
;	EXIT	If faulting address in tci_FaultLabels table,
;			Page Fault Logged
;			Jump to tci_Error to halt interpreter
;		Else
;			Panic

Procedure tci_PageFault
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
	mov	eax,ss:[esp].fault_iret.iret32_eip	; get fault address
	mov	edi,offset FLAT:tci_FaultLabels ; Table address
	mov	ecx,cbFaultTable/4	; Dword count
	push	es			; save (ES)
	push	ds
	pop	es			; (ES) = Flat
	repne	scasd			; Look for label
	pop	es			; (ES) = restored
	je	short pgf1		; label found - log a Page fault.

	Panic	<"tci_PageFault">

pgf1:	mov	al,DYN_LF_NOTPRESPAGE
	mov	ecx,cr2			; Log faulting linear address
	jmp	tci_LogFault		; Log fault, force an error and exit

EndProc tci_PageFault


;RJM
;Note: this routine is coded at this location because we assume
;      CS:DOSCODE
;***	tci_SysDump - Force System Dump
;
;	tci_SysDump forces an immediate call to RASRST. No data is
;	logged!
;
;	ENTRY	Standard tci entry.  See comment inside _dynInterpreter.
;
;	EXIT	none.
;

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


DYNLOCK_TEXT	ENDS

endif	; RAS

END
