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