/*static char *SCCSID = "@(#)tkinit.c   6.4 92/02/21";*/
#define SCCSID  "@(#)tkinit.c   6.4 92/02/21"

/*
 *      Tasking - Initialization routines
 *
 *      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 */
/******************************************************************************
 * CHANGE ACTIVITY =
 *  DATE      FLAG        APAR    CHANGE DESCRIPTION
 *  --------  ----------  ------  --------------------------------------
 *  mm/dd/yy  @Vr.mpppxx  xxxxxx  xxxxxxx
 *  04/11/95  @V3.2SEN00  151783  Add int 10 support
 *  08/02/96              161596  Add lie list support to querysysinfo.
 ******************************************************************************/

#define INCL_TYPES
#define INCL_ERROR_H
#define INCL_ERROR2_H
#define FNO_NUM FNO_TKINIT_C

#include        <fnotask.h>
#include <basemac.h>
#include <basedef.h>
#include <osmac.h>
#include <ostypes.h>
#include <infoseg.h>
#include <osconst.h>
#include <bseerr.h>
#include <dossymc.h>
#include <seldesc.h>
#include <sigdef.h>
#include <except.h>
#include <mi.h>
#include <pgexport.h>
#include <protmode.h>
#include <vmexport.h>
#include <vmowner.h>
#include <tkexport.h>
#include <sched.h>
#include <proc.h>
#include <sem.h>
#include <screen.h>
#include <curdir.h>
#include <dirent.h>
#include <find.h>
#include <tkptda.h>
#include <ldrxport.h>
#include <selxport.h>
#include <kmode.h>
#include <bsetib.h>
#include <tklocal.h>
#include <tom.h>
#include <timapi.h>

// stolen from vmlocal.h
#define vmCeil(x,m) (((ulong_t)(x) + (m)) & ~(m))
#define vmPageCeil(x) vmCeil(x,PAGESIZE - 1)

/***LC  INDEX definitions for Dos32QuerySysInfo */

#define INDX_FIRST                      1
#define INDX_MAXPATHLENGTH              1
#define INDX_MAXTEXTSESSIONS            2
#define INDX_MAXPMSESSIONS              3
#define INDX_MAXVDMSESSIONS             4
#define INDX_BOOTDRIVE                  5
#define INDX_PRIORITY                   6
#define INDX_MAXWAIT                    7
#define INDX_MINSLICE                   8
#define INDX_MAXSLICE                   9
#define INDX_PAGESIZE                   10
#define INDX_MAJORVERSION               11
#define INDX_MINORVERSION               12
#define INDX_REVISION                   13
#define INDX_MSCOUNT                    14
#define INDX_TIMELO                     15
#define INDX_TIMEHI                     16
#define INDX_TOTPHYSMEM                 17
#define INDX_TOTRESMEM                  18
#define INDX_TOTAVAILMEM                19
#define INDX_MAXPRMEM                   20
#define INDX_MAXSHMEM                   21
#define INDX_TIMERINTERVAL              22
#define INDX_MAXCOMPLENGTH              23
#define INDX_CURSCRNGRP                 24      // 26215
#define INDX_FGNDPID                    25      // 26215
/* #define MAXSYSINDEX                     26      // 26215 */
#define INDX_INT10ENABLED               26   //@V3.2SEN00
#define MAXSYSINDEX                     27   //@V3.2SEN00

/***LD  aulSysInfo - System Information area */

ulong_t aulSysInfo[MAXSYSINDEX];

/***LD  extern declarations for QuerySysInfo */

extern  ulong_t pgPhysPages;
extern  ulong_t pgHighPages;
extern  ulong_t pgResidentPages;
extern  ushort_t FgndSGID;            //26215
/* extern  KSEMMTX HdErrSem;            69005 */

/***LD  extern declarations for SuppressPopUps */

extern  KSEMMTX PopUpSem;

/***LD  extern declarations for QuerySysState */

extern  KSEMMTX QsSem;

/***ED+ TK - Tasking global variables */

page_t                  pageTKTSDs;      /* First page of TSD region */
page_t                  pageTKTSDsEnd;   /* First page after TSD region */
PPTDA                   pPTDACur = NULL;
                                         /* Current PTDA pointer */
