Author: fireball Date: Mon Sep 26 21:57:40 2011 New Revision: 53868
URL: http://svn.reactos.org/svn/reactos?rev=53868&view=rev Log: [NTOS] - Introduce two MM_EMPTY_LIST definitions - one for PTE as a whole and one for MMPTE_LIST NextEntry field only and move them to the actual architecture specific headers. - Implement special pool. This is a special (Capt. Obvious!) kernel pool which is used to catch overruns or underruns, freed memory access and perform additional validation for paged/nonpaged allocations access.
Added: trunk/reactos/ntoskrnl/mm/ARM3/special.c (with props) Modified: trunk/reactos/ntoskrnl/include/internal/amd64/mm.h trunk/reactos/ntoskrnl/include/internal/i386/mm.h trunk/reactos/ntoskrnl/include/internal/mm.h trunk/reactos/ntoskrnl/mm/ARM3/expool.c trunk/reactos/ntoskrnl/mm/ARM3/mminit.c trunk/reactos/ntoskrnl/mm/ARM3/syspte.c trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild
Modified: trunk/reactos/ntoskrnl/include/internal/amd64/mm.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/a... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/amd64/mm.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/amd64/mm.h [iso-8859-1] Mon Sep 26 21:57:40 2011 @@ -75,6 +75,11 @@ #define IS_ALIGNED(addr, align) (((ULONG64)(addr) & (align - 1)) == 0) #define IS_PAGE_ALIGNED(addr) IS_ALIGNED(addr, PAGE_SIZE)
+/* MMPTE related defines */ +#define MM_EMPTY_PTE_LIST ((ULONG64)0xFFFFFFFF) +#define MM_EMPTY_LIST ((ULONG_PTR)-1) +#define PTE_PER_PAGE 0x200 + #define ADDR_TO_PAGE_TABLE(v) ((ULONG)(((ULONG_PTR)(v)) / (512 * PAGE_SIZE))) #define ADDR_TO_PDE_OFFSET(v) ((ULONG)((((ULONG_PTR)(v)) / (512 * PAGE_SIZE)))) #define ADDR_TO_PTE_OFFSET(v) ((ULONG)((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE))
Modified: trunk/reactos/ntoskrnl/include/internal/i386/mm.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/i... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/i386/mm.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/i386/mm.h [iso-8859-1] Mon Sep 26 21:57:40 2011 @@ -16,6 +16,10 @@ #define PAGE_MASK(x) ((x)&(~0xfff)) #define PAE_PAGE_MASK(x) ((x)&(~0xfffLL))
+/* MMPTE related defines */ +#define MM_EMPTY_PTE_LIST ((ULONG)0xFFFFF) +#define MM_EMPTY_LIST ((ULONG_PTR)-1) + /* Base addresses of PTE and PDE */ #define PAGETABLE_MAP (0xc0000000) #define PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (1024))) @@ -26,6 +30,8 @@ #define PDE_TOP 0xC0300FFF #define PTE_TOP 0xC03FFFFF #define HYPER_SPACE 0xC0400000 + +#define PTE_PER_PAGE 0x400
/* Converting address to a corresponding PDE or PTE entry */ #define MiAddressToPde(x) \
Modified: trunk/reactos/ntoskrnl/include/internal/mm.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/m... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/mm.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/mm.h [iso-8859-1] Mon Sep 26 21:57:40 2011 @@ -887,6 +887,36 @@ ULONG ErrorCode );
+/* special.c *****************************************************************/ + +VOID +NTAPI +MiInitializeSpecialPool(); + +BOOLEAN +NTAPI +MmUseSpecialPool( + IN SIZE_T NumberOfBytes, + IN ULONG Tag); + +BOOLEAN +NTAPI +MmIsSpecialPoolAddress( + IN PVOID P); + +PVOID +NTAPI +MmAllocateSpecialPool( + IN SIZE_T NumberOfBytes, + IN ULONG Tag, + IN POOL_TYPE PoolType, + IN ULONG SpecialType); + +VOID +NTAPI +MmFreeSpecialPool( + IN PVOID P); + /* mm.c **********************************************************************/
NTSTATUS
Modified: trunk/reactos/ntoskrnl/mm/ARM3/expool.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/expool.c?r... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/expool.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/expool.c [iso-8859-1] Mon Sep 26 21:57:40 2011 @@ -469,6 +469,18 @@ ASSERT(PoolDesc != NULL);
// + // Check if this is a special pool allocation + // + if (MmUseSpecialPool(NumberOfBytes, Tag)) + { + // + // Try to allocate using special pool + // + Entry = MmAllocateSpecialPool(NumberOfBytes, Tag, PoolType, 2); + if (Entry) return Entry; + } + + // // Check if this is a big page allocation // if (NumberOfBytes > POOL_MAX_ALLOC) @@ -756,6 +768,18 @@ BOOLEAN Combined = FALSE;
// + // Check if it was allocated from a special pool + // + if (MmIsSpecialPoolAddress(P)) + { + // + // It is, so handle it via special pool free routine + // + MmFreeSpecialPool(P); + return; + } + + // // Quickly deal with big page allocations // if (PAGE_ALIGN(P) == P)
Modified: trunk/reactos/ntoskrnl/mm/ARM3/mminit.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/mminit.c?r... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/mminit.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/mminit.c [iso-8859-1] Mon Sep 26 21:57:40 2011 @@ -1792,6 +1792,9 @@ // InitializePool(PagedPool, 0);
+ /* Initialize special pool */ + MiInitializeSpecialPool(); + /* Default low threshold of 30MB or one fifth of paged pool */ MiLowPagedPoolThreshold = (30 * _1MB) >> PAGE_SHIFT; MiLowPagedPoolThreshold = min(MiLowPagedPoolThreshold, Size / 5);
Added: trunk/reactos/ntoskrnl/mm/ARM3/special.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/special.c?... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/special.c (added) +++ trunk/reactos/ntoskrnl/mm/ARM3/special.c [iso-8859-1] Mon Sep 26 21:57:40 2011 @@ -1,0 +1,536 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: ntoskrnl/mm/ARM3/special.c + * PURPOSE: ARM Memory Manager Special Pool implementation + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* + References: + http://msdn.microsoft.com/en-us/library/ff551832(v=VS.85).aspx +*/ + +/* INCLUDES *******************************************************************/ + +#include <ntoskrnl.h> +#define NDEBUG +#include <debug.h> + +#define MODULE_INVOLVED_IN_ARM3 +#include "../ARM3/miarm.h" + +extern PMMPTE MmSystemPteBase; + +PMMPTE +NTAPI +MiReserveAlignedSystemPtes(IN ULONG NumberOfPtes, + IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType, + IN ULONG Alignment); + +/* GLOBALS ********************************************************************/ + +#define SPECIAL_POOL_PAGED_PTE 0x2000 +#define SPECIAL_POOL_NONPAGED_PTE 0x4000 +#define SPECIAL_POOL_PAGED 0x8000 + +PVOID MmSpecialPoolStart; +PVOID MmSpecialPoolEnd; +PVOID MiSpecialPoolExtra; +ULONG MiSpecialPoolExtraCount; + +PMMPTE MiSpecialPoolFirstPte; +PMMPTE MiSpecialPoolLastPte; + +PFN_NUMBER MiSpecialPagesNonPagedMaximum; + +BOOLEAN MmSpecialPoolCatchOverruns = TRUE; + +typedef struct _MI_FREED_SPECIAL_POOL +{ + POOL_HEADER OverlaidPoolHeader; + /* TODO: Add overlaid verifier pool header */ + ULONG Signature; + ULONG TickCount; + ULONG NumberOfBytesRequested; + BOOLEAN Pagable; + PVOID VirtualAddress; + PVOID StackPointer; + ULONG StackBytes; + PETHREAD Thread; + UCHAR StackData[0x400]; +} MI_FREED_SPECIAL_POOL, *PMI_FREED_SPECIAL_POOL; + +/* PRIVATE FUNCTIONS **********************************************************/ + +VOID NTAPI MiTestSpecialPool(); + +BOOLEAN +NTAPI +MmUseSpecialPool(SIZE_T NumberOfBytes, ULONG Tag) +{ + /* Special pool is not suitable for allocations bigger than 1 page */ + if (NumberOfBytes > (PAGE_SIZE - sizeof(POOL_HEADER))) + return FALSE; + + // FIXME + //return TRUE; + return FALSE; +} + +BOOLEAN +NTAPI +MmIsSpecialPoolAddress(PVOID P) +{ + return((P >= MmSpecialPoolStart) && + (P <= MmSpecialPoolEnd)); +} + +VOID +NTAPI +MiInitializeSpecialPool() +{ + ULONG SpecialPoolPtes, i; + PMMPTE PointerPte; + + /* Check if there is a special pool tag */ + if ((MmSpecialPoolTag == 0) || + (MmSpecialPoolTag == -1)) return; + + /* Calculate number of system PTEs for the special pool */ + if ( MmNumberOfSystemPtes >= 0x3000 ) + SpecialPoolPtes = MmNumberOfSystemPtes / 3; + else + SpecialPoolPtes = MmNumberOfSystemPtes / 6; + + /* Don't let the number go too high */ + if (SpecialPoolPtes > 0x6000) SpecialPoolPtes = 0x6000; + + /* Round up to the page size */ + SpecialPoolPtes = PAGE_ROUND_UP(SpecialPoolPtes); + + ASSERT((SpecialPoolPtes & (PTE_PER_PAGE - 1)) == 0); + + /* Reserve those PTEs */ + do + { + PointerPte = MiReserveAlignedSystemPtes(SpecialPoolPtes, 0, /*0x400000*/0); // FIXME: + if (PointerPte) break; + + /* Reserving didn't work, so try to reduce the requested size */ + ASSERT(SpecialPoolPtes >= PTE_PER_PAGE); + SpecialPoolPtes -= 1024; + } while (SpecialPoolPtes); + + /* Fail if we couldn't reserve them at all */ + if (!SpecialPoolPtes) return; + + /* Make sure we got enough */ + ASSERT(SpecialPoolPtes >= PTE_PER_PAGE); + + /* Save first PTE and its address */ + MiSpecialPoolFirstPte = PointerPte; + MmSpecialPoolStart = MiPteToAddress(PointerPte); + + for (i = 0; i<512; i++) + { + /* Point it to the next entry */ + PointerPte->u.List.NextEntry = &PointerPte[2] - MmSystemPteBase; + + /* Move to the next pair */ + PointerPte += 2; + } + + /* Save extra values */ + MiSpecialPoolExtra = PointerPte; + MiSpecialPoolExtraCount = SpecialPoolPtes - 1024; + + /* Mark the previous PTE as the last one */ + MiSpecialPoolLastPte = PointerPte - 2; + MiSpecialPoolLastPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; + + /* Save end address of the special pool */ + MmSpecialPoolEnd = MiPteToAddress(MiSpecialPoolLastPte + 1); + + /* Calculate maximum non-paged part of the special pool */ + MiSpecialPagesNonPagedMaximum = MmResidentAvailablePages >> 4; + + /* And limit it if it turned out to be too big */ + if (MmNumberOfPhysicalPages > 0x3FFF) + MiSpecialPagesNonPagedMaximum = MmResidentAvailablePages >> 3; + + DPRINT1("Special pool start %p - end %p\n", MmSpecialPoolStart, MmSpecialPoolEnd); + + //MiTestSpecialPool(); +} + +PVOID +NTAPI +MmAllocateSpecialPool(SIZE_T NumberOfBytes, ULONG Tag, POOL_TYPE PoolType, ULONG SpecialType) +{ + KIRQL Irql; + MMPTE TempPte = ValidKernelPte; + PMMPTE PointerPte; + PFN_NUMBER PageFrameNumber; + LARGE_INTEGER TickCount; + PVOID Entry; + PPOOL_HEADER Header; + + DPRINT1("MmAllocateSpecialPool(%x %x %x %x)\n", NumberOfBytes, Tag, PoolType, SpecialType); + + /* Check if the pool is initialized and quit if it's not */ + if (!MiSpecialPoolFirstPte) return NULL; + + /* Get the pool type */ + PoolType &= BASE_POOL_TYPE_MASK; + + /* Check whether current IRQL matches the pool type */ + Irql = KeGetCurrentIrql(); + + if (((PoolType == PagedPool) && (Irql > APC_LEVEL)) || + ((PoolType != PagedPool) && (Irql > DISPATCH_LEVEL))) + { + /* Bad caller */ + KeBugCheckEx(SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION, Irql, PoolType, NumberOfBytes, 0x30); + } + + /* TODO: Take into account various limitations */ + /*if ((PoolType != NonPagedPool) && + MiSpecialPagesNonPaged > MiSpecialPagesNonPagedMaximum)*/ + + /* Lock PFN database */ + Irql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + /* Reject allocation in case amount of available pages is too small */ + if (MmAvailablePages < 0x100) + { + /* Release the PFN database lock */ + KeReleaseQueuedSpinLock(LockQueuePfnLock, Irql); + DPRINT1("Special pool: MmAvailablePages 0x%x is too small\n", MmAvailablePages); + return NULL; + } + + /* Reject allocation if special pool PTE list is exhausted */ + if (MiSpecialPoolFirstPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) + { + /* Release the PFN database lock */ + KeReleaseQueuedSpinLock(LockQueuePfnLock, Irql); + DPRINT1("Special pool: No PTEs left!\n"); + /* TODO: Expand the special pool */ + return NULL; + } + + /* Save allocation time */ + KeQueryTickCount(&TickCount); + + /* Get a pointer to the first PTE */ + PointerPte = MiSpecialPoolFirstPte; + + /* Set the first PTE pointer to the next one in the list */ + MiSpecialPoolFirstPte = MmSystemPteBase + PointerPte->u.List.NextEntry; + + /* Allocate a physical page */ + PageFrameNumber = MiRemoveAnyPage(MI_GET_NEXT_COLOR()); + + /* Initialize PFN and make it valid */ + TempPte.u.Hard.PageFrameNumber = PageFrameNumber; + MI_WRITE_VALID_PTE(PointerPte, TempPte); + MiInitializePfn(PageFrameNumber, PointerPte, TRUE); + + /* Release the PFN database lock */ + KeReleaseQueuedSpinLock(LockQueuePfnLock, Irql); + + /* Put some content into the page. Low value of tick count would do */ + Entry = MiPteToAddress(PointerPte); + RtlFillMemory(Entry, PAGE_SIZE, TickCount.LowPart); + + /* Calculate header and entry addresses */ + if ((SpecialType != 0) && + ((SpecialType == 1) || (!MmSpecialPoolCatchOverruns))) + { + /* We catch underruns. Data is at the beginning of the page */ + Header = (PPOOL_HEADER)((PUCHAR)Entry + PAGE_SIZE - sizeof(POOL_HEADER)); + } + else + { + /* We catch overruns. Data is at the end of the page */ + Header = (PPOOL_HEADER)Entry; + Entry = (PVOID)((ULONG_PTR)((PUCHAR)Entry - NumberOfBytes + PAGE_SIZE) & ~((LONG_PTR)sizeof(POOL_HEADER) - 1)); + } + + /* Initialize the header */ + RtlZeroMemory(Header, sizeof(POOL_HEADER)); + + /* Save allocation size there */ + Header->Ulong1 = NumberOfBytes; + + /* Make sure it's all good */ + ASSERT((NumberOfBytes <= PAGE_SIZE - sizeof(POOL_HEADER)) && + (PAGE_SIZE <= 32 * 1024)); + + /* Mark it as paged or nonpaged */ + if (PoolType == PagedPool) + { + /* Add pagedpool flag into the pool header too */ + Header->Ulong1 |= SPECIAL_POOL_PAGED; + + /* Also mark the next PTE as special-pool-paged */ + PointerPte[1].u.Soft.PageFileHigh |= SPECIAL_POOL_PAGED_PTE; + } + else + { + /* Mark the next PTE as special-pool-nonpaged */ + PointerPte[1].u.Soft.PageFileHigh |= SPECIAL_POOL_NONPAGED_PTE; + } + + /* Finally save tag and put allocation time into the header's blocksize. + That time will be used to check memory consistency within the allocated + page. */ + Header->PoolTag = Tag; + Header->BlockSize = TickCount.LowPart; + DPRINT1("%p\n", Entry); + return Entry; +} + +VOID +NTAPI +MiSpecialPoolCheckPattern(PUCHAR P, PPOOL_HEADER Header) +{ + ULONG BytesToCheck, BytesRequested, Index; + PUCHAR Ptr; + + /* Get amount of bytes user requested to be allocated by clearing out the paged mask */ + BytesRequested = (Header->Ulong1 & ~SPECIAL_POOL_PAGED) & 0xFFFF; + + /* Get a pointer to the end of user's area */ + Ptr = P + BytesRequested; + + /* Calculate how many bytes to check */ + BytesToCheck = (PUCHAR)PAGE_ALIGN(P) + PAGE_SIZE - Ptr; + + /* Remove pool header size if we're catching underruns */ + if (((ULONG_PTR)P & (PAGE_SIZE - 1)) == 0) + { + /* User buffer is located in the beginning of the page */ + BytesToCheck -= sizeof(POOL_HEADER); + } + + /* Check the pattern after user buffer */ + for (Index = 0; Index < BytesToCheck; Index++) + { + /* Bugcheck if bytes don't match */ + if (Ptr[Index] != Header->BlockSize) + { + KeBugCheckEx(BAD_POOL_HEADER, (ULONG_PTR)P, (ULONG_PTR)&Ptr[Index], Header->BlockSize, 0x24); + } + } +} + +VOID +NTAPI +MmFreeSpecialPool(PVOID P) +{ + PMMPTE PointerPte; + PPOOL_HEADER Header; + BOOLEAN Overruns = FALSE; + KIRQL Irql = KeGetCurrentIrql(); + POOL_TYPE PoolType; + ULONG BytesRequested, BytesReal = 0; + ULONG_PTR 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_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); +} + +VOID +NTAPI +MiTestSpecialPool() +{ + ULONG i; + PVOID p1, p2[100]; + //PUCHAR p3; + ULONG ByteSize; + POOL_TYPE PoolType = PagedPool; + + // First allocate/free + for (i=0; i<100; i++) + { + ByteSize = (100 * (i+1)) % (PAGE_SIZE - sizeof(POOL_HEADER)); + p1 = MmAllocateSpecialPool(ByteSize, 'TEST', PoolType, 0); + DPRINT1("p1 %p size %d\n", p1, ByteSize); + MmFreeSpecialPool(p1); + } + + // Now allocate all at once, then free at once + for (i=0; i<100; i++) + { + ByteSize = (100 * (i+1)) % (PAGE_SIZE - sizeof(POOL_HEADER)); + p2[i] = MmAllocateSpecialPool(ByteSize, 'TEST', PoolType, 0); + DPRINT1("p2[%d] %p size %d\n", i, p1, ByteSize); + } + for (i=0; i<100; i++) + { + DPRINT1("Freeing %p\n", p2[i]); + MmFreeSpecialPool(p2[i]); + } + + // Overrun the buffer to test + //ByteSize = 16; + //p3 = MmAllocateSpecialPool(ByteSize, 'TEST', NonPagedPool, 0); + //p3[ByteSize] = 0xF1; // This should cause an exception + + // Underrun the buffer to test + //p3 = MmAllocateSpecialPool(ByteSize, 'TEST', NonPagedPool, 1); + //p3--; + //*p3 = 0xF1; // This should cause an exception + +} + +/* EOF */
Propchange: trunk/reactos/ntoskrnl/mm/ARM3/special.c ------------------------------------------------------------------------------ svn:eol-style = native
Modified: trunk/reactos/ntoskrnl/mm/ARM3/syspte.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/syspte.c?r... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/syspte.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/syspte.c [iso-8859-1] Mon Sep 26 21:57:40 2011 @@ -55,9 +55,6 @@ // After the walk is complete, a new cluster is created that contains the PTEs // being released, which is then inserted in front of the recorded cluster. // - -/* This definition does not belong here and is most likely platform-dependent */ -#define MM_EMPTY_LIST (ULONG) (0xFFFFF)
ULONG FORCEINLINE @@ -101,7 +98,7 @@ // PreviousPte = &MmFirstFreeSystemPte[SystemPtePoolType];
- while (PreviousPte->u.List.NextEntry != MM_EMPTY_LIST) + while (PreviousPte->u.List.NextEntry != MM_EMPTY_PTE_LIST) { // // Get the next cluster and its size @@ -124,7 +121,7 @@ // // Make sure we didn't reach the end of the cluster list // - if (PreviousPte->u.List.NextEntry == MM_EMPTY_LIST) + if (PreviousPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { // // Release the System PTE lock and return failure @@ -185,7 +182,7 @@ // PreviousPte = &MmFirstFreeSystemPte[SystemPtePoolType];
- while (PreviousPte->u.List.NextEntry != MM_EMPTY_LIST) + while (PreviousPte->u.List.NextEntry != MM_EMPTY_PTE_LIST) { // // Get the next cluster @@ -301,7 +298,7 @@ PreviousPte = &MmFirstFreeSystemPte[SystemPtePoolType]; InsertPte = NULL;
- while (PreviousPte->u.List.NextEntry != MM_EMPTY_LIST) + while (PreviousPte->u.List.NextEntry != MM_EMPTY_PTE_LIST) { // // Get the next cluster and its size @@ -415,7 +412,7 @@ // // Make the first entry free and link it // - StartingPte->u.List.NextEntry = MM_EMPTY_LIST; + StartingPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; MmFirstFreeSystemPte[PoolType].u.Long = 0; MmFirstFreeSystemPte[PoolType].u.List.NextEntry = StartingPte - MmSystemPteBase;
Modified: trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ntoskrnl-generic.r... ============================================================================== --- trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild [iso-8859-1] Mon Sep 26 21:57:40 2011 @@ -476,6 +476,7 @@ <file>pool.c</file> <file>procsup.c</file> <file>section.c</file> + <file>special.c</file> <file>sysldr.c</file> <file>syspte.c</file> <file>vadnode.c</file>