From 36a816a58410778104ecfb3f41421fe296e9321a Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Fri, 3 Feb 2012 20:59:35 +0000 Subject: [PATCH] [NTOSKRNL] - Rewrite MmFindGapBottomUp and MmFindGapTopDown, the old versions were broken and were first checking the address range after the first memory area and only used the area below (above) the first memory are when nothing free was found. - Fix an ASSERT, that gets triggered now that the memory areas are created at the "right" locations - Create a memory are for the boot loaded images, which previously could be overwritten happily by new memory areas, which was only prevented by the brokenness of the code - Fix a few memory regions so that they are correct for amd64 builds as well svn path=/trunk/; revision=55397 --- reactos/ntoskrnl/ex/init.c | 2 +- reactos/ntoskrnl/include/internal/i386/mm.h | 1 + reactos/ntoskrnl/mm/marea.c | 237 +++++++++----------- reactos/ntoskrnl/mm/mminit.c | 35 ++- 4 files changed, 135 insertions(+), 140 deletions(-) diff --git a/reactos/ntoskrnl/ex/init.c b/reactos/ntoskrnl/ex/init.c index 5b16e200fdb..f8f2a7400bb 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -331,7 +331,7 @@ ExpInitNls(IN PLOADER_PARAMETER_BLOCK LoaderBlock) } /* Copy the codepage data in its new location. */ - ASSERT(SectionBase > MmSystemRangeStart); + ASSERT(SectionBase >= MmSystemRangeStart); RtlCopyMemory(SectionBase, ExpNlsTableBase, ExpNlsTableSize); /* Free the previously allocated buffer and set the new location */ diff --git a/reactos/ntoskrnl/include/internal/i386/mm.h b/reactos/ntoskrnl/include/internal/i386/mm.h index 4d659d658be..72bbcec2552 100644 --- a/reactos/ntoskrnl/include/internal/i386/mm.h +++ b/reactos/ntoskrnl/include/internal/i386/mm.h @@ -30,6 +30,7 @@ PULONG MmGetPageDirectory(VOID); #define PDE_TOP 0xC0300FFF #define PTE_TOP 0xC03FFFFF #define HYPER_SPACE 0xC0400000 +#define HYPER_SPACE_END 0xC07FFFFF #define PTE_PER_PAGE 0x400 diff --git a/reactos/ntoskrnl/mm/marea.c b/reactos/ntoskrnl/mm/marea.c index 11d7649900a..fab2ce5b037 100644 --- a/reactos/ntoskrnl/mm/marea.c +++ b/reactos/ntoskrnl/mm/marea.c @@ -456,78 +456,68 @@ MmFindGapBottomUp( ULONG_PTR Length, ULONG_PTR Granularity) { - PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart; - PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ? - MmHighestUserAddress : (PVOID)MAXULONG_PTR; - PVOID AlignedAddress; - PMEMORY_AREA Node; - PMEMORY_AREA FirstNode; - PMEMORY_AREA PreviousNode; + ULONG_PTR LowestAddress, HighestAddress, Candidate; + PMEMORY_AREA Root, Node; - DPRINT("LowestAddress: %p HighestAddress: %p\n", - LowestAddress, HighestAddress); + /* Get the margins of the address space */ + if (MmGetAddressSpaceOwner(AddressSpace) != NULL) + { + LowestAddress = MM_LOWEST_USER_ADDRESS; + HighestAddress = (ULONG_PTR)MmHighestUserAddress; + } + else + { + LowestAddress = (ULONG_PTR)MmSystemRangeStart; + HighestAddress = MAXULONG_PTR; + } - AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity); + /* Start with the lowest address */ + Candidate = LowestAddress; - /* Special case for empty tree. */ - if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL) - { - if ((ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length) - { - DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress); - return AlignedAddress; - } - DPRINT("MmFindGapBottomUp: 0\n"); - return 0; - } + /* Check for overflow */ + if ((Candidate + Length) < Candidate) return NULL; - /* Go to the node with lowest address in the tree. */ - FirstNode = Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink); + /* Get the root of the address space tree */ + Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; - /* Traverse the tree from left to right. */ - PreviousNode = Node; - for (;;) - { - Node = MmIterateNextNode(Node); - if (Node == NULL) - break; + /* Go to the node with lowest address in the tree. */ + Node = Root ? MmIterateFirstNode(Root) : NULL; + while (Node && ((ULONG_PTR)Node->EndingAddress < LowestAddress)) + { + Node = MmIterateNextNode(Node); + } - AlignedAddress = MM_ROUND_UP(PreviousNode->EndingAddress, Granularity); - if (AlignedAddress >= LowestAddress) - { - if (Node->StartingAddress > AlignedAddress && - (ULONG_PTR)Node->StartingAddress - (ULONG_PTR)AlignedAddress >= Length) - { - DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress); - ASSERT(AlignedAddress >= LowestAddress); - return AlignedAddress; - } - } - PreviousNode = Node; - } + /* Traverse the tree from low to high addresses */ + while (Node && ((ULONG_PTR)Node->EndingAddress < HighestAddress)) + { + /* Check if the memory area fits before the current node */ + if ((ULONG_PTR)Node->StartingAddress >= (Candidate + Length)) + { + DPRINT("MmFindGapBottomUp: %p\n", Candidate); + ASSERT(Candidate >= LowestAddress); + return (PVOID)Candidate; + } - /* Check if there is enough space after the last memory area. */ - AlignedAddress = MM_ROUND_UP(PreviousNode->EndingAddress, Granularity); - if ((ULONG_PTR)HighestAddress > (ULONG_PTR)AlignedAddress && - (ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length) - { - DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress); - ASSERT(AlignedAddress >= LowestAddress); - return AlignedAddress; - } + /* Calculate next possible adress above this node */ + Candidate = ALIGN_UP_BY((ULONG_PTR)Node->EndingAddress, Granularity); - /* Check if there is enough space before the first memory area. */ - AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity); - if (FirstNode->StartingAddress > AlignedAddress && - (ULONG_PTR)FirstNode->StartingAddress - (ULONG_PTR)AlignedAddress >= Length) - { - DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress); - ASSERT(AlignedAddress >= LowestAddress); - return AlignedAddress; - } + /* Check for overflow */ + if ((Candidate + Length) < (ULONG_PTR)Node->EndingAddress) return NULL; - DPRINT("MmFindGapBottomUp: 0\n"); - return 0; + /* Go to the next higher node */ + Node = MmIterateNextNode(Node); + } + + /* Check if there is enough space after the last memory area. */ + if ((Candidate + Length) <= HighestAddress) + { + DPRINT("MmFindGapBottomUp: %p\n", Candidate); + ASSERT(Candidate >= LowestAddress); + return (PVOID)Candidate; + } + + DPRINT("MmFindGapBottomUp: 0\n"); + return NULL; } @@ -537,81 +527,68 @@ MmFindGapTopDown( ULONG_PTR Length, ULONG_PTR Granularity) { - PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart; - PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ? - (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR; - PVOID AlignedAddress; - PMEMORY_AREA Node; - PMEMORY_AREA PreviousNode; + ULONG_PTR LowestAddress, HighestAddress, Candidate; + PMEMORY_AREA Root, Node; - DPRINT("LowestAddress: %p HighestAddress: %p\n", - LowestAddress, HighestAddress); + /* Get the margins of the address space */ + if (MmGetAddressSpaceOwner(AddressSpace) != NULL) + { + LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS; + HighestAddress = (ULONG_PTR)MmHighestUserAddress; + } + else + { + LowestAddress = (ULONG_PTR)MmSystemRangeStart; + HighestAddress = MAXULONG_PTR; + } - AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)HighestAddress - Length + 1, Granularity); + /* Calculate the highest candidate */ + Candidate = ALIGN_DOWN_BY(HighestAddress + 1 - Length, Granularity); - /* Check for overflow. */ - if (AlignedAddress > HighestAddress) - return NULL; + /* Check for overflow. */ + if (Candidate > HighestAddress) return NULL; - /* Special case for empty tree. */ - if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL) - { - if (AlignedAddress >= LowestAddress) - { - DPRINT("MmFindGapTopDown: %p\n", AlignedAddress); - return AlignedAddress; - } - DPRINT("MmFindGapTopDown: 0\n"); - return 0; - } + /* Get the root of the address space tree */ + Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; - /* Go to the node with highest address in the tree. */ - Node = MmIterateLastNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink); + /* Go to the node with highest address in the tree. */ + Node = Root ? MmIterateLastNode(Root) : NULL; + while (Node && ((ULONG_PTR)Node->StartingAddress > HighestAddress)) + { + Node = MmIteratePrevNode(Node); + } - /* Check if there is enough space after the last memory area. */ - if (Node->EndingAddress <= AlignedAddress) - { - DPRINT("MmFindGapTopDown: %p\n", AlignedAddress); - return AlignedAddress; - } + /* Traverse the tree from high to low addresses */ + while (Node && ((ULONG_PTR)Node->StartingAddress > LowestAddress)) + { + /* Check if the memory area fits after the current node */ + if ((ULONG_PTR)Node->EndingAddress <= Candidate) + { + DPRINT("MmFindGapTopDown: %p\n", Candidate); + return (PVOID)Candidate; + } - /* Traverse the tree from left to right. */ - PreviousNode = Node; - for (;;) - { - Node = MmIteratePrevNode(Node); - if (Node == NULL) - break; + /* Calculate next possible adress below this node */ + Candidate = ALIGN_DOWN_BY((ULONG_PTR)Node->StartingAddress - Length, + Granularity); - AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity); + /* Check for overflow. */ + if (Candidate > (ULONG_PTR)Node->StartingAddress) + return NULL; - /* Check for overflow. */ - if (AlignedAddress > PreviousNode->StartingAddress) - return NULL; + /* Go to the next lower node */ + Node = MmIteratePrevNode(Node); + } - if (Node->EndingAddress <= AlignedAddress) - { - DPRINT("MmFindGapTopDown: %p\n", AlignedAddress); - return AlignedAddress; - } + /* Check if the last candidate is inside the given range */ + if (Candidate >= LowestAddress) + { + DPRINT("MmFindGapTopDown: %p\n", Candidate); + return (PVOID)Candidate; + } - PreviousNode = Node; - } - - AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity); - - /* Check for overflow. */ - if (AlignedAddress > PreviousNode->StartingAddress) - return NULL; - - if (AlignedAddress >= LowestAddress) - { - DPRINT("MmFindGapTopDown: %p\n", AlignedAddress); - return AlignedAddress; - } - - DPRINT("MmFindGapTopDown: 0\n"); - return 0; + DPRINT("MmFindGapTopDown: 0\n"); + return NULL; } @@ -887,7 +864,7 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace, ULONG_PTR tmpLength; PMEMORY_AREA MemoryArea; - DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, " + DPRINT("MmCreateMemoryArea(Type 0x%lx, BaseAddress %p, " "*BaseAddress %p, Length %p, AllocationFlags %x, " "FixedAddress %x, Result %p)\n", Type, BaseAddress, *BaseAddress, Length, AllocationFlags, @@ -922,6 +899,7 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace, if (MmGetAddressSpaceOwner(AddressSpace) && (ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart) { + DPRINT("Memory area for user mode address space exceeds MmSystemRangeStart\n"); return STATUS_ACCESS_VIOLATION; } @@ -1026,8 +1004,9 @@ MmDeleteProcessAddressSpace(PEPROCESS Process) DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process, Process->ImageFileName); +#ifndef _M_AMD64 RemoveEntryList(&Process->MmProcessLinks); - +#endif MmLockAddressSpace(&Process->Vm); while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL) diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index 6f386d25570..c2b09fd8285 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -1,4 +1,4 @@ -/* +/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/mm/mminit.c @@ -44,6 +44,21 @@ MiInitSystemMemoryAreas() NTSTATUS Status; BoundaryAddressMultiple.QuadPart = 0; + // + // Create the memory area to define the loader mappings + // + BaseAddress = (PVOID)KSEG0_BASE; + Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), + MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC, + &BaseAddress, + MmBootImageSize, + PAGE_EXECUTE_READWRITE, + &MArea, + TRUE, + 0, + BoundaryAddressMultiple); + ASSERT(Status == STATUS_SUCCESS); + // // Create the memory area to define the PTE base // @@ -51,7 +66,7 @@ MiInitSystemMemoryAreas() Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC, &BaseAddress, - 4 * 1024 * 1024, + PTE_TOP - PTE_BASE + 1, PAGE_READWRITE, &MArea, TRUE, @@ -66,7 +81,7 @@ MiInitSystemMemoryAreas() Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC, &BaseAddress, - 4 * 1024 * 1024, + HYPER_SPACE_END - HYPER_SPACE + 1, PAGE_READWRITE, &MArea, TRUE, @@ -165,7 +180,7 @@ MiInitSystemMemoryAreas() 0, BoundaryAddressMultiple); ASSERT(Status == STATUS_SUCCESS); - +#ifndef _M_AMD64 // // Next, the KPCR // @@ -180,7 +195,7 @@ MiInitSystemMemoryAreas() 0, BoundaryAddressMultiple); ASSERT(Status == STATUS_SUCCESS); - +#endif // // Now the KUSER_SHARED_DATA // @@ -238,8 +253,8 @@ MiDbgDumpAddressSpace(VOID) // Print the memory layout // DPRINT1(" 0x%p - 0x%p\t%s\n", - MmSystemRangeStart, - (ULONG_PTR)MmSystemRangeStart + MmBootImageSize, + KSEG0_BASE, + (ULONG_PTR)KSEG0_BASE + MmBootImageSize, "Boot Loaded Image"); DPRINT1(" 0x%p - 0x%p\t%s\n", MmPfnDatabase, @@ -258,13 +273,13 @@ MiDbgDumpAddressSpace(VOID) MiSessionSpaceEnd, "Session Space"); DPRINT1(" 0x%p - 0x%p\t%s\n", - PTE_BASE, PDE_BASE, + PTE_BASE, PTE_TOP, "Page Tables"); DPRINT1(" 0x%p - 0x%p\t%s\n", - PDE_BASE, HYPER_SPACE, + PDE_BASE, PDE_TOP, "Page Directories"); DPRINT1(" 0x%p - 0x%p\t%s\n", - HYPER_SPACE, HYPER_SPACE + (4 * 1024 * 1024), + HYPER_SPACE, HYPER_SPACE_END, "Hyperspace"); DPRINT1(" 0x%p - 0x%p\t%s\n", MmPagedPoolStart,