Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1922 lines
44 KiB

page ,132
title TASK - task create/destroy procedures
.xlist
include kernel.inc
include tdb.inc
include pdb.inc
include newexe.inc
include dbgsvc.inc
include bop.inc
.list
outd macro msg,n
%out msg n
endm
if2
; outd <TDBsize =>,%TDBsize
endif
externW pStackBot
externW pStackMin
externW pStackTop
externFP SafeCall
externFP BuildPDB
externFP LockSegment
externFP UnlockSegment
;externFP Yield
externFP LocalInit
externFP GlobalAlloc
externFP GlobalFree
;externFP GlobalLock
externFP GlobalUnLock
externFP GlobalCompact
externFP IGlobalHandle
externFP GlobalLRUOldest
externFP AllocDStoCSAlias
;;;externFP FarMyLock
externFP FarSetOwner
externFP default_sig_handler
externFP CVW_Hack
externFP GlobalDOSAlloc
externFP GlobalDOSFree
externFP AllocSelector
externFP LongPtrAdd
externFP MyFarDebugCall
externFP Int21Handler
externFP far_get_arena_pointer32
externFP FarAssociateSelector32
externFP KRebootInit
if KDEBUG
externFP SetupAllocBreak
endif
ifdef WOW
externFP SetAppCompatFlags
externFP WowReserveHtask
externFP FreeSelector
externFP WowPassEnvironment
externFP ExitCall
endif
DataBegin
;externB fEMM
externB fBooting
externB kernel_flags
externB num_tasks
;externW hexehead
externW pGlobalHeap
externW curTDB
externW loadTDB
externW headTDB
externW headPDB
externW topPDB
externW cur_DOS_PDB
externW Win_PDB
externW MyCSAlias
externD pUserInitDone
externD ptrace_app_entry
externD ptrace_DLL_entry
externD pSignalProc
if KDEBUG
globalW allocTask,0
globalD allocCount,0
globalD allocBreak,0
globalB allocModName,0,8
endif ;KDEBUG
ifdef WOW
externD FastBop
externW DebugWOW
endif
DataEnd
sBegin CODE
assumes CS,CODE
assumes DS,NOTHING
assumes ES,NOTHING
externD prevInt00proc
externNP SaveState
externNP UnlinkObject
externNP genter
externNP gleave
nullcomline DB 0,0Dh
;-----------------------------------------------------------------------;
; GetCurrentTask ;
; ;
; Returns the current task. ;
; ;
; Arguments: ;
; none ;
; ;
; Returns: ;
; AX = curTDB ;
; DX = headTDB ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; all ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; nothing ;
; ;
; History: ;
; ;
; Sun Feb 01, 1987 07:45:40p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GetCurrentTask,<PUBLIC,FAR>
cBegin nogen
push es
SetKernelDS ES
mov ax,curTDB
mov dx,headTDB
; mov bx,codeOffset headTDB
; mov cx,codeOffset curTDB
pop es
ret
assumes es,nothing
cEnd nogen
;-----------------------------------------------------------------------;
; InsertTask ;
; ;
; Inserts a task into the task list. ;
; ;
; Arguments: ;
; parmW hTask ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; CX,DX,DI,SI,DS ;
; ;
; Registers Destroyed: ;
; AX,BX,ES ;
; ;
; Calls: ;
; nothing ;
; ;
; History: ;
; ;
; Sun Feb 01, 1987 09:41:24p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc InsertTask,<PUBLIC,NEAR>,<ds>
parmW hTask
cBegin
mov es,hTask ; get task handle
SetKernelDS
mov ax,headTDB ; get head of task list
UnSetKernelDS
or ax,ax ; anybody here?
jz ins1 ; no, just do trivial case
ins0: mov ds,ax ; point to head TDB
mov bl,es:[TDB_priority] ; get insert priority
cmp bl,ds:[TDB_priority] ; is it less than head task?
jg ins2 ; no, insert elsewhere
mov es:[TDB_next],ax
ins1: SetKernelDS
mov headTDB,es
UnSetKernelDS
jmps ins4
ins2: mov ds,ax ; save segment of previous TDB
mov ax,ds:[TDB_next] ; get segment of next tdb
or ax,ax ; if zero, insert now
jz ins3
mov es,ax ; point to new TDB
cmp bl,es:[TDB_priority]
jg ins2
ins3: mov es,hTask
mov ds:[TDB_next],es
mov es:[TDB_next],ax
ins4:
cEnd
;-----------------------------------------------------------------------;
; DeleteTask ;
; ;
; Deletes a task from the task list. ;
; ;
; Arguments: ;
; parmW hTask ;
; ;
; Returns: ;
; AX = hTask ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; UnlinkObject ;
; ;
; History: ;
; ;
; Sun Feb 01, 1987 09:41:24p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc DeleteTask,<PUBLIC,NEAR>
parmW hTask
cBegin
mov es,hTask
mov bx,dataOffset headTDB
mov dx,TDB_next
call UnlinkObject ; returns AX = hTask
cEnd
cProc FarCreateTask,<PUBLIC,FAR> ; Called from CreateTask
; parmW fPrev ; Calls several 'near' CODE funcs
cBegin
cCall SaveState,<ds>
SetKernelDS es
mov loadTDB,ds
cCall InsertTask,<ds>
clc
cEnd
if KDEBUG
;-----------------------------------------------------------------------
;
; CheckGAllocBreak
;
; Checks to see if the allocation break count has been reached.
; Returns CARRY SET if the allocation should fail, CLEAR otherwise.
; Increments the allocation count.
;
;-----------------------------------------------------------------------
LabelNP <PUBLIC, CheckGAllocBreak>
errn$ CheckLAllocBreak
cProc CheckLAllocBreak,<PUBLIC,NEAR>,<DS,AX>
cBegin
SetKernelDS
assumes ds,DATA
mov ax,allocTask ; if allocTask != curTDB, exit.
or ax,ax ; curTDB may be NULL during boot.
jz cab_nofail
cmp ax,curTDB
jnz cab_nofail
mov ax,word ptr allocBreak
cmp ax,word ptr allocCount ; if allocBreak != allocCount
jnz cab_increment ; inc allocCount
mov ax,word ptr allocBreak+2
cmp ax,word ptr allocCount+2
jnz cab_increment
or ax,word ptr allocBreak ; if allocBreak is 0L, just inc.
jz cab_increment
krDebugOut <DEB_ERROR>, "Alloc break: Failing allocation"
stc ; return carry set
jmp short cab_exit
cab_increment:
inc word ptr allocCount ; increment allocCount
jnz cab_nofail
inc word ptr allocCount+2
cab_nofail:
clc
cab_exit:
assumes ds,NOTHING
cEnd
endif ;KDEBUG
sEnd CODE
sBegin NRESCODE
assumes CS,NRESCODE
assumes DS,NOTHING
assumes ES,NOTHING
externNP MapDStoDATA
externNP GetInstance
externNP StartProcAddress
;-----------------------------------------------------------------------;
; CreateTask ;
; ;
; "Creates" a new task. It allocates the memory for the TDB+PDB struc, ;
; builds the PDB, constructs the TDB, initializes the EEMS memory ;
; arena, and sets the signature word in the TDB. TDB actually added ;
; to task queue by StartTask. ;
; ;
; Arguments: ;
; parmD pParmBlk ;
; parmW pExe ;
; parmW hPrev instance ;
; parmW fWOA ;
; ;
; Returns: ;
; AX = segment of TDB ;
; ;
; Error Returns: ;
; AX = 0 ;
; ;
; Registers Preserved: ;
; DI,SI,DS ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Thu 04-Jan-1990 21:18:25 -by- David N. Weise [davidw] ;
; Added support for OS/2 apps. ;
; ;
; Mon 07-Aug-1989 23:28:15 -by- David N. Weise [davidw] ;
; Added support for long command lines to winoldap. ;
; ;
; Thu Apr 09, 1987 03:53:16p -by- David N. Weise [davidw] ;
; Added the initialization for EMS a while ago, recently added the ;
; switching of stacks to do it. ;
; ;
; Sun Feb 01, 1987 07:46:53p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc CreateTask,<PUBLIC,FAR>,<si,di>
parmD pParmBlk
parmW pExe
; parmW fPrev
parmW fWOA
localW env_seg
localW comline_start
cBegin
call MapDStoDATA
ReSetKernelDS
cld
xor si,si
mov env_seg,si
mov comline_start,si
cmp si,pParmBlk.sel
jz parm_block_considered
cCall pass_environment,<pExe,pParmBlk>
inc ax
jnz @F
jmp ats6
@@: dec ax
mov env_seg,ax
mov comline_start,dx
mov si,size PDB ; start with size of PDB
cmp fWOA,0
jz parm_block_considered
les di,pParmBlk
les di,es:[di].lpcmdline
mov cx,es:[di]
sub cx,127 ; account for terminating 0Dh
jbe parm_block_considered
add si,cx
add si,15
and si,NOT 15
parm_block_considered:
add si,TDBsize+15 ; Room for task data and paragraph aligned.
; xor ax,ax ; Room for EMM save area if needed.
; mov al,fEMM
; add si,ax
and si,0FFF0h
mov di,si
mov cl,4
shr si,cl
ifdef WOW
; We need to ensure task handles are unique across multiple WOW VDMs
; on Windows NT, so that for example the undocumented feature of
; passing a 16-bit htask to Win32 Post(App|Thread)Message instead
; of a thread ID will work reliably with multiple WOW VDMs.
;
; To accomplish this we call WowReserveHtask, which will return
; the htask if the htask (ptdb) was previously unused and has
; been reserved for us. If it returns 0 another VDM is already
; using that value and so we need to allocate another and try again.
; To avoid risking exhausting low memory, we allocate memory for the
; TDB once using GlobalDOSAlloc, then clone it using AllocSelector.
; We test this cloned selector value using WowReserveHtask, if it
; fails we get another clone until one works. Then we free all but
; the clone we'll return, and magically swap things around so that
; the cloned selector owns the TDB memory and then free the original
; selector from GlobalDOSAlloc
;
xor dx,dx ; Make size of allocation a dword
regptr xsize,dx,di
cCall GlobalDOSAlloc,<xsize>
or ax,ax
jnz @f
jmp ats6 ; Return zero for failure.
@@: push di ; save TDB size on stack
push ax ; save GlobalDOSAlloc selector on stack
mov di,ax ; and in DI
cCall WowReserveHtask,<ax> ; returns htask or 0
or ax,ax ; Is this selector value avail as htask?
jz MustClone ; no, start cloning loop
pop ax ; htask to return
pop di ; TDB size
jmps NoClone
MustClone:
xor cx,cx ; count of clone selectors
xor si,si ; no selector to return yet
AnotherHtask:
push cx
cCall AllocSelector,<di> ; clone the selector
pop cx
or ax,ax
jz FreeAnyHtasks ; Out of selectors cleanup and exit
push ax ; save cloned selector on stack
inc cx
push cx
cCall WowReserveHtask,<ax> ; returns htask or 0
pop cx
or ax,ax
jz AnotherHtask ; conflict
mov si,ax ; SI = selector to return
pop bx ; pop the selector we're returning
dec cx
jcxz @f
FreeLoop:
pop bx ; pop an allocated selector from stack
push cx
cCall FreeSelector,<bx>
pop cx
dec cx
FreeAnyHtasks:
jcxz @f ; have we popped all the allocated selectors? Yes
jmps FreeLoop ; No
@@: mov ax,si
or si,si
jnz @f
pop ax ; original selector from GlobalDOSAlloc
cCall GlobalDOSFree,<ax>
pop di
jmp ats6
@@:
; SI is selector to return, top of stack is original GlobalDOSAlloc
; selector. We need to free the original selector and make the clone
; selector "own" the memory so it will be freed properly by GlobalDOSFree
; during task cleanup.
pop di ; DI = original GlobalDOSAlloc selector
push ds
mov ds, pGlobalHeap
UnSetKernelDS
.386
cCall far_get_arena_pointer32,<di>
push eax
cCall FarAssociateSelector32,<di,0,0>
pop eax
mov ds:[eax].pga_handle, si
cCall FarAssociateSelector32,<si,eax>
.286p
pop ds
ReSetKernelDS
cCall FreeSelector,<di>
mov ax,si ; AX is the final TDB selector/handle.
pop di ; TDB size
NoClone:
else
xor dx,dx ; Make size of allocation a dword
regptr xsize,dx,di
cCall GlobalDOSAlloc,<xsize>
or ax,ax
jnz @f
jmp ats6 ; Return zero for failure.
@@:
endif
mov es, ax
xor ax, ax ; zero allocated block
mov cx, di
shr cx, 1
xor di, di
rep stosw
mov ax, es
ats2a:
cCall FarSetOwner,<ax,ax> ; Set TDB owner to be itself
cmp fWOA,0 ; Is this WinOldApp?
mov ds,ax
UnSetKernelDS
jz no_it_isnt
or ds:[TDB_flags],TDBF_WINOLDAP
no_it_isnt:
; Initialize the task stack.
mov si,1 ; 1 for show means open window
les di,pParmBlk
mov ax,es
or ax,di
jnz @F
jmp ats4 ; AX = DI = 0 if no parmblock
@@: xor ax,ax ; Skip past EMM save area and
push ds
xor dx, dx
push es
mov es,pExe
mov dx,es:[ne_flags]
pop es
test dx,NEPROT
jz @F
or ds:[TDB_flags],TDBF_OS2APP
or ds:[TDB_ErrMode],08000h ; don't prompt for .DLL's
@@:
call MapDStoDATA
ReSetKernelDS
test dx,NEPROT ; OS/2 app?
mov dx,TopPDB ; DX has segment of parent PDB
jz use_kernel_TDB
; %OUT This should probably be Win_PDB
mov dx,cur_DOS_PDB ; inherit parent's stuff
use_kernel_TDB:
pop ds
UnSetKernelDS
push dx ; yes, get address of PDB
push es
mov si,(TDBsize+15) and not 15 ; Round up TDB size
cCall AllocSelector,<ds> ; Get us an alias selector
or ax, ax ; did we get it?
jnz ats_gotsel
mov bx, ds ; No, tidy up
mov ds, ax ; We will current ds, so zero it
cCall GlobalDOSFree,<bx> ; Free the memory
pop es
pop dx
xor ax, ax
jmp ats6
ats_gotsel:
xor dx, dx
cCall LongPtrAdd,<ax,dx,dx,si>
mov si, dx ; SI = selector of new PDB
pop es
pop dx
regptr esbx,es,bx ; es:bx points at parm block
mov bx,di
mov cx,256 ; just include enough room for PDB
cCall BuildPDB,<dx,si,esbx,cx,fWOA>; go build it
mov ax,si ; link on another PDB
push ds
call MapDStoDATA
ReSetKernelDS
xchg HeadPDB,ax
mov es,si
mov es:[PDB_Chain],ax
les di,pParmBlk
push si
lds si,es:[di].lpfcb1
UnSetKernelDS
mov di,PDB_5C_FCB
pop es
mov cx,ds
or cx,si
jz ats3b
mov cx,ds:[si]
inc cx
inc cx
cmp cx,24h
jbe ats3a
mov cx,24h
ats3a: rep movsb
ats3b: mov si,es
pop ds
mov ax,env_seg
or ax,ax
jz no_new_env
mov es:[PDB_environ],ax
no_new_env:
ats4: mov es,pExe
mov ds:[TDB_pModule],es ; Do this before InitTaskEMS
mov ax,comline_start ;!!! just for now os2
mov ds:[TDB_Validity],ax
push si
push ds
push ds
push es
pop ds
pop es
mov di,TDB_ModName
mov si,ds:[ne_restab]
lodsb ; get no of bytes in name
cbw
cmp ax,8
jbe @F
mov ax, ds
krDebugOut <DEB_WARN or DEB_krLoadMod>, "Module Name %AX0 (%AX1) too long"
mov ax,8
@@: mov cx,ax
cld
rep movsb
ifdef WOW
; (see other bug #74369 note)
; Load the App compatibility flags
; This ifdef WOW chunk is the same place as Win'95 task.asm to help get compat
; flags loaded sooner
mov cx,ds:[ne_expver]
mov es:[TDB_ExpWinVer],cx
cCall SetAppCompatFlags, <es>
mov es:[TDB_CompatFlags], ax
mov es:[TDB_CompatFlags2], dx
if KDEBUG
mov bx, ax
or bx, dx
jz @F
krDebugOut DEB_WARN, "Backward compatibility hack enabled: #dx#AX"
@@:
endif
endif
; initialize the interrupt vectors
mov di,TDB_INTVECS
call MapDStoDATA
ReSetKernelDS
mov ds,MyCSAlias
assumes ds,CODE
mov si,codeOffset prevInt00proc
mov cx,(4 * numTaskInts)/2
rep movsw
assumes ds,nothing
pop ds
pop si
cCall FarCreateTask ;,<fPrev>
jnc @F
jmp ats6
@@:
push ds
call MapDStoDATA
ReSetKernelDS
mov es,curTDB ; inherit the parents
pop ds
UnSetKernelDS
mov ds:[TDB_PDB],si ; save new PDB
or si,si ; do we have a new PDB?
jnz @F ; zero means no
mov si,es:[TDB_PDB]
mov ds:[TDB_PDB],si
@@: mov ds:[TDB_Parent],es
;
; Inherit parent's wow compatibiltiy flags
; Special code is required in wkman.c to exploit this
mov ax,es:[TDB_WOWCompatFlags]
mov ds:[TDB_WOWCompatFlags],ax
mov ax,es:[TDB_WOWCompatFlags2]
mov ds:[TDB_WOWCompatFlags2],ax
mov ax,es:[TDB_WOWCompatFlagsEx]
mov ds:[TDB_WOWCompatFlagsEx],ax
mov ax,es:[TDB_WOWCompatFlagsEx2]
mov ds:[TDB_WOWCompatFlagsEx2],ax
mov ds:[TDB_thread_tdb],ds
mov ds:[TDB_DTA].off,80h ; set initial DTA
mov ds:[TDB_DTA].sel,si
mov ds:[TDB_sig],TDB_SIGNATURE ; Set signature word.
mov ax,SEG default_sig_handler
mov ds:[TDB_ASignalProc].sel,ax
mov ax,codeOffset default_sig_handler
mov ds:[TDB_ASignalProc].off,ax
; Initialize the MakeProcInstance Thunks.
cCall AllocDStoCSAlias,<ds>
mov ds:[TDB_MPI_Sel],ax
mov ds:[TDB_MPI_Thunks],0
mov ds:[TDB_MPI_Thunks].2,MPIT_SIGNATURE
mov bx,TDB_MPI_Thunks + THUNKSIZE-2
mov cx,THUNKELEM-1
mov dx,bx
mp1: add dx,THUNKSIZE
.errnz THUNKELEM and 0FF00h
mov ds:[bx],dx
mov bx,dx
loop mp1
mov ds:[bx],cx
mov si, ds
mov di, ax
call MapDStoDATA
ReSetKernelDS
mov ds, pGlobalHeap
UnSetKernelDS
.386
cCall far_get_arena_pointer32,<si>
cCall FarAssociateSelector32,<di, eax>
.286p
mov ax, si
mov ds, si
ats6:
cEnd
;-----------------------------------------------------------------------;
; pass_environment
;
;
; Entry:
;
; Returns:
; AX = seg of new env if any
; DX = start of comline
;
; Error Return:
; AX = -1
;
; Registers Destroyed:
;
; History:
; Wed 27-Dec-1989 23:36:25 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
ifdef WOW
cProc pass_environment,<PUBLIC,NEAR>,<di,si,ds>
parmW pExe
parmD pParmBlk
cBegin
ReSetKernelDS
test fBooting,1
jz @F
xor ax,ax
jmp pe_exit
@@:
cCall WowPassEnvironment,<cur_DOS_PDB, pParmBlk, pExe>
or ax,ax
jz pe_error_exit
cCall FarSetOwner,<ax,pExe> ; Make this new guy the owner
jmps pe_exit
pe_error_exit:
mov ax, -1
pe_exit:
cEnd
else
cProc pass_environment,<PUBLIC,NEAR>,<di,si,ds>
parmW pExe
parmD pParmBlk
localW myEnv
cBegin
ReSetKernelDS
cld
test fBooting,1
jz @F
xor ax,ax
jmp pe_exit
@@:
cCall WowPassEnvironment,<Win_PDB, cur_DOS_PDB, pParmBlk, pExe>
mov es,curTDB
mov bl,es:[TDB_flags]
@@:
; massage environment
les di,pParmBlk
mov ax,es:[di].envseg
or ax,ax
jnz pe_given_env
; %OUT This should probably be Win_PDB
mov ds,cur_DOS_PDB
UnsetKernelDS
mov ax,ds:[PDB_environ]
pe_given_env:
mov myEnv,ax
mov es,ax ; ES => environment
xor ax,ax
mov cx,-1
xor di,di
@@: repnz scasb
cmp es:[di],al
jnz @B
neg cx
; dec cx ; include space for extra 0
push cx ; length of environment
mov dx,cx
; MORE TEST CODE TO SEE IF IT FIXES THE PROBLEM.
mov es,pExe
test es:[ne_flags],NEPROT
jnz @f
mov cx,3 ; Save room for magic word and nul
add dx,cx
push 8000h ; No command line after the env.
jmps pe_got_com_len
@@:
les di,pParmBlk
test bl,TDBF_OS2APP ; execer an OS/2 app?
jz pe_execer_dos_app
les di,es:[di].lpCmdLine
mov cx,-1
repnz scasb
repnz scasb ; get both strings
neg cx
add dx,cx
dec cx ; length of command line
or ch,80h ; mark special
push cx
jmps pe_got_com_len
pe_execer_dos_app:
inc es:[di].lpCmdLine.off
les di,es:[di].lpCmdLine
xor cx,cx
mov cl,es:[di][-1] ; length of command line
add dx,cx
inc dx ; We add a '\0' when we move it anyway
push cx
pe_got_com_len:
mov es,pExe
mov di,es:[ne_pfileinfo]
lea di,[di].opfile
mov cx,-1
repnz scasb
neg cx
dec cx
push cx ; length of file name
shl cx,1 ; for program pointer and arg 1
add dx,cx
cCall GlobalAlloc,<ax,ax,dx>
or ax,ax
jz @f
push ax
cCall FarSetOwner,<ax,pExe> ; Make this new guy the owner
pop ax
@@:
mov es,ax
pop dx ; length of filename
pop bx ; length of command line
pop cx ; length of environment
or ax,ax
jz pe_error_exit
mov ds,myEnv
xor di,di
xor si,si
rep movsb
mov ds,pExe
; MORE TEST CODE TO SEE IF IT FIXED THE PROBLEM
test ds:[ne_flags],NEPROT
jnz @f
mov ax,1
stosw
@@:
mov si,ds:[ne_pfileinfo]
lea si,[si].opfile
mov cx,dx ; length of filename
rep movsb
mov ax,di ; save position of comline start
test bh,80h ; if OS/2 execer comline is correct
jnz @F
mov si,ds:[ne_pfileinfo]
lea si,[si].opfile
mov cx,dx ; length of filename
rep movsb
@@: and bh,NOT 80h
lds si,pParmBlk
lds si,ds:[si].lpCmdLine
mov cx,bx
rep movsb
mov byte ptr es:[di],0 ; zero terminate
mov dx,ax ; comline start
mov ax,es
jmps pe_exit
pe_error_exit:
mov ax,-1
pe_exit:
cEnd
endif
;-----------------------------------------------------------------------;
; StartLibrary ;
; ;
; Initialize library registers. ;
; ;
; Arguments: ;
; parmW hExe ;
; parmD lpParms ;
; parmD startAddr ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; AX = 0 ;
; DS = data segment ;
; ;
; Registers Preserved: ;
; DI,SI ;
; ;
; Registers Destroyed: ;
; BX,CX,DX,ES ;
; ;
; Calls: ;
; GetInstance ;
; FarMyLock ;
; ;
; History: ;
; ;
; Thu 04-Jan-1990 22:48:25 -by- David N. Weise [davidw] ;
; Added support for OS/2 apps. ;
; ;
; Sat Apr 18, 1987 08:54:50p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc StartLibrary,<PUBLIC,NEAR>,<ds,si,di>
parmW hExe
parmD lpParms
parmD startAddr
localW hStartSeg
cBegin
cCall MapDStoDATA
ReSetKernelDS
cmp loadTDB,0
je notloading
test kernel_flags,KF_pUID ; All done booting?
jz notloading
mov es,loadTDB
test es:[TDB_Flags],TDBF_OS2APP
jnz notloading
mov ax,hExe
mov es,es:[TDB_LibInitSeg]
mov bx,es:[pStackTop]
xchg es:[bx-2],ax
mov es:[bx],ax
add es:[pStackTop],2
mov ax,hExe
jmp slxx
notloading:
mov si,hExe
mov es,si
test es:[ne_flags],NEPROT
jnz no_user_yet
cmp pSignalProc.sel,0
jz no_user_yet
xor ax,ax
mov bx,40h
cCall pSignalProc,<hExe,bx,ax,ax,ax> ; SignalProc(hModule,40h,wParam,lParam)
no_user_yet:
cCall GetInstance,<si>
mov di,ax
cCall IGlobalHandle,<SEG_startAddr>
xchg startAddr.sel,dx
mov hStartSeg,ax
;** Send the SDM_LOADDLL notification
mov bx,startAddr.off
mov cx,startAddr.sel
mov ax,SDM_LOADDLL
cCall MyFarDebugCall
cmp SEG_startAddr, 0
jnz HaveStart
mov ax, di
jmps slxx
HaveStart:
cCall IGlobalHandle,<di>
mov ds,si
UnSetKernelDS
mov cx,ds:[ne_heap]
mov ds,dx
les si,lpParms
mov ax,es
or ax,ax
jz dont_fault
les si,es:[si].lpcmdline
dont_fault:
mov ax,1 ; An Arts & Letters lib init doesn't
push di ; touch AX!!
ifdef WOW
push cs
push offset RetAddr
pushf
push startAddr.sel
push startAddr.off
push ax
push ds
push ax
mov ax,hExe
mov ds,ax
pop ax
push 0 ; hTask (meaningless for a DLL)
push ds ; hModule
push ds ; Pointer to module name
push ds:ne_restab
push ds ; Pointer to module path
push word ptr ds:ne_crc+2
cCall MapDStoDATA
ReSetKernelDS ds
push DBG_DLLSTART
test DebugWOW,DW_DEBUG
jz skip_bop
FBOP BOP_DEBUGGER,,FastBop
.286p
skip_bop:
add sp,+14
pop ds
UnSetKernelDS ds
pop ax
iret
RetAddr equ $
else
cCall SafeCall,<startAddr>
endif
pop di ; USER.EXE didn't save DI, maybe others
or ax,ax
jz slx
mov ax,di
slx:
push ax
pop ax
slxx:
cEnd
;-----------------------------------------------------------------------;
; StartTask ;
; ;
; Sets up the standard register values for a Windows task. ;
; ;
; Arguments: ;
; HANDLE hPrev = a previous instance ;
; HANDLE hExe = the EXE header ;
; FARP stackAddr = the normal task stack address (initial SS:SP) ;
; FARP startAddr = the normal task start address (initial CS:IP) ;
; ;
; Returns: ;
; AX = HANDLE ;
; ;
; Error Returns: ;
; AX = NULL ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; GetInstance ;
; FarMyLock ;
; ;
; History: ;
; ;
; Tue Apr 21, 1987 06:41:05p -by- David N. Weise [davidw] ;
; Added the EMS initialization of the entry tables in page 0. ;
; ;
; Thu Dec 11, 1986 11:38:53a -by- David N. Weise [dnw] ;
; Removed the superfluous call to calculate the largesr NR seg. ;
; ;
; Fri Sep 19, 1986 12:08:23p -by- Charles Whitmer [cxw] ;
; Made it return 0000 on error rather than terminate. ;
; ;
; Thu Sep 18, 1986 02:33:39p -by- Charles Whitmer [cxw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc StartTask,<PUBLIC,NEAR>,<si,di>
parmW hPrev
parmW hExe
parmD stackAddr
parmD startAddr
cBegin
cCall MapDStoDATA
ReSetKernelDS
xor di,di
cmp loadTDB,di
jnz st1
jmp stx
stfail0:
xor ax,ax
pop ds
jmp stfail
st1: push ds
cmp stackAddr.sel,di
jz stfail0
cmp startAddr.sel,di
jz stfail0
mov ds,loadTDB
UnSetKernelDS
cmp ds:[TDB_sig],TDB_SIGNATURE
jnz stfail0
; Get new task stack
cCall IGlobalHandle,<SEG_stackAddr>
mov ds:[TDB_taskSS],dx
mov ax,stackAddr.off
sub ax,(SIZE TASK_REGS)
mov ds:[TDB_taskSP],ax
; get my instance
cCall GetInstance,<hExe>
mov di,ax
mov ds:[TDB_Module],ax
; find my real code segment
cCall IGlobalHandle,<SEG_startAddr>
or dx,dx
jz stfail0
mov startAddr.sel,dx
; find my real data segment
cCall IGlobalHandle,<di> ; DI = handle of DGROUP
mov si,dx ; SI = address of DGROUP
if KDEBUG
; Set up the allocBreak globals if needed
cCall SetupAllocBreak,<ds>
endif ;KDEBUG
; copy junk from hExe -> TDB
mov es,hExe
mov cx,es:[ne_expver]
mov ds:[TDB_ExpWinVer],cx
mov cx,es:[ne_stack] ; CX = STACKSIZE
mov dx,es:[ne_heap] ; DX = HEAPSIZE
; set up the task registers
test es:[ne_flags],NEPROT
jnz st_OS2_binary
les bx,dword ptr ds:[TDB_TaskSP]
mov es:[bx].TASK_AX,0 ; Task AX = NULL
mov ax,ds:[TDB_PDB]
mov es:[bx].TASK_ES,ax ; Task ES = PDB
mov es:[bx].TASK_DI,di ; Task DI = hInstance or hExe
mov es:[bx].TASK_DS,si ; Task DS = data segment
mov ax,hPrev
mov es:[bx].TASK_SI,ax ; Task SI = previous instance
mov es:[bx].TASK_BX,cx ; Task BX = STACKSIZE
mov es:[bx].TASK_CX,dx ; Task CX = HEAPSIZE
mov es:[bx].TASK_BP,1 ; Task BP = 1 (far frame)
jmps st_regs_set
st_OS2_binary:
push di
mov es,ds:[TDB_PDB]
mov di,es:[PDB_environ]
les bx,dword ptr ds:[TDB_TaskSP]
mov es:[bx].TASK_AX,di ; Task AX = environment
mov es:[bx].TASK_DX,cx ; Task DX = STACKSIZE
lsl cx,si
inc cx
mov es:[bx].TASK_CX,cx ; Task CX = Length of data segment
mov ax,ds:[TDB_pModule]
mov es:[bx].TASK_DI,ax ; Task DI = hExe
mov es:[bx].TASK_SI,dx ; Task SI = HEAPSIZE
mov es:[bx].TASK_DS,si ; Task DS = data segment
mov es:[bx].TASK_ES,0 ; Task ES = 0
mov es:[bx].TASK_BP,1 ; Task BP = 1 (far frame)
xor ax,ax
xchg ax,ds:[TDB_Validity]
mov es:[bx].TASK_BX,ax ; Task BX = offset in env of comline
pop di
st_regs_set:
pop ds
push ds
ReSetKernelDS
test Kernel_Flags[2],KF2_PTRACE ;TOOLHELP.DLL and/or WINDEBUG.DLL?
jz st_NoPTrace
mov ax,startAddr.sel
mov ptrace_app_entry.sel,ax
mov ax,startAddr.off
mov ptrace_app_entry.off,ax
mov ax,SEG CVW_HACK
mov ds,ax
UnSetKernelDS
mov ax,codeOffset CVW_Hack
jmps st_PTraceHere
st_NoPTrace:
lds ax,startAddr ; Task CS:IP = start address
UnSetKernelDS
st_PTraceHere:
mov es:[bx].TASK_CS,ds
mov es:[bx].TASK_IP,ax
pop ds
ReSetKernelDS
stx: mov ax,di
stfail:
cEnd
;-----------------------------------------------------------------------;
; InitTask ;
; ;
; This should be the first thing called by app when first started. ;
; It massages the registers, massages the command line and inits ;
; the heap. ;
; ;
; Arguments: ;
; ;
; When a windows application starts up the registers look ;
; like this: ;
; ;
; AX = 0 ;
; BX = stack size ;
; CX = heap size ;
; DX = ? ;
; DI = hInstance ;
; SI = hPrevInstance ;
; BP = 0 ;
; ES = Segment of Program Segment Prefix (see page E-8) ;
; DS = Applications DS ;
; SS = DS ;
; SP = stack area ;
; ;
; FCB1 field at PSP:5CH contains up to 24h bytes of binary data. ;
; Windows apps get their ShowWindow parameter in the first word of ;
; of this data. ;
; ;
; Returns: ;
; AX = PSP address ;
; CX = stack limit ;
; DX = command show ;
; ES:BX = command line ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; LocalInit ;
; FarEMS_FirstTime ;
; ;
; History: ;
; ;
; Mon 11-Sep-1989 19:13:52 -by- David N. Weise [davidw] ;
; Remove entry of AX = validity check. ;
; ;
; Wed Mar 16, 1988 22:45:00a -by- T.H. [ ] ;
; Fix bug in exit path. It was not popping the saved DS from the ;
; far call frame properly. Normally, this is not a problem (since ;
; it does indeed save the DS register across the entire routine), ;
; but if the RET has to go through a RetThunk, the saved DS is not ;
; really the original DS value, but a special value needed by the ;
; INT3F RetThunk code. This causes a crash when something in this ;
; routine (like the call to UserInitDone) causes our calling code ;
; segment to be discarded. ;
; ;
; Sat Apr 18, 1987 08:43:54p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
STACKSLOP equ 150 ; stack slop for interrupt overhead
assumes ds,nothing
assumes es,nothing
; ES = TDB
public do_libinit
do_libinit proc near
push si
push es
mov si,es:[TDB_LibInitOff]
mov es,cx
libinit_loop:
cld
lods word ptr es:[si]
or ax,ax
jz libinit_done
push es
mov es,ax
cmp es:[ne_magic],NEMAGIC
jne libinit_loop1
mov ax,-1
push es
cCall StartProcAddress,<es,ax>
pop es
;;; jcxz libinit_loop1
xor cx,cx
cCall StartLibrary,<es,cx,cx,dx,ax>
or ax,ax
jnz libinit_loop1
mov ax,4CF0h
DOSFCALL
libinit_loop1:
pop es
jmp libinit_loop
libinit_done:
mov si,es
cCall GlobalUnlock,<si>
cCall GlobalFree,<si>
pop es
mov es:[TDB_LibInitSeg],0
mov es:[TDB_LibInitOff],0
pop si
ret
do_libinit endp
assumes ds,nothing
assumes es,nothing
cProc InitTask,<PUBLIC,FAR>
cBegin nogen
pop ax ; Get return address
pop dx
mov ss:[pStackMin],sp ; Save bottom of stack
mov ss:[pStackBot],sp
sub bx,sp ; Compute top of stack
neg bx
add bx,STACKSLOP
mov ss:[pStackTop],bx ; Setup for chkstk
xor bp,bp ; Initial stack frame
push bp ; is not a far frame as there
mov bp,sp ; is no return address
push dx ; Push return address back on
push ax
inc bp
push bp
mov bp,sp
push ds
jcxz noheap ; Initialize local heap if any
xor ax,ax
push es
cCall LocalInit,<ax,ax,cx>
pop es
or ax,ax
jnz noheap
push ds
jmp noinit
noheap:
push es
cCall GetCurrentTask
mov es,ax
mov cx,es:[TDB_LibInitSeg]
jcxz no_libinit
call do_libinit
no_libinit:
ifdef WOW
; (see other bug #74369 note)
; App compatibility flags are set during CreateTask time to make them avilable
; to .dll's that are loaded by do_libinit (this is the same as Win'95)
else
call SetAppCompatFlags
mov es:[TDB_CompatFlags], ax
mov es:[TDB_CompatFlags2], dx
if KDEBUG
mov bx, ax
or bx, dx
jz @F
krDebugOut DEB_WARN, "Backward compatibility hack enabled: #dx#AX"
@@:
endif
endif
pop es
push ds
cCall MapDStoDATA
ReSetKernelDS
test kernel_flags,KF_pUID ; All done booting?
jnz noboot ; Yes, continue
or kernel_flags,KF_pUID
mov fBooting,0
mov cx,ds
pop ds ; DS = caller's data segment
UnSetKernelDS
push es ; Save ES
push ax
push cx
cCall IGlobalHandle,<ds>
push ax
cCall UnlockSegment,<ds>
xor dx,dx
cCall GlobalCompact,<dx,dx> ; Compact memory
xor dx,dx
cCall GlobalCompact,<dx,dx> ; Once more for completeness
cCall IGlobalHandle ; ,<ax> from above
mov ds,dx
cCall LockSegment,<ds>
pop cx
push ds
mov ds,cx
ReSetKernelDS
cmp pUserInitDone.sel,0 ; for Iris's server
jz no_User_to_call
call pUserInitDone ; Let USER lock down stuff.
no_USER_to_call:
pop ds
UnSetKernelDS
pop ax
pop es
push ds
;** Initialize the reboot stuff here
push es ; Save across call
cCall KRebootInit ; Local reboot init code
pop es
noboot:
mov bx,PDB_DEF_DTA ; point at command line
mov cx,bx ; save copy in cx
cmp bh,es:[bx] ; any chars in command line?
je ws3a ; no - exit
ws1: inc bx ; point to next char
mov al,es:[bx] ; get the char
cmp al,' ' ; SPACE?
je ws1
cmp al,9 ; TAB?
je ws1
mov cx,bx ; save pointer to beginning
dec bx ; compensate for next inc
ws2: inc bl ; move to next char
jz ws3a ; bailout if wrapped past 0FFh
cmp byte ptr es:[bx],13 ; end of line?
jne ws2
ws3:
mov byte ptr es:[bx],0 ; null terminate the line
ws3a:
mov bx,cx ; ES:BX = command line
mov cx,ss:[pStackTop] ; CX = stack limit
mov dx,1 ; DX = default cmdshow
cmp word ptr es:[PDB_5C_FCB],2 ; Valid byte count?
jne wsa4 ; No, use default
mov dx,word ptr es:[PDB_5C_FCB][2] ; Yes, DX = passed cmdshow
wsa4:
mov ax,es ; AX = PSP address
noinit:
pop ds
; THIS is correct way to pop the call frame. Must pop the saved
; DS properly from stack (might have been plugged with a RetThunk).
sub bp,2
mov sp,bp
pop ds
pop bp
dec bp
ret
cEnd nogen
;-----------------------------------------------------------------------;
; InitLib ;
; ;
; Does what it says. ;
; ;
; Arguments: ;
; CX = # bytes wanted for heap ;
; ;
; Returns: ;
; ES:SI => null command line ;
; ;
; Error Returns: ;
; CX = 0 ;
; ;
; Registers Preserved: ;
; DI,DS ;
; ;
; Registers Destroyed: ;
; AX,BX,DX ;
; ;
; Calls: ;
; LocalInit ;
; ;
; History: ;
; ;
; Sat Apr 18, 1987 08:31:27p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc InitLib,<PUBLIC,FAR>
cBegin nogen
xor ax,ax
jcxz noheap1 ; Done if no heap
mov si,cx
cCall LocalInit,<ax,ax,cx>
jcxz noheap1 ; Done if no heap
mov cx,si
noheap1:
push ds
cCall MapDStoDATA
push ds
pop es
pop ds
mov si,codeOFFSET nullcomline
ret
cEnd nogen
if KDEBUG
if 0
;-----------------------------------------------------------------------
; SetupAllocBreak
;
; Initializes the allocation break globals
; from the ALLOCBRK environment variable.
;
; ALLOCBRK=MODULE,0x12345678
;
; Assumes:
; DS = loadTDB
;
; Trashes:
; ES, SI, AX, BX, CX, DX
;
szALLOCBRK db "ALLOCBRK="
cchALLOCBRK equ $-szALLOCBRK
cProc SetupAllocBreak,<NEAR, PUBLIC>,<SI>
cBegin
mov es,ds:[TDB_PDB]
mov es,es:[PDB_environ]
lea bx,szALLOCBRK
mov dx,cchALLOCBRK
call LookupEnvString
or bx,bx
jz nomatch
;
; See if TDB_ModName is the same as the ALLOCBRK= module.
;
mov si,TDB_ModName
modloop:
mov al,es:[bx] ; get next environment char
or al,al
jz nomatch ; if at end of environment, no match
cmp al,','
jz match ; if at comma, then they might match
cmp al,ds:[si]
jnz nomatch
inc bx ; advance ptrs and try next char
inc si
jmp modloop
match:
cmp byte ptr ds:[si],0 ; at end of module name string?
jnz nomatch
inc bx ; skip past comma.
call ParseHex ; parse hex constant into dx:ax
SetKernelDSNRes es
mov word ptr es:allocBreak,ax
mov word ptr es:allocBreak+2,dx
or ax,dx ; if allocBreak is 0, clear allocTask
jz @F
mov ax,ds ; otherwise allocTask = loadTDB.
@@:
mov es:allocTask,ax
xor ax,ax ; reset allocCount
mov word ptr es:allocCount,ax
mov word ptr es:allocCount+2,ax
nomatch:
cEnd
;-----------------------------------------------------------------------
; LookupEnvString
;
; ES -> environment segment
; CS:BX -> string to search for (which must include trailing '=')
; DX -> length of string to search for
;
; returns:
; es:bx = pointer to environment string past '='
;
cProc LookupEnvString,<NEAR, PUBLIC>,<SI,DI,DS>
cBegin
push cs ; ds = cs
pop ds
cld
xor di,di ;start at beginning of environment seg
lenv_nextstring:
mov si,bx ;si = start of compare string
mov cx,dx ;cx = string length
mov ax,di ;Save current position in env seg
repe cmpsb
je lenv_foundit
mov di,ax ; start at beginning again
xor ax,ax ; and skip to end.
xor cx,cx
dec cx ; cx = -1
repne scasb
cmp es:[di],al ;End of environment?
jne lenv_nextstring ;No, try next string
xor bx,bx ; BX == NULL == not found.
jmp short lenv_exit
lenv_foundit:
mov bx,di
lenv_exit:
cEnd
;---------------------------------------------------------------------------
;
; ParseHex
;
; Assumes:
; es:bx - pointer to hex string of form 0x12345678
;
; Returns:
; Hex value in dx:ax, es:bx pointing to char past constant.
;
; Trashes:
; cx
;
cProc ParseHex,<NEAR, PUBLIC>
cBegin
xor dx,dx ; zero break count
xor ax,ax
xor cx,cx ; clear hi byte of char
hexloop:
mov cl,es:[bx] ; get first digit
jcxz parse_exit
inc bx
cmp cl,' ' ; skip spaces
jz hexloop
cmp cl,'x' ; skip 'x' or 'X'
jz hexloop
cmp cl,'X'
jz hexloop
cmp cl,'0' ; '0'..'9'?
jb parse_exit
cmp cl,'9'
jbe hexdigit
or cl,'a'-'A' ; convert to lower case
cmp cl,'a' ; 'a'..'f'?
jb parse_exit
cmp cl,'f'
ja parse_exit
sub cl,'a'-'0'-10
hexdigit:
sub cl,'0'
add ax,ax ; dx:ax *= 16
adc dx,dx
add ax,ax
adc dx,dx
add ax,ax
adc dx,dx
add ax,ax
adc dx,dx
add ax,cx ; add in the new digit
adc dx,0
jmp hexloop
parse_exit:
cEnd
endif; 0
endif ;KDEBUG
sEnd NRESCODE
if KDEBUG
sBegin CODE
assumes cs,CODE
;------------------------------------------------------------------------
;
; char FAR* GetTaskModNamePtr(HTASK htask)
;
; Returns a far pointer to a task's module name
; Used by SetupAllocBreak to access the task module name.
;
; Coded in assembly because no C header file that describes
; the TDB exists (and it's a little late to create one now)
;
cProc GetTaskModNamePtr,<NEAR, PUBLIC>
ParmW htask
cBegin
mov dx,htask
mov ax,TDB_ModName
cEnd
sEnd CODE
endif; KDEBUG
sBegin MISCCODE
assumes cs, misccode
assumes ds, nothing
assumes es, nothing
externNP MISCMapDStoDATA
;-----------------------------------------------------------------------;
; GetDOSEnvironment
;
; Gets a pointer to the current task's starting environment string.
; Basically used by DLL's to find the environment.
;
; Entry:
; none
;
; Returns:
; DX:AX = pointer to current task's starting environment string
;
; Registers Destroyed:
;
; History:
; Tue 13-Jun-1989 20:52:58 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GetDOSEnvironment,<PUBLIC,FAR>
cBegin nogen
push ds
call GetCurrentTask
mov ds,ax
mov ds,ds:[TDB_PDB]
mov dx,ds:[PDB_environ]
xor ax,ax
pop ds
ret
cEnd nogen
;-----------------------------------------------------------------------;
; GetNumTasks ;
; ;
; Gets the number of tasks (AKA TDB) in the system. ;
; ;
; Arguments: ;
; none ;
; ;
; Returns: ;
; AX = number of tasks ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; all ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; nothing ;
; ;
; History: ;
; ;
; Thu Apr 09, 1987 11:34:30p -by- David N. Weise [davidw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GetNumTasks,<PUBLIC,FAR>
cBegin nogen
xor ax,ax
push ds
call MISCMapDStoDATA
ReSetKernelDS
mov al,num_tasks
pop ds
UnSetKernelDS
ret
cEnd nogen
sEnd MISCCODE
end