xref: /reactos/boot/freeldr/freeldr/lib/mm/meminit.c (revision 682f85ad)
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     PIMAGE_NT_HEADERS NtHeaders;
242     PIMAGE_FILE_HEADER FileHeader;
243     PIMAGE_OPTIONAL_HEADER OptionalHeader;
244 
245     /* Get the NT headers */
246     NtHeaders = RtlImageNtHeader(&__ImageBase);
247     if (!NtHeaders)
248     {
249         ERR("Could not get NtHeaders!\n");
250         FrLdrBugCheckWithMessage(
251             FREELDR_IMAGE_CORRUPTION,
252             __FILE__,
253             __LINE__,
254             "Could not get NtHeaders!\n");
255     }
256 
257     /* Check the file header */
258     FileHeader = &NtHeaders->FileHeader;
259     if ((FileHeader->Machine != IMAGE_FILE_MACHINE_NATIVE) ||
260         (FileHeader->NumberOfSections != FREELDR_SECTION_COUNT) ||
261         (FileHeader->PointerToSymbolTable != 0) ||  // Symbols stripped
262         (FileHeader->NumberOfSymbols != 0) ||       //    ""      ""
263         (FileHeader->SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)))
264     {
265         ERR("FreeLdr FileHeader is invalid.\n");
266         FrLdrBugCheckWithMessage(
267             FREELDR_IMAGE_CORRUPTION,
268             __FILE__,
269             __LINE__,
270             "FreeLdr FileHeader is invalid.\n"
271             "Machine == 0x%lx, expected 0x%lx\n"
272             "NumberOfSections == 0x%lx, expected 0x%lx\n"
273             "PointerToSymbolTable == 0x%lx, expected 0\n"
274             "NumberOfSymbols == 0x%lx, expected 0\n"
275             "SizeOfOptionalHeader == 0x%lx, expected 0x%lx\n",
276             FileHeader->Machine, IMAGE_FILE_MACHINE_NATIVE,
277             FileHeader->NumberOfSections, FREELDR_SECTION_COUNT,
278             FileHeader->PointerToSymbolTable,
279             FileHeader->NumberOfSymbols,
280             FileHeader->SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER));
281     }
282 
283     /* Check the optional header */
284     OptionalHeader = &NtHeaders->OptionalHeader;
285     if ((OptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) ||
286         (OptionalHeader->Subsystem != IMAGE_SUBSYSTEM_NATIVE) ||
287         (OptionalHeader->ImageBase != FREELDR_PE_BASE) ||
288         (OptionalHeader->SizeOfImage > MAX_FREELDR_PE_SIZE) ||
289         (OptionalHeader->SectionAlignment != OptionalHeader->FileAlignment))
290     {
291         ERR("FreeLdr OptionalHeader is invalid.\n");
292         FrLdrBugCheckWithMessage(
293             FREELDR_IMAGE_CORRUPTION,
294             __FILE__,
295             __LINE__,
296             "FreeLdr OptionalHeader is invalid.\n"
297             "Magic == 0x%lx, expected 0x%lx\n"
298             "Subsystem == 0x%lx, expected 1 (native)\n"
299             "ImageBase == 0x%lx, expected 0x%lx\n"
300             "SizeOfImage == 0x%lx, maximum 0x%lx\n"
301             "SectionAlignment 0x%lx doesn't match FileAlignment 0x%lx\n",
302             OptionalHeader->Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC,
303             OptionalHeader->Subsystem,
304             OptionalHeader->ImageBase, FREELDR_PE_BASE,
305             OptionalHeader->SizeOfImage, MAX_FREELDR_PE_SIZE,
306             OptionalHeader->SectionAlignment, OptionalHeader->FileAlignment);
307     }
308 
309     /* Calculate the full image size */
310     FrLdrImageSize = (ULONG_PTR)&__ImageBase + OptionalHeader->SizeOfImage - FREELDR_BASE;
311 }
312 
313 BOOLEAN MmInitializeMemoryManager(VOID)
314 {
315 #if DBG
316     const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
317 #endif
318 
319     TRACE("Initializing Memory Manager.\n");
320 
321     /* Check the freeldr binary */
322     MmCheckFreeldrImageFile();
323 
324     BiosMemoryMap = MachVtbl.GetMemoryMap(&BiosMemoryMapEntryCount);
325 
326 #if DBG
327     // Dump the system memory map
328     TRACE("System Memory Map (Base Address, Length, Type):\n");
329     while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
330     {
331         TRACE("%x\t %x\t %s\n",
332             MemoryDescriptor->BasePage * MM_PAGE_SIZE,
333             MemoryDescriptor->PageCount * MM_PAGE_SIZE,
334             MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
335     }
336 #endif
337 
338     // Find address for the page lookup table
339     TotalPagesInLookupTable = MmGetAddressablePageCountIncludingHoles();
340     PageLookupTableAddress = MmFindLocationForPageLookupTable(TotalPagesInLookupTable);
341     LastFreePageHint = MmHighestPhysicalPage;
342 
343     if (PageLookupTableAddress == 0)
344     {
345         // If we get here then we probably couldn't
346         // find a contiguous chunk of memory big
347         // enough to hold the page lookup table
348         printf("Error initializing memory manager!\n");
349         return FALSE;
350     }
351 
352     // Initialize the page lookup table
353     MmInitPageLookupTable(PageLookupTableAddress, TotalPagesInLookupTable);
354 
355     MmUpdateLastFreePageHint(PageLookupTableAddress, TotalPagesInLookupTable);
356 
357     FreePagesInLookupTable = MmCountFreePagesInLookupTable(PageLookupTableAddress,
358                                                         TotalPagesInLookupTable);
359 
360     MmInitializeHeap(PageLookupTableAddress);
361 
362     TRACE("Memory Manager initialized. 0x%x pages available.\n", FreePagesInLookupTable);
363 
364 
365     return TRUE;
366 }
367 
368 
369 PFN_NUMBER MmGetPageNumberFromAddress(PVOID Address)
370 {
371     return ((ULONG_PTR)Address) / MM_PAGE_SIZE;
372 }
373 
374 PFN_NUMBER MmGetAddressablePageCountIncludingHoles(VOID)
375 {
376     const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
377     PFN_NUMBER PageCount;
378 
379     //
380     // Go through the whole memory map to get max address
381     //
382     while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
383     {
384         //
385         // Check if we got a higher end page address
386         //
387         if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > MmHighestPhysicalPage)
388         {
389             //
390             // Yes, remember it if this is real memory
391             //
392             if (MemoryDescriptor->MemoryType == LoaderFree)
393                 MmHighestPhysicalPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount;
394         }
395 
396         //
397         // Check if we got a higher (usable) start page address
398         //
399         if (MemoryDescriptor->BasePage < MmLowestPhysicalPage)
400         {
401             //
402             // Yes, remember it if this is real memory
403             //
404             MmLowestPhysicalPage = MemoryDescriptor->BasePage;
405         }
406     }
407 
408     TRACE("lo/hi %lx %lx\n", MmLowestPhysicalPage, MmHighestPhysicalPage);
409     PageCount = MmHighestPhysicalPage - MmLowestPhysicalPage;
410     TRACE("MmGetAddressablePageCountIncludingHoles() returning 0x%x\n", PageCount);
411     return PageCount;
412 }
413 
414 PVOID MmFindLocationForPageLookupTable(PFN_NUMBER TotalPageCount)
415 {
416     const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
417     SIZE_T PageLookupTableSize;
418     PFN_NUMBER RequiredPages;
419     PFN_NUMBER CandidateBasePage = 0;
420     PFN_NUMBER CandidatePageCount;
421     PFN_NUMBER PageLookupTableEndPage;
422     PVOID PageLookupTableMemAddress = NULL;
423 
424     // Calculate how much pages we need to keep the page lookup table
425     PageLookupTableSize = TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM);
426     RequiredPages = PageLookupTableSize / MM_PAGE_SIZE;
427 
428     // Search the highest memory block big enough to contain lookup table
429     while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
430     {
431         // Continue, if memory is not free
432         if (MemoryDescriptor->MemoryType != LoaderFree) continue;
433 
434         // Continue, if the block is not big enough
435         if (MemoryDescriptor->PageCount < RequiredPages) continue;
436 
437         // Continue, if it is not at a higher address than previous address
438         if (MemoryDescriptor->BasePage < CandidateBasePage) continue;
439 
440         // Continue, if the address is too high
441         if (MemoryDescriptor->BasePage + RequiredPages >= MM_MAX_PAGE) continue;
442 
443         // Memory block is more suitable than the previous one
444         CandidateBasePage = MemoryDescriptor->BasePage;
445         CandidatePageCount = MemoryDescriptor->PageCount;
446     }
447 
448     // Calculate the end address for the lookup table
449     PageLookupTableEndPage = min(CandidateBasePage + CandidatePageCount,
450                                  MM_MAX_PAGE);
451 
452     // Calculate the virtual address
453     PageLookupTableMemAddress = (PVOID)((PageLookupTableEndPage * PAGE_SIZE)
454                                         - PageLookupTableSize);
455 
456     TRACE("MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress);
457 
458     return PageLookupTableMemAddress;
459 }
460 
461 VOID MmInitPageLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount)
462 {
463     const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
464     PFN_NUMBER PageLookupTableStartPage;
465     PFN_NUMBER PageLookupTablePageCount;
466 
467     TRACE("MmInitPageLookupTable()\n");
468 
469     // Mark every page as allocated initially
470     // We will go through and mark pages again according to the memory map
471     // But this will mark any holes not described in the map as allocated
472     MmMarkPagesInLookupTable(PageLookupTable, MmLowestPhysicalPage, TotalPageCount, LoaderFirmwarePermanent);
473 
474     // Parse the whole memory map
475     while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
476     {
477         // Mark used pages in the lookup table
478 
479         if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount <= TotalPageCount)
480         {
481             TRACE("Marking pages 0x%lx-0x%lx as type %s\n",
482                   MemoryDescriptor->BasePage,
483                   MemoryDescriptor->BasePage + MemoryDescriptor->PageCount,
484                   MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
485             MmMarkPagesInLookupTable(PageLookupTable,
486                                      MemoryDescriptor->BasePage,
487                                      MemoryDescriptor->PageCount,
488                                      MemoryDescriptor->MemoryType);
489         }
490         else
491             TRACE("Ignoring pages 0x%lx-0x%lx (%s)\n",
492                   MemoryDescriptor->BasePage,
493                   MemoryDescriptor->BasePage + MemoryDescriptor->PageCount,
494                   MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
495     }
496 
497     // Mark the pages that the lookup table occupies as reserved
498     PageLookupTableStartPage = MmGetPageNumberFromAddress(PageLookupTable);
499     PageLookupTablePageCount = MmGetPageNumberFromAddress((PVOID)((ULONG_PTR)PageLookupTable + ROUND_UP(TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM), MM_PAGE_SIZE))) - PageLookupTableStartPage;
500     TRACE("Marking the page lookup table pages as reserved StartPage: 0x%x PageCount: 0x%x\n", PageLookupTableStartPage, PageLookupTablePageCount);
501     MmMarkPagesInLookupTable(PageLookupTable, PageLookupTableStartPage, PageLookupTablePageCount, LoaderFirmwareTemporary);
502 }
503 
504 VOID MmMarkPagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY PageAllocated)
505 {
506     PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
507     PFN_NUMBER Index;
508     TRACE("MmMarkPagesInLookupTable()\n");
509 
510     /* Validate the range */
511     if ((StartPage < MmLowestPhysicalPage) ||
512         ((StartPage + PageCount - 1) > MmHighestPhysicalPage))
513     {
514         ERR("Memory (0x%lx:0x%lx) outside of lookup table! Valid range: 0x%lx-0x%lx.\n",
515             StartPage, PageCount, MmLowestPhysicalPage, MmHighestPhysicalPage);
516         return;
517     }
518 
519     StartPage -= MmLowestPhysicalPage;
520     for (Index=StartPage; Index<(StartPage+PageCount); Index++)
521     {
522 #if 0
523         if ((Index <= (StartPage + 16)) || (Index >= (StartPage+PageCount-16)))
524         {
525             TRACE("Index = 0x%x StartPage = 0x%x PageCount = 0x%x\n", Index, StartPage, PageCount);
526         }
527 #endif
528         RealPageLookupTable[Index].PageAllocated = PageAllocated;
529         RealPageLookupTable[Index].PageAllocationLength = (PageAllocated != LoaderFree) ? 1 : 0;
530     }
531     TRACE("MmMarkPagesInLookupTable() Done\n");
532 }
533 
534 VOID MmAllocatePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY MemoryType)
535 {
536     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
537     PFN_NUMBER                    Index;
538 
539     StartPage -= MmLowestPhysicalPage;
540     for (Index=StartPage; Index<(StartPage+PageCount); Index++)
541     {
542         RealPageLookupTable[Index].PageAllocated = MemoryType;
543         RealPageLookupTable[Index].PageAllocationLength = (Index == StartPage) ? PageCount : 0;
544     }
545 }
546 
547 PFN_NUMBER MmCountFreePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount)
548 {
549     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
550     PFN_NUMBER                            Index;
551     PFN_NUMBER                            FreePageCount;
552 
553     FreePageCount = 0;
554     for (Index=0; Index<TotalPageCount; Index++)
555     {
556         if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
557         {
558             FreePageCount++;
559         }
560     }
561 
562     return FreePageCount;
563 }
564 
565 PFN_NUMBER MmFindAvailablePages(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, BOOLEAN FromEnd)
566 {
567     PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
568     PFN_NUMBER AvailablePagesSoFar;
569     PFN_NUMBER Index;
570 
571     if (LastFreePageHint > TotalPageCount)
572     {
573         LastFreePageHint = TotalPageCount;
574     }
575 
576     AvailablePagesSoFar = 0;
577     if (FromEnd)
578     {
579         /* Allocate "high" (from end) pages */
580         for (Index=LastFreePageHint-1; Index>0; Index--)
581         {
582             if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
583             {
584                 AvailablePagesSoFar = 0;
585                 continue;
586             }
587             else
588             {
589                 AvailablePagesSoFar++;
590             }
591 
592             if (AvailablePagesSoFar >= PagesNeeded)
593             {
594                 return Index + MmLowestPhysicalPage;
595             }
596         }
597     }
598     else
599     {
600         TRACE("Alloc low memory, LastFreePageHint 0x%x, TPC 0x%x\n", LastFreePageHint, TotalPageCount);
601         /* Allocate "low" pages */
602         for (Index=1; Index < LastFreePageHint; Index++)
603         {
604             if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
605             {
606                 AvailablePagesSoFar = 0;
607                 continue;
608             }
609             else
610             {
611                 AvailablePagesSoFar++;
612             }
613 
614             if (AvailablePagesSoFar >= PagesNeeded)
615             {
616                 return Index - AvailablePagesSoFar + 1 + MmLowestPhysicalPage;
617             }
618         }
619     }
620 
621     return 0;
622 }
623 
624 PFN_NUMBER MmFindAvailablePagesBeforePage(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, PFN_NUMBER LastPage)
625 {
626     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
627     PFN_NUMBER                    AvailablePagesSoFar;
628     PFN_NUMBER                    Index;
629 
630     if (LastPage > TotalPageCount)
631     {
632         return MmFindAvailablePages(PageLookupTable, TotalPageCount, PagesNeeded, TRUE);
633     }
634 
635     AvailablePagesSoFar = 0;
636     for (Index=LastPage-1; Index>0; Index--)
637     {
638         if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
639         {
640             AvailablePagesSoFar = 0;
641             continue;
642         }
643         else
644         {
645             AvailablePagesSoFar++;
646         }
647 
648         if (AvailablePagesSoFar >= PagesNeeded)
649         {
650             return Index + MmLowestPhysicalPage;
651         }
652     }
653 
654     return 0;
655 }
656 
657 VOID MmUpdateLastFreePageHint(PVOID PageLookupTable, PFN_NUMBER TotalPageCount)
658 {
659     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
660     PFN_NUMBER                            Index;
661 
662     for (Index=TotalPageCount-1; Index>0; Index--)
663     {
664         if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
665         {
666             LastFreePageHint = Index + 1 + MmLowestPhysicalPage;
667             break;
668         }
669     }
670 }
671 
672 BOOLEAN MmAreMemoryPagesAvailable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PVOID PageAddress, PFN_NUMBER PageCount)
673 {
674     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
675     PFN_NUMBER                            StartPage;
676     PFN_NUMBER                            Index;
677 
678     StartPage = MmGetPageNumberFromAddress(PageAddress);
679 
680     if (StartPage < MmLowestPhysicalPage) return FALSE;
681 
682     StartPage -= MmLowestPhysicalPage;
683 
684     // Make sure they aren't trying to go past the
685     // end of available memory
686     if ((StartPage + PageCount) > TotalPageCount)
687     {
688         return FALSE;
689     }
690 
691     for (Index = StartPage; Index < (StartPage + PageCount); Index++)
692     {
693         // If this page is allocated then there obviously isn't
694         // memory available so return FALSE
695         if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
696         {
697             return FALSE;
698         }
699     }
700 
701     return TRUE;
702 }
703