1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * rtrap.S: Return from Sparc trap low-level code.
4 *
5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
6 */
7
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#include <asm/thread_info.h>
17
18#define t_psr     l0
19#define t_pc      l1
20#define t_npc     l2
21#define t_wim     l3
22#define twin_tmp1 l4
23#define glob_tmp  g4
24#define curptr    g6
25
26	/* 7 WINDOW SPARC PATCH INSTRUCTIONS */
27	.globl	rtrap_7win_patch1, rtrap_7win_patch2, rtrap_7win_patch3
28	.globl	rtrap_7win_patch4, rtrap_7win_patch5
29rtrap_7win_patch1:	srl	%t_wim, 0x6, %glob_tmp
30rtrap_7win_patch2:	and	%glob_tmp, 0x7f, %glob_tmp
31rtrap_7win_patch3:	srl	%g1, 7, %g2
32rtrap_7win_patch4:	srl	%g2, 6, %g2
33rtrap_7win_patch5:	and	%g1, 0x7f, %g1
34	/* END OF PATCH INSTRUCTIONS */
35
36	/* We need to check for a few things which are:
37	 * 1) The need to call schedule() because this
38	 *    processes quantum is up.
39	 * 2) Pending signals for this process, if any
40	 *    exist we need to call do_signal() to do
41	 *    the needy.
42	 *
43	 * Else we just check if the rett would land us
44	 * in an invalid window, if so we need to grab
45	 * it off the user/kernel stack first.
46	 */
47
48	.globl	ret_trap_entry, rtrap_patch1, rtrap_patch2
49	.globl	rtrap_patch3, rtrap_patch4, rtrap_patch5
50	.globl	ret_trap_lockless_ipi
51ret_trap_entry:
52ret_trap_lockless_ipi:
53	andcc	%t_psr, PSR_PS, %g0
54	sethi	%hi(PSR_SYSCALL), %g1
55	be	1f
56	 andn	%t_psr, %g1, %t_psr
57
58	wr	%t_psr, 0x0, %psr
59	b	ret_trap_kernel
60	 nop
61
621:
63	ld	[%curptr + TI_FLAGS], %g2
64	andcc	%g2, (_TIF_NEED_RESCHED), %g0
65	be	signal_p
66	 nop
67
68	call	schedule
69	 nop
70
71	ld	[%curptr + TI_FLAGS], %g2
72signal_p:
73	andcc	%g2, _TIF_DO_NOTIFY_RESUME_MASK, %g0
74	bz,a	ret_trap_continue
75	 ld	[%sp + STACKFRAME_SZ + PT_PSR], %t_psr
76
77	mov	%g2, %o2
78	mov	%l6, %o1
79	call	do_notify_resume
80	 add	%sp, STACKFRAME_SZ, %o0	! pt_regs ptr
81
82	b	signal_p
83	 ld	[%curptr + TI_FLAGS], %g2
84
85ret_trap_continue:
86	sethi	%hi(PSR_SYSCALL), %g1
87	andn	%t_psr, %g1, %t_psr
88	wr	%t_psr, 0x0, %psr
89	WRITE_PAUSE
90
91	ld	[%curptr + TI_W_SAVED], %twin_tmp1
92	orcc	%g0, %twin_tmp1, %g0
93	be	ret_trap_nobufwins
94	 nop
95
96	wr	%t_psr, PSR_ET, %psr
97	WRITE_PAUSE
98
99	mov	1, %o1
100	call	try_to_clear_window_buffer
101	 add	%sp, STACKFRAME_SZ, %o0
102
103	b	signal_p
104	 ld	[%curptr + TI_FLAGS], %g2
105
106ret_trap_nobufwins:
107	/* Load up the user's out registers so we can pull
108	 * a window from the stack, if necessary.
109	 */
110	LOAD_PT_INS(sp)
111
112	/* If there are already live user windows in the
113	 * set we can return from trap safely.
114	 */
115	ld	[%curptr + TI_UWINMASK], %twin_tmp1
116	orcc	%g0, %twin_tmp1, %g0
117	bne	ret_trap_userwins_ok
118	 nop
119
120		/* Calculate new %wim, we have to pull a register
121		 * window from the users stack.
122		 */
123ret_trap_pull_one_window:
124		rd	%wim, %t_wim
125		sll	%t_wim, 0x1, %twin_tmp1
126rtrap_patch1:	srl	%t_wim, 0x7, %glob_tmp
127		or	%glob_tmp, %twin_tmp1, %glob_tmp
128rtrap_patch2:	and	%glob_tmp, 0xff, %glob_tmp
129
130		wr	%glob_tmp, 0x0, %wim
131
132	/* Here comes the architecture specific
133	 * branch to the user stack checking routine
134	 * for return from traps.
135	 */
136	b	srmmu_rett_stackchk
137	 andcc	%fp, 0x7, %g0
138
139ret_trap_userwins_ok:
140	LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc)
141	or	%t_pc, %t_npc, %g2
142	andcc	%g2, 0x3, %g0
143	sethi	%hi(PSR_SYSCALL), %g2
144	be	1f
145	 andn	%t_psr, %g2, %t_psr
146
147	b	ret_trap_unaligned_pc
148	 add	%sp, STACKFRAME_SZ, %o0
149
1501:
151	LOAD_PT_YREG(sp, g1)
152	LOAD_PT_GLOBALS(sp)
153
154	wr	%t_psr, 0x0, %psr
155	WRITE_PAUSE
156
157	jmp	%t_pc
158	rett	%t_npc
159
160ret_trap_unaligned_pc:
161	ld	[%sp + STACKFRAME_SZ + PT_PC], %o1
162	ld	[%sp + STACKFRAME_SZ + PT_NPC], %o2
163	ld	[%sp + STACKFRAME_SZ + PT_PSR], %o3
164
165	wr	%t_wim, 0x0, %wim		! or else...
166
167	wr	%t_psr, PSR_ET, %psr
168	WRITE_PAUSE
169
170	call	do_memaccess_unaligned
171	 nop
172
173	b	signal_p
174	 ld	[%curptr + TI_FLAGS], %g2
175
176ret_trap_kernel:
177		/* Will the rett land us in the invalid window? */
178		mov	2, %g1
179		sll	%g1, %t_psr, %g1
180rtrap_patch3:	srl	%g1, 8, %g2
181		or	%g1, %g2, %g1
182		rd	%wim, %g2
183		andcc	%g2, %g1, %g0
184		be	1f		! Nope, just return from the trap
185		 sll	%g2, 0x1, %g1
186
187		/* We have to grab a window before returning. */
188rtrap_patch4:	srl	%g2, 7,  %g2
189		or	%g1, %g2, %g1
190rtrap_patch5:	and	%g1, 0xff, %g1
191
192	wr	%g1, 0x0, %wim
193
194	/* Grrr, make sure we load from the right %sp... */
195	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
196
197	restore	%g0, %g0, %g0
198	LOAD_WINDOW(sp)
199	b	2f
200	 save	%g0, %g0, %g0
201
202	/* Reload the entire frame in case this is from a
203	 * kernel system call or whatever...
204	 */
2051:
206	LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
2072:
208	sethi	%hi(PSR_SYSCALL), %twin_tmp1
209	andn	%t_psr, %twin_tmp1, %t_psr
210	wr	%t_psr, 0x0, %psr
211	WRITE_PAUSE
212
213	jmp	%t_pc
214	rett	%t_npc
215
216ret_trap_user_stack_is_bolixed:
217	wr	%t_wim, 0x0, %wim
218
219	wr	%t_psr, PSR_ET, %psr
220	WRITE_PAUSE
221
222	call	window_ret_fault
223	 add	%sp, STACKFRAME_SZ, %o0
224
225	b	signal_p
226	 ld	[%curptr + TI_FLAGS], %g2
227
228	.globl	srmmu_rett_stackchk
229srmmu_rett_stackchk:
230	bne	ret_trap_user_stack_is_bolixed
231	 sethi   %hi(PAGE_OFFSET), %g1
232	cmp	%g1, %fp
233	bleu	ret_trap_user_stack_is_bolixed
234	 mov	AC_M_SFSR, %g1
235LEON_PI(lda	[%g1] ASI_LEON_MMUREGS, %g0)
236SUN_PI_(lda	[%g1] ASI_M_MMUREGS, %g0)
237
238LEON_PI(lda	[%g0] ASI_LEON_MMUREGS, %g1)
239SUN_PI_(lda	[%g0] ASI_M_MMUREGS, %g1)
240	or	%g1, 0x2, %g1
241LEON_PI(sta	%g1, [%g0] ASI_LEON_MMUREGS)
242SUN_PI_(sta	%g1, [%g0] ASI_M_MMUREGS)
243
244	restore	%g0, %g0, %g0
245
246	LOAD_WINDOW(sp)
247
248	save	%g0, %g0, %g0
249
250	andn	%g1, 0x2, %g1
251LEON_PI(sta	%g1, [%g0] ASI_LEON_MMUREGS)
252SUN_PI_(sta	%g1, [%g0] ASI_M_MMUREGS)
253
254	mov	AC_M_SFAR, %g2
255LEON_PI(lda	[%g2] ASI_LEON_MMUREGS, %g2)
256SUN_PI_(lda	[%g2] ASI_M_MMUREGS, %g2)
257
258	mov	AC_M_SFSR, %g1
259LEON_PI(lda	[%g1] ASI_LEON_MMUREGS, %g1)
260SUN_PI_(lda	[%g1] ASI_M_MMUREGS, %g1)
261	andcc	%g1, 0x2, %g0
262	be	ret_trap_userwins_ok
263	 nop
264
265	b,a	ret_trap_user_stack_is_bolixed
266