#define SCCSID "@(#)tkexec.c    6.11 92/03/14"
/*
 *
 *  Tasking - Task Creation Routines
 *
 *  IBM/Microsoft Confidential
 *
 *  Copyright (c) IBM Corporation 1987, 1989
 *  Copyright (c) Microsoft Corporation 1987, 1989
 *
 *  All Rights Reserved
 *
 *  09/18/91  Khoa Dang Huynh
 *      CP20 DCR 1486  Provide selector packing support.
 *  03/15/95 Chg.Team  Initialized new member on PTDA structure "pPvwDataBlk".
 *           101504    Made a call to pvwDestroyLink if pvwdatablk is not null when
 *                     the process ends. It will free pvw data allocated by the process.
 *  18-Nov-95    MLM   Defect 72417, reduce fscrit serialization.
 *  04/11/96  @V3.2SEN00   151783    Add int10 support
 */

#pragma code_seg("TKSWAP_TEXT", "CODE")

#define INCL_TYPES
#define INCL_ERROR_H
#define FNO_NUM FNO_TKEXEC_C

#include <basedef.h>
#include <fnotask.h>
#include <osconst.h>
#include <ostypes.h>
#include <osmac.h>
#include <mi.h>
#include <pgexport.h>
#include <vmexport.h>
#include <selxport.h>
#include <seldesc.h>
#include <tkexport.h>
#include <dossymc.h>
#include <sigdef.h>
#include <except.h>
#include <infoseg.h>
#include <proc.h>
#include <curdir.h>
#include <dirent.h>
#include <find.h>
#include <screen.h>
#include <sem.h>
#include <tkptda.h>
#include <ldrxport.h>
#include <tkthread.h>
#include <kmode.h>
#include <bsetib.h>
#include <tklocal.h>
#include <vmowner.h>
#include <sched.h>
#include <harderr.h>
#include <bseerr.h>
#include <string.h>
#include <semxport.h>
#include <pvwxport.h>                   /* 101504 */
#include <perfvw.h>                     /* 101504 */


extern CRI    criVSF;   /* V86 frame descriptor */
extern BYTE   mathcop;
extern ulong_t    CpuStepping;  /* CPU stepping */
extern long   FPEMHandler;                                          /*b726833*/

#pragma code_seg()
#pragma code_seg("SWAP32_15", "CODE")

/***LP  tkSetPIB - set the process' PIB
 *
 *  This function sets the fields in the PIB for the current process.
 *
 *  tkSetPIB ()
 *
 *  ENTRY NONE
 *  RETURN  NONE
 *
 *  CALLS TKSuBuff
 *
 *  WARNING NONE
 *
 *  EFFECTS The PIB is set.
 */

void      tkSetPIB()
  {
    pib_t   pib;    /* PIB */

    /*
     *  Turn off the force flag.
     */
    pPTDACur->ptda_ForcedActions &= ~TK_FF_PIB;

    /*
     *  Initialize PIB fields.
     */
    pib.pib_ulpid = (ulong_t) pPTDACur->ptda_Pid;
    pib.pib_ulppid = (ulong_t) pPTDACur->ptda_Ppid;
    pib.pib_hmte = (ulong_t) pPTDACur->ptda_module;
    pib.pib_pchenv = (char *) SelToLaTiled(pPTDACur->ptda_infoseg.LIS_AX);
    pib.pib_pchcmd = pib.pib_pchenv + pPTDACur->ptda_infoseg.LIS_BX;
    pib.pib_flstatus = (ulong_t) pPTDACur->ptda_ProcStatus;
    pib.pib_ultype = (ulong_t) pPTDACur->ptda_ProcType;

    /*
     *  Set up PIB in user space.
     */
    TKSuBuff((char *) tkGetPPIB(pPTDACur),SSToDS(&pib),
      sizeof(pib_t),TK_UM_FATAL); /* Initialize PIB in user space */
  }

