1e71ca95Gerald Jelinek/*
2e71ca95Gerald Jelinek * CDDL HEADER START
3e71ca95Gerald Jelinek *
4e71ca95Gerald Jelinek * The contents of this file are subject to the terms of the
5e71ca95Gerald Jelinek * Common Development and Distribution License (the "License").
6e71ca95Gerald Jelinek * You may not use this file except in compliance with the License.
7e71ca95Gerald Jelinek *
8e71ca95Gerald Jelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e71ca95Gerald Jelinek * or http://www.opensolaris.org/os/licensing.
10e71ca95Gerald Jelinek * See the License for the specific language governing permissions
11e71ca95Gerald Jelinek * and limitations under the License.
12e71ca95Gerald Jelinek *
13e71ca95Gerald Jelinek * When distributing Covered Code, include this CDDL HEADER in each
14e71ca95Gerald Jelinek * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e71ca95Gerald Jelinek * If applicable, add the following below this CDDL HEADER, with the
16e71ca95Gerald Jelinek * fields enclosed by brackets "[]" replaced with your own identifying
17e71ca95Gerald Jelinek * information: Portions Copyright [yyyy] [name of copyright owner]
18e71ca95Gerald Jelinek *
19e71ca95Gerald Jelinek * CDDL HEADER END
20e71ca95Gerald Jelinek */
21e71ca95Gerald Jelinek/*
2280e2ca8<gerald.jelinek@sun.com> * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23e71ca95Gerald Jelinek */
24e71ca95Gerald Jelinek
2580e2ca8<gerald.jelinek@sun.com>#include <brand_misc.h>
26e71ca95Gerald Jelinek
27e71ca95Gerald Jelinek#if defined(lint)
28e71ca95Gerald Jelinek
29e71ca95Gerald Jelinekvoid
31e71ca95Gerald Jelinek{
32e71ca95Gerald Jelinek}
33e71ca95Gerald Jelinek
34e71ca95Gerald Jelinek#else	/* !lint */
35e71ca95Gerald Jelinek
36e71ca95Gerald Jelinek#define	PIC_SETUP(r)						\
37e71ca95Gerald Jelinek	mov	%o7, %g1;					\
38e71ca95Gerald Jelinek9:	call	8f;						\
39e71ca95Gerald Jelinek	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r;	\
40e71ca95Gerald Jelinek8:	or	r, %lo(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r;	\
41e71ca95Gerald Jelinek	add	r, %o7, r;					\
42e71ca95Gerald Jelinek	mov	%g1, %o7
43e71ca95Gerald Jelinek
44e71ca95Gerald Jelinek/*
45e71ca95Gerald Jelinek * Translate a global symbol into an address.  The resulting address
46e71ca95Gerald Jelinek * is returned in the first register parameter.  The second register
47e71ca95Gerald Jelinek * is just for scratch space.
48e71ca95Gerald Jelinek */
49e71ca95Gerald Jelinek#if defined(__sparcv9)
50e71ca95Gerald Jelinek#define	GET_SYM_ADDR(r1, r2, name)		\
51e71ca95Gerald Jelinek	PIC_SETUP(r1)				;\
52e71ca95Gerald Jelinek	sethi	%hi(name), r2			;\
53e71ca95Gerald Jelinek	or	r2, %lo(name), r2		;\
54e71ca95Gerald Jelinek	ldn	[r2 + r1], r1
55e71ca95Gerald Jelinek#else /* !__sparcv9 */
56e71ca95Gerald Jelinek#define	GET_SYM_ADDR(r1, r2, name)		\
57e71ca95Gerald Jelinek	PIC_SETUP(r1);			\
58e71ca95Gerald Jelinek	ld	[r1 + name], r1
59e71ca95Gerald Jelinek#endif /* !__sparcv9 */
60e71ca95Gerald Jelinek
61e71ca95Gerald Jelinek	.section	".text"
62e71ca95Gerald Jelinek
63e71ca95Gerald Jelinek	/*
64e71ca95Gerald Jelinek	 * When we get here, %g1 should contain the system call and
65e71ca95Gerald Jelinek	 * %g5 should contain the address immediately after the trap
66e71ca95Gerald Jelinek	 * instruction.
67e71ca95Gerald Jelinek	 */
6880e2ca8<gerald.jelinek@sun.com>	ENTRY_NP(brand_handler)
69e71ca95Gerald Jelinek
70e71ca95Gerald Jelinek	/*
71e71ca95Gerald Jelinek	 * 64-bit sparc may need to save 3 parameters on the stack.
72e71ca95Gerald Jelinek	 * 32-bit sparc may need to save 4 parameters on the stack.
73e71ca95Gerald Jelinek	 *
7480e2ca8<gerald.jelinek@sun.com>	 * Our stack frame format is documented in brand_misc.h.
75e71ca95Gerald Jelinek	 */
76e71ca95Gerald Jelinek	save	%sp, -SA(MINFRAME + EH_LOCALS_SIZE), %sp
77e71ca95Gerald Jelinek
78e71ca95Gerald Jelinek	/*
79e71ca95Gerald Jelinek	 * Save the current caller state into gregs and gwins.
80e71ca95Gerald Jelinek	 * Note that this state isn't exact, %g1 and %g5 have been
81e71ca95Gerald Jelinek	 * already been lost.  Also, we've pushed a stack frame so
82e71ca95Gerald Jelinek	 * the callers output registers are our input registers.
83e71ca95Gerald Jelinek	 */
84e71ca95Gerald Jelinek	stn	%g0, [%sp + EH_LOCALS_GREG(REG_G1)]	/* %g1 is lost */
85e71ca95Gerald Jelinek	stn	%g2, [%sp + EH_LOCALS_GREG(REG_G2)]
86e71ca95Gerald Jelinek	stn	%g3, [%sp + EH_LOCALS_GREG(REG_G3)]
87e71ca95Gerald Jelinek	stn	%g4, [%sp + EH_LOCALS_GREG(REG_G4)]
88e71ca95Gerald Jelinek	stn	%g0, [%sp + EH_LOCALS_GREG(REG_G5)]	/* %g5 is lost */
89e71ca95Gerald Jelinek	stn	%g6, [%sp + EH_LOCALS_GREG(REG_G6)]
90e71ca95Gerald Jelinek	stn	%g7, [%sp + EH_LOCALS_GREG(REG_G7)]
91e71ca95Gerald Jelinek	stn	%i0, [%sp + EH_LOCALS_GREG(REG_O0)]
92e71ca95Gerald Jelinek	stn	%i1, [%sp + EH_LOCALS_GREG(REG_O1)]
93e71ca95Gerald Jelinek	stn	%i2, [%sp + EH_LOCALS_GREG(REG_O2)]
94e71ca95Gerald Jelinek	stn	%i3, [%sp + EH_LOCALS_GREG(REG_O3)]
95e71ca95Gerald Jelinek	stn	%i4, [%sp + EH_LOCALS_GREG(REG_O4)]
96e71ca95Gerald Jelinek	stn	%i5, [%sp + EH_LOCALS_GREG(REG_O5)]
97e71ca95Gerald Jelinek	stn	%i6, [%sp + EH_LOCALS_GREG(REG_O6)]
98e71ca95Gerald Jelinek	stn	%i7, [%sp + EH_LOCALS_GREG(REG_O7)]
99e71ca95Gerald Jelinek	sub	%g5, 4, %o0
100e71ca95Gerald Jelinek	stn	%o0, [%sp + EH_LOCALS_GREG(REG_PC)]
101e71ca95Gerald Jelinek	stn	%g5, [%sp + EH_LOCALS_GREG(REG_nPC)]
102e71ca95Gerald Jelinek	rd	%y, %o0
103e71ca95Gerald Jelinek	stn	%o0, [%sp + EH_LOCALS_GREG(REG_Y)]
104e71ca95Gerald Jelinek#if defined(__sparcv9)
105e71ca95Gerald Jelinek	stn	%g0, [%sp + EH_LOCALS_GREG(REG_ASI)]
106e71ca95Gerald Jelinek	rd	%fprs, %o0
107e71ca95Gerald Jelinek	stn	%o0, [%sp + EH_LOCALS_GREG(REG_FPRS)]
108e71ca95Gerald Jelinek#endif /* __sparcv9 */
109e71ca95Gerald Jelinek
110e71ca95Gerald Jelinek	/*
111e71ca95Gerald Jelinek	 * Look up the system call's entry in the sysent table
112e71ca95Gerald Jelinek	 * and obtain the address of the proper emulation routine (%l2).
113e71ca95Gerald Jelinek	 */
114e71ca95Gerald Jelinek	mov	%g1, %l5			/* save syscall number */
11580e2ca8<gerald.jelinek@sun.com>	GET_SYM_ADDR(%l1, %l2, brand_sysent_table)
116e71ca95Gerald Jelinek	mov	%l5, %g1			/* restore syscall number */
117e71ca95Gerald Jelinek	sll	%g1, (1 + CLONGSHIFT), %l2	/* Each entry has 2 longs */
118e71ca95Gerald Jelinek	add	%l2, %l1, %l2			/* index to proper entry */
119e71ca95Gerald Jelinek	ldn	[%l2], %l2			/* emulation func address */
120e71ca95Gerald Jelinek
121e71ca95Gerald Jelinek	/*
122e71ca95Gerald Jelinek	 * Look up the system call's entry in the sysent table,
123e71ca95Gerald Jelinek	 * taking into account the posibility of indirect system calls, and
124e71ca95Gerald Jelinek	 * obtain the number of arguments (%l4) and return value flag (%l3).
125e71ca95Gerald Jelinek	 */
126e71ca95Gerald Jelinek#if defined(__sparcv9)
127e71ca95Gerald Jelinek	mov	%g1, %l3			/* %g1 == syscall number */
128e71ca95Gerald Jelinek#else /* !__sparcv9 */
129e71ca95Gerald Jelinek	/*
130e71ca95Gerald Jelinek	 * Check for indirect system calls, in which case the real syscall
131e71ca95Gerald Jelinek	 * number is the first parameter to the indirect system call.
132e71ca95Gerald Jelinek	 */
133e71ca95Gerald Jelinek	cmp	%g1, %g0			/* saved syscall number */
134e71ca95Gerald Jelinek	bne,a,pt %icc, no_indir			/* indirect syscall? */
135e71ca95Gerald Jelinek	mov	%g1, %l3			/* %g1 == syscall number */
136e71ca95Gerald Jelinek	mov	%i0, %l3			/* %i0 == syscall number */
137e71ca95Gerald Jelinekno_indir:
138e71ca95Gerald Jelinek#endif /* !__sparcv9 */
139e71ca95Gerald Jelinek	sll	%l3, (1 + CLONGSHIFT), %l3	/* Each entry has 2 longs */
140e71ca95Gerald Jelinek	add	%l3, %l1, %l3			/* index to proper entry */
141e71ca95Gerald Jelinek	ldn	[%l3 + CPTRSIZE], %l4		/* number of args + rv flag */
142e71ca95Gerald Jelinek	sethi	%hi(RV_MASK), %l5
143e71ca95Gerald Jelinek	or	%l5, %lo(RV_MASK), %l5
144e71ca95Gerald Jelinek	andcc	%l4, %l5, %l3			/* strip out number of args*/
145e71ca95Gerald Jelinek	andcc	%l4, NARGS_MASK, %l4		/* strip out rv flag */
146e71ca95Gerald Jelinek
147e71ca95Gerald Jelinek	/*
148e71ca95Gerald Jelinek	 * Setup arguments for our emulation call.  Our input arguments,
149e71ca95Gerald Jelinek	 * 0 to N, will become emulation call arguments 1 to N+1.
150e71ca95Gerald Jelinek	 * %l4 == number of arguments.
151e71ca95Gerald Jelinek	 */
152e71ca95Gerald Jelinek	mov	%i0, %o1
153e71ca95Gerald Jelinek	mov	%i1, %o2
154e71ca95Gerald Jelinek	mov	%i2, %o3
155e71ca95Gerald Jelinek	mov	%i3, %o4
156e71ca95Gerald Jelinek	mov	%i4, %o5
157e71ca95Gerald Jelinek
158e71ca95Gerald Jelinek	/* 7th argument and above get passed on the stack */
159e71ca95Gerald Jelinek	cmp	%l4, 0x6
160e71ca95Gerald Jelinek	bl,pt	%ncc, args_copied
161e71ca95Gerald Jelinek	nop
162e71ca95Gerald Jelinek	stn	%i5, [%sp + EH_ARGS_OFFSET(0)]	/* copy 6th syscall arg */
163e71ca95Gerald Jelinek	cmp	%l4, 0x7
164e71ca95Gerald Jelinek	bl,pt	%ncc, args_copied
165e71ca95Gerald Jelinek	nop
166e71ca95Gerald Jelinek	ldn	[%fp + EH_ARGS_OFFSET(0)], %l5	/* copy 7th syscall arg */
167e71ca95Gerald Jelinek	stn	%l5, [%sp + EH_ARGS_OFFSET(1)]
168e71ca95Gerald Jelinek	cmp	%l4, 0x8
169e71ca95Gerald Jelinek	bl,pt	%ncc, args_copied
170e71ca95Gerald Jelinek	nop
171e71ca95Gerald Jelinek	ldn	[%fp + EH_ARGS_OFFSET(1)], %l5
172e71ca95Gerald Jelinek	stn	%l5, [%sp + EH_ARGS_OFFSET(2)]	/* copy 8th syscall arg */
173e71ca95Gerald Jelinek#if !defined(__sparcv9)
174e71ca95Gerald Jelinek	cmp	%l4, 0x9
175e71ca95Gerald Jelinek	bl,pt	%ncc, args_copied
176e71ca95Gerald Jelinek	nop
177e71ca95Gerald Jelinek	ldn	[%fp + EH_ARGS_OFFSET(2)], %l5
178e71ca95Gerald Jelinek	stn	%l5, [%sp + EH_ARGS_OFFSET(3)]	/* copy 9th syscall arg */
179e71ca95Gerald Jelinek#endif /* !__sparcv9 */
180e71ca95Gerald Jelinek
181e71ca95Gerald Jelinekargs_copied:
182e71ca95Gerald Jelinek	/*
183e71ca95Gerald Jelinek	 * The first parameter to the emulation callback function is a
184e71ca95Gerald Jelinek	 * pointer to a sysret_t structure.
185e71ca95Gerald Jelinek	 *
186e71ca95Gerald Jelinek	 * invoke the emulation routine.
187e71ca95Gerald Jelinek	 */
18880e2ca8<gerald.jelinek@sun.com>	ALTENTRY(brand_handler_savepc)
189e71ca95Gerald Jelinek	call	%l2
190e71ca95Gerald Jelinek	add	%sp, EH_LOCALS_SYSRET, %o0	/* arg0 == sysret_t ptr */
191e71ca95Gerald Jelinek
192e71ca95Gerald Jelinek	/* Check for syscall emulation success or failure */
193e71ca95Gerald Jelinek	cmp	%g0, %o0
194e71ca95Gerald Jelinek	be	success
195e71ca95Gerald Jelinek	nop
196e71ca95Gerald Jelinek	subcc   %g0, 1, %g0			/* failure, set carry flag */
197e71ca95Gerald Jelinek	ba	return
198e71ca95Gerald Jelinek	mov	%o0, %i0			/* return, %o0 == errno */
199e71ca95Gerald Jelinek
200e71ca95Gerald Jelineksuccess:
201e71ca95Gerald Jelinek	/* There is always at least one return value. */
202e71ca95Gerald Jelinek	ldn	[%sp + EH_LOCALS_SYSRET1], %i0	/* %i0 == sys_rval1 */
203e71ca95Gerald Jelinek	cmp	%l3, RV_DEFAULT			/* check rv flag */
204e71ca95Gerald Jelinek	be,a	clear_carry
205e71ca95Gerald Jelinek	mov	%g0, %i1			/* clear second rval */
206e71ca95Gerald Jelinek	ldn	[%sp + EH_LOCALS_SYSRET2], %i1	/* %i1 == sys_rval2 */
207e71ca95Gerald Jelinekclear_carry:
208e71ca95Gerald Jelinek	addcc	%g0, %g0, %g0			/* success, clear carry flag */
209e71ca95Gerald Jelinek
210e71ca95Gerald Jelinekreturn:
211e71ca95Gerald Jelinek	/*
212e71ca95Gerald Jelinek	 * Our syscall emulation is complete.  Return to the caller that
213e71ca95Gerald Jelinek	 * originally invoked a system which needed emulation.  Note that
214e71ca95Gerald Jelinek	 * we have to load the return address that we saved earlier because
215e71ca95Gerald Jelinek	 * it's possible that %g5 was overwritten by a nested call into
216e71ca95Gerald Jelinek	 * this emulation library.
217e71ca95Gerald Jelinek	 */
218e71ca95Gerald Jelinek	ldn	[%sp + EH_LOCALS_GREG(REG_nPC)], %g5
219e71ca95Gerald Jelinek	jmp	%g5
220e71ca95Gerald Jelinek	restore					/* delay slot */
22180e2ca8<gerald.jelinek@sun.com>	SET_SIZE(brand_handler)
222e71ca95Gerald Jelinek
223e71ca95Gerald Jelinek
224e71ca95Gerald Jelinek#endif	/* !lint */