windows-nt/Source/XPSP1/NT/base/ntos/vdm/i386/vdmmisc.asm
2020-09-26 16:20:57 +08:00

486 lines
12 KiB
NASM

title "Miscellaneous support routines"
;++
;
;Copyright (c) 1991 Microsoft Corporation
;
;Module Name:
;
; vdmmisc.asm
;
;Abstract:
;
; This module contains miscellaneous support touines
;
;Author:
;
; Dave Hastings (daveh) 23-Feb-1992
;
;Revision History:
; 18-Dec-1992 sudeepb wrote vdmdispatchbop in assembly for performance
;
;--
.386p
.xlist
include ks386.inc
include callconv.inc
include mi386.inc
include vdm.inc
include vdmtib.inc
page ,132
_PAGE SEGMENT PARA PUBLIC 'CODE'
ASSUME DS:NOTHING, ES:NOTHING, SS:NOTHING, FS:NOTHING, GS:NOTHING
EXTRNP _Ki386AdjustEsp0,1
EXTRNP _KeRaiseIrql,2
EXTRNP _KeLowerIrql,1
EXTRNP _KeGetCurrentIrql,0
EXTRNP _KiDispatchException,5
EXTRNP _ObWaitForSingleObject,3
EXTRNP _NtReleaseSemaphore,3
EXTRNP _VdmpIsThreadTerminating, 1
EXTRNP _NtSetEvent,2
extrn _KeI386EFlagsAndMaskV86:DWORD
extrn _KeI386EFlagsOrMaskV86:DWORD
extrn _MmUserProbeAddress:DWORD
_PAGE ENDS
_DATA SEGMENT DWORD PUBLIC 'DATA'
public IcaLockTimeout
IcaLockTimeout DWORD 0ff676980h,0ffffffffh ; 1 sec time out in - hundred nanosecs
_DATA ENDS
_PAGE SEGMENT
ASSUME DS:FLAT, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING
page ,132
subttl "Switch between two contexts"
;++
;
; Routine Description:
;
; This routine unloads a context from a kframe, and loads a different
; context in it's place.
;
; ASSUMES that Irql is APC level, if it is not this routine
; may produce incorrect trapframes.
;
; Arguments:
;
; esp + 4 = PKTRAP_FRAME TrapFrame
; esp + 8 = PCONTEXT OutGoing
; esp + c = PCONTEXT InComming
;
; Returns:
;
; Nothing
;
;
cPublicProc _VdmSwapContexts,3
push ebp
mov ebp,esp
push esi
push edi
push ebx
if DBG
EXTRNP _DbgBreakPoint, 0
stdcall _KeGetCurrentIrql
cmp al, APC_LEVEL
je vs05
stdcall _DbgBreakPoint
vs05:
endif
;
;
; Move context from trap frame to outgoing context
;
mov esi,[ebp + 8]
mov edi,[ebp + 0ch]
if DBG
;
; Insure that we are really working on a stack frame
;
cmp [esi].TsDbgArgMark, 0BADB0D00h
jne vscfail
endif
test dword ptr [esi].TsEFlags,EFLAGS_V86_MASK
jz vs10
;
;
; Move segment registers
;
mov eax,[esi].TsV86Gs
mov [edi].CsSegGs,eax
mov eax,[esi].TsV86Fs
mov [edi].CsSegFs,eax
mov eax,[esi].TsV86Es
mov [edi].CsSegEs,eax
mov eax,[esi].TsV86Ds
mov [edi].CsSegDs,eax
jmp short vs20
vs10:
cmp word ptr [esi].TsSegCs,KGDT_R3_CODE OR RPL_MASK
je vs20 ; Flat Mode
mov eax,[esi].TsSegGs
mov [edi].CsSegGs,eax
mov eax,[esi].TsSegFs
mov [edi].CsSegFs,eax
mov eax,[esi].TsSegEs
mov [edi].CsSegEs,eax
mov eax,[esi].TsSegDs
mov [edi].CsSegDs,eax
vs20:
mov eax,[esi].TsSegCs
mov [edi].CsSegCs,eax
mov eax,[esi].TsHardwareSegSs
mov [edi].CsSegSs,eax
;
; Move General Registers
;
mov eax,[esi].TsEax
mov [edi].CsEax,eax
mov eax,[esi].TsEbx
mov [edi].CsEbx,eax
mov eax,[esi].TsEcx
mov [edi].CsEcx,eax
mov eax,[esi].TsEdx
mov [edi].CsEdx,eax
mov eax,[esi].TsEsi
mov [edi].CsEsi,eax
mov eax,[esi].TsEdi
mov [edi].CsEdi,eax
;
; Move Pointer registers
;
mov eax,[esi].TsEbp
mov [edi].CsEbp,eax
mov eax,[esi].TsHardwareEsp
mov [edi].CsEsp,eax
mov eax,[esi].TsEip
mov [edi].CsEip,eax
;
; Move Flags
;
mov eax,[esi].TsEFlags
mov [edi].CsEFlags,eax
;
; Move incoming context to trap frame
;
mov edi,esi
mov esi,[ebp + 10h]
mov eax,[esi].CsSegCs
mov ebx,[esi].CsSegSs
test dword ptr [esi].CsEFlags, EFLAGS_V86_MASK
jnz vsc05 ; don't worry about v86 segments
or ax, 3 ; RPL 3 only
or bx, 3 ; RPL 3 only
vsc05: mov [edi].TsSegCs,eax
mov [edi].TsHardwareSegSs,ebx
;
; Move General Registers
;
mov eax,[esi].CsEax
mov [edi].TsEax,eax
mov eax,[esi].CsEbx
mov [edi].TsEbx,eax
mov eax,[esi].CsEcx
mov [edi].TsEcx,eax
mov eax,[esi].CsEdx
mov [edi].TsEdx,eax
mov eax,[esi].CsEsi
mov [edi].TsEsi,eax
mov eax,[esi].CsEdi
mov [edi].TsEdi,eax
;
; Move Pointer registers
;
mov eax,[esi].CsEbp
mov [edi].TsEbp,eax
mov eax,[esi].CsEsp
mov [edi].TsHardwareEsp,eax
mov eax,[esi].CsEip
mov [edi].TsEip,eax
;
; Move Flags
;
mov eax,[esi].CsEFlags
test eax,EFLAGS_V86_MASK
jne vsc10
and eax,EFLAGS_USER_SANITIZE
or eax,EFLAGS_INTERRUPT_MASK
jmp vsc15
vsc10: and eax,_KeI386EFlagsAndMaskV86
or eax,_KeI386EFlagsOrMaskV86
vsc15: mov [edi].TsEFlags,eax
;
; Fix Esp 0 as necessary
;
mov esi,[ebp+0ch]
xor eax,[esi].CsEFlags
mov esi,[ebp + 10h]
test eax,EFLAGS_V86_MASK
jz vsc20
stdCall _Ki386AdjustEsp0, <edi>
test dword ptr [edi].TsEFlags,EFLAGS_V86_MASK
jz vsc20
;
; Move segment registers for vdm
;
mov eax,[esi].CsSegGs
mov [edi].TsV86Gs,eax
mov eax,[esi].CsSegFs
mov [edi].TsV86Fs,eax
mov eax,[esi].CsSegEs
mov [edi].TsV86Es,eax
mov eax,[esi].CsSegDs
mov [edi].TsV86Ds,eax
jmp short vsc30
vsc20:
;
; Move segment registers for monitor
;
mov eax,[esi].CsSegGs
mov [edi].TsSegGs,eax
mov eax,[esi].CsSegFs
mov [edi].TsSegFs,eax
mov eax,[esi].CsSegEs
mov [edi].TsSegEs,eax
mov eax,[esi].CsSegDs
mov [edi].TsSegDs,eax
;
; We are going back to 32 bit monitor code. Set Trapframe exception list
; to END_OF_CHAIN such that we won't bugcheck in KiExceptionExit.
;
mov eax, 0ffffffffh
mov [edi].TsExceptionList, eax
vsc30:
pop ebx
pop edi
pop esi
mov esp,ebp
pop ebp
stdRET _VdmSwapContexts
if DBG
vscfail: int 3
endif
_VdmSwapContexts endp
CriticalSection equ [esp+4]
page , 132
subttl "VdmpEnterCriticalSection"
;++
;
; NTSTATUS
; VdmpEnterIcaLock(
; IN PRTL_CRITICAL_SECTION pIcaLock
; )
;
; Routine Description:
;
; This function enters a UserMode critical section, with a fixed Timeout
; of several minutes.
;
; Touching the critical section may cause an exception to be raised which
; the caller must handle, since the critical section may be in UserMode
; memory.
;
;
; Arguments:
;
; CriticalSection - supplies a pointer to a critical section.
;
; Return Value:
;
; STATUS_SUCCESS - wait was satisfied and the thread owns the CS
; STATUS_INVALID_HANDLE - no semaphore available to wait on.
; STATUS_TIMEOUT
;
;
;--
align 16
cPublicProc _VdmpEnterIcaLock,1
cPublicFpo 1,0
mov edx,CriticalSection ; interlocked inc of
mov ecx,PCR[PcTeb]
mov ecx,TbClientId+4[ecx] ; NtCurrentTeb()->ClientId.UniqueThread
mov eax, STATUS_INVALID_HANDLE
cmp dword ptr CsLockSemaphore[edx],0 ; avoid lazy creates
jz short Eil20
xor eax,eax ; assume success
lock inc dword ptr CsLockCount[edx] ; ... CriticalSection->LockCount
jnz short Eil30
;
; Set Curr thread as Owner of CS with recursion count of 1
; and return SUCCESS
;
Eil10:
mov CsOwningThread[edx],ecx
mov dword ptr CsRecursionCount[edx],1
Eil20:
stdRET _VdmpEnterIcaLock
;
; If curr thread already owns CS,
; inc recusrion count and return SUCCESS
;
Eil30:
cmp CsOwningThread[edx],ecx
jne short Eil42
inc dword ptr CsRecursionCount[edx]
stdRET _VdmpEnterIcaLock
;
; Another Thread owns the CS so Wait on the lock semaphore,
;
Eil40:
mov edx, CriticalSection
Eil42:
xor eax,eax
lea ecx, IcaLockTimeout
stdCall _ObWaitForSingleObject <CsLockSemaphore[edx], eax, ecx>
mov ecx,PCR[PcTeb]
mov ecx,TbClientId+4[ecx] ; NtCurrentTeb()->ClientId.UniqueThread
mov edx,CriticalSection
or eax, eax
jz short Eil10 ; Take Ownership of CS
;
; If !NT_SUCCESS(Status) return with error. else some other
; less severe error occurred. In that case if thread terminating
; fail. Note: we may wake for user apc's even tho we are non
; alertable, because the vdm hw int dispatching code, and PsThread
; termination code forces these to occur.
;
test eax, 080000000h
jnz short Eil20 ; exit with Status in eax
Eil50:
stdCall _VdmpIsThreadTerminating <ecx> ; check for Term of self
or eax, eax
jnz short Eil20 ; exit with Status in eax
mov edx, CriticalSection
mov eax, CsOwningThread[edx]
stdCall _VdmpIsThreadTerminating <eax> ; check for Term of CSOwner
or eax, eax
jz short Eil40 ; retry
jmp short Eil20 ; exit with Status in eax
stdENDP _VdmpEnterIcaLock
page , 132
subttl "VdmpLeaveIcaLock"
;++
;
; NTSTATUS
; VdmpLeaveIcaLock(
; IN PRTL_CRITICAL_SECTION pIcaLock
; )
;
; Routine Description:
;
; This function leaves a critical section.
;
; Touching the critical section may cause an exception to be raised which
; the caller must handle, since the critical section may be in UserMode
; memory.
;
; Arguments:
;
; CriticalSection - supplies a pointer to a critical section.
;
; Return Value:
;
; STATUS_SUCCESS
; STATUS_INVALID_OWNER
; or NTSTATUS code from NtReleaseSemaphore
;
;--
align 16
cPublicProc _VdmpLeaveIcaLock,1
cPublicFpo 1,0
mov edx,CriticalSection
mov ecx,PCR[PcTeb]
mov ecx,TbClientId+4[ecx] ; NtCurrentTeb()->ClientId.UniqueThread
mov eax,STATUS_INVALID_OWNER ; Verify Owner of CritSect
cmp ecx,CsOwningThread[edx]
jne short Lil10
xor eax,eax ; Assume STATUS_SUCCESS
dec dword ptr CsRecursionCount[edx]
jnz short Lil30 ; leaving recursion
mov CsOwningThread[edx],eax ; clear owning thread id
lock dec dword ptr CsLockCount[edx] ; interlocked dec of LockCount
jge short Lil20 ; Thread waiting on LockSemaphore ?
Lil10:
stdRET _VdmpLeaveIcaLock
;
; release another thread waiting on the LockSemaphore
; and exit
Lil20:
stdCall _NtSetEvent, <CsLockSemaphore[edx], 0>
stdRET _VdmpLeaveIcaLock
;
; leaving recursion, just dec lock count
;
Lil30:
lock dec dword ptr CsLockCount[edx] ; interlocked dec of LockCount
stdRET _VdmpLeaveIcaLock
_VdmpLeaveIcaLock endp
_PAGE ends
end