sn1_brand_asm.s revision 4127:64886a16cf93
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 2007 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/machthread.h>
36#include <sys/privregs.h>
37#include "assym.h"
38
39#endif	/* lint */
40
41#ifdef	lint
42
43void
44sn1_brand_syscall_callback(void)
45{
46}
47
48#else	/* lint */
49
50#ifdef sun4v
51
52#define GLOBALS_SWAP(reg)				\
53	rdpr	%gl, reg				;\
54	wrpr	reg, 1, %gl
55
56#define GLOBALS_RESTORE(reg)				\
57	wrpr	reg, 0, %gl
58
59#else /* !sun4v */
60
61#define GLOBALS_SWAP(reg)				\
62	rdpr	%pstate, reg				;\
63	wrpr	reg, PSTATE_AG, %pstate
64
65#define GLOBALS_RESTORE(reg)				\
66	wrpr	reg, %g0, %pstate
67
68#endif /* !sun4v */
69
70	/*
71	 * Input parameters:
72	 * %g1: return point
73	 * %g2: pointer to our cpu structure
74	 */
75	ENTRY(sn1_brand_syscall_callback)
76
77	/*
78	 * save some locals in the CPU tmp area to give us a little
79	 * room to work.
80	 */
81	stn	%l0, [%g2 + CPU_TMP1]
82	stn	%l1, [%g2 + CPU_TMP2]
83
84#ifdef sun4v
85	/*
86	 * On sun4v save our input parameters (which are stored in the
87	 * alternate globals) since we'll need to switch between alternate
88	 * globals and normal globals, and on sun4v the alternate globals
89	 * are not preserved across these types of switches.
90	 */
91	stn	%l2, [%g2 + CPU_TMP3]
92	stn	%l3, [%g2 + CPU_TMP4]
93	mov	%g1, %l2
94	mov	%g2, %l3
95#endif /* sun4v */
96
97	/*
98	 * Switch from the alternate to user globals to grab the syscall
99	 * number, then switch back to the alternate globals.
100	 *
101	 * If the system call number is >= 1024, then it is coming from the
102	 * emulation support library and should not be emulated.
103	 */
104	GLOBALS_SWAP(%l0)		! switch to normal globals
105	cmp	%g1, 1024		! is this call from the library?
106	bl,a	1f
107	mov	%g1, %l1		! delay slot - grab syscall number
108	sub	%g1, 1024, %g1		! convert magic num to real syscall
109	ba	2f			! jump back into syscall path
1101:
111	GLOBALS_RESTORE(%l0)		! delay slot -
112					! switch back to alternate globals
113
114	/*
115	 * Check to see if we want to interpose on this system call.  If
116	 * not, we jump back into the normal syscall path and pretend
117	 * nothing happened.
118	 */
119	set	sn1_emulation_table, %g3
120	ldn	[%g3], %g3
121	add	%g3, %l1, %g3
122	ldub	[%g3], %g3
123	brz	%g3, 2f
124	nop
125
126	/*
127	 * Find the address of the userspace handler.
128	 * cpu->cpu_thread->t_procp->p_brandhdlr.
129	 */
130#ifdef sun4v
131	! restore the alternate global registers after incrementing %gl
132	mov	%l3, %g2
133#endif /* sun4v */
134	ldn	[%g2 + CPU_THREAD], %g3		! load thread pointer
135	ldn	[%g3 + T_PROCP], %g3		! get proc pointer
136	ldn	[%g3 + P_BRAND_DATA], %g3	! get brand handler
137	brz	%g3, 2f				! has it been set?
138	nop
139
140	/*
141	 * Now the magic happens.  Grab the trap return address and then
142	 * reset it to point to the user space handler.  When we execute
143	 * the 'done' instruction, we will jump into our handler instead of
144	 * the user's code.  We also stick the old return address in %g6,
145	 * so we can return to the proper instruction in the user's code.
146	 * Note: we also pass back the base address of the syscall
147	 * emulation table.  This is a performance hack to avoid having to
148	 * look it up on every call.
149	 */
150	rdpr	%tnpc, %l1		! save old tnpc
151	wrpr	%g0, %g3, %tnpc		! setup tnpc
152	GLOBALS_SWAP(%l0)		! switch to normal globals
153	mov	%l1, %g6		! pass tnpc to user code in %g6
154	GLOBALS_RESTORE(%l0)		! switch back to alternate globals
155
156	/* Update the address we're going to return to */
157#ifdef sun4v
158	set	fast_trap_done_chk_intr, %l2
159#else /* !sun4v */
160	set	fast_trap_done_chk_intr, %g1
161#endif /* !sun4v */
162
1632:
164	/*
165	 * Restore registers before returning.
166	 *
167	 * Note that %g2 should be loaded with the CPU struct addr and
168	 * %g1 should be loaded the address we're going to return to.
169	 */
170#ifdef sun4v
171	! restore the alternate global registers after incrementing %gl
172	mov	%l3, %g2
173	mov	%l2, %g1
174
175	ldn	[%g2 + CPU_TMP4], %l3	! restore locals
176	ldn	[%g2 + CPU_TMP3], %l2
177#endif /* sun4v */
178
179	ldn	[%g2 + CPU_TMP2], %l1	! restore locals
180	ldn	[%g2 + CPU_TMP1], %l0
181
182	jmp	%g1
183	nop
184	SET_SIZE(sn1_brand_syscall_callback)
185#endif	/* lint */
186