sn1_brand_asm.s revision 2712:f74a135872bc
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 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#if defined(lint)
29
30#include <sys/systm.h>
31
32#else	/* lint */
33
34#include <sys/asm_linkage.h>
35#include <sys/privregs.h>
36#include <sys/segments.h>
37
38#endif	/* lint */
39
40#ifdef	lint
41
42void
43sn1_brand_sysenter_callback(void)
44{
45}
46
47void
48sn1_brand_syscall_callback(void)
49{
50}
51
52#if defined(__amd64)
53void
54sn1_brand_syscall32_callback(void)
55{
56}
57#endif	/* amd64 */
58
59void
60sn1_brand_int91_callback(void)
61{
62}
63
64#else	/* lint */
65
66/*
67 * Each of the following macros returns to the standard syscall codepath if
68 * it detects that this process is not able, or intended, to emulate this
69 * system call.  They all assume that the routine provides a 'bail-out'
70 * label of '9'.
71 */
72
73/*
74 * See if this process has a user-space handler registered for it.  For the
75 * sn1 brand, the per-process brand data holds the address of the handler.
76 * As shown in the stack diagrams below, the callback code leaves that data
77 * at these offsets.
78 */
79#if defined(__amd64)
80#define	CHECK_FOR_HANDLER		 \
81	cmpq	$0, 24(%rsp)		;\
82	je	9f
83#else
84#define	CHECK_FOR_HANDLER		 \
85	cmpl	$0, 12(%esp)		;\
86	je	9f
87#endif	/* __amd64 */
88
89/*
90 * If the system call number is >= 1024, then it is coming from the
91 * emulation support library.  As such we should handle it natively instead
92 * of sending it back to the emulation library.
93 */
94#define	CHECK_FOR_NATIVE(reg)		\
95	cmp	$1024, reg		;\
96	jl	1f			;\
97	sub	$1024, reg		;\
98	jmp	9f			;\
991:
100
101/*
102 * Check to see if we want to interpose on this system call.  If not, we
103 * jump back into the normal syscall path and pretend nothing happened.
104 */
105#define CHECK_FOR_INTERPOSITION(sysr, scr, scr_low)		\
106	lea	sn1_emulation_table, scr			;\
107	mov	(scr), scr					;\
108	add	sysr, scr					;\
109	movb	(scr), scr_low					;\
110	cmpb	$0, scr_low					;\
111	je	9f						;\
112
113#define	CALLBACK_PROLOGUE(call, scr, scr_low)			;\
114	push	scr		/* Save scratch register */	;\
115	CHECK_FOR_HANDLER					;\
116	CHECK_FOR_NATIVE(call)					;\
117	CHECK_FOR_INTERPOSITION(call, scr, scr_low)
118
119/*
120 * The callback routines:
121 */
122
123#if defined(__amd64)
124	/*
125	 * When we get into any of these callback routines, the stack
126	 * looks like this:
127	 *  	   --------------------------------------
128	 *      32 | saved stack pointer		|
129	 *    | 24 | lwp brand data			|
130	 *    | 16 | proc brand data			|
131	 *    v  8 | user return address (*)		|
132	 *       0 | BRAND_CALLBACK()'s return addr 	|
133	 *         --------------------------------------
134	 *   (*) This is actually just the bottom value from the user's
135	 *       stack.  syscall puts this in %rcx instead of the stack,
136	 *       so it's just garbage for that entry point.
137	 */
138
139	/*
140	 * syscall handler for 32-bit user processes:
141	 *
142	 * %ecx contains the address of the instruction after the syscall
143	 */
144	ENTRY(sn1_brand_syscall32_callback)
145
146	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
147
148	movq	%rsp, %r15	/* save our stack pointer */
149
150	/*
151	 * Adjust the user's stack so that the 'ret' from our userspace
152	 * handler takes us to the post-syscall instruction instead of to
153	 * the routine that called the system call.
154	 */
155	movq	40(%rsp), %rsp	/* restore user's stack pointer 	*/
156	subq	$4, %rsp	/* save room for the post-syscall addr	*/
157	movl	%ecx, (%rsp)	/* Save post-syscall addr on stack	*/
158
159	/*
160	 * To 'return' to our user-space handler, we just need to copy
161	 * its address into %ecx.
162	 */
163	movq	24(%r15), %rcx	/* user-space handler == proc_data for sn1 */
164	movq	(%r15), %r15	/* Restore scratch register */
165	sysret
1669:
167	popq	%r15
168	retq
169	SET_SIZE(sn1_brand_syscall32_callback)
170
171	/*
172	 * syscall handler for 64-bit user processes:
173	 *     %rax - syscall number
174	 *     %rcx - user space %rip
175	 */
176	ENTRY(sn1_brand_syscall_callback)
177
178	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
179
180	movq	%rsp, %r15	/* save our stack pointer */
181
182	movq	40(%rsp), %rsp	/* restore user's stack pointer 	*/
183	subq	$8, %rsp	/* save room for the post-syscall addr	*/
184	movq	%rcx, (%rsp)	/* Save post-syscall addr on stack	*/
185
186	/*
187	 * To 'return' to our user-space handler, we just need to copy
188	 * its address into %ecx.
189	 */
190	movq	24(%r15), %rcx	/* user-space handler == proc_data for sn1 */
191	movq	(%r15), %r15	/* Restore scratch register */
192	sysretq
1939:
194	popq	%r15
195	retq
196
197	SET_SIZE(sn1_brand_syscall_callback)
198
199	/*
200	 * %rax - syscall number
201	 * %rcx - user space %esp
202	 * %rdx - user space return address
203	 *
204	 * XXX: not tested yet.  Need a Nocona machine first.
205	 */
206	ENTRY(sn1_brand_sysenter_callback)
207
208	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
209
210	subq	$4, %rcx	/* Save room for user ret addr	*/
211	movq	%rdx, (%rcx)	/* Save current return addr	*/
212	movq	24(%rsp), %rdx	/* user-space handler == proc_data for sn1 */
213	popq	%r15
214	sysexit
2159:
216	popq	%r15
217	ret
218	SET_SIZE(sn1_brand_sysenter_callback)
219
220	/*
221	 * The saved stack pointer points at the state saved when we took
222	 * the interrupt:
223	 *	   --------------------------------------
224	 *    | 32 | user's %ss				|
225	 *    | 24 | user's %esp			|
226	 *    | 16 | EFLAGS register			|
227	 *    v  8 | user's %cs				|
228	 *       0 | user's %eip			|
229	 *	   --------------------------------------
230	 */
231	ENTRY(sn1_brand_int91_callback)
232
233	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
234
235	movq	24(%rsp), %r15	/* user-space handler == proc_data for sn1 */
236	pushq	%rax		/* Save scratch register		*/
237	movq	48(%rsp), %rax	/* Get saved %esp			*/
238	movq	%r15, (%rax)	/* replace iret target address with hdlr */
239
240	/*
241	 * Adjust the caller's stack so we return to the instruction after
242	 * the syscall on the next 'ret' in userspace - not to the parent
243	 * routine.
244	 */
245	movq	24(%rax), %r15	/* Get user's %esp			*/
246	subq	$4, %r15	/* Make room for new ret addr		*/
247	movq	%r15, 24(%rax)	/* Replace current with updated %esp	*/
248	movl	24(%rsp), %eax	/* Get post-syscall address		*/
249	movl	%eax, (%r15)	/* Put it on the user's stack		*/
250
251	popq	%rax		/* Restore scratch register		*/
252	popq	%r15		/* Restore scratch register		*/
253	movq	32(%rsp), %rsp	/* Remove all callback stuff from stack	*/
254	iretq
2559:
256	popq	%r15
257	retq
258	SET_SIZE(sn1_brand_int91_callback)
259
260#else	/* __amd64 */
261
262	/*
263	 * When we get into any of these callback routines, the stack
264	 * looks like this:
265	 *	   --------------------------------------
266	 *    | 28 | 'scatch space'			|
267	 *    | 24 | user's %ebx			|
268	 *    | 20 | user's %gs selector		|
269	 *    | 16 | kernel's %gs selector		|
270	 *    | 12 | lwp brand data			|
271	 *    |  8 | proc brand data			|
272	 *    v  4 | user return address		|
273	 *       0 | callback wrapper return addr	|
274	 *         --------------------------------------
275	 */
276
277	/*
278	 * lcall handler for 32-bit OS
279	 *     %eax - syscall number
280	 *
281	 * Above the stack contents common to all callbacks is the
282	 * int/lcall-specific state:
283	 *	   --------------------------------------
284	 *    | 48 | user's %ss				|
285	 *    | 44 | user's %esp			|
286	 *    | 40 | EFLAGS register			|
287	 *    v 36 | user's %cs				|
288	 *      32 | user's %eip			|
289	 *	   --------------------------------------
290	 */
291	ENTRY(sn1_brand_syscall_callback)
292
293	CALLBACK_PROLOGUE(%eax, %ebx, %bl)
294
295	movl	12(%esp), %ebx	/* user-space handler == proc_data for sn1 */
296	movl	%ebx, 36(%esp)	/* replace iret target address with hdlr */
297
298	/*
299	 * Adjust the caller's stack so we return to the instruction after
300	 * the syscall on the next 'ret' in userspace - not to the parent
301	 * routine.
302	 */
303	pushl	%eax		/* Save scratch register		*/
304	movl	52(%esp), %eax	/* Get current %esp			*/
305	subl	$4, %eax	/* Make room for new ret addr		*/
306	movl	%eax, 52(%esp)	/* Replace current with updated %esp	*/
307	movl	12(%esp), %ebx	/* Get post-syscall address		*/
308	movl	%ebx, (%eax)	/* Put it on the user's stack		*/
309	popl	%eax		/* Restore scratch register 		*/
310
311	popl	%ebx		/* Restore scratch register 		*/
312	addl	$32, %esp	/* Remove all callback stuff from stack	*/
313	iret
3149:
315	popl	%ebx
316	ret
317	SET_SIZE(sn1_brand_syscall_callback)
318
319	/*
320	 * %eax - syscall number
321	 * %ecx - user space %esp
322	 * %edx - user space return address
323	 */
324	ENTRY(sn1_brand_sysenter_callback)
325
326	CALLBACK_PROLOGUE(%eax, %ebx, %bl)
327
328	subl	$4, %ecx	/* Save room for user ret addr	*/
329	movl	%edx, (%ecx)	/* Save current return addr	*/
330	movl	12(%esp), %edx	/* Return to user-space handler	*/
331	popl	%ebx		/* Restore scratch register	*/
332	sysexit
3339:
334	popl	%ebx
335	ret
336	SET_SIZE(sn1_brand_sysenter_callback)
337
338#endif	/* __amd64 */
339#endif	/* lint */
340
341