entry.S
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
- /*
- * 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=%pn"
- 79: .string " -> %xn"
- .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 */