- Initialize MmLowestPhysicalPage to -1, otherwise setting this value will never...
[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"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../../ARM3/miarm.h"
18
19 /* GLOBALS ********************************************************************/
20
21 //
22 // These are all registry-configurable, but by default, the memory manager will
23 // figure out the most appropriate values.
24 //
25 ULONG MmMaximumNonPagedPoolPercent;
26 ULONG MmSizeOfNonPagedPoolInBytes;
27 ULONG MmMaximumNonPagedPoolInBytes;
28
29 //
30 // These numbers describe the discrete equation components of the nonpaged
31 // pool sizing algorithm.
32 //
33 // They are described on http://support.microsoft.com/default.aspx/kb/126402/ja
34 // along with the algorithm that uses them, which is implemented later below.
35 //
36 ULONG MmMinimumNonPagedPoolSize = 256 * 1024;
37 ULONG MmMinAdditionNonPagedPoolPerMb = 32 * 1024;
38 ULONG MmDefaultMaximumNonPagedPool = 1024 * 1024;
39 ULONG MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
40
41 //
42 // The memory layout (and especially variable names) of the NT kernel mode
43 // components can be a bit hard to twig, especially when it comes to the non
44 // paged area.
45 //
46 // There are really two components to the non-paged pool:
47 //
48 // - The initial nonpaged pool, sized dynamically up to a maximum.
49 // - The expansion nonpaged pool, sized dynamically up to a maximum.
50 //
51 // The initial nonpaged pool is physically continuous for performance, and
52 // immediately follows the PFN database, typically sharing the same PDE. It is
53 // a very small resource (32MB on a 1GB system), and capped at 128MB.
54 //
55 // Right now we call this the "ARM³ Nonpaged Pool" and it begins somewhere after
56 // the PFN database (which starts at 0xB0000000).
57 //
58 // The expansion nonpaged pool, on the other hand, can grow much bigger (400MB
59 // for a 1GB system). On ARM³ however, it is currently capped at 128MB.
60 //
61 // The address where the initial nonpaged pool starts is aptly named
62 // MmNonPagedPoolStart, and it describes a range of MmSizeOfNonPagedPoolInBytes
63 // bytes.
64 //
65 // Expansion nonpaged pool starts at an address described by the variable called
66 // MmNonPagedPoolExpansionStart, and it goes on for MmMaximumNonPagedPoolInBytes
67 // minus MmSizeOfNonPagedPoolInBytes bytes, always reaching MmNonPagedPoolEnd
68 // (because of the way it's calculated) at 0xFFBE0000.
69 //
70 // Initial nonpaged pool is allocated and mapped early-on during boot, but what
71 // about the expansion nonpaged pool? It is instead composed of special pages
72 // which belong to what are called System PTEs. These PTEs are the matter of a
73 // later discussion, but they are also considered part of the "nonpaged" OS, due
74 // to the fact that they are never paged out -- once an address is described by
75 // a System PTE, it is always valid, until the System PTE is torn down.
76 //
77 // System PTEs are actually composed of two "spaces", the system space proper,
78 // and the nonpaged pool expansion space. The latter, as we've already seen,
79 // begins at MmNonPagedPoolExpansionStart. Based on the number of System PTEs
80 // that the system will support, the remaining address space below this address
81 // is used to hold the system space PTEs. This address, in turn, is held in the
82 // variable named MmNonPagedSystemStart, which itself is never allowed to go
83 // below 0xEB000000 (thus creating an upper bound on the number of System PTEs).
84 //
85 // This means that 330MB are reserved for total nonpaged system VA, on top of
86 // whatever the initial nonpaged pool allocation is.
87 //
88 // The following URLs, valid as of April 23rd, 2008, support this evidence:
89 //
90 // http://www.cs.miami.edu/~burt/journal/NT/memory.html
91 // http://www.ditii.com/2007/09/28/windows-memory-management-x86-virtual-address-space/
92 //
93 PVOID MmNonPagedSystemStart;
94 PVOID MmNonPagedPoolStart;
95 PVOID MmNonPagedPoolExpansionStart;
96 PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
97
98 //
99 // Old ReactOS Mm nonpaged pool
100 //
101 extern PVOID MiNonPagedPoolStart;
102 extern ULONG MiNonPagedPoolLength;
103
104 //
105 // This is where paged pool starts by default
106 //
107 PVOID MmPagedPoolStart = MI_PAGED_POOL_START;
108 PVOID MmPagedPoolEnd;
109
110 //
111 // And this is its default size
112 //
113 ULONG MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
114 PFN_NUMBER MmSizeOfPagedPoolInPages = MI_MIN_INIT_PAGED_POOLSIZE / PAGE_SIZE;
115
116 //
117 // Session space starts at 0xBFFFFFFF and grows downwards
118 // By default, it includes an 8MB image area where we map win32k and video card
119 // drivers, followed by a 4MB area containing the session's working set. This is
120 // then followed by a 20MB mapped view area and finally by the session's paged
121 // pool, by default 16MB.
122 //
123 // On a normal system, this results in session space occupying the region from
124 // 0xBD000000 to 0xC0000000
125 //
126 // See miarm.h for the defines that determine the sizing of this region. On an
127 // NT system, some of these can be configured through the registry, but we don't
128 // support that yet.
129 //
130 PVOID MiSessionSpaceEnd; // 0xC0000000
131 PVOID MiSessionImageEnd; // 0xC0000000
132 PVOID MiSessionImageStart; // 0xBF800000
133 PVOID MiSessionViewStart; // 0xBE000000
134 PVOID MiSessionPoolEnd; // 0xBE000000
135 PVOID MiSessionPoolStart; // 0xBD000000
136 PVOID MmSessionBase; // 0xBD000000
137 ULONG MmSessionSize;
138 ULONG MmSessionViewSize;
139 ULONG MmSessionPoolSize;
140 ULONG MmSessionImageSize;
141
142 //
143 // The system view space, on the other hand, is where sections that are memory
144 // mapped into "system space" end up.
145 //
146 // By default, it is a 16MB region.
147 //
148 PVOID MiSystemViewStart;
149 ULONG MmSystemViewSize;
150
151 //
152 // A copy of the system page directory (the page directory associated with the
153 // System process) is kept (double-mapped) by the manager in order to lazily
154 // map paged pool PDEs into external processes when they fault on a paged pool
155 // address.
156 //
157 PFN_NUMBER MmSystemPageDirectory;
158 PMMPTE MmSystemPagePtes;
159
160 //
161 // Windows NT seems to choose between 7000, 11000 and 50000
162 // On systems with more than 32MB, this number is then doubled, and further
163 // aligned up to a PDE boundary (4MB).
164 //
165 ULONG MmNumberOfSystemPtes;
166
167 //
168 // This is how many pages the PFN database will take up
169 // In Windows, this includes the Quark Color Table, but not in ARM³
170 //
171 ULONG MxPfnAllocation;
172
173 //
174 // Unlike the old ReactOS Memory Manager, ARM³ (and Windows) does not keep track
175 // of pages that are not actually valid physical memory, such as ACPI reserved
176 // regions, BIOS address ranges, or holes in physical memory address space which
177 // could indicate device-mapped I/O memory.
178 //
179 // In fact, the lack of a PFN entry for a page usually indicates that this is
180 // I/O space instead.
181 //
182 // A bitmap, called the PFN bitmap, keeps track of all page frames by assigning
183 // a bit to each. If the bit is set, then the page is valid physical RAM.
184 //
185 RTL_BITMAP MiPfnBitMap;
186
187 //
188 // This structure describes the different pieces of RAM-backed address space
189 //
190 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
191
192 //
193 // Before we have a PFN database, memory comes straight from our physical memory
194 // blocks, which is nice because it's guaranteed contiguous and also because once
195 // we take a page from here, the system doesn't see it anymore.
196 // However, once the fun is over, those pages must be re-integrated back into
197 // PFN society life, and that requires us keeping a copy of the original layout
198 // so that we can parse it later.
199 //
200 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
201 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
202
203 //
204 // This is where we keep track of the most basic physical layout markers
205 //
206 ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage = -1;
207
208 //
209 // The total number of pages mapped by the boot loader, which include the kernel
210 // HAL, boot drivers, registry, NLS files and other loader data structures is
211 // kept track of here. This depends on "LoaderPagesSpanned" being correct when
212 // coming from the loader.
213 //
214 // This number is later aligned up to a PDE boundary.
215 //
216 ULONG MmBootImageSize;
217
218 //
219 // These three variables keep track of the core separation of address space that
220 // exists between kernel mode and user mode.
221 //
222 ULONG MmUserProbeAddress;
223 PVOID MmHighestUserAddress;
224 PVOID MmSystemRangeStart;
225
226 /* PRIVATE FUNCTIONS **********************************************************/
227
228 //
229 // In Bavaria, this is probably a hate crime
230 //
231 VOID
232 FASTCALL
233 MiSyncARM3WithROS(IN PVOID AddressStart,
234 IN PVOID AddressEnd)
235 {
236 //
237 // Puerile piece of junk-grade carbonized horseshit puss sold to the lowest bidder
238 //
239 ULONG Pde = ADDR_TO_PDE_OFFSET(AddressStart);
240 while (Pde <= ADDR_TO_PDE_OFFSET(AddressEnd))
241 {
242 //
243 // This both odious and heinous
244 //
245 extern ULONG MmGlobalKernelPageDirectory[1024];
246 MmGlobalKernelPageDirectory[Pde] = ((PULONG)PDE_BASE)[Pde];
247 Pde++;
248 }
249 }
250
251 PFN_NUMBER
252 NTAPI
253 MxGetNextPage(IN PFN_NUMBER PageCount)
254 {
255 PFN_NUMBER Pfn;
256
257 //
258 // Make sure we have enough pages
259 //
260 if (PageCount > MxFreeDescriptor->PageCount)
261 {
262 //
263 // Crash the system
264 //
265 KeBugCheckEx(INSTALL_MORE_MEMORY,
266 MmNumberOfPhysicalPages,
267 MxFreeDescriptor->PageCount,
268 MxOldFreeDescriptor.PageCount,
269 PageCount);
270 }
271
272 //
273 // Use our lowest usable free pages
274 //
275 Pfn = MxFreeDescriptor->BasePage;
276 MxFreeDescriptor->BasePage += PageCount;
277 MxFreeDescriptor->PageCount -= PageCount;
278 return Pfn;
279 }
280
281 PPHYSICAL_MEMORY_DESCRIPTOR
282 NTAPI
283 MmInitializeMemoryLimits(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
284 IN PBOOLEAN IncludeType)
285 {
286 PLIST_ENTRY NextEntry;
287 ULONG Run = 0, InitialRuns = 0;
288 PFN_NUMBER NextPage = -1, PageCount = 0;
289 PPHYSICAL_MEMORY_DESCRIPTOR Buffer, NewBuffer;
290 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
291
292 //
293 // Scan the memory descriptors
294 //
295 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
296 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
297 {
298 //
299 // For each one, increase the memory allocation estimate
300 //
301 InitialRuns++;
302 NextEntry = NextEntry->Flink;
303 }
304
305 //
306 // Allocate the maximum we'll ever need
307 //
308 Buffer = ExAllocatePoolWithTag(NonPagedPool,
309 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
310 sizeof(PHYSICAL_MEMORY_RUN) *
311 (InitialRuns - 1),
312 'lMmM');
313 if (!Buffer) return NULL;
314
315 //
316 // For now that's how many runs we have
317 //
318 Buffer->NumberOfRuns = InitialRuns;
319
320 //
321 // Now loop through the descriptors again
322 //
323 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
324 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
325 {
326 //
327 // Grab each one, and check if it's one we should include
328 //
329 MdBlock = CONTAINING_RECORD(NextEntry,
330 MEMORY_ALLOCATION_DESCRIPTOR,
331 ListEntry);
332 if ((MdBlock->MemoryType < LoaderMaximum) &&
333 (IncludeType[MdBlock->MemoryType]))
334 {
335 //
336 // Add this to our running total
337 //
338 PageCount += MdBlock->PageCount;
339
340 //
341 // Check if the next page is described by the next descriptor
342 //
343 if (MdBlock->BasePage == NextPage)
344 {
345 //
346 // Combine it into the same physical run
347 //
348 ASSERT(MdBlock->PageCount != 0);
349 Buffer->Run[Run - 1].PageCount += MdBlock->PageCount;
350 NextPage += MdBlock->PageCount;
351 }
352 else
353 {
354 //
355 // Otherwise just duplicate the descriptor's contents
356 //
357 Buffer->Run[Run].BasePage = MdBlock->BasePage;
358 Buffer->Run[Run].PageCount = MdBlock->PageCount;
359 NextPage = Buffer->Run[Run].BasePage + Buffer->Run[Run].PageCount;
360
361 //
362 // And in this case, increase the number of runs
363 //
364 Run++;
365 }
366 }
367
368 //
369 // Try the next descriptor
370 //
371 NextEntry = MdBlock->ListEntry.Flink;
372 }
373
374 //
375 // We should not have been able to go past our initial estimate
376 //
377 ASSERT(Run <= Buffer->NumberOfRuns);
378
379 //
380 // Our guess was probably exaggerated...
381 //
382 if (InitialRuns > Run)
383 {
384 //
385 // Allocate a more accurately sized buffer
386 //
387 NewBuffer = ExAllocatePoolWithTag(NonPagedPool,
388 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
389 sizeof(PHYSICAL_MEMORY_RUN) *
390 (Run - 1),
391 'lMmM');
392 if (NewBuffer)
393 {
394 //
395 // Copy the old buffer into the new, then free it
396 //
397 RtlCopyMemory(NewBuffer->Run,
398 Buffer->Run,
399 sizeof(PHYSICAL_MEMORY_RUN) * Run);
400 ExFreePool(Buffer);
401
402 //
403 // Now use the new buffer
404 //
405 Buffer = NewBuffer;
406 }
407 }
408
409 //
410 // Write the final numbers, and return it
411 //
412 Buffer->NumberOfRuns = Run;
413 Buffer->NumberOfPages = PageCount;
414 return Buffer;
415 }
416
417 VOID
418 NTAPI
419 MiBuildPagedPool(VOID)
420 {
421 PMMPTE PointerPte, PointerPde;
422 MMPTE TempPte = HyperTemplatePte;
423 PFN_NUMBER PageFrameIndex;
424 KIRQL OldIrql;
425 ULONG Size, BitMapSize;
426
427 //
428 // Get the page frame number for the system page directory
429 //
430 PointerPte = MiAddressToPte(PDE_BASE);
431 MmSystemPageDirectory = PFN_FROM_PTE(PointerPte);
432
433 //
434 // Allocate a system PTE which will hold a copy of the page directory
435 //
436 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
437 ASSERT(PointerPte);
438 MmSystemPagePtes = MiPteToAddress(PointerPte);
439
440 //
441 // Make this system PTE point to the system page directory.
442 // It is now essentially double-mapped. This will be used later for lazy
443 // evaluation of PDEs accross process switches, similarly to how the Global
444 // page directory array in the old ReactOS Mm is used (but in a less hacky
445 // way).
446 //
447 TempPte = HyperTemplatePte;
448 TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory;
449 ASSERT(PointerPte->u.Hard.Valid == 0);
450 ASSERT(TempPte.u.Hard.Valid == 1);
451 *PointerPte = TempPte;
452
453 //
454 // Let's get back to paged pool work: size it up.
455 // By default, it should be twice as big as nonpaged pool.
456 //
457 MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes;
458 if (MmSizeOfPagedPoolInBytes > ((ULONG_PTR)MmNonPagedSystemStart -
459 (ULONG_PTR)MmPagedPoolStart))
460 {
461 //
462 // On the other hand, we have limited VA space, so make sure that the VA
463 // for paged pool doesn't overflow into nonpaged pool VA. Otherwise, set
464 // whatever maximum is possible.
465 //
466 MmSizeOfPagedPoolInBytes = (ULONG_PTR)MmNonPagedSystemStart -
467 (ULONG_PTR)MmPagedPoolStart;
468 }
469
470 //
471 // Get the size in pages and make sure paged pool is at least 32MB.
472 //
473 Size = MmSizeOfPagedPoolInBytes;
474 if (Size < MI_MIN_INIT_PAGED_POOLSIZE) Size = MI_MIN_INIT_PAGED_POOLSIZE;
475 Size = BYTES_TO_PAGES(Size);
476
477 //
478 // Now check how many PTEs will be required for these many pages.
479 //
480 Size = (Size + (1024 - 1)) / 1024;
481
482 //
483 // Recompute the page-aligned size of the paged pool, in bytes and pages.
484 //
485 MmSizeOfPagedPoolInBytes = Size * PAGE_SIZE * 1024;
486 MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
487
488 //
489 // Let's be really sure this doesn't overflow into nonpaged system VA
490 //
491 ASSERT((MmSizeOfPagedPoolInBytes + (ULONG_PTR)MmPagedPoolStart) <=
492 (ULONG_PTR)MmNonPagedSystemStart);
493
494 //
495 // This is where paged pool ends
496 //
497 MmPagedPoolEnd = (PVOID)(((ULONG_PTR)MmPagedPoolStart +
498 MmSizeOfPagedPoolInBytes) - 1);
499
500 //
501 // So now get the PDE for paged pool and zero it out
502 //
503 PointerPde = MiAddressToPde(MmPagedPoolStart);
504 RtlZeroMemory(PointerPde,
505 (1 + MiAddressToPde(MmPagedPoolEnd) - PointerPde) * sizeof(MMPTE));
506
507 //
508 // Next, get the first and last PTE
509 //
510 PointerPte = MiAddressToPte(MmPagedPoolStart);
511 MmPagedPoolInfo.FirstPteForPagedPool = PointerPte;
512 MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
513
514 //
515 // Lock the PFN database
516 //
517 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
518
519 //
520 // Allocate a page and map the first paged pool PDE
521 //
522 PageFrameIndex = MmAllocPage(MC_NPPOOL, 0);
523 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
524 ASSERT(PointerPde->u.Hard.Valid == 0);
525 ASSERT(TempPte.u.Hard.Valid == 1);
526 *PointerPde = TempPte;
527
528 //
529 // Release the PFN database lock
530 //
531 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
532
533 //
534 // We only have one PDE mapped for now... at fault time, additional PDEs
535 // will be allocated to handle paged pool growth. This is where they'll have
536 // to start.
537 //
538 MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde + 1;
539
540 //
541 // We keep track of each page via a bit, so check how big the bitmap will
542 // have to be (make sure to align our page count such that it fits nicely
543 // into a 4-byte aligned bitmap.
544 //
545 // We'll also allocate the bitmap header itself part of the same buffer.
546 //
547 Size = Size * 1024;
548 ASSERT(Size == MmSizeOfPagedPoolInPages);
549 BitMapSize = sizeof(RTL_BITMAP) + (((Size + 31) / 32) * sizeof(ULONG));
550
551 //
552 // Allocate the allocation bitmap, which tells us which regions have not yet
553 // been mapped into memory
554 //
555 MmPagedPoolInfo.PagedPoolAllocationMap = ExAllocatePoolWithTag(NonPagedPool,
556 BitMapSize,
557 ' mM');
558 ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
559
560 //
561 // Initialize it such that at first, only the first page's worth of PTEs is
562 // marked as allocated (incidentially, the first PDE we allocated earlier).
563 //
564 RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
565 (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
566 BitMapSize);
567 RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
568 RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 1024);
569
570 //
571 // We have a second bitmap, which keeps track of where allocations end.
572 // Given the allocation bitmap and a base address, we can therefore figure
573 // out which page is the last page of that allocation, and thus how big the
574 // entire allocation is.
575 //
576 MmPagedPoolInfo.EndOfPagedPoolBitmap = ExAllocatePoolWithTag(NonPagedPool,
577 BitMapSize,
578 ' mM');
579 ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
580 RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
581 (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
582 BitMapSize);
583
584 //
585 // Since no allocations have been made yet, there are no bits set as the end
586 //
587 RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
588
589 //
590 // Initialize paged pool.
591 //
592 //InitializePool(PagedPool, 0);
593 }
594
595 NTSTATUS
596 NTAPI
597 MmArmInitSystem(IN ULONG Phase,
598 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
599 {
600 PLIST_ENTRY NextEntry;
601 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
602 ULONG FreePages = 0;
603 PMEMORY_AREA MArea;
604 PHYSICAL_ADDRESS BoundaryAddressMultiple;
605 PFN_NUMBER PageFrameIndex;
606 PMMPTE StartPde, EndPde, PointerPte, LastPte;
607 MMPTE TempPde = HyperTemplatePte, TempPte = HyperTemplatePte;
608 PVOID NonPagedPoolExpansionVa, BaseAddress;
609 NTSTATUS Status;
610 ULONG OldCount;
611 BOOLEAN IncludeType[LoaderMaximum];
612 ULONG i;
613 PVOID Bitmap;
614 PPHYSICAL_MEMORY_RUN Run;
615 PFN_NUMBER FreePage, FreePageCount, PagesLeft, BasePage, PageCount;
616 BoundaryAddressMultiple.QuadPart = 0;
617
618 if (Phase == 0)
619 {
620 //
621 // Define the basic user vs. kernel address space separation
622 //
623 MmSystemRangeStart = (PVOID)KSEG0_BASE;
624 MmUserProbeAddress = (ULONG_PTR)MmSystemRangeStart - 0x10000;
625 MmHighestUserAddress = (PVOID)(MmUserProbeAddress - 1);
626
627 //
628 // Get the size of the boot loader's image allocations and then round
629 // that region up to a PDE size, so that any PDEs we might create for
630 // whatever follows are separate from the PDEs that boot loader might've
631 // already created (and later, we can blow all that away if we want to).
632 //
633 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
634 MmBootImageSize *= PAGE_SIZE;
635 MmBootImageSize = (MmBootImageSize + (4 * 1024 * 1024) - 1) & ~((4 * 1024 * 1024) - 1);
636 ASSERT((MmBootImageSize % (4 * 1024 * 1024)) == 0);
637
638 //
639 // Set the size of session view, pool, and image
640 //
641 MmSessionSize = MI_SESSION_SIZE;
642 MmSessionViewSize = MI_SESSION_VIEW_SIZE;
643 MmSessionPoolSize = MI_SESSION_POOL_SIZE;
644 MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
645
646 //
647 // Set the size of system view
648 //
649 MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
650
651 //
652 // This is where it all ends
653 //
654 MiSessionImageEnd = (PVOID)PTE_BASE;
655
656 //
657 // This is where we will load Win32k.sys and the video driver
658 //
659 MiSessionImageStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
660 MmSessionImageSize);
661
662 //
663 // So the view starts right below the session working set (itself below
664 // the image area)
665 //
666 MiSessionViewStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
667 MmSessionImageSize -
668 MI_SESSION_WORKING_SET_SIZE -
669 MmSessionViewSize);
670
671 //
672 // Session pool follows
673 //
674 MiSessionPoolEnd = MiSessionViewStart;
675 MiSessionPoolStart = (PVOID)((ULONG_PTR)MiSessionPoolEnd -
676 MmSessionPoolSize);
677
678 //
679 // And it all begins here
680 //
681 MmSessionBase = MiSessionPoolStart;
682
683 //
684 // Sanity check that our math is correct
685 //
686 ASSERT((ULONG_PTR)MmSessionBase + MmSessionSize == PTE_BASE);
687
688 //
689 // Session space ends wherever image session space ends
690 //
691 MiSessionSpaceEnd = MiSessionImageEnd;
692
693 //
694 // System view space ends at session space, so now that we know where
695 // this is, we can compute the base address of system view space itself.
696 //
697 MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase -
698 MmSystemViewSize);
699
700 //
701 // Set CR3 for the system process
702 //
703 PointerPte = MiAddressToPde(PTE_BASE);
704 PageFrameIndex = PFN_FROM_PTE(PointerPte) << PAGE_SHIFT;
705 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameIndex;
706
707 //
708 // Blow away user-mode
709 //
710 StartPde = MiAddressToPde(0);
711 EndPde = MiAddressToPde(KSEG0_BASE);
712 RtlZeroMemory(StartPde, (EndPde - StartPde) * sizeof(MMPTE));
713
714 //
715 // Loop the memory descriptors
716 //
717 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
718 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
719 {
720 //
721 // Get the memory block
722 //
723 MdBlock = CONTAINING_RECORD(NextEntry,
724 MEMORY_ALLOCATION_DESCRIPTOR,
725 ListEntry);
726
727 //
728 // Skip invisible memory
729 //
730 if ((MdBlock->MemoryType != LoaderFirmwarePermanent) &&
731 (MdBlock->MemoryType != LoaderSpecialMemory) &&
732 (MdBlock->MemoryType != LoaderHALCachedMemory) &&
733 (MdBlock->MemoryType != LoaderBBTMemory))
734 {
735 //
736 // Check if BURNMEM was used
737 //
738 if (MdBlock->MemoryType != LoaderBad)
739 {
740 //
741 // Count this in the total of pages
742 //
743 MmNumberOfPhysicalPages += MdBlock->PageCount;
744 }
745
746 //
747 // Check if this is the new lowest page
748 //
749 if (MdBlock->BasePage < MmLowestPhysicalPage)
750 {
751 //
752 // Update the lowest page
753 //
754 MmLowestPhysicalPage = MdBlock->BasePage;
755 }
756
757 //
758 // Check if this is the new highest page
759 //
760 PageFrameIndex = MdBlock->BasePage + MdBlock->PageCount;
761 if (PageFrameIndex > MmHighestPhysicalPage)
762 {
763 //
764 // Update the highest page
765 //
766 MmHighestPhysicalPage = PageFrameIndex - 1;
767 }
768
769 //
770 // Check if this is free memory
771 //
772 if ((MdBlock->MemoryType == LoaderFree) ||
773 (MdBlock->MemoryType == LoaderLoadedProgram) ||
774 (MdBlock->MemoryType == LoaderFirmwareTemporary) ||
775 (MdBlock->MemoryType == LoaderOsloaderStack))
776 {
777 //
778 // Check if this is the largest memory descriptor
779 //
780 if (MdBlock->PageCount > FreePages)
781 {
782 //
783 // For now, it is
784 //
785 FreePages = MdBlock->PageCount;
786 MxFreeDescriptor = MdBlock;
787 }
788 }
789 }
790
791 //
792 // Keep going
793 //
794 NextEntry = MdBlock->ListEntry.Flink;
795 }
796
797 //
798 // Save original values of the free descriptor, since it'll be
799 // altered by early allocations
800 //
801 MxOldFreeDescriptor = *MxFreeDescriptor;
802
803 //
804 // Check if this is a machine with less than 19MB of RAM
805 //
806 if (MmNumberOfPhysicalPages < MI_MIN_PAGES_FOR_SYSPTE_TUNING)
807 {
808 //
809 // Use the very minimum of system PTEs
810 //
811 MmNumberOfSystemPtes = 7000;
812 }
813 else
814 {
815 //
816 // Use the default, but check if we have more than 32MB of RAM
817 //
818 MmNumberOfSystemPtes = 11000;
819 if (MmNumberOfPhysicalPages > MI_MIN_PAGES_FOR_SYSPTE_BOOST)
820 {
821 //
822 // Double the amount of system PTEs
823 //
824 MmNumberOfSystemPtes <<= 1;
825 }
826 }
827
828 DPRINT("System PTE count has been tuned to %d (%d bytes)\n",
829 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
830
831 //
832 // Check if this is a machine with less than 256MB of RAM, and no overide
833 //
834 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
835 !(MmSizeOfNonPagedPoolInBytes))
836 {
837 //
838 // Force the non paged pool to be 2MB so we can reduce RAM usage
839 //
840 MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
841 }
842
843 //
844 // Check if the user gave a ridicuously large nonpaged pool RAM size
845 //
846 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
847 (MmNumberOfPhysicalPages * 7 / 8))
848 {
849 //
850 // More than 7/8ths of RAM was dedicated to nonpaged pool, ignore!
851 //
852 MmSizeOfNonPagedPoolInBytes = 0;
853 }
854
855 //
856 // Check if no registry setting was set, or if the setting was too low
857 //
858 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
859 {
860 //
861 // Start with the minimum (256 KB) and add 32 KB for each MB above 4
862 //
863 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
864 MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
865 256 * MmMinAdditionNonPagedPoolPerMb;
866 }
867
868 //
869 // Check if the registy setting or our dynamic calculation was too high
870 //
871 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
872 {
873 //
874 // Set it to the maximum
875 //
876 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
877 }
878
879 //
880 // Check if a percentage cap was set through the registry
881 //
882 if (MmMaximumNonPagedPoolPercent)
883 {
884 //
885 // Don't feel like supporting this right now
886 //
887 UNIMPLEMENTED;
888 }
889
890 //
891 // Page-align the nonpaged pool size
892 //
893 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
894
895 //
896 // Now, check if there was a registry size for the maximum size
897 //
898 if (!MmMaximumNonPagedPoolInBytes)
899 {
900 //
901 // Start with the default (1MB) and add 400 KB for each MB above 4
902 //
903 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
904 MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
905 256 * MmMaxAdditionNonPagedPoolPerMb;
906 }
907
908 //
909 // Don't let the maximum go too high
910 //
911 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
912 {
913 //
914 // Set it to the upper limit
915 //
916 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
917 }
918
919 //
920 // Calculate the number of bytes, and then convert to pages
921 //
922 MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN);
923 MxPfnAllocation >>= PAGE_SHIFT;
924
925 //
926 // We have to add one to the count here, because in the process of
927 // shifting down to the page size, we actually ended up getting the
928 // lower aligned size (so say, 0x5FFFF bytes is now 0x5F pages).
929 // Later on, we'll shift this number back into bytes, which would cause
930 // us to end up with only 0x5F000 bytes -- when we actually want to have
931 // 0x60000 bytes.
932 //
933 MxPfnAllocation++;
934
935 //
936 // Now calculate the nonpaged pool expansion VA region
937 //
938 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmNonPagedPoolEnd -
939 MmMaximumNonPagedPoolInBytes +
940 MmSizeOfNonPagedPoolInBytes);
941 MmNonPagedPoolStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolStart);
942 NonPagedPoolExpansionVa = MmNonPagedPoolStart;
943 DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
944 MmSizeOfNonPagedPoolInBytes, MmMaximumNonPagedPoolInBytes);
945
946 //
947 // Now calculate the nonpaged system VA region, which includes the
948 // nonpaged pool expansion (above) and the system PTEs. Note that it is
949 // then aligned to a PDE boundary (4MB).
950 //
951 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolStart -
952 (MmNumberOfSystemPtes + 1) * PAGE_SIZE);
953 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
954 ~((4 * 1024 * 1024) - 1));
955
956 //
957 // Don't let it go below the minimum
958 //
959 if (MmNonPagedSystemStart < (PVOID)0xEB000000)
960 {
961 //
962 // This is a hard-coded limit in the Windows NT address space
963 //
964 MmNonPagedSystemStart = (PVOID)0xEB000000;
965
966 //
967 // Reduce the amount of system PTEs to reach this point
968 //
969 MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolStart -
970 (ULONG_PTR)MmNonPagedSystemStart) >>
971 PAGE_SHIFT;
972 MmNumberOfSystemPtes--;
973 ASSERT(MmNumberOfSystemPtes > 1000);
974 }
975
976 //
977 // Normally, the PFN database should start after the loader images.
978 // This is already the case in ReactOS, but for now we want to co-exist
979 // with the old memory manager, so we'll create a "Shadow PFN Database"
980 // instead, and arbitrarly start it at 0xB0000000.
981 //
982 MmPfnDatabase = (PVOID)0xB0000000;
983 ASSERT(((ULONG_PTR)MmPfnDatabase & ((4 * 1024 * 1024) - 1)) == 0);
984
985 //
986 // Non paged pool comes after the PFN database
987 //
988 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmPfnDatabase +
989 (MxPfnAllocation << PAGE_SHIFT));
990
991 //
992 // Now we actually need to get these many physical pages. Nonpaged pool
993 // is actually also physically contiguous (but not the expansion)
994 //
995 PageFrameIndex = MxGetNextPage(MxPfnAllocation +
996 (MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT));
997 ASSERT(PageFrameIndex != 0);
998 DPRINT("PFN DB PA PFN begins at: %lx\n", PageFrameIndex);
999 DPRINT("NP PA PFN begins at: %lx\n", PageFrameIndex + MxPfnAllocation);
1000
1001 //
1002 // Now we need some pages to create the page tables for the NP system VA
1003 // which includes system PTEs and expansion NP
1004 //
1005 StartPde = MiAddressToPde(MmNonPagedSystemStart);
1006 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
1007 while (StartPde <= EndPde)
1008 {
1009 //
1010 // Sanity check
1011 //
1012 ASSERT(StartPde->u.Hard.Valid == 0);
1013
1014 //
1015 // Get a page
1016 //
1017 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
1018 ASSERT(TempPde.u.Hard.Valid == 1);
1019 *StartPde = TempPde;
1020
1021 //
1022 // Zero out the page table
1023 //
1024 PointerPte = MiPteToAddress(StartPde);
1025 RtlZeroMemory(PointerPte, PAGE_SIZE);
1026
1027 //
1028 // Next
1029 //
1030 StartPde++;
1031 }
1032
1033 //
1034 // Now we need pages for the page tables which will map initial NP
1035 //
1036 StartPde = MiAddressToPde(MmPfnDatabase);
1037 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
1038 MmSizeOfNonPagedPoolInBytes - 1));
1039 while (StartPde <= EndPde)
1040 {
1041 //
1042 // Sanity check
1043 //
1044 ASSERT(StartPde->u.Hard.Valid == 0);
1045
1046 //
1047 // Get a page
1048 //
1049 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
1050 ASSERT(TempPde.u.Hard.Valid == 1);
1051 *StartPde = TempPde;
1052
1053 //
1054 // Zero out the page table
1055 //
1056 PointerPte = MiPteToAddress(StartPde);
1057 RtlZeroMemory(PointerPte, PAGE_SIZE);
1058
1059 //
1060 // Next
1061 //
1062 StartPde++;
1063 }
1064
1065 //
1066 // Now remember where the expansion starts
1067 //
1068 MmNonPagedPoolExpansionStart = NonPagedPoolExpansionVa;
1069
1070 //
1071 // Last step is to actually map the nonpaged pool
1072 //
1073 PointerPte = MiAddressToPte(MmNonPagedPoolStart);
1074 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
1075 MmSizeOfNonPagedPoolInBytes - 1));
1076 while (PointerPte <= LastPte)
1077 {
1078 //
1079 // Use one of our contigous pages
1080 //
1081 TempPte.u.Hard.PageFrameNumber = PageFrameIndex++;
1082 ASSERT(PointerPte->u.Hard.Valid == 0);
1083 ASSERT(TempPte.u.Hard.Valid == 1);
1084 *PointerPte++ = TempPte;
1085 }
1086
1087 //
1088 // ReactOS requires a memory area to keep the initial NP area off-bounds
1089 //
1090 BaseAddress = MmNonPagedPoolStart;
1091 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
1092 MEMORY_AREA_SYSTEM | MEMORY_AREA_STATIC,
1093 &BaseAddress,
1094 MmSizeOfNonPagedPoolInBytes,
1095 PAGE_READWRITE,
1096 &MArea,
1097 TRUE,
1098 0,
1099 BoundaryAddressMultiple);
1100 ASSERT(Status == STATUS_SUCCESS);
1101
1102 //
1103 // And we need one more for the system NP
1104 //
1105 BaseAddress = MmNonPagedSystemStart;
1106 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
1107 MEMORY_AREA_SYSTEM | MEMORY_AREA_STATIC,
1108 &BaseAddress,
1109 (ULONG_PTR)MmNonPagedPoolEnd -
1110 (ULONG_PTR)MmNonPagedSystemStart,
1111 PAGE_READWRITE,
1112 &MArea,
1113 TRUE,
1114 0,
1115 BoundaryAddressMultiple);
1116 ASSERT(Status == STATUS_SUCCESS);
1117
1118 //
1119 // Sanity check: make sure we have properly defined the system PTE space
1120 //
1121 ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
1122 MiAddressToPte(MmNonPagedPoolExpansionStart));
1123
1124 //
1125 // Now go ahead and initialize the ARM³ nonpaged pool
1126 //
1127 MiInitializeArmPool();
1128
1129 //
1130 // Get current page data, since we won't be using MxGetNextPage as it
1131 // would corrupt our state
1132 //
1133 FreePage = MxFreeDescriptor->BasePage;
1134 FreePageCount = MxFreeDescriptor->PageCount;
1135 PagesLeft = 0;
1136
1137 //
1138 // Loop the memory descriptors
1139 //
1140 NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
1141 while (NextEntry != &KeLoaderBlock->MemoryDescriptorListHead)
1142 {
1143 //
1144 // Get the descriptor
1145 //
1146 MdBlock = CONTAINING_RECORD(NextEntry,
1147 MEMORY_ALLOCATION_DESCRIPTOR,
1148 ListEntry);
1149 if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
1150 (MdBlock->MemoryType == LoaderBBTMemory) ||
1151 (MdBlock->MemoryType == LoaderSpecialMemory))
1152 {
1153 //
1154 // These pages are not part of the PFN database
1155 //
1156 NextEntry = MdBlock->ListEntry.Flink;
1157 continue;
1158 }
1159
1160 //
1161 // Next, check if this is our special free descriptor we've found
1162 //
1163 if (MdBlock == MxFreeDescriptor)
1164 {
1165 //
1166 // Use the real numbers instead
1167 //
1168 BasePage = MxOldFreeDescriptor.BasePage;
1169 PageCount = MxOldFreeDescriptor.PageCount;
1170 }
1171 else
1172 {
1173 //
1174 // Use the descriptor's numbers
1175 //
1176 BasePage = MdBlock->BasePage;
1177 PageCount = MdBlock->PageCount;
1178 }
1179
1180 //
1181 // Get the PTEs for this range
1182 //
1183 PointerPte = MiAddressToPte(&MmPfnDatabase[BasePage]);
1184 LastPte = MiAddressToPte(((ULONG_PTR)&MmPfnDatabase[BasePage + PageCount]) - 1);
1185 DPRINT("MD Type: %lx Base: %lx Count: %lx\n", MdBlock->MemoryType, BasePage, PageCount);
1186
1187 //
1188 // Loop them
1189 //
1190 while (PointerPte <= LastPte)
1191 {
1192 //
1193 // We'll only touch PTEs that aren't already valid
1194 //
1195 if (PointerPte->u.Hard.Valid == 0)
1196 {
1197 //
1198 // Use the next free page
1199 //
1200 TempPte.u.Hard.PageFrameNumber = FreePage;
1201 ASSERT(FreePageCount != 0);
1202
1203 //
1204 // Consume free pages
1205 //
1206 FreePage++;
1207 FreePageCount--;
1208 if (!FreePageCount)
1209 {
1210 //
1211 // Out of memory
1212 //
1213 KeBugCheckEx(INSTALL_MORE_MEMORY,
1214 MmNumberOfPhysicalPages,
1215 FreePageCount,
1216 MxOldFreeDescriptor.PageCount,
1217 1);
1218 }
1219
1220 //
1221 // Write out this PTE
1222 //
1223 PagesLeft++;
1224 ASSERT(PointerPte->u.Hard.Valid == 0);
1225 ASSERT(TempPte.u.Hard.Valid == 1);
1226 *PointerPte = TempPte;
1227
1228 //
1229 // Zero this page
1230 //
1231 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
1232 }
1233
1234 //
1235 // Next!
1236 //
1237 PointerPte++;
1238 }
1239
1240 //
1241 // Do the next address range
1242 //
1243 NextEntry = MdBlock->ListEntry.Flink;
1244 }
1245
1246 //
1247 // Now update the free descriptors to consume the pages we used up during
1248 // the PFN allocation loop
1249 //
1250 MxFreeDescriptor->BasePage = FreePage;
1251 MxFreeDescriptor->PageCount = FreePageCount;
1252 }
1253 else if (Phase == 1) // IN BETWEEN, THE PFN DATABASE IS NOW CREATED
1254 {
1255 //
1256 // Reset the descriptor back so we can create the correct memory blocks
1257 //
1258 *MxFreeDescriptor = MxOldFreeDescriptor;
1259
1260 //
1261 // Initialize the nonpaged pool
1262 //
1263 InitializePool(NonPagedPool, 0);
1264
1265 //
1266 // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
1267 //
1268 PointerPte = MiAddressToPte(MmNonPagedSystemStart);
1269 OldCount = MmNumberOfSystemPtes;
1270 MmNumberOfSystemPtes = MiAddressToPte(MmNonPagedPoolExpansionStart) -
1271 PointerPte;
1272 MmNumberOfSystemPtes--;
1273 DPRINT("Final System PTE count: %d (%d bytes)\n",
1274 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
1275
1276 //
1277 // Create the system PTE space
1278 //
1279 MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
1280
1281 //
1282 // Get the PDE For hyperspace
1283 //
1284 StartPde = MiAddressToPde(HYPER_SPACE);
1285
1286 //
1287 // Allocate a page for it and create it
1288 //
1289 PageFrameIndex = MmAllocPage(MC_SYSTEM, 0);
1290 TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
1291 TempPde.u.Hard.Global = FALSE; // Hyperspace is local!
1292 ASSERT(StartPde->u.Hard.Valid == 0);
1293 ASSERT(TempPde.u.Hard.Valid == 1);
1294 *StartPde = TempPde;
1295
1296 //
1297 // Zero out the page table now
1298 //
1299 PointerPte = MiAddressToPte(HYPER_SPACE);
1300 RtlZeroMemory(PointerPte, PAGE_SIZE);
1301
1302 //
1303 // Setup the mapping PTEs
1304 //
1305 MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START);
1306 MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
1307 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
1308
1309 //
1310 // Reserve system PTEs for zeroing PTEs and clear them
1311 //
1312 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES,
1313 SystemPteSpace);
1314 RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
1315
1316 //
1317 // Set the counter to maximum to boot with
1318 //
1319 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
1320
1321 //
1322 // Sync us up with ReactOS Mm
1323 //
1324 MiSyncARM3WithROS(MmNonPagedSystemStart, (PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
1325 MiSyncARM3WithROS(MmPfnDatabase, (PVOID)((ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes - 1));
1326 MiSyncARM3WithROS((PVOID)HYPER_SPACE, (PVOID)(HYPER_SPACE + PAGE_SIZE - 1));
1327 }
1328 else // NOW WE HAVE NONPAGED POOL
1329 {
1330 //
1331 // Instantiate memory that we don't consider RAM/usable
1332 // We use the same exclusions that Windows does, in order to try to be
1333 // compatible with WinLDR-style booting
1334 //
1335 for (i = 0; i < LoaderMaximum; i++) IncludeType[i] = TRUE;
1336 IncludeType[LoaderBad] = FALSE;
1337 IncludeType[LoaderFirmwarePermanent] = FALSE;
1338 IncludeType[LoaderSpecialMemory] = FALSE;
1339 IncludeType[LoaderBBTMemory] = FALSE;
1340
1341 //
1342 // Build the physical memory block
1343 //
1344 MmPhysicalMemoryBlock = MmInitializeMemoryLimits(LoaderBlock,
1345 IncludeType);
1346
1347 //
1348 // Allocate enough buffer for the PFN bitmap
1349 // Align it up to a 32-bit boundary
1350 //
1351 Bitmap = ExAllocatePoolWithTag(NonPagedPool,
1352 (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
1353 ' mM');
1354 if (!Bitmap)
1355 {
1356 //
1357 // This is critical
1358 //
1359 KeBugCheckEx(INSTALL_MORE_MEMORY,
1360 MmNumberOfPhysicalPages,
1361 MmLowestPhysicalPage,
1362 MmHighestPhysicalPage,
1363 0x101);
1364 }
1365
1366 //
1367 // Initialize it and clear all the bits to begin with
1368 //
1369 RtlInitializeBitMap(&MiPfnBitMap,
1370 Bitmap,
1371 MmHighestPhysicalPage + 1);
1372 RtlClearAllBits(&MiPfnBitMap);
1373
1374 //
1375 // Loop physical memory runs
1376 //
1377 for (i = 0; i < MmPhysicalMemoryBlock->NumberOfRuns; i++)
1378 {
1379 //
1380 // Get the run
1381 //
1382 Run = &MmPhysicalMemoryBlock->Run[i];
1383 DPRINT("PHYSICAL RAM [0x%08p to 0x%08p]\n",
1384 Run->BasePage << PAGE_SHIFT,
1385 (Run->BasePage + Run->PageCount) << PAGE_SHIFT);
1386
1387 //
1388 // Make sure it has pages inside it
1389 //
1390 if (Run->PageCount)
1391 {
1392 //
1393 // Set the bits in the PFN bitmap
1394 //
1395 RtlSetBits(&MiPfnBitMap, Run->BasePage, Run->PageCount);
1396 }
1397 }
1398
1399 //
1400 // Size up paged pool and build the shadow system page directory
1401 //
1402 MiBuildPagedPool();
1403
1404 //
1405 // Print the memory layout
1406 //
1407 DPRINT1(" 0x%p - 0x%p\t%s\n",
1408 MmSystemRangeStart,
1409 (ULONG_PTR)MmSystemRangeStart + MmBootImageSize,
1410 "Boot Loaded Image");
1411 DPRINT1(" 0x%p - 0x%p\t%s\n",
1412 MiNonPagedPoolStart,
1413 (ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength,
1414 "Non Paged Pool");
1415 DPRINT1(" 0x%p - 0x%p\t%s\n",
1416 MmPagedPoolBase,
1417 (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize,
1418 "Paged Pool");
1419 DPRINT1(" 0x%p - 0x%p\t%s\n",
1420 MmPfnDatabase,
1421 (ULONG_PTR)MmPfnDatabase + (MxPfnAllocation << PAGE_SHIFT),
1422 "PFN Database");
1423 DPRINT1(" 0x%p - 0x%p\t%s\n",
1424 MmNonPagedPoolStart,
1425 (ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes,
1426 "ARM³ Non Paged Pool");
1427 DPRINT1(" 0x%p - 0x%p\t%s\n",
1428 MiSystemViewStart,
1429 (ULONG_PTR)MiSystemViewStart + MmSystemViewSize,
1430 "System View Space");
1431 DPRINT1(" 0x%p - 0x%p\t%s\n",
1432 MmSessionBase,
1433 MiSessionSpaceEnd,
1434 "Session Space");
1435 DPRINT1(" 0x%p - 0x%p\t%s\n",
1436 PTE_BASE, PDE_BASE,
1437 "Page Tables");
1438 DPRINT1(" 0x%p - 0x%p\t%s\n",
1439 PDE_BASE, HYPER_SPACE,
1440 "Page Directories");
1441 DPRINT1(" 0x%p - 0x%p\t%s\n",
1442 HYPER_SPACE, HYPER_SPACE + (4 * 1024 * 1024),
1443 "Hyperspace");
1444 DPRINT1(" 0x%p - 0x%p\t%s\n",
1445 MmPagedPoolStart,
1446 (ULONG_PTR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes,
1447 "ARM³ Paged Pool");
1448 DPRINT1(" 0x%p - 0x%p\t%s\n",
1449 MmNonPagedSystemStart, MmNonPagedPoolExpansionStart,
1450 "System PTE Space");
1451 DPRINT1(" 0x%p - 0x%p\t%s\n",
1452 MmNonPagedPoolExpansionStart, MmNonPagedPoolEnd,
1453 "Non Paged Pool Expansion PTE Space");
1454 }
1455
1456 //
1457 // Always return success for now
1458 //
1459 return STATUS_SUCCESS;
1460 }
1461
1462 /* EOF */