[CLT2012]
[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 << PAGE_SHIFT)}};
36
37 /* Sizes */
38 SIZE_T MiNonPagedSystemSize;
39
40 /* Address ranges */
41 PVOID MiSessionViewEnd;
42
43 ULONG64 MxPfnSizeInBytes;
44 BOOLEAN MiIncludeType[LoaderMaximum];
45 PFN_NUMBER MxFreePageBase;
46 ULONG64 MxFreePageCount = 0;
47
48 BOOLEAN MiPfnsInitialized = FALSE;
49
50 /* FUNCTIONS *****************************************************************/
51
52 VOID
53 NTAPI
54 INIT_FUNCTION
55 MiInitializeSessionSpaceLayout()
56 {
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;
62
63 /* Set up session space */
64 MiSessionSpaceEnd = (PVOID)MI_SESSION_SPACE_END;
65
66 /* This is where we will load Win32k.sys and the video driver */
67 MiSessionImageEnd = MiSessionSpaceEnd;
68 MiSessionImageStart = (PCHAR)MiSessionImageEnd - MmSessionImageSize;
69
70 /* The view starts right below the session working set (itself below
71 * the image area) */
72 MiSessionViewEnd = MI_SESSION_VIEW_END;
73 MiSessionViewStart = (PCHAR)MiSessionViewEnd - MmSessionViewSize;
74 ASSERT(IS_PAGE_ALIGNED(MiSessionViewStart));
75
76 /* Session pool follows */
77 MiSessionPoolEnd = MiSessionViewStart;
78 MiSessionPoolStart = (PCHAR)MiSessionPoolEnd - MmSessionPoolSize;
79 ASSERT(IS_PAGE_ALIGNED(MiSessionPoolStart));
80
81 /* And it all begins here */
82 MmSessionBase = MiSessionPoolStart;
83
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));
88
89 /* Sanity checks */
90 ASSERT(MiSessionViewEnd <= MiSessionImageStart);
91 ASSERT(MmSessionBase <= MiSessionPoolStart);
92 }
93
94 VOID
95 NTAPI
96 MiMapPPEs(
97 PVOID StartAddress,
98 PVOID EndAddress)
99 {
100 PMMPDE PointerPpe;
101 MMPDE TmplPde = ValidKernelPde;
102
103 /* Loop the PPEs */
104 for (PointerPpe = MiAddressToPpe(StartAddress);
105 PointerPpe <= MiAddressToPpe(EndAddress);
106 PointerPpe++)
107 {
108 /* Check if its already mapped */
109 if (!PointerPpe->u.Hard.Valid)
110 {
111 /* No, map it! */
112 TmplPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
113 *PointerPpe = TmplPde;
114
115 /* Zero out the page table */
116 RtlZeroMemory(MiPteToAddress(PointerPpe), PAGE_SIZE);
117 }
118 }
119 }
120
121 VOID
122 NTAPI
123 MiMapPDEs(
124 PVOID StartAddress,
125 PVOID EndAddress)
126 {
127 PMMPDE PointerPde;
128 MMPDE TmplPde = ValidKernelPde;
129
130 /* Loop the PDEs */
131 for (PointerPde = MiAddressToPde(StartAddress);
132 PointerPde <= MiAddressToPde(EndAddress);
133 PointerPde++)
134 {
135 /* Check if its already mapped */
136 if (!PointerPde->u.Hard.Valid)
137 {
138 /* No, map it! */
139 TmplPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
140 *PointerPde = TmplPde;
141
142 /* Zero out the page table */
143 RtlZeroMemory(MiPteToAddress(PointerPde), PAGE_SIZE);
144 }
145 }
146 }
147
148 VOID
149 NTAPI
150 MiMapPTEs(
151 PVOID StartAddress,
152 PVOID EndAddress)
153 {
154 PMMPTE PointerPte;
155 MMPTE TmplPte = ValidKernelPte;
156
157 /* Loop the PTEs */
158 for (PointerPte = MiAddressToPte(StartAddress);
159 PointerPte <= MiAddressToPte(EndAddress);
160 PointerPte++)
161 {
162 /* Check if its already mapped */
163 if (!PointerPte->u.Hard.Valid)
164 {
165 /* No, map it! */
166 TmplPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
167 *PointerPte = TmplPte;
168 }
169 }
170 }
171
172 VOID
173 NTAPI
174 INIT_FUNCTION
175 MiInitializePageTable()
176 {
177 ULONG64 PxePhysicalAddress;
178 MMPTE TmplPte, *PointerPxe;
179 PFN_NUMBER PxePfn;
180
181 /* Get current directory base */
182 PxePfn = ((PMMPTE)PXE_SELFMAP)->u.Hard.PageFrameNumber;
183 PxePhysicalAddress = PxePfn << PAGE_SHIFT;
184 ASSERT(PxePhysicalAddress == __readcr3());
185
186 /* Set directory base for the system process */
187 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PxePhysicalAddress;
188
189 /* Enable global pages */
190 __writecr4(__readcr4() | CR4_PGE);
191 ASSERT(__readcr4() & CR4_PGE);
192
193 /* Enable no execute */
194 __writemsr(X86_MSR_EFER, __readmsr(X86_MSR_EFER) | EFER_NXE);
195
196 /* Loop the user mode PXEs */
197 for (PointerPxe = MiAddressToPxe(0);
198 PointerPxe <= MiAddressToPxe(MmHighestUserAddress);
199 PointerPxe++)
200 {
201 /* Zero the PXE, clear all mappings */
202 PointerPxe->u.Long = 0;
203 }
204
205 /* Flush the TLB */
206 KeFlushCurrentTb();
207
208 /* Set up a template PTE */
209 TmplPte.u.Long = 0;
210 TmplPte.u.Flush.Valid = 1;
211 TmplPte.u.Flush.Write = 1;
212 HyperTemplatePte = TmplPte;
213
214 /* Create PDPTs (72 KB) for shared system address space,
215 * skip page tables and hyperspace */
216
217 /* Loop the PXEs */
218 for (PointerPxe = MiAddressToPxe((PVOID)(HYPER_SPACE_END + 1));
219 PointerPxe <= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS);
220 PointerPxe++)
221 {
222 /* Is the PXE already valid? */
223 if (!PointerPxe->u.Hard.Valid)
224 {
225 /* It's not Initialize it */
226 TmplPte.u.Flush.PageFrameNumber = MxGetNextPage(1);
227 *PointerPxe = TmplPte;
228
229 /* Zero the page. The PXE is the PTE for the PDPT. */
230 RtlZeroMemory(MiPteToAddress(PointerPxe), PAGE_SIZE);
231 }
232 }
233
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);
237
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;
242
243 #ifdef _WINKD_
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);
248 #endif
249 }
250
251 VOID
252 NTAPI
253 INIT_FUNCTION
254 MiBuildNonPagedPool(VOID)
255 {
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))
259 {
260 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
261 MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
262 }
263
264 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
265 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
266 (MmNumberOfPhysicalPages * 7 / 8))
267 {
268 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
269 MmSizeOfNonPagedPoolInBytes = 0;
270 }
271
272 /* Check if no registry setting was set, or if the setting was too low */
273 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
274 {
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;
279 }
280
281 /* Check if the registy setting or our dynamic calculation was too high */
282 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
283 {
284 /* Set it to the maximum */
285 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
286 }
287
288 /* Check if a percentage cap was set through the registry */
289 if (MmMaximumNonPagedPoolPercent)
290 {
291 /* Don't feel like supporting this right now */
292 UNIMPLEMENTED;
293 }
294
295 /* Page-align the nonpaged pool size */
296 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
297
298 /* Now, check if there was a registry size for the maximum size */
299 if (!MmMaximumNonPagedPoolInBytes)
300 {
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;
305 }
306
307 /* Don't let the maximum go too high */
308 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
309 {
310 /* Set it to the upper limit */
311 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
312 }
313
314 /* Put non paged pool to the end of the region */
315 MmNonPagedPoolStart = (PCHAR)MmNonPagedPoolEnd - MmMaximumNonPagedPoolInBytes;
316
317 /* Make sure it doesn't collide with the PFN database */
318 if ((PCHAR)MmNonPagedPoolStart < (PCHAR)MmPfnDatabase + MxPfnSizeInBytes)
319 {
320 /* Put non paged pool after the PFN database */
321 MmNonPagedPoolStart = (PCHAR)MmPfnDatabase + MxPfnSizeInBytes;
322 MmMaximumNonPagedPoolInBytes = (ULONG64)MmNonPagedPoolEnd -
323 (ULONG64)MmNonPagedPoolStart;
324 }
325
326 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolStart));
327
328 /* Calculate the nonpaged pool expansion start region */
329 MmNonPagedPoolExpansionStart = (PCHAR)MmNonPagedPoolStart +
330 MmSizeOfNonPagedPoolInBytes;
331 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart));
332
333 /* Map PPEs and PDEs for non paged pool (including expansion) */
334 MiMapPPEs(MmNonPagedPoolStart, MmNonPagedPoolEnd);
335 MiMapPDEs(MmNonPagedPoolStart, MmNonPagedPoolEnd);
336
337 /* Map the nonpaged pool PTEs (without expansion) */
338 MiMapPTEs(MmNonPagedPoolStart, (PUCHAR)MmNonPagedPoolExpansionStart - 1);
339
340 /* Initialize the ARM3 nonpaged pool */
341 MiInitializeNonPagedPool();
342
343 /* Initialize the nonpaged pool */
344 InitializePool(NonPagedPool, 0);
345 }
346
347 VOID
348 NTAPI
349 INIT_FUNCTION
350 MiBuildSystemPteSpace()
351 {
352 PMMPTE PointerPte;
353
354 /* Use the default numer of system PTEs */
355 MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES;
356
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);
361
362 /* Don't let it go below the minimum */
363 if (MmNonPagedSystemStart < (PVOID)MI_NON_PAGED_SYSTEM_START_MIN)
364 {
365 /* This is a hard-coded limit in the Windows NT address space */
366 MmNonPagedSystemStart = (PVOID)MI_NON_PAGED_SYSTEM_START_MIN;
367
368 /* Reduce the amount of system PTEs to reach this point */
369 MmNumberOfSystemPtes = (ULONG)(((ULONG64)MmPfnDatabase -
370 (ULONG64)MmNonPagedSystemStart) >>
371 PAGE_SHIFT);
372 MmNumberOfSystemPtes--;
373 ASSERT(MmNumberOfSystemPtes > 1000);
374 }
375
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);
379
380 /* Create the system PTE space */
381 PointerPte = MiAddressToPte(MI_SYSTEM_PTE_START);
382 MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
383
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));
387
388 /* Set the counter to maximum */
389 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
390 }
391
392 NTSTATUS
393 NTAPI
394 INIT_FUNCTION
395 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
396 {
397
398 MmHyperSpaceEnd = (PVOID)HYPER_SPACE_END;
399
400 MiInitializePageTable();
401
402 MiBuildNonPagedPool();
403
404 MiBuildSystemPteSpace();
405
406 return STATUS_SUCCESS;
407 }