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
7 * PROGRAMMERS: Timo kreuzer (timo.kreuzer@reactos.org)
8 * ReactOS Portable Systems Group
11 /* INCLUDES ***************************************************************/
17 #include "../ARM3/miarm.h"
20 extern PMMPTE MmDebugPte
;
23 /* GLOBALS *****************************************************************/
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
}};
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
}};
33 /* Template PTE for prototype page */
34 MMPTE PrototypePte
= {{(MM_READWRITE
<< MM_PTE_SOFTWARE_PROTECTION_BITS
) |
35 PTE_PROTOTYPE
| (MI_PTE_LOOKUP_NEEDED
<< PAGE_SHIFT
)}};
38 SIZE_T MiNonPagedSystemSize
;
41 PVOID MiSessionViewEnd
;
43 ULONG64 MxPfnSizeInBytes
;
44 BOOLEAN MiIncludeType
[LoaderMaximum
];
45 PFN_NUMBER MxFreePageBase
;
46 ULONG64 MxFreePageCount
= 0;
48 BOOLEAN MiPfnsInitialized
= FALSE
;
50 /* FUNCTIONS *****************************************************************/
55 MiInitializeSessionSpaceLayout()
57 MmSessionSize
= MI_SESSION_SIZE
;
58 MmSessionViewSize
= MI_SESSION_VIEW_SIZE
;
59 MmSessionPoolSize
= MI_SESSION_POOL_SIZE
;
60 MmSessionImageSize
= MI_SESSION_IMAGE_SIZE
;
61 MmSystemViewSize
= MI_SYSTEM_VIEW_SIZE
;
63 /* Set up session space */
64 MiSessionSpaceEnd
= (PVOID
)MI_SESSION_SPACE_END
;
66 /* This is where we will load Win32k.sys and the video driver */
67 MiSessionImageEnd
= MiSessionSpaceEnd
;
68 MiSessionImageStart
= (PCHAR
)MiSessionImageEnd
- MmSessionImageSize
;
70 /* The view starts right below the session working set (itself below
72 MiSessionViewEnd
= MI_SESSION_VIEW_END
;
73 MiSessionViewStart
= (PCHAR
)MiSessionViewEnd
- MmSessionViewSize
;
74 ASSERT(IS_PAGE_ALIGNED(MiSessionViewStart
));
76 /* Session pool follows */
77 MiSessionPoolEnd
= MiSessionViewStart
;
78 MiSessionPoolStart
= (PCHAR
)MiSessionPoolEnd
- MmSessionPoolSize
;
79 ASSERT(IS_PAGE_ALIGNED(MiSessionPoolStart
));
81 /* And it all begins here */
82 MmSessionBase
= MiSessionPoolStart
;
84 /* System view space ends at session space, so now that we know where
85 * this is, we can compute the base address of system view space itself. */
86 MiSystemViewStart
= (PCHAR
)MmSessionBase
- MmSystemViewSize
;
87 ASSERT(IS_PAGE_ALIGNED(MiSystemViewStart
));
90 ASSERT(MiSessionViewEnd
<= MiSessionImageStart
);
91 ASSERT(MmSessionBase
<= MiSessionPoolStart
);
101 MMPDE TmplPde
= ValidKernelPde
;
104 for (PointerPpe
= MiAddressToPpe(StartAddress
);
105 PointerPpe
<= MiAddressToPpe(EndAddress
);
108 /* Check if its already mapped */
109 if (!PointerPpe
->u
.Hard
.Valid
)
112 TmplPde
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
113 *PointerPpe
= TmplPde
;
115 /* Zero out the page table */
116 RtlZeroMemory(MiPteToAddress(PointerPpe
), PAGE_SIZE
);
128 MMPDE TmplPde
= ValidKernelPde
;
131 for (PointerPde
= MiAddressToPde(StartAddress
);
132 PointerPde
<= MiAddressToPde(EndAddress
);
135 /* Check if its already mapped */
136 if (!PointerPde
->u
.Hard
.Valid
)
139 TmplPde
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
140 *PointerPde
= TmplPde
;
142 /* Zero out the page table */
143 RtlZeroMemory(MiPteToAddress(PointerPde
), PAGE_SIZE
);
155 MMPTE TmplPte
= ValidKernelPte
;
158 for (PointerPte
= MiAddressToPte(StartAddress
);
159 PointerPte
<= MiAddressToPte(EndAddress
);
162 /* Check if its already mapped */
163 if (!PointerPte
->u
.Hard
.Valid
)
166 TmplPte
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
167 *PointerPte
= TmplPte
;
175 MiInitializePageTable()
177 ULONG64 PxePhysicalAddress
;
178 MMPTE TmplPte
, *PointerPxe
;
181 /* Get current directory base */
182 PxePfn
= ((PMMPTE
)PXE_SELFMAP
)->u
.Hard
.PageFrameNumber
;
183 PxePhysicalAddress
= PxePfn
<< PAGE_SHIFT
;
184 ASSERT(PxePhysicalAddress
== __readcr3());
186 /* Set directory base for the system process */
187 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0] = PxePhysicalAddress
;
189 /* Enable global pages */
190 __writecr4(__readcr4() | CR4_PGE
);
191 ASSERT(__readcr4() & CR4_PGE
);
193 /* Enable no execute */
194 __writemsr(X86_MSR_EFER
, __readmsr(X86_MSR_EFER
) | EFER_NXE
);
196 /* Loop the user mode PXEs */
197 for (PointerPxe
= MiAddressToPxe(0);
198 PointerPxe
<= MiAddressToPxe(MmHighestUserAddress
);
201 /* Zero the PXE, clear all mappings */
202 PointerPxe
->u
.Long
= 0;
208 /* Set up a template PTE */
210 TmplPte
.u
.Flush
.Valid
= 1;
211 TmplPte
.u
.Flush
.Write
= 1;
212 HyperTemplatePte
= TmplPte
;
214 /* Create PDPTs (72 KB) for shared system address space,
215 * skip page tables and hyperspace */
218 for (PointerPxe
= MiAddressToPxe((PVOID
)(HYPER_SPACE_END
+ 1));
219 PointerPxe
<= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS
);
222 /* Is the PXE already valid? */
223 if (!PointerPxe
->u
.Hard
.Valid
)
225 /* It's not Initialize it */
226 TmplPte
.u
.Flush
.PageFrameNumber
= MxGetNextPage(1);
227 *PointerPxe
= TmplPte
;
229 /* Zero the page. The PXE is the PTE for the PDPT. */
230 RtlZeroMemory(MiPteToAddress(PointerPxe
), PAGE_SIZE
);
234 /* Setup the mapping PPEs and PDEs */
235 MiMapPPEs((PVOID
)MI_MAPPING_RANGE_START
, (PVOID
)MI_MAPPING_RANGE_END
);
236 MiMapPDEs((PVOID
)MI_MAPPING_RANGE_START
, (PVOID
)MI_MAPPING_RANGE_END
);
238 /* Setup the mapping PTEs */
239 MmFirstReservedMappingPte
= MiAddressToPte((PVOID
)MI_MAPPING_RANGE_START
);
240 MmLastReservedMappingPte
= MiAddressToPte((PVOID
)MI_MAPPING_RANGE_END
);
241 MmFirstReservedMappingPte
->u
.Hard
.PageFrameNumber
= MI_HYPERSPACE_PTES
;
244 /* Setup debug mapping PTE */
245 MiMapPPEs((PVOID
)MI_DEBUG_MAPPING
, (PVOID
)MI_DEBUG_MAPPING
);
246 MiMapPDEs((PVOID
)MI_DEBUG_MAPPING
, (PVOID
)MI_DEBUG_MAPPING
);
247 MmDebugPte
= MiAddressToPte((PVOID
)MI_DEBUG_MAPPING
);
254 MiBuildNonPagedPool(VOID
)
256 /* Check if this is a machine with less than 256MB of RAM, and no overide */
257 if ((MmNumberOfPhysicalPages
<= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING
) &&
258 !(MmSizeOfNonPagedPoolInBytes
))
260 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
261 MmSizeOfNonPagedPoolInBytes
= 2 * 1024 * 1024;
264 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
265 if ((MmSizeOfNonPagedPoolInBytes
>> PAGE_SHIFT
) >
266 (MmNumberOfPhysicalPages
* 7 / 8))
268 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
269 MmSizeOfNonPagedPoolInBytes
= 0;
272 /* Check if no registry setting was set, or if the setting was too low */
273 if (MmSizeOfNonPagedPoolInBytes
< MmMinimumNonPagedPoolSize
)
275 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
276 MmSizeOfNonPagedPoolInBytes
= MmMinimumNonPagedPoolSize
;
277 MmSizeOfNonPagedPoolInBytes
+= (MmNumberOfPhysicalPages
- 1024) /
278 256 * MmMinAdditionNonPagedPoolPerMb
;
281 /* Check if the registy setting or our dynamic calculation was too high */
282 if (MmSizeOfNonPagedPoolInBytes
> MI_MAX_INIT_NONPAGED_POOL_SIZE
)
284 /* Set it to the maximum */
285 MmSizeOfNonPagedPoolInBytes
= MI_MAX_INIT_NONPAGED_POOL_SIZE
;
288 /* Check if a percentage cap was set through the registry */
289 if (MmMaximumNonPagedPoolPercent
)
291 /* Don't feel like supporting this right now */
295 /* Page-align the nonpaged pool size */
296 MmSizeOfNonPagedPoolInBytes
&= ~(PAGE_SIZE
- 1);
298 /* Now, check if there was a registry size for the maximum size */
299 if (!MmMaximumNonPagedPoolInBytes
)
301 /* Start with the default (1MB) and add 400 KB for each MB above 4 */
302 MmMaximumNonPagedPoolInBytes
= MmDefaultMaximumNonPagedPool
;
303 MmMaximumNonPagedPoolInBytes
+= (MmNumberOfPhysicalPages
- 1024) /
304 256 * MmMaxAdditionNonPagedPoolPerMb
;
307 /* Don't let the maximum go too high */
308 if (MmMaximumNonPagedPoolInBytes
> MI_MAX_NONPAGED_POOL_SIZE
)
310 /* Set it to the upper limit */
311 MmMaximumNonPagedPoolInBytes
= MI_MAX_NONPAGED_POOL_SIZE
;
314 /* Put non paged pool to the end of the region */
315 MmNonPagedPoolStart
= (PCHAR
)MmNonPagedPoolEnd
- MmMaximumNonPagedPoolInBytes
;
317 /* Make sure it doesn't collide with the PFN database */
318 if ((PCHAR
)MmNonPagedPoolStart
< (PCHAR
)MmPfnDatabase
+ MxPfnSizeInBytes
)
320 /* Put non paged pool after the PFN database */
321 MmNonPagedPoolStart
= (PCHAR
)MmPfnDatabase
+ MxPfnSizeInBytes
;
322 MmMaximumNonPagedPoolInBytes
= (ULONG64
)MmNonPagedPoolEnd
-
323 (ULONG64
)MmNonPagedPoolStart
;
326 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolStart
));
328 /* Calculate the nonpaged pool expansion start region */
329 MmNonPagedPoolExpansionStart
= (PCHAR
)MmNonPagedPoolStart
+
330 MmSizeOfNonPagedPoolInBytes
;
331 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart
));
333 /* Map PPEs and PDEs for non paged pool (including expansion) */
334 MiMapPPEs(MmNonPagedPoolStart
, MmNonPagedPoolEnd
);
335 MiMapPDEs(MmNonPagedPoolStart
, MmNonPagedPoolEnd
);
337 /* Map the nonpaged pool PTEs (without expansion) */
338 MiMapPTEs(MmNonPagedPoolStart
, (PUCHAR
)MmNonPagedPoolExpansionStart
- 1);
340 /* Initialize the ARM3 nonpaged pool */
341 MiInitializeNonPagedPool();
343 /* Initialize the nonpaged pool */
344 InitializePool(NonPagedPool
, 0);
350 MiBuildSystemPteSpace()
354 /* Use the default numer of system PTEs */
355 MmNumberOfSystemPtes
= MI_NUMBER_SYSTEM_PTES
;
357 /* System PTE pool is below the PFN database */
358 MiNonPagedSystemSize
= (MmNumberOfSystemPtes
+ 1) * PAGE_SIZE
;
359 MmNonPagedSystemStart
= (PCHAR
)MmPfnDatabase
- MiNonPagedSystemSize
;
360 MmNonPagedSystemStart
= MM_ROUND_DOWN(MmNonPagedSystemStart
, 512 * PAGE_SIZE
);
362 /* Don't let it go below the minimum */
363 if (MmNonPagedSystemStart
< (PVOID
)MI_NON_PAGED_SYSTEM_START_MIN
)
365 /* This is a hard-coded limit in the Windows NT address space */
366 MmNonPagedSystemStart
= (PVOID
)MI_NON_PAGED_SYSTEM_START_MIN
;
368 /* Reduce the amount of system PTEs to reach this point */
369 MmNumberOfSystemPtes
= (ULONG
)(((ULONG64
)MmPfnDatabase
-
370 (ULONG64
)MmNonPagedSystemStart
) >>
372 MmNumberOfSystemPtes
--;
373 ASSERT(MmNumberOfSystemPtes
> 1000);
376 /* Map the PDEs and PPEs for the system PTEs */
377 MiMapPPEs(MI_SYSTEM_PTE_START
, MI_SYSTEM_PTE_END
);
378 MiMapPDEs(MI_SYSTEM_PTE_START
, MI_SYSTEM_PTE_END
);
380 /* Create the system PTE space */
381 PointerPte
= MiAddressToPte(MI_SYSTEM_PTE_START
);
382 MiInitializeSystemPtes(PointerPte
, MmNumberOfSystemPtes
, SystemPteSpace
);
384 /* Reserve system PTEs for zeroing PTEs and clear them */
385 MiFirstReservedZeroingPte
= MiReserveSystemPtes(MI_ZERO_PTES
, SystemPteSpace
);
386 RtlZeroMemory(MiFirstReservedZeroingPte
, MI_ZERO_PTES
* sizeof(MMPTE
));
388 /* Set the counter to maximum */
389 MiFirstReservedZeroingPte
->u
.Hard
.PageFrameNumber
= MI_ZERO_PTES
- 1;
395 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
398 MmHyperSpaceEnd
= (PVOID
)HYPER_SPACE_END
;
400 MiInitializePageTable();
402 MiBuildNonPagedPool();
404 MiBuildSystemPteSpace();
406 return STATUS_SUCCESS
;