/***LP  tkAllocPIB - allocate the PIB for the process
 *
 *  This function allocates the PIB for the process.
 *  Initialization is postponed until the first dispatch
 *  so that we can initialize it in the thread's own
 *  process context (this saves creating a temporary
 *  alias in the parent's context).
 *
 *  tkAllocPIB (pptda)
 *
 *  ENTRY pptda   - PTDA pointer
 *  RETURN  int   - return code (NO_ERROR if successful)
 *
 *  This function allocates the initial TIB pool and places the
 *  process' PIB at the beginning of the pool.
 *
 *  CALLS VMAllocMem
 *
 *  WARNING The TIB pool never shrinks.  This function must be
 *    called after VMInitTask.
 *
 *  EFFECTS A PIB is allocated at the beginning of the TIB pool.
 */

int     tkAllocPIB(pptda)
ptda_t      *pptda;   /* PTDA pointer */
  {
    int     i;    /* Return code, loop index */
    VMAC    ac;   /* VMAllocMem() return info buffer */

    tkAssert(CSEGTIB == TKCSEGTIB); /* So tib.h not needed for tkptda.h */
    tkAssert(CTIBSKIP < CTIBPERSEG);  /* PIB must fit in 64K */
    tkAssert(PAGESIZE >= CTIBSKIP*CBTIB);
          /* Must have enough room */
    if((i = VMAllocMem(CTIBPERSEG*CBTIB,/* Virtual size */
      PAGESIZE,       /* Committed size */
      VMATIB,       /* VM flags */
      pptda->ptda_handle,   /* Context */
      pptda->ptda_handle,   /* Owner */
      TKTIBOWNER,     /* MTE handle */
      0,        /* No Selector Manager flags */
      0,        /* No block number */
      SSToDS(&ac))) != NO_ERROR)  /* Pointer to return info buffer */
  return(i);      /* Return error if allocation fails */
    pptda->ptda_avatib[0] = ac.ac_va; /* Save address of pool */
    pptda->ptda_ctib = (ushort_t)(PAGESIZE / CBTIB);
          /* Set new count */
    for(i = TKCSEGTIB; i-- > 1; ) pptda->ptda_avatib[i] = -1;
          /* Initialize rest of TIB pool data */
    return(NO_ERROR);     /* Successful */
  }

#pragma code_seg()
#pragma code_seg("SWAP32_13", "CODE")
/***LP  tkAllocPTDA - allocate and initialize a PTDA
 *
 *  tkAllocPTDA allocates and initializes a new PTDA.  Much of the
 *  new PTDA is initialized by copying the values from the parent's
 *  PTDA.  In fact, we start out by completely copying the parent's
 *  PTDA then edit the fields we want to be different.
 *
 *  This procedure also initializes the memory arena for the
 *  new process.
 *
 *  tkAllocPTDA (ppptda, lat)
 *
 *  ENTRY ppptda    - place to return pointer to new PTDA
 *    lat   - arena type
 *            VMAT_PRIV_TILED
 *              Regular protect-mode 64K granular
 *              tiled arena
 *            VMAT_PRIV_VDM
 *              VDM 4K-granular arena
 *
 *  RETURN  int   - return code (NO_ERROR if successful)
 *
 *  CALLS VMCreatePseudoHandle, BMPGet, VMInitTask,
 *    VMFreePseudoHandle, BMPFree
 *
 *  WARNING
 *
 *  EFFECTS If successful, *ppptda points to the new PTDA.
 */

