mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1121 lines
30 KiB
1121 lines
30 KiB
|
|
title "OS/2 16B asm special routines"
|
|
;++
|
|
;
|
|
; Copyright (c) 1991 Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; dll16.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This module contains callbacks and dispatchers that help implementing
|
|
; some of the 16b OS2 1.X APIs that cannot be done by C code.
|
|
;
|
|
; Author:
|
|
;
|
|
; Yaron Shamir (YaronS) 30-May-1991
|
|
;
|
|
; Revision History:
|
|
;
|
|
;--
|
|
|
|
DCT_RUNABLE equ 0 ; Create thread in a runable state
|
|
DCT_RUNABLE_HIDDEN equ 2 ; Create thread in a runable state but with
|
|
; a high number (see os2v20.h)
|
|
.386p
|
|
|
|
EXTRN _Save32Esp@4:PROC
|
|
EXTRN _DosCreateThread@20:PROC
|
|
EXTRN _LDRDoscallsSel:WORD
|
|
EXTRN _DosExit@8:PROC
|
|
EXTRN _DosExitList@8:PROC
|
|
EXTRN _Od2Start16Stack:DWORD
|
|
EXTRN _Od2ExitListInProgress:DWORD
|
|
EXTRN _Od2Start16DS:DWORD
|
|
EXTRN _DosFlagProcess@20:PROC
|
|
EXTRN _DosSendSignal@12:PROC
|
|
EXTRN _DosHoldSignal@8:PROC
|
|
EXTRN _Od2GetTebInfoSeg@0:PROC
|
|
EXTRN _Od2CheckForCritSectOrSuspend@0:PROC
|
|
EXTRN _Od2GetInfoSegWasCalled:DWORD
|
|
EXTRN _Od2GetThread1TebBackup@0:PROC
|
|
|
|
_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
|
|
ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
;
|
|
; The Thread Starter is dispatched from the os2 server
|
|
; It get us to the 16b code, stack, DS and ES of the new thread.
|
|
; It takes as a parameter (ebp+8) a pointer to the 16 stack frame as
|
|
; created by the 16b thunk of DosCreateThread (doscalls.asm)
|
|
;
|
|
public _Od2ThreadStarter16
|
|
_Od2ThreadStarter16 proc
|
|
|
|
;
|
|
; Save the esp for later use by the thread when it will call APIs
|
|
;
|
|
mov eax, esp
|
|
push eax
|
|
call _Save32Esp@4
|
|
call _MoveInfoSegintoTeb
|
|
;
|
|
; Put selector of doscalls into AX
|
|
;
|
|
mov ax,_LDRDoscallsSel; Selector to Doscalls
|
|
|
|
; Now fetch the 16b context frame from the new stack
|
|
; the stack frame is created by Dos16CreateThread below
|
|
;
|
|
mov ebx, [esp+4]
|
|
;
|
|
; ebx points at
|
|
; IP:CS (of the user's start procedure)
|
|
; ES:DS
|
|
; SP:SS (they inturn point to ES)
|
|
;
|
|
lss sp, [ebx - 26]
|
|
|
|
;
|
|
; Restore 16-bit registers
|
|
;
|
|
db 066h ; force two byte pop
|
|
pop di
|
|
db 066h ; force two byte pop
|
|
pop si
|
|
db 066h ; force two byte pop
|
|
pop cx
|
|
db 066h ; force two byte pop
|
|
pop bx
|
|
db 066h ; force two byte pop
|
|
pop dx
|
|
;
|
|
; For segment registers ES, DS, we need to verify
|
|
; selectors before we fix them
|
|
;
|
|
mov bp,ax ; save ax (doscalls selector)
|
|
db 066H ; force two byte pop
|
|
pop ax ; ax<-saved ES
|
|
verr ax ; see if the value is still valid!
|
|
jz SetES
|
|
xor ax,ax
|
|
SetES:
|
|
mov es,ax
|
|
;
|
|
db 066H ; force two byte pop
|
|
pop ax ; ax<-saved DS
|
|
verr ax ; see if the value is still valid!
|
|
jz SetDS
|
|
xor ax,ax
|
|
SetDS:
|
|
mov ds,ax
|
|
;
|
|
;
|
|
; Before we return to the new thread, we need to setup
|
|
; That if it returns (instead of calling DosExit) -
|
|
; it goes into DosExitStub Thunk which will call
|
|
; DosExit (EXIT_THREAD, 0)
|
|
;
|
|
|
|
mov ax,bp
|
|
mov bp,sp
|
|
mov [bp+6],ax ; Segment
|
|
xor ax, ax
|
|
mov [bp+4],ax ; offset 0 in Doscalls.dll
|
|
xor ebp,ebp
|
|
|
|
;
|
|
; Now jump by far return
|
|
;
|
|
db 66h, 0cah ; 16-bit retf
|
|
dw 0 ; no params
|
|
|
|
|
|
_Od2ThreadStarter16 endp
|
|
|
|
;
|
|
; Dos16CreateThread copies relevant info from the saved 16b frame
|
|
; as was setup in the thunk to DosCreateThread, then
|
|
; calls DosCreateThread (the 32 bit version, dlltask.c) with &TID.
|
|
;
|
|
; APIRET
|
|
; Dos16CreateThread(
|
|
; PFNTHREAD pfnFunction(VOID),
|
|
; PTID16 ptidThread,
|
|
; PCHAR pbThrdStack)
|
|
;
|
|
;
|
|
public _Dos16CreateThread@12
|
|
_Dos16CreateThread@12 proc
|
|
|
|
;
|
|
; 16 bit segmented params pushed by apps
|
|
;
|
|
; ebx+40 pfnFun
|
|
; ebx+36 pTid
|
|
; ebx+32 pbStack
|
|
;
|
|
; 16 bit seg registers pushed by thunk
|
|
;
|
|
; ebx+24 ES
|
|
; ebx+26 DS
|
|
;
|
|
|
|
push ebp
|
|
mov ebp,esp
|
|
|
|
;
|
|
; now also (flat parameters called by the thunk)
|
|
;
|
|
; ebp+8 pfnFun
|
|
; ebp+12 pTid
|
|
; ebp+16 pbStack
|
|
;
|
|
|
|
;
|
|
; makeup a 16 bit saved state for ThreadStarter16
|
|
; we must put this on the new stack, otherwise it can
|
|
; be washed out if the calling thread is scheduled before
|
|
; the new thread
|
|
;
|
|
cmp word ptr[ebp+16],0 ; check for 64K stack (offset = 0)
|
|
jnz @F
|
|
inc word ptr[ebp+18] ; sel++ to prevent underflow
|
|
@@:
|
|
push ecx
|
|
mov eax, [ebp+16]
|
|
|
|
sub eax,4 ; save space on stack for DosExit return
|
|
sub eax,2
|
|
mov cx, [ebx+34] ; new thread's CS
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+32] ; new thread's IP
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+18] ; new thread's DS
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+16] ; new thread's ES
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+6] ; new thread's DX
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+8] ; new thread's BX
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+10] ; new thread's CX
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+12] ; new thread's SI
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+14] ; new thread's DI
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+26] ; new thread's SS
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+24]
|
|
sub cx,22 ; for DI:SI:CX:BX:DX:ES:DS:IP:CS:DOSEXIT
|
|
mov [eax], cx ; new thread's SP
|
|
pop ecx
|
|
|
|
;
|
|
; Now call DosCreateThread (32b)
|
|
; The 'ThreadParameter' parameter is setup to point to the frame above
|
|
;
|
|
|
|
; StackSize - set to default (4K for now)
|
|
;
|
|
|
|
push 1 ; will be rounded up
|
|
|
|
; Flags - set to be runnable immediately
|
|
;
|
|
push DCT_RUNABLE
|
|
|
|
; Thread Parameter
|
|
;
|
|
push dword ptr [ebp+16] ; the new 16 bit stack
|
|
|
|
; pfnFun
|
|
;
|
|
push offset FLAT:_Od2ThreadStarter16
|
|
|
|
; pTid
|
|
;
|
|
push dword ptr [ebp+12]
|
|
|
|
call _DosCreateThread@20 ; call 32-bit version
|
|
|
|
leave
|
|
ret 12 ; return to thunk
|
|
|
|
_Dos16CreateThread@12 endp
|
|
|
|
;
|
|
; PMNT16CreateThread copies relevant info from the saved 16b frame
|
|
; as was setup in the thunk to PMNTCreateThread, then
|
|
; calls DosCreateThread (the 32 bit version, dlltask.c) with &TID.
|
|
; The diffrence betwin PMNT16CreateThread and Dos16CreateThread is that
|
|
; PMNT16Create thread pushes DCT_RUNABLE_HIDDEN and Dos16CreateThread pushes
|
|
; DCT_RUNABLE
|
|
;
|
|
; APIRET
|
|
; PMNT16CreateThread(
|
|
; PFNTHREAD pfnFunction(VOID),
|
|
; PTID16 ptidThread,
|
|
; PCHAR pbThrdStack)
|
|
;
|
|
;
|
|
public _PMNT16CreateThread@12
|
|
_PMNT16CreateThread@12 proc
|
|
|
|
;
|
|
; 16 bit segmented params pushed by apps
|
|
;
|
|
; ebx+40 pfnFun
|
|
; ebx+36 pTid
|
|
; ebx+32 pbStack
|
|
;
|
|
; 16 bit seg registers pushed by thunk
|
|
;
|
|
; ebx+24 ES
|
|
; ebx+26 DS
|
|
;
|
|
|
|
push ebp
|
|
mov ebp,esp
|
|
|
|
;
|
|
; now also (flat parameters called by the thunk)
|
|
;
|
|
; ebp+8 pfnFun
|
|
; ebp+12 pTid
|
|
; ebp+16 pbStack
|
|
;
|
|
|
|
;
|
|
; makeup a 16 bit saved state for ThreadStarter16
|
|
; we must put this on the new stack, otherwise it can
|
|
; be washed out if the calling thread is scheduled before
|
|
; the new thread
|
|
;
|
|
push ecx
|
|
mov eax, [ebp+16]
|
|
|
|
sub eax,4 ; save space on stack for DosExit return
|
|
sub eax,2
|
|
mov cx, [ebx+34] ; new thread's CS
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+32] ; new thread's IP
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+18] ; new thread's DS
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+16] ; new thread's ES
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+6] ; new thread's DX
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+8] ; new thread's BX
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+10] ; new thread's CX
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+12] ; new thread's SI
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+14] ; new thread's DI
|
|
mov [eax], cx
|
|
sub eax, 2
|
|
mov cx, [ebx+26] ; new thread's SS
|
|
mov [eax], cx
|
|
sub eax,2
|
|
mov cx, [ebx+24]
|
|
sub cx,22 ; for DI:SI:CX:BX:DX:ES:DS:IP:CS:DOSEXIT
|
|
mov [eax], cx ; new thread's SP
|
|
pop ecx
|
|
|
|
;
|
|
; Now call DosCreateThread (32b)
|
|
; The 'ThreadParameter' parameter is setup to point to the frame above
|
|
;
|
|
|
|
; StackSize - set to default (4K for now)
|
|
;
|
|
|
|
push 1 ; will be rounded up
|
|
|
|
; Flags - set to be runnable immediately
|
|
;
|
|
push DCT_RUNABLE_HIDDEN
|
|
|
|
; Thread Parameter
|
|
;
|
|
push dword ptr [ebp+16] ; the new 16 bit stack
|
|
|
|
; pfnFun
|
|
;
|
|
push offset FLAT:_Od2ThreadStarter16
|
|
|
|
; pTid
|
|
;
|
|
push dword ptr [ebp+12]
|
|
|
|
call _DosCreateThread@20 ; call 32-bit version
|
|
|
|
leave
|
|
ret 12 ; return to thunk
|
|
|
|
_PMNT16CreateThread@12 endp
|
|
|
|
|
|
public _DosExitStub@0
|
|
_DosExitStub@0 proc
|
|
|
|
push 0
|
|
push 0
|
|
call _DosExit@8
|
|
leave
|
|
ret 0
|
|
|
|
_DosExitStub@0 endp
|
|
|
|
public _DosExitProcessStub@0
|
|
_DosExitProcessStub@0 proc
|
|
|
|
push 0
|
|
push 1
|
|
call _DosExit@8
|
|
|
|
leave
|
|
ret 0
|
|
|
|
_DosExitProcessStub@0 endp
|
|
|
|
public _Od2JumpTo16ExitRoutine@8
|
|
_Od2JumpTo16ExitRoutine@8 proc
|
|
|
|
mov bx, [esp+6]
|
|
lsl ax,bx ;// see if the value is still valid!
|
|
jz GoodRoutine
|
|
|
|
;
|
|
; The CS of the exit routine had become invalid, call DosExitList
|
|
; to skip this routine
|
|
;
|
|
pop eax ;// Return addresss (ignore)
|
|
pop eax ;// ExitRoutine address (ignore)
|
|
pop eax ;// ExitReason code (ignore)
|
|
|
|
;// push now parameters for DosExitList
|
|
push 0 ;//
|
|
push 3 ;// EXLST_EXIT
|
|
call _DosExitList@8
|
|
|
|
GoodRoutine:
|
|
mov _Od2ExitListInProgress, 1
|
|
call _MoveInfoSegintoTeb
|
|
pop ecx ;// Return addresss (ignore)
|
|
pop ecx ;// ExitRoutine address
|
|
pop edx ;// ExitReason code
|
|
xor ebp,ebp
|
|
lss sp,_Od2Start16Stack
|
|
mov eax,_Od2Start16DS
|
|
mov ds,ax
|
|
push dx ;// call (ExitRoutine)(ExitReason)
|
|
push 0 ; Force GP if returning from the ExitList routine
|
|
push ecx
|
|
db 066h, 0cbh ;// do a 16-bit retf
|
|
|
|
_Od2JumpTo16ExitRoutine@8 endp
|
|
|
|
|
|
; Entry point for 16-bit DosFlagProcess
|
|
; Setup call to C code by passing parameters plus pointer to 16-bit registers
|
|
;
|
|
; APIRET
|
|
; DosFlagProcess(
|
|
; ULONG pid,
|
|
; ULONG fScope,
|
|
; ULONG usFlagNum,
|
|
; ULONG usFlagArg)
|
|
;
|
|
; ebp+8 pid
|
|
; ebp+12 fScope
|
|
; ebp+16 usFlagNum
|
|
; ebp+20 usFlagArg
|
|
|
|
public DosFlagProcess16@16
|
|
DosFlagProcess16@16 proc
|
|
|
|
push ebp
|
|
mov ebp,esp
|
|
push ebx ; pointer to 16-bit stack
|
|
push dword ptr [ebp+20] ; usFlagArg
|
|
push dword ptr [ebp+16] ; usFlagNum
|
|
push dword ptr [ebp+12] ; fScope
|
|
push dword ptr [ebp+8] ; pid
|
|
call _DosFlagProcess@20
|
|
pop ebp
|
|
ret 16
|
|
|
|
DosFlagProcess16@16 endp
|
|
|
|
; Entry point for 16-bit DosSendSignal
|
|
; Setup call to C code by passing parameters plus pointer to 16-bit registers
|
|
;
|
|
; APIRET
|
|
; DosSendSignal(
|
|
; ULONG pid,
|
|
; ULONG usSigNumber
|
|
; )
|
|
;
|
|
; ebp+8 pid
|
|
; ebp+12 usSigNumber
|
|
|
|
public DosSendSignal16@8
|
|
DosSendSignal16@8 proc
|
|
|
|
push ebp
|
|
mov ebp,esp
|
|
push ebx ; pointer to 16-bit stack
|
|
push dword ptr [ebp+12] ; usSigNumber
|
|
push dword ptr [ebp+8] ; pid
|
|
call _DosSendSignal@12
|
|
pop ebp
|
|
ret 8
|
|
|
|
DosSendSignal16@8 endp
|
|
|
|
; Entry point for 16-bit DosHoldSignal
|
|
; Setup call to C code by passing parameters plus pointer to 16-bit registers
|
|
;
|
|
; APIRET
|
|
; DosHoldSignal(
|
|
; ULONG fDisable
|
|
; )
|
|
;
|
|
; ebp+8 fDisable
|
|
|
|
public DosHoldSignal16@4
|
|
DosHoldSignal16@4 proc
|
|
|
|
push ebp
|
|
mov ebp,esp
|
|
push ebx ; pointer to 16-bit stack
|
|
push dword ptr [ebp+8] ; fDisable
|
|
call _DosHoldSignal@8
|
|
pop ebp
|
|
ret 4
|
|
|
|
DosHoldSignal16@4 endp
|
|
|
|
public _SaveFSSeg@4
|
|
_SaveFSSeg@4 proc
|
|
push edi
|
|
mov edi, [esp+8]
|
|
mov eax,dword ptr fs:0
|
|
mov dword ptr [edi],eax
|
|
mov eax,dword ptr fs:4
|
|
mov dword ptr [edi+4],eax
|
|
mov eax,dword ptr fs:8
|
|
mov dword ptr [edi+8],eax
|
|
mov eax,dword ptr fs:12
|
|
mov dword ptr [edi+12],eax
|
|
mov eax,dword ptr fs:16
|
|
mov dword ptr [edi+16],eax
|
|
mov eax,dword ptr fs:20
|
|
mov dword ptr [edi+20],eax
|
|
mov eax,dword ptr fs:24
|
|
mov dword ptr [edi+24],eax
|
|
mov eax,dword ptr fs:28
|
|
mov dword ptr [edi+28],eax
|
|
mov eax,dword ptr fs:32
|
|
mov dword ptr [edi+32],eax
|
|
mov eax,dword ptr fs:36
|
|
mov dword ptr [edi+36],eax
|
|
pop edi
|
|
ret 4
|
|
_SaveFSSeg@4 endp
|
|
|
|
public _RestoreFSSeg@4
|
|
_RestoreFSSeg@4 proc
|
|
push esi
|
|
mov esi, [esp+8]
|
|
mov eax, dword ptr [esi+36]
|
|
mov dword ptr fs:36, eax
|
|
mov eax, dword ptr [esi]
|
|
mov dword ptr fs:0, eax
|
|
mov eax, dword ptr [esi+4]
|
|
mov dword ptr fs:4, eax
|
|
mov eax, dword ptr [esi+8]
|
|
mov dword ptr fs:8, eax
|
|
mov eax, dword ptr [esi+12]
|
|
mov dword ptr fs:12, eax
|
|
mov eax, dword ptr [esi+16]
|
|
mov dword ptr fs:16, eax
|
|
mov eax, dword ptr [esi+20]
|
|
mov dword ptr fs:20, eax
|
|
mov eax, dword ptr [esi+24]
|
|
mov dword ptr fs:24, eax
|
|
mov eax, dword ptr [esi+28]
|
|
mov dword ptr fs:28, eax
|
|
mov eax, dword ptr [esi+32]
|
|
mov dword ptr fs:32, eax
|
|
pop esi
|
|
ret 4
|
|
_RestoreFSSeg@4 endp
|
|
|
|
public _MoveInfoSegintoTeb
|
|
_MoveInfoSegintoTeb proc
|
|
|
|
;
|
|
; We are using this entry point
|
|
; to suspend threads going to 16
|
|
; bit when DosEnterCritSect is
|
|
; in power, and no signal processing
|
|
;
|
|
push ebp
|
|
mov ebp, esp
|
|
push eax
|
|
push ebx
|
|
push ecx
|
|
push edx
|
|
call _Od2CheckForCritSectOrSuspend@0
|
|
cmp _Od2GetInfoSegWasCalled, 0
|
|
je minfo2
|
|
|
|
call _Od2GetTebInfoSeg@0 ; eax contains pointer to InfoSeg
|
|
cmp dword ptr [eax+36],0
|
|
jnz minfo2 ; We are already in 16 bit
|
|
|
|
push eax
|
|
add eax,40
|
|
|
|
|
|
push eax
|
|
call _SaveFSSeg@4 ;Save TEB backup copy
|
|
|
|
call _RestoreFSSeg@4
|
|
|
|
minfo2:
|
|
pop edx
|
|
pop ecx
|
|
pop ebx
|
|
pop eax
|
|
pop ebp
|
|
ret
|
|
|
|
_MoveInfoSegintoTeb endp
|
|
|
|
;
|
|
; IMORTANT !!!
|
|
; This routine is used in thunk. EBX register must not be used inside it. This
|
|
; value will be used by signal handler as pointer to 16bit stack in the case that
|
|
; it will interrupt thread1 in thunk entry.
|
|
;
|
|
public _RestoreTeb
|
|
_RestoreTeb proc
|
|
|
|
cmp _Od2GetInfoSegWasCalled, 0
|
|
je rteb2
|
|
cmp dword ptr fs:36,0
|
|
jnz rteb2 ; We are already in 32 bit
|
|
|
|
push eax
|
|
push esi
|
|
rtebContinue1:
|
|
mov esi, dword ptr fs:32
|
|
rtebContinue2:
|
|
|
|
mov eax, dword ptr [esi]
|
|
mov dword ptr fs:0, eax
|
|
mov eax, dword ptr [esi+4]
|
|
mov dword ptr fs:4, eax
|
|
mov eax, dword ptr [esi+8]
|
|
mov dword ptr fs:8, eax
|
|
mov eax, dword ptr [esi+12]
|
|
mov dword ptr fs:12, eax
|
|
mov eax, dword ptr [esi+16]
|
|
mov dword ptr fs:16, eax
|
|
mov eax, dword ptr [esi+20]
|
|
mov dword ptr fs:20, eax
|
|
mov eax, dword ptr [esi+24]
|
|
mov dword ptr fs:24, eax
|
|
mov eax, dword ptr [esi+28]
|
|
mov dword ptr fs:28, eax
|
|
mov eax, dword ptr [esi+32]
|
|
mov dword ptr fs:32, eax
|
|
mov eax, dword ptr [esi+36]
|
|
mov dword ptr fs:36, eax
|
|
|
|
pop esi
|
|
pop eax
|
|
rteb2:
|
|
ret
|
|
|
|
_RestoreTeb endp
|
|
|
|
; Restore TEB for exit list dispatcher. The address of TEB backup will be taken
|
|
; from thread1 structure.
|
|
; This function is the spouse of RestoreTeb and it is similar. The only difference that
|
|
; we try to get TEB save block directly from the thread structure.
|
|
|
|
public _RestoreTebForThread1
|
|
_RestoreTebForThread1 proc
|
|
|
|
cmp _Od2GetInfoSegWasCalled, 0
|
|
je rteb2
|
|
cmp dword ptr fs:36, 0 ;CID thread in TEB
|
|
jnz rteb2
|
|
|
|
push eax
|
|
push esi
|
|
push ebx
|
|
push ecx
|
|
push edx
|
|
call _Od2GetThread1TebBackup@0 ;fs:32 can be overwritten with
|
|
;enviroment pointer
|
|
pop edx
|
|
pop ecx
|
|
pop ebx
|
|
test eax, eax
|
|
jz rtebContinue1 ;we failed to find thread1, use
|
|
;the saved pointer.
|
|
mov esi, eax
|
|
jmp rtebContinue2
|
|
_RestoreTebForThread1 endp
|
|
|
|
public _Od2GetFSSelector@0
|
|
_Od2GetFSSelector@0 proc
|
|
|
|
mov ax, fs
|
|
ret
|
|
|
|
_Od2GetFSSelector@0 endp
|
|
|
|
;
|
|
;VOID
|
|
;Od2JumpTo16NetBiosPostDispatcher(
|
|
; IN PVOID pUsersPostRoutine, // CS:IP format EBP+8
|
|
; IN PVOID UserStackFlat, // Flat pointer to user stack EBP+12
|
|
; IN USHORT UserStackSize, // User stack size EBP+16
|
|
; IN SEL UserStackSel, // Data selector to user stack EBP+20
|
|
; IN SEL UserStackAlias, // Code selector to user stack EBP+24
|
|
; IN PVOID pNcb, // 16 bit SEG:OFF ptr to NCB EBP+28
|
|
; IN UCHAR NcbRetCode // return code from NCB EBP+32
|
|
; );
|
|
;
|
|
; This routine is used to call a user's 16 bit net bios post routine.
|
|
; It thunks to the 16 bit code, and thunks back on user's return.
|
|
;
|
|
; Parameters:
|
|
; pUsersPostRoutine -- 16 bit far ptr to user's routine (which should end with a far return)
|
|
; UserStackFlat -- a 32 bit flat pointer to a 16-bit stack for the user to use
|
|
; UserStackSize -- a 16 bit value specifying the size of the stack
|
|
; UserStackSel -- a 16 bit selector to the segment containing the stack
|
|
; UserStackAlias -- a 16 bit code selector alias for the stack selector
|
|
; pNcb -- a 16 bit far ptr to be passed to user's routine in ES:BX
|
|
; NcbRetCode -- a byte to be passed to user's routine in AL (with AH = 0)
|
|
;
|
|
; Operation:
|
|
;
|
|
; On the top of the user's stack it prepares a 24 byte area that looks like this:
|
|
;
|
|
; A. 8 bytes -- a 32 bit far jump instruction to NetBiosDispatcherReturnPoint.
|
|
; this will be used by the user to return.
|
|
; B. 8 bytes -- an aligned 48 bit pointer saving the current 32 bit stack pointer
|
|
; prior to entry into the user's stack and routine
|
|
; C. 4 bytes -- a 16 bit far pointer to the point in the stack designated by A above.
|
|
; This is the return address prepared for the user. When he RETF's on this
|
|
; address he will jump to area A which contains a jump instruction back to
|
|
; our code. Note that the selector in this pointer is a code alias for the
|
|
; stack segment.
|
|
; D. 4 bytes -- The pointer pUsersPostRoutine. We RETF on this pointer in order to jump to
|
|
; the user's routine.
|
|
;
|
|
; When the stack is ready, it loads the registers and the new stackpointer, and then does a far
|
|
; return to jump to the user's routine.
|
|
; On return from the user's routine, the stack is restored back to its original state, we clean
|
|
; up, and return.
|
|
;
|
|
|
|
|
|
public _Od2JumpTo16NetBiosPostDispatcher@28
|
|
_Od2JumpTo16NetBiosPostDispatcher@28 proc
|
|
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
; save registers
|
|
|
|
push esi
|
|
push edi
|
|
push ebx
|
|
push es
|
|
push ds
|
|
|
|
;
|
|
; Save the esp for later use by the thread when it will call APIs
|
|
;
|
|
mov eax, esp
|
|
push eax
|
|
call _Save32Esp@4
|
|
call _MoveInfoSegintoTeb
|
|
|
|
; get esi to point to end of user's stack
|
|
|
|
mov esi, dword ptr [ebp+12]
|
|
mov word ptr [ebp+18], 0
|
|
add esi, dword ptr [ebp+16]
|
|
|
|
; put a 32 bit far jmp NetBiosDispatcherReturnPoint on user's stack
|
|
|
|
mov word ptr [esi-8], 0ea66h
|
|
mov dword ptr [esi-6], offset NetBiosDispatcherReturnPoint
|
|
mov word ptr [esi-2], cs
|
|
|
|
; save my own stack pointer
|
|
|
|
mov dword ptr [esi-16], esp
|
|
mov word ptr [esi-12], ss
|
|
|
|
; set up return address for user
|
|
|
|
mov ax, word ptr [ebp+24]
|
|
mov word ptr [esi-18], ax
|
|
mov ax, word ptr [ebp+16]
|
|
sub ax, 8
|
|
mov word ptr [esi-20], ax
|
|
|
|
; set up user's post routine address on user stack so we can RET to it
|
|
|
|
mov eax, dword ptr [ebp+8]
|
|
mov dword ptr [esi-24], eax
|
|
|
|
; set up ES:BX and AX for user
|
|
|
|
les bx, dword ptr [ebp+28]
|
|
movzx ax, byte ptr [ebp+32]
|
|
|
|
; set up stack pointer for user
|
|
|
|
sub word ptr [ebp+16], 24
|
|
lss esp, [ebp+16]
|
|
|
|
; jump to user's routine (with a 16 bit far return)
|
|
|
|
dw 0cb66h
|
|
|
|
NetBiosDispatcherReturnPoint:
|
|
|
|
; comes here after user routine finishes (returns with 16 bit far ret)
|
|
|
|
; start off by restoring my original stack pointer
|
|
|
|
movzx ebp, sp
|
|
lss esp, [ebp]
|
|
pop ds
|
|
pop es
|
|
|
|
;
|
|
|
|
call _RestoreTeb
|
|
|
|
; restore original registers, and return to caller
|
|
|
|
pop ebx
|
|
pop edi
|
|
pop esi
|
|
|
|
pop ebp
|
|
ret 28
|
|
|
|
_Od2JumpTo16NetBiosPostDispatcher@28 endp
|
|
|
|
;
|
|
; A utility routine to verify a segment for write.
|
|
; returns:
|
|
; 1 if segment reachable
|
|
; 0 if segment not reachable
|
|
; Implemented using inline i386 VERW instruction
|
|
;
|
|
; int
|
|
; IsLegalSelector(
|
|
; unsigned short aSelector)
|
|
;
|
|
PUBLIC _IsLegalSelector
|
|
_IsLegalSelector PROC
|
|
push ebp
|
|
mov ebp, esp
|
|
mov eax, 1 ; assume Selector is reachable
|
|
verw WORD PTR [ebp+8] ; verify the selector
|
|
je addr_ok ; exit if reachable
|
|
mov eax, 0 ; address not reachable
|
|
addr_ok:
|
|
leave
|
|
ret
|
|
_IsLegalSelector ENDP
|
|
|
|
;
|
|
; IMPORTANT !!!
|
|
; Changing the code below (Od2SetSegmentRegisters and Od2Continue) check the follows:
|
|
; - Od2GetSegmentRegisters (dlltask.c)
|
|
; - Od2PrepareEnterToSignalHandler (dlltask.c)
|
|
; - Od2JumpTo16SignalDispatch (ldrstart.asm)
|
|
; - Entry flat and Exit flat (doscalls.asm)
|
|
; - Os2SignalGetThreadContext (srvxcpt.c)
|
|
;
|
|
|
|
public _Od2SetSegmentRegisters@0
|
|
_Od2SetSegmentRegisters@0 proc
|
|
mov eax,ecx
|
|
shr eax,16 ; ES
|
|
verr ax ; see if the value is still valid!
|
|
jnz FixES
|
|
mov es,ax
|
|
jmp ESFixed
|
|
FixES:
|
|
xor ax,ax
|
|
mov es,ax
|
|
ESFixed:
|
|
mov eax,edx
|
|
shr eax,16 ; DS
|
|
verr ax ; see if the value is still valid!
|
|
jnz FixDS
|
|
mov ds,ax
|
|
jmp DSFixed
|
|
FixDS:
|
|
xor ax,ax
|
|
mov ds,ax
|
|
DSFixed:
|
|
ret
|
|
public _Od2SetSegmentRegistersEnd@0
|
|
_Od2SetSegmentRegistersEnd@0:
|
|
_Od2SetSegmentRegisters@0 endp
|
|
|
|
;
|
|
; The susbstitute for NtContinue. Return to the interrupted context.
|
|
; Parameter : pContext <- esp+4
|
|
; ret <- esp
|
|
; pContext :
|
|
; ES ;0
|
|
; DS ;4
|
|
; EDI ;8
|
|
; ESI ;12
|
|
; EBX ;16
|
|
; EDX ;20
|
|
; ECX ;24
|
|
; EAX ;28
|
|
; EBP ;32
|
|
; EIP ;36
|
|
; CS ;40
|
|
; EFLAGS ;44
|
|
; ESP ;48
|
|
; SS ;52
|
|
; There are 3 types of context:
|
|
; - 32bit stack, 32bit code (32bit)
|
|
; - 16bit stack, 16bit code (16bit)
|
|
; - 16bit stack, 32bit code (thunk)
|
|
;
|
|
public _Od2Continue@4
|
|
_Od2Continue@4 proc
|
|
|
|
mov eax,dword ptr [esp+4] ;eax - pointer to context
|
|
;
|
|
; restore registers that we will never use more
|
|
;
|
|
mov ebp,dword ptr [eax+32] ;EBP
|
|
mov edi,dword ptr [eax+8] ;EDI
|
|
mov esi,dword ptr [eax+12] ;ESI
|
|
|
|
;
|
|
; check if the interrupted context is 32bit
|
|
;
|
|
cmp word ptr [eax+52],23H ;SS
|
|
jne Od2Continue16bit
|
|
|
|
;
|
|
; 32bit
|
|
;
|
|
; | |
|
|
; --------- <- ESP of interrupted context
|
|
; | EIP |
|
|
; | EAX |
|
|
; ---------
|
|
;
|
|
mov ebx,dword ptr [eax+16] ;EBX
|
|
|
|
sub dword ptr [eax+48],8 ;ESP-8
|
|
mov edx,dword ptr [eax+48] ;ESP
|
|
mov ecx,dword ptr [eax+28] ;EAX
|
|
mov dword ptr [edx], ecx
|
|
mov ecx,dword ptr [eax+36] ;EIP
|
|
mov dword ptr [edx+4],ecx
|
|
|
|
mov edx,dword ptr [eax+20] ;EDX
|
|
mov ecx,dword ptr [eax+24] ;ECX
|
|
push dword ptr [eax+44] ;EFlags
|
|
popfd
|
|
|
|
mov esp,dword ptr [eax+48] ;ESP
|
|
|
|
pop eax
|
|
ret
|
|
;
|
|
; 16bit or thunk
|
|
;
|
|
; 16 bytes of the 16bit stack beyond it's top will be used:
|
|
; | |
|
|
; ------------- <- SP of interrupted context
|
|
; | ret address |
|
|
; | EAX |
|
|
; | EFlags |
|
|
; ------------- <- temprorary stack top (EDX)
|
|
Od2Continue16bit:
|
|
sub word ptr [eax+48],12 ;SP - substruct 12 bytes
|
|
;
|
|
; calculate the flat address of the temprorary stack top
|
|
;
|
|
mov ebx,dword ptr [eax+52] ;SS
|
|
shr bx,3
|
|
add bx,3800H
|
|
shl ebx,16
|
|
mov bx,word ptr [eax+48] ;EBX == temprorary stack top
|
|
|
|
;
|
|
; Set the values of EAX, DS and ES to 16bit stack
|
|
;
|
|
mov ecx,dword ptr [eax+28] ;EAX
|
|
mov dword ptr [ebx+4],ecx
|
|
mov ecx,dword ptr [eax+44] ;EFlags
|
|
mov dword ptr [ebx],ecx
|
|
mov dx,word ptr [eax+4] ;DS
|
|
cmp dx,23H
|
|
je Od2ContinueThunkFlat
|
|
shl edx,16
|
|
mov cx,word ptr [eax] ;ES
|
|
cmp dx,23H
|
|
je Od2ContinueThunkFlat
|
|
shl ecx,16
|
|
|
|
;
|
|
; check if the interrupted context was 16bit or thunk
|
|
;
|
|
cmp word ptr [eax+40],1bH ;CS
|
|
je Od2ContinueThunk
|
|
|
|
;
|
|
; 16 bit
|
|
;
|
|
;
|
|
; Copy CS:IP to the 16bit stack
|
|
;
|
|
mov cx,word ptr [eax+40] ;CS
|
|
mov word ptr [ebx+10],cx
|
|
mov cx,word ptr [eax+36] ;IP
|
|
mov word ptr [ebx+8],cx
|
|
|
|
mov ebx,dword ptr [eax+16] ;EBX
|
|
mov cx,word ptr [eax+24] ;ECX
|
|
mov dx,word ptr [eax+20] ;EDX
|
|
|
|
public _Od2ContinueStartBorder@0
|
|
_Od2ContinueStartBorder@0:
|
|
lss esp,[eax+48] ;ESP:SS
|
|
call _Od2SetSegmentRegisters@0
|
|
popfd
|
|
pop eax
|
|
db 66h, 0cah ; 16-bit retf
|
|
dw 0 ; 16-bit parameters
|
|
|
|
Od2ContinueThunk:
|
|
|
|
;
|
|
; Thunk to 16 bit
|
|
;
|
|
;
|
|
; Copy EIP to the 16bit stack
|
|
;
|
|
mov ecx,dword ptr [eax+36] ;EIP
|
|
mov dword ptr [ebx+8],ecx
|
|
|
|
mov ebx,dword ptr [eax+16] ;EBX
|
|
mov cx,word ptr [eax+24] ;ECX
|
|
mov dx,word ptr [eax+20] ;EDX
|
|
|
|
lss esp,[eax+48] ;ESP:SS
|
|
call _Od2SetSegmentRegisters@0
|
|
popfd
|
|
pop eax
|
|
ret
|
|
public _Od2ContinueEndBorder@0
|
|
_Od2ContinueEndBorder@0:
|
|
|
|
Od2ContinueThunkFlat:
|
|
|
|
;
|
|
; Return to Thunk that use flat registers (or Entry flat or part of JumpTo16)
|
|
;
|
|
;
|
|
; Copy EIP to the 16bit stack
|
|
;
|
|
mov ecx,dword ptr [eax+36] ;EIP
|
|
mov dword ptr [ebx+8],ecx
|
|
|
|
mov ebx,dword ptr [eax+16] ;EBX
|
|
mov ecx,dword ptr [eax+24] ;ECX
|
|
mov edx,dword ptr [eax+20] ;EDX
|
|
|
|
lss esp,[eax+48] ;ESP:SS
|
|
popfd
|
|
pop eax
|
|
ret
|
|
_Od2Continue@4 endp
|
|
|
|
IFDEF PMNT
|
|
|
|
EXTRN _PMNT_DosLockSeg@4:PROC
|
|
EXTRN _PMNT_DosUnlockSeg@4:PROC
|
|
EXTRN _LNotesPatchLock@4:PROC
|
|
EXTRN _LNotesPatchUnlock@4:PROC
|
|
|
|
public _DosLockSeg@4
|
|
_DosLockSeg@4 proc
|
|
push ebx
|
|
push dword ptr [esp+8]
|
|
call _PMNT_DosLockSeg@4
|
|
test eax,eax
|
|
jnz DosLockSegExit_1
|
|
call _LNotesPatchLock@4
|
|
xor eax,eax
|
|
ret 4
|
|
DosLockSegExit_1:
|
|
pop ebx
|
|
ret 4
|
|
_DosLockSeg@4 endp
|
|
|
|
public _DosUnlockSeg@4
|
|
_DosUnlockSeg@4 proc
|
|
push dword ptr [esp+4]
|
|
push ebx
|
|
call _LNotesPatchUnlock@4
|
|
call _PMNT_DosUnlockSeg@4
|
|
ret 4
|
|
_DosUnlockSeg@4 endp
|
|
|
|
ENDIF
|
|
|
|
_TEXT ends
|
|
end
|
|
|