📄 mm.c
字号:
/*
* FreeLoader
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <freeldr.h>
#include <debug.h>
ULONG AllocationCount = 0;
#ifdef DBG
VOID VerifyHeap(VOID);
VOID DumpMemoryAllocMap(VOID);
VOID IncrementAllocationCount(VOID);
VOID DecrementAllocationCount(VOID);
VOID MemAllocTest(VOID);
#endif // DBG
/*
* Hack alert
* Normally, we allocate whole pages. This is ofcourse wastefull for small
* allocations (a few bytes). So, for small allocations (smaller than a page)
* we sub-allocate. When the first small allocation is done, a page is
* requested. We keep a pointer to that page in SubAllocationPage. The alloc
* is satisfied by returning a pointer to the beginning of the page. We also
* keep track of how many bytes are still available in the page in SubAllocationRest.
* When the next small request comes in, we try to allocate it just after the
* memory previously allocated. If it won't fit, we allocate a new page and
* the whole process starts again.
* Note that suballocations are done back-to-back, there's no bookkeeping at all.
* That also means that we cannot really free suballocations. So, when a free is
* done and it is determined that this might be a free of a sub-allocation, we
* just no-op the free.
* Perhaps we should use the heap routines from ntdll here.
*/
static PVOID SubAllocationPage = NULL;
static unsigned SubAllocationRest = 0;
BOOLEAN AllocateFromEnd = TRUE;
VOID MmChangeAllocationPolicy(BOOLEAN PolicyAllocatePagesFromEnd)
{
AllocateFromEnd = PolicyAllocatePagesFromEnd;
}
PVOID MmAllocateMemory(ULONG MemorySize)
{
ULONG PagesNeeded;
ULONG FirstFreePageFromEnd;
PVOID MemPointer;
if (MemorySize == 0)
{
DbgPrint((DPRINT_MEMORY, "MmAllocateMemory() called for 0 bytes. Returning NULL.\n"));
UiMessageBoxCritical("Memory allocation failed: MmAllocateMemory() called for 0 bytes.");
return NULL;
}
MemorySize = ROUND_UP(MemorySize, 4);
if (MemorySize <= SubAllocationRest)
{
MemPointer = (PVOID)((ULONG_PTR)SubAllocationPage + MM_PAGE_SIZE - SubAllocationRest);
SubAllocationRest -= MemorySize;
return MemPointer;
}
// Find out how many blocks it will take to
// satisfy this allocation
PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
// If we don't have enough available mem
// then return NULL
if (FreePagesInLookupTable < PagesNeeded)
{
DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount));
UiMessageBoxCritical("Memory allocation failed: out of memory.");
return NULL;
}
FirstFreePageFromEnd = MmFindAvailablePages(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, AllocateFromEnd);
if (FirstFreePageFromEnd == (ULONG)-1)
{
DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount));
UiMessageBoxCritical("Memory allocation failed: out of memory.");
return NULL;
}
MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded);
FreePagesInLookupTable -= PagesNeeded;
MemPointer = (PVOID)(FirstFreePageFromEnd * MM_PAGE_SIZE);
if (MemorySize < MM_PAGE_SIZE)
{
SubAllocationPage = MemPointer;
SubAllocationRest = MM_PAGE_SIZE - MemorySize;
}
#ifdef DBG
IncrementAllocationCount();
DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, FirstFreePageFromEnd, AllocationCount));
DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer));
//VerifyHeap();
#endif // DBG
// Now return the pointer
return MemPointer;
}
PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress)
{
ULONG PagesNeeded;
ULONG StartPageNumber;
PVOID MemPointer;
if (MemorySize == 0)
{
DbgPrint((DPRINT_MEMORY, "MmAllocateMemoryAtAddress() called for 0 bytes. Returning NULL.\n"));
UiMessageBoxCritical("Memory allocation failed: MmAllocateMemoryAtAddress() called for 0 bytes.");
return NULL;
}
// Find out how many blocks it will take to
// satisfy this allocation
PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
// Get the starting page number
StartPageNumber = MmGetPageNumberFromAddress(DesiredAddress);
// If we don't have enough available mem
// then return NULL
if (FreePagesInLookupTable < PagesNeeded)
{
DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
"Not enough free memory to allocate %d bytes (requesting %d pages but have only %d). "
"AllocationCount: %d\n", MemorySize, PagesNeeded, FreePagesInLookupTable, AllocationCount));
UiMessageBoxCritical("Memory allocation failed: out of memory.");
return NULL;
}
if (MmAreMemoryPagesAvailable(PageLookupTableAddress, TotalPagesInLookupTable, DesiredAddress, PagesNeeded) == FALSE)
{
DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
"Not enough free memory to allocate %d bytes at address %p. AllocationCount: %d\n",
MemorySize, DesiredAddress, AllocationCount));
// Don't tell this to user since caller should try to alloc this memory
// at a different address
//UiMessageBoxCritical("Memory allocation failed: out of memory.");
return NULL;
}
MmAllocatePagesInLookupTable(PageLookupTableAddress, StartPageNumber, PagesNeeded);
FreePagesInLookupTable -= PagesNeeded;
MemPointer = (PVOID)(StartPageNumber * MM_PAGE_SIZE);
#ifdef DBG
IncrementAllocationCount();
DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, StartPageNumber, AllocationCount));
DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer));
//VerifyHeap();
#endif // DBG
// Now return the pointer
return MemPointer;
}
PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress)
{
ULONG PagesNeeded;
ULONG FirstFreePageFromEnd;
ULONG DesiredAddressPageNumber;
PVOID MemPointer;
if (MemorySize == 0)
{
DbgPrint((DPRINT_MEMORY, "MmAllocateHighestMemoryBelowAddress() called for 0 bytes. Returning NULL.\n"));
UiMessageBoxCritical("Memory allocation failed: MmAllocateHighestMemoryBelowAddress() called for 0 bytes.");
return NULL;
}
// Find out how many blocks it will take to
// satisfy this allocation
PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
// Get the page number for their desired address
DesiredAddressPageNumber = (ULONG)DesiredAddress / MM_PAGE_SIZE;
// If we don't have enough available mem
// then return NULL
if (FreePagesInLookupTable < PagesNeeded)
{
DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount));
UiMessageBoxCritical("Memory allocation failed: out of memory.");
return NULL;
}
FirstFreePageFromEnd = MmFindAvailablePagesBeforePage(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, DesiredAddressPageNumber);
if (FirstFreePageFromEnd == 0)
{
DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount));
UiMessageBoxCritical("Memory allocation failed: out of memory.");
return NULL;
}
MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded);
FreePagesInLookupTable -= PagesNeeded;
MemPointer = (PVOID)(FirstFreePageFromEnd * MM_PAGE_SIZE);
#ifdef DBG
IncrementAllocationCount();
DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, FirstFreePageFromEnd, AllocationCount));
DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer));
//VerifyHeap();
#endif // DBG
// Now return the pointer
return MemPointer;
}
VOID MmFreeMemory(PVOID MemoryPointer)
{
ULONG PageNumber;
ULONG PageCount;
ULONG Idx;
PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
#ifdef DBG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -