/*++ 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 #include #include #include #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++; } }