;       SCCSID = @(#)dyntrap.asm	6.1 90/11/17
;      SCCSID = @(#)dyntrap.asm	1.9 90/09/17
;
;*	IBM/Microsoft Confidential
;*
;*	Copyright (c) IBM Corporation 1987, 1989
;*	Copyright (c) Microsoft Corporation 1987, 1989
;*
;*	All Rights Reserved
;
PAGE	,132
TITLE	DYNTRAP.ASM - Dynamic Trace Trap Services
NAME	DYNTRAP

;***	DYNTRAP.ASM -- Dynamic Trace Trap Services
;
;	This file implements the Dynamic Trace trap-time services.
;

.xlist
	include basemaca.inc
	include osmaca.inc
	include dosseg.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 curdir.inc
	include dirent.inc
	include screen.inc
	include sem.inc
	include find.inc
	include tkptda.inc
	include mi.inc
;	include ..\memory\pglocal.inc

PT_PRESENT	EQU	000000001H
PT_RING3WRITE	EQU	000000002H
PT_RING3ACCESS	EQU	000000004H
PT_STATE	EQU	000000e00H
PT_FRAME	EQU	0fffff000H
PTS_UVIRT	EQU	000000600H

	include dynxport.inc
	include dynapi.inc
	include dynlocal.inc
.list

if	RAS

	CpuMode 386
	ModName DYNTRAP

	EXTRN32		_dynInterpreter
	EXTRN32		_pgPageToPte
	EXTRN32		_VMIsPrivatized

	EXTRN		K_F_Systrace:NEAR

	ReferFlat	_pbDYNResetPoint,DWORD
	ReferFlat	_DYNNullResetPoint,DWORD
	ReferFlat	_dynsemTrap,BYTE
	ReferFlat	_dynselDTB,WORD
	ReferFlat	_DYNSavedUserFlags,DWORD
	ReferFlat	_pptedynTraceAlias,DWORD
	ReferFlat	_pbdynTraceAlias,DWORD
	ReferFlat	_pptedynTraceIntAlias,DWORD
	ReferFlat	_pbdynTraceIntAlias,DWORD

	ReferFlat	InterruptLevel,DWORD
	ReferFlat	_SELGDTLaddr,DWORD
	ReferFlat	_pPTDACur,DWORD
	ReferFlat	_pdtoHeadScan,DWORD
	ReferFlat	_pgPhysPageDir,DWORD

	FARCODE HIGH32
DYNLOCK_TEXT	SEGMENT

;***********************************************
;
;	Dynamic Trace Trap Service Routines
;
;***********************************************

;***	_dynapfnEmulate: Instruction Emulation Jump Table
;
;	This is a jump table to get us to the actual instruction
;	emulator routine.

_dynapfnEmulate:
			IAPFN_SSTEP = ($-_dynapfnEmulate)/4
	dd	offset FLAT:_dynSStep		; Single-Step (Default)
			IAPFN_NOP = ($-_dynapfnEmulate)/4
	dd	offset FLAT:_dynEmulateNOP	; Opcode 090h - NOP
			IAPFN_CMC = ($-_dynapfnEmulate)/4
	dd	offset FLAT:_dynEmulateCMC	; Opcode 0F5h - CMC
			IAPFN_CLC = ($-_dynapfnEmulate)/4
	dd	offset FLAT:_dynEmulateCLC	; Opcode 0F8h - CLC
			IAPFN_STC = ($-_dynapfnEmulate)/4
	dd	offset FLAT:_dynEmulateSTC	; Opcode 0F9h - STC
			IAPFN_CLD = ($-_dynapfnEmulate)/4
	dd	offset FLAT:_dynEmulateCLD	; Opcode 0FCh - CLD

;***	_dynaiapfnEmulate is an array of indicies into _dynapfnEmulate.
;	The opcode byte is used to index into this array, and then
;	the value stored there is used to index into _dynapfnEmulate,
;	which is a just a jump table.

_dynaiapfnEmulate:
	db	(090h - 0)	DUP	(IAPFN_SSTEP)
.errnz	($-offset _dynaiapfnEmulate - 090h)
	db	IAPFN_NOP			; 090h - NOP
	db	(0F5h - 091h)	DUP	(IAPFN_SSTEP)
.errnz	($-offset _dynaiapfnEmulate - 0F5h)
	db	IAPFN_CMC			; 0F5h - CMC
	db	IAPFN_SSTEP			; 0F6h
	db	IAPFN_SSTEP			; 0F7h
	db	IAPFN_CLC			; 0F8h - CLC
	db	IAPFN_STC			; 0F9h - STC
	db	IAPFN_SSTEP			; 0FAh
	db	IAPFN_SSTEP			; 0FBh
	db	IAPFN_CLD			; 0FCh - CLD
	db	IAPFN_SSTEP			; 0FDh
	db	IAPFN_SSTEP			; 0FEh
	db	IAPFN_SSTEP			; 0FFh
.errnz	($-offset _dynaiapfnEmulate - 0100H)


;***EP	_DYNTrap3 - Dynamic Trace Trap 3 handler
;
;	_DYNTrap3 is called whenever a Trap 3 occurs, before any
;	other trap 3 services occur.  It checks to see if the Trap 3
;	is for DynamicTrace, and if so, it calls _dynInterpreter
;	to generate the log data.
;
;	After the _dynInterpreter runs, _DYNTrap3 replaces the
;	original instruction in memory, sets _pbDYNResetPoint to
;	point at the instruction (through an alias), and
;	single-steps the instruction.
;
;	After the instruction executes, the INT 3 is replaced in
;	memory again via _pbDYNResetPoint, _pbDYNResetPoint is
;	restored, and processing continues.  If the single-step
;	succeeded, then the log is moved to the STDA and the
;	tracepoint is complete.  If it fails due to a restartable
;	fault, the entire tracepoint process repeats after the
;	fault is complete.
;
;	If (_pbDYNResetPoint != &(_DYNNullResetPoint)) {
;		Preemption is disabled until the next exception.
;	}
;
;	Note to kernel debugger users : The Kernel debugger and DosDebug
;	also use trap 3.  When setting breakpoints for debugging
;	this code, the earliest breakpoint must be placed AFTER the
;	inc _dynsemTrap instruction.  Any earlier int3 will cause
;	trap3 nesting until the stack overruns.  See the note below
;	regarding debugging.
;
;	If a tracepoint is taken at interrupt time, or is reententrant,
;	the INT 3 is silently removed, and processing continues.  The
;	protection against reentrant tracepoints is not perfect, but is
;	completely effective within the interpreter.   No tracepoints
;	should be set in this file.
;
;	The Major Event Code and Minor Event Code arrays do not control
;	dynamic tracepoints.  Having a valid tracepoint is sufficient to
;	enable a tracepoint.
;
;	The scanning loop is extremely time-critical.  Typical clocks
;	between completing the frame setup (mov ebp,esp) and finding the
;	tracepoint are something close to this magnitude :
;
;	Clks =	<constant-time overhead> +
;		40 * (number of modules traced) +
;		.3 * (number of tracepoints in the system) +
;		.3 * (average number of tracepoints per module)
;
;	A minimal tracepoint has been measured to take about 127 usec,
;	while a typical one seems to take about 150 usec.
;
;	The stack on entry looks like this.  Items pushed by _DYNTrap3 are
;	also shown here, below (SS:ESP).
;			SS			; DWORD
;			ESP
;			EFlags
;			CS			; DWORD
;			EIP
;			Error Code		; DWORD
;	     (SS:ESP)-> Trap Number		; DWORD = 3
;			return EIP to trap03
;			DS			; DWORD
;			PUSHAD frame
;			ES			; DWORD
;			FS			; DWORD
;			GS			; DWORD
;	     (SS:EBP)-> <other local variables>
;
;	ENTRY	(SS:ESP) = pointer to stack frame, as per above.
;		Interrupts disabled only if disabled when tracepoint was hit.
;
;	EXIT	Carry Clear :
;			Dynamic trace active and complete.
;			Do an Iret ASAP to Single-Step.
;		Carry Set :
;			Dynamic trace not active.
;			Assume some other reason for int 3.
;
;	USES	EFlags
;

Procedure _DYNTrap3			; DEPENDENCY ON dtci_frame.dt_ret
	ASSUME DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING

;	*************** CAVEAT PROGRAMMER ***************
;
;	USE NO KERNEL DEBUGGER BRAKPOINTS PRIOR TO THE DRAS3
;	LABEL UNLESS YOU REALLY KNOW WHAT YOU'RE DOING!!
;
;	*************** CAVEAT PROGRAMMER ***************

;	Push the entry frame for _dynInterpreter (see dtci_frame)

	push	ds
	pushad
	push	es			; WARNING: ES DO NOT LOAD ES YET !
	push	fs
	push	gs			; WARNING: GS NEVER RESTORED BELOW !
	sub	esp,offset dt_gs	; fill out the rest of the frame
	mov	ebp,esp			; frame complete
	cld				; clear direction flag

;	Find the linear address of the Trap 3...
;	WARNING:  ALL SEGMENT REGISTERS EXCEPT DS: ARE UNDEFINED!
;	Note: Don't waste any time here!

	FlatContext	ds,si
	mov	esi,[_SELGDTLaddr]	; (ESI) = _SELGDTLaddr
	movzx	eax,[ebp].dt_iret.pltiret32_cs
	shr	eax,3			; shift out RPL and TABLE bits
	jnc	short dt31		; GDT selector - use descriptor base.

	mov	edx,eax
	shl	edx,16			; build base linear address via CRMA
	jmp	short dt31a		; got LDT address - continue.

;	(EAX) = (CS selector >> 3)
;	(ESI) = Descriptor table to use

dt31:	mov	edx,[esi+eax*8+1]	; (high 3 bytes of EDX) = low 3 bytes
	mov	dl,[esi+eax*8+7]	; (low byte of EDX) = high base byte
	ror	edx,8			; (EDX) = Base Address of traced CS
dt31a:	add	edx,[ebp].dt_iret.pltiret32_eip
					; (EDX) = Linear address of CS:EIP
	dec	edx			; (EDX) = Linear address of tracepoint

;	Setup for scanning loop.

	mov	edi,[_pPTDACur]		; (EDI) = [_pPTDACur]
	movzx	eax,[edi].ptda_module	; (EAX) = Program MTE Handle
	mov	ebx,[_pdtoHeadScan]	; Start the scan at the first DTO
	mov	edi,edx			; Calculate the hash table index
	shr	edx,2			; ...Hash using bits 2 through 10
	movzx	edx,dl			; (DL) = hash table index
	xchg	edi,edx			; (EDX) = tracepoint addr; (EDI) = Hash.
	jmp	short dt35		; Begin the scan.

;	------- BEGIN SCANNING LOOP
;	In the following code, the registers contain :
;	(EAX) = program MTE handle
;	(EBX) = pdto (Dynamic Trace Object Pointer)
;	(ECX) = pdtr (Dynamic Trace Record Pointer)
;	(EDX) = Linear address of tracepoint
;	(EDI) = Hash table index
;	(ESI) = [_SELGDTLaddr]
;	(EBP) = Stack frame pointer
;	(DS) = Flat
;	(SS) = Undefined
;	ES, FS, and GS may not be modified yet as they will not be restored.

;	Search DTR hash bucket.  (Note: Buckets linked via dtr_Object)

dt32:	mov	ecx,[ebx].dto_dti.dti_apDTRHash[4*edi]	; Hash into DTR bucket
	jecxz	short dt34		; DTR hash bucket empty - next DTO

dt33:	cmp	[ecx].dtr_Offset,edx	; Is this the right tracepoint?
	je	short dt36		; yes - Tracepoint Found.    LOOP EXIT

	mov	ecx,[ecx].dtr_Object	; Move to next DTR in hash bucket
	or	ecx,ecx			; DTR hash bucket empty?
	jnz	short dt33		; no - continue scan DTR hash bucket

;	Move to next DTO to scan.  (Note: Do NOT use dti_pDTONext here)

dt34:	mov	ebx,[ebx].dto_dti.dti_pDTOScan	; Move to next DTO to Scan
dt35:	or	ebx,ebx			; End of DTO list?	     LOOP ENTRY
	jz	dt3xe			; yes - It's a breakpoint.   LOOP EXIT

	test	[ebx].dto_dti.dti_lfState,DTO_PROGRAM	; Program DTO?
	jz	short dt32		; no - scan next shared arena DTO

;	Multiple matches on the same linear address may occur in the
;	private arena.  We must verify that the hMTE stored in the dto
;	matches that stored in the current PTDA for all PROGRAM arena DTOs.

	cmp	[ebx].dto_dth.dth_hMTE,eax	; Program module MTE?
	je	short dt32			; yes - search this DTO.
	jmp	short dt34			; no - skip this DTO.

;	------- END SCANNING LOOP
;	Tracepoint Match Found. (Even if in private arena)
;	(EBX) = pdto
;	(ECX) = pdtr
;	(EDX) = Tracepoint Address
;	(ESI) = [_SELGDTLaddr]
;	(EBP) = (SS) relative dtci_frame pointer
;	(DS) = Flat

dt36:	mov	ss:[ebp].dt_pdto,ebx
	mov	ss:[ebp].dt_pdtr,ecx

;	_dynsemTrap is -1 if tracing is allowed at this point.

	inc	_dynsemTrap		; disallow other tracing
	jnz	dt3A			; reentrant tracepoint - remove it.

;	*************** CAVEAT PROGRAMMER ***************
;
;	Normal kernel debugger breakpoints are allowed now.
;
;	*************** CAVEAT PROGRAMMER ***************

;	DRAS3 labels the earliest safe breakpoint (for testing ONLY).
;	DRAS3 IS NOT AN ENTRY POINT.
PUBLIC	DRAS3				; let debugger see it in sym file.
DRAS3:					; earliest safe breakpoint.
	cmp	InterruptLevel,-1	; Interrupt time tracepoint?
	jne	dt3A			; yes - remove it.

	test	[ecx].dtr_Reserved,DTR_PURGED	; Purged tracepoint?
	jz	short dt37			; no - continue

	mov	edi,[_pPTDACur]			; (EDI) = [_pPTDACur]
	cmp	[edi].ptda_flDbgEnabled,0	; Debugged process context?
	je	short dt37			; no - continue

;	Here, we probably have a DosDebug breakpoint.  Find out for sure.
;	Performance gets killed here - hence the DTR_PURGED bit..

	SaveReg <es>
	FlatContext	es,ax
	movzx	eax,[edi].ptda_handle	; (EAX) = Current PTDA handle
					; (EDX) = Linear Address of tracepoint.
	CCALL32 _VMIsPrivatized <edx,eax>
	RestoreReg <es>

;	We need to maintain the state of _dynsemTrap in case this is a
;	breakpoint, so we decrement _dynsemTrap here.

	dec	_dynsemTrap		; Assume this is a breakpoint.
	or	eax,eax			; Privatized address?
	jnz	dt3xe			; yes - treat as a breakpoint

;	This was a tracepoint after all!  Continue...

	inc	_dynsemTrap		; not a breakpoint - continue.
	mov	ecx,ss:[ebp].dt_pdtr	; (ECX) = pdtr, again.

;	Here we set the limit of the DTB log selector and then load it
;	into (ES).  This lets us strictly enforce the log size without
;	constantly checking to see if the log had overflowed, improving
;	the overall performance of _dynInterpreter.  Note that loading
;	(ES) before this point would be a waste of time as (DS) is flat.
;	(ESI) = _SELGDTLaddr

dt37:	mov	ax,WORD PTR [ebx].dto_dth.dth_cbLogMax
	add	ax,offset dtb_Log - 1
	movzx	edx,[_dynselDTB]
	mov	[esi.edx].d_limit,ax	; set limit of DTB log selector
	mov	es,dx			; (ES) = DTB log selector

;	(EBX) = pdto
;	(ECX) = pdtr
;	(EBP) = (SS) relative dtci_frame pointer
;	(DS) = Flat
;	(ES) = DTB log selector

	CCALL32 _dynInterpreter		; not C Callable.

	mov	edi,ss:[ebp].dt_pdtr		; (EDI) = pdtr
	test	[edi].dtr_Reserved,DTR_REMOVED	; need to remove tracepoint?
	jnz	dt3AA				; yes - go remove tracepoint

;	See if we can emulate the one-byte simple opcode.
;
;	Note that if we are single-stepping the tracepoint, emulation of
;	the instruction would cause us to single-step two instructions
;	in a row.  We avoid this here by checking dt_iret.pltiret32_eflag.
;	We store the flags image in _DYNSavedUserFlags for trap01 to use
;	later - it needs to know the F_Trace bit on entry to the tracepoint.

	mov	eax,[ebp].dt_iret.pltiret32_eflag
	mov	_DYNSavedUserFlags,eax	; Save user flags for Trap 1 handler
	test	eax,F_TRACE
	jnz	short _dynSStep		; If single-stepping, we can't emulate

	movzx	eax,[edi].dtr_Opcode	; Get opcode (One byte)
	movzx	ebx,BYTE PTR cs:_dynaiapfnEmulate[eax]	; Get table index byte
	jmp	DWORD PTR cs:_dynapfnEmulate[4*ebx]	; SStep/Emulate opcode

;	A single step is required.  We cannot emulate the instruction.

Entry _dynSStep

;	Setup the alias PTE to the code.
;	WARNING: This prevents placing a tracepoint in _pgPageToPte.

	FlatContext	es,ax,NOASSUME
	mov	esi,[edi].dtr_Offset	; (EDI) = pdtr, (ESI) = Flat Offset
	mov	eax,esi
	shr	eax,PAGESHIFT		; (EAX) = page of dtr_Offset
	CCALL32 _pgPageToPte <eax, [_pPTDACur]>
	mov	eax,[eax]		; (EAX) = *ppte
	and	eax,NOT (PT_STATE or PT_RING3ACCESS)
	or	eax,(PTS_UVIRT or PT_RING3WRITE)
	mov	ecx,[_pptedynTraceAlias]; (ECX) -> Alias PTE
	mov	[ecx],eax		; setup writable alias to tracepoint

;	Flush the TLB.

	mov	eax,[_pgPhysPageDir]
	mov	cr3,eax

;	(ESI) = dtr_Offset
;	(EDI) = pdtr

	and	esi,PAGEMASK		; get low 12 bits of address
	add	esi,[_pbdynTraceAlias]	; add high 20 bits to get to alias addr
	mov	[_pbDYNResetPoint],esi	; save tracepoint reset point

;	RING 3 PREEMPTION DISABLED NOW

	mov	al,[edi].dtr_Opcode	; get the opcode to replace
	mov	[esi],al		; Remove INT 3 - replace opcode

;	Be sure to set the RF bit here so that Execute Debug Registers
;	work properly.
;
;	Convert the "Trap 3" into a "Fault 3" (dec eip, set F_RF in eflags).
;	Get ready to single-step the code. (set F_TRACE in eflags)

	dec	[ebp].dt_iret.pltiret32_eip
	or	[ebp].dt_iret.pltiret32_eflag,(F_TRACE or F_RF)

dt38:	add	esp,offset dt_fs	; pop frame (clears carry)
	pop	fs			; restore FS
	pop	es			; restore ES
	popad				; restore other registers
	dec	_dynsemTrap		; Allow tracepoints again.

;	SET NO BREAKPOINTS STARTING HERE

dt39:	pop	ds			; restore DS
	RETC				; return to trap03

;	Breakpoint...  Exit without wasting any mainline clocks...

dt3xe:	add	esp,offset dt_pad	; pop: dt_rasf, dt_gs, dt_fs, dt_es
	popad				; restore other registers
	stc				; Indicate an Error
	jmp	short dt39		; Exit.

;	BREAKPOINTS OK AGAIN.

;	This tracepoint is being removed because the REMOVE opcode was
;	interpreted (i.e., DTR_REMOVED got set during the execution
;	of _dynInterpreter).  Note that the tracepoint has not really
;	been removed yet, we're just using the DTR_REMOVED flag bit in
;	a non-standard way.
;
;	(EDI) = pdtr	(also in ss:[ebp].dt_pdtr)
;	(EBP) = (SS)	relative dtci_frame pointer
;	(DS) = Flat
;
dt3AA:	mov	ecx, edi			; (ECX) = pdtr
						; fall through to silently
						; remove tracepoint

;	Interrupt-time or reentrant tracepoint.	  Silently remove it.
;
;	(EBX) = pdto	(also in ss:[ebp].dt_pdto)
;	(ECX) = pdtr	(also in ss:[ebp].dt_pdtr)
;	(EBP) = (SS) relative dtci_frame pointer
;	(DS) = Flat

;	Setup the alias PTE to the code.
;	WARNING: This prevents placing a tracepoint in _pgPageToPte.

dt3A:	mov	ax,ds
	mov	es,ax			; (ES) = (DS) = Flat
	mov	edi,ecx			; (EDI) = pdtr
	mov	esi,[edi].dtr_Offset	; (ESI) = Flat Offset of tracepoint.
	mov	eax,esi
	shr	eax,PAGESHIFT		; (EAX) = page of dtr_Offset
	CCALL32 _pgPageToPte <eax, [_pPTDACur]>
					; (EAX) = ppte of tracepoint code
	mov	eax,[eax]		; (EAX) = *ppte
	and	eax,NOT (PT_STATE or PT_RING3ACCESS)
	or	eax,(PTS_UVIRT or PT_RING3WRITE); (EAX) = alias pte contents
	mov	ecx,[_pptedynTraceIntAlias]	; (ECX) -> Int. time Alias PTE
	and	esi,PAGEMASK		; get low 12 bits of address, then add
	add	esi,[_pbdynTraceIntAlias];high 20 bits to get to alias addr
	dec	[ebp].dt_iret.pltiret32_eip	; account for int 3.
	or	[ebp].dt_iret.pltiret32_eflag,F_RF	; set the RF bit
	mov	bl,[edi].dtr_Opcode	; (BL) = opcode to replace
	mov	edx,[_pgPhysPageDir]	; CR3 contents to flush TLB with.

;	(EAX) = alias pte contents
;	(BL) =	dtr_Opcode
;	(ECX) -> Int. time Alias PTE
;	(EDX) = [_pgPhysPageDir]
;	(ESI) -> Spot to write opcode.
;	(EDI) = pdtr

	cli				; DISABLE INTERRUPTS FOR REMOVAL.
	mov	[ecx],eax		; setup writable alias to tracepoint
	mov	cr3,edx			; Flush the TLB after pte edit.
	mov	[esi],bl		; Remove INT 3; replace opcode

;	Remove the tracepoint record from the hash chain so we won't
;	have any more spurious hash collisions.

	or	[edi].dtr_Reserved,DTR_REMOVED	; mark tracepoint as 'removed'
	mov	edx,[edi].dtr_Offset	; (EDX) = tracepoint address.
	shr	edx,2			; ...Hash using bits 2 through 10
	movzx	edx,dl			; (DL) = hash table index
	mov	ebx,ss:[ebp].dt_pdto	; (EBX) = pdto
	lea	edx,[ebx].dto_dti.dti_apDTRHash[4*edx]	; Hash into DTR bucket

;	(EDX) = ppdtr (pointer to pointer to modify)
;	(EDI) = pdtr (pointer to dtr to remove)

dt3B:	cmp	[edx],edi		; at hash bucket link to edit?
	je	short dt3C		; yes - remove the tracepoint.

	mov	edx,[edx]		; move to next element in the list.
;;	lea	edx,[edx].dtr_Object	; point at the link field.
.errnz	(offset dtr_Object)		; (Link field is at offset zero in DTR)
	or	edx,edx			; At end of chain?
	jnz	short dt3B		; no-continue searching for tracepoint


;	End of list - tracepoint has already been removed by a
;	reentrant or nested interrupt-time tracepoint.  Just exit.

	jmp	dt38			; Exit with carry clear.

dt3C:	mov	edi,[edi].dtr_Object	; (EDI) = Address of next DTR
	mov	[edx],edi		; remove old DTR from the bucket.
	jmp	dt38			; Exit with carry clear.
					; Interrupts reenabled upon iretd

;	Instruction Emulation Entry Points
;
;	These routines replace the single-step technology in the
;	cases where we have a simple one-byte opcode.  Tracepoints
;	placed on these instructions will be much faster than the
;	norm.  If the instruction has a prefix, it will not be emulated.
;	Note that code can be added to emulate more opcodes without
;	affecting the performance of opcodes already emulated at all.
;
;	Instuctions Emulated :
;		CLD, CLC, CMC, STC, NOP
;
;	Other Emulatable Instructions Not Emulated (rare opcodes) :
;		AAA, AAS, CBW, CWDE, CWD, CDQ, DAA, DAS, LAHF, STD, SAHF

Entry	_dynEmulateCLD			; Clear	 Direction Flag
	and	[ebp].dt_iret.pltiret32_eflag,NOT F_DIRECTION
	jmp	short _dynEmulateNOP

Entry	_dynEmulateSTC			; Set Carry
	or	[ebp].dt_iret.pltiret32_eflag,F_CARRY
	jmp	short _dynEmulateNOP

Entry	_dynEmulateCMC			; Complement Carry (well done, carry)
	btc	[ebp].dt_iret.pltiret32_eflag,0 ; bit index of F_CARRY = 0
.errnz	(F_CARRY - (1 SHL 0))		; verify bit index of F_CARRY = 0
	jmp	short _dynEmulateNOP

Entry	_dynEmulateCLC			; Clear Carry
	and	[ebp].dt_iret.pltiret32_eflag,NOT F_CARRY
;;	FallInto _dynEmulateNOP

Entry	_dynEmulateNOP
	push	offset FLAT:dt38	; emulate return to dt38

;;	FallInto _DYNRecordPoint

;	The above push emulates and optimizes the following code sequence:
;	CCALL32 _DYNRecordPoint		; record the tracepoint
;	jmp	short dt38		; exit

EndProc _DYNTrap3


;***EP	_DYNRecordPoint - Move DynTrc logging information to STDA
;
;	_DYNRecordPoint completes the logging of the tracepoint by
;	moving the gathered information into the STDA.  If the
;	tracepoint was aborted, no information will be saved.
;
;	ENTRY	(DS) = Flat
;
;	EXIT	None
;
;	USES	EAX, EBX, EDX, ESI, EFlags

Procedure	_DYNRecordPoint
	ASSUME DS:FLAT, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
;;	FallFrom _DYNTrap3		; Possibly fall from _DYNTrap3.
	push	ds
	mov	ds,[_dynselDTB]		; Address DTB

	ASSUME	DS:NOTHING

	cmp	ds:[dtb_fAbort],0	; Abort tracepoint?
	jnz	short drp8		; yes - save no information.

	movzx	eax,ds:[dtb_MajCode]
	mov	ah,BYTE PTR ds:[dtb_bfRas]
	mov	ebx,ds:[dtb_cbLog]
	mov	dx,ds:[dtb_MinCode]
	mov	esi,offset dtb_Log
	CALL16	K_F_Systrace		; Log the information
drp8:	pop	ds
	RETC
EndProc _DYNRecordPoint

DYNLOCK_TEXT	ENDS


;***EP	K_F_Systrace - far16 stub to near K_F_Systrace
;
;	It is not possible to change K_F_Systrace to far16 in
;	RASSTRP.ASM at the current time, due to the way it was coded.
;	This is a temporary far16 thunk to K_F_Systrace, and should
;	be removed at some future date.
;
;	ENTRY	See RASSTRP.ASM
;	EXIT	See RASSTRP.ASM
;	USES	See RASSTRP.ASM

	FARCODE HIGH4
HIGH4CODE    SEGMENT

Procedure	K_F_Systrace,far16
	call	K_F_Systrace
	RETC
EndProc K_F_Systrace

HIGH4CODE    ENDS

endif	; RAS

END
