ULONG NTAPI MiFreePoolPages(IN PVOID StartingVa) { PMMPTE PointerPte, StartPte; PMMPFN Pfn1, StartPfn; PFN_NUMBER FreePages, NumberOfPages; KIRQL OldIrql; PMMFREE_POOL_ENTRY FreeEntry, NextEntry, LastEntry; ULONG i, End; // // Handle paged pool // if ((StartingVa >= MmPagedPoolStart) && (StartingVa <= MmPagedPoolEnd)) { // // Calculate the offset from the beginning of paged pool, and convert it // into pages // i = ((ULONG_PTR)StartingVa - (ULONG_PTR)MmPagedPoolStart) >> PAGE_SHIFT; End = i; // // Now use the end bitmap to scan until we find a set bit, meaning that // this allocation finishes here // while (!RtlTestBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, End)) End++; // // Now calculate the total number of pages this allocation spans // NumberOfPages = End - i + 1; /* Delete the actual pages */ PointerPte = MmPagedPoolInfo.FirstPteForPagedPool + i; FreePages = MiDeleteSystemPageableVm(PointerPte, NumberOfPages, 0, NULL); ASSERT(FreePages == NumberOfPages); // // Acquire the paged pool lock // KeAcquireGuardedMutex(&MmPagedPoolMutex); // // Clear the allocation and free bits // RtlClearBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, End); RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, i, NumberOfPages); // // Update the hint if we need to // if (i < MmPagedPoolInfo.PagedPoolHint) MmPagedPoolInfo.PagedPoolHint = i; // // Release the lock protecting the bitmaps // KeReleaseGuardedMutex(&MmPagedPoolMutex); // // And finally return the number of pages freed // return NumberOfPages; }
ULONG NTAPI MiFreePoolPages(IN PVOID StartingVa) { PMMPTE PointerPte, StartPte; PMMPFN Pfn1, StartPfn; PFN_COUNT FreePages, NumberOfPages; KIRQL OldIrql; PMMFREE_POOL_ENTRY FreeEntry, NextEntry, LastEntry; ULONG i, End; ULONG_PTR Offset; // // Handle paged pool // if ((StartingVa >= MmPagedPoolStart) && (StartingVa <= MmPagedPoolEnd)) { // // Calculate the offset from the beginning of paged pool, and convert it // into pages // Offset = (ULONG_PTR)StartingVa - (ULONG_PTR)MmPagedPoolStart; i = (ULONG)(Offset >> PAGE_SHIFT); End = i; // // Now use the end bitmap to scan until we find a set bit, meaning that // this allocation finishes here // while (!RtlTestBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, End)) End++; // // Now calculate the total number of pages this allocation spans. If it's // only one page, add it to the S-LIST instead of freeing it // NumberOfPages = End - i + 1; if ((NumberOfPages == 1) && (ExQueryDepthSList(&MiPagedPoolSListHead) < MiPagedPoolSListMaximum)) { InterlockedPushEntrySList(&MiPagedPoolSListHead, StartingVa); return 1; } /* Delete the actual pages */ PointerPte = MmPagedPoolInfo.FirstPteForPagedPool + i; FreePages = MiDeleteSystemPageableVm(PointerPte, NumberOfPages, 0, NULL); ASSERT(FreePages == NumberOfPages); // // Acquire the paged pool lock // KeAcquireGuardedMutex(&MmPagedPoolMutex); // // Clear the allocation and free bits // RtlClearBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, End); RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, i, NumberOfPages); // // Update the hint if we need to // if (i < MmPagedPoolInfo.PagedPoolHint) MmPagedPoolInfo.PagedPoolHint = i; // // Release the lock protecting the bitmaps // KeReleaseGuardedMutex(&MmPagedPoolMutex); // // And finally return the number of pages freed // return NumberOfPages; }
VOID NTAPI MmFreeSpecialPool(PVOID P) { PMMPTE PointerPte; PPOOL_HEADER Header; BOOLEAN Overruns = FALSE; KIRQL Irql = KeGetCurrentIrql(); POOL_TYPE PoolType; ULONG BytesRequested, BytesReal = 0; ULONG PtrOffset; PUCHAR b; PMI_FREED_SPECIAL_POOL FreedHeader; LARGE_INTEGER TickCount; PMMPFN Pfn; DPRINT1("MmFreeSpecialPool(%p)\n", P); /* Get the PTE */ PointerPte = MiAddressToPte(P); /* Check if it's valid */ if (PointerPte->u.Hard.Valid == 0) { /* Bugcheck if it has NOACCESS or 0 set as protection */ if (PointerPte->u.Soft.Protection == MM_NOACCESS || !PointerPte->u.Soft.Protection) { KeBugCheckEx(BAD_POOL_HEADER, (ULONG_PTR)P, (ULONG_PTR)PointerPte, 0, 0x20); } } /* Determine if it's a underruns or overruns pool pointer */ PtrOffset = (ULONG)((ULONG_PTR)P & (PAGE_SIZE - 1)); if (PtrOffset) { /* Pool catches overruns */ Header = PAGE_ALIGN(P); Overruns = TRUE; } else { /* Pool catches underruns */ Header = (PPOOL_HEADER)((PUCHAR)PAGE_ALIGN(P) + PAGE_SIZE - sizeof(POOL_HEADER)); } /* Check if it's non paged pool */ if ((Header->Ulong1 & SPECIAL_POOL_PAGED) == 0) { /* Non-paged allocation, ensure that IRQ is not higher that DISPATCH */ ASSERT((PointerPte + 1)->u.Soft.PageFileHigh == SPECIAL_POOL_NONPAGED_PTE); if (Irql > DISPATCH_LEVEL) { KeBugCheckEx(BAD_POOL_HEADER, Irql, (ULONG_PTR)P, 0, 0x31); } PoolType = NonPagedPool; } else { /* Paged allocation, ensure */ ASSERT((PointerPte + 1)->u.Soft.PageFileHigh == SPECIAL_POOL_PAGED_PTE); if (Irql > DISPATCH_LEVEL) { KeBugCheckEx(BAD_POOL_HEADER, Irql, (ULONG_PTR)P, 1, 0x31); } PoolType = PagedPool; } /* Get amount of bytes user requested to be allocated by clearing out the paged mask */ BytesRequested = (Header->Ulong1 & ~SPECIAL_POOL_PAGED) & 0xFFFF; /* Check memory before the allocated user buffer in case of overruns detection */ if (Overruns) { /* Calculate the real placement of the buffer */ BytesReal = PAGE_SIZE - PtrOffset; /* If they mismatch, it's unrecoverable */ if (BytesRequested > BytesReal) { KeBugCheckEx(BAD_POOL_HEADER, (ULONG_PTR)P, BytesRequested, BytesReal, 0x21); } if (BytesRequested + sizeof(POOL_HEADER) < BytesReal) { KeBugCheckEx(BAD_POOL_HEADER, (ULONG_PTR)P, BytesRequested, BytesReal, 0x22); } /* Actually check the memory pattern */ for (b = (PUCHAR)(Header + 1); b < (PUCHAR)P; b++) { if (Header->BlockSize != b[0]) { /* Bytes mismatch */ KeBugCheckEx(BAD_POOL_HEADER, (ULONG_PTR)P, (ULONG_PTR)b, Header->BlockSize, 0x23); } } } /* Check the memory pattern after the user buffer */ MiSpecialPoolCheckPattern(P, Header); /* Fill the freed header */ KeQueryTickCount(&TickCount); FreedHeader = (PMI_FREED_SPECIAL_POOL)PAGE_ALIGN(P); FreedHeader->Signature = 0x98764321; FreedHeader->TickCount = TickCount.LowPart; FreedHeader->NumberOfBytesRequested = BytesRequested; FreedHeader->Pagable = PoolType; FreedHeader->VirtualAddress = P; FreedHeader->Thread = PsGetCurrentThread(); /* TODO: Fill StackPointer and StackBytes */ FreedHeader->StackPointer = NULL; FreedHeader->StackBytes = 0; if (PoolType == NonPagedPool) { /* Non pagable. Get PFN element corresponding to the PTE */ Pfn = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber); /* Lock PFN database */ ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); Irql = KeAcquireQueuedSpinLock(LockQueuePfnLock); /* Delete this PFN */ MI_SET_PFN_DELETED(Pfn); /* Decrement share count of this PFN */ MiDecrementShareCount(Pfn, PointerPte->u.Hard.PageFrameNumber); /* Flush the TLB */ //FIXME: Use KeFlushSingleTb() instead KeFlushEntireTb(TRUE, TRUE); } else { /* Pagable. Delete that virtual address */ MiDeleteSystemPageableVm(PointerPte, 1, 0, NULL); /* Lock PFN database */ ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); Irql = KeAcquireQueuedSpinLock(LockQueuePfnLock); } /* Mark next PTE as invalid */ PointerPte[1].u.Long = 0; //|= 8000; /* Make sure that the last entry is really the last one */ ASSERT(MiSpecialPoolLastPte->u.List.NextEntry == MM_EMPTY_PTE_LIST); /* Update the current last PTE next pointer */ MiSpecialPoolLastPte->u.List.NextEntry = PointerPte - MmSystemPteBase; /* PointerPte becomes the new last PTE */ PointerPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; MiSpecialPoolLastPte = PointerPte; /* Release the PFN database lock */ KeReleaseQueuedSpinLock(LockQueuePfnLock, Irql); }