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