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.
29 ULONG AllocationCount
= 0;
31 VOID
VerifyHeap(VOID
);
32 VOID
DumpMemoryAllocMap(VOID
);
33 VOID
IncrementAllocationCount(VOID
);
34 VOID
DecrementAllocationCount(VOID
);
35 VOID
MemAllocTest(VOID
);
40 * Normally, we allocate whole pages. This is ofcourse wastefull for small
41 * allocations (a few bytes). So, for small allocations (smaller than a page)
42 * we sub-allocate. When the first small allocation is done, a page is
43 * requested. We keep a pointer to that page in SubAllocationPage. The alloc
44 * is satisfied by returning a pointer to the beginning of the page. We also
45 * keep track of how many bytes are still available in the page in SubAllocationRest.
46 * When the next small request comes in, we try to allocate it just after the
47 * memory previously allocated. If it won't fit, we allocate a new page and
48 * the whole process starts again.
49 * Note that suballocations are done back-to-back, there's no bookkeeping at all.
50 * That also means that we cannot really free suballocations. So, when a free is
51 * done and it is determined that this might be a free of a sub-allocation, we
52 * just no-op the free.
53 * Perhaps we should use the heap routines from ntdll here.
55 static PVOID SubAllocationPage
= NULL
;
56 static unsigned SubAllocationRest
= 0;
58 BOOLEAN AllocateFromEnd
= TRUE
;
60 VOID
MmChangeAllocationPolicy(BOOLEAN PolicyAllocatePagesFromEnd
)
62 AllocateFromEnd
= PolicyAllocatePagesFromEnd
;
65 PVOID
MmAllocateMemory(ULONG MemorySize
)
68 ULONG FirstFreePageFromEnd
;
69 PVOID MemPointer
= NULL
;
73 DbgPrint((DPRINT_MEMORY
, "MmAllocateMemory() called for 0 bytes. Returning NULL.\n"));
74 UiMessageBoxCritical("Memory allocation failed: MmAllocateMemory() called for 0 bytes.");
78 MemorySize
= ROUND_UP(MemorySize
, 4);
79 if (MemorySize
<= SubAllocationRest
)
81 MemPointer
= (PVOID
)((ULONG_PTR
)SubAllocationPage
+ MM_PAGE_SIZE
- SubAllocationRest
);
82 SubAllocationRest
-= MemorySize
;
86 // Find out how many blocks it will take to
87 // satisfy this allocation
88 PagesNeeded
= ROUND_UP(MemorySize
, MM_PAGE_SIZE
) / MM_PAGE_SIZE
;
90 // If we don't have enough available mem
92 if (FreePagesInLookupTable
< PagesNeeded
)
96 printf("Allocating %d bytes directly ...\n", MemorySize
);
97 ptr
= ofw_claim(0,MemorySize
,MM_PAGE_SIZE
);
98 MemPointer
= (PVOID
)(REV(ptr
));
102 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed. Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize
, AllocationCount
));
103 UiMessageBoxCritical("Memory allocation failed: out of memory.");
111 FirstFreePageFromEnd
= MmFindAvailablePages(PageLookupTableAddress
, TotalPagesInLookupTable
, PagesNeeded
, AllocateFromEnd
);
113 if (FirstFreePageFromEnd
== (ULONG
)-1)
115 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize
, AllocationCount
));
116 UiMessageBoxCritical("Memory allocation failed: out of memory.");
120 MmAllocatePagesInLookupTable(PageLookupTableAddress
, FirstFreePageFromEnd
, PagesNeeded
);
122 FreePagesInLookupTable
-= PagesNeeded
;
123 MemPointer
= (PVOID
)(FirstFreePageFromEnd
* MM_PAGE_SIZE
);
125 if (MemorySize
< MM_PAGE_SIZE
)
127 SubAllocationPage
= MemPointer
;
128 SubAllocationRest
= MM_PAGE_SIZE
- MemorySize
;
133 IncrementAllocationCount();
134 DbgPrint((DPRINT_MEMORY
, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize
, PagesNeeded
, FirstFreePageFromEnd
, AllocationCount
));
135 DbgPrint((DPRINT_MEMORY
, "Memory allocation pointer: 0x%x\n", MemPointer
));
139 // Now return the pointer
143 PVOID
MmAllocateMemoryAtAddress(ULONG MemorySize
, PVOID DesiredAddress
)
146 ULONG StartPageNumber
;
151 DbgPrint((DPRINT_MEMORY
, "MmAllocateMemoryAtAddress() called for 0 bytes. Returning NULL.\n"));
152 UiMessageBoxCritical("Memory allocation failed: MmAllocateMemoryAtAddress() called for 0 bytes.");
156 // Find out how many blocks it will take to
157 // satisfy this allocation
158 PagesNeeded
= ROUND_UP(MemorySize
, MM_PAGE_SIZE
) / MM_PAGE_SIZE
;
160 // Get the starting page number
161 StartPageNumber
= MmGetPageNumberFromAddress(DesiredAddress
);
163 // If we don't have enough available mem
165 if (FreePagesInLookupTable
< PagesNeeded
)
167 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
168 "Not enough free memory to allocate %d bytes (requesting %d pages but have only %d). "
169 "AllocationCount: %d\n", MemorySize
, PagesNeeded
, FreePagesInLookupTable
, AllocationCount
));
170 UiMessageBoxCritical("Memory allocation failed: out of memory.");
174 if (MmAreMemoryPagesAvailable(PageLookupTableAddress
, TotalPagesInLookupTable
, DesiredAddress
, PagesNeeded
) == FALSE
)
176 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
177 "Not enough free memory to allocate %d bytes at address %p. AllocationCount: %d\n",
178 MemorySize
, DesiredAddress
, AllocationCount
));
180 // Don't tell this to user since caller should try to alloc this memory
181 // at a different address
182 //UiMessageBoxCritical("Memory allocation failed: out of memory.");
186 MmAllocatePagesInLookupTable(PageLookupTableAddress
, StartPageNumber
, PagesNeeded
);
188 FreePagesInLookupTable
-= PagesNeeded
;
189 MemPointer
= (PVOID
)(StartPageNumber
* MM_PAGE_SIZE
);
192 IncrementAllocationCount();
193 DbgPrint((DPRINT_MEMORY
, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize
, PagesNeeded
, StartPageNumber
, AllocationCount
));
194 DbgPrint((DPRINT_MEMORY
, "Memory allocation pointer: 0x%x\n", MemPointer
));
198 // Now return the pointer
202 PVOID
MmAllocateHighestMemoryBelowAddress(ULONG MemorySize
, PVOID DesiredAddress
)
205 ULONG FirstFreePageFromEnd
;
206 ULONG DesiredAddressPageNumber
;
211 DbgPrint((DPRINT_MEMORY
, "MmAllocateHighestMemoryBelowAddress() called for 0 bytes. Returning NULL.\n"));
212 UiMessageBoxCritical("Memory allocation failed: MmAllocateHighestMemoryBelowAddress() called for 0 bytes.");
216 // Find out how many blocks it will take to
217 // satisfy this allocation
218 PagesNeeded
= ROUND_UP(MemorySize
, MM_PAGE_SIZE
) / MM_PAGE_SIZE
;
220 // Get the page number for their desired address
221 DesiredAddressPageNumber
= (ULONG
)DesiredAddress
/ MM_PAGE_SIZE
;
223 // If we don't have enough available mem
225 if (FreePagesInLookupTable
< PagesNeeded
)
227 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize
, AllocationCount
));
228 UiMessageBoxCritical("Memory allocation failed: out of memory.");
232 FirstFreePageFromEnd
= MmFindAvailablePagesBeforePage(PageLookupTableAddress
, TotalPagesInLookupTable
, PagesNeeded
, DesiredAddressPageNumber
);
234 if (FirstFreePageFromEnd
== 0)
236 DbgPrint((DPRINT_MEMORY
, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize
, AllocationCount
));
237 UiMessageBoxCritical("Memory allocation failed: out of memory.");
241 MmAllocatePagesInLookupTable(PageLookupTableAddress
, FirstFreePageFromEnd
, PagesNeeded
);
243 FreePagesInLookupTable
-= PagesNeeded
;
244 MemPointer
= (PVOID
)(FirstFreePageFromEnd
* MM_PAGE_SIZE
);
247 IncrementAllocationCount();
248 DbgPrint((DPRINT_MEMORY
, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize
, PagesNeeded
, FirstFreePageFromEnd
, AllocationCount
));
249 DbgPrint((DPRINT_MEMORY
, "Memory allocation pointer: 0x%x\n", MemPointer
));
253 // Now return the pointer
257 VOID
MmFreeMemory(PVOID MemoryPointer
)
262 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTableAddress
;
266 // Make sure we didn't get a bogus pointer
267 if (MemoryPointer
>= (PVOID
)(TotalPagesInLookupTable
* MM_PAGE_SIZE
))
269 BugCheck((DPRINT_MEMORY
, "Bogus memory pointer (0x%x) passed to MmFreeMemory()\n", MemoryPointer
));
273 // Find out the page number of the first
274 // page of memory they allocated
275 PageNumber
= MmGetPageNumberFromAddress(MemoryPointer
);
276 PageCount
= RealPageLookupTable
[PageNumber
].PageAllocationLength
;
279 // Make sure we didn't get a bogus pointer
280 if ((PageCount
< 1) || (PageCount
> (TotalPagesInLookupTable
- PageNumber
)))
282 BugCheck((DPRINT_MEMORY
, "Invalid page count in lookup table. PageLookupTable[%d].PageAllocationLength = %d\n", PageNumber
, RealPageLookupTable
[PageNumber
].PageAllocationLength
));
285 // Loop through our array check all the pages
286 // to make sure they are allocated with a length of 0
287 for (Idx
=PageNumber
+1; Idx
<(PageNumber
+ PageCount
); Idx
++)
289 if ((RealPageLookupTable
[Idx
].PageAllocated
!= 1) ||
290 (RealPageLookupTable
[Idx
].PageAllocationLength
!= 0))
292 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
));
298 /* If this allocation is only a single page, it could be a sub-allocated page.
299 * Just don't free it */
305 // Loop through our array and mark all the
307 for (Idx
=PageNumber
; Idx
<(PageNumber
+ PageCount
); Idx
++)
309 RealPageLookupTable
[Idx
].PageAllocated
= 0;
310 RealPageLookupTable
[Idx
].PageAllocationLength
= 0;
313 FreePagesInLookupTable
+= PageCount
;
316 DecrementAllocationCount();
317 DbgPrint((DPRINT_MEMORY
, "Freed %d pages of memory starting at page %d. AllocationCount: %d\n", PageCount
, PageNumber
, AllocationCount
));
323 VOID
VerifyHeap(VOID
)
328 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTableAddress
;
330 if (DUMP_MEM_MAP_ON_VERIFY
)
332 DumpMemoryAllocMap();
335 // Loop through the array and verify that
336 // everything is kosher
337 for (Idx
=0; Idx
<TotalPagesInLookupTable
; Idx
++)
339 // Check if this block is allocated
340 if (RealPageLookupTable
[Idx
].PageAllocated
!= 0)
342 // This is the first block in the run so it
343 // had better have a length that is within range
344 if ((RealPageLookupTable
[Idx
].PageAllocationLength
< 1) || (RealPageLookupTable
[Idx
].PageAllocationLength
> (TotalPagesInLookupTable
- Idx
)))
346 BugCheck((DPRINT_MEMORY
, "Allocation length out of range in heap table. PageLookupTable[Idx].PageAllocationLength = %d\n", RealPageLookupTable
[Idx
].PageAllocationLength
));
349 // Now go through and verify that the rest of
350 // this run has the blocks marked allocated
351 // with a length of zero but don't check the
352 // first one because we already did
353 Count
= RealPageLookupTable
[Idx
].PageAllocationLength
;
354 for (Idx2
=1; Idx2
<Count
; Idx2
++)
356 // Make sure it's allocated
357 if (RealPageLookupTable
[Idx
+ Idx2
].PageAllocated
== 0)
359 BugCheck((DPRINT_MEMORY
, "Lookup table indicates hole in memory allocation. RealPageLookupTable[Idx + Idx2].PageAllocated == 0\n"));
362 // Make sure the length is zero
363 if (RealPageLookupTable
[Idx
+ Idx2
].PageAllocationLength
!= 0)
365 BugCheck((DPRINT_MEMORY
, "Allocation chain has non-zero value in non-first block in lookup table. RealPageLookupTable[Idx + Idx2].PageAllocationLength != 0\n"));
369 // Move on to the next run
374 // Nope, not allocated so make sure the length is zero
375 if (RealPageLookupTable
[Idx
].PageAllocationLength
!= 0)
377 BugCheck((DPRINT_MEMORY
, "Free block is start of memory allocation. RealPageLookupTable[Idx].PageAllocationLength != 0\n"));
383 VOID
DumpMemoryAllocMap(VOID
)
386 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTableAddress
;
388 DbgPrint((DPRINT_MEMORY
, "----------- Memory Allocation Bitmap -----------\n"));
390 for (Idx
=0; Idx
<TotalPagesInLookupTable
; Idx
++)
394 DbgPrint((DPRINT_MEMORY
, "\n"));
395 DbgPrint((DPRINT_MEMORY
, "%x:\t", (Idx
* MM_PAGE_SIZE
)));
397 else if ((Idx
% 4) == 0)
399 DbgPrint((DPRINT_MEMORY
, " "));
402 switch (RealPageLookupTable
[Idx
].PageAllocated
)
405 DbgPrint((DPRINT_MEMORY
, "*"));
408 DbgPrint((DPRINT_MEMORY
, "A"));
410 case BiosMemoryReserved
:
411 DbgPrint((DPRINT_MEMORY
, "R"));
413 case BiosMemoryAcpiReclaim
:
414 DbgPrint((DPRINT_MEMORY
, "M"));
416 case BiosMemoryAcpiNvs
:
417 DbgPrint((DPRINT_MEMORY
, "N"));
420 DbgPrint((DPRINT_MEMORY
, "X"));
425 DbgPrint((DPRINT_MEMORY
, "\n"));
428 VOID
IncrementAllocationCount(VOID
)
433 VOID
DecrementAllocationCount(VOID
)
438 VOID
MemAllocTest(VOID
)
446 MemPtr1
= MmAllocateMemory(4096);
447 printf("MemPtr1: 0x%x\n", (int)MemPtr1
);
449 MemPtr2
= MmAllocateMemory(4096);
450 printf("MemPtr2: 0x%x\n", (int)MemPtr2
);
452 MemPtr3
= MmAllocateMemory(4096);
453 printf("MemPtr3: 0x%x\n", (int)MemPtr3
);
454 DumpMemoryAllocMap();
458 MmFreeMemory(MemPtr2
);
461 MemPtr4
= MmAllocateMemory(2048);
462 printf("MemPtr4: 0x%x\n", (int)MemPtr4
);
464 MemPtr5
= MmAllocateMemory(4096);
465 printf("MemPtr5: 0x%x\n", (int)MemPtr5
);
470 ULONG
GetSystemMemorySize(VOID
)
472 return (TotalPagesInLookupTable
* MM_PAGE_SIZE
);
475 PPAGE_LOOKUP_TABLE_ITEM
MmGetMemoryMap(ULONG
*NoEntries
)
477 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTableAddress
;
479 *NoEntries
= TotalPagesInLookupTable
;
481 return RealPageLookupTable
;