[MM]
[reactos.git] / reactos / ntoskrnl / mm / amd64 / init.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/amd64/init.c
5 * PURPOSE: Memory Manager Initialization for amd64
6 *
7 * PROGRAMMERS: Timo kreuzer (timo.kreuzer@reactos.org)
8 * ReactOS Portable Systems Group
9 */
10
11 /* INCLUDES ***************************************************************/
12
13 #include <ntoskrnl.h>
14 //#define NDEBUG
15 #include <debug.h>
16
17 #include "../ARM3/miarm.h"
18
19 extern PMMPTE MmDebugPte;
20
21 /* GLOBALS *****************************************************************/
22
23 ULONG64 MmUserProbeAddress = 0x7FFFFFF0000ULL;
24 PVOID MmHighestUserAddress = (PVOID)0x7FFFFFEFFFFULL;
25 PVOID MmSystemRangeStart = (PVOID)0xFFFF080000000000ULL;
26
27 /* Size of session view, pool, and image */
28 ULONG64 MmSessionSize = MI_SESSION_SIZE;
29 ULONG64 MmSessionViewSize = MI_SESSION_VIEW_SIZE;
30 ULONG64 MmSessionPoolSize = MI_SESSION_POOL_SIZE;
31 ULONG64 MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
32
33 /* Session space addresses */
34 PVOID MiSessionSpaceEnd = MI_SESSION_SPACE_END; // FFFFF98000000000
35 PVOID MiSessionImageEnd; // FFFFF98000000000 = MiSessionSpaceEnd
36 PVOID MiSessionImageStart; // ?FFFFF97FFF000000 = MiSessionImageEnd - MmSessionImageSize
37 PVOID MiSessionViewEnd; // FFFFF97FFF000000
38 PVOID MiSessionViewStart; // = MiSessionViewEnd - MmSessionViewSize
39 PVOID MiSessionPoolEnd; // = MiSessionViewStart
40 PVOID MiSessionPoolStart; // FFFFF90000000000 = MiSessionPoolEnd - MmSessionPoolSize
41 PVOID MmSessionBase; // FFFFF90000000000 = MiSessionPoolStart
42
43 /* System view */
44 ULONG64 MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
45 PVOID MiSystemViewStart;
46
47 ULONG64 MmMinimumNonPagedPoolSize = 256 * 1024;
48 ULONG64 MmSizeOfNonPagedPoolInBytes;
49 ULONG64 MmMaximumNonPagedPoolInBytes;
50 ULONG64 MmMaximumNonPagedPoolPercent;
51 ULONG64 MmMinAdditionNonPagedPoolPerMb = 32 * 1024;
52 ULONG64 MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
53 ULONG64 MmDefaultMaximumNonPagedPool = 1024 * 1024;
54 PVOID MmNonPagedSystemStart;
55 PVOID MmNonPagedPoolStart;
56 PVOID MmNonPagedPoolExpansionStart;
57 PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
58
59 ULONG64 MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
60 PVOID MmPagedPoolStart = MI_PAGED_POOL_START;
61 PVOID MmPagedPoolEnd;
62
63
64 ULONG64 MmBootImageSize;
65 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
66 RTL_BITMAP MiPfnBitMap;
67 ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage = -1; // FIXME: ULONG64
68 ULONG64 MmNumberOfSystemPtes;
69 PMMPTE MmSystemPagePtes;
70 ULONG64 MxPfnAllocation;
71 ULONG64 MxPfnSizeInBytes;
72
73 PVOID MmSystemCacheStart;
74 PVOID MmSystemCacheEnd;
75 MMSUPPORT MmSystemCacheWs;
76
77 ULONG MiNumberDescriptors = 0;
78 BOOLEAN MiIncludeType[LoaderMaximum];
79
80 ///////////////////////////////////////////////
81
82 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
83 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
84
85 PFN_NUMBER MxFreePageBase;
86 ULONG64 MxFreePageCount = 0;
87
88 ULONG
89 NoDbgPrint(const char *Format, ...)
90 {
91 return 0;
92 }
93
94 VOID
95 NTAPI
96 MiEvaluateMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
97 {
98 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
99 PLIST_ENTRY ListEntry;
100 PFN_NUMBER LastPage;
101 ULONG i;
102
103 /* Instantiate memory that we don't consider RAM/usable */
104 for (i = 0; i < LoaderMaximum; i++) MiIncludeType[i] = TRUE;
105 MiIncludeType[LoaderBad] = FALSE;
106 MiIncludeType[LoaderFirmwarePermanent] = FALSE;
107 MiIncludeType[LoaderSpecialMemory] = FALSE;
108 MiIncludeType[LoaderBBTMemory] = FALSE;
109
110 /* Loop the memory descriptors */
111 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
112 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
113 ListEntry = ListEntry->Flink)
114 {
115 /* Get the memory descriptor */
116 MdBlock = CONTAINING_RECORD(ListEntry,
117 MEMORY_ALLOCATION_DESCRIPTOR,
118 ListEntry);
119
120 /* Count it */
121 MiNumberDescriptors++;
122
123 /* Skip pages that are not part of the PFN database */
124 if (!MiIncludeType[MdBlock->MemoryType])
125 {
126 continue;
127 }
128
129 /* Add this to the total of pages */
130 MmNumberOfPhysicalPages += MdBlock->PageCount;
131
132 /* Check if this is the new lowest page */
133 if (MdBlock->BasePage < MmLowestPhysicalPage)
134 {
135 /* Update the lowest page */
136 MmLowestPhysicalPage = MdBlock->BasePage;
137 }
138
139 /* Check if this is the new highest page */
140 LastPage = MdBlock->BasePage + MdBlock->PageCount - 1;
141 if (LastPage > MmHighestPhysicalPage)
142 {
143 /* Update the highest page */
144 MmHighestPhysicalPage = LastPage;
145 }
146
147 /* Check if this is currently free memory */
148 if ((MdBlock->MemoryType == LoaderFree) ||
149 (MdBlock->MemoryType == LoaderLoadedProgram) ||
150 (MdBlock->MemoryType == LoaderFirmwareTemporary) ||
151 (MdBlock->MemoryType == LoaderOsloaderStack))
152 {
153 /* Check if this is the largest memory descriptor */
154 if (MdBlock->PageCount > MxFreePageCount)
155 {
156 /* For now, it is */
157 MxFreeDescriptor = MdBlock;
158 MxFreePageBase = MdBlock->BasePage;
159 MxFreePageCount = MdBlock->PageCount;
160 }
161 }
162 }
163 }
164
165 PFN_NUMBER
166 NTAPI
167 MxGetNextPage(IN PFN_NUMBER PageCount)
168 {
169 PFN_NUMBER Pfn;
170
171 /* Make sure we have enough pages */
172 if (PageCount > MxFreePageCount)
173 {
174 /* Crash the system */
175 KeBugCheckEx(INSTALL_MORE_MEMORY,
176 MmNumberOfPhysicalPages,
177 MxFreeDescriptor->PageCount,
178 MxOldFreeDescriptor.PageCount,
179 PageCount);
180 }
181
182 /* Use our lowest usable free pages */
183 Pfn = MxFreePageBase;
184 MxFreePageBase += PageCount;
185 MxFreePageCount -= PageCount;
186 return Pfn;
187 }
188
189 PMMPTE
190 NTAPI
191 MxGetPte(PVOID Address)
192 {
193 PMMPTE Pte;
194 MMPTE TmpPte;
195
196 /* Setup template pte */
197 TmpPte.u.Long = 0;
198 TmpPte.u.Flush.Valid = 1;
199 TmpPte.u.Flush.Write = 1;
200
201 /* Get a pointer to the PXE */
202 Pte = MiAddressToPxe(Address);
203 if (!Pte->u.Hard.Valid)
204 {
205 /* It's not valid, map it! */
206 TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
207 *Pte = TmpPte;
208 }
209
210 /* Get a pointer to the PPE */
211 Pte = MiAddressToPpe(Address);
212 if (!Pte->u.Hard.Valid)
213 {
214 /* It's not valid, map it! */
215 TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
216 *Pte = TmpPte;
217 }
218
219 /* Get a pointer to the PDE */
220 Pte = MiAddressToPde(Address);
221 if (!Pte->u.Hard.Valid)
222 {
223 /* It's not valid, map it! */
224 TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
225 *Pte = TmpPte;
226 }
227
228 /* Get a pointer to the PTE */
229 Pte = MiAddressToPte(Address);
230 return Pte;
231 }
232
233 VOID
234 MxMapPageRange(PVOID Address, ULONG64 PageCount)
235 {
236 MMPTE TmpPte, *Pte;
237
238 /* Setup template pte */
239 TmpPte.u.Long = 0;
240 TmpPte.u.Flush.Valid = 1;
241 TmpPte.u.Flush.Write = 1;
242
243 while (PageCount--)
244 {
245 /* Get the PTE for that page */
246 Pte = MxGetPte(Address);
247 ASSERT(Pte->u.Hard.Valid == 0);
248
249 /* Map a physical page */
250 TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
251 *Pte = TmpPte;
252
253 /* Goto next page */
254 Address = (PVOID)((ULONG64)Address + PAGE_SIZE);
255 }
256 }
257
258 VOID
259 NTAPI
260 MiArmConfigureMemorySizes(IN PLOADER_PARAMETER_BLOCK LoaderBloc)
261 {
262 /* Get the size of the boot loader's image allocations */
263 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned * PAGE_SIZE;
264 MmBootImageSize = ROUND_UP(MmBootImageSize, 4 * 1024 * 1024);
265
266 /* Check if this is a machine with less than 256MB of RAM, and no overide */
267 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
268 !(MmSizeOfNonPagedPoolInBytes))
269 {
270 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
271 MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
272 }
273
274 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
275 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
276 (MmNumberOfPhysicalPages * 7 / 8))
277 {
278 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
279 MmSizeOfNonPagedPoolInBytes = 0;
280 }
281
282 /* Check if no registry setting was set, or if the setting was too low */
283 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
284 {
285 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
286 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
287 MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
288 256 * MmMinAdditionNonPagedPoolPerMb;
289 }
290
291 /* Check if the registy setting or our dynamic calculation was too high */
292 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
293 {
294 // Set it to the maximum */
295 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
296 }
297
298 /* Check if a percentage cap was set through the registry */
299 if (MmMaximumNonPagedPoolPercent)
300 {
301 /* Don't feel like supporting this right now */
302 UNIMPLEMENTED;
303 }
304
305 /* Page-align the nonpaged pool size */
306 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
307
308 /* Now, check if there was a registry size for the maximum size */
309 if (!MmMaximumNonPagedPoolInBytes)
310 {
311 /* Start with the default (1MB) and add 400 KB for each MB above 4 */
312 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
313 MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
314 256 * MmMaxAdditionNonPagedPoolPerMb;
315 }
316
317 /* Don't let the maximum go too high */
318 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
319 {
320 /* Set it to the upper limit */
321 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
322 }
323
324 // MmSessionImageSize
325 }
326
327 VOID
328 NTAPI
329 MiArmInitializeMemoryLayout(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
330 {
331 /* Set up session space */
332 MiSessionSpaceEnd = (PVOID)MI_SESSION_SPACE_END;
333
334 /* This is where we will load Win32k.sys and the video driver */
335 MiSessionImageEnd = MiSessionSpaceEnd;
336 MiSessionImageStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
337 MmSessionImageSize);
338
339 /* The view starts right below the session working set (itself below
340 * the image area) */
341 MiSessionViewEnd = MI_SESSION_VIEW_END;
342 MiSessionViewStart = (PVOID)((ULONG_PTR)MiSessionViewStart -
343 MmSessionViewSize);
344
345 /* Session pool follows */
346 MiSessionPoolEnd = MiSessionViewStart;
347 MiSessionPoolStart = (PVOID)((ULONG_PTR)MiSessionPoolEnd -
348 MmSessionPoolSize);
349
350 /* And it all begins here */
351 MmSessionBase = MiSessionPoolStart;
352
353 /* System view space ends at session space, so now that we know where
354 * this is, we can compute the base address of system view space itself. */
355 MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase -
356 MmSystemViewSize);
357
358 /* Use the default */
359 MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES;
360
361 ASSERT(MiSessionViewEnd <= MiSessionImageStart);
362 ASSERT(MmSessionBase <= MiSessionPoolStart);
363 }
364
365
366 VOID
367 MiArmInitializePageTable()
368 {
369 ULONG64 PageFrameOffset;
370 PMMPTE Pte, StartPte, EndPte;
371 MMPTE TmplPte;
372
373 /* HACK: don't use freeldr debug print anymore */
374 FrLdrDbgPrint = NoDbgPrint;
375
376 /* Get current directory base */
377 PageFrameOffset = ((PMMPTE)PXE_SELFMAP)->u.Hard.PageFrameNumber << PAGE_SHIFT;
378 ASSERT(PageFrameOffset == __readcr3());
379
380 /* Set directory base for the system process */
381 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameOffset;
382
383 /* Enable global pages */
384 __writecr4(__readcr4() | CR4_PGE);
385 ASSERT(__readcr4() & CR4_PGE);
386
387 /* Set user mode address range */
388 StartPte = MiAddressToPxe(0);
389 EndPte = MiAddressToPxe(MmHighestUserAddress);
390
391 /* Loop the user mode PXEs */
392 for (Pte = StartPte; Pte <= EndPte; Pte++)
393 {
394 /* Zero the PXE, clear all mappings */
395 Pte->u.Long = 0;
396 }
397
398 /* Set up a template PTE */
399 TmplPte.u.Long = 0;
400 TmplPte.u.Flush.Valid = 1;
401 TmplPte.u.Flush.Write = 1;
402 HyperTemplatePte = TmplPte;
403
404 /* Create PDPTs (72 KB) for shared system address space,
405 * skip page tables and hyperspace */
406
407 /* Set the range */
408 StartPte = MiAddressToPxe((PVOID)(HYPER_SPACE_END + 1));
409 EndPte = MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS);
410
411 /* Loop the PXEs */
412 for (Pte = StartPte; Pte <= EndPte; Pte++)
413 {
414 /* Is the PXE already valid? */
415 if (!Pte->u.Hard.Valid)
416 {
417 /* It's not Initialize it */
418 TmplPte.u.Flush.PageFrameNumber = MxGetNextPage(1);
419 *Pte = TmplPte;
420
421 /* Zero the page. The PXE is the PTE for the PDPT. */
422 RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
423 }
424 }
425
426 /* Set the range of system PTEs */
427 StartPte = MiAddressToPte(MI_SYSTEM_PTE_START);
428 EndPte = StartPte + MmNumberOfSystemPtes - 1;
429
430 /* Loop the system PTEs */
431 for (Pte = StartPte; Pte <= EndPte; Pte++)
432 {
433 /* Make sure the PTE is valid */
434 MxGetPte(MiPteToAddress(Pte));
435 }
436
437 /* Flush the TLB */
438 KeFlushCurrentTb();
439
440 /* Setup the mapping PTEs */
441 MmFirstReservedMappingPte = MxGetPte((PVOID)MI_MAPPING_RANGE_START);
442 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
443 MmLastReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_END);
444
445 /* Setup debug mapping PTE */
446 MmDebugPte = MxGetPte(MI_DEBUG_MAPPING);
447 }
448
449
450 VOID
451 NTAPI
452 MiArmPreparePfnDatabse(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
453 {
454 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
455 PLIST_ENTRY ListEntry;
456 SIZE_T Size;
457 PUCHAR Page, FirstPage;
458
459 /* The PFN database is at the start of the non paged region */
460 MmPfnDatabase = (PVOID)((ULONG64)MmNonPagedPoolEnd - MmMaximumNonPagedPoolInBytes);
461
462 /* Loop the memory descriptors */
463 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
464 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
465 ListEntry = ListEntry->Flink)
466 {
467 /* Get the memory descriptor */
468 MdBlock = CONTAINING_RECORD(ListEntry,
469 MEMORY_ALLOCATION_DESCRIPTOR,
470 ListEntry);
471
472 /* Skip pages that are not part of the PFN database */
473 if (!MiIncludeType[MdBlock->MemoryType])
474 {
475 continue;
476 }
477
478 /* Get the base and size of this pfn database entry */
479 FirstPage = PAGE_ALIGN(&MmPfnDatabase[MdBlock->BasePage]);
480 Size = ROUND_TO_PAGES(MdBlock->PageCount * sizeof(MMPFN));
481
482 /* Loop the pages of this Pfn database entry */
483 for (Page = FirstPage; Page < FirstPage + Size; Page += PAGE_SIZE)
484 {
485 /* Is the page already mapped? */
486 if (!MmIsAddressValid(Page))
487 {
488 /* It's not, map it now */
489 MxMapPageRange(Page, 1);
490 }
491 }
492
493 /* Zero out the pages */
494 RtlZeroMemory(FirstPage, Size);
495 }
496
497 /* Calculate the number of bytes, and then convert to pages */
498 MxPfnSizeInBytes = ROUND_TO_PAGES(MmHighestPhysicalPage + 1) * sizeof(MMPFN);
499 MxPfnAllocation = MxPfnSizeInBytes >> PAGE_SHIFT;
500
501 /* Reduce maximum pool size */
502 MmMaximumNonPagedPoolInBytes -= MxPfnSizeInBytes;
503 }
504
505
506 VOID
507 NTAPI
508 MiArmPrepareNonPagedPool()
509 {
510 PFN_NUMBER PageCount;
511 PVOID Address;
512
513 /* Non paged pool comes after the PFN database */
514 MmNonPagedPoolStart = (PVOID)((ULONG64)MmPfnDatabase +
515 MxPfnSizeInBytes);
516 ASSERT((ULONG64)MmNonPagedPoolEnd == (ULONG64)MmNonPagedPoolStart +
517 MmMaximumNonPagedPoolInBytes);
518
519 /* Calculate the nonpaged pool expansion start region */
520 MmNonPagedPoolExpansionStart = (PVOID)((ULONG_PTR)MmNonPagedPoolEnd -
521 MmMaximumNonPagedPoolInBytes +
522 MmSizeOfNonPagedPoolInBytes);
523 MmNonPagedPoolExpansionStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolExpansionStart);
524
525 /* Now calculate the nonpaged system VA region, which includes the
526 * nonpaged pool expansion (above) and the system PTEs. Note that it is
527 * then aligned to a PDE boundary (4MB). */
528 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolExpansionStart -
529 (MmNumberOfSystemPtes + 1) * PAGE_SIZE);
530 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
531 ~((4 * 1024 * 1024) - 1));
532
533 /* Don't let it go below the minimum */
534 if (MmNonPagedSystemStart < (PVOID)MI_NON_PAGED_SYSTEM_START_MIN)
535 {
536 /* This is a hard-coded limit in the Windows NT address space */
537 MmNonPagedSystemStart = (PVOID)MI_NON_PAGED_SYSTEM_START_MIN;
538
539 /* Reduce the amount of system PTEs to reach this point */
540 MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolExpansionStart -
541 (ULONG_PTR)MmNonPagedSystemStart) >>
542 PAGE_SHIFT;
543 MmNumberOfSystemPtes--;
544 ASSERT(MmNumberOfSystemPtes > 1000);
545 }
546
547 /* Map the nonpaged pool */
548 PageCount = (MmSizeOfNonPagedPoolInBytes + PAGE_SIZE - 1) / PAGE_SIZE;
549 MxMapPageRange(MmNonPagedPoolStart, PageCount);
550
551 /* Create PTEs for the paged pool extension */
552 for (Address = MmNonPagedPoolExpansionStart;
553 Address < MmNonPagedPoolEnd;
554 Address = (PVOID)((ULONG64)Address + PAGE_SIZE))
555 {
556 /* Create PXE, PPE, PDE and set PTE to 0*/
557 MxGetPte(Address)->u.Long = 0;
558 }
559
560 /* Sanity check */
561 ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
562 MiAddressToPte(MmNonPagedPoolExpansionStart));
563
564 }
565
566
567 VOID
568 NTAPI
569 MiBuildPhysicalMemoryBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
570 {
571 PPHYSICAL_MEMORY_DESCRIPTOR Buffer, NewBuffer;
572 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
573 PLIST_ENTRY ListEntry;
574 PFN_NUMBER NextPage = -1;
575 PULONG Bitmap;
576 ULONG Runs = 0;
577 ULONG Size, i;
578
579 /* Calculate size for the PFN bitmap */
580 Size = (MmHighestPhysicalPage + sizeof(ULONG)) / sizeof(ULONG);
581
582 /* Allocate the PFN bitmap */
583 Bitmap = ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
584
585 /* Allocate enough memory for the physical memory block */
586 Buffer = ExAllocatePoolWithTag(NonPagedPool,
587 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
588 sizeof(PHYSICAL_MEMORY_RUN) *
589 (MiNumberDescriptors - 1),
590 'lMmM');
591 if (!Bitmap || !Buffer)
592 {
593 /* This is critical */
594 KeBugCheckEx(INSTALL_MORE_MEMORY,
595 MmNumberOfPhysicalPages,
596 MmLowestPhysicalPage,
597 MmHighestPhysicalPage,
598 0x101);
599 }
600
601 /* Initialize the bitmap and clear all bits */
602 RtlInitializeBitMap(&MiPfnBitMap, Bitmap, MmHighestPhysicalPage + 1);
603 RtlClearAllBits(&MiPfnBitMap);
604
605 /* Loop the memory descriptors */
606 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
607 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
608 ListEntry = ListEntry->Flink)
609 {
610 /* Get the memory descriptor */
611 MdBlock = CONTAINING_RECORD(ListEntry,
612 MEMORY_ALLOCATION_DESCRIPTOR,
613 ListEntry);
614
615 /* Skip pages that are not part of the PFN database */
616 if (!MiIncludeType[MdBlock->MemoryType])
617 {
618 continue;
619 }
620
621 /* Does the memory block begin where the last ended? */
622 if (MdBlock->BasePage == NextPage)
623 {
624 /* Add it to the current run */
625 Buffer->Run[Runs - 1].PageCount += MdBlock->PageCount;
626 }
627 else
628 {
629 /* Create a new run */
630 Runs++;
631 Buffer->Run[Runs - 1].BasePage = MdBlock->BasePage;
632 Buffer->Run[Runs - 1].PageCount = MdBlock->PageCount;
633 }
634
635 /* Set the bits in the PFN bitmap */
636 RtlSetBits(&MiPfnBitMap, MdBlock->BasePage, MdBlock->PageCount);
637
638 /* Set the next page */
639 NextPage = MdBlock->BasePage + MdBlock->PageCount;
640 }
641
642 // FIXME: allocate a buffer of better size
643
644 Buffer->NumberOfRuns = Runs;
645 Buffer->NumberOfPages = MmNumberOfPhysicalPages;
646 MmPhysicalMemoryBlock = Buffer;
647 }
648
649 VOID
650 NTAPI
651 MiBuildPagedPool(VOID)
652 {
653 UNIMPLEMENTED;
654 }
655
656
657 NTSTATUS
658 NTAPI
659 MmArmInitSystem(IN ULONG Phase,
660 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
661 {
662 if (Phase == 0)
663 {
664 /* Parse memory descriptors */
665 MiEvaluateMemoryDescriptors(LoaderBlock);
666
667 /* Configure the memory sizes */
668 MiArmConfigureMemorySizes(LoaderBlock);
669
670 /* Initialize the memory layout */
671 MiArmInitializeMemoryLayout(LoaderBlock);
672
673 /* Prepare PFN database mappings */
674 MiArmPreparePfnDatabse(LoaderBlock);
675
676 /* Prepare paged pool mappings */
677 MiArmPrepareNonPagedPool();
678
679 /* Initialize some mappings */
680 MiArmInitializePageTable();
681
682 /* Initialize the ARM3 nonpaged pool */
683 MiInitializeArmPool();
684
685 /* Update the memory descriptor, to make sure the pages we used
686 won't get inserted into the PFN database */
687 MxOldFreeDescriptor = *MxFreeDescriptor;
688 MxFreeDescriptor->BasePage = MxFreePageBase;
689 MxFreeDescriptor->PageCount = MxFreePageCount;
690 }
691 else if (Phase == 1)
692 {
693 PMMPTE Pte;
694 ULONG OldCount;
695 PPHYSICAL_MEMORY_RUN Run;
696
697 /* The PFN database was created, restore the free descriptor */
698 *MxFreeDescriptor = MxOldFreeDescriptor;
699
700 /* Initialize the nonpaged pool */
701 InitializePool(NonPagedPool, 0);
702
703 /* Create the system PTE space */
704 Pte = MiAddressToPte(MI_SYSTEM_PTE_START);
705 MiInitializeSystemPtes(Pte, MmNumberOfSystemPtes, SystemPteSpace);
706
707 /* Reserve system PTEs for zeroing PTEs and clear them */
708 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES,
709 SystemPteSpace);
710 RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
711
712 /* Set the counter to maximum */
713 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
714
715 /* Build the physical memory block */
716 MiBuildPhysicalMemoryBlock(LoaderBlock);
717
718 /* Size up paged pool and build the shadow system page directory */
719 MiBuildPagedPool();
720 }
721
722 return STATUS_SUCCESS;
723 }
724