/*static char *SCCSID = "@(#)ldrinit.c  6.13 92/02/22";*/
#define SCCSID  "@(#)ldrinit.c  6.13 92/02/22"

/***    OS/2 Loader initializtion
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 *
 *      The initialize routines for the Loader.
 */

#define INCL_ERROR_H
#include <bseerr.h>

#include <osconst.h>
#include <ostypes.h>
#define FNO_NUM         FNO_LDRINIT_C
#include <fnomem.h>
#include <osmac.h>
#define INCL_OS2STD
#include <os2def.h>
#include <mi.h>
#include <dossymc.h>
#include <sigdef.h>
#include <except.h>
#include <pgexport.h>
#include <vmexport.h>
#include <vmowner.h>
#include <tkexport.h>
#include <infoseg.h>
#include <curdir.h>
#include <dirent.h>
#include <find.h>
#include <screen.h>
#include <sem.h>
#include <tkptda.h>
#include <ldrxport.h>
#include <setjmp.h>
#include <selxport.h>
#include <seldesc.h>
#include <ioexp.h>
#include <ordinals.h>
#include <sysentry.h>

#define FOR_EXEHDR      1
#include <newexe.h>
#include <exe386.h>
#include <ldrvars.h>


/* Validate QAppType values */

#if     QAT_PMAPI != NEWINAPI
#error  QAT_PMAPI != NEWINAPI
#endif

#if     QAT_BOUNDEXE != NEBOUND
#error  QAT_BOUNDEXE != NEBOUND
#endif

#if     QAT_EXETYPE != NEAPPTYP
#error  QAT_EXETYPE != NEAPPTYP
#endif

#if     QAT_NOPMW != NENOTWINCOMPAT
#error  QAT_NOPMW != NENOTWINCOMPAT
#endif

#if     QAT_PMW !=NEWINCOMPAT
#error  QAT_PMW !=NEWINCOMPAT
#endif

// Structure for the LDRQAppType cache - see LDRMTE.C
struct
{
    unsigned long QATTimeStamp;
    unsigned long QATHashName;
    unsigned long QATFlags;
} ldrQATCache;

// Moved to sdata.asm for System Anchor Block - f122427
extern KSEMMTX         LdrSem;                 /* allocate loader semaphore */
extern ushort_t        DosModHdl;              /* DOSCALLS pseudo handle */
extern struct nonres_s *pNonResNamTbl;         /* pointer to Non-resdient name table */
extern int             cNonResNamTbl;          /* count of non-resident name entries */
extern ldrmte_t        *program_h;             /* head of list of program modules */
extern ldrmte_t        *program_l;             /* tail of list of program modules */
extern ldrmte_t        *global_l;              /* tail of list of global modules */
extern ldrmte_t        *specific_h;            /* head of list of specific modules */
extern ldrmte_t        *specific_l;            /* tail of list of specific modules */
extern int             swapping;               /* flag for swapping or not */

uchar_t *ldrpFileNameBuf;      // 16:16 and 0:32 pointers to the loader file
ulong_t  ldr16pFileNameBuf;    // name buffer. Both point to the same storage,
                               // which is accessed from both flat and
                               // segmented code.

char            *pheaderbuf;            /* pointer to buffer to read header */

HKSEM           hNonResNamTbl;          /* sem. for non-resident name table  */

ldrmte_t        *mte_h;                 /* head of linked mte list */

ldrmte_t        *global_h = NULL;       /* head of list of global modules */

unsigned char   do_gcollect = FALSE;    /* flag for garbage collection req */

uchar_t         *LDRLibPath;            /* pointer to libpath */

ulong_t         LDRLibPathLen;          /* length of libpath */

uchar_t         *LDRLieList = NULL;     /* pointer to lie list */

// Not needed - so, not implemented.
// ulong_t         LDRLieListLen;          /* length of lie list */

/*
 * Setup low level loader read pointers
 */
unsigned        (*_stdcall pldrOpen) (vaddr_t fname, unsigned mode,
                                      unsigned flags, SFN_t *pSFN,
                                      ulong_t TransPathBuf) = IOSftOpen;

