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 */