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 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, 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,, 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, parmW hTask cBegin mov es,hTask mov bx,dataOffset headTDB mov dx,TDB_next call UnlinkObject ; returns AX = hTask cEnd cProc FarCreateTask, ; Called from CreateTask ; parmW fPrev ; Calls several 'near' CODE funcs cBegin cCall SaveState, SetKernelDS es mov loadTDB,ds cCall InsertTask, 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 errn$ CheckLAllocBreak cProc CheckLAllocBreak,, 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 , "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,, 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, 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, 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, ; 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, ; 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, ; 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, 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, 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, push eax cCall FarAssociateSelector32, pop eax mov ds:[eax].pga_handle, si cCall FarAssociateSelector32, .286p pop ds ReSetKernelDS cCall FreeSelector, 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, 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, ; 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, ; 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, ; Free the memory pop es pop dx xor ax, ax jmp ats6 ats_gotsel: xor dx, dx cCall LongPtrAdd, 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,; 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 , "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, 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 ;, 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, 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, cCall FarAssociateSelector32, .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,, parmW pExe parmD pParmBlk cBegin ReSetKernelDS test fBooting,1 jz @F xor ax,ax jmp pe_exit @@: cCall WowPassEnvironment, or ax,ax jz pe_error_exit cCall FarSetOwner, ; Make this new guy the owner jmps pe_exit pe_error_exit: mov ax, -1 pe_exit: cEnd else cProc pass_environment,, parmW pExe parmD pParmBlk localW myEnv cBegin ReSetKernelDS cld test fBooting,1 jz @F xor ax,ax jmp pe_exit @@: cCall WowPassEnvironment, 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, or ax,ax jz @f push ax cCall FarSetOwner, ; 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,, 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, ; SignalProc(hModule,40h,wParam,lParam) no_user_yet: cCall GetInstance, mov di,ax cCall IGlobalHandle, 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, 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, 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,, 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, mov ds:[TDB_taskSS],dx mov ax,stackAddr.off sub ax,(SIZE TASK_REGS) mov ds:[TDB_taskSP],ax ; get my instance cCall GetInstance, mov di,ax mov ds:[TDB_Module],ax ; find my real code segment cCall IGlobalHandle, or dx,dx jz stfail0 mov startAddr.sel,dx ; find my real data segment cCall IGlobalHandle, ; DI = handle of DGROUP mov si,dx ; SI = address of DGROUP if KDEBUG ; Set up the allocBreak globals if needed cCall SetupAllocBreak, 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, pop es ;;; jcxz libinit_loop1 xor cx,cx cCall StartLibrary, or ax,ax jnz libinit_loop1 mov ax,4CF0h DOSFCALL libinit_loop1: pop es jmp libinit_loop libinit_done: mov si,es cCall GlobalUnlock, cCall GlobalFree, 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, 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, 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, push ax cCall UnlockSegment, xor dx,dx cCall GlobalCompact, ; Compact memory xor dx,dx cCall GlobalCompact, ; Once more for completeness cCall IGlobalHandle ; , from above mov ds,dx cCall LockSegment, 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, cBegin nogen xor ax,ax jcxz noheap1 ; Done if no heap mov si,cx cCall LocalInit, 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,, 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,, 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, 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, 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, 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, cBegin nogen xor ax,ax push ds call MISCMapDStoDATA ReSetKernelDS mov al,num_tasks pop ds UnSetKernelDS ret cEnd nogen sEnd MISCCODE end