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  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
24  */
25 
26 #ifndef _COMMON_BRAND_ASM_H
27 #define	_COMMON_BRAND_ASM_H
28 
29 #ifdef  __cplusplus
30 extern "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 	cmpq	$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;			\
199 1:
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 #endif	/* _ASM */
241 
242 #ifdef  __cplusplus
243 }
244 #endif
245 
246 #endif	/* _COMMON_BRAND_ASM_H */
247