PTCB                    pTCBCur = NULL;  /* Current TCB pointer */
ulong_t                 pTKTSDs = 0;     /* Base of TSD array */
tsd_t                   *pTSDCur = NULL; /* Current TSD pointer */
char                    *TKSSBase = 0;   /* SS-to-flat TSD conversion */
ulong_t                 TKTCBBias = 0;   /* SS-to-flat TCB conversion */
int                     (*pfntkSuBuff)() = tkSuBuff386;
                                         /* Set User Buffer function pointer */
int     _stdcall        tkIsTCBInUse(tcb_t*ptcb);
/*end*/



/***LP  tkIsTCBInUse - return TRUE if a TCB is in use.
 *
 *      Note: tkIsTCBInUse must never be called with the SysInit's TCB.
 *      As tkIsTCBInUse is only called from BMP, this is not a problem.
 *
 *      ENTRY   ptcb    - address of TCB
 *
 *      EXIT    TRUE    - TCB is in use
 *              FALSE   - TCB is not in use
 *
 */

int     _stdcall        tkIsTCBInUse(tcb_t *ptcb)
  {
    return(ptcb->TCBpPTDA != NULL);
  }


/***LP  tkIsPTDAInUse - return TRUE if a PTDA is in use.
 *
 *      Note: tkIsPTDAInUse must never be called with a decommitted PTDA.
 *      As tkIsPTDAInUse is only called from BMP, this is not a problem.
 *
 *      ENTRY   pptda   - address of PTDA
 *
 *      EXIT    TRUE    - PTDA is in use
 *              FALSE   - PTDA is not in use
 *
 */

ulong_t tkIsPTDAInUse (pptda)
ptda_t  *pptda;
{
        return (pptda->pPTDASelf == pptda);
}

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

/***EP  VR32QuerySysInfo - Query System information (API entry)
 *
 *      This is the worker for the Dos32QuerySysInfo API
 *
 *      ENTRY
 *              sef     System Entry Frame
 *              indxStrt        Index for the first piece of info
 *              indxLast        Index for the last  piece of info
 *              pulBuf          pointer to the buffer to hold info
 *              cchBuf          size of buffer in bytes
 *
 *      RETURNS
 *              NO_ERROR        Sucess
 *              ERROR_INVALID_PARAMETER
 *              ERROR_BUFFER_OVERFLOW
 */

