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