106b6cf06S /*
206b6cf06S  * CDDL HEADER START
306b6cf06S  *
406b6cf06S  * The contents of this file are subject to the terms of the
506b6cf06S  * Common Development and Distribution License (the "License").
606b6cf06S  * You may not use this file except in compliance with the License.
706b6cf06S  *
806b6cf06S  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
906b6cf06S  * or http://www.opensolaris.org/os/licensing.
1006b6cf06S  * See the License for the specific language governing permissions
1106b6cf06S  * and limitations under the License.
1206b6cf06S  *
1306b6cf06S  * When distributing Covered Code, include this CDDL HEADER in each
1406b6cf06S  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1506b6cf06S  * If applicable, add the following below this CDDL HEADER, with the
1606b6cf06S  * fields enclosed by brackets "[]" replaced with your own identifying
1706b6cf06S  * information: Portions Copyright [yyyy] [name of copyright owner]
1806b6cf06S  *
1906b6cf06S  * CDDL HEADER END
2006b6cf06S  */
2106b6cf06S /*
2280e2ca85S  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23*abe1e6b3SAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
2406b6cf06S  */
2506b6cf06S 
2606b6cf06S #ifndef _COMMON_BRAND_ASM_H
2706b6cf06S #define	_COMMON_BRAND_ASM_H
2806b6cf06S 
2906b6cf06S #ifdef  __cplusplus
3006b6cf06S extern "C" {
3106b6cf06S #endif
3206b6cf06S 
3306b6cf06S #ifndef	lint
3406b6cf06S 
3506b6cf06S #include <sys/asm_linkage.h>
3606b6cf06S #include <sys/privregs.h>
3706b6cf06S #include <sys/segments.h>
3806b6cf06S #include "assym.h"
3906b6cf06S 
4006b6cf06S #endif	/* lint */
4106b6cf06S 
4206b6cf06S #ifdef _ASM	/* The remainder of this file is only for assembly files */
4306b6cf06S 
4406b6cf06S #if defined(__amd64)
4506b6cf06S /*
4606b6cf06S  * Common to all 64-bit callbacks:
4706b6cf06S  *
4806b6cf06S  * We're running on the kernel's %gs.
4906b6cf06S  *
5006b6cf06S  * We return directly to userland, bypassing the _update_sregs logic, so
5106b6cf06S  * the routine must NOT do anything that could cause a context switch.
5206b6cf06S  *
5306b6cf06S  * %rax - syscall number
5406b6cf06S  *
5506b6cf06S  * When called, all general registers, except for %r15, are as they were when
5606b6cf06S  * the user process made the system call.  %r15 is available to the callback as
5706b6cf06S  * a scratch register.  If the callback returns to the kernel path, %r15 does
5806b6cf06S  * not have to be restored to the user value.  If the callback returns to the
5906b6cf06S  * userlevel emulation code, the callback should restore %r15 if the emulation
6006b6cf06S  * depends on the original userlevel value.
6106b6cf06S  *
6206b6cf06S  * 64-BIT INTERPOSITION STACK
6306b6cf06S  * On entry to the callback the stack looks like this:
6406b6cf06S  *         --------------------------------------
6506b6cf06S  *      32 | callback pointer			|
6606b6cf06S  *      24 | saved stack pointer		|
6706b6cf06S  *    | 16 | lwp pointer			|
6806b6cf06S  *    v  8 | user return address		|
69*abe1e6b3SAndy Fiddaman  *       0 | BRAND_CALLBACK()'s return addr	|
7006b6cf06S  *         --------------------------------------
7106b6cf06S  */
7206b6cf06S 
7306b6cf06S #define	V_COUNT	5
7406b6cf06S #define	V_END		(CLONGSIZE * 5)
7506b6cf06S #define	V_SSP		(CLONGSIZE * 3)
7606b6cf06S #define	V_LWP		(CLONGSIZE * 2)
7706b6cf06S #define	V_URET_ADDR	(CLONGSIZE * 1)
7806b6cf06S #define	V_CB_ADDR	(CLONGSIZE * 0)
7906b6cf06S 
8006b6cf06S #define	SP_REG		%rsp
8106b6cf06S #define	SCR_REG		%r15
8206b6cf06S #define	SCR_REGB	%r15b
8306b6cf06S #define	SYSCALL_REG	%rax
8406b6cf06S 
8506b6cf06S /*
8606b6cf06S  * 64-BIT INT STACK
8706b6cf06S  * For int callbacks (e.g. int91) the saved stack pointer (V_SSP) points at
8806b6cf06S  * the state saved when we took the interrupt:
8906b6cf06S  *	   --------------------------------------
9006b6cf06S  *    | 32 | user's %ss				|
9106b6cf06S  *    | 24 | user's %esp			|
9206b6cf06S  *    | 16 | EFLAGS register			|
9306b6cf06S  *    v  8 | user's %cs				|
9406b6cf06S  *       0 | user's %eip (user return address)	|
9506b6cf06S  *	   --------------------------------------
9606b6cf06S  */
9706b6cf06S #define	V_U_EIP		(CLONGSIZE * 0)
9806b6cf06S 
9906b6cf06S #else	/* !__amd64 */
10006b6cf06S /*
10106b6cf06S  * 32-BIT INTERPOSITION STACK
10206b6cf06S  * When our syscall interposition callback entry point gets invoked the
10306b6cf06S  * stack looks like this:
10406b6cf06S  *         --------------------------------------
10506b6cf06S  *    | 16 | 'scratch space'			|
10606b6cf06S  *    | 12 | user's %ebx			|
10706b6cf06S  *    |  8 | user's %gs selector		|
10806b6cf06S  *    v  4 | lwp pointer			|
10906b6cf06S  *       0 | callback wrapper return addr	|
11006b6cf06S  *         --------------------------------------
11106b6cf06S  */
11206b6cf06S 
11306b6cf06S #define	V_COUNT	5
11406b6cf06S #define	V_END		(CLONGSIZE * 5)
11506b6cf06S #define	V_U_EBX		(CLONGSIZE * 3)
11606b6cf06S #define	V_LWP		(CLONGSIZE * 1)
11706b6cf06S #define	V_CB_ADDR	(CLONGSIZE * 0)
11806b6cf06S 
11906b6cf06S #define	SP_REG		%esp
12006b6cf06S #define	SCR_REG		%ebx
12106b6cf06S #define	SCR_REGB	%bl
12206b6cf06S #define	SYSCALL_REG	%eax
12306b6cf06S 
12406b6cf06S /*
12506b6cf06S  * 32-BIT INT STACK
12606b6cf06S  * For the lcall handler for 32-bit OS (i.e. xxx_brand_syscall_callback)
12706b6cf06S  * above the stack contents common to all callbacks is the int/lcall-specific
12806b6cf06S  * state:
12906b6cf06S  *	   --------------------------------------
13006b6cf06S  *    | 36 | user's %ss				|
13106b6cf06S  *    | 32 | user's %esp			|
13206b6cf06S  *    | 28 | EFLAGS register			|
13306b6cf06S  *    v 24 | user's %cs				|
13406b6cf06S  *      20 | user's %eip (user return address)	|
13506b6cf06S  *	   --------------------------------------
13606b6cf06S  */
13706b6cf06S #define	V_U_EIP		(V_END + (CLONGSIZE * 0))
13806b6cf06S 
13906b6cf06S #endif	/* !__amd64 */
14006b6cf06S 
14106b6cf06S /*
14206b6cf06S  * The following macros allow us to access to variables/parameters passed
14306b6cf06S  * in on the stack.  They take the following variables:
14406b6cf06S  *	sp	- a register with the current stack pointer value
14506b6cf06S  *	pcnt	- the number of words currently pushed onto the stack
14606b6cf06S  *	var	- the variable to lookup
14706b6cf06S  *	reg	- a register to read the variable into, or
14806b6cf06S  *		  a register to write to the variable
14906b6cf06S  */
15006b6cf06S #define	V_OFFSET(pcnt, var)						\
15106b6cf06S 	(var + (pcnt * CLONGSIZE))
15206b6cf06S 
15306b6cf06S #define	GET_V(sp, pcnt, var, reg)					\
15406b6cf06S 	mov	V_OFFSET(pcnt, var)(sp), reg
15506b6cf06S 
15606b6cf06S #define	SET_V(sp, pcnt, var, reg)					\
15706b6cf06S 	mov	reg, V_OFFSET(pcnt, var)(sp)
15806b6cf06S 
15906b6cf06S #define	GET_PROCP(sp, pcnt, reg)					\
16006b6cf06S 	GET_V(sp, pcnt, V_LWP, reg);		/* get lwp pointer */	\
16106b6cf06S 	mov	LWP_PROCP(reg), reg		/* get proc pointer */
16206b6cf06S 
16306b6cf06S #define	GET_P_BRAND_DATA(sp, pcnt, reg)					\
16406b6cf06S 	GET_PROCP(sp, pcnt, reg);					\
16506b6cf06S 	mov	P_BRAND_DATA(reg), reg		/* get p_brand_data */
16606b6cf06S 
16706b6cf06S /*
16806b6cf06S  * Each of the following macros returns to the standard syscall codepath if
16906b6cf06S  * it detects that this process is not able, or intended, to emulate this
17006b6cf06S  * system call.  They all assume that the routine provides a 'bail-out'
17106b6cf06S  * label of '9'.
17206b6cf06S  */
17306b6cf06S 
17406b6cf06S /*
17506b6cf06S  * See if this process has a user-space handler registered for it.  For the
17606b6cf06S  * brand, the per-process brand data holds the address of the handler.
17706b6cf06S  * As shown in the stack diagrams above, the callback code leaves the lwp
17806b6cf06S  * pointer at well-defined offsets, so check if proc_data_t->X_handler is
17906b6cf06S  * non-NULL.  For each brand, the handler parameter refers to the brand's
18006b6cf06S  * user-space handler variable name.
18106b6cf06S  */
18206b6cf06S #define	CHECK_FOR_HANDLER(scr, handler)					\
18306b6cf06S 	GET_P_BRAND_DATA(SP_REG, 0, scr);	/* get p_brand_data */	\
18406b6cf06S 	cmp	$0, scr;						\
18506b6cf06S 	je	9f;							\
186*abe1e6b3SAndy Fiddaman 	cmpq	$0, handler(scr);		/* check handler */	\
18706b6cf06S 	je	9f
18806b6cf06S 
18906b6cf06S /*
19006b6cf06S  * If the system call number is >= 1024, then it is coming from the
19106b6cf06S  * emulation support library.  As such we should handle it natively instead
19206b6cf06S  * of sending it back to the emulation library.
19306b6cf06S  */
19406b6cf06S #define	CHECK_FOR_NATIVE(reg)		\
19506b6cf06S 	cmp	$1024, reg;		\
19606b6cf06S 	jl	1f;			\
19706b6cf06S 	sub	$1024, reg;		\
19806b6cf06S 	jmp	9f;			\
19906b6cf06S 1:
20006b6cf06S 
20106b6cf06S /*
20206b6cf06S  * Check to see if we want to interpose on this system call.  If not, we
20306b6cf06S  * jump back into the normal syscall path and pretend nothing happened.
20406b6cf06S  * This macro is usable for brands which have the same number of syscalls
20506b6cf06S  * as the base OS.
20606b6cf06S  */
20706b6cf06S #define	CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low)		\
20806b6cf06S 	cmp	$NSYSCALL, call;	/* is 0 <= syscall <= MAX? */	\
20906b6cf06S 	ja	9f;			/* no, take normal ret path */	\
21006b6cf06S 	lea	emul_table, scr;					\
21106b6cf06S 	/*CSTYLED*/							\
21206b6cf06S 	mov	(scr), scr;						\
21306b6cf06S 	add	call, scr;						\
21406b6cf06S 	/*CSTYLED*/							\
21506b6cf06S 	movb	(scr), scr_low;						\
21606b6cf06S 	cmpb	$0, scr_low;						\
21706b6cf06S 	je	9f			/* no, take normal ret path */
21806b6cf06S 
21906b6cf06S #define	CALLBACK_PROLOGUE(emul_table, handler, call, scr, scr_low)	\
22006b6cf06S 	CHECK_FOR_HANDLER(scr, handler);				\
22106b6cf06S 	CHECK_FOR_NATIVE(call);						\
22206b6cf06S 	CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low)
22306b6cf06S 
22406b6cf06S /*
22506b6cf06S  * Rather than returning to the instruction after the syscall, we need to
22606b6cf06S  * transfer control into the brand library's handler table at
22706b6cf06S  * table_addr + (16 * syscall_num), thus encoding the system call number in the
22806b6cf06S  * instruction pointer.  The CALC_TABLE_ADDR macro performs that calculation.
22906b6cf06S  *
23006b6cf06S  * This macro assumes the syscall number is in SYSCALL_REG and it clobbers
23106b6cf06S  * that register.  It leaves the calculated handler table return address in
23206b6cf06S  * the scratch reg.
23306b6cf06S  */
23406b6cf06S #define	CALC_TABLE_ADDR(scr, handler)					\
23506b6cf06S 	GET_P_BRAND_DATA(SP_REG, 0, scr); /* get p_brand_data ptr */	\
23606b6cf06S 	mov	handler(scr), scr;	/* get p_brand_data->XX_handler */ \
23706b6cf06S 	shl	$4, SYSCALL_REG;	/* syscall_num * 16 */		\
23806b6cf06S 	add	SYSCALL_REG, scr	/* leave return addr in scr reg. */
23906b6cf06S 
24006b6cf06S #endif	/* _ASM */
24106b6cf06S 
24206b6cf06S #ifdef  __cplusplus
24306b6cf06S }
24406b6cf06S #endif
24506b6cf06S 
24606b6cf06S #endif	/* _COMMON_BRAND_ASM_H */
247