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