/* Version X-18 ************************************************************************* * * * VMS SOFTWARE, INC. CONFIDENTIAL. This software is confidential * * proprietary software licensed by VMS Software, Inc., and is not * * authorized to be used, duplicated or disclosed to anyone without * * the prior written permission of VMS Software, Inc. * * Copyright 2019 VMS Software, Inc. * * * ************************************************************************* */ /* *++ * FACILITY: * * Open/VMS AXP (LIB) * * ABSTRACT: * * This header file will provide big page inline functions equivalent to * the LIB big page macros which exist for BLISS and Macro. * * AUTHOR: * * Karen Noel * * CREATION DATE: 12-Sep-1994 * * MODIFICATION HISTORY: * * X-18 CEG0915 Clair Grant 25-Sep-2020 * Change comment in X-17 * * X-17 CEG0906 Clair Grant 24-Sep-2020 * Replace "// comment" style to eliminate * confusion when compiling /STANDARD=VAXC. * * X-16 AHM Drew Mason 17-Jun-2019 * Bug located and fixed. Revert to contents of X-13. * * X-15 AHM Drew Mason 13-Jun-2019 * Set __required_pointer_size to long in case some code * using this include file has it as short. * * X-14 AHM Drew Mason 11-Jun-2019 * Back out X-13 and feed it in piece by piece to identify * the failing part. Define mmg$gq_shared_va_ptes, * mmg$gq_bpt_base, and mmg$gq_phymem_window_base_addr * based on architecture, not on __SYSBOOT flag. * * X-13 LMN Lisa Nevin 07-Jun-2019 * X86 support for $is_process_pte_va, removed source * conditionals based on the __SYSBOOT flag * * X-12 LMN Lisa Nevin 15-Mar-2019 * Add x86 bug fix to is_private_va, to check also if equal on * boundary mmg$gq_bpt_base * * X-11 MJM Michael Moroney 13-Sep-2018 * Add X86 specific versions of $is_private_va, $is_shared_va * and $is_system_pte_va where mmg$gq_shared_va_ptes is really * an array of four addresses, one per mode. * * X-10 AHM Drew Mason 10-Aug-2018 * Change BIGPAGE$BWP_WIDTH, BIGPAGE$BWP_MASK, and * BIGPAGE$PAGE_SIZE on x86 for page allocation size. * Define BIGPAGE$VA_MASK and BIGPAGE$PT_MASK. Fix * macros to use the correct revised symbols. * * X-9 DOF Dave Fairbanks 13-Jun-2018 * Move the following RUNCONST symbols: * - mmg$gq_level_width * - mmg$gq_ptes_per_page * - mmg$gl_bwp_width * - mmg$gl_bwp_mask * - mmg$gl_page_size * before the #ifdef __x86_64 conditional so they are * also declared for X86. * * X-8 AHM Drew Mason 15-May-2018 * Fix bug where defined symbols conflict with symbols in other * modules with the same name. Add BIGPAGE$ to all defined * symbols. * * X-7 AHM Drew Mason 4-May-2018 * For x86, use compile-time constants for level width, ptes * per page, bwp width, bwp mask, and page size. * * X-6 AHM Drew Mason 12-Apr-2018 * Fix improper declaration of mmg$gq_phymem_window_base_addr * as int64 rather than __int64. * * X-5 AHM Drew Mason 9-Mar-2018 * Resync modification history. Add definition of * __RUNCONST to allow SYSBOOT to write the "constants" * used here. Update macros $is_system_pte_va, * $is_shared_va, and $is_private_va for x86 complexities. * * X-3A1A3 KLN3058 Karen L. Noel 18-Apr-2002 * o Add more parens in $make_va macro so it works in conditional * statements and with complex arguments. * o Add $is_valid_address macro. * * X-3A1A2 KLN3037 Karen L. Noel 13-Mar-2002 * We don't trust the compiler anymore. Put the inlines * back in. It messes up initialization routines. * * X-3A1A1 KLN3025 Karen L. Noel 26-Feb-2002 * o Port PT space to IA64. * o Remove inline pragmas. We trust the compiler now. * * X-3A1 KLN2202 Karen L. Noel 27-Nov-2000 * Fix $make_va so it properly returns a VOID_PQ. * * X-3 KLN1396 Karen L. Noel 24-Feb-1995 * Add $is_shared_va and $is_private_va. * * X-2 KLN1322 Karen L. Noel 22-Sep-1994 * 64-bit project: Internal programming * Define roundup argument. * *-- */ #ifndef __LIB_BIGPAGE_LOADED #define __LIB_BIGPAGE_LOADED 1 #ifdef __INITIAL_POINTER_SIZE #pragma __required_pointer_size save #pragma __required_pointer_size long #endif /* * Included files: * * */ #include #include #include #ifdef __x86_64 /* Verified for x86 port--Drew Mason */ #include #endif /* This construct allows SYSBOOT write access to variables that are */ /* run-time constants, but need to be initialized at boot time. */ #ifdef __SYSBOOT #define __RUNCONST #else #define __RUNCONST const #endif /* * * External data cells: * */ #ifdef __x86_64 /* Verified for x86 port--Drew Mason */ extern PTE_PQ __RUNCONST mmg$gq_shared_va_ptes [4]; extern PTE_PQ __RUNCONST mmg$gq_bpt_base [4]; extern __int64 __RUNCONST mmg$gq_phymem_window_base_addr; #else extern PTE_PQ __RUNCONST mmg$gq_shared_va_ptes; extern PTE_PQ __RUNCONST mmg$gq_pt_base [VA$C_VRNX_COUNT]; #endif extern VOID_PQ __RUNCONST mmg$gq_system_virtual_base; extern __RUNCONST unsigned __int64 mmg$gq_non_va_mask; /* The symbols defined below cannot be UNDEFINED because they * need to be available in the source file that includes them. * So prefix them with BIGPAGE$, which is unlikely to conflict * with other symbol names. */ extern __RUNCONST unsigned __int64 mmg$gq_level_width; extern __RUNCONST unsigned __int64 mmg$gq_ptes_per_page; extern __RUNCONST int mmg$gl_bwp_width; extern __RUNCONST int mmg$gl_bwp_mask; extern __RUNCONST int mmg$gl_page_size; #ifdef __x86_64 /* Verified for x86 port--Drew Mason */ extern __RUNCONST unsigned __int64 mmg$gq_pt_mask; extern __RUNCONST unsigned __int64 mmg$gq_va_mask; #define BIGPAGE$LEVEL_WIDTH MMG$$C_PTE_SEGMENT_SIZE #define BIGPAGE$PTES_PER_PAGE MMG$$C_PTES_PER_PAGE #define BIGPAGE$PT_MASK mmg$gq_pt_mask #define BIGPAGE$VA_MASK mmg$gq_va_mask /* These next three are based on the page allocation size of 8 kB, not the */ /* page size defined in the x86 architecture of 4 kB. */ #define BIGPAGE$BWP_WIDTH MMG$$C_BWP_WIDTH #define BIGPAGE$BWP_MASK MMG$$C_BOFF_MASK_8K #define BIGPAGE$PAGE_SIZE MMG$$C_BYTES_PER_PAGE #else #define BIGPAGE$LEVEL_WIDTH mmg$gq_level_width #define BIGPAGE$PTES_PER_PAGE mmg$gq_ptes_per_page #define BIGPAGE$BWP_WIDTH mmg$gl_bwp_width #define BIGPAGE$BWP_MASK mmg$gl_bwp_mask #define BIGPAGE$PAGE_SIZE mmg$gl_page_size #define BIGPAGE$PT_MASK (~mmg$gq_non_pt_mask) #define BIGPAGE$VA_MASK (~mmg$gq_non_va_mask) #endif /* *++ * $sys_start_of_page - Calculate the starting address of the page. * * Inputs: * source_va - source address * * Returns: * The address of the first byte within the page specified by source_va. *-- */ #define $sys_start_of_page(source_va) \ (VOID_PQ)((unsigned __int64)source_va & ~(unsigned __int64)(BIGPAGE$BWP_MASK)) /* *++ * $sys_next_page - Calculate the address of the next page. * * Inputs: * source_va - source address * clearbwp - If 1, masks the bwp portion of the VA. * * Returns: * The address of one page after the source address. If clearbwp is 1, * the address will be rounded down to be the start of the next page. * *-- */ #define $sys_next_page(source_va, clearbwp) \ (VOID_PQ)(((unsigned __int64)source_va + \ (unsigned __int64)BIGPAGE$PAGE_SIZE) & \ ~(clearbwp * ((unsigned __int64)BIGPAGE$BWP_MASK)) ) /* *++ * $sys_previous_page - Calculate the address of the previous page. * * Inputs: * source_va - source address * clearbwp - If 1, masks the bwp portion of the VA. * * Returns: * The address of one page before the source address. If clearbwp is 1, * the address will be rounded down to be the start of the previous page. * *-- */ #define $sys_previous_page(source_va, clearbwp) \ (VOID_PQ)(((unsigned __int64)source_va - \ (unsigned __int64)BIGPAGE$PAGE_SIZE) & \ ~(clearbwp * ((unsigned __int64)BIGPAGE$BWP_MASK)) ) /* *++ * $sys_pages_to_bytes - Convert pages to bytes * * Inputs: * page_count - source page count * * Returns: * The number of bytes in page_count. * *-- */ #define $sys_pages_to_bytes(page_count) (page_count << BIGPAGE$BWP_WIDTH) /* *++ * $bytes_to_pages - Convert bytes to pages * * Inputs: * byte_count - Byte count * roundup = 1 if byte_count is to be rounded up before converted to pages * = 0 if rounding is not required. * * Returns: * The number of pages in byte_count. * *-- */ #define $sys_bytes_to_pages(byte_count, roundup) \ ((byte_count + (roundup*BIGPAGE$BWP_MASK)) >> BIGPAGE$BWP_WIDTH) /* *++ * $extract_vpn - Extract page table space vpn from va * * Inputs: * addr - source virtual address * * Extracts a VPN from a virtual address * *-- */ #define $extract_vpn(addr) \ (unsigned int)(((unsigned __int64)addr & BIGPAGE$VA_MASK) \ >> BIGPAGE$BWP_WIDTH) /* *++ * $extract_pte_offset - Extract page table space pte offset from va * * Inputs: * addr - source virtual address * * Extracts a PTE offset from a virtual address * *-- */ #define $extract_pte_offset(addr) \ (((unsigned __int64)addr & BIGPAGE$PT_MASK) \ >> BIGPAGE$LEVEL_WIDTH) /* *++ * $make_va - Make a virtual address from a virtual page number in page table * space * * Input: * vpn - source virtual page number * * Output: * va - virtual address (VOID_PQ) * * Makes a virtual address from virtual page number * *-- */ /* Shift a VPN into the proper location in a virtual address. */ #define $$$non_sext_va(vpn) \ ((unsigned __int64)(vpn) << BIGPAGE$BWP_WIDTH) /* Mask to extract the one bit in a shifted VPN that needs to be sign */ /* extended when crafting a canonical virtual address. */ #define $$$sext_bit \ ((unsigned __int64)1<<(mmg$gq_va_bits-1)) #define $make_va(vpn) \ ((($$$non_sext_va(vpn) & $$$sext_bit) == 0) ? \ (VOID_PQ)($$$non_sext_va(vpn)) : \ (VOID_PQ)($$$non_sext_va(vpn) | BIGPAGE$VA_MASK)) /* *++ * $is_pt_space_va - Test if quadword is a PT space address * * Inputs: arg - 64-bit address * * Output: 1 if arg is PT space address * 0 if arg is not PT space address * *-- */ #pragma inline ($$$is_pt_space_va) static int $$$is_pt_space_va (unsigned __int64 arg) { # ifdef __x86_64 /* Verified for x86 port--Drew Mason */ if (arg < (unsigned __int64) mmg$gq_bpt_base [PSL$C_KERNEL]) return 0; if (arg >= (unsigned __int64) mmg$gq_phymem_window_base_addr) return 0; return 1; # else int vrnx; unsigned __int64 p,size_of_pt_space; # ifdef __NEW_STARLET VA v; v.va$q_quad = arg; # else va v; v.va$q_quad[0] = arg; v.va$q_quad[1] = arg>>32; # endif /* __NEW_STARLET */ /* Get VRNX from the VA */ vrnx = v.va$v_vrnx; /* If less that pt_base, it's not a PT space VA */ if (arg < (unsigned __int64)mmg$gq_pt_base[vrnx]) return 0; /* Get size of a PT space given 3 levels of page tables */ p = BIGPAGE$PTES_PER_PAGE; size_of_pt_space = p*p*p*PTE$C_BYTES_PER_PTE; /* If greater than or equal to the top of PT space, it's not a PT space VA */ if (arg >= (unsigned __int64)mmg$gq_pt_base[vrnx] + size_of_pt_space) return 0; /* It's a PT space VA */ return 1; # endif /* __x86_64 */ } #define $is_pt_space_va(arg) $$$is_pt_space_va((unsigned __int64)(arg)) /* *++ * $is_process_pte_va - Test if quadword is a process pte address * for X86 page table entries are between Kernel bpt base and < Physical Memory Window * since we are checking for only process the max would be shared[USER] * * Inputs: arg - 64-bit address * * Output: 1 if arg is process pte address * 0 if arg is not process pte address * *-- */ #pragma inline ($$$is_process_pte_va) static int $$$is_process_pte_va (unsigned __int64 arg) { #ifdef __x86_64 return ( ( (arg >= (unsigned __int64) mmg$gq_bpt_base [PSL$C_KERNEL]) && ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_KERNEL]) ) || \ ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_bpt_base[PSL$C_EXEC]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_EXEC]) ) || \ ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_bpt_base[PSL$C_SUPER]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_SUPER]) ) || \ ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_bpt_base[PSL$C_USER]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_USER]) ) ); #else int vrnx; unsigned __int64 size_of_pt_space; #ifdef __NEW_STARLET VA v; v.va$q_quad = arg; #else va v; v.va$q_quad[0] = arg; v.va$q_quad[1] = arg>>32; #endif /* Get VRNX from the VA */ vrnx = v.va$v_vrnx; /* If VRNX is system space, it's not a process PTE address */ if (vrnx == VA$C_VRNX_SYSTEM) return 0; /* Return the results from the PT space VA test */ return ($is_pt_space_va(arg)); #endif /* __x86_64 */ } #define $is_process_pte_va(arg) $$$is_process_pte_va ((unsigned __int64)(arg)) /* *++ * $is_system_pte_va - Test if quadword is a system pte address * * Inputs: arg - 64-bit address * * Output: 1 if arg is system pte address * 0 if arg is not system pte address * *-- */ #ifdef __x86_64 /* Verified for x86 port--Drew Mason */ #define $is_system_pte_va(arg) \ ( ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_KERNEL]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_bpt_base[PSL$C_EXEC])) || \ ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_EXEC]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_bpt_base[PSL$C_SUPER])) || \ ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_SUPER]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_bpt_base[PSL$C_USER])) || \ ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_USER]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_phymem_window_base_addr)) ) #else #define $is_system_pte_va(arg) \ (((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_system_virtual_base)) #endif /* __x86_64 */ /* *++ * $is_shared_va - Test if quadword is a shared va * * Inputs: arg - 64-bit address * * Output: 1 if arg is shared address * 0 if arg is not shared address * *-- */ #ifdef __x86_64 /* Verified for x86 port--Drew Mason */ #define $is_shared_va(arg) \ ( ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_KERNEL]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_bpt_base[PSL$C_EXEC])) || \ ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_EXEC]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_bpt_base[PSL$C_SUPER])) || \ ( ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_SUPER]) && \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_bpt_base[PSL$C_USER])) || \ ( (unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_USER]) ) #else #define $is_shared_va(arg) \ ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_shared_va_ptes) #endif /* __x86_64 */ /* *++ * $is_private_va - Test if quadword is a private va * * Inputs: arg - 64-bit address * * Output: 1 if arg is private address * 0 if arg is not private address * *-- */ #ifdef __x86_64 /* Verified for x86 port--Drew Mason */ #define $is_private_va(arg) \ ( ( (unsigned __int64)(arg) < (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_KERNEL]) || \ ( ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_EXEC]) && \ ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_bpt_base[PSL$C_EXEC])) || \ ( ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_SUPER]) && \ ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_bpt_base[PSL$C_SUPER])) || \ ( ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_shared_va_ptes[PSL$C_USER]) && \ ((unsigned __int64)(arg) >= (unsigned __int64)mmg$gq_bpt_base[PSL$C_USER])) ) #else #define $is_private_va(arg) \ ((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_shared_va_ptes) #endif /* __x86_64 */ /* *++ * $is_valid_address - Test if quadword is a valid 64-bit address * * Inputs: arg - 64-bit address * * Output: 1 if arg is valid address * 0 if arg is not valid address * *-- */ extern VOID_PQ __RUNCONST mmg$gq_gap_lo_va; extern VOID_PQ __RUNCONST mmg$gq_gap_hi_va; #define $is_valid_address(arg) \ (((unsigned __int64)(arg) < (unsigned __int64)mmg$gq_gap_lo_va) || \ ((unsigned __int64)(arg) > (unsigned __int64)mmg$gq_gap_hi_va) ) #ifdef __INITIAL_POINTER_SIZE #pragma __required_pointer_size restore #endif #endif /* __LIB_BIGPAGE_LOADED */