1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2019 Joyent, Inc.
  29  */
  30 
  31 #ifndef _IA32_SYS_ASM_LINKAGE_H
  32 #define _IA32_SYS_ASM_LINKAGE_H
  33 
  34 #include <sys/stack.h>
  35 #include <sys/trap.h>
  36 
  37 #ifdef  __cplusplus
  38 extern "C" {
  39 #endif
  40 
  41 #ifdef _ASM     /* The remainder of this file is only for assembly files */
  42 
  43 /*
  44  * make annoying differences in assembler syntax go away
  45  */
  46 
  47 /*
  48  * D16 and A16 are used to insert instructions prefixes; the
  49  * macros help the assembler code be slightly more portable.
  50  */
  51 #if !defined(__GNUC_AS__)
  52 /*
  53  * /usr/ccs/bin/as prefixes are parsed as separate instructions
  54  */
  55 #define D16     data16;
  56 #define A16     addr16;
  57 
  58 /*
  59  * (There are some weird constructs in constant expressions)
  60  */
  61 #define _CONST(const)           [const]
  62 #define _BITNOT(const)          -1!_CONST(const)
  63 #define _MUL(a, b)              _CONST(a \* b)
  64 
  65 #else
  66 /*
  67  * Why not use the 'data16' and 'addr16' prefixes .. well, the
  68  * assembler doesn't quite believe in real mode, and thus argues with
  69  * us about what we're trying to do.
  70  */
  71 #define D16     .byte   0x66;
  72 #define A16     .byte   0x67;
  73 
  74 #define _CONST(const)           (const)
  75 #define _BITNOT(const)          ~_CONST(const)
  76 #define _MUL(a, b)              _CONST(a * b)
  77 
  78 #endif
  79 
  80 /*
  81  * C pointers are different sizes between i386 and amd64.
  82  * These constants can be used to compute offsets into pointer arrays.
  83  */
  84 #if defined(__amd64)
  85 #define CLONGSHIFT      3
  86 #define CLONGSIZE       8
  87 #define CLONGMASK       7
  88 #elif defined(__i386)
  89 #define CLONGSHIFT      2
  90 #define CLONGSIZE       4
  91 #define CLONGMASK       3
  92 #endif
  93 
  94 /*
  95  * Since we know we're either ILP32 or LP64 ..
  96  */
  97 #define CPTRSHIFT       CLONGSHIFT
  98 #define CPTRSIZE        CLONGSIZE
  99 #define CPTRMASK        CLONGMASK
 100 
 101 #if CPTRSIZE != (1 << CPTRSHIFT) || CLONGSIZE != (1 << CLONGSHIFT)
 102 #error  "inconsistent shift constants"
 103 #endif
 104 
 105 #if CPTRMASK != (CPTRSIZE - 1) || CLONGMASK != (CLONGSIZE - 1)
 106 #error  "inconsistent mask constants"
 107 #endif
 108 
 109 #define ASM_ENTRY_ALIGN 16
 110 
 111 /*
 112  * SSE register alignment and save areas
 113  */
 114 
 115 #define XMM_SIZE        16
 116 #define XMM_ALIGN       16
 117 
 118 #if defined(__amd64)
 119 
 120 #define SAVE_XMM_PROLOG(sreg, nreg)                             \
 121         subq    $_CONST(_MUL(XMM_SIZE, nreg)), %rsp;            \
 122         movq    %rsp, sreg
 123 
 124 #define RSTOR_XMM_EPILOG(sreg, nreg)                            \
 125         addq    $_CONST(_MUL(XMM_SIZE, nreg)), %rsp
 126 
 127 #elif defined(__i386)
 128 
 129 #define SAVE_XMM_PROLOG(sreg, nreg)                             \
 130         subl    $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp; \
 131         movl    %esp, sreg;                                     \
 132         addl    $XMM_ALIGN, sreg;                               \
 133         andl    $_BITNOT(XMM_ALIGN-1), sreg
 134 
 135 #define RSTOR_XMM_EPILOG(sreg, nreg)                            \
 136         addl    $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp;
 137 
 138 #endif  /* __i386 */
 139 
 140 /*
 141  * profiling causes definitions of the MCOUNT and RTMCOUNT
 142  * particular to the type
 143  */
 144 #ifdef GPROF
 145 
 146 #define MCOUNT(x) \
 147         pushl   %ebp; \
 148         movl    %esp, %ebp; \
 149         call    _mcount; \
 150         popl    %ebp
 151 
 152 #endif /* GPROF */
 153 
 154 #ifdef PROF
 155 
 156 #define MCOUNT(x) \
 157 /* CSTYLED */ \
 158         .lcomm .L_/**/x/**/1, 4, 4; \
 159         pushl   %ebp; \
 160         movl    %esp, %ebp; \
 161 /* CSTYLED */ \
 162         movl    $.L_/**/x/**/1, %edx; \
 163         call    _mcount; \
 164         popl    %ebp
 165 
 166 #endif /* PROF */
 167 
 168 /*
 169  * if we are not profiling, MCOUNT should be defined to nothing
 170  */
 171 #if !defined(PROF) && !defined(GPROF)
 172 #define MCOUNT(x)
 173 #endif /* !defined(PROF) && !defined(GPROF) */
 174 
 175 #define RTMCOUNT(x)     MCOUNT(x)
 176 
 177 /*
 178  * Macro to define weak symbol aliases. These are similar to the ANSI-C
 179  *      #pragma weak _name = name
 180  * except a compiler can determine type. The assembler must be told. Hence,
 181  * the second parameter must be the type of the symbol (i.e.: function,...)
 182  */
 183 #define ANSI_PRAGMA_WEAK(sym, stype)    \
 184 /* CSTYLED */ \
 185         .weak   _/**/sym; \
 186 /* CSTYLED */ \
 187         .type   _/**/sym, @stype; \
 188 /* CSTYLED */ \
 189 _/**/sym = sym
 190 
 191 /*
 192  * Like ANSI_PRAGMA_WEAK(), but for unrelated names, as in:
 193  *      #pragma weak sym1 = sym2
 194  */
 195 #define ANSI_PRAGMA_WEAK2(sym1, sym2, stype)    \
 196         .weak   sym1; \
 197         .type sym1, @stype; \
 198 sym1    = sym2
 199 
 200 /*
 201  * ENTRY provides the standard procedure entry code and an easy way to
 202  * insert the calls to mcount for profiling. ENTRY_NP is identical, but
 203  * never calls mcount.
 204  */
 205 #define ENTRY(x) \
 206         .text; \
 207         .align  ASM_ENTRY_ALIGN; \
 208         .globl  x; \
 209         .type   x, @function; \
 210 x:      MCOUNT(x)
 211 
 212 #define ENTRY_NP(x) \
 213         .text; \
 214         .align  ASM_ENTRY_ALIGN; \
 215         .globl  x; \
 216         .type   x, @function; \
 217 x:
 218 
 219 #define RTENTRY(x) \
 220         .text; \
 221         .align  ASM_ENTRY_ALIGN; \
 222         .globl  x; \
 223         .type   x, @function; \
 224 x:      RTMCOUNT(x)
 225 
 226 /*
 227  * ENTRY2 is identical to ENTRY but provides two labels for the entry point.
 228  */
 229 #define ENTRY2(x, y) \
 230         .text; \
 231         .align  ASM_ENTRY_ALIGN; \
 232         .globl  x, y; \
 233         .type   x, @function; \
 234         .type   y, @function; \
 235 /* CSTYLED */ \
 236 x:      ; \
 237 y:      MCOUNT(x)
 238 
 239 #define ENTRY_NP2(x, y) \
 240         .text; \
 241         .align  ASM_ENTRY_ALIGN; \
 242         .globl  x, y; \
 243         .type   x, @function; \
 244         .type   y, @function; \
 245 /* CSTYLED */ \
 246 x:      ; \
 247 y:
 248 
 249 
 250 /*
 251  * ALTENTRY provides for additional entry points.
 252  */
 253 #define ALTENTRY(x) \
 254         .globl x; \
 255         .type   x, @function; \
 256 x:
 257 
 258 /*
 259  * DGDEF and DGDEF2 provide global data declarations.
 260  *
 261  * DGDEF provides a word aligned word of storage.
 262  *
 263  * DGDEF2 allocates "sz" bytes of storage with **NO** alignment.  This
 264  * implies this macro is best used for byte arrays.
 265  *
 266  * DGDEF3 allocates "sz" bytes of storage with "algn" alignment.
 267  */
 268 #define DGDEF2(name, sz) \
 269         .data; \
 270         .globl  name; \
 271         .type   name, @object; \
 272         .size   name, sz; \
 273 name:
 274 
 275 #define DGDEF3(name, sz, algn) \
 276         .data; \
 277         .align  algn; \
 278         .globl  name; \
 279         .type   name, @object; \
 280         .size   name, sz; \
 281 name:
 282 
 283 #define DGDEF(name)     DGDEF3(name, 4, 4)
 284 
 285 /*
 286  * SET_SIZE trails a function and set the size for the ELF symbol table.
 287  */
 288 #define SET_SIZE(x) \
 289         .size   x, [.-x]
 290 
 291 /*
 292  * NWORD provides native word value.
 293  */
 294 #if defined(__amd64)
 295 
 296 /*CSTYLED*/
 297 #define NWORD   quad
 298 
 299 #elif defined(__i386)
 300 
 301 #define NWORD   long
 302 
 303 #endif  /* __i386 */
 304 
 305 /*
 306  * These macros should be used when making indirect calls in the kernel. They
 307  * will perform a jump or call to the corresponding register in a way that knows
 308  * about retpolines and handles whether such mitigations are enabled or not.
 309  *
 310  * INDIRECT_JMP_REG will jump to named register. INDIRECT_CALL_REG will instead
 311  * do a call. These macros cannot be used to dereference a register. For
 312  * example, if you need to do something that looks like the following:
 313  *
 314  *      call    *24(%rdi)
 315  *      jmp     *(%r15)
 316  *
 317  * You must instead first do a movq into the corresponding location. You need to
 318  * be careful to make sure that the register that its loaded into is safe to
 319  * use. Often that register may be saved or used elsewhere so it may not be safe
 320  * to clobber the value. Usually, loading into %rax would be safe. These would
 321  * turn into something like:
 322  *
 323  *      movq 24(%rdi), %rdi; INDIRECT_CALL_REG(rdi)
 324  *      movq (%r15), %r15; INDIRECT_JMP_REG(r15)
 325  *
 326  * If you are trying to call a global function, then use the following pattern
 327  * (substituting the register in question):
 328  *
 329  *      leaq    my_favorite_function(%rip), %rax
 330  *      INDIRECT_CALL_REG(rax)
 331  *
 332  * If you instead have a function pointer (say gethrtimef for example), then you
 333  * need to do:
 334  *
 335  *      movq    my_favorite_function_pointer(%rip), %rax
 336  *      INDIRECT_CALL_REG(rax)
 337  */
 338 
 339 /* CSTYLED */
 340 #define INDIRECT_JMP_REG(reg)   jmp     __x86_indirect_thunk_/**/reg;
 341 
 342 /* CSTYLED */
 343 #define INDIRECT_CALL_REG(reg)  call    __x86_indirect_thunk_/**/reg;
 344 
 345 #endif /* _ASM */
 346 
 347 #ifdef  __cplusplus
 348 }
 349 #endif
 350 
 351 #endif  /* _IA32_SYS_ASM_LINKAGE_H */