[NTOSKRNL/AMD64]
[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 "../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 the mapping PDEs */
246 MiMapPDEs((PVOID)MI_MAPPING_RANGE_START, (PVOID)MI_MAPPING_RANGE_END);
247
248 /* Setup the mapping PTEs */
249 MmFirstReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_START);
250 MmLastReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_END);
251 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
252
253 #ifdef _WINKD_
254 /* Setup debug mapping PTE */
255 MiMapPPEs((PVOID)MI_DEBUG_MAPPING, (PVOID)MI_DEBUG_MAPPING);
256 MiMapPDEs((PVOID)MI_DEBUG_MAPPING, (PVOID)MI_DEBUG_MAPPING);
257 MmDebugPte = MiAddressToPte((PVOID)MI_DEBUG_MAPPING);
258 #endif
259
260 /* Setup PDE and PTEs for VAD bitmap and working set list */
261 MiMapPDEs((PVOID)MI_VAD_BITMAP, (PVOID)(MI_WORKING_SET_LIST + PAGE_SIZE - 1));
262 MiMapPTEs((PVOID)MI_VAD_BITMAP, (PVOID)(MI_WORKING_SET_LIST + PAGE_SIZE - 1));
263 }
264
265 VOID
266 NTAPI
267 INIT_FUNCTION
268 MiBuildNonPagedPool(VOID)
269 {
270 /* Check if this is a machine with less than 256MB of RAM, and no overide */
271 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
272 !(MmSizeOfNonPagedPoolInBytes))
273 {
274 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
275 MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
276 }
277
278 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
279 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
280 (MmNumberOfPhysicalPages * 7 / 8))
281 {
282 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
283 MmSizeOfNonPagedPoolInBytes = 0;
284 }
285
286 /* Check if no registry setting was set, or if the setting was too low */
287 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
288 {
289 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
290 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
291 MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
292 256 * MmMinAdditionNonPagedPoolPerMb;
293 }
294
295 /* Check if the registy setting or our dynamic calculation was too high */
296 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
297 {
298 /* Set it to the maximum */
299 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
300 }
301
302 /* Check if a percentage cap was set through the registry */
303 if (MmMaximumNonPagedPoolPercent)
304 {
305 /* Don't feel like supporting this right now */
306 UNIMPLEMENTED;
307 }
308
309 /* Page-align the nonpaged pool size */
310 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
311
312 /* Now, check if there was a registry size for the maximum size */
313 if (!MmMaximumNonPagedPoolInBytes)
314 {
315 /* Start with the default (1MB) and add 400 KB for each MB above 4 */
316 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
317 MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
318 256 * MmMaxAdditionNonPagedPoolPerMb;
319 }
320
321 /* Don't let the maximum go too high */
322 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
323 {
324 /* Set it to the upper limit */
325 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
326 }
327
328 /* Convert nonpaged pool size from bytes to pages */
329 MmMaximumNonPagedPoolInPages = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT;
330
331 /* Non paged pool starts after the PFN database */
332 MmNonPagedPoolStart = MmPfnDatabase + MxPfnAllocation * PAGE_SIZE;
333
334 /* Calculate the nonpaged pool expansion start region */
335 MmNonPagedPoolExpansionStart = (PCHAR)MmNonPagedPoolStart +
336 MmSizeOfNonPagedPoolInBytes;
337 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart));
338
339 /* And this is where the none paged pool ends */
340 MmNonPagedPoolEnd = (PCHAR)MmNonPagedPoolStart + MmMaximumNonPagedPoolInBytes;
341 ASSERT(MmNonPagedPoolEnd < (PVOID)MM_HAL_VA_START);
342
343 /* Map PPEs and PDEs for non paged pool (including expansion) */
344 MiMapPPEs(MmNonPagedPoolStart, MmNonPagedPoolEnd);
345 MiMapPDEs(MmNonPagedPoolStart, MmNonPagedPoolEnd);
346
347 /* Map the nonpaged pool PTEs (without expansion) */
348 MiMapPTEs(MmNonPagedPoolStart, (PCHAR)MmNonPagedPoolExpansionStart - 1);
349
350 /* Initialize the ARM3 nonpaged pool */
351 MiInitializeNonPagedPool();
352 MiInitializeNonPagedPoolThresholds();
353
354 }
355
356 VOID
357 NTAPI
358 INIT_FUNCTION
359 MiBuildSystemPteSpace()
360 {
361 PMMPTE PointerPte;
362
363 /* Use the default numer of system PTEs */
364 MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES;
365 MiNonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE;
366
367 /* Put system PTEs at the start of the system VA space */
368 MiSystemPteSpaceStart = MmNonPagedSystemStart;
369 MiSystemPteSpaceEnd = (PUCHAR)MiSystemPteSpaceStart + MiNonPagedSystemSize;
370
371 /* Map the PPEs and PDEs for the system PTEs */
372 MiMapPPEs(MiSystemPteSpaceStart, MiSystemPteSpaceEnd);
373 MiMapPDEs(MiSystemPteSpaceStart, MiSystemPteSpaceEnd);
374
375 /* Initialize the system PTE space */
376 PointerPte = MiAddressToPte(MiSystemPteSpaceStart);
377 MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
378
379 /* Reserve system PTEs for zeroing PTEs and clear them */
380 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES, SystemPteSpace);
381 RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
382
383 /* Set the counter to maximum */
384 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
385 }
386
387 static
388 VOID
389 MiSetupPfnForPageTable(
390 PFN_NUMBER PageFrameIndex,
391 PMMPTE PointerPte)
392 {
393 PMMPFN Pfn;
394 PMMPDE PointerPde;
395
396 /* Get the pfn entry for this page */
397 Pfn = MiGetPfnEntry(PageFrameIndex);
398
399 /* Check if it's valid memory */
400 if ((PageFrameIndex <= MmHighestPhysicalPage) &&
401 (MmIsAddressValid(Pfn)) &&
402 (Pfn->u3.e1.PageLocation == ActiveAndValid))
403 {
404 /* Setup the PFN entry */
405 Pfn->u1.WsIndex = 0;
406 Pfn->u2.ShareCount++;
407 Pfn->PteAddress = PointerPte;
408 Pfn->OriginalPte = *PointerPte;
409 Pfn->u3.e1.PageLocation = ActiveAndValid;
410 Pfn->u3.e1.CacheAttribute = MiNonCached;
411 Pfn->u3.e2.ReferenceCount = 1;
412 Pfn->u4.PteFrame = PFN_FROM_PTE(MiAddressToPte(PointerPte));
413 }
414
415 /* Increase the shared count of the PFN entry for the PDE */
416 PointerPde = MiAddressToPde(MiPteToAddress(PointerPte));
417 Pfn = MiGetPfnEntry(PFN_FROM_PTE(PointerPde));
418 Pfn->u2.ShareCount++;
419 }
420
421 VOID
422 NTAPI
423 MiBuildPfnDatabaseFromPageTables(VOID)
424 {
425 PVOID Address = NULL;
426 PFN_NUMBER PageFrameIndex;
427 PMMPDE PointerPde;
428 PMMPTE PointerPte;
429 ULONG k, l;
430 PMMPFN Pfn;
431 #if (_MI_PAGING_LEVELS >= 3)
432 PMMPDE PointerPpe;
433 ULONG j;
434 #endif
435 #if (_MI_PAGING_LEVELS == 4)
436 PMMPDE PointerPxe;
437 ULONG i;
438 #endif
439
440 /* Manual setup of the top level page directory */
441 #if (_MI_PAGING_LEVELS == 4)
442 PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(PXE_BASE));
443 #elif (_MI_PAGING_LEVELS == 3)
444 PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(PPE_BASE));
445 #else
446 PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(PDE_BASE));
447 #endif
448 Pfn = MiGetPfnEntry(PageFrameIndex);
449 ASSERT(Pfn->u3.e1.PageLocation == ActiveAndValid);
450 Pfn->u1.WsIndex = 0;
451 Pfn->u2.ShareCount = 1;
452 Pfn->PteAddress = NULL;
453 Pfn->u3.e1.CacheAttribute = MiNonCached;
454 Pfn->u3.e2.ReferenceCount = 1;
455 Pfn->u4.PteFrame = 0;
456
457 #if (_MI_PAGING_LEVELS == 4)
458 /* Loop all PXEs in the PML4 */
459 PointerPxe = MiAddressToPxe(Address);
460 for (i = 0; i < PXE_PER_PAGE; i++, PointerPxe++)
461 {
462 /* Skip invalid PXEs */
463 if (!PointerPxe->u.Hard.Valid) continue;
464
465 /* Handle the PFN */
466 PageFrameIndex = PFN_FROM_PXE(PointerPxe);
467 MiSetupPfnForPageTable(PageFrameIndex, PointerPxe);
468
469 /* Get starting VA for this PXE */
470 Address = MiPxeToAddress(PointerPxe);
471 #endif
472 #if (_MI_PAGING_LEVELS >= 3)
473 /* Loop all PPEs in this PDP */
474 PointerPpe = MiAddressToPpe(Address);
475 for (j = 0; j < PPE_PER_PAGE; j++, PointerPpe++)
476 {
477 /* Skip invalid PPEs */
478 if (!PointerPpe->u.Hard.Valid) continue;
479
480 /* Handle the PFN */
481 PageFrameIndex = PFN_FROM_PPE(PointerPpe);
482 MiSetupPfnForPageTable(PageFrameIndex, PointerPpe);
483
484 /* Get starting VA for this PPE */
485 Address = MiPpeToAddress(PointerPpe);
486 #endif
487 /* Loop all PDEs in this PD */
488 PointerPde = MiAddressToPde(Address);
489 for (k = 0; k < PDE_PER_PAGE; k++, PointerPde++)
490 {
491 /* Skip invalid PDEs */
492 if (!PointerPde->u.Hard.Valid) continue;
493
494 /* Handle the PFN */
495 PageFrameIndex = PFN_FROM_PDE(PointerPde);
496 MiSetupPfnForPageTable(PageFrameIndex, PointerPde);
497
498 /* Get starting VA for this PDE */
499 Address = MiPdeToAddress(PointerPde);
500
501 /* Loop all PTEs in this PT */
502 PointerPte = MiAddressToPte(Address);
503 for (l = 0; l < PTE_PER_PAGE; l++, PointerPte++)
504 {
505 /* Skip invalid PTEs */
506 if (!PointerPte->u.Hard.Valid) continue;
507
508 /* Handle the PFN */
509 PageFrameIndex = PFN_FROM_PTE(PointerPte);
510 MiSetupPfnForPageTable(PageFrameIndex, PointerPte);
511 }
512 }
513 #if (_MI_PAGING_LEVELS >= 3)
514 }
515 #endif
516 #if (_MI_PAGING_LEVELS == 4)
517 }
518 #endif
519 }
520
521 VOID
522 NTAPI
523 INIT_FUNCTION
524 MiAddDescriptorToDatabase(
525 PFN_NUMBER BasePage,
526 PFN_NUMBER PageCount,
527 TYPE_OF_MEMORY MemoryType)
528 {
529 PMMPFN Pfn;
530
531 ASSERT(!MiIsMemoryTypeInvisible(MemoryType));
532
533 /* Check if the memory is free */
534 if (MiIsMemoryTypeFree(MemoryType))
535 {
536 /* Get the last pfn of this descriptor. Note we loop backwards */
537 Pfn = &MmPfnDatabase[BasePage + PageCount - 1];
538
539 /* Loop all pages */
540 while (PageCount--)
541 {
542 /* Add it to the free list */
543 Pfn->u3.e1.CacheAttribute = MiNonCached;
544 MiInsertPageInFreeList(BasePage + PageCount);
545
546 /* Go to the previous page */
547 Pfn--;
548 }
549 }
550 else if (MemoryType == LoaderXIPRom)
551 {
552 Pfn = &MmPfnDatabase[BasePage];
553 while (PageCount--)
554 {
555 /* Make it a pseudo-I/O ROM mapping */
556 Pfn->PteAddress = 0;
557 Pfn->u1.Flink = 0;
558 Pfn->u2.ShareCount = 0;
559 Pfn->u3.e1.PageLocation = 0;
560 Pfn->u3.e1.CacheAttribute = MiNonCached;
561 Pfn->u3.e1.Rom = 1;
562 Pfn->u3.e1.PrototypePte = 1;
563 Pfn->u3.e2.ReferenceCount = 0;
564 Pfn->u4.InPageError = 0;
565 Pfn->u4.PteFrame = 0;
566
567 /* Advance one */
568 Pfn++;
569 }
570 }
571 else if (MemoryType == LoaderBad)
572 {
573 // FIXME: later
574 ASSERT(FALSE);
575 }
576 else
577 {
578 /* For now skip it */
579 DbgPrint("Skipping BasePage=0x%lx, PageCount=0x%lx, MemoryType=%lx\n",
580 BasePage, PageCount, MemoryType);
581 Pfn = &MmPfnDatabase[BasePage];
582 while (PageCount--)
583 {
584 /* Make an active PFN */
585 Pfn->u3.e1.PageLocation = ActiveAndValid;
586
587 /* Advance one */
588 Pfn++;
589 }
590 }
591 }
592
593 VOID
594 NTAPI
595 INIT_FUNCTION
596 MiBuildPfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
597 {
598 PLIST_ENTRY ListEntry;
599 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
600 PFN_NUMBER BasePage, PageCount;
601
602 /* Map the PDEs and PPEs for the pfn database (ignore holes) */
603 #if (_MI_PAGING_LEVELS >= 3)
604 MiMapPPEs(MmPfnDatabase, (PUCHAR)MmPfnDatabase + MxPfnAllocation - 1);
605 #endif
606 MiMapPDEs(MmPfnDatabase, (PUCHAR)MmPfnDatabase + MxPfnAllocation - 1);
607
608 /* First initialize the color tables */
609 MiInitializeColorTables();
610
611 /* Loop the memory descriptors */
612 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
613 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
614 ListEntry = ListEntry->Flink)
615 {
616 /* Get the descriptor */
617 Descriptor = CONTAINING_RECORD(ListEntry,
618 MEMORY_ALLOCATION_DESCRIPTOR,
619 ListEntry);
620
621 /* Skip invisible memory */
622 if (MiIsMemoryTypeInvisible(Descriptor->MemoryType)) continue;
623
624 /* If this is the free descriptor, use the copy instead */
625 if (Descriptor == MxFreeDescriptor) Descriptor = &MxOldFreeDescriptor;
626
627 /* Get the range for this descriptor */
628 BasePage = Descriptor->BasePage;
629 PageCount = Descriptor->PageCount;
630
631 /* Map the pages for the database */
632 MiMapPTEs(&MmPfnDatabase[BasePage],
633 (PUCHAR)(&MmPfnDatabase[BasePage + PageCount]) - 1);
634
635 /* If this was the free descriptor, skip the next step */
636 if (Descriptor == &MxOldFreeDescriptor) continue;
637
638 /* Add this descriptor to the database */
639 MiAddDescriptorToDatabase(BasePage, PageCount, Descriptor->MemoryType);
640 }
641
642 /* At this point the whole pfn database is mapped. We are about to add the
643 pages from the free descriptor to the database, so from now on we cannot
644 use it anymore. */
645
646 /* Now add the free descriptor */
647 BasePage = MxFreeDescriptor->BasePage;
648 PageCount = MxFreeDescriptor->PageCount;
649 MiAddDescriptorToDatabase(BasePage, PageCount, LoaderFree);
650
651 /* And finally the memory we used */
652 BasePage = MxOldFreeDescriptor.BasePage;
653 PageCount = MxFreeDescriptor->BasePage - BasePage;
654 MiAddDescriptorToDatabase(BasePage, PageCount, LoaderMemoryData);
655
656 /* Reset the descriptor back so we can create the correct memory blocks */
657 *MxFreeDescriptor = MxOldFreeDescriptor;
658 }
659
660 NTSTATUS
661 NTAPI
662 INIT_FUNCTION
663 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
664 {
665 KIRQL OldIrql;
666
667 ASSERT(MxPfnAllocation != 0);
668
669 /* Set some hardcoded addresses */
670 MmHyperSpaceEnd = (PVOID)HYPER_SPACE_END;
671 MmNonPagedSystemStart = (PVOID)MM_SYSTEM_SPACE_START;
672 MmPfnDatabase = (PVOID)MI_PFN_DATABASE;
673 MmWorkingSetList = (PVOID)MI_WORKING_SET_LIST;
674
675
676 // PrototypePte.u.Proto.Valid = 1
677 // PrototypePte.u.ReadOnly
678 // PrototypePte.u.Prototype
679 // PrototypePte.u.Protection = MM_READWRITE;
680 // PrototypePte.u.ProtoAddress
681 PrototypePte.u.Soft.PageFileHigh = MI_PTE_LOOKUP_NEEDED;
682
683
684 MiInitializePageTable();
685
686 MiBuildNonPagedPool();
687
688 MiBuildSystemPteSpace();
689
690 /* Need to be at DISPATCH_LEVEL for MiInsertPageInFreeList */
691 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
692
693 /* Map the PFN database pages */
694 MiBuildPfnDatabase(LoaderBlock);
695
696 /* Now process the page tables */
697 MiBuildPfnDatabaseFromPageTables();
698
699 /* PFNs are initialized now! */
700 MiPfnsInitialized = TRUE;
701
702 //KeLowerIrql(OldIrql);
703
704 /* Need to be at DISPATCH_LEVEL for InitializePool */
705 //KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
706
707 /* Initialize the nonpaged pool */
708 InitializePool(NonPagedPool, 0);
709
710 KeLowerIrql(OldIrql);
711
712 /* Initialize the balancer */
713 MmInitializeBalancer((ULONG)MmAvailablePages, 0);
714
715 /* Make sure we have everything we need */
716 ASSERT(MmPfnDatabase);
717 ASSERT(MmNonPagedSystemStart);
718 ASSERT(MmNonPagedPoolStart);
719 ASSERT(MmSizeOfNonPagedPoolInBytes);
720 ASSERT(MmMaximumNonPagedPoolInBytes);
721 ASSERT(MmNonPagedPoolExpansionStart);
722 ASSERT(MmHyperSpaceEnd);
723 ASSERT(MmNumberOfSystemPtes);
724 ASSERT(MiAddressToPde(MmNonPagedPoolStart)->u.Hard.Valid);
725 ASSERT(MiAddressToPte(MmNonPagedPoolStart)->u.Hard.Valid);
726
727 return STATUS_SUCCESS;
728 }