patch-2.4.19 linux-2.4.19/arch/ppc64/kernel/entry.S
Next file: linux-2.4.19/arch/ppc64/kernel/flight_recorder.c
Previous file: linux-2.4.19/arch/ppc64/kernel/eeh.c
Back to the patch index
Back to the overall index
- Lines: 611
- Date:
Fri Aug 2 17:39:43 2002
- Orig file:
linux-2.4.18/arch/ppc64/kernel/entry.S
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN linux-2.4.18/arch/ppc64/kernel/entry.S linux-2.4.19/arch/ppc64/kernel/entry.S
@@ -0,0 +1,610 @@
+/*
+ * arch/ppc64/kernel/entry.S
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ * Adapted for Power Macintosh by Paul Mackerras.
+ * Low-level exception handlers and MMU support
+ * rewritten by Paul Mackerras.
+ * Copyright (C) 1996 Paul Mackerras.
+ * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
+ *
+ * This file contains the system call entry code, context switch
+ * code, and exception/interrupt return code for PowerPC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "ppc_asm.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <linux/errno.h>
+#include <linux/sys.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_PPC_ISERIES
+#define DO_SOFT_DISABLE
+#endif
+
+#undef SHOW_SYSCALLS
+#undef SHOW_SYSCALLS_TASK
+
+#ifdef SHOW_SYSCALLS_TASK
+ .data
+show_syscalls_task:
+ .long -1
+#endif
+
+/*
+ * Handle a system call.
+ */
+ .text
+_GLOBAL(DoSyscall)
+ std r0,THREAD+LAST_SYSCALL(r13)
+ ld r11,_CCR(r1) /* Clear SO bit in CR */
+ lis r10,0x1000
+ andc r11,r11,r10
+ std r11,_CCR(r1)
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+ LOADBASE(r31,show_syscalls_task)
+ ld r31,show_syscalls_task@l(r31)
+ cmp 0,r13,r31
+ bne 1f
+#endif
+ LOADADDR(r3,7f)
+ ld r4,GPR0(r1)
+ ld r5,GPR3(r1)
+ ld r6,GPR4(r1)
+ ld r7,GPR5(r1)
+ ld r8,GPR6(r1)
+ ld r9,GPR7(r1)
+ bl .printk
+ LOADADDR(r3,77f)
+ ld r4,GPR8(r1)
+ ld r5,GPR9(r1)
+ mr r6,r13
+ bl .printk
+ ld r0,GPR0(r1)
+ ld r3,GPR3(r1)
+ ld r4,GPR4(r1)
+ ld r5,GPR5(r1)
+ ld r6,GPR6(r1)
+ ld r7,GPR7(r1)
+ ld r8,GPR8(r1)
+1:
+#endif /* SHOW_SYSCALLS */
+ ld r10,TASK_PTRACE(r13)
+ andi. r10,r10,PT_TRACESYS
+ bne- 50f
+ cmpli 0,r0,NR_syscalls
+ bge- 66f
+/* Ken Aaker: Need to vector to 32 Bit or default sys_call_table here,
+ * based on caller's run-mode / personality.
+ *
+ */
+#ifdef CONFIG_BINFMT_ELF32
+ ld r10,THREAD+THREAD_FLAGS(r13)
+ andi. r10,r10,PPC_FLAG_32BIT
+ beq- 15f
+ LOADADDR(r10,.sys_call_table32)
+/* Now mung the first 4 parameters into shape, by making certain that
+ * the high bits (most significant 32 bits in 64 bit reg) are 0
+ * for the first 4 parameter regs(3-6).
+ */
+ clrldi r3,r3,32
+ clrldi r4,r4,32
+ clrldi r5,r5,32
+ clrldi r6,r6,32
+ b 17f
+15:
+#endif
+ LOADADDR(r10,.sys_call_table)
+17:
+ slwi r0,r0,3
+ ldx r10,r10,r0 /* Fetch system call handler [ptr] */
+ mtlr r10
+ addi r9,r1,STACK_FRAME_OVERHEAD
+ blrl /* Call handler */
+_GLOBAL(ret_from_syscall_1)
+20: std r3,RESULT(r1) /* Save result */
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+ cmp 0,r13,r31
+ bne 91f
+#endif
+ mr r4,r3
+ LOADADDR(r3,79f)
+ bl .printk
+ ld r3,RESULT(r1)
+91:
+#endif
+ li r10,-_LAST_ERRNO
+ cmpl 0,r3,r10
+ blt 30f
+ neg r3,r3
+ cmpi 0,r3,ERESTARTNOHAND
+ bne 22f
+ li r3,EINTR
+22: ld r10,_CCR(r1) /* Set SO bit in CR */
+ oris r10,r10,0x1000
+ std r10,_CCR(r1)
+30: std r3,GPR3(r1) /* Update return value */
+ b .ret_from_except
+66: li r3,ENOSYS
+ b 22b
+
+/* Traced system call support */
+50: bl .syscall_trace
+ ld r0,GPR0(r1) /* Restore original registers */
+ ld r3,GPR3(r1)
+ ld r4,GPR4(r1)
+ ld r5,GPR5(r1)
+ ld r6,GPR6(r1)
+ ld r7,GPR7(r1)
+ ld r8,GPR8(r1)
+ ld r9,GPR9(r1)
+ cmpli 0,r0,NR_syscalls
+ bge- 66f
+#ifdef CONFIG_BINFMT_ELF32
+ ld r10,THREAD+THREAD_FLAGS(r13)
+ andi. r10,r10,PPC_FLAG_32BIT
+ beq- 55f
+ LOADADDR(r10,.sys_call_table32)
+/* Now mung the first 4 parameters into shape, by making certain that
+ * the high bits (most significant 32 bits in 64 bit reg) are 0
+ * for the first 4 parameter regs(3-6).
+ */
+ clrldi r3,r3,32
+ clrldi r4,r4,32
+ clrldi r5,r5,32
+ clrldi r6,r6,32
+ b 57f
+55:
+#endif
+ LOADADDR(r10,.sys_call_table)
+57:
+ slwi r0,r0,3
+ ldx r10,r10,r0 /* Fetch system call handler [ptr] */
+ mtlr r10
+ addi r9,r1,STACK_FRAME_OVERHEAD
+ blrl /* Call handler */
+_GLOBAL(ret_from_syscall_2)
+58: std r3,RESULT(r1) /* Save result */
+ std r3,GPR0(r1) /* temporary gross hack to make strace work */
+ li r10,-_LAST_ERRNO
+ cmpl 0,r3,r10
+ blt 60f
+ neg r3,r3
+ cmpi 0,r3,ERESTARTNOHAND
+ bne 57f
+ li r3,EINTR
+57: ld r10,_CCR(r1) /* Set SO bit in CR */
+ oris r10,r10,0x1000
+ std r10,_CCR(r1)
+60: std r3,GPR3(r1) /* Update return value */
+ bl .syscall_trace
+ b .ret_from_except
+66: li r3,ENOSYS
+ b 57b
+#ifdef SHOW_SYSCALLS
+7: .string "syscall %d(%x, %x, %x, %x, %x, "
+77: .string "%x, %x), current=%p\n"
+79: .string " -> %x\n"
+ .align 2,0
+#endif
+
+_GLOBAL(ppc32_sigreturn)
+ bl .sys32_sigreturn
+ b 80f
+
+_GLOBAL(ppc32_rt_sigreturn)
+ bl .sys32_rt_sigreturn
+ b 80f
+
+_GLOBAL(ppc64_sigreturn)
+ bl .sys_sigreturn
+ b 80f
+
+_GLOBAL(ppc64_rt_sigreturn)
+ bl .sys_rt_sigreturn
+
+80: ld r10,TASK_PTRACE(r13)
+ andi. r10,r10,PT_TRACESYS
+ bne- 81f
+ cmpi 0,r3,0
+ bge .ret_from_except
+ b 20b
+81: cmpi 0,r3,0
+ blt 58b
+ bl .syscall_trace
+ b .ret_from_except
+
+/*
+ * This routine switches between two different tasks. The process
+ * state of one is saved on its kernel stack. Then the state
+ * of the other is restored from its kernel stack. The memory
+ * management hardware is updated to the second process's state.
+ * Finally, we can return to the second process, via ret_from_except.
+ * On entry, r3 points to the THREAD for the current task, r4
+ * points to the THREAD for the new task.
+ *
+ * Note: there are two ways to get to the "going out" portion
+ * of this code; either by coming in via the entry (_switch)
+ * or via "fork" which must set up an environment equivalent
+ * to the "_switch" path. If you change this (or in particular, the
+ * SAVE_REGS macro), you'll have to change the fork code also.
+ *
+ * The code which creates the new task context is in 'copy_thread'
+ * in arch/ppc64/kernel/process.c
+ */
+_GLOBAL(_switch)
+ stdu r1,-INT_FRAME_SIZE(r1)
+ ld r6,0(r1)
+ std r6,GPR1(r1)
+ /* r3-r13 are caller saved -- Cort */
+ SAVE_GPR(2, r1)
+ SAVE_8GPRS(14, r1)
+ SAVE_10GPRS(22, r1)
+ mflr r20 /* Return to switch caller */
+ mfmsr r22
+ li r6,MSR_FP /* Disable floating-point */
+ andc r22,r22,r6
+ mtmsrd r22
+ isync
+ std r20,_NIP(r1)
+ std r22,_MSR(r1)
+ std r20,_LINK(r1)
+ mfcr r20
+ std r20,_CCR(r1)
+ li r6,0x0ff0
+ std r6,TRAP(r1)
+ std r1,KSP(r3) /* Set old stack pointer */
+
+ mfspr r5,SPRG3 /* Get Paca */
+ addi r3,r3,-THREAD /* old 'current' for return value */
+ addi r13,r4,-THREAD /* Convert THREAD to 'current' */
+ std r13,PACACURRENT(r5) /* Set new 'current' */
+
+#ifdef CONFIG_PPC_ISERIES
+ ld r7,THREAD_FLAGS(r4) /* Get run light flag */
+ mfspr r9,CTRLF
+ srdi r7,r7,1 /* Align to run light bit in CTRL reg */
+ insrdi r9,r7,1,63 /* Insert run light into CTRL */
+ mtspr CTRLT,r9
+#endif
+ ld r1,KSP(r4) /* Load new stack pointer */
+ ld r6,_CCR(r1)
+ mtcrf 0xFF,r6
+ /* r3-r13 are destroyed -- Cort */
+ REST_8GPRS(14, r1)
+ REST_10GPRS(22, r1)
+
+ ld r7,_NIP(r1) /* Return to _switch caller in new task */
+ ld r1,GPR1(r1)
+ mtlr r7
+ blr
+
+_GLOBAL(ret_from_fork)
+ bl .schedule_tail
+ ld r0,TASK_PTRACE(r13)
+ andi. r0,r0,PT_TRACESYS
+ beq+ .ret_from_except
+ bl .syscall_trace
+ b .ret_from_except
+
+_GLOBAL(ret_from_except)
+#ifdef CONFIG_PPC_ISERIES
+ ld r5,SOFTE(r1)
+ cmpdi 0,r5,0
+ beq 4f
+irq_recheck:
+ /*
+ * Check for pending interrupts (iSeries)
+ */
+ CHECKANYINT(r3,r4)
+ beq+ 4f /* skip do_IRQ if no interrupts */
+
+ mfspr r5,SPRG3
+ li r3,0
+ stb r3,PACAPROCENABLED(r5) /* ensure we are disabled */
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .do_IRQ
+ b irq_recheck /* loop back and handle more */
+4:
+#endif
+_GLOBAL(do_bottom_half_ret)
+ ld r3,_MSR(r1) /* Returning to user mode? */
+ andi. r3,r3,MSR_PR
+ beq+ restore /* if so, check need_resched and signals */
+_GLOBAL(ret_to_user_hook)
+ nop
+ /* NEED_RESCHED is a volatile long (64-bits) */
+ ld r3,NEED_RESCHED(r13)
+ cmpi 0,r3,0 /* check need_resched flag */
+ beq+ 7f
+ bl .schedule
+ /* SIGPENDING is an int (32-bits) */
+7:
+ lwz r5,SIGPENDING(r13) /* Check for pending unblocked signals */
+ cmpwi 0,r5,0
+ beq+ restore
+ li r3,0
+ addi r4,r1,STACK_FRAME_OVERHEAD
+ bl .do_signal
+_GLOBAL(do_signal_ret)
+restore:
+ ld r3,_CTR(r1)
+ ld r0,_LINK(r1)
+ mtctr r3
+ mtlr r0
+ ld r3,_XER(r1)
+ mtspr XER,r3
+ REST_8GPRS(5, r1)
+ REST_10GPRS(14, r1)
+ REST_8GPRS(24, r1)
+
+ /* make sure we hard disable here, even if rtl is active, to protect
+ * SRR[01] and SPRG2 -- Cort
+ */
+ mfmsr r0 /* Get current interrupt state */
+ li r4,0
+ ori r4,r4,MSR_EE|MSR_RI
+ andc r0,r0,r4 /* clear MSR_EE and MSR_RI */
+ mtmsrd r0 /* Update machine state */
+#ifdef CONFIG_PPC_ISERIES
+ ld r0,SOFTE(r1)
+ cmpi 0,r0,0
+ beq+ 1f
+
+ CHECKANYINT(r4,r3)
+ beq+ 1f
+ mfmsr r0
+ ori r0,r0,MSR_EE|MSR_RI
+ mtmsrd r0
+ b irq_recheck
+
+1:
+#endif
+ stdcx. r0,0,r1 /* to clear the reservation */
+
+ mfspr r4,SPRG3 /* current task's PACA */
+#ifdef DO_SOFT_DISABLE
+ ld r0,SOFTE(r1)
+ stb r0,PACAPROCENABLED(r4)
+#endif
+ /* if returning to user mode, save kernel SP */
+ ld r0,_MSR(r1)
+ andi. r0,r0,MSR_PR
+ beq+ 1f
+ addi r0,r1,INT_FRAME_SIZE /* size of frame */
+ std r0,THREAD+KSP(r13) /* save kernel stack pointer */
+ std r1,PACAKSAVE(r4) /* save exception stack pointer */
+1:
+ ld r0,_MSR(r1)
+ mtspr SRR1,r0
+ ld r2,_CCR(r1)
+ mtcrf 0xFF,r2
+ ld r2,_NIP(r1)
+ mtspr SRR0,r2
+ REST_GPR(13,r1)
+ ld r0,GPR0(r1)
+ ld r2,GPR2(r1)
+ ld r3,GPR3(r1)
+ ld r4,GPR4(r1)
+ ld r1,GPR1(r1)
+
+ rfid
+
+/*
+ * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
+ * called with the MMU off.
+ *
+ * In addition, we need to be in 32b mode, at least for now.
+ *
+ * Note: r3 is an input parameter to rtas, so don't trash it...
+ */
+_GLOBAL(enter_rtas)
+ mflr r0
+ std r0,16(r1)
+ stdu r1,-RTAS_FRAME_SIZE(r1) /* Save SP and create stack space. */
+
+ /* Because RTAS is running in 32b mode, it clobbers the high order half
+ * of all registers that it saves. We therefore save those registers
+ * RTAS might touch to the stack. (r0, r3-r13 are caller saved)
+ */
+ SAVE_GPR(2, r1) /* Save the TOC */
+ SAVE_GPR(13, r1) /* Save current */
+ SAVE_8GPRS(14, r1) /* Save the non-volatiles */
+ SAVE_10GPRS(22, r1) /* ditto */
+
+ mfcr r4
+ std r4,_CCR(r1)
+ mfctr r5
+ std r5,_CTR(r1)
+ mfspr r6,XER
+ std r6,_XER(r1)
+ mfdar r7
+ std r7,_DAR(r1)
+ mfdsisr r8
+ std r8,_DSISR(r1)
+ mfsrr0 r9
+ std r9,_SRR0(r1)
+ mfsrr1 r10
+ std r10,_SRR1(r1)
+
+ /* Unfortunatly, the stack pointer and the MSR are also clobbered,
+ * so they are saved in the PACA (SPRG3) which allows us to restore
+ * our original state after RTAS returns.
+ */
+ mfspr r4,SPRG3 /* Get PACA */
+ std r1,PACAR1(r4)
+ mfmsr r6
+ std r6,PACASAVEDMSR(r4)
+
+ /* Setup our real return addr */
+ SET_REG_TO_LABEL(r4,.rtas_return_loc)
+ SET_REG_TO_CONST(r9,KERNELBASE)
+ sub r4,r4,r9
+ mtlr r4
+
+ li r0,0
+ ori r0,r0,MSR_EE|MSR_SE|MSR_BE|MSR_RI
+ andc r0,r6,r0
+
+ li r9,1
+ rldicr r9,r9,MSR_SF_LG,(63-MSR_SF_LG)
+ ori r9,r9,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP|MSR_RI
+ andc r6,r0,r9
+ sync /* disable interrupts so SRR0/1 */
+ mtmsrd r0 /* don't get trashed */
+
+ SET_REG_TO_LABEL(r4,rtas)
+ ld r5,RTASENTRY(r4) /* get the rtas->entry value */
+ ld r4,RTASBASE(r4) /* get the rtas->base value */
+
+ mtspr SRR0,r5
+ mtspr SRR1,r6
+ rfid
+
+_STATIC(rtas_return_loc)
+ /* relocation is off at this point */
+ mfspr r4,SPRG3 /* Get PACA */
+ SET_REG_TO_CONST(r5, KERNELBASE)
+ sub r4,r4,r5 /* RELOC the PACA base pointer */
+
+ ld r1,PACAR1(r4) /* Restore our SP */
+ LOADADDR(r3,.rtas_restore_regs)
+ ld r4,PACASAVEDMSR(r4) /* Restore our MSR */
+
+ mtspr SRR0,r3
+ mtspr SRR1,r4
+ rfid
+
+_STATIC(rtas_restore_regs)
+ /* relocation is on at this point */
+ REST_GPR(2, r1) /* Restore the TOC */
+ REST_GPR(13, r1) /* Restore current */
+ REST_8GPRS(14, r1) /* Restore the non-volatiles */
+ REST_10GPRS(22, r1) /* ditto */
+
+ /* put back current in r13 */
+ mfspr r4,SPRG3
+ ld r13,PACACURRENT(r4)
+
+ ld r4,_CCR(r1)
+ mtcr r4
+ ld r5,_CTR(r1)
+ mtctr r5
+ ld r6,_XER(r1)
+ mtspr XER,r6
+ ld r7,_DAR(r1)
+ mtdar r7
+ ld r8,_DSISR(r1)
+ mtdsisr r8
+ ld r9,_SRR0(r1)
+ mtsrr0 r9
+ ld r10,_SRR1(r1)
+ mtsrr1 r10
+
+ addi r1,r1,RTAS_FRAME_SIZE /* Unstack our frame */
+ ld r0,16(r1) /* get return address */
+
+ mtlr r0
+ blr /* return to caller */
+
+_GLOBAL(enter_prom)
+ mflr r0
+ std r0,16(r1)
+ stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
+
+ /* Because PROM is running in 32b mode, it clobbers the high order half
+ * of all registers that it saves. We therefore save those registers
+ * PROM might touch to the stack. (r0, r3-r13 are caller saved)
+ */
+ SAVE_8GPRS(2, r1) /* Save the TOC & incoming param(s) */
+ SAVE_GPR(13, r1) /* Save current */
+ SAVE_8GPRS(14, r1) /* Save the non-volatiles */
+ SAVE_10GPRS(22, r1) /* ditto */
+
+ mfcr r4
+ std r4,_CCR(r1)
+ mfctr r5
+ std r5,_CTR(r1)
+ mfspr r6,XER
+ std r6,_XER(r1)
+ mfdar r7
+ std r7,_DAR(r1)
+ mfdsisr r8
+ std r8,_DSISR(r1)
+ mfsrr0 r9
+ std r9,_SRR0(r1)
+ mfsrr1 r10
+ std r10,_SRR1(r1)
+ mfmsr r11
+ std r11,_MSR(r1)
+
+ /* Unfortunatly, the stack pointer is also clobbered, so it is saved
+ * in the SPRG2 which allows us to restore our original state after
+ * PROM returns.
+ */
+ mtspr SPRG2,r1
+
+ /* put a relocation offset into r3 */
+ bl .reloc_offset
+ LOADADDR(r12,prom)
+ sub r12,r12,r3
+ ld r12,PROMENTRY(r12) /* get the prom->entry value */
+ mtlr r12
+
+ mfmsr r11 /* grab the current MSR */
+ li r12,1
+ rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
+ andc r11,r11,r12
+ li r12,1
+ rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
+ andc r11,r11,r12
+ mtmsrd r11
+ isync
+
+ REST_8GPRS(2, r1) /* Restore the TOC & param(s) */
+ REST_GPR(13, r1) /* Restore current */
+ REST_8GPRS(14, r1) /* Restore the non-volatiles */
+ REST_10GPRS(22, r1) /* ditto */
+ blrl /* Entering PROM here... */
+
+ mfspr r1,SPRG2 /* Restore the stack pointer */
+ ld r6,_MSR(r1) /* Restore the MSR */
+ mtmsrd r6
+ isync
+
+ REST_GPR(2, r1) /* Restore the TOC */
+ REST_GPR(13, r1) /* Restore current */
+ REST_8GPRS(14, r1) /* Restore the non-volatiles */
+ REST_10GPRS(22, r1) /* ditto */
+
+ ld r4,_CCR(r1)
+ mtcr r4
+ ld r5,_CTR(r1)
+ mtctr r5
+ ld r6,_XER(r1)
+ mtspr XER,r6
+ ld r7,_DAR(r1)
+ mtdar r7
+ ld r8,_DSISR(r1)
+ mtdsisr r8
+ ld r9,_SRR0(r1)
+ mtsrr0 r9
+ ld r10,_SRR1(r1)
+ mtsrr1 r10
+ addi r1,r1,PROM_FRAME_SIZE
+ ld r0,16(r1) /* get return address */
+
+ mtlr r0
+ blr /* return to caller */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)