Import 2.3.16
[davej-history.git] / arch / ppc / kernel / entry.S
blob17e1eac6dfa104ba551ba16fc4e12551093826dc
1 /*
2  *  arch/ppc/kernel/entry.S
3  *
4  *  $Id: entry.S,v 1.2 1999/08/23 02:53:16 paulus 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 <linux/errno.h>
30 #include <linux/sys.h>
31 #include <linux/config.h>
33 #define SHOW_SYSCALLS
34 #define SHOW_SYSCALLS_TASK
36 #ifdef SHOW_SYSCALLS_TASK
37         .data
38 show_syscalls_task:
39         .long   -1
40 #endif
43  * Handle a system call.
44  */
45         .text
46 _GLOBAL(DoSyscall)
47         stw     r0,THREAD+LAST_SYSCALL(r2)
48         lwz     r11,_CCR(r1)    /* Clear SO bit in CR */
49         lis     r10,0x1000
50         andc    r11,r11,r10
51         stw     r11,_CCR(r1)
52 #ifdef SHOW_SYSCALLS
53 #ifdef SHOW_SYSCALLS_TASK
54         lis     r31,show_syscalls_task@ha
55         lwz     r31,show_syscalls_task@l(r31)
56         cmp     0,r2,r31
57         bne     1f
58 #endif
59         lis     r3,7f@ha
60         addi    r3,r3,7f@l
61         lwz     r4,GPR0(r1)
62         lwz     r5,GPR3(r1)
63         lwz     r6,GPR4(r1)
64         lwz     r7,GPR5(r1)
65         lwz     r8,GPR6(r1)
66         lwz     r9,GPR7(r1)
67         bl      printk
68         lis     r3,77f@ha
69         addi    r3,r3,77f@l
70         lwz     r4,GPR8(r1)
71         lwz     r5,GPR9(r1)
72         mr      r6,r2
73         bl      printk
74         lwz     r0,GPR0(r1)
75         lwz     r3,GPR3(r1)
76         lwz     r4,GPR4(r1)
77         lwz     r5,GPR5(r1)
78         lwz     r6,GPR6(r1)
79         lwz     r7,GPR7(r1)
80         lwz     r8,GPR8(r1)
82 #endif /* SHOW_SYSCALLS */
83         cmpi    0,r0,0x7777     /* Special case for 'sys_sigreturn' */
84         beq-    10f
85         lwz     r10,TASK_FLAGS(r2)
86         andi.   r10,r10,PF_TRACESYS
87         bne-    50f
88         cmpli   0,r0,NR_syscalls
89         bge-    66f
90         lis     r10,sys_call_table@h
91         ori     r10,r10,sys_call_table@l
92         slwi    r0,r0,2
93         lwzx    r10,r10,r0      /* Fetch system call handler [ptr] */
94         cmpi    0,r10,0
95         beq-    66f
96         mtlr    r10
97         addi    r9,r1,STACK_FRAME_OVERHEAD
98         blrl                    /* Call handler */
99         .globl  ret_from_syscall_1
100 ret_from_syscall_1:
101 20:     stw     r3,RESULT(r1)   /* Save result */
102 #ifdef SHOW_SYSCALLS
103 #ifdef SHOW_SYSCALLS_TASK
104         cmp     0,r2,r31
105         bne     91f
106 #endif
107         mr      r4,r3
108         lis     r3,79f@ha
109         addi    r3,r3,79f@l
110         bl      printk
111         lwz     r3,RESULT(r1)
113 #endif
114         li      r10,-_LAST_ERRNO
115         cmpl    0,r3,r10
116         blt     30f
117         neg     r3,r3
118         cmpi    0,r3,ERESTARTNOHAND
119         bne     22f
120         li      r3,EINTR
121 22:     lwz     r10,_CCR(r1)    /* Set SO bit in CR */
122         oris    r10,r10,0x1000
123         stw     r10,_CCR(r1)
124 30:     stw     r3,GPR3(r1)     /* Update return value */
125         b       ret_from_except
126 66:     li      r3,ENOSYS
127         b       22b
128 /* sys_sigreturn */
129 10:     addi    r3,r1,STACK_FRAME_OVERHEAD
130         bl      sys_sigreturn
131         cmpi    0,r3,0          /* Check for restarted system call */
132         bge     ret_from_except
133         b       20b
134 /* Traced system call support */
135 50:     bl      syscall_trace
136         lwz     r0,GPR0(r1)     /* Restore original registers */
137         lwz     r3,GPR3(r1)
138         lwz     r4,GPR4(r1)
139         lwz     r5,GPR5(r1)
140         lwz     r6,GPR6(r1)
141         lwz     r7,GPR7(r1)
142         lwz     r8,GPR8(r1)
143         lwz     r9,GPR9(r1)
144         cmpli   0,r0,NR_syscalls
145         bge-    66f
146         lis     r10,sys_call_table@h
147         ori     r10,r10,sys_call_table@l
148         slwi    r0,r0,2
149         lwzx    r10,r10,r0      /* Fetch system call handler [ptr] */
150         cmpi    0,r10,0
151         beq-    66f
152         mtlr    r10
153         addi    r9,r1,STACK_FRAME_OVERHEAD
154         blrl                    /* Call handler */
155         .globl  ret_from_syscall_2
156 ret_from_syscall_2:
157         stw     r3,RESULT(r1)   /* Save result */       
158         stw     r3,GPR0(r1)     /* temporary gross hack to make strace work */
159         li      r10,-_LAST_ERRNO
160         cmpl    0,r3,r10
161         blt     60f
162         neg     r3,r3
163         cmpi    0,r3,ERESTARTNOHAND
164         bne     52f
165         li      r3,EINTR
166 52:     lwz     r10,_CCR(r1)    /* Set SO bit in CR */
167         oris    r10,r10,0x1000
168         stw     r10,_CCR(r1)
169 60:     stw     r3,GPR3(r1)     /* Update return value */
170         bl      syscall_trace
171         b       ret_from_except
172 66:     li      r3,ENOSYS
173         b       52b
174 #ifdef SHOW_SYSCALLS
175 7:      .string "syscall %d(%x, %x, %x, %x, %x, "
176 77:     .string "%x, %x), current=%p\n"
177 79:     .string " -> %x\n"
178         .align  2
179 #endif
182  * This routine switches between two different tasks.  The process
183  * state of one is saved on its kernel stack.  Then the state
184  * of the other is restored from its kernel stack.  The memory
185  * management hardware is updated to the second process's state.
186  * Finally, we can return to the second process, via ret_from_except.
187  * On entry, r3 points to the THREAD for the current task, r4
188  * points to the THREAD for the new task.
190  * Note: there are two ways to get to the "going out" portion
191  * of this code; either by coming in via the entry (_switch)
192  * or via "fork" which must set up an environment equivalent
193  * to the "_switch" path.  If you change this (or in particular, the
194  * SAVE_REGS macro), you'll have to change the fork code also.
196  * The code which creates the new task context is in 'copy_thread'
197  * in arch/ppc/kernel/process.c
198  */     
199 _GLOBAL(_switch)
200         stwu    r1,-INT_FRAME_SIZE(r1)
201         stw     r0,GPR0(r1)
202         lwz     r0,0(r1)
203         stw     r0,GPR1(r1)
204         /* r3-r13 are caller saved -- Cort */
205         SAVE_GPR(2, r1)
206         SAVE_8GPRS(14, r1)
207         SAVE_10GPRS(22, r1)
208         mflr    r20             /* Return to switch caller */
209         mfmsr   r22
210         li      r0,MSR_FP       /* Disable floating-point */
211         andc    r22,r22,r0
212         stw     r20,_NIP(r1)
213         stw     r22,_MSR(r1)
214         stw     r20,_LINK(r1)
215         mfcr    r20
216         mfctr   r22
217         mfspr   r23,XER
218         stw     r20,_CCR(r1)
219         stw     r22,_CTR(r1)
220         stw     r23,_XER(r1)
221         li      r0,0x0ff0
222         stw     r0,TRAP(r1)
223         stw     r1,KSP(r3)      /* Set old stack pointer */
224         sync
225         tophys(r0,r4)
226         mtspr   SPRG3,r0        /* Update current THREAD phys addr */
227 #ifdef CONFIG_8xx
228         /* XXX it would be nice to find a SPRGx for this on 6xx,7xx too */
229         lwz     r9,PGDIR(r4)    /* cache the page table root */
230         tophys(r9,r9)           /* convert to phys addr */
231         mtspr   M_TWB,r9        /* Update MMU base address */
232 #endif /* CONFIG_8xx */
233         lwz     r1,KSP(r4)      /* Load new stack pointer */
234         /* save the old current 'last' for return value */
235         mr      r3,r2
236         addi    r2,r4,-THREAD   /* Update current */
237         lwz     r9,_MSR(r1)     /* Returning to user mode? */
238         andi.   r9,r9,MSR_PR
239         beq+    10f             /* if not, don't adjust kernel stack */
240 8:      addi    r4,r1,INT_FRAME_SIZE    /* size of frame */
241         stw     r4,THREAD+KSP(r2)       /* save kernel stack pointer */
242         tophys(r9,r1)
243         mtspr   SPRG2,r9        /* phys exception stack pointer */
244 10:     lwz     r2,_CTR(r1)
245         lwz     r0,_LINK(r1)
246         mtctr   r2
247         mtlr    r0
248         lwz     r2,_XER(r1)
249         lwz     r0,_CCR(r1)
250         mtspr   XER,r2
251         mtcrf   0xFF,r0
252         /* r3-r13 are destroyed -- Cort */
253         REST_GPR(14, r1)
254         REST_8GPRS(15, r1)
255         REST_8GPRS(23, r1)
256         REST_GPR(31, r1)
257         lwz     r2,_NIP(r1)     /* Restore environment */
258         lwz     r0,_MSR(r1)
259         mtspr   SRR0,r2
260         mtspr   SRR1,r0
261         lwz     r0,GPR0(r1)
262         lwz     r2,GPR2(r1)
263         lwz     r1,GPR1(r1)
264         SYNC
265         rfi
268  * ret_from_int():
270  * Return from an interrupt (external interrupt and
271  * decrementer).  This checks the first argument so
272  * we know if rtl_intercept wants us to check for
273  * a bottom half, signals and so on (normal return) or
274  * we're returning from a real-time interrupt or have
275  * interrupts soft disabled so we cannot enter Linux.
276  *   -- Cort
277  */
278         .globl  ret_from_int
279 ret_from_int:
280         cmpi    0,r3,0
281         beq     10f
282         /* we're allowed to do signal/bh checks */
283         b       ret_from_syscall
284 #ifdef __SMP__  
285         .globl  ret_from_smpfork
286 ret_from_smpfork:
287         bl      schedule_tail
288 #endif
289         .globl  ret_from_syscall
290 ret_from_syscall:
291         .globl  ret_from_except
292 ret_from_except:
293 0:      mfmsr   r30             /* Disable interrupts */
294         li      r3,0
295         ori     r3,r3,MSR_EE
296         andc    r30,r30,r3
297         SYNC                    /* Some chip revs need this... */
298         mtmsr   r30
299         SYNC
300         lwz     r5,_MSR(r1)
301         and.    r5,r5,r4
302         beq     2f
303 3:      lis     r4,ppc_n_lost_interrupts@ha
304         lwz     r4,ppc_n_lost_interrupts@l(r4)
305         cmpi    0,r4,0
306         beq+    1f
307         addi    r3,r1,STACK_FRAME_OVERHEAD
308         bl      do_IRQ
309         .globl  lost_irq_ret
310 lost_irq_ret:
311         b       3b
312 1:      lis     r4,bh_mask@ha
313         lwz     r4,bh_mask@l(r4)
314         lis     r5,bh_active@ha
315         lwz     r5,bh_active@l(r5)
316         and.    r4,r4,r5
317         beq+    2f
318         bl      do_bottom_half
319         .globl  do_bottom_half_ret
320 do_bottom_half_ret:
321 2:      SYNC
322         mtmsr   r30             /* disable interrupts again */
323         SYNC
324         lwz     r3,_MSR(r1)     /* Returning to user mode? */
325         andi.   r3,r3,MSR_PR
326         beq+    10f             /* if so, check need_resched and signals */
327         lwz     r3,NEED_RESCHED(r2)
328         cmpi    0,r3,0          /* check need_resched flag */
329         beq+    7f
330         bl      schedule
331         b       0b
332 7:      lwz     r5,SIGPENDING(r2) /* Check for pending unblocked signals */
333         cmpwi   0,r5,0
334         beq+    8f
335         li      r3,0
336         addi    r4,r1,STACK_FRAME_OVERHEAD
337         bl      do_signal
338         .globl  do_signal_ret
339 do_signal_ret:
340         b       0b
341 8:      addi    r4,r1,INT_FRAME_SIZE    /* size of frame */
342         stw     r4,THREAD+KSP(r2)       /* save kernel stack pointer */
343         tophys(r3,r1)
344         mtspr   SPRG2,r3        /* phys exception stack pointer */
345 10:     lwz     r2,_CTR(r1)
346         lwz     r0,_LINK(r1)
347         mtctr   r2
348         mtlr    r0
349         lwz     r2,_XER(r1)
350         lwz     r0,_CCR(r1)
351         mtspr   XER,r2
352         mtcrf   0xFF,r0
353         REST_10GPRS(3, r1)
354         REST_10GPRS(13, r1)
355         REST_8GPRS(23, r1)
356         REST_GPR(31, r1)
357         lwz     r2,_NIP(r1)     /* Restore environment */
358         lwz     r0,_MSR(r1)
359         mtspr   SRR0,r2
360         mtspr   SRR1,r0
361         lwz     r0,GPR0(r1)
362         lwz     r2,GPR2(r1)
363         lwz     r1,GPR1(r1)
364         SYNC
365         rfi
368  * Fake an interrupt from kernel mode.
369  * This is used when enable_irq loses an interrupt.
370  * We only fill in the stack frame minimally.
371  */
372 _GLOBAL(fake_interrupt)
373         mflr    r0
374         stw     r0,4(r1)
375         stwu    r1,-INT_FRAME_SIZE(r1)
376         stw     r0,_NIP(r1)
377         stw     r0,_LINK(r1)
378         mfmsr   r3
379         stw     r3,_MSR(r1)
380         li      r0,0x0fac
381         stw     r0,TRAP(r1)
382         addi    r3,r1,STACK_FRAME_OVERHEAD
383         li      r4,1
384         bl      do_IRQ
385         addi    r1,r1,INT_FRAME_SIZE
386         lwz     r0,4(r1)
387         mtlr    r0
388         blr
390 #ifndef CONFIG_8xx
392  * PROM code for specific machines follows.  Put it 
393  * here so it's easy to add arch-specific sections later.
394  * -- Cort
395  */
396         
398  * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
399  * called with the MMU off.
400  */
401         .globl  enter_rtas
402 enter_rtas:
403         mflr    r0
404         stw     r0,20(r1)
405         lis     r4,rtas_data@ha
406         lwz     r4,rtas_data@l(r4)
407         addis   r4,r4,-KERNELBASE@h
408         lis     r6,1f@ha        /* physical return address for rtas */
409         addi    r6,r6,1f@l
410         addis   r6,r6,-KERNELBASE@h
411         subi    r7,r1,INT_FRAME_SIZE
412         addis   r7,r7,-KERNELBASE@h
413         lis     r8,rtas_entry@ha
414         lwz     r8,rtas_entry@l(r8)
415         addis   r5,r8,-KERNELBASE@h
416         mfmsr   r9
417         stw     r9,8(r1)
418         ori     r0,r0,MSR_EE|MSR_SE|MSR_BE
419         andc    r0,r9,r0
420         andi.   r9,r9,MSR_ME|MSR_RI
421         sync                    /* disable interrupts so SRR0/1 */
422         mtmsr   r0              /* don't get trashed */
423         mtlr    r6
424         mtspr   SPRG2,r7
425         mtspr   SRR0,r8
426         mtspr   SRR1,r9
427         rfi
428 1:      addis   r9,r1,-KERNELBASE@h
429         lwz     r8,20(r9)       /* get return address */
430         lwz     r9,8(r9)        /* original msr value */
431         li      r0,0
432         mtspr   SPRG2,r0
433         mtspr   SRR0,r8
434         mtspr   SRR1,r9
435         rfi                     /* return to caller */
436 #endif /* CONFIG_8xx */