/*
- * 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
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <asm/unistd.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
#include <asm/cputable.h>
-
-#ifdef CONFIG_PPC_ISERIES
-#define DO_SOFT_DISABLE
-#endif
+#include <asm/firmware.h>
+#include <asm/bug.h>
/*
* System calls.
beq- 1f
ld r1,PACAKSAVE(r13)
1: std r10,0(r1)
+ crclr so
std r11,_NIP(r1)
std r12,_MSR(r1)
std r0,GPR0(r1)
std r10,GPR1(r1)
+ ACCOUNT_CPU_USER_ENTRY(r10, r11)
std r2,GPR2(r1)
std r3,GPR3(r1)
std r4,GPR4(r1)
std r11,GPR11(r1)
std r11,GPR12(r1)
std r9,GPR13(r1)
- crclr so
mfcr r9
mflr r10
li r11,0xc01
addi r9,r1,STACK_FRAME_OVERHEAD
ld r11,exception_marker@toc(r2)
std r11,-16(r9) /* "regshere" marker */
+ li r10,1
+ stb r10,PACASOFTIRQEN(r13)
+ stb r10,PACAHARDIRQEN(r13)
+ std r10,SOFTE(r1)
#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
/* Hack for handling interrupts when soft-enabling on iSeries */
cmpdi cr1,r0,0x5555 /* syscall 0x5555 */
andi. r10,r12,MSR_PR /* from kernel */
crand 4*cr0+eq,4*cr1+eq,4*cr0+eq
- beq hardware_interrupt_entry
- lbz r10,PACAPROCENABLED(r13)
- std r10,SOFTE(r1)
+ bne 2f
+ b hardware_interrupt_entry
+2:
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
mfmsr r11
ori r11,r11,MSR_EE
mtmsrd r10,1
ld r9,TI_FLAGS(r12)
li r11,-_LAST_ERRNO
- andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR)
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK)
bne- syscall_exit_work
cmpld r3,r11
ld r5,_CCR(r1)
stdcx. r0,0,r1 /* to clear the reservation */
andi. r6,r8,MSR_PR
ld r4,_LINK(r1)
- beq- 1f /* only restore r13 if */
- ld r13,GPR13(r1) /* returning to usermode */
-1: ld r2,GPR2(r1)
+ /*
+ * Clear RI before restoring r13. If we are returning to
+ * userspace and we take an exception after restoring r13,
+ * we end up corrupting the userspace r13 value.
+ */
li r12,MSR_RI
andc r11,r10,r12
mtmsrd r11,1 /* clear MSR.RI */
+ beq- 1f
+ ACCOUNT_CPU_USER_EXIT(r11, r12)
+ ld r13,GPR13(r1) /* only restore r13 if returning to usermode */
+1: ld r2,GPR2(r1)
ld r1,GPR1(r1)
mtlr r4
mtcr r5
If TIF_NOERROR is set, just save r3 as it is. */
andi. r0,r9,_TIF_RESTOREALL
- bne- 2f
- cmpld r3,r11 /* r10 is -LAST_ERRNO */
+ beq+ 0f
+ REST_NVGPRS(r1)
+ b 2f
+0: cmpld r3,r11 /* r10 is -LAST_ERRNO */
blt+ 1f
andi. r0,r9,_TIF_NOERROR
bne- 1f
2: andi. r0,r9,(_TIF_PERSYSCALL_MASK)
beq 4f
- /* Clear per-syscall TIF flags if any are set, but _leave_
- _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
- yet. */
+ /* Clear per-syscall TIF flags if any are set. */
li r11,_TIF_PERSYSCALL_MASK
addi r12,r12,TI_FLAGS
stdcx. r10,0,r12
bne- 3b
subi r12,r12,TI_FLAGS
-
-4: bl .save_nvgprs
- /* Anything else left to do? */
- andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
+
+4: /* Anything else left to do? */
+ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
beq .ret_from_except_lite
/* Re-enable interrupts */
ori r10,r10,MSR_EE
mtmsrd r10,1
- andi. r0,r9,_TIF_SAVE_NVGPRS
- bne save_user_nvgprs
-
- /* If tracing, re-enable interrupts and do it */
-save_user_nvgprs_cont:
- andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
- beq 5f
-
+ bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
bl .do_syscall_trace_leave
- REST_NVGPRS(r1)
- clrrdi r12,r1,THREAD_SHIFT
-
- /* Disable interrupts again and handle other work if any */
-5: mfmsr r10
- rldicl r10,r10,48,1
- rotldi r10,r10,16
- mtmsrd r10,1
-
- b .ret_from_except_lite
+ b .ret_from_except
/* Save non-volatile GPRs, if not already saved. */
_GLOBAL(save_nvgprs)
std r0,_TRAP(r1)
blr
-
-save_user_nvgprs:
- ld r10,TI_SIGFRAME(r12)
- andi. r0,r9,_TIF_32BIT
- beq- save_user_nvgprs_64
-
- /* 32-bit save to userspace */
-
-.macro savewords start, end
- 1: stw \start,4*(\start)(r10)
- .section __ex_table,"a"
- .align 3
- .llong 1b,save_user_nvgprs_fault
- .previous
- .if \end - \start
- savewords "(\start+1)",\end
- .endif
-.endm
- savewords 14,31
- b save_user_nvgprs_cont
-
-save_user_nvgprs_64:
- /* 64-bit save to userspace */
-
-.macro savelongs start, end
- 1: std \start,8*(\start)(r10)
- .section __ex_table,"a"
- .align 3
- .llong 1b,save_user_nvgprs_fault
- .previous
- .if \end - \start
- savelongs "(\start+1)",\end
- .endif
-.endm
- savelongs 14,31
- b save_user_nvgprs_cont
-
-save_user_nvgprs_fault:
- li r3,11 /* SIGSEGV */
- ld r4,TI_TASK(r12)
- bl .force_sigsegv
-
- clrrdi r12,r1,THREAD_SHIFT
- ld r9,TI_FLAGS(r12)
- b save_user_nvgprs_cont
/*
* The sigsuspend and rt_sigsuspend system calls can call do_signal
bl .sys_clone
b syscall_exit
+_GLOBAL(ppc32_swapcontext)
+ bl .save_nvgprs
+ bl .compat_sys_swapcontext
+ b syscall_exit
+
+_GLOBAL(ppc64_swapcontext)
+ bl .save_nvgprs
+ bl .sys_swapcontext
+ b syscall_exit
+
_GLOBAL(ret_from_fork)
bl .schedule_tail
REST_NVGPRS(r1)
* the fork code also.
*
* The code which creates the new task context is in 'copy_thread'
- * in arch/ppc64/kernel/process.c
+ * in arch/powerpc/kernel/process.c
*/
.align 7
_GLOBAL(_switch)
ld r7,KSP_VSID(r4) /* Get new stack's VSID */
oris r0,r6,(SLB_ESID_V)@h
ori r0,r0,(SLB_NUM_BOLTED-1)@l
+
+ /* Update the last bolted SLB */
+ ld r9,PACA_SLBSHADOWPTR(r13)
+ li r12,0
+ std r12,SLBSHADOW_STACKESID(r9) /* Clear ESID */
+ std r7,SLBSHADOW_STACKVSID(r9) /* Save VSID */
+ std r0,SLBSHADOW_STACKESID(r9) /* Save ESID */
+
slbie r6
slbie r6 /* Workaround POWER5 < DD2.1 issue */
slbmte r7,r0
#endif
restore:
-#ifdef CONFIG_PPC_ISERIES
ld r5,SOFTE(r1)
+#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
cmpdi 0,r5,0
beq 4f
/* Check for pending interrupts (iSeries) */
beq+ 4f /* skip do_IRQ if no interrupts */
li r3,0
- stb r3,PACAPROCENABLED(r13) /* ensure we are soft-disabled */
+ stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */
ori r10,r10,MSR_EE
mtmsrd r10 /* hard-enable again */
addi r3,r1,STACK_FRAME_OVERHEAD
bl .do_IRQ
b .ret_from_except_lite /* loop back and handle more */
-
-4: stb r5,PACAPROCENABLED(r13)
+4:
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
+ stb r5,PACASOFTIRQEN(r13)
+ /* extract EE bit and use it to restore paca->hard_enabled */
ld r3,_MSR(r1)
+ rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */
+ stb r4,PACAHARDIRQEN(r13)
+
+ ld r4,_CTR(r1)
+ ld r0,_LINK(r1)
+ mtctr r4
+ mtlr r0
+ ld r4,_XER(r1)
+ mtspr SPRN_XER,r4
+
+ REST_8GPRS(5, r1)
+
andi. r0,r3,MSR_RI
beq- unrecov_restore
- andi. r0,r3,MSR_PR
+ stdcx. r0,0,r1 /* to clear the reservation */
+
+ /*
+ * Clear RI before restoring r13. If we are returning to
+ * userspace and we take an exception after restoring r13,
+ * we end up corrupting the userspace r13 value.
+ */
+ mfmsr r4
+ andc r4,r4,r0 /* r0 contains MSR_RI here */
+ mtmsrd r4,1
/*
* r13 is our per cpu area, only restore it if we are returning to
* userspace
*/
+ andi. r0,r3,MSR_PR
beq 1f
+ ACCOUNT_CPU_USER_EXIT(r2, r4)
REST_GPR(13, r1)
1:
- ld r3,_CTR(r1)
- ld r0,_LINK(r1)
- mtctr r3
- mtlr r0
- ld r3,_XER(r1)
- mtspr SPRN_XER,r3
-
- REST_8GPRS(5, r1)
-
- stdcx. r0,0,r1 /* to clear the reservation */
-
- mfmsr r0
- li r2, MSR_RI
- andc r0,r0,r2
- mtmsrd r0,1
-
- ld r0,_MSR(r1)
- mtspr SPRN_SRR1,r0
+ mtspr SPRN_SRR1,r3
ld r2,_CCR(r1)
mtcrf 0xFF,r2
/* Check that preempt_count() == 0 and interrupts are enabled */
lwz r8,TI_PREEMPT(r9)
cmpwi cr1,r8,0
-#ifdef CONFIG_PPC_ISERIES
ld r0,SOFTE(r1)
cmpdi r0,0
-#else
- andi. r0,r3,MSR_EE
-#endif
crandc eq,cr1*4+eq,eq
bne restore
/* here we are preempting the current task */
1:
-#ifdef CONFIG_PPC_ISERIES
li r0,1
- stb r0,PACAPROCENABLED(r13)
-#endif
+ stb r0,PACASOFTIRQEN(r13)
+ stb r0,PACAHARDIRQEN(r13)
ori r10,r10,MSR_EE
mtmsrd r10,1 /* reenable interrupts */
bl .preempt_schedule
mfsrr1 r10
std r10,_SRR1(r1)
+ /* Temporary workaround to clear CR until RTAS can be modified to
+ * ignore all bits.
+ */
+ li r0,0
+ mtcr r0
+
+#ifdef CONFIG_BUG
/* There is no way it is acceptable to get here with interrupts enabled,
* check it with the asm equivalent of WARN_ON
*/
- mfmsr r6
- andi. r0,r6,MSR_EE
+ lbz r0,PACASOFTIRQEN(r13)
1: tdnei r0,0
-.section __bug_table,"a"
- .llong 1b,__LINE__ + 0x1000000, 1f, 2f
-.previous
-.section .rodata,"a"
-1: .asciz __FILE__
-2: .asciz "enter_rtas"
-.previous
+ EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
+#endif
+ /* Hard-disable interrupts */
+ mfmsr r6
+ rldicl r7,r6,48,1
+ rotldi r7,r7,16
+ mtmsrd r7,1
+
/* Unfortunately, the stack pointer and the MSR are also clobbered,
* so they are saved in the PACA which allows us to restore
* our original state after RTAS returns.
#endif /* CONFIG_PPC_RTAS */
-#ifdef CONFIG_PPC_MULTIPLATFORM
-
_GLOBAL(enter_prom)
mflr r0
std r0,16(r1)
ld r0,16(r1)
mtlr r0
blr
-
-#endif /* CONFIG_PPC_MULTIPLATFORM */