unsigned        (*_stdcall pldrReadAt) (SFN_t sfn, xfercnt_t *pcb,
                                vaddr_t addr, ulong_t uOffset) = IOSftReadAt;

unsigned        (*_stdcall pldrClose) (SFN_t sfn) = IOSftClose;

unsigned        (*_stdcall pIOSftTransPath) (vaddr_t fname) = IOSftTransPath;

unsigned        (*pldrGetMedia) (void) = ldrGetMedia;

#ifdef PMDEBUG
void            (*pDebugLoadSymDosFS) (void);

void            (*pDebugLoadSymModule) (void);
#endif

UCHAR           ldrMiniFileIOFlag = FALSE;

/*
 * this table is used to expand a 16-bit mte header to a 32-bit mte header
 */
  ushort_t mptbl[] = {
    SKIPCOPY,                                   /* 40->--  reserved */
    FIELDOFFSET(struct e32_exe, e32_res3),      /* 3E->AC  ne_expver */
    SKIPCOPY,                                   /* 3C->--  reserved */
    SKIPCOPY,                                   /* 3A->--  reserved */
    SKIPCOPY,                                   /* 38->--  reserved */
    FIELDOFFSET(struct e32_exe, e32_res3)+2,    /* 36->AE  ne_exetype, ne_flagsothers */
    FIELDOFFSET(struct e32_exe, e32_rsrccnt),   /* 34->54  e32_resrctbl_cnt */
    FIELDOFFSET(struct e32_exe, e32_res3)+4,    /* 32->B0  e32_alignshft */
    SKIPCOPY,                                   /* 30->--  e32_movent_cnt */
    FIELDOFFSET(struct e32_exe, e32_nrestab)+2, /* 2E->8A  e32_nonresnam_off+2 */
    FIELDOFFSET(struct e32_exe, e32_nrestab),   /* 2C->88  e32_nonresnam_off */
    FIELDOFFSET(struct e32_exe, e32_impproc),   /* 2A->78  e32_importnam_off */
    FIELDOFFSET(struct e32_exe, e32_impmod),    /* 28->70  e32_modref_off */
    FIELDOFFSET(struct e32_exe, e32_restab),    /* 26->58  e32_resnamtbl_off */
    FIELDOFFSET(struct e32_exe, e32_rsrctab),   /* 24->50  e32_resrctbl_off */
    FIELDOFFSET(struct e32_exe, e32_objtab),    /* 22->40  e32_segtbl_off */
    FIELDOFFSET(struct e32_exe, e32_cbnrestab), /* 20->8C  e32_nonresnam_len */
    FIELDOFFSET(struct e32_exe, e32_impmodcnt), /* 1E->74  e32_modref_cnt */
    FIELDOFFSET(struct e32_exe, e32_objcnt),    /* 1C->44  e32_segtbl_cnt */
    FIELDOFFSET(struct e32_exe, e32_stackobj),  /* 18->20  e32_stack_ss */
    FIELDOFFSET(struct e32_exe, e32_esp),       /* 18->24  e32_stack_sp */
    FIELDOFFSET(struct e32_exe, e32_startobj),  /* 16->18  e32_startproc_cs */
    FIELDOFFSET(struct e32_exe, e32_eip),       /* 14->1C  e32_startproc_ip */
    FIELDOFFSET(struct e32_exe, e32_res3)+6,    /* 12->B2  e32_stacksiz */
    FIELDOFFSET(struct e32_exe, e32_heapsize),  /* 10->A8  e32_heapsiz */
    FIELDOFFSET(struct e32_exe, e32_autodata),  /* 0E->94  e32_autods */
    FIELDOFFSET(struct e32_exe, e32_mflags),    /* 0C->10  e32_flags */
    SKIPCOPY,                                   /* 0A  --  e32_crc+2 */
    SKIPCOPY,                                   /* 08  --  e32_crc */
    FIELDOFFSET(struct e32_exe, e32_ldrsize),   /* 06->38  e32_entrytbl_len */
    FIELDOFFSET(struct e32_exe, e32_enttab),    /* 04->5C  e32_entrytbl_off */
    SKIPCOPY,                                   /* 02  --  e32_version, e32_revision */
    (ushort_t) FIELDOFFSET(struct e32_exe, e32_magic[0]),/* 00->00  e32_signature */
    ENDMTETBL,                                  /* MUST BE AT END OF TABLE */
  };


  /*
   * this table is used to validate and update pointer in the MTE in
   * mtevalidateptrs
   */
  ushort_t validatetbl[] =
  {
    FIELDOFFSET(ldrsmte_t, smte_objmap),  /* object page map */
    FIELDOFFSET(ldrsmte_t, smte_rsrctab), /* resource table */
    FIELDOFFSET(ldrsmte_t, smte_restab),  /* resident name table */
    FIELDOFFSET(ldrsmte_t, smte_enttab),  /* entry table */
    FIELDOFFSET(ldrsmte_t, smte_fpagetab),/* fixup page table */
    FIELDOFFSET(ldrsmte_t, smte_frectab), /* fixup record table */
    FIELDOFFSET(ldrsmte_t, smte_impmod),  /* import module name table */
    FIELDOFFSET(ldrsmte_t, smte_impproc), /* import procedure name table */
    ENDMTETBL,                            /* MUST BE AT END OF TABLE */
  };


