mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1159 lines
43 KiB
1159 lines
43 KiB
|
|
#include "ldrextrn.h"
|
|
|
|
extern ldrste_t segtab;
|
|
|
|
VOID ldrSetDescInfo(
|
|
SEL Selector, // selector to set desc info on
|
|
ULONG MemoryAddress, // base address of selector
|
|
USHORT ste_flags, // ste flags
|
|
USHORT SegSize) // size of segment
|
|
{
|
|
PROCESS_LDT_INFORMATION LdtInfo;
|
|
NTSTATUS Status;
|
|
|
|
LdtInfo.Start = Selector & 0xfff8;
|
|
LdtInfo.Length = sizeof(LDT_ENTRY);
|
|
|
|
LdtInfo.LdtEntries[0].LimitLow = SegSize - 1;
|
|
LdtInfo.LdtEntries[0].BaseLow = (USHORT)(MemoryAddress);
|
|
LdtInfo.LdtEntries[0].HighWord.Bytes.BaseMid = (UCHAR)(MemoryAddress >> 16);
|
|
LdtInfo.LdtEntries[0].HighWord.Bytes.BaseHi = (UCHAR)(MemoryAddress >> 24);
|
|
LdtInfo.LdtEntries[0].HighWord.Bytes.Flags1 = D_SEG+D_PRES+D_DPL3;
|
|
LdtInfo.LdtEntries[0].HighWord.Bytes.Flags2 = 0;
|
|
|
|
if ((ste_flags & STE_DATA) == 0) {
|
|
LdtInfo.LdtEntries[0].HighWord.Bytes.Flags1 |= D_CODE;
|
|
}
|
|
|
|
if ((ste_flags & STE_ERONLY) == 0) {
|
|
// The STE_ERONLY is applicable for both D_RX in CODE segments
|
|
// and D_RW in DATA segments. D_RX and D_RW are the same bit
|
|
LdtInfo.LdtEntries[0].HighWord.Bytes.Flags1 |= D_RX;
|
|
}
|
|
|
|
Status = NtSetInformationProcess( CurrentThread->Process->ProcessHandle,
|
|
ProcessLdtInformation,
|
|
&LdtInfo,
|
|
sizeof(PROCESS_LDT_INFORMATION)
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint ("ldrSetDescInfo: Invalid request\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/***LP ldrLoadModule - Load a new exe file for given module table entry.
|
|
*
|
|
* Each segment in the module which has not been
|
|
* previously initialized will be initialized and
|
|
* loaded as required.
|
|
*
|
|
* ENTRY plv - pointer to local variables
|
|
*
|
|
* EXIT Module marked as loaded
|
|
*
|
|
*
|
|
* This procedure performs the following steps:
|
|
*
|
|
* - calls TKLibiRecordMTE
|
|
* - calls DebugLoadSymMTE
|
|
* - must attach to or load each module that is referenced by our module
|
|
* - if 32-bit module finish loading objects
|
|
* - mark mte as module has been loaded
|
|
*/
|
|
|
|
APIRET ldrLoadModule(plv)
|
|
ldrlv_t *plv; /* local variables */
|
|
{
|
|
register ldrmte_t *pmte; /* pointer to mte */
|
|
register ldrsmte_t *psmte; /* pointer to swappable mte */
|
|
ldrste_t *pste;
|
|
ldrlibi_t *ptmp;
|
|
ulong_t csegs;
|
|
int rc;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrLoadModule(pmte=%x) was called\n", plv->lv_pmte);
|
|
}
|
|
#endif
|
|
|
|
pmte = plv->lv_pmte; /* point to mte */
|
|
psmte = pmte->mte_swapmte; /* pointer to swappable mte */
|
|
|
|
/*
|
|
* Setup for Library init
|
|
*/
|
|
if (((pmte->mte_mflags & LIBRARYMOD) != 0) &&
|
|
((pmte->mte_mflags & USED) == 0) &&
|
|
((pmte->mte_mflags & (INSTLIBINIT | GINIDONE)) != GINIDONE)) {
|
|
ptmp = &pldrLibiRecord[*pldrLibiCounter];
|
|
ptmp->handle = pmte->mte_handle;
|
|
pste = ldrNumToSte(pmte, psmte->smte_startobj);
|
|
ptmp->startaddr.ptr_off = (USHORT) psmte->smte_eip;
|
|
ptmp->startaddr.ptr_sel = pste->ste_selector | 7;
|
|
if (psmte->smte_stackobj != 0) {
|
|
if ((pste = ldrNumToSte(pmte, psmte->smte_stackobj))==0) {
|
|
rc = ERROR_INVALID_STACKSEG;
|
|
return(rc);
|
|
}
|
|
ptmp->stackaddr.ptr_off = (USHORT) psmte->smte_esp;
|
|
ptmp->stackaddr.ptr_sel = pste->ste_selector | 7;
|
|
}
|
|
else {
|
|
ptmp->stackaddr.ptr_off = 0;
|
|
ptmp->stackaddr.ptr_sel = 0;
|
|
}
|
|
if ((psmte->smte_autods == 0) ||
|
|
(pste = ldrNumToSte(pmte, psmte->smte_autods)) == NULL)
|
|
ptmp->ds = 0;
|
|
else
|
|
ptmp->ds = pste->ste_selector | 7;
|
|
ptmp->heapsize = (USHORT) psmte->smte_heapsize;
|
|
(*pldrLibiCounter)++;
|
|
pmte->mte_mflags |= GINIDONE;
|
|
}
|
|
|
|
//
|
|
// For system dll's other than Doscalls don't load segments
|
|
//
|
|
if ((pmte->mte_mflags & DOSMOD) != 0) {
|
|
ASSERT(LDRDoscallsSel != 0);
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
//
|
|
// If this module has already been loaded, no need to load again
|
|
//
|
|
if ((pmte->mte_mflags & MTEPROCESSED) != 0) {
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
/*
|
|
* Make sure starting point (or init routine) is ring 3
|
|
*/
|
|
if (ldrIsNE(pmte) &&
|
|
psmte->smte_startobj != 0) {
|
|
if ((pste=ldrNumToSte(pmte, psmte->smte_startobj)) == NULL) {
|
|
rc = ERROR_INVALID_STARTING_CODESEG;
|
|
return(rc);
|
|
}
|
|
|
|
if ((pste->ste_selector & RPL_MASK) != RPL_RING3) {
|
|
if (pmte->mte_mflags & LIBRARYMOD) {
|
|
rc = ERROR_INVALID_DLL_INIT_RING;
|
|
}
|
|
else {
|
|
rc = ERROR_INVALID_STARTING_RING, pmte;
|
|
}
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
pste = (ldrste_t *) psmte->smte_objtab;
|
|
for (csegs = 0;
|
|
csegs < psmte->smte_objcnt;
|
|
csegs++, pste++
|
|
) {
|
|
if ((rc = ldrLoadSegment(pmte, pste)) != NO_ERROR) {
|
|
#if DBG
|
|
DbgPrint("OS2LDR: ldrGetModule - failed to ldrLoadSegment, rc = %d\n", rc);
|
|
#endif
|
|
return(rc);
|
|
}
|
|
}
|
|
if ((psmte->smte_autods != 0) &&
|
|
(psmte->smte_autods <= psmte->smte_objcnt)
|
|
) {
|
|
ldrEachObjEntry(0, pmte, ldrEditProlog, NULL);
|
|
}
|
|
pmte->mte_mflags |= MTEPROCESSED;
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
/***LP ldrAllocSegments - allocate segments/selectors for requested mte.
|
|
*
|
|
* Each segment in the module which requests to be
|
|
* preloaded is allocated and all selectors for the
|
|
* module are allocated for the child task.
|
|
*
|
|
* ENTRY plv - pointer to set of local variables
|
|
*
|
|
* EXIT None
|
|
*
|
|
*
|
|
* This procedure performs the following steps:
|
|
*
|
|
* - For each segment in this module
|
|
* - check if load should abort
|
|
* - allocate memory
|
|
*/
|
|
|
|
APIRET ldrAllocSegments(plv)
|
|
register ldrlv_t *plv; /* pointer to set of local variables */
|
|
{
|
|
ldrmte_t *pmte; /* pointer to mte */
|
|
ldrsmte_t *psmte; /* pointer to swappable mte */
|
|
register ldrste_t *pste; /* pointer to a segment table entry */
|
|
//PVOID MemoryAddress;
|
|
ULONG LastSuccessful;
|
|
int rc;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrAllocSegments(pste=%x) was called\n", plv->lv_pmte);
|
|
}
|
|
#endif
|
|
|
|
pmte = plv->lv_pmte;
|
|
psmte = pmte->mte_swapmte;
|
|
pste = (ldrste_t *) psmte->smte_objtab;
|
|
|
|
for (plv->lv_objnum = 1; plv->lv_objnum <= psmte->smte_objcnt;
|
|
plv->lv_objnum++, pste++) {
|
|
|
|
if ((rc=ldrAllocSegment(pmte, pste, plv->lv_objnum)) != NO_ERROR) {
|
|
|
|
/*
|
|
* We got an error allocating the segments for this
|
|
* module. We must cleanup any segments that were
|
|
* allocated before the error if the module we are loading
|
|
* was a library module. The reason is that the mte for this
|
|
* module will not have a run time attachment to this process.
|
|
* The case we are covering here is if a module that references
|
|
* another, is not loaded that module's module pointer table
|
|
* will not get the pointer to the mte for this one. Therefore
|
|
* when garbage collection is run this module will be freed
|
|
* and the allocated segments will not get freed.
|
|
*/
|
|
LastSuccessful = plv->lv_objnum - 1;
|
|
pste = (ldrste_t *) psmte->smte_objtab;
|
|
|
|
for (plv->lv_objnum = 1; plv->lv_objnum <= LastSuccessful;
|
|
plv->lv_objnum++, pste++) {
|
|
|
|
NtUnmapViewOfSection(CurrentThread->Process->ProcessHandle,
|
|
SELTOFLAT(pste->ste_selector)
|
|
);
|
|
|
|
if ((pmte->mte_mflags & MTEPROCESSED) == 0) {
|
|
//
|
|
// If the allocated segment is a ring 2 segment, check
|
|
// entry records that need to be referenced by call gates.
|
|
// Remove the emulation thunk for the call gate.
|
|
//
|
|
if (((pste->ste_flags & STE_SEGDPL) == STE_RING_2) && // ring 2 segment
|
|
((pste->ste_flags & STE_DATA) == 0) && // code segment
|
|
((pste->ste_flags & STE_CONFORM) == 0) // non conforming
|
|
) {
|
|
ldrEachObjEntry(plv->lv_objnum, pmte, ldrFreeCallGate, NULL);
|
|
}
|
|
NtUnmapViewOfSection(NtCurrentProcess(),
|
|
SELTOFLAT(pste->ste_selector)
|
|
);
|
|
NtClose((HANDLE)pste->ste_seghdl);
|
|
ldrFreeSel(pste->ste_selector, 1);
|
|
}
|
|
}
|
|
// /*
|
|
// * Slip packed segments, free as one object later
|
|
// */
|
|
// if (pste->ste_flags & STE_PACKED)
|
|
// continue;
|
|
// if ((pste->ste_seghdl != HOBNULL) &&
|
|
// (pste->ste_selector & SEL_LDTBIT) &&
|
|
// ((pste->ste_flags & STE_SHARED) == 0)) {
|
|
// /* If cached instance data object */
|
|
// ldrAssert(pste->ste_offset != 0);
|
|
// if (VMHandleVerify(pste->ste_seghdl,
|
|
// 1,SSToDS(&pbcache)) == NO_ERROR) {
|
|
// /* Free the pseudohandle */
|
|
// VMFreePseudoHandle(pste->ste_seghdl);
|
|
// /* Free small caches from heap */
|
|
// VMFreeKHB(VM_HKH_PUB_SWAPRW, pbcache);
|
|
// }
|
|
// else { /* Else cache has own object */
|
|
// rc = VMGetLaddr(pste->ste_seghdl, SSToDS(&laddr));
|
|
// ldrAssert(rc == NO_ERROR);
|
|
// while (VMFreeMem(laddr,HOBNULL,0)==ERROR_INTERRUPT)
|
|
// ; /* Free the object */
|
|
// }
|
|
// pste->ste_seghdl = HOBNULL;
|
|
// /* Clear the handle */
|
|
// }
|
|
// else if (pste->ste_selector != 0)
|
|
// VMFreeMem(SelToLaTiled(pste->ste_selector),
|
|
// (VMHOB) ((pPTDACur->ptda_child != HOBNULL) ?
|
|
// pPTDACur->ptda_child :
|
|
// pPTDACur->ptda_handle),
|
|
// VMFM_NOLDR | VMFM_GC);
|
|
|
|
// /*
|
|
// * See if any packed segments exists, free as one object.
|
|
// */
|
|
// if (psmte->smte_csegpack > 0)
|
|
// VMFreeMem(psmte->smte_ssegpack, NA, NA);
|
|
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Clear packed segment flag for second load of EXE
|
|
*/
|
|
if (psmte->smte_csegpack > 0)
|
|
psmte->smte_csegpack = 0;
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
/***LP ldrAllocSegment - verify allocation size and allocate memory
|
|
*
|
|
* If the segment's file size is larger than the minimum
|
|
* allocation size an error is reported.
|
|
* Both the allocation size and the segment handle are saved in
|
|
* the segment table entry. Also indicate the segment
|
|
* is being loaded so that it's memory will not be
|
|
* discarded during the load.
|
|
*
|
|
* ldrAllocSegment (pmte, pste, iseg)
|
|
*
|
|
* ENTRY pmte - pointer to mte
|
|
* pste - pointer to ste
|
|
* iseg - segment number
|
|
* RETURN int - error code (NO_ERROR if successful)
|
|
*
|
|
*/
|
|
|
|
static ULONG RegionSize64K = _64K;
|
|
|
|
APIRET ldrAllocSegment(pmte,pste,iseg)
|
|
register ldrmte_t *pmte; /* MTE pointer */
|
|
register ldrste_t *pste; /* STE pointer */
|
|
ulong_t iseg; /* Segment number (1-based) */
|
|
{
|
|
register ldrsmte_t *psmte; /* swappable mte pointer */
|
|
ulong_t fl; /* Memory allocation flags */
|
|
int frsrc; /* Resource segment flag */
|
|
int frsrcused; /* True if resource really used */
|
|
ULONG RegionSize;
|
|
uchar_t sharename[23] = "\\sharemem\\";
|
|
uchar_t *psharename = sharename;
|
|
uchar_t ext[3] = {0,0,0};
|
|
ulong_t Index;
|
|
PVOID MemoryAddress;
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER LargeRegionSize;
|
|
HANDLE SectionHandle;
|
|
ULONG ViewSize;
|
|
ULONG Protect;
|
|
BOOLEAN SectionCreated = FALSE;
|
|
APIRET rc;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrAllocSegment(pmte=%x) was called\n", pmte);
|
|
}
|
|
#endif
|
|
|
|
psmte = pmte->mte_swapmte;
|
|
|
|
frsrc = iseg > psmte->smte_objcnt - psmte->smte_rsrccnt;
|
|
/* Set resource flag */
|
|
/*
|
|
* Note that for debugging purposes, we will actually allocate
|
|
* memory for resources that are not marked STE_PRELOAD if the
|
|
* ldrLoadRsrc flag is set. Such resources are born with a
|
|
* reference count of zero instead of one, however. The flag
|
|
* frsrcused is used to distinguish the special case.
|
|
*/
|
|
// if (!(pste->ste_flags & STE_PRELOAD) && frsrc)
|
|
// return(NO_ERROR); /* Skip non-preloaded resources */
|
|
frsrcused = FALSE; /* Assume not meant to be used yet */
|
|
fl = 0; /* Initialize VM and PG flags */
|
|
|
|
if ((pste->ste_flags & STE_PRELOAD)) {
|
|
/* If swapping off or preload seg */
|
|
/*
|
|
* For a resource, the preload attribute does not actually
|
|
* mean the resource should be preloaded. It just means we
|
|
* should allocate the segment for the resource at load time.
|
|
* Unless we are loading the resource from a floppy, we should
|
|
* always preload it.
|
|
*/
|
|
if (pste->ste_flags & STE_SHARED) {
|
|
/* If shared object */
|
|
pste->ste_flags &= ~STE_PRELOAD;
|
|
/* Only preload shared guys once */
|
|
frsrcused = TRUE; /* Resource actually referenced */
|
|
}
|
|
}
|
|
|
|
RegionSize = pste->ste_minsiz;
|
|
if (RegionSize == 0) {
|
|
RegionSize = _64K;
|
|
}
|
|
|
|
if ((pmte->mte_mflags & MTEPROCESSED) == 0) {
|
|
if ((pmte->mte_mflags & DOSLIB) != 0) {
|
|
Index = 0;
|
|
// DOSCALLS.DLL is loaded into fixed locationions
|
|
MemoryAddress = (PVOID)(DOSCALLS_BASE + (iseg - 1) * _64K);
|
|
}
|
|
else {
|
|
Index = ldrAllocateSel(1, FALSE); // _64K are exactly 1 selector
|
|
MemoryAddress = SELTOFLAT(Index);
|
|
}
|
|
//
|
|
// Special handling for the R2XFER_BASE segment which has
|
|
// already been allocated at ldrInit()
|
|
//
|
|
if (MemoryAddress == (PVOID)R2XFER_BASE) {
|
|
pste->ste_seghdl = (ulong_t)R2XferSegHandle;
|
|
SectionHandle = R2XferSegHandle;
|
|
}
|
|
else {
|
|
LargeRegionSize.LowPart = _64K;
|
|
LargeRegionSize.HighPart = 0;
|
|
Status = NtCreateSection(&SectionHandle,
|
|
SECTION_ALL_ACCESS,
|
|
NULL,
|
|
&LargeRegionSize,
|
|
PAGE_EXECUTE_READWRITE,
|
|
SEC_RESERVE,
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("OS2LDR: ldrAllocSegment - Can't create section, Status=%x\n", Status);
|
|
#endif
|
|
if (Index != 0) {
|
|
ldrFreeSel(Index, 1);
|
|
}
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
ViewSize = 0;
|
|
Status = NtMapViewOfSection(SectionHandle,
|
|
NtCurrentProcess(),
|
|
&MemoryAddress,
|
|
1,
|
|
RegionSize,
|
|
NULL,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("OS2LDR: ldrAllocSegment - Can't map section to server process at addr=%x, Status=%x\n",
|
|
MemoryAddress, Status);
|
|
#endif
|
|
NtClose(SectionHandle);
|
|
if (Index != 0) {
|
|
ldrFreeSel(Index, 1);
|
|
}
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
SectionCreated = TRUE;
|
|
pste->ste_seghdl = (ulong_t)SectionHandle;
|
|
}
|
|
}
|
|
else {
|
|
SectionHandle = (HANDLE)pste->ste_seghdl;
|
|
MemoryAddress = SELTOFLAT(pste->ste_selector);
|
|
}
|
|
|
|
//
|
|
// Any change in determinig the Protect value should be
|
|
// done in ldrsubr.c LDRDosGetResource() too.
|
|
//
|
|
if ((pste->ste_flags & STE_DATA) == 0) {
|
|
// This is a code segment
|
|
if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) {
|
|
Protect = PAGE_EXECUTE_WRITECOPY;
|
|
}
|
|
else {
|
|
if ((pste->ste_flags & STE_ERONLY) != 0) {
|
|
// This is an execute only segment
|
|
Protect = PAGE_EXECUTE;
|
|
}
|
|
else {
|
|
Protect = PAGE_EXECUTE_READ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// This is a data segment
|
|
if ((pste->ste_flags & STE_SHARED) != 0) {
|
|
// This is a shared data segment
|
|
if ((pste->ste_flags & STE_ERONLY) != 0) {
|
|
// This is a read only segment
|
|
Protect = PAGE_READONLY;
|
|
}
|
|
else {
|
|
// This is a read/write segment
|
|
Protect = PAGE_READWRITE;
|
|
}
|
|
}
|
|
else {
|
|
// This is a non shared data segment
|
|
if ((pste->ste_flags & STE_ERONLY) != 0) {
|
|
// This is a read only segment
|
|
if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) {
|
|
Protect = PAGE_EXECUTE_WRITECOPY;
|
|
}
|
|
else {
|
|
Protect = PAGE_READONLY;
|
|
}
|
|
}
|
|
else {
|
|
// This is a sizeable read/write segment
|
|
Protect = PAGE_EXECUTE_WRITECOPY;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((pmte->mte_mflags & MTEPROCESSED) == 0) {
|
|
pste->ste_selector = FLATTOSEL((ULONG)MemoryAddress);
|
|
pste->ste_selector = (SEL)((pste->ste_selector & SEL_RPLCLR) |
|
|
((pste->ste_flags & STE_SEGDPL) >> 10));
|
|
pste->ste_fixups = (ulong_t)MemoryAddress;
|
|
}
|
|
|
|
//
|
|
// Non resource segments are mapped into the address space of the
|
|
// client process.
|
|
// Resources are not mapped yet into the address space of the process.
|
|
// DosGetResource() does the mapping job for resources.
|
|
//
|
|
if (iseg <= psmte->smte_objcnt - psmte->smte_rsrccnt) {
|
|
if (Protect == PAGE_EXECUTE_WRITECOPY) {
|
|
ViewSize = RegionSize;
|
|
}
|
|
else {
|
|
ViewSize = 0;
|
|
}
|
|
Status = NtMapViewOfSection(SectionHandle,
|
|
CurrentThread->Process->ProcessHandle,
|
|
&MemoryAddress,
|
|
1,
|
|
RegionSize,
|
|
NULL,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
0,
|
|
Protect
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("OS2LDR: ldrAllocSegment - Can't map section to client process %x at addr=%x, Status=%x\n",
|
|
CurrentThread->Process->ProcessHandle, MemoryAddress, Status);
|
|
#endif
|
|
if (SectionCreated) {
|
|
NtUnmapViewOfSection(NtCurrentProcess(), MemoryAddress);
|
|
NtClose(SectionHandle);
|
|
if (Index != 0) {
|
|
ldrFreeSel(Index, 1);
|
|
}
|
|
}
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
if ((pmte->mte_mflags & MTEPROCESSED) == 0) {
|
|
/*
|
|
* If this is Doscalls module save the code selector
|
|
* of the first code segment
|
|
*/
|
|
if (((pmte->mte_mflags & DOSLIB) != 0) &&
|
|
(iseg == 1)
|
|
) {
|
|
LDRDoscallsSel = pste->ste_selector | 7;
|
|
segtab = *pste;
|
|
}
|
|
//
|
|
// If the allocated segment is a ring 2 segment, check for
|
|
// entry records that need to be referenced by call gates.
|
|
// Create an emulation thunk for the call gate.
|
|
//
|
|
if (((pste->ste_flags & STE_SEGDPL) == STE_RING_2) && // ring 2 segment
|
|
((pste->ste_flags & STE_DATA) == 0) && // code segment
|
|
((pste->ste_flags & STE_CONFORM) == 0) // non conforming
|
|
) {
|
|
rc = ldrEachObjEntry(iseg, pmte, ldrGetCallGate, NULL);
|
|
if (rc != NO_ERROR) {
|
|
ldrEachObjEntry(iseg, pmte, ldrFreeCallGate, NULL);
|
|
NtUnmapViewOfSection(CurrentThread->Process->ProcessHandle,
|
|
MemoryAddress
|
|
);
|
|
|
|
if (SectionCreated) {
|
|
NtUnmapViewOfSection(NtCurrentProcess(), MemoryAddress);
|
|
NtClose(SectionHandle);
|
|
if (Index != 0) {
|
|
ldrFreeSel(Index, 1);
|
|
}
|
|
}
|
|
return(rc);
|
|
}
|
|
}
|
|
}
|
|
|
|
ldrSetDescInfo(pste->ste_selector, (ULONG) MemoryAddress,
|
|
pste->ste_flags, pste->ste_minsiz);
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
/***LP ldrLoadSegment - segment load
|
|
*
|
|
* Setup to call ldrLoadSegment
|
|
*
|
|
* ENTRY pmte - pointer to mte
|
|
* pste - pointer to a segment table entry
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
*
|
|
*/
|
|
|
|
APIRET ldrLoadSegment(pmte, pste)
|
|
ldrmte_t *pmte; /* pointer to mte */
|
|
ldrste_t *pste; /* pointer to segment table entry */
|
|
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PIO_STATUS_BLOCK pIoStatusBlock = &IoStatusBlock;
|
|
LARGE_INTEGER ByteOffset;
|
|
ldrmte_t *ptgtmte;
|
|
ldrsmte_t *psmte;
|
|
ldrste_t *ptgtste;
|
|
struct taddr_s taddr;
|
|
ULONG laddr;
|
|
ULONG seek;
|
|
uchar_t relocbuf[RELOCBUFLEN];
|
|
ushort_t crelrecs;
|
|
ushort_t i;
|
|
ulong_t cbread;
|
|
ushort_t crecs;
|
|
ri_t *pri;
|
|
uchar_t *pprocname;
|
|
ushort_t ord;
|
|
uchar_t *pchar;
|
|
ulong_t minsiz;
|
|
int rc = NO_ERROR;
|
|
NTSTATUS Status;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrLoadSegment(pmte=%x, pste=%x) was called\n", pmte, pste);
|
|
}
|
|
#endif
|
|
|
|
ldrSetupSrcErrTxt(((char *) pmte->mte_modname)+1,
|
|
(USHORT) *((char *) pmte->mte_modname));
|
|
|
|
psmte = pmte->mte_swapmte;
|
|
|
|
// BUGBUG - remove after LDT defined
|
|
// laddr = SelToLaTiled(pste->ste_selector);
|
|
laddr = pste->ste_fixups;
|
|
|
|
if (pste->ste_offset != 0) {
|
|
|
|
if (pste->ste_flags & STE_ITERATED) {
|
|
if ((rc = ldrLoadIteratedData(pmte,
|
|
pste,
|
|
pIoStatusBlock,
|
|
laddr)) != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
IoStatusBlock.Status -= laddr;
|
|
cbread = IoStatusBlock.Information;
|
|
ByteOffset.LowPart = (ULONG)
|
|
(pste->ste_offset << psmte->smte_alignshift);
|
|
ByteOffset.HighPart = 0;
|
|
}
|
|
|
|
else {
|
|
seek = (ULONG) (pste->ste_offset << psmte->smte_alignshift);
|
|
ByteOffset.LowPart = seek;
|
|
ByteOffset.HighPart = 0;
|
|
cbread = (ulong_t) ((pste->ste_size == 0) ? _64K :
|
|
pste->ste_size);
|
|
if ((Status = NtReadFile(pmte->mte_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
(void *) laddr,
|
|
cbread,
|
|
&ByteOffset,
|
|
0)) != 0) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
}
|
|
if (IoStatusBlock.Information != cbread)
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
|
|
if (pste->ste_size != 0) {
|
|
minsiz = (ulong_t) pste->ste_minsiz;
|
|
if (minsiz == 0) { /* size = 64k */
|
|
minsiz = 0x10000;
|
|
}
|
|
//
|
|
// Need to handle this special case because the segment
|
|
// is already set with the ring 2 xfer thunks
|
|
//
|
|
if (laddr != R2XFER_BASE) {
|
|
memset((void *) (laddr +
|
|
((pste->ste_flags & STE_ITERATED) ?
|
|
IoStatusBlock.Status :
|
|
IoStatusBlock.Information)),
|
|
'\0',
|
|
(pste->ste_flags & STE_ITERATED) ?
|
|
minsiz - IoStatusBlock.Status :
|
|
minsiz - pste->ste_size);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* HACK - This will check for Doscalls.dll and if it is
|
|
* the code segment it will search the code for the OPCodes
|
|
* "0xDD, 0x1f" which will be changed to a call to
|
|
* _EntryFlat
|
|
*/
|
|
if (((pmte->mte_mflags & DOSLIB) != 0) &&
|
|
((pste->ste_flags & STE_TYPE_MASK) == STE_CODE) &&
|
|
(!DoscallsLoaded)
|
|
) {
|
|
pchar = (uchar_t *) laddr;
|
|
while(TRUE) {
|
|
while (*pchar++ != 0xdd &&
|
|
pchar < (uchar_t *) (laddr + cbread));
|
|
if (pchar == (uchar_t *) (laddr + cbread))
|
|
break;
|
|
if (*pchar == 0x1f) {
|
|
pchar--;
|
|
*((ULONG *) pchar) = Ol2EntryFlat;
|
|
break;
|
|
}
|
|
}
|
|
DoscallsLoaded = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Process fixups if present
|
|
*/
|
|
if (pste->ste_flags & STE_RELOCINFO) {
|
|
|
|
/*
|
|
* Read the number of relocation records
|
|
*/
|
|
cbread = 2;
|
|
ByteOffset.LowPart += IoStatusBlock.Information;
|
|
if ((Status = NtReadFile(pmte->mte_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
&crelrecs,
|
|
cbread,
|
|
&ByteOffset,
|
|
0 )) != 0) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
if (IoStatusBlock.Information != cbread)
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
|
|
crecs = RELOCSPERBUF;
|
|
for (i = 0; i < crelrecs; i++, crecs++) {
|
|
|
|
if ((crecs % RELOCSPERBUF) == 0) {
|
|
if (crelrecs - i > RELOCSPERBUF)
|
|
cbread = RELOCBUFLEN;
|
|
else
|
|
cbread = (crelrecs - i) * sizeof(struct ri_s);
|
|
|
|
ByteOffset.LowPart += IoStatusBlock.Information;
|
|
if ((Status = NtReadFile(pmte->mte_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
&relocbuf,
|
|
cbread,
|
|
&ByteOffset,
|
|
0)) != 0) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
if (IoStatusBlock.Information != cbread)
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
crecs = 0;
|
|
}
|
|
pri = (ri_t *) &relocbuf[crecs * sizeof(struct ri_s)];
|
|
|
|
switch (pri->ri_flags & TARGET_MASK) {
|
|
|
|
case INTERNALREF: /* Internal fixup */
|
|
|
|
/*
|
|
* Check for fixed or movable
|
|
*/
|
|
if (pri->ri_target_seg != B16MOVABLE) {
|
|
if ((ptgtste=ldrNumToSte(pmte,
|
|
pri->ri_target_seg
|
|
))== NULL) {
|
|
return(ERROR_INVALID_SEGMENT_NUMBER);
|
|
}
|
|
taddr.tsel = ptgtste->ste_selector | 7;
|
|
taddr.toff = (ulong_t) pri->ri_target_off;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* A movable entry exists
|
|
*/
|
|
else {
|
|
if ((rc = ldrGetEntAddr(pri->ri_target_off,
|
|
pmte,
|
|
&taddr,
|
|
pste,
|
|
pmte)) != NO_ERROR) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IMPORTNAME: /* Import by name fixup */
|
|
case IMPORTORDINAL: /* Import by ordinal fixup */
|
|
|
|
if ((rc = ldrGetTgtMte(pri->ri_target_modnam,
|
|
pmte,
|
|
&ptgtmte)) != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
ldrSetupTgtErrTxt(((char *) ptgtmte->mte_modname)+1,
|
|
(USHORT) *((char *) ptgtmte->mte_modname));
|
|
|
|
if ((pri->ri_flags & TARGET_MASK) == IMPORTNAME) {
|
|
pprocname = (uchar_t *) (psmte->smte_impproc +
|
|
(ulong_t) pri->ri_target_impnam);
|
|
if (pprocname[1] == '#') {
|
|
//BUGBUG - convert routine from asm
|
|
// ldrStop(0xffff, 0);
|
|
// ord = (ushort_t) ldrAscToOrd(&pprocname[2],
|
|
// (ushort_t) pprocname[0] - 1);
|
|
}
|
|
else {
|
|
|
|
ldrProcNameBufL = (USHORT) (pprocname[0]);
|
|
ldrProcNameBuf = (PUCHAR) (pprocname + 1);
|
|
if ((rc = ldrGetOrdNum(ptgtmte,
|
|
pprocname,
|
|
&ord,
|
|
STRINGNONNULL
|
|
)) != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
ord = pri->ri_target_ord;
|
|
ldrProcNameBufL = 2;
|
|
ldrProcNameBuf = (PUCHAR) &pri->ri_target_ord;
|
|
}
|
|
|
|
if ((rc = ldrGetEntAddr(ord,
|
|
ptgtmte,
|
|
&taddr,
|
|
pste,
|
|
pmte)) != NO_ERROR) {
|
|
#if DBG
|
|
DbgPrint("ldrLoadSegment: failed to locate ordinal %d in %s for %s\n",
|
|
pri->ri_target_ord,
|
|
1+(char *) (ptgtmte->mte_modname),
|
|
1+(char *) (pmte->mte_modname)
|
|
);
|
|
#endif
|
|
return(rc);
|
|
}
|
|
ldrInvTgtErrTxt();
|
|
break;
|
|
|
|
default:
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((rc = ldrDoFixups(pri, laddr, &taddr,
|
|
pste->ste_minsiz)) != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
}
|
|
}
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
/***LP ldrLoadIteratedData - load iterated data
|
|
*
|
|
* Reads the iterated data from the file, expands it and loads it into
|
|
* the segment.
|
|
*
|
|
* ENTRY
|
|
* pmte - pointer to mte
|
|
* pste - pointer to segment table
|
|
* pIoStatusBlock - pointer to IO status buffer
|
|
* laddr - address of page we are loading
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
*
|
|
*/
|
|
|
|
APIRET ldrLoadIteratedData(pmte, pste, pIoStatusBlock, laddr)
|
|
ldrmte_t *pmte;
|
|
ldrste_t *pste;
|
|
PIO_STATUS_BLOCK pIoStatusBlock;
|
|
ULONG laddr;
|
|
|
|
{
|
|
ldrsmte_t *psmte;
|
|
ULONG IOcount = 0;
|
|
ULONG seek;
|
|
LARGE_INTEGER ByteOffset;
|
|
ULONG cbread;
|
|
int rc;
|
|
ULONG filedata;
|
|
ULONG segsize;
|
|
struct iter {
|
|
USHORT numberiter;
|
|
USHORT patternsize;
|
|
} iterdata;
|
|
ULONG expandsize;
|
|
ULONG temp;
|
|
ULONG i;
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( TRACE ) {
|
|
DbgPrint("OS2LDR: ldrLoadIteratedData(pmte=%x) was called\n", pmte);
|
|
}
|
|
#endif
|
|
|
|
psmte = pmte->mte_swapmte;
|
|
filedata = (ULONG) pste->ste_size; /* size of data */
|
|
if (filedata == 0) { /* check if file data = 64k */
|
|
filedata = 0x10000;
|
|
}
|
|
|
|
segsize = pste->ste_minsiz; /* size of segment */
|
|
if (segsize == 0) { /* check if size = 64k */
|
|
segsize = _64K;
|
|
}
|
|
|
|
seek = (ULONG) (pste->ste_offset << psmte->smte_alignshift);
|
|
|
|
while (TRUE) {
|
|
|
|
if (filedata < 3) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
|
|
filedata -= 4;
|
|
|
|
if (filedata == 0) /* See if done */
|
|
break;
|
|
|
|
ByteOffset.LowPart = seek;
|
|
ByteOffset.HighPart = 0;
|
|
cbread = 4;
|
|
if ((rc = NtReadFile(pmte->mte_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
pIoStatusBlock,
|
|
&iterdata,
|
|
cbread,
|
|
&ByteOffset,
|
|
0)) != 0) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
|
|
if (pIoStatusBlock->Information != cbread) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
|
|
seek += 4; /* We read 4 bytes */
|
|
IOcount += pIoStatusBlock->Information;
|
|
|
|
if (iterdata.numberiter == 0 || iterdata.patternsize == 0)
|
|
continue;
|
|
|
|
filedata -= iterdata.patternsize;
|
|
if (filedata > 0xffff) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
|
|
expandsize = (ULONG) (iterdata.patternsize * iterdata.numberiter);
|
|
if (expandsize > 0xffff) {
|
|
return(ERROR_ITERATED_DATA_EXCEEDS_64k);
|
|
}
|
|
|
|
segsize -= expandsize;
|
|
if (segsize > 0xffff) {
|
|
return(ERROR_INVALID_MINALLOCSIZE);
|
|
}
|
|
|
|
ByteOffset.LowPart = seek;
|
|
ByteOffset.HighPart = 0;
|
|
cbread = iterdata.patternsize;
|
|
if ((rc = NtReadFile(pmte->mte_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
pIoStatusBlock,
|
|
(void *) laddr,
|
|
cbread,
|
|
&ByteOffset,
|
|
0)) != 0) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
|
|
if (pIoStatusBlock->Information != cbread) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
|
|
seek += iterdata.patternsize;
|
|
IOcount += pIoStatusBlock->Information;
|
|
|
|
temp = laddr;
|
|
laddr += iterdata.patternsize;
|
|
for (i=1; i<iterdata.numberiter; i++) {
|
|
memmove((void *) laddr,
|
|
(void *) temp,
|
|
iterdata.patternsize);
|
|
laddr += iterdata.patternsize;
|
|
}
|
|
|
|
if (filedata == 0)
|
|
break;
|
|
|
|
}
|
|
|
|
pIoStatusBlock->Information = IOcount;
|
|
pIoStatusBlock->Status = laddr;
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
/***LP ldrDoFixups - Do the fixups following the source chain
|
|
*
|
|
* Apply fixups to source
|
|
*
|
|
*
|
|
* ENTRY pri - pointer to fixup record
|
|
* laddr - address of start of segment
|
|
* taddr - pointer to target address
|
|
* segsize - size of segment
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
*
|
|
*/
|
|
|
|
APIRET ldrDoFixups(pri, laddr, ptaddr, segsize)
|
|
ri_t *pri; /* pointer to fixup record */
|
|
ulong_t laddr; /* address of start of segment */
|
|
struct taddr_s *ptaddr; /* target address */
|
|
ushort_t segsize; /* size of segment */
|
|
|
|
{
|
|
uchar_t *pcoffset;
|
|
ushort_t *psoffset;
|
|
ushort_t chain;
|
|
int count;
|
|
ulong_t segsize_l = RESIZE64K(segsize);
|
|
|
|
#if DBG
|
|
IF_OL2_DEBUG ( FIXUP ) {
|
|
DbgPrint("OS2LDR: ldrDoFixups(): laddr=%x\n", laddr);
|
|
}
|
|
#endif
|
|
|
|
chain = 1; /* we do at least one fixup */
|
|
count = (int) (segsize_l / sizeof(ushort_t));
|
|
|
|
if ((ulong_t)pri->ri_source > segsize_l)
|
|
return(ERROR_RELOC_CHAIN_XEEDS_SEGLIM);
|
|
|
|
pcoffset = (uchar_t *) (laddr + (ulong_t) pri->ri_source);
|
|
|
|
while (chain != 0xffff) {
|
|
|
|
if (!(pri->ri_flags & ADDITIVE))
|
|
chain = *((ushort_t *) pcoffset);
|
|
else
|
|
chain = 0xffff;
|
|
|
|
switch(pri->ri_stype & SOURCE_MASK) {
|
|
|
|
case BYTE_ADR:
|
|
if (pri->ri_flags & ADDITIVE)
|
|
*pcoffset += (uchar_t) (ptaddr->toff & BYTEMASK);
|
|
else
|
|
*pcoffset = (uchar_t) (ptaddr->toff & BYTEMASK);
|
|
break;
|
|
case SEG_ADR:
|
|
psoffset = (ushort_t *) pcoffset;
|
|
if (pri->ri_flags & ADDITIVE)
|
|
*psoffset += ptaddr->tsel;
|
|
else
|
|
*psoffset = ptaddr->tsel;
|
|
break;
|
|
case FAR_ADR:
|
|
psoffset = (ushort_t *) pcoffset;
|
|
if (pri->ri_flags & ADDITIVE) {
|
|
*psoffset += (ushort_t) (ptaddr->toff & WORDMASK);
|
|
psoffset++;
|
|
*psoffset += ptaddr->tsel;
|
|
}
|
|
else {
|
|
*psoffset = (ushort_t) (ptaddr->toff & WORDMASK);
|
|
psoffset++;
|
|
*psoffset = ptaddr->tsel;
|
|
}
|
|
break;
|
|
case OFF_ADR:
|
|
psoffset = (ushort_t *) pcoffset;
|
|
if (pri->ri_flags & ADDITIVE) {
|
|
*psoffset += (ushort_t) (ptaddr->toff & WORDMASK);
|
|
}
|
|
else {
|
|
*psoffset = (ushort_t) (ptaddr->toff & WORDMASK);
|
|
}
|
|
}
|
|
if (!(pri->ri_flags & ADDITIVE)) {
|
|
if (chain != 0xffff && (ulong_t)chain > segsize_l)
|
|
return(ERROR_RELOC_CHAIN_XEEDS_SEGLIM);
|
|
|
|
pcoffset = (uchar_t *) (laddr + (ulong_t) chain);
|
|
}
|
|
|
|
if (--count < 0) { // check for internal loops
|
|
return(ERROR_RELOC_CHAIN_XEEDS_SEGLIM);
|
|
}
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
|
|
}
|