1 /* SPDX-License-Identifier: GPL-2.0 */
5 #include <asm/ptrace.h> /* for STACK_FRAME_REGS_MARKER */
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.
13 .macro EXCEPTION_PROLOG handle_dar_dsisr
=0
14 EXCEPTION_PROLOG_0 handle_dar_dsisr
=\handle_dar_dsisr
16 EXCEPTION_PROLOG_2 handle_dar_dsisr
=\handle_dar_dsisr
19 .macro EXCEPTION_PROLOG_0 handle_dar_dsisr
=0
20 mtspr SPRN_SPRG_SCRATCH0
,r10
21 mtspr SPRN_SPRG_SCRATCH1
,r11
22 #ifdef CONFIG_VMAP_STACK
23 mfspr r10
, SPRN_SPRG_THREAD
33 mfspr r11
, SPRN_SRR1
/* check whether user or kernel */
34 #ifdef CONFIG_VMAP_STACK
38 andi
. r11
, r11
, MSR_PR
41 .macro EXCEPTION_PROLOG_1 for_rtas
=0
42 #ifdef CONFIG_VMAP_STACK
43 mtspr SPRN_SPRG_SCRATCH2
,r1
44 subi r1
, r1
, INT_FRAME_SIZE
/* use r1 if kernel */
46 mfspr r1
,SPRN_SPRG_THREAD
47 lwz r1
,TASK_STACK
-THREAD(r1
)
48 addi r1
, r1
, THREAD_SIZE
- INT_FRAME_SIZE
51 bt
32 - THREAD_ALIGN_SHIFT
, stack_overflow
53 subi r11
, r1
, INT_FRAME_SIZE
/* use r1 if kernel */
55 mfspr r11
,SPRN_SPRG_THREAD
56 lwz r11
,TASK_STACK
-THREAD(r11
)
57 addi r11
, r11
, THREAD_SIZE
- INT_FRAME_SIZE
62 .macro EXCEPTION_PROLOG_2 handle_dar_dsisr
=0
63 #ifdef CONFIG_VMAP_STACK
64 li r11
, MSR_KERNEL
& ~(MSR_IR
| MSR_RI
) /* can take DTLB miss */
67 mfspr r11
, SPRN_SPRG_SCRATCH2
74 tovirt(r1
, r11
) /* set new kernel sp */
76 stw r10
,_CCR(r11
) /* save registers */
79 mfspr r10
,SPRN_SPRG_SCRATCH0
80 mfspr r12
,SPRN_SPRG_SCRATCH1
85 #ifdef CONFIG_VMAP_STACK
86 mfspr r12
, SPRN_SPRG_THREAD
101 rlwinm r9
,r9
,0,14,12 /* clear MSR_WE (necessary?) */
103 #ifdef CONFIG_VMAP_STACK
104 li r10
, MSR_KERNEL
& ~MSR_IR
/* can take exceptions */
106 li r10
,MSR_KERNEL
& ~(MSR_IR
|MSR_DR
) /* can take exceptions */
108 mtmsr r10
/* (except for mach check in rtas) */
111 lis r10
,STACK_FRAME_REGS_MARKER@ha
/* exception frame marker */
112 addi r10
,r10
,STACK_FRAME_REGS_MARKER@l
118 .macro SYSCALL_ENTRY trapno
119 mfspr r12
,SPRN_SPRG_THREAD
121 #ifdef CONFIG_VMAP_STACK
125 andi
. r11
, r9
, MSR_PR
126 lwz r11
,TASK_STACK
-THREAD(r12
)
128 addi r11
, r11
, THREAD_SIZE
- INT_FRAME_SIZE
129 #ifdef CONFIG_VMAP_STACK
130 li r10
, MSR_KERNEL
& ~(MSR_IR
| MSR_RI
) /* can take DTLB miss */
134 tovirt_vmstack r12
, r12
135 tophys_novmstack r11
, r11
138 #ifdef CONFIG_VMAP_STACK
145 tovirt_novmstack r1
, r11
/* set new kernel sp */
148 rlwinm r10
,r10
,0,4,2 /* Clear SO bit in CR */
149 stw r10
,_CCR(r11
) /* save registers */
151 rlwinm r9
,r9
,0,14,12 /* clear MSR_WE (necessary?) */
153 #ifdef CONFIG_VMAP_STACK
154 LOAD_REG_IMMEDIATE(r10
, MSR_KERNEL
& ~MSR_IR
) /* can take exceptions */
156 LOAD_REG_IMMEDIATE(r10
, MSR_KERNEL
& ~(MSR_IR
|MSR_DR
)) /* can take exceptions */
158 mtmsr r10
/* (except for mach check in rtas) */
160 lis r10
,STACK_FRAME_REGS_MARKER@ha
/* exception frame marker */
162 addi r10
,r10
,STACK_FRAME_REGS_MARKER@l
170 addi r11
,r1
,STACK_FRAME_OVERHEAD
173 #if defined(CONFIG_40x)
174 /* Check to see if the dbcr0 register is set up to debug. Use the
175 internal debug mode bit to do this. */
176 lwz r12
,THREAD_DBCR0(r12
)
177 andis
. r12
,r12
,DBCR0_IDM@h
179 ACCOUNT_CPU_USER_ENTRY(r2
, r11
, r12
)
180 #if defined(CONFIG_40x)
182 /* From user and task is ptraced - load up global dbcr0 */
183 li r12
,-1 /* clear all pending debug events */
185 lis r11
,global_dbcr0@ha
187 addi r11
,r11
,global_dbcr0@l
196 tovirt_novmstack r2
, r2
/* set r2 to current */
197 lis r11
, transfer_to_syscall@h
198 ori r11
, r11
, transfer_to_syscall@l
199 #ifdef CONFIG_TRACE_IRQFLAGS
201 * If MSR is changing we need to keep interrupts disabled at this point
202 * otherwise we might risk taking an interrupt before we tell lockdep
205 LOAD_REG_IMMEDIATE(r10
, MSR_KERNEL
)
206 rlwimi r10
, r9
, 0, MSR_EE
208 LOAD_REG_IMMEDIATE(r10
, MSR_KERNEL
| MSR_EE
)
210 #if defined(CONFIG_PPC_8xx) && defined(CONFIG_PERF_EVENTS)
215 rfi
/* jump to handler, enable MMU */
217 b
. /* Prevent prefetch past rfi */
219 99: b ret_from_kernel_syscall
222 .macro save_dar_dsisr_on_stack reg1
, reg2
, sp
223 #ifndef CONFIG_VMAP_STACK
224 mfspr
\reg
1, SPRN_DAR
225 mfspr
\reg
2, SPRN_DSISR
227 stw
\reg
2, _DSISR(\sp
)
231 .macro get_and_save_dar_dsisr_on_stack reg1
, reg2
, sp
232 #ifdef CONFIG_VMAP_STACK
234 lwz
\reg
2, _DSISR(\sp
)
236 save_dar_dsisr_on_stack
\reg
1, \reg
2, \sp
240 .macro tovirt_vmstack dst
, src
241 #ifdef CONFIG_VMAP_STACK
250 .macro tovirt_novmstack dst
, src
251 #ifndef CONFIG_VMAP_STACK
260 .macro tophys_novmstack dst
, src
261 #ifndef CONFIG_VMAP_STACK
271 * Note: code which follows this uses cr0.eq (set if from kernel),
272 * r11, r12 (SRR0), and r9 (SRR1).
274 * Note2: once we have set r1 we are in a position to take exceptions
275 * again, and we could thus set MSR:RI at that point.
281 #ifdef CONFIG_PPC_BOOK3S
282 #define START_EXCEPTION(n, label) \
288 #define START_EXCEPTION(n, label) \
294 #define EXCEPTION(n, label, hdlr, xfer) \
295 START_EXCEPTION(n, label) \
297 addi r3,r1,STACK_FRAME_OVERHEAD; \
300 #define EXC_XFER_TEMPLATE(hdlr, trap, msr, tfer, ret) \
302 stw r10,_TRAP(r11); \
303 LOAD_REG_IMMEDIATE(r10, msr); \
308 #define EXC_XFER_STD(n, hdlr) \
309 EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, transfer_to_handler_full, \
310 ret_from_except_full)
312 #define EXC_XFER_LITE(n, hdlr) \
313 EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, transfer_to_handler, \
316 .macro vmap_stack_overflow_exception
317 #ifdef CONFIG_VMAP_STACK
319 mfspr r1
, SPRN_SPRG_THREAD
320 lwz r1
, TASK_CPU
- THREAD(r1
)
322 addis r1
, r1
, emergency_ctx@ha
324 lis r1
, emergency_ctx@ha
326 lwz r1
, emergency_ctx@
l(r1
)
329 lis r1
, init_thread_union@ha
330 addi r1
, r1
, init_thread_union@l
331 1: addi r1
, r1
, THREAD_SIZE
- INT_FRAME_SIZE
334 addi r3
, r1
, STACK_FRAME_OVERHEAD
335 EXC_XFER_STD(0, stack_overflow_exception
)
339 #endif /* __HEAD_32_H__ */