/*++ Copyright (c) 1995-1998 Microsoft Corporation Module Name: epalloc.c Abstract: This module allocates memory for the entry point structures Author: 21-Aug-1995 Ori Gershony (t-orig) Revision History: 24-Aug-1999 [askhalid] copied from 32-bit wx86 directory and make work for 64bit. --*/ #include #include #include #include #include "wx86.h" #include "cpuassrt.h" #include "config.h" #include "entrypt.h" ASSERTNAME; PVOID allocBase; // Base of the allocation unit PVOID commitLimit; // Top of commited memory PVOID allocLimit; // Top of memory allocated to the user #if DBG #define EPTRASHVALUE 0x0b #endif INT initEPAlloc( VOID ) /*++ Routine Description: Initializes the entry point memory allocator Arguments: none Return Value: return-value - non-zero for success, 0 for failure --*/ { NTSTATUS Status; ULONGLONG ReserveSize = CpuEntryPointReserve; Status = NtAllocateVirtualMemory(NtCurrentProcess(), &allocBase, 0, &ReserveSize, MEM_RESERVE, PAGE_READWRITE ); if (!NT_SUCCESS(Status)) { return 0; } // No memory is commited yet, nor is any allocated to the user allocLimit = commitLimit = allocBase; return (INT)(LONGLONG)allocBase; } VOID termEPAlloc( VOID ) /*++ Routine Description: Frees the memory used the the allocator. This should only be called before the process is terminated. Arguments: none Return Value: return-value - none --*/ { ULONGLONG ReserveSize = CpuEntryPointReserve; NtFreeVirtualMemory(NtCurrentProcess(), &allocBase, &ReserveSize, MEM_RELEASE ); } BOOLEAN commitMemory( LONG CommitDiff ) /*++ Routine Description: This routine tries to commit memory for use by the allocator. If there is no more memory left, is fails and returns with zero. Else it returns 1 for success. This is an internal function for use by the allocator only. Arguments: none Return Value: return-value - TRUE for success, FALSE for failure --*/ { LONG CommitSize; DWORD i; LONGLONG TempCommitDiff = CommitDiff; for (i=0; i (LONG)(ULONGLONG)CpuEntryPointReserve) { // // The commit would extend pase the reserve. Fail the // alloc, which will cause a cache/entrypoint flush. // return FALSE; } Status = NtAllocateVirtualMemory(NtCurrentProcess(), &commitLimit, 0, &TempCommitDiff, MEM_COMMIT, PAGE_READWRITE ); if (NT_SUCCESS(Status)) { // // Allocation succeeded. Move commitLimit up and return success // #if DBG RtlFillMemory(commitLimit, TempCommitDiff, EPTRASHVALUE); #endif commitLimit = (PVOID) ((ULONG)(ULONGLONG)commitLimit + TempCommitDiff); return TRUE; } // // No pages available. Sleep a bit and hope another thread frees a // page. // Timeout.QuadPart = (LONGLONG)CpuWaitForMemoryTime * -10000i64; NtDelayExecution(FALSE, &Timeout); } // // No pages available. Return failure. Caller will attempt to free // some pages and retry the EPAlloc call. return FALSE; } PVOID EPAlloc( DWORD cb ) /*++ Routine Description: This routine allocated memory for use by the entry point module. Arguments: cb - count of bytes to allocate from the entrypoint memory. Return Value: return-value - The memory allocated if succeeded, NULL otherwise --*/ { PVOID newAllocLimit, oldAllocLimit; LONG CommitDiff; CPUASSERTMSG(allocLimit == commitLimit || *(PBYTE)allocLimit == EPTRASHVALUE, "Entrypoint memory overrun"); // Calculate new allocation limit oldAllocLimit = allocLimit; newAllocLimit = (PVOID) ((ULONG)(ULONGLONG)oldAllocLimit + cb); // See if we need to commit more memory CommitDiff = (LONG)(ULONGLONG)newAllocLimit - (LONG)(ULONGLONG)commitLimit; if (CommitDiff > 0){ // Yes we do, so try to commit more memory if (!commitMemory(CommitDiff)){ // Cannot commit more memory, so return failure return NULL; } } allocLimit = newAllocLimit; return oldAllocLimit; } VOID EPFree( VOID ) /*++ Routine Description: This routine frees all entry point memory allocated so far Arguments: none Return Value: none --*/ { #if DBG // // Fill the committed space with a known value to make // debugging easier // RtlFillMemory(allocBase, (ULONG)(ULONGLONG)allocLimit-(ULONG)(ULONGLONG)allocBase, EPTRASHVALUE); #endif allocLimit = allocBase; }