[POWERPC] Add cpu feature for SPE handling
[deliverable/linux.git] / arch / powerpc / kernel / entry_32.S
CommitLineData
9994a338
PM
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
9994a338
PM
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 single-step bit to do this. */
114 lwz r12,THREAD_DBCR0(r12)
115 andis. r12,r12,DBCR0_IC@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 lwz r12,0(r11)
124 mtspr SPRN_DBCR0,r12
125 lwz r12,4(r11)
126 addi r12,r12,-1
127 stw r12,4(r11)
128#endif
129 b 3f
f39224a8 130
9994a338
PM
1312: /* if from kernel, check interrupted DOZE/NAP mode and
132 * check for stack overflow
133 */
f39224a8
PM
134 lwz r9,THREAD_INFO-THREAD(r12)
135 cmplw r1,r9 /* if r1 <= current->thread_info */
136 ble- stack_ovf /* then the kernel stack overflowed */
1375:
9994a338 138#ifdef CONFIG_6xx
f39224a8
PM
139 tophys(r9,r9) /* check local flags */
140 lwz r12,TI_LOCAL_FLAGS(r9)
141 mtcrf 0x01,r12
142 bt- 31-TLF_NAPPING,4f
9994a338
PM
143#endif /* CONFIG_6xx */
144 .globl transfer_to_handler_cont
145transfer_to_handler_cont:
9994a338
PM
1463:
147 mflr r9
148 lwz r11,0(r9) /* virtual address of handler */
149 lwz r9,4(r9) /* where to go when done */
9994a338
PM
150 mtspr SPRN_SRR0,r11
151 mtspr SPRN_SRR1,r10
152 mtlr r9
153 SYNC
154 RFI /* jump to handler, enable MMU */
155
f39224a8
PM
156#ifdef CONFIG_6xx
1574: rlwinm r12,r12,0,~_TLF_NAPPING
158 stw r12,TI_LOCAL_FLAGS(r9)
159 b power_save_6xx_restore
a0652fc9
PM
160#endif
161
9994a338
PM
162/*
163 * On kernel stack overflow, load up an initial stack pointer
164 * and call StackOverflow(regs), which should not return.
165 */
166stack_ovf:
167 /* sometimes we use a statically-allocated stack, which is OK. */
f39224a8
PM
168 lis r12,_end@h
169 ori r12,r12,_end@l
170 cmplw r1,r12
171 ble 5b /* r1 <= &_end is OK */
9994a338
PM
172 SAVE_NVGPRS(r11)
173 addi r3,r1,STACK_FRAME_OVERHEAD
174 lis r1,init_thread_union@ha
175 addi r1,r1,init_thread_union@l
176 addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
177 lis r9,StackOverflow@ha
178 addi r9,r9,StackOverflow@l
179 LOAD_MSR_KERNEL(r10,MSR_KERNEL)
180 FIX_SRR1(r10,r12)
181 mtspr SPRN_SRR0,r9
182 mtspr SPRN_SRR1,r10
183 SYNC
184 RFI
185
186/*
187 * Handle a system call.
188 */
189 .stabs "arch/powerpc/kernel/",N_SO,0,0,0f
190 .stabs "entry_32.S",N_SO,0,0,0f
1910:
192
193_GLOBAL(DoSyscall)
9994a338
PM
194 stw r3,ORIG_GPR3(r1)
195 li r12,0
196 stw r12,RESULT(r1)
197 lwz r11,_CCR(r1) /* Clear SO bit in CR */
198 rlwinm r11,r11,0,4,2
199 stw r11,_CCR(r1)
200#ifdef SHOW_SYSCALLS
201 bl do_show_syscall
202#endif /* SHOW_SYSCALLS */
6cb7bfeb 203 rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
9994a338
PM
204 lwz r11,TI_FLAGS(r10)
205 andi. r11,r11,_TIF_SYSCALL_T_OR_A
206 bne- syscall_dotrace
207syscall_dotrace_cont:
208 cmplwi 0,r0,NR_syscalls
209 lis r10,sys_call_table@h
210 ori r10,r10,sys_call_table@l
211 slwi r0,r0,2
212 bge- 66f
213 lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
214 mtlr r10
215 addi r9,r1,STACK_FRAME_OVERHEAD
216 PPC440EP_ERR42
217 blrl /* Call handler */
218 .globl ret_from_syscall
219ret_from_syscall:
220#ifdef SHOW_SYSCALLS
221 bl do_show_syscall_exit
222#endif
223 mr r6,r3
6cb7bfeb 224 rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
9994a338 225 /* disable interrupts so current_thread_info()->flags can't change */
401d1f02 226 LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
9994a338
PM
227 SYNC
228 MTMSRD(r10)
229 lwz r9,TI_FLAGS(r12)
401d1f02 230 li r8,-_LAST_ERRNO
1bd79336 231 andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK)
9994a338 232 bne- syscall_exit_work
401d1f02
DW
233 cmplw 0,r3,r8
234 blt+ syscall_exit_cont
235 lwz r11,_CCR(r1) /* Load CR */
236 neg r3,r3
237 oris r11,r11,0x1000 /* Set SO bit in CR */
238 stw r11,_CCR(r1)
9994a338
PM
239syscall_exit_cont:
240#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
241 /* If the process has its own DBCR0 value, load it up. The single
242 step bit tells us that dbcr0 should be loaded. */
243 lwz r0,THREAD+THREAD_DBCR0(r2)
244 andis. r10,r0,DBCR0_IC@h
245 bnel- load_dbcr0
246#endif
247 stwcx. r0,0,r1 /* to clear the reservation */
248 lwz r4,_LINK(r1)
249 lwz r5,_CCR(r1)
250 mtlr r4
251 mtcr r5
252 lwz r7,_NIP(r1)
253 lwz r8,_MSR(r1)
254 FIX_SRR1(r8, r0)
255 lwz r2,GPR2(r1)
256 lwz r1,GPR1(r1)
257 mtspr SPRN_SRR0,r7
258 mtspr SPRN_SRR1,r8
259 SYNC
260 RFI
261
26266: li r3,-ENOSYS
263 b ret_from_syscall
264
265 .globl ret_from_fork
266ret_from_fork:
267 REST_NVGPRS(r1)
268 bl schedule_tail
269 li r3,0
270 b ret_from_syscall
271
272/* Traced system call support */
273syscall_dotrace:
274 SAVE_NVGPRS(r1)
275 li r0,0xc00
d73e0c99 276 stw r0,_TRAP(r1)
9994a338
PM
277 addi r3,r1,STACK_FRAME_OVERHEAD
278 bl do_syscall_trace_enter
279 lwz r0,GPR0(r1) /* Restore original registers */
280 lwz r3,GPR3(r1)
281 lwz r4,GPR4(r1)
282 lwz r5,GPR5(r1)
283 lwz r6,GPR6(r1)
284 lwz r7,GPR7(r1)
285 lwz r8,GPR8(r1)
286 REST_NVGPRS(r1)
287 b syscall_dotrace_cont
288
289syscall_exit_work:
401d1f02 290 andi. r0,r9,_TIF_RESTOREALL
1bd79336
PM
291 beq+ 0f
292 REST_NVGPRS(r1)
293 b 2f
2940: cmplw 0,r3,r8
401d1f02
DW
295 blt+ 1f
296 andi. r0,r9,_TIF_NOERROR
297 bne- 1f
298 lwz r11,_CCR(r1) /* Load CR */
299 neg r3,r3
300 oris r11,r11,0x1000 /* Set SO bit in CR */
301 stw r11,_CCR(r1)
302
3031: stw r6,RESULT(r1) /* Save result */
9994a338 304 stw r3,GPR3(r1) /* Update return value */
401d1f02
DW
3052: andi. r0,r9,(_TIF_PERSYSCALL_MASK)
306 beq 4f
307
1bd79336 308 /* Clear per-syscall TIF flags if any are set. */
401d1f02
DW
309
310 li r11,_TIF_PERSYSCALL_MASK
311 addi r12,r12,TI_FLAGS
3123: lwarx r8,0,r12
313 andc r8,r8,r11
314#ifdef CONFIG_IBM405_ERR77
315 dcbt 0,r12
316#endif
317 stwcx. r8,0,r12
318 bne- 3b
319 subi r12,r12,TI_FLAGS
320
3214: /* Anything which requires enabling interrupts? */
1bd79336
PM
322 andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
323 beq ret_from_except
324
325 /* Re-enable interrupts */
326 ori r10,r10,MSR_EE
327 SYNC
328 MTMSRD(r10)
401d1f02
DW
329
330 /* Save NVGPRS if they're not saved already */
d73e0c99 331 lwz r4,_TRAP(r1)
9994a338 332 andi. r4,r4,1
401d1f02 333 beq 5f
9994a338
PM
334 SAVE_NVGPRS(r1)
335 li r4,0xc00
d73e0c99 336 stw r4,_TRAP(r1)
1bd79336 3375:
9994a338
PM
338 addi r3,r1,STACK_FRAME_OVERHEAD
339 bl do_syscall_trace_leave
1bd79336 340 b ret_from_except_full
9994a338
PM
341
342#ifdef SHOW_SYSCALLS
343do_show_syscall:
344#ifdef SHOW_SYSCALLS_TASK
345 lis r11,show_syscalls_task@ha
346 lwz r11,show_syscalls_task@l(r11)
347 cmp 0,r2,r11
348 bnelr
349#endif
350 stw r31,GPR31(r1)
351 mflr r31
352 lis r3,7f@ha
353 addi r3,r3,7f@l
354 lwz r4,GPR0(r1)
355 lwz r5,GPR3(r1)
356 lwz r6,GPR4(r1)
357 lwz r7,GPR5(r1)
358 lwz r8,GPR6(r1)
359 lwz r9,GPR7(r1)
360 bl printk
361 lis r3,77f@ha
362 addi r3,r3,77f@l
363 lwz r4,GPR8(r1)
364 mr r5,r2
365 bl printk
366 lwz r0,GPR0(r1)
367 lwz r3,GPR3(r1)
368 lwz r4,GPR4(r1)
369 lwz r5,GPR5(r1)
370 lwz r6,GPR6(r1)
371 lwz r7,GPR7(r1)
372 lwz r8,GPR8(r1)
373 mtlr r31
374 lwz r31,GPR31(r1)
375 blr
376
377do_show_syscall_exit:
378#ifdef SHOW_SYSCALLS_TASK
379 lis r11,show_syscalls_task@ha
380 lwz r11,show_syscalls_task@l(r11)
381 cmp 0,r2,r11
382 bnelr
383#endif
384 stw r31,GPR31(r1)
385 mflr r31
386 stw r3,RESULT(r1) /* Save result */
387 mr r4,r3
388 lis r3,79f@ha
389 addi r3,r3,79f@l
390 bl printk
391 lwz r3,RESULT(r1)
392 mtlr r31
393 lwz r31,GPR31(r1)
394 blr
395
3967: .string "syscall %d(%x, %x, %x, %x, %x, "
39777: .string "%x), current=%p\n"
39879: .string " -> %x\n"
399 .align 2,0
400
401#ifdef SHOW_SYSCALLS_TASK
402 .data
403 .globl show_syscalls_task
404show_syscalls_task:
405 .long -1
406 .text
407#endif
408#endif /* SHOW_SYSCALLS */
409
410/*
401d1f02
DW
411 * The fork/clone functions need to copy the full register set into
412 * the child process. Therefore we need to save all the nonvolatile
413 * registers (r13 - r31) before calling the C code.
9994a338 414 */
9994a338
PM
415 .globl ppc_fork
416ppc_fork:
417 SAVE_NVGPRS(r1)
d73e0c99 418 lwz r0,_TRAP(r1)
9994a338 419 rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
d73e0c99 420 stw r0,_TRAP(r1) /* register set saved */
9994a338
PM
421 b sys_fork
422
423 .globl ppc_vfork
424ppc_vfork:
425 SAVE_NVGPRS(r1)
d73e0c99 426 lwz r0,_TRAP(r1)
9994a338 427 rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
d73e0c99 428 stw r0,_TRAP(r1) /* register set saved */
9994a338
PM
429 b sys_vfork
430
431 .globl ppc_clone
432ppc_clone:
433 SAVE_NVGPRS(r1)
d73e0c99 434 lwz r0,_TRAP(r1)
9994a338 435 rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
d73e0c99 436 stw r0,_TRAP(r1) /* register set saved */
9994a338
PM
437 b sys_clone
438
1bd79336
PM
439 .globl ppc_swapcontext
440ppc_swapcontext:
441 SAVE_NVGPRS(r1)
442 lwz r0,_TRAP(r1)
443 rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
444 stw r0,_TRAP(r1) /* register set saved */
445 b sys_swapcontext
446
9994a338
PM
447/*
448 * Top-level page fault handling.
449 * This is in assembler because if do_page_fault tells us that
450 * it is a bad kernel page fault, we want to save the non-volatile
451 * registers before calling bad_page_fault.
452 */
453 .globl handle_page_fault
454handle_page_fault:
455 stw r4,_DAR(r1)
456 addi r3,r1,STACK_FRAME_OVERHEAD
457 bl do_page_fault
458 cmpwi r3,0
459 beq+ ret_from_except
460 SAVE_NVGPRS(r1)
d73e0c99 461 lwz r0,_TRAP(r1)
9994a338 462 clrrwi r0,r0,1
d73e0c99 463 stw r0,_TRAP(r1)
9994a338
PM
464 mr r5,r3
465 addi r3,r1,STACK_FRAME_OVERHEAD
466 lwz r4,_DAR(r1)
467 bl bad_page_fault
468 b ret_from_except_full
469
470/*
471 * This routine switches between two different tasks. The process
472 * state of one is saved on its kernel stack. Then the state
473 * of the other is restored from its kernel stack. The memory
474 * management hardware is updated to the second process's state.
475 * Finally, we can return to the second process.
476 * On entry, r3 points to the THREAD for the current task, r4
477 * points to the THREAD for the new task.
478 *
479 * This routine is always called with interrupts disabled.
480 *
481 * Note: there are two ways to get to the "going out" portion
482 * of this code; either by coming in via the entry (_switch)
483 * or via "fork" which must set up an environment equivalent
484 * to the "_switch" path. If you change this , you'll have to
485 * change the fork code also.
486 *
487 * The code which creates the new task context is in 'copy_thread'
488 * in arch/ppc/kernel/process.c
489 */
490_GLOBAL(_switch)
491 stwu r1,-INT_FRAME_SIZE(r1)
492 mflr r0
493 stw r0,INT_FRAME_SIZE+4(r1)
494 /* r3-r12 are caller saved -- Cort */
495 SAVE_NVGPRS(r1)
496 stw r0,_NIP(r1) /* Return to switch caller */
497 mfmsr r11
498 li r0,MSR_FP /* Disable floating-point */
499#ifdef CONFIG_ALTIVEC
500BEGIN_FTR_SECTION
501 oris r0,r0,MSR_VEC@h /* Disable altivec */
502 mfspr r12,SPRN_VRSAVE /* save vrsave register value */
503 stw r12,THREAD+THREAD_VRSAVE(r2)
504END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
505#endif /* CONFIG_ALTIVEC */
506#ifdef CONFIG_SPE
5e14d21e 507BEGIN_FTR_SECTION
9994a338
PM
508 oris r0,r0,MSR_SPE@h /* Disable SPE */
509 mfspr r12,SPRN_SPEFSCR /* save spefscr register value */
510 stw r12,THREAD+THREAD_SPEFSCR(r2)
5e14d21e 511END_FTR_SECTION_IFSET(CPU_FTR_SPE)
9994a338
PM
512#endif /* CONFIG_SPE */
513 and. r0,r0,r11 /* FP or altivec or SPE enabled? */
514 beq+ 1f
515 andc r11,r11,r0
516 MTMSRD(r11)
517 isync
5181: stw r11,_MSR(r1)
519 mfcr r10
520 stw r10,_CCR(r1)
521 stw r1,KSP(r3) /* Set old stack pointer */
522
523#ifdef CONFIG_SMP
524 /* We need a sync somewhere here to make sure that if the
525 * previous task gets rescheduled on another CPU, it sees all
526 * stores it has performed on this one.
527 */
528 sync
529#endif /* CONFIG_SMP */
530
531 tophys(r0,r4)
532 CLR_TOP32(r0)
533 mtspr SPRN_SPRG3,r0 /* Update current THREAD phys addr */
534 lwz r1,KSP(r4) /* Load new stack pointer */
535
536 /* save the old current 'last' for return value */
537 mr r3,r2
538 addi r2,r4,-THREAD /* Update current */
539
540#ifdef CONFIG_ALTIVEC
541BEGIN_FTR_SECTION
542 lwz r0,THREAD+THREAD_VRSAVE(r2)
543 mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */
544END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
545#endif /* CONFIG_ALTIVEC */
546#ifdef CONFIG_SPE
5e14d21e 547BEGIN_FTR_SECTION
9994a338
PM
548 lwz r0,THREAD+THREAD_SPEFSCR(r2)
549 mtspr SPRN_SPEFSCR,r0 /* restore SPEFSCR reg */
5e14d21e 550END_FTR_SECTION_IFSET(CPU_FTR_SPE)
9994a338
PM
551#endif /* CONFIG_SPE */
552
553 lwz r0,_CCR(r1)
554 mtcrf 0xFF,r0
555 /* r3-r12 are destroyed -- Cort */
556 REST_NVGPRS(r1)
557
558 lwz r4,_NIP(r1) /* Return to _switch caller in new task */
559 mtlr r4
560 addi r1,r1,INT_FRAME_SIZE
561 blr
562
563 .globl fast_exception_return
564fast_exception_return:
565#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
566 andi. r10,r9,MSR_RI /* check for recoverable interrupt */
567 beq 1f /* if not, we've got problems */
568#endif
569
5702: REST_4GPRS(3, r11)
571 lwz r10,_CCR(r11)
572 REST_GPR(1, r11)
573 mtcr r10
574 lwz r10,_LINK(r11)
575 mtlr r10
576 REST_GPR(10, r11)
577 mtspr SPRN_SRR1,r9
578 mtspr SPRN_SRR0,r12
579 REST_GPR(9, r11)
580 REST_GPR(12, r11)
581 lwz r11,GPR11(r11)
582 SYNC
583 RFI
584
585#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
586/* check if the exception happened in a restartable section */
5871: lis r3,exc_exit_restart_end@ha
588 addi r3,r3,exc_exit_restart_end@l
589 cmplw r12,r3
590 bge 3f
591 lis r4,exc_exit_restart@ha
592 addi r4,r4,exc_exit_restart@l
593 cmplw r12,r4
594 blt 3f
595 lis r3,fee_restarts@ha
596 tophys(r3,r3)
597 lwz r5,fee_restarts@l(r3)
598 addi r5,r5,1
599 stw r5,fee_restarts@l(r3)
600 mr r12,r4 /* restart at exc_exit_restart */
601 b 2b
602
991eb43a
KG
603 .section .bss
604 .align 2
605fee_restarts:
606 .space 4
607 .previous
9994a338
PM
608
609/* aargh, a nonrecoverable interrupt, panic */
610/* aargh, we don't know which trap this is */
611/* but the 601 doesn't implement the RI bit, so assume it's OK */
6123:
613BEGIN_FTR_SECTION
614 b 2b
615END_FTR_SECTION_IFSET(CPU_FTR_601)
616 li r10,-1
d73e0c99 617 stw r10,_TRAP(r11)
9994a338
PM
618 addi r3,r1,STACK_FRAME_OVERHEAD
619 lis r10,MSR_KERNEL@h
620 ori r10,r10,MSR_KERNEL@l
621 bl transfer_to_handler_full
622 .long nonrecoverable_exception
623 .long ret_from_except
624#endif
625
9994a338
PM
626 .globl ret_from_except_full
627ret_from_except_full:
628 REST_NVGPRS(r1)
629 /* fall through */
630
631 .globl ret_from_except
632ret_from_except:
633 /* Hard-disable interrupts so that current_thread_info()->flags
634 * can't change between when we test it and when we return
635 * from the interrupt. */
636 LOAD_MSR_KERNEL(r10,MSR_KERNEL)
637 SYNC /* Some chip revs have problems here... */
638 MTMSRD(r10) /* disable interrupts */
639
640 lwz r3,_MSR(r1) /* Returning to user mode? */
641 andi. r0,r3,MSR_PR
642 beq resume_kernel
643
644user_exc_return: /* r10 contains MSR_KERNEL here */
645 /* Check current_thread_info()->flags */
6cb7bfeb 646 rlwinm r9,r1,0,0,(31-THREAD_SHIFT)
9994a338 647 lwz r9,TI_FLAGS(r9)
1bd79336 648 andi. r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED)
9994a338
PM
649 bne do_work
650
651restore_user:
652#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
653 /* Check whether this process has its own DBCR0 value. The single
654 step bit tells us that dbcr0 should be loaded. */
655 lwz r0,THREAD+THREAD_DBCR0(r2)
656 andis. r10,r0,DBCR0_IC@h
657 bnel- load_dbcr0
658#endif
659
660#ifdef CONFIG_PREEMPT
661 b restore
662
663/* N.B. the only way to get here is from the beq following ret_from_except. */
664resume_kernel:
665 /* check current_thread_info->preempt_count */
6cb7bfeb 666 rlwinm r9,r1,0,0,(31-THREAD_SHIFT)
9994a338
PM
667 lwz r0,TI_PREEMPT(r9)
668 cmpwi 0,r0,0 /* if non-zero, just restore regs and return */
669 bne restore
670 lwz r0,TI_FLAGS(r9)
671 andi. r0,r0,_TIF_NEED_RESCHED
672 beq+ restore
673 andi. r0,r3,MSR_EE /* interrupts off? */
674 beq restore /* don't schedule if so */
6751: bl preempt_schedule_irq
6cb7bfeb 676 rlwinm r9,r1,0,0,(31-THREAD_SHIFT)
9994a338
PM
677 lwz r3,TI_FLAGS(r9)
678 andi. r0,r3,_TIF_NEED_RESCHED
679 bne- 1b
680#else
681resume_kernel:
682#endif /* CONFIG_PREEMPT */
683
684 /* interrupts are hard-disabled at this point */
685restore:
686 lwz r0,GPR0(r1)
687 lwz r2,GPR2(r1)
688 REST_4GPRS(3, r1)
689 REST_2GPRS(7, r1)
690
691 lwz r10,_XER(r1)
692 lwz r11,_CTR(r1)
693 mtspr SPRN_XER,r10
694 mtctr r11
695
696 PPC405_ERR77(0,r1)
697 stwcx. r0,0,r1 /* to clear the reservation */
698
699#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
700 lwz r9,_MSR(r1)
701 andi. r10,r9,MSR_RI /* check if this exception occurred */
702 beql nonrecoverable /* at a bad place (MSR:RI = 0) */
703
704 lwz r10,_CCR(r1)
705 lwz r11,_LINK(r1)
706 mtcrf 0xFF,r10
707 mtlr r11
708
709 /*
710 * Once we put values in SRR0 and SRR1, we are in a state
711 * where exceptions are not recoverable, since taking an
712 * exception will trash SRR0 and SRR1. Therefore we clear the
713 * MSR:RI bit to indicate this. If we do take an exception,
714 * we can't return to the point of the exception but we
715 * can restart the exception exit path at the label
716 * exc_exit_restart below. -- paulus
717 */
718 LOAD_MSR_KERNEL(r10,MSR_KERNEL & ~MSR_RI)
719 SYNC
720 MTMSRD(r10) /* clear the RI bit */
721 .globl exc_exit_restart
722exc_exit_restart:
723 lwz r9,_MSR(r1)
724 lwz r12,_NIP(r1)
725 FIX_SRR1(r9,r10)
726 mtspr SPRN_SRR0,r12
727 mtspr SPRN_SRR1,r9
728 REST_4GPRS(9, r1)
729 lwz r1,GPR1(r1)
730 .globl exc_exit_restart_end
731exc_exit_restart_end:
732 SYNC
733 RFI
734
735#else /* !(CONFIG_4xx || CONFIG_BOOKE) */
736 /*
737 * This is a bit different on 4xx/Book-E because it doesn't have
738 * the RI bit in the MSR.
739 * The TLB miss handler checks if we have interrupted
740 * the exception exit path and restarts it if so
741 * (well maybe one day it will... :).
742 */
743 lwz r11,_LINK(r1)
744 mtlr r11
745 lwz r10,_CCR(r1)
746 mtcrf 0xff,r10
747 REST_2GPRS(9, r1)
748 .globl exc_exit_restart
749exc_exit_restart:
750 lwz r11,_NIP(r1)
751 lwz r12,_MSR(r1)
752exc_exit_start:
753 mtspr SPRN_SRR0,r11
754 mtspr SPRN_SRR1,r12
755 REST_2GPRS(11, r1)
756 lwz r1,GPR1(r1)
757 .globl exc_exit_restart_end
758exc_exit_restart_end:
759 PPC405_ERR77_SYNC
760 rfi
761 b . /* prevent prefetch past rfi */
762
763/*
764 * Returning from a critical interrupt in user mode doesn't need
765 * to be any different from a normal exception. For a critical
766 * interrupt in the kernel, we just return (without checking for
767 * preemption) since the interrupt may have happened at some crucial
768 * place (e.g. inside the TLB miss handler), and because we will be
769 * running with r1 pointing into critical_stack, not the current
770 * process's kernel stack (and therefore current_thread_info() will
771 * give the wrong answer).
772 * We have to restore various SPRs that may have been in use at the
773 * time of the critical interrupt.
774 *
775 */
776#ifdef CONFIG_40x
777#define PPC_40x_TURN_OFF_MSR_DR \
778 /* avoid any possible TLB misses here by turning off MSR.DR, we \
779 * assume the instructions here are mapped by a pinned TLB entry */ \
780 li r10,MSR_IR; \
781 mtmsr r10; \
782 isync; \
783 tophys(r1, r1);
784#else
785#define PPC_40x_TURN_OFF_MSR_DR
786#endif
787
788#define RET_FROM_EXC_LEVEL(exc_lvl_srr0, exc_lvl_srr1, exc_lvl_rfi) \
789 REST_NVGPRS(r1); \
790 lwz r3,_MSR(r1); \
791 andi. r3,r3,MSR_PR; \
792 LOAD_MSR_KERNEL(r10,MSR_KERNEL); \
793 bne user_exc_return; \
794 lwz r0,GPR0(r1); \
795 lwz r2,GPR2(r1); \
796 REST_4GPRS(3, r1); \
797 REST_2GPRS(7, r1); \
798 lwz r10,_XER(r1); \
799 lwz r11,_CTR(r1); \
800 mtspr SPRN_XER,r10; \
801 mtctr r11; \
802 PPC405_ERR77(0,r1); \
803 stwcx. r0,0,r1; /* to clear the reservation */ \
804 lwz r11,_LINK(r1); \
805 mtlr r11; \
806 lwz r10,_CCR(r1); \
807 mtcrf 0xff,r10; \
808 PPC_40x_TURN_OFF_MSR_DR; \
809 lwz r9,_DEAR(r1); \
810 lwz r10,_ESR(r1); \
811 mtspr SPRN_DEAR,r9; \
812 mtspr SPRN_ESR,r10; \
813 lwz r11,_NIP(r1); \
814 lwz r12,_MSR(r1); \
815 mtspr exc_lvl_srr0,r11; \
816 mtspr exc_lvl_srr1,r12; \
817 lwz r9,GPR9(r1); \
818 lwz r12,GPR12(r1); \
819 lwz r10,GPR10(r1); \
820 lwz r11,GPR11(r1); \
821 lwz r1,GPR1(r1); \
822 PPC405_ERR77_SYNC; \
823 exc_lvl_rfi; \
824 b .; /* prevent prefetch past exc_lvl_rfi */
825
826 .globl ret_from_crit_exc
827ret_from_crit_exc:
828 RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
829
830#ifdef CONFIG_BOOKE
831 .globl ret_from_debug_exc
832ret_from_debug_exc:
833 RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI)
834
835 .globl ret_from_mcheck_exc
836ret_from_mcheck_exc:
837 RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI)
838#endif /* CONFIG_BOOKE */
839
840/*
841 * Load the DBCR0 value for a task that is being ptraced,
842 * having first saved away the global DBCR0. Note that r0
843 * has the dbcr0 value to set upon entry to this.
844 */
845load_dbcr0:
846 mfmsr r10 /* first disable debug exceptions */
847 rlwinm r10,r10,0,~MSR_DE
848 mtmsr r10
849 isync
850 mfspr r10,SPRN_DBCR0
851 lis r11,global_dbcr0@ha
852 addi r11,r11,global_dbcr0@l
853 stw r10,0(r11)
854 mtspr SPRN_DBCR0,r0
855 lwz r10,4(r11)
856 addi r10,r10,1
857 stw r10,4(r11)
858 li r11,-1
859 mtspr SPRN_DBSR,r11 /* clear all pending debug events */
860 blr
861
991eb43a
KG
862 .section .bss
863 .align 4
864global_dbcr0:
865 .space 8
866 .previous
9994a338
PM
867#endif /* !(CONFIG_4xx || CONFIG_BOOKE) */
868
869do_work: /* r10 contains MSR_KERNEL here */
870 andi. r0,r9,_TIF_NEED_RESCHED
871 beq do_user_signal
872
873do_resched: /* r10 contains MSR_KERNEL here */
874 ori r10,r10,MSR_EE
875 SYNC
876 MTMSRD(r10) /* hard-enable interrupts */
877 bl schedule
878recheck:
879 LOAD_MSR_KERNEL(r10,MSR_KERNEL)
880 SYNC
881 MTMSRD(r10) /* disable interrupts */
6cb7bfeb 882 rlwinm r9,r1,0,0,(31-THREAD_SHIFT)
9994a338
PM
883 lwz r9,TI_FLAGS(r9)
884 andi. r0,r9,_TIF_NEED_RESCHED
885 bne- do_resched
f27201da 886 andi. r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK
9994a338
PM
887 beq restore_user
888do_user_signal: /* r10 contains MSR_KERNEL here */
889 ori r10,r10,MSR_EE
890 SYNC
891 MTMSRD(r10) /* hard-enable interrupts */
892 /* save r13-r31 in the exception frame, if not already done */
d73e0c99 893 lwz r3,_TRAP(r1)
9994a338
PM
894 andi. r0,r3,1
895 beq 2f
896 SAVE_NVGPRS(r1)
897 rlwinm r3,r3,0,0,30
d73e0c99 898 stw r3,_TRAP(r1)
9994a338
PM
8992: li r3,0
900 addi r4,r1,STACK_FRAME_OVERHEAD
901 bl do_signal
902 REST_NVGPRS(r1)
903 b recheck
904
905/*
906 * We come here when we are at the end of handling an exception
907 * that occurred at a place where taking an exception will lose
908 * state information, such as the contents of SRR0 and SRR1.
909 */
910nonrecoverable:
911 lis r10,exc_exit_restart_end@ha
912 addi r10,r10,exc_exit_restart_end@l
913 cmplw r12,r10
914 bge 3f
915 lis r11,exc_exit_restart@ha
916 addi r11,r11,exc_exit_restart@l
917 cmplw r12,r11
918 blt 3f
919 lis r10,ee_restarts@ha
920 lwz r12,ee_restarts@l(r10)
921 addi r12,r12,1
922 stw r12,ee_restarts@l(r10)
923 mr r12,r11 /* restart at exc_exit_restart */
924 blr
9253: /* OK, we can't recover, kill this process */
926 /* but the 601 doesn't implement the RI bit, so assume it's OK */
927BEGIN_FTR_SECTION
928 blr
929END_FTR_SECTION_IFSET(CPU_FTR_601)
d73e0c99 930 lwz r3,_TRAP(r1)
9994a338
PM
931 andi. r0,r3,1
932 beq 4f
933 SAVE_NVGPRS(r1)
934 rlwinm r3,r3,0,0,30
d73e0c99 935 stw r3,_TRAP(r1)
9994a338
PM
9364: addi r3,r1,STACK_FRAME_OVERHEAD
937 bl nonrecoverable_exception
938 /* shouldn't return */
939 b 4b
940
991eb43a
KG
941 .section .bss
942 .align 2
943ee_restarts:
944 .space 4
945 .previous
9994a338
PM
946
947/*
948 * PROM code for specific machines follows. Put it
949 * here so it's easy to add arch-specific sections later.
950 * -- Cort
951 */
033ef338 952#ifdef CONFIG_PPC_RTAS
9994a338
PM
953/*
954 * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
955 * called with the MMU off.
956 */
957_GLOBAL(enter_rtas)
958 stwu r1,-INT_FRAME_SIZE(r1)
959 mflr r0
960 stw r0,INT_FRAME_SIZE+4(r1)
e58c3495 961 LOAD_REG_ADDR(r4, rtas)
9994a338
PM
962 lis r6,1f@ha /* physical return address for rtas */
963 addi r6,r6,1f@l
964 tophys(r6,r6)
965 tophys(r7,r1)
033ef338
PM
966 lwz r8,RTASENTRY(r4)
967 lwz r4,RTASBASE(r4)
9994a338
PM
968 mfmsr r9
969 stw r9,8(r1)
970 LOAD_MSR_KERNEL(r0,MSR_KERNEL)
971 SYNC /* disable interrupts so SRR0/1 */
972 MTMSRD(r0) /* don't get trashed */
973 li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR)
974 mtlr r6
9994a338
PM
975 mtspr SPRN_SPRG2,r7
976 mtspr SPRN_SRR0,r8
977 mtspr SPRN_SRR1,r9
978 RFI
9791: tophys(r9,r1)
980 lwz r8,INT_FRAME_SIZE+4(r9) /* get return address */
981 lwz r9,8(r9) /* original msr value */
982 FIX_SRR1(r9,r0)
983 addi r1,r1,INT_FRAME_SIZE
984 li r0,0
985 mtspr SPRN_SPRG2,r0
986 mtspr SPRN_SRR0,r8
987 mtspr SPRN_SRR1,r9
988 RFI /* return to caller */
989
990 .globl machine_check_in_rtas
991machine_check_in_rtas:
992 twi 31,0,0
993 /* XXX load up BATs and panic */
994
033ef338 995#endif /* CONFIG_PPC_RTAS */
This page took 0.230393 seconds and 5 git commands to generate.