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