/*
 * This table is used to copy header info for the API DosQueryHeaderInfo
 * function HEADER_EXEINFO, see VR32QueryHeaderInfo.
 */
struct hit_s HeaderInfoTbl[] =
{
    {
0,//FIELDOFFSET(ldrsmte_t, smte_NEflags),    /* Original flags from NE header */
2,//sizeof(((ldrsmte_t *) 0)->smte_NEflags), /* number of bytes to copy */
    },
    {
0,//FIELDOFFSET(ldrsmte_t, smte_NEflagsothers),   /* fixup page table */
2,//sizeof(((ldrsmte_t *) 0)->smte_NEflagsothers),/* number of bytes to copy */
    },
    {
    FIELDOFFSET(ldrsmte_t, smte_NEexetype),   /* exetyp from NE header */
    sizeof(((ldrsmte_t *) 0)->smte_NEexetype),/* number of bytes to copy */
    },
    {
    FIELDOFFSET(ldrsmte_t, smte_NEexpver),   /* expver from NE header */
    sizeof(((ldrsmte_t *) 0)->smte_NEexpver),/* number of bytes to copy */
    },
    {
    0,                                  /* special case for size of rsrc table */
    2,                                  /* copy 2 bytes */
    },
    {
    ENDMTETBL,                          /* MUST BE AT END OF TABLE */
    0,                                  /* copy 0 bytes */
    }
  };


/*
 * This table is used to copy header info for the API DosQueryHeaderInfo
 * function HEADER_STE, see VR32QueryHeaderInfo.
 */
struct his_s HeaderInfoSTE[] = {
    {
    FIELDOFFSET(ldrste_t, ste_offset),  /* file offset to segment data */
    2,                                  /* copy 2 bytes */
    },
    {
    FIELDOFFSET(ldrste_t, ste_size),    /* file data size */
    2,                                  /* copy 2 byte */
    },
    {
    FIELDOFFSET(ldrste_t, ste_flags),   /* type and attribute flags */
    2,                                  /* copy 2 byte - bugbug - flags long */
    },
    {
    FIELDOFFSET(ldrste_t, ste_minsiz),  /* minimum allocation size */
    2,                                  /* copy 2 bytes */
    },
    {
    ENDMTETBL,                          /* MUST BE AT END OF TABLE */
    0,                                  /* copy 0 bytes */
    }
  };

/*
 * This structure is used to convert from Object type flags to the
 * required VM flags needed for allocation of memory.  See setVMflags()
 * for use.
 */

struct objflags_s       objflags[] =
  {
    {
      OBJREAD,                          /* Readable Object */
      PG_R,                             /* Allocate as Readable */
      },
    {
      OBJWRITE,                         /* Writeable Object */
      PG_W,                             /* Allocate as Writeable */
      },
    {
      OBJEXEC,                          /* Executable Object */
      PG_X | VMAC_SHARED,        /* Allocate as eXecutable and shared */
      },
    {
      OBJSHARED,                        /* Object is shared */
      VMAC_SHARED,                       /* physical contents shared */
      },
    {
      OBJALIAS16,                       /* 16:16 alias is required */
      VMAC_SELALLOC,
      },
    {
      OBJCONFORM,                       /* Object is conforming */
      PG_U,
      },
    {
      0,                                /* must have end of table entry */
      0,
      }
  };

