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
29extern "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;			\
1981:
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