xref: /illumos-gate/usr/src/uts/intel/sys/asm_linkage.h (revision 34bbc83afbf22a6f8e504cb99d76c97c017cb5f4)
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 _SYS_ASM_LINKAGE_H
32 #define	_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  * Why not use the 'data16' and 'addr16' prefixes .. well, the
49  * assembler doesn't quite believe in real mode, and thus argues with
50  * us about what we're trying to do.
51  */
52 #define	D16	.byte	0x66;
53 #define	A16	.byte	0x67;
54 
55 #define	_CONST(const)		(const)
56 #define	_BITNOT(const)		~_CONST(const)
57 #define	_MUL(a, b)		_CONST(a * b)
58 
59 /*
60  * C pointers are different sizes between i386 and amd64.
61  * These constants can be used to compute offsets into pointer arrays.
62  */
63 #if defined(__amd64)
64 #define	CLONGSHIFT	3
65 #define	CLONGSIZE	8
66 #define	CLONGMASK	7
67 #elif defined(__i386)
68 #define	CLONGSHIFT	2
69 #define	CLONGSIZE	4
70 #define	CLONGMASK	3
71 #endif
72 
73 /*
74  * Since we know we're either ILP32 or LP64 ..
75  */
76 #define	CPTRSHIFT	CLONGSHIFT
77 #define	CPTRSIZE	CLONGSIZE
78 #define	CPTRMASK	CLONGMASK
79 
80 #if CPTRSIZE != (1 << CPTRSHIFT) || CLONGSIZE != (1 << CLONGSHIFT)
81 #error	"inconsistent shift constants"
82 #endif
83 
84 #if CPTRMASK != (CPTRSIZE - 1) || CLONGMASK != (CLONGSIZE - 1)
85 #error	"inconsistent mask constants"
86 #endif
87 
88 #define	ASM_ENTRY_ALIGN	16
89 
90 /*
91  * SSE register alignment and save areas
92  */
93 
94 #define	XMM_SIZE	16
95 #define	XMM_ALIGN	16
96 
97 #if defined(__amd64)
98 
99 #define	SAVE_XMM_PROLOG(sreg, nreg)				\
100 	subq	$_CONST(_MUL(XMM_SIZE, nreg)), %rsp;		\
101 	movq	%rsp, sreg
102 
103 #define	RSTOR_XMM_EPILOG(sreg, nreg)				\
104 	addq	$_CONST(_MUL(XMM_SIZE, nreg)), %rsp
105 
106 #elif defined(__i386)
107 
108 #define	SAVE_XMM_PROLOG(sreg, nreg)				\
109 	subl	$_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp; \
110 	movl	%esp, sreg;					\
111 	addl	$XMM_ALIGN, sreg;				\
112 	andl	$_BITNOT(XMM_ALIGN-1), sreg
113 
114 #define	RSTOR_XMM_EPILOG(sreg, nreg)				\
115 	addl	$_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp;
116 
117 #endif	/* __i386 */
118 
119 /*
120  * profiling causes definitions of the MCOUNT and RTMCOUNT
121  * particular to the type
122  */
123 #ifdef GPROF
124 
125 #define	MCOUNT(x) \
126 	pushl	%ebp; \
127 	movl	%esp, %ebp; \
128 	call	_mcount; \
129 	popl	%ebp
130 
131 #endif /* GPROF */
132 
133 #ifdef PROF
134 
135 #define	MCOUNT(x) \
136 /* CSTYLED */ \
137 	.lcomm .L_##x##1, 4, 4; \
138 	pushl	%ebp; \
139 	movl	%esp, %ebp; \
140 /* CSTYLED */ \
141 	movl	$.L_##x##1, %edx; \
142 	call	_mcount; \
143 	popl	%ebp
144 
145 #endif /* PROF */
146 
147 /*
148  * if we are not profiling, MCOUNT should be defined to nothing
149  */
150 #if !defined(PROF) && !defined(GPROF)
151 #define	MCOUNT(x)
152 #endif /* !defined(PROF) && !defined(GPROF) */
153 
154 #define	RTMCOUNT(x)	MCOUNT(x)
155 
156 /*
157  * Macro to define weak symbol aliases. These are similar to the ANSI-C
158  *	#pragma weak _name = name
159  * except a compiler can determine type. The assembler must be told. Hence,
160  * the second parameter must be the type of the symbol (i.e.: function,...)
161  */
162 #define	ANSI_PRAGMA_WEAK(sym, stype)	\
163 /* CSTYLED */ \
164 	.weak	_##sym; \
165 /* CSTYLED */ \
166 	.type	_##sym, @stype; \
167 /* CSTYLED */ \
168 _##sym = sym
169 
170 /*
171  * Like ANSI_PRAGMA_WEAK(), but for unrelated names, as in:
172  *	#pragma weak sym1 = sym2
173  */
174 #define	ANSI_PRAGMA_WEAK2(sym1, sym2, stype)	\
175 	.weak	sym1; \
176 	.type sym1, @stype; \
177 sym1	= sym2
178 
179 /*
180  * ENTRY provides the standard procedure entry code and an easy way to
181  * insert the calls to mcount for profiling. ENTRY_NP is identical, but
182  * never calls mcount.
183  */
184 #define	ENTRY(x) \
185 	.text; \
186 	.align	ASM_ENTRY_ALIGN; \
187 	.globl	x; \
188 	.type	x, @function; \
189 x:	MCOUNT(x)
190 
191 #define	ENTRY_NP(x) \
192 	.text; \
193 	.align	ASM_ENTRY_ALIGN; \
194 	.globl	x; \
195 	.type	x, @function; \
196 x:
197 
198 #define	RTENTRY(x) \
199 	.text; \
200 	.align	ASM_ENTRY_ALIGN; \
201 	.globl	x; \
202 	.type	x, @function; \
203 x:	RTMCOUNT(x)
204 
205 /*
206  * ENTRY2 is identical to ENTRY but provides two labels for the entry point.
207  */
208 #define	ENTRY2(x, y) \
209 	.text; \
210 	.align	ASM_ENTRY_ALIGN; \
211 	.globl	x, y; \
212 	.type	x, @function; \
213 	.type	y, @function; \
214 /* CSTYLED */ \
215 x:	; \
216 y:	MCOUNT(x)
217 
218 #define	ENTRY_NP2(x, y) \
219 	.text; \
220 	.align	ASM_ENTRY_ALIGN; \
221 	.globl	x, y; \
222 	.type	x, @function; \
223 	.type	y, @function; \
224 /* CSTYLED */ \
225 x:	; \
226 y:
227 
228 
229 /*
230  * ALTENTRY provides for additional entry points.
231  */
232 #define	ALTENTRY(x) \
233 	.globl x; \
234 	.type	x, @function; \
235 x:
236 
237 /*
238  * DGDEF and DGDEF2 provide global data declarations.
239  *
240  * DGDEF provides a word aligned word of storage.
241  *
242  * DGDEF2 allocates "sz" bytes of storage with **NO** alignment.  This
243  * implies this macro is best used for byte arrays.
244  *
245  * DGDEF3 allocates "sz" bytes of storage with "algn" alignment.
246  */
247 #define	DGDEF2(name, sz) \
248 	.data; \
249 	.globl	name; \
250 	.type	name, @object; \
251 	.size	name, sz; \
252 name:
253 
254 #define	DGDEF3(name, sz, algn) \
255 	.data; \
256 	.align	algn; \
257 	.globl	name; \
258 	.type	name, @object; \
259 	.size	name, sz; \
260 name:
261 
262 #define	DGDEF(name)	DGDEF3(name, 4, 4)
263 
264 /*
265  * SET_SIZE trails a function and set the size for the ELF symbol table.
266  */
267 #define	SET_SIZE(x) \
268 	.size	x, [.-x]
269 
270 /*
271  * NWORD provides native word value.
272  */
273 #if defined(__amd64)
274 
275 /*CSTYLED*/
276 #define	NWORD	quad
277 
278 #elif defined(__i386)
279 
280 #define	NWORD	long
281 
282 #endif  /* __i386 */
283 
284 /*
285  * These macros should be used when making indirect calls in the kernel. They
286  * will perform a jump or call to the corresponding register in a way that knows
287  * about retpolines and handles whether such mitigations are enabled or not.
288  *
289  * INDIRECT_JMP_REG will jump to named register. INDIRECT_CALL_REG will instead
290  * do a call. These macros cannot be used to dereference a register. For
291  * example, if you need to do something that looks like the following:
292  *
293  *	call	*24(%rdi)
294  *	jmp	*(%r15)
295  *
296  * You must instead first do a movq into the corresponding location. You need to
297  * be careful to make sure that the register that its loaded into is safe to
298  * use. Often that register may be saved or used elsewhere so it may not be safe
299  * to clobber the value. Usually, loading into %rax would be safe. These would
300  * turn into something like:
301  *
302  *	movq 24(%rdi), %rdi; INDIRECT_CALL_REG(rdi)
303  *	movq (%r15), %r15; INDIRECT_JMP_REG(r15)
304  *
305  * If you are trying to call a global function, then use the following pattern
306  * (substituting the register in question):
307  *
308  *	leaq	my_favorite_function(%rip), %rax
309  *	INDIRECT_CALL_REG(rax)
310  *
311  * If you instead have a function pointer (say gethrtimef for example), then you
312  * need to do:
313  *
314  *	movq	my_favorite_function_pointer(%rip), %rax
315  *	INDIRECT_CALL_REG(rax)
316  */
317 
318 /* CSTYLED */
319 #define	INDIRECT_JMP_REG(reg)	jmp	__x86_indirect_thunk_##reg;
320 
321 /* CSTYLED */
322 #define	INDIRECT_CALL_REG(reg)	call	__x86_indirect_thunk_##reg;
323 
324 #endif /* _ASM */
325 
326 #ifdef	__cplusplus
327 }
328 #endif
329 
330 #endif	/* _SYS_ASM_LINKAGE_H */
331