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
7 * PROGRAMMERS: Timo kreuzer (timo.kreuzer@reactos.org)
10 /* INCLUDES ***************************************************************/
16 #include "../ARM3/miarm.h"
18 #define MI_SESSION_SPACE_END (PVOID)0xFFFFF98000000000ULL
19 #define MI_SESSION_VIEW_END 0xFFFFF97FFF000000ULL
20 #define MI_NON_PAGED_SYSTEM_START_MIN 0x0FFFFFAA000000000ULL
22 /* GLOBALS *****************************************************************/
24 ULONG64 MmUserProbeAddress
= 0x7FFFFFF0000ULL
;
25 PVOID MmHighestUserAddress
= (PVOID
)0x7FFFFFEFFFFULL
;
26 PVOID MmSystemRangeStart
= (PVOID
)KSEG0_BASE
; // FFFF080000000000
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
;
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
45 ULONG64 MmSystemViewSize
= MI_SYSTEM_VIEW_SIZE
;
46 PVOID MiSystemViewStart
;
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
;
60 ULONG64 MmSizeOfPagedPoolInBytes
= MI_MIN_INIT_PAGED_POOLSIZE
;
61 PVOID MmPagedPoolStart
= MI_PAGED_POOL_START
;
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
;
73 PVOID MmSystemCacheStart
;
74 PVOID MmSystemCacheEnd
;
75 MMSUPPORT MmSystemCacheWs
;
78 ///////////////////////////////////////////////
80 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor
;
81 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor
;
83 PFN_NUMBER MxFreePageBase
;
84 ULONG64 MxFreePageCount
= 0;
88 MxSetupFreePageList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
90 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
91 PLIST_ENTRY ListEntry
;
93 /* Loop the memory descriptors */
94 for (ListEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
95 ListEntry
!= &LoaderBlock
->MemoryDescriptorListHead
;
96 ListEntry
= ListEntry
->Flink
)
98 /* Get the memory block */
99 MdBlock
= CONTAINING_RECORD(ListEntry
,
100 MEMORY_ALLOCATION_DESCRIPTOR
,
103 /* Check if this is free memory */
104 if ((MdBlock
->MemoryType
== LoaderFree
) ||
105 (MdBlock
->MemoryType
== LoaderLoadedProgram
) ||
106 (MdBlock
->MemoryType
== LoaderFirmwareTemporary
) ||
107 (MdBlock
->MemoryType
== LoaderOsloaderStack
))
109 /* Check if this is the largest memory descriptor */
110 if (MdBlock
->PageCount
> MxFreePageCount
)
113 MxFreeDescriptor
= MdBlock
;
114 MxFreePageBase
= MdBlock
->BasePage
;
115 MxFreePageCount
= MdBlock
->PageCount
;
123 MxGetNextPage(IN PFN_NUMBER PageCount
)
127 /* Make sure we have enough pages */
128 if (PageCount
> MxFreePageCount
)
130 /* Crash the system */
131 KeBugCheckEx(INSTALL_MORE_MEMORY
,
132 MmNumberOfPhysicalPages
,
133 MxFreeDescriptor
->PageCount
,
134 MxOldFreeDescriptor
.PageCount
,
138 /* Use our lowest usable free pages */
139 Pfn
= MxFreePageBase
;
140 MxFreePageBase
+= PageCount
;
141 MxFreePageCount
-= PageCount
;
146 MxMapPage(PVOID Address
)
152 TmpPte
.u
.Hard
.Valid
= 1;
154 /* Get a pointer to the PXE */
155 Pte
= MiAddressToPxe(Address
);
156 if (!Pte
->u
.Hard
.Valid
)
158 /* It's not valid, map it! */
159 TmpPte
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
163 /* Get a pointer to the PPE */
164 Pte
= MiAddressToPpe(Address
);
165 if (!Pte
->u
.Hard
.Valid
)
167 /* It's not valid, map it! */
168 TmpPte
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
172 /* Get a pointer to the PDE */
173 Pte
= MiAddressToPde(Address
);
174 if (!Pte
->u
.Hard
.Valid
)
176 /* It's not valid, map it! */
177 TmpPte
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
181 /* Get a pointer to the PTE */
182 Pte
= MiAddressToPte(Address
);
183 if (!Pte
->u
.Hard
.Valid
)
185 /* It's not valid, map it! */
186 TmpPte
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
192 MxMapPageRange(PVOID Address
, ULONG64 PageCount
)
196 for (i
= 0; i
< PageCount
; i
++)
199 Address
= (PVOID
)((ULONG64
)Address
+ PAGE_SIZE
);
206 MiArmIninializeMemoryLayout(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
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);
214 MiSessionSpaceEnd
= (PVOID
)MI_SESSION_SPACE_END
;
216 /* This is where we will load Win32k.sys and the video driver */
217 MiSessionImageEnd
= MiSessionSpaceEnd
;
218 MiSessionImageStart
= (PVOID
)((ULONG_PTR
)MiSessionImageEnd
-
221 /* The view starts right below the session working set (itself below
223 MiSessionViewEnd
= (PVOID
)MI_SESSION_VIEW_END
;
224 MiSessionViewStart
= (PVOID
)((ULONG_PTR
)MiSessionViewStart
-
227 /* Session pool follows */
228 MiSessionPoolEnd
= MiSessionViewStart
;
229 MiSessionPoolStart
= (PVOID
)((ULONG_PTR
)MiSessionPoolEnd
-
232 /* And it all begins here */
233 MmSessionBase
= MiSessionPoolStart
;
235 // Sanity check that our math is correct
236 //ASSERT((ULONG_PTR)MmSessionBase + MmSessionSize == PTE_BASE);
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
-
243 /* Use the default */
244 MmNumberOfSystemPtes
= 22000;
246 /* FIXME: should start below paged pool */
247 MmPfnDatabase
= (PVOID
)0xFFFFFD5FC0000000ULL
;
252 MiArmInitializePageTable()
254 ULONG64 PageFrameOffset
;
255 PMMPTE StartPte
, EndPte
;
257 /* Set CR3 for the system process */
258 PageFrameOffset
= ((PMMPTE
)PXE_BASE
)->u
.Hard
.PageFrameNumber
<< PAGE_SHIFT
;
259 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0] = PageFrameOffset
;
261 /* Clear user mode mappings in PML4 */
262 StartPte
= MiAddressToPxe(0);
263 EndPte
= MiAddressToPxe(MmSystemRangeStart
);
264 RtlZeroMemory(StartPte
, (EndPte
- StartPte
) * sizeof(MMPTE
));
270 MiArmEvaluateMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
272 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
273 PLIST_ENTRY ListEntry
;
274 PFN_NUMBER BasePage
, LastPage
, PageCount
;
276 /* Loop the memory descriptors */
277 for (ListEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
278 ListEntry
!= &LoaderBlock
->MemoryDescriptorListHead
;
279 ListEntry
= ListEntry
->Flink
)
281 /* Get the descriptor */
282 MdBlock
= CONTAINING_RECORD(ListEntry
,
283 MEMORY_ALLOCATION_DESCRIPTOR
,
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
))
295 /* Check if BURNMEM was used */
296 if (MdBlock
->MemoryType
!= LoaderBad
)
298 /* Count this in the total of pages */
299 MmNumberOfPhysicalPages
+= MdBlock
->PageCount
;
302 BasePage
= MdBlock
->BasePage
;
303 LastPage
= MdBlock
->BasePage
+ MdBlock
->PageCount
- 1;
305 /* Check if this is the new lowest page */
306 if (BasePage
< MmLowestPhysicalPage
)
308 /* Update the lowest page */
309 MmLowestPhysicalPage
= BasePage
;
312 /* Check if this is the new highest page */
313 if (LastPage
> MmHighestPhysicalPage
)
315 /* Update the highest page */
316 MmHighestPhysicalPage
= LastPage
;
318 DPRINT1("BasePage = %ld, LastPage = %ld\n", BasePage
, LastPage
);
320 /* Map pages for the PFN database */
321 PageCount
= PAGE_ROUND_UP(MdBlock
->PageCount
* sizeof(MMPFN
)) / PAGE_SIZE
;
322 MxMapPageRange(&MmPfnDatabase
[BasePage
], PageCount
);
324 /* Zero out the pages */
325 RtlZeroMemory(&MmPfnDatabase
[BasePage
], PageCount
* PAGE_SIZE
);
328 /* Calculate the number of bytes, and then convert to pages */
329 MxPfnAllocation
= (MmHighestPhysicalPage
+ 1) * sizeof(MMPFN
);
330 MxPfnAllocation
>>= PAGE_SHIFT
;
337 MiArmPrepareNonPagedPool()
339 PFN_NUMBER PageCount
;
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
))
345 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
346 MmSizeOfNonPagedPoolInBytes
= 2 * 1024 * 1024;
349 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
350 if ((MmSizeOfNonPagedPoolInBytes
>> PAGE_SHIFT
) >
351 (MmNumberOfPhysicalPages
* 7 / 8))
353 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
354 MmSizeOfNonPagedPoolInBytes
= 0;
357 /* Check if no registry setting was set, or if the setting was too low */
358 if (MmSizeOfNonPagedPoolInBytes
< MmMinimumNonPagedPoolSize
)
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
;
366 /* Check if the registy setting or our dynamic calculation was too high */
367 if (MmSizeOfNonPagedPoolInBytes
> MI_MAX_INIT_NONPAGED_POOL_SIZE
)
369 // Set it to the maximum */
370 MmSizeOfNonPagedPoolInBytes
= MI_MAX_INIT_NONPAGED_POOL_SIZE
;
373 /* Check if a percentage cap was set through the registry */
374 if (MmMaximumNonPagedPoolPercent
)
376 /* Don't feel like supporting this right now */
380 /* Page-align the nonpaged pool size */
381 MmSizeOfNonPagedPoolInBytes
&= ~(PAGE_SIZE
- 1);
383 /* Now, check if there was a registry size for the maximum size */
384 if (!MmMaximumNonPagedPoolInBytes
)
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
;
392 /* Don't let the maximum go too high */
393 if (MmMaximumNonPagedPoolInBytes
> MI_MAX_NONPAGED_POOL_SIZE
)
395 /* Set it to the upper limit */
396 MmMaximumNonPagedPoolInBytes
= MI_MAX_NONPAGED_POOL_SIZE
;
399 /* Calculate the nonpaged pool expansion start region */
400 MmNonPagedPoolExpansionStart
= (PVOID
)((ULONG_PTR
)MmNonPagedPoolEnd
-
401 MmMaximumNonPagedPoolInBytes
+
402 MmSizeOfNonPagedPoolInBytes
);
403 MmNonPagedPoolExpansionStart
= (PVOID
)PAGE_ALIGN(MmNonPagedPoolExpansionStart
);
405 DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
406 MmSizeOfNonPagedPoolInBytes
, MmMaximumNonPagedPoolInBytes
);
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));
416 /* Don't let it go below the minimum */
417 if (MmNonPagedSystemStart
< (PVOID
)MI_NON_PAGED_SYSTEM_START_MIN
)
419 /* This is a hard-coded limit in the Windows NT address space */
420 MmNonPagedSystemStart
= (PVOID
)MI_NON_PAGED_SYSTEM_START_MIN
;
422 /* Reduce the amount of system PTEs to reach this point */
423 MmNumberOfSystemPtes
= ((ULONG_PTR
)MmNonPagedPoolExpansionStart
-
424 (ULONG_PTR
)MmNonPagedSystemStart
) >>
426 MmNumberOfSystemPtes
--;
427 ASSERT(MmNumberOfSystemPtes
> 1000);
430 /* Non paged pool comes after the PFN database */
431 MmNonPagedPoolStart
= (PVOID
)((ULONG_PTR
)MmPfnDatabase
+
432 (MxPfnAllocation
<< PAGE_SHIFT
));
434 /* Map the nonpaged pool */
435 PageCount
= (MmSizeOfNonPagedPoolInBytes
+ PAGE_SIZE
- 1) / PAGE_SIZE
;
436 MxMapPageRange(MmNonPagedPoolStart
, PageCount
);
438 /* Sanity check: make sure we have properly defined the system PTE space */
439 ASSERT(MiAddressToPte(MmNonPagedSystemStart
) <
440 MiAddressToPte(MmNonPagedPoolExpansionStart
));
446 MmArmInitSystem(IN ULONG Phase
,
447 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
451 /* Get a continuous range of physical pages */
452 MxSetupFreePageList(LoaderBlock
);
454 /* Initialize the memory layout */
455 MiArmIninializeMemoryLayout(LoaderBlock
);
457 /* Loop descriptors and prepare PFN database */
458 MiArmEvaluateMemoryDescriptors(LoaderBlock
);
460 MiArmInitializePageTable();
462 /* Configure size of the non paged pool */
463 MiArmPrepareNonPagedPool();
465 /* Initialize the ARM3 nonpaged pool */
466 MiInitializeArmPool();
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
;
476 /* The PFN database was created, restore the free descriptor */
477 *MxFreeDescriptor
= MxOldFreeDescriptor
;
482 return STATUS_SUCCESS
;