#define NDEBUG
#include <debug.h>
-#line 15 "ARM³::INIT"
+#line 15 "ARM³::INIT:X86"
#define MODULE_INVOLVED_IN_ARM3
#include "../../ARM3/miarm.h"
/* GLOBALS ********************************************************************/
-//
-// These are all registry-configurable, but by default, the memory manager will
-// figure out the most appropriate values.
-//
-ULONG MmMaximumNonPagedPoolPercent;
-ULONG MmSizeOfNonPagedPoolInBytes;
-ULONG MmMaximumNonPagedPoolInBytes;
-
-//
-// These numbers describe the discrete equation components of the nonpaged
-// pool sizing algorithm.
-//
-// They are described on http://support.microsoft.com/default.aspx/kb/126402/ja
-// along with the algorithm that uses them, which is implemented later below.
-//
-ULONG MmMinimumNonPagedPoolSize = 256 * 1024;
-ULONG MmMinAdditionNonPagedPoolPerMb = 32 * 1024;
-ULONG MmDefaultMaximumNonPagedPool = 1024 * 1024;
-ULONG MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
-
-//
-// The memory layout (and especially variable names) of the NT kernel mode
-// components can be a bit hard to twig, especially when it comes to the non
-// paged area.
-//
-// There are really two components to the non-paged pool:
-//
-// - The initial nonpaged pool, sized dynamically up to a maximum.
-// - The expansion nonpaged pool, sized dynamically up to a maximum.
-//
-// The initial nonpaged pool is physically continuous for performance, and
-// immediately follows the PFN database, typically sharing the same PDE. It is
-// a very small resource (32MB on a 1GB system), and capped at 128MB.
-//
-// Right now we call this the "ARM³ Nonpaged Pool" and it begins somewhere after
-// the PFN database (which starts at 0xB0000000).
-//
-// The expansion nonpaged pool, on the other hand, can grow much bigger (400MB
-// for a 1GB system). On ARM³ however, it is currently capped at 128MB.
-//
-// The address where the initial nonpaged pool starts is aptly named
-// MmNonPagedPoolStart, and it describes a range of MmSizeOfNonPagedPoolInBytes
-// bytes.
-//
-// Expansion nonpaged pool starts at an address described by the variable called
-// MmNonPagedPoolExpansionStart, and it goes on for MmMaximumNonPagedPoolInBytes
-// minus MmSizeOfNonPagedPoolInBytes bytes, always reaching MmNonPagedPoolEnd
-// (because of the way it's calculated) at 0xFFBE0000.
-//
-// Initial nonpaged pool is allocated and mapped early-on during boot, but what
-// about the expansion nonpaged pool? It is instead composed of special pages
-// which belong to what are called System PTEs. These PTEs are the matter of a
-// later discussion, but they are also considered part of the "nonpaged" OS, due
-// to the fact that they are never paged out -- once an address is described by
-// a System PTE, it is always valid, until the System PTE is torn down.
-//
-// System PTEs are actually composed of two "spaces", the system space proper,
-// and the nonpaged pool expansion space. The latter, as we've already seen,
-// begins at MmNonPagedPoolExpansionStart. Based on the number of System PTEs
-// that the system will support, the remaining address space below this address
-// is used to hold the system space PTEs. This address, in turn, is held in the
-// variable named MmNonPagedSystemStart, which itself is never allowed to go
-// below 0xEB000000 (thus creating an upper bound on the number of System PTEs).
-//
-// This means that 330MB are reserved for total nonpaged system VA, on top of
-// whatever the initial nonpaged pool allocation is.
-//
-// The following URLs, valid as of April 23rd, 2008, support this evidence:
-//
-// http://www.cs.miami.edu/~burt/journal/NT/memory.html
-// http://www.ditii.com/2007/09/28/windows-memory-management-x86-virtual-address-space/
-//
-PVOID MmNonPagedSystemStart;
-PVOID MmNonPagedPoolStart;
-PVOID MmNonPagedPoolExpansionStart;
-PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
-
-//
-// This is where paged pool starts by default
-//
-PVOID MmPagedPoolStart = MI_PAGED_POOL_START;
-PVOID MmPagedPoolEnd;
-
-//
-// And this is its default size
-//
-ULONG MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
-PFN_NUMBER MmSizeOfPagedPoolInPages = MI_MIN_INIT_PAGED_POOLSIZE / PAGE_SIZE;
-
-//
-// Session space starts at 0xBFFFFFFF and grows downwards
-// By default, it includes an 8MB image area where we map win32k and video card
-// drivers, followed by a 4MB area containing the session's working set. This is
-// then followed by a 20MB mapped view area and finally by the session's paged
-// pool, by default 16MB.
-//
-// On a normal system, this results in session space occupying the region from
-// 0xBD000000 to 0xC0000000
-//
-// See miarm.h for the defines that determine the sizing of this region. On an
-// NT system, some of these can be configured through the registry, but we don't
-// support that yet.
-//
-PVOID MiSessionSpaceEnd; // 0xC0000000
-PVOID MiSessionImageEnd; // 0xC0000000
-PVOID MiSessionImageStart; // 0xBF800000
-PVOID MiSessionViewStart; // 0xBE000000
-PVOID MiSessionPoolEnd; // 0xBE000000
-PVOID MiSessionPoolStart; // 0xBD000000
-PVOID MmSessionBase; // 0xBD000000
-ULONG MmSessionSize;
-ULONG MmSessionViewSize;
-ULONG MmSessionPoolSize;
-ULONG MmSessionImageSize;
-
-//
-// The system view space, on the other hand, is where sections that are memory
-// mapped into "system space" end up.
-//
-// By default, it is a 16MB region.
-//
-PVOID MiSystemViewStart;
-ULONG MmSystemViewSize;
-
-//
-// A copy of the system page directory (the page directory associated with the
-// System process) is kept (double-mapped) by the manager in order to lazily
-// map paged pool PDEs into external processes when they fault on a paged pool
-// address.
-//
-PFN_NUMBER MmSystemPageDirectory;
-PMMPTE MmSystemPagePtes;
-
-//
-// The system cache starts right after hyperspace. The first few pages are for
-// keeping track of the system working set list.
-//
-// This should be 0xC0C00000 -- the cache itself starts at 0xC1000000
-//
-PMMWSL MmSystemCacheWorkingSetList = MI_SYSTEM_CACHE_WS_START;
-
-//
-// Windows NT seems to choose between 7000, 11000 and 50000
-// On systems with more than 32MB, this number is then doubled, and further
-// aligned up to a PDE boundary (4MB).
-//
-ULONG MmNumberOfSystemPtes;
-
-//
-// This is how many pages the PFN database will take up
-// In Windows, this includes the Quark Color Table, but not in ARM³
-//
-ULONG MxPfnAllocation;
-
-//
-// Unlike the old ReactOS Memory Manager, ARM³ (and Windows) does not keep track
-// of pages that are not actually valid physical memory, such as ACPI reserved
-// regions, BIOS address ranges, or holes in physical memory address space which
-// could indicate device-mapped I/O memory.
-//
-// In fact, the lack of a PFN entry for a page usually indicates that this is
-// I/O space instead.
-//
-// A bitmap, called the PFN bitmap, keeps track of all page frames by assigning
-// a bit to each. If the bit is set, then the page is valid physical RAM.
-//
-RTL_BITMAP MiPfnBitMap;
-
-//
-// This structure describes the different pieces of RAM-backed address space
-//
-PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
-
//
// Before we have a PFN database, memory comes straight from our physical memory
// blocks, which is nice because it's guaranteed contiguous and also because once
PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
-//
-// This is where we keep track of the most basic physical layout markers
-//
-ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage = -1;
-
-//
-// The total number of pages mapped by the boot loader, which include the kernel
-// HAL, boot drivers, registry, NLS files and other loader data structures is
-// kept track of here. This depends on "LoaderPagesSpanned" being correct when
-// coming from the loader.
-//
-// This number is later aligned up to a PDE boundary.
-//
-ULONG MmBootImageSize;
-
-//
-// These three variables keep track of the core separation of address space that
-// exists between kernel mode and user mode.
-//
-ULONG MmUserProbeAddress;
-PVOID MmHighestUserAddress;
-PVOID MmSystemRangeStart;
-
-
-
-PVOID MmSystemCacheStart;
-PVOID MmSystemCacheEnd;
-MMSUPPORT MmSystemCacheWs;
-
-//
-// This is where hyperspace ends (followed by the system cache working set)
-//
-PVOID MmHyperSpaceEnd;
-
-//
-// Page coloring algorithm data
-//
-ULONG MmSecondaryColors;
-ULONG MmSecondaryColorMask;
-
-//
-// Actual (registry-configurable) size of a GUI thread's stack
-//
-ULONG MmLargeStackSize;
-
/* PRIVATE FUNCTIONS **********************************************************/
-//
-// In Bavaria, this is probably a hate crime
-//
-VOID
-FASTCALL
-MiSyncARM3WithROS(IN PVOID AddressStart,
- IN PVOID AddressEnd)
-{
- //
- // Puerile piece of junk-grade carbonized horseshit puss sold to the lowest bidder
- //
- ULONG Pde = ADDR_TO_PDE_OFFSET(AddressStart);
- while (Pde <= ADDR_TO_PDE_OFFSET(AddressEnd))
- {
- //
- // This both odious and heinous
- //
- extern ULONG MmGlobalKernelPageDirectory[1024];
- MmGlobalKernelPageDirectory[Pde] = ((PULONG)PDE_BASE)[Pde];
- Pde++;
- }
-}
-
PFN_NUMBER
NTAPI
MxGetNextPage(IN PFN_NUMBER PageCount)
return Pfn;
}
-PFN_NUMBER
+NTSTATUS
NTAPI
-MiPagesInLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
- IN PBOOLEAN IncludeType)
+MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
PLIST_ENTRY NextEntry;
- PFN_NUMBER PageCount = 0;
PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
-
- //
- // Now loop through the descriptors
- //
- NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
- while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
- {
- //
- // Grab each one, and check if it's one we should include
- //
- MdBlock = CONTAINING_RECORD(NextEntry,
- MEMORY_ALLOCATION_DESCRIPTOR,
- ListEntry);
- if ((MdBlock->MemoryType < LoaderMaximum) &&
- (IncludeType[MdBlock->MemoryType]))
- {
- //
- // Add this to our running total
- //
- PageCount += MdBlock->PageCount;
- }
+ ULONG FreePages = 0;
+ PFN_NUMBER PageFrameIndex, PoolPages;
+ PMMPTE StartPde, EndPde, PointerPte, LastPte;
+ MMPTE TempPde = HyperTemplatePte, TempPte = HyperTemplatePte;
+ PVOID NonPagedPoolExpansionVa;
+ ULONG OldCount, L2Associativity;
+ PFN_NUMBER FreePage, FreePageCount, PagesLeft, BasePage, PageCount;
- //
- // Try the next descriptor
- //
- NextEntry = MdBlock->ListEntry.Flink;
- }
-
//
- // Return the total
+ // The large kernel stack is cutomizable, but use default value for now
//
- return PageCount;
-}
+ MmLargeStackSize = KERNEL_LARGE_STACK_SIZE;
-PPHYSICAL_MEMORY_DESCRIPTOR
-NTAPI
-MmInitializeMemoryLimits(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
- IN PBOOLEAN IncludeType)
-{
- PLIST_ENTRY NextEntry;
- ULONG Run = 0, InitialRuns = 0;
- PFN_NUMBER NextPage = -1, PageCount = 0;
- PPHYSICAL_MEMORY_DESCRIPTOR Buffer, NewBuffer;
- PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
-
//
- // Scan the memory descriptors
+ // Set CR3 for the system process
//
- NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
- while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
- {
- //
- // For each one, increase the memory allocation estimate
- //
- InitialRuns++;
- NextEntry = NextEntry->Flink;
- }
+ PointerPte = MiAddressToPde(PTE_BASE);
+ PageFrameIndex = PFN_FROM_PTE(PointerPte) << PAGE_SHIFT;
+ PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameIndex;
//
- // Allocate the maximum we'll ever need
- //
- Buffer = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
- sizeof(PHYSICAL_MEMORY_RUN) *
- (InitialRuns - 1),
- 'lMmM');
- if (!Buffer) return NULL;
-
- //
- // For now that's how many runs we have
+ // Blow away user-mode
//
- Buffer->NumberOfRuns = InitialRuns;
+ StartPde = MiAddressToPde(0);
+ EndPde = MiAddressToPde(KSEG0_BASE);
+ RtlZeroMemory(StartPde, (EndPde - StartPde) * sizeof(MMPTE));
//
- // Now loop through the descriptors again
+ // Loop the memory descriptors
//
NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
{
//
- // Grab each one, and check if it's one we should include
+ // Get the memory block
//
MdBlock = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
- if ((MdBlock->MemoryType < LoaderMaximum) &&
- (IncludeType[MdBlock->MemoryType]))
+
+ //
+ // Skip invisible memory
+ //
+ if ((MdBlock->MemoryType != LoaderFirmwarePermanent) &&
+ (MdBlock->MemoryType != LoaderSpecialMemory) &&
+ (MdBlock->MemoryType != LoaderHALCachedMemory) &&
+ (MdBlock->MemoryType != LoaderBBTMemory))
{
//
- // Add this to our running total
+ // Check if BURNMEM was used
//
- PageCount += MdBlock->PageCount;
+ if (MdBlock->MemoryType != LoaderBad)
+ {
+ //
+ // Count this in the total of pages
+ //
+ MmNumberOfPhysicalPages += MdBlock->PageCount;
+ }
+
+ //
+ // Check if this is the new lowest page
+ //
+ if (MdBlock->BasePage < MmLowestPhysicalPage)
+ {
+ //
+ // Update the lowest page
+ //
+ MmLowestPhysicalPage = MdBlock->BasePage;
+ }
//
- // Check if the next page is described by the next descriptor
- //
- if (MdBlock->BasePage == NextPage)
+ // Check if this is the new highest page
+ //
+ PageFrameIndex = MdBlock->BasePage + MdBlock->PageCount;
+ if (PageFrameIndex > MmHighestPhysicalPage)
{
//
- // Combine it into the same physical run
+ // Update the highest page
//
- ASSERT(MdBlock->PageCount != 0);
- Buffer->Run[Run - 1].PageCount += MdBlock->PageCount;
- NextPage += MdBlock->PageCount;
+ MmHighestPhysicalPage = PageFrameIndex - 1;
}
- else
+
+ //
+ // Check if this is free memory
+ //
+ if ((MdBlock->MemoryType == LoaderFree) ||
+ (MdBlock->MemoryType == LoaderLoadedProgram) ||
+ (MdBlock->MemoryType == LoaderFirmwareTemporary) ||
+ (MdBlock->MemoryType == LoaderOsloaderStack))
{
//
- // Otherwise just duplicate the descriptor's contents
+ // Check if this is the largest memory descriptor
//
- Buffer->Run[Run].BasePage = MdBlock->BasePage;
- Buffer->Run[Run].PageCount = MdBlock->PageCount;
- NextPage = Buffer->Run[Run].BasePage + Buffer->Run[Run].PageCount;
+ if (MdBlock->PageCount > FreePages)
+ {
+ //
+ // For now, it is
+ //
+ MxFreeDescriptor = MdBlock;
+ }
//
- // And in this case, increase the number of runs
+ // More free pages
//
- Run++;
+ FreePages += MdBlock->PageCount;
}
}
//
- // Try the next descriptor
+ // Keep going
//
NextEntry = MdBlock->ListEntry.Flink;
}
//
- // We should not have been able to go past our initial estimate
+ // Save original values of the free descriptor, since it'll be
+ // altered by early allocations
//
- ASSERT(Run <= Buffer->NumberOfRuns);
-
+ MxOldFreeDescriptor = *MxFreeDescriptor;
+
//
- // Our guess was probably exaggerated...
+ // Check if this is a machine with less than 256MB of RAM, and no overide
//
- if (InitialRuns > Run)
+ if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
+ !(MmSizeOfNonPagedPoolInBytes))
{
//
- // Allocate a more accurately sized buffer
+ // Force the non paged pool to be 2MB so we can reduce RAM usage
//
- NewBuffer = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
- sizeof(PHYSICAL_MEMORY_RUN) *
- (Run - 1),
- 'lMmM');
- if (NewBuffer)
- {
- //
- // Copy the old buffer into the new, then free it
- //
- RtlCopyMemory(NewBuffer->Run,
- Buffer->Run,
- sizeof(PHYSICAL_MEMORY_RUN) * Run);
- ExFreePool(Buffer);
-
- //
- // Now use the new buffer
- //
- Buffer = NewBuffer;
- }
+ MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
}
//
- // Write the final numbers, and return it
+ // Hyperspace ends here
//
- Buffer->NumberOfRuns = Run;
- Buffer->NumberOfPages = PageCount;
- return Buffer;
-}
-
-VOID
-NTAPI
-MiBuildPagedPool(VOID)
-{
- PMMPTE PointerPte, PointerPde;
- MMPTE TempPte = HyperTemplatePte;
- PFN_NUMBER PageFrameIndex;
- KIRQL OldIrql;
- ULONG Size, BitMapSize;
+ MmHyperSpaceEnd = (PVOID)((ULONG_PTR)MmSystemCacheWorkingSetList - 1);
//
- // Get the page frame number for the system page directory
+ // Check if the user gave a ridicuously large nonpaged pool RAM size
//
- PointerPte = MiAddressToPte(PDE_BASE);
- MmSystemPageDirectory = PFN_FROM_PTE(PointerPte);
+ if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
+ (MmNumberOfPhysicalPages * 7 / 8))
+ {
+ //
+ // More than 7/8ths of RAM was dedicated to nonpaged pool, ignore!
+ //
+ MmSizeOfNonPagedPoolInBytes = 0;
+ }
//
- // Allocate a system PTE which will hold a copy of the page directory
+ // Check if no registry setting was set, or if the setting was too low
//
- PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
- ASSERT(PointerPte);
- MmSystemPagePtes = MiPteToAddress(PointerPte);
-
+ if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
+ {
+ //
+ // Start with the minimum (256 KB) and add 32 KB for each MB above 4
+ //
+ MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
+ MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
+ 256 * MmMinAdditionNonPagedPoolPerMb;
+ }
+
//
- // Make this system PTE point to the system page directory.
- // It is now essentially double-mapped. This will be used later for lazy
- // evaluation of PDEs accross process switches, similarly to how the Global
- // page directory array in the old ReactOS Mm is used (but in a less hacky
- // way).
- //
- TempPte = HyperTemplatePte;
- TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory;
- ASSERT(PointerPte->u.Hard.Valid == 0);
- ASSERT(TempPte.u.Hard.Valid == 1);
- *PointerPte = TempPte;
-
+ // Check if the registy setting or our dynamic calculation was too high
+ //
+ if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
+ {
+ //
+ // Set it to the maximum
+ //
+ MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
+ }
+
//
- // Let's get back to paged pool work: size it up.
- // By default, it should be twice as big as nonpaged pool.
+ // Check if a percentage cap was set through the registry
//
- MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes;
- if (MmSizeOfPagedPoolInBytes > ((ULONG_PTR)MmNonPagedSystemStart -
- (ULONG_PTR)MmPagedPoolStart))
+ if (MmMaximumNonPagedPoolPercent)
{
//
- // On the other hand, we have limited VA space, so make sure that the VA
- // for paged pool doesn't overflow into nonpaged pool VA. Otherwise, set
- // whatever maximum is possible.
+ // Don't feel like supporting this right now
//
- MmSizeOfPagedPoolInBytes = (ULONG_PTR)MmNonPagedSystemStart -
- (ULONG_PTR)MmPagedPoolStart;
+ UNIMPLEMENTED;
}
-
+
//
- // Get the size in pages and make sure paged pool is at least 32MB.
+ // Page-align the nonpaged pool size
//
- Size = MmSizeOfPagedPoolInBytes;
- if (Size < MI_MIN_INIT_PAGED_POOLSIZE) Size = MI_MIN_INIT_PAGED_POOLSIZE;
- Size = BYTES_TO_PAGES(Size);
-
+ MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
+
//
- // Now check how many PTEs will be required for these many pages.
+ // Now, check if there was a registry size for the maximum size
//
- Size = (Size + (1024 - 1)) / 1024;
-
+ if (!MmMaximumNonPagedPoolInBytes)
+ {
+ //
+ // Start with the default (1MB)
+ //
+ MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
+
+ //
+ // Add space for PFN database
+ //
+ MmMaximumNonPagedPoolInBytes += (ULONG)
+ PAGE_ALIGN((MmHighestPhysicalPage + 1) * sizeof(MMPFN));
+
+ //
+ // Add 400KB for each MB above 4
+ //
+ MmMaximumNonPagedPoolInBytes += (FreePages - 1024) / 256 *
+ MmMaxAdditionNonPagedPoolPerMb;
+ }
+
//
- // Recompute the page-aligned size of the paged pool, in bytes and pages.
+ // Make sure there's at least 16 pages + the PFN available for expansion
//
- MmSizeOfPagedPoolInBytes = Size * PAGE_SIZE * 1024;
- MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
-
+ PoolPages = MmSizeOfNonPagedPoolInBytes + (PAGE_SIZE * 16) +
+ ((ULONG)PAGE_ALIGN(MmHighestPhysicalPage + 1) *
+ sizeof(MMPFN));
+ if (MmMaximumNonPagedPoolInBytes < PoolPages)
+ {
+ //
+ // Set it to the minimum value for the maximum (yuck!)
+ //
+ MmMaximumNonPagedPoolInBytes = PoolPages;
+ }
+
//
- // Let's be really sure this doesn't overflow into nonpaged system VA
+ // Systems with 2GB of kernel address space get double the size
//
- ASSERT((MmSizeOfPagedPoolInBytes + (ULONG_PTR)MmPagedPoolStart) <=
- (ULONG_PTR)MmNonPagedSystemStart);
-
+ PoolPages = MI_MAX_NONPAGED_POOL_SIZE * 2;
+
//
- // This is where paged pool ends
+ // Don't let the maximum go too high
//
- MmPagedPoolEnd = (PVOID)(((ULONG_PTR)MmPagedPoolStart +
- MmSizeOfPagedPoolInBytes) - 1);
-
+ if (MmMaximumNonPagedPoolInBytes > PoolPages)
+ {
+ //
+ // Set it to the upper limit
+ //
+ MmMaximumNonPagedPoolInBytes = PoolPages;
+ }
+
//
- // So now get the PDE for paged pool and zero it out
+ // Check if this is a system with > 128MB of non paged pool
//
- PointerPde = MiAddressToPde(MmPagedPoolStart);
- RtlZeroMemory(PointerPde,
- (1 + MiAddressToPde(MmPagedPoolEnd) - PointerPde) * sizeof(MMPTE));
-
+ if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
+ {
+ //
+ // FIXME: Unsure about additional checks needed
+ //
+ DPRINT1("Untested path\n");
+ }
+
//
- // Next, get the first and last PTE
+ // Get L2 cache information
//
- PointerPte = MiAddressToPte(MmPagedPoolStart);
- MmPagedPoolInfo.FirstPteForPagedPool = PointerPte;
- MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
-
+ L2Associativity = KeGetPcr()->SecondLevelCacheAssociativity;
+ MmSecondaryColors = KeGetPcr()->SecondLevelCacheSize;
+ if (L2Associativity) MmSecondaryColors /= L2Associativity;
+
//
- // Lock the PFN database
+ // Compute final color mask and count
//
- OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-
+ MmSecondaryColors >>= PAGE_SHIFT;
+ if (!MmSecondaryColors) MmSecondaryColors = 1;
+ MmSecondaryColorMask = MmSecondaryColors - 1;
+
//
- // Allocate a page and map the first paged pool PDE
+ // Store it
//
- PageFrameIndex = MmAllocPage(MC_NPPOOL, 0);
- TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
- ASSERT(PointerPde->u.Hard.Valid == 0);
- ASSERT(TempPte.u.Hard.Valid == 1);
- *PointerPde = TempPte;
-
+ KeGetCurrentPrcb()->SecondaryColorMask = MmSecondaryColorMask;
+
//
- // Release the PFN database lock
+ // Calculate the number of bytes for the PFN database
+ // and then convert to pages
//
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-
+ MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN);
+ MxPfnAllocation >>= PAGE_SHIFT;
+
//
- // We only have one PDE mapped for now... at fault time, additional PDEs
- // will be allocated to handle paged pool growth. This is where they'll have
- // to start.
+ // We have to add one to the count here, because in the process of
+ // shifting down to the page size, we actually ended up getting the
+ // lower aligned size (so say, 0x5FFFF bytes is now 0x5F pages).
+ // Later on, we'll shift this number back into bytes, which would cause
+ // us to end up with only 0x5F000 bytes -- when we actually want to have
+ // 0x60000 bytes.
//
- MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde + 1;
-
+ MxPfnAllocation++;
+
//
- // We keep track of each page via a bit, so check how big the bitmap will
- // have to be (make sure to align our page count such that it fits nicely
- // into a 4-byte aligned bitmap.
+ // Now calculate the nonpaged pool expansion VA region
//
- // We'll also allocate the bitmap header itself part of the same buffer.
+ MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmNonPagedPoolEnd -
+ MmMaximumNonPagedPoolInBytes +
+ MmSizeOfNonPagedPoolInBytes);
+ MmNonPagedPoolStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolStart);
+ NonPagedPoolExpansionVa = MmNonPagedPoolStart;
+ DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
+ MmSizeOfNonPagedPoolInBytes, MmMaximumNonPagedPoolInBytes);
+
//
- Size = Size * 1024;
- ASSERT(Size == MmSizeOfPagedPoolInPages);
- BitMapSize = Size;
- Size = sizeof(RTL_BITMAP) + (((Size + 31) / 32) * sizeof(ULONG));
-
+ // Now calculate the nonpaged system VA region, which includes the
+ // nonpaged pool expansion (above) and the system PTEs. Note that it is
+ // then aligned to a PDE boundary (4MB).
//
- // Allocate the allocation bitmap, which tells us which regions have not yet
- // been mapped into memory
+ MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolStart -
+ (MmNumberOfSystemPtes + 1) * PAGE_SIZE);
+ MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
+ ~((4 * 1024 * 1024) - 1));
+
//
- MmPagedPoolInfo.PagedPoolAllocationMap = ExAllocatePoolWithTag(NonPagedPool,
- Size,
- ' mM');
- ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
-
+ // Don't let it go below the minimum
//
- // Initialize it such that at first, only the first page's worth of PTEs is
- // marked as allocated (incidentially, the first PDE we allocated earlier).
+ if (MmNonPagedSystemStart < (PVOID)0xEB000000)
+ {
+ //
+ // This is a hard-coded limit in the Windows NT address space
+ //
+ MmNonPagedSystemStart = (PVOID)0xEB000000;
+
+ //
+ // Reduce the amount of system PTEs to reach this point
+ //
+ MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolStart -
+ (ULONG_PTR)MmNonPagedSystemStart) >>
+ PAGE_SHIFT;
+ MmNumberOfSystemPtes--;
+ ASSERT(MmNumberOfSystemPtes > 1000);
+ }
+
//
- RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
- (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
- BitMapSize);
- RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
- RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 1024);
-
+ // Check if we are in a situation where the size of the paged pool
+ // is so large that it overflows into nonpaged pool
//
- // We have a second bitmap, which keeps track of where allocations end.
- // Given the allocation bitmap and a base address, we can therefore figure
- // out which page is the last page of that allocation, and thus how big the
- // entire allocation is.
- //
- MmPagedPoolInfo.EndOfPagedPoolBitmap = ExAllocatePoolWithTag(NonPagedPool,
- Size,
- ' mM');
- ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
- RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
- (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
- BitMapSize);
-
+ if (MmSizeOfPagedPoolInBytes >
+ ((ULONG_PTR)MmNonPagedSystemStart - (ULONG_PTR)MmPagedPoolStart))
+ {
+ //
+ // We need some recalculations here
+ //
+ DPRINT1("Paged pool is too big!\n");
+ }
+
//
- // Since no allocations have been made yet, there are no bits set as the end
+ // Normally, the PFN database should start after the loader images.
+ // This is already the case in ReactOS, but for now we want to co-exist
+ // with the old memory manager, so we'll create a "Shadow PFN Database"
+ // instead, and arbitrarly start it at 0xB0000000.
//
- RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
-
+ MmPfnDatabase = (PVOID)0xB0000000;
+ ASSERT(((ULONG_PTR)MmPfnDatabase & ((4 * 1024 * 1024) - 1)) == 0);
+
//
- // Initialize paged pool.
+ // Non paged pool comes after the PFN database
//
- InitializePool(PagedPool, 0);
+ MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmPfnDatabase +
+ (MxPfnAllocation << PAGE_SHIFT));
//
- // Initialize the paged pool mutex
+ // Now we actually need to get these many physical pages. Nonpaged pool
+ // is actually also physically contiguous (but not the expansion)
//
- KeInitializeGuardedMutex(&MmPagedPoolMutex);
-}
+ PageFrameIndex = MxGetNextPage(MxPfnAllocation +
+ (MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT));
+ ASSERT(PageFrameIndex != 0);
+ DPRINT("PFN DB PA PFN begins at: %lx\n", PageFrameIndex);
+ DPRINT("NP PA PFN begins at: %lx\n", PageFrameIndex + MxPfnAllocation);
-NTSTATUS
-NTAPI
-MmArmInitSystem(IN ULONG Phase,
- IN PLOADER_PARAMETER_BLOCK LoaderBlock)
-{
- PLIST_ENTRY NextEntry;
- PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
- ULONG FreePages = 0;
- PFN_NUMBER PageFrameIndex, PoolPages;
- PMMPTE StartPde, EndPde, PointerPte, LastPte;
- MMPTE TempPde = HyperTemplatePte, TempPte = HyperTemplatePte;
- PVOID NonPagedPoolExpansionVa;
- ULONG OldCount, i, L2Associativity;
- BOOLEAN IncludeType[LoaderMaximum];
- PVOID Bitmap;
- PPHYSICAL_MEMORY_RUN Run;
- PFN_NUMBER FreePage, FreePageCount, PagesLeft, BasePage, PageCount;
-
//
- // Instantiate memory that we don't consider RAM/usable
- // We use the same exclusions that Windows does, in order to try to be
- // compatible with WinLDR-style booting
+ // Now we need some pages to create the page tables for the NP system VA
+ // which includes system PTEs and expansion NP
//
- for (i = 0; i < LoaderMaximum; i++) IncludeType[i] = TRUE;
- IncludeType[LoaderBad] = FALSE;
- IncludeType[LoaderFirmwarePermanent] = FALSE;
- IncludeType[LoaderSpecialMemory] = FALSE;
- IncludeType[LoaderBBTMemory] = FALSE;
- if (Phase == 0)
+ StartPde = MiAddressToPde(MmNonPagedSystemStart);
+ EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
+ while (StartPde <= EndPde)
{
//
- // Define the basic user vs. kernel address space separation
- //
- MmSystemRangeStart = (PVOID)KSEG0_BASE;
- MmUserProbeAddress = (ULONG_PTR)MmSystemRangeStart - 0x10000;
- MmHighestUserAddress = (PVOID)(MmUserProbeAddress - 1);
-
- //
- // Get the size of the boot loader's image allocations and then round
- // that region up to a PDE size, so that any PDEs we might create for
- // whatever follows are separate from the PDEs that boot loader might've
- // already created (and later, we can blow all that away if we want to).
- //
- MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
- MmBootImageSize *= PAGE_SIZE;
- MmBootImageSize = (MmBootImageSize + (4 * 1024 * 1024) - 1) & ~((4 * 1024 * 1024) - 1);
- ASSERT((MmBootImageSize % (4 * 1024 * 1024)) == 0);
-
- //
- // Set the size of session view, pool, and image
- //
- MmSessionSize = MI_SESSION_SIZE;
- MmSessionViewSize = MI_SESSION_VIEW_SIZE;
- MmSessionPoolSize = MI_SESSION_POOL_SIZE;
- MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
-
- //
- // Set the size of system view
- //
- MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
-
- //
- // This is where it all ends
- //
- MiSessionImageEnd = (PVOID)PTE_BASE;
-
- //
- // This is where we will load Win32k.sys and the video driver
- //
- MiSessionImageStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
- MmSessionImageSize);
-
+ // Sanity check
//
- // So the view starts right below the session working set (itself below
- // the image area)
- //
- MiSessionViewStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
- MmSessionImageSize -
- MI_SESSION_WORKING_SET_SIZE -
- MmSessionViewSize);
-
- //
- // Session pool follows
- //
- MiSessionPoolEnd = MiSessionViewStart;
- MiSessionPoolStart = (PVOID)((ULONG_PTR)MiSessionPoolEnd -
- MmSessionPoolSize);
-
- //
- // And it all begins here
- //
- MmSessionBase = MiSessionPoolStart;
+ ASSERT(StartPde->u.Hard.Valid == 0);
//
- // Sanity check that our math is correct
+ // Get a page
//
- ASSERT((ULONG_PTR)MmSessionBase + MmSessionSize == PTE_BASE);
+ TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
+ ASSERT(TempPde.u.Hard.Valid == 1);
+ *StartPde = TempPde;
//
- // Session space ends wherever image session space ends
+ // Zero out the page table
//
- MiSessionSpaceEnd = MiSessionImageEnd;
+ PointerPte = MiPteToAddress(StartPde);
+ RtlZeroMemory(PointerPte, PAGE_SIZE);
//
- // System view space ends at session space, so now that we know where
- // this is, we can compute the base address of system view space itself.
- //
- MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase -
- MmSystemViewSize);
-
- //
- // Count physical pages on the system
+ // Next
//
- PageCount = MiPagesInLoaderBlock(LoaderBlock, IncludeType);
-
+ StartPde++;
+ }
+
+ //
+ // Now we need pages for the page tables which will map initial NP
+ //
+ StartPde = MiAddressToPde(MmPfnDatabase);
+ EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
+ MmSizeOfNonPagedPoolInBytes - 1));
+ while (StartPde <= EndPde)
+ {
//
- // Check if this is a machine with less than 19MB of RAM
+ // Sanity check
//
- if (PageCount < MI_MIN_PAGES_FOR_SYSPTE_TUNING)
- {
- //
- // Use the very minimum of system PTEs
- //
- MmNumberOfSystemPtes = 7000;
- }
- else
- {
- //
- // Use the default, but check if we have more than 32MB of RAM
- //
- MmNumberOfSystemPtes = 11000;
- if (PageCount > MI_MIN_PAGES_FOR_SYSPTE_BOOST)
- {
- //
- // Double the amount of system PTEs
- //
- MmNumberOfSystemPtes <<= 1;
- }
- }
+ ASSERT(StartPde->u.Hard.Valid == 0);
- DPRINT("System PTE count has been tuned to %d (%d bytes)\n",
- MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
-
- //
- //
- // Start of Architecture Specific Initialization Code
//
+ // Get a page
//
+ TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
+ ASSERT(TempPde.u.Hard.Valid == 1);
+ *StartPde = TempPde;
//
- // The large kernel stack is cutomizable, but use default value for now
+ // Zero out the page table
//
- MmLargeStackSize = KERNEL_LARGE_STACK_SIZE;
+ PointerPte = MiPteToAddress(StartPde);
+ RtlZeroMemory(PointerPte, PAGE_SIZE);
//
- // Setup template
+ // Next
//
- HyperTemplatePte.u.Long = 0;
- HyperTemplatePte.u.Hard.Valid = 1;
- HyperTemplatePte.u.Hard.Write = 1;
- HyperTemplatePte.u.Hard.Dirty = 1;
- HyperTemplatePte.u.Hard.Accessed = 1;
- if (Ke386GlobalPagesEnabled) HyperTemplatePte.u.Hard.Global = 1;
+ StartPde++;
+ }
+ //
+ // Now remember where the expansion starts
+ //
+ MmNonPagedPoolExpansionStart = NonPagedPoolExpansionVa;
+
+ //
+ // Last step is to actually map the nonpaged pool
+ //
+ PointerPte = MiAddressToPte(MmNonPagedPoolStart);
+ LastPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
+ MmSizeOfNonPagedPoolInBytes - 1));
+ while (PointerPte <= LastPte)
+ {
//
- // Set CR3 for the system process
- //
- PointerPte = MiAddressToPde(PTE_BASE);
- PageFrameIndex = PFN_FROM_PTE(PointerPte) << PAGE_SHIFT;
- PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameIndex;
-
- //
- // Blow away user-mode
+ // Use one of our contigous pages
//
- StartPde = MiAddressToPde(0);
- EndPde = MiAddressToPde(KSEG0_BASE);
- RtlZeroMemory(StartPde, (EndPde - StartPde) * sizeof(MMPTE));
-
+ TempPte.u.Hard.PageFrameNumber = PageFrameIndex++;
+ ASSERT(PointerPte->u.Hard.Valid == 0);
+ ASSERT(TempPte.u.Hard.Valid == 1);
+ *PointerPte++ = TempPte;
+ }
+
+ //
+ // Sanity check: make sure we have properly defined the system PTE space
+ //
+ ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
+ MiAddressToPte(MmNonPagedPoolExpansionStart));
+
+ //
+ // Now go ahead and initialize the ARM³ nonpaged pool
+ //
+ MiInitializeArmPool();
+
+ //
+ // Get current page data, since we won't be using MxGetNextPage as it
+ // would corrupt our state
+ //
+ FreePage = MxFreeDescriptor->BasePage;
+ FreePageCount = MxFreeDescriptor->PageCount;
+ PagesLeft = 0;
+
+ //
+ // Loop the memory descriptors
+ //
+ NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &KeLoaderBlock->MemoryDescriptorListHead)
+ {
//
- // Loop the memory descriptors
+ // Get the descriptor
//
- NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
- while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
+ MdBlock = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+ if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
+ (MdBlock->MemoryType == LoaderBBTMemory) ||
+ (MdBlock->MemoryType == LoaderSpecialMemory))
{
//
- // Get the memory block
- //
- MdBlock = CONTAINING_RECORD(NextEntry,
- MEMORY_ALLOCATION_DESCRIPTOR,
- ListEntry);
-
- //
- // Skip invisible memory
- //
- if ((MdBlock->MemoryType != LoaderFirmwarePermanent) &&
- (MdBlock->MemoryType != LoaderSpecialMemory) &&
- (MdBlock->MemoryType != LoaderHALCachedMemory) &&
- (MdBlock->MemoryType != LoaderBBTMemory))
- {
- //
- // Check if BURNMEM was used
- //
- if (MdBlock->MemoryType != LoaderBad)
- {
- //
- // Count this in the total of pages
- //
- MmNumberOfPhysicalPages += MdBlock->PageCount;
- }
-
- //
- // Check if this is the new lowest page
- //
- if (MdBlock->BasePage < MmLowestPhysicalPage)
- {
- //
- // Update the lowest page
- //
- MmLowestPhysicalPage = MdBlock->BasePage;
- }
-
- //
- // Check if this is the new highest page
- //
- PageFrameIndex = MdBlock->BasePage + MdBlock->PageCount;
- if (PageFrameIndex > MmHighestPhysicalPage)
- {
- //
- // Update the highest page
- //
- MmHighestPhysicalPage = PageFrameIndex - 1;
- }
-
- //
- // Check if this is free memory
- //
- if ((MdBlock->MemoryType == LoaderFree) ||
- (MdBlock->MemoryType == LoaderLoadedProgram) ||
- (MdBlock->MemoryType == LoaderFirmwareTemporary) ||
- (MdBlock->MemoryType == LoaderOsloaderStack))
- {
- //
- // Check if this is the largest memory descriptor
- //
- if (MdBlock->PageCount > FreePages)
- {
- //
- // For now, it is
- //
- MxFreeDescriptor = MdBlock;
- }
-
- //
- // More free pages
- //
- FreePages += MdBlock->PageCount;
- }
- }
-
- //
- // Keep going
+ // These pages are not part of the PFN database
//
NextEntry = MdBlock->ListEntry.Flink;
+ continue;
}
//
- // Save original values of the free descriptor, since it'll be
- // altered by early allocations
- //
- MxOldFreeDescriptor = *MxFreeDescriptor;
-
+ // Next, check if this is our special free descriptor we've found
//
- // Check if this is a machine with less than 256MB of RAM, and no overide
- //
- if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
- !(MmSizeOfNonPagedPoolInBytes))
- {
- //
- // Force the non paged pool to be 2MB so we can reduce RAM usage
- //
- MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
- }
-
- //
- // Hyperspace ends here
- //
- MmHyperSpaceEnd = (PVOID)((ULONG_PTR)MmSystemCacheWorkingSetList - 1);
-
- //
- // Check if the user gave a ridicuously large nonpaged pool RAM size
- //
- if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
- (MmNumberOfPhysicalPages * 7 / 8))
- {
- //
- // More than 7/8ths of RAM was dedicated to nonpaged pool, ignore!
- //
- MmSizeOfNonPagedPoolInBytes = 0;
- }
-
- //
- // Check if no registry setting was set, or if the setting was too low
- //
- if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
+ if (MdBlock == MxFreeDescriptor)
{
//
- // Start with the minimum (256 KB) and add 32 KB for each MB above 4
+ // Use the real numbers instead
//
- MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
- MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
- 256 * MmMinAdditionNonPagedPoolPerMb;
+ BasePage = MxOldFreeDescriptor.BasePage;
+ PageCount = MxOldFreeDescriptor.PageCount;
}
-
- //
- // Check if the registy setting or our dynamic calculation was too high
- //
- if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
- {
- //
- // Set it to the maximum
- //
- MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
- }
-
- //
- // Check if a percentage cap was set through the registry
- //
- if (MmMaximumNonPagedPoolPercent)
- {
- //
- // Don't feel like supporting this right now
- //
- UNIMPLEMENTED;
- }
-
- //
- // Page-align the nonpaged pool size
- //
- MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
-
- //
- // Now, check if there was a registry size for the maximum size
- //
- if (!MmMaximumNonPagedPoolInBytes)
- {
- //
- // Start with the default (1MB)
- //
- MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
-
- //
- // Add space for PFN database
- //
- MmMaximumNonPagedPoolInBytes += (ULONG)
- PAGE_ALIGN((MmHighestPhysicalPage + 1) * sizeof(MMPFN));
-
- //
- // Add 400KB for each MB above 4
- //
- MmMaximumNonPagedPoolInBytes += (FreePages - 1024) / 256 *
- MmMaxAdditionNonPagedPoolPerMb;
- }
-
- //
- // Make sure there's at least 16 pages + the PFN available for expansion
- //
- PoolPages = MmSizeOfNonPagedPoolInBytes + (PAGE_SIZE * 16) +
- ((ULONG)PAGE_ALIGN(MmHighestPhysicalPage + 1) *
- sizeof(MMPFN));
- if (MmMaximumNonPagedPoolInBytes < PoolPages)
- {
- //
- // Set it to the minimum value for the maximum (yuck!)
- //
- MmMaximumNonPagedPoolInBytes = PoolPages;
- }
-
- //
- // Systems with 2GB of kernel address space get double the size
- //
- PoolPages = MI_MAX_NONPAGED_POOL_SIZE * 2;
-
- //
- // Don't let the maximum go too high
- //
- if (MmMaximumNonPagedPoolInBytes > PoolPages)
- {
- //
- // Set it to the upper limit
- //
- MmMaximumNonPagedPoolInBytes = PoolPages;
- }
-
- //
- // Check if this is a system with > 128MB of non paged pool
- //
- if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
- {
- //
- // FIXME: Unsure about additional checks needed
- //
- DPRINT1("Untested path\n");
- }
-
- //
- // Get L2 cache information
- //
- L2Associativity = KeGetPcr()->SecondLevelCacheAssociativity;
- MmSecondaryColors = KeGetPcr()->SecondLevelCacheSize;
- if (L2Associativity) MmSecondaryColors /= L2Associativity;
-
- //
- // Compute final color mask and count
- //
- MmSecondaryColors >>= PAGE_SHIFT;
- if (!MmSecondaryColors) MmSecondaryColors = 1;
- MmSecondaryColorMask = MmSecondaryColors - 1;
-
- //
- // Store it
- //
- KeGetCurrentPrcb()->SecondaryColorMask = MmSecondaryColorMask;
-
- //
- // Calculate the number of bytes for the PFN database
- // and then convert to pages
- //
- MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN);
- MxPfnAllocation >>= PAGE_SHIFT;
-
- //
- // We have to add one to the count here, because in the process of
- // shifting down to the page size, we actually ended up getting the
- // lower aligned size (so say, 0x5FFFF bytes is now 0x5F pages).
- // Later on, we'll shift this number back into bytes, which would cause
- // us to end up with only 0x5F000 bytes -- when we actually want to have
- // 0x60000 bytes.
- //
- MxPfnAllocation++;
-
- //
- // Now calculate the nonpaged pool expansion VA region
- //
- MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmNonPagedPoolEnd -
- MmMaximumNonPagedPoolInBytes +
- MmSizeOfNonPagedPoolInBytes);
- MmNonPagedPoolStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolStart);
- NonPagedPoolExpansionVa = MmNonPagedPoolStart;
- DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
- MmSizeOfNonPagedPoolInBytes, MmMaximumNonPagedPoolInBytes);
-
- //
- // Now calculate the nonpaged system VA region, which includes the
- // nonpaged pool expansion (above) and the system PTEs. Note that it is
- // then aligned to a PDE boundary (4MB).
- //
- MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolStart -
- (MmNumberOfSystemPtes + 1) * PAGE_SIZE);
- MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
- ~((4 * 1024 * 1024) - 1));
-
- //
- // Don't let it go below the minimum
- //
- if (MmNonPagedSystemStart < (PVOID)0xEB000000)
+ else
{
//
- // This is a hard-coded limit in the Windows NT address space
- //
- MmNonPagedSystemStart = (PVOID)0xEB000000;
-
+ // Use the descriptor's numbers
//
- // Reduce the amount of system PTEs to reach this point
- //
- MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolStart -
- (ULONG_PTR)MmNonPagedSystemStart) >>
- PAGE_SHIFT;
- MmNumberOfSystemPtes--;
- ASSERT(MmNumberOfSystemPtes > 1000);
+ BasePage = MdBlock->BasePage;
+ PageCount = MdBlock->PageCount;
}
//
- // Check if we are in a situation where the size of the paged pool
- // is so large that it overflows into nonpaged pool
+ // Get the PTEs for this range
//
- if (MmSizeOfPagedPoolInBytes >
- ((ULONG_PTR)MmNonPagedSystemStart - (ULONG_PTR)MmPagedPoolStart))
- {
- //
- // We need some recalculations here
- //
- DPRINT1("Paged pool is too big!\n");
- }
+ PointerPte = MiAddressToPte(&MmPfnDatabase[BasePage]);
+ LastPte = MiAddressToPte(((ULONG_PTR)&MmPfnDatabase[BasePage + PageCount]) - 1);
+ DPRINT("MD Type: %lx Base: %lx Count: %lx\n", MdBlock->MemoryType, BasePage, PageCount);
//
- // Normally, the PFN database should start after the loader images.
- // This is already the case in ReactOS, but for now we want to co-exist
- // with the old memory manager, so we'll create a "Shadow PFN Database"
- // instead, and arbitrarly start it at 0xB0000000.
+ // Loop them
//
- MmPfnDatabase = (PVOID)0xB0000000;
- ASSERT(((ULONG_PTR)MmPfnDatabase & ((4 * 1024 * 1024) - 1)) == 0);
-
- //
- // Non paged pool comes after the PFN database
- //
- MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmPfnDatabase +
- (MxPfnAllocation << PAGE_SHIFT));
-
- //
- // Now we actually need to get these many physical pages. Nonpaged pool
- // is actually also physically contiguous (but not the expansion)
- //
- PageFrameIndex = MxGetNextPage(MxPfnAllocation +
- (MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT));
- ASSERT(PageFrameIndex != 0);
- DPRINT("PFN DB PA PFN begins at: %lx\n", PageFrameIndex);
- DPRINT("NP PA PFN begins at: %lx\n", PageFrameIndex + MxPfnAllocation);
-
- //
- // Now we need some pages to create the page tables for the NP system VA
- // which includes system PTEs and expansion NP
- //
- StartPde = MiAddressToPde(MmNonPagedSystemStart);
- EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
- while (StartPde <= EndPde)
- {
- //
- // Sanity check
- //
- ASSERT(StartPde->u.Hard.Valid == 0);
-
- //
- // Get a page
- //
- TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
- ASSERT(TempPde.u.Hard.Valid == 1);
- *StartPde = TempPde;
-
- //
- // Zero out the page table
- //
- PointerPte = MiPteToAddress(StartPde);
- RtlZeroMemory(PointerPte, PAGE_SIZE);
-
- //
- // Next
- //
- StartPde++;
- }
-
- //
- // Now we need pages for the page tables which will map initial NP
- //
- StartPde = MiAddressToPde(MmPfnDatabase);
- EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
- MmSizeOfNonPagedPoolInBytes - 1));
- while (StartPde <= EndPde)
- {
- //
- // Sanity check
- //
- ASSERT(StartPde->u.Hard.Valid == 0);
-
- //
- // Get a page
- //
- TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1);
- ASSERT(TempPde.u.Hard.Valid == 1);
- *StartPde = TempPde;
-
- //
- // Zero out the page table
- //
- PointerPte = MiPteToAddress(StartPde);
- RtlZeroMemory(PointerPte, PAGE_SIZE);
-
- //
- // Next
- //
- StartPde++;
- }
-
- //
- // Now remember where the expansion starts
- //
- MmNonPagedPoolExpansionStart = NonPagedPoolExpansionVa;
-
- //
- // Last step is to actually map the nonpaged pool
- //
- PointerPte = MiAddressToPte(MmNonPagedPoolStart);
- LastPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolStart +
- MmSizeOfNonPagedPoolInBytes - 1));
while (PointerPte <= LastPte)
{
//
- // Use one of our contigous pages
- //
- TempPte.u.Hard.PageFrameNumber = PageFrameIndex++;
- ASSERT(PointerPte->u.Hard.Valid == 0);
- ASSERT(TempPte.u.Hard.Valid == 1);
- *PointerPte++ = TempPte;
- }
-
- //
- // Sanity check: make sure we have properly defined the system PTE space
- //
- ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
- MiAddressToPte(MmNonPagedPoolExpansionStart));
-
- //
- // Now go ahead and initialize the ARM³ nonpaged pool
- //
- MiInitializeArmPool();
-
- //
- // Get current page data, since we won't be using MxGetNextPage as it
- // would corrupt our state
- //
- FreePage = MxFreeDescriptor->BasePage;
- FreePageCount = MxFreeDescriptor->PageCount;
- PagesLeft = 0;
-
- //
- // Loop the memory descriptors
- //
- NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
- while (NextEntry != &KeLoaderBlock->MemoryDescriptorListHead)
- {
- //
- // Get the descriptor
- //
- MdBlock = CONTAINING_RECORD(NextEntry,
- MEMORY_ALLOCATION_DESCRIPTOR,
- ListEntry);
- if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
- (MdBlock->MemoryType == LoaderBBTMemory) ||
- (MdBlock->MemoryType == LoaderSpecialMemory))
- {
- //
- // These pages are not part of the PFN database
- //
- NextEntry = MdBlock->ListEntry.Flink;
- continue;
- }
-
- //
- // Next, check if this is our special free descriptor we've found
+ // We'll only touch PTEs that aren't already valid
//
- if (MdBlock == MxFreeDescriptor)
+ if (PointerPte->u.Hard.Valid == 0)
{
//
- // Use the real numbers instead
- //
- BasePage = MxOldFreeDescriptor.BasePage;
- PageCount = MxOldFreeDescriptor.PageCount;
- }
- else
- {
+ // Use the next free page
//
- // Use the descriptor's numbers
- //
- BasePage = MdBlock->BasePage;
- PageCount = MdBlock->PageCount;
- }
-
- //
- // Get the PTEs for this range
- //
- PointerPte = MiAddressToPte(&MmPfnDatabase[BasePage]);
- LastPte = MiAddressToPte(((ULONG_PTR)&MmPfnDatabase[BasePage + PageCount]) - 1);
- DPRINT("MD Type: %lx Base: %lx Count: %lx\n", MdBlock->MemoryType, BasePage, PageCount);
-
- //
- // Loop them
- //
- while (PointerPte <= LastPte)
- {
+ TempPte.u.Hard.PageFrameNumber = FreePage;
+ ASSERT(FreePageCount != 0);
+
//
- // We'll only touch PTEs that aren't already valid
+ // Consume free pages
//
- if (PointerPte->u.Hard.Valid == 0)
+ FreePage++;
+ FreePageCount--;
+ if (!FreePageCount)
{
//
- // Use the next free page
- //
- TempPte.u.Hard.PageFrameNumber = FreePage;
- ASSERT(FreePageCount != 0);
-
- //
- // Consume free pages
- //
- FreePage++;
- FreePageCount--;
- if (!FreePageCount)
- {
- //
- // Out of memory
- //
- KeBugCheckEx(INSTALL_MORE_MEMORY,
- MmNumberOfPhysicalPages,
- FreePageCount,
- MxOldFreeDescriptor.PageCount,
- 1);
- }
-
- //
- // Write out this PTE
- //
- PagesLeft++;
- ASSERT(PointerPte->u.Hard.Valid == 0);
- ASSERT(TempPte.u.Hard.Valid == 1);
- *PointerPte = TempPte;
-
- //
- // Zero this page
+ // Out of memory
//
- RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
+ KeBugCheckEx(INSTALL_MORE_MEMORY,
+ MmNumberOfPhysicalPages,
+ FreePageCount,
+ MxOldFreeDescriptor.PageCount,
+ 1);
}
//
- // Next!
+ // Write out this PTE
//
- PointerPte++;
+ PagesLeft++;
+ ASSERT(PointerPte->u.Hard.Valid == 0);
+ ASSERT(TempPte.u.Hard.Valid == 1);
+ *PointerPte = TempPte;
+
+ //
+ // Zero this page
+ //
+ RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
}
//
- // Do the next address range
+ // Next!
//
- NextEntry = MdBlock->ListEntry.Flink;
+ PointerPte++;
}
//
- // Now update the free descriptors to consume the pages we used up during
- // the PFN allocation loop
+ // Do the next address range
//
- MxFreeDescriptor->BasePage = FreePage;
- MxFreeDescriptor->PageCount = FreePageCount;
+ NextEntry = MdBlock->ListEntry.Flink;
}
- else if (Phase == 1) // IN BETWEEN, THE PFN DATABASE IS NOW CREATED
- {
- //
- // Reset the descriptor back so we can create the correct memory blocks
- //
- *MxFreeDescriptor = MxOldFreeDescriptor;
-
- //
- // Initialize the nonpaged pool
- //
- InitializePool(NonPagedPool, 0);
-
- //
- // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
- //
- PointerPte = MiAddressToPte(MmNonPagedSystemStart);
- OldCount = MmNumberOfSystemPtes;
- MmNumberOfSystemPtes = MiAddressToPte(MmNonPagedPoolExpansionStart) -
- PointerPte;
- MmNumberOfSystemPtes--;
- DPRINT("Final System PTE count: %d (%d bytes)\n",
- MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
-
- //
- // Create the system PTE space
- //
- MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
-
- //
- // Get the PDE For hyperspace
- //
- StartPde = MiAddressToPde(HYPER_SPACE);
-
- //
- // Allocate a page for it and create it
- //
- PageFrameIndex = MmAllocPage(MC_SYSTEM, 0);
- TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
- TempPde.u.Hard.Global = FALSE; // Hyperspace is local!
- ASSERT(StartPde->u.Hard.Valid == 0);
- ASSERT(TempPde.u.Hard.Valid == 1);
- *StartPde = TempPde;
-
- //
- // Zero out the page table now
- //
- PointerPte = MiAddressToPte(HYPER_SPACE);
- RtlZeroMemory(PointerPte, PAGE_SIZE);
-
- //
- // Setup the mapping PTEs
- //
- MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START);
- MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
- MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
+
+ //
+ // Now update the free descriptors to consume the pages we used up during
+ // the PFN allocation loop
+ //
+ MxFreeDescriptor->BasePage = FreePage;
+ MxFreeDescriptor->PageCount = FreePageCount;
- //
- // Reserve system PTEs for zeroing PTEs and clear them
- //
- MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES,
- SystemPteSpace);
- RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
+ /* Call back into shitMM to setup the PFN database */
+ MmInitializePageList();
- //
- // Set the counter to maximum to boot with
- //
- MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
-
- //
- // Sync us up with ReactOS Mm
- //
- MiSyncARM3WithROS(MmNonPagedSystemStart, (PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
- MiSyncARM3WithROS(MmPfnDatabase, (PVOID)((ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes - 1));
- MiSyncARM3WithROS((PVOID)HYPER_SPACE, (PVOID)(HYPER_SPACE + PAGE_SIZE - 1));
+ //
+ // Reset the descriptor back so we can create the correct memory blocks
+ //
+ *MxFreeDescriptor = MxOldFreeDescriptor;
- //
- // Build the physical memory block
- //
- MmPhysicalMemoryBlock = MmInitializeMemoryLimits(LoaderBlock,
- IncludeType);
-
- //
- // Allocate enough buffer for the PFN bitmap
- // Align it up to a 32-bit boundary
- //
- Bitmap = ExAllocatePoolWithTag(NonPagedPool,
- (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
- ' mM');
- if (!Bitmap)
- {
- //
- // This is critical
- //
- KeBugCheckEx(INSTALL_MORE_MEMORY,
- MmNumberOfPhysicalPages,
- MmLowestPhysicalPage,
- MmHighestPhysicalPage,
- 0x101);
- }
-
- //
- // Initialize it and clear all the bits to begin with
- //
- RtlInitializeBitMap(&MiPfnBitMap,
- Bitmap,
- MmHighestPhysicalPage + 1);
- RtlClearAllBits(&MiPfnBitMap);
-
- //
- // Loop physical memory runs
- //
- for (i = 0; i < MmPhysicalMemoryBlock->NumberOfRuns; i++)
- {
- //
- // Get the run
- //
- Run = &MmPhysicalMemoryBlock->Run[i];
- DPRINT("PHYSICAL RAM [0x%08p to 0x%08p]\n",
- Run->BasePage << PAGE_SHIFT,
- (Run->BasePage + Run->PageCount) << PAGE_SHIFT);
+ //
+ // Initialize the nonpaged pool
+ //
+ InitializePool(NonPagedPool, 0);
+
+ //
+ // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs!
+ //
+ PointerPte = MiAddressToPte(MmNonPagedSystemStart);
+ OldCount = MmNumberOfSystemPtes;
+ MmNumberOfSystemPtes = MiAddressToPte(MmNonPagedPoolExpansionStart) -
+ PointerPte;
+ MmNumberOfSystemPtes--;
+ DPRINT("Final System PTE count: %d (%d bytes)\n",
+ MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
+
+ //
+ // Create the system PTE space
+ //
+ MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
+
+ //
+ // Get the PDE For hyperspace
+ //
+ StartPde = MiAddressToPde(HYPER_SPACE);
+
+ //
+ // Allocate a page for it and create it
+ //
+ PageFrameIndex = MmAllocPage(MC_SYSTEM, 0);
+ TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
+ TempPde.u.Hard.Global = FALSE; // Hyperspace is local!
+ ASSERT(StartPde->u.Hard.Valid == 0);
+ ASSERT(TempPde.u.Hard.Valid == 1);
+ *StartPde = TempPde;
+
+ //
+ // Zero out the page table now
+ //
+ PointerPte = MiAddressToPte(HYPER_SPACE);
+ RtlZeroMemory(PointerPte, PAGE_SIZE);
+
+ //
+ // Setup the mapping PTEs
+ //
+ MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START);
+ MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
+ MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
- //
- // Make sure it has pages inside it
- //
- if (Run->PageCount)
- {
- //
- // Set the bits in the PFN bitmap
- //
- RtlSetBits(&MiPfnBitMap, Run->BasePage, Run->PageCount);
- }
- }
-
- //
- // Size up paged pool and build the shadow system page directory
- //
- MiBuildPagedPool();
- }
+ //
+ // Reserve system PTEs for zeroing PTEs and clear them
+ //
+ MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES,
+ SystemPteSpace);
+ RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
//
- // Always return success for now
+ // Set the counter to maximum to boot with
//
+ MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
+
return STATUS_SUCCESS;
}
--- /dev/null
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * FILE: ntoskrnl/mm/ARM3/mminit.c
+ * PURPOSE: ARM Memory Manager Initialization
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+#line 15 "ARM³::INIT"
+#define MODULE_INVOLVED_IN_ARM3
+#include "miarm.h"
+
+/* GLOBALS ********************************************************************/
+
+//
+// These are all registry-configurable, but by default, the memory manager will
+// figure out the most appropriate values.
+//
+ULONG MmMaximumNonPagedPoolPercent;
+ULONG MmSizeOfNonPagedPoolInBytes;
+ULONG MmMaximumNonPagedPoolInBytes;
+
+//
+// These numbers describe the discrete equation components of the nonpaged
+// pool sizing algorithm.
+//
+// They are described on http://support.microsoft.com/default.aspx/kb/126402/ja
+// along with the algorithm that uses them, which is implemented later below.
+//
+ULONG MmMinimumNonPagedPoolSize = 256 * 1024;
+ULONG MmMinAdditionNonPagedPoolPerMb = 32 * 1024;
+ULONG MmDefaultMaximumNonPagedPool = 1024 * 1024;
+ULONG MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
+
+//
+// The memory layout (and especially variable names) of the NT kernel mode
+// components can be a bit hard to twig, especially when it comes to the non
+// paged area.
+//
+// There are really two components to the non-paged pool:
+//
+// - The initial nonpaged pool, sized dynamically up to a maximum.
+// - The expansion nonpaged pool, sized dynamically up to a maximum.
+//
+// The initial nonpaged pool is physically continuous for performance, and
+// immediately follows the PFN database, typically sharing the same PDE. It is
+// a very small resource (32MB on a 1GB system), and capped at 128MB.
+//
+// Right now we call this the "ARM³ Nonpaged Pool" and it begins somewhere after
+// the PFN database (which starts at 0xB0000000).
+//
+// The expansion nonpaged pool, on the other hand, can grow much bigger (400MB
+// for a 1GB system). On ARM³ however, it is currently capped at 128MB.
+//
+// The address where the initial nonpaged pool starts is aptly named
+// MmNonPagedPoolStart, and it describes a range of MmSizeOfNonPagedPoolInBytes
+// bytes.
+//
+// Expansion nonpaged pool starts at an address described by the variable called
+// MmNonPagedPoolExpansionStart, and it goes on for MmMaximumNonPagedPoolInBytes
+// minus MmSizeOfNonPagedPoolInBytes bytes, always reaching MmNonPagedPoolEnd
+// (because of the way it's calculated) at 0xFFBE0000.
+//
+// Initial nonpaged pool is allocated and mapped early-on during boot, but what
+// about the expansion nonpaged pool? It is instead composed of special pages
+// which belong to what are called System PTEs. These PTEs are the matter of a
+// later discussion, but they are also considered part of the "nonpaged" OS, due
+// to the fact that they are never paged out -- once an address is described by
+// a System PTE, it is always valid, until the System PTE is torn down.
+//
+// System PTEs are actually composed of two "spaces", the system space proper,
+// and the nonpaged pool expansion space. The latter, as we've already seen,
+// begins at MmNonPagedPoolExpansionStart. Based on the number of System PTEs
+// that the system will support, the remaining address space below this address
+// is used to hold the system space PTEs. This address, in turn, is held in the
+// variable named MmNonPagedSystemStart, which itself is never allowed to go
+// below 0xEB000000 (thus creating an upper bound on the number of System PTEs).
+//
+// This means that 330MB are reserved for total nonpaged system VA, on top of
+// whatever the initial nonpaged pool allocation is.
+//
+// The following URLs, valid as of April 23rd, 2008, support this evidence:
+//
+// http://www.cs.miami.edu/~burt/journal/NT/memory.html
+// http://www.ditii.com/2007/09/28/windows-memory-management-x86-virtual-address-space/
+//
+PVOID MmNonPagedSystemStart;
+PVOID MmNonPagedPoolStart;
+PVOID MmNonPagedPoolExpansionStart;
+PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
+
+//
+// This is where paged pool starts by default
+//
+PVOID MmPagedPoolStart = MI_PAGED_POOL_START;
+PVOID MmPagedPoolEnd;
+
+//
+// And this is its default size
+//
+ULONG MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
+PFN_NUMBER MmSizeOfPagedPoolInPages = MI_MIN_INIT_PAGED_POOLSIZE / PAGE_SIZE;
+
+//
+// Session space starts at 0xBFFFFFFF and grows downwards
+// By default, it includes an 8MB image area where we map win32k and video card
+// drivers, followed by a 4MB area containing the session's working set. This is
+// then followed by a 20MB mapped view area and finally by the session's paged
+// pool, by default 16MB.
+//
+// On a normal system, this results in session space occupying the region from
+// 0xBD000000 to 0xC0000000
+//
+// See miarm.h for the defines that determine the sizing of this region. On an
+// NT system, some of these can be configured through the registry, but we don't
+// support that yet.
+//
+PVOID MiSessionSpaceEnd; // 0xC0000000
+PVOID MiSessionImageEnd; // 0xC0000000
+PVOID MiSessionImageStart; // 0xBF800000
+PVOID MiSessionViewStart; // 0xBE000000
+PVOID MiSessionPoolEnd; // 0xBE000000
+PVOID MiSessionPoolStart; // 0xBD000000
+PVOID MmSessionBase; // 0xBD000000
+ULONG MmSessionSize;
+ULONG MmSessionViewSize;
+ULONG MmSessionPoolSize;
+ULONG MmSessionImageSize;
+
+//
+// The system view space, on the other hand, is where sections that are memory
+// mapped into "system space" end up.
+//
+// By default, it is a 16MB region.
+//
+PVOID MiSystemViewStart;
+ULONG MmSystemViewSize;
+
+//
+// A copy of the system page directory (the page directory associated with the
+// System process) is kept (double-mapped) by the manager in order to lazily
+// map paged pool PDEs into external processes when they fault on a paged pool
+// address.
+//
+PFN_NUMBER MmSystemPageDirectory;
+PMMPTE MmSystemPagePtes;
+
+//
+// The system cache starts right after hyperspace. The first few pages are for
+// keeping track of the system working set list.
+//
+// This should be 0xC0C00000 -- the cache itself starts at 0xC1000000
+//
+PMMWSL MmSystemCacheWorkingSetList = MI_SYSTEM_CACHE_WS_START;
+
+//
+// Windows NT seems to choose between 7000, 11000 and 50000
+// On systems with more than 32MB, this number is then doubled, and further
+// aligned up to a PDE boundary (4MB).
+//
+ULONG MmNumberOfSystemPtes;
+
+//
+// This is how many pages the PFN database will take up
+// In Windows, this includes the Quark Color Table, but not in ARM³
+//
+ULONG MxPfnAllocation;
+
+//
+// Unlike the old ReactOS Memory Manager, ARM³ (and Windows) does not keep track
+// of pages that are not actually valid physical memory, such as ACPI reserved
+// regions, BIOS address ranges, or holes in physical memory address space which
+// could indicate device-mapped I/O memory.
+//
+// In fact, the lack of a PFN entry for a page usually indicates that this is
+// I/O space instead.
+//
+// A bitmap, called the PFN bitmap, keeps track of all page frames by assigning
+// a bit to each. If the bit is set, then the page is valid physical RAM.
+//
+RTL_BITMAP MiPfnBitMap;
+
+//
+// This structure describes the different pieces of RAM-backed address space
+//
+PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
+
+//
+// This is where we keep track of the most basic physical layout markers
+//
+ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage = -1;
+
+//
+// The total number of pages mapped by the boot loader, which include the kernel
+// HAL, boot drivers, registry, NLS files and other loader data structures is
+// kept track of here. This depends on "LoaderPagesSpanned" being correct when
+// coming from the loader.
+//
+// This number is later aligned up to a PDE boundary.
+//
+ULONG MmBootImageSize;
+
+//
+// These three variables keep track of the core separation of address space that
+// exists between kernel mode and user mode.
+//
+ULONG MmUserProbeAddress;
+PVOID MmHighestUserAddress;
+PVOID MmSystemRangeStart;
+
+PVOID MmSystemCacheStart;
+PVOID MmSystemCacheEnd;
+MMSUPPORT MmSystemCacheWs;
+
+//
+// This is where hyperspace ends (followed by the system cache working set)
+//
+PVOID MmHyperSpaceEnd;
+
+//
+// Page coloring algorithm data
+//
+ULONG MmSecondaryColors;
+ULONG MmSecondaryColorMask;
+
+//
+// Actual (registry-configurable) size of a GUI thread's stack
+//
+ULONG MmLargeStackSize;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+//
+// In Bavaria, this is probably a hate crime
+//
+VOID
+FASTCALL
+MiSyncARM3WithROS(IN PVOID AddressStart,
+ IN PVOID AddressEnd)
+{
+ //
+ // Puerile piece of junk-grade carbonized horseshit puss sold to the lowest bidder
+ //
+ ULONG Pde = ADDR_TO_PDE_OFFSET(AddressStart);
+ while (Pde <= ADDR_TO_PDE_OFFSET(AddressEnd))
+ {
+ //
+ // This both odious and heinous
+ //
+ extern ULONG MmGlobalKernelPageDirectory[1024];
+ MmGlobalKernelPageDirectory[Pde] = ((PULONG)PDE_BASE)[Pde];
+ Pde++;
+ }
+}
+
+PFN_NUMBER
+NTAPI
+MiPagesInLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN PBOOLEAN IncludeType)
+{
+ PLIST_ENTRY NextEntry;
+ PFN_NUMBER PageCount = 0;
+ PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
+
+ //
+ // Now loop through the descriptors
+ //
+ NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
+ {
+ //
+ // Grab each one, and check if it's one we should include
+ //
+ MdBlock = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+ if ((MdBlock->MemoryType < LoaderMaximum) &&
+ (IncludeType[MdBlock->MemoryType]))
+ {
+ //
+ // Add this to our running total
+ //
+ PageCount += MdBlock->PageCount;
+ }
+
+ //
+ // Try the next descriptor
+ //
+ NextEntry = MdBlock->ListEntry.Flink;
+ }
+
+ //
+ // Return the total
+ //
+ return PageCount;
+}
+
+PPHYSICAL_MEMORY_DESCRIPTOR
+NTAPI
+MmInitializeMemoryLimits(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN PBOOLEAN IncludeType)
+{
+ PLIST_ENTRY NextEntry;
+ ULONG Run = 0, InitialRuns = 0;
+ PFN_NUMBER NextPage = -1, PageCount = 0;
+ PPHYSICAL_MEMORY_DESCRIPTOR Buffer, NewBuffer;
+ PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
+
+ //
+ // Scan the memory descriptors
+ //
+ NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
+ {
+ //
+ // For each one, increase the memory allocation estimate
+ //
+ InitialRuns++;
+ NextEntry = NextEntry->Flink;
+ }
+
+ //
+ // Allocate the maximum we'll ever need
+ //
+ Buffer = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
+ sizeof(PHYSICAL_MEMORY_RUN) *
+ (InitialRuns - 1),
+ 'lMmM');
+ if (!Buffer) return NULL;
+
+ //
+ // For now that's how many runs we have
+ //
+ Buffer->NumberOfRuns = InitialRuns;
+
+ //
+ // Now loop through the descriptors again
+ //
+ NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
+ {
+ //
+ // Grab each one, and check if it's one we should include
+ //
+ MdBlock = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+ if ((MdBlock->MemoryType < LoaderMaximum) &&
+ (IncludeType[MdBlock->MemoryType]))
+ {
+ //
+ // Add this to our running total
+ //
+ PageCount += MdBlock->PageCount;
+
+ //
+ // Check if the next page is described by the next descriptor
+ //
+ if (MdBlock->BasePage == NextPage)
+ {
+ //
+ // Combine it into the same physical run
+ //
+ ASSERT(MdBlock->PageCount != 0);
+ Buffer->Run[Run - 1].PageCount += MdBlock->PageCount;
+ NextPage += MdBlock->PageCount;
+ }
+ else
+ {
+ //
+ // Otherwise just duplicate the descriptor's contents
+ //
+ Buffer->Run[Run].BasePage = MdBlock->BasePage;
+ Buffer->Run[Run].PageCount = MdBlock->PageCount;
+ NextPage = Buffer->Run[Run].BasePage + Buffer->Run[Run].PageCount;
+
+ //
+ // And in this case, increase the number of runs
+ //
+ Run++;
+ }
+ }
+
+ //
+ // Try the next descriptor
+ //
+ NextEntry = MdBlock->ListEntry.Flink;
+ }
+
+ //
+ // We should not have been able to go past our initial estimate
+ //
+ ASSERT(Run <= Buffer->NumberOfRuns);
+
+ //
+ // Our guess was probably exaggerated...
+ //
+ if (InitialRuns > Run)
+ {
+ //
+ // Allocate a more accurately sized buffer
+ //
+ NewBuffer = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
+ sizeof(PHYSICAL_MEMORY_RUN) *
+ (Run - 1),
+ 'lMmM');
+ if (NewBuffer)
+ {
+ //
+ // Copy the old buffer into the new, then free it
+ //
+ RtlCopyMemory(NewBuffer->Run,
+ Buffer->Run,
+ sizeof(PHYSICAL_MEMORY_RUN) * Run);
+ ExFreePool(Buffer);
+
+ //
+ // Now use the new buffer
+ //
+ Buffer = NewBuffer;
+ }
+ }
+
+ //
+ // Write the final numbers, and return it
+ //
+ Buffer->NumberOfRuns = Run;
+ Buffer->NumberOfPages = PageCount;
+ return Buffer;
+}
+
+VOID
+NTAPI
+MiBuildPagedPool(VOID)
+{
+ PMMPTE PointerPte, PointerPde;
+ MMPTE TempPte = HyperTemplatePte;
+ PFN_NUMBER PageFrameIndex;
+ KIRQL OldIrql;
+ ULONG Size, BitMapSize;
+
+ //
+ // Get the page frame number for the system page directory
+ //
+ PointerPte = MiAddressToPte(PDE_BASE);
+ MmSystemPageDirectory = PFN_FROM_PTE(PointerPte);
+
+ //
+ // Allocate a system PTE which will hold a copy of the page directory
+ //
+ PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
+ ASSERT(PointerPte);
+ MmSystemPagePtes = MiPteToAddress(PointerPte);
+
+ //
+ // Make this system PTE point to the system page directory.
+ // It is now essentially double-mapped. This will be used later for lazy
+ // evaluation of PDEs accross process switches, similarly to how the Global
+ // page directory array in the old ReactOS Mm is used (but in a less hacky
+ // way).
+ //
+ TempPte = HyperTemplatePte;
+ TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory;
+ ASSERT(PointerPte->u.Hard.Valid == 0);
+ ASSERT(TempPte.u.Hard.Valid == 1);
+ *PointerPte = TempPte;
+
+ //
+ // Let's get back to paged pool work: size it up.
+ // By default, it should be twice as big as nonpaged pool.
+ //
+ MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes;
+ if (MmSizeOfPagedPoolInBytes > ((ULONG_PTR)MmNonPagedSystemStart -
+ (ULONG_PTR)MmPagedPoolStart))
+ {
+ //
+ // On the other hand, we have limited VA space, so make sure that the VA
+ // for paged pool doesn't overflow into nonpaged pool VA. Otherwise, set
+ // whatever maximum is possible.
+ //
+ MmSizeOfPagedPoolInBytes = (ULONG_PTR)MmNonPagedSystemStart -
+ (ULONG_PTR)MmPagedPoolStart;
+ }
+
+ //
+ // Get the size in pages and make sure paged pool is at least 32MB.
+ //
+ Size = MmSizeOfPagedPoolInBytes;
+ if (Size < MI_MIN_INIT_PAGED_POOLSIZE) Size = MI_MIN_INIT_PAGED_POOLSIZE;
+ Size = BYTES_TO_PAGES(Size);
+
+ //
+ // Now check how many PTEs will be required for these many pages.
+ //
+ Size = (Size + (1024 - 1)) / 1024;
+
+ //
+ // Recompute the page-aligned size of the paged pool, in bytes and pages.
+ //
+ MmSizeOfPagedPoolInBytes = Size * PAGE_SIZE * 1024;
+ MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
+
+ //
+ // Let's be really sure this doesn't overflow into nonpaged system VA
+ //
+ ASSERT((MmSizeOfPagedPoolInBytes + (ULONG_PTR)MmPagedPoolStart) <=
+ (ULONG_PTR)MmNonPagedSystemStart);
+
+ //
+ // This is where paged pool ends
+ //
+ MmPagedPoolEnd = (PVOID)(((ULONG_PTR)MmPagedPoolStart +
+ MmSizeOfPagedPoolInBytes) - 1);
+
+ //
+ // So now get the PDE for paged pool and zero it out
+ //
+ PointerPde = MiAddressToPde(MmPagedPoolStart);
+ RtlZeroMemory(PointerPde,
+ (1 + MiAddressToPde(MmPagedPoolEnd) - PointerPde) * sizeof(MMPTE));
+
+ //
+ // Next, get the first and last PTE
+ //
+ PointerPte = MiAddressToPte(MmPagedPoolStart);
+ MmPagedPoolInfo.FirstPteForPagedPool = PointerPte;
+ MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
+
+ //
+ // Lock the PFN database
+ //
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ //
+ // Allocate a page and map the first paged pool PDE
+ //
+ PageFrameIndex = MmAllocPage(MC_NPPOOL, 0);
+ TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+ ASSERT(PointerPde->u.Hard.Valid == 0);
+ ASSERT(TempPte.u.Hard.Valid == 1);
+ *PointerPde = TempPte;
+
+ //
+ // Release the PFN database lock
+ //
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ //
+ // We only have one PDE mapped for now... at fault time, additional PDEs
+ // will be allocated to handle paged pool growth. This is where they'll have
+ // to start.
+ //
+ MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde + 1;
+
+ //
+ // We keep track of each page via a bit, so check how big the bitmap will
+ // have to be (make sure to align our page count such that it fits nicely
+ // into a 4-byte aligned bitmap.
+ //
+ // We'll also allocate the bitmap header itself part of the same buffer.
+ //
+ Size = Size * 1024;
+ ASSERT(Size == MmSizeOfPagedPoolInPages);
+ BitMapSize = Size;
+ Size = sizeof(RTL_BITMAP) + (((Size + 31) / 32) * sizeof(ULONG));
+
+ //
+ // Allocate the allocation bitmap, which tells us which regions have not yet
+ // been mapped into memory
+ //
+ MmPagedPoolInfo.PagedPoolAllocationMap = ExAllocatePoolWithTag(NonPagedPool,
+ Size,
+ ' mM');
+ ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
+
+ //
+ // Initialize it such that at first, only the first page's worth of PTEs is
+ // marked as allocated (incidentially, the first PDE we allocated earlier).
+ //
+ RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
+ (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
+ BitMapSize);
+ RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
+ RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 1024);
+
+ //
+ // We have a second bitmap, which keeps track of where allocations end.
+ // Given the allocation bitmap and a base address, we can therefore figure
+ // out which page is the last page of that allocation, and thus how big the
+ // entire allocation is.
+ //
+ MmPagedPoolInfo.EndOfPagedPoolBitmap = ExAllocatePoolWithTag(NonPagedPool,
+ Size,
+ ' mM');
+ ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
+ RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
+ (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
+ BitMapSize);
+
+ //
+ // Since no allocations have been made yet, there are no bits set as the end
+ //
+ RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
+
+ //
+ // Initialize paged pool.
+ //
+ InitializePool(PagedPool, 0);
+
+ //
+ // Initialize the paged pool mutex
+ //
+ KeInitializeGuardedMutex(&MmPagedPoolMutex);
+}
+
+NTSTATUS
+NTAPI
+MmArmInitSystem(IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ ULONG i;
+ BOOLEAN IncludeType[LoaderMaximum];
+ PVOID Bitmap;
+ PPHYSICAL_MEMORY_RUN Run;
+ PFN_NUMBER PageCount;
+
+ //
+ // Instantiate memory that we don't consider RAM/usable
+ // We use the same exclusions that Windows does, in order to try to be
+ // compatible with WinLDR-style booting
+ //
+ for (i = 0; i < LoaderMaximum; i++) IncludeType[i] = TRUE;
+ IncludeType[LoaderBad] = FALSE;
+ IncludeType[LoaderFirmwarePermanent] = FALSE;
+ IncludeType[LoaderSpecialMemory] = FALSE;
+ IncludeType[LoaderBBTMemory] = FALSE;
+ if (Phase == 0)
+ {
+ //
+ // Define the basic user vs. kernel address space separation
+ //
+ MmSystemRangeStart = (PVOID)KSEG0_BASE;
+ MmUserProbeAddress = (ULONG_PTR)MmSystemRangeStart - 0x10000;
+ MmHighestUserAddress = (PVOID)(MmUserProbeAddress - 1);
+
+ //
+ // Get the size of the boot loader's image allocations and then round
+ // that region up to a PDE size, so that any PDEs we might create for
+ // whatever follows are separate from the PDEs that boot loader might've
+ // already created (and later, we can blow all that away if we want to).
+ //
+ MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
+ MmBootImageSize *= PAGE_SIZE;
+ MmBootImageSize = (MmBootImageSize + (4 * 1024 * 1024) - 1) & ~((4 * 1024 * 1024) - 1);
+ ASSERT((MmBootImageSize % (4 * 1024 * 1024)) == 0);
+
+ //
+ // Set the size of session view, pool, and image
+ //
+ MmSessionSize = MI_SESSION_SIZE;
+ MmSessionViewSize = MI_SESSION_VIEW_SIZE;
+ MmSessionPoolSize = MI_SESSION_POOL_SIZE;
+ MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
+
+ //
+ // Set the size of system view
+ //
+ MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
+
+ //
+ // This is where it all ends
+ //
+ MiSessionImageEnd = (PVOID)PTE_BASE;
+
+ //
+ // This is where we will load Win32k.sys and the video driver
+ //
+ MiSessionImageStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
+ MmSessionImageSize);
+
+ //
+ // So the view starts right below the session working set (itself below
+ // the image area)
+ //
+ MiSessionViewStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
+ MmSessionImageSize -
+ MI_SESSION_WORKING_SET_SIZE -
+ MmSessionViewSize);
+
+ //
+ // Session pool follows
+ //
+ MiSessionPoolEnd = MiSessionViewStart;
+ MiSessionPoolStart = (PVOID)((ULONG_PTR)MiSessionPoolEnd -
+ MmSessionPoolSize);
+
+ //
+ // And it all begins here
+ //
+ MmSessionBase = MiSessionPoolStart;
+
+ //
+ // Sanity check that our math is correct
+ //
+ ASSERT((ULONG_PTR)MmSessionBase + MmSessionSize == PTE_BASE);
+
+ //
+ // Session space ends wherever image session space ends
+ //
+ MiSessionSpaceEnd = MiSessionImageEnd;
+
+ //
+ // System view space ends at session space, so now that we know where
+ // this is, we can compute the base address of system view space itself.
+ //
+ MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase -
+ MmSystemViewSize);
+
+ //
+ // Count physical pages on the system
+ //
+ PageCount = MiPagesInLoaderBlock(LoaderBlock, IncludeType);
+
+ //
+ // Check if this is a machine with less than 19MB of RAM
+ //
+ if (PageCount < MI_MIN_PAGES_FOR_SYSPTE_TUNING)
+ {
+ //
+ // Use the very minimum of system PTEs
+ //
+ MmNumberOfSystemPtes = 7000;
+ }
+ else
+ {
+ //
+ // Use the default, but check if we have more than 32MB of RAM
+ //
+ MmNumberOfSystemPtes = 11000;
+ if (PageCount > MI_MIN_PAGES_FOR_SYSPTE_BOOST)
+ {
+ //
+ // Double the amount of system PTEs
+ //
+ MmNumberOfSystemPtes <<= 1;
+ }
+ }
+
+ DPRINT("System PTE count has been tuned to %d (%d bytes)\n",
+ MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
+
+ /* Initialize the platform-specific parts */
+ MiInitMachineDependent(LoaderBlock);
+
+ //
+ // Sync us up with ReactOS Mm
+ //
+ MiSyncARM3WithROS(MmNonPagedSystemStart, (PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1));
+ MiSyncARM3WithROS(MmPfnDatabase, (PVOID)((ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes - 1));
+ MiSyncARM3WithROS((PVOID)HYPER_SPACE, (PVOID)(HYPER_SPACE + PAGE_SIZE - 1));
+
+ //
+ // Build the physical memory block
+ //
+ MmPhysicalMemoryBlock = MmInitializeMemoryLimits(LoaderBlock,
+ IncludeType);
+
+ //
+ // Allocate enough buffer for the PFN bitmap
+ // Align it up to a 32-bit boundary
+ //
+ Bitmap = ExAllocatePoolWithTag(NonPagedPool,
+ (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
+ ' mM');
+ if (!Bitmap)
+ {
+ //
+ // This is critical
+ //
+ KeBugCheckEx(INSTALL_MORE_MEMORY,
+ MmNumberOfPhysicalPages,
+ MmLowestPhysicalPage,
+ MmHighestPhysicalPage,
+ 0x101);
+ }
+
+ //
+ // Initialize it and clear all the bits to begin with
+ //
+ RtlInitializeBitMap(&MiPfnBitMap,
+ Bitmap,
+ MmHighestPhysicalPage + 1);
+ RtlClearAllBits(&MiPfnBitMap);
+
+ //
+ // Loop physical memory runs
+ //
+ for (i = 0; i < MmPhysicalMemoryBlock->NumberOfRuns; i++)
+ {
+ //
+ // Get the run
+ //
+ Run = &MmPhysicalMemoryBlock->Run[i];
+ DPRINT("PHYSICAL RAM [0x%08p to 0x%08p]\n",
+ Run->BasePage << PAGE_SHIFT,
+ (Run->BasePage + Run->PageCount) << PAGE_SHIFT);
+
+ //
+ // Make sure it has pages inside it
+ //
+ if (Run->PageCount)
+ {
+ //
+ // Set the bits in the PFN bitmap
+ //
+ RtlSetBits(&MiPfnBitMap, Run->BasePage, Run->PageCount);
+ }
+ }
+
+ //
+ // Size up paged pool and build the shadow system page directory
+ //
+ MiBuildPagedPool();
+ }
+
+ //
+ // Always return success for now
+ //
+ return STATUS_SUCCESS;
+}
+
+/* EOF */