/*++ Copyright (c) 1990 Microsoft Corporation Copyright (c) 1992 Digital Equipment Corporation Module Name: mialpha.h Abstract: This module contains the private data structures and procedure prototypes for the hardware dependent portion of the memory management system. It is specifically tailored for the DEC ALPHA architecture. Author: Lou Perazzoli (loup) 12-Mar-1990 Joe Notarangelo 23-Apr-1992 ALPHA version Revision History: Landy Wang (landyw) 02-June-1998 : Modifications for full 3-level 64-bit NT. --*/ /*++ Virtual Memory Layout on the AXP64 is: +------------------------------------+ 0000000000000000 | User mode addresses - 4tb | | | 000003FFFFFEFFFF | | MM_HIGHEST_USER_ADDRESS +------------------------------------+ 000003FFFFFF0000 | 64k No Access Region | MM_USER_PROBE_ADDRESS +------------------------------------+ +------------------------------------+ FFFFFC0000000000 | Start of System space and 2tb of | MM_SYSTEM_RANGE_START | physically addressable memory. | KSEG43_BASE | | +------------------------------------+ FFFFFE0000000000 | 8gb three level page table map. | PTE_BASE +------------------------------------+ KSEG43_LIMIT FFFFFE0200000000 | HyperSpace - working set lists | HYPER_SPACE | and per process memory management | | structures mapped in this 8gb | | region. | HYPER_SPACE_END +------------------------------------+ MM_WORKING_SET_END FFFFFE0400000000 | win32k.sys | | | | Hydra configurations have session | | data structures. | | | | This is an 8gb region. | +------------------------------------+ FFFFFE0600000000 | The system cache working set | MM_SYSTEM_CACHE_WORKING_SET MM_SYSTEM_SPACE_START | information resides in this 8gb | | region. | +------------------------------------+ FFFFFE0800000000 | System cache resides here. | MM_SYSTEM_CACHE_START | Kernel mode access only. | | 1tb. | | | MM_SYSTEM_CACHE_END +------------------------------------+ FFFFFF0800000000 | Start of paged system area. | MM_PAGED_POOL_START | Kernel mode access only. | | 128gb. | +------------------------------------+ | System mapped views start just | | after paged pool. Default is | | 104MB, can be registry-overridden. | | 8GB maximum. | +------------------------------------+ | | . . In general, the next two areas (system PTE pool and nonpaged pool) will both be shifted upwards to conserve a PPE... . . +------------------------------------+ FFFFFF2800000000 | System PTE pool. | MM_LOWEST_NONPAGED_SYSTEM_START | Kernel mode access only. | | 128gb. | +------------------------------------+ FFFFFF4800000000 | NonPaged pool. | MM_NON_PAGED_POOL_START | Kernel mode access only. | | 128gb. | | | FFFFFF67FFFFFFFF | NonPaged System area | MM_NONPAGED_POOL_END +------------------------------------+ | | . . . +------------------------------------+ FFFFFFFF80000000 | The HAL, kernel, initial drivers, | KSEG0_BASE | NLS data, and registry load in the | | first 16mb of this region which | | physically addresses memory. | | | | Kernel mode access only. | | | | Initial NonPaged Pool is within | | KSEG0 | | | +------------------------------------+ FFFFFFFFC0000000 | Unused. | KSEG2_BASE | | | | | | +------------------------------------+ FFFFFFFFFF000000 | Shared system page | KI_USER_SHARED_DATA +------------------------------------+ FFFFFFFFFF002000 | Reserved for the HAL. | | | | | FFFFFFFFFFFFFFFF | | MM_SYSTEM_SPACE_END +------------------------------------+ --*/ #define _MI_PAGING_LEVELS 3 // // Define empty list marker. // #define MM_EMPTY_LIST (-1) // #define MM_EMPTY_PTE_LIST 0xFFFFFFFFUI64 // N.B. tied to MMPTE definition #define MI_PTE_BASE_FOR_LOWEST_KERNEL_ADDRESS (MiGetPteAddress (PTE_BASE)) // // Define start of KSEG0. // #define MM_KSEG0_BASE KSEG0_BASE // // // 43-Bit virtual address mask. // #define MASK_43 0x7FFFFFFFFFFUI64 // // // Top level page parent is the same for both kernel and user in AXP64. // #define PDE_KTBASE PDE_TBASE // // Address space definitions. // #define PTE_TOP 0xFFFFFE01FFFFFFFFUI64 #define PDE_TOP 0xFFFFFE01FFFFFFFFUI64 #define MM_PAGES_IN_KSEG0 (ULONG)(((KSEG2_BASE - KSEG0_BASE) >> PAGE_SHIFT)) #define MM_USER_ADDRESS_RANGE_LIMIT 0xFFFFFFFFFFFFFFFF // user address range limit #define MM_MAXIMUM_ZERO_BITS 53 // maximum number of zero bits #define MM_SYSTEM_SPACE_START 0xFFFFFE0600000000UI64 #define MM_SYSTEM_CACHE_START 0xFFFFFE0800000000UI64 #define MM_SYSTEM_CACHE_END 0xFFFFFF0800000000UI64 #define MM_MAXIMUM_SYSTEM_CACHE_SIZE \ ((MM_SYSTEM_CACHE_END - MM_SYSTEM_CACHE_START) >> PAGE_SHIFT) #define MM_SYSTEM_CACHE_WORKING_SET 0xFFFFFE0600000000UI64 // // Define area for mapping views into system space. // #define MM_SESSION_SPACE_DEFAULT 0xFFFFFE0400000000UI64 #define MM_SYSTEM_VIEW_SIZE (48 * 1024 * 1024) #define MM_PAGED_POOL_START ((PVOID)0xFFFFFF0800000000) #define MM_LOWEST_NONPAGED_SYSTEM_START ((PVOID)0xFFFFFF2800000000) #define MM_NONPAGED_POOL_END ((PVOID)(0xFFFFFF6800000000 - (16 * PAGE_SIZE))) #define NON_PAGED_SYSTEM_END ((PVOID)0xFFFFFFFFFFFFFFF0) //quadword aligned. #define MM_SYSTEM_SPACE_END 0xFFFFFFFFFFFFFFFFUI64 // // Define absolute minimum and maximum count for system PTEs. // #define MM_MINIMUM_SYSTEM_PTES 5000 #define MM_MAXIMUM_SYSTEM_PTES (16*1024*1024) #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 (96 * 1024 * 1024) // // The total amount of nonpaged pool. // #define MM_MAX_ADDITIONAL_NONPAGED_POOL (((SIZE_T)128 * 1024 * 1024 * 1024) - 16) // // The maximum amount of paged pool that can be created. // #define MM_MAX_PAGED_POOL ((SIZE_T)128 * 1024 * 1024 * 1024) // // Define the maximum default for pool (user specified 0 in registry). // #define MM_MAX_DEFAULT_NONPAGED_POOL ((SIZE_T)8 * 1024 * 1024 * 1024) // // Granularity Hint definitions. // // // Granularity Hint = 3, page size = 8**3 * PAGE_SIZE // #define GH3 (3) #define GH3_PAGE_SIZE (PAGE_SIZE << 9) // // Granularity Hint = 2, page size = 8**2 * PAGE_SIZE // #define GH2 (2) #define GH2_PAGE_SIZE (PAGE_SIZE << 6) // // Granularity Hint = 1, page size = 8**1 * PAGE_SIZE // #define GH1 (1) #define GH1_PAGE_SIZE (PAGE_SIZE << 3) // // Granularity Hint = 0, page size = PAGE_SIZE // #define GH0 (0) #define GH0_PAGE_SIZE PAGE_SIZE // // Physical memory size and boundary constants. // #define __1GB (0x40000000) // // PAGE_SIZE for ALPHA (at least current implementation) is 8k // PAGE_SHIFT bytes for an offset leaves 19 // #define MM_VIRTUAL_PAGE_FILLER (13 - 12) #define MM_VIRTUAL_PAGE_SIZE (43 - 13) #define MM_PROTO_PTE_ALIGNMENT ((ULONG)MM_MAXIMUM_NUMBER_OF_COLORS * (ULONG)PAGE_SIZE) // // Define maximum number of paging files // #define MAX_PAGE_FILES (8) // // Define the address bits mapped by one PPE entry. // #define PAGE_PARENT_MASK 0x1FFFFFFFFUI64 #define MM_VA_MAPPED_BY_PPE (0x200000000UI64) // // Define the address bits mapped by PPE and PDE entries. // // A PPE entry maps 10+10+13 = 33 bits of address space. // A PDE entry maps 10+13 = 23 bits of address space. // #define PAGE_DIRECTORY1_MASK 0x1FFFFFFFFUI64 #define PAGE_DIRECTORY2_MASK 0x7FFFFFUI64 #define MM_VA_MAPPED_BY_PDE (0x800000) #define LOWEST_IO_ADDRESS (0) #define PTE_SHIFT (3) // // Number of physical address bits, maximum for ALPHA architecture = 48. // #define PHYSICAL_ADDRESS_BITS (48) #define MM_MAXIMUM_NUMBER_OF_COLORS 1 // // Alpha 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 1mb worth of secondary colors. // #define MM_SECONDARY_COLORS_DEFAULT ((1024 * 1024) >> PAGE_SHIFT) #define MM_SECONDARY_COLORS_MIN (2) #define MM_SECONDARY_COLORS_MAX (2048) // // Hyper space definitions. // // Hyper space consists of a single top level page directory parent entry // that maps a series of PDE/PTEs that can be used for temporary per process // mapping and the working set list. // #define HYPER_SPACE ((PVOID)0xFFFFFE0200000000) #define FIRST_MAPPING_PTE 0xFFFFFE0200000000UI64 #define NUMBER_OF_MAPPING_PTES 639 #define LAST_MAPPING_PTE \ (FIRST_MAPPING_PTE + (NUMBER_OF_MAPPING_PTES * PAGE_SIZE)) #define IMAGE_MAPPING_PTE ((PMMPTE)((ULONG_PTR)LAST_MAPPING_PTE + PAGE_SIZE)) #define ZEROING_PAGE_PTE ((PMMPTE)((ULONG_PTR)IMAGE_MAPPING_PTE + PAGE_SIZE)) #define WORKING_SET_LIST ((PVOID)((ULONG_PTR)ZEROING_PAGE_PTE + PAGE_SIZE)) #define MM_MAXIMUM_WORKING_SET \ ((((ULONG_PTR)4 * 1024 * 1024 * 1024 * 1024) - (64 * 1024 * 1024)) >> PAGE_SHIFT) //4Tb-64Mb #define MmWorkingSetList ((PMMWSL)WORKING_SET_LIST) #define MmWsle ((PMMWSLE)((PUCHAR)WORKING_SET_LIST + sizeof(MMWSL))) #define HYPER_SPACE_END 0xFFFFFE03FFFFFFFFUI64 #define MM_WORKING_SET_END 0xFFFFFE0400000000UI64 // // Define PTE mask bits. // // These definitions are derived from the hardware PTE format and from the // software PTE formats. They are defined as masks to avoid the cost of // shifting and masking to insert and extract these fields. // #define MM_PTE_VALID_MASK 0x1105 // kernel read-write, fault-on-write, valid #define MM_PTE_PROTOTYPE_MASK 0x2 // not valid and prototype #define MM_PTE_DIRTY_MASK 0x4 // fault on write #define MM_PTE_TRANSITION_MASK 0x4 // not valid and transition #define MM_PTE_GLOBAL_MASK 0x10 // global #define MM_PTE_WRITE_MASK 0x10000 // software write #define MM_PTE_COPY_ON_WRITE_MASK 0x20000 // software copy-on-write #define MM_PTE_OWNER_MASK 0x2200 // user read-write // // 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 ALPHA #define MM_PTE_READONLY 0x4 // fault on write #define MM_PTE_READWRITE (MM_PTE_WRITE_MASK) // software write enable #define MM_PTE_WRITECOPY (MM_PTE_WRITE_MASK | MM_PTE_COPY_ON_WRITE_MASK) // #define MM_PTE_EXECUTE 0x4 // fault on write #define MM_PTE_EXECUTE_READ 0x4 // fault on write #define MM_PTE_EXECUTE_READWRITE (MM_PTE_WRITE_MASK) // software write enable #define MM_PTE_EXECUTE_WRITECOPY (MM_PTE_WRITE_MASK | MM_PTE_COPY_ON_WRITE_MASK) // #define MM_PTE_NOCACHE 0x0 // not expressable on ALPHA #define MM_PTE_GUARD 0x0 // not expressable on ALPHA #define MM_PTE_CACHE 0x0 // #define MM_PROTECT_FIELD_SHIFT 3 // // Bits available for the software working set index within the hardware PTE. // #define MI_MAXIMUM_PTE_WORKING_SET_INDEX (1 << _HARDWARE_PTE_WORKING_SET_BITS) // // Zero PTE // #define MM_ZERO_PTE 0 // // Zero Kernel PTE // #define MM_ZERO_KERNEL_PTE 0 // // A demand zero PTE with a protection or PAGE_READWRITE. // #define MM_DEMAND_ZERO_WRITE_PTE (MM_READWRITE << MM_PROTECT_FIELD_SHIFT) // // A demand zero PTE with a protection or 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) // // Dirty bit definitions for clean and dirty. // #define MM_PTE_CLEAN 1 #define MM_PTE_DIRTY 0 // // Kernel stack alignment requirements. // #define MM_STACK_ALIGNMENT 0x0 #define MM_STACK_OFFSET 0x0 // // System process definitions // #define PDE_PER_PAGE 1024 #define PTE_PER_PAGE 1024 #define PTE_PER_PAGE_BITS 11 // This handles the case where the page is full #if PTE_PER_PAGE_BITS > 32 error - too many bits to fit into MMPTE_SOFTWARE or MMPFN.u1 #endif // // Number of page table pages for user addresses. // #define MM_USER_PAGE_TABLE_PAGES (PTE_PER_PAGE * PDE_PER_PAGE / 2) #define MM_USER_PAGE_DIRECTORY_PAGES (PDE_PER_PAGE / 2) //++ //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 = MmProtectToPteMask[PMASK] | MM_PTE_VALID_MASK; \ (OUTPTE).u.Hard.PageFrameNumber = (FRAME); \ if (MI_DETERMINE_OWNER(PPTE)) { \ (OUTPTE).u.Long |= MM_PTE_OWNER_MASK; \ } \ if (((PMMPTE)PPTE) >= MiGetPteAddress(MM_SYSTEM_SPACE_START)) { \ (OUTPTE).u.Hard.Global = 1; \ } \ } //++ //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; //++ //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) { \ (OUTPTE).u.Long = MmProtectToPteMask[(PPTE)->u.Trans.Protection] | MM_PTE_VALID_MASK; \ (OUTPTE).u.Hard.PageFrameNumber = (PPTE)->u.Hard.PageFrameNumber; \ if (MI_DETERMINE_OWNER(PPTE)) { \ (OUTPTE).u.Long |= MM_PTE_OWNER_MASK; \ } \ if (((PMMPTE)PPTE) >= MiGetPteAddress(MM_SYSTEM_SPACE_START)) { \ (OUTPTE).u.Hard.Global = 1; \ } \ } //++ //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. // // No TB invalidation is needed for other processors (or this one) even // though the entry may already be in a TB - it's just a software field // update and doesn't affect miss resolution. // // 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) { \ MMPTE _TempPte; \ _TempPte = *(PTE); \ _TempPte.u.Hard.SoftwareWsIndex = (WSINDEX); \ ASSERT (_TempPte.u.Long != 0); \ *(PTE) = _TempPte; \ } //++ //ULONG WsIndex //MI_GET_WORKING_SET_FROM_PTE( // IN PMMPTE PTE // ); // // Routine Description: // // This macro returns the working set index from the argument PTE. // // 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) (ULONG)(PTE)->u.Hard.SoftwareWsIndex //++ //VOID //MI_SET_PTE_WRITE_COMBINE ( // IN MMPTE PTE // ); // // Routine Description: // // This macro sets the write combined bit(s) in the specified PTE. // // Arguments // // PTE - Supplies the PTE to set dirty. // // Return Value: // // None. // //-- #define MI_SET_PTE_WRITE_COMBINE(PTE) //++ //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.Hard.FaultOnWrite = MM_PTE_DIRTY //++ //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.Hard.FaultOnWrite = MM_PTE_CLEAN //++ //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.FaultOnWrite != MM_PTE_CLEAN) //++ // 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) //++ // VOID // MI_SET_GLOBAL_STATE ( // IN MMPTE PTE, // IN ULONG STATE // ); // // Routine Description: // // This macro sets the global bit in the PTE. // // Arguments // // PTE - Supplies the PTE to set global state into. // // Return Value: // // None. // //-- #define MI_SET_GLOBAL_STATE(PTE, STATE) (PTE).u.Hard.Global = STATE; //++ // VOID // MI_ENABLE_CACHING ( // IN MMPTE PTE // ); // // Routine Description: // // This macro takes a valid PTE and sets the caching state to be // enabled. // // Arguments // // PTE - Supplies a valid PTE. // // Return Value: // // None. // //-- #define MI_ENABLE_CACHING(PTE) //++ // VOID // MI_DISABLE_CACHING ( // IN MMPTE PTE // ); // // Routine Description: // // This macro takes a valid PTE and sets the caching state to be // disabled. // // N.B. This function performs no operation on Alpha. Caching is // never disabled. // // Arguments // // PTE - Supplies a valid PTE. // // Return Value: // // None. // //-- #define MI_DISABLE_CACHING(PTE) //++ // BOOLEAN // MI_IS_CACHING_DISABLED ( // IN PMMPTE PPTE // ); // // Routine Description: // // This macro takes a valid PTE and returns TRUE if caching is // disabled. // // N.B. This function always return FALSE for alpha. // // Arguments // // PPTE - Supplies a pointer to the valid PTE. // // Return Value: // // FALSE. // //-- #define MI_IS_CACHING_DISABLED(PPTE) FALSE //++ // 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 // // PPTE - Supplies a pointer to the PFN element. // // Return Value: // // none. // //-- #define MI_SET_PFN_DELETED(PPFN) \ (((ULONG_PTR)(PPFN)->PteAddress) = ((((ULONG_PTR)(PPFN)->PteAddress) << 1) >> 1)) //++ //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) >> 63) == 0) //++ // VOID // MI_CHECK_PAGE_ALIGNMENT ( // IN ULONG PAGE, // IN ULONG COLOR // ); // // 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. // COLOR - Supplies the new page color of the page. // // Return Value: // // none. // //-- #define MI_CHECK_PAGE_ALIGNMENT(PAGE, COLOR) //++ //VOID //MI_INITIALIZE_HYPERSPACE_MAP ( // VOID // ); // // Routine Description: // // This macro initializes the PTEs reserved for double mapping within // hyperspace. // // Arguments // // None. // // Return Value: // // None. // //-- #define MI_INITIALIZE_HYPERSPACE_MAP(HYPER_PAGE) //++ //ULONG //MI_GET_PAGE_COLOR_FROM_PTE ( // IN PMMPTE PTEADDRESS // ); // // Routine Description: // // This macro determines the pages 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)) //++ //ULONG //MI_GET_PAGE_COLOR_FROM_VA ( // IN PVOID ADDRESS // ); // // Routine Description: // // This macro determines the pages 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 pages color. // //-- #define MI_GET_PAGE_COLOR_FROM_VA(ADDRESS) \ ((ULONG)((MI_SYSTEM_PAGE_COLOR++) & MmSecondaryColorMask)) //++ //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)) //++ //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) //++ //ULONG //MI_PAGE_COLOR_VA_PROCESS ( // IN PVOID ADDRESS, // IN PEPROCESS COLOR // ); // // Routine Description: // // This macro determines the pages 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 pages color. // //-- #define MI_PAGE_COLOR_VA_PROCESS(ADDRESS,COLOR) \ ((ULONG)((*(COLOR))++) & MmSecondaryColorMask) //++ //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) ((COLOR-1) & MM_COLOR_MASK) #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 fro 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 the 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 { \ while( MmModifiedPageListByColor[COLOR].Flink == MM_EMPTY_LIST ){ \ COLOR = MI_GET_NEXT_COLOR(COLOR); \ } \ 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. // //-- #define MI_MAKE_VALID_PTE_WRITE_COPY(PPTE) \ if ((PPTE)->u.Hard.Write == 1) { \ (PPTE)->u.Hard.CopyOnWrite = 1; \ (PPTE)->u.Hard.FaultOnWrite = MM_PTE_CLEAN;\ } //++ //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) \ ((PMMPTE)(PPTE) <= MiHighestUserPte) //++ //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: // // 1 if the owner is USER_MODE, 0 if the owner is KERNEL_MODE. // //-- #define MI_SET_ACCESSED_IN_PTE(PPTE,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) 0 //++ //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.UserReadAccess = (PPTE)->u.Hard.UserWriteAccess = 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.UserReadAccess) // // Mask to clear all fields but protection in a PTE to or in paging file // location. // #define CLEAR_FOR_PAGE_FILE 0xF8 //++ // ULONG_PTR // 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: // // PTE Value. // //-- #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) & 0xF) << 28) | \ (((ULONG64)(OFFSET) & 0xFFFFFFFF) << 32)); //++ // PMMPTE // MiPteToProto ( // IN OUT MMPTE PPTE // ); // // 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)((lpte)->u.Proto.ProtoAddress)) //++ // ULONG_PTR // 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 MM_PTE_PROTOTYPE_MASK PTE // 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) \ (((ULONG_PTR)proto_va << 16) | MM_PTE_PROTOTYPE_MASK) //++ // ULONG_PTR // 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 MM_PTE_PROTOTYPE_MASK PTE // bit. // // 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. // //-- #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 // paged and 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)((lpte)->u.Subsect.SubsectionAddress)) //++ // ULONG_PTR // MiGetSubsectionAddressForPte ( // IN PSUBSECTION VA // ); // // N.B. This macro is dependent on the layout of the subsection PTE. // // 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) ((ULONG_PTR)VA << 16) //++ //PMMPTE //MiGetPpeAddress ( // IN PVOID va // ); // // Routine Description: // // MiGetPpeAddress returns the address of the page directory parent entry // which maps the given virtual address. This is one level above the // page directory. // // Arguments // // Va - Supplies the virtual address to locate the PPE for. // // Return Value: // // The address of the PPE. // //-- #define MiGetPpeAddress(va) ((PMMPTE)PDE_TBASE + MiGetPpeOffset(va)) //++ //PMMPTE //MiGetPdeAddress ( // IN PVOID va // ); // // Routine Description: // // This funtion computes the address of the second level PDE which maps // the given virtual address. The computation is done by recursively // applying the computation to find the PTE that maps the virtual address. // // Arguments // // Va - Supplies the virtual address for which to compute the second level // PDE address. // // Return Value: // // The address of the PDE. // //-- #define MiGetPdeAddress(va) \ MiGetPteAddress(MiGetPteAddress(va)) #define MiGetPdeAddress64(va) \ MiGetPteAddress(MiGetPteAddress(va)) //++ //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_PTR)(va) & MASK_43) >> PTI_SHIFT) << 3) + PTE_BASE)) #define MiGetPteAddress64(va) \ ((PMMPTE)(((((ULONG_PTR)(va) & MASK_43) >> PTI_SHIFT) << 3) + PTE_BASE)) //++ // ULONG // MiGetPpeOffset ( // IN PVOID va // ); // // Routine Description: // // MiGetPpeOffset returns the offset into a page directory parent for a // given virtual address. // // Arguments // // Va - Supplies the virtual address to locate the offset for. // // Return Value: // // The offset into the parent page directory table the corresponding // PPE is at. // //-- #define MiGetPpeOffset(va) ((ULONG)(((ULONG_PTR)(va) >> PDI1_SHIFT) & PDI_MASK)) //++ //ULONG //MiGetPpeIndex ( // IN PVOID va // ); // // Routine Description: // // MiGetPpeIndex returns the page directory parent index // for a given virtual address. // // N.B. This does not mask off PXE bits. // // Arguments // // Va - Supplies the virtual address to locate the index for. // // Return Value: // // The index into the page directory parent - ie: the virtual page directory // number. This is different from the page directory parent offset because // this spans page directory parents on supported platforms. //-- #define MiGetPpeIndex(va) ((ULONG)((ULONG_PTR)(va) >> PDI1_SHIFT)) //++ // 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)(((ULONG_PTR)(va) >> PDI2_SHIFT) & PDI_MASK)) //++ //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)((ULONG_PTR)(va) >> PDI2_SHIFT)) //++ // 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)(((ULONG_PTR)(va) >> PTI_SHIFT) & PDI_MASK)) //++ //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) \ MiGetVirtualAddressMappedByPte(MiGetVirtualAddressMappedByPde(PPE)) //++ //PVOID //MiGetVirtualAddressMappedByPde ( // IN PMMPTE PDE // ); // // 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) \ MiGetVirtualAddressMappedByPte(MiGetVirtualAddressMappedByPte(Pde)) //++ //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)((LONG_PTR)(((LONG_PTR)(Pte) - PTE_BASE) << (PAGE_SHIFT + VA_SHIFT - 3)) >> VA_SHIFT)) #define MiGetVirtualAddressMappedByPte64(Pte) \ ((PVOID)((LONG_PTR)(((LONG_PTR)(Pte) - PTE_BASE64) << (PAGE_SHIFT + VA_SHIFT - 3)) >> VA_SHIFT)) #define MiGetVirtualPageNumberMappedByPte64(Pte) \ ((PVOID)(((ULONG_PTR)(Pte) - PTE_BASE64) >> 3)) //++ //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) (((ULONG_PTR)(VA) & PAGE_DIRECTORY1_MASK) == 0) //++ //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 an 8MB PDE boundary, FALSE if not. // //-- #define MiIsVirtualAddressOnPdeBoundary(VA) (((ULONG_PTR)(VA) & PAGE_DIRECTORY2_MASK) == 0) //++ //LOGICAL //MiIsPteOnPpeBoundary ( // IN PVOID VA // ); // // Routine Description: // // MiIsPteOnPpeBoundary returns TRUE if the PTE is // on a page directory parent entry boundary. // // Arguments // // VA - Supplies the virtual address to check. // // Return Value: // // TRUE if on a boundary, FALSE if not. // //-- #define MiIsPteOnPpeBoundary(PTE) (((ULONG_PTR)(PTE) & (MM_VA_MAPPED_BY_PDE - 1)) == 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 8MB 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.Soft.PageFileLow))) //++ //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 & ~0xFE) //++ //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.Long & 0x20) { \ ((PTE).u.Long |= 0x8); \ } //++ //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 // // TEMP - Supplies a temporary for usage. // // 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. // //-- #define MI_SET_PAGE_DIRTY(PPTE,VA,PFNHELD) \ if ((PPTE)->u.Hard.FaultOnWrite == MM_PTE_CLEAN) { \ MiSetDirtyBit ((VA),(PPTE),(PFNHELD)); \ } //++ //VOID //MI_NO_FAULT_FOUND( // IN TEMP, // 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 // // TEMP - Supplies a temporary for usage. // // 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. // //-- #define MI_NO_FAULT_FOUND(TEMP, PPTE, VA, PFNHELD) \ if (StoreInstruction && ((PPTE)->u.Hard.FaultOnWrite == MM_PTE_CLEAN)) { \ MiSetDirtyBit((VA),(PPTE), (PFNHELD)); \ } else { \ KiFlushSingleTb(1, VA); \ } //++ //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) \ if (((PPFN)->u3.e1.Modified == 0) && \ ((PPTE)->u.Hard.FaultOnWrite == MM_PTE_DIRTY)) { \ (PPFN)->u3.e1.Modified = 1; \ 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 give 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_PTR)(Va) >= KSEG43_BASE) && ((ULONG_PTR)(Va) < KSEG43_LIMIT)) || \ (((ULONG_PTR)(Va) >= KSEG0_BASE) && ((ULONG_PTR)(Va) < KSEG2_BASE))) //++ //PFN_NUMBER //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_PTR)(Va) < KSEG0_BASE) ? \ ((PFN_NUMBER)(((ULONG_PTR)(Va) - KSEG43_BASE) >> PAGE_SHIFT)) : \ ((PFN_NUMBER)(((ULONG_PTR)(Va) - KSEG0_BASE) >> PAGE_SHIFT))) //++ // PFN_NUMBER // MI_CONVERT_PHYSICAL_BUS_TO_PFN( // PHYSICAL_ADDRESS Pa, // ) // // Routine Description: // // This macro takes a physical address and returns the pfn to which // it corresponds. // // Arguments // // Pa - Supplies the physical address to convert. // // Return Value: // // The Pfn that corresponds to the physical address is returned. // //-- #define MI_CONVERT_PHYSICAL_BUS_TO_PFN(Pa) \ ((PFN_NUMBER)((Pa).QuadPart >> ((CCHAR)PAGE_SHIFT))) typedef struct _MMCOLOR_TABLES { PFN_NUMBER Flink; PVOID Blink; } MMCOLOR_TABLES, *PMMCOLOR_TABLES; typedef struct _MMPRIMARY_COLOR_TABLES { LIST_ENTRY ListHead; } MMPRIMARY_COLOR_TABLES, *PMMPRIMARY_COLOR_TABLES; #if MM_MAXIMUM_NUMBER_OF_COLORS > 1 extern MMPFNLIST MmFreePagesByPrimaryColor[2][MM_MAXIMUM_NUMBER_OF_COLORS]; #endif extern PMMCOLOR_TABLES MmFreePagesByColor[2]; extern PFN_NUMBER MmTotalPagesForPagingFile; #define MI_PTE_LOOKUP_NEEDED ((ULONG64)0xffffffff) // // The hardware PTE is defined in ntos\inc\alpha.h. // // Invalid PTEs have the following definition. // typedef struct _MMPTE_SOFTWARE { ULONGLONG Valid: 1; ULONGLONG Prototype : 1; ULONGLONG Transition : 1; ULONGLONG Protection : 5; ULONGLONG UsedPageTableEntries : PTE_PER_PAGE_BITS; ULONGLONG Reserved : 20 - PTE_PER_PAGE_BITS; ULONGLONG PageFileLow: 4; ULONGLONG PageFileHigh : 32; } MMPTE_SOFTWARE; typedef struct _MMPTE_TRANSITION { ULONGLONG Valid : 1; ULONGLONG Prototype : 1; ULONGLONG Transition : 1; ULONGLONG Protection : 5; ULONGLONG filler01 : 24; ULONGLONG PageFrameNumber : 32; } MMPTE_TRANSITION; typedef struct _MMPTE_PROTOTYPE { ULONGLONG Valid : 1; ULONGLONG Prototype : 1; ULONGLONG ReadOnly : 1; ULONGLONG Protection : 5; ULONGLONG filler02 : 8; LONGLONG ProtoAddress : 48; } MMPTE_PROTOTYPE; typedef struct _MMPTE_LIST { ULONGLONG Valid : 1; ULONGLONG filler07 : 7; ULONGLONG OneEntry : 1; ULONGLONG filler03 : 23; ULONGLONG NextEntry : 32; } MMPTE_LIST; typedef struct _MMPTE_SUBSECTION { ULONGLONG Valid : 1; ULONGLONG Prototype : 1; ULONGLONG WhichPool : 1; ULONGLONG Protection : 5; ULONGLONG Filler04 : 8; LONGLONG SubsectionAddress : 48; } MMPTE_SUBSECTION; // // A Valid Page Table Entry on a DEC AXP64 system has the following format. // // typedef struct _HARDWARE_PTE { // ULONGLONG Valid : 1; // ULONGLONG Reserved1 : 1; // ULONGLONG FaultOnWrite : 1; // ULONGLONG Reserved2 : 1; // ULONGLONG Global : 1; // ULONGLONG GranularityHint : 2; // ULONGLONG Reserved3 : 1; // ULONGLONG KernelReadAccess : 1; // ULONGLONG UserReadAccess : 1; // ULONGLONG Reserved4 : 2; // ULONGLONG KernelWriteAccess : 1; // ULONGLONG UserWriteAccess : 1; // ULONGLONG Reserved5 : 2; // ULONGLONG Write : 1; // ULONGLONG CopyOnWrite: 1; // ULONGLONG SoftwareWsIndex : 14; // ULONGLONG PageFrameNumber : 32; // } HARDWARE_PTE, *PHARDWARE_PTE; // #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) // // A Page Table Entry on a DEC ALPHA has the following definition. // typedef struct _MMPTE { union { ULONG_PTR Long; HARDWARE_PTE Hard; HARDWARE_PTE Flush; MMPTE_PROTOTYPE Proto; MMPTE_SOFTWARE Soft; MMPTE_TRANSITION Trans; MMPTE_LIST List; MMPTE_SUBSECTION Subsect; } u; } MMPTE, *PMMPTE; //++ //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. // // 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) \ (*(_PointerPte) = (_PteContents)) //++ //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. // // 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) \ (*(_PointerPte) = (_PteContents)) //++ //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. // // 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) \ (*(_PointerPte) = (_PteContents)) //++ //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)) //++ //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)PDE_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)PDE_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_UBASE && (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)PDE_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)) //++ //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. // //-- #if defined(NT_UP) #define MI_BARRIER_SYNCHRONIZE(TimeStamp) \ __MB(); #else #define MI_BARRIER_SYNCHRONIZE(TimeStamp) \ if ((ULONG)TimeStamp == KeReadMbTimeStamp()) { \ KeSynchronizeMemoryAccess(); \ } #endif //++ //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. // //-- #if defined(NT_UP) #define MI_BARRIER_STAMP_ZEROED_PAGE(PointerTimeStamp) NOTHING #else #define MI_BARRIER_SUPPORTED 1 #define MI_BARRIER_STAMP_ZEROED_PAGE(PointerTimeStamp) (*(PULONG)PointerTimeStamp = KeReadMbTimeStamp()) #endif //++ //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 Alpha supports ASNs and session space doesn't have one, the entire // TB needs to be flushed. // // 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 = *PtePointer; \ *PtePointer = PteValue; \ KeFlushEntireTb (TRUE, TRUE); //++ //VOID //MI_FLUSH_ENTIRE_SESSION_TB ( // IN ULONG Invalid, // IN LOGICAL AllProcessors // ); // // Routine Description: // // MI_FLUSH_ENTIRE_SESSION_TB flushes the entire TB on Alphas since // the Alpha supports ASNs. // // 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) \ KeFlushEntireTb (Invalid, AllProcessors);