3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 ULONG AllocationCount
= 0;
26 VOID
VerifyHeap(VOID
);
27 VOID
DumpMemoryAllocMap(VOID
);
28 VOID
IncrementAllocationCount(VOID
);
29 VOID
DecrementAllocationCount(VOID
);
30 VOID
MemAllocTest(VOID
);
35 * Normally, we allocate whole pages. This is ofcourse wastefull for small
36 * allocations (a few bytes). So, for small allocations (smaller than a page)
37 * we sub-allocate. When the first small allocation is done, a page is
38 * requested. We keep a pointer to that page in SubAllocationPage. The alloc
39 * is satisfied by returning a pointer to the beginning of the page. We also
40 * keep track of how many bytes are still available in the page in SubAllocationRest.
41 * When the next small request comes in, we try to allocate it just after the
42 * memory previously allocated. If it won't fit, we allocate a new page and
43 * the whole process starts again.
44 * Note that suballocations are done back-to-back, there's no bookkeeping at all.
45 * That also means that we cannot really free suballocations. So, when a free is
46 * done and it is determined that this might be a free of a sub-allocation, we
47 * just no-op the free.
48 * Perhaps we should use the heap routines from ntdll here.
50 static PVOID SubAllocationPage
= NULL
;
51 static unsigned SubAllocationRest
= 0;
53 BOOLEAN AllocateFromEnd
= TRUE
;
55 VOID
MmChangeAllocationPolicy(BOOLEAN PolicyAllocatePagesFromEnd
)
57 AllocateFromEnd
= PolicyAllocatePagesFromEnd
;
60 PVOID
MmAllocateMemoryWithType(ULONG MemorySize
, TYPE_OF_MEMORY MemoryType
)
63 ULONG FirstFreePageFromEnd
;
68 DbgPrint((DPRINT_MEMORY
, "MmAllocateMemory() called for 0 bytes. Returning NULL.\n"));
69 UiMessageBoxCritical("Memory allocation failed: MmAllocateMemory() called for 0 bytes.");
73 MemorySize
= ROUND_UP(MemorySize
, 4);
74 if (MemorySize
<= SubAllocationRest
)
76 MemPointer
= (PVOID
)((ULONG_PTR
)SubAllocationPage
+ MM_PAGE_SIZE
- SubAllocationRest
);
77 SubAllocationRest
-= MemorySize
;
81 // Find out how many blocks it will take to
82 // satisfy this allocation
83 PagesNeeded
= ROUND_UP(MemorySize
, MM_PAGE_SIZE
) / MM_PAGE_SIZE
;
85 // If we don't have enough available mem
87 if (FreePagesInLookupTable
< PagesNeeded
)
89 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize
, AllocationCount
));
90 UiMessageBoxCritical("Memory allocation failed: out of memory.");
94 FirstFreePageFromEnd
= MmFindAvailablePages(PageLookupTableAddress
, TotalPagesInLookupTable
, PagesNeeded
, AllocateFromEnd
);
96 if (FirstFreePageFromEnd
== (ULONG
)-1)
98 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize
, AllocationCount
));
99 UiMessageBoxCritical("Memory allocation failed: out of memory.");
103 MmAllocatePagesInLookupTable(PageLookupTableAddress
, FirstFreePageFromEnd
, PagesNeeded
, MemoryType
);
105 FreePagesInLookupTable
-= PagesNeeded
;
106 MemPointer
= (PVOID
)(FirstFreePageFromEnd
* MM_PAGE_SIZE
);
108 if (MemorySize
< MM_PAGE_SIZE
)
110 SubAllocationPage
= MemPointer
;
111 SubAllocationRest
= MM_PAGE_SIZE
- MemorySize
;
116 IncrementAllocationCount();
117 DbgPrint((DPRINT_MEMORY
, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize
, PagesNeeded
, FirstFreePageFromEnd
, AllocationCount
));
118 DbgPrint((DPRINT_MEMORY
, "Memory allocation pointer: 0x%x\n", MemPointer
));
122 // Now return the pointer
126 PVOID
MmAllocateMemory(ULONG MemorySize
)
128 // Temporary forwarder...
129 return MmAllocateMemoryWithType(MemorySize
, LoaderOsloaderHeap
);
132 PVOID
MmAllocateMemoryAtAddress(ULONG MemorySize
, PVOID DesiredAddress
, TYPE_OF_MEMORY MemoryType
)
135 ULONG StartPageNumber
;
140 DbgPrint((DPRINT_MEMORY
, "MmAllocateMemoryAtAddress() called for 0 bytes. Returning NULL.\n"));
141 UiMessageBoxCritical("Memory allocation failed: MmAllocateMemoryAtAddress() called for 0 bytes.");
145 // Find out how many blocks it will take to
146 // satisfy this allocation
147 PagesNeeded
= ROUND_UP(MemorySize
, MM_PAGE_SIZE
) / MM_PAGE_SIZE
;
149 // Get the starting page number
150 StartPageNumber
= MmGetPageNumberFromAddress(DesiredAddress
);
152 // If we don't have enough available mem
154 if (FreePagesInLookupTable
< PagesNeeded
)
156 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
157 "Not enough free memory to allocate %d bytes (requesting %d pages but have only %d). "
158 "AllocationCount: %d\n", MemorySize
, PagesNeeded
, FreePagesInLookupTable
, AllocationCount
));
159 UiMessageBoxCritical("Memory allocation failed: out of memory.");
163 if (MmAreMemoryPagesAvailable(PageLookupTableAddress
, TotalPagesInLookupTable
, DesiredAddress
, PagesNeeded
) == FALSE
)
165 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
166 "Not enough free memory to allocate %d bytes at address %p. AllocationCount: %d\n",
167 MemorySize
, DesiredAddress
, AllocationCount
));
169 // Don't tell this to user since caller should try to alloc this memory
170 // at a different address
171 //UiMessageBoxCritical("Memory allocation failed: out of memory.");
175 MmAllocatePagesInLookupTable(PageLookupTableAddress
, StartPageNumber
, PagesNeeded
, MemoryType
);
177 FreePagesInLookupTable
-= PagesNeeded
;
178 MemPointer
= (PVOID
)(StartPageNumber
* MM_PAGE_SIZE
);
181 IncrementAllocationCount();
182 DbgPrint((DPRINT_MEMORY
, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize
, PagesNeeded
, StartPageNumber
, AllocationCount
));
183 DbgPrint((DPRINT_MEMORY
, "Memory allocation pointer: 0x%x\n", MemPointer
));
187 // Now return the pointer
191 PVOID
MmAllocateHighestMemoryBelowAddress(ULONG MemorySize
, PVOID DesiredAddress
, TYPE_OF_MEMORY MemoryType
)
194 ULONG FirstFreePageFromEnd
;
195 ULONG DesiredAddressPageNumber
;
200 DbgPrint((DPRINT_MEMORY
, "MmAllocateHighestMemoryBelowAddress() called for 0 bytes. Returning NULL.\n"));
201 UiMessageBoxCritical("Memory allocation failed: MmAllocateHighestMemoryBelowAddress() called for 0 bytes.");
205 // Find out how many blocks it will take to
206 // satisfy this allocation
207 PagesNeeded
= ROUND_UP(MemorySize
, MM_PAGE_SIZE
) / MM_PAGE_SIZE
;
209 // Get the page number for their desired address
210 DesiredAddressPageNumber
= (ULONG
)DesiredAddress
/ MM_PAGE_SIZE
;
212 // If we don't have enough available mem
214 if (FreePagesInLookupTable
< PagesNeeded
)
216 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize
, AllocationCount
));
217 UiMessageBoxCritical("Memory allocation failed: out of memory.");
221 FirstFreePageFromEnd
= MmFindAvailablePagesBeforePage(PageLookupTableAddress
, TotalPagesInLookupTable
, PagesNeeded
, DesiredAddressPageNumber
);
223 if (FirstFreePageFromEnd
== 0)
225 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize
, AllocationCount
));
226 UiMessageBoxCritical("Memory allocation failed: out of memory.");
230 MmAllocatePagesInLookupTable(PageLookupTableAddress
, FirstFreePageFromEnd
, PagesNeeded
, MemoryType
);
232 FreePagesInLookupTable
-= PagesNeeded
;
233 MemPointer
= (PVOID
)(FirstFreePageFromEnd
* MM_PAGE_SIZE
);
236 IncrementAllocationCount();
237 DbgPrint((DPRINT_MEMORY
, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize
, PagesNeeded
, FirstFreePageFromEnd
, AllocationCount
));
238 DbgPrint((DPRINT_MEMORY
, "Memory allocation pointer: 0x%x\n", MemPointer
));
242 // Now return the pointer
246 VOID
MmFreeMemory(PVOID MemoryPointer
)
251 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTableAddress
;
255 // Make sure we didn't get a bogus pointer
256 if (MemoryPointer
>= (PVOID
)(TotalPagesInLookupTable
* MM_PAGE_SIZE
))
258 BugCheck((DPRINT_MEMORY
, "Bogus memory pointer (0x%x) passed to MmFreeMemory()\n", MemoryPointer
));
262 // Find out the page number of the first
263 // page of memory they allocated
264 PageNumber
= MmGetPageNumberFromAddress(MemoryPointer
);
265 PageCount
= RealPageLookupTable
[PageNumber
].PageAllocationLength
;
268 // Make sure we didn't get a bogus pointer
269 if ((PageCount
< 1) || (PageCount
> (TotalPagesInLookupTable
- PageNumber
)))
271 BugCheck((DPRINT_MEMORY
, "Invalid page count in lookup table. PageLookupTable[%d].PageAllocationLength = %d\n", PageNumber
, RealPageLookupTable
[PageNumber
].PageAllocationLength
));
274 // Loop through our array check all the pages
275 // to make sure they are allocated with a length of 0
276 for (Idx
=PageNumber
+1; Idx
<(PageNumber
+ PageCount
); Idx
++)
278 if ((RealPageLookupTable
[Idx
].PageAllocated
== LoaderFree
) ||
279 (RealPageLookupTable
[Idx
].PageAllocationLength
!= 0))
281 BugCheck((DPRINT_MEMORY
, "Invalid page entry in lookup table, PageAllocated should = 1 and PageAllocationLength should = 0 because this is not the first block in the run. PageLookupTable[%d].PageAllocated = %d PageLookupTable[%d].PageAllocationLength = %d\n", PageNumber
, RealPageLookupTable
[PageNumber
].PageAllocated
, PageNumber
, RealPageLookupTable
[PageNumber
].PageAllocationLength
));
287 /* If this allocation is only a single page, it could be a sub-allocated page.
288 * Just don't free it */
294 // Loop through our array and mark all the
296 for (Idx
=PageNumber
; Idx
<(PageNumber
+ PageCount
); Idx
++)
298 RealPageLookupTable
[Idx
].PageAllocated
= LoaderFree
;
299 RealPageLookupTable
[Idx
].PageAllocationLength
= 0;
302 FreePagesInLookupTable
+= PageCount
;
305 DecrementAllocationCount();
306 DbgPrint((DPRINT_MEMORY
, "Freed %d pages of memory starting at page %d. AllocationCount: %d\n", PageCount
, PageNumber
, AllocationCount
));
311 PVOID
MmHeapAlloc(ULONG MemorySize
)
317 VOID
MmHeapFree(PVOID MemoryPointer
)
324 VOID
VerifyHeap(VOID
)
329 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTableAddress
;
331 if (DUMP_MEM_MAP_ON_VERIFY
)
333 DumpMemoryAllocMap();
336 // Loop through the array and verify that
337 // everything is kosher
338 for (Idx
=0; Idx
<TotalPagesInLookupTable
; Idx
++)
340 // Check if this block is allocated
341 if (RealPageLookupTable
[Idx
].PageAllocated
!= LoaderFree
)
343 // This is the first block in the run so it
344 // had better have a length that is within range
345 if ((RealPageLookupTable
[Idx
].PageAllocationLength
< 1) || (RealPageLookupTable
[Idx
].PageAllocationLength
> (TotalPagesInLookupTable
- Idx
)))
347 BugCheck((DPRINT_MEMORY
, "Allocation length out of range in heap table. PageLookupTable[Idx].PageAllocationLength = %d\n", RealPageLookupTable
[Idx
].PageAllocationLength
));
350 // Now go through and verify that the rest of
351 // this run has the blocks marked allocated
352 // with a length of zero but don't check the
353 // first one because we already did
354 Count
= RealPageLookupTable
[Idx
].PageAllocationLength
;
355 for (Idx2
=1; Idx2
<Count
; Idx2
++)
357 // Make sure it's allocated
358 if (RealPageLookupTable
[Idx
+ Idx2
].PageAllocated
== LoaderFree
)
360 BugCheck((DPRINT_MEMORY
, "Lookup table indicates hole in memory allocation. RealPageLookupTable[Idx + Idx2].PageAllocated == 0\n"));
363 // Make sure the length is zero
364 if (RealPageLookupTable
[Idx
+ Idx2
].PageAllocationLength
!= 0)
366 BugCheck((DPRINT_MEMORY
, "Allocation chain has non-zero value in non-first block in lookup table. RealPageLookupTable[Idx + Idx2].PageAllocationLength != 0\n"));
370 // Move on to the next run
375 // Nope, not allocated so make sure the length is zero
376 if (RealPageLookupTable
[Idx
].PageAllocationLength
!= 0)
378 BugCheck((DPRINT_MEMORY
, "Free block is start of memory allocation. RealPageLookupTable[Idx].PageAllocationLength != 0\n"));
384 VOID
DumpMemoryAllocMap(VOID
)
387 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTableAddress
;
389 DbgPrint((DPRINT_MEMORY
, "----------- Memory Allocation Bitmap -----------\n"));
391 for (Idx
=0; Idx
<TotalPagesInLookupTable
; Idx
++)
395 DbgPrint((DPRINT_MEMORY
, "\n"));
396 DbgPrint((DPRINT_MEMORY
, "%x:\t", (Idx
* MM_PAGE_SIZE
)));
398 else if ((Idx
% 4) == 0)
400 DbgPrint((DPRINT_MEMORY
, " "));
403 switch (RealPageLookupTable
[Idx
].PageAllocated
)
406 DbgPrint((DPRINT_MEMORY
, "*"));
409 DbgPrint((DPRINT_MEMORY
, "-"));
411 case LoaderLoadedProgram
:
412 DbgPrint((DPRINT_MEMORY
, "O"));
414 case LoaderFirmwareTemporary
:
415 DbgPrint((DPRINT_MEMORY
, "T"));
417 case LoaderFirmwarePermanent
:
418 DbgPrint((DPRINT_MEMORY
, "P"));
420 case LoaderOsloaderHeap
:
421 DbgPrint((DPRINT_MEMORY
, "H"));
423 case LoaderOsloaderStack
:
424 DbgPrint((DPRINT_MEMORY
, "S"));
426 case LoaderSystemCode
:
427 DbgPrint((DPRINT_MEMORY
, "K"));
430 DbgPrint((DPRINT_MEMORY
, "L"));
432 case LoaderBootDriver
:
433 DbgPrint((DPRINT_MEMORY
, "B"));
435 case LoaderStartupPcrPage
:
436 DbgPrint((DPRINT_MEMORY
, "G"));
438 case LoaderRegistryData
:
439 DbgPrint((DPRINT_MEMORY
, "R"));
441 case LoaderMemoryData
:
442 DbgPrint((DPRINT_MEMORY
, "M"));
445 DbgPrint((DPRINT_MEMORY
, "N"));
447 case LoaderSpecialMemory
:
448 DbgPrint((DPRINT_MEMORY
, "C"));
451 DbgPrint((DPRINT_MEMORY
, "?"));
456 DbgPrint((DPRINT_MEMORY
, "\n"));
459 VOID
IncrementAllocationCount(VOID
)
464 VOID
DecrementAllocationCount(VOID
)
469 VOID
MemAllocTest(VOID
)
477 MemPtr1
= MmAllocateMemory(4096);
478 printf("MemPtr1: 0x%x\n", (int)MemPtr1
);
480 MemPtr2
= MmAllocateMemory(4096);
481 printf("MemPtr2: 0x%x\n", (int)MemPtr2
);
483 MemPtr3
= MmAllocateMemory(4096);
484 printf("MemPtr3: 0x%x\n", (int)MemPtr3
);
485 DumpMemoryAllocMap();
489 MmFreeMemory(MemPtr2
);
492 MemPtr4
= MmAllocateMemory(2048);
493 printf("MemPtr4: 0x%x\n", (int)MemPtr4
);
495 MemPtr5
= MmAllocateMemory(4096);
496 printf("MemPtr5: 0x%x\n", (int)MemPtr5
);
501 ULONG
GetSystemMemorySize(VOID
)
503 return (TotalPagesInLookupTable
* MM_PAGE_SIZE
);
506 PPAGE_LOOKUP_TABLE_ITEM
MmGetMemoryMap(ULONG
*NoEntries
)
508 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTableAddress
;
510 *NoEntries
= TotalPagesInLookupTable
;
512 return RealPageLookupTable
;