/*
 * This structure is used to convert from Object type flags to the
 * required SEL flags needed for allocation of memory.  See setVMflags()
 * for use.
 */

struct selflags_s       selflags[] =
  {
    {
      OBJREAD,                          /* Readable Object */
      SELAL_R,                          /* Allocate as Readable */
      },
    {
      OBJWRITE,                         /* Writeable Object */
      SELAL_W,                          /* Allocate as Writeable */
      },
    {
      OBJEXEC,                          /* Executable Object */
      SELAL_CODE|SELAL_R,               /* Alloc as eXecutable and readable */
      },
    {
      OBJCONFORM,                       /* Objects is conforming */
      SELAL_CONFORM,
      },
    {
      0,                                /* must have end of table entry */
      0,
      }
  };

/*
 * This structure is used to set the VMAlloc flags for the initial memory
 * allocation of objects. The complete table can be found in LDRSTE.C
 * module ldrAllocObjects().
 */

struct objmem_s objmem[] =
  {
    /*
     * For a object with no force preload, readonly and non-sparse pages
     */
    VMS_COMMIT |                        /* allocate as */
    PG_DISCARDABLE,

    /*
     * For a object with no force preload, readonly and sparse pages
     */
    NA,                                 /* allocate as */

    /*
     * For a object with no force preload, read/write and non-sparse pages
     */
    NA | VMS_COMMIT |                   /* allocate as */
    PG_SWAPONWRITE,

    /*
     * For a object with no force preload, read/write and sparse pages
     */
    NA,                                 /* allocate as */

    /*
     * For a object with force preload, readonly and non-sparse pages
     */
    NA | VMS_COMMIT |   /* allocate as */
    PG_SWAPONWRITE,

    /*
     * For a object with force preload, readonly and sparse pages
     */
    NA,                 /* allocate as */

    /*
     * For a object with force preload, read/write and non-sparse pages
     */
    NA | VMS_COMMIT |   /* allocate as */
    PG_SWAPONWRITE,

    /*
     * For a object with force preload, read/write and sparse pages
     */
    NA,                 /* allocate as */
  };

struct pgstatechg_s pgstatechg[] =
  {
    /*
     * For a readonly and valid page
     */
    VMS_COMMIT |        /* allocate as */
    PG_DISCARDABLE,

    /*
     * For a read/write and valid page
     */
    VMS_COMMIT |        /* allocate as */
    PG_SWAPONWRITE
  };

#ifdef  LDRSTRICT
   ulong_t  ldrDebugFlags;
#endif


/*
 *  Beginning of initialization code
 */

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


/***EP  LDRInit - initializes data for the loader
 *
 *      Initialize data structures for loader.
 *
 *      ENTRY   none
 *
 *      EXIT    data structures initialized
 */

