#ifndef _M_AMD64
-#define MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING ((255*1024*1024) >> PAGE_SHIFT)
-#define MI_MIN_PAGES_FOR_SYSPTE_TUNING ((19*1024*1024) >> PAGE_SHIFT)
-#define MI_MIN_PAGES_FOR_SYSPTE_BOOST ((32*1024*1024) >> PAGE_SHIFT)
-#define MI_MAX_INIT_NONPAGED_POOL_SIZE (128 * 1024 * 1024)
-#define MI_MAX_NONPAGED_POOL_SIZE (128 * 1024 * 1024)
-#define MI_MAX_FREE_PAGE_LISTS 4
-
-#define MI_MIN_INIT_PAGED_POOLSIZE (32 * 1024 * 1024)
-
-#define MI_SESSION_VIEW_SIZE (20 * 1024 * 1024)
-#define MI_SESSION_POOL_SIZE (16 * 1024 * 1024)
-#define MI_SESSION_IMAGE_SIZE (8 * 1024 * 1024)
-#define MI_SESSION_WORKING_SET_SIZE (4 * 1024 * 1024)
-#define MI_SESSION_SIZE (MI_SESSION_VIEW_SIZE + \
- MI_SESSION_POOL_SIZE + \
- MI_SESSION_IMAGE_SIZE + \
- MI_SESSION_WORKING_SET_SIZE)
-
-#define MI_SYSTEM_VIEW_SIZE (16 * 1024 * 1024)
-
-#define MI_SYSTEM_CACHE_WS_START (PVOID)0xC0C00000
-#define MI_PAGED_POOL_START (PVOID)0xE1000000
-#define MI_NONPAGED_POOL_END (PVOID)0xFFBE0000
-#define MI_DEBUG_MAPPING (PVOID)0xFFBFF000
+#define MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING ((255 * _1MB) >> PAGE_SHIFT)
+#define MI_MIN_PAGES_FOR_SYSPTE_TUNING ((19 * _1MB) >> PAGE_SHIFT)
+#define MI_MIN_PAGES_FOR_SYSPTE_BOOST ((32 * _1MB) >> PAGE_SHIFT)
+#define MI_MAX_INIT_NONPAGED_POOL_SIZE (128 * _1MB)
+#define MI_MAX_NONPAGED_POOL_SIZE (128 * _1MB)
+#define MI_MAX_FREE_PAGE_LISTS 4
+
+#define MI_MIN_INIT_PAGED_POOLSIZE (32 * _1MB)
+
+#define MI_SESSION_VIEW_SIZE (20 * _1MB)
+#define MI_SESSION_POOL_SIZE (16 * _1MB)
+#define MI_SESSION_IMAGE_SIZE (8 * _1MB)
+#define MI_SESSION_WORKING_SET_SIZE (4 * _1MB)
+#define MI_SESSION_SIZE (MI_SESSION_VIEW_SIZE + \
+ MI_SESSION_POOL_SIZE + \
+ MI_SESSION_IMAGE_SIZE + \
+ MI_SESSION_WORKING_SET_SIZE)
+
+#define MI_SYSTEM_VIEW_SIZE (16 * _1MB)
+
+#define MI_SYSTEM_CACHE_WS_START (PVOID)0xC0C00000
+#define MI_PAGED_POOL_START (PVOID)0xE1000000
+#define MI_NONPAGED_POOL_END (PVOID)0xFFBE0000
+#define MI_DEBUG_MAPPING (PVOID)0xFFBFF000
+
+#define MI_SYSTEM_PTE_BASE (PVOID)MiAddressToPte(NULL)
#define MI_MIN_SECONDARY_COLORS 8
#define MI_SECONDARY_COLORS 64
#define MI_MAX_SECONDARY_COLORS 1024
+#define MI_MIN_ALLOCATION_FRAGMENT (4 * _1KB)
+#define MI_ALLOCATION_FRAGMENT (64 * _1KB)
+#define MI_MAX_ALLOCATION_FRAGMENT (2 * _1MB)
+
#define MM_HIGHEST_VAD_ADDRESS \
(PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE))
+/* The range 0x10000->0x7FEFFFFF is reserved for the ROSMM MAREA Allocator */
+#define MI_LOWEST_VAD_ADDRESS (PVOID)0x7FF00000
+
#endif /* !_M_AMD64 */
/* Make the code cleaner with some definitions for size multiples */
-#define _1KB (1024)
+#define _1KB (1024u)
#define _1MB (1024 * _1KB)
+#define _1GB (1024 * _1MB)
/* Area mapped by a PDE */
#define PDE_MAPPED_VA (PTE_COUNT * PAGE_SIZE)
#define PTE_WRITECOPY 0x200
#define PTE_EXECUTE_READWRITE 0x0
#define PTE_EXECUTE_WRITECOPY 0x200
+#define PTE_PROTOTYPE 0x400
//
// Cache flags
//
#define MI_IS_SESSION_PTE(Pte) \
((((PMMPTE)Pte) >= MiSessionBasePte) && (((PMMPTE)Pte) < MiSessionLastPte))
+#define MI_IS_PAGE_TABLE_ADDRESS(Address) \
+ (((PVOID)(Address) >= (PVOID)PTE_BASE) && ((PVOID)(Address) <= (PVOID)PTE_TOP))
+
+#define MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address) \
+ (((Address) >= (PVOID)MiAddressToPte(MmSystemRangeStart)) && ((Address) <= (PVOID)PTE_TOP))
+
+#define MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address) \
+ (((PVOID)(Address) >= (PVOID)PTE_BASE) && ((PVOID)(Address) <= (PVOID)MmHyperSpaceEnd))
+
//
// Corresponds to MMPTE_SOFTWARE.Protection
//
extern MMPTE HyperTemplatePte;
extern MMPDE ValidKernelPde;
extern MMPTE ValidKernelPte;
+extern MMPDE DemandZeroPde;
+extern MMPTE PrototypePte;
extern BOOLEAN MmLargeSystemCache;
extern BOOLEAN MmZeroPageFile;
extern BOOLEAN MmProtectFreedNonPagedPool;
extern BOOLEAN MmMirroring;
extern BOOLEAN MmMakeLowMemory;
extern BOOLEAN MmEnforceWriteProtection;
-extern ULONG MmAllocationFragment;
+extern SIZE_T MmAllocationFragment;
extern ULONG MmConsumedPoolPercentage;
extern ULONG MmVerifyDriverBufferType;
extern ULONG MmVerifyDriverLevel;
extern BOOLEAN MiLargePageAllDrivers;
extern ULONG MmVerifyDriverBufferLength;
extern ULONG MmLargePageDriverBufferLength;
-extern ULONG MmSizeOfNonPagedPoolInBytes;
-extern ULONG MmMaximumNonPagedPoolInBytes;
+extern SIZE_T MmSizeOfNonPagedPoolInBytes;
+extern SIZE_T MmMaximumNonPagedPoolInBytes;
extern PFN_NUMBER MmMaximumNonPagedPoolInPages;
extern PFN_NUMBER MmSizeOfPagedPoolInPages;
extern PVOID MmNonPagedSystemStart;
extern PVOID MmNonPagedPoolStart;
extern PVOID MmNonPagedPoolExpansionStart;
extern PVOID MmNonPagedPoolEnd;
-extern ULONG MmSizeOfPagedPoolInBytes;
+extern SIZE_T MmSizeOfPagedPoolInBytes;
extern PVOID MmPagedPoolStart;
extern PVOID MmPagedPoolEnd;
extern PVOID MmSessionBase;
-extern ULONG MmSessionSize;
+extern SIZE_T MmSessionSize;
extern PMMPTE MmFirstReservedMappingPte, MmLastReservedMappingPte;
extern PMMPTE MiFirstReservedZeroingPte;
extern MI_PFN_CACHE_ATTRIBUTE MiPlatformCacheAttributes[2][MmMaximumCacheType];
extern PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
-extern ULONG MmBootImageSize;
+extern SIZE_T MmBootImageSize;
extern PMMPTE MmSystemPtesStart[MaximumPtePoolTypes];
extern PMMPTE MmSystemPtesEnd[MaximumPtePoolTypes];
extern PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
extern MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
-extern ULONG MxPfnAllocation;
+extern ULONG_PTR MxPfnAllocation;
extern MM_PAGED_POOL_INFO MmPagedPoolInfo;
extern RTL_BITMAP MiPfnBitMap;
extern KGUARDED_MUTEX MmPagedPoolMutex;
extern PVOID MmPagedPoolEnd;
extern PVOID MmNonPagedSystemStart;
extern PVOID MiSystemViewStart;
-extern ULONG MmSystemViewSize;
+extern SIZE_T MmSystemViewSize;
extern PVOID MmSessionBase;
extern PVOID MiSessionSpaceEnd;
extern PMMPTE MiSessionImagePteStart;
extern PMMPTE MiSessionImagePteEnd;
extern PMMPTE MiSessionBasePte;
extern PMMPTE MiSessionLastPte;
-extern ULONG MmSizeOfPagedPoolInBytes;
+extern SIZE_T MmSizeOfPagedPoolInBytes;
extern PMMPTE MmSystemPagePtes;
extern PVOID MmSystemCacheStart;
extern PVOID MmSystemCacheEnd;
extern ULONG MmSpecialPoolTag;
extern PVOID MmHyperSpaceEnd;
extern PMMWSL MmSystemCacheWorkingSetList;
-extern ULONG MmMinimumNonPagedPoolSize;
+extern SIZE_T MmMinimumNonPagedPoolSize;
extern ULONG MmMinAdditionNonPagedPoolPerMb;
-extern ULONG MmDefaultMaximumNonPagedPool;
+extern SIZE_T MmDefaultMaximumNonPagedPool;
extern ULONG MmMaxAdditionNonPagedPoolPerMb;
extern ULONG MmSecondaryColors;
extern ULONG MmSecondaryColorMask;
-extern ULONG MmNumberOfSystemPtes;
+extern ULONG_PTR MmNumberOfSystemPtes;
extern ULONG MmMaximumNonPagedPoolPercent;
extern ULONG MmLargeStackSize;
extern PMMCOLOR_TABLES MmFreePagesByColor[FreePageList + 1];
extern PMMPTE MiHighestUserPte;
extern PMMPDE MiHighestUserPde;
extern PFN_NUMBER MmSystemPageDirectory[PD_COUNT];
+extern PMMPTE MmSharedUserDataPte;
#define MI_PFN_TO_PFNENTRY(x) (&MmPfnDatabase[1][x])
#define MI_PFNENTRY_TO_PFN(x) (x - MmPfnDatabase[1])
+//
+// Figures out the hardware bits for a PTE
+//
+ULONG
+FORCEINLINE
+MiDetermineUserGlobalPteMask(IN PMMPTE PointerPte)
+{
+ MMPTE TempPte;
+
+ /* Start fresh */
+ TempPte.u.Long = 0;
+
+ /* Make it valid and accessed */
+ TempPte.u.Hard.Valid = TRUE;
+ TempPte.u.Hard.Accessed = TRUE;
+
+ /* Is this for user-mode? */
+ if ((PointerPte <= MiHighestUserPte) ||
+ ((PointerPte >= MiAddressToPde(NULL)) && (PointerPte <= MiHighestUserPde)))
+ {
+ /* Set the owner bit */
+ TempPte.u.Hard.Owner = TRUE;
+ }
+
+ /* FIXME: We should also set the global bit */
+
+ /* Return the protection */
+ return TempPte.u.Long;
+}
+
//
// Creates a valid kernel PTE with the given protection
//
FORCEINLINE
VOID
+MI_MAKE_HARDWARE_PTE_KERNEL(IN PMMPTE NewPte,
+ IN PMMPTE MappingPte,
+ IN ULONG ProtectionMask,
+ IN PFN_NUMBER PageFrameNumber)
+{
+ /* Only valid for kernel, non-session PTEs */
+ ASSERT(MappingPte > MiHighestUserPte);
+ ASSERT(!MI_IS_SESSION_PTE(MappingPte));
+ ASSERT((MappingPte < (PMMPTE)PDE_BASE) || (MappingPte > (PMMPTE)PDE_TOP));
+
+ /* Start fresh */
+ *NewPte = ValidKernelPte;
+
+ /* Set the protection and page */
+ NewPte->u.Hard.PageFrameNumber = PageFrameNumber;
+ NewPte->u.Long |= MmProtectToPteMask[ProtectionMask];
+}
+
+//
+// Creates a valid PTE with the given protection
+//
+FORCEINLINE
+VOID
MI_MAKE_HARDWARE_PTE(IN PMMPTE NewPte,
IN PMMPTE MappingPte,
IN ULONG ProtectionMask,
IN PFN_NUMBER PageFrameNumber)
+{
+ /* Set the protection and page */
+ NewPte->u.Long = MiDetermineUserGlobalPteMask(MappingPte);
+ NewPte->u.Long |= MmProtectToPteMask[ProtectionMask];
+ NewPte->u.Hard.PageFrameNumber = PageFrameNumber;
+}
+
+//
+// Creates a valid user PTE with the given protection
+//
+FORCEINLINE
+VOID
+MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte,
+ IN PMMPTE MappingPte,
+ IN ULONG ProtectionMask,
+ IN PFN_NUMBER PageFrameNumber)
{
/* Only valid for kernel, non-session PTEs */
- ASSERT(MappingPte > MiHighestUserPte);
- ASSERT(!MI_IS_SESSION_PTE(MappingPte));
- ASSERT((MappingPte < (PMMPTE)PDE_BASE) || (MappingPte > (PMMPTE)PDE_TOP));
+ ASSERT(MappingPte <= MiHighestUserPte);
/* Start fresh */
*NewPte = ValidKernelPte;
/* Set the protection and page */
+ NewPte->u.Hard.Owner = TRUE;
NewPte->u.Hard.PageFrameNumber = PageFrameNumber;
NewPte->u.Long |= MmProtectToPteMask[ProtectionMask];
}
*PointerPte = InvalidPte;
}
+//
+// Checks if the thread already owns a working set
+//
+FORCEINLINE
+BOOLEAN
+MM_ANY_WS_LOCK_HELD(IN PETHREAD Thread)
+{
+ /* If any of these are held, return TRUE */
+ return ((Thread->OwnsProcessWorkingSetExclusive) ||
+ (Thread->OwnsProcessWorkingSetShared) ||
+ (Thread->OwnsSystemWorkingSetExclusive) ||
+ (Thread->OwnsSystemWorkingSetShared) ||
+ (Thread->OwnsSessionWorkingSetExclusive) ||
+ (Thread->OwnsSessionWorkingSetShared));
+}
+
+//
+// Checks if the process owns the working set lock
+//
+FORCEINLINE
+BOOLEAN
+MI_WS_OWNER(IN PEPROCESS Process)
+{
+ /* Check if this process is the owner, and that the thread owns the WS */
+ return ((KeGetCurrentThread()->ApcState.Process == &Process->Pcb) &&
+ ((PsGetCurrentThread()->OwnsProcessWorkingSetExclusive) ||
+ (PsGetCurrentThread()->OwnsProcessWorkingSetShared)));
+}
+
+//
+// Locks the working set for the given process
+//
+FORCEINLINE
+VOID
+MiLockProcessWorkingSet(IN PEPROCESS Process,
+ IN PETHREAD Thread)
+{
+ /* Shouldn't already be owning the process working set */
+ ASSERT(Thread->OwnsProcessWorkingSetShared == FALSE);
+ ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
+
+ /* Block APCs, make sure that still nothing is already held */
+ KeEnterGuardedRegion();
+ ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
+
+ /* FIXME: Actually lock it (we can't because Vm is used by MAREAs) */
+
+ /* FIXME: This also can't be checked because Vm is used by MAREAs) */
+ //ASSERT(Process->Vm.Flags.AcquiredUnsafe == 0);
+
+ /* Okay, now we can own it exclusively */
+ ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
+ Thread->OwnsProcessWorkingSetExclusive = TRUE;
+}
+
+//
+// Unlocks the working set for the given process
+//
+FORCEINLINE
+VOID
+MiUnlockProcessWorkingSet(IN PEPROCESS Process,
+ IN PETHREAD Thread)
+{
+ /* Make sure this process really is owner, and it was a safe acquisition */
+ ASSERT(MI_WS_OWNER(Process));
+ /* This can't be checked because Vm is used by MAREAs) */
+ //ASSERT(Process->Vm.Flags.AcquiredUnsafe == 0);
+
+ /* The thread doesn't own it anymore */
+ ASSERT(Thread->OwnsProcessWorkingSetExclusive == TRUE);
+ Thread->OwnsProcessWorkingSetExclusive = FALSE;
+
+ /* FIXME: Actually release it (we can't because Vm is used by MAREAs) */
+
+ /* Unblock APCs */
+ KeLeaveGuardedRegion();
+}
+
+//
+// Locks the working set
+//
+FORCEINLINE
+VOID
+MiLockWorkingSet(IN PETHREAD Thread,
+ IN PMMSUPPORT WorkingSet)
+{
+ /* Block APCs */
+ KeEnterGuardedRegion();
+
+ /* Working set should be in global memory */
+ ASSERT(MI_IS_SESSION_ADDRESS((PVOID)WorkingSet) == FALSE);
+
+ /* Thread shouldn't already be owning something */
+ ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
+
+ /* FIXME: Actually lock it (we can't because Vm is used by MAREAs) */
+
+ /* Which working set is this? */
+ if (WorkingSet == &MmSystemCacheWs)
+ {
+ /* Own the system working set */
+ ASSERT((Thread->OwnsSystemWorkingSetExclusive == FALSE) &&
+ (Thread->OwnsSystemWorkingSetShared == FALSE));
+ Thread->OwnsSystemWorkingSetExclusive = TRUE;
+ }
+ else if (WorkingSet->Flags.SessionSpace)
+ {
+ /* We don't implement this yet */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+ else
+ {
+ /* Own the process working set */
+ ASSERT((Thread->OwnsProcessWorkingSetExclusive == FALSE) &&
+ (Thread->OwnsProcessWorkingSetShared == FALSE));
+ Thread->OwnsProcessWorkingSetExclusive = TRUE;
+ }
+}
+
+//
+// Unlocks the working set
+//
+FORCEINLINE
+VOID
+MiUnlockWorkingSet(IN PETHREAD Thread,
+ IN PMMSUPPORT WorkingSet)
+{
+ /* Working set should be in global memory */
+ ASSERT(MI_IS_SESSION_ADDRESS((PVOID)WorkingSet) == FALSE);
+
+ /* Which working set is this? */
+ if (WorkingSet == &MmSystemCacheWs)
+ {
+ /* Release the system working set */
+ ASSERT((Thread->OwnsSystemWorkingSetExclusive == TRUE) ||
+ (Thread->OwnsSystemWorkingSetShared == TRUE));
+ Thread->OwnsSystemWorkingSetExclusive = FALSE;
+ }
+ else if (WorkingSet->Flags.SessionSpace)
+ {
+ /* We don't implement this yet */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+ else
+ {
+ /* Release the process working set */
+ ASSERT((Thread->OwnsProcessWorkingSetExclusive) ||
+ (Thread->OwnsProcessWorkingSetShared));
+ Thread->OwnsProcessWorkingSetExclusive = FALSE;
+ }
+
+ /* FIXME: Actually release it (we can't because Vm is used by MAREAs) */
+
+ /* Unblock APCs */
+ KeLeaveGuardedRegion();
+}
+
NTSTATUS
NTAPI
MmArmInitSystem(
IN PMMPFN Pfn1
);
+PMMVAD
+NTAPI
+MiLocateAddress(
+ IN PVOID VirtualAddress
+);
+
+PMMADDRESS_NODE
+NTAPI
+MiCheckForConflictingNode(
+ IN ULONG_PTR StartVpn,
+ IN ULONG_PTR EndVpn,
+ IN PMM_AVL_TABLE Table
+);
+
+NTSTATUS
+NTAPI
+MiFindEmptyAddressRangeDownTree(
+ IN SIZE_T Length,
+ IN ULONG_PTR BoundaryAddress,
+ IN ULONG_PTR Alignment,
+ IN PMM_AVL_TABLE Table,
+ OUT PULONG_PTR Base
+);
+
+VOID
+NTAPI
+MiInsertNode(
+ IN PMMADDRESS_NODE NewNode,
+ IN PMM_AVL_TABLE Table
+);
+
/* EOF */