int     tkAllocPTDA(PPTDA *ppptda, ulong_t lat)
  {
    VMHOB   hobptda;  /* PTDA handle */
    register PPTDA  pptda;    /* PTDA pointer */
    int     rc;   /* Return code */
    int     rc2;    /* Return code */

    if((rc = BMPGet(paPTDA,ppptda)) == NO_ERROR)
      {         /* If allocation succeeds */
  pptda = *ppptda;    /* Point at new PTDA */
  pptda->pPTDASelf = pptda; /* Mark PTDA as allocated (for BMP) */

  if (NO_ERROR != (rc = SELAllocGDT(&(pptda->ThisPTDA)))) {
    BMPFree(paPTDA, pptda);
    return (rc);
  }

  SELSetDescInfo (SELSD_ALL,
      (D_PRES+D_DPL0+D_SEG+D_DATA+D_EXPDN+D_W) |
      (D_UVIRT << 8),
      pptda->ThisPTDA,
      CBPTDA,
      (ulong_t) pptda,
      HOBNULL,
      HOBNULL,
      0);

  if((rc = VMCreatePseudoHandle(pptda,TKPTDAOWNER,SSToDS(&hobptda))) ==
    NO_ERROR)     /* If pseudohandle created */
    {
      rc = pptda->ThisPTDA; // Save pptda->ThisPTDA around memcpy

      *(pptda) = *(pPTDACur); // Copy parent's PTDA

      // NOTE: All data that was stored in new PTDA is now gone !!!

      pptda->ThisPTDA = (ushort_t) rc;  // Restore pptda->ThisPTDA
      pptda->pPTDASelf = pptda; /* Point PTDA to itself */
      pptda->ptda_handle = hobptda;
          /* Set its handle */

      pptda->ptda_timerhead = NULL;
          /* New process has no timers */

      if((rc = SEMInitPTDA(pptda)) == NO_ERROR)
        {       /* If 32-bit semaphores initialized */
    if((rc = VMInitTask(pptda, lat)) == NO_ERROR)
      {     /* If memory arena initialized */
        pptda->Csid = pptda->ptda_Pid = tkNewPid();
          /* Allocate a new process i.d. */
        pptda->ptda_Ppid = pPTDACur->ptda_Pid;
          /* Set parent's process i.d. */
        pptda->ptda_cTCB = 0;
          /* No threads yet */
        pptda->ptda_pTCBHole = NULL;
          /* No thread one yet */
        pptda->ptda_pTCBHead = NULL;
          /* TCB list is empty */
        /*
         *  Reset fields not inherited from parent.
         */

        pptda->seltss = TKGetProtTSS();
        pptda->pPTDAFirstChild = NULL;
          /* Initialize process links */
        pptda->pPTDANextSibling = NULL;
        pptda->pPTDAPrevSibling = NULL;
        pptda->pPTDAParent = NULL;
#ifdef PROFILE
        pptda->sPCB = 0;  /* No Profile Control Block */
#endif

        // Thread Local Memory is not inherited.
        // Setup the TLMA allocation maps such that the first dword
        // is reserved for PM/Kernel communication.

        pptda->ptda_TLMA = 1;
        memset(pptda->ptda_TLMABM, 0, TLMA_MAX_BME);
        memset(pptda->ptda_TLMASizeMap, 0, TLMA_MAX_VARS);
        pptda->ptda_TLMABM[0] = 0x80;
        pptda->ptda_TLMASizeMap[0] = 1;

        pptda->ptda_pPCB = 0;
          /* No Profile Control Block */
        pptda->ptda_infoseg.LIS_Fgnd = 0;
          /* Initialize Infoseg field */
        pptda->SrchRmp = 0; /* Zero out search RMP handle */
        pptda->FNotifyLocal_Count = 0;
          /* Zero local FindNotify Local Count */
        pptda->KBD_Mode = 0;/* KBD mode not set by any thread */
        pptda->ptda_child = 0;
          /* No child process allocated */
        pptda->pPTDAExecChild = NULL;
        pptda->ptda_childalias = 0;
        pptda->ptda_pexllist = NULL;
          /* No exitlist yet */
        pptda->ptda_pldrdldHead = NULL;
          /* No demand loads yet */
        pptda->ptda_module = 0;
          /* No program module allocated */

#if RAS
        pptda->ptda_rasflag = 0;
          /* RAS flag not inherited */
#endif /* RAS */

        pptda->CurrentPDB = 0;
          /* No PDB */
        pptda->ptda_ProcStatus = PS_EMBRYO;
          /* Don't inherit parent's status */
#if PT_FULLSCRN != 0
#error  PT_FULLSCRN != 0
#endif
        pptda->ptda_cCritSec = 0;
          /* Don't inherit this stuff */
        pptda->ptda_pTCBCritSec = NULL;
        pptda->ptda_pTCBPriQCritSec = NULL;
        pptda->Fgnd = 0;
        pptda->FgndOnly = 0;
        pptda->ptda_NewFiles = 0;
        KSEMInit((HKSEM)&pptda->ptda_ptdasem, KRNL_MUTEXSEM, NA);
        KSEMInit((HKSEM)&pptda->ptda_DLMsem, KRNL_MUTEXSEM, NA); // b732954 Edd
        pptda->ptda_cdllterm = 0;
          /* No DLL terminations yet */
        pptda->Sig_hndf = 0;/* No signal handlers */
        pptda->Sig_ignf = 0;/* No ignored signals */
        pptda->Sig_errf = 0;/* No error-causing signals */
        pptda->HoldSigCnt = 0;
          /* Signals are not being postponed */
        pptda->Sig_attempted = 0;
          /* No EH's passed signals */
#ifdef SECURITY                                                          //@SEC
        pptda->SigFTerm = 0;                                             //@SEC
#endif                                                                   //@SEC
        pptda->SigFocusCnt = 0;
          /* No exception focus specified */
        pptda->SavedHardErr = NULL;
          /* No saved hard errors yet */
        memset(pptda->Sig_vec,'\0',NSIG*sizeof(long));
          /* No signal handlers */
        memset(pptda->Exc_vec,'\0',EXCUSR*sizeof(long));
          /* No signal handlers */
        pptda->Cons_Loc.Cons_Mode &= ~(CL_RAW2 | CL_RAW3);
          /* Reset console locus info */
        pptda->Cons_Loc.Prev_Loc = 0;
        if(!(pptda->AutoFail & DOSERR_INHERIT)) pptda->AutoFail = 0;
          /* Turn off hard error auto fail */

/*      pptda->ptda_pOpenBuf = 0;            Defect 72417, moved to TCB */
          /* Reset pointer to FS temp buffer  */
        pptda->ptda_pCDS = 0;
          /* Reset pointer to CDS buffer  */
        pptda->MSW = CR0_PE | CR0_EM;
          /* assume NPX not pres */
        if(mathcop) pptda->MSW = CR0_PE | CR0_MP;
          /* NPX is present */
        pptda->ptda_NPX_em_cs = R2CS;                               /*b726833*/
        pptda->ptda_NPX_em_eip= FPEMHandler;                        /*b726833*/
        pptda->ptda_pSGSList = NULL;
          /* Initialize SGS list to 0 */

#if RAS
        pptda->ptda_pdcb = NULL;
#endif /* RAS */

          /* Clear debug fields */
#ifdef INCDEBUG
        pptda->ptda_flDbg = 0;
#endif /* DEBUG */

        pptda->ProcFlag = 0;   /* initialize process flag b721159 */
        pptda->ptda_ForcedActions = 0;
          /* No forced actions yet */
#ifdef MEMSTAT
        pptda->ptda_pmemstatcur = &(pptda->ptda_memstat);
          /* memory manager per-process stats */
#endif
#ifdef PERFVIEW
        pptda->ptda_pPVDBPrc = NULL;
        pptda->pPvwDataBlk = NULL;           //101504
          /* Perfview data block ptr */
#endif
        pptda->ptda_infoseg.LIS_PackSel = 0;
        pptda->ptda_infoseg.LIS_PackShrSel = SelShrPackedStart;

          /* Feature 75220: initialized beginning/end per process */
          /*                libpath to none                       */
        pptda->ptda_pBeginLIBPATH = NULL;
        pptda->ptda_pEndLIBPATH = NULL;
        return(NO_ERROR); /* Success */
      }
    SEMTerminatePTDA(pptda);/* Clean up the semaphore stuff */
        }
      VMFreePseudoHandle(hobptda);/* Free the pseudohandle */
    }
  rc2 = SELFreeGDT(pptda->ThisPTDA);
          /* Free the PTDA selector */
  tkAssert (rc2 == NO_ERROR);

  pptda->pPTDASelf = NULL;  /* Mark PTDA as free (for BMP) */
  BMPFree(paPTDA,pptda);    /* Free the PTDA */
      }
    return(rc);       /* Return error code */
  }
