sync with trunk r46493
[reactos.git] / ntoskrnl / mm / ARM3 / i386 / init.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #line 15 "ARMĀ³::INIT:X86"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../../ARM3/miarm.h"
18
19 /* GLOBALS ********************************************************************/
20
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};
24
25 /* PRIVATE FUNCTIONS **********************************************************/
26
27 VOID
28 NTAPI
29 MiComputeNonPagedPoolVa(IN ULONG FreePages)
30 {
31 IN PFN_NUMBER PoolPages;
32
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))
36 {
37 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
38 MmSizeOfNonPagedPoolInBytes = 2 * _1MB;
39 }
40
41 /* Hyperspace ends here */
42 MmHyperSpaceEnd = (PVOID)((ULONG_PTR)MmSystemCacheWorkingSetList - 1);
43
44 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
45 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) > (FreePages * 7 / 8))
46 {
47 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
48 MmSizeOfNonPagedPoolInBytes = 0;
49 }
50
51 /* Check if no registry setting was set, or if the setting was too low */
52 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
53 {
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;
57 }
58
59 /* Check if the registy setting or our dynamic calculation was too high */
60 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
61 {
62 /* Set it to the maximum */
63 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
64 }
65
66 /* Check if a percentage cap was set through the registry */
67 if (MmMaximumNonPagedPoolPercent) UNIMPLEMENTED;
68
69 /* Page-align the nonpaged pool size */
70 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
71
72 /* Now, check if there was a registry size for the maximum size */
73 if (!MmMaximumNonPagedPoolInBytes)
74 {
75 /* Start with the default (1MB) */
76 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
77
78 /* Add space for PFN database */
79 MmMaximumNonPagedPoolInBytes += (ULONG)
80 PAGE_ALIGN((MmHighestPhysicalPage + 1) * sizeof(MMPFN));
81
82 /* Check if the machine has more than 512MB of free RAM */
83 if (FreePages >= 0x1F000)
84 {
85 /* Add 200KB for each MB above 4 */
86 MmMaximumNonPagedPoolInBytes += (FreePages - 1024) / 256 *
87 (MmMaxAdditionNonPagedPoolPerMb / 2);
88 if (MmMaximumNonPagedPoolInBytes < MI_MAX_NONPAGED_POOL_SIZE)
89 {
90 /* Make it at least 128MB since this machine has a lot of RAM */
91 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
92 }
93 }
94 else
95 {
96 /* Add 400KB for each MB above 4 */
97 MmMaximumNonPagedPoolInBytes += (FreePages - 1024) / 256 *
98 MmMaxAdditionNonPagedPoolPerMb;
99 }
100 }
101
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)
106 {
107 /* The maximum should be at least high enough to cover all the above */
108 MmMaximumNonPagedPoolInBytes = PoolPages;
109 }
110
111 /* Systems with 2GB of kernel address space get double the size */
112 PoolPages = MI_MAX_NONPAGED_POOL_SIZE * 2;
113
114 /* On the other hand, make sure that PFN + nonpaged pool doesn't get too big */
115 if (MmMaximumNonPagedPoolInBytes > PoolPages)
116 {
117 /* Trim it down to the maximum architectural limit (256MB) */
118 MmMaximumNonPagedPoolInBytes = PoolPages;
119 }
120
121 /* Check if this is a system with > 128MB of non paged pool */
122 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
123 {
124 /* Check if the initial size is less than the extra 128MB boost */
125 if (MmSizeOfNonPagedPoolInBytes < (MmMaximumNonPagedPoolInBytes -
126 MI_MAX_NONPAGED_POOL_SIZE))
127 {
128 /* FIXME: Should check if the initial pool can be expanded */
129
130 /* Assume no expansion possible, check ift he maximum is too large */
131 if (MmMaximumNonPagedPoolInBytes > (MmSizeOfNonPagedPoolInBytes +
132 MI_MAX_NONPAGED_POOL_SIZE))
133 {
134 /* Set it to the initial value plus the boost */
135 MmMaximumNonPagedPoolInBytes = MmSizeOfNonPagedPoolInBytes +
136 MI_MAX_NONPAGED_POOL_SIZE;
137 }
138 }
139 }
140 }
141
142 NTSTATUS
143 NTAPI
144 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
145 {
146 PLIST_ENTRY NextEntry;
147 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
148 ULONG FreePages = 0;
149 PFN_NUMBER PageFrameIndex;
150 PMMPTE StartPde, EndPde, PointerPte, LastPte;
151 MMPTE TempPde, TempPte;
152 PVOID NonPagedPoolExpansionVa;
153 ULONG OldCount;
154
155 /* Check for kernel stack size that's too big */
156 if (MmLargeStackSize > (KERNEL_LARGE_STACK_SIZE / _1KB))
157 {
158 /* Sanitize to default value */
159 MmLargeStackSize = KERNEL_LARGE_STACK_SIZE;
160 }
161 else
162 {
163 /* Take the registry setting, and convert it into bytes */
164 MmLargeStackSize *= _1KB;
165
166 /* Now align it to a page boundary */
167 MmLargeStackSize = PAGE_ROUND_UP(MmLargeStackSize);
168
169 /* Sanity checks */
170 ASSERT(MmLargeStackSize <= KERNEL_LARGE_STACK_SIZE);
171 ASSERT((MmLargeStackSize & (PAGE_SIZE - 1)) == 0);
172
173 /* Make sure it's not too low */
174 if (MmLargeStackSize < KERNEL_STACK_SIZE) MmLargeStackSize = KERNEL_STACK_SIZE;
175 }
176
177 /* Check for global bit */
178 #if 0
179 if (KeFeatureBits & KF_GLOBAL_PAGE)
180 {
181 /* Set it on the template PTE and PDE */
182 ValidKernelPte.u.Hard.Global = TRUE;
183 ValidKernelPde.u.Hard.Global = TRUE;
184 }
185 #endif
186 /* Now templates are ready */
187 TempPte = ValidKernelPte;
188 TempPde = ValidKernelPde;
189
190 //
191 // Set CR3 for the system process
192 //
193 PointerPte = MiAddressToPde(PTE_BASE);
194 PageFrameIndex = PFN_FROM_PTE(PointerPte) << PAGE_SHIFT;
195 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameIndex;
196
197 //
198 // Blow away user-mode
199 //
200 StartPde = MiAddressToPde(0);
201 EndPde = MiAddressToPde(KSEG0_BASE);
202 RtlZeroMemory(StartPde, (EndPde - StartPde) * sizeof(MMPTE));
203
204 //
205 // Loop the memory descriptors
206 //
207 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
208 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
209 {
210 //
211 // Get the memory block
212 //
213 MdBlock = CONTAINING_RECORD(NextEntry,
214 MEMORY_ALLOCATION_DESCRIPTOR,
215 ListEntry);
216
217 //
218 // Skip invisible memory
219 //
220 if ((MdBlock->MemoryType != LoaderFirmwarePermanent) &&
221 (MdBlock->MemoryType != LoaderSpecialMemory) &&
222 (MdBlock->MemoryType != LoaderHALCachedMemory) &&
223 (MdBlock->MemoryType != LoaderBBTMemory))
224 {
225 //
226 // Check if BURNMEM was used
227 //
228 if (MdBlock->MemoryType != LoaderBad)
229 {
230 //
231 // Count this in the total of pages
232 //
233 MmNumberOfPhysicalPages += MdBlock->PageCount;
234 }
235
236 //
237 // Check if this is the new lowest page
238 //
239 if (MdBlock->BasePage < MmLowestPhysicalPage)
240 {
241 //
242 // Update the lowest page
243 //
244 MmLowestPhysicalPage = MdBlock->BasePage;
245 }
246
247 //
248 // Check if this is the new highest page
249 //
250 PageFrameIndex = MdBlock->BasePage + MdBlock->PageCount;
251 if (PageFrameIndex > MmHighestPhysicalPage)
252 {
253 //
254 // Update the highest page
255 //
256 MmHighestPhysicalPage = PageFrameIndex - 1;
257 }
258
259 //
260 // Check if this is free memory
261 //
262 if ((MdBlock->MemoryType == LoaderFree) ||
263 (MdBlock->MemoryType == LoaderLoadedProgram) ||
264 (MdBlock->MemoryType == LoaderFirmwareTemporary) ||
265 (MdBlock->MemoryType == LoaderOsloaderStack))
266 {
267 //
268 // Check if this is the largest memory descriptor
269 //
270 if (MdBlock->PageCount > FreePages)
271 {
272 //
273 // For now, it is
274 //
275 MxFreeDescriptor = MdBlock;
276 }
277
278 //
279 // More free pages
280 //
281 FreePages += MdBlock->PageCount;
282 }
283 }
284
285 //
286 // Keep going
287 //
288 NextEntry = MdBlock->ListEntry.Flink;
289 }
290
291 //
292 // Save original values of the free descriptor, since it'll be
293 // altered by early allocations
294 //
295 MxOldFreeDescriptor = *MxFreeDescriptor;
296
297 /* Compute non paged pool limits and size */
298 MiComputeNonPagedPoolVa(FreePages);
299
300 /* Compute color information (L2 cache-separated paging lists) */
301 MiComputeColorInformation();
302
303 //
304 // Calculate the number of bytes for the PFN database, double it for ARM3,
305 // then add the color tables and convert to pages
306 //
307 MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN);
308 MxPfnAllocation <<= 1;
309 MxPfnAllocation += (MmSecondaryColors * sizeof(MMCOLOR_TABLES) * 2);
310 MxPfnAllocation >>= PAGE_SHIFT;
311
312 //
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
318 // 0x60000 bytes.
319 //
320 MxPfnAllocation++;
321
322 //
323 // Now calculate the nonpaged pool expansion VA region
324 //
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);
332
333 //
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).
337 //
338 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolStart -
339 (MmNumberOfSystemPtes + 1) * PAGE_SIZE);
340 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
341 ~((4 * 1024 * 1024) - 1));
342
343 //
344 // Don't let it go below the minimum
345 //
346 if (MmNonPagedSystemStart < (PVOID)0xEB000000)
347 {
348 //
349 // This is a hard-coded limit in the Windows NT address space
350 //
351 MmNonPagedSystemStart = (PVOID)0xEB000000;
352
353 //
354 // Reduce the amount of system PTEs to reach this point
355 //
356 MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolStart -
357 (ULONG_PTR)MmNonPagedSystemStart) >>
358 PAGE_SHIFT;
359 MmNumberOfSystemPtes--;
360 ASSERT(MmNumberOfSystemPtes > 1000);
361 }
362
363 //
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
366 //
367 if (MmSizeOfPagedPoolInBytes >
368 ((ULONG_PTR)MmNonPagedSystemStart - (ULONG_PTR)MmPagedPoolStart))
369 {
370 //
371 // We need some recalculations here
372 //
373 DPRINT1("Paged pool is too big!\n");
374 }
375
376 //
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.
381 //
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).
386 //
387 MmPfnDatabase[0] = (PVOID)0xB0000000;
388 MmPfnDatabase[1] = &MmPfnDatabase[0][MmHighestPhysicalPage];
389 ASSERT(((ULONG_PTR)MmPfnDatabase[0] & ((4 * 1024 * 1024) - 1)) == 0);
390
391 //
392 // Non paged pool comes after the PFN database
393 //
394 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmPfnDatabase[0] +
395 (MxPfnAllocation << PAGE_SHIFT));
396
397 //
398 // Now we actually need to get these many physical pages. Nonpaged pool
399 // is actually also physically contiguous (but not the expansion)
400 //
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);
406
407 /* Convert nonpaged pool size from bytes to pages */
408 MmMaximumNonPagedPoolInPages = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT;
409
410 //
411 // Now we need some pages to create the page tables for the NP system VA
412 // which includes system PTEs and expansion NP
413 //
414 StartPde = MiAddressToPde(MmNonPagedSystemStart);
415 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
416 while (StartPde <= EndPde)
417 {
418 //
419 // Sanity check
420 //
421 ASSERT(StartPde->u.Hard.Valid == 0);
422
423 //
424 // Get a page
425 //
426 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
427 ASSERT(TempPde.u.Hard.Valid == 1);
428 *StartPde = TempPde;
429
430 //
431 // Zero out the page table
432 //
433 PointerPte = MiPteToAddress(StartPde);
434 RtlZeroMemory(PointerPte, PAGE_SIZE);
435
436 //
437 // Next
438 //
439 StartPde++;
440 }
441
442 //
443 // Now we need pages for the page tables which will map initial NP
444 //
445 StartPde = MiAddressToPde(MmPfnDatabase[0]);
446 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
447 MmSizeOfNonPagedPoolInBytes - 1));
448 while (StartPde <= EndPde)
449 {
450 //
451 // Sanity check
452 //
453 ASSERT(StartPde->u.Hard.Valid == 0);
454
455 //
456 // Get a page
457 //
458 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
459 ASSERT(TempPde.u.Hard.Valid == 1);
460 *StartPde = TempPde;
461
462 //
463 // Zero out the page table
464 //
465 PointerPte = MiPteToAddress(StartPde);
466 RtlZeroMemory(PointerPte, PAGE_SIZE);
467
468 //
469 // Next
470 //
471 StartPde++;
472 }
473
474 //
475 // Now remember where the expansion starts
476 //
477 MmNonPagedPoolExpansionStart = NonPagedPoolExpansionVa;
478
479 //
480 // Last step is to actually map the nonpaged pool
481 //
482 PointerPte = MiAddressToPte(MmNonPagedPoolStart);
483 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
484 MmSizeOfNonPagedPoolInBytes - 1));
485 while (PointerPte <= LastPte)
486 {
487 //
488 // Use one of our contigous pages
489 //
490 TempPte.u.Hard.PageFrameNumber = PageFrameIndex++;
491 ASSERT(PointerPte->u.Hard.Valid == 0);
492 ASSERT(TempPte.u.Hard.Valid == 1);
493 *PointerPte++ = TempPte;
494 }
495
496 //
497 // Sanity check: make sure we have properly defined the system PTE space
498 //
499 ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
500 MiAddressToPte(MmNonPagedPoolExpansionStart));
501
502 /* Now go ahead and initialize the nonpaged pool */
503 MiInitializeNonPagedPool();
504 MiInitializeNonPagedPoolThresholds();
505
506 /* Map the PFN database pages */
507 MiMapPfnDatabase(LoaderBlock);
508
509 /* Initialize the color tables */
510 MiInitializeColorTables();
511
512 /* Build the PFN Database */
513 MiInitializePfnDatabase(LoaderBlock);
514
515 /* Call back into shitMM to setup the ReactOS PFN database */
516 MmInitializePageList();
517
518 //
519 // Reset the descriptor back so we can create the correct memory blocks
520 //
521 *MxFreeDescriptor = MxOldFreeDescriptor;
522
523 //
524 // Initialize the nonpaged pool
525 //
526 InitializePool(NonPagedPool, 0);
527
528 //
529 // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
530 //
531 PointerPte = MiAddressToPte(MmNonPagedSystemStart);
532 OldCount = MmNumberOfSystemPtes;
533 MmNumberOfSystemPtes = MiAddressToPte(MmNonPagedPoolExpansionStart) -
534 PointerPte;
535 MmNumberOfSystemPtes--;
536 DPRINT("Final System PTE count: %d (%d bytes)\n",
537 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
538
539 //
540 // Create the system PTE space
541 //
542 MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
543
544 //
545 // Get the PDE For hyperspace
546 //
547 StartPde = MiAddressToPde(HYPER_SPACE);
548
549 //
550 // Allocate a page for it and create it
551 //
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);
557 *StartPde = TempPde;
558
559 //
560 // Zero out the page table now
561 //
562 PointerPte = MiAddressToPte(HYPER_SPACE);
563 RtlZeroMemory(PointerPte, PAGE_SIZE);
564
565 //
566 // Setup the mapping PTEs
567 //
568 MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START);
569 MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
570 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
571
572 //
573 // Reserve system PTEs for zeroing PTEs and clear them
574 //
575 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES,
576 SystemPteSpace);
577 RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
578
579 //
580 // Set the counter to maximum to boot with
581 //
582 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
583
584 return STATUS_SUCCESS;
585 }
586
587 /* EOF */