;       SCCSID = @(#)exec.asm   6.10 92/03/11
SCCSID  equ     "@(#)exec.asm   6.10 92/03/11"
        PAGE    ,132
TITLE   EXEC - OS/2 2.0 EXEC system call
NAME    EXEC

;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved
;
;  Modification History
;
;  05-Mar-87  IDB       Initialize KBD_Mode to 0 in new PTDA (PTM 1420)
;  01-Jun-87  BWS       Initialize PTDA profile control block ptr.
;  18-Jul-87  SRW       Save Program Startup Registers in the Process Local
;                       Infoseg. mark =(@SR)                 (1.1.1 DCR 1)
;  15-Aug-87  IS        don't keep user's selectors in ES/DS any longer
;                       than is necessary (1.0 PTM 7090)
;  06-Dec-87  IS        Inherit ProcType from the parent (PTM 1413).
;  11-Jan-88  FJD       Added Ptrace Multiprocess support (DCR 71)
;  21-Jan-88  FJD       Deserialized Syncronous Exec's (PTM 1446)
;  06-Jun-88  JSF       Add tracing of entire trees or just child.
;                       (1.1 DCR 114)
;  26-Aug-88  JSF       Initialise ExitList semaphore to zero
;                       (1.2 PTM 1858)
;  07-Sep-88  JSF       Initialise InCritSec flag to zero
;                       (1.2 PTM 1974)
;  16-Oct-89  JH        Rewrote ExecPgm in 32-bit code
;  08-Nar-92  SFB       b734380 take out process perfview group
;  15-Nov-94   Change Team  85346 Remove call to _LDRClearSem from tkExecPgm
;  18:Nov-95    MLM     Defect 72417, moved find.inc after tkexport.inc

.xlist
INCL_ERROR_H    equ     1
        include fnotask.inc
        include dosseg.inc
        include basemaca.inc
        include osmaca.inc
        include dossymc.inc
        include mi.inc
        include harderr.inc
        include osconst.inc
        include bseerr.inc
        include curdir.inc
        include dirent.inc
        include exec.inc
        include screen.inc
        include vpb.inc
        include protmode.inc
        include seldesc.inc
        include mult.inc
        include sigdef.inc
        include except.inc
        include proc.inc
        include sem.inc
        include pgexport.inc
        include vmexport.inc
        include vmowner.inc
        include selxport.inc
        include infoseg.inc
        include tkexport.inc
        include find.inc
        include ldrxport.inc
        include virtsym.inc
        include kmode.inc
        include tkptda.inc
        include tkthread.inc
        include sched.inc
        include dbgex.inc
        include ldrvars.inc
.list

        ModName exec,FNO_EXEC_ASM
        CpuMode 386

        ReferFlat       _fTKUsesR2,BYTE
        ReferFlat       _pPTDACur,DWORD
        ReferFlat       _pTCBCur,DWORD
;b734380ReferFlat       _fPerfview,DWORD
        ReferGDT        GDT_PTDA,WORD
ifdef SECURITY
        ReferFlat       _fSec,BYTE                                        ;@SEC
        EXTRN32         _SecExec                                          ;@SEC
        EXTRN32         _SecExecPost                                      ;@SEC
endif

        EXTRN16         FuBuff
        EXTRN16         StrLen
        EXTRN16         FuStrLenZ
        EXTRN16         DupJFN
        EXTRN16         DupCDS
        EXTRN16         StrLen32                                     ;75220
        EXTRN16         FStrCpy32                                    ;75220

ifdef INCDEBUG
        EXTRN32         _DbgEnable
        EXTRN32         _DbgDisable
ENDIF

if RAS
        EXTRN32         _DYNAttach
        EXTRN32         _DYNAttachError
ENDIF
        EXTRN32         _LDRClearSem
        EXTRN32         _LDRFreeTask
        EXTRN32         _LDRLoadExe
        EXTRN32         _SELVirtToLin
        EXTRN32         _SELGetDescInfo:near
        EXTRN32         _SELGetSelector
        EXTRN32         _SELMemMapAlias
        EXTRN32         _SELMemUnmapAlias
        EXTRN32         _KSEMQueryMutex
        EXTRN32         _KSEMRequestMutex
        EXTRN32         _KSEMReleaseMutex
        EXTRN32         _TKCreateThread
        EXTRN32         _tkAllocPTDA
        EXTRN32         _tkEvapPTDA
        EXTRN32         _SEMTerminatePTDA                            ;AA04564
        EXTRN32         _VMFreeTask                                  ;AA04564
        EXTRN32         _tkStartProcess
        EXTRN32         _TKLibiError
        EXTRN32         _TKLibiStartDispatch
        EXTRN32         _TKLinkTask                                  ; D110795
        EXTRN32         _VMAllocMem
        EXTRN32         _VMAllocKHB                                  ;75220
        EXTRN32         _VMFreeKHB
;b734380 EXTRN32         _PVWCreateInstance_Prc
;b734380 EXTRN32         _PVWKillInstance_Prc

        FARCODE HIGH3
HIGH3CODE SEGMENT

;**     w_ExecPgm - Load in a protected mode program.
;
;       See tkExecPgm for details

        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

Procedure w_ExecPgm,faronly
        CALLF32 tkExecPgm,,nocheck
        RETC
EndProc w_ExecPgm

HIGH3CODE  ENDS


        FARCODE HIGH32
SWAP32_15  segment


;**     tkExecPgm - Load in a protected mode program.
;
;       ENTRY   (AX) = Exec flag
;               (DS:DX) = pathname address
;               (ES:BX) = Environment string address
;               (DI:SI) = Argument string address
;               (TCB_ObjNameBufL) = Load error object buffer length
;               (TCB_ObjNameBuf) = Load error object buffer address
;
;       EXIT    Carry Clear
;                   Async exec
;                       (EAX) = PID
;                       (EDX) = 0
;                   Sync exec
;                       (EAX) = Exit_Type
;                       (EDX) = Exit_Code
;               Carry Set
;                       (EAX) = Error Code
;
;       USES    All except BP
;
;       EFFECTS Switches Context
;
;       AX  Exec Flag
;       --  ---------
;        0  Start Sync Process
;        1  Start Async Process, discard result code
;        2  Start Async Process, save result code
;        3  Start Async Process, with Debug enabled.
;        4  Start Async Process, discard result code, and detach from parent
;        5  Start Async Process, start frozen
;        6  Start Async Process, with Debug enabled for entire subtree
;
;       ExecFlagTbl is used to translate the Exec Flag parameter
;       into the function and mode parameters used by tkStartProcess

ExecFlagTbl     db      exec_func_lgo,0         ; 0 - Sync, save result code
                db      exec_func_async,1       ; 1 - Async, discard result code
                db      exec_func_async,0       ; 2 - Async, save result code
                db      exec_func_trace,0       ; 3 - Trace, save result code
                db      exec_func_async,3       ; 4 - Async, detach from parent
                db      exec_func_ice,0         ; 5 - Freeze, save result code
                db      exec_func_trace_tree,0  ; 6 - Trace entire tree, save
                                                ;      result code for parent

MAX_EXEC_FLAG   equ     ((($ - ExecFlagTbl)/2)-1)       ; max valid ExecFlag

        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING
Procedure tkExecPgm,far32
LocalVar        ep_pathname,DWORD
LocalVar        ep_fqPath,DWORD                ; fully qualified path
LocalVar        ep_envstr,DWORD
LocalVar        ep_argstr,DWORD
LocalVar        ep_funcmode,DBYTE,ep_func,ep_mode
LocalVar        ep_envhdl,WORD
LocalVar        ep_info,<SIZE tkthrd_s>
LocalVar        ep_pptda,DWORD
LocalVar        ep_ptcb,DWORD
LocalVar        ep_sel,WORD                     ; for _SELGetSelector
LocalVar        ep_ac,<size vmac_s>             ; for _VMAlloc
LocalVar        ep_desc,<SIZE seldesc_s>        ; for _SELGetDescInfo
LocalVar        ep_prc,DWORD                    ; for tkStartProcess
                                                ; should be SIZE _RESULTCODES
LocalVar        ep_SecPreCalled,WORD            ; Did the SecExec callout happen?

ep_cmdoff  equ  <ep_info.ti_pcmdline.ptr_off>
ep_dslen   equ  <ep_info.ti_cbdata>
ep_envsel  equ  <ep_info.ti_penvdata.ptr_sel>

        EnterProc

        mov     ep_envstr.Offst,bx      ; Save environment string
        mov     ep_envstr.Segmt,es
        mov     ep_pathname.Offst,dx    ; Save pathname pointer
        mov     ep_pathname.Segmt,ds
        mov     ep_argstr.Offst,si      ; Save argument string pointer
        mov     ep_argstr.Segmt,di
        mov     ep_SecPreCalled,0
        mov     ep_fqPath,0

;       MMIOPH Performance Hook Removed
;       Maj/Min = 1064H, Data = Pathname (string at ds:dx)

        movzx   eax,ax
        cmp     eax,MAX_EXEC_FLAG       ; Validate Exec flag
        ja      tkeR1                   ; it's invalid..

        FlatContext <ds,es>,ebx

        mov     ebx,_pPTDACur           ; EBX = Current PTDA
        test    [ebx].ptda_infoseg.LIS_ProcStatus,PS_XITLST
        jnz     tkeR2                   ; No execs during ExitList

        push    eax                     ; save exec flag
        TKTakeKernelSem                 ; serialize PTDA variables.
        or      eax,eax
        .errnz  NO_ERROR
        pop     eax
        jnz     tkeE


;       get func and mode for tkStartProcess

        mov     ax,word ptr cs:ExecFlagTbl[eax*2]

        mov     ep_funcmode,ax          ; (AL) = function type
                                        ; (AH) = mode Save mode

        SSToDS  eax,ep_pptda            ; (EAX) = flat addr of ptda pointer
        CCALL32 _tkAllocPTDA <eax, VMAT_PRIV_TILED>     ; Allocate a PTDA
        or      eax,eax                 ; Error?
        .errnz  NO_ERROR
        jz      short tke1              ; No, continue
        mov     ebx,eax                 ; Error in ebx
        jmp     tkeD                    ;  yes, exit

tke1:   mov     esi,ep_pptda            ; (ESI) = child PTDA pointer

;       EBX = pPTDACur Parent PTDA
;       ESI = ep_pptda Child  PTDA

        mov     ax,[esi].ptda_handle    ; (AX) = child's handle
        mov     [ebx].ptda_child,ax     ; Save in parent
        mov     ax,[esi].ThisPTDA       ; (AX) = child's PTDA selector
        mov     [ebx].ptda_childalias,ax; Save in parent
        mov     [ebx].pPTDAExecChild,esi; Save flat pointer to child
        mov     [esi].ptda_rsrclist.Offst,0

        ;Inherit the Parent's LIBPATHs
        CCALL32 _tkInheritLIBPATH <ebx,esi>   ;moved here for defect 95157


; ????
        LDRGetSem                       ; prevent race conditions for mte's
        or      eax,eax
        jnz     tkeF                    ; interrupted by a signal    ;AA04564

ifdef INCDEBUG

;       If the current process is Debugged with the option trace entire tree,
;       or the child is to execed with tracing, start it now

        test    [ebx].ptda_flDbg,DBGP_TREE
                                        ; Trace entire tree?
        jnz     short tke2              ; yes, jump to trace child

        cmp     ep_func,exec_func_trace ; Exec for tracing ?
        je      short tke2              ; Yes, DbgEnable

        cmp     ep_func,exec_func_trace_tree
                                        ; Exec for tracing entire tree ?
        jne     short tke3              ; No, skip DbgEnable

tke2:   CCALL32 _DbgEnable <esi>        ; new process is now Debugged
        or      eax,eax
        jnz     tkeB

endif ;DEBUG

tke3:   mov     edi,_pTCBCur            ; (EDI) = pointer to current TCB

;       Mark global error text invalid (Used by loader)
        ldrInvErrTxt edi

;       We need to convert the pointer in TCB_ObjNameBuf from 16:16 to FLAT
;       because the loader expects it that way. EDI = pTCBCur

        movzx   eax,[edi].TCB_ObjNameBuf.Segmt
        movzx   edx,[edi].TCB_ObjNameBuf.Offst
        CCALL32 _SELVirtToLin <edx,eax>
        mov     [edi].TCB_ObjNameBuf,eax
        cmp     eax,-1
        jne     short tke4
        mov     [edi].TCB_ObjNameBuf,0

tke4:   lea     eax,ep_info
        SSToDS  eax
        PushP   eax                     ; pEnvInfo

        CCallNest
        movzx   eax,word ptr ep_pathname.Segmt
        movzx   edx,word ptr ep_pathname.Offst
        CCALL32 _SELVirtToLin <edx,eax>

        PushP   eax                     ; pchPathName
        CCALL32 _LDRLoadExe,,,PushP
        or      eax,eax
        jnz     tkeB



tke5:   cmp     ep_info.ei_loadtype,LDR_16bit
                                        ; 16-bit EXE ?
        jne     short tke7              ;  no, skip ahead

        movzx   ecx,ep_info.ei_ds       ; (CX) = data segment selector
        or      ecx,ecx
        jz      short tke6              ; PTR-B795909 allow zero DS
        SSToDS  eax,ep_desc
        movzx   edx,[ebx].ptda_child
        CCALL32 _SELGetDescInfo <ecx,edx,eax>
        or      eax,eax
        mov     ax,ERROR_BAD_FORMAT     ; assume error
        jnz     tkeB                    ; report an error on carry

        test    ep_desc.desc_acc,D_SEG  ; check access byte
        jz      tkeB                    ; report an error

tke6:   mov     edx,ep_desc.desc_cb
        mov     ep_dslen,dx             ; save auto data segment length
tke7:   SaveReg <ebx,esi,ds,es>
        CCALL32 tkgetnewenviron         ; get environment variables
        RestoreReg <es,ds,esi,ebx>
        jc      tkeB                    ; can't allocate environment
        mov     ax,ep_envhdl            ; (AX) = environment segment handle
        mov     [esi].ptda_environ,ax   ; Save it in child's PTDA

ifdef SECURITY
;       EBX = current PTDA
;       ESI = child PTDA
;       EDI = current TCB

;@SEC 125864  Moved callout after user args have been probed
;@SEC 108011  Moved callout after the program is loaded.
;@SEC         Now we can get the full canonacalized path from child ptda
;@SEC         May need to make sure cleanup frees all mem.
        cmp     _fSec,0
        jz      tke7a
        ; need to malloc a tmp buffer to hold process name

        SSToDS  eax,ep_fqPath
        CCALL32 _VMAllocKHB,<VM_HKH_PUB_RESRW,MAXPATHLEN,RASOWNER , NA, eax>
        or      eax,eax
        jnz     tkeB

        SaveReg <ebx,esi,edi,ds,es>               ; Save the world
        CCALL32 _SecExec < [esi].ptda_pszproc,ep_argstr, ep_fqPath>
        or      eax,eax                           ; check rc
        RestoreReg <es,ds,edi,esi,ebx>            ; restore the world
        jnz     tkeB                              ; Security failed call
        ; if successful security callout, then need to call exec post
        inc     ep_SecPreCalled
;@SEC end of changes
tke7a:
endif

        mov     ep_info.ti_fs,TKCT_EXTERNAL + TKCTE_FIRST + TKCT_SWAPTSD
        cmp     _fTKUsesR2,0            ; Module uses ring 2?
        jz      short tke8              ;  no, skip ahead
        or      ep_info.ti_fs,TKCTE_R2STACK ; Cause ring 2 stack allocation
tke8:   cmp     ep_info.ei_loadtype,LDR_16bit ; 16-bit dispatch?
        je      short tke9              ;  yes, skip ahead

;       Set up packet parameters for flat dispatch.

        or      ep_info.ti_fs,TKCTE_FLAT ; 32-bit dispatch
        movzx   eax,ep_envsel
        shr     eax , 3
        shl     eax , 16

;       CCALL32 _SELVirtToLin <0, eax>

        mov     ep_info.ti_penvdata,eax ; Set flat pointer to environment
        movzx   eax,ep_cmdoff           ; Get command line offset
        add     eax,ep_info.ti_penvdata ; Add base of env. seg.
        mov     ep_info.ti_pcmdline,eax ; Save address in packet

;       Create thread one.

tke9:   SSToDS  eax,ep_ptcb             ; EAX = address of the tcb pointer
        SSToDS  edx,ep_info             ; EDX = pointer to the info packet
        CCALL32 _TKCreateThread <esi,edx,eax,STATE_VOID>
                                        ; Create the new thread
        or      eax,eax                 ; Successful?
        .errnz  NO_ERROR
        jne     tkeB                    ;  no, fail the exec

if RAS
        CCALL32 _DYNAttach              ; Do DynamicTrace Attachments
        or      eax,eax
        jnz     tkeB                    ; Error attaching new tracepoints.

ENDIF ;RAS

;b734380cmp     _fPerfview,0            ; check if perfview is up
;b734380je      short tke9a             ;
;b734380CCALL32 _PVWCreateInstance_Prc,<esi,ep_ptcb>
;b734380                                ; Create Perfview per-process data blk
;b734380tke9a:
;       Set up LibInit dispatch (if any).

        cmp     ep_info.ei_loadtype,LDR_16bit ; 16-bit dispatch?
        jne     short tkeA              ;  no, skip ahead
        movzx   eax,ep_envsel           ; pass users AX

tkeA:   CCALL32 _TKLibiStartDispatch,<eax>
                                        ; set up library module init (if any)
        or      eax,eax                 ; Setup failed?
        .errnz  NO_ERROR
        jnz     tkeB                    ;  yes, go clean up

        CCALL32 _tkDupProcData,<esi>    ; Dup parent's files to child
        or      eax,eax                 ; Error?
        .errnz  NO_ERROR
        jnz     tkeB                    ;  yes, go clean up

        mov     eax,ep_ptcb             ; (EAX) = new thread's TCB
        push    dword ptr [eax].TCBNumber ; Save task slot

        test    ep_funcmode,0200h       ; D110795 detached process?
        jz      short tkeA1             ; D110795 no
        mov     [esi].ptda_Ppid,0       ; D110795 must be cleared for _TKLinkTask
tkeA1:
        CCALL32 _TKLinkTask,esi         ; D110795 Link child into process tree

;       Invalidate the user buffer pointer copy by setting its length
;       to 0.  This stops subsequent demand load error handling from
;       using the pointer when no longer valid (PTM 2763)

        mov     eax,_pTCBCur
        mov     [eax].TCB_ObjNameBufL,0 ; Set buffer length to 0

;85346        CCALL32 _LDRClearSem            ; release loader semaphore

        pop     ecx                     ; (CX) = task slot
        push    dword ptr [esi].ptda_infoseg.LIS_CurProcID

        xor     eax,eax
        mov     [ebx].pPTDAExecChild,eax
        mov     [ebx].ptda_childalias,ax

                                        ; Child was delivered ok
        mov     [ebx].ptda_child,ax     ; (AX) = Handle to child's PTDA

        TKClearKernelSem                ; deserialize PTDA variables

        mov     bx,ep_funcmode          ; (BL) = function (go/freeze)
                                        ; (BH) = exec mode (orphan flag)
        SSToDS  eax,ep_prc              ; prc
        movzx   edx,bh                  ; type
        movzx   ecx,bl                  ; state
        CCALL32 _tkStartProcess,<esi,ecx,edx,eax>

        mov     edx,ep_prc
        mov     ecx,edx
        shr     edx,16

        pop     eax                     ; (AX) = child's PID
        movzx   eax,ax

;       If Aync. Exec: tkStartProcess ret'd (EDX) = 0

tkeS1:  or      bl,bl                   ; wait for child to die?
        jnz     tkeX                    ; no, just leave  (CY clear)

;       Sync. Exec: ProcessCreate ret'd (ECX) = Exit_Type, (EDX) = Exit_Code

        mov     eax,ecx                 ; (EAX) = Exit_Type from child.
        jmp     tkeX

;       General error handler for ExecPgm errors
;       (AX) = loader error code
;       (BP) = base of loader stack frame variables

tkeB:   mov     ebx,eax                 ; save error code

        CCALL32 _TKLibiError            ; Clean up LibInit structures
;b734380cmp     _fPerfview,0            ; check if perfview is up
;b734380je      short tkeb1
;b734380CCALL32 _PVWKillInstance_Prc,<ep_pptda>
;b734380                                ; Clean up Perfview data block
;b734380tkeb1:
if RAS
        CCALL32 _DYNAttachError         ; Clean up DynamicTrace structures
endif ;RAS

ifdef INCDEBUG
;       Clear up any debugging

        CCALL32 _DbgDisable <ep_pptda>  ; disable debugging, if enabled
ENDIF ;INCDEBUG

        CCALL32 _LDRFreeTask <ep_pptda> ; release memory, mte, etc...

; ????
        CCALL32 _LDRClearSem            ; Release loader semaphore

tkeC:   mov     esi,_pPTDACur                                        ;AA04564
        xor     eax,eax
        mov     [esi].ptda_child,ax     ; Clear links from parent to child
        mov     [esi].ptda_childalias,ax
        mov     [esi].pPTDAExecChild,eax

        CCALL32 _tkEvapPTDA <ep_pptda>  ; Evaporate the PTDA

tkeD:   TKClearKernelSem                ; deserialize PTDA variables
        mov     eax,ebx                 ; (AX) = error code
tkeE:   stc                             ; set CARRY to indicate error

tkeX:
ifdef SECURITY
;@SEC Notifiy Security
;@SEC 108011 - also changed this callout to get name from child ptda
        pushf
        FlatContext <ds,es>,ebx                    ; Ensure flat. 130376
        cmp     _fSec,0
        jz      tkeX4
        SaveReg <eax,ecx,edx>                      ; save
        cmp     ep_SecPreCalled,0
        je      tkeX2                              ; callout didn't happen or was failed
        mov     ecx, ep_fqPath
        CCALL32 _SecExecPost < ecx,ep_argstr,eax>

tkeX2:  mov     eax, ep_fqPath
        or      eax,eax                            ; did we allocate buffer?
        jz      tkeX3
        CCALL32 _VMFreeKHB < VM_HKH_PUB_RESRW, eax>
tkeX3:  RestoreReg <edx,ecx,eax>                   ; restore
tkeX4:  popf
endif
        LeaveProc
        RETC

tkeR1:  mov     eax,ERROR_INVALID_DATA  ; Exec Flag invalid
        jmp     short tkeE

tkeR2:  mov     eax,ERROR_INVALID_FUNCTION ; not during exitlist.
        jmp     short tkeE

        ; If we failed to obtain the LDR semaphore we must           ;AA04564
        ; reverse what tkAllocPTDA has done.                         ;AA04564
                                                                     ;AA04564
tkeF:   CCALL32 _SEMTerminatePTDA <ep_pptda>                         ;AA04564
        CCALL32 _VMFreeTask <ep_pptda>                               ;AA04564
        jmp           tkeC                                           ;AA04564

EndProc tkExecPgm
SWAP32_15      ENDS
SWAP32_13 segment
;***    _tkDupProcData - Duplicate current directory and file handle data
;
;       Duplicate the parent process's current directory structures and
;       file handles for the child process.
;
;       ENTRY   pptda = pointer to the child's ptda
;       EXIT    (EAX) = error code

        ASSUME  DS:FLAT, ES:FLAT

Procedure _tkDupProcData,near
ArgVar  pptda,DWORD
        EnterProc
        SaveReg <ebx,esi,edi>

        CCALL32 tkInitSemPTDATbl <pptda>; Initialize system semaphore PTDA tbl

;       Bump ref. counts on current directories

        SaveReg <ds,es>
        mov     eax,pptda
        mov     ds,[eax].ThisPTDA       ; DS = Child PTDA selector
        mov     esi,TKOPTDA+CDS_Handle
        mov     ecx,NUMDRIVE

dpd1:   lodsw                           ; Get next handle
        or      ax,ax
        jz      short dpd2              ; Empty handle
        CALL16  DupCDS
        jnc     short dpd2              ; CDS dup'ed ok

        mov     WORD PTR [esi-2],0      ; invalid CDS handle, zero it out

dpd2:   loop    short dpd1              ; Dup next handle

;*  Copy JFN table to child process
;

        push    ds
        pop     es                      ; (ES) = new PTDA

        mov     edi,TKOPTDA+JFN_Table   ; (DI) = start of JFN table in PTDA
        mov     ecx,GSEL GDT_PTDA       ; BUGBUG  This is an incredibly
                                        ; gross hack; we need a separate
; NOTE: This code is in                 ; GDT selector for each PTDA in the
;       dos3task.asm, too!              ; system, but that change heavily
                                        ; impacts the scheduler and cannot
                                        ; be made now.
;*  Setup for DupJFN
;
;   (CX)    = selector of new PTDA (permanent)
;   (DS)    = new PTDA
;   (ES:DI) = addr of JFN table in the new PTDA

        CALL16  DupJFN                  ; Duplicate handle table to new PTDA
        sbb     ecx,ecx                 ; (ECX) = -1 if error else 0
        and     eax,ecx                 ; (AX) = error code or NO_ERROR
        movzx   eax,ax
        RestoreReg <es,ds>
        RestoreReg <edi,esi,ebx>
        LeaveProc
        RETC
EndProc _tkDupProcData
SWAP32_13 ENDS
SWAP32_15  segment

;***LP  tkgetnewenviron - create process's environment variable segment
;
;       tkgetnewenviron allocates and initializes the child process's
;       environment variable segment.  The command line arguments are also
;       added to the environment segment.
;
;       ENTRY   (BP) = base of ExecPgm stack frame variables
;                      ep_envstr, ep_pathname, ep_argstr are set up
;               (ESI) = Child's PTDA
;       EXIT    Carry flag clear - success
;                   ep_envhdl and ep_envsel is setup
;               Carry flag set - error
;                   (AX) = error code
;       USES    All except BP
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

SELFL   EQU     SELAL_SELMAP or D_PRES or D_DPL3 or D_DATA or D_W
VMFL    EQU     VMAC_ALIGNSEL or VMAC_ARENAPRV or VMAC_SELALLOC or \
                VMAC_OBAPI or PG_SWAPPABLE or PG_U or PG_R or PG_W

Procedure tkgetnewenviron,near,local
;       PMONLY


        mov     eax,_pPTDACur           ; Have eax point to Parent's
                                        ;  PTDA- must still be in
                                        ;  eax for load of environment
                                        ;  handle below

        movzx   edi,ep_envstr.Offst
        movzx   ebx,ep_envstr.Segmt
        test    ebx,RPL_CLR             ; check for null pointer
        jnz     short gne1

        movzx   esi,[eax].ptda_environ  ; (SI) = parents environ handle
        or      esi,esi
        jz      short gne2              ; no environment

        SSToDS  eax,ep_sel
        CCALL32 _SELGetSelector <esi,eax>
        xor     ebx,ebx                 ; Assume error
        or      eax,eax
        .errnz  NO_ERROR
        jnz     short gne0
        movzx   ebx,ep_sel              ; (EBX) = selector

gne0:   xor     edi,edi                 ; (EBX:EDI) = parents environment
        mov     ep_envstr.Offst,di
        mov     ep_envstr.Segmt,bx      ; Save environment string for later

gne1:   CALL16  FuStrLenZ               ; CX = FuStrLenZ(bx:di)
        jnc     short gne2              ; return an error
        mov     eax,ERROR_BAD_ENVIRONMENT
        jmp     gnex

gne2:   movzx   edx,cx                  ; (EDX) == length of environment
        les     di,ep_pathname          ; (ES:DI) = name (already verified)
        CALL16  StrLen                  ; (CX) = StrLen(ES:DI=path)
        xor     edi,edi
        mov     es,edi                  ; Clear user SEL out of ES
        movzx   ecx,cx

;       (ECX) = pathname size
;       (EDX) = environment length

        movzx   edi,ep_argstr.Offst     ; (EDI) = offset for arg string
        movzx   ebx,ep_argstr.Segmt     ; (EBX) = selector for arg string
        test    ebx,RPL_CLR             ; check for null pointer
        mov     eax,2                   ; null argument length
        jz      short gne3

        push    ecx
        push    edx
        CALL16  FuStrLenZ               ; CX = FuStrLenZ(bx:di)
        pop     edx
        movzx   eax,cx                  ; (EAX) = arguments
        pop     ecx
        jnc     short gne3              ; return an error
        mov     eax,ERROR_BAD_ARGUMENTS
        jmp     gnex

gne3:   mov     ebx,ecx                 ; pathname +
        add     ebx,edx                 ; environment +
        mov     ep_cmdoff,bx            ; save command line offset
        add     ebx,eax                 ; arguments

;       (EBX) = environment length
;       (EDX) = size of environment
;       (ECX) = size of pathname
;       (EAX) = size of arguments

        push    eax
        push    ecx
        push    edx

;       Set up the environment segment

        push    ds
        pop     es                      ; ES = FLAT
        SSToDS  eax,ep_ac
        PushP   eax                     ; pac
        PushP   0                       ; blkno
        PushP   SELFL                   ; SEL flags
        PushP   TKENVOWNER              ; hobmte
        mov     eax,_pPTDACur
        movzx   eax,[eax].ptda_child
        PushP   eax                     ; hobowner
        PushP   eax                     ; hobptda
        PushP   VMFL                    ; VM flags
        PushP   ebx                     ; cbcommit
        add     ebx,WORDMASK
        xor     bx,bx                   ; round to nearest 64K
        PushP   ebx                     ; cb
        CCALL32 _VMAllocMem,,,PushP
        or      eax,eax
        .errnz  NO_ERROR
        jz      short gne4
        add     esp,12                  ; clean off stack (eax,ecx,edx)
        mov     eax,ERROR_NOT_ENOUGH_MEMORY
        stc
        jmp     gnex

gne4:   movzx   esi,ep_ac.ac_hob
        mov     ep_envhdl,si
        mov     bx,ep_ac.ac_sel
        mov     ep_envsel,bx

        CCALL32 _SELMemMapAlias <esi>   ; Request addressability
        xchg    eax,ecx                 ; EAX = error code, ECX = selector
        cmp     eax,1
        .errnz  NO_ERROR
        cmc
        jnc     short gne4a                                             ;d024387
        add     esp,12                  ; clean off stack (eax,ecx,edx) ;d024387
        stc                                                             ;d024387
        jmp     short gnex                                              ;d024387
gne4a:  mov     es,cx                                                   ;d024387
        xor     di,di                   ; start at beginning of segment

        pop     ecx                     ; (ECX) = size of environment
        cmp     ecx,2                   ; is this a null environment?
        jnz     short gne5              ;  no, copy it
        xor     eax,eax
        stosw                           ; CX = 2, create null environment
        jmp     short gne6

gne5:   movzx   esi,ep_envstr.Offst     ; get offset
        movzx   ebx,ep_envstr.Segmt     ; get selector to environment
        push    es
        CALL16  FuBuff                  ; copy environment
        pop     es
        jnc     short gne6
        mov     eax,ERROR_BAD_ENVIRONMENT
        add     esp,8                   ; clear off stack (eax,ecx)
        stc
        jmp     short gne8

gne6:   pop     ecx                     ; (ECX) = size of pathname
        lds     si,ep_pathname          ; (DS:SI) = name (already verified)
        rep     movsb
        pop     ecx                     ; get pathname
        cmp     ecx,2                   ; is this a null pathname?
        jnz     short gne7              ;  no, copy it
        xor     eax,eax
        stosw                           ; CX = 2, create null argument
        jmp     short gne8

gne7:   movzx   esi,ep_argstr.Offst
        movzx   ebx,ep_argstr.Segmt     ; copy argument string to environment
        push    es
        CALL16  FuBuff
        pop     es
        jnc     short gne8
        mov     eax,ERROR_BAD_ENVIRONMENT

gne8:   pushf
        push    eax
        mov     eax,es
        FlatContext <ds,es>,edx
        CCALL32 _SELMemUnmapAlias <eax>
        pop     eax
        popf
gnex:   RETC

EndProc tkgetnewenviron

;find out what the above should be, since it is called by getnewenvironment
; I assumed it should be in the same swap segment
;***    _tkInheritLIBPATH - Duplicate parent's extended libpath to the child
;
;       Duplicate the parent process's extended libpath structures
;       handles for the child process.
;
;       ENTRY   parent_ptda = pointer to the parent's ptda
;               child_ptda = pointer to the child's ptda
;       EXIT    (EAX) = error code

        ASSUME  DS:FLAT, ES:FLAT

Procedure _tkInheritLIBPATH,near
ArgVar          parent_ptda,DWORD
ArgVar          child_ptda,DWORD
LocalVar        libpath,DWORD
        EnterProc
        SaveReg <edi,ecx,edx,eax,esi>

        xor     eax,eax                 ; Assume no error
        mov     edi,parent_ptda
        mov     edi,[edi].ptda_pBeginLIBPATH
                                        ; Store address of beginlibpath
                                        ;  in edi
        or      edi,edi
        jz      ilp001                  ; If it is null, go check endlibpath

        CALL16  StrLen32                ; StrLen computes the stringlength
                                        ; of the string at ES:EDI and returns
                                        ; the amount-including the null in ECX

        cmp     ecx,1
        jz      ilp001                  ; If the string is null, don't
                                        ; bother copying it.

        SSToDS  edx,libpath
        CCALL32 _VMAllocKHB <VM_HKH_PUB_RESRW, ecx, LDRMTEPATHOWNER, NA, edx>

        or      eax,eax                 ; test for success
        jnz     ilperr

        SaveReg <es,ds>
        mov     esi,edi                 ; move source address into si
        mov     edi,libpath             ; move destination into es:di

        CALL16  FStrCpy32               ; ds:esi=source es:edi=destination
        mov     esi,child_ptda
        mov     edi,libpath             ; refresh edi- FStrCpy32 modifies it
        mov     [esi].ptda_pBeginLIBPATH,edi
                                        ; move pointer to copied libpath
                                        ; into the child's ptda
        RestoreReg <ds,es>


ilp001: mov     edi,parent_ptda
        mov     edi,[edi].ptda_pEndLIBPATH
                                        ; Store address of endlibpath
                                        ;  in edi
        or      edi,edi
        jz      ilpdone                 ; If it is null, all done

        CALL16  StrLen32                ; StrLen computes the stringlength
                                        ; of the string at ES:EDI and returns
                                        ; the amount-including the null in ECX

        cmp     ecx,1
        jz      ilpdone                 ; If the string is null, don't
                                        ; bother copying it.

        SSToDS  edx,libpath
        CCALL32 _VMAllocKHB <VM_HKH_PUB_RESRW, ecx, LDRMTEPATHOWNER, NA, edx>

        or      eax,eax                 ; test for success
        jnz     ilperr

        SaveReg <es,ds>
        mov     esi,edi                 ; move source address into si
        mov     edi,libpath             ; move destination into es:di

        CALL16  FStrCpy32               ; ds:esi=source es:edi=destination
        mov     edi,libpath             ; refresh edi- FStrCpy32 modifies it
        mov     esi,child_ptda
        mov     [esi].ptda_pEndLIBPATH,edi  ;changed from begin to end- 95157
                                        ; move pointer to copied libpath
                                        ; into the child's ptda
        RestoreReg <ds,es>
ilperr: mov     eax, ERROR_BAD_ENVIRONMENT
                                        ; only failure is not being able
                                        ; to get memory for libpath


ilpdone:RestoreReg <esi,eax,edx,ecx,edi>

        LeaveProc
ilpex:  RETC
EndProc _tkInheritLIBPATH

SWAP32_15 ENDS

SWAP32_13 segment
;***LP  tkInitSemPTDATbl - Inherit open system semaphores
;
;       Initializes a new processes PTDA system semaphore table.  The
;       child process's PTDA system semaphore table is initialized to
;       all "INVALID_ENTRY".
;
;       ENTRY:  pptd    ChildPTDA pointer.
;
;       EXIT:   NONE
;
;       USES:   AX, CX, DI, Flags
;
;       InitSemPTDATbl()
;       {
;           for(each entry in SysSemPTDATbl) {
;               SysSemPTDATbl[index] = INVALID_ENTRY
;           }
;       }
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

Procedure tkInitSemPTDATbl,near,local
ArgVar  pptda,DWORD

        EnterProc
        TaskTime
        mov     edi,pptda
        add     edi,SysSemPTDATbl
        mov     eax,INVALID_ENTRY
        mov     ecx,SYSSEM_MAXIMUM/4            ; (CX) = # dwords (1/4 # entries)
IF      SYSSEM_MAXIMUM and 1
        stosb                                   ; in case entries is odd # bytes
ENDIF
IF      SYSSEM_MAXIMUM and 2
        stosw                                   ; in case entries is odd # words
ENDIF
        rep stosd
        .errnz  (size SysSemPTDAStruc) - (size OpenSemTable)
        LeaveProc
        RETC

EndProc   tkInitSemPTDATbl
SWAP32_13 ENDS

        FARCODE HIGH32
_TEXT   SEGMENT

;***EP  _TKTstnClrKernelSem - Release PTDA semaphore if owned
;
;       Releases the PTDA semaphore, if owned.
;
;       ENTRY   None
;       EXIT    ptda_ptdasem is released if owned
;
;       EFFECTS Calls _KSEMReleaseMutex, _KSEMQueryMutex

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING
Procedure _TKTstnClrKernelSem,<near,far32>
LocalVar cnest,WORD
        EnterProc
        mov     edx,[_pPTDACur]
        lea     edx,[edx].ptda_ptdasem
        SSToDS  eax,cnest
        push    edx
        CCALL32 _KSEMQueryMutex, <edx, eax>
        pop     edx
        or      eax,eax                 ; Owned ?
        jz      short tncs10            ; No, skip TKClearKernelSem
        cmp     cnest,0                 ; Free ?
        jz      short tncs10            ; Yes, skip TKClearKernelSem
        CCALL32 _KSEMReleaseMutex,<edx>
tncs10: LeaveProc
        RETC
EndProc _TKTstnClrKernelSem

_TEXT   ENDS
        END
