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