From ddedfd132a72d8cb96aeca68d1790c4706698a1c Mon Sep 17 00:00:00 2001 From: ReactOS Portable Systems Group Date: Sat, 27 Jun 2009 08:41:45 +0000 Subject: [PATCH] - Reimplement kernel stack allocation (MmCreateKernelStack, MmDeleteKernelStack, MmGrowKernelStack, MmGrowKernelStackEx): - Use System PTEs. - Allocate 12KB stacks with a 4KB guard page, and expand them up to 60KB as required. - Previous implementation always allocated 60KB, without any guard page. - The result is that on a minimal ReactOS install, simply booting up now requires an average of 0.5MB less of physical memory than before. - And once again, optimizations to the system PTE allocation code should significantly improve performance. - Should also analyze benefits of using a dead stack slist as done on Windows. (Assembla Ticket #39). svn path=/trunk/; revision=41636 --- reactos/ntoskrnl/mm/ARM3/procsup.c | 285 +++++++++++++++++++++++ reactos/ntoskrnl/mm/procsup.c | 132 ----------- reactos/ntoskrnl/ntoskrnl-generic.rbuild | 1 + 3 files changed, 286 insertions(+), 132 deletions(-) create mode 100644 reactos/ntoskrnl/mm/ARM3/procsup.c diff --git a/reactos/ntoskrnl/mm/ARM3/procsup.c b/reactos/ntoskrnl/mm/ARM3/procsup.c new file mode 100644 index 00000000000..be05ce67f9e --- /dev/null +++ b/reactos/ntoskrnl/mm/ARM3/procsup.c @@ -0,0 +1,285 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: ntoskrnl/mm/ARM3/procsup.c + * PURPOSE: ARM Memory Manager Process Related Management + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include +#define NDEBUG +#include + +#line 15 "ARM³::PROCSUP" +#define MODULE_INVOLVED_IN_ARM3 +#include "../ARM3/miarm.h" + +ULONG PagesForStacks = 0; + +/* PRIVATE FUNCTIONS **********************************************************/ + +VOID +NTAPI +MmDeleteKernelStack(IN PVOID StackBase, + IN BOOLEAN GuiStack) +{ + PMMPTE PointerPte; + PFN_NUMBER StackPages; + ULONG i; + + // + // This should be the guard page, so decrement by one + // + PointerPte = MiAddressToPte(StackBase); + PointerPte--; + + // + // Calculate pages used + // + StackPages = BYTES_TO_PAGES(GuiStack ? + KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE); + + // + // Loop them + // + for (i = 0; i < StackPages; i++) + { + // + // Check if this is a valid PTE + // + if (PointerPte->u.Hard.Valid == 1) + { + // + // Nuke it + // + MmReleasePageMemoryConsumer(MC_NPPOOL, PFN_FROM_PTE(PointerPte)); + PagesForStacks--; + } + + // + // Next one + // + PointerPte--; + } + + // + // We should be at the guard page now + // + ASSERT(PointerPte->u.Hard.Valid == 0); + + // + // Release the PTEs + // + MiReleaseSystemPtes(PointerPte, StackPages + 1, SystemPteSpace); +} + +PVOID +NTAPI +MmCreateKernelStack(IN BOOLEAN GuiStack, + IN UCHAR Node) +{ + PFN_NUMBER StackPtes, StackPages; + PMMPTE PointerPte, StackPte; + PVOID BaseAddress; + MMPTE TempPte; + KIRQL OldIrql; + PFN_NUMBER PageFrameIndex; + ULONG i; + + // + // Calculate pages needed + // + if (GuiStack) + { + // + // We'll allocate 64KB stack, but only commit 12K + // + StackPtes = BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE); + StackPages = BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT); + + } + else + { + // + // We'll allocate 12K and that's it + // + StackPtes = BYTES_TO_PAGES(KERNEL_STACK_SIZE); + StackPages = StackPtes; + } + + // + // Reserve stack pages, plus a guard page + // + StackPte = MiReserveSystemPtes(StackPtes + 1, SystemPteSpace); + if (!StackPte) return NULL; + + // + // Get the stack address + // + BaseAddress = MiPteToAddress(StackPte + StackPtes + 1); + + // + // Select the right PTE address where we actually start committing pages + // + PointerPte = StackPte; + if (GuiStack) PointerPte += BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE - + KERNEL_LARGE_STACK_COMMIT); + + // + // Setup the template stack PTE + // + TempPte = HyperTemplatePte; + TempPte.u.Hard.Global = FALSE; + TempPte.u.Hard.PageFrameNumber = 0; + TempPte.u.Hard.Dirty = TRUE; + + // + // Acquire the PFN DB lock + // + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + // + // Loop each stack page + // + for (i = 0; i < StackPages; i++) + { + // + // Next PTE + // + PointerPte++; + ASSERT(PointerPte->u.Hard.Valid == 0); + + // + // Get a page + // + PageFrameIndex = MmAllocPage(MC_NPPOOL, 0); + TempPte.u.Hard.PageFrameNumber = PageFrameIndex; + + // + // Write it + // + *PointerPte = TempPte; + PagesForStacks++; + } + + // + // Release the PFN lock + // + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + + // + // Return the stack address + // + return BaseAddress; +} + +NTSTATUS +NTAPI +MmGrowKernelStackEx(IN PVOID StackPointer, + IN ULONG GrowSize) +{ + PKTHREAD Thread = KeGetCurrentThread(); + PMMPTE LimitPte, NewLimitPte, LastPte; + PFN_NUMBER StackPages; + KIRQL OldIrql; + MMPTE TempPte; + PFN_NUMBER PageFrameIndex; + + // + // Make sure the stack did not overflow + // + ASSERT(((ULONG_PTR)Thread->StackBase - (ULONG_PTR)Thread->StackLimit) <= + (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE)); + + // + // Get the current stack limit + // + LimitPte = MiAddressToPte(Thread->StackLimit); + ASSERT(LimitPte->u.Hard.Valid == 1); + + // + // Get the new one and make sure this isn't a retarded request + // + NewLimitPte = MiAddressToPte((PVOID)((ULONG_PTR)StackPointer - GrowSize)); + if (NewLimitPte == LimitPte) return STATUS_SUCCESS; + + // + // Now make sure you're not going past the reserved space + // + LastPte = MiAddressToPte((PVOID)((ULONG_PTR)Thread->StackBase - + KERNEL_LARGE_STACK_SIZE)); + if (NewLimitPte < LastPte) + { + // + // Sorry! + // + DPRINT1("Thread wants too much stack\n"); + return STATUS_STACK_OVERFLOW; + } + + // + // Calculate the number of new pages + // + LimitPte--; + StackPages = (LimitPte - NewLimitPte + 1); + + // + // Setup the template stack PTE + // + TempPte = HyperTemplatePte; + TempPte.u.Hard.Global = FALSE; + TempPte.u.Hard.PageFrameNumber = 0; + TempPte.u.Hard.Dirty = TRUE; + + // + // Acquire the PFN DB lock + // + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + // + // Loop each stack page + // + while (LimitPte >= NewLimitPte) + { + // + // Sanity check + // + ASSERT(LimitPte->u.Hard.Valid == 0); + + // + // Get a page + // + PageFrameIndex = MmAllocPage(MC_NPPOOL, 0); + TempPte.u.Hard.PageFrameNumber = PageFrameIndex; + + // + // Write it + // + *LimitPte-- = TempPte; + } + + // + // Release the PFN lock + // + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + + // + // Set the new limit + // + Thread->StackLimit = (ULONG_PTR)MiPteToAddress(NewLimitPte); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +MmGrowKernelStack(IN PVOID StackPointer) +{ + // + // Call the extended version + // + return MmGrowKernelStackEx(StackPointer, KERNEL_LARGE_STACK_COMMIT); +} + +/* EOF */ diff --git a/reactos/ntoskrnl/mm/procsup.c b/reactos/ntoskrnl/mm/procsup.c index 4dca5d8afa9..3a68aa0e9ad 100644 --- a/reactos/ntoskrnl/mm/procsup.c +++ b/reactos/ntoskrnl/mm/procsup.c @@ -126,38 +126,6 @@ MiCreatePebOrTeb(PEPROCESS Process, return RVA(AllocatedBase, PAGE_SIZE); } -VOID -MiFreeStackPage(PVOID Context, - MEMORY_AREA* MemoryArea, - PVOID Address, - PFN_TYPE Page, - SWAPENTRY SwapEntry, - BOOLEAN Dirty) -{ - ASSERT(SwapEntry == 0); - if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page); -} - -VOID -NTAPI -MmDeleteKernelStack(PVOID StackBase, - BOOLEAN GuiStack) -{ - ULONG StackSize = GuiStack ? KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE; - - /* Lock the Address Space */ - MmLockAddressSpace(MmGetKernelAddressSpace()); - - /* Delete the Stack */ - MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), - (PVOID)((ULONG_PTR)StackBase - StackSize), - MiFreeStackPage, - NULL); - - /* Unlock the Address Space */ - MmUnlockAddressSpace(MmGetKernelAddressSpace()); -} - VOID NTAPI MmDeleteTeb(PEPROCESS Process, @@ -180,106 +148,6 @@ MmDeleteTeb(PEPROCESS Process, MmUnlockAddressSpace(ProcessAddressSpace); } -PVOID -NTAPI -MmCreateKernelStack(BOOLEAN GuiStack, - UCHAR Node) -{ - PMEMORY_AREA StackArea; - ULONG i; - PHYSICAL_ADDRESS BoundaryAddressMultiple; - ULONG StackSize = GuiStack ? KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE; - PFN_TYPE Page[KERNEL_LARGE_STACK_SIZE / PAGE_SIZE]; - PVOID KernelStack = NULL; - NTSTATUS Status; - - /* Initialize the Boundary Address */ - BoundaryAddressMultiple.QuadPart = 0; - - /* Lock the Kernel Address Space */ - MmLockAddressSpace(MmGetKernelAddressSpace()); - - /* Create a MAREA for the Kernel Stack */ - Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), - MEMORY_AREA_KERNEL_STACK, - &KernelStack, - StackSize, - PAGE_READWRITE, - &StackArea, - FALSE, - 0, - BoundaryAddressMultiple); - - /* Unlock the Address Space */ - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - - /* Check for Success */ - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to create thread stack\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - - /* - * Mark the Stack in use. - * Note: Currently we mark all 60KB in use for a GUI Thread. - * We should only do this inside MmGrowKernelStack. TODO! - */ - for (i = 0; i < (StackSize / PAGE_SIZE); i++) - { - Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]); - } - - /* Create a Virtual Mapping for it */ - Status = MmCreateVirtualMapping(NULL, - KernelStack, - PAGE_READWRITE, - Page, - StackSize / PAGE_SIZE); - - /* Check for success */ - if (!NT_SUCCESS(Status)) - { - DPRINT1("Could not create Virtual Mapping for Kernel Stack\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - - /* Return the stack base */ - return (PVOID)((ULONG_PTR)KernelStack + - (GuiStack ? KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE)); -} - -/* - * @implemented - */ -NTSTATUS -NTAPI -MmGrowKernelStack(PVOID StackPointer) -{ - PETHREAD Thread = PsGetCurrentThread(); - - /* Make sure the stack did not overflow */ - ASSERT(((PCHAR)Thread->Tcb.StackBase - (PCHAR)Thread->Tcb.StackLimit) <= - (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE)); - - /* Check if we have reserved space for our grow */ - if ((PCHAR)Thread->Tcb.StackBase - (PCHAR)Thread->Tcb.StackLimit + - KERNEL_STACK_SIZE > KERNEL_LARGE_STACK_SIZE) - { - return STATUS_STACK_OVERFLOW; - } - - /* - * We'll give you three more pages. - * NOTE: See note in MmCreateKernelStack. These pages are already being reserved. - * It would be more efficient to only grow them (commit them) here. - */ - Thread->Tcb.StackLimit -= KERNEL_STACK_SIZE; - - /* Return success */ - return STATUS_SUCCESS; -} - NTSTATUS NTAPI MmCreatePeb(PEPROCESS Process) diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index 2e301fed4d0..854e1ad6e4d 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -364,6 +364,7 @@ init.c iosup.c pool.c + procsup.c syspte.c anonmem.c