bb7efaed4884f7b2f650f11b1e424654980de4fd
[reactos.git] / reactos / boot / freeldr / freeldr / mm / meminit.c
1 /*
2 * FreeLoader
3 * Copyright (C) 2006-2008 Aleksey Bragin <aleksey@reactos.org>
4 * Copyright (C) 2006-2009 Hervé Poussineau <hpoussin@reactos.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <freeldr.h>
22 #include <debug.h>
23
24 DBG_DEFAULT_CHANNEL(MEMORY);
25
26 #if DBG
27 typedef struct
28 {
29 MEMORY_TYPE Type;
30 PCSTR TypeString;
31 } FREELDR_MEMORY_TYPE, *PFREELDR_MEMORY_TYPE;
32
33 FREELDR_MEMORY_TYPE MemoryTypeArray[] =
34 {
35 { MemoryMaximum, "Unknown memory" },
36 { MemoryExceptionBlock, "Exception block" },
37 { MemorySystemBlock, "System block" },
38 { MemoryFree, "Free memory" },
39 { MemoryBad, "Bad memory" },
40 { MemoryLoadedProgram, "Loaded program" },
41 { MemoryFirmwareTemporary, "Firmware temporary" },
42 { MemoryFirmwarePermanent, "Firmware permanent" },
43 { MemoryFreeContiguous, "Free contiguous memory" },
44 { MemorySpecialMemory, "Special memory" },
45 };
46 ULONG MemoryTypeCount = sizeof(MemoryTypeArray) / sizeof(MemoryTypeArray[0]);
47 #endif
48
49 PVOID PageLookupTableAddress = NULL;
50 ULONG TotalPagesInLookupTable = 0;
51 ULONG FreePagesInLookupTable = 0;
52 ULONG LastFreePageHint = 0;
53 ULONG MmLowestPhysicalPage = 0xFFFFFFFF;
54 ULONG MmHighestPhysicalPage = 0;
55
56 extern ULONG_PTR MmHeapPointer;
57 extern ULONG_PTR MmHeapStart;
58
59 typedef struct
60 {
61 MEMORY_DESCRIPTOR m;
62 ULONG Index;
63 BOOLEAN GeneratedDescriptor;
64 } MEMORY_DESCRIPTOR_INT;
65 static const MEMORY_DESCRIPTOR_INT MemoryDescriptors[] =
66 {
67 #if defined (__i386__) || defined (_M_AMD64)
68 { { MemoryFirmwarePermanent, 0x00, 1 }, 0, }, // realmode int vectors
69 { { MemoryFirmwareTemporary, 0x01, 7 }, 1, }, // freeldr stack + cmdline
70 { { MemoryLoadedProgram, 0x08, 0x70 }, 2, }, // freeldr image (roughly max. 0x64 pages)
71 { { MemorySpecialMemory, 0x78, 8 }, 3, }, // prot mode stack. BIOSCALLBUFFER
72 { { MemoryFirmwareTemporary, 0x80, 0x10 }, 4, }, // File system read buffer. FILESYSBUFFER
73 { { MemoryFirmwareTemporary, 0x90, 0x10 }, 5, }, // Disk read buffer for int 13h. DISKREADBUFFER
74 { { MemoryFirmwarePermanent, 0xA0, 0x60 }, 6, }, // ROM / Video
75 { { MemorySpecialMemory, 0xFFF, 1 }, 7, }, // unusable memory
76 #elif __arm__ // This needs to be done per-platform specific way
77
78 #endif
79 };
80
81 static
82 VOID MmFixupSystemMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG* MapCount)
83 {
84 int Index;
85 int Index2;
86 ULONGLONG BaseAddressOffset;
87
88 // Loop through each entry in the array
89 for (Index=0; Index<*MapCount; Index++)
90 {
91 // Correct all the addresses to be aligned on page boundaries
92 BaseAddressOffset = ROUND_UP(BiosMemoryMap[Index].BaseAddress, MM_PAGE_SIZE) - BiosMemoryMap[Index].BaseAddress;
93 BiosMemoryMap[Index].BaseAddress += BaseAddressOffset;
94 if (BiosMemoryMap[Index].Length < BaseAddressOffset)
95 {
96 BiosMemoryMap[Index].Length = 0;
97 }
98 else
99 {
100 BiosMemoryMap[Index].Length -= BaseAddressOffset;
101 }
102 BiosMemoryMap[Index].Length = ROUND_DOWN(BiosMemoryMap[Index].Length, MM_PAGE_SIZE);
103
104 // If the entry type isn't usable then remove
105 // it from the memory map (this will help reduce
106 // the size of our lookup table)
107 // If the length is less than a full page then
108 // get rid of it also.
109 if (BiosMemoryMap[Index].Type != BiosMemoryUsable ||
110 BiosMemoryMap[Index].Length < MM_PAGE_SIZE)
111 {
112 // Slide every entry after this down one
113 for (Index2=Index; Index2<(*MapCount - 1); Index2++)
114 {
115 BiosMemoryMap[Index2] = BiosMemoryMap[Index2 + 1];
116 }
117 (*MapCount)--;
118 Index--;
119 }
120 }
121 }
122
123 const MEMORY_DESCRIPTOR*
124 ArcGetMemoryDescriptor(const MEMORY_DESCRIPTOR* Current)
125 {
126 MEMORY_DESCRIPTOR_INT* CurrentDescriptor;
127 PBIOS_MEMORY_MAP BiosMemoryMap;
128 static ULONG BiosMemoryMapEntryCount;
129 static MEMORY_DESCRIPTOR_INT BiosMemoryDescriptors[32];
130 static BOOLEAN MemoryMapInitialized = FALSE;
131 ULONG i, j;
132
133 //
134 // Check if it is the first time we're called
135 //
136 if (!MemoryMapInitialized)
137 {
138 //
139 // Get the machine generated memory map
140 //
141 BiosMemoryMap = MachVtbl.GetMemoryMap(&BiosMemoryMapEntryCount);
142
143 //
144 // Fix entries that are not page aligned
145 //
146 MmFixupSystemMemoryMap(BiosMemoryMap, &BiosMemoryMapEntryCount);
147
148 //
149 // Copy the entries to our structure
150 //
151 for (i = 0, j = 0; i < BiosMemoryMapEntryCount; i++)
152 {
153 //
154 // Is it suitable memory?
155 //
156 if (BiosMemoryMap[i].Type != BiosMemoryUsable)
157 {
158 //
159 // No. Process next descriptor
160 //
161 continue;
162 }
163
164 //
165 // Copy this memory descriptor
166 //
167 BiosMemoryDescriptors[j].m.MemoryType = MemoryFree;
168 BiosMemoryDescriptors[j].m.BasePage = (ULONG)(BiosMemoryMap[i].BaseAddress / MM_PAGE_SIZE);
169 BiosMemoryDescriptors[j].m.PageCount = (ULONG)(BiosMemoryMap[i].Length / MM_PAGE_SIZE);
170 BiosMemoryDescriptors[j].Index = j;
171 BiosMemoryDescriptors[j].GeneratedDescriptor = TRUE;
172 j++;
173 }
174
175 //
176 // Remember how much descriptors we found
177 //
178 BiosMemoryMapEntryCount = j;
179
180 //
181 // Mark memory map as already retrieved and initialized
182 //
183 MemoryMapInitialized = TRUE;
184 }
185
186 CurrentDescriptor = CONTAINING_RECORD(Current, MEMORY_DESCRIPTOR_INT, m);
187
188 if (Current == NULL)
189 {
190 //
191 // First descriptor requested
192 //
193 if (BiosMemoryMapEntryCount > 0)
194 {
195 //
196 // Return first generated memory descriptor
197 //
198 return &BiosMemoryDescriptors[0].m;
199 }
200 else if (sizeof(MemoryDescriptors) > 0)
201 {
202 //
203 // Return first fixed memory descriptor
204 //
205 return &MemoryDescriptors[0].m;
206 }
207 else
208 {
209 //
210 // Strange case, we have no memory descriptor
211 //
212 return NULL;
213 }
214 }
215 else if (CurrentDescriptor->GeneratedDescriptor)
216 {
217 //
218 // Current entry is a generated descriptor
219 //
220 if (CurrentDescriptor->Index + 1 < BiosMemoryMapEntryCount)
221 {
222 //
223 // Return next generated descriptor
224 //
225 return &BiosMemoryDescriptors[CurrentDescriptor->Index + 1].m;
226 }
227 else if (sizeof(MemoryDescriptors) > 0)
228 {
229 //
230 // Return first fixed memory descriptor
231 //
232 return &MemoryDescriptors[0].m;
233 }
234 else
235 {
236 //
237 // No fixed memory descriptor; end of memory map
238 //
239 return NULL;
240 }
241 }
242 else
243 {
244 //
245 // Current entry is a fixed descriptor
246 //
247 if (CurrentDescriptor->Index + 1 < sizeof(MemoryDescriptors) / sizeof(MemoryDescriptors[0]))
248 {
249 //
250 // Return next fixed descriptor
251 //
252 return &MemoryDescriptors[CurrentDescriptor->Index + 1].m;
253 }
254 else
255 {
256 //
257 // No more fixed memory descriptor; end of memory map
258 //
259 return NULL;
260 }
261 }
262 }
263
264
265 BOOLEAN MmInitializeMemoryManager(VOID)
266 {
267 #if DBG
268 const MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
269 #endif
270
271 TRACE("Initializing Memory Manager.\n");
272
273 #if DBG
274 // Dump the system memory map
275 TRACE("System Memory Map (Base Address, Length, Type):\n");
276 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
277 {
278 TRACE("%x\t %x\t %s\n",
279 MemoryDescriptor->BasePage * MM_PAGE_SIZE,
280 MemoryDescriptor->PageCount * MM_PAGE_SIZE,
281 MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
282 }
283 #endif
284
285 // Find address for the page lookup table
286 TotalPagesInLookupTable = MmGetAddressablePageCountIncludingHoles();
287 PageLookupTableAddress = MmFindLocationForPageLookupTable(TotalPagesInLookupTable);
288 LastFreePageHint = MmHighestPhysicalPage;
289
290 if (PageLookupTableAddress == 0)
291 {
292 // If we get here then we probably couldn't
293 // find a contiguous chunk of memory big
294 // enough to hold the page lookup table
295 printf("Error initializing memory manager!\n");
296 return FALSE;
297 }
298
299 // Initialize the page lookup table
300 MmInitPageLookupTable(PageLookupTableAddress, TotalPagesInLookupTable);
301 MmUpdateLastFreePageHint(PageLookupTableAddress, TotalPagesInLookupTable);
302
303 FreePagesInLookupTable = MmCountFreePagesInLookupTable(PageLookupTableAddress, TotalPagesInLookupTable);
304
305 MmInitializeHeap(PageLookupTableAddress);
306
307 TRACE("Memory Manager initialized. %d pages available.\n", FreePagesInLookupTable);
308 return TRUE;
309 }
310
311 #if DBG
312 PCSTR MmGetSystemMemoryMapTypeString(MEMORY_TYPE Type)
313 {
314 ULONG Index;
315
316 for (Index=1; Index<MemoryTypeCount; Index++)
317 {
318 if (MemoryTypeArray[Index].Type == Type)
319 {
320 return MemoryTypeArray[Index].TypeString;
321 }
322 }
323
324 return MemoryTypeArray[0].TypeString;
325 }
326 #endif
327
328 ULONG MmGetPageNumberFromAddress(PVOID Address)
329 {
330 return ((ULONG_PTR)Address) / MM_PAGE_SIZE;
331 }
332
333 ULONG MmGetAddressablePageCountIncludingHoles(VOID)
334 {
335 const MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
336 ULONG PageCount;
337
338 //
339 // Go through the whole memory map to get max address
340 //
341 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
342 {
343 //
344 // Check if we got a higher end page address
345 //
346 if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > MmHighestPhysicalPage)
347 {
348 //
349 // Yes, remember it if this is real memory
350 //
351 if (MemoryDescriptor->MemoryType == MemoryFree) MmHighestPhysicalPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount;
352 }
353
354 //
355 // Check if we got a higher (usable) start page address
356 //
357 if (MemoryDescriptor->BasePage < MmLowestPhysicalPage)
358 {
359 //
360 // Yes, remember it if this is real memory
361 //
362 if (MemoryDescriptor->MemoryType == MemoryFree) MmLowestPhysicalPage = MemoryDescriptor->BasePage;
363 }
364 }
365
366 TRACE("lo/hi %lx %lxn", MmLowestPhysicalPage, MmHighestPhysicalPage);
367 PageCount = MmHighestPhysicalPage - MmLowestPhysicalPage;
368 TRACE("MmGetAddressablePageCountIncludingHoles() returning 0x%x\n", PageCount);
369 return PageCount;
370 }
371
372 PVOID MmFindLocationForPageLookupTable(ULONG TotalPageCount)
373 {
374 const MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
375 ULONG PageLookupTableSize;
376 ULONG PageLookupTablePages;
377 ULONG PageLookupTableStartPage = 0;
378 PVOID PageLookupTableMemAddress = NULL;
379
380 //
381 // Calculate how much pages we need to keep the page lookup table
382 //
383 PageLookupTableSize = TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM);
384 PageLookupTablePages = PageLookupTableSize / MM_PAGE_SIZE;
385
386 //
387 // Search the highest memory block big enough to contain lookup table
388 //
389 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
390 {
391 //
392 // Is it suitable memory?
393 //
394 if (MemoryDescriptor->MemoryType != MemoryFree)
395 {
396 //
397 // No. Process next descriptor
398 //
399 continue;
400 }
401
402 //
403 // Is the block big enough?
404 //
405 if (MemoryDescriptor->PageCount < PageLookupTablePages)
406 {
407 //
408 // No. Process next descriptor
409 //
410 continue;
411 }
412
413 //
414 // Is it at a higher address than previous suitable address?
415 //
416 if (MemoryDescriptor->BasePage < PageLookupTableStartPage)
417 {
418 //
419 // No. Process next descriptor
420 //
421 continue;
422 }
423
424 //
425 // Can we use this address?
426 //
427 if (MemoryDescriptor->BasePage >= MM_MAX_PAGE)
428 {
429 //
430 // No. Process next descriptor
431 //
432 continue;
433 }
434
435 //
436 // Memory block is more suitable than the previous one
437 //
438 PageLookupTableStartPage = MemoryDescriptor->BasePage;
439 PageLookupTableMemAddress = (PVOID)((ULONG_PTR)
440 (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) * MM_PAGE_SIZE
441 - PageLookupTableSize);
442 }
443
444 TRACE("MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress);
445
446 return PageLookupTableMemAddress;
447 }
448
449 VOID MmInitPageLookupTable(PVOID PageLookupTable, ULONG TotalPageCount)
450 {
451 const MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
452 TYPE_OF_MEMORY MemoryMapPageAllocated;
453 ULONG PageLookupTableStartPage;
454 ULONG PageLookupTablePageCount;
455
456 TRACE("MmInitPageLookupTable()\n");
457
458 //
459 // Mark every page as allocated initially
460 // We will go through and mark pages again according to the memory map
461 // But this will mark any holes not described in the map as allocated
462 //
463 MmMarkPagesInLookupTable(PageLookupTable, MmLowestPhysicalPage, TotalPageCount, LoaderFirmwarePermanent);
464
465 //
466 // Parse the whole memory map
467 //
468 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
469 {
470 //
471 // Convert ARC memory type to loader memory type
472 //
473 switch (MemoryDescriptor->MemoryType)
474 {
475 case MemoryFree:
476 {
477 //
478 // Allocatable memory
479 //
480 MemoryMapPageAllocated = LoaderFree;
481 break;
482 }
483 case MemoryFirmwarePermanent:
484 {
485 //
486 // Firmware permanent memory
487 //
488 MemoryMapPageAllocated = LoaderFirmwarePermanent;
489 break;
490 }
491 case MemoryFirmwareTemporary:
492 {
493 //
494 // Firmware temporary memory
495 //
496 MemoryMapPageAllocated = LoaderFirmwareTemporary;
497 break;
498 }
499 case MemoryLoadedProgram:
500 {
501 //
502 // Bootloader code
503 //
504 MemoryMapPageAllocated = LoaderLoadedProgram;
505 break;
506 }
507 case MemorySpecialMemory:
508 {
509 //
510 // OS Loader Stack
511 //
512 MemoryMapPageAllocated = LoaderOsloaderStack;
513 break;
514 }
515 default:
516 {
517 //
518 // Put something sensible here, which won't be overwritten
519 //
520 MemoryMapPageAllocated = LoaderSpecialMemory;
521 break;
522 }
523 }
524
525 //
526 // Mark used pages in the lookup table
527 //
528 TRACE("Marking pages as type %d: StartPage: %d PageCount: %d\n", MemoryMapPageAllocated, MemoryDescriptor->BasePage, MemoryDescriptor->PageCount);
529 MmMarkPagesInLookupTable(PageLookupTable, MemoryDescriptor->BasePage, MemoryDescriptor->PageCount, MemoryMapPageAllocated);
530 }
531
532 //
533 // Mark the pages that the lookup table occupies as reserved
534 //
535 PageLookupTableStartPage = MmGetPageNumberFromAddress(PageLookupTable);
536 PageLookupTablePageCount = MmGetPageNumberFromAddress((PVOID)((ULONG_PTR)PageLookupTable + ROUND_UP(TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM), MM_PAGE_SIZE))) - PageLookupTableStartPage;
537 TRACE("Marking the page lookup table pages as reserved StartPage: %d PageCount: %d\n", PageLookupTableStartPage, PageLookupTablePageCount);
538 MmMarkPagesInLookupTable(PageLookupTable, PageLookupTableStartPage, PageLookupTablePageCount, LoaderFirmwareTemporary);
539 }
540
541 VOID MmMarkPagesInLookupTable(PVOID PageLookupTable, ULONG StartPage, ULONG PageCount, TYPE_OF_MEMORY PageAllocated)
542 {
543 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
544 ULONG Index;
545 TRACE("MmMarkPagesInLookupTable()\n");
546
547 StartPage -= MmLowestPhysicalPage;
548 for (Index=StartPage; Index<(StartPage+PageCount); Index++)
549 {
550 #if 0
551 if ((Index <= (StartPage + 16)) || (Index >= (StartPage+PageCount-16)))
552 {
553 TRACE("Index = %d StartPage = %d PageCount = %d\n", Index, StartPage, PageCount);
554 }
555 #endif
556 RealPageLookupTable[Index].PageAllocated = PageAllocated;
557 RealPageLookupTable[Index].PageAllocationLength = (PageAllocated != LoaderFree) ? 1 : 0;
558 }
559 TRACE("MmMarkPagesInLookupTable() Done\n");
560 }
561
562 VOID MmAllocatePagesInLookupTable(PVOID PageLookupTable, ULONG StartPage, ULONG PageCount, TYPE_OF_MEMORY MemoryType)
563 {
564 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
565 ULONG Index;
566
567 StartPage -= MmLowestPhysicalPage;
568 for (Index=StartPage; Index<(StartPage+PageCount); Index++)
569 {
570 RealPageLookupTable[Index].PageAllocated = MemoryType;
571 RealPageLookupTable[Index].PageAllocationLength = (Index == StartPage) ? PageCount : 0;
572 }
573 }
574
575 ULONG MmCountFreePagesInLookupTable(PVOID PageLookupTable, ULONG TotalPageCount)
576 {
577 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
578 ULONG Index;
579 ULONG FreePageCount;
580
581 FreePageCount = 0;
582 for (Index=0; Index<TotalPageCount; Index++)
583 {
584 if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
585 {
586 FreePageCount++;
587 }
588 }
589
590 return FreePageCount;
591 }
592
593 ULONG MmFindAvailablePages(PVOID PageLookupTable, ULONG TotalPageCount, ULONG PagesNeeded, BOOLEAN FromEnd)
594 {
595 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
596 ULONG AvailablePagesSoFar;
597 ULONG Index;
598
599 if (LastFreePageHint > TotalPageCount)
600 {
601 LastFreePageHint = TotalPageCount;
602 }
603
604 AvailablePagesSoFar = 0;
605 if (FromEnd)
606 {
607 /* Allocate "high" (from end) pages */
608 for (Index=LastFreePageHint-1; Index>0; Index--)
609 {
610 if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
611 {
612 AvailablePagesSoFar = 0;
613 continue;
614 }
615 else
616 {
617 AvailablePagesSoFar++;
618 }
619
620 if (AvailablePagesSoFar >= PagesNeeded)
621 {
622 return Index + MmLowestPhysicalPage;
623 }
624 }
625 }
626 else
627 {
628 TRACE("Alloc low memory, LastFreePageHint %d, TPC %d\n", LastFreePageHint, TotalPageCount);
629 /* Allocate "low" pages */
630 for (Index=1; Index < LastFreePageHint; Index++)
631 {
632 if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
633 {
634 AvailablePagesSoFar = 0;
635 continue;
636 }
637 else
638 {
639 AvailablePagesSoFar++;
640 }
641
642 if (AvailablePagesSoFar >= PagesNeeded)
643 {
644 return Index - AvailablePagesSoFar + 1 + MmLowestPhysicalPage;
645 }
646 }
647 }
648
649 return 0;
650 }
651
652 ULONG MmFindAvailablePagesBeforePage(PVOID PageLookupTable, ULONG TotalPageCount, ULONG PagesNeeded, ULONG LastPage)
653 {
654 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
655 ULONG AvailablePagesSoFar;
656 ULONG Index;
657
658 if (LastPage > TotalPageCount)
659 {
660 return MmFindAvailablePages(PageLookupTable, TotalPageCount, PagesNeeded, TRUE);
661 }
662
663 AvailablePagesSoFar = 0;
664 for (Index=LastPage-1; Index>0; Index--)
665 {
666 if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
667 {
668 AvailablePagesSoFar = 0;
669 continue;
670 }
671 else
672 {
673 AvailablePagesSoFar++;
674 }
675
676 if (AvailablePagesSoFar >= PagesNeeded)
677 {
678 return Index + MmLowestPhysicalPage;
679 }
680 }
681
682 return 0;
683 }
684
685 VOID MmUpdateLastFreePageHint(PVOID PageLookupTable, ULONG TotalPageCount)
686 {
687 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
688 ULONG Index;
689
690 for (Index=TotalPageCount-1; Index>0; Index--)
691 {
692 if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
693 {
694 LastFreePageHint = Index + 1 + MmLowestPhysicalPage;
695 break;
696 }
697 }
698 }
699
700 BOOLEAN MmAreMemoryPagesAvailable(PVOID PageLookupTable, ULONG TotalPageCount, PVOID PageAddress, ULONG PageCount)
701 {
702 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
703 ULONG StartPage;
704 ULONG Index;
705
706 StartPage = MmGetPageNumberFromAddress(PageAddress);
707 StartPage -= MmLowestPhysicalPage;
708
709 // Make sure they aren't trying to go past the
710 // end of availabe memory
711 if ((StartPage + PageCount) > TotalPageCount)
712 {
713 return FALSE;
714 }
715
716 for (Index=StartPage; Index<(StartPage + PageCount); Index++)
717 {
718 // If this page is allocated then there obviously isn't
719 // memory availabe so return FALSE
720 if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
721 {
722 return FALSE;
723 }
724 }
725
726 return TRUE;
727 }