1559 lines
37 KiB
C
1559 lines
37 KiB
C
/*++
|
|
|
|
Copyright (c) 1989-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mi.h
|
|
|
|
Abstract:
|
|
|
|
This module contains the private data structures and procedure
|
|
prototypes for the memory management system.
|
|
|
|
--*/
|
|
|
|
#ifndef _MI_
|
|
#define _MI_
|
|
|
|
#include <ntos.h>
|
|
#include <bldr.h>
|
|
#include <ki.h>
|
|
#include <pool.h>
|
|
#include <pci.h>
|
|
#include <av.h>
|
|
#include <xlaunch.h>
|
|
|
|
//
|
|
// Break DEVKIT functionality into CONSOLE versus ARCADE features with the
|
|
// following macro.
|
|
//
|
|
|
|
#if defined(DEVKIT) && !defined(ARCADE)
|
|
#define CONSOLE_DEVKIT
|
|
#endif
|
|
|
|
//
|
|
// DBG sensitive DbgPrint wrapper.
|
|
//
|
|
|
|
#if DBG
|
|
#define MiDbgPrint(x) DbgPrint x
|
|
#else
|
|
#define MiDbgPrint(x)
|
|
#endif
|
|
|
|
//
|
|
// Bit flag macros.
|
|
//
|
|
|
|
#define MiIsFlagSet(flagset, flag) (((flagset) & (flag)) != 0)
|
|
#define MiIsFlagClear(flagset, flag) (((flagset) & (flag)) == 0)
|
|
|
|
//
|
|
// Returns the index of the supplied element relative to the supplied base
|
|
// address.
|
|
//
|
|
|
|
#define ARRAY_ELEMENT_NUMBER(base, type, element) \
|
|
((ULONG)(((type *)(element)) - (base)))
|
|
|
|
//
|
|
// Returns the number of elements in the supplied array.
|
|
//
|
|
|
|
#define ARRAY_ELEMENTS(array) \
|
|
(sizeof((array)) / sizeof((array)[0]))
|
|
|
|
//
|
|
// Shortcuts to common multiplication factors.
|
|
//
|
|
|
|
#define X64K ((ULONG)64*1024)
|
|
#define X1024K ((ULONG)1024*1024)
|
|
|
|
//
|
|
// Define the NVIDIA NV2A constants for controlling the last accessible byte of
|
|
// memory. These are accessed from the host bridge device.
|
|
//
|
|
|
|
#define CR_CPU_MEMTOP_LIMIT 0x87
|
|
#define CR_CPU_MEMTOP_LIMIT_64MB 0x03
|
|
#define CR_CPU_MEMTOP_LIMIT_128MB 0x07
|
|
|
|
//
|
|
// Define the lowest physical page available in the system.
|
|
//
|
|
|
|
#define MM_LOWEST_PHYSICAL_PAGE 0x00000
|
|
|
|
//
|
|
// Define the highest physical page available in the system.
|
|
//
|
|
|
|
#if defined(ARCADE)
|
|
#define MM_HIGHEST_PHYSICAL_PAGE 0x07FFF
|
|
#elif defined(DEVKIT)
|
|
#define MM_HIGHEST_PHYSICAL_PAGE MmHighestPhysicalPage
|
|
#else
|
|
#define MM_HIGHEST_PHYSICAL_PAGE 0x03FFF
|
|
#endif
|
|
|
|
//
|
|
// Define the physical page that's reserved for use by D3D. D3D needs the first
|
|
// ULONG in the system in order to initialize the push buffer, so we reserve the
|
|
// entire page for D3D's use.
|
|
//
|
|
|
|
#define MM_D3D_PHYSICAL_PAGE 0x00000
|
|
|
|
//
|
|
// Define the highest physical page that's allowed for a contiguous memory
|
|
// allocation. All contiguous memory allocations are constrained to the memory
|
|
// available on a retail system.
|
|
//
|
|
// Additionally, the NVIDIA NV2A can use up to 128K of instance memory that must
|
|
// be allocated from the top of memory. In order to leave the maximum amount of
|
|
// instance memory available from quick boot to quick boot, we don't allow
|
|
// anybody to allocate contiguous pages from the upper 128K (64K of which is
|
|
// already consumed by the PFN database). This prevents somebody from
|
|
// persisting a contiguous allocation in this range across a quick reboot and
|
|
// screwing up the next title.
|
|
//
|
|
// For ARCADE, we require a 128K PFN database to describe the 128M retail
|
|
// system. With 64K reserved for NVIDIA NV2A instance memory, this pushes the
|
|
// contiguous memory limit to 196K from the top of memory.
|
|
//
|
|
|
|
#ifdef ARCADE
|
|
#define MM_CONTIGUOUS_MEMORY_LIMIT 0x07FCF
|
|
#else
|
|
#define MM_CONTIGUOUS_MEMORY_LIMIT 0x03FDF
|
|
#endif
|
|
|
|
//
|
|
// Define the first physical page that's used to hold the PFN database. The
|
|
// page number is selected such that the first 64M's half of the database sits
|
|
// at the end of the first 64M and the second 64M's half of the database sits
|
|
// at the start of the second 64M.
|
|
//
|
|
// For ARCADE, the PFN database is always 128K. NVIDIA NV2A instance memory
|
|
// must be located in the top 128K of memory, but we only reserve 64K of
|
|
// instance memory. The PFN database is instead located below the reserved
|
|
// instance memory.
|
|
//
|
|
|
|
#ifdef ARCADE
|
|
#define MM_DATABASE_PHYSICAL_PAGE 0x07FD0
|
|
#else
|
|
#define MM_DATABASE_PHYSICAL_PAGE 0x03FF0
|
|
#endif
|
|
|
|
//
|
|
// Define the bottom of the region that is reserved at system startup for NVIDIA
|
|
// NV2A instance memory. These pages may be made available for other use when
|
|
// the D3D library calls MmClaimGpuInstanceMemory.
|
|
//
|
|
// For ARCADE, the PFN database is always 128K. This would consume all of the
|
|
// usable pages for NVIDIA NV2A instance memory, so instead this instance memory
|
|
// is reserved at the top of memory and the PFN database is located below this
|
|
// instance memory.
|
|
//
|
|
|
|
#ifdef ARCADE
|
|
#define MM_INSTANCE_PHYSICAL_PAGE 0x07FF0
|
|
#else
|
|
#define MM_INSTANCE_PHYSICAL_PAGE 0x03FE0
|
|
#endif
|
|
|
|
#define MM_INSTANCE_PAGE_COUNT 16
|
|
|
|
//
|
|
// Define the first physical page that's available only on a development kit
|
|
// system.
|
|
//
|
|
|
|
#define MM_64M_PHYSICAL_PAGE 0x04000
|
|
|
|
//
|
|
// Define the write combine system memory aperture that's exposed by the NVIDIA
|
|
// NV2A. PAGE_VIDEO allocations are mapped through this aperture instead of the
|
|
// standard system memory aperture starting at physical page zero.
|
|
//
|
|
|
|
#define MM_WRITE_COMBINE_APERTURE 0x40000
|
|
|
|
//
|
|
// Fixed addresses for memory manager data structures.
|
|
//
|
|
|
|
#define MM_PHYSICAL_MAP_BASE ((ULONG)0x80000000)
|
|
#define MM_PHYSICAL_MAP_END ((ULONG)0x8FFFFFFF)
|
|
|
|
#define MM_DEVKIT_PTE_BASE ((ULONG)0xB0000000)
|
|
#define MM_DEVKIT_PTE_END ((ULONG)0xBFFFFFFF)
|
|
|
|
#define MM_PAGE_TABLES_BASE ((ULONG)0xC0000000)
|
|
#define MM_PAGE_TABLES_END ((ULONG)0xC03FFFFF)
|
|
|
|
#define MM_DEBUG_VA ((ULONG)0xC0800000)
|
|
|
|
#define MM_SYSTEM_PTE_BASE ((ULONG)0xD0000000)
|
|
#define MM_SYSTEM_PTE_END ((ULONG)0xEFFFFFFF)
|
|
|
|
#define MM_DEVICE_WC_BASE ((ULONG)0xF0000000)
|
|
#define MM_DEVICE_WC_END ((ULONG)0xF7FFFFFF)
|
|
#define MM_DEVICE_UC_BASE ((ULONG)0xF8000000)
|
|
#define MM_DEVICE_UC_END ((ULONG)0xFFBFFFFF)
|
|
|
|
#define MM_HIGHEST_VAD_ADDRESS ((PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - X64K))
|
|
#define MM_USER_ADDRESS_RANGE_LIMIT 0xFFFFFFFF
|
|
#define MM_MAXIMUM_ZERO_BITS 21
|
|
|
|
//
|
|
// Page color support.
|
|
//
|
|
|
|
#define MM_NUMBER_OF_COLORS_BITS 5
|
|
#define MM_NUMBER_OF_COLORS (1 << MM_NUMBER_OF_COLORS_BITS)
|
|
#define MM_NUMBER_OF_COLORS_MASK (MM_NUMBER_OF_COLORS - 1)
|
|
|
|
typedef ULONG MMCOLOR;
|
|
|
|
//
|
|
// Macros to lock and unlock the memory manager data structures.
|
|
//
|
|
|
|
#define MI_LOCK_MM(OldIrql) (*OldIrql) = KeRaiseIrqlToDpcLevel()
|
|
#define MI_UNLOCK_MM(OldIrql) KeLowerIrql(OldIrql)
|
|
#define MI_ASSERT_LOCK_MM() ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL)
|
|
|
|
#define MI_UNLOCK_MM_AND_THEN_WAIT(OldIrql) { \
|
|
PKTHREAD Thread = KeGetCurrentThread(); \
|
|
MI_ASSERT_LOCK_MM(); \
|
|
ASSERT((OldIrql) <= APC_LEVEL); \
|
|
Thread->WaitIrql = (OldIrql); \
|
|
Thread->WaitNext = TRUE; \
|
|
}
|
|
|
|
//
|
|
// Page table entry data structure as overloaded by the memory manager.
|
|
//
|
|
|
|
typedef struct _MMPTE {
|
|
union {
|
|
ULONG Long;
|
|
HARDWARE_PTE Hard;
|
|
struct {
|
|
ULONG Valid : 1;
|
|
ULONG OneEntry : 1;
|
|
ULONG NextEntry : 30;
|
|
} List;
|
|
};
|
|
} MMPTE, *PMMPTE;
|
|
|
|
#define PTE_PER_PAGE (PAGE_SIZE / sizeof(MMPTE))
|
|
#define PDE_PER_PAGE (PAGE_SIZE / sizeof(MMPTE))
|
|
|
|
//
|
|
// Define masks for fields within the PTE.
|
|
//
|
|
|
|
#define MM_PTE_VALID_MASK 0x00000001
|
|
#define MM_PTE_WRITE_MASK 0x00000002
|
|
#define MM_PTE_OWNER_MASK 0x00000004
|
|
#define MM_PTE_WRITE_THROUGH_MASK 0x00000008
|
|
#define MM_PTE_CACHE_DISABLE_MASK 0x00000010
|
|
#define MM_PTE_ACCESS_MASK 0x00000020
|
|
#define MM_PTE_DIRTY_MASK 0x00000040
|
|
#define MM_PTE_LARGE_PAGE_MASK 0x00000080
|
|
#define MM_PTE_GLOBAL_MASK 0x00000100
|
|
#define MM_PTE_GUARD_MASK 0x00000200
|
|
#define MM_PTE_NEXT_ENTRY_MASK 0xFFFFFFFC
|
|
|
|
//
|
|
// Bit fields to or into PTE to make a PTE valid based on the protection field
|
|
// of the invalid PTE.
|
|
//
|
|
// Note that for guard pages, we overload the supervisor/user PTE flag to mean
|
|
// that the page is a guard page. Because we never go to user mode, this flag
|
|
// is effectively unused by hardware.
|
|
//
|
|
|
|
#define MM_PTE_NOACCESS 0x000 // not expressable on i386
|
|
#define MM_PTE_READONLY 0x000
|
|
#define MM_PTE_READWRITE MM_PTE_WRITE_MASK
|
|
#define MM_PTE_NOCACHE MM_PTE_CACHE_DISABLE_MASK
|
|
#define MM_PTE_GUARD MM_PTE_GUARD_MASK
|
|
#define MM_PTE_CACHE 0x000
|
|
|
|
//
|
|
// Define the set of bits that MiMakePteProtectionMask will return. This mask
|
|
// can be used to check if an existing PTE has compatible attributes.
|
|
//
|
|
|
|
#define MM_PTE_PROTECTION_MASK 0x0000021B
|
|
|
|
//
|
|
// Define the set of bits that MiMakeSystemPteProtectionMask will return. This
|
|
// mask can be used to check if an existing PTE has compatible attributes.
|
|
//
|
|
|
|
#define MM_SYSTEM_PTE_PROTECTION_MASK 0x0000001B
|
|
|
|
//
|
|
// Define the end of list marker for the linked list contained in a PTE.
|
|
//
|
|
|
|
#define MM_EMPTY_PTE_LIST ((ULONG)0x3FFFFFFF)
|
|
|
|
//
|
|
// Enumeration to identify what a busy page frame is being used for.
|
|
//
|
|
|
|
typedef enum _MMPFN_BUSY_TYPE {
|
|
MmUnknownUsage,
|
|
MmStackUsage,
|
|
MmVirtualPageTableUsage,
|
|
MmSystemPageTableUsage,
|
|
MmPoolUsage,
|
|
MmVirtualMemoryUsage,
|
|
MmSystemMemoryUsage,
|
|
MmImageUsage,
|
|
MmFsCacheUsage,
|
|
MmContiguousUsage,
|
|
MmDebuggerUsage,
|
|
MmMaximumUsage
|
|
} MMPFN_BUSY_TYPE;
|
|
|
|
//
|
|
// PFN free page element.
|
|
//
|
|
// The low bit of PackedPfnFlink must be clear so that the overloaded
|
|
// MMPFN.Pte.Valid is clear.
|
|
//
|
|
// The low bit of PackedPfnBlink must be clear so that the overloaded
|
|
// MMPFN.Busy.Busy is clear.
|
|
//
|
|
|
|
typedef struct _MMPFNFREE {
|
|
USHORT PackedPfnFlink; // low bit must be clear
|
|
USHORT PackedPfnBlink; // low bit must be clear
|
|
} MMPFNFREE, *PMMPFNFREE;
|
|
|
|
//
|
|
// PFN database element.
|
|
//
|
|
|
|
typedef struct _MMPFN {
|
|
union {
|
|
ULONG Long;
|
|
MMPTE Pte;
|
|
MMPFNFREE Free;
|
|
struct {
|
|
ULONG LockCount : 16; // low bit must be clear
|
|
ULONG Busy : 1;
|
|
ULONG Reserved : 1;
|
|
ULONG PteIndex : 10;
|
|
ULONG BusyType : 4;
|
|
} Busy;
|
|
struct {
|
|
ULONG LockCount : 16; // low bit must be clear
|
|
ULONG Busy : 1;
|
|
ULONG ElementIndex : 11;
|
|
ULONG BusyType : 4;
|
|
} FsCache;
|
|
struct {
|
|
ULONG LockCount : 16; // low bit must be clear
|
|
ULONG Busy : 1;
|
|
ULONG NumberOfUsedPtes : 11;
|
|
ULONG BusyType : 4;
|
|
} Directory;
|
|
};
|
|
} MMPFN, *PMMPFN;
|
|
|
|
#define MM_PFN_NULL ((PFN_NUMBER)-1)
|
|
#define MM_PACKED_PFN_NULL ((USHORT)0xFFFE)
|
|
|
|
#define MM_PFN_DATABASE ((PMMPFN)MI_CONVERT_PFN_TO_PHYSICAL(MM_DATABASE_PHYSICAL_PAGE))
|
|
|
|
#define MI_PFN_ELEMENT(pfn) (&MM_PFN_DATABASE[pfn])
|
|
#define MI_PFN_NUMBER(pmmpfn) ((PFN_NUMBER)ARRAY_ELEMENT_NUMBER(MM_PFN_DATABASE, MMPFN, pmmpfn))
|
|
|
|
//
|
|
// Define the basic unit for the MMPFN.Busy.LockCount field. The low bit must
|
|
// always be clear in order for the entry to not be viewed by the processor as a
|
|
// valid PTE, so we always increment or decrement the LockCount field in units
|
|
// of two.
|
|
//
|
|
|
|
#define MI_LOCK_COUNT_UNIT 2
|
|
#define MI_LOCK_COUNT_MAXIMUM 0xFFFE
|
|
|
|
//
|
|
// PFN region descriptor.
|
|
//
|
|
|
|
typedef struct _MMPFNREGION {
|
|
MMPFNFREE FreePagesByColor[MM_NUMBER_OF_COLORS];
|
|
PFN_COUNT AvailablePages;
|
|
} MMPFNREGION, *PMMPFNREGION;
|
|
|
|
#ifdef CONSOLE_DEVKIT
|
|
#define MI_PFN_REGION_SHIFT 14
|
|
#define MI_PAGES_IN_PFN_REGION (1 << MI_PFN_REGION_SHIFT)
|
|
#define MI_BYTES_IN_PFN_REGION (MI_PAGES_IN_PFN_REGION << PAGE_SHIFT)
|
|
#define MI_NUMBER_OF_REGIONS (MM_PAGES_IN_PHYSICAL_MAP / MI_PAGES_IN_PFN_REGION)
|
|
#define MI_PFN_REGION(pfn) (MmPfnRegions[((pfn) >> MI_PFN_REGION_SHIFT)])
|
|
#else
|
|
#define MI_PAGES_IN_PFN_REGION (MM_PAGES_IN_PHYSICAL_MAP)
|
|
#define MI_BYTES_IN_PFN_REGION (MI_PAGES_IN_PFN_REGION << PAGE_SHIFT)
|
|
#define MI_PFN_REGION(pfn) &MmRetailPfnRegion
|
|
#endif
|
|
|
|
//
|
|
// Define the function signature for a routine that removes a page with the
|
|
// supplied busy type code and target page table entry address.
|
|
//
|
|
|
|
typedef
|
|
PFN_NUMBER
|
|
(FASTCALL *PMMREMOVE_PAGE_ROUTINE)(
|
|
IN MMPFN_BUSY_TYPE BusyType,
|
|
IN PMMPTE TargetPte
|
|
);
|
|
|
|
//
|
|
// Page table entry range structure.
|
|
//
|
|
|
|
typedef struct _MMPTERANGE {
|
|
MMPTE HeadPte;
|
|
PMMPTE FirstCommittedPte;
|
|
PMMPTE LastCommittedPte;
|
|
PMMPTE LastReservedPte;
|
|
PFN_COUNT *AvailablePages;
|
|
PMMREMOVE_PAGE_ROUTINE RemovePageRoutine;
|
|
} MMPTERANGE, *PMMPTERANGE;
|
|
|
|
//
|
|
// Address node.
|
|
//
|
|
|
|
typedef struct _MMADDRESS_NODE {
|
|
ULONG_PTR StartingVpn;
|
|
ULONG_PTR EndingVpn;
|
|
struct _MMADDRESS_NODE *Parent;
|
|
struct _MMADDRESS_NODE *LeftChild;
|
|
struct _MMADDRESS_NODE *RightChild;
|
|
} MMADDRESS_NODE, *PMMADDRESS_NODE;
|
|
|
|
//
|
|
// Virtual address descriptor.
|
|
//
|
|
|
|
#ifdef __cplusplus
|
|
typedef struct _MMVAD : public MMADDRESS_NODE {
|
|
#else
|
|
typedef struct _MMVAD {
|
|
MMADDRESS_NODE;
|
|
#endif
|
|
ULONG AllocationProtect;
|
|
} MMVAD, *PMMVAD;
|
|
|
|
//
|
|
// Macros to guard access to the virtual memory space.
|
|
//
|
|
|
|
#define MI_LOCK_ADDRESS_SPACE() RtlEnterCriticalSectionAndRegion(&MmAddressSpaceLock)
|
|
#define MI_UNLOCK_ADDRESS_SPACE() RtlLeaveCriticalSectionAndRegion(&MmAddressSpaceLock)
|
|
|
|
//
|
|
// Macros to convert between virtual address and virtual page numbers.
|
|
//
|
|
|
|
#define MI_VA_TO_PAGE(va) ((ULONG_PTR)(va) >> PAGE_SHIFT)
|
|
#define MI_VA_TO_VPN(va) ((ULONG_PTR)(va) >> PAGE_SHIFT)
|
|
#define MI_VPN_TO_VA(vpn) (PVOID)((vpn) << PAGE_SHIFT)
|
|
#define MI_VPN_TO_VA_ENDING(vpn) (PVOID)(((vpn) << PAGE_SHIFT) | (PAGE_SIZE - 1))
|
|
|
|
//++
|
|
//ULONG
|
|
//MI_ROUND_TO_SIZE (
|
|
// IN ULONG LENGTH,
|
|
// IN ULONG ALIGNMENT
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// The ROUND_TO_SIZE macro takes a LENGTH in bytes and rounds it up to a
|
|
// multiple of the alignment.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// LENGTH - LENGTH in bytes to round up to.
|
|
//
|
|
// ALIGNMENT - alignment to round to, must be a power of 2, e.g, 2**n.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns the LENGTH rounded up to a multiple of the alignment.
|
|
//
|
|
//--
|
|
|
|
#define MI_ROUND_TO_SIZE(LENGTH,ALIGNMENT) \
|
|
(((LENGTH) + ((ALIGNMENT) - 1)) & ~((ALIGNMENT) - 1))
|
|
|
|
//++
|
|
//PVOID
|
|
//MI_ALIGN_TO_SIZE (
|
|
// IN PVOID VA
|
|
// IN ULONG ALIGNMENT
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// The MI_ALIGN_TO_SIZE macro takes a virtual address and returns a
|
|
// virtual address for that page with the specified alignment.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// VA - Virtual address.
|
|
//
|
|
// ALIGNMENT - alignment to round to, must be a power of 2, e.g, 2**n.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns the aligned virtual address.
|
|
//
|
|
//--
|
|
|
|
#define MI_ALIGN_TO_SIZE(VA,ALIGNMENT) \
|
|
((PVOID)((ULONG_PTR)(VA) & ~((ULONG_PTR) ALIGNMENT - 1)))
|
|
|
|
//++
|
|
//VOID
|
|
//MI_WRITE_PTE (
|
|
// IN PMMPTE PointerPte,
|
|
// IN MMPTE PteContents
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MI_WRITE_PTE fills in the specified PTE with the specified contents.
|
|
//
|
|
// Arguments
|
|
//
|
|
// PointerPte - Supplies a PTE to fill.
|
|
//
|
|
// PteContents - Supplies the contents to put in the PTE.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
#define MI_WRITE_PTE(_PointerPte, _PteContents) \
|
|
(*(_PointerPte) = (_PteContents))
|
|
|
|
//++
|
|
//VOID
|
|
//MI_WRITE_ZERO_PTE (
|
|
// IN PMMPTE PointerPte
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MI_WRITE_PTE fills in the specified PTE with zero.
|
|
//
|
|
// Arguments
|
|
//
|
|
// PointerPte - Supplies a PTE to fill.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
#define MI_WRITE_ZERO_PTE(_PointerPte) \
|
|
((_PointerPte)->Long = 0)
|
|
|
|
//++
|
|
//VOID
|
|
//MI_WRITE_AND_FLUSH_PTE(
|
|
// IN PMMPTE PointerPte,
|
|
// IN MMPTE PteContents
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MI_WRITE_AND_FLUSH_PTE fills in the specified PTE with the specified
|
|
// contents and invalidates the TLB line associated with the page.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// PointerPte - Supplies a PTE to fill.
|
|
//
|
|
// PteContents - Supplies the contents to put in the PTE.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
__inline
|
|
VOID
|
|
MI_WRITE_AND_FLUSH_PTE(
|
|
PMMPTE PointerPte,
|
|
MMPTE PteContents
|
|
)
|
|
{
|
|
MI_WRITE_PTE(PointerPte, PteContents);
|
|
|
|
__asm {
|
|
mov eax, PointerPte
|
|
shl eax, 10 ; eax = MiGetVirtualAddressMappedByPte(eax)
|
|
invlpg [eax]
|
|
}
|
|
}
|
|
|
|
//++
|
|
//VOID
|
|
//MI_FLUSH_VA(
|
|
// IN PVOID VirtualAddress
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MI_FLUSH_VA invalidates the TLB line associated with the page.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// VirtualAddress - Supplies the virtual address to flush.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
__inline
|
|
VOID
|
|
MI_FLUSH_VA(
|
|
PVOID VirtualAddress
|
|
)
|
|
{
|
|
__asm {
|
|
mov ecx, VirtualAddress
|
|
invlpg [ecx]
|
|
}
|
|
}
|
|
|
|
//++
|
|
//VOID
|
|
//MI_DISABLE_CACHING (
|
|
// IN MMPTE PTE
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro takes a valid PTE and sets the caching state to be
|
|
// disabled. This is performed by setting the PCD and PWT bits in the PTE.
|
|
//
|
|
// Semantics of the overlap between PCD, PWT, and the
|
|
// USWC memory type in the MTRR are:
|
|
//
|
|
// PCD PWT Mtrr Mem Type Effective Memory Type
|
|
// 1 0 USWC USWC
|
|
// 1 1 USWC UC
|
|
//
|
|
// Since an effective memory type of UC is desired here,
|
|
// the WT bit is set.
|
|
//
|
|
// Arguments
|
|
//
|
|
// PTE - Supplies a pointer to the valid PTE.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
#define MI_DISABLE_CACHING(PTE) { \
|
|
((PTE).Hard.CacheDisable = 1); \
|
|
((PTE).Hard.WriteThrough = 1); \
|
|
}
|
|
|
|
//++
|
|
//VOID
|
|
//MI_SET_PTE_WRITE_COMBINE (
|
|
// IN MMPTE PTE
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro takes a valid PTE and enables WriteCombining as the
|
|
// caching state. Note that the PTE bits may only be set this way
|
|
// if the Page Attribute Table is present and the PAT has been
|
|
// initialized to provide Write Combining.
|
|
//
|
|
// If either of the above conditions is not satisfied, then
|
|
// the macro enables WEAK UC (PCD = 1, PWT = 0) in the PTE.
|
|
//
|
|
// Arguments
|
|
//
|
|
// PTE - Supplies a valid PTE.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
#define MI_SET_PTE_WRITE_COMBINE(PTE) { \
|
|
((PTE).Hard.CacheDisable = 0); \
|
|
((PTE).Hard.WriteThrough = 1); \
|
|
}
|
|
|
|
//++
|
|
//PMMPTE
|
|
//MiGetPdeAddress (
|
|
// IN PVOID va
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiGetPdeAddress returns the address of the PDE which maps the
|
|
// given virtual address.
|
|
//
|
|
// Arguments
|
|
//
|
|
// Va - Supplies the virtual address to locate the PDE for.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The address of the PDE.
|
|
//
|
|
//--
|
|
|
|
#define MiGetPdeAddress(va) ((PMMPTE)(((((ULONG)(va)) >> 22) << 2) + PDE_BASE))
|
|
|
|
//++
|
|
//PMMPTE
|
|
//MiGetPteAddress (
|
|
// IN PVOID va
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiGetPteAddress returns the address of the PTE which maps the
|
|
// given virtual address.
|
|
//
|
|
// Arguments
|
|
//
|
|
// Va - Supplies the virtual address to locate the PTE for.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The address of the PTE.
|
|
//
|
|
//--
|
|
|
|
#define MiGetPteAddress(va) ((PMMPTE)(((((ULONG)(va)) >> 12) << 2) + PTE_BASE))
|
|
|
|
//++
|
|
//ULONG
|
|
//MiGetPdeOffset (
|
|
// IN PVOID va
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiGetPdeOffset returns the offset into a page directory
|
|
// for a given virtual address.
|
|
//
|
|
// Arguments
|
|
//
|
|
// Va - Supplies the virtual address to locate the offset for.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The offset into the page directory table the corresponding PDE is at.
|
|
//
|
|
//--
|
|
|
|
#define MiGetPdeOffset(va) (((ULONG)(va)) >> 22)
|
|
|
|
//++
|
|
//ULONG
|
|
//MiGetPteOffset (
|
|
// IN PVOID va
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiGetPteOffset returns the offset into a page table page
|
|
// for a given virtual address.
|
|
//
|
|
// Arguments
|
|
//
|
|
// Va - Supplies the virtual address to locate the offset for.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The offset into the page table page table the corresponding PTE is at.
|
|
//
|
|
//--
|
|
|
|
#define MiGetPteOffset(va) ((((ULONG)(va)) << 10) >> 22)
|
|
|
|
//++
|
|
//PVOID
|
|
//MiGetVirtualAddressMappedByPde (
|
|
// IN PMMPTE PTE
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiGetVirtualAddressMappedByPde returns the virtual address
|
|
// which is mapped by a given PDE address.
|
|
//
|
|
// Arguments
|
|
//
|
|
// PDE - Supplies the PDE to get the virtual address for.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Virtual address mapped by the PDE.
|
|
//
|
|
//--
|
|
|
|
#define MiGetVirtualAddressMappedByPde(PDE) ((PVOID)((ULONG)(PDE) << 20))
|
|
|
|
//++
|
|
//PVOID
|
|
//MiGetVirtualAddressMappedByPte (
|
|
// IN PMMPTE PTE
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiGetVirtualAddressMappedByPte returns the virtual address
|
|
// which is mapped by a given PTE address.
|
|
//
|
|
// Arguments
|
|
//
|
|
// PTE - Supplies the PTE to get the virtual address for.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Virtual address mapped by the PTE.
|
|
//
|
|
//--
|
|
|
|
#define MiGetVirtualAddressMappedByPte(PTE) ((PVOID)((ULONG)(PTE) << 10))
|
|
|
|
//++
|
|
//LOGICAL
|
|
//MiIsPteOnPdeBoundary (
|
|
// IN PVOID PTE
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiIsPteOnPdeBoundary returns TRUE if the PTE is
|
|
// on a page directory entry boundary.
|
|
//
|
|
// Arguments
|
|
//
|
|
// PTE - Supplies the PTE to check.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// TRUE if on a 4MB PDE boundary, FALSE if not.
|
|
//
|
|
//--
|
|
|
|
#define MiIsPteOnPdeBoundary(PTE) (((ULONG_PTR)(PTE) & (PAGE_SIZE - 1)) == 0)
|
|
|
|
//++
|
|
//MMPTE
|
|
//MiGetValidKernelPdeBits (
|
|
// VOID
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiGetValidKernelPde returns the basic bits for a valid kernel PDE.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The bits for the PDE.
|
|
//
|
|
//--
|
|
|
|
#define MiGetValidKernelPdeBits() \
|
|
(MM_PTE_VALID_MASK | MM_PTE_WRITE_MASK | MM_PTE_OWNER_MASK | MM_PTE_DIRTY_MASK | MM_PTE_ACCESS_MASK)
|
|
|
|
//++
|
|
//MMPTE
|
|
//MiGetValidKernelPteBits (
|
|
// VOID
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiGetValidKernelPde returns the basic bits for a valid kernel PTE.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The bits for the PTE.
|
|
//
|
|
//--
|
|
|
|
#define MiGetValidKernelPteBits() \
|
|
(MM_PTE_VALID_MASK | MM_PTE_WRITE_MASK | MM_PTE_DIRTY_MASK | MM_PTE_ACCESS_MASK)
|
|
|
|
//++
|
|
//MMPTE
|
|
//MiGetValidCachePteBits (
|
|
// VOID
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// MiGetValidKernelPde returns the basic bits for a valid cache PTE.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The bits for the PTE.
|
|
//
|
|
//--
|
|
|
|
#define MiGetValidCachePteBits() \
|
|
(MM_PTE_VALID_MASK | MM_PTE_WRITE_MASK | MM_PTE_ACCESS_MASK)
|
|
|
|
//++
|
|
//BOOLEAN
|
|
//MI_IS_PHYSICAL_ADDRESS (
|
|
// IN PVOID VA
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro determines if a given virtual address is really a
|
|
// physical address.
|
|
//
|
|
// Arguments
|
|
//
|
|
// VA - Supplies the virtual address.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// FALSE if it is not a physical address, TRUE if it is.
|
|
//
|
|
//--
|
|
|
|
#define MI_IS_PHYSICAL_ADDRESS(Va) \
|
|
(((ULONG)(Va) - MM_PHYSICAL_MAP_BASE) <= (MM_PHYSICAL_MAP_END - MM_PHYSICAL_MAP_BASE))
|
|
|
|
//++
|
|
//ULONG
|
|
//MI_CONVERT_PHYSICAL_TO_PFN (
|
|
// IN PVOID VA
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro converts a physical address (see MI_IS_PHYSICAL_ADDRESS)
|
|
// to its corresponding physical frame number.
|
|
//
|
|
// Arguments
|
|
//
|
|
// VA - Supplies a pointer to the physical address.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns the PFN for the page.
|
|
//
|
|
//--
|
|
|
|
#define MI_CONVERT_PHYSICAL_TO_PFN(Va) \
|
|
(((ULONG)(Va) & (MM_BYTES_IN_PHYSICAL_MAP - 1)) >> PAGE_SHIFT)
|
|
|
|
//++
|
|
//PCHAR
|
|
//MI_CONVERT_PFN_TO_PHYSICAL (
|
|
// IN PAGE_FRAME_NUMBER Pfn
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro converts a physical frame number to its corresponding
|
|
// physical address.
|
|
//
|
|
// Arguments
|
|
//
|
|
// Pfn - Supplies the physical frame number.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns the physical address for the page number.
|
|
//
|
|
//--
|
|
|
|
#define MI_CONVERT_PFN_TO_PHYSICAL(Pfn) \
|
|
((PCHAR)MM_SYSTEM_PHYSICAL_MAP + ((ULONG)(Pfn) << PAGE_SHIFT))
|
|
|
|
//++
|
|
//BOOLEAN
|
|
//MI_IS_SYSTEM_PTE_ADDRESS (
|
|
// IN PVOID VA
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro takes a virtual address and determines if
|
|
// it is an address in the system PTE space.
|
|
//
|
|
// Arguments
|
|
//
|
|
// VA - Supplies a virtual address.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// TRUE if the address is in the system PTE space, FALSE if not.
|
|
//
|
|
//--
|
|
|
|
#define MI_IS_SYSTEM_PTE_ADDRESS(Va) \
|
|
(((ULONG)(Va) - MM_SYSTEM_PTE_BASE) <= (MM_SYSTEM_PTE_END - MM_SYSTEM_PTE_BASE))
|
|
|
|
//++
|
|
//BOOLEAN
|
|
//MI_SIZE_OF_MDL (
|
|
// IN PVOID BASE,
|
|
// IN SIZE_T LENGTH
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function returns the number of bytes required for an MDL for a
|
|
// given buffer and size.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Base - Supplies the base virtual address for the buffer.
|
|
//
|
|
// Length - Supplies the size of the buffer in bytes.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns the number of bytes required to contain the MDL.
|
|
//
|
|
//--
|
|
|
|
#define MI_SIZE_OF_MDL(BASE,LENGTH) \
|
|
(sizeof(MDL) + (ADDRESS_AND_SIZE_TO_SPAN_PAGES((BASE), (LENGTH)) * sizeof(PFN_NUMBER)))
|
|
|
|
//++
|
|
//USHORT
|
|
//MiPackFreePfn(
|
|
// IN PFN_NUMBER PFN
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function packs a page frame number for storage in the MMPFN free
|
|
// link fields. The returned number must have the low bit clear in order
|
|
// to make the entry appear as non-busy.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// PFN - Supplies the page frame number.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns the packed form of the page frame number.
|
|
//
|
|
//--
|
|
|
|
#define MiPackFreePfn(PFN) \
|
|
((USHORT)((((PFN_NUMBER)(PFN)) >> MM_NUMBER_OF_COLORS_BITS) << 1))
|
|
|
|
//++
|
|
//PFN_NUMBER
|
|
//MiUnpackFreePfn(
|
|
// IN USHORT CPFN,
|
|
// IN ULONG COLOR
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function unpacks a MMPFN free link field to obtain the original
|
|
// page frame number. The low bit of the packed page frame number will
|
|
// have the low bit clear.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// CPFN - Supplies the packed page frame number.
|
|
//
|
|
// COLOR - Supplies the color of the original page frame number.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns the unpacked page frame number.
|
|
//
|
|
//--
|
|
|
|
#define MiUnpackFreePfn(CPFN,COLOR) \
|
|
((((ULONG)(CPFN)) << (MM_NUMBER_OF_COLORS_BITS - 1)) + (ULONG)(COLOR))
|
|
|
|
//++
|
|
//PMMPFN
|
|
//MiUnpackFreePfnElement(
|
|
// IN USHORT CPFN,
|
|
// IN ULONG COLOR
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function unpacks a MMPFN free link field to obtain the original
|
|
// page frame element. The low bit of the packed page frame number will
|
|
// have the low bit clear.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// CPFN - Supplies the packed page frame number.
|
|
//
|
|
// COLOR - Supplies the color of the original page frame number.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns the unpacked page frame element.
|
|
//
|
|
//--
|
|
|
|
#define MiUnpackFreePfnElement(CPFN,COLOR) \
|
|
MI_PFN_ELEMENT(MiUnpackFreePfn((CPFN),(COLOR)))
|
|
|
|
//++
|
|
//MMCOLOR
|
|
//MiGetPfnColor(
|
|
// IN ULONG PFN
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function computes the color of the supplied page frame number.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// PFN - Supplies the page frame number.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns the color of the page frame number.
|
|
//
|
|
//--
|
|
|
|
#define MiGetPfnColor(PFN) \
|
|
((PFN_NUMBER)(PFN) & (MM_NUMBER_OF_COLORS - 1))
|
|
|
|
// PVOID
|
|
// MiFindEmptyAddressRangeDown (
|
|
// IN ULONG_PTR SizeOfRange,
|
|
// IN PVOID HighestAddressToEndAt,
|
|
// IN ULONG_PTR Alignment
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// The function examines the virtual address descriptors to locate
|
|
// an unused range of the specified size and returns the starting
|
|
// address of the range. This routine looks from the top down.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// SizeOfRange - Supplies the size in bytes of the range to locate.
|
|
//
|
|
// HighestAddressToEndAt - Supplies the virtual address to begin looking
|
|
// at.
|
|
//
|
|
// Alignment - Supplies the alignment for the address. Must be
|
|
// a power of 2 and greater than the page_size.
|
|
//
|
|
//Return Value:
|
|
//
|
|
// Returns the starting address of a suitable range.
|
|
//
|
|
|
|
#define MiFindEmptyAddressRangeDown(SizeOfRange,HighestAddressToEndAt,Alignment) \
|
|
(MiFindEmptyAddressRangeDownTree( \
|
|
(SizeOfRange), \
|
|
(HighestAddressToEndAt), \
|
|
(Alignment), \
|
|
MmVadRoot))
|
|
|
|
// PMMVAD
|
|
// MiGetPreviousVad (
|
|
// IN PMMVAD Vad
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function locates the virtual address descriptor which contains
|
|
// the address range which logically precedes the specified virtual
|
|
// address descriptor.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Vad - Supplies a pointer to a virtual address descriptor.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns a pointer to the virtual address descriptor containing the
|
|
// next address range, NULL if none.
|
|
//
|
|
//
|
|
|
|
#define MiGetPreviousVad(VAD) ((PMMVAD)MiGetPreviousNode((PMMADDRESS_NODE)(VAD)))
|
|
|
|
// PMMVAD
|
|
// MiGetNextVad (
|
|
// IN PMMVAD Vad
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function locates the virtual address descriptor which contains
|
|
// the address range which logically follows the specified address range.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// VAD - Supplies a pointer to a virtual address descriptor.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns a pointer to the virtual address descriptor containing the
|
|
// next address range, NULL if none.
|
|
//
|
|
|
|
#define MiGetNextVad(VAD) ((PMMVAD)MiGetNextNode((PMMADDRESS_NODE)(VAD)))
|
|
|
|
// PMMVAD
|
|
// MiCheckForConflictingVad (
|
|
// IN PVOID StartingAddress,
|
|
// IN PVOID EndingAddress
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// The function determines if any addresses between a given starting and
|
|
// ending address is contained within a virtual address descriptor.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// StartingAddress - Supplies the virtual address to locate a containing
|
|
// descriptor.
|
|
//
|
|
// EndingAddress - Supplies the virtual address to locate a containing
|
|
// descriptor.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns a pointer to the first conflicting virtual address descriptor
|
|
// if one is found, otherwise a NULL value is returned.
|
|
//
|
|
|
|
#define MiCheckForConflictingVad(StartingAddress,EndingAddress) \
|
|
((PMMVAD)MiCheckForConflictingNode( \
|
|
MI_VA_TO_VPN(StartingAddress), \
|
|
MI_VA_TO_VPN(EndingAddress), \
|
|
MmVadRoot))
|
|
|
|
//++
|
|
//LOGICAL
|
|
//MiIsRetryIoStatus(
|
|
// IN NTSTATUS S
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function tests the supplied status code to see if the error might
|
|
// have been caused by a verifier induced error or by temporarily being out
|
|
// of system resources.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// S - Supplies the status code to test.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Returns TRUE if the I/O operation should be retried, else FALSE.
|
|
//
|
|
//--
|
|
|
|
#define MiIsRetryIoStatus(S) \
|
|
(((S) == STATUS_INSUFFICIENT_RESOURCES) || ((S) == STATUS_NO_MEMORY))
|
|
|
|
//
|
|
// Routines which operate on the page frame database.
|
|
//
|
|
|
|
VOID
|
|
MiInitializePfnDatabase(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
MiReinitializePfnDatabase(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiInsertPageInFreeList(
|
|
IN PFN_NUMBER PageFrameNumber,
|
|
IN BOOLEAN InsertAtHeadList
|
|
);
|
|
|
|
VOID
|
|
MiInsertPhysicalMemoryInFreeList(
|
|
IN PFN_NUMBER PageFrameNumber,
|
|
IN PFN_NUMBER EndingPageFrameNumberExclusive
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiRemovePageFromFreeList(
|
|
IN PFN_NUMBER PageFrameNumber
|
|
);
|
|
|
|
PFN_NUMBER
|
|
FASTCALL
|
|
MiRemoveAnyPage(
|
|
IN MMPFN_BUSY_TYPE BusyType,
|
|
IN PMMPTE TargetPte
|
|
);
|
|
|
|
PFN_NUMBER
|
|
FASTCALL
|
|
MiRemoveZeroPage(
|
|
IN MMPFN_BUSY_TYPE BusyType,
|
|
IN PMMPTE TargetPte
|
|
);
|
|
|
|
PFN_NUMBER
|
|
FASTCALL
|
|
MiRemoveDebuggerPage(
|
|
IN MMPFN_BUSY_TYPE BusyType,
|
|
IN PMMPTE TargetPte
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiRelocateBusyPage(
|
|
IN PFN_NUMBER PageFrameNumber
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiReleasePageOwnership(
|
|
IN PFN_NUMBER PageFrameNumber
|
|
);
|
|
|
|
//
|
|
// Routines to obtain and release system PTEs.
|
|
//
|
|
|
|
PMMPTE
|
|
MiReserveSystemPtes(
|
|
IN PMMPTERANGE PteRange,
|
|
IN PFN_COUNT NumberOfPtes
|
|
);
|
|
|
|
VOID
|
|
MiReleaseSystemPtes(
|
|
IN PMMPTERANGE PteRange,
|
|
IN PMMPTE StartingPte,
|
|
IN PFN_COUNT NumberOfPtes
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiZeroAndFlushPtes(
|
|
IN PMMPTE StartingPte,
|
|
IN PFN_COUNT NumberOfPtes
|
|
);
|
|
|
|
//
|
|
// Routines which operate on an address tree.
|
|
//
|
|
|
|
PMMADDRESS_NODE
|
|
FASTCALL
|
|
MiGetNextNode(
|
|
IN PMMADDRESS_NODE Node
|
|
);
|
|
|
|
PMMADDRESS_NODE
|
|
FASTCALL
|
|
MiGetPreviousNode(
|
|
IN PMMADDRESS_NODE Node
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiInsertNode(
|
|
IN PMMADDRESS_NODE Node,
|
|
IN OUT PMMADDRESS_NODE *Root
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiRemoveNode(
|
|
IN PMMADDRESS_NODE Node,
|
|
IN OUT PMMADDRESS_NODE *Root
|
|
);
|
|
|
|
PMMADDRESS_NODE
|
|
FASTCALL
|
|
MiLocateAddressInTree(
|
|
IN ULONG_PTR Vpn,
|
|
IN PMMADDRESS_NODE *Root
|
|
);
|
|
|
|
PMMADDRESS_NODE
|
|
MiCheckForConflictingNode(
|
|
IN ULONG_PTR StartVpn,
|
|
IN ULONG_PTR EndVpn,
|
|
IN PMMADDRESS_NODE Root
|
|
);
|
|
|
|
PVOID
|
|
MiFindEmptyAddressRangeInTree(
|
|
IN SIZE_T SizeOfRange,
|
|
IN ULONG_PTR Alignment,
|
|
IN PMMADDRESS_NODE Root,
|
|
OUT PMMADDRESS_NODE *PreviousVad
|
|
);
|
|
|
|
PVOID
|
|
MiFindEmptyAddressRangeDownTree(
|
|
IN SIZE_T SizeOfRange,
|
|
IN PVOID HighestAddressToEndAt,
|
|
IN ULONG_PTR Alignment,
|
|
IN PMMADDRESS_NODE Root
|
|
);
|
|
|
|
//
|
|
// Routines which operate on the tree of virtual address descriptors.
|
|
//
|
|
|
|
VOID
|
|
MiInsertVad(
|
|
IN PMMVAD Vad
|
|
);
|
|
|
|
VOID
|
|
MiRemoveVad(
|
|
IN PMMVAD Vad
|
|
);
|
|
|
|
PMMVAD
|
|
FASTCALL
|
|
MiLocateAddress(
|
|
IN PVOID Vad
|
|
);
|
|
|
|
PVOID
|
|
MiFindEmptyAddressRange(
|
|
IN SIZE_T SizeOfRange,
|
|
IN ULONG_PTR Alignment,
|
|
IN ULONG QuickCheck
|
|
);
|
|
|
|
//
|
|
// Miscellaneous routines.
|
|
//
|
|
|
|
PVOID
|
|
MiAllocateMappedMemory(
|
|
IN PMMPTERANGE PteRange,
|
|
IN MMPFN_BUSY_TYPE BusyType,
|
|
IN ULONG Protect,
|
|
IN SIZE_T NumberOfBytes,
|
|
IN PMMREMOVE_PAGE_ROUTINE RemovePageRoutine,
|
|
IN BOOLEAN AddBarrierPage
|
|
);
|
|
|
|
PFN_COUNT
|
|
MiFreeMappedMemory(
|
|
IN PMMPTERANGE PteRange,
|
|
IN PVOID BaseAddress,
|
|
IN SIZE_T NumberOfBytes OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
MiMakePteProtectionMask(
|
|
IN ULONG Protect,
|
|
OUT PULONG PteProtectionMask
|
|
);
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
MiMakeSystemPteProtectionMask(
|
|
IN ULONG Protect,
|
|
OUT PMMPTE ProtoPte
|
|
);
|
|
|
|
ULONG
|
|
FASTCALL
|
|
MiDecodePteProtectionMask(
|
|
IN ULONG PteProtectionMask
|
|
);
|
|
|
|
//
|
|
// Global data structure.
|
|
//
|
|
|
|
typedef struct _MMGLOBALDATA {
|
|
PMMPFNREGION RetailPfnRegion;
|
|
PMMPTERANGE SystemPteRange;
|
|
PULONG AvailablePages;
|
|
PFN_COUNT *AllocatedPagesByUsage;
|
|
PRTL_CRITICAL_SECTION AddressSpaceLock;
|
|
PMMADDRESS_NODE *VadRoot;
|
|
PMMADDRESS_NODE *VadHint;
|
|
PMMADDRESS_NODE *VadFreeHint;
|
|
} MMGLOBALDATA, *PMMGLOBALDATA;
|
|
|
|
//
|
|
// External symbols.
|
|
//
|
|
|
|
extern PFN_COUNT MmNumberOfPhysicalPages;
|
|
extern PMMPFNREGION MmPfnRegions[];
|
|
extern MMPFNREGION MmRetailPfnRegion;
|
|
extern MMPFNREGION MmDeveloperKitPfnRegion;
|
|
extern PFN_COUNT MmAvailablePages;
|
|
extern PFN_COUNT MmAllocatedPagesByUsage[MmMaximumUsage];
|
|
extern RTL_CRITICAL_SECTION MmAddressSpaceLock;
|
|
extern SIZE_T MmVirtualMemoryBytesReserved;
|
|
extern PMMADDRESS_NODE MmVadRoot;
|
|
extern PMMADDRESS_NODE MmVadHint;
|
|
extern PMMADDRESS_NODE MmVadFreeHint;
|
|
extern MMPTERANGE MmSystemPteRange;
|
|
extern MMPTERANGE MmDeveloperKitPteRange;
|
|
extern PFSCACHE_ELEMENT FscElementArray;
|
|
extern ULONG FscNumberOfCachePages;
|
|
extern PMMPTE FscWriteFFsPtes;
|
|
|
|
#endif // MI
|