xref: /illumos-gate/usr/src/uts/intel/brand/common/brand_asm.h (revision c65ebfc7045424bd04a6c7719a27b0ad3399ad54)
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  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #ifndef _COMMON_BRAND_ASM_H
26 #define	_COMMON_BRAND_ASM_H
27 
28 #ifdef  __cplusplus
29 extern "C" {
30 #endif
31 
32 #ifndef	lint
33 
34 #include <sys/asm_linkage.h>
35 #include <sys/privregs.h>
36 #include <sys/segments.h>
37 #include "assym.h"
38 
39 #endif	/* lint */
40 
41 #ifdef _ASM	/* The remainder of this file is only for assembly files */
42 
43 #if defined(__amd64)
44 /*
45  * Common to all 64-bit callbacks:
46  *
47  * We're running on the kernel's %gs.
48  *
49  * We return directly to userland, bypassing the _update_sregs logic, so
50  * the routine must NOT do anything that could cause a context switch.
51  *
52  * %rax - syscall number
53  *
54  * When called, all general registers, except for %r15, are as they were when
55  * the user process made the system call.  %r15 is available to the callback as
56  * a scratch register.  If the callback returns to the kernel path, %r15 does
57  * not have to be restored to the user value.  If the callback returns to the
58  * userlevel emulation code, the callback should restore %r15 if the emulation
59  * depends on the original userlevel value.
60  *
61  * 64-BIT INTERPOSITION STACK
62  * On entry to the callback the stack looks like this:
63  *         --------------------------------------
64  *      32 | callback pointer			|
65  *      24 | saved stack pointer		|
66  *    | 16 | lwp pointer			|
67  *    v  8 | user return address		|
68  *       0 | BRAND_CALLBACK()'s return addr 	|
69  *         --------------------------------------
70  */
71 
72 #define	V_COUNT	5
73 #define	V_END		(CLONGSIZE * 5)
74 #define	V_SSP		(CLONGSIZE * 3)
75 #define	V_LWP		(CLONGSIZE * 2)
76 #define	V_URET_ADDR	(CLONGSIZE * 1)
77 #define	V_CB_ADDR	(CLONGSIZE * 0)
78 
79 #define	SP_REG		%rsp
80 #define	SCR_REG		%r15
81 #define	SCR_REGB	%r15b
82 #define	SYSCALL_REG	%rax
83 
84 /*
85  * 64-BIT INT STACK
86  * For int callbacks (e.g. int91) the saved stack pointer (V_SSP) points at
87  * the state saved when we took the interrupt:
88  *	   --------------------------------------
89  *    | 32 | user's %ss				|
90  *    | 24 | user's %esp			|
91  *    | 16 | EFLAGS register			|
92  *    v  8 | user's %cs				|
93  *       0 | user's %eip (user return address)	|
94  *	   --------------------------------------
95  */
96 #define	V_U_EIP		(CLONGSIZE * 0)
97 
98 #else	/* !__amd64 */
99 /*
100  * 32-BIT INTERPOSITION STACK
101  * When our syscall interposition callback entry point gets invoked the
102  * stack looks like this:
103  *         --------------------------------------
104  *    | 16 | 'scratch space'			|
105  *    | 12 | user's %ebx			|
106  *    |  8 | user's %gs selector		|
107  *    v  4 | lwp pointer			|
108  *       0 | callback wrapper return addr	|
109  *         --------------------------------------
110  */
111 
112 #define	V_COUNT	5
113 #define	V_END		(CLONGSIZE * 5)
114 #define	V_U_EBX		(CLONGSIZE * 3)
115 #define	V_LWP		(CLONGSIZE * 1)
116 #define	V_CB_ADDR	(CLONGSIZE * 0)
117 
118 #define	SP_REG		%esp
119 #define	SCR_REG		%ebx
120 #define	SCR_REGB	%bl
121 #define	SYSCALL_REG	%eax
122 
123 /*
124  * 32-BIT INT STACK
125  * For the lcall handler for 32-bit OS (i.e. xxx_brand_syscall_callback)
126  * above the stack contents common to all callbacks is the int/lcall-specific
127  * state:
128  *	   --------------------------------------
129  *    | 36 | user's %ss				|
130  *    | 32 | user's %esp			|
131  *    | 28 | EFLAGS register			|
132  *    v 24 | user's %cs				|
133  *      20 | user's %eip (user return address)	|
134  *	   --------------------------------------
135  */
136 #define	V_U_EIP		(V_END + (CLONGSIZE * 0))
137 
138 #endif	/* !__amd64 */
139 
140 /*
141  * The following macros allow us to access to variables/parameters passed
142  * in on the stack.  They take the following variables:
143  *	sp	- a register with the current stack pointer value
144  *	pcnt	- the number of words currently pushed onto the stack
145  *	var	- the variable to lookup
146  *	reg	- a register to read the variable into, or
147  *		  a register to write to the variable
148  */
149 #define	V_OFFSET(pcnt, var)						\
150 	(var + (pcnt * CLONGSIZE))
151 
152 #define	GET_V(sp, pcnt, var, reg)					\
153 	mov	V_OFFSET(pcnt, var)(sp), reg
154 
155 #define	SET_V(sp, pcnt, var, reg)					\
156 	mov	reg, V_OFFSET(pcnt, var)(sp)
157 
158 #define	GET_PROCP(sp, pcnt, reg)					\
159 	GET_V(sp, pcnt, V_LWP, reg);		/* get lwp pointer */	\
160 	mov	LWP_PROCP(reg), reg		/* get proc pointer */
161 
162 #define	GET_P_BRAND_DATA(sp, pcnt, reg)					\
163 	GET_PROCP(sp, pcnt, reg);					\
164 	mov	P_BRAND_DATA(reg), reg		/* get p_brand_data */
165 
166 /*
167  * Each of the following macros returns to the standard syscall codepath if
168  * it detects that this process is not able, or intended, to emulate this
169  * system call.  They all assume that the routine provides a 'bail-out'
170  * label of '9'.
171  */
172 
173 /*
174  * See if this process has a user-space handler registered for it.  For the
175  * brand, the per-process brand data holds the address of the handler.
176  * As shown in the stack diagrams above, the callback code leaves the lwp
177  * pointer at well-defined offsets, so check if proc_data_t->X_handler is
178  * non-NULL.  For each brand, the handler parameter refers to the brand's
179  * user-space handler variable name.
180  */
181 #define	CHECK_FOR_HANDLER(scr, handler)					\
182 	GET_P_BRAND_DATA(SP_REG, 0, scr);	/* get p_brand_data */	\
183 	cmp	$0, scr;						\
184 	je	9f;							\
185 	cmp	$0, handler(scr);		/* check handler */	\
186 	je	9f
187 
188 /*
189  * If the system call number is >= 1024, then it is coming from the
190  * emulation support library.  As such we should handle it natively instead
191  * of sending it back to the emulation library.
192  */
193 #define	CHECK_FOR_NATIVE(reg)		\
194 	cmp	$1024, reg;		\
195 	jl	1f;			\
196 	sub	$1024, reg;		\
197 	jmp	9f;			\
198 1:
199 
200 /*
201  * Check to see if we want to interpose on this system call.  If not, we
202  * jump back into the normal syscall path and pretend nothing happened.
203  * This macro is usable for brands which have the same number of syscalls
204  * as the base OS.
205  */
206 #define	CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low)		\
207 	cmp	$NSYSCALL, call;	/* is 0 <= syscall <= MAX? */	\
208 	ja	9f;			/* no, take normal ret path */	\
209 	lea	emul_table, scr;					\
210 	/*CSTYLED*/							\
211 	mov	(scr), scr;						\
212 	add	call, scr;						\
213 	/*CSTYLED*/							\
214 	movb	(scr), scr_low;						\
215 	cmpb	$0, scr_low;						\
216 	je	9f			/* no, take normal ret path */
217 
218 #define	CALLBACK_PROLOGUE(emul_table, handler, call, scr, scr_low)	\
219 	CHECK_FOR_HANDLER(scr, handler);				\
220 	CHECK_FOR_NATIVE(call);						\
221 	CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low)
222 
223 /*
224  * Rather than returning to the instruction after the syscall, we need to
225  * transfer control into the brand library's handler table at
226  * table_addr + (16 * syscall_num), thus encoding the system call number in the
227  * instruction pointer.  The CALC_TABLE_ADDR macro performs that calculation.
228  *
229  * This macro assumes the syscall number is in SYSCALL_REG and it clobbers
230  * that register.  It leaves the calculated handler table return address in
231  * the scratch reg.
232  */
233 #define	CALC_TABLE_ADDR(scr, handler)					\
234 	GET_P_BRAND_DATA(SP_REG, 0, scr); /* get p_brand_data ptr */	\
235 	mov	handler(scr), scr;	/* get p_brand_data->XX_handler */ \
236 	shl	$4, SYSCALL_REG;	/* syscall_num * 16 */		\
237 	add	SYSCALL_REG, scr	/* leave return addr in scr reg. */
238 
239 #endif	/* _ASM */
240 
241 #ifdef  __cplusplus
242 }
243 #endif
244 
245 #endif	/* _COMMON_BRAND_ASM_H */
246