bbf7a571fe433912a1b9515c8dbd348f6819c46b
[reactos.git] / boot / freeldr / freeldr / lib / 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 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 PageLookupTablePages;
419 PFN_NUMBER PageLookupTableStartPage = 0;
420 PVOID PageLookupTableMemAddress = NULL;
421
422 // Calculate how much pages we need to keep the page lookup table
423 PageLookupTableSize = TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM);
424 PageLookupTablePages = PageLookupTableSize / MM_PAGE_SIZE;
425
426 // Search the highest memory block big enough to contain lookup table
427 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
428 {
429 // Continue, if memory is not free
430 if (MemoryDescriptor->MemoryType != LoaderFree) continue;
431
432 // Continue, if the block is not big enough?
433 if (MemoryDescriptor->PageCount < PageLookupTablePages) continue;
434
435 // Continue, if it is not at a higher address than previous address
436 if (MemoryDescriptor->BasePage < PageLookupTableStartPage) continue;
437
438 // Continue, if the address is too high
439 if (MemoryDescriptor->BasePage >= MM_MAX_PAGE) continue;
440
441 // Memory block is more suitable than the previous one
442 PageLookupTableStartPage = MemoryDescriptor->BasePage;
443 PageLookupTableMemAddress = (PVOID)((ULONG_PTR)
444 (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) * MM_PAGE_SIZE
445 - PageLookupTableSize);
446 }
447
448 TRACE("MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress);
449
450 return PageLookupTableMemAddress;
451 }
452
453 VOID MmInitPageLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount)
454 {
455 const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL;
456 PFN_NUMBER PageLookupTableStartPage;
457 PFN_NUMBER PageLookupTablePageCount;
458
459 TRACE("MmInitPageLookupTable()\n");
460
461 // Mark every page as allocated initially
462 // We will go through and mark pages again according to the memory map
463 // But this will mark any holes not described in the map as allocated
464 MmMarkPagesInLookupTable(PageLookupTable, MmLowestPhysicalPage, TotalPageCount, LoaderFirmwarePermanent);
465
466 // Parse the whole memory map
467 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL)
468 {
469 // Mark used pages in the lookup table
470
471 if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount <= TotalPageCount)
472 {
473 TRACE("Marking pages 0x%lx-0x%lx as type %s\n",
474 MemoryDescriptor->BasePage,
475 MemoryDescriptor->BasePage + MemoryDescriptor->PageCount,
476 MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
477 MmMarkPagesInLookupTable(PageLookupTable,
478 MemoryDescriptor->BasePage,
479 MemoryDescriptor->PageCount,
480 MemoryDescriptor->MemoryType);
481 }
482 else
483 TRACE("Ignoring pages 0x%lx-0x%lx (%s)\n",
484 MemoryDescriptor->BasePage,
485 MemoryDescriptor->BasePage + MemoryDescriptor->PageCount,
486 MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType));
487 }
488
489 // Mark the pages that the lookup table occupies as reserved
490 PageLookupTableStartPage = MmGetPageNumberFromAddress(PageLookupTable);
491 PageLookupTablePageCount = MmGetPageNumberFromAddress((PVOID)((ULONG_PTR)PageLookupTable + ROUND_UP(TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM), MM_PAGE_SIZE))) - PageLookupTableStartPage;
492 TRACE("Marking the page lookup table pages as reserved StartPage: 0x%x PageCount: 0x%x\n", PageLookupTableStartPage, PageLookupTablePageCount);
493 MmMarkPagesInLookupTable(PageLookupTable, PageLookupTableStartPage, PageLookupTablePageCount, LoaderFirmwareTemporary);
494 }
495
496 VOID MmMarkPagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY PageAllocated)
497 {
498 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
499 PFN_NUMBER Index;
500 TRACE("MmMarkPagesInLookupTable()\n");
501
502 /* Validate the range */
503 if ((StartPage < MmLowestPhysicalPage) ||
504 ((StartPage + PageCount - 1) > MmHighestPhysicalPage))
505 {
506 ERR("Memory (0x%lx:0x%lx) outside of lookup table! Valid range: 0x%lx-0x%lx.\n",
507 StartPage, PageCount, MmLowestPhysicalPage, MmHighestPhysicalPage);
508 return;
509 }
510
511 StartPage -= MmLowestPhysicalPage;
512 for (Index=StartPage; Index<(StartPage+PageCount); Index++)
513 {
514 #if 0
515 if ((Index <= (StartPage + 16)) || (Index >= (StartPage+PageCount-16)))
516 {
517 TRACE("Index = 0x%x StartPage = 0x%x PageCount = 0x%x\n", Index, StartPage, PageCount);
518 }
519 #endif
520 RealPageLookupTable[Index].PageAllocated = PageAllocated;
521 RealPageLookupTable[Index].PageAllocationLength = (PageAllocated != LoaderFree) ? 1 : 0;
522 }
523 TRACE("MmMarkPagesInLookupTable() Done\n");
524 }
525
526 VOID MmAllocatePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY MemoryType)
527 {
528 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
529 PFN_NUMBER Index;
530
531 StartPage -= MmLowestPhysicalPage;
532 for (Index=StartPage; Index<(StartPage+PageCount); Index++)
533 {
534 RealPageLookupTable[Index].PageAllocated = MemoryType;
535 RealPageLookupTable[Index].PageAllocationLength = (Index == StartPage) ? PageCount : 0;
536 }
537 }
538
539 PFN_NUMBER MmCountFreePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount)
540 {
541 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
542 PFN_NUMBER Index;
543 PFN_NUMBER FreePageCount;
544
545 FreePageCount = 0;
546 for (Index=0; Index<TotalPageCount; Index++)
547 {
548 if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
549 {
550 FreePageCount++;
551 }
552 }
553
554 return FreePageCount;
555 }
556
557 PFN_NUMBER MmFindAvailablePages(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, BOOLEAN FromEnd)
558 {
559 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
560 PFN_NUMBER AvailablePagesSoFar;
561 PFN_NUMBER Index;
562
563 if (LastFreePageHint > TotalPageCount)
564 {
565 LastFreePageHint = TotalPageCount;
566 }
567
568 AvailablePagesSoFar = 0;
569 if (FromEnd)
570 {
571 /* Allocate "high" (from end) pages */
572 for (Index=LastFreePageHint-1; Index>0; Index--)
573 {
574 if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
575 {
576 AvailablePagesSoFar = 0;
577 continue;
578 }
579 else
580 {
581 AvailablePagesSoFar++;
582 }
583
584 if (AvailablePagesSoFar >= PagesNeeded)
585 {
586 return Index + MmLowestPhysicalPage;
587 }
588 }
589 }
590 else
591 {
592 TRACE("Alloc low memory, LastFreePageHint 0x%x, TPC 0x%x\n", LastFreePageHint, TotalPageCount);
593 /* Allocate "low" pages */
594 for (Index=1; Index < LastFreePageHint; Index++)
595 {
596 if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
597 {
598 AvailablePagesSoFar = 0;
599 continue;
600 }
601 else
602 {
603 AvailablePagesSoFar++;
604 }
605
606 if (AvailablePagesSoFar >= PagesNeeded)
607 {
608 return Index - AvailablePagesSoFar + 1 + MmLowestPhysicalPage;
609 }
610 }
611 }
612
613 return 0;
614 }
615
616 PFN_NUMBER MmFindAvailablePagesBeforePage(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, PFN_NUMBER LastPage)
617 {
618 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
619 PFN_NUMBER AvailablePagesSoFar;
620 PFN_NUMBER Index;
621
622 if (LastPage > TotalPageCount)
623 {
624 return MmFindAvailablePages(PageLookupTable, TotalPageCount, PagesNeeded, TRUE);
625 }
626
627 AvailablePagesSoFar = 0;
628 for (Index=LastPage-1; Index>0; Index--)
629 {
630 if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
631 {
632 AvailablePagesSoFar = 0;
633 continue;
634 }
635 else
636 {
637 AvailablePagesSoFar++;
638 }
639
640 if (AvailablePagesSoFar >= PagesNeeded)
641 {
642 return Index + MmLowestPhysicalPage;
643 }
644 }
645
646 return 0;
647 }
648
649 VOID MmUpdateLastFreePageHint(PVOID PageLookupTable, PFN_NUMBER TotalPageCount)
650 {
651 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
652 PFN_NUMBER Index;
653
654 for (Index=TotalPageCount-1; Index>0; Index--)
655 {
656 if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
657 {
658 LastFreePageHint = Index + 1 + MmLowestPhysicalPage;
659 break;
660 }
661 }
662 }
663
664 BOOLEAN MmAreMemoryPagesAvailable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PVOID PageAddress, PFN_NUMBER PageCount)
665 {
666 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
667 PFN_NUMBER StartPage;
668 PFN_NUMBER Index;
669
670 StartPage = MmGetPageNumberFromAddress(PageAddress);
671
672 if (StartPage < MmLowestPhysicalPage) return FALSE;
673
674 StartPage -= MmLowestPhysicalPage;
675
676 // Make sure they aren't trying to go past the
677 // end of available memory
678 if ((StartPage + PageCount) > TotalPageCount)
679 {
680 return FALSE;
681 }
682
683 for (Index = StartPage; Index < (StartPage + PageCount); Index++)
684 {
685 // If this page is allocated then there obviously isn't
686 // memory available so return FALSE
687 if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
688 {
689 return FALSE;
690 }
691 }
692
693 return TRUE;
694 }