2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/i386/init.c
5 * PURPOSE: ARM Memory Manager Initialization for x86
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #line 15 "ARMĀ³::INIT:X86"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../../ARM3/miarm.h"
19 /* GLOBALS ********************************************************************/
21 /* Template PTE and PDE for a kernel page */
22 MMPTE ValidKernelPde
= {.u
.Hard
.Valid
= 1, .u
.Hard
.Write
= 1, .u
.Hard
.Dirty
= 1, .u
.Hard
.Accessed
= 1};
23 MMPTE ValidKernelPte
= {.u
.Hard
.Valid
= 1, .u
.Hard
.Write
= 1, .u
.Hard
.Dirty
= 1, .u
.Hard
.Accessed
= 1};
25 /* PRIVATE FUNCTIONS **********************************************************/
29 MiComputeNonPagedPoolVa(IN ULONG FreePages
)
31 IN PFN_NUMBER PoolPages
;
33 /* Check if this is a machine with less than 256MB of RAM, and no overide */
34 if ((MmNumberOfPhysicalPages
<= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING
) &&
35 !(MmSizeOfNonPagedPoolInBytes
))
37 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
38 MmSizeOfNonPagedPoolInBytes
= 2 * _1MB
;
41 /* Hyperspace ends here */
42 MmHyperSpaceEnd
= (PVOID
)((ULONG_PTR
)MmSystemCacheWorkingSetList
- 1);
44 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
45 if ((MmSizeOfNonPagedPoolInBytes
>> PAGE_SHIFT
) > (FreePages
* 7 / 8))
47 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
48 MmSizeOfNonPagedPoolInBytes
= 0;
51 /* Check if no registry setting was set, or if the setting was too low */
52 if (MmSizeOfNonPagedPoolInBytes
< MmMinimumNonPagedPoolSize
)
54 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
55 MmSizeOfNonPagedPoolInBytes
= MmMinimumNonPagedPoolSize
;
56 MmSizeOfNonPagedPoolInBytes
+= (FreePages
- 1024) / 256 * MmMinAdditionNonPagedPoolPerMb
;
59 /* Check if the registy setting or our dynamic calculation was too high */
60 if (MmSizeOfNonPagedPoolInBytes
> MI_MAX_INIT_NONPAGED_POOL_SIZE
)
62 /* Set it to the maximum */
63 MmSizeOfNonPagedPoolInBytes
= MI_MAX_INIT_NONPAGED_POOL_SIZE
;
66 /* Check if a percentage cap was set through the registry */
67 if (MmMaximumNonPagedPoolPercent
) UNIMPLEMENTED
;
69 /* Page-align the nonpaged pool size */
70 MmSizeOfNonPagedPoolInBytes
&= ~(PAGE_SIZE
- 1);
72 /* Now, check if there was a registry size for the maximum size */
73 if (!MmMaximumNonPagedPoolInBytes
)
75 /* Start with the default (1MB) */
76 MmMaximumNonPagedPoolInBytes
= MmDefaultMaximumNonPagedPool
;
78 /* Add space for PFN database */
79 MmMaximumNonPagedPoolInBytes
+= (ULONG
)
80 PAGE_ALIGN((MmHighestPhysicalPage
+ 1) * sizeof(MMPFN
));
82 /* Check if the machine has more than 512MB of free RAM */
83 if (FreePages
>= 0x1F000)
85 /* Add 200KB for each MB above 4 */
86 MmMaximumNonPagedPoolInBytes
+= (FreePages
- 1024) / 256 *
87 (MmMaxAdditionNonPagedPoolPerMb
/ 2);
88 if (MmMaximumNonPagedPoolInBytes
< MI_MAX_NONPAGED_POOL_SIZE
)
90 /* Make it at least 128MB since this machine has a lot of RAM */
91 MmMaximumNonPagedPoolInBytes
= MI_MAX_NONPAGED_POOL_SIZE
;
96 /* Add 400KB for each MB above 4 */
97 MmMaximumNonPagedPoolInBytes
+= (FreePages
- 1024) / 256 *
98 MmMaxAdditionNonPagedPoolPerMb
;
102 /* Make sure there's at least 16 pages + the PFN available for expansion */
103 PoolPages
= MmSizeOfNonPagedPoolInBytes
+ (PAGE_SIZE
* 16) +
104 ((ULONG
)PAGE_ALIGN(MmHighestPhysicalPage
+ 1) * sizeof(MMPFN
));
105 if (MmMaximumNonPagedPoolInBytes
< PoolPages
)
107 /* The maximum should be at least high enough to cover all the above */
108 MmMaximumNonPagedPoolInBytes
= PoolPages
;
111 /* Systems with 2GB of kernel address space get double the size */
112 PoolPages
= MI_MAX_NONPAGED_POOL_SIZE
* 2;
114 /* On the other hand, make sure that PFN + nonpaged pool doesn't get too big */
115 if (MmMaximumNonPagedPoolInBytes
> PoolPages
)
117 /* Trim it down to the maximum architectural limit (256MB) */
118 MmMaximumNonPagedPoolInBytes
= PoolPages
;
121 /* Check if this is a system with > 128MB of non paged pool */
122 if (MmMaximumNonPagedPoolInBytes
> MI_MAX_NONPAGED_POOL_SIZE
)
124 /* Check if the initial size is less than the extra 128MB boost */
125 if (MmSizeOfNonPagedPoolInBytes
< (MmMaximumNonPagedPoolInBytes
-
126 MI_MAX_NONPAGED_POOL_SIZE
))
128 /* FIXME: Should check if the initial pool can be expanded */
130 /* Assume no expansion possible, check ift he maximum is too large */
131 if (MmMaximumNonPagedPoolInBytes
> (MmSizeOfNonPagedPoolInBytes
+
132 MI_MAX_NONPAGED_POOL_SIZE
))
134 /* Set it to the initial value plus the boost */
135 MmMaximumNonPagedPoolInBytes
= MmSizeOfNonPagedPoolInBytes
+
136 MI_MAX_NONPAGED_POOL_SIZE
;
144 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
146 PLIST_ENTRY NextEntry
;
147 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
149 PFN_NUMBER PageFrameIndex
;
150 PMMPTE StartPde
, EndPde
, PointerPte
, LastPte
;
151 MMPTE TempPde
, TempPte
;
152 PVOID NonPagedPoolExpansionVa
;
155 /* Check for kernel stack size that's too big */
156 if (MmLargeStackSize
> (KERNEL_LARGE_STACK_SIZE
/ _1KB
))
158 /* Sanitize to default value */
159 MmLargeStackSize
= KERNEL_LARGE_STACK_SIZE
;
163 /* Take the registry setting, and convert it into bytes */
164 MmLargeStackSize
*= _1KB
;
166 /* Now align it to a page boundary */
167 MmLargeStackSize
= PAGE_ROUND_UP(MmLargeStackSize
);
170 ASSERT(MmLargeStackSize
<= KERNEL_LARGE_STACK_SIZE
);
171 ASSERT((MmLargeStackSize
& (PAGE_SIZE
- 1)) == 0);
173 /* Make sure it's not too low */
174 if (MmLargeStackSize
< KERNEL_STACK_SIZE
) MmLargeStackSize
= KERNEL_STACK_SIZE
;
177 /* Check for global bit */
179 if (KeFeatureBits
& KF_GLOBAL_PAGE
)
181 /* Set it on the template PTE and PDE */
182 ValidKernelPte
.u
.Hard
.Global
= TRUE
;
183 ValidKernelPde
.u
.Hard
.Global
= TRUE
;
186 /* Now templates are ready */
187 TempPte
= ValidKernelPte
;
188 TempPde
= ValidKernelPde
;
191 // Set CR3 for the system process
193 PointerPte
= MiAddressToPde(PTE_BASE
);
194 PageFrameIndex
= PFN_FROM_PTE(PointerPte
) << PAGE_SHIFT
;
195 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0] = PageFrameIndex
;
198 // Blow away user-mode
200 StartPde
= MiAddressToPde(0);
201 EndPde
= MiAddressToPde(KSEG0_BASE
);
202 RtlZeroMemory(StartPde
, (EndPde
- StartPde
) * sizeof(MMPTE
));
205 // Loop the memory descriptors
207 NextEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
208 while (NextEntry
!= &LoaderBlock
->MemoryDescriptorListHead
)
211 // Get the memory block
213 MdBlock
= CONTAINING_RECORD(NextEntry
,
214 MEMORY_ALLOCATION_DESCRIPTOR
,
218 // Skip invisible memory
220 if ((MdBlock
->MemoryType
!= LoaderFirmwarePermanent
) &&
221 (MdBlock
->MemoryType
!= LoaderSpecialMemory
) &&
222 (MdBlock
->MemoryType
!= LoaderHALCachedMemory
) &&
223 (MdBlock
->MemoryType
!= LoaderBBTMemory
))
226 // Check if BURNMEM was used
228 if (MdBlock
->MemoryType
!= LoaderBad
)
231 // Count this in the total of pages
233 MmNumberOfPhysicalPages
+= MdBlock
->PageCount
;
237 // Check if this is the new lowest page
239 if (MdBlock
->BasePage
< MmLowestPhysicalPage
)
242 // Update the lowest page
244 MmLowestPhysicalPage
= MdBlock
->BasePage
;
248 // Check if this is the new highest page
250 PageFrameIndex
= MdBlock
->BasePage
+ MdBlock
->PageCount
;
251 if (PageFrameIndex
> MmHighestPhysicalPage
)
254 // Update the highest page
256 MmHighestPhysicalPage
= PageFrameIndex
- 1;
260 // Check if this is free memory
262 if ((MdBlock
->MemoryType
== LoaderFree
) ||
263 (MdBlock
->MemoryType
== LoaderLoadedProgram
) ||
264 (MdBlock
->MemoryType
== LoaderFirmwareTemporary
) ||
265 (MdBlock
->MemoryType
== LoaderOsloaderStack
))
268 // Check if this is the largest memory descriptor
270 if (MdBlock
->PageCount
> FreePages
)
275 MxFreeDescriptor
= MdBlock
;
281 FreePages
+= MdBlock
->PageCount
;
288 NextEntry
= MdBlock
->ListEntry
.Flink
;
292 // Save original values of the free descriptor, since it'll be
293 // altered by early allocations
295 MxOldFreeDescriptor
= *MxFreeDescriptor
;
297 /* Compute non paged pool limits and size */
298 MiComputeNonPagedPoolVa(FreePages
);
300 /* Compute color information (L2 cache-separated paging lists) */
301 MiComputeColorInformation();
304 // Calculate the number of bytes for the PFN database, double it for ARM3,
305 // then add the color tables and convert to pages
307 MxPfnAllocation
= (MmHighestPhysicalPage
+ 1) * sizeof(MMPFN
);
308 MxPfnAllocation
<<= 1;
309 MxPfnAllocation
+= (MmSecondaryColors
* sizeof(MMCOLOR_TABLES
) * 2);
310 MxPfnAllocation
>>= PAGE_SHIFT
;
313 // We have to add one to the count here, because in the process of
314 // shifting down to the page size, we actually ended up getting the
315 // lower aligned size (so say, 0x5FFFF bytes is now 0x5F pages).
316 // Later on, we'll shift this number back into bytes, which would cause
317 // us to end up with only 0x5F000 bytes -- when we actually want to have
323 // Now calculate the nonpaged pool expansion VA region
325 MmNonPagedPoolStart
= (PVOID
)((ULONG_PTR
)MmNonPagedPoolEnd
-
326 MmMaximumNonPagedPoolInBytes
+
327 MmSizeOfNonPagedPoolInBytes
);
328 MmNonPagedPoolStart
= (PVOID
)PAGE_ALIGN(MmNonPagedPoolStart
);
329 NonPagedPoolExpansionVa
= MmNonPagedPoolStart
;
330 DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
331 MmSizeOfNonPagedPoolInBytes
, MmMaximumNonPagedPoolInBytes
);
334 // Now calculate the nonpaged system VA region, which includes the
335 // nonpaged pool expansion (above) and the system PTEs. Note that it is
336 // then aligned to a PDE boundary (4MB).
338 MmNonPagedSystemStart
= (PVOID
)((ULONG_PTR
)MmNonPagedPoolStart
-
339 (MmNumberOfSystemPtes
+ 1) * PAGE_SIZE
);
340 MmNonPagedSystemStart
= (PVOID
)((ULONG_PTR
)MmNonPagedSystemStart
&
341 ~((4 * 1024 * 1024) - 1));
344 // Don't let it go below the minimum
346 if (MmNonPagedSystemStart
< (PVOID
)0xEB000000)
349 // This is a hard-coded limit in the Windows NT address space
351 MmNonPagedSystemStart
= (PVOID
)0xEB000000;
354 // Reduce the amount of system PTEs to reach this point
356 MmNumberOfSystemPtes
= ((ULONG_PTR
)MmNonPagedPoolStart
-
357 (ULONG_PTR
)MmNonPagedSystemStart
) >>
359 MmNumberOfSystemPtes
--;
360 ASSERT(MmNumberOfSystemPtes
> 1000);
364 // Check if we are in a situation where the size of the paged pool
365 // is so large that it overflows into nonpaged pool
367 if (MmSizeOfPagedPoolInBytes
>
368 ((ULONG_PTR
)MmNonPagedSystemStart
- (ULONG_PTR
)MmPagedPoolStart
))
371 // We need some recalculations here
373 DPRINT1("Paged pool is too big!\n");
377 // Normally, the PFN database should start after the loader images.
378 // This is already the case in ReactOS, but for now we want to co-exist
379 // with the old memory manager, so we'll create a "Shadow PFN Database"
380 // instead, and arbitrarly start it at 0xB0000000.
382 // We actually create two PFN databases, one for ReactOS starting here,
383 // and the next one used for ARM3, which starts right after. The MmPfnAllocation
384 // variable actually holds the size of both (the colored tables come after
385 // the ARM3 PFN database).
387 MmPfnDatabase
[0] = (PVOID
)0xB0000000;
388 MmPfnDatabase
[1] = &MmPfnDatabase
[0][MmHighestPhysicalPage
];
389 ASSERT(((ULONG_PTR
)MmPfnDatabase
[0] & ((4 * 1024 * 1024) - 1)) == 0);
392 // Non paged pool comes after the PFN database
394 MmNonPagedPoolStart
= (PVOID
)((ULONG_PTR
)MmPfnDatabase
[0] +
395 (MxPfnAllocation
<< PAGE_SHIFT
));
398 // Now we actually need to get these many physical pages. Nonpaged pool
399 // is actually also physically contiguous (but not the expansion)
401 PageFrameIndex
= MxGetNextPage(MxPfnAllocation
+
402 (MmSizeOfNonPagedPoolInBytes
>> PAGE_SHIFT
));
403 ASSERT(PageFrameIndex
!= 0);
404 DPRINT("PFN DB PA PFN begins at: %lx\n", PageFrameIndex
);
405 DPRINT("NP PA PFN begins at: %lx\n", PageFrameIndex
+ MxPfnAllocation
);
407 /* Convert nonpaged pool size from bytes to pages */
408 MmMaximumNonPagedPoolInPages
= MmMaximumNonPagedPoolInBytes
>> PAGE_SHIFT
;
411 // Now we need some pages to create the page tables for the NP system VA
412 // which includes system PTEs and expansion NP
414 StartPde
= MiAddressToPde(MmNonPagedSystemStart
);
415 EndPde
= MiAddressToPde((PVOID
)((ULONG_PTR
)MmNonPagedPoolEnd
- 1));
416 while (StartPde
<= EndPde
)
421 ASSERT(StartPde
->u
.Hard
.Valid
== 0);
426 TempPde
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
427 ASSERT(TempPde
.u
.Hard
.Valid
== 1);
431 // Zero out the page table
433 PointerPte
= MiPteToAddress(StartPde
);
434 RtlZeroMemory(PointerPte
, PAGE_SIZE
);
443 // Now we need pages for the page tables which will map initial NP
445 StartPde
= MiAddressToPde(MmPfnDatabase
[0]);
446 EndPde
= MiAddressToPde((PVOID
)((ULONG_PTR
)MmNonPagedPoolStart
+
447 MmSizeOfNonPagedPoolInBytes
- 1));
448 while (StartPde
<= EndPde
)
453 ASSERT(StartPde
->u
.Hard
.Valid
== 0);
458 TempPde
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
459 ASSERT(TempPde
.u
.Hard
.Valid
== 1);
463 // Zero out the page table
465 PointerPte
= MiPteToAddress(StartPde
);
466 RtlZeroMemory(PointerPte
, PAGE_SIZE
);
475 // Now remember where the expansion starts
477 MmNonPagedPoolExpansionStart
= NonPagedPoolExpansionVa
;
480 // Last step is to actually map the nonpaged pool
482 PointerPte
= MiAddressToPte(MmNonPagedPoolStart
);
483 LastPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)MmNonPagedPoolStart
+
484 MmSizeOfNonPagedPoolInBytes
- 1));
485 while (PointerPte
<= LastPte
)
488 // Use one of our contigous pages
490 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
++;
491 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
492 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
493 *PointerPte
++ = TempPte
;
497 // Sanity check: make sure we have properly defined the system PTE space
499 ASSERT(MiAddressToPte(MmNonPagedSystemStart
) <
500 MiAddressToPte(MmNonPagedPoolExpansionStart
));
502 /* Now go ahead and initialize the nonpaged pool */
503 MiInitializeNonPagedPool();
504 MiInitializeNonPagedPoolThresholds();
506 /* Map the PFN database pages */
507 MiMapPfnDatabase(LoaderBlock
);
509 /* Initialize the color tables */
510 MiInitializeColorTables();
512 /* Build the PFN Database */
513 MiInitializePfnDatabase(LoaderBlock
);
515 /* Call back into shitMM to setup the ReactOS PFN database */
516 MmInitializePageList();
519 // Reset the descriptor back so we can create the correct memory blocks
521 *MxFreeDescriptor
= MxOldFreeDescriptor
;
524 // Initialize the nonpaged pool
526 InitializePool(NonPagedPool
, 0);
529 // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
531 PointerPte
= MiAddressToPte(MmNonPagedSystemStart
);
532 OldCount
= MmNumberOfSystemPtes
;
533 MmNumberOfSystemPtes
= MiAddressToPte(MmNonPagedPoolExpansionStart
) -
535 MmNumberOfSystemPtes
--;
536 DPRINT("Final System PTE count: %d (%d bytes)\n",
537 MmNumberOfSystemPtes
, MmNumberOfSystemPtes
* PAGE_SIZE
);
540 // Create the system PTE space
542 MiInitializeSystemPtes(PointerPte
, MmNumberOfSystemPtes
, SystemPteSpace
);
545 // Get the PDE For hyperspace
547 StartPde
= MiAddressToPde(HYPER_SPACE
);
550 // Allocate a page for it and create it
552 PageFrameIndex
= MmAllocPage(MC_SYSTEM
);
553 TempPde
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
554 TempPde
.u
.Hard
.Global
= FALSE
; // Hyperspace is local!
555 ASSERT(StartPde
->u
.Hard
.Valid
== 0);
556 ASSERT(TempPde
.u
.Hard
.Valid
== 1);
560 // Zero out the page table now
562 PointerPte
= MiAddressToPte(HYPER_SPACE
);
563 RtlZeroMemory(PointerPte
, PAGE_SIZE
);
566 // Setup the mapping PTEs
568 MmFirstReservedMappingPte
= MiAddressToPte(MI_MAPPING_RANGE_START
);
569 MmLastReservedMappingPte
= MiAddressToPte(MI_MAPPING_RANGE_END
);
570 MmFirstReservedMappingPte
->u
.Hard
.PageFrameNumber
= MI_HYPERSPACE_PTES
;
573 // Reserve system PTEs for zeroing PTEs and clear them
575 MiFirstReservedZeroingPte
= MiReserveSystemPtes(MI_ZERO_PTES
,
577 RtlZeroMemory(MiFirstReservedZeroingPte
, MI_ZERO_PTES
* sizeof(MMPTE
));
580 // Set the counter to maximum to boot with
582 MiFirstReservedZeroingPte
->u
.Hard
.PageFrameNumber
= MI_ZERO_PTES
- 1;
584 return STATUS_SUCCESS
;