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