int cdecl VR32QuerySysInfo(sef, indxStrt, indxLast, pulBuf, cchBuf)
THUNKSEF        sef;                    /* System Entry Frame */
register int    indxStrt;               /* Index into array */
register int    indxLast;               /* Index into Sys Info */
ulong_t         *pulBuf;                /* Array of ulongs */
int             cchBuf;                 /* Size of Buffer in bytes */
{
  int     rc;
  ulong_t cpg;                    /* count of pages */
  unsigned newVersion;            /* the version to lie about    161596 */
  ulong_t oldMajorVer = 0;        /* saved base os major version 161596 */
  ulong_t oldMinorVer = 0;        /* saved base os minor version 161596 */
  
  if (indxStrt > indxLast || indxStrt-- < INDX_FIRST || indxLast > MAXSYSINDEX)
    return (ERROR_INVALID_PARAMETER);

  if (cchBuf < (indxLast - indxStrt)*sizeof(ulong_t))
    return (ERROR_BUFFER_OVERFLOW);

  aulSysInfo[INDX_TIMELO - 1] = SISData.SIS_BigTime;
  /* Update time in seconds */
  aulSysInfo[INDX_MSCOUNT - 1] = SISData.SIS_MsCount;
  /* Update millisecond counter */
  /* Update count of resident pages */
  aulSysInfo[INDX_TOTRESMEM - 1] = pgResidentPages << PAGESHIFT;
  
  aulSysInfo[INDX_CURSCRNGRP - 1] = FgndSGID;     // 26215
    /* Update Current screen group */
    
    
  aulSysInfo[INDX_FGNDPID - 1] = tkFgndPID;         // 26215
    /* Update the foregroung PID */
    
  if (indxStrt < INDX_TOTAVAILMEM && indxLast >= INDX_TOTAVAILMEM) {
    /* Update count of available pages */
    while((rc = PGAllocSizeQuery(SSToDS(&cpg))) == ERROR_INTERRUPT)
      ;
    tkAssert(rc == NO_ERROR);
    aulSysInfo[INDX_TOTAVAILMEM - 1] = cpg << PAGESHIFT;
  }
  
  if (indxStrt < INDX_MAXPRMEM && indxLast >= INDX_MAXPRMEM) {
    /* Update count of reservable linear
     * memory bytes in private arena.
     */
    VMQueryArenaAvailMem(VMAC_ARENAPRV,
			 &aulSysInfo[INDX_MAXPRMEM - 1]);
  }
  
  if (indxStrt < INDX_MAXSHMEM && indxLast >= INDX_MAXSHMEM) {
    /* Update count of reservable linear
     * memory bytes in shared arena.
     */
    VMQueryArenaAvailMem(VMAC_ARENASHR,
			 &aulSysInfo[INDX_MAXSHMEM - 1]);
    
  }
  
  
  /*
  **---------------------------------------------------------------
  ** Check to see if the user is requesting information about the
  ** major or minor version.  If they are then call the assembler
  ** routine to find out if the exe needs to be lied to.  Either
  ** way, copy the new version in the system data array and then
  ** let the buffer be copied.  Restore the old information for
  ** the next call.  Note: We modify the array instead of trying to
  ** copy the data into the users buffer.  OS2VER file is read
  ** at boot time.
  **---------------------------------------------------------------
  */
  
  if ((indxStrt < INDX_MAJORVERSION && indxLast >= INDX_MAJORVERSION) ||
      (indxStrt < INDX_MINORVERSION && indxLast >= INDX_MINORVERSION)) {
    
    
    /*
    **------------------------------------------------
    ** Get the version, maybe lied about if in OS2VER.
    **------------------------------------------------
    */
    
    newVersion = GetVersionInfo32 ();
    
    
    /*
    **------------------------------------------------
    ** Save off the old version information.
    **------------------------------------------------
    */
    
    oldMajorVer = aulSysInfo[INDX_MAJORVERSION - 1];
    oldMinorVer = aulSysInfo[INDX_MINORVERSION - 1];
    
    
    /*
    **------------------------------------------------
    ** Format the version data into 2 bytes (2).
    **------------------------------------------------
    */
    
    aulSysInfo[INDX_MAJORVERSION - 1] = (newVersion & 0xff00) >> 8;
    aulSysInfo[INDX_MINORVERSION - 1] = newVersion & 0x00ff;
    
  }
  
  rc = (TKSuBuff((uchar_t *) pulBuf,
		 (uchar_t *) &aulSysInfo[indxStrt],
		 (indxLast - indxStrt)*sizeof(ulong_t),
		 TK_UM_FATAL | TK_UM_USER));
  
  
  /*
  **------------------------------------------------
  ** Restore the old version information, if we used it.
  **------------------------------------------------
  */
  
  if (oldMajorVer || oldMinorVer) {
    
    aulSysInfo[INDX_MAJORVERSION - 1] = oldMajorVer;
    aulSysInfo[INDX_MINORVERSION - 1] = oldMinorVer;
    
  }
  
  return rc;

}



#pragma code_seg()

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


/***EP  TKPreInit - Perform System Initialization for Tasking (1st stage)
 *
 *      This routine remaps the TaskGroup limit to expand-down, and
 *      decommits the unused space in that area.
 *
 *      ENTRY   None
 *
 *      EXIT    A return to the caller means success.  Any error results
 *              in an Internal Error.
 *
 */

