diff --git a/reactos/ntoskrnl/mm/ARM3/contmem.c b/reactos/ntoskrnl/mm/ARM3/contmem.c new file mode 100644 index 00000000000..bc1a18eb3da --- /dev/null +++ b/reactos/ntoskrnl/mm/ARM3/contmem.c @@ -0,0 +1,440 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: ntoskrnl/mm/ARM3/contmem.c + * PURPOSE: ARM Memory Manager Contiguous Memory Allocator + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include +#define NDEBUG +#include + +#line 15 "ARM³::CONTMEM" +#define MODULE_INVOLVED_IN_ARM3 +#include "../ARM3/miarm.h" + +/* PRIVATE FUNCTIONS **********************************************************/ + +PVOID +NTAPI +MiCheckForContiguousMemory(IN PVOID BaseAddress, + IN PFN_NUMBER BaseAddressPages, + IN PFN_NUMBER SizeInPages, + IN PFN_NUMBER LowestPfn, + IN PFN_NUMBER HighestPfn, + IN PFN_NUMBER BoundaryPfn, + IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute) +{ + PMMPTE StartPte, EndPte; + PFN_NUMBER PreviousPage = 0, Page, HighPage, BoundaryMask, Pages = 0; + + // + // Okay, first of all check if the PFNs match our restrictions + // + if (LowestPfn > HighestPfn) return NULL; + if (LowestPfn + SizeInPages <= LowestPfn) return NULL; + if (LowestPfn + SizeInPages - 1 > HighestPfn) return NULL; + if (BaseAddressPages < SizeInPages) return NULL; + + // + // This is the last page we need to get to and the boundary requested + // + HighPage = HighestPfn + 1 - SizeInPages; + BoundaryMask = ~(BoundaryPfn - 1); + + // + // And here's the PTEs for this allocation. Let's go scan them. + // + StartPte = MiAddressToPte(BaseAddress); + EndPte = StartPte + BaseAddressPages; + while (StartPte < EndPte) + { + // + // Get this PTE's page number + // + ASSERT (StartPte->u.Hard.Valid == 1); + Page = PFN_FROM_PTE(StartPte); + + // + // Is this the beginning of our adventure? + // + if (!Pages) + { + // + // Check if this PFN is within our range + // + if ((Page >= LowestPfn) && (Page <= HighPage)) + { + // + // It is! Do you care about boundary (alignment)? + // + if (!(BoundaryPfn) || + (!((Page ^ (Page + SizeInPages - 1)) & BoundaryMask))) + { + // + // You don't care, or you do care but we deliver + // + Pages++; + } + } + + // + // Have we found all the pages we need by now? + // Incidently, this means you only wanted one page + // + if (Pages == SizeInPages) + { + // + // Mission complete + // + return MiPteToAddress(StartPte); + } + } + else + { + // + // Have we found a page that doesn't seem to be contiguous? + // + if (Page != (PreviousPage + 1)) + { + // + // Ah crap, we have to start over + // + Pages = 0; + continue; + } + + // + // Otherwise, we're still in the game. Do we have all our pages? + // + if (++Pages == SizeInPages) + { + // + // We do! This entire range was contiguous, so we'll return it! + // + return MiPteToAddress(StartPte - Pages + 1); + } + } + + // + // Try with the next PTE, remember this PFN + // + PreviousPage = Page; + StartPte++; + continue; + } + + // + // All good returns are within the loop... + // + return NULL; +} + +PVOID +NTAPI +MiFindContiguousMemory(IN PFN_NUMBER LowestPfn, + IN PFN_NUMBER HighestPfn, + IN PFN_NUMBER BoundaryPfn, + IN PFN_NUMBER SizeInPages, + IN MEMORY_CACHING_TYPE CacheType) +{ + PFN_NUMBER Page; + PHYSICAL_ADDRESS PhysicalAddress; + PAGED_CODE (); + ASSERT(SizeInPages != 0); + + // + // Our last hope is to scan the free page list for contiguous pages + // + Page = MiFindContiguousPages(LowestPfn, + HighestPfn, + BoundaryPfn, + SizeInPages, + CacheType); + if (!Page) return NULL; + + // + // We'll just piggyback on the I/O memory mapper + // + PhysicalAddress.QuadPart = Page << PAGE_SHIFT; + return MmMapIoSpace(PhysicalAddress, SizeInPages << PAGE_SHIFT, CacheType); +} + +PVOID +NTAPI +MiAllocateContiguousMemory(IN SIZE_T NumberOfBytes, + IN PFN_NUMBER LowestAcceptablePfn, + IN PFN_NUMBER HighestAcceptablePfn, + IN PFN_NUMBER BoundaryPfn, + IN MEMORY_CACHING_TYPE CacheType) +{ + PVOID BaseAddress; + PFN_NUMBER SizeInPages; + MI_PFN_CACHE_ATTRIBUTE CacheAttribute; + ASSERT(NumberOfBytes != 0); + + // + // Compute size requested + // + SizeInPages = BYTES_TO_PAGES(NumberOfBytes); + + // + // Convert the cache attribute and check for cached requests + // + CacheAttribute = MiPlatformCacheAttributes[FALSE][CacheType]; + if (CacheAttribute == MiCached) + { + // + // Because initial nonpaged pool is supposed to be contiguous, go ahead + // and try making a nonpaged pool allocation first. + // + BaseAddress = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, + NumberOfBytes, + 'mCmM'); + if (BaseAddress) + { + // + // Now make sure it's actually contiguous (if it came from expansion + // it might not be). + // + if (MiCheckForContiguousMemory(BaseAddress, + SizeInPages, + SizeInPages, + LowestAcceptablePfn, + HighestAcceptablePfn, + BoundaryPfn, + CacheAttribute)) + { + // + // Sweet, we're in business! + // + return BaseAddress; + } + + // + // No such luck + // + ExFreePool(BaseAddress); + } + } + + // + // According to MSDN, the system won't try anything else if you're higher + // than APC level. + // + if (KeGetCurrentIrql() > APC_LEVEL) return NULL; + + // + // Otherwise, we'll go try to find some + // + return MiFindContiguousMemory(LowestAcceptablePfn, + HighestAcceptablePfn, + BoundaryPfn, + SizeInPages, + CacheType); +} + +VOID +NTAPI +MiFreeContiguousMemory(IN PVOID BaseAddress) +{ + KIRQL OldIrql; + PFN_NUMBER PageFrameIndex, LastPage, PageCount; + PMMPFN Pfn1, StartPfn; + PAGED_CODE(); + + // + // First, check if the memory came from initial nonpaged pool, or expansion + // + if (((BaseAddress >= MmNonPagedPoolStart) && + (BaseAddress < (PVOID)((ULONG_PTR)MmNonPagedPoolStart + + MmSizeOfNonPagedPoolInBytes))) || + ((BaseAddress >= MmNonPagedPoolExpansionStart) && + (BaseAddress < MmNonPagedPoolEnd))) + { + // + // It did, so just use the pool to free this + // + ExFreePool(BaseAddress); + return; + } + + // + // Otherwise, get the PTE and page number for the allocation + // + PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(BaseAddress)); + + // + // Now get the PFN entry for this, and make sure it's the correct one + // + Pfn1 = MiGetPfnEntry(PageFrameIndex); + if (Pfn1->u3.e1.StartOfAllocation == 0) + { + // + // This probably means you did a free on an address that was in between + // + KeBugCheckEx (BAD_POOL_CALLER, + 0x60, + (ULONG_PTR)BaseAddress, + 0, + 0); + } + + // + // Now this PFN isn't the start of any allocation anymore, it's going out + // + StartPfn = Pfn1; + Pfn1->u3.e1.StartOfAllocation = 0; + + // + // Look the PFNs + // + do + { + // + // Until we find the one that marks the end of the allocation + // + } while (Pfn1++->u3.e1.EndOfAllocation == 0); + + // + // Found it, unmark it + // + Pfn1--; + Pfn1->u3.e1.EndOfAllocation = 0; + + // + // Now compute how many pages this represents + // + PageCount = (ULONG)(Pfn1 - StartPfn + 1); + + // + // So we can know how much to unmap (recall we piggyback on I/O mappings) + // + MmUnmapIoSpace(BaseAddress, PageCount << PAGE_SHIFT); + + // + // Lock the PFN database + // + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + // + // Loop all the pages + // + LastPage = PageFrameIndex + PageCount; + do + { + // + // Free each one, and move on + // + MmReleasePageMemoryConsumer(MC_NPPOOL, PageFrameIndex); + } while (++PageFrameIndex < LastPage); + + // + // Release the PFN lock + // + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +/* + * @implemented + */ +PVOID +NTAPI +MmAllocateContiguousMemorySpecifyCache(IN SIZE_T NumberOfBytes, + IN PHYSICAL_ADDRESS LowestAcceptableAddress OPTIONAL, + IN PHYSICAL_ADDRESS HighestAcceptableAddress, + IN PHYSICAL_ADDRESS BoundaryAddressMultiple OPTIONAL, + IN MEMORY_CACHING_TYPE CacheType OPTIONAL) +{ + PFN_NUMBER LowestPfn, HighestPfn, BoundaryPfn; + ASSERT (NumberOfBytes != 0); + + // + // Convert the lowest address into a PFN + // + LowestPfn = (PFN_NUMBER)(LowestAcceptableAddress.QuadPart >> PAGE_SHIFT); + if (BYTE_OFFSET(LowestAcceptableAddress.LowPart)) LowestPfn++; + + // + // Convert and validate the boundary address into a PFN + // + if (BYTE_OFFSET(BoundaryAddressMultiple.LowPart)) return NULL; + BoundaryPfn = (PFN_NUMBER)(BoundaryAddressMultiple.QuadPart >> PAGE_SHIFT); + + // + // Convert the highest address into a PFN + // + HighestPfn = (PFN_NUMBER)(HighestAcceptableAddress.QuadPart >> PAGE_SHIFT); + if (HighestPfn > MmHighestPhysicalPage) HighestPfn = MmHighestPhysicalPage; + + // + // Validate the PFN bounds + // + if (LowestPfn > HighestPfn) return NULL; + + // + // Let the contiguous memory allocator handle it + // + return MiAllocateContiguousMemory(NumberOfBytes, + LowestPfn, + HighestPfn, + BoundaryPfn, + CacheType); +} + +/* + * @implemented + */ +PVOID +NTAPI +MmAllocateContiguousMemory(IN ULONG NumberOfBytes, + IN PHYSICAL_ADDRESS HighestAcceptableAddress) +{ + PFN_NUMBER HighestPfn; + + // + // Convert and normalize the highest address into a PFN + // + HighestPfn = (PFN_NUMBER)(HighestAcceptableAddress.QuadPart >> PAGE_SHIFT); + if (HighestPfn > MmHighestPhysicalPage) HighestPfn = MmHighestPhysicalPage; + + // + // Let the contiguous memory allocator handle it + // + return MiAllocateContiguousMemory(NumberOfBytes, 0, HighestPfn, 0, MmCached); +} + +/* + * @implemented + */ +VOID +NTAPI +MmFreeContiguousMemory(IN PVOID BaseAddress) +{ + // + // Let the contiguous memory allocator handle it + // + MiFreeContiguousMemory(BaseAddress); +} + +/* + * @implemented + */ +VOID +NTAPI +MmFreeContiguousMemorySpecifyCache(IN PVOID BaseAddress, + IN ULONG NumberOfBytes, + IN MEMORY_CACHING_TYPE CacheType) +{ + // + // Just call the non-cached version (there's no cache issues for freeing) + // + MiFreeContiguousMemory(BaseAddress); +} + +/* EOF */ diff --git a/reactos/ntoskrnl/mm/ARM3/miarm.h b/reactos/ntoskrnl/mm/ARM3/miarm.h index aa9850b649d..9708f2e0733 100644 --- a/reactos/ntoskrnl/mm/ARM3/miarm.h +++ b/reactos/ntoskrnl/mm/ARM3/miarm.h @@ -47,8 +47,10 @@ extern ULONG MmSizeOfNonPagedPoolInBytes; extern ULONG MmMaximumNonPagedPoolInBytes; extern PVOID MmNonPagedPoolStart; extern PVOID MmNonPagedPoolExpansionStart; +extern PVOID MmNonPagedPoolEnd; extern PMMPTE MmFirstReservedMappingPte, MmLastReservedMappingPte; extern PMMPTE MiFirstReservedZeroingPte; +extern MI_PFN_CACHE_ATTRIBUTE MiPlatformCacheAttributes[2][MmMaximumCacheType]; extern PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock; VOID @@ -80,4 +82,27 @@ MiReleaseSystemPtes( IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType ); + +PFN_NUMBER +NTAPI +MiFindContiguousPages( + IN PFN_NUMBER LowestPfn, + IN PFN_NUMBER HighestPfn, + IN PFN_NUMBER BoundaryPfn, + IN PFN_NUMBER SizeInPages, + IN MEMORY_CACHING_TYPE CacheType +); + +PVOID +NTAPI +MiCheckForContiguousMemory( + IN PVOID BaseAddress, + IN PFN_NUMBER BaseAddressPages, + IN PFN_NUMBER SizeInPages, + IN PFN_NUMBER LowestPfn, + IN PFN_NUMBER HighestPfn, + IN PFN_NUMBER BoundaryPfn, + IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute +); + /* EOF */ diff --git a/reactos/ntoskrnl/mm/cont.c b/reactos/ntoskrnl/mm/cont.c deleted file mode 100644 index 577e1ca8ea9..00000000000 --- a/reactos/ntoskrnl/mm/cont.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/mm/cont.c - * PURPOSE: Manages continuous memory - * - * PROGRAMMERS: David Welch (welch@cwcom.net) - */ - -/* INCLUDES *****************************************************************/ - -#include -#define NDEBUG -#include - -/* FUNCTIONS *****************************************************************/ - -static VOID -MmFreeContinuousPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, - PFN_TYPE Page, SWAPENTRY SwapEntry, - BOOLEAN Dirty) -{ - ASSERT(SwapEntry == 0); - if (Page != 0) - { - MmReleasePageMemoryConsumer(MC_NPPOOL, Page); - } -} - -/********************************************************************** - * NAME EXPORTED - * MmAllocateContiguousMemorySpecifyCache@32 - * - * DESCRIPTION - * Allocates a range of physically contiguous memory - * with a cache parameter. - * - * ARGUMENTS - * NumberOfBytes - * Size of the memory block to allocate; - * - * LowestAcceptableAddress - * Lowest address valid for the caller. - * - * HighestAcceptableAddress - * Highest address valid for the caller. - * - * BoundaryAddressMultiple - * Address multiple not to be crossed by allocated buffer (optional). - * - * CacheType - * Type of caching to use. - * - * RETURN VALUE - * The virtual address of the memory block on success; - * NULL on error. - * - * REVISIONS - * - * @implemented - */ -PVOID NTAPI -MmAllocateContiguousMemorySpecifyCache(IN SIZE_T NumberOfBytes, - IN PHYSICAL_ADDRESS LowestAcceptableAddress OPTIONAL, - IN PHYSICAL_ADDRESS HighestAcceptableAddress, - IN PHYSICAL_ADDRESS BoundaryAddressMultiple OPTIONAL, - IN MEMORY_CACHING_TYPE CacheType OPTIONAL) -{ - PMEMORY_AREA MArea; - NTSTATUS Status; - PVOID BaseAddress = NULL; - PFN_TYPE PBase; - ULONG Protect; - ULONG i; - - Protect = PAGE_EXECUTE_READWRITE | PAGE_SYSTEM; - if (CacheType == MmNonCached || CacheType == MmWriteCombined) - { - Protect |= PAGE_NOCACHE; - } - if (CacheType == MmWriteCombined) - { - Protect |= PAGE_WRITECOMBINE; - } - - MmLockAddressSpace(MmGetKernelAddressSpace()); - Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), - MEMORY_AREA_CONTINUOUS_MEMORY, - &BaseAddress, - NumberOfBytes, - PAGE_READWRITE, - &MArea, - FALSE, - 0, - RtlConvertLongToLargeInteger(0)); - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - - if (!NT_SUCCESS(Status)) - { - return(NULL); - } - DPRINT( "Base = %x\n", BaseAddress ); - PBase = MmGetContinuousPages(NumberOfBytes, - LowestAcceptableAddress, - HighestAcceptableAddress, - BoundaryAddressMultiple, - TRUE); - if (PBase == 0) - { - MmLockAddressSpace(MmGetKernelAddressSpace()); - MmFreeMemoryArea(MmGetKernelAddressSpace(), - MArea, - NULL, - NULL); - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - return(NULL); - } - for (i = 0; i < (PAGE_ROUND_UP(NumberOfBytes) / PAGE_SIZE); i++, PBase++) - { - MmCreateVirtualMapping(NULL, - (char*)BaseAddress + (i * PAGE_SIZE), - Protect, - &PBase, - 1); - } - return(BaseAddress); -} - -/********************************************************************** - * NAME EXPORTED - * MmAllocateContiguousMemory@12 - * - * DESCRIPTION - * Allocates a range of physically contiguous cache aligned - * memory from the non-paged pool. - * - * ARGUMENTS - * NumberOfBytes - * Size of the memory block to allocate; - * - * HighestAcceptableAddress - * Highest address valid for the caller. - * - * RETURN VALUE - * The virtual address of the memory block on success; - * NULL on error. - * - * NOTE - * Description taken from include/ddk/mmfuncs.h. - * Code taken from ntoskrnl/mm/special.c. - * - * REVISIONS - * - * @implemented - */ -PVOID NTAPI -MmAllocateContiguousMemory (IN ULONG NumberOfBytes, - IN PHYSICAL_ADDRESS HighestAcceptableAddress) -{ - return MmAllocateContiguousMemorySpecifyCache(NumberOfBytes, - RtlConvertLongToLargeInteger(0), - HighestAcceptableAddress, - RtlConvertLongToLargeInteger(0), - MmCached); -} - - -/********************************************************************** - * NAME EXPORTED - * MmFreeContiguousMemory@4 - * - * DESCRIPTION - * Releases a range of physically contiguous memory allocated - * with MmAllocateContiguousMemory. - * - * ARGUMENTS - * BaseAddress - * Virtual address of the memory to be freed. - * - * RETURN VALUE - * None. - * - * NOTE - * Description taken from include/ddk/mmfuncs.h. - * Code taken from ntoskrnl/mm/special.c. - * - * REVISIONS - * - * @implemented - */ -VOID NTAPI -MmFreeContiguousMemory(IN PVOID BaseAddress) -{ - MmLockAddressSpace(MmGetKernelAddressSpace()); - MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), - BaseAddress, - MmFreeContinuousPage, - NULL); - MmUnlockAddressSpace(MmGetKernelAddressSpace()); -} - -/********************************************************************** - * NAME EXPORTED - * MmFreeContiguousMemorySpecifyCache@12 - * - * DESCRIPTION - * Releases a range of physically contiguous memory allocated - * with MmAllocateContiguousMemorySpecifyCache. - * - * ARGUMENTS - * BaseAddress - * Virtual address of the memory to be freed. - * - * NumberOfBytes - * Size of the memory block to free. - * - * CacheType - * Type of caching used. - * - * RETURN VALUE - * None. - * - * REVISIONS - * - * @implemented - */ -VOID NTAPI -MmFreeContiguousMemorySpecifyCache(IN PVOID BaseAddress, - IN ULONG NumberOfBytes, - IN MEMORY_CACHING_TYPE CacheType) -{ - MmLockAddressSpace(MmGetKernelAddressSpace()); - MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), - BaseAddress, - MmFreeContinuousPage, - NULL); - MmUnlockAddressSpace(MmGetKernelAddressSpace()); -} - - -/* EOF */ diff --git a/reactos/ntoskrnl/mm/freelist.c b/reactos/ntoskrnl/mm/freelist.c index 020de2cb440..ab83236deaf 100644 --- a/reactos/ntoskrnl/mm/freelist.c +++ b/reactos/ntoskrnl/mm/freelist.c @@ -18,6 +18,8 @@ #pragma alloc_text(INIT, MmInitializePageList) #endif +#define MODULE_INVOLVED_IN_ARM3 +#include "ARM3/miarm.h" /* TYPES *******************************************************************/ @@ -237,6 +239,206 @@ MmGetContinuousPages(ULONG NumberOfBytes, return 0; } +PFN_NUMBER +NTAPI +MiFindContiguousPages(IN PFN_NUMBER LowestPfn, + IN PFN_NUMBER HighestPfn, + IN PFN_NUMBER BoundaryPfn, + IN PFN_NUMBER SizeInPages, + IN MEMORY_CACHING_TYPE CacheType) +{ + PFN_NUMBER Page, PageCount, LastPage, Length, BoundaryMask; + ULONG i = 0; + PMMPFN Pfn1, EndPfn; + KIRQL OldIrql; + PAGED_CODE (); + ASSERT(SizeInPages != 0); + + // + // Convert the boundary PFN into an alignment mask + // + BoundaryMask = ~(BoundaryPfn - 1); + + // + // Loop all the physical memory blocks + // + do + { + // + // Capture the base page and length of this memory block + // + Page = MmPhysicalMemoryBlock->Run[i].BasePage; + PageCount = MmPhysicalMemoryBlock->Run[i].PageCount; + + // + // Check how far this memory block will go + // + LastPage = Page + PageCount; + + // + // Trim it down to only the PFNs we're actually interested in + // + if ((LastPage - 1) > HighestPfn) LastPage = HighestPfn + 1; + if (Page < LowestPfn) Page = LowestPfn; + + // + // Skip this run if it's empty or fails to contain all the pages we need + // + if (!(PageCount) || ((Page + SizeInPages) > LastPage)) continue; + + // + // Now scan all the relevant PFNs in this run + // + Length = 0; + for (Pfn1 = MiGetPfnEntry(Page); Page < LastPage; Page++, Pfn1++) + { + // + // If this PFN is in use, ignore it + // + if (Pfn1->Flags.Type != MM_PHYSICAL_PAGE_FREE) continue; + + // + // If we haven't chosen a start PFN yet and the caller specified an + // alignment, make sure the page matches the alignment restriction + // + if ((!(Length) && (BoundaryPfn)) && + (((Page ^ (Page + SizeInPages - 1)) & BoundaryMask))) + { + // + // It does not, so bail out + // + continue; + } + + // + // Increase the number of valid pages, and check if we have enough + // + if (++Length == SizeInPages) + { + // + // It appears we've amassed enough legitimate pages, rollback + // + Pfn1 -= (Length - 1); + Page -= (Length - 1); + + // + // Acquire the PFN lock + // + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + do + { + // + // Things might've changed for us. Is the page still free? + // + if (Pfn1->Flags.Type != MM_PHYSICAL_PAGE_FREE) break; + + // + // So far so good. Is this the last confirmed valid page? + // + if (!--Length) + { + // + // Sanity check that we didn't go out of bounds + // + ASSERT(i != MmPhysicalMemoryBlock->NumberOfRuns); + + // + // Loop until all PFN entries have been processed + // + EndPfn = Pfn1 - SizeInPages + 1; + do + { + // + // If this was an unzeroed page, there are now less + // + if (Pfn1->Flags.Zero == 0) UnzeroedPageCount--; + + // + // One less free page, one more system page + // + MmStats.NrFreePages--; + MmStats.NrSystemPages++; + + // + // This PFN is now a used page, set it up + // + RemoveEntryList(&Pfn1->ListEntry); + Pfn1->Flags.Type = MM_PHYSICAL_PAGE_USED; + Pfn1->Flags.Consumer = MC_NPPOOL; + Pfn1->ReferenceCount = 1; + Pfn1->LockCount = 0; + Pfn1->MapCount = 0; + Pfn1->SavedSwapEntry = 0; + + // + // Check if it was already zeroed + // + if (Pfn1->Flags.Zero == 0) + { + // + // It wasn't, so zero it + // + MiZeroPage(MiGetPfnEntryIndex(Pfn1)); + } + + // + // Check if this is the last PFN, otherwise go on + // + if (Pfn1 == EndPfn) break; + Pfn1--; + } while (TRUE); + + // + // Mark the first and last PFN so we can find them later + // + Pfn1->Flags.StartOfAllocation = 1; + (Pfn1 + SizeInPages - 1)->Flags.EndOfAllocation = 1; + + // + // Now it's safe to let go of the PFN lock + // + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + + // + // Quick sanity check that the last PFN is consistent + // + EndPfn = Pfn1 + SizeInPages; + ASSERT(EndPfn == MiGetPfnEntry(Page + 1)); + + // + // Compute the first page, and make sure it's consistent + // + Page -= SizeInPages - 1; + ASSERT(Pfn1 == MiGetPfnEntry(Page)); + ASSERT(Page != 0); + return Page; + } + + // + // Keep going. The purpose of this loop is to reconfirm that + // after acquiring the PFN lock these pages are still usable + // + Pfn1++; + Page++; + } while (TRUE); + + // + // If we got here, something changed while we hadn't acquired + // the PFN lock yet, so we'll have to restart + // + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + Length = 0; + } + } + } while (++i != MmPhysicalMemoryBlock->NumberOfRuns); + + + // + // And if we get here, it means no suitable physical memory runs were found + // + return 0; +} + PFN_TYPE NTAPI MmAllocEarlyPage(VOID) diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index cb0d4c6d7c5..07dcc17bd67 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -360,6 +360,7 @@ + contmem.c dynamic.c hypermap.c init.c @@ -370,7 +371,6 @@ anonmem.c balance.c - cont.c dbgpool.c drvlck.c freelist.c