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