diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index b9799c40f64..a905b96ed80 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -257,7 +257,7 @@ typedef struct _MEMORY_AREA ULONG Protect; ULONG Flags; BOOLEAN DeleteInProgress; - ULONG PageOpCount; + ULONG Magic; PVOID Vad; union { @@ -586,6 +586,15 @@ MmMapMemoryArea(PVOID BaseAddress, ULONG Consumer, ULONG Protection); +VOID +NTAPI +MiRosCheckMemoryAreas( + PMMSUPPORT AddressSpace); + +VOID +NTAPI +MiCheckAllProcessMemoryAreas(VOID); + /* npool.c *******************************************************************/ VOID @@ -1748,3 +1757,13 @@ MmGetKernelAddressSpace(VOID) { return MmKernelAddressSpace; } + + +/* expool.c ******************************************************************/ + +VOID +NTAPI +ExpCheckPoolAllocation( + PVOID P, + POOL_TYPE PoolType, + ULONG Tag); diff --git a/reactos/ntoskrnl/kdbg/kdb.h b/reactos/ntoskrnl/kdbg/kdb.h index 1872377e96a..55c6698f29b 100644 --- a/reactos/ntoskrnl/kdbg/kdb.h +++ b/reactos/ntoskrnl/kdbg/kdb.h @@ -114,6 +114,12 @@ KdbpPrint( IN PCHAR Format, IN ... OPTIONAL); +BOOLEAN +NTAPI +KdbpGetHexNumber( + IN PCHAR pszNum, + OUT ULONG_PTR *pulValue); + /* from kdb_expr.c */ BOOLEAN diff --git a/reactos/ntoskrnl/kdbg/kdb_cli.c b/reactos/ntoskrnl/kdbg/kdb_cli.c index ec0e53f89e3..e7d04517647 100644 --- a/reactos/ntoskrnl/kdbg/kdb_cli.c +++ b/reactos/ntoskrnl/kdbg/kdb_cli.c @@ -90,6 +90,8 @@ static BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]); static BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]); static BOOLEAN KdbpCmdDmesg(ULONG Argc, PCHAR Argv[]); +BOOLEAN ExpKdbgExtPool(ULONG Argc, PCHAR Argv[]); + #ifdef __ROS_DWARF__ static BOOLEAN KdbpCmdPrintStruct(ULONG Argc, PCHAR Argv[]); #endif @@ -178,7 +180,8 @@ static const struct { "set", "set [var] [value]", "Sets var to value or displays value of var.", KdbpCmdSet }, { "dmesg", "dmesg", "Display debug messages on screen, with navigation on pages.", KdbpCmdDmesg }, { "kmsg", "kmsg", "Kernel dmesg. Alias for dmesg.", KdbpCmdDmesg }, - { "help", "help", "Display help screen.", KdbpCmdHelp } + { "help", "help", "Display help screen.", KdbpCmdHelp }, + { "!pool", "!pool [Address [Flags]]", "Display information about pool allocations.", ExpKdbgExtPool } }; /* FUNCTIONS *****************************************************************/ @@ -403,6 +406,24 @@ KdbpEvaluateExpression( return Ok; } +BOOLEAN +NTAPI +KdbpGetHexNumber( + IN PCHAR pszNum, + OUT ULONG_PTR *pulValue) +{ + char *endptr; + + /* Skip optional '0x' prefix */ + if ((pszNum[0] == '0') && ((pszNum[1] == 'x') || (pszNum[1] == 'X'))) + pszNum += 2; + + /* Make a number from the string (hex) */ + *pulValue = strtoul(pszNum, &endptr, 16); + + return (*endptr == '\0'); +} + /*!\brief Evaluates an expression and displays the result. */ static BOOLEAN diff --git a/reactos/ntoskrnl/mm/ARM3/expool.c b/reactos/ntoskrnl/mm/ARM3/expool.c index d496345e5d8..39e3cccb7ed 100644 --- a/reactos/ntoskrnl/mm/ARM3/expool.c +++ b/reactos/ntoskrnl/mm/ARM3/expool.c @@ -281,6 +281,86 @@ ExpCheckPoolHeader(IN PPOOL_HEADER Entry) } } +VOID +NTAPI +ExpCheckPoolAllocation( + PVOID P, + POOL_TYPE PoolType, + ULONG Tag) +{ + PPOOL_HEADER Entry; + ULONG i; + KIRQL OldIrql; + POOL_TYPE RealPoolType; + + /* Get the pool header */ + Entry = ((PPOOL_HEADER)P) - 1; + + /* Check if this is a large allocation */ + if (PAGE_ALIGN(P) == P) + { + /* Lock the pool table */ + KeAcquireSpinLock(&ExpLargePoolTableLock, &OldIrql); + + /* Find the pool tag */ + for (i = 0; i < PoolBigPageTableSize; i++) + { + /* Check if this is our allocation */ + if (PoolBigPageTable[i].Va == P) + { + /* Make sure the tag is ok */ + if (PoolBigPageTable[i].Key != Tag) + { + KeBugCheckEx(BAD_POOL_CALLER, 0x0A, (ULONG_PTR)P, PoolBigPageTable[i].Key, Tag); + } + + break; + } + } + + /* Release the lock */ + KeReleaseSpinLock(&ExpLargePoolTableLock, OldIrql); + + if (i == PoolBigPageTableSize) + { + /* Did not find the allocation */ + //ASSERT(FALSE); + } + + /* Get Pool type by address */ + RealPoolType = MmDeterminePoolType(P); + } + else + { + /* Verify the tag */ + if (Entry->PoolTag != Tag) + { + DPRINT1("Allocation has wrong pool tag! Expected '%.4s', got '%.4s' (0x%08lx)\n", + &Tag, &Entry->PoolTag, Entry->PoolTag); + KeBugCheckEx(BAD_POOL_CALLER, 0x0A, (ULONG_PTR)P, Entry->PoolTag, Tag); + } + + /* Check the rest of the header */ + ExpCheckPoolHeader(Entry); + + /* Get Pool type from entry */ + RealPoolType = (Entry->PoolType - 1); + } + + /* Should we check the pool type? */ + if (PoolType != -1) + { + /* Verify the pool type */ + if (RealPoolType != PoolType) + { + DPRINT1("Wrong pool type! Expected %s, got %s\n", + PoolType & BASE_POOL_TYPE_MASK ? "PagedPool" : "NonPagedPool", + (Entry->PoolType - 1) & BASE_POOL_TYPE_MASK ? "PagedPool" : "NonPagedPool"); + KeBugCheckEx(BAD_POOL_CALLER, 0xCC, (ULONG_PTR)P, Entry->PoolTag, Tag); + } + } +} + VOID NTAPI ExpCheckPoolBlocks(IN PVOID Block) @@ -2436,4 +2516,101 @@ ExAllocatePoolWithQuotaTag(IN POOL_TYPE PoolType, return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag); } + +BOOLEAN +ExpKdbgExtPool( + ULONG Argc, + PCHAR Argv[]) +{ + ULONG_PTR Address = 0, Flags = 0; + PVOID PoolPage; + PPOOL_HEADER Entry; + BOOLEAN ThisOne; + PULONG Data; + + if (Argc > 1) + { + /* Get address */ + if (!KdbpGetHexNumber(Argv[1], &Address)) + { + KdbpPrint("Invalid parameter: %s\n", Argv[0]); + return TRUE; + } + } + + if (Argc > 2) + { + /* Get address */ + if (!KdbpGetHexNumber(Argv[1], &Flags)) + { + KdbpPrint("Invalid parameter: %s\n", Argv[0]); + return TRUE; + } + } + + /* Check if we got an address */ + if (Address != 0) + { + /* Get the base page */ + PoolPage = PAGE_ALIGN(Address); + } + else + { + KdbpPrint("Heap is unimplemented\n"); + return TRUE; + } + + /* No paging support! */ + if (!MmIsAddressValid(PoolPage)) + { + KdbpPrint("Address not accessible!\n"); + return TRUE; + } + + /* Get pool type */ + if ((Address >= (ULONG_PTR)MmPagedPoolStart) && (Address <= (ULONG_PTR)MmPagedPoolEnd)) + KdbpPrint("Allocation is from PagedPool region\n"); + else if ((Address >= (ULONG_PTR)MmNonPagedPoolStart) && (Address <= (ULONG_PTR)MmNonPagedPoolEnd)) + KdbpPrint("Allocation is from NonPagedPool region\n"); + else + { + KdbpPrint("Address 0x%p is not within any pool!\n", (PVOID)Address); + return TRUE; + } + + /* Loop all entries of that page */ + Entry = PoolPage; + do + { + /* Check if the address is within that entry */ + ThisOne = ((Address >= (ULONG_PTR)Entry) && + (Address < (ULONG_PTR)(Entry + Entry->BlockSize))); + + if (!(Flags & 1) || ThisOne) + { + /* Print the line */ + KdbpPrint("%c%p size: %4d previous size: %4d %s %.4s\n", + ThisOne ? '*' : ' ', Entry, Entry->BlockSize, Entry->PreviousSize, + (Flags & 0x80000000) ? "" : (Entry->PoolType ? "(Allocated)" : "(Free) "), + (Flags & 0x80000000) ? "" : (PCHAR)&Entry->PoolTag); + } + + if (Flags & 1) + { + Data = (PULONG)(Entry + 1); + KdbpPrint(" %p %08lx %08lx %08lx %08lx\n" + " %p %08lx %08lx %08lx %08lx\n", + &Data[0], Data[0], Data[1], Data[2], Data[3], + &Data[4], Data[4], Data[5], Data[6], Data[7]); + } + + /* Go to next entry */ + Entry = POOL_BLOCK(Entry, Entry->BlockSize); + } + while ((Entry->BlockSize != 0) && ((ULONG_PTR)Entry < (ULONG_PTR)PoolPage + PAGE_SIZE)); + + return TRUE; +} + + /* EOF */ diff --git a/reactos/ntoskrnl/mm/marea.c b/reactos/ntoskrnl/mm/marea.c index 9ecaeb91883..aae43d6f19e 100644 --- a/reactos/ntoskrnl/mm/marea.c +++ b/reactos/ntoskrnl/mm/marea.c @@ -401,7 +401,7 @@ MmInsertMemoryArea( Vad->u.VadFlags.Spare = 1; Vad->u.VadFlags.PrivateMemory = 1; Vad->u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect); - + /* Insert the VAD */ MiInsertVad(Vad, Process); marea->Vad = Vad; @@ -676,6 +676,100 @@ NTAPI MiRemoveNode(IN PMMADDRESS_NODE Node, IN PMM_AVL_TABLE Table); +#if DBG + +static +VOID +MiRosCheckMemoryAreasRecursive( + PMEMORY_AREA Node) +{ + /* Check if the allocation is ok */ + ExpCheckPoolAllocation(Node, NonPagedPool, 'ERAM'); + + /* Check some fields */ + ASSERT(Node->Magic == 'erAM'); + ASSERT(PAGE_ALIGN(Node->StartingAddress) == Node->StartingAddress); + ASSERT(Node->EndingAddress != NULL); + ASSERT(PAGE_ALIGN(Node->EndingAddress) == Node->EndingAddress); + ASSERT((ULONG_PTR)Node->StartingAddress < (ULONG_PTR)Node->EndingAddress); + ASSERT((Node->Type == 0) || + (Node->Type == MEMORY_AREA_CACHE) || + // (Node->Type == MEMORY_AREA_CACHE_SEGMENT) || + (Node->Type == MEMORY_AREA_SECTION_VIEW) || + (Node->Type == MEMORY_AREA_OWNED_BY_ARM3) || + (Node->Type == (MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC))); + + /* Recursively check children */ + if (Node->LeftChild != NULL) + MiRosCheckMemoryAreasRecursive(Node->LeftChild); + if (Node->RightChild != NULL) + MiRosCheckMemoryAreasRecursive(Node->RightChild); +} + +VOID +NTAPI +MiRosCheckMemoryAreas( + PMMSUPPORT AddressSpace) +{ + PMEMORY_AREA RootNode; + PEPROCESS AddressSpaceOwner; + BOOLEAN NeedReleaseLock; + + NeedReleaseLock = FALSE; + + /* Get the address space owner */ + AddressSpaceOwner = CONTAINING_RECORD(AddressSpace, EPROCESS, Vm); + + /* Check if we already own the address space lock */ + if (AddressSpaceOwner->AddressCreationLock.Owner != KeGetCurrentThread()) + { + /* We must own it! */ + MmLockAddressSpace(AddressSpace); + NeedReleaseLock = TRUE; + } + + /* Check all memory areas */ + RootNode = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; + MiRosCheckMemoryAreasRecursive(RootNode); + + /* Release the lock, if we acquired it */ + if (NeedReleaseLock) + { + MmUnlockAddressSpace(AddressSpace); + } +} + +extern KGUARDED_MUTEX PspActiveProcessMutex; + +VOID +NTAPI +MiCheckAllProcessMemoryAreas(VOID) +{ + PEPROCESS Process; + PLIST_ENTRY Entry; + + /* Acquire the Active Process Lock */ + KeAcquireGuardedMutex(&PspActiveProcessMutex); + + /* Loop the process list */ + Entry = PsActiveProcessHead.Flink; + while (Entry != &PsActiveProcessHead) + { + /* Get the process */ + Process = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks); + + /* Check memory areas */ + MiRosCheckMemoryAreas(&Process->Vm); + + Entry = Entry->Flink; + } + + /* Release the lock */ + KeReleaseGuardedMutex(&PspActiveProcessMutex); +} + +#endif + /** * @name MmFreeMemoryArea * @@ -712,6 +806,12 @@ MmFreeMemoryArea( ULONG_PTR Address; PVOID EndAddress; + /* Make sure we own the address space lock! */ + ASSERT(CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock.Owner == KeGetCurrentThread()); + + /* Check magic */ + ASSERT(MemoryArea->Magic == 'erAM'); + if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3) { PEPROCESS CurrentProcess = PsGetCurrentProcess(); @@ -731,7 +831,7 @@ MmFreeMemoryArea( BOOLEAN Dirty = FALSE; SWAPENTRY SwapEntry = 0; PFN_NUMBER Page = 0; - + if (MmIsPageSwapEntry(Process, (PVOID)Address)) { MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry); @@ -788,9 +888,6 @@ MmFreeMemoryArea( } } - /* There must be no page ops in progress */ - ASSERT(MemoryArea->PageOpCount == 0); - /* Remove the tree item. */ { if (MemoryArea->Parent != NULL) @@ -979,7 +1076,7 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace, MemoryArea->Protect = Protect; MemoryArea->Flags = AllocationFlags; //MemoryArea->LockCount = 0; - MemoryArea->PageOpCount = 0; + MemoryArea->Magic = 'erAM'; MemoryArea->DeleteInProgress = FALSE; MmInsertMemoryArea(AddressSpace, MemoryArea); @@ -1072,17 +1169,17 @@ MmDeleteProcessAddressSpace(PEPROCESS Process) KeBugCheck(MEMORY_MANAGEMENT); } } - + #if (_MI_PAGING_LEVELS == 2) { KIRQL OldIrql; PMMPDE pointerPde; /* Attach to Process */ KeAttachProcess(&Process->Pcb); - + /* Acquire PFN lock */ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); - + for(Address = MI_LOWEST_VAD_ADDRESS; Address < MM_HIGHEST_VAD_ADDRESS; Address =(PVOID)((ULONG_PTR)Address + (PAGE_SIZE * PTE_COUNT))) @@ -1098,7 +1195,7 @@ MmDeleteProcessAddressSpace(PEPROCESS Process) } /* Release lock */ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); - + /* Detach */ KeDetachProcess(); } diff --git a/reactos/ntoskrnl/ps/kill.c b/reactos/ntoskrnl/ps/kill.c index d864d96c08e..bea94ce9133 100644 --- a/reactos/ntoskrnl/ps/kill.c +++ b/reactos/ntoskrnl/ps/kill.c @@ -205,6 +205,52 @@ PspReapRoutine(IN PVOID Context) (PVOID)1) != (PVOID)1); } +#if DBG +VOID +NTAPI +PspCheckProcessList() +{ + PLIST_ENTRY Entry; + + KeAcquireGuardedMutex(&PspActiveProcessMutex); + DbgPrint("# checking PsActiveProcessHead @ %p\n", &PsActiveProcessHead); + for (Entry = PsActiveProcessHead.Flink; + Entry != &PsActiveProcessHead; + Entry = Entry->Flink) + { + PEPROCESS Process = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks); + POBJECT_HEADER Header; + PVOID Info, HeaderLocation; + + /* Get the header and assume this is what we'll free */ + Header = OBJECT_TO_OBJECT_HEADER(Process); + HeaderLocation = Header; + + /* To find the header, walk backwards from how we allocated */ + if ((Info = OBJECT_HEADER_TO_CREATOR_INFO(Header))) + { + HeaderLocation = Info; + } + if ((Info = OBJECT_HEADER_TO_NAME_INFO(Header))) + { + HeaderLocation = Info; + } + if ((Info = OBJECT_HEADER_TO_HANDLE_INFO(Header))) + { + HeaderLocation = Info; + } + if ((Info = OBJECT_HEADER_TO_QUOTA_INFO(Header))) + { + HeaderLocation = Info; + } + + ExpCheckPoolAllocation(HeaderLocation, NonPagedPool, 'corP'); + } + + KeReleaseGuardedMutex(&PspActiveProcessMutex); +} +#endif + VOID NTAPI PspDeleteProcess(IN PVOID ObjectBody) @@ -221,6 +267,8 @@ PspDeleteProcess(IN PVOID ObjectBody) /* Remove it from the Active List */ KeAcquireGuardedMutex(&PspActiveProcessMutex); RemoveEntryList(&Process->ActiveProcessLinks); + Process->ActiveProcessLinks.Flink = NULL; + Process->ActiveProcessLinks.Blink = NULL; KeReleaseGuardedMutex(&PspActiveProcessMutex); }