1/* $Id: rtrap.S,v 1.1.1.1 2007-08-03 18:52:17 $
2 * rtrap.S: Return from Sparc trap low-level code.
3 *
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 */
6
7#include <asm/page.h>
8#include <asm/ptrace.h>
9#include <asm/psr.h>
10#include <asm/asi.h>
11#include <asm/smp.h>
12#include <asm/contregs.h>
13#include <asm/winmacro.h>
14#include <asm/asmmacro.h>
15#include <asm/thread_info.h>
16
17#define t_psr     l0
18#define t_pc      l1
19#define t_npc     l2
20#define t_wim     l3
21#define twin_tmp1 l4
22#define glob_tmp  g4
23#define curptr    g6
24
25	/* 7 WINDOW SPARC PATCH INSTRUCTIONS */
26	.globl	rtrap_7win_patch1, rtrap_7win_patch2, rtrap_7win_patch3
27	.globl	rtrap_7win_patch4, rtrap_7win_patch5
28rtrap_7win_patch1:	srl	%t_wim, 0x6, %glob_tmp
29rtrap_7win_patch2:	and	%glob_tmp, 0x7f, %glob_tmp
30rtrap_7win_patch3:	srl	%g1, 7, %g2
31rtrap_7win_patch4:	srl	%g2, 6, %g2
32rtrap_7win_patch5:	and	%g1, 0x7f, %g1
33	/* END OF PATCH INSTRUCTIONS */
34
35	/* We need to check for a few things which are:
36	 * 1) The need to call schedule() because this
37	 *    processes quantum is up.
38	 * 2) Pending signals for this process, if any
39	 *    exist we need to call do_signal() to do
40	 *    the needy.
41	 *
42	 * Else we just check if the rett would land us
43	 * in an invalid window, if so we need to grab
44	 * it off the user/kernel stack first.
45	 */
46
47	.globl	ret_trap_entry, rtrap_patch1, rtrap_patch2
48	.globl	rtrap_patch3, rtrap_patch4, rtrap_patch5
49	.globl	ret_trap_lockless_ipi
50ret_trap_entry:
51ret_trap_lockless_ipi:
52	andcc	%t_psr, PSR_PS, %g0
53	be	1f
54	 nop
55
56	wr	%t_psr, 0x0, %psr
57	b	ret_trap_kernel
58	 nop
59
601:
61	ld	[%curptr + TI_FLAGS], %g2
62	andcc	%g2, (_TIF_NEED_RESCHED), %g0
63	be	signal_p
64	 nop
65
66	call	schedule
67	 nop
68
69	ld	[%curptr + TI_FLAGS], %g2
70signal_p:
71	andcc	%g2, (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %g0
72	bz,a	ret_trap_continue
73	 ld	[%sp + STACKFRAME_SZ + PT_PSR], %t_psr
74
75	mov	%l5, %o1
76	mov	%l6, %o2
77	call	do_signal
78	 add	%sp, STACKFRAME_SZ, %o0	! pt_regs ptr
79
80	/* Fall through. */
81	ld	[%sp + STACKFRAME_SZ + PT_PSR], %t_psr
82	clr	%l6
83ret_trap_continue:
84	wr	%t_psr, 0x0, %psr
85	WRITE_PAUSE
86
87	ld	[%curptr + TI_W_SAVED], %twin_tmp1
88	orcc	%g0, %twin_tmp1, %g0
89	be	ret_trap_nobufwins
90	 nop
91
92	wr	%t_psr, PSR_ET, %psr
93	WRITE_PAUSE
94
95	mov	1, %o1
96	call	try_to_clear_window_buffer
97	 add	%sp, STACKFRAME_SZ, %o0
98
99	b	signal_p
100	 ld	[%curptr + TI_FLAGS], %g2
101
102ret_trap_nobufwins:
103	/* Load up the user's out registers so we can pull
104	 * a window from the stack, if necessary.
105	 */
106	LOAD_PT_INS(sp)
107
108	/* If there are already live user windows in the
109	 * set we can return from trap safely.
110	 */
111	ld	[%curptr + TI_UWINMASK], %twin_tmp1
112	orcc	%g0, %twin_tmp1, %g0
113	bne	ret_trap_userwins_ok
114	 nop
115
116		/* Calculate new %wim, we have to pull a register
117		 * window from the users stack.
118		 */
119ret_trap_pull_one_window:
120		rd	%wim, %t_wim
121		sll	%t_wim, 0x1, %twin_tmp1
122rtrap_patch1:	srl	%t_wim, 0x7, %glob_tmp
123		or	%glob_tmp, %twin_tmp1, %glob_tmp
124rtrap_patch2:	and	%glob_tmp, 0xff, %glob_tmp
125
126		wr	%glob_tmp, 0x0, %wim
127
128				/* Here comes the architecture specific
129				 * branch to the user stack checking routine
130				 * for return from traps.
131				 */
132				.globl	rtrap_mmu_patchme
133rtrap_mmu_patchme:	b	sun4c_rett_stackchk
134				 andcc	%fp, 0x7, %g0
135
136ret_trap_userwins_ok:
137	LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc)
138	or	%t_pc, %t_npc, %g2
139	andcc	%g2, 0x3, %g0
140	be	1f
141	 nop
142
143	b	ret_trap_unaligned_pc
144	 add	%sp, STACKFRAME_SZ, %o0
145
1461:
147	LOAD_PT_YREG(sp, g1)
148	LOAD_PT_GLOBALS(sp)
149
150	wr	%t_psr, 0x0, %psr
151	WRITE_PAUSE
152
153	jmp	%t_pc
154	rett	%t_npc
155
156ret_trap_unaligned_pc:
157	ld	[%sp + STACKFRAME_SZ + PT_PC], %o1
158	ld	[%sp + STACKFRAME_SZ + PT_NPC], %o2
159	ld	[%sp + STACKFRAME_SZ + PT_PSR], %o3
160
161	wr	%t_wim, 0x0, %wim		! or else...
162
163	wr	%t_psr, PSR_ET, %psr
164	WRITE_PAUSE
165
166	call	do_memaccess_unaligned
167	 nop
168
169	b	signal_p
170	 ld	[%curptr + TI_FLAGS], %g2
171
172ret_trap_kernel:
173		/* Will the rett land us in the invalid window? */
174		mov	2, %g1
175		sll	%g1, %t_psr, %g1
176rtrap_patch3:	srl	%g1, 8, %g2
177		or	%g1, %g2, %g1
178		rd	%wim, %g2
179		andcc	%g2, %g1, %g0
180		be	1f		! Nope, just return from the trap
181		 sll	%g2, 0x1, %g1
182
183		/* We have to grab a window before returning. */
184rtrap_patch4:	srl	%g2, 7,  %g2
185		or	%g1, %g2, %g1
186rtrap_patch5:	and	%g1, 0xff, %g1
187
188	wr	%g1, 0x0, %wim
189
190	/* Grrr, make sure we load from the right %sp... */
191	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
192
193	restore	%g0, %g0, %g0
194	LOAD_WINDOW(sp)
195	b	2f
196	 save	%g0, %g0, %g0
197
198	/* Reload the entire frame in case this is from a
199	 * kernel system call or whatever...
200	 */
2011:
202	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
2032:
204	wr	%t_psr, 0x0, %psr
205	WRITE_PAUSE
206
207	jmp	%t_pc
208	rett	%t_npc
209
210ret_trap_user_stack_is_bolixed:
211	wr	%t_wim, 0x0, %wim
212
213	wr	%t_psr, PSR_ET, %psr
214	WRITE_PAUSE
215
216	call	window_ret_fault
217	 add	%sp, STACKFRAME_SZ, %o0
218
219	b	signal_p
220	 ld	[%curptr + TI_FLAGS], %g2
221
222
223	.globl	sun4c_rett_stackchk
224sun4c_rett_stackchk:
225	be	1f
226	 and	%fp, 0xfff, %g1		! delay slot
227
228	b	ret_trap_user_stack_is_bolixed + 0x4
229	 wr	%t_wim, 0x0, %wim
230
231	/* See if we have to check the sanity of one page or two */
2321:
233	add	%g1, 0x38, %g1
234	sra	%fp, 29, %g2
235	add	%g2, 0x1, %g2
236	andncc	%g2, 0x1, %g0
237	be	1f
238	 andncc	%g1, 0xff8, %g0
239
240	/* %sp is in vma hole, yuck */
241	b	ret_trap_user_stack_is_bolixed + 0x4
242	 wr	%t_wim, 0x0, %wim
243
2441:
245	be	sun4c_rett_onepage	/* Only one page to check */
246	 lda	[%fp] ASI_PTE, %g2
247
248sun4c_rett_twopages:
249	add	%fp, 0x38, %g1
250	sra	%g1, 29, %g2
251	add	%g2, 0x1, %g2
252	andncc	%g2, 0x1, %g0
253	be	1f
254	 lda	[%g1] ASI_PTE, %g2
255
256	/* Second page is in vma hole */
257	b	ret_trap_user_stack_is_bolixed + 0x4
258	 wr	%t_wim, 0x0, %wim
259
2601:
261	srl	%g2, 29, %g2
262	andcc	%g2, 0x4, %g0
263	bne	sun4c_rett_onepage
264	 lda	[%fp] ASI_PTE, %g2
265
266	/* Second page has bad perms */
267	b	ret_trap_user_stack_is_bolixed + 0x4
268	 wr	%t_wim, 0x0, %wim
269
270sun4c_rett_onepage:
271	srl	%g2, 29, %g2
272	andcc	%g2, 0x4, %g0
273	bne,a	1f
274	 restore %g0, %g0, %g0
275
276	/* A page had bad page permissions, losing... */
277	b	ret_trap_user_stack_is_bolixed + 0x4
278	 wr	%t_wim, 0x0, %wim
279
280	/* Whee, things are ok, load the window and continue. */
2811:
282	LOAD_WINDOW(sp)
283
284	b	ret_trap_userwins_ok
285	 save	%g0, %g0, %g0
286
287	.globl	srmmu_rett_stackchk
288srmmu_rett_stackchk:
289	bne	ret_trap_user_stack_is_bolixed
290	 sethi   %hi(PAGE_OFFSET), %g1
291	cmp	%g1, %fp
292	bleu	ret_trap_user_stack_is_bolixed
293	 mov	AC_M_SFSR, %g1
294	lda	[%g1] ASI_M_MMUREGS, %g0
295
296	lda	[%g0] ASI_M_MMUREGS, %g1
297	or	%g1, 0x2, %g1
298	sta	%g1, [%g0] ASI_M_MMUREGS
299
300	restore	%g0, %g0, %g0
301
302	LOAD_WINDOW(sp)
303
304	save	%g0, %g0, %g0
305
306	andn	%g1, 0x2, %g1
307	sta	%g1, [%g0] ASI_M_MMUREGS
308
309	mov	AC_M_SFAR, %g2
310	lda	[%g2] ASI_M_MMUREGS, %g2
311
312	mov	AC_M_SFSR, %g1
313	lda	[%g1] ASI_M_MMUREGS, %g1
314	andcc	%g1, 0x2, %g0
315	be	ret_trap_userwins_ok
316	 nop
317
318	b,a	ret_trap_user_stack_is_bolixed
319