xref: /reactos/boot/freeldr/freeldr/lib/mm/meminit.c (revision ccef43f3)
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 
23 #include <debug.h>
24 DBG_DEFAULT_CHANNEL(MEMORY);
25 
26 PVOID    PageLookupTableAddress = NULL;
27 PFN_NUMBER TotalPagesInLookupTable = 0;
28 PFN_NUMBER FreePagesInLookupTable = 0;
29 PFN_NUMBER LastFreePageHint = 0;
30 PFN_NUMBER MmLowestPhysicalPage = 0xFFFFFFFF;
31 PFN_NUMBER MmHighestPhysicalPage = 0;
32 
33 PFREELDR_MEMORY_DESCRIPTOR BiosMemoryMap;
34 ULONG BiosMemoryMapEntryCount;
35 SIZE_T FrLdrImageSize;
36 
37 #if DBG
38 typedef struct
39 {
40     TYPE_OF_MEMORY Type;
41     PCSTR TypeString;
42 } FREELDR_MEMORY_TYPE, *PFREELDR_MEMORY_TYPE;
43 
44 FREELDR_MEMORY_TYPE MemoryTypeArray[] =
45 {
46     { LoaderMaximum, "Unknown memory" },
47     { LoaderFree, "Free memory" },
48     { LoaderBad, "Bad memory" },
49     { LoaderLoadedProgram, "LoadedProgram" },
50     { LoaderFirmwareTemporary, "FirmwareTemporary" },
51     { LoaderFirmwarePermanent, "FirmwarePermanent" },
52     { LoaderOsloaderHeap, "OsloaderHeap" },
53     { LoaderOsloaderStack, "OsloaderStack" },
54     { LoaderSystemCode, "SystemCode" },
55     { LoaderHalCode, "HalCode" },
56     { LoaderBootDriver, "BootDriver" },
57     { LoaderRegistryData, "RegistryData" },
58     { LoaderMemoryData, "MemoryData" },
59     { LoaderNlsData, "NlsData" },
60     { LoaderSpecialMemory, "SpecialMemory" },
61     { LoaderReserve, "Reserve" },
62 };
63 ULONG MemoryTypeCount = sizeof(MemoryTypeArray) / sizeof(MemoryTypeArray[0]);
64 
65 PCSTR
66 MmGetSystemMemoryMapTypeString(
67     TYPE_OF_MEMORY Type)
68 {
69     ULONG Index;
70 
71     for (Index = 1; Index < MemoryTypeCount; Index++)
72     {
73         if (MemoryTypeArray[Index].Type == Type)
74         {
75             return MemoryTypeArray[Index].TypeString;
76         }
77     }
78 
79     return MemoryTypeArray[0].TypeString;
80 }
81 
82 VOID
83 DbgDumpMemoryMap(
84     PFREELDR_MEMORY_DESCRIPTOR List)
85 {
86     ULONG i;
87 
88     DbgPrint("Dumping Memory map:\n");
89     for (i = 0; List[i].PageCount != 0; i++)
90     {
91         DbgPrint("%02d %08x - %08x: %s\n",
92                  i,
93                  List[i].BasePage * PAGE_SIZE,
94                  (List[i].BasePage + List[i].PageCount) * PAGE_SIZE,
95                  MmGetSystemMemoryMapTypeString(List[i].MemoryType));
96     }
97     DbgPrint("\n");
98 }
99 #endif
100 
101 ULONG
102 AddMemoryDescriptor(
103     IN OUT PFREELDR_MEMORY_DESCRIPTOR List,
104     IN ULONG MaxCount,
105     IN PFN_NUMBER BasePage,
106     IN PFN_NUMBER PageCount,
107     IN TYPE_OF_MEMORY MemoryType)
108 {
109     ULONG Index, DescriptCount;
110     PFN_NUMBER EndPage;
111     TRACE("AddMemoryDescriptor(0x%Ix, 0x%Ix, %u)\n",
112           BasePage, PageCount, MemoryType);
113 
114     EndPage = BasePage + PageCount;
115 
116     /* Skip over all descriptor below the new range */
117     Index = 0;
118     while ((List[Index].PageCount != 0) &&
119            ((List[Index].BasePage + List[Index].PageCount) <= BasePage))
120     {
121         Index++;
122     }
123 
124     /* Count the descriptors */
125     DescriptCount = Index;
126     while (List[DescriptCount].PageCount != 0)
127     {
128         DescriptCount++;
129     }
130 
131     /* Check if the existing range conflicts with the new range */
132     while ((List[Index].PageCount != 0) &&
133            (List[Index].BasePage < EndPage))
134     {
135         TRACE("AddMemoryDescriptor conflict @%lu: new=[%lx:%lx], existing=[%lx,%lx]\n",
136               Index, BasePage, PageCount, List[Index].BasePage, List[Index].PageCount);
137 
138         /*
139          * We have 4 overlapping cases:
140          *
141          * Case              (a)       (b)       (c)       (d)
142          * Existing range  |---|     |-----|    |---|      |---|
143          * New range         |---|    |---|    |-----|   |---|
144          *
145          */
146 
147         /* Check if the existing range starts before the new range (a)/(b) */
148         if (List[Index].BasePage < BasePage)
149         {
150             /* Check if the existing range extends beyond the new range (b) */
151             if (List[Index].BasePage + List[Index].PageCount > EndPage)
152             {
153                 /* Split the descriptor */
154                 RtlMoveMemory(&List[Index + 1],
155                               &List[Index],
156                               (DescriptCount - Index) * sizeof(List[0]));
157                 List[Index + 1].BasePage = EndPage;
158                 List[Index + 1].PageCount = List[Index].BasePage +
159                                             List[Index].PageCount -
160                                             List[Index + 1].BasePage;
161                 List[Index].PageCount = BasePage - List[Index].BasePage;
162                 Index++;
163                 DescriptCount++;
164                 break;
165             }
166             else
167             {
168                 /* Crop the existing range and continue with the next range */
169                 List[Index].PageCount = BasePage - List[Index].BasePage;
170                 Index++;
171             }
172         }
173         /* Check if the existing range is fully covered by the new range (c) */
174         else if ((List[Index].BasePage + List[Index].PageCount) <=
175                  EndPage)
176         {
177             /* Delete this descriptor */
178             RtlMoveMemory(&List[Index],
179                           &List[Index + 1],
180                           (DescriptCount - Index) * sizeof(List[0]));
181             DescriptCount--;
182         }
183         /* Otherwise the existing range ends after the new range (d) */
184         else
185         {
186             /* Crop the existing range at the start and bail out */
187             List[Index].PageCount -= EndPage - List[Index].BasePage;
188             List[Index].BasePage = EndPage;
189             break;
190         }
191     }
192 
193     /* Make sure we can still add a new descriptor */
194     if (DescriptCount >= MaxCount)
195     {
196         FrLdrBugCheckWithMessage(
197             MEMORY_INIT_FAILURE,
198             __FILE__,
199             __LINE__,
200             "Ran out of static memory descriptors!");
201     }
202 
203     /* Insert the new descriptor */
204     if (Index < DescriptCount)
205     {
206         RtlMoveMemory(&List[Index + 1],
207                       &List[Index],
208                       (DescriptCount - Index) * sizeof(List[0]));
209     }
210 
211     List[Index].BasePage = BasePage;
212     List[Index].PageCount = PageCount;
213     List[Index].MemoryType = MemoryType;
214     DescriptCount++;
215 
216 #if 0 // only enable on demand!
217     DbgDumpMemoryMap(List);
218 #endif
219     return DescriptCount;
220 }
221 
222 const FREELDR_MEMORY_DESCRIPTOR*
223 ArcGetMemoryDescriptor(const FREELDR_MEMORY_DESCRIPTOR* Current)
224 {
225     if (Current == NULL)
226     {
227         return BiosMemoryMap;
228     }
229     else
230     {
231         Current++;
232         if (Current->PageCount == 0) return NULL;
233         return Current;
234     }
235 }
236 
237 static
238 VOID
239 MmCheckFreeldrImageFile(VOID)
240 {
241 #ifndef UEFIBOOT
242     PIMAGE_NT_HEADERS NtHeaders;
243     PIMAGE_FILE_HEADER FileHeader;
244     PIMAGE_OPTIONAL_HEADER OptionalHeader;
245 
246     /* Get the NT headers */
247     NtHeaders = RtlImageNtHeader(&__ImageBase);
248     if (!NtHeaders)
249     {
250         ERR("Could not get NtHeaders!\n");
251         FrLdrBugCheckWithMessage(
252             FREELDR_IMAGE_CORRUPTION,
253             __FILE__,
254             __LINE__,
255             "Could not get NtHeaders!\n");
256     }
257 
258     /* Check the file header */
259     FileHeader = &NtHeaders->FileHeader;
260     if ((FileHeader->Machine != IMAGE_FILE_MACHINE_NATIVE) ||
261         (FileHeader->NumberOfSections != FREELDR_SECTION_COUNT) ||
262         (FileHeader->PointerToSymbolTable != 0) ||  // Symbols stripped
263         (FileHeader->NumberOfSymbols != 0) ||       //    ""      ""
264         (FileHeader->SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)))
265     {
266         ERR("FreeLdr FileHeader is invalid.\n");
267         FrLdrBugCheckWithMessage(
268             FREELDR_IMAGE_CORRUPTION,
269             __FILE__,
270             __LINE__,
271             "FreeLdr FileHeader is invalid.\n"
272             "Machine == 0x%lx, expected 0x%lx\n"
273             "NumberOfSections == 0x%lx, expected 0x%lx\n"
274             "PointerToSymbolTable == 0x%lx, expected 0\n"
275             "NumberOfSymbols == 0x%lx, expected 0\n"
276             "SizeOfOptionalHeader == 0x%lx, expected 0x%lx\n",
277             FileHeader->Machine, IMAGE_FILE_MACHINE_NATIVE,
278             FileHeader->NumberOfSections, FREELDR_SECTION_COUNT,
279             FileHeader->PointerToSymbolTable,
280             FileHeader->NumberOfSymbols,
281             FileHeader->SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER));
282     }
283 
284     /* Check the optional header */
285     OptionalHeader = &NtHeaders->OptionalHeader;
286     if ((OptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) ||
287         (OptionalHeader->Subsystem != IMAGE_SUBSYSTEM_NATIVE) ||
288         (OptionalHeader->ImageBase != FREELDR_PE_BASE) ||
289         (OptionalHeader->SizeOfImage > MAX_FREELDR_PE_SIZE) ||
290         (OptionalHeader->SectionAlignment != OptionalHeader->FileAlignment))
291     {
292         ERR("FreeLdr OptionalHeader is invalid.\n");
293         FrLdrBugCheckWithMessage(
294             FREELDR_IMAGE_CORRUPTION,
295             __FILE__,
296             __LINE__,
297             "FreeLdr OptionalHeader is invalid.\n"
298             "Magic == 0x%lx, expected 0x%lx\n"
299             "Subsystem == 0x%lx, expected 1 (native)\n"
300             "ImageBase == 0x%lx, expected 0x%lx\n"
301             "SizeOfImage == 0x%lx, maximum 0x%lx\n"
302             "SectionAlignment 0x%lx doesn't match FileAlignment 0x%lx\n",
303             OptionalHeader->Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC,
304             OptionalHeader->Subsystem,
305             OptionalHeader->ImageBase, FREELDR_PE_BASE,
306             OptionalHeader->SizeOfImage, MAX_FREELDR_PE_SIZE,
307             OptionalHeader->SectionAlignment, OptionalHeader->FileAlignment);
308     }
309 
310     /* Calculate the full image size */
311     FrLdrImageSize = (ULONG_PTR)&__ImageBase + OptionalHeader->SizeOfImage - FREELDR_BASE;
312 #endif
313 }
314 
315 BOOLEAN MmInitializeMemoryManager(VOID)
316 {
317 #if DBG
318     const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
319 #endif
320 
321     TRACE("Initializing Memory Manager.\n");
322 
323     /* Check the freeldr binary */
324     MmCheckFreeldrImageFile();
325 
326     BiosMemoryMap = MachVtbl.GetMemoryMap(&BiosMemoryMapEntryCount);
327 
328 #if DBG
329     // Dump the system memory map
330     TRACE("System Memory Map (Base Address, Length, Type):\n");
331     while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
332     {
333         TRACE("%x\t %x\t %s\n",
334             MemoryDescriptor->BasePage * MM_PAGE_SIZE,
335             MemoryDescriptor->PageCount * MM_PAGE_SIZE,
336             MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
337     }
338 #endif
339 
340     // Find address for the page lookup table
341     TotalPagesInLookupTable = MmGetAddressablePageCountIncludingHoles();
342     PageLookupTableAddress = MmFindLocationForPageLookupTable(TotalPagesInLookupTable);
343     LastFreePageHint = MmHighestPhysicalPage;
344 
345     if (PageLookupTableAddress == 0)
346     {
347         // If we get here then we probably couldn't
348         // find a contiguous chunk of memory big
349         // enough to hold the page lookup table
350         printf("Error initializing memory manager!\n");
351         return FALSE;
352     }
353 
354     // Initialize the page lookup table
355     MmInitPageLookupTable(PageLookupTableAddress, TotalPagesInLookupTable);
356 
357     MmUpdateLastFreePageHint(PageLookupTableAddress, TotalPagesInLookupTable);
358 
359     FreePagesInLookupTable = MmCountFreePagesInLookupTable(PageLookupTableAddress,
360                                                         TotalPagesInLookupTable);
361 
362     MmInitializeHeap(PageLookupTableAddress);
363 
364     TRACE("Memory Manager initialized. 0x%x pages available.\n", FreePagesInLookupTable);
365 
366 
367     return TRUE;
368 }
369 
370 
371 PFN_NUMBER MmGetPageNumberFromAddress(PVOID Address)
372 {
373     return ((ULONG_PTR)Address) / MM_PAGE_SIZE;
374 }
375 
376 PFN_NUMBER MmGetAddressablePageCountIncludingHoles(VOID)
377 {
378     const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
379     PFN_NUMBER PageCount;
380 
381     //
382     // Go through the whole memory map to get max address
383     //
384     while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
385     {
386         //
387         // Check if we got a higher end page address
388         //
389         if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > MmHighestPhysicalPage)
390         {
391             //
392             // Yes, remember it if this is real memory
393             //
394             if (MemoryDescriptor->MemoryType == LoaderFree)
395                 MmHighestPhysicalPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount;
396         }
397 
398         //
399         // Check if we got a higher (usable) start page address
400         //
401         if (MemoryDescriptor->BasePage < MmLowestPhysicalPage)
402         {
403             //
404             // Yes, remember it if this is real memory
405             //
406             MmLowestPhysicalPage = MemoryDescriptor->BasePage;
407         }
408     }
409 
410     TRACE("lo/hi %lx %lx\n", MmLowestPhysicalPage, MmHighestPhysicalPage);
411     PageCount = MmHighestPhysicalPage - MmLowestPhysicalPage;
412     TRACE("MmGetAddressablePageCountIncludingHoles() returning 0x%x\n", PageCount);
413     return PageCount;
414 }
415 
416 PVOID MmFindLocationForPageLookupTable(PFN_NUMBER TotalPageCount)
417 {
418     const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
419     SIZE_T PageLookupTableSize;
420     PFN_NUMBER RequiredPages;
421     PFN_NUMBER CandidateBasePage = 0;
422     PFN_NUMBER CandidatePageCount;
423     PFN_NUMBER PageLookupTableEndPage;
424     PVOID PageLookupTableMemAddress = NULL;
425 
426     // Calculate how much pages we need to keep the page lookup table
427     PageLookupTableSize = TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM);
428     RequiredPages = PageLookupTableSize / MM_PAGE_SIZE;
429 
430     // Search the highest memory block big enough to contain lookup table
431     while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
432     {
433         // Continue, if memory is not free
434         if (MemoryDescriptor->MemoryType != LoaderFree) continue;
435 
436         // Continue, if the block is not big enough
437         if (MemoryDescriptor->PageCount < RequiredPages) continue;
438 
439         // Continue, if it is not at a higher address than previous address
440         if (MemoryDescriptor->BasePage < CandidateBasePage) continue;
441 
442         // Continue, if the address is too high
443         if (MemoryDescriptor->BasePage + RequiredPages >= MM_MAX_PAGE_LOADER) continue;
444 
445         // Memory block is more suitable than the previous one
446         CandidateBasePage = MemoryDescriptor->BasePage;
447         CandidatePageCount = MemoryDescriptor->PageCount;
448     }
449 
450     // Calculate the end address for the lookup table
451     PageLookupTableEndPage = min(CandidateBasePage + CandidatePageCount,
452                                  MM_MAX_PAGE_LOADER);
453 
454     // Calculate the virtual address
455     PageLookupTableMemAddress = (PVOID)((PageLookupTableEndPage * PAGE_SIZE)
456                                         - PageLookupTableSize);
457 
458     TRACE("MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress);
459 
460     return PageLookupTableMemAddress;
461 }
462 
463 VOID MmInitPageLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount)
464 {
465     const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
466     PFN_NUMBER PageLookupTableStartPage;
467     PFN_NUMBER PageLookupTablePageCount;
468 
469     TRACE("MmInitPageLookupTable()\n");
470 
471     // Mark every page as allocated initially
472     // We will go through and mark pages again according to the memory map
473     // But this will mark any holes not described in the map as allocated
474     MmMarkPagesInLookupTable(PageLookupTable, MmLowestPhysicalPage, TotalPageCount, LoaderFirmwarePermanent);
475 
476     // Parse the whole memory map
477     while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
478     {
479         // Mark used pages in the lookup table
480 
481         if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount <= TotalPageCount)
482         {
483             TRACE("Marking pages 0x%lx-0x%lx as type %s\n",
484                   MemoryDescriptor->BasePage,
485                   MemoryDescriptor->BasePage + MemoryDescriptor->PageCount,
486                   MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
487             MmMarkPagesInLookupTable(PageLookupTable,
488                                      MemoryDescriptor->BasePage,
489                                      MemoryDescriptor->PageCount,
490                                      MemoryDescriptor->MemoryType);
491         }
492         else
493             TRACE("Ignoring pages 0x%lx-0x%lx (%s)\n",
494                   MemoryDescriptor->BasePage,
495                   MemoryDescriptor->BasePage + MemoryDescriptor->PageCount,
496                   MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
497     }
498 
499     // Mark the pages that the lookup table occupies as reserved
500     PageLookupTableStartPage = MmGetPageNumberFromAddress(PageLookupTable);
501     PageLookupTablePageCount = MmGetPageNumberFromAddress((PVOID)((ULONG_PTR)PageLookupTable + ROUND_UP(TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM), MM_PAGE_SIZE))) - PageLookupTableStartPage;
502     TRACE("Marking the page lookup table pages as reserved StartPage: 0x%x PageCount: 0x%x\n", PageLookupTableStartPage, PageLookupTablePageCount);
503     MmMarkPagesInLookupTable(PageLookupTable, PageLookupTableStartPage, PageLookupTablePageCount, LoaderFirmwareTemporary);
504 }
505 
506 VOID MmMarkPagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY PageAllocated)
507 {
508     PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
509     PFN_NUMBER Index;
510     TRACE("MmMarkPagesInLookupTable()\n");
511 
512     /* Validate the range */
513     if ((StartPage < MmLowestPhysicalPage) ||
514         ((StartPage + PageCount - 1) > MmHighestPhysicalPage))
515     {
516         ERR("Memory (0x%lx:0x%lx) outside of lookup table! Valid range: 0x%lx-0x%lx.\n",
517             StartPage, PageCount, MmLowestPhysicalPage, MmHighestPhysicalPage);
518         return;
519     }
520 
521     StartPage -= MmLowestPhysicalPage;
522     for (Index=StartPage; Index<(StartPage+PageCount); Index++)
523     {
524 #if 0
525         if ((Index <= (StartPage + 16)) || (Index >= (StartPage+PageCount-16)))
526         {
527             TRACE("Index = 0x%x StartPage = 0x%x PageCount = 0x%x\n", Index, StartPage, PageCount);
528         }
529 #endif
530         RealPageLookupTable[Index].PageAllocated = PageAllocated;
531         RealPageLookupTable[Index].PageAllocationLength = (PageAllocated != LoaderFree) ? 1 : 0;
532     }
533     TRACE("MmMarkPagesInLookupTable() Done\n");
534 }
535 
536 VOID MmAllocatePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY MemoryType)
537 {
538     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
539     PFN_NUMBER                    Index;
540 
541     StartPage -= MmLowestPhysicalPage;
542     for (Index=StartPage; Index<(StartPage+PageCount); Index++)
543     {
544         RealPageLookupTable[Index].PageAllocated = MemoryType;
545         RealPageLookupTable[Index].PageAllocationLength = (Index == StartPage) ? PageCount : 0;
546     }
547 }
548 
549 PFN_NUMBER MmCountFreePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount)
550 {
551     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
552     PFN_NUMBER                            Index;
553     PFN_NUMBER                            FreePageCount;
554 
555     FreePageCount = 0;
556     for (Index=0; Index<TotalPageCount; Index++)
557     {
558         if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
559         {
560             FreePageCount++;
561         }
562     }
563 
564     return FreePageCount;
565 }
566 
567 PFN_NUMBER MmFindAvailablePages(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, BOOLEAN FromEnd)
568 {
569     PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
570     PFN_NUMBER AvailablePagesSoFar;
571     PFN_NUMBER Index;
572 
573     if (LastFreePageHint > TotalPageCount)
574     {
575         LastFreePageHint = TotalPageCount;
576     }
577 
578     AvailablePagesSoFar = 0;
579     if (FromEnd)
580     {
581         /* Allocate "high" (from end) pages */
582         for (Index=LastFreePageHint-1; Index>0; Index--)
583         {
584             if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
585             {
586                 AvailablePagesSoFar = 0;
587                 continue;
588             }
589             else
590             {
591                 AvailablePagesSoFar++;
592             }
593 
594             if (AvailablePagesSoFar >= PagesNeeded)
595             {
596                 return Index + MmLowestPhysicalPage;
597             }
598         }
599     }
600     else
601     {
602         TRACE("Alloc low memory, LastFreePageHint 0x%x, TPC 0x%x\n", LastFreePageHint, TotalPageCount);
603         /* Allocate "low" pages */
604         for (Index=1; Index < LastFreePageHint; Index++)
605         {
606             if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
607             {
608                 AvailablePagesSoFar = 0;
609                 continue;
610             }
611             else
612             {
613                 AvailablePagesSoFar++;
614             }
615 
616             if (AvailablePagesSoFar >= PagesNeeded)
617             {
618                 return Index - AvailablePagesSoFar + 1 + MmLowestPhysicalPage;
619             }
620         }
621     }
622 
623     return 0;
624 }
625 
626 PFN_NUMBER MmFindAvailablePagesBeforePage(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, PFN_NUMBER LastPage)
627 {
628     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
629     PFN_NUMBER                    AvailablePagesSoFar;
630     PFN_NUMBER                    Index;
631 
632     if (LastPage > TotalPageCount)
633     {
634         return MmFindAvailablePages(PageLookupTable, TotalPageCount, PagesNeeded, TRUE);
635     }
636 
637     AvailablePagesSoFar = 0;
638     for (Index=LastPage-1; Index>0; Index--)
639     {
640         if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
641         {
642             AvailablePagesSoFar = 0;
643             continue;
644         }
645         else
646         {
647             AvailablePagesSoFar++;
648         }
649 
650         if (AvailablePagesSoFar >= PagesNeeded)
651         {
652             return Index + MmLowestPhysicalPage;
653         }
654     }
655 
656     return 0;
657 }
658 
659 VOID MmUpdateLastFreePageHint(PVOID PageLookupTable, PFN_NUMBER TotalPageCount)
660 {
661     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
662     PFN_NUMBER                            Index;
663 
664     for (Index=TotalPageCount-1; Index>0; Index--)
665     {
666         if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
667         {
668             LastFreePageHint = Index + 1 + MmLowestPhysicalPage;
669             break;
670         }
671     }
672 }
673 
674 BOOLEAN MmAreMemoryPagesAvailable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PVOID PageAddress, PFN_NUMBER PageCount)
675 {
676     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
677     PFN_NUMBER                            StartPage;
678     PFN_NUMBER                            Index;
679 
680     StartPage = MmGetPageNumberFromAddress(PageAddress);
681 
682     if (StartPage < MmLowestPhysicalPage) return FALSE;
683 
684     StartPage -= MmLowestPhysicalPage;
685 
686     // Make sure they aren't trying to go past the
687     // end of available memory
688     if ((StartPage + PageCount) > TotalPageCount)
689     {
690         return FALSE;
691     }
692 
693     for (Index = StartPage; Index < (StartPage + PageCount); Index++)
694     {
695         // If this page is allocated then there obviously isn't
696         // memory available so return FALSE
697         if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
698         {
699             return FALSE;
700         }
701     }
702 
703     return TRUE;
704 }
705