266 lines
5.5 KiB
C
266 lines
5.5 KiB
C
/*++
|
|
|
|
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 <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#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<CpuMaxAllocRetries; ++i) {
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER Timeout;
|
|
|
|
//
|
|
// Try to allocate more memory
|
|
//
|
|
if ((LONG)(ULONGLONG)commitLimit + CommitDiff -(LONG)(ULONGLONG)allocBase > (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;
|
|
}
|