#pragma code_seg()
#pragma code_seg("SWAP32_27", "CODE")


/***LP  tkEvapPTDA - free the given PTDA
 *
 *  This procedure is called to free the specified PTDA.
 *
 *  tkEvapPTDA (pptda)
 *
 *  ENTRY pptda   - pointer to PTDA to free
 *  RETURN  NONE
 *
 *  CALLS BMPFree, VMFreePseudoHandle
 *
 *  WARNING NONE
 *
 *  EFFECTS Returns the given PTDA to the pool of free PTDAs.
 */

void  tkEvapPTDA(pptda)
PPTDA pptda;        /* PTDA pointer */
  {
    ulong_t rc;

  // 101504 start
#ifdef PERFVIEW
    if (pptda->pPvwDataBlk != NULL)
     {
       PVWDestroyLink(pptda);
     }
#endif
  // 101504 ends

    /* Feature 75220 */
    if (pptda->ptda_pBeginLIBPATH)
    {
      VMFreeKHB(VM_HKH_PUB_RESRW,pptda->ptda_pBeginLIBPATH);
    }

    if (pptda->ptda_pEndLIBPATH)
    {
      VMFreeKHB(VM_HKH_PUB_RESRW,pptda->ptda_pEndLIBPATH);
    } /* endif */

    rc = SELFreeGDT (pptda->ThisPTDA);  /* Free the PTDA selector */
    tkAssert (rc == NO_ERROR);
    VMFreePseudoHandle(pptda->ptda_handle);
          /* Free the pseudohandle */
    pptda->pPTDASelf = NULL;    /* Mark PTDA as FREE */
    BMPFree(paPTDA,pptda);    /* Free the PTDA */
  }

