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 *******************************************************************/
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../../ARM3/miarm.h"
19 /* GLOBALS ********************************************************************/
22 // These are all registry-configurable, but by default, the memory manager will
23 // figure out the most appropriate values.
25 ULONG MmMaximumNonPagedPoolPercent
;
26 ULONG MmSizeOfNonPagedPoolInBytes
;
27 ULONG MmMaximumNonPagedPoolInBytes
;
30 // These numbers describe the discrete equation components of the nonpaged
31 // pool sizing algorithm.
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.
36 ULONG MmMinimumNonPagedPoolSize
= 256 * 1024;
37 ULONG MmMinAdditionNonPagedPoolPerMb
= 32 * 1024;
38 ULONG MmDefaultMaximumNonPagedPool
= 1024 * 1024;
39 ULONG MmMaxAdditionNonPagedPoolPerMb
= 400 * 1024;
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
46 // There are really two components to the non-paged pool:
48 // - The initial nonpaged pool, sized dynamically up to a maximum.
49 // - The expansion nonpaged pool, sized dynamically up to a maximum.
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.
55 // Right now we call this the "ARM³ Nonpaged Pool" and it begins somewhere after
56 // the PFN database (which starts at 0xB0000000).
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.
61 // The address where the initial nonpaged pool starts is aptly named
62 // MmNonPagedPoolStart, and it describes a range of MmSizeOfNonPagedPoolInBytes
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.
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.
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).
85 // This means that 330MB are reserved for total nonpaged system VA, on top of
86 // whatever the initial nonpaged pool allocation is.
88 // The following URLs, valid as of April 23rd, 2008, support this evidence:
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/
93 PVOID MmNonPagedSystemStart
;
94 PVOID MmNonPagedPoolStart
;
95 PVOID MmNonPagedPoolExpansionStart
;
96 PVOID MmNonPagedPoolEnd
= MI_NONPAGED_POOL_END
;
99 // This is where paged pool starts by default
101 PVOID MmPagedPoolStart
= MI_PAGED_POOL_START
;
102 PVOID MmPagedPoolEnd
;
105 // And this is its default size
107 ULONG MmSizeOfPagedPoolInBytes
= MI_MIN_INIT_PAGED_POOLSIZE
;
108 PFN_NUMBER MmSizeOfPagedPoolInPages
= MI_MIN_INIT_PAGED_POOLSIZE
/ PAGE_SIZE
;
111 // Session space starts at 0xBFFFFFFF and grows downwards
112 // By default, it includes an 8MB image area where we map win32k and video card
113 // drivers, followed by a 4MB area containing the session's working set. This is
114 // then followed by a 20MB mapped view area and finally by the session's paged
115 // pool, by default 16MB.
117 // On a normal system, this results in session space occupying the region from
118 // 0xBD000000 to 0xC0000000
120 // See miarm.h for the defines that determine the sizing of this region. On an
121 // NT system, some of these can be configured through the registry, but we don't
124 PVOID MiSessionSpaceEnd
; // 0xC0000000
125 PVOID MiSessionImageEnd
; // 0xC0000000
126 PVOID MiSessionImageStart
; // 0xBF800000
127 PVOID MiSessionViewStart
; // 0xBE000000
128 PVOID MiSessionPoolEnd
; // 0xBE000000
129 PVOID MiSessionPoolStart
; // 0xBD000000
130 PVOID MmSessionBase
; // 0xBD000000
132 ULONG MmSessionViewSize
;
133 ULONG MmSessionPoolSize
;
134 ULONG MmSessionImageSize
;
137 // The system view space, on the other hand, is where sections that are memory
138 // mapped into "system space" end up.
140 // By default, it is a 16MB region.
142 PVOID MiSystemViewStart
;
143 ULONG MmSystemViewSize
;
146 // A copy of the system page directory (the page directory associated with the
147 // System process) is kept (double-mapped) by the manager in order to lazily
148 // map paged pool PDEs into external processes when they fault on a paged pool
151 PFN_NUMBER MmSystemPageDirectory
;
152 PMMPTE MmSystemPagePtes
;
155 // The system cache starts right after hyperspace. The first few pages are for
156 // keeping track of the system working set list.
158 // This should be 0xC0C00000 -- the cache itself starts at 0xC1000000
160 PMMWSL MmSystemCacheWorkingSetList
= MI_SYSTEM_CACHE_WS_START
;
163 // Windows NT seems to choose between 7000, 11000 and 50000
164 // On systems with more than 32MB, this number is then doubled, and further
165 // aligned up to a PDE boundary (4MB).
167 ULONG MmNumberOfSystemPtes
;
170 // This is how many pages the PFN database will take up
171 // In Windows, this includes the Quark Color Table, but not in ARM³
173 ULONG MxPfnAllocation
;
176 // Unlike the old ReactOS Memory Manager, ARM³ (and Windows) does not keep track
177 // of pages that are not actually valid physical memory, such as ACPI reserved
178 // regions, BIOS address ranges, or holes in physical memory address space which
179 // could indicate device-mapped I/O memory.
181 // In fact, the lack of a PFN entry for a page usually indicates that this is
182 // I/O space instead.
184 // A bitmap, called the PFN bitmap, keeps track of all page frames by assigning
185 // a bit to each. If the bit is set, then the page is valid physical RAM.
187 RTL_BITMAP MiPfnBitMap
;
190 // This structure describes the different pieces of RAM-backed address space
192 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock
;
195 // Before we have a PFN database, memory comes straight from our physical memory
196 // blocks, which is nice because it's guaranteed contiguous and also because once
197 // we take a page from here, the system doesn't see it anymore.
198 // However, once the fun is over, those pages must be re-integrated back into
199 // PFN society life, and that requires us keeping a copy of the original layout
200 // so that we can parse it later.
202 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor
;
203 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor
;
206 // This is where we keep track of the most basic physical layout markers
208 ULONG MmNumberOfPhysicalPages
, MmHighestPhysicalPage
, MmLowestPhysicalPage
= -1;
211 // The total number of pages mapped by the boot loader, which include the kernel
212 // HAL, boot drivers, registry, NLS files and other loader data structures is
213 // kept track of here. This depends on "LoaderPagesSpanned" being correct when
214 // coming from the loader.
216 // This number is later aligned up to a PDE boundary.
218 ULONG MmBootImageSize
;
221 // These three variables keep track of the core separation of address space that
222 // exists between kernel mode and user mode.
224 ULONG MmUserProbeAddress
;
225 PVOID MmHighestUserAddress
;
226 PVOID MmSystemRangeStart
;
230 PVOID MmSystemCacheStart
;
231 PVOID MmSystemCacheEnd
;
232 MMSUPPORT MmSystemCacheWs
;
235 // This is where hyperspace ends (followed by the system cache working set)
237 PVOID MmHyperSpaceEnd
;
240 // Page coloring algorithm data
242 ULONG MmSecondaryColors
;
243 ULONG MmSecondaryColorMask
;
246 // Actual (registry-configurable) size of a GUI thread's stack
248 ULONG MmLargeStackSize
;
250 /* PRIVATE FUNCTIONS **********************************************************/
253 // In Bavaria, this is probably a hate crime
257 MiSyncARM3WithROS(IN PVOID AddressStart
,
261 // Puerile piece of junk-grade carbonized horseshit puss sold to the lowest bidder
263 ULONG Pde
= ADDR_TO_PDE_OFFSET(AddressStart
);
264 while (Pde
<= ADDR_TO_PDE_OFFSET(AddressEnd
))
267 // This both odious and heinous
269 extern ULONG MmGlobalKernelPageDirectory
[1024];
270 MmGlobalKernelPageDirectory
[Pde
] = ((PULONG
)PDE_BASE
)[Pde
];
277 MxGetNextPage(IN PFN_NUMBER PageCount
)
282 // Make sure we have enough pages
284 if (PageCount
> MxFreeDescriptor
->PageCount
)
289 KeBugCheckEx(INSTALL_MORE_MEMORY
,
290 MmNumberOfPhysicalPages
,
291 MxFreeDescriptor
->PageCount
,
292 MxOldFreeDescriptor
.PageCount
,
297 // Use our lowest usable free pages
299 Pfn
= MxFreeDescriptor
->BasePage
;
300 MxFreeDescriptor
->BasePage
+= PageCount
;
301 MxFreeDescriptor
->PageCount
-= PageCount
;
307 MiPagesInLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
308 IN PBOOLEAN IncludeType
)
310 PLIST_ENTRY NextEntry
;
311 PFN_NUMBER PageCount
= 0;
312 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
315 // Now loop through the descriptors
317 NextEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
318 while (NextEntry
!= &LoaderBlock
->MemoryDescriptorListHead
)
321 // Grab each one, and check if it's one we should include
323 MdBlock
= CONTAINING_RECORD(NextEntry
,
324 MEMORY_ALLOCATION_DESCRIPTOR
,
326 if ((MdBlock
->MemoryType
< LoaderMaximum
) &&
327 (IncludeType
[MdBlock
->MemoryType
]))
330 // Add this to our running total
332 PageCount
+= MdBlock
->PageCount
;
336 // Try the next descriptor
338 NextEntry
= MdBlock
->ListEntry
.Flink
;
347 PPHYSICAL_MEMORY_DESCRIPTOR
349 MmInitializeMemoryLimits(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
350 IN PBOOLEAN IncludeType
)
352 PLIST_ENTRY NextEntry
;
353 ULONG Run
= 0, InitialRuns
= 0;
354 PFN_NUMBER NextPage
= -1, PageCount
= 0;
355 PPHYSICAL_MEMORY_DESCRIPTOR Buffer
, NewBuffer
;
356 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
359 // Scan the memory descriptors
361 NextEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
362 while (NextEntry
!= &LoaderBlock
->MemoryDescriptorListHead
)
365 // For each one, increase the memory allocation estimate
368 NextEntry
= NextEntry
->Flink
;
372 // Allocate the maximum we'll ever need
374 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
375 sizeof(PHYSICAL_MEMORY_DESCRIPTOR
) +
376 sizeof(PHYSICAL_MEMORY_RUN
) *
379 if (!Buffer
) return NULL
;
382 // For now that's how many runs we have
384 Buffer
->NumberOfRuns
= InitialRuns
;
387 // Now loop through the descriptors again
389 NextEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
390 while (NextEntry
!= &LoaderBlock
->MemoryDescriptorListHead
)
393 // Grab each one, and check if it's one we should include
395 MdBlock
= CONTAINING_RECORD(NextEntry
,
396 MEMORY_ALLOCATION_DESCRIPTOR
,
398 if ((MdBlock
->MemoryType
< LoaderMaximum
) &&
399 (IncludeType
[MdBlock
->MemoryType
]))
402 // Add this to our running total
404 PageCount
+= MdBlock
->PageCount
;
407 // Check if the next page is described by the next descriptor
409 if (MdBlock
->BasePage
== NextPage
)
412 // Combine it into the same physical run
414 ASSERT(MdBlock
->PageCount
!= 0);
415 Buffer
->Run
[Run
- 1].PageCount
+= MdBlock
->PageCount
;
416 NextPage
+= MdBlock
->PageCount
;
421 // Otherwise just duplicate the descriptor's contents
423 Buffer
->Run
[Run
].BasePage
= MdBlock
->BasePage
;
424 Buffer
->Run
[Run
].PageCount
= MdBlock
->PageCount
;
425 NextPage
= Buffer
->Run
[Run
].BasePage
+ Buffer
->Run
[Run
].PageCount
;
428 // And in this case, increase the number of runs
435 // Try the next descriptor
437 NextEntry
= MdBlock
->ListEntry
.Flink
;
441 // We should not have been able to go past our initial estimate
443 ASSERT(Run
<= Buffer
->NumberOfRuns
);
446 // Our guess was probably exaggerated...
448 if (InitialRuns
> Run
)
451 // Allocate a more accurately sized buffer
453 NewBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
454 sizeof(PHYSICAL_MEMORY_DESCRIPTOR
) +
455 sizeof(PHYSICAL_MEMORY_RUN
) *
461 // Copy the old buffer into the new, then free it
463 RtlCopyMemory(NewBuffer
->Run
,
465 sizeof(PHYSICAL_MEMORY_RUN
) * Run
);
469 // Now use the new buffer
476 // Write the final numbers, and return it
478 Buffer
->NumberOfRuns
= Run
;
479 Buffer
->NumberOfPages
= PageCount
;
485 MiBuildPagedPool(VOID
)
487 PMMPTE PointerPte
, PointerPde
;
488 MMPTE TempPte
= HyperTemplatePte
;
489 PFN_NUMBER PageFrameIndex
;
491 ULONG Size
, BitMapSize
;
494 // Get the page frame number for the system page directory
496 PointerPte
= MiAddressToPte(PDE_BASE
);
497 MmSystemPageDirectory
= PFN_FROM_PTE(PointerPte
);
500 // Allocate a system PTE which will hold a copy of the page directory
502 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
504 MmSystemPagePtes
= MiPteToAddress(PointerPte
);
507 // Make this system PTE point to the system page directory.
508 // It is now essentially double-mapped. This will be used later for lazy
509 // evaluation of PDEs accross process switches, similarly to how the Global
510 // page directory array in the old ReactOS Mm is used (but in a less hacky
513 TempPte
= HyperTemplatePte
;
514 TempPte
.u
.Hard
.PageFrameNumber
= MmSystemPageDirectory
;
515 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
516 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
517 *PointerPte
= TempPte
;
520 // Let's get back to paged pool work: size it up.
521 // By default, it should be twice as big as nonpaged pool.
523 MmSizeOfPagedPoolInBytes
= 2 * MmMaximumNonPagedPoolInBytes
;
524 if (MmSizeOfPagedPoolInBytes
> ((ULONG_PTR
)MmNonPagedSystemStart
-
525 (ULONG_PTR
)MmPagedPoolStart
))
528 // On the other hand, we have limited VA space, so make sure that the VA
529 // for paged pool doesn't overflow into nonpaged pool VA. Otherwise, set
530 // whatever maximum is possible.
532 MmSizeOfPagedPoolInBytes
= (ULONG_PTR
)MmNonPagedSystemStart
-
533 (ULONG_PTR
)MmPagedPoolStart
;
537 // Get the size in pages and make sure paged pool is at least 32MB.
539 Size
= MmSizeOfPagedPoolInBytes
;
540 if (Size
< MI_MIN_INIT_PAGED_POOLSIZE
) Size
= MI_MIN_INIT_PAGED_POOLSIZE
;
541 Size
= BYTES_TO_PAGES(Size
);
544 // Now check how many PTEs will be required for these many pages.
546 Size
= (Size
+ (1024 - 1)) / 1024;
549 // Recompute the page-aligned size of the paged pool, in bytes and pages.
551 MmSizeOfPagedPoolInBytes
= Size
* PAGE_SIZE
* 1024;
552 MmSizeOfPagedPoolInPages
= MmSizeOfPagedPoolInBytes
>> PAGE_SHIFT
;
555 // Let's be really sure this doesn't overflow into nonpaged system VA
557 ASSERT((MmSizeOfPagedPoolInBytes
+ (ULONG_PTR
)MmPagedPoolStart
) <=
558 (ULONG_PTR
)MmNonPagedSystemStart
);
561 // This is where paged pool ends
563 MmPagedPoolEnd
= (PVOID
)(((ULONG_PTR
)MmPagedPoolStart
+
564 MmSizeOfPagedPoolInBytes
) - 1);
567 // So now get the PDE for paged pool and zero it out
569 PointerPde
= MiAddressToPde(MmPagedPoolStart
);
570 RtlZeroMemory(PointerPde
,
571 (1 + MiAddressToPde(MmPagedPoolEnd
) - PointerPde
) * sizeof(MMPTE
));
574 // Next, get the first and last PTE
576 PointerPte
= MiAddressToPte(MmPagedPoolStart
);
577 MmPagedPoolInfo
.FirstPteForPagedPool
= PointerPte
;
578 MmPagedPoolInfo
.LastPteForPagedPool
= MiAddressToPte(MmPagedPoolEnd
);
581 // Lock the PFN database
583 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
586 // Allocate a page and map the first paged pool PDE
588 PageFrameIndex
= MmAllocPage(MC_NPPOOL
, 0);
589 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
590 ASSERT(PointerPde
->u
.Hard
.Valid
== 0);
591 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
592 *PointerPde
= TempPte
;
595 // Release the PFN database lock
597 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
600 // We only have one PDE mapped for now... at fault time, additional PDEs
601 // will be allocated to handle paged pool growth. This is where they'll have
604 MmPagedPoolInfo
.NextPdeForPagedPoolExpansion
= PointerPde
+ 1;
607 // We keep track of each page via a bit, so check how big the bitmap will
608 // have to be (make sure to align our page count such that it fits nicely
609 // into a 4-byte aligned bitmap.
611 // We'll also allocate the bitmap header itself part of the same buffer.
614 ASSERT(Size
== MmSizeOfPagedPoolInPages
);
616 Size
= sizeof(RTL_BITMAP
) + (((Size
+ 31) / 32) * sizeof(ULONG
));
619 // Allocate the allocation bitmap, which tells us which regions have not yet
620 // been mapped into memory
622 MmPagedPoolInfo
.PagedPoolAllocationMap
= ExAllocatePoolWithTag(NonPagedPool
,
625 ASSERT(MmPagedPoolInfo
.PagedPoolAllocationMap
);
628 // Initialize it such that at first, only the first page's worth of PTEs is
629 // marked as allocated (incidentially, the first PDE we allocated earlier).
631 RtlInitializeBitMap(MmPagedPoolInfo
.PagedPoolAllocationMap
,
632 (PULONG
)(MmPagedPoolInfo
.PagedPoolAllocationMap
+ 1),
634 RtlSetAllBits(MmPagedPoolInfo
.PagedPoolAllocationMap
);
635 RtlClearBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 0, 1024);
638 // We have a second bitmap, which keeps track of where allocations end.
639 // Given the allocation bitmap and a base address, we can therefore figure
640 // out which page is the last page of that allocation, and thus how big the
641 // entire allocation is.
643 MmPagedPoolInfo
.EndOfPagedPoolBitmap
= ExAllocatePoolWithTag(NonPagedPool
,
646 ASSERT(MmPagedPoolInfo
.EndOfPagedPoolBitmap
);
647 RtlInitializeBitMap(MmPagedPoolInfo
.EndOfPagedPoolBitmap
,
648 (PULONG
)(MmPagedPoolInfo
.EndOfPagedPoolBitmap
+ 1),
652 // Since no allocations have been made yet, there are no bits set as the end
654 RtlClearAllBits(MmPagedPoolInfo
.EndOfPagedPoolBitmap
);
657 // Initialize paged pool.
659 InitializePool(PagedPool
, 0);
662 // Initialize the paged pool mutex
664 KeInitializeGuardedMutex(&MmPagedPoolMutex
);
669 MmArmInitSystem(IN ULONG Phase
,
670 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
672 PLIST_ENTRY NextEntry
;
673 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
675 PFN_NUMBER PageFrameIndex
, PoolPages
;
676 PMMPTE StartPde
, EndPde
, PointerPte
, LastPte
;
677 MMPTE TempPde
= HyperTemplatePte
, TempPte
= HyperTemplatePte
;
678 PVOID NonPagedPoolExpansionVa
;
679 ULONG OldCount
, i
, L2Associativity
;
680 BOOLEAN IncludeType
[LoaderMaximum
];
682 PPHYSICAL_MEMORY_RUN Run
;
683 PFN_NUMBER FreePage
, FreePageCount
, PagesLeft
, BasePage
, PageCount
;
686 // Instantiate memory that we don't consider RAM/usable
687 // We use the same exclusions that Windows does, in order to try to be
688 // compatible with WinLDR-style booting
690 for (i
= 0; i
< LoaderMaximum
; i
++) IncludeType
[i
] = TRUE
;
691 IncludeType
[LoaderBad
] = FALSE
;
692 IncludeType
[LoaderFirmwarePermanent
] = FALSE
;
693 IncludeType
[LoaderSpecialMemory
] = FALSE
;
694 IncludeType
[LoaderBBTMemory
] = FALSE
;
698 // Define the basic user vs. kernel address space separation
700 MmSystemRangeStart
= (PVOID
)KSEG0_BASE
;
701 MmUserProbeAddress
= (ULONG_PTR
)MmSystemRangeStart
- 0x10000;
702 MmHighestUserAddress
= (PVOID
)(MmUserProbeAddress
- 1);
705 // Get the size of the boot loader's image allocations and then round
706 // that region up to a PDE size, so that any PDEs we might create for
707 // whatever follows are separate from the PDEs that boot loader might've
708 // already created (and later, we can blow all that away if we want to).
710 MmBootImageSize
= KeLoaderBlock
->Extension
->LoaderPagesSpanned
;
711 MmBootImageSize
*= PAGE_SIZE
;
712 MmBootImageSize
= (MmBootImageSize
+ (4 * 1024 * 1024) - 1) & ~((4 * 1024 * 1024) - 1);
713 ASSERT((MmBootImageSize
% (4 * 1024 * 1024)) == 0);
716 // Set the size of session view, pool, and image
718 MmSessionSize
= MI_SESSION_SIZE
;
719 MmSessionViewSize
= MI_SESSION_VIEW_SIZE
;
720 MmSessionPoolSize
= MI_SESSION_POOL_SIZE
;
721 MmSessionImageSize
= MI_SESSION_IMAGE_SIZE
;
724 // Set the size of system view
726 MmSystemViewSize
= MI_SYSTEM_VIEW_SIZE
;
729 // This is where it all ends
731 MiSessionImageEnd
= (PVOID
)PTE_BASE
;
734 // This is where we will load Win32k.sys and the video driver
736 MiSessionImageStart
= (PVOID
)((ULONG_PTR
)MiSessionImageEnd
-
740 // So the view starts right below the session working set (itself below
743 MiSessionViewStart
= (PVOID
)((ULONG_PTR
)MiSessionImageEnd
-
745 MI_SESSION_WORKING_SET_SIZE
-
749 // Session pool follows
751 MiSessionPoolEnd
= MiSessionViewStart
;
752 MiSessionPoolStart
= (PVOID
)((ULONG_PTR
)MiSessionPoolEnd
-
756 // And it all begins here
758 MmSessionBase
= MiSessionPoolStart
;
761 // Sanity check that our math is correct
763 ASSERT((ULONG_PTR
)MmSessionBase
+ MmSessionSize
== PTE_BASE
);
766 // Session space ends wherever image session space ends
768 MiSessionSpaceEnd
= MiSessionImageEnd
;
771 // System view space ends at session space, so now that we know where
772 // this is, we can compute the base address of system view space itself.
774 MiSystemViewStart
= (PVOID
)((ULONG_PTR
)MmSessionBase
-
778 // Count physical pages on the system
780 PageCount
= MiPagesInLoaderBlock(LoaderBlock
, IncludeType
);
783 // Check if this is a machine with less than 19MB of RAM
785 if (PageCount
< MI_MIN_PAGES_FOR_SYSPTE_TUNING
)
788 // Use the very minimum of system PTEs
790 MmNumberOfSystemPtes
= 7000;
795 // Use the default, but check if we have more than 32MB of RAM
797 MmNumberOfSystemPtes
= 11000;
798 if (PageCount
> MI_MIN_PAGES_FOR_SYSPTE_BOOST
)
801 // Double the amount of system PTEs
803 MmNumberOfSystemPtes
<<= 1;
807 DPRINT("System PTE count has been tuned to %d (%d bytes)\n",
808 MmNumberOfSystemPtes
, MmNumberOfSystemPtes
* PAGE_SIZE
);
812 // Start of Architecture Specific Initialization Code
817 // The large kernel stack is cutomizable, but use default value for now
819 MmLargeStackSize
= KERNEL_LARGE_STACK_SIZE
;
824 HyperTemplatePte
.u
.Long
= 0;
825 HyperTemplatePte
.u
.Hard
.Valid
= 1;
826 HyperTemplatePte
.u
.Hard
.Write
= 1;
827 HyperTemplatePte
.u
.Hard
.Dirty
= 1;
828 HyperTemplatePte
.u
.Hard
.Accessed
= 1;
829 if (Ke386GlobalPagesEnabled
) HyperTemplatePte
.u
.Hard
.Global
= 1;
832 // Set CR3 for the system process
834 PointerPte
= MiAddressToPde(PTE_BASE
);
835 PageFrameIndex
= PFN_FROM_PTE(PointerPte
) << PAGE_SHIFT
;
836 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0] = PageFrameIndex
;
839 // Blow away user-mode
841 StartPde
= MiAddressToPde(0);
842 EndPde
= MiAddressToPde(KSEG0_BASE
);
843 RtlZeroMemory(StartPde
, (EndPde
- StartPde
) * sizeof(MMPTE
));
846 // Loop the memory descriptors
848 NextEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
849 while (NextEntry
!= &LoaderBlock
->MemoryDescriptorListHead
)
852 // Get the memory block
854 MdBlock
= CONTAINING_RECORD(NextEntry
,
855 MEMORY_ALLOCATION_DESCRIPTOR
,
859 // Skip invisible memory
861 if ((MdBlock
->MemoryType
!= LoaderFirmwarePermanent
) &&
862 (MdBlock
->MemoryType
!= LoaderSpecialMemory
) &&
863 (MdBlock
->MemoryType
!= LoaderHALCachedMemory
) &&
864 (MdBlock
->MemoryType
!= LoaderBBTMemory
))
867 // Check if BURNMEM was used
869 if (MdBlock
->MemoryType
!= LoaderBad
)
872 // Count this in the total of pages
874 MmNumberOfPhysicalPages
+= MdBlock
->PageCount
;
878 // Check if this is the new lowest page
880 if (MdBlock
->BasePage
< MmLowestPhysicalPage
)
883 // Update the lowest page
885 MmLowestPhysicalPage
= MdBlock
->BasePage
;
889 // Check if this is the new highest page
891 PageFrameIndex
= MdBlock
->BasePage
+ MdBlock
->PageCount
;
892 if (PageFrameIndex
> MmHighestPhysicalPage
)
895 // Update the highest page
897 MmHighestPhysicalPage
= PageFrameIndex
- 1;
901 // Check if this is free memory
903 if ((MdBlock
->MemoryType
== LoaderFree
) ||
904 (MdBlock
->MemoryType
== LoaderLoadedProgram
) ||
905 (MdBlock
->MemoryType
== LoaderFirmwareTemporary
) ||
906 (MdBlock
->MemoryType
== LoaderOsloaderStack
))
909 // Check if this is the largest memory descriptor
911 if (MdBlock
->PageCount
> FreePages
)
916 MxFreeDescriptor
= MdBlock
;
922 FreePages
+= MdBlock
->PageCount
;
929 NextEntry
= MdBlock
->ListEntry
.Flink
;
933 // Save original values of the free descriptor, since it'll be
934 // altered by early allocations
936 MxOldFreeDescriptor
= *MxFreeDescriptor
;
939 // Check if this is a machine with less than 256MB of RAM, and no overide
941 if ((MmNumberOfPhysicalPages
<= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING
) &&
942 !(MmSizeOfNonPagedPoolInBytes
))
945 // Force the non paged pool to be 2MB so we can reduce RAM usage
947 MmSizeOfNonPagedPoolInBytes
= 2 * 1024 * 1024;
951 // Hyperspace ends here
953 MmHyperSpaceEnd
= (PVOID
)((ULONG_PTR
)MmSystemCacheWorkingSetList
- 1);
956 // Check if the user gave a ridicuously large nonpaged pool RAM size
958 if ((MmSizeOfNonPagedPoolInBytes
>> PAGE_SHIFT
) >
959 (MmNumberOfPhysicalPages
* 7 / 8))
962 // More than 7/8ths of RAM was dedicated to nonpaged pool, ignore!
964 MmSizeOfNonPagedPoolInBytes
= 0;
968 // Check if no registry setting was set, or if the setting was too low
970 if (MmSizeOfNonPagedPoolInBytes
< MmMinimumNonPagedPoolSize
)
973 // Start with the minimum (256 KB) and add 32 KB for each MB above 4
975 MmSizeOfNonPagedPoolInBytes
= MmMinimumNonPagedPoolSize
;
976 MmSizeOfNonPagedPoolInBytes
+= (MmNumberOfPhysicalPages
- 1024) /
977 256 * MmMinAdditionNonPagedPoolPerMb
;
981 // Check if the registy setting or our dynamic calculation was too high
983 if (MmSizeOfNonPagedPoolInBytes
> MI_MAX_INIT_NONPAGED_POOL_SIZE
)
986 // Set it to the maximum
988 MmSizeOfNonPagedPoolInBytes
= MI_MAX_INIT_NONPAGED_POOL_SIZE
;
992 // Check if a percentage cap was set through the registry
994 if (MmMaximumNonPagedPoolPercent
)
997 // Don't feel like supporting this right now
1003 // Page-align the nonpaged pool size
1005 MmSizeOfNonPagedPoolInBytes
&= ~(PAGE_SIZE
- 1);
1008 // Now, check if there was a registry size for the maximum size
1010 if (!MmMaximumNonPagedPoolInBytes
)
1013 // Start with the default (1MB)
1015 MmMaximumNonPagedPoolInBytes
= MmDefaultMaximumNonPagedPool
;
1018 // Add space for PFN database
1020 MmMaximumNonPagedPoolInBytes
+= (ULONG
)
1021 PAGE_ALIGN((MmHighestPhysicalPage
+ 1) * sizeof(MMPFN
));
1024 // Add 400KB for each MB above 4
1026 MmMaximumNonPagedPoolInBytes
+= (FreePages
- 1024) / 256 *
1027 MmMaxAdditionNonPagedPoolPerMb
;
1031 // Make sure there's at least 16 pages + the PFN available for expansion
1033 PoolPages
= MmSizeOfNonPagedPoolInBytes
+ (PAGE_SIZE
* 16) +
1034 ((ULONG
)PAGE_ALIGN(MmHighestPhysicalPage
+ 1) *
1036 if (MmMaximumNonPagedPoolInBytes
< PoolPages
)
1039 // Set it to the minimum value for the maximum (yuck!)
1041 MmMaximumNonPagedPoolInBytes
= PoolPages
;
1045 // Systems with 2GB of kernel address space get double the size
1047 PoolPages
= MI_MAX_NONPAGED_POOL_SIZE
* 2;
1050 // Don't let the maximum go too high
1052 if (MmMaximumNonPagedPoolInBytes
> PoolPages
)
1055 // Set it to the upper limit
1057 MmMaximumNonPagedPoolInBytes
= PoolPages
;
1061 // Check if this is a system with > 128MB of non paged pool
1063 if (MmMaximumNonPagedPoolInBytes
> MI_MAX_NONPAGED_POOL_SIZE
)
1066 // FIXME: Unsure about additional checks needed
1068 DPRINT1("Untested path\n");
1072 // Get L2 cache information
1074 L2Associativity
= KeGetPcr()->SecondLevelCacheAssociativity
;
1075 MmSecondaryColors
= KeGetPcr()->SecondLevelCacheSize
;
1076 if (L2Associativity
) MmSecondaryColors
/= L2Associativity
;
1079 // Compute final color mask and count
1081 MmSecondaryColors
>>= PAGE_SHIFT
;
1082 if (!MmSecondaryColors
) MmSecondaryColors
= 1;
1083 MmSecondaryColorMask
= MmSecondaryColors
- 1;
1088 KeGetCurrentPrcb()->SecondaryColorMask
= MmSecondaryColorMask
;
1091 // Calculate the number of bytes for the PFN database
1092 // and then convert to pages
1094 MxPfnAllocation
= (MmHighestPhysicalPage
+ 1) * sizeof(MMPFN
);
1095 MxPfnAllocation
>>= PAGE_SHIFT
;
1098 // We have to add one to the count here, because in the process of
1099 // shifting down to the page size, we actually ended up getting the
1100 // lower aligned size (so say, 0x5FFFF bytes is now 0x5F pages).
1101 // Later on, we'll shift this number back into bytes, which would cause
1102 // us to end up with only 0x5F000 bytes -- when we actually want to have
1108 // Now calculate the nonpaged pool expansion VA region
1110 MmNonPagedPoolStart
= (PVOID
)((ULONG_PTR
)MmNonPagedPoolEnd
-
1111 MmMaximumNonPagedPoolInBytes
+
1112 MmSizeOfNonPagedPoolInBytes
);
1113 MmNonPagedPoolStart
= (PVOID
)PAGE_ALIGN(MmNonPagedPoolStart
);
1114 NonPagedPoolExpansionVa
= MmNonPagedPoolStart
;
1115 DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
1116 MmSizeOfNonPagedPoolInBytes
, MmMaximumNonPagedPoolInBytes
);
1119 // Now calculate the nonpaged system VA region, which includes the
1120 // nonpaged pool expansion (above) and the system PTEs. Note that it is
1121 // then aligned to a PDE boundary (4MB).
1123 MmNonPagedSystemStart
= (PVOID
)((ULONG_PTR
)MmNonPagedPoolStart
-
1124 (MmNumberOfSystemPtes
+ 1) * PAGE_SIZE
);
1125 MmNonPagedSystemStart
= (PVOID
)((ULONG_PTR
)MmNonPagedSystemStart
&
1126 ~((4 * 1024 * 1024) - 1));
1129 // Don't let it go below the minimum
1131 if (MmNonPagedSystemStart
< (PVOID
)0xEB000000)
1134 // This is a hard-coded limit in the Windows NT address space
1136 MmNonPagedSystemStart
= (PVOID
)0xEB000000;
1139 // Reduce the amount of system PTEs to reach this point
1141 MmNumberOfSystemPtes
= ((ULONG_PTR
)MmNonPagedPoolStart
-
1142 (ULONG_PTR
)MmNonPagedSystemStart
) >>
1144 MmNumberOfSystemPtes
--;
1145 ASSERT(MmNumberOfSystemPtes
> 1000);
1149 // Check if we are in a situation where the size of the paged pool
1150 // is so large that it overflows into nonpaged pool
1152 if (MmSizeOfPagedPoolInBytes
>
1153 ((ULONG_PTR
)MmNonPagedSystemStart
- (ULONG_PTR
)MmPagedPoolStart
))
1156 // We need some recalculations here
1158 DPRINT1("Paged pool is too big!\n");
1162 // Normally, the PFN database should start after the loader images.
1163 // This is already the case in ReactOS, but for now we want to co-exist
1164 // with the old memory manager, so we'll create a "Shadow PFN Database"
1165 // instead, and arbitrarly start it at 0xB0000000.
1167 MmPfnDatabase
= (PVOID
)0xB0000000;
1168 ASSERT(((ULONG_PTR
)MmPfnDatabase
& ((4 * 1024 * 1024) - 1)) == 0);
1171 // Non paged pool comes after the PFN database
1173 MmNonPagedPoolStart
= (PVOID
)((ULONG_PTR
)MmPfnDatabase
+
1174 (MxPfnAllocation
<< PAGE_SHIFT
));
1177 // Now we actually need to get these many physical pages. Nonpaged pool
1178 // is actually also physically contiguous (but not the expansion)
1180 PageFrameIndex
= MxGetNextPage(MxPfnAllocation
+
1181 (MmSizeOfNonPagedPoolInBytes
>> PAGE_SHIFT
));
1182 ASSERT(PageFrameIndex
!= 0);
1183 DPRINT("PFN DB PA PFN begins at: %lx\n", PageFrameIndex
);
1184 DPRINT("NP PA PFN begins at: %lx\n", PageFrameIndex
+ MxPfnAllocation
);
1187 // Now we need some pages to create the page tables for the NP system VA
1188 // which includes system PTEs and expansion NP
1190 StartPde
= MiAddressToPde(MmNonPagedSystemStart
);
1191 EndPde
= MiAddressToPde((PVOID
)((ULONG_PTR
)MmNonPagedPoolEnd
- 1));
1192 while (StartPde
<= EndPde
)
1197 ASSERT(StartPde
->u
.Hard
.Valid
== 0);
1202 TempPde
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
1203 ASSERT(TempPde
.u
.Hard
.Valid
== 1);
1204 *StartPde
= TempPde
;
1207 // Zero out the page table
1209 PointerPte
= MiPteToAddress(StartPde
);
1210 RtlZeroMemory(PointerPte
, PAGE_SIZE
);
1219 // Now we need pages for the page tables which will map initial NP
1221 StartPde
= MiAddressToPde(MmPfnDatabase
);
1222 EndPde
= MiAddressToPde((PVOID
)((ULONG_PTR
)MmNonPagedPoolStart
+
1223 MmSizeOfNonPagedPoolInBytes
- 1));
1224 while (StartPde
<= EndPde
)
1229 ASSERT(StartPde
->u
.Hard
.Valid
== 0);
1234 TempPde
.u
.Hard
.PageFrameNumber
= MxGetNextPage(1);
1235 ASSERT(TempPde
.u
.Hard
.Valid
== 1);
1236 *StartPde
= TempPde
;
1239 // Zero out the page table
1241 PointerPte
= MiPteToAddress(StartPde
);
1242 RtlZeroMemory(PointerPte
, PAGE_SIZE
);
1251 // Now remember where the expansion starts
1253 MmNonPagedPoolExpansionStart
= NonPagedPoolExpansionVa
;
1256 // Last step is to actually map the nonpaged pool
1258 PointerPte
= MiAddressToPte(MmNonPagedPoolStart
);
1259 LastPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)MmNonPagedPoolStart
+
1260 MmSizeOfNonPagedPoolInBytes
- 1));
1261 while (PointerPte
<= LastPte
)
1264 // Use one of our contigous pages
1266 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
++;
1267 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
1268 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
1269 *PointerPte
++ = TempPte
;
1273 // Sanity check: make sure we have properly defined the system PTE space
1275 ASSERT(MiAddressToPte(MmNonPagedSystemStart
) <
1276 MiAddressToPte(MmNonPagedPoolExpansionStart
));
1279 // Now go ahead and initialize the ARM³ nonpaged pool
1281 MiInitializeArmPool();
1284 // Get current page data, since we won't be using MxGetNextPage as it
1285 // would corrupt our state
1287 FreePage
= MxFreeDescriptor
->BasePage
;
1288 FreePageCount
= MxFreeDescriptor
->PageCount
;
1292 // Loop the memory descriptors
1294 NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
1295 while (NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
)
1298 // Get the descriptor
1300 MdBlock
= CONTAINING_RECORD(NextEntry
,
1301 MEMORY_ALLOCATION_DESCRIPTOR
,
1303 if ((MdBlock
->MemoryType
== LoaderFirmwarePermanent
) ||
1304 (MdBlock
->MemoryType
== LoaderBBTMemory
) ||
1305 (MdBlock
->MemoryType
== LoaderSpecialMemory
))
1308 // These pages are not part of the PFN database
1310 NextEntry
= MdBlock
->ListEntry
.Flink
;
1315 // Next, check if this is our special free descriptor we've found
1317 if (MdBlock
== MxFreeDescriptor
)
1320 // Use the real numbers instead
1322 BasePage
= MxOldFreeDescriptor
.BasePage
;
1323 PageCount
= MxOldFreeDescriptor
.PageCount
;
1328 // Use the descriptor's numbers
1330 BasePage
= MdBlock
->BasePage
;
1331 PageCount
= MdBlock
->PageCount
;
1335 // Get the PTEs for this range
1337 PointerPte
= MiAddressToPte(&MmPfnDatabase
[BasePage
]);
1338 LastPte
= MiAddressToPte(((ULONG_PTR
)&MmPfnDatabase
[BasePage
+ PageCount
]) - 1);
1339 DPRINT("MD Type: %lx Base: %lx Count: %lx\n", MdBlock
->MemoryType
, BasePage
, PageCount
);
1344 while (PointerPte
<= LastPte
)
1347 // We'll only touch PTEs that aren't already valid
1349 if (PointerPte
->u
.Hard
.Valid
== 0)
1352 // Use the next free page
1354 TempPte
.u
.Hard
.PageFrameNumber
= FreePage
;
1355 ASSERT(FreePageCount
!= 0);
1358 // Consume free pages
1367 KeBugCheckEx(INSTALL_MORE_MEMORY
,
1368 MmNumberOfPhysicalPages
,
1370 MxOldFreeDescriptor
.PageCount
,
1375 // Write out this PTE
1378 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
1379 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
1380 *PointerPte
= TempPte
;
1385 RtlZeroMemory(MiPteToAddress(PointerPte
), PAGE_SIZE
);
1395 // Do the next address range
1397 NextEntry
= MdBlock
->ListEntry
.Flink
;
1401 // Now update the free descriptors to consume the pages we used up during
1402 // the PFN allocation loop
1404 MxFreeDescriptor
->BasePage
= FreePage
;
1405 MxFreeDescriptor
->PageCount
= FreePageCount
;
1407 else if (Phase
== 1) // IN BETWEEN, THE PFN DATABASE IS NOW CREATED
1410 // Reset the descriptor back so we can create the correct memory blocks
1412 *MxFreeDescriptor
= MxOldFreeDescriptor
;
1415 // Initialize the nonpaged pool
1417 InitializePool(NonPagedPool
, 0);
1420 // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
1422 PointerPte
= MiAddressToPte(MmNonPagedSystemStart
);
1423 OldCount
= MmNumberOfSystemPtes
;
1424 MmNumberOfSystemPtes
= MiAddressToPte(MmNonPagedPoolExpansionStart
) -
1426 MmNumberOfSystemPtes
--;
1427 DPRINT("Final System PTE count: %d (%d bytes)\n",
1428 MmNumberOfSystemPtes
, MmNumberOfSystemPtes
* PAGE_SIZE
);
1431 // Create the system PTE space
1433 MiInitializeSystemPtes(PointerPte
, MmNumberOfSystemPtes
, SystemPteSpace
);
1436 // Get the PDE For hyperspace
1438 StartPde
= MiAddressToPde(HYPER_SPACE
);
1441 // Allocate a page for it and create it
1443 PageFrameIndex
= MmAllocPage(MC_SYSTEM
, 0);
1444 TempPde
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
1445 TempPde
.u
.Hard
.Global
= FALSE
; // Hyperspace is local!
1446 ASSERT(StartPde
->u
.Hard
.Valid
== 0);
1447 ASSERT(TempPde
.u
.Hard
.Valid
== 1);
1448 *StartPde
= TempPde
;
1451 // Zero out the page table now
1453 PointerPte
= MiAddressToPte(HYPER_SPACE
);
1454 RtlZeroMemory(PointerPte
, PAGE_SIZE
);
1457 // Setup the mapping PTEs
1459 MmFirstReservedMappingPte
= MiAddressToPte(MI_MAPPING_RANGE_START
);
1460 MmLastReservedMappingPte
= MiAddressToPte(MI_MAPPING_RANGE_END
);
1461 MmFirstReservedMappingPte
->u
.Hard
.PageFrameNumber
= MI_HYPERSPACE_PTES
;
1464 // Reserve system PTEs for zeroing PTEs and clear them
1466 MiFirstReservedZeroingPte
= MiReserveSystemPtes(MI_ZERO_PTES
,
1468 RtlZeroMemory(MiFirstReservedZeroingPte
, MI_ZERO_PTES
* sizeof(MMPTE
));
1471 // Set the counter to maximum to boot with
1473 MiFirstReservedZeroingPte
->u
.Hard
.PageFrameNumber
= MI_ZERO_PTES
- 1;
1476 // Sync us up with ReactOS Mm
1478 MiSyncARM3WithROS(MmNonPagedSystemStart
, (PVOID
)((ULONG_PTR
)MmNonPagedPoolEnd
- 1));
1479 MiSyncARM3WithROS(MmPfnDatabase
, (PVOID
)((ULONG_PTR
)MmNonPagedPoolStart
+ MmSizeOfNonPagedPoolInBytes
- 1));
1480 MiSyncARM3WithROS((PVOID
)HYPER_SPACE
, (PVOID
)(HYPER_SPACE
+ PAGE_SIZE
- 1));
1483 // Build the physical memory block
1485 MmPhysicalMemoryBlock
= MmInitializeMemoryLimits(LoaderBlock
,
1489 // Allocate enough buffer for the PFN bitmap
1490 // Align it up to a 32-bit boundary
1492 Bitmap
= ExAllocatePoolWithTag(NonPagedPool
,
1493 (((MmHighestPhysicalPage
+ 1) + 31) / 32) * 4,
1500 KeBugCheckEx(INSTALL_MORE_MEMORY
,
1501 MmNumberOfPhysicalPages
,
1502 MmLowestPhysicalPage
,
1503 MmHighestPhysicalPage
,
1508 // Initialize it and clear all the bits to begin with
1510 RtlInitializeBitMap(&MiPfnBitMap
,
1512 MmHighestPhysicalPage
+ 1);
1513 RtlClearAllBits(&MiPfnBitMap
);
1516 // Loop physical memory runs
1518 for (i
= 0; i
< MmPhysicalMemoryBlock
->NumberOfRuns
; i
++)
1523 Run
= &MmPhysicalMemoryBlock
->Run
[i
];
1524 DPRINT("PHYSICAL RAM [0x%08p to 0x%08p]\n",
1525 Run
->BasePage
<< PAGE_SHIFT
,
1526 (Run
->BasePage
+ Run
->PageCount
) << PAGE_SHIFT
);
1529 // Make sure it has pages inside it
1534 // Set the bits in the PFN bitmap
1536 RtlSetBits(&MiPfnBitMap
, Run
->BasePage
, Run
->PageCount
);
1541 // Size up paged pool and build the shadow system page directory
1547 // Always return success for now
1549 return STATUS_SUCCESS
;