1/* $Id: rtrap.S,v 1.57 2001/07/17 16:17:33 anton Exp $
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/cprefix.h>
8#include <asm/page.h>
9#include <asm/ptrace.h>
10#include <asm/psr.h>
11#include <asm/asi.h>
12#include <asm/smp.h>
13#include <asm/contregs.h>
14#include <asm/winmacro.h>
15#include <asm/asmmacro.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	C_LABEL(ret_trap_lockless_ipi)
50ret_trap_entry:
51C_LABEL(ret_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 + AOFF_task_need_resched], %g2
62	orcc	%g2, %g0, %g0
63	be	signal_p
64	 ld	[%curptr + AOFF_task_sigpending], %g2
65
66	call	C_LABEL(schedule)
67	 nop
68
69	ld	[%curptr + AOFF_task_sigpending], %g2
70signal_p:
71	cmp	%g2, 0
72	bz,a	ret_trap_continue
73	 ld	[%sp + STACKFRAME_SZ + PT_PSR], %t_psr
74
75	clr	%o0
76	mov	%l5, %o2
77	mov	%l6, %o3
78	call	C_LABEL(do_signal)
79	 add	%sp, STACKFRAME_SZ, %o1	! pt_regs ptr
80
81	/* Fall through. */
82	ld	[%sp + STACKFRAME_SZ + PT_PSR], %t_psr
83	clr	%l6
84ret_trap_continue:
85	wr	%t_psr, 0x0, %psr
86	WRITE_PAUSE
87
88	ld	[%curptr + AOFF_task_thread + AOFF_thread_w_saved], %twin_tmp1
89	orcc	%g0, %twin_tmp1, %g0
90	be	ret_trap_nobufwins
91	 nop
92
93	wr	%t_psr, PSR_ET, %psr
94	WRITE_PAUSE
95
96	mov	1, %o1
97	call	C_LABEL(try_to_clear_window_buffer)
98	 add	%sp, STACKFRAME_SZ, %o0
99
100	b	signal_p
101	 ld	[%curptr + AOFF_task_sigpending], %g2
102
103ret_trap_nobufwins:
104	/* Load up the user's out registers so we can pull
105	 * a window from the stack, if necessary.
106	 */
107	LOAD_PT_INS(sp)
108
109	/* If there are already live user windows in the
110	 * set we can return from trap safely.
111	 */
112	ld	[%curptr + AOFF_task_thread + AOFF_thread_uwinmask], %twin_tmp1
113	orcc	%g0, %twin_tmp1, %g0
114	bne	ret_trap_userwins_ok
115	 nop
116
117		/* Calculate new %wim, we have to pull a register
118		 * window from the users stack.
119		 */
120ret_trap_pull_one_window:
121		rd	%wim, %t_wim
122		sll	%t_wim, 0x1, %twin_tmp1
123rtrap_patch1:	srl	%t_wim, 0x7, %glob_tmp
124		or	%glob_tmp, %twin_tmp1, %glob_tmp
125rtrap_patch2:	and	%glob_tmp, 0xff, %glob_tmp
126
127		wr	%glob_tmp, 0x0, %wim
128
129				/* Here comes the architecture specific
130				 * branch to the user stack checking routine
131				 * for return from traps.
132				 */
133				.globl	C_LABEL(rtrap_mmu_patchme)
134C_LABEL(rtrap_mmu_patchme):	b	C_LABEL(sun4c_rett_stackchk)
135				 andcc	%fp, 0x7, %g0
136
137ret_trap_userwins_ok:
138	LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc)
139	or	%t_pc, %t_npc, %g2
140	andcc	%g2, 0x3, %g0
141	be	1f
142	 nop
143
144	b	ret_trap_unaligned_pc
145	 add	%sp, STACKFRAME_SZ, %o0
146
1471:
148	LOAD_PT_YREG(sp, g1)
149	LOAD_PT_GLOBALS(sp)
150
151	wr	%t_psr, 0x0, %psr
152	WRITE_PAUSE
153
154	jmp	%t_pc
155	rett	%t_npc
156
157ret_trap_unaligned_pc:
158	ld	[%sp + STACKFRAME_SZ + PT_PC], %o1
159	ld	[%sp + STACKFRAME_SZ + PT_NPC], %o2
160	ld	[%sp + STACKFRAME_SZ + PT_PSR], %o3
161
162	wr	%t_wim, 0x0, %wim		! or else...
163
164	wr	%t_psr, PSR_ET, %psr
165	WRITE_PAUSE
166
167	call	C_LABEL(do_memaccess_unaligned)
168	 nop
169
170	b	signal_p
171	 ld	[%curptr + AOFF_task_sigpending], %g2
172
173ret_trap_kernel:
174		/* Will the rett land us in the invalid window? */
175		mov	2, %g1
176		sll	%g1, %t_psr, %g1
177rtrap_patch3:	srl	%g1, 8, %g2
178		or	%g1, %g2, %g1
179		rd	%wim, %g2
180		andcc	%g2, %g1, %g0
181		be	1f		! Nope, just return from the trap
182		 sll	%g2, 0x1, %g1
183
184		/* We have to grab a window before returning. */
185rtrap_patch4:	srl	%g2, 7,  %g2
186		or	%g1, %g2, %g1
187rtrap_patch5:	and	%g1, 0xff, %g1
188
189	wr	%g1, 0x0, %wim
190
191	/* Grrr, make sure we load from the right %sp... */
192	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
193
194	restore	%g0, %g0, %g0
195	LOAD_WINDOW(sp)
196	b	2f
197	 save	%g0, %g0, %g0
198
199	/* Reload the entire frame in case this is from a
200	 * kernel system call or whatever...
201	 */
2021:
203	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
2042:
205	wr	%t_psr, 0x0, %psr
206	WRITE_PAUSE
207
208	jmp	%t_pc
209	rett	%t_npc
210
211ret_trap_user_stack_is_bolixed:
212	wr	%t_wim, 0x0, %wim
213
214	wr	%t_psr, PSR_ET, %psr
215	WRITE_PAUSE
216
217	call	C_LABEL(window_ret_fault)
218	 add	%sp, STACKFRAME_SZ, %o0
219
220	b	signal_p
221	 ld	[%curptr + AOFF_task_sigpending], %g2
222
223	.globl	C_LABEL(sun4c_rett_stackchk)
224C_LABEL(sun4c_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	C_LABEL(srmmu_rett_stackchk)
288C_LABEL(srmmu_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