1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef __HEAD_32_H__
3#define __HEAD_32_H__
4
5#include <asm/ptrace.h>	/* for STACK_FRAME_REGS_MARKER */
6
7/*
8 * Exception entry code.  This code runs with address translation
9 * turned off, i.e. using physical addresses.
10 * We assume sprg3 has the physical address of the current
11 * task's thread_struct.
12 */
13.macro EXCEPTION_PROLOG		trapno name handle_dar_dsisr=0
14	EXCEPTION_PROLOG_0	handle_dar_dsisr=\handle_dar_dsisr
15	EXCEPTION_PROLOG_1
16	EXCEPTION_PROLOG_2	\trapno \name handle_dar_dsisr=\handle_dar_dsisr
17.endm
18
19.macro EXCEPTION_PROLOG_0 handle_dar_dsisr=0
20	mtspr	SPRN_SPRG_SCRATCH0,r10
21	mtspr	SPRN_SPRG_SCRATCH1,r11
22	mfspr	r10, SPRN_SPRG_THREAD
23	.if	\handle_dar_dsisr
24#ifdef CONFIG_40x
25	mfspr	r11, SPRN_DEAR
26#else
27	mfspr	r11, SPRN_DAR
28#endif
29	stw	r11, DAR(r10)
30#ifdef CONFIG_40x
31	mfspr	r11, SPRN_ESR
32#else
33	mfspr	r11, SPRN_DSISR
34#endif
35	stw	r11, DSISR(r10)
36	.endif
37	mfspr	r11, SPRN_SRR0
38	stw	r11, SRR0(r10)
39	mfspr	r11, SPRN_SRR1		/* check whether user or kernel */
40	stw	r11, SRR1(r10)
41	mfcr	r10
42	andi.	r11, r11, MSR_PR
43.endm
44
45.macro EXCEPTION_PROLOG_1
46	mtspr	SPRN_SPRG_SCRATCH2,r1
47	subi	r1, r1, INT_FRAME_SIZE		/* use r1 if kernel */
48	beq	1f
49	mfspr	r1,SPRN_SPRG_THREAD
50	lwz	r1,TASK_STACK-THREAD(r1)
51	addi	r1, r1, THREAD_SIZE - INT_FRAME_SIZE
521:
53#ifdef CONFIG_VMAP_STACK
54	mtcrf	0x3f, r1
55	bt	32 - THREAD_ALIGN_SHIFT, vmap_stack_overflow
56#endif
57.endm
58
59.macro EXCEPTION_PROLOG_2 trapno name handle_dar_dsisr=0
60#ifdef CONFIG_PPC_8xx
61	.if	\handle_dar_dsisr
62	li	r11, RPN_PATTERN
63	mtspr	SPRN_DAR, r11	/* Tag DAR, to be used in DTLB Error */
64	.endif
65#endif
66	LOAD_REG_IMMEDIATE(r11, MSR_KERNEL & ~MSR_RI) /* re-enable MMU */
67	mtspr	SPRN_SRR1, r11
68	lis	r11, 1f@h
69	ori	r11, r11, 1f@l
70	mtspr	SPRN_SRR0, r11
71	mfspr	r11, SPRN_SPRG_SCRATCH2
72	rfi
73
74	.text
75\name\()_virt:
761:
77	stw	r11,GPR1(r1)
78	stw	r11,0(r1)
79	mr	r11, r1
80	stw	r10,_CCR(r11)		/* save registers */
81	stw	r12,GPR12(r11)
82	stw	r9,GPR9(r11)
83	mfspr	r10,SPRN_SPRG_SCRATCH0
84	mfspr	r12,SPRN_SPRG_SCRATCH1
85	stw	r10,GPR10(r11)
86	stw	r12,GPR11(r11)
87	mflr	r10
88	stw	r10,_LINK(r11)
89	mfspr	r12, SPRN_SPRG_THREAD
90	tovirt(r12, r12)
91	.if	\handle_dar_dsisr
92	lwz	r10, DAR(r12)
93	stw	r10, _DAR(r11)
94	lwz	r10, DSISR(r12)
95	stw	r10, _DSISR(r11)
96	.endif
97	lwz	r9, SRR1(r12)
98	lwz	r12, SRR0(r12)
99#ifdef CONFIG_40x
100	rlwinm	r9,r9,0,14,12		/* clear MSR_WE (necessary?) */
101#elif defined(CONFIG_PPC_8xx)
102	mtspr	SPRN_EID, r2		/* Set MSR_RI */
103#else
104	li	r10, MSR_KERNEL		/* can take exceptions */
105	mtmsr	r10			/* (except for mach check in rtas) */
106#endif
107	COMMON_EXCEPTION_PROLOG_END \trapno
108_ASM_NOKPROBE_SYMBOL(\name\()_virt)
109.endm
110
111.macro COMMON_EXCEPTION_PROLOG_END trapno
112	stw	r0,GPR0(r1)
113	lis	r10,STACK_FRAME_REGS_MARKER@ha /* exception frame marker */
114	addi	r10,r10,STACK_FRAME_REGS_MARKER@l
115	stw	r10,STACK_INT_FRAME_MARKER(r1)
116	li	r10, \trapno
117	stw	r10,_TRAP(r1)
118	SAVE_GPRS(3, 8, r1)
119	SAVE_NVGPRS(r1)
120	stw	r2,GPR2(r1)
121	stw	r12,_NIP(r1)
122	stw	r9,_MSR(r1)
123	mfctr	r10
124	mfspr	r2,SPRN_SPRG_THREAD
125	stw	r10,_CTR(r1)
126	tovirt(r2, r2)
127	mfspr	r10,SPRN_XER
128	addi	r2, r2, -THREAD
129	stw	r10,_XER(r1)
130	addi	r3,r1,STACK_INT_FRAME_REGS
131.endm
132
133.macro prepare_transfer_to_handler
134#ifdef CONFIG_PPC_BOOK3S_32
135	andi.	r12,r9,MSR_PR
136	bne	777f
137	bl	prepare_transfer_to_handler
138#ifdef CONFIG_PPC_KUEP
139	b	778f
140777:
141	bl	__kuep_lock
142778:
143#endif
144777:
145#endif
146.endm
147
148.macro SYSCALL_ENTRY trapno
149	mfspr	r9, SPRN_SRR1
150	mfspr	r12, SPRN_SRR0
151	LOAD_REG_IMMEDIATE(r11, MSR_KERNEL)		/* can take exceptions */
152	lis	r10, 1f@h
153	ori	r10, r10, 1f@l
154	mtspr	SPRN_SRR1, r11
155	mtspr	SPRN_SRR0, r10
156	mfspr	r10,SPRN_SPRG_THREAD
157	mr	r11, r1
158	lwz	r1,TASK_STACK-THREAD(r10)
159	tovirt(r10, r10)
160	addi	r1, r1, THREAD_SIZE - INT_FRAME_SIZE
161	rfi
1621:
163	stw	r12,_NIP(r1)
164	mfcr	r12
165	rlwinm	r12,r12,0,4,2	/* Clear SO bit in CR */
166	stw	r12,_CCR(r1)
167	b	transfer_to_syscall		/* jump to handler */
168.endm
169
170/*
171 * Note: code which follows this uses cr0.eq (set if from kernel),
172 * r11, r12 (SRR0), and r9 (SRR1).
173 *
174 * Note2: once we have set r1 we are in a position to take exceptions
175 * again, and we could thus set MSR:RI at that point.
176 */
177
178/*
179 * Exception vectors.
180 */
181#ifdef CONFIG_PPC_BOOK3S
182#define	START_EXCEPTION(n, label)		\
183	__HEAD;					\
184	. = n;					\
185	DO_KVM n;				\
186label:
187
188#else
189#define	START_EXCEPTION(n, label)		\
190	__HEAD;					\
191	. = n;					\
192label:
193
194#endif
195
196#define EXCEPTION(n, label, hdlr)		\
197	START_EXCEPTION(n, label)		\
198	EXCEPTION_PROLOG n label;		\
199	prepare_transfer_to_handler;		\
200	bl	hdlr;				\
201	b	interrupt_return
202
203.macro vmap_stack_overflow_exception
204	__HEAD
205vmap_stack_overflow:
206#ifdef CONFIG_SMP
207	mfspr	r1, SPRN_SPRG_THREAD
208	lwz	r1, TASK_CPU - THREAD(r1)
209	slwi	r1, r1, 3
210	addis	r1, r1, emergency_ctx-PAGE_OFFSET@ha
211#else
212	lis	r1, emergency_ctx-PAGE_OFFSET@ha
213#endif
214	lwz	r1, emergency_ctx-PAGE_OFFSET@l(r1)
215	addi	r1, r1, THREAD_SIZE - INT_FRAME_SIZE
216	EXCEPTION_PROLOG_2 0 vmap_stack_overflow
217	prepare_transfer_to_handler
218	bl	stack_overflow_exception
219	b	interrupt_return
220.endm
221
222#endif /* __HEAD_32_H__ */
223