Merge with 2.3.48.
[linux-2.6/linux-mips.git] / arch / ppc / kernel / entry.S
blobcc647a58b6187f3d7291b1b811ea526865433bed
1 /*
2  *  arch/ppc/kernel/entry.S
3  *
4  *  $Id: entry.S,v 1.4 1999/09/14 05:18:14 dmalek Exp $
5  *
6  *  PowerPC version 
7  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
8  *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
9  *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
10  *  Adapted for Power Macintosh by Paul Mackerras.
11  *  Low-level exception handlers and MMU support
12  *  rewritten by Paul Mackerras.
13  *    Copyright (C) 1996 Paul Mackerras.
14  *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
15  *
16  *  This file contains the system call entry code, context switch
17  *  code, and exception/interrupt return code for PowerPC.
18  *
19  *  This program is free software; you can redistribute it and/or
20  *  modify it under the terms of the GNU General Public License
21  *  as published by the Free Software Foundation; either version
22  *  2 of the License, or (at your option) any later version.
23  *      
24  */
26 #include "ppc_asm.h"
27 #include <asm/processor.h>
28 #include <asm/page.h>
29 #include <asm/mmu.h>
30 #include <linux/errno.h>
31 #include <linux/sys.h>
32 #include <linux/config.h>
34 #define SHOW_SYSCALLS
35 #define SHOW_SYSCALLS_TASK
37 #ifdef SHOW_SYSCALLS_TASK
38         .data
39 show_syscalls_task:
40         .long   -1
41 #endif
44  * Handle a system call.
45  */
46         .text
47 _GLOBAL(DoSyscall)
48         stw     r0,THREAD+LAST_SYSCALL(r2)
49         lwz     r11,_CCR(r1)    /* Clear SO bit in CR */
50         lis     r10,0x1000
51         andc    r11,r11,r10
52         stw     r11,_CCR(r1)
53 #ifdef SHOW_SYSCALLS
54 #ifdef SHOW_SYSCALLS_TASK
55         lis     r31,show_syscalls_task@ha
56         lwz     r31,show_syscalls_task@l(r31)
57         cmp     0,r2,r31
58         bne     1f
59 #endif
60         lis     r3,7f@ha
61         addi    r3,r3,7f@l
62         lwz     r4,GPR0(r1)
63         lwz     r5,GPR3(r1)
64         lwz     r6,GPR4(r1)
65         lwz     r7,GPR5(r1)
66         lwz     r8,GPR6(r1)
67         lwz     r9,GPR7(r1)
68         bl      printk
69         lis     r3,77f@ha
70         addi    r3,r3,77f@l
71         lwz     r4,GPR8(r1)
72         lwz     r5,GPR9(r1)
73         mr      r6,r2
74         bl      printk
75         lwz     r0,GPR0(r1)
76         lwz     r3,GPR3(r1)
77         lwz     r4,GPR4(r1)
78         lwz     r5,GPR5(r1)
79         lwz     r6,GPR6(r1)
80         lwz     r7,GPR7(r1)
81         lwz     r8,GPR8(r1)
83 #endif /* SHOW_SYSCALLS */
84         cmpi    0,r0,0x7777     /* Special case for 'sys_sigreturn' */
85         beq-    10f
86         lwz     r10,TASK_FLAGS(r2)
87         andi.   r10,r10,PF_TRACESYS
88         bne-    50f
89         cmpli   0,r0,NR_syscalls
90         bge-    66f
91         lis     r10,sys_call_table@h
92         ori     r10,r10,sys_call_table@l
93         slwi    r0,r0,2
94         lwzx    r10,r10,r0      /* Fetch system call handler [ptr] */
95         cmpi    0,r10,0
96         beq-    66f
97         mtlr    r10
98         addi    r9,r1,STACK_FRAME_OVERHEAD
99         blrl                    /* Call handler */
100         .globl  ret_from_syscall_1
101 ret_from_syscall_1:
102 20:     stw     r3,RESULT(r1)   /* Save result */
103 #ifdef SHOW_SYSCALLS
104 #ifdef SHOW_SYSCALLS_TASK
105         cmp     0,r2,r31
106         bne     91f
107 #endif
108         mr      r4,r3
109         lis     r3,79f@ha
110         addi    r3,r3,79f@l
111         bl      printk
112         lwz     r3,RESULT(r1)
114 #endif
115         li      r10,-_LAST_ERRNO
116         cmpl    0,r3,r10
117         blt     30f
118         neg     r3,r3
119         cmpi    0,r3,ERESTARTNOHAND
120         bne     22f
121         li      r3,EINTR
122 22:     lwz     r10,_CCR(r1)    /* Set SO bit in CR */
123         oris    r10,r10,0x1000
124         stw     r10,_CCR(r1)
125 30:     stw     r3,GPR3(r1)     /* Update return value */
126         b       ret_from_except
127 66:     li      r3,ENOSYS
128         b       22b
129 /* sys_sigreturn */
130 10:     addi    r3,r1,STACK_FRAME_OVERHEAD
131         bl      sys_sigreturn
132         cmpi    0,r3,0          /* Check for restarted system call */
133         bge     ret_from_except
134         b       20b
135 /* Traced system call support */
136 50:     bl      syscall_trace
137         lwz     r0,GPR0(r1)     /* Restore original registers */
138         lwz     r3,GPR3(r1)
139         lwz     r4,GPR4(r1)
140         lwz     r5,GPR5(r1)
141         lwz     r6,GPR6(r1)
142         lwz     r7,GPR7(r1)
143         lwz     r8,GPR8(r1)
144         lwz     r9,GPR9(r1)
145         cmpli   0,r0,NR_syscalls
146         bge-    66f
147         lis     r10,sys_call_table@h
148         ori     r10,r10,sys_call_table@l
149         slwi    r0,r0,2
150         lwzx    r10,r10,r0      /* Fetch system call handler [ptr] */
151         cmpi    0,r10,0
152         beq-    66f
153         mtlr    r10
154         addi    r9,r1,STACK_FRAME_OVERHEAD
155         blrl                    /* Call handler */
156         .globl  ret_from_syscall_2
157 ret_from_syscall_2:
158         stw     r3,RESULT(r1)   /* Save result */       
159         stw     r3,GPR0(r1)     /* temporary gross hack to make strace work */
160         li      r10,-_LAST_ERRNO
161         cmpl    0,r3,r10
162         blt     60f
163         neg     r3,r3
164         cmpi    0,r3,ERESTARTNOHAND
165         bne     52f
166         li      r3,EINTR
167 52:     lwz     r10,_CCR(r1)    /* Set SO bit in CR */
168         oris    r10,r10,0x1000
169         stw     r10,_CCR(r1)
170 60:     stw     r3,GPR3(r1)     /* Update return value */
171         bl      syscall_trace
172         b       ret_from_except
173 66:     li      r3,ENOSYS
174         b       52b
175 #ifdef SHOW_SYSCALLS
176 7:      .string "syscall %d(%x, %x, %x, %x, %x, "
177 77:     .string "%x, %x), current=%p\n"
178 79:     .string " -> %x\n"
179         .align  2,0
180 #endif
183  * This routine switches between two different tasks.  The process
184  * state of one is saved on its kernel stack.  Then the state
185  * of the other is restored from its kernel stack.  The memory
186  * management hardware is updated to the second process's state.
187  * Finally, we can return to the second process, via ret_from_except.
188  * On entry, r3 points to the THREAD for the current task, r4
189  * points to the THREAD for the new task.
191  * Note: there are two ways to get to the "going out" portion
192  * of this code; either by coming in via the entry (_switch)
193  * or via "fork" which must set up an environment equivalent
194  * to the "_switch" path.  If you change this (or in particular, the
195  * SAVE_REGS macro), you'll have to change the fork code also.
197  * The code which creates the new task context is in 'copy_thread'
198  * in arch/ppc/kernel/process.c
199  */     
200 _GLOBAL(_switch)
201         stwu    r1,-INT_FRAME_SIZE(r1)
202         stw     r0,GPR0(r1)
203         lwz     r0,0(r1)
204         stw     r0,GPR1(r1)
205         /* r3-r13 are caller saved -- Cort */
206         SAVE_GPR(2, r1)
207         SAVE_8GPRS(14, r1)
208         SAVE_10GPRS(22, r1)
209         mflr    r20             /* Return to switch caller */
210         mfmsr   r22
211         li      r0,MSR_FP       /* Disable floating-point */
212 #ifdef CONFIG_ALTIVEC
213         oris    r0,r0,MSR_VEC@h
214 #endif /* CONFIG_ALTIVEC */
215         andc    r22,r22,r0
216         stw     r20,_NIP(r1)
217         stw     r22,_MSR(r1)
218         stw     r20,_LINK(r1)
219         mfcr    r20
220         mfctr   r22
221         mfspr   r23,XER
222         stw     r20,_CCR(r1)
223         stw     r22,_CTR(r1)
224         stw     r23,_XER(r1)
225         li      r0,0x0ff0
226         stw     r0,TRAP(r1)
227         stw     r1,KSP(r3)      /* Set old stack pointer */
228         sync
229         tophys(r0,r4)
230         mtspr   SPRG3,r0        /* Update current THREAD phys addr */
231 #ifdef CONFIG_8xx
232         /* XXX it would be nice to find a SPRGx for this on 6xx,7xx too */
233         lwz     r9,PGDIR(r4)    /* cache the page table root */
234         tophys(r9,r9)           /* convert to phys addr */
235         mtspr   M_TWB,r9        /* Update MMU base address */
236 #endif /* CONFIG_8xx */
237         lwz     r1,KSP(r4)      /* Load new stack pointer */
238         /* save the old current 'last' for return value */
239         mr      r3,r2
240         addi    r2,r4,-THREAD   /* Update current */
241         lwz     r9,_MSR(r1)     /* Returning to user mode? */
242         andi.   r9,r9,MSR_PR
243         beq+    10f             /* if not, don't adjust kernel stack */
244 8:      addi    r4,r1,INT_FRAME_SIZE    /* size of frame */
245         stw     r4,THREAD+KSP(r2)       /* save kernel stack pointer */
246         tophys(r9,r1)
247         mtspr   SPRG2,r9        /* phys exception stack pointer */
248 10:     lwz     r2,_CTR(r1)
249         lwz     r0,_LINK(r1)
250         mtctr   r2
251         mtlr    r0
252         lwz     r2,_XER(r1)
253         lwz     r0,_CCR(r1)
254         mtspr   XER,r2
255         mtcrf   0xFF,r0
256         /* r3-r13 are destroyed -- Cort */
257         REST_GPR(14, r1)
258         REST_8GPRS(15, r1)
259         REST_8GPRS(23, r1)
260         REST_GPR(31, r1)
261         lwz     r2,_NIP(r1)     /* Restore environment */
262         /* 
263          * We need to hard disable here even if RTL is active since
264          * being interrupted after here trashes SRR{0,1}
265          *  -- Cort
266          */ 
267         mfmsr   r0              /* Get current interrupt state */
268         rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
269         mtmsr   r0              /* Update machine state */
270         
271         lwz     r0,_MSR(r1)
272         mtspr   SRR0,r2
273         mtspr   SRR1,r0
274         lwz     r0,GPR0(r1)
275         lwz     r2,GPR2(r1)
276         lwz     r1,GPR1(r1)
277         SYNC
278         rfi
280 #ifdef CONFIG_SMP       
281         .globl  ret_from_smpfork
282 ret_from_smpfork:
283         bl      schedule_tail
284         b       ret_from_except
285 #endif
287         .globl  ret_from_intercept
288 ret_from_intercept:
289         /*
290          * We may be returning from RTL and cannot do the normal checks
291          * -- Cort
292          */
293         cmpi    0,r3,0
294         bne     ret_from_except
295         /*
296          * If we're returning from user mode we do things differently
297          * -- Cort
298          */
299         lwz     r3,_MSR(r1)
300         andi.   r3,r3,MSR_PR
301         beq+    10f
302         b       8f
304         .globl  ret_from_except
305 ret_from_except:
306 0:      /* disable interrupts */
307         lis     r30,int_control@h
308         ori     r30,r30,int_control@l
309         lwz     r30,0(r30)
310         mtlr    r30
311         blrl
312         
313         lwz     r5,_MSR(r1)
314         andi.   r5,r5,MSR_EE
315         beq     2f
316         .globl  lost_irq_ret
317 lost_irq_ret:
318 3:      lis     r4,ppc_n_lost_interrupts@ha
319         lwz     r4,ppc_n_lost_interrupts@l(r4)
320         cmpi    0,r4,0
321         beq+    1f
322         addi    r3,r1,STACK_FRAME_OVERHEAD
323         bl      do_IRQ
324         b       3b
325 1:      lis     r4,softirq_state@ha
326         addi    r4,r4,softirq_state@l
327 #ifdef CONFIG_SMP
328         /* get processor # */
329         lwz     r3,PROCESSOR(r2)
330 #ifndef CONFIG_PPC64
331         slwi    r3,r3,5
332 #else
333 #error not 64-bit ready 
334 #endif
335         add     r4,r4,r3
336 #endif /* CONFIG_SMP */
337         lwz     r5,0(r4)
338         lwz     r4,4(r4)
339         and.    r5,r5,r4
340         beq+    2f
341         bl      do_softirq
342         .globl  do_bottom_half_ret
343 do_bottom_half_ret:
344 2:      /* disable interrupts */        
345         lis     r30,int_control@h
346         ori     r30,r30,int_control@l
347         lwz     r30,0(r30)
348         mtlr    r30
349         blrl
350         lwz     r3,_MSR(r1)     /* Returning to user mode? */
351         andi.   r3,r3,MSR_PR
352         beq+    10f             /* if so, check need_resched and signals */
353         lwz     r3,NEED_RESCHED(r2)
354         cmpi    0,r3,0          /* check need_resched flag */
355         beq+    7f
356         bl      schedule
357         b       0b
358 7:      lwz     r5,SIGPENDING(r2) /* Check for pending unblocked signals */
359         cmpwi   0,r5,0
360         beq+    8f
361         li      r3,0
362         addi    r4,r1,STACK_FRAME_OVERHEAD
363         bl      do_signal
364         .globl  do_signal_ret
365 do_signal_ret:
366         b       0b
367 8:      /* 
368          * We need to hard disable here even if RTL is active since
369          * being interrupted after here trashes the SPRG2
370          *  -- Cort
371          */ 
372         mfmsr   r0              /* Get current interrupt state */
373         rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
374         mtmsr   r0              /* Update machine state */
375         
376         addi    r4,r1,INT_FRAME_SIZE    /* size of frame */
377         stw     r4,THREAD+KSP(r2)       /* save kernel stack pointer */
378         tophys(r3,r1)
379         mtspr   SPRG2,r3        /* phys exception stack pointer */
380         b       11f
381 10:     /* make sure we hard disable here, even if rtl is active -- Cort */
382         mfmsr   r0              /* Get current interrupt state */
383         rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
384         sync                    /* Some chip revs have problems here... */
385         mtmsr   r0              /* Update machine state */
386 11: 
387         lwz     r2,_CTR(r1)
388         lwz     r0,_LINK(r1)
389         mtctr   r2
390         mtlr    r0
391         lwz     r2,_XER(r1)
392         lwz     r0,_CCR(r1)
393         mtspr   XER,r2
394         mtcrf   0xFF,r0
395         REST_10GPRS(3, r1)
396         REST_10GPRS(13, r1)
397         REST_8GPRS(23, r1)
398         REST_GPR(31, r1)
399         lwz     r2,_NIP(r1)     /* Restore environment */
400         lwz     r0,_MSR(r1)
401         mtspr   SRR0,r2
402         mtspr   SRR1,r0
403         lwz     r0,GPR0(r1)
404         lwz     r2,GPR2(r1)
405         lwz     r1,GPR1(r1)
406         SYNC
407         rfi
410  * Fake an interrupt from kernel mode.
411  * This is used when enable_irq loses an interrupt.
412  * We only fill in the stack frame minimally.
413  */
414 _GLOBAL(fake_interrupt)
415         mflr    r0
416         stw     r0,4(r1)
417         stwu    r1,-INT_FRAME_SIZE(r1)
418         stw     r0,_NIP(r1)
419         stw     r0,_LINK(r1)
420         mfmsr   r3
421         stw     r3,_MSR(r1)
422         li      r0,0x0fac
423         stw     r0,TRAP(r1)
424         addi    r3,r1,STACK_FRAME_OVERHEAD
425         li      r4,1
426         bl      do_IRQ
427         addi    r1,r1,INT_FRAME_SIZE
428         lwz     r0,4(r1)
429         mtlr    r0
430         blr
434  * PROM code for specific machines follows.  Put it 
435  * here so it's easy to add arch-specific sections later.
436  * -- Cort
437  */
438 #if defined(CONFIG_ALL_PPC)
440  * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
441  * called with the MMU off.
442  */
443         .globl  enter_rtas
444 enter_rtas:
445         mflr    r0
446         stw     r0,20(r1)
447         lis     r4,rtas_data@ha
448         lwz     r4,rtas_data@l(r4)
449         addis   r4,r4,-KERNELBASE@h
450         lis     r6,1f@ha        /* physical return address for rtas */
451         addi    r6,r6,1f@l
452         addis   r6,r6,-KERNELBASE@h
453         subi    r7,r1,INT_FRAME_SIZE
454         addis   r7,r7,-KERNELBASE@h
455         lis     r8,rtas_entry@ha
456         lwz     r8,rtas_entry@l(r8)
457         mfmsr   r9
458         stw     r9,8(r1)
459         li      r0,0
460         ori     r0,r0,MSR_EE|MSR_SE|MSR_BE
461         andc    r0,r9,r0
462         andi.   r9,r9,MSR_ME|MSR_RI
463         sync                    /* disable interrupts so SRR0/1 */
464         mtmsr   r0              /* don't get trashed */
465         mtlr    r6
466         mtspr   SPRG2,r7
467         mtspr   SRR0,r8
468         mtspr   SRR1,r9
469         rfi
470 1:      addis   r9,r1,-KERNELBASE@h
471         lwz     r8,20(r9)       /* get return address */
472         lwz     r9,8(r9)        /* original msr value */
473         li      r0,0
474         mtspr   SPRG2,r0
475         mtspr   SRR0,r8
476         mtspr   SRR1,r9
477         rfi                     /* return to caller */
478 #endif /* CONFIG_ALL_PPC */