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
38extern "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; \
198sym1	= 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; \
210x:	MCOUNT(x)
211
212#define	ENTRY_NP(x) \
213	.text; \
214	.align	ASM_ENTRY_ALIGN; \
215	.globl	x; \
216	.type	x, @function; \
217x:
218
219#define	RTENTRY(x) \
220	.text; \
221	.align	ASM_ENTRY_ALIGN; \
222	.globl	x; \
223	.type	x, @function; \
224x:	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 */ \
236x:	; \
237y:	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 */ \
246x:	; \
247y:
248
249
250/*
251 * ALTENTRY provides for additional entry points.
252 */
253#define	ALTENTRY(x) \
254	.globl x; \
255	.type	x, @function; \
256x:
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; \
273name:
274
275#define	DGDEF3(name, sz, algn) \
276	.data; \
277	.align	algn; \
278	.globl	name; \
279	.type	name, @object; \
280	.size	name, sz; \
281name:
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 */
352