windows-nt/Source/XPSP1/NT/base/wow64/mscpu/entrypt/epalloc.c
2020-09-26 16:20:57 +08:00

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;
}