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