#pragma code_seg()
#pragma code_seg("SWAP32_23", "CODE")
extern ULONG iINT10Creation;  //@V3.2SEN00
/***EP  TKCreateVDMProcess - create a process for a new VDM
 *
 *  Do fundamental process creation work for a VDM.
 *
 *  TKCreateVDMProcess (pfnStart, ussgid, prc)
 *
 *  ENTRY pfnStart  - initial start address
 *    ussgid    - screen group i.d. for new process
 *    prc   - pointer to result code structure
 *  RETURN  int   - return code (NO_ERROR if successful)
 */

#define CBSTACKLINK ((ulong_t)((char *)&((tsd_t *) 0)->TSDPMStack - \
        (char *)(((tsd_t *) 0)->TSDUserStack + TSDStackSize)))

int     TKCreateVDMProcess(pfnStart,ussgid,prc)
void      (*pfnStart)(void);/* Start address */
ushort_t    ussgid;   /* Screen group i.d. */
RESULTCODES   *prc;   /* Pointer to result code buffer */
  {
    char    *pframebase;  /* Base of kernel stack frame */
    ptda_t    *pptda;   /* PTDA pointer */
    tcb_t   *ptcb;    /* TCB pointer */
    tsd_t   *ptsd;    /* TSD pointer */
    int     rc;   /* Return code */
    tkthrd_t    ti;   /* Thread information block */

    if((rc = tkAllocPTDA(SSToDS(&pptda), VMAT_PRIV_VDM)) == NO_ERROR)
      {         /* If PTDA allocated */
  tkAssert(rc == NO_ERROR); /* Make sure we succeeded */
  /* Fill in some local info seg fields */
  pptda->ptda_infoseg.LIS_CurScrnGrp = ussgid;
  pptda->Cons_Loc.Scrn_Num = (uchar_t) ussgid;


// BUG-BUG
//  Machines without coprocessors will hang if a DOS app issues
//  a NPX instruction.  Without the following line remarked out,
//  the entire machine goes down.  Jeff Muir 10/24/91
//  Needed to put it back since DOS apps can issue FINIT without
//  trapping entire system... we have to further research how
//  to fix NPX VDM emulation       Jeff Muir 10/30/91
//  I'm back one last time to allow the EM bit to be set
//  for VDMs.  We changed VNPX to properly handle this condition. Jeff 03/11/92

//  pptda->MSW &= ~CR0_EM;    /* Clear the EM bit for VDMs */

  /* Create a thread for the process */
  ti.ti_fs = TKCT_INTERNAL | TKCT_SWAPTSD;
          /* Pretend it's an internal thread */
  ti_cbbuf(ti) = KMQueryStackFrameSize(&criVSF);
          /* Get space to leave on frame */
  tkAssert(ti_cbbuf(ti) >= CBSTACKLINK);
          /* Must have enough room */
  ti_cbbuf(ti) -= CBSTACKLINK;  /* Allow for TCBUserSS, TCBUserESP */
  ti_pbuf(ti) = NULL;   /* Don't actually copy anything */
  ti.ti_ustart.ptr_flat = (ulong_t) pfnStart;
          /* Set starting address */
  if((rc = TKCreateThread(pptda,SSToDS(&ti),SSToDS(&ptcb),STATE_VOID)) ==
    NO_ERROR)     /* If thread created okay */
    {
      ptsd = ptcb->TCBpTSD; /* Get TSD pointer */
      pframebase = (char *) &ptsd->TSDPMStack -
        KMQueryStackFrameSize(&criVSF);
          /* Compute frame base */
      ptcb->TCB_pFrameBase = pframebase;
          /* Set frame base */
      ptcb->TCB_pcriFrameType = &criVSF;
          /* V86 stack frame */
      tkDupProcData(pptda); /* Dup parent's file handles */

                            /* D110795 (detached test not necessary) */
      TKLinkTask(pptda);    /* D110795 Link child into process tree */

      if (iINT10Creation)                                         //@V3.2SEN00
      {                                                           //@V3.2SEN00
        tkStartProcess(pptda,4,3,prc);      //detach the process. //@V3.2SEN00
        iINT10Creation = 0;                                       //@V3.2SEN00
      }                                                           //@V3.2SEN00
      else                                                        //@V3.2SEN00
         tkStartProcess(pptda,4,0,prc);
          /* Start the new process */
      return(NO_ERROR);   /* Success */
    }
  tkEvapPTDA(pptda);    /* Evaporate the PTDA */
      }
    return(rc);       /* Return error code */
  }

