Import 2.3.18pre1
[davej-history.git] / arch / ppc / kernel / entry.S
blobabff78bc36e922629a9ef3b1bcc27bc9e5d9926f
1 /*
2  *  arch/ppc/kernel/entry.S
3  *
4  *  $Id: entry.S,v 1.3 1999/09/05 11:56:26 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         rlwinm  r30,r30,0,17,15 /* clear MSR_EE */
295         SYNC                    /* Some chip revs need this... */
296         mtmsr   r30
297         SYNC
298         lwz     r5,_MSR(r1)
299         andi.   r5,r5,MSR_EE
300         beq     2f
301 3:      lis     r4,ppc_n_lost_interrupts@ha
302         lwz     r4,ppc_n_lost_interrupts@l(r4)
303         cmpi    0,r4,0
304         beq+    1f
305         addi    r3,r1,STACK_FRAME_OVERHEAD
306         bl      do_IRQ
307         .globl  lost_irq_ret
308 lost_irq_ret:
309         b       3b
310 1:      lis     r4,bh_mask@ha
311         lwz     r4,bh_mask@l(r4)
312         lis     r5,bh_active@ha
313         lwz     r5,bh_active@l(r5)
314         and.    r4,r4,r5
315         beq+    2f
316         bl      do_bottom_half
317         .globl  do_bottom_half_ret
318 do_bottom_half_ret:
319 2:      SYNC
320         mtmsr   r30             /* disable interrupts again */
321         SYNC
322         lwz     r3,_MSR(r1)     /* Returning to user mode? */
323         andi.   r3,r3,MSR_PR
324         beq+    10f             /* if so, check need_resched and signals */
325         lwz     r3,NEED_RESCHED(r2)
326         cmpi    0,r3,0          /* check need_resched flag */
327         beq+    7f
328         bl      schedule
329         b       0b
330 7:      lwz     r5,SIGPENDING(r2) /* Check for pending unblocked signals */
331         cmpwi   0,r5,0
332         beq+    8f
333         li      r3,0
334         addi    r4,r1,STACK_FRAME_OVERHEAD
335         bl      do_signal
336         .globl  do_signal_ret
337 do_signal_ret:
338         b       0b
339 8:      addi    r4,r1,INT_FRAME_SIZE    /* size of frame */
340         stw     r4,THREAD+KSP(r2)       /* save kernel stack pointer */
341         tophys(r3,r1)
342         mtspr   SPRG2,r3        /* phys exception stack pointer */
343 10:     lwz     r2,_CTR(r1)
344         lwz     r0,_LINK(r1)
345         mtctr   r2
346         mtlr    r0
347         lwz     r2,_XER(r1)
348         lwz     r0,_CCR(r1)
349         mtspr   XER,r2
350         mtcrf   0xFF,r0
351         REST_10GPRS(3, r1)
352         REST_10GPRS(13, r1)
353         REST_8GPRS(23, r1)
354         REST_GPR(31, r1)
355         lwz     r2,_NIP(r1)     /* Restore environment */
356         lwz     r0,_MSR(r1)
357         mtspr   SRR0,r2
358         mtspr   SRR1,r0
359         lwz     r0,GPR0(r1)
360         lwz     r2,GPR2(r1)
361         lwz     r1,GPR1(r1)
362         SYNC
363         rfi
366  * Fake an interrupt from kernel mode.
367  * This is used when enable_irq loses an interrupt.
368  * We only fill in the stack frame minimally.
369  */
370 _GLOBAL(fake_interrupt)
371         mflr    r0
372         stw     r0,4(r1)
373         stwu    r1,-INT_FRAME_SIZE(r1)
374         stw     r0,_NIP(r1)
375         stw     r0,_LINK(r1)
376         mfmsr   r3
377         stw     r3,_MSR(r1)
378         li      r0,0x0fac
379         stw     r0,TRAP(r1)
380         addi    r3,r1,STACK_FRAME_OVERHEAD
381         li      r4,1
382         bl      do_IRQ
383         addi    r1,r1,INT_FRAME_SIZE
384         lwz     r0,4(r1)
385         mtlr    r0
386         blr
388 #ifndef CONFIG_8xx
390  * PROM code for specific machines follows.  Put it 
391  * here so it's easy to add arch-specific sections later.
392  * -- Cort
393  */
394         
396  * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
397  * called with the MMU off.
398  */
399         .globl  enter_rtas
400 enter_rtas:
401         mflr    r0
402         stw     r0,20(r1)
403         lis     r4,rtas_data@ha
404         lwz     r4,rtas_data@l(r4)
405         addis   r4,r4,-KERNELBASE@h
406         lis     r6,1f@ha        /* physical return address for rtas */
407         addi    r6,r6,1f@l
408         addis   r6,r6,-KERNELBASE@h
409         subi    r7,r1,INT_FRAME_SIZE
410         addis   r7,r7,-KERNELBASE@h
411         lis     r8,rtas_entry@ha
412         lwz     r8,rtas_entry@l(r8)
413         addis   r5,r8,-KERNELBASE@h
414         mfmsr   r9
415         stw     r9,8(r1)
416         ori     r0,r0,MSR_EE|MSR_SE|MSR_BE
417         andc    r0,r9,r0
418         andi.   r9,r9,MSR_ME|MSR_RI
419         sync                    /* disable interrupts so SRR0/1 */
420         mtmsr   r0              /* don't get trashed */
421         mtlr    r6
422         mtspr   SPRG2,r7
423         mtspr   SRR0,r8
424         mtspr   SRR1,r9
425         rfi
426 1:      addis   r9,r1,-KERNELBASE@h
427         lwz     r8,20(r9)       /* get return address */
428         lwz     r9,8(r9)        /* original msr value */
429         li      r0,0
430         mtspr   SPRG2,r0
431         mtspr   SRR0,r8
432         mtspr   SRR1,r9
433         rfi                     /* return to caller */
434 #endif /* CONFIG_8xx */