/*++ Copyright (c) 1990 Microsoft Corporation Module Name: mipae.h Abstract: This module contains the private data structures and procedure prototypes for the hardware dependent portion of the memory management system. This module is specifically tailored for the PAE x86, Author: Landy Wang (landyw) 30-Nov-1998 Revision History: --*/ #if defined(_X86PAE_) /*++ Virtual Memory Layout on the PAE x86 is: +------------------------------------+ 00000000 | | | | | | | User Mode Addresses | | | | All pages within this range | | are potentially accessible while | | the CPU is in USER mode. | | | | | +------------------------------------+ 7ffff000 | 64k No Access Area | +------------------------------------+ 80000000 | | | NTLDR loads the kernel, HAL and | | boot drivers here. The kernel | | then relocates the drivers to the | | system PTE area. | | | | Kernel mode access only. | | | | When possible, the PFN database & | | initial non paged pool is built | | here using large page mappings. | | | +------------------------------------+ | | | Additional system PTEs, system | | cache or special pooling | | | +------------------------------------+ | | | System mapped views. | | | +------------------------------------+ | | | Session space. | | | +------------------------------------+ C0000000 | Page Table Pages mapped through | | this 8mb region | | Kernel mode access only. | | | +------------------------------------+ C0800000 | HyperSpace - working set lists | | and per process memory management | | structures mapped in this 4mb | | region. | | Kernel mode access only. | +------------------------------------+ C0C00000 | System Cache Structures | | reside in this 4mb region | | Kernel mode access only. | +------------------------------------+ C1000000 | System cache resides here. | | Kernel mode access only. | | | | | +------------------------------------+ E1000000 | Start of paged system area | | Kernel mode access only. | | | +------------------------------------+ | | | System PTE area - for mapping | | kernel thread stacks and MDLs | | that require system VAs. | | Kernel mode access only. | | | +------------------------------------+ | | | NonPaged System area | | Kernel mode access only. | | | +------------------------------------+ FFBE0000 | Crash Dump Driver area | | Kernel mode access only. | +------------------------------------+ FFC00000 | Last 4mb reserved for HAL usage | +------------------------------------+ --*/ #define _MI_PAGING_LEVELS 2 #define _MI_MORE_THAN_4GB_ 1 // // Define empty list markers. // #define MM_EMPTY_LIST ((ULONG)0xFFFFFFFF) // #define MM_EMPTY_PTE_LIST ((ULONG)0xFFFFFFFF) // N.B. tied to MMPTE definition #define MI_PTE_BASE_FOR_LOWEST_KERNEL_ADDRESS (MiGetPteAddress (0x00000000)) #define MM_SESSION_SPACE_DEFAULT (0xA0000000) #define MM_SESSION_SPACE_DEFAULT_END (0xC0000000) extern ULONG_PTR MmBootImageSize; // // PAGE_SIZE for PAE x86 is 4k, virtual page is 20 bits with a PAGE_SHIFT // byte offset. // #define MM_VIRTUAL_PAGE_FILLER 0 #define MM_VIRTUAL_PAGE_SIZE 20 // // Address space layout definitions. // #define MM_KSEG0_BASE ((ULONG)0x80000000) #define MM_KSEG2_BASE ((ULONG)0xA0000000) #define MM_PAGES_IN_KSEG0 ((MM_KSEG2_BASE - MM_KSEG0_BASE) >> PAGE_SHIFT) #define CODE_START MM_KSEG0_BASE #define CODE_END MM_KSEG2_BASE #define MM_SYSTEM_SPACE_START (0xC0C00000) #define MM_SYSTEM_SPACE_END (0xFFFFFFFF) #define HYPER_SPACE ((PVOID)0xC0800000) #define HYPER_SPACE2 ((PVOID)0xC0A00000) #define HYPER_SPACE_END (0xC0BFFFFF) #define MM_SYSTEM_VIEW_START (0xA0000000) #define MM_SYSTEM_VIEW_SIZE (16*1024*1024) #define MM_USER_ADDRESS_RANGE_LIMIT 0xFFFFFFFF // user address range limit #define MM_MAXIMUM_ZERO_BITS 21 // maximum number of zero bits // // Define the start and maximum size for the system cache. // Maximum size is normally 512MB, but can be up to 512MB + 448MB = 960MB for // large system cache machines. // #define MM_SYSTEM_CACHE_WORKING_SET (0xC0C00000) #define MM_SYSTEM_CACHE_START (0xC1000000) #define MM_SYSTEM_CACHE_END (0xE1000000) // // // Various resources like additional system PTEs or system cache views, etc, // can be allocated out of this virtual address range. // extern ULONG MiExtraResourceStart; extern ULONG MiExtraResourceEnd; extern ULONG_PTR MiUseMaximumSystemSpace; extern ULONG_PTR MiUseMaximumSystemSpaceEnd; extern ULONG MiNumberOfExtraSystemPdes; extern ULONG MiMaximumSystemExtraSystemPdes; extern ULONG MiMaximumSystemCacheSizeExtra; extern PVOID MiSystemCacheStartExtra; extern PVOID MiSystemCacheEndExtra; #define MM_SYSTEM_CACHE_END_EXTRA (0xC0000000) #define MM_PAGED_POOL_START (MmPagedPoolStart) #define MM_DEFAULT_PAGED_POOL_START (0xE1000000) #define MM_LOWEST_NONPAGED_SYSTEM_START ((PVOID)(0xEB000000)) #define MmProtopte_Base ((ULONG)MmPagedPoolStart) #define MM_NONPAGED_POOL_END ((PVOID)(0xFFBE0000)) #define MM_CRASH_DUMP_VA ((PVOID)(0xFFBE0000)) #define MM_DEBUG_VA ((PVOID)0xFFBFF000) #define NON_PAGED_SYSTEM_END ((ULONG)0xFFFFFFF0) //quadword aligned. extern BOOLEAN MiWriteCombiningPtes; LOGICAL MiRecoverExtraPtes ( VOID ); // // Define absolute minimum and maximum count for system PTEs. // #define MM_MINIMUM_SYSTEM_PTES 7000 #define MM_MAXIMUM_SYSTEM_PTES 50000 #define MM_DEFAULT_SYSTEM_PTES 11000 // // Pool limits // // // The maximum amount of nonpaged pool that can be initially created. // #define MM_MAX_INITIAL_NONPAGED_POOL ((ULONG)(128*1024*1024)) // // The total amount of nonpaged pool (initial pool + expansion). // #define MM_MAX_ADDITIONAL_NONPAGED_POOL ((ULONG)(128*1024*1024)) // // The maximum amount of paged pool that can be created. // #define MM_MAX_PAGED_POOL ((ULONG)MM_NONPAGED_POOL_END - (ULONG)MM_PAGED_POOL_START) #define MM_MAX_TOTAL_POOL (((ULONG)MM_NONPAGED_POOL_END) - ((ULONG)(MM_PAGED_POOL_START))) // // Structure layout definitions. // #define MM_PROTO_PTE_ALIGNMENT ((ULONG)PAGE_SIZE) #define PAGE_DIRECTORY_MASK ((ULONG)0x001FFFFF) #define MM_VA_MAPPED_BY_PDE (0x200000) #define LOWEST_IO_ADDRESS 0xa0000 #define PTE_SHIFT 3 // // The number of bits in a physical address. // #define PHYSICAL_ADDRESS_BITS 36 #define MM_MAXIMUM_NUMBER_OF_COLORS (1) // // x86 does not require support for colored pages. // #define MM_NUMBER_OF_COLORS (1) // // Mask for obtaining color from a physical page number. // #define MM_COLOR_MASK (0) // // Boundary for aligned pages of like color upon. // #define MM_COLOR_ALIGNMENT (0) // // Mask for isolating color from virtual address. // #define MM_COLOR_MASK_VIRTUAL (0) // // Define 256k worth of secondary colors. // #define MM_SECONDARY_COLORS_DEFAULT (64) #define MM_SECONDARY_COLORS_MIN (2) #define MM_SECONDARY_COLORS_MAX (1024) // // Maximum number of paging files. // #define MAX_PAGE_FILES 16 // // Hyper space definitions. // #define FIRST_MAPPING_PTE ((ULONG)0xC0801000) #define NUMBER_OF_MAPPING_PTES 126 #define LAST_MAPPING_PTE \ ((ULONG)((ULONG)FIRST_MAPPING_PTE + (NUMBER_OF_MAPPING_PTES * PAGE_SIZE))) #define COMPRESSION_MAPPING_PTE ((PMMPTE)((ULONG)LAST_MAPPING_PTE + PAGE_SIZE)) #define IMAGE_MAPPING_PTE ((PMMPTE)((ULONG)COMPRESSION_MAPPING_PTE + PAGE_SIZE)) #define NUMBER_OF_ZEROING_PTES 256 // // This bitmap consumes 4K when booted /2GB and 6K when booted /3GB, thus // the working set list start is variable. // #define VAD_BITMAP_SPACE ((PVOID)((ULONG)IMAGE_MAPPING_PTE + PAGE_SIZE)) #define WORKING_SET_LIST MmWorkingSetList #define MM_MAXIMUM_WORKING_SET MiMaximumWorkingSet #define MmWsle ((PMMWSLE)((PUCHAR)WORKING_SET_LIST + sizeof(MMWSL))) extern ULONG MiMaximumWorkingSet; #define MM_WORKING_SET_END ((ULONG)0xC0BFF000) // // Define masks for fields within the PTE. /// #define MM_PTE_VALID_MASK 0x1 #if defined(NT_UP) #define MM_PTE_WRITE_MASK 0x2 #else #define MM_PTE_WRITE_MASK 0x800 #endif #define MM_PTE_OWNER_MASK 0x4 #define MM_PTE_WRITE_THROUGH_MASK 0x8 #define MM_PTE_CACHE_DISABLE_MASK 0x10 #define MM_PTE_ACCESS_MASK 0x20 #if defined(NT_UP) #define MM_PTE_DIRTY_MASK 0x40 #else #define MM_PTE_DIRTY_MASK 0x42 #endif #define MM_PTE_LARGE_PAGE_MASK 0x80 #define MM_PTE_GLOBAL_MASK 0x100 #define MM_PTE_COPY_ON_WRITE_MASK 0x200 #define MM_PTE_PROTOTYPE_MASK 0x400 #define MM_PTE_TRANSITION_MASK 0x800 // // Bit fields to or into PTE to make a PTE valid based on the // protection field of the invalid PTE. // #define MM_PTE_NOACCESS 0x0 // not expressable on x86 #define MM_PTE_READONLY 0x0 #define MM_PTE_READWRITE MM_PTE_WRITE_MASK #define MM_PTE_WRITECOPY 0x200 // read-only copy on write bit set. #define MM_PTE_EXECUTE 0x0 // read-only on x86 #define MM_PTE_EXECUTE_READ 0x0 #define MM_PTE_EXECUTE_READWRITE MM_PTE_WRITE_MASK #define MM_PTE_EXECUTE_WRITECOPY 0x200 // read-only copy on write bit set. #define MM_PTE_NOCACHE 0x010 #define MM_PTE_GUARD 0x0 // not expressable on x86 #define MM_PTE_CACHE 0x0 #define MM_PROTECT_FIELD_SHIFT 5 // // Bits available for the software working set index within the hardware PTE. // #define MI_MAXIMUM_PTE_WORKING_SET_INDEX 0 // // Zero PTE // #define MM_ZERO_PTE 0 // // Zero Kernel PTE // #define MM_ZERO_KERNEL_PTE 0 // // A demand zero PTE with a protection of PAGE_READWRITE. // #define MM_DEMAND_ZERO_WRITE_PTE (MM_READWRITE << MM_PROTECT_FIELD_SHIFT) // // A demand zero PTE with a protection of PAGE_READWRITE for system space. // #define MM_KERNEL_DEMAND_ZERO_PTE (MM_READWRITE << MM_PROTECT_FIELD_SHIFT) // // A no access PTE for system space. // #define MM_KERNEL_NOACCESS_PTE (MM_NOACCESS << MM_PROTECT_FIELD_SHIFT) // // Kernel stack alignment requirements. // #define MM_STACK_ALIGNMENT 0x0 #define MM_STACK_OFFSET 0x0 // // System process definitions // #define PDE_PER_PAGE ((ULONG)512) #define PTE_PER_PAGE ((ULONG)512) #define PD_PER_SYSTEM ((ULONG)4) // // Number of page table pages for user addresses. // #define MM_USER_PAGE_TABLE_PAGES (1536) VOID MiPaeInitialize ( VOID ); //++ //VOID //MI_MAKE_VALID_PTE ( // OUT OUTPTE, // IN FRAME, // IN PMASK, // IN PPTE // ); // // Routine Description: // // This macro makes a valid PTE from a page frame number, protection mask, // and owner. // // Arguments // // OUTPTE - Supplies the PTE in which to build the transition PTE. // // FRAME - Supplies the page frame number for the PTE. // // PMASK - Supplies the protection to set in the transition PTE. // // PPTE - Supplies a pointer to the PTE which is being made valid. // For prototype PTEs NULL should be specified. // // Return Value: // // None. // //-- #define MI_MAKE_VALID_PTE(OUTPTE,FRAME,PMASK,PPTE) \ (OUTPTE).u.Long = (((ULONGLONG)FRAME << 12) | \ (MmProtectToPteMask[PMASK]) | \ MiDetermineUserGlobalPteMask ((PMMPTE)PPTE)); \ if (MmPaeMask != 0) { \ if (((PPTE) >= (PMMPTE)PDE_BASE) && ((PPTE) < (PMMPTE)PDE_TOP)) { \ (OUTPTE).u.Long &= ~MmPaeMask; \ } \ } //++ //VOID //MI_MAKE_VALID_PTE_TRANSITION ( // IN OUT OUTPTE // IN PROTECT // ); // // Routine Description: // // This macro takes a valid pte and turns it into a transition PTE. // // Arguments // // OUTPTE - Supplies the current valid PTE. This PTE is then // modified to become a transition PTE. // // PROTECT - Supplies the protection to set in the transition PTE. // // Return Value: // // None. // //-- #define MI_MAKE_VALID_PTE_TRANSITION(OUTPTE,PROTECT) \ (OUTPTE).u.Soft.Transition = 1; \ (OUTPTE).u.Soft.Valid = 0; \ (OUTPTE).u.Soft.Prototype = 0; \ (OUTPTE).u.Soft.Protection = PROTECT; //++ //VOID //MI_MAKE_TRANSITION_PTE ( // OUT OUTPTE, // IN PAGE, // IN PROTECT, // IN PPTE // ); // // Routine Description: // // This macro takes a valid pte and turns it into a transition PTE. // // Arguments // // OUTPTE - Supplies the PTE in which to build the transition PTE. // // PAGE - Supplies the page frame number for the PTE. // // PROTECT - Supplies the protection to set in the transition PTE. // // PPTE - Supplies a pointer to the PTE, this is used to determine // the owner of the PTE. // // Return Value: // // None. // //-- #define MI_MAKE_TRANSITION_PTE(OUTPTE,PAGE,PROTECT,PPTE) \ (OUTPTE).u.Long = 0; \ (OUTPTE).u.Trans.PageFrameNumber = PAGE; \ (OUTPTE).u.Trans.Transition = 1; \ (OUTPTE).u.Trans.Protection = PROTECT; \ (OUTPTE).u.Trans.Owner = MI_DETERMINE_OWNER(PPTE); //++ //VOID //MI_MAKE_TRANSITION_PTE_VALID ( // OUT OUTPTE, // IN PPTE // ); // // Routine Description: // // This macro takes a transition pte and makes it a valid PTE. // // Arguments // // OUTPTE - Supplies the PTE in which to build the valid PTE. // // PPTE - Supplies a pointer to the transition PTE. // // Return Value: // // None. // //-- #define MI_MAKE_TRANSITION_PTE_VALID(OUTPTE,PPTE) \ ASSERT (((PPTE)->u.Hard.Valid == 0) && \ ((PPTE)->u.Trans.Prototype == 0) && \ ((PPTE)->u.Trans.Transition == 1)); \ (OUTPTE).u.Long = (((PPTE)->u.Long & ~0xFFF) | \ (MmProtectToPteMask[(PPTE)->u.Trans.Protection]) | \ MiDetermineUserGlobalPteMask ((PMMPTE)PPTE)); #define MI_FAULT_STATUS_INDICATES_EXECUTION(_FaultStatus) (_FaultStatus & MmPaeErrMask) #define MI_FAULT_STATUS_INDICATES_WRITE(_FaultStatus) (_FaultStatus & 0x1) #define MI_CLEAR_FAULT_STATUS(_FaultStatus) (_FaultStatus = 0) #define MI_IS_PTE_EXECUTABLE(_TempPte) (((_TempPte)->u.Long & MmPaeMask) == 0) //++ //VOID //MI_SET_PTE_IN_WORKING_SET ( // OUT PMMPTE PTE, // IN ULONG WSINDEX // ); // // Routine Description: // // This macro inserts the specified working set index into the argument PTE. // Since the x86 PTE has no free bits in the valid PTE, nothing needs to // be done on this architecture. // // Arguments // // OUTPTE - Supplies the PTE in which to insert the working set index. // // WSINDEX - Supplies the working set index for the PTE. // // Return Value: // // None. // //-- #define MI_SET_PTE_IN_WORKING_SET(PTE, WSINDEX) //++ //ULONG WsIndex //MI_GET_WORKING_SET_FROM_PTE( // IN PMMPTE PTE // ); // // Routine Description: // // This macro returns the working set index from the argument PTE. // Since the x86 PTE has no free bits in the valid PTE, nothing needs to // be done on this architecture. // // Arguments // // PTE - Supplies the PTE to extract the working set index from. // // Return Value: // // This macro returns the working set index for the argument PTE. // //-- #define MI_GET_WORKING_SET_FROM_PTE(PTE) 0 //++ //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) \ { \ if (MiWriteCombiningPtes == TRUE) { \ ((PTE).u.Hard.CacheDisable = 0); \ ((PTE).u.Hard.WriteThrough = 1); \ } else { \ ((PTE).u.Hard.CacheDisable = 1); \ ((PTE).u.Hard.WriteThrough = 0); \ } \ } //++ //VOID //MI_PREPARE_FOR_NONCACHED ( // IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute // ); // // Routine Description: // // This macro prepares the system prior to noncached PTEs being created. // // Note the entire TB must be flushed on all processors because there may // be stale system PTE (or hyperspace or zeropage) mappings in the TB which // may refer to the same physical page but with a different cache attribute. // // Arguments // // CacheAttribute - Supplies the cache attribute the PTEs will be filled // with. // // Return Value: // // None. // //-- #define MI_PREPARE_FOR_NONCACHED(_CacheAttribute) \ if (_CacheAttribute != MiCached) { \ KeFlushEntireTb (FALSE, TRUE); \ KeInvalidateAllCaches (TRUE); \ } //++ //VOID //MI_SWEEP_CACHE ( // IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute, // IN PVOID StartVa, // IN ULONG NumberOfBytes // ); // // Routine Description: // // This macro prepares the system prior to noncached PTEs being created. // This does nothing on x86. // // Arguments // // CacheAttribute - Supplies the cache attribute the PTEs were filled with. // // StartVa - Supplies the starting address that's been mapped. // // NumberOfBytes - Supplies the number of bytes that have been mapped. // // Return Value: // // None. // //-- #define MI_SWEEP_CACHE(_CacheType,_StartVa,_NumberOfBytes) LOGICAL MiMustFrameBeCached ( IN PFN_NUMBER PageFrameIndex ); typedef struct _MI_LARGE_PAGE_RANGES { PFN_NUMBER StartFrame; PFN_NUMBER LastFrame; } MI_LARGE_PAGE_RANGES, *PMI_LARGE_PAGE_RANGES; extern ULONG MiLargePageRangeIndex; extern MI_LARGE_PAGE_RANGES MiLargePageRanges[]; #define MI_PAGE_FRAME_INDEX_MUST_BE_CACHED(PageFrameIndex) \ MiMustFrameBeCached (PageFrameIndex) //++ //VOID //MI_SET_PTE_DIRTY ( // IN MMPTE PTE // ); // // Routine Description: // // This macro sets the dirty bit(s) in the specified PTE. // // Arguments // // PTE - Supplies the PTE to set dirty. // // Return Value: // // None. // //-- #define MI_SET_PTE_DIRTY(PTE) (PTE).u.Long |= HARDWARE_PTE_DIRTY_MASK //++ //VOID //MI_SET_PTE_CLEAN ( // IN MMPTE PTE // ); // // Routine Description: // // This macro clears the dirty bit(s) in the specified PTE. // // Arguments // // PTE - Supplies the PTE to set clear. // // Return Value: // // None. // //-- #define MI_SET_PTE_CLEAN(PTE) (PTE).u.Long &= ~HARDWARE_PTE_DIRTY_MASK //++ //VOID //MI_IS_PTE_DIRTY ( // IN MMPTE PTE // ); // // Routine Description: // // This macro checks the dirty bit(s) in the specified PTE. // // Arguments // // PTE - Supplies the PTE to check. // // Return Value: // // TRUE if the page is dirty (modified), FALSE otherwise. // //-- #define MI_IS_PTE_DIRTY(PTE) ((PTE).u.Hard.Dirty != 0) //++ //VOID //MI_SET_GLOBAL_BIT_IF_SYSTEM ( // OUT OUTPTE, // IN PPTE // ); // // Routine Description: // // This macro sets the global bit if the pointer PTE is within // system space. // // Arguments // // OUTPTE - Supplies the PTE in which to build the valid PTE. // // PPTE - Supplies a pointer to the PTE becoming valid. // // Return Value: // // None. // //-- #define MI_SET_GLOBAL_BIT_IF_SYSTEM(OUTPTE,PPTE) \ if ((((PMMPTE)PPTE) > MiHighestUserPte) && \ ((((PMMPTE)PPTE) <= MiGetPteAddress (PTE_BASE)) || \ (((PMMPTE)PPTE) >= MiGetPteAddress (MM_SYSTEM_CACHE_WORKING_SET)))) { \ (OUTPTE).u.Long |= MmPteGlobal.u.Long; \ } \ else { \ (OUTPTE).u.Long &= ~MmPteGlobal.u.Long; \ } //++ //VOID //MI_SET_GLOBAL_STATE ( // IN MMPTE PTE, // IN ULONG STATE // ); // // Routine Description: // // This macro sets the global bit in the PTE based on the state argument. // // Arguments // // PTE - Supplies the PTE to set global state into. // // STATE - Supplies 1 if global, 0 if not. // // Return Value: // // None. // //-- #define MI_SET_GLOBAL_STATE(PTE,STATE) \ if (STATE) { \ (PTE).u.Long |= MmPteGlobal.u.Long; \ } \ else { \ (PTE).u.Long &= ~MmPteGlobal.u.Long; \ } //++ //VOID //MI_ENABLE_CACHING ( // IN MMPTE PTE // ); // // Routine Description: // // This macro takes a valid PTE and sets the caching state to be // enabled. This is performed by clearing 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 // // Arguments // // PTE - Supplies a valid PTE. // // Return Value: // // None. // //-- #define MI_ENABLE_CACHING(PTE) \ { \ ((PTE).u.Hard.CacheDisable = 0); \ ((PTE).u.Hard.WriteThrough = 0); \ } //++ //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).u.Hard.CacheDisable = 1); \ ((PTE).u.Hard.WriteThrough = 1); \ } //++ //BOOLEAN //MI_IS_CACHING_DISABLED ( // IN PMMPTE PPTE // ); // // Routine Description: // // This macro takes a valid PTE and returns TRUE if caching is // disabled. // // Arguments // // PPTE - Supplies a pointer to the valid PTE. // // Return Value: // // TRUE if caching is disabled, FALSE if it is enabled. // //-- #define MI_IS_CACHING_DISABLED(PPTE) \ ((PPTE)->u.Hard.CacheDisable == 1) //++ //VOID //MI_SET_PFN_DELETED ( // IN PMMPFN PPFN // ); // // Routine Description: // // This macro takes a pointer to a PFN element and indicates that // the PFN is no longer in use. // // Arguments // // PPFN - Supplies a pointer to the PFN element. // // Return Value: // // none. // //-- #define MI_SET_PFN_DELETED(PPFN) \ PPFN->PteAddress = (PMMPTE)(((ULONG_PTR)(PPFN->PteAddress)) | 0x1); //++ //VOID //MI_MARK_PFN_UNDELETED ( // IN PMMPFN PPFN // ); // // Routine Description: // // This macro takes a pointer to a deleted PFN element and mark that // the PFN is not deleted. // // Arguments // // PPTE - Supplies a pointer to the PFN element. // // Return Value: // // none. // //-- #define MI_MARK_PFN_UNDELETED(PPFN) \ PPFN->PteAddress = (PMMPTE)((ULONG_PTR)PPFN->PteAddress & ~0x1); //++ //BOOLEAN //MI_IS_PFN_DELETED ( // IN PMMPFN PPFN // ); // // Routine Description: // // This macro takes a pointer to a PFN element and determines if // the PFN is no longer in use. // // Arguments // // PPTE - Supplies a pointer to the PFN element. // // Return Value: // // TRUE if PFN is no longer used, FALSE if it is still being used. // //-- #define MI_IS_PFN_DELETED(PPFN) \ ((ULONG_PTR)(PPFN)->PteAddress & 0x1) //++ //VOID //MI_CHECK_PAGE_ALIGNMENT ( // IN ULONG PAGE, // IN PMMPTE PPTE // ); // // Routine Description: // // This macro takes a PFN element number (Page) and checks to see // if the virtual alignment for the previous address of the page // is compatible with the new address of the page. If they are // not compatible, the D cache is flushed. // // Arguments // // PAGE - Supplies the PFN element. // PPTE - Supplies a pointer to the new PTE which will contain the page. // // Return Value: // // none. // //-- // does nothing on x86. #define MI_CHECK_PAGE_ALIGNMENT(PAGE,PPTE) //++ //VOID //MI_INITIALIZE_HYPERSPACE_MAP ( // VOID // ); // // Routine Description: // // This macro initializes the PTEs reserved for double mapping within // hyperspace. // // Arguments // // None. // // Return Value: // // None. // //-- // does nothing on x86. #define MI_INITIALIZE_HYPERSPACE_MAP(INDEX) //++ //ULONG //MI_GET_PAGE_COLOR_FROM_PTE ( // IN PMMPTE PTEADDRESS // ); // // Routine Description: // // This macro determines the page's color based on the PTE address // that maps the page. // // Arguments // // PTEADDRESS - Supplies the PTE address the page is (or was) mapped at. // // Return Value: // // The page's color. // //-- #define MI_GET_PAGE_COLOR_FROM_PTE(PTEADDRESS) \ ((ULONG)((MI_SYSTEM_PAGE_COLOR++) & MmSecondaryColorMask) | MI_CURRENT_NODE_COLOR) //++ //ULONG //MI_GET_PAGE_COLOR_FROM_VA ( // IN PVOID ADDRESS // ); // // Routine Description: // // This macro determines the page's color based on the PTE address // that maps the page. // // Arguments // // ADDRESS - Supplies the address the page is (or was) mapped at. // // Return Value: // // The page's color. // //-- #define MI_GET_PAGE_COLOR_FROM_VA(ADDRESS) \ ((ULONG)((MI_SYSTEM_PAGE_COLOR++) & MmSecondaryColorMask) | MI_CURRENT_NODE_COLOR) //++ //ULONG //MI_GET_PAGE_COLOR_FROM_SESSION ( // IN PMM_SESSION_SPACE SessionSpace // ); // // Routine Description: // // This macro determines the page's color based on the PTE address // that maps the page. // // Arguments // // SessionSpace - Supplies the session space the page will be mapped into. // // Return Value: // // The page's color. // //-- #define MI_GET_PAGE_COLOR_FROM_SESSION(_SessionSpace) \ ((ULONG)((_SessionSpace->Color++) & MmSecondaryColorMask) | MI_CURRENT_NODE_COLOR) //++ //ULONG //MI_PAGE_COLOR_PTE_PROCESS ( // IN PMMPTE PTE, // IN PUSHORT COLOR // ); // // Routine Description: // // Select page color for this process. // // Arguments // // PTE Not used. // COLOR Value from which color is determined. This // variable is incremented. // // Return Value: // // Page color. // //-- #define MI_PAGE_COLOR_PTE_PROCESS(PTE,COLOR) \ (((ULONG)((*(COLOR))++) & MmSecondaryColorMask) | MI_CURRENT_NODE_COLOR) //++ //ULONG //MI_PAGE_COLOR_VA_PROCESS ( // IN PVOID ADDRESS, // IN PEPROCESS COLOR // ); // // Routine Description: // // This macro determines the page's color based on the PTE address // that maps the page. // // Arguments // // ADDRESS - Supplies the address the page is (or was) mapped at. // // Return Value: // // The page's color. // //-- #define MI_PAGE_COLOR_VA_PROCESS(ADDRESS,COLOR) \ (((ULONG)((*(COLOR))++) & MmSecondaryColorMask) | MI_CURRENT_NODE_COLOR) //++ //ULONG //MI_GET_NEXT_COLOR ( // IN ULONG COLOR // ); // // Routine Description: // // This macro returns the next color in the sequence. // // Arguments // // COLOR - Supplies the color to return the next of. // // Return Value: // // Next color in sequence. // //-- #define MI_GET_NEXT_COLOR(COLOR) ((COLOR + 1) & MM_COLOR_MASK) //++ //ULONG //MI_GET_PREVIOUS_COLOR ( // IN ULONG COLOR // ); // // Routine Description: // // This macro returns the previous color in the sequence. // // Arguments // // COLOR - Supplies the color to return the previous of. // // Return Value: // // Previous color in sequence. // //-- #define MI_GET_PREVIOUS_COLOR(COLOR) (0) #define MI_GET_SECONDARY_COLOR(PAGE,PFN) (PAGE & MmSecondaryColorMask) #define MI_GET_COLOR_FROM_SECONDARY(SECONDARY_COLOR) (0) //++ //VOID //MI_GET_MODIFIED_PAGE_BY_COLOR ( // OUT ULONG PAGE, // IN ULONG COLOR // ); // // Routine Description: // // This macro returns the first page destined for a paging // file with the desired color. It does NOT remove the page // from its list. // // Arguments // // PAGE - Returns the page located, the value MM_EMPTY_LIST is // returned if there is no page of the specified color. // // COLOR - Supplies the color of page to locate. // // Return Value: // // none. // //-- #define MI_GET_MODIFIED_PAGE_BY_COLOR(PAGE,COLOR) \ PAGE = MmModifiedPageListByColor[COLOR].Flink //++ //VOID //MI_GET_MODIFIED_PAGE_ANY_COLOR ( // OUT ULONG PAGE, // IN OUT ULONG COLOR // ); // // Routine Description: // // This macro returns the first page destined for a paging // file with the desired color. If not page of the desired // color exists, all colored lists are searched for a page. // It does NOT remove the page from its list. // // Arguments // // PAGE - Returns the page located, the value MM_EMPTY_LIST is // returned if there is no page of the specified color. // // COLOR - Supplies the color of page to locate and returns the // color of the page located. // // Return Value: // // none. // //-- #define MI_GET_MODIFIED_PAGE_ANY_COLOR(PAGE,COLOR) \ { \ if (MmTotalPagesForPagingFile == 0) { \ PAGE = MM_EMPTY_LIST; \ } else { \ PAGE = MmModifiedPageListByColor[COLOR].Flink; \ } \ } //++ //VOID //MI_MAKE_VALID_PTE_WRITE_COPY ( // IN OUT PMMPTE PTE // ); // // Routine Description: // // This macro checks to see if the PTE indicates that the // page is writable and if so it clears the write bit and // sets the copy-on-write bit. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // None. // //-- #if defined(NT_UP) #define MI_MAKE_VALID_PTE_WRITE_COPY(PPTE) \ if ((PPTE)->u.Hard.Write == 1) { \ (PPTE)->u.Hard.CopyOnWrite = 1; \ (PPTE)->u.Hard.Write = 0; \ } #else #define MI_MAKE_VALID_PTE_WRITE_COPY(PPTE) \ if ((PPTE)->u.Hard.Write == 1) { \ (PPTE)->u.Hard.CopyOnWrite = 1; \ (PPTE)->u.Hard.Write = 0; \ (PPTE)->u.Hard.Writable = 0; \ } #endif //++ //ULONG //MI_DETERMINE_OWNER ( // IN MMPTE PPTE // ); // // Routine Description: // // This macro examines the virtual address of the PTE and determines // if the PTE resides in system space or user space. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // 1 if the owner is USER_MODE, 0 if the owner is KERNEL_MODE. // //-- #define MI_DETERMINE_OWNER(PPTE) \ ((((PPTE) <= MiHighestUserPte) || \ ((PPTE) >= MiGetPdeAddress(NULL) && \ ((PPTE) <= MiHighestUserPde))) ? 1 : 0) //++ //VOID //MI_SET_ACCESSED_IN_PTE ( // IN OUT MMPTE PPTE // ); // // Routine Description: // // This macro sets the ACCESSED field in the PTE. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // None // //-- #define MI_SET_ACCESSED_IN_PTE(PPTE,ACCESSED) \ ((PPTE)->u.Hard.Accessed = ACCESSED) //++ //ULONG //MI_GET_ACCESSED_IN_PTE ( // IN OUT MMPTE PPTE // ); // // Routine Description: // // This macro returns the state of the ACCESSED field in the PTE. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // The state of the ACCESSED field. // //-- #define MI_GET_ACCESSED_IN_PTE(PPTE) ((PPTE)->u.Hard.Accessed) //++ //VOID //MI_SET_OWNER_IN_PTE ( // IN PMMPTE PPTE // IN ULONG OWNER // ); // // Routine Description: // // This macro sets the owner field in the PTE. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // None. // //-- #define MI_SET_OWNER_IN_PTE(PPTE,OWNER) ((PPTE)->u.Hard.Owner = OWNER) //++ //ULONG //MI_GET_OWNER_IN_PTE ( // IN PMMPTE PPTE // ); // // Routine Description: // // This macro gets the owner field from the PTE. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // The state of the OWNER field. // //-- #define MI_GET_OWNER_IN_PTE(PPTE) ((PPTE)->u.Hard.Owner) // // bit mask to clear out fields in a PTE to or in paging file location. // #define CLEAR_FOR_PAGE_FILE 0x000003E0 //++ //VOID //MI_SET_PAGING_FILE_INFO ( // OUT MMPTE OUTPTE, // IN MMPTE PPTE, // IN ULONG FILEINFO, // IN ULONG OFFSET // ); // // Routine Description: // // This macro sets into the specified PTE the supplied information // to indicate where the backing store for the page is located. // // Arguments // // OUTPTE - Supplies the PTE in which to store the result. // // PTE - Supplies the PTE to operate upon. // // FILEINFO - Supplies the number of the paging file. // // OFFSET - Supplies the offset into the paging file. // // Return Value: // // None. // //-- #define MI_SET_PAGING_FILE_INFO(OUTPTE,PPTE,FILEINFO,OFFSET) \ (OUTPTE).u.Long = (PPTE).u.Long; \ (OUTPTE).u.Long &= CLEAR_FOR_PAGE_FILE; \ (OUTPTE).u.Long |= (FILEINFO << 1); \ (OUTPTE).u.Soft.PageFileHigh = (OFFSET); //++ //PMMPTE //MiPteToProto ( // IN OUT MMPTE PPTE, // IN ULONG FILEINFO, // IN ULONG OFFSET // ); // // Routine Description: // // This macro returns the address of the corresponding prototype which // was encoded earlier into the supplied PTE. // // Arguments // // lpte - Supplies the PTE to operate upon. // // Return Value: // // Pointer to the prototype PTE that backs this PTE. // //-- #define MiPteToProto(lpte) \ ((PMMPTE)(ULONG_PTR)((lpte)->u.Proto.ProtoAddress)) //++ //MMPTE //MiProtoAddressForPte ( // IN PMMPTE proto_va // ); // // Routine Description: // // This macro sets into the specified PTE the supplied information // to indicate where the backing store for the page is located. // MiProtoAddressForPte returns the bit field to OR into the PTE to // reference a prototype PTE. And set the protoPTE bit, // // N.B. This macro is dependent on the layout of the prototype PTE. // // Arguments // // proto_va - Supplies the address of the prototype PTE. // // Return Value: // // Mask to set into the PTE. // //-- #define MiProtoAddressForPte(proto_va) \ (((ULONGLONG)proto_va << 32) | MM_PTE_PROTOTYPE_MASK) //++ //ULONG //MiProtoAddressForKernelPte ( // IN PMMPTE proto_va // ); // // Routine Description: // // This macro sets into the specified PTE the supplied information // to indicate where the backing store for the page is located. // MiProtoAddressForPte returns the bit field to OR into the PTE to // reference a prototype PTE. And set the protoPTE bit, // MM_PTE_PROTOTYPE_MASK. // // This macro also sets any other information (such as global bits) // required for kernel mode PTEs. // // Arguments // // proto_va - Supplies the address of the prototype PTE. // // Return Value: // // Mask to set into the PTE. // //-- // not different on x86. #define MiProtoAddressForKernelPte(proto_va) MiProtoAddressForPte(proto_va) //++ //PSUBSECTION //MiGetSubsectionAddress ( // IN PMMPTE lpte // ); // // Routine Description: // // This macro takes a PTE and returns the address of the subsection that // the PTE refers to. Subsections are quadword structures allocated // from nonpaged pool. // // Arguments // // lpte - Supplies the PTE to operate upon. // // Return Value: // // A pointer to the subsection referred to by the supplied PTE. // //-- #define MiGetSubsectionAddress(lpte) \ ((PSUBSECTION)(ULONG_PTR)((lpte)->u.Subsect.SubsectionAddress)) //++ //ULONG //MiGetSubsectionAddressForPte ( // IN PSUBSECTION VA // ); // // Routine Description: // // This macro takes the address of a subsection and encodes it for use // in a PTE. // // Arguments // // VA - Supplies a pointer to the subsection to encode. // // Return Value: // // The mask to set into the PTE to make it reference the supplied // subsection. // //-- #define MiGetSubsectionAddressForPte(VA) ((ULONGLONG)VA << 32) //++ //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)(PDE_BASE + ((((ULONG)(va)) >> 21) << 3))) //++ //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)(PTE_BASE + ((((ULONG)(va)) >> 12) << 3))) //++ //ULONG //MiGetPpeOffset ( // IN PVOID va // ); // // Routine Description: // // MiGetPpeOffset returns the offset into a page root // for a given virtual address. // // Arguments // // Va - Supplies the virtual address to locate the offset for. // // Return Value: // // The offset into the page root table the corresponding PPE is at. // //-- #define MiGetPpeOffset(va) (0) //++ //ULONG //MiGetPdPteOffset ( // IN PVOID va // ); // // Routine Description: // // MiGetPdPteOffset returns the offset into a page directory // pointer PTE table for a given virtual address. // // Arguments // // Va - Supplies the virtual address to locate the offset for. // // Return Value: // // The offset into the page directory pointer PTE table the corresponding // PDE is at. // //-- #define MiGetPdPteOffset(va) (((ULONG)(va)) >> 30) //++ //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)) >> 21) & 0x1FF) //++ //ULONG //MiGetPdeIndex ( // IN PVOID va // ); // // Routine Description: // // MiGetPdeIndex returns the page directory index // for a given virtual address. // // N.B. This does not mask off PPE bits. // // Arguments // // Va - Supplies the virtual address to locate the offset for. // // Return Value: // // The index into the page directory - ie: the virtual page table number. // This is different from the page directory offset because this spans // page directories on supported platforms. // //-- #define MiGetPdeIndex(va) (((ULONG)(va)) >> 21) //++ //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)) << 11) >> 23) //++ //PVOID //MiGetVirtualAddressMappedByPpe ( // IN PMMPTE PTE // ); // // Routine Description: // // MiGetVirtualAddressMappedByPpe returns the virtual address // which is mapped by a given PPE address. // // Arguments // // PPE - Supplies the PPE to get the virtual address for. // // Return Value: // // Virtual address mapped by the PPE. // //-- #define MiGetVirtualAddressMappedByPpe(PPE) (NULL) //++ //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) << 18)) //++ //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) << 9)) //++ //LOGICAL //MiIsVirtualAddressOnPpeBoundary ( // IN PVOID VA // ); // // Routine Description: // // MiIsVirtualAddressOnPpeBoundary returns TRUE if the virtual address is // on a page directory entry boundary. // // Arguments // // VA - Supplies the virtual address to check. // // Return Value: // // TRUE if on a boundary, FALSE if not. // //-- #define MiIsVirtualAddressOnPpeBoundary(VA) (FALSE) //++ //LOGICAL //MiIsVirtualAddressOnPdeBoundary ( // IN PVOID VA // ); // // Routine Description: // // MiIsVirtualAddressOnPdeBoundary returns TRUE if the virtual address is // on a page directory entry boundary. // // Arguments // // VA - Supplies the virtual address to check. // // Return Value: // // TRUE if on a 4MB PDE boundary, FALSE if not. // //-- #define MiIsVirtualAddressOnPdeBoundary(VA) (((ULONG_PTR)(VA) & PAGE_DIRECTORY_MASK) == 0) //++ //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) //++ //ULONG //GET_PAGING_FILE_NUMBER ( // IN MMPTE PTE // ); // // Routine Description: // // This macro extracts the paging file number from a PTE. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // The paging file number. // //-- #define GET_PAGING_FILE_NUMBER(PTE) ((ULONG)((((PTE).u.Long) >> 1) & 0x0000000F)) //++ //ULONG //GET_PAGING_FILE_OFFSET ( // IN MMPTE PTE // ); // // Routine Description: // // This macro extracts the offset into the paging file from a PTE. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // The paging file offset. // //-- #define GET_PAGING_FILE_OFFSET(PTE) ((ULONG)((PTE).u.Soft.PageFileHigh)) //++ //ULONG //IS_PTE_NOT_DEMAND_ZERO ( // IN PMMPTE PPTE // ); // // Routine Description: // // This macro checks to see if a given PTE is NOT a demand zero PTE. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // Returns 0 if the PTE is demand zero, non-zero otherwise. // //-- #define IS_PTE_NOT_DEMAND_ZERO(PTE) ((PTE).u.Long & ~0x3FE) //++ //VOID //MI_MAKING_VALID_PTE_INVALID( // IN PMMPTE PPTE // ); // // Routine Description: // // Prepare to make a single valid PTE invalid. // No action is required on x86. // // Arguments // // SYSTEM_WIDE - Supplies TRUE if this will happen on all processors. // // Return Value: // // None. // //-- #define MI_MAKING_VALID_PTE_INVALID(SYSTEM_WIDE) //++ //VOID //MI_MAKING_VALID_MULTIPLE_PTES_INVALID( // IN PMMPTE PPTE // ); // // Routine Description: // // Prepare to make multiple valid PTEs invalid. // No action is required on x86. // // Arguments // // SYSTEM_WIDE - Supplies TRUE if this will happen on all processors. // // Return Value: // // None. // //-- #define MI_MAKING_MULTIPLE_PTES_INVALID(SYSTEM_WIDE) //++ //VOID //MI_MAKE_PROTECT_WRITE_COPY ( // IN OUT MMPTE PPTE // ); // // Routine Description: // // This macro makes a writable PTE a writable-copy PTE. // // Arguments // // PTE - Supplies the PTE to operate upon. // // Return Value: // // NONE // //-- #define MI_MAKE_PROTECT_WRITE_COPY(PTE) \ if ((PTE).u.Soft.Protection & MM_PROTECTION_WRITE_MASK) { \ (PTE).u.Long |= MM_PROTECTION_COPY_MASK << MM_PROTECT_FIELD_SHIFT; \ } //++ //VOID //MI_SET_PAGE_DIRTY( // IN PMMPTE PPTE, // IN PVOID VA, // IN PVOID PFNHELD // ); // // Routine Description: // // This macro sets the dirty bit (and release page file space). // // Arguments // // PPTE - Supplies a pointer to the PTE that corresponds to VA. // // VA - Supplies a the virtual address of the page fault. // // PFNHELD - Supplies TRUE if the PFN lock is held. // // Return Value: // // None. // //-- #if defined(NT_UP) #define MI_SET_PAGE_DIRTY(PPTE,VA,PFNHELD) #else #define MI_SET_PAGE_DIRTY(PPTE,VA,PFNHELD) \ if ((PPTE)->u.Hard.Dirty == 1) { \ MiSetDirtyBit ((VA),(PPTE),(PFNHELD)); \ } #endif //++ //VOID //MI_NO_FAULT_FOUND( // IN FAULTSTATUS, // IN PMMPTE PPTE, // IN PVOID VA, // IN PVOID PFNHELD // ); // // Routine Description: // // This macro handles the case when a page fault is taken and no // PTE with the valid bit clear is found. // // Arguments // // FAULTSTATUS - Supplies the fault status. // // PPTE - Supplies a pointer to the PTE that corresponds to VA. // // VA - Supplies a the virtual address of the page fault. // // PFNHELD - Supplies TRUE if the PFN lock is held. // // Return Value: // // None. // //-- #if defined(NT_UP) #define MI_NO_FAULT_FOUND(FAULTSTATUS,PPTE,VA,PFNHELD) #else #define MI_NO_FAULT_FOUND(FAULTSTATUS,PPTE,VA,PFNHELD) \ if ((MI_FAULT_STATUS_INDICATES_WRITE(FAULTSTATUS)) && ((PPTE)->u.Hard.Dirty == 0)) { \ MiSetDirtyBit ((VA),(PPTE),(PFNHELD)); \ } #endif //++ //ULONG //MI_CAPTURE_DIRTY_BIT_TO_PFN ( // IN PMMPTE PPTE, // IN PMMPFN PPFN // ); // // Routine Description: // // This macro gets captures the state of the dirty bit to the PFN // and frees any associated page file space if the PTE has been // modified element. // // NOTE - THE PFN LOCK MUST BE HELD! // // Arguments // // PPTE - Supplies the PTE to operate upon. // // PPFN - Supplies a pointer to the PFN database element that corresponds // to the page mapped by the PTE. // // Return Value: // // None. // //-- #define MI_CAPTURE_DIRTY_BIT_TO_PFN(PPTE,PPFN) \ ASSERT (KeGetCurrentIrql() > APC_LEVEL); \ if (((PPFN)->u3.e1.Modified == 0) && \ ((PPTE)->u.Hard.Dirty != 0)) { \ MI_SET_MODIFIED (PPFN, 1, 0x18); \ if (((PPFN)->OriginalPte.u.Soft.Prototype == 0) && \ ((PPFN)->u3.e1.WriteInProgress == 0)) { \ MiReleasePageFileSpace ((PPFN)->OriginalPte); \ (PPFN)->OriginalPte.u.Soft.PageFileHigh = 0; \ } \ } //++ //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) \ ((MiGetPdeAddress(Va)->u.Long & 0x81) == 0x81) //++ //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) \ ((PFN_NUMBER)(MiGetPdeAddress(Va)->u.Hard.PageFrameNumber) + (MiGetPteOffset((ULONG)Va))) typedef struct _MMCOLOR_TABLES { PFN_NUMBER Flink; PVOID Blink; PFN_NUMBER Count; } MMCOLOR_TABLES, *PMMCOLOR_TABLES; extern PMMCOLOR_TABLES MmFreePagesByColor[2]; extern ULONG MmTotalPagesForPagingFile; // // A VALID Page Table Entry on PAE x86 has the following definition. // #define MI_MAXIMUM_PAGEFILE_SIZE (((UINT64)4 * 1024 * 1024 * 1024 - 1) * PAGE_SIZE) #define MI_PTE_LOOKUP_NEEDED (0xffffffff) typedef struct _MMPTE_SOFTWARE { ULONGLONG Valid : 1; ULONGLONG PageFileLow : 4; ULONGLONG Protection : 5; ULONGLONG Prototype : 1; ULONGLONG Transition : 1; ULONGLONG Unused : 20; ULONGLONG PageFileHigh : 32; } MMPTE_SOFTWARE; typedef struct _MMPTE_TRANSITION { ULONGLONG Valid : 1; ULONGLONG Write : 1; ULONGLONG Owner : 1; ULONGLONG WriteThrough : 1; ULONGLONG CacheDisable : 1; ULONGLONG Protection : 5; ULONGLONG Prototype : 1; ULONGLONG Transition : 1; ULONGLONG PageFrameNumber : 26; ULONGLONG Unused : 26; } MMPTE_TRANSITION; typedef struct _MMPTE_PROTOTYPE { ULONGLONG Valid : 1; ULONGLONG Unused0: 7; ULONGLONG ReadOnly : 1; // if set allow read only access. ULONGLONG Unused1: 1; ULONGLONG Prototype : 1; ULONGLONG Protection : 5; ULONGLONG Unused: 16; ULONGLONG ProtoAddress: 32; } MMPTE_PROTOTYPE; typedef struct _MMPTE_SUBSECTION { ULONGLONG Valid : 1; ULONGLONG Unused0 : 4; ULONGLONG Protection : 5; ULONGLONG Prototype : 1; ULONGLONG Unused1 : 21; ULONGLONG SubsectionAddress : 32; } MMPTE_SUBSECTION; typedef struct _MMPTE_LIST { ULONGLONG Valid : 1; ULONGLONG OneEntry : 1; ULONGLONG filler0 : 8; // // Note the Prototype bit must not be used for lists like freed nonpaged // pool because lookaside pops can legitimately reference bogus addresses // (since the pop is unsynchronized) and the fault handler must be able to // distinguish lists from protos so a retry status can be returned (vs a // fatal bugcheck). // ULONGLONG Prototype : 1; // MUST BE ZERO as per above comment. ULONGLONG filler1 : 21; ULONGLONG NextEntry : 32; } MMPTE_LIST; typedef struct _MMPTE_HIGHLOW { ULONG LowPart; ULONG HighPart; } MMPTE_HIGHLOW; // // A Page Table Entry on PAE has the following definition. // Note the MP version is to avoid stalls when flushing TBs across processors. // // // Uniprocessor version. // typedef struct _MMPTE_HARDWARE { ULONGLONG Valid : 1; #if defined(NT_UP) ULONGLONG Write : 1; // UP version #else ULONGLONG Writable : 1; // changed for MP version #endif ULONGLONG Owner : 1; ULONGLONG WriteThrough : 1; ULONGLONG CacheDisable : 1; ULONGLONG Accessed : 1; ULONGLONG Dirty : 1; ULONGLONG LargePage : 1; ULONGLONG Global : 1; ULONGLONG CopyOnWrite : 1; // software field ULONGLONG Prototype : 1; // software field #if defined(NT_UP) ULONGLONG reserved0 : 1; // software field #else ULONGLONG Write : 1; // software field - MP change #endif ULONGLONG PageFrameNumber : 26; ULONGLONG reserved1 : 26; // software field } MMPTE_HARDWARE, *PMMPTE_HARDWARE; #if defined(NT_UP) #define HARDWARE_PTE_DIRTY_MASK 0x40 #else #define HARDWARE_PTE_DIRTY_MASK 0x42 #endif #define MI_GET_PAGE_FRAME_FROM_PTE(PTE) ((PFN_NUMBER)(PTE)->u.Hard.PageFrameNumber) #define MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(PTE) ((PFN_NUMBER)(PTE)->u.Trans.PageFrameNumber) #define MI_GET_PROTECTION_FROM_SOFT_PTE(PTE) ((ULONG)(PTE)->u.Soft.Protection) #define MI_GET_PROTECTION_FROM_TRANSITION_PTE(PTE) ((ULONG)(PTE)->u.Trans.Protection) typedef struct _MMPTE { union { ULONGLONG Long; MMPTE_HIGHLOW HighLow; MMPTE_HARDWARE Hard; HARDWARE_PTE Flush; MMPTE_PROTOTYPE Proto; MMPTE_SOFTWARE Soft; MMPTE_TRANSITION Trans; MMPTE_SUBSECTION Subsect; MMPTE_LIST List; } u; } MMPTE; typedef MMPTE *PMMPTE; extern MMPTE MmPteGlobal; // Set if processor supports Global Page, else zero. extern PMMPTE MiFirstReservedZeroingPte; // // A compiler intrinsic for InterlockedCompareExchange64I would be much better // but since there isn't, make it an inline. // FORCEINLINE LONG64 FASTCALL InterlockedCompareExchange64I ( IN OUT LONG64 volatile *Destination, IN PLONG64 Exchange, IN PLONG64 Comperand ) { __asm { push ebx push esi mov esi, Destination ; set destination address mov edx, Exchange mov ebx, [edx] ; get exchange value mov ecx, [edx] + 4 ; mov edx, Comperand ; get comperand address mov eax, [edx] ; get comperand value mov edx, [edx] + 4 ; lock cmpxchg8b qword ptr [esi] ; compare and exchange pop esi ; restore nonvolatile registers pop ebx ; } } #define InterlockedCompareExchangePte(Destination, ExChange, Comperand) \ InterlockedCompareExchange64I((LONG64 volatile *)(Destination), (PLONG64)&(ExChange), (PLONG64)&(Comperand)) //++ //VOID //MI_WRITE_VALID_PTE ( // IN PMMPTE PointerPte, // IN MMPTE PteContents // ); // // Routine Description: // // MI_WRITE_VALID_PTE fills in the specified PTE making it valid with the // specified contents. Note that the contents are very carefully written. // // Arguments // // PointerPte - Supplies a PTE to fill. // // PteContents - Supplies the contents to put in the PTE. // // Return Value: // // None. // //-- #define MI_WRITE_VALID_PTE(_PointerPte, _PteContents) \ ASSERT ((_PointerPte)->u.Hard.Valid == 0); \ ASSERT ((_PteContents).u.Hard.Valid == 1); \ ((_PointerPte)->u.HighLow.HighPart = ((_PteContents).u.HighLow.HighPart)); \ ((_PointerPte)->u.HighLow.LowPart = ((_PteContents).u.HighLow.LowPart)) //++ //VOID //MI_WRITE_INVALID_PTE ( // IN PMMPTE PointerPte, // IN MMPTE PteContents // ); // // Routine Description: // // MI_WRITE_INVALID_PTE fills in the specified PTE making it invalid with the // specified contents. Note that the contents are very carefully written. // // Arguments // // PointerPte - Supplies a PTE to fill. // // PteContents - Supplies the contents to put in the PTE. // // Return Value: // // None. // //-- #define MI_WRITE_INVALID_PTE(_PointerPte, _PteContents) \ ASSERT ((_PteContents).u.Hard.Valid == 0); \ ((_PointerPte)->u.HighLow.LowPart = ((_PteContents).u.HighLow.LowPart)); \ ((_PointerPte)->u.HighLow.HighPart = ((_PteContents).u.HighLow.HighPart)) //++ //VOID //MI_WRITE_VALID_PTE_NEW_PROTECTION ( // IN PMMPTE PointerPte, // IN MMPTE PteContents // ); // // Routine Description: // // MI_WRITE_VALID_PTE_NEW_PROTECTION fills in the specified PTE (which was // already valid) changing only the protection or the dirty bit. // Note that the contents are very carefully written. // // Arguments // // PointerPte - Supplies a PTE to fill. // // PteContents - Supplies the contents to put in the PTE. // // Return Value: // // None. // //-- #define MI_WRITE_VALID_PTE_NEW_PROTECTION(_PointerPte, _PteContents) \ ASSERT ((_PointerPte)->u.Hard.Valid == 1); \ ASSERT ((_PteContents).u.Hard.Valid == 1); \ ASSERT ((_PointerPte)->u.Hard.PageFrameNumber == (_PteContents).u.Hard.PageFrameNumber); \ ((_PointerPte)->u.HighLow.LowPart = ((_PteContents).u.HighLow.LowPart)); //++ //VOID //MiFillMemoryPte ( // IN PMMPTE Destination, // IN ULONG Length, // IN MMPTE Pattern, // }; // // Routine Description: // // This function fills memory with the specified PTE pattern. // // Arguments // // Destination - Supplies a pointer to the memory to fill. // // Length - Supplies the length, in bytes, of the memory to be // filled. // // Pattern - Supplies the PTE fill pattern. // // Return Value: // // None. // //-- #define MiFillMemoryPte(Destination, Length, Pattern) \ RtlFillMemoryUlonglong ((Destination), (Length), (Pattern)) ULONG FASTCALL MiDetermineUserGlobalPteMask ( IN PMMPTE Pte ); //++ //BOOLEAN //MI_IS_PAGE_TABLE_ADDRESS ( // IN PVOID VA // ); // // Routine Description: // // This macro takes a virtual address and determines if // it is a page table address. // // Arguments // // VA - Supplies a virtual address. // // Return Value: // // TRUE if the address is a page table address, FALSE if not. // //-- #define MI_IS_PAGE_TABLE_ADDRESS(VA) \ ((PVOID)(VA) >= (PVOID)PTE_BASE && (PVOID)(VA) <= (PVOID)PTE_TOP) //++ //BOOLEAN //MI_IS_KERNEL_PAGE_TABLE_ADDRESS ( // IN PVOID VA // ); // // Routine Description: // // This macro takes a virtual address and determines if // it is a page table address for a kernel address. // // Arguments // // VA - Supplies a virtual address. // // Return Value: // // TRUE if the address is a kernel page table address, FALSE if not. // //-- #define MI_IS_KERNEL_PAGE_TABLE_ADDRESS(VA) \ ((PVOID)(VA) >= (PVOID)MiGetPteAddress(MmSystemRangeStart) && (PVOID)(VA) <= (PVOID)PTE_TOP) //++ //BOOLEAN //MI_IS_PAGE_DIRECTORY_ADDRESS ( // IN PVOID VA // ); // // Routine Description: // // This macro takes a virtual address and determines if // it is a page directory address. // // Arguments // // VA - Supplies a virtual address. // // Return Value: // // TRUE if the address is a page directory address, FALSE if not. // //-- #define MI_IS_PAGE_DIRECTORY_ADDRESS(VA) \ ((PVOID)(VA) >= (PVOID)PDE_BASE && (PVOID)(VA) <= (PVOID)PDE_TOP) //++ //BOOLEAN //MI_IS_HYPER_SPACE_ADDRESS ( // IN PVOID VA // ); // // Routine Description: // // This macro takes a virtual address and determines if // it is a hyper space address. // // Arguments // // VA - Supplies a virtual address. // // Return Value: // // TRUE if the address is a hyper space address, FALSE if not. // //-- #define MI_IS_HYPER_SPACE_ADDRESS(VA) \ ((PVOID)(VA) >= (PVOID)HYPER_SPACE && (PVOID)(VA) <= (PVOID)HYPER_SPACE_END) //++ //BOOLEAN //MI_IS_PROCESS_SPACE_ADDRESS ( // IN PVOID VA // ); // // Routine Description: // // This macro takes a virtual address and determines if // it is a process-specific address. This is an address in user space // or page table pages or hyper space. // // Arguments // // VA - Supplies a virtual address. // // Return Value: // // TRUE if the address is a process-specific address, FALSE if not. // //-- #define MI_IS_PROCESS_SPACE_ADDRESS(VA) \ (((PVOID)(VA) <= (PVOID)MM_HIGHEST_USER_ADDRESS) || \ ((PVOID)(VA) >= (PVOID)PTE_BASE && (PVOID)(VA) <= (PVOID)HYPER_SPACE_END)) //++ //BOOLEAN //MI_IS_PTE_PROTOTYPE ( // IN PMMPTE PTE // ); // // Routine Description: // // This macro takes a PTE address and determines if it is a prototype PTE. // // Arguments // // PTE - Supplies the virtual address of the PTE to check. // // Return Value: // // TRUE if the PTE is in a segment (ie, a prototype PTE), FALSE if not. // //-- #define MI_IS_PTE_PROTOTYPE(PTE) \ ((PTE) > (PMMPTE)PTE_TOP) //++ //BOOLEAN //MI_IS_SYSTEM_CACHE_ADDRESS ( // IN PVOID VA // ); // // Routine Description: // // This macro takes a virtual address and determines if // it is a system cache address. // // Arguments // // VA - Supplies a virtual address. // // Return Value: // // TRUE if the address is in the system cache, FALSE if not. // //-- #define MI_IS_SYSTEM_CACHE_ADDRESS(VA) \ (((PVOID)(VA) >= (PVOID)MmSystemCacheStart && \ (PVOID)(VA) <= (PVOID)MmSystemCacheEnd) || \ ((PVOID)(VA) >= (PVOID)MiSystemCacheStartExtra && \ (PVOID)(VA) <= (PVOID)MiSystemCacheEndExtra)) //++ //VOID //MI_BARRIER_SYNCHRONIZE ( // IN ULONG TimeStamp // ); // // Routine Description: // // MI_BARRIER_SYNCHRONIZE compares the argument timestamp against the // current IPI barrier sequence stamp. When equal, all processors will // issue memory barriers to ensure that newly created pages remain coherent. // // When a page is put in the zeroed or free page list the current // barrier sequence stamp is read (interlocked - this is necessary // to get the correct value - memory barriers won't do the trick) // and stored in the pfn entry for the page. The current barrier // sequence stamp is maintained by the IPI send logic and is // incremented (interlocked) when the target set of an IPI send // includes all processors, but the one doing the send. When a page // is needed its sequence number is compared against the current // barrier sequence number. If it is equal, then the contents of // the page may not be coherent on all processors, and an IPI must // be sent to all processors to ensure a memory barrier is // executed (generic call can be used for this). Sending the IPI // automatically updates the barrier sequence number. The compare // is for equality as this is the only value that requires the IPI // (i.e., the sequence number wraps, values in both directions are // older). When a page is removed in this fashion and either found // to be coherent or made coherent, it cannot be modified between // that time and writing the PTE. If the page is modified between // these times, then an IPI must be sent. // // Arguments // // TimeStamp - Supplies the timestamp at the time when the page was zeroed. // // Return Value: // // None. // //-- // does nothing on PAE. #define MI_BARRIER_SYNCHRONIZE(TimeStamp) //++ //VOID //MI_BARRIER_STAMP_ZEROED_PAGE ( // IN PULONG PointerTimeStamp // ); // // Routine Description: // // MI_BARRIER_STAMP_ZEROED_PAGE issues an interlocked read to get the // current IPI barrier sequence stamp. This is called AFTER a page is // zeroed. // // Arguments // // PointerTimeStamp - Supplies a timestamp pointer to fill with the // current IPI barrier sequence stamp. // // Return Value: // // None. // //-- // does nothing on PAE. #define MI_BARRIER_STAMP_ZEROED_PAGE(PointerTimeStamp) typedef struct _PAE_PAGEINFO { LIST_ENTRY ListHead; PFN_NUMBER PageFrameNumber; ULONG EntriesInUse; } PAE_PAGEINFO, *PPAE_PAGEINFO; typedef struct _PAE_ENTRY { union { MMPTE PteEntry[PD_PER_SYSTEM]; PAE_PAGEINFO PaeEntry; SINGLE_LIST_ENTRY NextPae; }; } PAE_ENTRY, *PPAE_ENTRY; extern PAE_ENTRY MiSystemPaeVa; //++ //VOID //MI_FLUSH_SINGLE_SESSION_TB ( // IN PVOID Virtual, // IN ULONG Invalid, // IN LOGICAL AllProcessors, // IN PMMPTE PtePointer, // IN MMPTE PteValue, // IN MMPTE PreviousPte // ); // // Routine Description: // // MI_FLUSH_SINGLE_SESSION_TB flushes the requested single address // translation from the TB. // // Since there are no ASNs on the x86, this routine becomes a single // TB invalidate. // // Arguments // // Virtual - Supplies the virtual address to invalidate. // // Invalid - TRUE if invalidating. // // AllProcessors - TRUE if all processors need to be IPI'd. // // PtePointer - Supplies the PTE to invalidate. // // PteValue - Supplies the new PTE value. // // PreviousPte - The previous PTE value is returned here. // // Return Value: // // None. // //-- #define MI_FLUSH_SINGLE_SESSION_TB(Virtual, Invalid, AllProcessors, PtePointer, PteValue, PreviousPte) \ PreviousPte.u.Flush = KeFlushSingleTb (Virtual, \ TRUE, \ TRUE, \ PtePointer, \ PteValue); //++ //VOID //MI_FLUSH_ENTIRE_SESSION_TB ( // IN ULONG Invalid, // IN LOGICAL AllProcessors // ); // // Routine Description: // // MI_FLUSH_ENTIRE_SESSION_TB flushes the entire TB on processors which // support ASNs. // // Since there are no ASNs on the x86, this routine does nothing. // // Arguments // // Invalid - TRUE if invalidating. // // AllProcessors - TRUE if all processors need to be IPI'd. // // Return Value: // // None. // #define MI_FLUSH_ENTIRE_SESSION_TB(Invalid, AllProcessors) \ NOTHING; //++ //LOGICAL //MI_RESERVED_BITS_CANONICAL ( // IN PVOID VirtualAddress // ); // // Routine Description: // // This routine checks whether all of the reserved bits are correct. // // This does nothing on PAE x86. // // Arguments // // VirtualAddress - Supplies the virtual address to check. // // Return Value: // // None. // #define MI_RESERVED_BITS_CANONICAL(VirtualAddress) TRUE //++ //VOID //MI_DISPLAY_TRAP_INFORMATION ( // IN PVOID TrapInformation // ); // // Routine Description: // // Display any relevant trap information to aid debugging. // // Arguments // // TrapInformation - Supplies a pointer to a trap frame. // // Return Value: // // None. // #define MI_DISPLAY_TRAP_INFORMATION(TrapInformation) \ KdPrint(("MM:***EIP %p, EFL %p\n", \ ((PKTRAP_FRAME) (TrapInformation))->Eip, \ ((PKTRAP_FRAME) (TrapInformation))->EFlags)); \ KdPrint(("MM:***EAX %p, ECX %p EDX %p\n", \ ((PKTRAP_FRAME) (TrapInformation))->Eax, \ ((PKTRAP_FRAME) (TrapInformation))->Ecx, \ ((PKTRAP_FRAME) (TrapInformation))->Edx)); \ KdPrint(("MM:***EBX %p, ESI %p EDI %p\n", \ ((PKTRAP_FRAME) (TrapInformation))->Ebx, \ ((PKTRAP_FRAME) (TrapInformation))->Esi, \ ((PKTRAP_FRAME) (TrapInformation))->Edi)); // // Turn off U/S, R/W and any other appropriate bits required by the processor. // #define MM_PAE_PDPTE_MASK 0x1e6 ULONG MiPaeAllocate ( PPAE_ENTRY * ); VOID MiPaeFree ( PPAE_ENTRY Pae ); #endif