xref: /reactos/ntoskrnl/mm/amd64/init.c (revision 84344399)
1 /*
2  * COPYRIGHT:       GPL, 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 <mm/ARM3/miarm.h>
18 #include <fltkernel.h>
19 
20 extern PMMPTE MmDebugPte;
21 
22 /* Helper macros */
23 #define IS_PAGE_ALIGNED(addr) IS_ALIGNED(addr, PAGE_SIZE)
24 
25 /* GLOBALS *****************************************************************/
26 
27 /* Template PTE and PDE for a kernel page */
28 MMPTE ValidKernelPde = {{PTE_VALID|PTE_EXECUTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}};
29 MMPTE ValidKernelPte = {{PTE_VALID|PTE_EXECUTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}};
30 
31 /* The same, but for local pages */
32 MMPTE ValidKernelPdeLocal = {{PTE_VALID|PTE_EXECUTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}};
33 MMPTE ValidKernelPteLocal = {{PTE_VALID|PTE_EXECUTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}};
34 
35 /* Template PDE for a demand-zero page */
36 MMPDE DemandZeroPde  = {{MM_EXECUTE_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS}};
37 MMPTE DemandZeroPte  = {{MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS}};
38 
39 /* Template PTE for prototype page */
40 MMPTE PrototypePte = {{(MM_EXECUTE_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS) |
41                       PTE_PROTOTYPE | (MI_PTE_LOOKUP_NEEDED << 32)}};
42 
43 /* Template PTE for decommited page */
44 MMPTE MmDecommittedPte = {{MM_DECOMMIT << MM_PTE_SOFTWARE_PROTECTION_BITS}};
45 
46 /* Address ranges */
47 PVOID MiSessionViewEnd;
48 PVOID MiSystemPteSpaceStart;
49 PVOID MiSystemPteSpaceEnd;
50 
51 ULONG64 MxPfnSizeInBytes;
52 BOOLEAN MiIncludeType[LoaderMaximum];
53 PFN_NUMBER MxFreePageBase;
54 ULONG64 MxFreePageCount = 0;
55 
56 BOOLEAN MiPfnsInitialized = FALSE;
57 
58 /* FUNCTIONS *****************************************************************/
59 
60 CODE_SEG("INIT")
61 VOID
62 NTAPI
63 MiInitializeSessionSpaceLayout(VOID)
64 {
65     /* This is the entire size */
66     MmSessionSize = MI_SESSION_SIZE;
67 
68     /* Start with session space end */
69     MiSessionSpaceEnd = (PVOID)MI_SESSION_SPACE_END;
70 
71     /* The highest range is the session image range */
72     MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
73     MiSessionImageEnd = MiSessionSpaceEnd;
74     MiSessionImageStart = (PUCHAR)MiSessionImageEnd - MmSessionImageSize;
75     ASSERT(IS_PAGE_ALIGNED(MiSessionImageStart));
76 
77     /* Session working set is below the session image range */
78     MiSessionSpaceWs = (PUCHAR)MiSessionImageStart - MI_SESSION_WORKING_SET_SIZE;
79 
80     /* Session view is below the session working set */
81     MmSessionViewSize = MI_SESSION_VIEW_SIZE;
82     MiSessionViewEnd = MiSessionSpaceWs;
83     MiSessionViewStart = (PUCHAR)MiSessionViewEnd - MmSessionViewSize;
84     ASSERT(IS_PAGE_ALIGNED(MiSessionViewStart));
85 
86     /* Session pool is below session view */
87     MmSessionPoolSize = MI_SESSION_POOL_SIZE;
88     MiSessionPoolEnd = MiSessionViewStart;
89     MiSessionPoolStart = (PUCHAR)MiSessionPoolEnd - MmSessionPoolSize;
90     ASSERT(IS_PAGE_ALIGNED(MiSessionPoolStart));
91 
92     /* And it all begins here */
93     MmSessionBase = MiSessionPoolStart;
94 
95     /* System view space ends at session space, so now that we know where
96      * this is, we can compute the base address of system view space itself. */
97     MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
98     MiSystemViewStart = (PUCHAR)MmSessionBase - MmSystemViewSize;
99     ASSERT(IS_PAGE_ALIGNED(MiSystemViewStart));
100 
101     /* Sanity checks */
102     ASSERT(Add2Ptr(MmSessionBase, MmSessionSize) == MiSessionSpaceEnd);
103     ASSERT(MiSessionViewEnd <= MiSessionImageStart);
104     ASSERT(MmSessionBase <= MiSessionPoolStart);
105 
106     /* Compute the PTE addresses for all the addresses we carved out */
107     MiSessionImagePteStart = MiAddressToPte(MiSessionImageStart);
108     MiSessionImagePteEnd = MiAddressToPte(MiSessionImageEnd);
109     MiSessionBasePte = MiAddressToPte(MmSessionBase);
110     MiSessionLastPte = MiAddressToPte(MiSessionSpaceEnd);
111 
112     /* Initialize the pointer to the session space structure */
113     MmSessionSpace = (PMM_SESSION_SPACE)Add2Ptr(MiSessionImageStart, 0x10000);
114 }
115 
116 VOID
117 NTAPI
118 MiMapPPEs(
119     PVOID StartAddress,
120     PVOID EndAddress)
121 {
122     PMMPDE PointerPpe;
123     MMPDE TmplPde = ValidKernelPde;
124 
125     /* Loop the PPEs */
126     for (PointerPpe = MiAddressToPpe(StartAddress);
127          PointerPpe <= MiAddressToPpe(EndAddress);
128          PointerPpe++)
129     {
130         /* Check if its already mapped */
131         if (!PointerPpe->u.Hard.Valid)
132         {
133             /* No, map it! */
134             TmplPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
135             MI_WRITE_VALID_PTE(PointerPpe, TmplPde);
136 
137             /* Zero out the page table */
138             RtlZeroMemory(MiPteToAddress(PointerPpe), PAGE_SIZE);
139         }
140     }
141 }
142 
143 VOID
144 NTAPI
145 MiMapPDEs(
146     PVOID StartAddress,
147     PVOID EndAddress)
148 {
149     PMMPDE PointerPde;
150     MMPDE TmplPde = ValidKernelPde;
151 
152     /* Loop the PDEs */
153     for (PointerPde = MiAddressToPde(StartAddress);
154          PointerPde <= MiAddressToPde(EndAddress);
155          PointerPde++)
156     {
157         /* Check if its already mapped */
158         if (!PointerPde->u.Hard.Valid)
159         {
160             /* No, map it! */
161             TmplPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
162             MI_WRITE_VALID_PTE(PointerPde, TmplPde);
163 
164             /* Zero out the page table */
165             RtlZeroMemory(MiPteToAddress(PointerPde), PAGE_SIZE);
166         }
167     }
168 }
169 
170 VOID
171 NTAPI
172 MiMapPTEs(
173     PVOID StartAddress,
174     PVOID EndAddress)
175 {
176     PMMPTE PointerPte;
177     MMPTE TmplPte = ValidKernelPte;
178 
179     /* Loop the PTEs */
180     for (PointerPte = MiAddressToPte(StartAddress);
181          PointerPte <= MiAddressToPte(EndAddress);
182          PointerPte++)
183     {
184         /* Check if its already mapped */
185         if (!PointerPte->u.Hard.Valid)
186         {
187             /* No, map it! */
188             TmplPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
189             MI_WRITE_VALID_PTE(PointerPte, TmplPte);
190 
191             /* Zero out the page (FIXME: not always neccessary) */
192             RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
193         }
194     }
195 }
196 
197 CODE_SEG("INIT")
198 VOID
199 NTAPI
200 MiInitializePageTable(VOID)
201 {
202     ULONG64 PxePhysicalAddress;
203     MMPTE TmplPte, *PointerPxe;
204     PFN_NUMBER PxePfn;
205 
206     /* Get current directory base */
207     PxePfn = ((PMMPTE)PXE_SELFMAP)->u.Hard.PageFrameNumber;
208     PxePhysicalAddress = PxePfn << PAGE_SHIFT;
209     ASSERT(PxePhysicalAddress == __readcr3());
210 
211     /* Set directory base for the system process */
212     PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PxePhysicalAddress;
213 
214     /* Enable global pages */
215     __writecr4(__readcr4() | CR4_PGE);
216     ASSERT(__readcr4() & CR4_PGE);
217 
218     /* Loop the user mode PXEs */
219     for (PointerPxe = MiAddressToPxe(0);
220          PointerPxe <= MiAddressToPxe(MmHighestUserAddress);
221          PointerPxe++)
222     {
223         /* Zero the PXE, clear all mappings */
224         PointerPxe->u.Long = 0;
225     }
226 
227     /* Flush the TLB */
228     KeFlushCurrentTb();
229 
230     /* Set up a template PTE */
231     TmplPte.u.Long = 0;
232     TmplPte.u.Flush.Valid = 1;
233     TmplPte.u.Flush.Write = 1;
234     HyperTemplatePte = TmplPte;
235 
236     /* Create PDPTs (72 KB) for shared system address space,
237      * skip page tables TODO: use global pages. */
238 
239     /* Loop the PXEs */
240     for (PointerPxe = MiAddressToPxe((PVOID)HYPER_SPACE);
241          PointerPxe <= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS);
242          PointerPxe++)
243     {
244         /* Is the PXE already valid? */
245         if (!PointerPxe->u.Hard.Valid)
246         {
247             /* It's not Initialize it */
248             TmplPte.u.Flush.PageFrameNumber = MxGetNextPage(1);
249             *PointerPxe = TmplPte;
250 
251             /* Zero the page. The PXE is the PTE for the PDPT. */
252             RtlZeroMemory(MiPteToAddress(PointerPxe), PAGE_SIZE);
253         }
254     }
255     PxePfn = PFN_FROM_PXE(MiAddressToPxe((PVOID)HYPER_SPACE));
256     PsGetCurrentProcess()->Pcb.DirectoryTableBase[1] = PxePfn << PAGE_SHIFT;
257 
258     /* Map PPEs for paged pool */
259     MiMapPPEs(MmPagedPoolStart, MmPagedPoolEnd);
260 
261     /* Setup 1 PPE for hyper space */
262     MiMapPPEs((PVOID)HYPER_SPACE, (PVOID)HYPER_SPACE_END);
263 
264     /* Setup PPEs for system space view */
265     MiMapPPEs(MiSystemViewStart, (PCHAR)MiSystemViewStart + MmSystemViewSize);
266 
267     /* Setup the mapping PDEs */
268     MiMapPDEs((PVOID)MI_MAPPING_RANGE_START, (PVOID)MI_MAPPING_RANGE_END);
269 
270     /* Setup the mapping PTEs */
271     MmFirstReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_START);
272     MmLastReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_END);
273     MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
274 
275     /* Setup debug mapping PTE */
276     MiMapPPEs((PVOID)MI_DEBUG_MAPPING, (PVOID)MI_DEBUG_MAPPING);
277     MiMapPDEs((PVOID)MI_DEBUG_MAPPING, (PVOID)MI_DEBUG_MAPPING);
278     MmDebugPte = MiAddressToPte((PVOID)MI_DEBUG_MAPPING);
279 
280     /* Setup PDE and PTEs for VAD bitmap and working set list */
281     MiMapPDEs((PVOID)MI_VAD_BITMAP, (PVOID)(MI_WORKING_SET_LIST + PAGE_SIZE - 1));
282     MiMapPTEs((PVOID)MI_VAD_BITMAP, (PVOID)(MI_WORKING_SET_LIST + PAGE_SIZE - 1));
283 }
284 
285 CODE_SEG("INIT")
286 VOID
287 NTAPI
288 MiBuildNonPagedPool(VOID)
289 {
290     /* Check if this is a machine with less than 256MB of RAM, and no overide */
291     if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
292         !(MmSizeOfNonPagedPoolInBytes))
293     {
294         /* Force the non paged pool to be 2MB so we can reduce RAM usage */
295         MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
296     }
297 
298     /* Check if the user gave a ridicuously large nonpaged pool RAM size */
299     if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
300         (MmNumberOfPhysicalPages * 7 / 8))
301     {
302         /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
303         MmSizeOfNonPagedPoolInBytes = 0;
304     }
305 
306     /* Check if no registry setting was set, or if the setting was too low */
307     if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
308     {
309         /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
310         MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
311         MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
312                                        256 * MmMinAdditionNonPagedPoolPerMb;
313     }
314 
315     /* Check if the registy setting or our dynamic calculation was too high */
316     if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
317     {
318         /* Set it to the maximum */
319         MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
320     }
321 
322     /* Check if a percentage cap was set through the registry */
323     if (MmMaximumNonPagedPoolPercent)
324     {
325         /* Don't feel like supporting this right now */
326         UNIMPLEMENTED;
327     }
328 
329     /* Page-align the nonpaged pool size */
330     MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
331 
332     /* Now, check if there was a registry size for the maximum size */
333     if (!MmMaximumNonPagedPoolInBytes)
334     {
335         /* Start with the default (1MB) and add 400 KB for each MB above 4 */
336         MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
337         MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
338                                          256 * MmMaxAdditionNonPagedPoolPerMb;
339     }
340 
341     /* Don't let the maximum go too high */
342     if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
343     {
344         /* Set it to the upper limit */
345         MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
346     }
347 
348     /* Convert nonpaged pool size from bytes to pages */
349     MmMaximumNonPagedPoolInPages = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT;
350 
351     /* Non paged pool starts after the PFN database */
352     MmNonPagedPoolStart = MmPfnDatabase + MxPfnAllocation * PAGE_SIZE;
353 
354     /* Calculate the nonpaged pool expansion start region */
355     MmNonPagedPoolExpansionStart = (PCHAR)MmNonPagedPoolStart +
356                                           MmSizeOfNonPagedPoolInBytes;
357     ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart));
358 
359     /* And this is where the none paged pool ends */
360     MmNonPagedPoolEnd = (PCHAR)MmNonPagedPoolStart + MmMaximumNonPagedPoolInBytes;
361     ASSERT(MmNonPagedPoolEnd < (PVOID)MM_HAL_VA_START);
362 
363     /* Map PPEs and PDEs for non paged pool (including expansion) */
364     MiMapPPEs(MmNonPagedPoolStart, MmNonPagedPoolEnd);
365     MiMapPDEs(MmNonPagedPoolStart, MmNonPagedPoolEnd);
366 
367     /* Map the nonpaged pool PTEs (without expansion) */
368     MiMapPTEs(MmNonPagedPoolStart, (PCHAR)MmNonPagedPoolExpansionStart - 1);
369 
370     /* Initialize the ARM3 nonpaged pool */
371     MiInitializeNonPagedPool();
372     MiInitializeNonPagedPoolThresholds();
373 
374 }
375 
376 CODE_SEG("INIT")
377 VOID
378 NTAPI
379 MiBuildSystemPteSpace(VOID)
380 {
381     PMMPTE PointerPte;
382     SIZE_T NonPagedSystemSize;
383 
384     /* Use the default number of system PTEs */
385     MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES;
386     NonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE;
387 
388     /* Put system PTEs at the start of the system VA space */
389     MiSystemPteSpaceStart = MmNonPagedSystemStart;
390     MiSystemPteSpaceEnd = (PUCHAR)MiSystemPteSpaceStart + NonPagedSystemSize;
391 
392     /* Map the PPEs and PDEs for the system PTEs */
393     MiMapPPEs(MiSystemPteSpaceStart, MiSystemPteSpaceEnd);
394     MiMapPDEs(MiSystemPteSpaceStart, MiSystemPteSpaceEnd);
395 
396     /* Initialize the system PTE space */
397     PointerPte = MiAddressToPte(MiSystemPteSpaceStart);
398     MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
399 
400     /* Reserve system PTEs for zeroing PTEs and clear them */
401     MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES + 1,
402                                                     SystemPteSpace);
403     RtlZeroMemory(MiFirstReservedZeroingPte, (MI_ZERO_PTES + 1) * sizeof(MMPTE));
404 
405     /* Set the counter to maximum */
406     MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES;
407 }
408 
409 static
410 VOID
411 MiSetupPfnForPageTable(
412     PFN_NUMBER PageFrameIndex,
413     PMMPTE PointerPte)
414 {
415     PMMPFN Pfn;
416     PMMPDE PointerPde;
417 
418     /* Get the pfn entry for this page */
419     Pfn = MiGetPfnEntry(PageFrameIndex);
420 
421     /* Check if it's valid memory */
422     if ((PageFrameIndex <= MmHighestPhysicalPage) &&
423         (MmIsAddressValid(Pfn)) &&
424         (Pfn->u3.e1.PageLocation == ActiveAndValid))
425     {
426         /* Setup the PFN entry */
427         Pfn->u1.WsIndex = 0;
428         Pfn->u2.ShareCount++;
429         Pfn->PteAddress = PointerPte;
430         Pfn->OriginalPte = *PointerPte;
431         Pfn->u3.e1.PageLocation = ActiveAndValid;
432         Pfn->u3.e1.CacheAttribute = MiNonCached;
433         Pfn->u3.e2.ReferenceCount = 1;
434         Pfn->u4.PteFrame = PFN_FROM_PTE(MiAddressToPte(PointerPte));
435     }
436 
437     /* Increase the shared count of the PFN entry for the PDE */
438     PointerPde = MiAddressToPde(MiPteToAddress(PointerPte));
439     Pfn = MiGetPfnEntry(PFN_FROM_PTE(PointerPde));
440     Pfn->u2.ShareCount++;
441 }
442 
443 CODE_SEG("INIT")
444 static
445 VOID
446 MiBuildPfnDatabaseFromPageTables(VOID)
447 {
448     PVOID Address = NULL;
449     PFN_NUMBER PageFrameIndex;
450     PMMPDE PointerPde;
451     PMMPTE PointerPte;
452     ULONG k, l;
453     PMMPFN Pfn;
454 #if (_MI_PAGING_LEVELS >= 3)
455     PMMPDE PointerPpe;
456     ULONG j;
457 #endif
458 #if (_MI_PAGING_LEVELS == 4)
459     PMMPDE PointerPxe;
460     ULONG i;
461 #endif
462 
463     /* Manual setup of the top level page directory */
464 #if (_MI_PAGING_LEVELS == 4)
465     PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(PXE_BASE));
466 #elif (_MI_PAGING_LEVELS == 3)
467     PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(PPE_BASE));
468 #else
469     PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(PDE_BASE));
470 #endif
471     Pfn = MiGetPfnEntry(PageFrameIndex);
472     ASSERT(Pfn->u3.e1.PageLocation == ActiveAndValid);
473     Pfn->u1.WsIndex = 0;
474     Pfn->u2.ShareCount = 1;
475     Pfn->PteAddress = NULL;
476     Pfn->u3.e1.CacheAttribute = MiNonCached;
477     Pfn->u3.e2.ReferenceCount = 1;
478     Pfn->u4.PteFrame = 0;
479 
480 #if (_MI_PAGING_LEVELS == 4)
481     /* Loop all PXEs in the PML4 */
482     PointerPxe = MiAddressToPxe(Address);
483     for (i = 0; i < PXE_PER_PAGE; i++, PointerPxe++)
484     {
485         /* Skip invalid PXEs */
486         if (!PointerPxe->u.Hard.Valid) continue;
487 
488         /* Handle the PFN */
489         PageFrameIndex = PFN_FROM_PXE(PointerPxe);
490         MiSetupPfnForPageTable(PageFrameIndex, PointerPxe);
491 
492         /* Get starting VA for this PXE */
493         Address = MiPxeToAddress(PointerPxe);
494 #endif
495 #if (_MI_PAGING_LEVELS >= 3)
496         /* Loop all PPEs in this PDP */
497         PointerPpe = MiAddressToPpe(Address);
498         for (j = 0; j < PPE_PER_PAGE; j++, PointerPpe++)
499         {
500             /* Skip invalid PPEs */
501             if (!PointerPpe->u.Hard.Valid) continue;
502 
503             /* Handle the PFN */
504             PageFrameIndex = PFN_FROM_PPE(PointerPpe);
505             MiSetupPfnForPageTable(PageFrameIndex, PointerPpe);
506 
507             /* Get starting VA for this PPE */
508             Address = MiPpeToAddress(PointerPpe);
509 #endif
510             /* Loop all PDEs in this PD */
511             PointerPde = MiAddressToPde(Address);
512             for (k = 0; k < PDE_PER_PAGE; k++, PointerPde++)
513             {
514                 /* Skip invalid PDEs */
515                 if (!PointerPde->u.Hard.Valid) continue;
516 
517                 /* Handle the PFN */
518                 PageFrameIndex = PFN_FROM_PDE(PointerPde);
519                 MiSetupPfnForPageTable(PageFrameIndex, PointerPde);
520 
521                 /* Get starting VA for this PDE */
522                 Address = MiPdeToAddress(PointerPde);
523 
524                 /* Loop all PTEs in this PT */
525                 PointerPte = MiAddressToPte(Address);
526                 for (l = 0; l < PTE_PER_PAGE; l++, PointerPte++)
527                 {
528                     /* Skip invalid PTEs */
529                     if (!PointerPte->u.Hard.Valid) continue;
530 
531                     /* Handle the PFN */
532                     PageFrameIndex = PFN_FROM_PTE(PointerPte);
533                     MiSetupPfnForPageTable(PageFrameIndex, PointerPte);
534                 }
535             }
536 #if (_MI_PAGING_LEVELS >= 3)
537         }
538 #endif
539 #if (_MI_PAGING_LEVELS == 4)
540     }
541 #endif
542 }
543 
544 CODE_SEG("INIT")
545 static
546 VOID
547 MiAddDescriptorToDatabase(
548     PFN_NUMBER BasePage,
549     PFN_NUMBER PageCount,
550     TYPE_OF_MEMORY MemoryType)
551 {
552     PMMPFN Pfn;
553 
554     ASSERT(!MiIsMemoryTypeInvisible(MemoryType));
555 
556     /* Check if the memory is free */
557     if (MiIsMemoryTypeFree(MemoryType))
558     {
559         /* Get the last pfn of this descriptor. Note we loop backwards */
560         Pfn = &MmPfnDatabase[BasePage + PageCount - 1];
561 
562         /* Loop all pages */
563         while (PageCount--)
564         {
565             /* Add it to the free list */
566             Pfn->u3.e1.CacheAttribute = MiNonCached; // FIXME: Windows ASSERTs MiChached, but why not MiNotMapped?
567             MiInsertPageInFreeList(BasePage + PageCount);
568 
569             /* Go to the previous page */
570             Pfn--;
571         }
572     }
573     else if (MemoryType == LoaderXIPRom)
574     {
575         Pfn = &MmPfnDatabase[BasePage];
576         while (PageCount--)
577         {
578             /* Make it a pseudo-I/O ROM mapping */
579             Pfn->PteAddress = 0;
580             Pfn->u1.Flink = 0;
581             Pfn->u2.ShareCount = 0;
582             Pfn->u3.e1.PageLocation = 0;
583             Pfn->u3.e1.CacheAttribute = MiNonCached;
584             Pfn->u3.e1.Rom = 1;
585             Pfn->u3.e1.PrototypePte = 1;
586             Pfn->u3.e2.ReferenceCount = 0;
587             Pfn->u4.InPageError = 0;
588             Pfn->u4.PteFrame = 0;
589 
590             /* Advance one */
591             Pfn++;
592         }
593     }
594     else if (MemoryType == LoaderBad)
595     {
596         // FIXME: later
597         ASSERT(FALSE);
598     }
599     else
600     {
601         /* For now skip it */
602         Pfn = &MmPfnDatabase[BasePage];
603         while (PageCount--)
604         {
605             /* Make an active PFN */
606             Pfn->u3.e1.PageLocation = ActiveAndValid;
607 
608             /* Advance one */
609             Pfn++;
610         }
611     }
612 }
613 
614 CODE_SEG("INIT")
615 VOID
616 NTAPI
617 MiBuildPfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
618 {
619     PLIST_ENTRY ListEntry;
620     PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
621     PFN_NUMBER BasePage, PageCount;
622     KIRQL OldIrql;
623 
624     /* Lock the PFN Database */
625     OldIrql = MiAcquirePfnLock();
626 
627     /* Map the PDEs and PPEs for the pfn database (ignore holes) */
628 #if (_MI_PAGING_LEVELS >= 3)
629     MiMapPPEs(MmPfnDatabase, (PUCHAR)MmPfnDatabase + (MxPfnAllocation * PAGE_SIZE) - 1);
630 #endif
631     MiMapPDEs(MmPfnDatabase, (PUCHAR)MmPfnDatabase + (MxPfnAllocation * PAGE_SIZE) - 1);
632 
633     /* First initialize the color tables */
634     MiInitializeColorTables();
635 
636     /* Loop the memory descriptors */
637     for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
638          ListEntry != &LoaderBlock->MemoryDescriptorListHead;
639          ListEntry = ListEntry->Flink)
640     {
641         /* Get the descriptor */
642         Descriptor = CONTAINING_RECORD(ListEntry,
643                                        MEMORY_ALLOCATION_DESCRIPTOR,
644                                        ListEntry);
645 
646         /* Skip invisible memory */
647         if (MiIsMemoryTypeInvisible(Descriptor->MemoryType)) continue;
648 
649         /* If this is the free descriptor, use the copy instead */
650         if (Descriptor == MxFreeDescriptor) Descriptor = &MxOldFreeDescriptor;
651 
652         /* Get the range for this descriptor */
653         BasePage = Descriptor->BasePage;
654         PageCount = Descriptor->PageCount;
655 
656         /* Map the pages for the database */
657         MiMapPTEs(&MmPfnDatabase[BasePage],
658                   (PUCHAR)(&MmPfnDatabase[BasePage + PageCount]) - 1);
659 
660         /* If this was the free descriptor, skip the next step */
661         if (Descriptor == &MxOldFreeDescriptor) continue;
662 
663         /* Add this descriptor to the database */
664         MiAddDescriptorToDatabase(BasePage, PageCount, Descriptor->MemoryType);
665     }
666 
667     /* At this point the whole pfn database is mapped. We are about to add the
668        pages from the free descriptor to the database, so from now on we cannot
669        use it anymore. */
670 
671     /* Now add the free descriptor */
672     BasePage = MxFreeDescriptor->BasePage;
673     PageCount = MxFreeDescriptor->PageCount;
674     MiAddDescriptorToDatabase(BasePage, PageCount, LoaderFree);
675 
676     /* And finally the memory we used */
677     BasePage = MxOldFreeDescriptor.BasePage;
678     PageCount = MxFreeDescriptor->BasePage - BasePage;
679     MiAddDescriptorToDatabase(BasePage, PageCount, LoaderMemoryData);
680 
681     /* Reset the descriptor back so we can create the correct memory blocks */
682     *MxFreeDescriptor = MxOldFreeDescriptor;
683 
684     /* Now process the page tables */
685     MiBuildPfnDatabaseFromPageTables();
686 
687     /* PFNs are initialized now! */
688     MiPfnsInitialized = TRUE;
689 
690     /* Release PFN database */
691     MiReleasePfnLock(OldIrql);
692 }
693 
694 CODE_SEG("INIT")
695 NTSTATUS
696 NTAPI
697 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
698 {
699     NTSTATUS Status;
700     ULONG Flags;
701 
702     ASSERT(MxPfnAllocation != 0);
703 
704     /* Set some hardcoded addresses */
705     MmHyperSpaceEnd = (PVOID)HYPER_SPACE_END;
706     MmNonPagedSystemStart = (PVOID)MM_SYSTEM_SPACE_START;
707     MmPfnDatabase = (PVOID)MI_PFN_DATABASE;
708     MmWorkingSetList = (PVOID)MI_WORKING_SET_LIST;
709 
710 
711 //    PrototypePte.u.Proto.Valid = 1
712 //    PrototypePte.u.ReadOnly
713 //    PrototypePte.u.Prototype
714 //    PrototypePte.u.Protection = MM_READWRITE;
715 //    PrototypePte.u.ProtoAddress
716     PrototypePte.u.Soft.PageFileHigh = MI_PTE_LOOKUP_NEEDED;
717 
718     MiInitializePageTable();
719 
720     MiBuildNonPagedPool();
721 
722     MiBuildSystemPteSpace();
723 
724     /* Map the PFN database pages */
725     MiBuildPfnDatabase(LoaderBlock);
726 
727     /* Reset the ref/share count so that MmInitializeProcessAddressSpace works */
728     PMMPFN Pfn = MiGetPfnEntry(PFN_FROM_PTE((PMMPTE)PXE_SELFMAP));
729     Pfn->u2.ShareCount = 0;
730     Pfn->u3.e2.ReferenceCount = 0;
731 
732     Pfn = MiGetPfnEntry(PFN_FROM_PDE(MiAddressToPde((PVOID)HYPER_SPACE)));
733     Pfn->u2.ShareCount = 0;
734     Pfn->u3.e2.ReferenceCount = 0;
735 
736     Pfn = MiGetPfnEntry(PFN_FROM_PPE(MiAddressToPpe((PVOID)HYPER_SPACE)));
737     Pfn->u2.ShareCount = 0;
738     Pfn->u3.e2.ReferenceCount = 0;
739 
740     Pfn = MiGetPfnEntry(PFN_FROM_PXE(MiAddressToPxe((PVOID)HYPER_SPACE)));
741     Pfn->u2.ShareCount = 0;
742     Pfn->u3.e2.ReferenceCount = 0;
743 
744     Pfn = MiGetPfnEntry(PFN_FROM_PTE(MiAddressToPte(MmWorkingSetList)));
745     Pfn->u2.ShareCount = 0;
746     Pfn->u3.e2.ReferenceCount = 0;
747 
748     /* Initialize the nonpaged pool */
749     InitializePool(NonPagedPool, 0);
750 
751     /* Initialize the bogus address space */
752     Flags = 0;
753     Status = MmInitializeProcessAddressSpace(PsGetCurrentProcess(), NULL, NULL, &Flags, NULL);
754     if (!NT_SUCCESS(Status))
755     {
756         DPRINT1("MmInitializeProcessAddressSpace(9 failed: 0x%lx\n", Status);
757         return Status;
758     }
759 
760     /* Initialize the balancer */
761     MmInitializeBalancer((ULONG)MmAvailablePages, 0);
762 
763     /* Make sure we have everything we need */
764     ASSERT(MmPfnDatabase);
765     ASSERT(MmNonPagedSystemStart);
766     ASSERT(MmNonPagedPoolStart);
767     ASSERT(MmSizeOfNonPagedPoolInBytes);
768     ASSERT(MmMaximumNonPagedPoolInBytes);
769     ASSERT(MmNonPagedPoolExpansionStart);
770     ASSERT(MmHyperSpaceEnd);
771     ASSERT(MmNumberOfSystemPtes);
772     ASSERT(MiAddressToPde(MmNonPagedPoolStart)->u.Hard.Valid);
773     ASSERT(MiAddressToPte(MmNonPagedPoolStart)->u.Hard.Valid);
774 
775     return STATUS_SUCCESS;
776 }
777