void LDRInit()
{
    VMAC ac;   // used for SELAllocKHB

    // Init Loader Semaphore
    KSEMInit( (HKSEM)&LdrSem, KRNL_MUTEXSEM, NA );

    // Initialise the ldrQATCache structure.
    ldrQATCache.QATTimeStamp = 0;

#ifdef  LDRSTRICT

    ldrDebugFlags = LDR_DEBUG_OFF;

    if (sizeof(struct ldrrsrc32_s) != sizeof(struct rsrc32))
        panic("ldr: res struct");

#endif

    // allocate memory for the loader buffer
    if ( SELAllocKHB( VM_HKSH_PUBRW,
                      PMPATHLEN+4,
                      PG_U,
                      D_W | D_DATA | D_DPL0,
                      (VMHOB) LDRMTEOWNER,
                      SSToDS(&ac) ) )
        panic("ldr: AllocKHB ldrbuf");
    ldrpFileNameBuf = (uchar_t *)ac.ac_va;
    ldr16pFileNameBuf = ((ac.ac_sel)<<16) & 0xFFFF0000;

    // allocate memory for reading of MTE for executable image
    if ( VMAllocKHB( VM_HKH_PUB_RESRW,
                     sizeof(struct e32_exe),
                     (VMHOB) LDRMTEOWNER,
                     NA,
                     &pheaderbuf ) )
        panic("ldr: AllocKHB hbuf");

    // create handle to MTE for kernel (VDD MTE)
    if ( VMCreatePseudoHandle( (void *)&VDDModMte,
                               (VMHOB) LDRMTEOWNER,
                               &VDDModMte.mte_handle ) )
        panic("ldr: PseudoHandle VDD");

    // link VDD mte into list
    VDDModMte.mte_link = mte_h;
    mte_h = global_h = &VDDModMte;

    // create handle to MTE for FSH
    if ( VMCreatePseudoHandle( (void *)&FSHModMte,
                               (VMHOB) LDRMTEOWNER,
                               &FSHModMte.mte_handle ) )
        panic("ldr: PseudoHandle FSH");

    // initialize handle to MTE for kernal (DOSCALLS), Handle, already
    // created by VMInit, is stored in DosModHdl.
    DosModMte.mte_handle = DosModHdl;

    // Note - DOSCALLS mte already linked into list

    // Create Non-Resident Name Table Semaphore
    KSEMCreate( &hNonResNamTbl, KRNL_MUTEXSEM );
}



/***EP  LDRDisableDirtyHooks - disable dirty hook exports
 *
 *      This procedure is called just before the end of initialization
 *      to invalidate those ordinals used to export the offsets of
 *      data in system data structures that are manipulated by "dirty"
 *      device drivers and IFSs, such as LANMAN and HPFS.
 *
 *      LDRDisableDirtyHooks ()
 *
 *      ENTRY   NONE
 *      RETURNS NONE
 *
 *      All ordinals in DOSCALLS between DIRTY_HOOK_MIN and
 *      DIRTY_HOOK_MAX (inclusive) are invalidated.
 *
 *      CALLS   NONE
 *
 *      WARNING If additional exports are made, then this procedure
 *              will have to be modified to account for them.  This
 *              procedure is valid only during initialization.
 *
 *      EFFECTS The specified set of ordinals is invalidated.
 */

void LDRDisableDirtyHooks()
{
    register struct dce_s *pdos;            /* DOSCALLS entry pointer */
    register struct dce_s *pdoslast;        /* Last entry to blast */

    pdos =
    (struct dce_s *)(DosModMteSwappable.smte_enttab + sizeof(ushort_t)) +
      DIRTY_HOOK_MIN - 1;                   /* Point to first entry */
    pdoslast = pdos + (DIRTY_HOOK_MAX - DIRTY_HOOK_MIN);
                                            /* Compute last entry address */
    while (pdos <= pdoslast) {              /* Loop to invalidate entries */
        ldrAssert(pdos->dce_flags == IS_ABSOLUTE);
                                            /* Should be absolute entry */
        pdos->dce_flags = IS_DOSCALL1;      /* Invalidate the entry */
        ++pdos;                             /* Advance to next entry */
    }
}


/***EP  LDRFreeVDDMTEs - Free the MTEs and close the files for VDDs
 *
 *      Free the swappable MTEs and close the files for VDDs GEB BUGBUG
 *
 *      Used to: do nothing
 *
 *      ENTRY   none
 *
 *      EXIT    MTEs Freed and files closed
 */
void LDRFreeVDDMTEs()
{
   // PERF - defect 98488

    register ldrmte_t *pmte;
    register ldrmte_t *pmte2;

    pmte = mte_h;

    while (pmte != NULL) {
        pmte2 = pmte->mte_link;
        if (pmte->mte_flags1 & VDDMOD) {
           ldrUnlinkMTE(pmte);
           VMFreeKHB( VM_HKH_PUB_SWAPRW, pmte->mte_swapmte);
           pmte->mte_swapmte = 0;
        }
        pmte = pmte2;
    }
    // end 98488
    return;
}


/*
 *  End of initialization code
 */

#pragma code_seg()
