1628e3cbeSEdward Pilatowicz/*
2628e3cbeSEdward Pilatowicz * CDDL HEADER START
3628e3cbeSEdward Pilatowicz *
4628e3cbeSEdward Pilatowicz * The contents of this file are subject to the terms of the
5628e3cbeSEdward Pilatowicz * Common Development and Distribution License (the "License").
6628e3cbeSEdward Pilatowicz * You may not use this file except in compliance with the License.
7628e3cbeSEdward Pilatowicz *
8628e3cbeSEdward Pilatowicz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9628e3cbeSEdward Pilatowicz * or http://www.opensolaris.org/os/licensing.
10628e3cbeSEdward Pilatowicz * See the License for the specific language governing permissions
11628e3cbeSEdward Pilatowicz * and limitations under the License.
12628e3cbeSEdward Pilatowicz *
13628e3cbeSEdward Pilatowicz * When distributing Covered Code, include this CDDL HEADER in each
14628e3cbeSEdward Pilatowicz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15628e3cbeSEdward Pilatowicz * If applicable, add the following below this CDDL HEADER, with the
16628e3cbeSEdward Pilatowicz * fields enclosed by brackets "[]" replaced with your own identifying
17628e3cbeSEdward Pilatowicz * information: Portions Copyright [yyyy] [name of copyright owner]
18628e3cbeSEdward Pilatowicz *
19628e3cbeSEdward Pilatowicz * CDDL HEADER END
20628e3cbeSEdward Pilatowicz */
211b30f017Sgvasick
22628e3cbeSEdward Pilatowicz/*
2380e2ca85S * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24628e3cbeSEdward Pilatowicz */
25628e3cbeSEdward Pilatowicz
2680e2ca85S#include <brand_misc.h>
27628e3cbeSEdward Pilatowicz
28b72c368aS/*
29b72c368aS * Each JMP must occupy 16 bytes
30b72c368aS */
31b72c368aS#define	JMP	\
3280e2ca85S	pushl	$_CONST(. - brand_handler_table); \
3380e2ca85S	jmp	brand_handler;	\
34*55fea89dSDan Cross	.align	16;
35b72c368aS
36b72c368aS#define	JMP4	JMP; JMP; JMP; JMP
37b72c368aS#define JMP16	JMP4; JMP4; JMP4; JMP4
38b72c368aS#define JMP64	JMP16; JMP16; JMP16; JMP16
39b72c368aS#define JMP256	JMP64; JMP64; JMP64; JMP64
40b72c368aS
41628e3cbeSEdward Pilatowicz#if defined(lint)
42628e3cbeSEdward Pilatowicz
43b72c368aSvoid
4480e2ca85Sbrand_handler_table(void)
45b72c368aS{}
46b72c368aS
47628e3cbeSEdward Pilatowiczvoid
4880e2ca85Sbrand_handler(void)
49628e3cbeSEdward Pilatowicz{
50628e3cbeSEdward Pilatowicz}
51628e3cbeSEdward Pilatowicz
52628e3cbeSEdward Pilatowicz#else	/* lint */
53628e3cbeSEdward Pilatowicz
54b72c368aS	/*
55b72c368aS	 * On entry to this table, %eax will hold the return address. The
56b72c368aS	 * location where we enter the table is a function of the system
57b72c368aS	 * call number. The table needs the same alignment as the individual
58b72c368aS	 * entries.
59b72c368aS	 */
60b72c368aS	.align	16
6180e2ca85S	ENTRY_NP(brand_handler_table)
62b72c368aS	JMP256
6380e2ca85S	SET_SIZE(brand_handler_table)
64b72c368aS
65628e3cbeSEdward Pilatowicz#define	PIC_SETUP(r)					\
66628e3cbeSEdward Pilatowicz	call	9f;					\
67628e3cbeSEdward Pilatowicz9:							\
68628e3cbeSEdward Pilatowicz	popl	r;					\
69628e3cbeSEdward Pilatowicz	addl	$_GLOBAL_OFFSET_TABLE_ + [. - 9b], r
70628e3cbeSEdward Pilatowicz
71628e3cbeSEdward Pilatowicz	/*
72b72c368aS	 * %eax - userland return address
73628e3cbeSEdward Pilatowicz	 * stack contains:
74b72c368aS	 *    |    --------------------------------------
75b72c368aS	 *    v  4 | syscall arguments			|
76b72c368aS	 *  %esp+0 | syscall number			|
77628e3cbeSEdward Pilatowicz	 *         --------------------------------------
78628e3cbeSEdward Pilatowicz	 */
7980e2ca85S	ENTRY_NP(brand_handler)
80628e3cbeSEdward Pilatowicz	pushl	%ebp				/* allocate a stack frame */
81628e3cbeSEdward Pilatowicz	movl	%esp, %ebp
82628e3cbeSEdward Pilatowicz
83628e3cbeSEdward Pilatowicz	/* Save registers at the time of the syscall. */
84628e3cbeSEdward Pilatowicz	movl	$0, EH_LOCALS_GREG(TRAPNO)(%ebp)
85628e3cbeSEdward Pilatowicz	movl	$0, EH_LOCALS_GREG(ERR)(%ebp)
86628e3cbeSEdward Pilatowicz	movl	%ebx, EH_LOCALS_GREG(EBX)(%ebp)
87628e3cbeSEdward Pilatowicz	movl	%ecx, EH_LOCALS_GREG(ECX)(%ebp)
88628e3cbeSEdward Pilatowicz	movl	%edx, EH_LOCALS_GREG(EDX)(%ebp)
89628e3cbeSEdward Pilatowicz	movl	%edi, EH_LOCALS_GREG(EDI)(%ebp)
90628e3cbeSEdward Pilatowicz	movl	%esi, EH_LOCALS_GREG(ESI)(%ebp)
911b30f017Sgvasick	mov	%cs, EH_LOCALS_GREG(CS)(%ebp)
921b30f017Sgvasick	mov	%ds, EH_LOCALS_GREG(DS)(%ebp)
931b30f017Sgvasick	mov	%es, EH_LOCALS_GREG(ES)(%ebp)
941b30f017Sgvasick	mov	%fs, EH_LOCALS_GREG(FS)(%ebp)
951b30f017Sgvasick	mov	%gs, EH_LOCALS_GREG(GS)(%ebp)
96628e3cbeSEdward Pilatowicz	pushfl					/* save syscall flags */
97628e3cbeSEdward Pilatowicz	popl	%ecx
98628e3cbeSEdward Pilatowicz	movl	%ecx, EH_LOCALS_GREG(EFL)(%ebp)
99628e3cbeSEdward Pilatowicz	movl	EH_ARGS_OFFSET(0)(%ebp), %ecx	/* save syscall ebp */
100628e3cbeSEdward Pilatowicz	movl	%ecx, EH_LOCALS_GREG(EBP)(%ebp)
101628e3cbeSEdward Pilatowicz	movl	%ebp, %ecx			/* save syscall esp */
102628e3cbeSEdward Pilatowicz	addl	$CPTRSIZE, %ecx
103628e3cbeSEdward Pilatowicz	movl	%ecx, EH_LOCALS_GREG(ESP)(%ebp)
104b72c368aS
105b72c368aS	/*
10680e2ca85S	 * The kernel drops us into the middle of the brand_handle_table
107b72c368aS	 * above that then pushes that table offset onto the stack, and calls
10880e2ca85S	 * into brand_handler. That offset indicates the system call number
10980e2ca85S	 * while %eax holds the return address for the system call. We replace
11080e2ca85S	 * the value on the stack with the return address, and use the value to
111b72c368aS	 * compute the system call number by dividing by the table entry size.
112b72c368aS	 */
113b72c368aS	xchgl	CPTRSIZE(%ebp), %eax	/* swap JMP table offset and ret addr */
114b72c368aS	shrl	$4, %eax		/* table_offset/size = syscall num */
115b72c368aS	movl	%eax, EH_LOCALS_GREG(EAX)(%ebp)	/* save syscall num */
116628e3cbeSEdward Pilatowicz
117628e3cbeSEdward Pilatowicz	/*
118628e3cbeSEdward Pilatowicz	 * Finish setting up our stack frame.  We would normally do this
119628e3cbeSEdward Pilatowicz	 * upon entry to this function, but in this case we delayed it
120628e3cbeSEdward Pilatowicz	 * because a "sub" operation can modify flags and we wanted to
121628e3cbeSEdward Pilatowicz	 * save the flags into the gregset_t above before they get modified.
122628e3cbeSEdward Pilatowicz	 *
12380e2ca85S	 * Our stack frame format is documented in brand_misc.h.
124628e3cbeSEdward Pilatowicz	 */
125628e3cbeSEdward Pilatowicz	subl	$EH_LOCALS_SIZE, %esp
126628e3cbeSEdward Pilatowicz
127628e3cbeSEdward Pilatowicz	/* Look up the system call's entry in the sysent table */
128628e3cbeSEdward Pilatowicz	PIC_SETUP(%ecx)
12980e2ca85S	movl	brand_sysent_table@GOT(%ecx), %edx   /* %edx = sysent_table */
130628e3cbeSEdward Pilatowicz	shll	$3, %eax	/* each entry is 8 bytes */
131628e3cbeSEdward Pilatowicz	add	%eax, %edx	/* %edx = sysent entry address */
132628e3cbeSEdward Pilatowicz
133628e3cbeSEdward Pilatowicz	/*
134628e3cbeSEdward Pilatowicz	 * Get the return value flag and the number of arguments from the
135628e3cbeSEdward Pilatowicz	 * sysent table.
136628e3cbeSEdward Pilatowicz	 */
137628e3cbeSEdward Pilatowicz	movl	CPTRSIZE(%edx), %ecx		/* number of args + rv flag */
138628e3cbeSEdward Pilatowicz	andl	$RV_MASK, %ecx			/* strip out number of args */
139628e3cbeSEdward Pilatowicz	movl	%ecx, EH_LOCALS_RVFLAG(%ebp)	/* save rv flag */
140628e3cbeSEdward Pilatowicz	movl	CPTRSIZE(%edx), %ecx		/* number of args + rv flag */
141628e3cbeSEdward Pilatowicz	andl	$NARGS_MASK, %ecx		/* strip out rv flag */
142628e3cbeSEdward Pilatowicz
143628e3cbeSEdward Pilatowicz	/*
144628e3cbeSEdward Pilatowicz	 * Setup arguments for our emulation call.  Our input arguments,
145628e3cbeSEdward Pilatowicz	 * 0 to N, will become emulation call arguments 1 to N+1.
146628e3cbeSEdward Pilatowicz	 * %ecx == number of arguments.
147628e3cbeSEdward Pilatowicz	 */
148628e3cbeSEdward Pilatowicz	movl	%ebp, %esi			/* args are at 12(%ebp) */
149*55fea89dSDan Cross	addl	$EH_ARGS_OFFSET(3), %esi
150628e3cbeSEdward Pilatowicz	movl	%esp, %edi			/* copy args to 4(%esp) */
151*55fea89dSDan Cross	addl	$EH_ARGS_OFFSET(1), %edi
152628e3cbeSEdward Pilatowicz	rep;	smovl				/* copy: (%esi) -> (%edi) */
153628e3cbeSEdward Pilatowicz						/* copy: %ecx 32-bit words */
154628e3cbeSEdward Pilatowicz	movl	EH_LOCALS_GREG(ESI)(%ebp), %esi	/* restore %esi */
155628e3cbeSEdward Pilatowicz	movl	EH_LOCALS_GREG(EDI)(%ebp), %edi	/* restore %edi */
156628e3cbeSEdward Pilatowicz
157628e3cbeSEdward Pilatowicz	/*
158628e3cbeSEdward Pilatowicz	 * The first parameter to the emulation callback function is a
159628e3cbeSEdward Pilatowicz	 * pointer to a sysret_t structure.
160628e3cbeSEdward Pilatowicz	 */
161628e3cbeSEdward Pilatowicz	movl	%ebp, %ecx
162628e3cbeSEdward Pilatowicz	addl	$EH_LOCALS_SYSRET, %ecx
163628e3cbeSEdward Pilatowicz	movl	%ecx, EH_ARGS_OFFSET(0)(%esp)	/* arg0 == sysret_t ptr */
164628e3cbeSEdward Pilatowicz
165628e3cbeSEdward Pilatowicz	/* invoke the emulation routine */
16680e2ca85S	ALTENTRY(brand_handler_savepc)
167628e3cbeSEdward Pilatowicz	call	*(%edx)				/* call emulation routine */
168628e3cbeSEdward Pilatowicz
169628e3cbeSEdward Pilatowicz	/* restore scratch registers */
170628e3cbeSEdward Pilatowicz	movl	EH_LOCALS_GREG(ECX)(%ebp), %ecx	/* restore %ecx */
171628e3cbeSEdward Pilatowicz	movl	EH_LOCALS_GREG(EDX)(%ebp), %edx	/* restore %edx */
172628e3cbeSEdward Pilatowicz
173628e3cbeSEdward Pilatowicz	/* Check for syscall emulation success or failure */
174628e3cbeSEdward Pilatowicz	cmpl	$0, %eax			/* check for an error */
175628e3cbeSEdward Pilatowicz	je	success
176628e3cbeSEdward Pilatowicz	stc					/* failure, set carry flag */
177628e3cbeSEdward Pilatowicz	jmp	return				/* return, %rax == errno */
178628e3cbeSEdward Pilatowicz
179628e3cbeSEdward Pilatowiczsuccess:
180628e3cbeSEdward Pilatowicz	/* There is always at least one return value. */
181628e3cbeSEdward Pilatowicz	movl	EH_LOCALS_SYSRET1(%ebp), %eax	/* %eax == sys_rval1 */
182628e3cbeSEdward Pilatowicz	cmpl	$RV_DEFAULT, EH_LOCALS_RVFLAG(%ebp) /* check rv flag */
183628e3cbeSEdward Pilatowicz	je	clear_carry
184628e3cbeSEdward Pilatowicz	mov	EH_LOCALS_SYSRET2(%ebp), %edx	/* %edx == sys_rval2 */
185628e3cbeSEdward Pilatowiczclear_carry:
186628e3cbeSEdward Pilatowicz	clc					/* success, clear carry flag */
187628e3cbeSEdward Pilatowicz
188628e3cbeSEdward Pilatowiczreturn:
189628e3cbeSEdward Pilatowicz	movl	%ebp, %esp			/* restore stack */
190628e3cbeSEdward Pilatowicz	popl	%ebp
191628e3cbeSEdward Pilatowicz	ret					/* ret to instr after syscall */
19280e2ca85S	SET_SIZE(brand_handler)
193628e3cbeSEdward Pilatowicz
194628e3cbeSEdward Pilatowicz
195628e3cbeSEdward Pilatowicz#endif	/* lint */
196