#pragma code_seg()
#pragma code_seg("TKSWAP_TEXT", "CODE")
/***EP  TKCreateVDMThread - create a thread for an existing VDM
 *
 *  Add a thread to associate work with a VDM.
 *
 *  TKCreateVDMThread (pfnStart)
 *
 *  ENTRY   pfnStart  - initial start address
 *  RETURN  int       - return code (NO_ERROR if successful)
 */

int     TKCreateVDMThread(ptid,pfnStart)
  unsigned long *ptid;        /* pointer to thread id */
  void      (*pfnStart)(void);/* Start address */
  {
    tcb_t   *ptcb;    /* TCB pointer */
    tsd_t   *ptsd;    /* TSD pointer */
    int     rc;   /* Return code */
    tkthrd_t    ti;   /* Thread information block */

  /* Create a thread for the process */
  ti.ti_fs = TKCT_INTERNAL | TKCT_SWAPTSD;       /* Pretend it's an internal thread */
  ti_cbbuf(ti) = KMQueryStackFrameSize(&criVSF); /* Get space to leave on frame */
  tkAssert(ti_cbbuf(ti) >= CBSTACKLINK);         /* Must have enough room */
  ti_cbbuf(ti) -= CBSTACKLINK;                   /* Allow for TCBUserSS, TCBUserESP */
  ti_pbuf(ti) = NULL;                            /* Don't actually copy anything */
  ti.ti_ustart.ptr_flat = (ulong_t) pfnStart;    /* Set starting address */

  if((rc = TKCreateThread(pPTDACur,SSToDS(&ti),SSToDS(&ptcb),STATE_READY)) ==
    NO_ERROR)     /* If thread created okay */
    {
      ptsd = ptcb->TCBpTSD; /* Get TSD pointer */

      /* Compute frame base */
      ptcb->TCB_pFrameBase = (char *) &ptsd->TSDPMStack -
                                      KMQueryStackFrameSize(&criVSF);
      ptcb->TCB_pcriFrameType = &criVSF; /* V86 stack frame */
   /*#68035   tkDupProcData(pPTDACur); */          /* Dup parent's file handles */
      *ptid = (unsigned long) ptcb->TCBOrdinal;  /* Thread ID */
      rc=NO_ERROR;   /* Success */
    }
  return(rc);       /* Return error code */
  }
