bdbda30fbbe668674629c79c227201143f009a5c
[reactos.git] / reactos / 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 //
408 // Now we need some pages to create the page tables for the NP system VA
409 // which includes system PTEs and expansion NP
410 //
411 StartPde = MiAddressToPde(MmNonPagedSystemStart);
412 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
413 while (StartPde <= EndPde)
414 {
415 //
416 // Sanity check
417 //
418 ASSERT(StartPde->u.Hard.Valid == 0);
419
420 //
421 // Get a page
422 //
423 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
424 ASSERT(TempPde.u.Hard.Valid == 1);
425 *StartPde = TempPde;
426
427 //
428 // Zero out the page table
429 //
430 PointerPte = MiPteToAddress(StartPde);
431 RtlZeroMemory(PointerPte, PAGE_SIZE);
432
433 //
434 // Next
435 //
436 StartPde++;
437 }
438
439 //
440 // Now we need pages for the page tables which will map initial NP
441 //
442 StartPde = MiAddressToPde(MmPfnDatabase[0]);
443 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
444 MmSizeOfNonPagedPoolInBytes - 1));
445 while (StartPde <= EndPde)
446 {
447 //
448 // Sanity check
449 //
450 ASSERT(StartPde->u.Hard.Valid == 0);
451
452 //
453 // Get a page
454 //
455 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
456 ASSERT(TempPde.u.Hard.Valid == 1);
457 *StartPde = TempPde;
458
459 //
460 // Zero out the page table
461 //
462 PointerPte = MiPteToAddress(StartPde);
463 RtlZeroMemory(PointerPte, PAGE_SIZE);
464
465 //
466 // Next
467 //
468 StartPde++;
469 }
470
471 //
472 // Now remember where the expansion starts
473 //
474 MmNonPagedPoolExpansionStart = NonPagedPoolExpansionVa;
475
476 //
477 // Last step is to actually map the nonpaged pool
478 //
479 PointerPte = MiAddressToPte(MmNonPagedPoolStart);
480 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
481 MmSizeOfNonPagedPoolInBytes - 1));
482 while (PointerPte <= LastPte)
483 {
484 //
485 // Use one of our contigous pages
486 //
487 TempPte.u.Hard.PageFrameNumber = PageFrameIndex++;
488 ASSERT(PointerPte->u.Hard.Valid == 0);
489 ASSERT(TempPte.u.Hard.Valid == 1);
490 *PointerPte++ = TempPte;
491 }
492
493 //
494 // Sanity check: make sure we have properly defined the system PTE space
495 //
496 ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
497 MiAddressToPte(MmNonPagedPoolExpansionStart));
498
499 //
500 // Now go ahead and initialize the ARMĀ³ nonpaged pool
501 //
502 MiInitializeArmPool();
503
504 /* Map the PFN database pages */
505 MiMapPfnDatabase(LoaderBlock);
506
507 /* Initialize the color tables */
508 MiInitializeColorTables();
509
510 /* Build the PFN Database */
511 MiInitializePfnDatabase(LoaderBlock);
512
513 /* Call back into shitMM to setup the ReactOS PFN database */
514 MmInitializePageList();
515
516 //
517 // Reset the descriptor back so we can create the correct memory blocks
518 //
519 *MxFreeDescriptor = MxOldFreeDescriptor;
520
521 //
522 // Initialize the nonpaged pool
523 //
524 InitializePool(NonPagedPool, 0);
525
526 //
527 // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
528 //
529 PointerPte = MiAddressToPte(MmNonPagedSystemStart);
530 OldCount = MmNumberOfSystemPtes;
531 MmNumberOfSystemPtes = MiAddressToPte(MmNonPagedPoolExpansionStart) -
532 PointerPte;
533 MmNumberOfSystemPtes--;
534 DPRINT("Final System PTE count: %d (%d bytes)\n",
535 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
536
537 //
538 // Create the system PTE space
539 //
540 MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
541
542 //
543 // Get the PDE For hyperspace
544 //
545 StartPde = MiAddressToPde(HYPER_SPACE);
546
547 //
548 // Allocate a page for it and create it
549 //
550 PageFrameIndex = MmAllocPage(MC_SYSTEM);
551 TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
552 TempPde.u.Hard.Global = FALSE; // Hyperspace is local!
553 ASSERT(StartPde->u.Hard.Valid == 0);
554 ASSERT(TempPde.u.Hard.Valid == 1);
555 *StartPde = TempPde;
556
557 //
558 // Zero out the page table now
559 //
560 PointerPte = MiAddressToPte(HYPER_SPACE);
561 RtlZeroMemory(PointerPte, PAGE_SIZE);
562
563 //
564 // Setup the mapping PTEs
565 //
566 MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START);
567 MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
568 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
569
570 //
571 // Reserve system PTEs for zeroing PTEs and clear them
572 //
573 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES,
574 SystemPteSpace);
575 RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
576
577 //
578 // Set the counter to maximum to boot with
579 //
580 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
581
582 return STATUS_SUCCESS;
583 }
584
585 /* EOF */