windows-nt/Source/XPSP1/NT/termsrv/remdsk/rds/as/as16/ut.asm

493 lines
10 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
;
; UT.ASM
; Tracing goop, debug only
; Mouse/Keyboard event interrupt junk, all flavors
;
.386
option oldstructs
option readonly
option segment:use16
.model large,pascal
ifdef DEBUG
externDef _wsprintf:far16
externDef OutputDebugString:far16
externDef DebugBreak:far16
endif ; DEBUG
externDef DrvMouseEvent:far16
externDef DrvKeyboardEvent:far16
externDef mouse_event:far16
externDef keybd_event:far16
externDef MaphinstLS:far16
.data
ifdef DEBUG
externDef g_szDbgBuf:word
externDef g_szNewline:word
externDef g_dbgRet:word
externDef g_trcConfig:word
endif ; DEBUG
if 0
; DOS key redirection
externDef g_imDOSShellVDDEntry:dword
externDef g_imDOSVKDEntry:dword
endif
.code _TEXT
ifdef DEBUG
;
; We come in here with _cdecl var args. We use DebugOutput() to spit out
; the message. Then we do the debugbreak ourself.
;
_DbgZPrintWarning proc near
; Save IP of caller. What's left on stack is var args
pop [g_dbgRet] ; Save IP of output caller
; Push g_szDbgBuf to put result into.
push ds
push offset g_szDbgBuf
; We now have _cdecl args to wsprintf
call _wsprintf
;
; The same args are left on the stack, since wsprintf is _cdecl. The
; first is g_szDbgBuf. So we can convienently pass this to OutputDebugString().
; That routine is NOT _cdecl, so when it returns, we have exactly the
; same args that were passed in to us.
;
call OutputDebugString
; Now output a new line
push ds
push offset g_szNewline
call OutputDebugString
; Now we just need to do a near RET to the caller
push [g_dbgRet]
ret
_DbgZPrintWarning endp
;
; We come in here with _cdecl var args
;
_DbgZPrintTrace proc near
; Is tracing on?
test [g_trcConfig], 0001h
jnz _DbgZPrintWarning
ret
_DbgZPrintTrace endp
_DbgZPrintError proc near
; Save IP of caller. What's left on stack is var args
pop [g_dbgRet] ; Save IP of output caller
; Push g_szDbgBuf to put result into.
push ds
push offset g_szDbgBuf
; We now have _cdecl args to wsprintf
call _wsprintf
;
; The same args are left on the stack, since wsprintf is _cdecl. The
; first is g_szDbgBuf. So we can convienently pass this to OutputDebugString().
; That routine is NOT _cdecl, so when it returns, we have exactly the
; same args that were passed in to us.
;
call OutputDebugString
; Now output a new line
push ds
push offset g_szNewline
call OutputDebugString
; Break into the debugger
call DebugBreak
; Now we just need to do a near RET to the caller
push [g_dbgRet]
ret
_DbgZprintError endp
endif
;
; ASMMouseEvent()
; This passes the registers as parameters to a C function, DrvMouseEvent.
; It is basically the inverse of CallMouseEvent().
;
; NOTE:
; To be on the safe side, we preserve all registers just like keybd_event().
; USER trashes some registers, but it would not come as a surprise to find
; mouse drivers that expect incorrectly a register or two to not be
; altered.
;
ASMMouseEvent proc far
; Save registers that C code doesn't preserve
push eax
push ebx
push ecx
push edx
; Save original flags for turning ints off/on
pushf
; Push AX for DrvMouseEvent() call
push ax
; Do we need to turn interrupts off? We don't if they are already
pushf
pop ax
test ax, 0200h
jz SkipCli
cli
SkipCli:
; AX has already been pushed; push the rest of the parameters
push bx
push cx
push dx
push si
push di
cld
call DrvMouseEvent
; If interrupts were not disabled before, enable them now.
pop cx ; saved flags
pushf
pop ax ; current flags
; Find out what is different
xor ax, cx
test ax, 0200h
jz InterruptsOk
; The interrupt flag needs to be changed, do it
test cx, 0200h
jnz EnableInterrupts
cli
jmp InterruptsOk
EnableInterrupts:
sti
InterruptsOk:
; Does the direction flag need to be changed?
test ax, 0400h
jz DirectionOk
; The direction flag needs to be changed, do it
test cx, 0400h
jnz SetDirectionFlag
cld
jmp DirectionOk
SetDirectionFlag:
std
DirectionOk:
; Restore registers
pop edx
pop ecx
pop ebx
pop eax
retf
ASMMouseEvent endp
;
; CallMouseEvent()
; This puts the parameters into registers and calls the original mouse_event.
;
; There are two ways we can call this function:
; (1) Injection code is piping mouse events through USER. It is
; responsible for disabling/enabling interrupts before calling us.
; (2) mouse_event patch is calling through to USER.
;
CallMouseEvent proc near
;
; This is the stack, BP relative:
; WORD bpSave
; WORD near_ret
; WORD regDI
; WORD regSI
; WORD regDX
; WORD regCX
; WORD regBX
; WORD regAX
;
; We must preserve SI and DI
;
push bp
mov bp, sp
push si
push di
mov di, word ptr ss:[bp+4]
mov si, word ptr ss:[bp+6]
mov dx, word ptr ss:[bp+8]
mov cx, word ptr ss:[bp+10]
mov bx, word ptr ss:[bp+12]
mov ax, word ptr ss:[bp+14]
call mouse_event
pop di
pop si
mov sp, bp
pop bp
ret 6*2
CallMouseEvent endp
;
; ASMKeyboardEvent()
; This passes the registers as parameters to a C function, DrvKeyboardEvent.
; It is basically the inverse of CallKeyboardEvent().
;
; NOTE:
; keybd_event() MUST preserve all registers, unlike mouse_event().
;
ASMKeyboardEvent proc far
; Save flags and registers that aren't preserved in C code
push eax
push ebx
push ecx
push edx
pushf
; Push AX for DrvKeyboardEvent() call
push ax
; Check if interrupts off, w/o trashing CX permanently
pushf
pop ax
test ax, 0200h
jz SkipCli
cli
SkipCli:
; AX has already been pushed; push the rest of the parameters
push bx
push si
push di
cld
call DrvKeyboardEvent
;
; Restore the interrupt and string move direction flags to what they
; were before.
;
pop cx ; Original flags
pushf
pop ax ; Current flags
; What has changed?
xor ax, cx
; Has the interrupt state been altered?
test ax, 0200h
jz InterruptsOk
; Interrupts need to be turned on/off
test cx, 0200h
jnz EnableInterrupts
cli
jmp InterruptsOk
EnableInterrupts:
sti
InterruptsOk:
; Has the direction flag been altered?
test ax, 0400h
jz DirectionOk
; Direction flag needs to be set/cleared
test cx, 0400h
jnz SetDirection
cld
jmp DirectionOk
SetDirection:
std
DirectionOk:
; Restore registers
pop edx
pop ecx
pop ebx
pop eax
retf
ASMKeyboardEvent endp
;
; CallKeyboardEvent()
; This puts the parameters in registers and calls USER's keybd_event.
;
; There are two ways we can call this function:
; (1) Injection code is piping keybd events through USER. It is
; responsible for disabling/enabling interrupts before calling us.
; (2) keybd_event patch is calling through to USER.
;
CallKeyboardEvent proc near
;
; This is the stack, BP relative:
; WORD bpSave
; WORD near_ret
; WORD regDI
; WORD regSI
; WORD regBX
; WORD regAX
;
; We must preserve SI and DI
;
push bp
mov bp, sp
push si
push di
mov di, word ptr ss:[bp+4]
mov si, word ptr ss:[bp+6]
mov bx, word ptr ss:[bp+8]
mov ax, word ptr ss:[bp+10]
call keybd_event
pop di
pop si
mov sp, bp
pop bp
ret 4*2
CallKeyboardEvent endp
;
; This is our wrapper around krnl386's MaphinstLS() routine, which expects
; the 32-bit instance handle in EAX
;
MapInstance32 proc far
; Pop far return, pop 32-bit instance into eax, and replace far return
pop edx
pop eax
push edx
; Call krnl386 -- when MaphinstLS returns, it will return to our caller
jmp MaphinstLS
MapInstance32 endp
if 0
;
; DOS box key injection gunk. We use the shell vdd service.
;
IMGetDOSShellVDDEntry proc near
; Save DI, int2f will trash it
push di
; int2f 0x1684, vdd 0x0017 (shell) gets the service entry point
; It is returned in es:di
mov ax, 1684h
mov bx, 017h
int 2F
; Save the address (even if null)
mov word ptr ds:[g_imDOSShellVDDEntry], di
mov word ptr ds:[g_imDOSShellVDDEntry+2], es
pop di
ret
IMGetDOSShellVDDEntry endp
IMGetDOSVKDEntry proc near
; Save DI, int2f will trash it
push di
; int2f 0x1684, vkd 0x000d (vkd) gets the service entry point
; It is returned in es:di
mov ax, 1684h
mov bx, 00dh
int 2Fh
mov word ptr ds:[g_imDOSVKDEntry], di
mov word ptr ds:[g_imDOSVKDEntry+1], es
pop di
ret
IMGetDOSVKDEntry endp
IMForceDOSKey proc near
; ss:[sp] is near ret
; ss:[sp+2] is scanCode
; ss:[sp+4] is keyState
push bp
mov bp, sp
; Preserve extended registers
push ebx
push ecx
push edx
; Setup for VKD call
mov eax, 1 ; Service 1, stuff key
xor ebx, ebx ; VM 0, current VM
movzx ecx, word ptr ss:[bp+4]
shl ecx, 8 ; Scan code in high byte
or ecx, 1 ; Repeat count in low byte
movzx edx, word ptr ss:[bp+6] ; Shift state
call dword ptr ds:[g_imDOSVKDEntry]
mov ax, 0
; Failure?
jc DoneForceKey
; Success!
inc ax
DoneForceKey:
pop edx
pop ecx
pop ebx
mov sp, bp
pop bp
ret 2+2
IMForceDOSKey endp
endif ; if 0 for DOS key redirection
end