2 * arch/ppc/kernel/entry.S
4 * $Id: entry.S,v 1.2 1999/08/23 02:53:16 paulus Exp $
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).
16 * This file contains the system call entry code, context switch
17 * code, and exception/interrupt return code for PowerPC.
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.
27 #include <asm/processor.h>
29 #include <linux/errno.h>
30 #include <linux/sys.h>
31 #include <linux/config.h>
34 #define SHOW_SYSCALLS_TASK
36 #ifdef SHOW_SYSCALLS_TASK
43 * Handle a system call.
47 stw r0,THREAD+LAST_SYSCALL(r2)
48 lwz r11,_CCR(r1) /* Clear SO bit in CR */
53 #ifdef SHOW_SYSCALLS_TASK
54 lis r31,show_syscalls_task@ha
55 lwz r31,show_syscalls_task@l(r31)
82 #endif /* SHOW_SYSCALLS */
83 cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
85 lwz r10,TASK_FLAGS(r2)
86 andi. r10,r10,PF_TRACESYS
88 cmpli 0,r0,NR_syscalls
90 lis r10,sys_call_table@h
91 ori r10,r10,sys_call_table@l
93 lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
97 addi r9,r1,STACK_FRAME_OVERHEAD
98 blrl /* Call handler */
99 .globl ret_from_syscall_1
101 20: stw r3,RESULT(r1) /* Save result */
103 #ifdef SHOW_SYSCALLS_TASK
118 cmpi 0,r3,ERESTARTNOHAND
121 22: lwz r10,_CCR(r1) /* Set SO bit in CR */
124 30: stw r3,GPR3(r1) /* Update return value */
129 10: addi r3,r1,STACK_FRAME_OVERHEAD
131 cmpi 0,r3,0 /* Check for restarted system call */
134 /* Traced system call support */
136 lwz r0,GPR0(r1) /* Restore original registers */
144 cmpli 0,r0,NR_syscalls
146 lis r10,sys_call_table@h
147 ori r10,r10,sys_call_table@l
149 lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
153 addi r9,r1,STACK_FRAME_OVERHEAD
154 blrl /* Call handler */
155 .globl ret_from_syscall_2
157 stw r3,RESULT(r1) /* Save result */
158 stw r3,GPR0(r1) /* temporary gross hack to make strace work */
163 cmpi 0,r3,ERESTARTNOHAND
166 52: lwz r10,_CCR(r1) /* Set SO bit in CR */
169 60: stw r3,GPR3(r1) /* Update return value */
175 7: .string "syscall %d(%x, %x, %x, %x, %x, "
176 77: .string "%x, %x), current=%p\n"
177 79: .string " -> %x\n"
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
200 stwu r1,-INT_FRAME_SIZE(r1)
204 /* r3-r13 are caller saved -- Cort */
208 mflr r20 /* Return to switch caller */
210 li r0,MSR_FP /* Disable floating-point */
223 stw r1,KSP(r3) /* Set old stack pointer */
226 mtspr SPRG3,r0 /* Update current THREAD phys addr */
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 */
236 addi r2,r4,-THREAD /* Update current */
237 lwz r9,_MSR(r1) /* Returning to user mode? */
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 */
243 mtspr SPRG2,r9 /* phys exception stack pointer */
252 /* r3-r13 are destroyed -- Cort */
257 lwz r2,_NIP(r1) /* Restore environment */
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.
282 /* we're allowed to do signal/bh checks */
285 .globl ret_from_smpfork
289 .globl ret_from_syscall
291 .globl ret_from_except
293 0: mfmsr r30 /* Disable interrupts */
297 SYNC /* Some chip revs need this... */
303 3: lis r4,ppc_n_lost_interrupts@ha
304 lwz r4,ppc_n_lost_interrupts@l(r4)
307 addi r3,r1,STACK_FRAME_OVERHEAD
315 lwz r5,bh_active@l(r5)
319 .globl do_bottom_half_ret
322 mtmsr r30 /* disable interrupts again */
324 lwz r3,_MSR(r1) /* Returning to user mode? */
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 */
332 7: lwz r5,SIGPENDING(r2) /* Check for pending unblocked signals */
336 addi r4,r1,STACK_FRAME_OVERHEAD
341 8: addi r4,r1,INT_FRAME_SIZE /* size of frame */
342 stw r4,THREAD+KSP(r2) /* save kernel stack pointer */
344 mtspr SPRG2,r3 /* phys exception stack pointer */
357 lwz r2,_NIP(r1) /* Restore environment */
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.
372 _GLOBAL(fake_interrupt)
375 stwu r1,-INT_FRAME_SIZE(r1)
382 addi r3,r1,STACK_FRAME_OVERHEAD
385 addi r1,r1,INT_FRAME_SIZE
392 * PROM code for specific machines follows. Put it
393 * here so it's easy to add arch-specific sections later.
398 * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
399 * called with the MMU off.
406 lwz r4,rtas_data@l(r4)
407 addis r4,r4,-KERNELBASE@h
408 lis r6,1f@ha /* physical return address for rtas */
410 addis r6,r6,-KERNELBASE@h
411 subi r7,r1,INT_FRAME_SIZE
412 addis r7,r7,-KERNELBASE@h
414 lwz r8,rtas_entry@l(r8)
415 addis r5,r8,-KERNELBASE@h
418 ori r0,r0,MSR_EE|MSR_SE|MSR_BE
420 andi. r9,r9,MSR_ME|MSR_RI
421 sync /* disable interrupts so SRR0/1 */
422 mtmsr r0 /* don't get trashed */
428 1: addis r9,r1,-KERNELBASE@h
429 lwz r8,20(r9) /* get return address */
430 lwz r9,8(r9) /* original msr value */
435 rfi /* return to caller */
436 #endif /* CONFIG_8xx */