void TKPreInit(void)
{
        extern ulong_t CpuType;

//      Decide which SuBuff function to use.

        if (CpuType >= CPU_486)
            pfntkSuBuff = tkSuBuff486;  /* Hurrah!  Chip not brain-damaged! */

//      Remap TaskGroup limit to expand-down.

        SELSetDescInfo (SELSD_ALL, (D_PRES+D_DPL0+D_SEG+D_DATA+D_EXPDN+D_W) |
                        (D_UVIRT << 8), pPTDACur-> ThisPTDA,
                        (64*1024) - TKOTCB1, (ulong_t) pTCBCur, HOBNULL,
                        HOBNULL, 0);

//      Free the unused pages of TaskGroup.
//      Note that we MUST NOT decommit the space for the first TCB!

        VMSetMem ((ulong_t) pPTDACur-TKOPTDA,
                  ((TKOTCB1 >> PAGESHIFT) - 1) << PAGESHIFT, HOBNULL,
                  VMS_DECOMMIT, NA);
        KSEMInit((HKSEM)&pPTDACur->ptda_ptdasem, KRNL_MUTEXSEM, NA);
        KSEMInit((HKSEM)&pPTDACur->ptda_DLMsem, KRNL_MUTEXSEM, NA); // b732954 Edd
}


/***EP  TKSchedInit - Initialize Scheduling Data Structures
 *
 *      TKSchedInit places the Sysinit thread into the Scheduler
 *      data structures, and marks it RUNNING.  pPTDACur and
 *      pTCBCur must have already been initialized.
 *
 *      ENTRY   NONE
 *
 *      EXIT    NONE
 *
 */

void
TKSchedInit (void)
{
        pTCBCur-> TCBOrdinal = 1;
        pTCBCur-> TCBNumber = 1;
        pTCBCur-> TCBpTCBNext = NULL;
        pTCBCur-> TCBpPTDA = pPTDACur;
        pPTDACur-> ptda_cTCB = 1;
        pPTDACur-> ptda_Pid = 1;
        pPTDACur-> ptda_pTCBHead = pTCBCur;
        pPTDACur-> ptda_pTCBHole = pTCBCur;
        ctcbTKInUse = 1;
        papTCBSlots[1] = pTCBCur;
        TaskNumber = 1;
        pTCBCur-> TCBQState = STATE_VOID;
        pTCBCur-> TCBState = STATE_RUNNING;
        TKUpdateState(pTCBCur);
}


/***EP  TKInit - Perform System Initialization for Tasking (2nd stage)
 *
 *      TKInit allocates the TCB and PTDA BMP regions.  CreateThread
 *      may not be called until after TKInit is complete.
 *
 *      ENTRY   None
 *
 *      EXIT    A return to the caller means success.  Any error results
 *              in an Internal Error.
 *
 */

#define VMATSD          (VMAC_LOCANY | VMAC_ALIGNPAGE | VMAC_ARENASYS | \
                        PG_RESIDENT | PG_R | PG_W)
                                        /* TSD Allocation flags */

