fix build of ntoskrnl
[reactos.git] / reactos / ntoskrnl / mm / amd64 / init.c
1 /*
2 * COPYRIGHT: 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 */
9
10 /* INCLUDES ***************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #include "../ARM3/miarm.h"
17
18 #define MI_SESSION_SPACE_END (PVOID)0xFFFFF98000000000ULL
19 #define MI_SESSION_VIEW_END 0xFFFFF97FFF000000ULL
20 #define MI_NON_PAGED_SYSTEM_START_MIN 0x0FFFFFAA000000000ULL
21
22 /* GLOBALS *****************************************************************/
23
24 ULONG64 MmUserProbeAddress = 0x7FFFFFF0000ULL;
25 PVOID MmHighestUserAddress = (PVOID)0x7FFFFFEFFFFULL;
26 PVOID MmSystemRangeStart = (PVOID)KSEG0_BASE; // FFFF080000000000
27
28 /* Size of session view, pool, and image */
29 ULONG64 MmSessionSize = MI_SESSION_SIZE;
30 ULONG64 MmSessionViewSize = MI_SESSION_VIEW_SIZE;
31 ULONG64 MmSessionPoolSize = MI_SESSION_POOL_SIZE;
32 ULONG64 MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
33
34 /* Session space addresses */
35 PVOID MiSessionSpaceEnd = MI_SESSION_SPACE_END; // FFFFF98000000000
36 PVOID MiSessionImageEnd; // FFFFF98000000000 = MiSessionSpaceEnd
37 PVOID MiSessionImageStart; // ?FFFFF97FFF000000 = MiSessionImageEnd - MmSessionImageSize
38 PVOID MiSessionViewEnd; // FFFFF97FFF000000
39 PVOID MiSessionViewStart; // = MiSessionViewEnd - MmSessionViewSize
40 PVOID MiSessionPoolEnd; // = MiSessionViewStart
41 PVOID MiSessionPoolStart; // FFFFF90000000000 = MiSessionPoolEnd - MmSessionPoolSize
42 PVOID MmSessionBase; // FFFFF90000000000 = MiSessionPoolStart
43
44 /* System view */
45 ULONG64 MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
46 PVOID MiSystemViewStart;
47
48 ULONG64 MmMinimumNonPagedPoolSize = 256 * 1024;
49 ULONG64 MmSizeOfNonPagedPoolInBytes;
50 ULONG64 MmMaximumNonPagedPoolInBytes;
51 ULONG64 MmMaximumNonPagedPoolPercent;
52 ULONG64 MmMinAdditionNonPagedPoolPerMb = 32 * 1024;
53 ULONG64 MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
54 ULONG64 MmDefaultMaximumNonPagedPool = 1024 * 1024;
55 PVOID MmNonPagedSystemStart;
56 PVOID MmNonPagedPoolStart;
57 PVOID MmNonPagedPoolExpansionStart;
58 PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
59
60 ULONG64 MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
61 PVOID MmPagedPoolStart = MI_PAGED_POOL_START;
62 PVOID MmPagedPoolEnd;
63
64
65 ULONG64 MmBootImageSize;
66 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
67 RTL_BITMAP MiPfnBitMap;
68 ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage = -1;
69 ULONG64 MmNumberOfSystemPtes;
70 PMMPTE MmSystemPagePtes;
71 ULONG64 MxPfnAllocation;
72
73 PVOID MmSystemCacheStart;
74 PVOID MmSystemCacheEnd;
75 MMSUPPORT MmSystemCacheWs;
76
77
78 ///////////////////////////////////////////////
79
80 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
81 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
82
83 PFN_NUMBER MxFreePageBase;
84 ULONG64 MxFreePageCount = 0;
85
86 VOID
87 NTAPI
88 MxSetupFreePageList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
89 {
90 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
91 PLIST_ENTRY ListEntry;
92
93 /* Loop the memory descriptors */
94 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
95 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
96 ListEntry = ListEntry->Flink)
97 {
98 /* Get the memory block */
99 MdBlock = CONTAINING_RECORD(ListEntry,
100 MEMORY_ALLOCATION_DESCRIPTOR,
101 ListEntry);
102
103 /* Check if this is free memory */
104 if ((MdBlock->MemoryType == LoaderFree) ||
105 (MdBlock->MemoryType == LoaderLoadedProgram) ||
106 (MdBlock->MemoryType == LoaderFirmwareTemporary) ||
107 (MdBlock->MemoryType == LoaderOsloaderStack))
108 {
109 /* Check if this is the largest memory descriptor */
110 if (MdBlock->PageCount > MxFreePageCount)
111 {
112 /* For now, it is */
113 MxFreeDescriptor = MdBlock;
114 MxFreePageBase = MdBlock->BasePage;
115 MxFreePageCount = MdBlock->PageCount;
116 }
117 }
118 }
119 }
120
121 PFN_NUMBER
122 NTAPI
123 MxGetNextPage(IN PFN_NUMBER PageCount)
124 {
125 PFN_NUMBER Pfn;
126
127 /* Make sure we have enough pages */
128 if (PageCount > MxFreePageCount)
129 {
130 /* Crash the system */
131 KeBugCheckEx(INSTALL_MORE_MEMORY,
132 MmNumberOfPhysicalPages,
133 MxFreeDescriptor->PageCount,
134 MxOldFreeDescriptor.PageCount,
135 PageCount);
136 }
137
138 /* Use our lowest usable free pages */
139 Pfn = MxFreePageBase;
140 MxFreePageBase += PageCount;
141 MxFreePageCount -= PageCount;
142 return Pfn;
143 }
144
145 VOID
146 MxMapPage(PVOID Address)
147 {
148 PMMPTE Pte;
149 MMPTE TmpPte;
150
151 TmpPte.u.Long = 0;
152 TmpPte.u.Hard.Valid = 1;
153
154 /* Get a pointer to the PXE */
155 Pte = MiAddressToPxe(Address);
156 if (!Pte->u.Hard.Valid)
157 {
158 /* It's not valid, map it! */
159 TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
160 *Pte = TmpPte;
161 }
162
163 /* Get a pointer to the PPE */
164 Pte = MiAddressToPpe(Address);
165 if (!Pte->u.Hard.Valid)
166 {
167 /* It's not valid, map it! */
168 TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
169 *Pte = TmpPte;
170 }
171
172 /* Get a pointer to the PDE */
173 Pte = MiAddressToPde(Address);
174 if (!Pte->u.Hard.Valid)
175 {
176 /* It's not valid, map it! */
177 TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
178 *Pte = TmpPte;
179 }
180
181 /* Get a pointer to the PTE */
182 Pte = MiAddressToPte(Address);
183 if (!Pte->u.Hard.Valid)
184 {
185 /* It's not valid, map it! */
186 TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
187 *Pte = TmpPte;
188 }
189 }
190
191 VOID
192 MxMapPageRange(PVOID Address, ULONG64 PageCount)
193 {
194 ULONG64 i;
195
196 for (i = 0; i < PageCount; i++)
197 {
198 MxMapPage(Address);
199 Address = (PVOID)((ULONG64)Address + PAGE_SIZE);
200 }
201 }
202
203
204 VOID
205 NTAPI
206 MiArmIninializeMemoryLayout(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
207 {
208 /* Get the size of the boot loader's image allocations */
209 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
210 MmBootImageSize *= PAGE_SIZE;
211 MmBootImageSize = (MmBootImageSize + (4 * 1024 * 1024) - 1) & ~((4 * 1024 * 1024) - 1);
212 ASSERT((MmBootImageSize % (4 * 1024 * 1024)) == 0);
213
214 MiSessionSpaceEnd = (PVOID)MI_SESSION_SPACE_END;
215
216 /* This is where we will load Win32k.sys and the video driver */
217 MiSessionImageEnd = MiSessionSpaceEnd;
218 MiSessionImageStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
219 MmSessionImageSize);
220
221 /* The view starts right below the session working set (itself below
222 * the image area) */
223 MiSessionViewEnd = (PVOID)MI_SESSION_VIEW_END;
224 MiSessionViewStart = (PVOID)((ULONG_PTR)MiSessionViewStart -
225 MmSessionViewSize);
226
227 /* Session pool follows */
228 MiSessionPoolEnd = MiSessionViewStart;
229 MiSessionPoolStart = (PVOID)((ULONG_PTR)MiSessionPoolEnd -
230 MmSessionPoolSize);
231
232 /* And it all begins here */
233 MmSessionBase = MiSessionPoolStart;
234
235 // Sanity check that our math is correct
236 //ASSERT((ULONG_PTR)MmSessionBase + MmSessionSize == PTE_BASE);
237
238 /* System view space ends at session space, so now that we know where
239 * this is, we can compute the base address of system view space itself. */
240 MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase -
241 MmSystemViewSize);
242
243 /* Use the default */
244 MmNumberOfSystemPtes = 22000;
245
246 /* FIXME: should start below paged pool */
247 MmPfnDatabase = (PVOID)0xFFFFFD5FC0000000ULL;
248
249 }
250
251 VOID
252 MiArmInitializePageTable()
253 {
254 ULONG64 PageFrameOffset;
255 PMMPTE StartPte, EndPte;
256
257 /* Set CR3 for the system process */
258 PageFrameOffset = ((PMMPTE)PXE_BASE)->u.Hard.PageFrameNumber << PAGE_SHIFT;
259 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameOffset;
260
261 /* Clear user mode mappings in PML4 */
262 StartPte = MiAddressToPxe(0);
263 EndPte = MiAddressToPxe(MmSystemRangeStart);
264 RtlZeroMemory(StartPte, (EndPte - StartPte) * sizeof(MMPTE));
265 }
266
267
268 VOID
269 NTAPI
270 MiArmEvaluateMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
271 {
272 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
273 PLIST_ENTRY ListEntry;
274 PFN_NUMBER BasePage, LastPage, PageCount;
275
276 /* Loop the memory descriptors */
277 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
278 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
279 ListEntry = ListEntry->Flink)
280 {
281 /* Get the descriptor */
282 MdBlock = CONTAINING_RECORD(ListEntry,
283 MEMORY_ALLOCATION_DESCRIPTOR,
284 ListEntry);
285
286 /* Skip pages that are not part of the PFN database */
287 if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
288 (MdBlock->MemoryType == LoaderBBTMemory) ||
289 (MdBlock->MemoryType == LoaderHALCachedMemory) || // ???
290 (MdBlock->MemoryType == LoaderSpecialMemory))
291 {
292 continue;
293 }
294
295 /* Check if BURNMEM was used */
296 if (MdBlock->MemoryType != LoaderBad)
297 {
298 /* Count this in the total of pages */
299 MmNumberOfPhysicalPages += MdBlock->PageCount;
300 }
301
302 BasePage = MdBlock->BasePage;
303 LastPage = MdBlock->BasePage + MdBlock->PageCount - 1;
304
305 /* Check if this is the new lowest page */
306 if (BasePage < MmLowestPhysicalPage)
307 {
308 /* Update the lowest page */
309 MmLowestPhysicalPage = BasePage;
310 }
311
312 /* Check if this is the new highest page */
313 if (LastPage > MmHighestPhysicalPage)
314 {
315 /* Update the highest page */
316 MmHighestPhysicalPage = LastPage;
317 }
318 DPRINT1("BasePage = %ld, LastPage = %ld\n", BasePage, LastPage);
319 __debugbreak();
320 /* Map pages for the PFN database */
321 PageCount = PAGE_ROUND_UP(MdBlock->PageCount * sizeof(MMPFN)) / PAGE_SIZE;
322 MxMapPageRange(&MmPfnDatabase[BasePage], PageCount);
323
324 /* Zero out the pages */
325 RtlZeroMemory(&MmPfnDatabase[BasePage], PageCount * PAGE_SIZE);
326 }
327
328 /* Calculate the number of bytes, and then convert to pages */
329 MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN);
330 MxPfnAllocation >>= PAGE_SHIFT;
331 MxPfnAllocation++;
332
333 }
334
335 VOID
336 NTAPI
337 MiArmPrepareNonPagedPool()
338 {
339 PFN_NUMBER PageCount;
340
341 /* Check if this is a machine with less than 256MB of RAM, and no overide */
342 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
343 !(MmSizeOfNonPagedPoolInBytes))
344 {
345 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
346 MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
347 }
348
349 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
350 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
351 (MmNumberOfPhysicalPages * 7 / 8))
352 {
353 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
354 MmSizeOfNonPagedPoolInBytes = 0;
355 }
356
357 /* Check if no registry setting was set, or if the setting was too low */
358 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
359 {
360 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
361 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
362 MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
363 256 * MmMinAdditionNonPagedPoolPerMb;
364 }
365
366 /* Check if the registy setting or our dynamic calculation was too high */
367 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
368 {
369 // Set it to the maximum */
370 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
371 }
372
373 /* Check if a percentage cap was set through the registry */
374 if (MmMaximumNonPagedPoolPercent)
375 {
376 /* Don't feel like supporting this right now */
377 UNIMPLEMENTED;
378 }
379
380 /* Page-align the nonpaged pool size */
381 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
382
383 /* Now, check if there was a registry size for the maximum size */
384 if (!MmMaximumNonPagedPoolInBytes)
385 {
386 /* Start with the default (1MB) and add 400 KB for each MB above 4 */
387 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
388 MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
389 256 * MmMaxAdditionNonPagedPoolPerMb;
390 }
391
392 /* Don't let the maximum go too high */
393 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
394 {
395 /* Set it to the upper limit */
396 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
397 }
398
399 /* Calculate the nonpaged pool expansion start region */
400 MmNonPagedPoolExpansionStart = (PVOID)((ULONG_PTR)MmNonPagedPoolEnd -
401 MmMaximumNonPagedPoolInBytes +
402 MmSizeOfNonPagedPoolInBytes);
403 MmNonPagedPoolExpansionStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolExpansionStart);
404
405 DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
406 MmSizeOfNonPagedPoolInBytes, MmMaximumNonPagedPoolInBytes);
407
408 /* Now calculate the nonpaged system VA region, which includes the
409 * nonpaged pool expansion (above) and the system PTEs. Note that it is
410 * then aligned to a PDE boundary (4MB). */
411 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolExpansionStart -
412 (MmNumberOfSystemPtes + 1) * PAGE_SIZE);
413 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
414 ~((4 * 1024 * 1024) - 1));
415
416 /* Don't let it go below the minimum */
417 if (MmNonPagedSystemStart < (PVOID)MI_NON_PAGED_SYSTEM_START_MIN)
418 {
419 /* This is a hard-coded limit in the Windows NT address space */
420 MmNonPagedSystemStart = (PVOID)MI_NON_PAGED_SYSTEM_START_MIN;
421
422 /* Reduce the amount of system PTEs to reach this point */
423 MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolExpansionStart -
424 (ULONG_PTR)MmNonPagedSystemStart) >>
425 PAGE_SHIFT;
426 MmNumberOfSystemPtes--;
427 ASSERT(MmNumberOfSystemPtes > 1000);
428 }
429
430 /* Non paged pool comes after the PFN database */
431 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmPfnDatabase +
432 (MxPfnAllocation << PAGE_SHIFT));
433
434 /* Map the nonpaged pool */
435 PageCount = (MmSizeOfNonPagedPoolInBytes + PAGE_SIZE - 1) / PAGE_SIZE;
436 MxMapPageRange(MmNonPagedPoolStart, PageCount);
437
438 /* Sanity check: make sure we have properly defined the system PTE space */
439 ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
440 MiAddressToPte(MmNonPagedPoolExpansionStart));
441
442 }
443
444 NTSTATUS
445 NTAPI
446 MmArmInitSystem(IN ULONG Phase,
447 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
448 {
449 if (Phase == 0)
450 {
451 /* Get a continuous range of physical pages */
452 MxSetupFreePageList(LoaderBlock);
453
454 /* Initialize the memory layout */
455 MiArmIninializeMemoryLayout(LoaderBlock);
456
457 /* Loop descriptors and prepare PFN database */
458 MiArmEvaluateMemoryDescriptors(LoaderBlock);
459
460 MiArmInitializePageTable();
461
462 /* Configure size of the non paged pool */
463 MiArmPrepareNonPagedPool();
464
465 /* Initialize the ARM3 nonpaged pool */
466 MiInitializeArmPool();
467
468 /* Update the memory descriptor, to make sure the pages we used
469 won't get inserted into the PFN database */
470 MxOldFreeDescriptor = *MxFreeDescriptor;
471 MxFreeDescriptor->BasePage = MxFreePageBase;
472 MxFreeDescriptor->PageCount = MxFreePageCount;
473 }
474 else if (Phase == 1)
475 {
476 /* The PFN database was created, restore the free descriptor */
477 *MxFreeDescriptor = MxOldFreeDescriptor;
478
479
480 }
481
482 return STATUS_SUCCESS;
483 }
484