#ifndef __SYS_FUNCTIONS_LOADED #define __SYS_FUNCTIONS_LOADED 1 /* IDENT X-19 */ /***************************************************************************** * * * COPYRIGHT (c) 1996 BY * * DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. * * ALL RIGHTS RESERVED. * * * * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED * * ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE * * INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER * * COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY * * OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY * * TRANSFERRED. * * * * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE * * AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT * * CORPORATION. * * * * DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS * * SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. * * * *****************************************************************************/ /* *++ * FACILITY: * * VMS Executive (LIB) * * ABSTRACT: * * This header file will provide a basic set of C inline functions for * OpenVMS system services. * * AUTHOR: * * Karen L. Noel * * CREATION DATE: 15-Nov-1994 * * MODIFICATION HISTORY: * * X-19 KLN3364 Karen L. Noel 29-Sep-2003 * Fix declaration of exe$reflect. * * X-18 KLN3362 Karen L. Noel 25-Sep-2003 * Acces return address as an argument to $priv_instr_trap. * * X-17 KLN3175 Karen L. Noel 19-Dec-2002 * Disable the $$SEXT macro for IA64. Virtual addresses should * not require extending like on Alpha. On IA64, process space * does not contain a gap. * * X-16 KLN3112 Karen L. Noel 22-Oct-2002 * Add static to $priv_instr_trap to avoid it being defined * as global in every module that invokes it. * * X-15 Clair Grant 24-Jul-2002 * intstk$l_ipl and intstk$l_pprevmode should be bytes * not longwords. * * X-14 KLN3065 Karen L. Noel 22-May-2002 * Add $priv_instr_trap for IA64 code. * * X-13 KLN3039 Karen L. Noel 25-Mar-2002 * Add $get_interrupt_ps for IA64 port. * * X-12 AHM0022 Drew Mason 13-Nov-1997 * Fix bug in $align_va by surrounding the definition with * parentheses. * * X-11 NYK662 Nitin Y. Karkhanis 1-Aug-1996 * Add $align_va. * * X-10 KLN1533 Karen L. Noel 24-Oct-1995 * Move $probe functions here from mmg_functions.h so * they can be used in a more general purpose way. * * X-9 KLN1530 Karen L. Noel 13-Oct-1995 * 1. Include builtins.h for completeness. * 2. Conditionalize $get_ps_info so header will compile * with and without __NEW_STARLET. * * X-8 KLN1471 Karen L. Noel 7-Jul-1995 * Add $$trunc macro. * * X-7 KLN1394 Karen L. Noel 27-Feb-1995 * Fix $make_bigpage_inclusive macro. * * X-6 KLN1367 Karen L. Noel 20-Jan-1995 * Fix cut-and-paste error. * * X-5 KLN1365 Karen L. Noel 19-Jan-1995 * Add $make_big_page_inclusive function * * X-4 KLN1350 Karen L. Noel 6-Dec-1994 * Fix definition of PS. * * X-3 KLN1342 Karen L. Noel 30-Nov-1994 * Add $get_ps_info * * X-2 KLN1336 Karen L. Noel 22-Nov-1994 * Take out definitions of SS$_IVACMODE. *-- */ /* Include any header files we need to make these functions work */ #include #include #include #include #include #include #ifdef __ia64 #include #include #include #endif /* *++ * $$sext - sign extend a 64-bit VA * * Input: va - 64-bit VA * *-- */ #ifdef __alpha #define $$sext(va)\ (VOID_PQ)(((__int64)(va) << (64-mmg$gl_va_bits)) >> (64-mmg$gl_va_bits)) #else #define $$sext(va) (VOID_PQ)(va) #endif /* *++ * $$trunc - truncate a 64-bit VA * * Input: va - 64-bit VA * *-- */ #define $$trunc(va)\ (uint64)(((uint64)(va) << (64-mmg$gl_va_bits)) >> (64-mmg$gl_va_bits)) /* *++ * $make_big_page_inclusive - Make start_va and length on even page boundaries * * Input: start_va - Unaligned starting address * length - Non-page multiple length * * Output: return_va - Aligned starting address * return_length - Page multiple length * * This function ensures that original start_va and length are covered with * the returned va and length. If the length was just blindly rounded up, * the original intended end_va may not get covered by the returned range. *-- */ #pragma inline ($make_big_page_inclusive) static void $make_big_page_inclusive(VOID_PQ start_va, uint64 length, VOID_PQ *return_va, uint64 *return_length) { extern const uint64 mmg$gq_bwp_mask; uint64 temp_length; VOID_PQ lo_va,hi_va; /* Round down starting address */ lo_va = (VOID_PQ)((uint64)start_va & ~mmg$gq_bwp_mask); *return_va = lo_va; /* Compute high address */ hi_va = (VOID_PQ)((uint64)start_va + length); /* Compute length not yet rounded up */ temp_length = ((uint64)hi_va - (uint64)lo_va); /* Round up return length */ *return_length = (temp_length + mmg$gq_bwp_mask) & ~mmg$gq_bwp_mask; } /* *++ * $maximize_access_mode - maximize the acmode argument with the caller's mode. * * Input: acmode - Access mode provided by caller * callers_mode - Access mode of caller * * Output: Returns SS$_IVACMODE status if acmode is greater than PSL$C_USER * If success, returns SS$_NORMAL. * max_mode - Maximum of acmode and caller's mode. * *-- */ #pragma inline ($maximize_access_mode) static int $maximize_access_mode(int acmode, int callers_mode, int *max_mode) { if (acmode > PSL$C_USER) return (SS$_IVACMODE); if (acmode <= callers_mode) *max_mode = callers_mode; else *max_mode = acmode; return (SS$_NORMAL); } /* *++ * $is_aligned - check if arg is properly aligned * * Input: arg - 64-bit value * alignment - alignment factor (page size or block size for example) * * Output: returns 1 if aligned * returns 0 if not aligned * *-- */ #define $is_aligned(arg,alignment)\ (((uint64)(arg) & ((uint64)(alignment)-1)) == 0) /* *++ * $align_va - Align va up or down to alignment factor * * Input: arg - 64-bit value * alignment - alignment factor (page size or block size for example) * up - 1 for round up or 0 for round down * * Output: Aligned 64-bit value * *-- */ #define $align_va(arg,alignment,up)\ ( (up)\ ? (VOID_PQ)(((uint64)(arg)+(uint64)(alignment)-1) & ~((uint64)(alignment)-1))\ : (VOID_PQ)((uint64)(arg) & ~((uint64)(alignment)-1)) ) /* *++ * $get_ps_info - Read PS and get IPL and callers_mode * * Note: * This function is only available with __NEW_STARLET due to the differences * with PSLDEF. Since there is no current need for $get_ps_info without * __NEW_STARLET, it will not be implemented at this time. * * Inputs: none * * Outpus: *callers_mode - Previous mode from PS * *ipl - Current IPL *-- */ #ifdef __NEW_STARLET #pragma inline ($get_ps_info) static void $get_ps_info(int *callers_mode, int *ipl) { typedef union { PSLDEF fields; uint64 quad; } PS; PS ps; /* Read PS and get IPL and caller's mode */ ps.quad = __PAL_RD_PS(); *ipl = (int)(ps.fields.psl$v_ipl); *callers_mode = (int)(ps.fields.psl$v_prvmod); } #endif /* __NEW_STARLET */ /* *++ * $make_interrupt_ps - Construct an interrupt PS from the interrupt stack frame * * Input: intstk_p - pointer to interrupt stack frame * * Output: int_ps - PS as if it were in the Alpha interrupt stack * *-- */ #pragma inline ($get_interrupt_ps) static unsigned __int64 $get_interrupt_ps (INTSTK * intstk_p) { #ifdef __alpha return (intstk_p->intstk$q_ps); #endif #ifdef __ia64 /* Create a type for the PS */ typedef union { PSLDEF fields; unsigned __int64 quad; } PS; PS int_ps; PSR ipsr; // Interrupt processor status register /* Fill in PS fields from fields in the interrupt stack */ int_ps.quad = 0; int_ps.fields.psl$v_ipl = intstk_p->intstk$b_ipl; ipsr.psr$q_processor_status = intstk_p->intstk$q_ipsr; int_ps.fields.psl$v_curmod = ipsr.psr$v_cpl; int_ps.fields.psl$v_prvmod = intstk_p->intstk$b_pprevmode; /* Return the results */ return (int_ps.quad); #endif } /* *++ * $prober_1q - Probe 1 quadword for readability. * * Input: va - Address of quadword * callers_mode - Mode of caller * * Output: Returns 1 if quadword is readable. * Returns 0 if quadword is not readable. * *-- */ #define $prober_1q(va, callers_mode)\ __PAL_PROBER((va), sizeof(uint64)-1, (char)callers_mode) /* *++ * $probew_1q - Probe 1 quadword for writability. * * Input: va - Address of quadword * callers_mode - Mode of caller * * Output: Returns 1 if quadword is writable. * Returns 0 if quadword is not writable. * *-- */ #define $probew_1q(va, callers_mode)\ __PAL_PROBEW((va), sizeof(uint64)-1, (char)callers_mode) /* *++ * $probew_2q - Probe 2 quadwords for writability. * * Input: va1 - Address of first quadword * va2 - Address of second quadword * callers_mode - Mode of caller * * Output: Returns 1 if both quadwords are writable. * Returns 0 if one or both quadwords are not writable. * *-- */ #pragma inline ($probew_2q) static int $probew_2q (VOID_PQ va1, VOID_PQ va2, int callers_mode) { VOID_PQ lo, hi; uint64 diff; /* Order addresses */ if (va1 < va2) { lo = va1; hi = va2; } else { lo = va2; hi = va1; } /* If diff is less than or equal to minimum page size, do one probe */ diff = ((uint64)hi - (uint64)lo) + sizeof(uint64); if (diff <= 0x8000) return (__PAL_PROBEW(lo, (int)diff-1, (char)callers_mode)); /* Both probes must succeed to return 1 */ return (__PAL_PROBEW(lo, sizeof(uint64)-1, (char)callers_mode) & __PAL_PROBEW(hi, sizeof(uint64)-1, (char)callers_mode)); } // If the caller's mode is not kernel, reflect an illegal instruction trap // AKA - privileged instruction trap // AKA - opcdec #ifdef __ia64 // Verified for IA64 port - KLN #pragma inline ($priv_instr_trap) static void $priv_instr_trap(__int64 ret_addr) { extern void exe$reflect (int mode, VOID_PQ ret_addr, int sscode, ...); PFS pfs; int mode; // Get the caller's mode from the PFS pfs.pfs$iq_prev_func_state = __getReg (_IA64_REG_AR_PFS); mode = pfs.pfs$v_ppl; // If the caller's mode is not kernel if (mode != PL$C_KERNEL) // The caller tried to execute a privileged instruction exe$reflect (mode, (VOID_PQ)ret_addr, SS$_OPCDEC); return; } #endif #endif /* SYS_FUNCTIONS_LOADED */