void TKInit(void)
{
        int rc;                         // Return code
        VMAC ac;                        // VMAllocMem return info buffer

        tkAssert(MaxThreads > 2);       // Must be allocating something

//      Allocate PTDA array

        if((rc = BMPInit(MaxThreads - 2, CBPTDA, PG_RESIDENT, TKPTDAOWNER,
            tkIsPTDAInUse,&paPTDA)) != NO_ERROR)
                Panic(("TKInit: BMPInit PTDA error %u",rc));

//      Allocate TCB array
//
//      Note that there is no TCB for slot 0 and slot 1's TCB is
//      SysInit's TCB which is not a part of this array.  Thus, we
//      allow TKCTCBMAX - 2 TCBs in the BMP pool.

        if((rc = BMPInit(MaxThreads - 2,sizeof(tcb_t),PG_RESIDENT,TKTCBOWNER,
           tkIsTCBInUse,&paTCB)) != NO_ERROR)  {
               Panic(("TKInit: BMPInit TCB error %u",rc));
        }
//      Allocate TSD array
//
//      Note that we need exactly one TSD for each TCB.

        if ( (PGGlobalFlags & PG_SYS_CONSTRAINED) && (MaxThreads <= 260)) {
            /*
             * perf enh - to keep swappable page tables together allocate
             *            the bmp package memory from the swappable heap this
             *            helps the AGER in aging pages
             */
            rc = VMAllocKHB( VM_HKH_PUB_SWAPRW,
                             vmPageCeil((MaxThreads - 2)*CPGTSD*PAGESIZE),
                             TKTSDOWNER,
                             VMAC_ALIGNPAGE,
                             SSToDS(&ac));
            tkAssert(rc == 0);

            rc = VMSetMem((ulong_t)ac.ac_va,
                          vmPageCeil((MaxThreads - 2)*CPGTSD*PAGESIZE),
                          HOBNULL,
                          VMS_DECOMMIT,
                          NA);
            tkAssert(rc == 0);
        } else {

            rc = VMAllocMem((MaxThreads - 2)*CPGTSD*PAGESIZE,0L,VMATSD,HOBNULL,
                TKTSDOWNER,HOBNULL,0L,0L,SSToDS(&ac));
            tkAssert(rc == 0);

        }

        pTKTSDs = ac.ac_va;
        pageTKTSDs = pTKTSDs >> PAGESHIFT;
                                        /* Starting page of region */
        pageTKTSDsEnd = pageTKTSDs + (MaxThreads - 2)*CPGTSD;
                                        /* End of region */
        tkInitSysInfo();

        if ((rc = TIMInit()) != NO_ERROR)
            Panic(("TKInit: TIMInit error %u",rc));

        if (SISData.SIS_Dynamic) {
            cmsecStarveLength = SISData.SIS_MaxWait * 1000;
        }
        tkMaxWait = SISData.SIS_MaxWait;
        tkTSDSwapRateMax = tkMaxSlice = SISData.SIS_MaxSlice;
        tkMinSlice = SISData.SIS_MinSlice;

        KSEMInit((HKSEM)&QsSem, KRNL_MUTEXSEM, NA);
   /*     KSEMInit((HKSEM)&HdErrSem, KRNL_MUTEXSEM, NA);   69005 */
        KSEMInit((HKSEM)&PopUpSem, KRNL_MUTEXSEM, NA);
}


/***LP  tkInitSysInfo - Initialize array of system info ints from GlobalInfoSeg
 *
 *      ENTRY   NONE
 *
 *      RETURNS NONE
 *
 */

void    tkInitSysInfo()
{
        register ulong_t *pul = aulSysInfo;

        pul[INDX_MAXPATHLENGTH  - 1] = MAXPATHLEN;
        pul[INDX_MAXTEXTSESSIONS- 1] = SISData.SIS_MaxVioWinSG;
        pul[INDX_MAXPMSESSIONS  - 1] = SISData.SIS_MaxPresMgrSG;
        pul[INDX_MAXVDMSESSIONS - 1] = MaxThreads;
        pul[INDX_BOOTDRIVE      - 1] = SISData.SIS_BootDrv;
        pul[INDX_PRIORITY       - 1] = SISData.SIS_Dynamic;
        pul[INDX_MAXWAIT        - 1] = SISData.SIS_MaxWait;
        pul[INDX_MINSLICE       - 1] = SISData.SIS_MinSlice;
        pul[INDX_MAXSLICE       - 1] = SISData.SIS_MaxSlice;
        pul[INDX_PAGESIZE       - 1] = PAGESIZE;
        pul[INDX_MAJORVERSION   - 1] = SISData.SIS_VerMajor;
        pul[INDX_MINORVERSION   - 1] = SISData.SIS_VerMinor;
        pul[INDX_REVISION       - 1] = SISData.SIS_RevLettr << 16;      //71936; the rev.level is in high word only
        pul[INDX_TIMEHI         - 1] = 0;
        pul[INDX_TOTPHYSMEM     - 1] = (pgPhysPages+pgHighPages) << PAGESHIFT;
        pul[INDX_MAXPRMEM       - 1] = 0;
        pul[INDX_MAXSHMEM       - 1] = 0;
        pul[INDX_TIMERINTERVAL  - 1] = SISData.SIS_ClkIntrvl;
        pul[INDX_MAXCOMPLENGTH  - 1] = MAXCOMPLEN;
        pul[INDX_CURSCRNGRP     - 1] = 0;                      //26215
        pul[INDX_FGNDPID        - 1] = 0;                      //26215
        pul[INDX_INT10ENABLED  - 1] = 1;        //@V3.2SEN00

}

#pragma code_seg()
