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.
392 lines
7.6 KiB
392 lines
7.6 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
entrypt.c
|
|
|
|
Abstract:
|
|
|
|
This module stores the Entry Point structures, and retrieves them
|
|
given either an intel address or a native address.
|
|
|
|
Author:
|
|
|
|
16-Jun-1995 t-orig
|
|
|
|
Revision History:
|
|
|
|
24-Aug-1999 [askhalid] copied from 32-bit wx86 directory and make work for 64bit.
|
|
|
|
--*/
|
|
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include "cpuassrt.h"
|
|
#include "entrypt.h"
|
|
#include "wx86.h"
|
|
#include "redblack.h"
|
|
#include "mrsw.h"
|
|
|
|
ASSERTNAME;
|
|
|
|
//
|
|
// Count of modifications made to the ENTRYPOINT tree. Useful for code
|
|
// which unlocks the Entrypoint MRSW object and needs to see if another thread
|
|
// has invalidated the ENTRYPOINT tree or not.
|
|
//
|
|
DWORD EntrypointTimestamp;
|
|
|
|
EPNODE _NIL;
|
|
PEPNODE NIL=&_NIL;
|
|
PEPNODE intelRoot=&_NIL;
|
|
#if DBG_DUAL_TREES
|
|
PEPNODE dualRoot=&_NIL;
|
|
#endif
|
|
|
|
#if DBG_DUAL_TREES
|
|
VOID
|
|
VerifySubTree(
|
|
PEPNODE intelEP,
|
|
PEPNODE dualEP
|
|
)
|
|
{
|
|
CPUASSERT(intelEP != NILL || dualEP == NIL);
|
|
CPUASSERT(intelEP->dual == dualEP);
|
|
CPUASSERT(dualEP->dual == intelEP);
|
|
CPUASSERT(intelEP->ep.intelStart == dualEP->ep.intelStart);
|
|
CPUASSERT(intelEP->ep.intelEnd == dualEP->ep.intelEnd);
|
|
CPUASSERT(intelEP->ep.nativeStart == dualEP->ep.nativeStart);
|
|
CPUASSERT(intelEP->intelColor == dualEP->intelColor);
|
|
|
|
VerifySubTree(intelEP->intelLeft, dualEP->intelLeft);
|
|
VerifySubTree(intelEP->intelRight, dualEP->intelRight);
|
|
}
|
|
|
|
VOID
|
|
VerifyTrees(
|
|
VOID
|
|
)
|
|
{
|
|
VerifySubTree(intelRoot, dualRoot);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef PROFILE
|
|
void StartCAP(void);
|
|
#endif
|
|
|
|
|
|
|
|
INT
|
|
initializeEntryPointModule(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the entry point module by allocating initial dll tables.
|
|
Should be called once for each process (thus this need not be called
|
|
by each thread).
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
return-value - 1 for success, 0 for failure
|
|
|
|
--*/
|
|
{
|
|
NIL->intelLeft = NIL->intelRight = NIL->intelParent = NIL;
|
|
NIL->intelColor = BLACK;
|
|
|
|
#ifdef PROFILE
|
|
StartCAP();
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
insertEntryPoint(
|
|
PEPNODE pNewEntryPoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inserts the entry point structure into the correct red/black trees
|
|
(both intel and native)
|
|
|
|
Arguments:
|
|
|
|
pNewEntryPoint - A pointer to the entry point structure to be inserted
|
|
into the trees
|
|
|
|
Return Value:
|
|
|
|
return-value - 1 - Success
|
|
0 - No entry for that region of memory
|
|
-1 -- There's a problem with the entry point table
|
|
|
|
--*/
|
|
{
|
|
#if DBG_DUAL_TREES
|
|
PEPNODE pdualNewEntryPoint = malloc(sizeof(EPNODE));
|
|
memcpy(pdualNewEntryPoint, pNewEntryPoint, sizeof(EPNODE));
|
|
#endif
|
|
intelRoot = insertNodeIntoIntelTree (intelRoot,
|
|
pNewEntryPoint,
|
|
NIL);
|
|
|
|
#if DBG_DUAL_TREES
|
|
dualRoot = insertNodeIntoIntelTree (dualRoot,
|
|
pdualNewEntryPoint,
|
|
NIL);
|
|
pdualNewEntryPoint->dual = pNewEntryPoint;
|
|
pNewEntryPoint->dual = pdualNewEntryPoint;
|
|
VerifyTrees();
|
|
#endif
|
|
|
|
//
|
|
// Bump the timestamp
|
|
//
|
|
EntrypointTimestamp++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
#if 0 // dead code, but keep it around in case we decide we want it later.
|
|
INT
|
|
removeEntryPoint(
|
|
PEPNODE pEP
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes an entry point structure from both the intel and native
|
|
red/black trees
|
|
|
|
Arguments:
|
|
|
|
pEP - A pointer to the entry point structure to be removed
|
|
|
|
Return Value:
|
|
|
|
return-value - 1 - Success
|
|
0 - No entry for that region of memory
|
|
-1 -- There's a problem with the entry point table
|
|
|
|
--*/
|
|
{
|
|
intelRoot = intelRBDelete (intelRoot,
|
|
pEP,
|
|
NIL);
|
|
|
|
#if DBG_DUAL_TREES
|
|
CPUASSERT(pEP->dual->dual == pEP);
|
|
dualRoot = intelRBDelete(dualRoot,
|
|
pEP->dual,
|
|
NIL);
|
|
free(pEP->dual);
|
|
pEP->dual = NULL;
|
|
VerifyTrees();
|
|
#endif
|
|
|
|
EntrypointTimestamp++;
|
|
|
|
return 1;
|
|
}
|
|
#endif // 0
|
|
|
|
|
|
PENTRYPOINT
|
|
EPFromIntelAddr(
|
|
PVOID intelAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves an entry point structure containing the given intel address
|
|
|
|
Arguments:
|
|
|
|
intelAddr - The intel address contained within the code corresponding to
|
|
the entry point structure
|
|
|
|
Return Value:
|
|
|
|
return-value - The entry point structure if found, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PENTRYPOINT EP;
|
|
PEPNODE pEPNode;
|
|
|
|
pEPNode = findIntel(intelRoot, intelAddr, NIL);
|
|
if (!pEPNode) {
|
|
//
|
|
// No EPNODE contains the address
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// The ENTRYPOINT inside the EPNODE contains the address. Search
|
|
// for an ENTRYPOINT which matches that address exactly.
|
|
//
|
|
EP = &pEPNode->ep;
|
|
do {
|
|
if (EP->intelStart == intelAddr) {
|
|
//
|
|
// Found a sub-Entrypoint whose Intel address exactly matches
|
|
// the one we were looking for.
|
|
//
|
|
return EP;
|
|
}
|
|
EP=EP->SubEP;
|
|
} while (EP);
|
|
|
|
//
|
|
// The EPNODE in the Red-black tree contains the Intel address, but
|
|
// no sub-Entrypoint exactly describes the Intel address.
|
|
//
|
|
return &pEPNode->ep;
|
|
}
|
|
|
|
PENTRYPOINT
|
|
GetNextEPFromIntelAddr(
|
|
PVOID intelAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves the entry point following
|
|
|
|
Arguments:
|
|
|
|
intelAddr - The intel address contained within the code corresponding to
|
|
the entry point structure
|
|
|
|
Return Value:
|
|
|
|
A pointer to the first EntryPoint which follows a particular Intel Address.
|
|
|
|
--*/
|
|
{
|
|
PEPNODE pEP;
|
|
#if DBG_DUAL_TREES
|
|
PEPNODE pDual;
|
|
#endif
|
|
|
|
pEP = findIntelNext (intelRoot, intelAddr, NIL);
|
|
|
|
#if DBG_DUAL_TREES
|
|
pDual = findIntelNext(dualRoot, intelAddr, NIL);
|
|
CPUASSERT((pDual==NULL && pEP==NULL) ||
|
|
(pDual->dual == pEP));
|
|
VerifyTrees();
|
|
#endif
|
|
|
|
return &pEP->ep;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
IsIntelRangeInCache(
|
|
PVOID Addr,
|
|
DWORD Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if any entrypoints are contained within a range of memory.
|
|
Used to determine if the Translation Cache must be flushed.
|
|
|
|
Must be called with either EP write or read lock.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN fContains;
|
|
|
|
if (intelRoot == NIL) {
|
|
//
|
|
// Empty tree - no need to flush
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
fContains = intelContainsRange(intelRoot,
|
|
NIL,
|
|
Addr,
|
|
(PVOID)((ULONGLONG)Addr + Length)
|
|
);
|
|
|
|
return fContains;
|
|
}
|
|
|
|
|
|
VOID
|
|
FlushEntrypoints(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Quickly deletes all entrypoints. Called by the Translation Cache when
|
|
the cache is flushed.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (intelRoot != NIL) {
|
|
//
|
|
// Delete the heap containing all entrypoints in the tree
|
|
//
|
|
EPFree();
|
|
|
|
//
|
|
// Reset the root of the tree
|
|
//
|
|
intelRoot = NIL;
|
|
#if DBG_DUAL_TREES
|
|
dualRoot = NIL;
|
|
#endif
|
|
|
|
//
|
|
// Bump the timestamp
|
|
//
|
|
EntrypointTimestamp++;
|
|
}
|
|
}
|