xref: /linux/arch/powerpc/kernel/entry_32.S (revision f7511d5f66f01fc451747b24e79f3ada7a3af9af)
1/*
2 *  PowerPC version
3 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
4 *  Rewritten by Cort Dougan (cort@fsmlabs.com) for PReP
5 *    Copyright (C) 1996 Cort Dougan <cort@fsmlabs.com>
6 *  Adapted for Power Macintosh by Paul Mackerras.
7 *  Low-level exception handlers and MMU support
8 *  rewritten by Paul Mackerras.
9 *    Copyright (C) 1996 Paul Mackerras.
10 *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
11 *
12 *  This file contains the system call entry code, context switch
13 *  code, and exception/interrupt return code for PowerPC.
14 *
15 *  This program is free software; you can redistribute it and/or
16 *  modify it under the terms of the GNU General Public License
17 *  as published by the Free Software Foundation; either version
18 *  2 of the License, or (at your option) any later version.
19 *
20 */
21
22#include <linux/errno.h>
23#include <linux/sys.h>
24#include <linux/threads.h>
25#include <asm/reg.h>
26#include <asm/page.h>
27#include <asm/mmu.h>
28#include <asm/cputable.h>
29#include <asm/thread_info.h>
30#include <asm/ppc_asm.h>
31#include <asm/asm-offsets.h>
32#include <asm/unistd.h>
33
34#undef SHOW_SYSCALLS
35#undef SHOW_SYSCALLS_TASK
36
37/*
38 * MSR_KERNEL is > 0x10000 on 4xx/Book-E since it include MSR_CE.
39 */
40#if MSR_KERNEL >= 0x10000
41#define LOAD_MSR_KERNEL(r, x)	lis r,(x)@h; ori r,r,(x)@l
42#else
43#define LOAD_MSR_KERNEL(r, x)	li r,(x)
44#endif
45
46#ifdef CONFIG_BOOKE
47#include "head_booke.h"
48#define TRANSFER_TO_HANDLER_EXC_LEVEL(exc_level)	\
49	mtspr	exc_level##_SPRG,r8;			\
50	BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);		\
51	lwz	r0,GPR10-INT_FRAME_SIZE(r8);		\
52	stw	r0,GPR10(r11);				\
53	lwz	r0,GPR11-INT_FRAME_SIZE(r8);		\
54	stw	r0,GPR11(r11);				\
55	mfspr	r8,exc_level##_SPRG
56
57	.globl	mcheck_transfer_to_handler
58mcheck_transfer_to_handler:
59	TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK)
60	b	transfer_to_handler_full
61
62	.globl	debug_transfer_to_handler
63debug_transfer_to_handler:
64	TRANSFER_TO_HANDLER_EXC_LEVEL(DEBUG)
65	b	transfer_to_handler_full
66
67	.globl	crit_transfer_to_handler
68crit_transfer_to_handler:
69	TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT)
70	/* fall through */
71#endif
72
73#ifdef CONFIG_40x
74	.globl	crit_transfer_to_handler
75crit_transfer_to_handler:
76	lwz	r0,crit_r10@l(0)
77	stw	r0,GPR10(r11)
78	lwz	r0,crit_r11@l(0)
79	stw	r0,GPR11(r11)
80	/* fall through */
81#endif
82
83/*
84 * This code finishes saving the registers to the exception frame
85 * and jumps to the appropriate handler for the exception, turning
86 * on address translation.
87 * Note that we rely on the caller having set cr0.eq iff the exception
88 * occurred in kernel mode (i.e. MSR:PR = 0).
89 */
90	.globl	transfer_to_handler_full
91transfer_to_handler_full:
92	SAVE_NVGPRS(r11)
93	/* fall through */
94
95	.globl	transfer_to_handler
96transfer_to_handler:
97	stw	r2,GPR2(r11)
98	stw	r12,_NIP(r11)
99	stw	r9,_MSR(r11)
100	andi.	r2,r9,MSR_PR
101	mfctr	r12
102	mfspr	r2,SPRN_XER
103	stw	r12,_CTR(r11)
104	stw	r2,_XER(r11)
105	mfspr	r12,SPRN_SPRG3
106	addi	r2,r12,-THREAD
107	tovirt(r2,r2)			/* set r2 to current */
108	beq	2f			/* if from user, fix up THREAD.regs */
109	addi	r11,r1,STACK_FRAME_OVERHEAD
110	stw	r11,PT_REGS(r12)
111#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
112	/* Check to see if the dbcr0 register is set up to debug.  Use the
113	   internal debug mode bit to do this. */
114	lwz	r12,THREAD_DBCR0(r12)
115	andis.	r12,r12,DBCR0_IDM@h
116	beq+	3f
117	/* From user and task is ptraced - load up global dbcr0 */
118	li	r12,-1			/* clear all pending debug events */
119	mtspr	SPRN_DBSR,r12
120	lis	r11,global_dbcr0@ha
121	tophys(r11,r11)
122	addi	r11,r11,global_dbcr0@l
123#ifdef CONFIG_SMP
124	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
125	lwz	r9,TI_CPU(r9)
126	slwi	r9,r9,3
127	add	r11,r11,r9
128#endif
129	lwz	r12,0(r11)
130	mtspr	SPRN_DBCR0,r12
131	lwz	r12,4(r11)
132	addi	r12,r12,-1
133	stw	r12,4(r11)
134#endif
135	b	3f
136
1372:	/* if from kernel, check interrupted DOZE/NAP mode and
138         * check for stack overflow
139         */
140	lwz	r9,KSP_LIMIT(r12)
141	cmplw	r1,r9			/* if r1 <= ksp_limit */
142	ble-	stack_ovf		/* then the kernel stack overflowed */
1435:
144#ifdef CONFIG_6xx
145	rlwinm	r9,r1,0,0,31-THREAD_SHIFT
146	tophys(r9,r9)			/* check local flags */
147	lwz	r12,TI_LOCAL_FLAGS(r9)
148	mtcrf	0x01,r12
149	bt-	31-TLF_NAPPING,4f
150#endif /* CONFIG_6xx */
151	.globl transfer_to_handler_cont
152transfer_to_handler_cont:
1533:
154	mflr	r9
155	lwz	r11,0(r9)		/* virtual address of handler */
156	lwz	r9,4(r9)		/* where to go when done */
157	mtspr	SPRN_SRR0,r11
158	mtspr	SPRN_SRR1,r10
159	mtlr	r9
160	SYNC
161	RFI				/* jump to handler, enable MMU */
162
163#ifdef CONFIG_6xx
1644:	rlwinm	r12,r12,0,~_TLF_NAPPING
165	stw	r12,TI_LOCAL_FLAGS(r9)
166	b	power_save_6xx_restore
167#endif
168
169/*
170 * On kernel stack overflow, load up an initial stack pointer
171 * and call StackOverflow(regs), which should not return.
172 */
173stack_ovf:
174	/* sometimes we use a statically-allocated stack, which is OK. */
175	lis	r12,_end@h
176	ori	r12,r12,_end@l
177	cmplw	r1,r12
178	ble	5b			/* r1 <= &_end is OK */
179	SAVE_NVGPRS(r11)
180	addi	r3,r1,STACK_FRAME_OVERHEAD
181	lis	r1,init_thread_union@ha
182	addi	r1,r1,init_thread_union@l
183	addi	r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
184	lis	r9,StackOverflow@ha
185	addi	r9,r9,StackOverflow@l
186	LOAD_MSR_KERNEL(r10,MSR_KERNEL)
187	FIX_SRR1(r10,r12)
188	mtspr	SPRN_SRR0,r9
189	mtspr	SPRN_SRR1,r10
190	SYNC
191	RFI
192
193/*
194 * Handle a system call.
195 */
196	.stabs	"arch/powerpc/kernel/",N_SO,0,0,0f
197	.stabs	"entry_32.S",N_SO,0,0,0f
1980:
199
200_GLOBAL(DoSyscall)
201	stw	r3,ORIG_GPR3(r1)
202	li	r12,0
203	stw	r12,RESULT(r1)
204	lwz	r11,_CCR(r1)	/* Clear SO bit in CR */
205	rlwinm	r11,r11,0,4,2
206	stw	r11,_CCR(r1)
207#ifdef SHOW_SYSCALLS
208	bl	do_show_syscall
209#endif /* SHOW_SYSCALLS */
210	rlwinm	r10,r1,0,0,(31-THREAD_SHIFT)	/* current_thread_info() */
211	lwz	r11,TI_FLAGS(r10)
212	andi.	r11,r11,_TIF_SYSCALL_T_OR_A
213	bne-	syscall_dotrace
214syscall_dotrace_cont:
215	cmplwi	0,r0,NR_syscalls
216	lis	r10,sys_call_table@h
217	ori	r10,r10,sys_call_table@l
218	slwi	r0,r0,2
219	bge-	66f
220	lwzx	r10,r10,r0	/* Fetch system call handler [ptr] */
221	mtlr	r10
222	addi	r9,r1,STACK_FRAME_OVERHEAD
223	PPC440EP_ERR42
224	blrl			/* Call handler */
225	.globl	ret_from_syscall
226ret_from_syscall:
227#ifdef SHOW_SYSCALLS
228	bl	do_show_syscall_exit
229#endif
230	mr	r6,r3
231	rlwinm	r12,r1,0,0,(31-THREAD_SHIFT)	/* current_thread_info() */
232	/* disable interrupts so current_thread_info()->flags can't change */
233	LOAD_MSR_KERNEL(r10,MSR_KERNEL)	/* doesn't include MSR_EE */
234	SYNC
235	MTMSRD(r10)
236	lwz	r9,TI_FLAGS(r12)
237	li	r8,-_LAST_ERRNO
238	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK)
239	bne-	syscall_exit_work
240	cmplw	0,r3,r8
241	blt+	syscall_exit_cont
242	lwz	r11,_CCR(r1)			/* Load CR */
243	neg	r3,r3
244	oris	r11,r11,0x1000	/* Set SO bit in CR */
245	stw	r11,_CCR(r1)
246syscall_exit_cont:
247#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
248	/* If the process has its own DBCR0 value, load it up.  The internal
249	   debug mode bit tells us that dbcr0 should be loaded. */
250	lwz	r0,THREAD+THREAD_DBCR0(r2)
251	andis.	r10,r0,DBCR0_IDM@h
252	bnel-	load_dbcr0
253#endif
254#ifdef CONFIG_44x
255	lis	r4,icache_44x_need_flush@ha
256	lwz	r5,icache_44x_need_flush@l(r4)
257	cmplwi	cr0,r5,0
258	bne-	2f
2591:
260#endif /* CONFIG_44x */
261BEGIN_FTR_SECTION
262	lwarx	r7,0,r1
263END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
264	stwcx.	r0,0,r1			/* to clear the reservation */
265	lwz	r4,_LINK(r1)
266	lwz	r5,_CCR(r1)
267	mtlr	r4
268	mtcr	r5
269	lwz	r7,_NIP(r1)
270	lwz	r8,_MSR(r1)
271	FIX_SRR1(r8, r0)
272	lwz	r2,GPR2(r1)
273	lwz	r1,GPR1(r1)
274	mtspr	SPRN_SRR0,r7
275	mtspr	SPRN_SRR1,r8
276	SYNC
277	RFI
278#ifdef CONFIG_44x
2792:	li	r7,0
280	iccci	r0,r0
281	stw	r7,icache_44x_need_flush@l(r4)
282	b	1b
283#endif  /* CONFIG_44x */
284
28566:	li	r3,-ENOSYS
286	b	ret_from_syscall
287
288	.globl	ret_from_fork
289ret_from_fork:
290	REST_NVGPRS(r1)
291	bl	schedule_tail
292	li	r3,0
293	b	ret_from_syscall
294
295/* Traced system call support */
296syscall_dotrace:
297	SAVE_NVGPRS(r1)
298	li	r0,0xc00
299	stw	r0,_TRAP(r1)
300	addi	r3,r1,STACK_FRAME_OVERHEAD
301	bl	do_syscall_trace_enter
302	lwz	r0,GPR0(r1)	/* Restore original registers */
303	lwz	r3,GPR3(r1)
304	lwz	r4,GPR4(r1)
305	lwz	r5,GPR5(r1)
306	lwz	r6,GPR6(r1)
307	lwz	r7,GPR7(r1)
308	lwz	r8,GPR8(r1)
309	REST_NVGPRS(r1)
310	b	syscall_dotrace_cont
311
312syscall_exit_work:
313	andi.	r0,r9,_TIF_RESTOREALL
314	beq+	0f
315	REST_NVGPRS(r1)
316	b	2f
3170:	cmplw	0,r3,r8
318	blt+	1f
319	andi.	r0,r9,_TIF_NOERROR
320	bne-	1f
321	lwz	r11,_CCR(r1)			/* Load CR */
322	neg	r3,r3
323	oris	r11,r11,0x1000	/* Set SO bit in CR */
324	stw	r11,_CCR(r1)
325
3261:	stw	r6,RESULT(r1)	/* Save result */
327	stw	r3,GPR3(r1)	/* Update return value */
3282:	andi.	r0,r9,(_TIF_PERSYSCALL_MASK)
329	beq	4f
330
331	/* Clear per-syscall TIF flags if any are set.  */
332
333	li	r11,_TIF_PERSYSCALL_MASK
334	addi	r12,r12,TI_FLAGS
3353:	lwarx	r8,0,r12
336	andc	r8,r8,r11
337#ifdef CONFIG_IBM405_ERR77
338	dcbt	0,r12
339#endif
340	stwcx.	r8,0,r12
341	bne-	3b
342	subi	r12,r12,TI_FLAGS
343
3444:	/* Anything which requires enabling interrupts? */
345	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
346	beq	ret_from_except
347
348	/* Re-enable interrupts */
349	ori	r10,r10,MSR_EE
350	SYNC
351	MTMSRD(r10)
352
353	/* Save NVGPRS if they're not saved already */
354	lwz	r4,_TRAP(r1)
355	andi.	r4,r4,1
356	beq	5f
357	SAVE_NVGPRS(r1)
358	li	r4,0xc00
359	stw	r4,_TRAP(r1)
3605:
361	addi	r3,r1,STACK_FRAME_OVERHEAD
362	bl	do_syscall_trace_leave
363	b	ret_from_except_full
364
365#ifdef SHOW_SYSCALLS
366do_show_syscall:
367#ifdef SHOW_SYSCALLS_TASK
368	lis	r11,show_syscalls_task@ha
369	lwz	r11,show_syscalls_task@l(r11)
370	cmp	0,r2,r11
371	bnelr
372#endif
373	stw	r31,GPR31(r1)
374	mflr	r31
375	lis	r3,7f@ha
376	addi	r3,r3,7f@l
377	lwz	r4,GPR0(r1)
378	lwz	r5,GPR3(r1)
379	lwz	r6,GPR4(r1)
380	lwz	r7,GPR5(r1)
381	lwz	r8,GPR6(r1)
382	lwz	r9,GPR7(r1)
383	bl	printk
384	lis	r3,77f@ha
385	addi	r3,r3,77f@l
386	lwz	r4,GPR8(r1)
387	mr	r5,r2
388	bl	printk
389	lwz	r0,GPR0(r1)
390	lwz	r3,GPR3(r1)
391	lwz	r4,GPR4(r1)
392	lwz	r5,GPR5(r1)
393	lwz	r6,GPR6(r1)
394	lwz	r7,GPR7(r1)
395	lwz	r8,GPR8(r1)
396	mtlr	r31
397	lwz	r31,GPR31(r1)
398	blr
399
400do_show_syscall_exit:
401#ifdef SHOW_SYSCALLS_TASK
402	lis	r11,show_syscalls_task@ha
403	lwz	r11,show_syscalls_task@l(r11)
404	cmp	0,r2,r11
405	bnelr
406#endif
407	stw	r31,GPR31(r1)
408	mflr	r31
409	stw	r3,RESULT(r1)	/* Save result */
410	mr	r4,r3
411	lis	r3,79f@ha
412	addi	r3,r3,79f@l
413	bl	printk
414	lwz	r3,RESULT(r1)
415	mtlr	r31
416	lwz	r31,GPR31(r1)
417	blr
418
4197:	.string	"syscall %d(%x, %x, %x, %x, %x, "
42077:	.string	"%x), current=%p\n"
42179:	.string	" -> %x\n"
422	.align	2,0
423
424#ifdef SHOW_SYSCALLS_TASK
425	.data
426	.globl	show_syscalls_task
427show_syscalls_task:
428	.long	-1
429	.text
430#endif
431#endif /* SHOW_SYSCALLS */
432
433/*
434 * The fork/clone functions need to copy the full register set into
435 * the child process. Therefore we need to save all the nonvolatile
436 * registers (r13 - r31) before calling the C code.
437 */
438	.globl	ppc_fork
439ppc_fork:
440	SAVE_NVGPRS(r1)
441	lwz	r0,_TRAP(r1)
442	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
443	stw	r0,_TRAP(r1)		/* register set saved */
444	b	sys_fork
445
446	.globl	ppc_vfork
447ppc_vfork:
448	SAVE_NVGPRS(r1)
449	lwz	r0,_TRAP(r1)
450	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
451	stw	r0,_TRAP(r1)		/* register set saved */
452	b	sys_vfork
453
454	.globl	ppc_clone
455ppc_clone:
456	SAVE_NVGPRS(r1)
457	lwz	r0,_TRAP(r1)
458	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
459	stw	r0,_TRAP(r1)		/* register set saved */
460	b	sys_clone
461
462	.globl	ppc_swapcontext
463ppc_swapcontext:
464	SAVE_NVGPRS(r1)
465	lwz	r0,_TRAP(r1)
466	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
467	stw	r0,_TRAP(r1)		/* register set saved */
468	b	sys_swapcontext
469
470/*
471 * Top-level page fault handling.
472 * This is in assembler because if do_page_fault tells us that
473 * it is a bad kernel page fault, we want to save the non-volatile
474 * registers before calling bad_page_fault.
475 */
476	.globl	handle_page_fault
477handle_page_fault:
478	stw	r4,_DAR(r1)
479	addi	r3,r1,STACK_FRAME_OVERHEAD
480	bl	do_page_fault
481	cmpwi	r3,0
482	beq+	ret_from_except
483	SAVE_NVGPRS(r1)
484	lwz	r0,_TRAP(r1)
485	clrrwi	r0,r0,1
486	stw	r0,_TRAP(r1)
487	mr	r5,r3
488	addi	r3,r1,STACK_FRAME_OVERHEAD
489	lwz	r4,_DAR(r1)
490	bl	bad_page_fault
491	b	ret_from_except_full
492
493/*
494 * This routine switches between two different tasks.  The process
495 * state of one is saved on its kernel stack.  Then the state
496 * of the other is restored from its kernel stack.  The memory
497 * management hardware is updated to the second process's state.
498 * Finally, we can return to the second process.
499 * On entry, r3 points to the THREAD for the current task, r4
500 * points to the THREAD for the new task.
501 *
502 * This routine is always called with interrupts disabled.
503 *
504 * Note: there are two ways to get to the "going out" portion
505 * of this code; either by coming in via the entry (_switch)
506 * or via "fork" which must set up an environment equivalent
507 * to the "_switch" path.  If you change this , you'll have to
508 * change the fork code also.
509 *
510 * The code which creates the new task context is in 'copy_thread'
511 * in arch/ppc/kernel/process.c
512 */
513_GLOBAL(_switch)
514	stwu	r1,-INT_FRAME_SIZE(r1)
515	mflr	r0
516	stw	r0,INT_FRAME_SIZE+4(r1)
517	/* r3-r12 are caller saved -- Cort */
518	SAVE_NVGPRS(r1)
519	stw	r0,_NIP(r1)	/* Return to switch caller */
520	mfmsr	r11
521	li	r0,MSR_FP	/* Disable floating-point */
522#ifdef CONFIG_ALTIVEC
523BEGIN_FTR_SECTION
524	oris	r0,r0,MSR_VEC@h	/* Disable altivec */
525	mfspr	r12,SPRN_VRSAVE	/* save vrsave register value */
526	stw	r12,THREAD+THREAD_VRSAVE(r2)
527END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
528#endif /* CONFIG_ALTIVEC */
529#ifdef CONFIG_SPE
530BEGIN_FTR_SECTION
531	oris	r0,r0,MSR_SPE@h	 /* Disable SPE */
532	mfspr	r12,SPRN_SPEFSCR /* save spefscr register value */
533	stw	r12,THREAD+THREAD_SPEFSCR(r2)
534END_FTR_SECTION_IFSET(CPU_FTR_SPE)
535#endif /* CONFIG_SPE */
536	and.	r0,r0,r11	/* FP or altivec or SPE enabled? */
537	beq+	1f
538	andc	r11,r11,r0
539	MTMSRD(r11)
540	isync
5411:	stw	r11,_MSR(r1)
542	mfcr	r10
543	stw	r10,_CCR(r1)
544	stw	r1,KSP(r3)	/* Set old stack pointer */
545
546#ifdef CONFIG_SMP
547	/* We need a sync somewhere here to make sure that if the
548	 * previous task gets rescheduled on another CPU, it sees all
549	 * stores it has performed on this one.
550	 */
551	sync
552#endif /* CONFIG_SMP */
553
554	tophys(r0,r4)
555	CLR_TOP32(r0)
556	mtspr	SPRN_SPRG3,r0	/* Update current THREAD phys addr */
557	lwz	r1,KSP(r4)	/* Load new stack pointer */
558
559	/* save the old current 'last' for return value */
560	mr	r3,r2
561	addi	r2,r4,-THREAD	/* Update current */
562
563#ifdef CONFIG_ALTIVEC
564BEGIN_FTR_SECTION
565	lwz	r0,THREAD+THREAD_VRSAVE(r2)
566	mtspr	SPRN_VRSAVE,r0		/* if G4, restore VRSAVE reg */
567END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
568#endif /* CONFIG_ALTIVEC */
569#ifdef CONFIG_SPE
570BEGIN_FTR_SECTION
571	lwz	r0,THREAD+THREAD_SPEFSCR(r2)
572	mtspr	SPRN_SPEFSCR,r0		/* restore SPEFSCR reg */
573END_FTR_SECTION_IFSET(CPU_FTR_SPE)
574#endif /* CONFIG_SPE */
575
576	lwz	r0,_CCR(r1)
577	mtcrf	0xFF,r0
578	/* r3-r12 are destroyed -- Cort */
579	REST_NVGPRS(r1)
580
581	lwz	r4,_NIP(r1)	/* Return to _switch caller in new task */
582	mtlr	r4
583	addi	r1,r1,INT_FRAME_SIZE
584	blr
585
586	.globl	fast_exception_return
587fast_exception_return:
588#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
589	andi.	r10,r9,MSR_RI		/* check for recoverable interrupt */
590	beq	1f			/* if not, we've got problems */
591#endif
592
5932:	REST_4GPRS(3, r11)
594	lwz	r10,_CCR(r11)
595	REST_GPR(1, r11)
596	mtcr	r10
597	lwz	r10,_LINK(r11)
598	mtlr	r10
599	REST_GPR(10, r11)
600	mtspr	SPRN_SRR1,r9
601	mtspr	SPRN_SRR0,r12
602	REST_GPR(9, r11)
603	REST_GPR(12, r11)
604	lwz	r11,GPR11(r11)
605	SYNC
606	RFI
607
608#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
609/* check if the exception happened in a restartable section */
6101:	lis	r3,exc_exit_restart_end@ha
611	addi	r3,r3,exc_exit_restart_end@l
612	cmplw	r12,r3
613	bge	3f
614	lis	r4,exc_exit_restart@ha
615	addi	r4,r4,exc_exit_restart@l
616	cmplw	r12,r4
617	blt	3f
618	lis	r3,fee_restarts@ha
619	tophys(r3,r3)
620	lwz	r5,fee_restarts@l(r3)
621	addi	r5,r5,1
622	stw	r5,fee_restarts@l(r3)
623	mr	r12,r4		/* restart at exc_exit_restart */
624	b	2b
625
626	.section .bss
627	.align	2
628fee_restarts:
629	.space	4
630	.previous
631
632/* aargh, a nonrecoverable interrupt, panic */
633/* aargh, we don't know which trap this is */
634/* but the 601 doesn't implement the RI bit, so assume it's OK */
6353:
636BEGIN_FTR_SECTION
637	b	2b
638END_FTR_SECTION_IFSET(CPU_FTR_601)
639	li	r10,-1
640	stw	r10,_TRAP(r11)
641	addi	r3,r1,STACK_FRAME_OVERHEAD
642	lis	r10,MSR_KERNEL@h
643	ori	r10,r10,MSR_KERNEL@l
644	bl	transfer_to_handler_full
645	.long	nonrecoverable_exception
646	.long	ret_from_except
647#endif
648
649	.globl	ret_from_except_full
650ret_from_except_full:
651	REST_NVGPRS(r1)
652	/* fall through */
653
654	.globl	ret_from_except
655ret_from_except:
656	/* Hard-disable interrupts so that current_thread_info()->flags
657	 * can't change between when we test it and when we return
658	 * from the interrupt. */
659	LOAD_MSR_KERNEL(r10,MSR_KERNEL)
660	SYNC			/* Some chip revs have problems here... */
661	MTMSRD(r10)		/* disable interrupts */
662
663	lwz	r3,_MSR(r1)	/* Returning to user mode? */
664	andi.	r0,r3,MSR_PR
665	beq	resume_kernel
666
667user_exc_return:		/* r10 contains MSR_KERNEL here */
668	/* Check current_thread_info()->flags */
669	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
670	lwz	r9,TI_FLAGS(r9)
671	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED)
672	bne	do_work
673
674restore_user:
675#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
676	/* Check whether this process has its own DBCR0 value.  The internal
677	   debug mode bit tells us that dbcr0 should be loaded. */
678	lwz	r0,THREAD+THREAD_DBCR0(r2)
679	andis.	r10,r0,DBCR0_IDM@h
680	bnel-	load_dbcr0
681#endif
682
683#ifdef CONFIG_PREEMPT
684	b	restore
685
686/* N.B. the only way to get here is from the beq following ret_from_except. */
687resume_kernel:
688	/* check current_thread_info->preempt_count */
689	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
690	lwz	r0,TI_PREEMPT(r9)
691	cmpwi	0,r0,0		/* if non-zero, just restore regs and return */
692	bne	restore
693	lwz	r0,TI_FLAGS(r9)
694	andi.	r0,r0,_TIF_NEED_RESCHED
695	beq+	restore
696	andi.	r0,r3,MSR_EE	/* interrupts off? */
697	beq	restore		/* don't schedule if so */
6981:	bl	preempt_schedule_irq
699	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
700	lwz	r3,TI_FLAGS(r9)
701	andi.	r0,r3,_TIF_NEED_RESCHED
702	bne-	1b
703#else
704resume_kernel:
705#endif /* CONFIG_PREEMPT */
706
707	/* interrupts are hard-disabled at this point */
708restore:
709#ifdef CONFIG_44x
710	lis	r4,icache_44x_need_flush@ha
711	lwz	r5,icache_44x_need_flush@l(r4)
712	cmplwi	cr0,r5,0
713	beq+	1f
714	li	r6,0
715	iccci	r0,r0
716	stw	r6,icache_44x_need_flush@l(r4)
7171:
718#endif  /* CONFIG_44x */
719	lwz	r0,GPR0(r1)
720	lwz	r2,GPR2(r1)
721	REST_4GPRS(3, r1)
722	REST_2GPRS(7, r1)
723
724	lwz	r10,_XER(r1)
725	lwz	r11,_CTR(r1)
726	mtspr	SPRN_XER,r10
727	mtctr	r11
728
729	PPC405_ERR77(0,r1)
730BEGIN_FTR_SECTION
731	lwarx	r11,0,r1
732END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
733	stwcx.	r0,0,r1			/* to clear the reservation */
734
735#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
736	lwz	r9,_MSR(r1)
737	andi.	r10,r9,MSR_RI		/* check if this exception occurred */
738	beql	nonrecoverable		/* at a bad place (MSR:RI = 0) */
739
740	lwz	r10,_CCR(r1)
741	lwz	r11,_LINK(r1)
742	mtcrf	0xFF,r10
743	mtlr	r11
744
745	/*
746	 * Once we put values in SRR0 and SRR1, we are in a state
747	 * where exceptions are not recoverable, since taking an
748	 * exception will trash SRR0 and SRR1.  Therefore we clear the
749	 * MSR:RI bit to indicate this.  If we do take an exception,
750	 * we can't return to the point of the exception but we
751	 * can restart the exception exit path at the label
752	 * exc_exit_restart below.  -- paulus
753	 */
754	LOAD_MSR_KERNEL(r10,MSR_KERNEL & ~MSR_RI)
755	SYNC
756	MTMSRD(r10)		/* clear the RI bit */
757	.globl exc_exit_restart
758exc_exit_restart:
759	lwz	r9,_MSR(r1)
760	lwz	r12,_NIP(r1)
761	FIX_SRR1(r9,r10)
762	mtspr	SPRN_SRR0,r12
763	mtspr	SPRN_SRR1,r9
764	REST_4GPRS(9, r1)
765	lwz	r1,GPR1(r1)
766	.globl exc_exit_restart_end
767exc_exit_restart_end:
768	SYNC
769	RFI
770
771#else /* !(CONFIG_4xx || CONFIG_BOOKE) */
772	/*
773	 * This is a bit different on 4xx/Book-E because it doesn't have
774	 * the RI bit in the MSR.
775	 * The TLB miss handler checks if we have interrupted
776	 * the exception exit path and restarts it if so
777	 * (well maybe one day it will... :).
778	 */
779	lwz	r11,_LINK(r1)
780	mtlr	r11
781	lwz	r10,_CCR(r1)
782	mtcrf	0xff,r10
783	REST_2GPRS(9, r1)
784	.globl exc_exit_restart
785exc_exit_restart:
786	lwz	r11,_NIP(r1)
787	lwz	r12,_MSR(r1)
788exc_exit_start:
789	mtspr	SPRN_SRR0,r11
790	mtspr	SPRN_SRR1,r12
791	REST_2GPRS(11, r1)
792	lwz	r1,GPR1(r1)
793	.globl exc_exit_restart_end
794exc_exit_restart_end:
795	PPC405_ERR77_SYNC
796	rfi
797	b	.			/* prevent prefetch past rfi */
798
799/*
800 * Returning from a critical interrupt in user mode doesn't need
801 * to be any different from a normal exception.  For a critical
802 * interrupt in the kernel, we just return (without checking for
803 * preemption) since the interrupt may have happened at some crucial
804 * place (e.g. inside the TLB miss handler), and because we will be
805 * running with r1 pointing into critical_stack, not the current
806 * process's kernel stack (and therefore current_thread_info() will
807 * give the wrong answer).
808 * We have to restore various SPRs that may have been in use at the
809 * time of the critical interrupt.
810 *
811 */
812#ifdef CONFIG_40x
813#define PPC_40x_TURN_OFF_MSR_DR						    \
814	/* avoid any possible TLB misses here by turning off MSR.DR, we	    \
815	 * assume the instructions here are mapped by a pinned TLB entry */ \
816	li	r10,MSR_IR;						    \
817	mtmsr	r10;							    \
818	isync;								    \
819	tophys(r1, r1);
820#else
821#define PPC_40x_TURN_OFF_MSR_DR
822#endif
823
824#define RET_FROM_EXC_LEVEL(exc_lvl_srr0, exc_lvl_srr1, exc_lvl_rfi)	\
825	REST_NVGPRS(r1);						\
826	lwz	r3,_MSR(r1);						\
827	andi.	r3,r3,MSR_PR;						\
828	LOAD_MSR_KERNEL(r10,MSR_KERNEL);				\
829	bne	user_exc_return;					\
830	lwz	r0,GPR0(r1);						\
831	lwz	r2,GPR2(r1);						\
832	REST_4GPRS(3, r1);						\
833	REST_2GPRS(7, r1);						\
834	lwz	r10,_XER(r1);						\
835	lwz	r11,_CTR(r1);						\
836	mtspr	SPRN_XER,r10;						\
837	mtctr	r11;							\
838	PPC405_ERR77(0,r1);						\
839	stwcx.	r0,0,r1;		/* to clear the reservation */	\
840	lwz	r11,_LINK(r1);						\
841	mtlr	r11;							\
842	lwz	r10,_CCR(r1);						\
843	mtcrf	0xff,r10;						\
844	PPC_40x_TURN_OFF_MSR_DR;					\
845	lwz	r9,_DEAR(r1);						\
846	lwz	r10,_ESR(r1);						\
847	mtspr	SPRN_DEAR,r9;						\
848	mtspr	SPRN_ESR,r10;						\
849	lwz	r11,_NIP(r1);						\
850	lwz	r12,_MSR(r1);						\
851	mtspr	exc_lvl_srr0,r11;					\
852	mtspr	exc_lvl_srr1,r12;					\
853	lwz	r9,GPR9(r1);						\
854	lwz	r12,GPR12(r1);						\
855	lwz	r10,GPR10(r1);						\
856	lwz	r11,GPR11(r1);						\
857	lwz	r1,GPR1(r1);						\
858	PPC405_ERR77_SYNC;						\
859	exc_lvl_rfi;							\
860	b	.;		/* prevent prefetch past exc_lvl_rfi */
861
862	.globl	ret_from_crit_exc
863ret_from_crit_exc:
864	RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
865
866#ifdef CONFIG_BOOKE
867	.globl	ret_from_debug_exc
868ret_from_debug_exc:
869	RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI)
870
871	.globl	ret_from_mcheck_exc
872ret_from_mcheck_exc:
873	RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI)
874#endif /* CONFIG_BOOKE */
875
876/*
877 * Load the DBCR0 value for a task that is being ptraced,
878 * having first saved away the global DBCR0.  Note that r0
879 * has the dbcr0 value to set upon entry to this.
880 */
881load_dbcr0:
882	mfmsr	r10		/* first disable debug exceptions */
883	rlwinm	r10,r10,0,~MSR_DE
884	mtmsr	r10
885	isync
886	mfspr	r10,SPRN_DBCR0
887	lis	r11,global_dbcr0@ha
888	addi	r11,r11,global_dbcr0@l
889#ifdef CONFIG_SMP
890	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
891	lwz	r9,TI_CPU(r9)
892	slwi	r9,r9,3
893	add	r11,r11,r9
894#endif
895	stw	r10,0(r11)
896	mtspr	SPRN_DBCR0,r0
897	lwz	r10,4(r11)
898	addi	r10,r10,1
899	stw	r10,4(r11)
900	li	r11,-1
901	mtspr	SPRN_DBSR,r11	/* clear all pending debug events */
902	blr
903
904	.section .bss
905	.align	4
906global_dbcr0:
907	.space	8*NR_CPUS
908	.previous
909#endif /* !(CONFIG_4xx || CONFIG_BOOKE) */
910
911do_work:			/* r10 contains MSR_KERNEL here */
912	andi.	r0,r9,_TIF_NEED_RESCHED
913	beq	do_user_signal
914
915do_resched:			/* r10 contains MSR_KERNEL here */
916	ori	r10,r10,MSR_EE
917	SYNC
918	MTMSRD(r10)		/* hard-enable interrupts */
919	bl	schedule
920recheck:
921	LOAD_MSR_KERNEL(r10,MSR_KERNEL)
922	SYNC
923	MTMSRD(r10)		/* disable interrupts */
924	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
925	lwz	r9,TI_FLAGS(r9)
926	andi.	r0,r9,_TIF_NEED_RESCHED
927	bne-	do_resched
928	andi.	r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK
929	beq	restore_user
930do_user_signal:			/* r10 contains MSR_KERNEL here */
931	ori	r10,r10,MSR_EE
932	SYNC
933	MTMSRD(r10)		/* hard-enable interrupts */
934	/* save r13-r31 in the exception frame, if not already done */
935	lwz	r3,_TRAP(r1)
936	andi.	r0,r3,1
937	beq	2f
938	SAVE_NVGPRS(r1)
939	rlwinm	r3,r3,0,0,30
940	stw	r3,_TRAP(r1)
9412:	li	r3,0
942	addi	r4,r1,STACK_FRAME_OVERHEAD
943	bl	do_signal
944	REST_NVGPRS(r1)
945	b	recheck
946
947/*
948 * We come here when we are at the end of handling an exception
949 * that occurred at a place where taking an exception will lose
950 * state information, such as the contents of SRR0 and SRR1.
951 */
952nonrecoverable:
953	lis	r10,exc_exit_restart_end@ha
954	addi	r10,r10,exc_exit_restart_end@l
955	cmplw	r12,r10
956	bge	3f
957	lis	r11,exc_exit_restart@ha
958	addi	r11,r11,exc_exit_restart@l
959	cmplw	r12,r11
960	blt	3f
961	lis	r10,ee_restarts@ha
962	lwz	r12,ee_restarts@l(r10)
963	addi	r12,r12,1
964	stw	r12,ee_restarts@l(r10)
965	mr	r12,r11		/* restart at exc_exit_restart */
966	blr
9673:	/* OK, we can't recover, kill this process */
968	/* but the 601 doesn't implement the RI bit, so assume it's OK */
969BEGIN_FTR_SECTION
970	blr
971END_FTR_SECTION_IFSET(CPU_FTR_601)
972	lwz	r3,_TRAP(r1)
973	andi.	r0,r3,1
974	beq	4f
975	SAVE_NVGPRS(r1)
976	rlwinm	r3,r3,0,0,30
977	stw	r3,_TRAP(r1)
9784:	addi	r3,r1,STACK_FRAME_OVERHEAD
979	bl	nonrecoverable_exception
980	/* shouldn't return */
981	b	4b
982
983	.section .bss
984	.align	2
985ee_restarts:
986	.space	4
987	.previous
988
989/*
990 * PROM code for specific machines follows.  Put it
991 * here so it's easy to add arch-specific sections later.
992 * -- Cort
993 */
994#ifdef CONFIG_PPC_RTAS
995/*
996 * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
997 * called with the MMU off.
998 */
999_GLOBAL(enter_rtas)
1000	stwu	r1,-INT_FRAME_SIZE(r1)
1001	mflr	r0
1002	stw	r0,INT_FRAME_SIZE+4(r1)
1003	LOAD_REG_ADDR(r4, rtas)
1004	lis	r6,1f@ha	/* physical return address for rtas */
1005	addi	r6,r6,1f@l
1006	tophys(r6,r6)
1007	tophys(r7,r1)
1008	lwz	r8,RTASENTRY(r4)
1009	lwz	r4,RTASBASE(r4)
1010	mfmsr	r9
1011	stw	r9,8(r1)
1012	LOAD_MSR_KERNEL(r0,MSR_KERNEL)
1013	SYNC			/* disable interrupts so SRR0/1 */
1014	MTMSRD(r0)		/* don't get trashed */
1015	li	r9,MSR_KERNEL & ~(MSR_IR|MSR_DR)
1016	mtlr	r6
1017	mtspr	SPRN_SPRG2,r7
1018	mtspr	SPRN_SRR0,r8
1019	mtspr	SPRN_SRR1,r9
1020	RFI
10211:	tophys(r9,r1)
1022	lwz	r8,INT_FRAME_SIZE+4(r9)	/* get return address */
1023	lwz	r9,8(r9)	/* original msr value */
1024	FIX_SRR1(r9,r0)
1025	addi	r1,r1,INT_FRAME_SIZE
1026	li	r0,0
1027	mtspr	SPRN_SPRG2,r0
1028	mtspr	SPRN_SRR0,r8
1029	mtspr	SPRN_SRR1,r9
1030	RFI			/* return to caller */
1031
1032	.globl	machine_check_in_rtas
1033machine_check_in_rtas:
1034	twi	31,0,0
1035	/* XXX load up BATs and panic */
1036
1037#endif /* CONFIG_PPC_RTAS */
1038