aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
-rw-r--r--arch/powerpc/kernel/signal_32.c50
1 files changed, 38 insertions, 12 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index e6474a45cef5..2d47cc79e5b3 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -470,9 +470,9 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
470 return 1; 470 return 1;
471 471
472 if (sigret) { 472 if (sigret) {
473 /* Set up the sigreturn trampoline: li r0,sigret; sc */ 473 /* Set up the sigreturn trampoline: li 0,sigret; sc */
474 if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) 474 if (__put_user(PPC_INST_ADDI + sigret, &frame->tramp[0])
475 || __put_user(0x44000002UL, &frame->tramp[1])) 475 || __put_user(PPC_INST_SC, &frame->tramp[1]))
476 return 1; 476 return 1;
477 flush_icache_range((unsigned long) &frame->tramp[0], 477 flush_icache_range((unsigned long) &frame->tramp[0],
478 (unsigned long) &frame->tramp[2]); 478 (unsigned long) &frame->tramp[2]);
@@ -619,9 +619,9 @@ static int save_tm_user_regs(struct pt_regs *regs,
619 if (__put_user(msr, &frame->mc_gregs[PT_MSR])) 619 if (__put_user(msr, &frame->mc_gregs[PT_MSR]))
620 return 1; 620 return 1;
621 if (sigret) { 621 if (sigret) {
622 /* Set up the sigreturn trampoline: li r0,sigret; sc */ 622 /* Set up the sigreturn trampoline: li 0,sigret; sc */
623 if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) 623 if (__put_user(PPC_INST_ADDI + sigret, &frame->tramp[0])
624 || __put_user(0x44000002UL, &frame->tramp[1])) 624 || __put_user(PPC_INST_SC, &frame->tramp[1]))
625 return 1; 625 return 1;
626 flush_icache_range((unsigned long) &frame->tramp[0], 626 flush_icache_range((unsigned long) &frame->tramp[0],
627 (unsigned long) &frame->tramp[2]); 627 (unsigned long) &frame->tramp[2]);
@@ -848,7 +848,23 @@ static long restore_tm_user_regs(struct pt_regs *regs,
848 /* If TM bits are set to the reserved value, it's an invalid context */ 848 /* If TM bits are set to the reserved value, it's an invalid context */
849 if (MSR_TM_RESV(msr_hi)) 849 if (MSR_TM_RESV(msr_hi))
850 return 1; 850 return 1;
851 /* Pull in the MSR TM bits from the user context */ 851
852 /*
853 * Disabling preemption, since it is unsafe to be preempted
854 * with MSR[TS] set without recheckpointing.
855 */
856 preempt_disable();
857
858 /*
859 * CAUTION:
860 * After regs->MSR[TS] being updated, make sure that get_user(),
861 * put_user() or similar functions are *not* called. These
862 * functions can generate page faults which will cause the process
863 * to be de-scheduled with MSR[TS] set but without calling
864 * tm_recheckpoint(). This can cause a bug.
865 *
866 * Pull in the MSR TM bits from the user context
867 */
852 regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK); 868 regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK);
853 /* Now, recheckpoint. This loads up all of the checkpointed (older) 869 /* Now, recheckpoint. This loads up all of the checkpointed (older)
854 * registers, including FP and V[S]Rs. After recheckpointing, the 870 * registers, including FP and V[S]Rs. After recheckpointing, the
@@ -873,6 +889,8 @@ static long restore_tm_user_regs(struct pt_regs *regs,
873 } 889 }
874#endif 890#endif
875 891
892 preempt_enable();
893
876 return 0; 894 return 0;
877} 895}
878#endif 896#endif
@@ -1140,11 +1158,11 @@ SYSCALL_DEFINE0(rt_sigreturn)
1140{ 1158{
1141 struct rt_sigframe __user *rt_sf; 1159 struct rt_sigframe __user *rt_sf;
1142 struct pt_regs *regs = current_pt_regs(); 1160 struct pt_regs *regs = current_pt_regs();
1161 int tm_restore = 0;
1143#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 1162#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
1144 struct ucontext __user *uc_transact; 1163 struct ucontext __user *uc_transact;
1145 unsigned long msr_hi; 1164 unsigned long msr_hi;
1146 unsigned long tmp; 1165 unsigned long tmp;
1147 int tm_restore = 0;
1148#endif 1166#endif
1149 /* Always make any pending restarted system calls return -EINTR */ 1167 /* Always make any pending restarted system calls return -EINTR */
1150 current->restart_block.fn = do_no_restart_syscall; 1168 current->restart_block.fn = do_no_restart_syscall;
@@ -1192,11 +1210,19 @@ SYSCALL_DEFINE0(rt_sigreturn)
1192 goto bad; 1210 goto bad;
1193 } 1211 }
1194 } 1212 }
1195 if (!tm_restore) 1213 if (!tm_restore) {
1196 /* Fall through, for non-TM restore */ 1214 /*
1215 * Unset regs->msr because ucontext MSR TS is not
1216 * set, and recheckpoint was not called. This avoid
1217 * hitting a TM Bad thing at RFID
1218 */
1219 regs->msr &= ~MSR_TS_MASK;
1220 }
1221 /* Fall through, for non-TM restore */
1197#endif 1222#endif
1198 if (do_setcontext(&rt_sf->uc, regs, 1)) 1223 if (!tm_restore)
1199 goto bad; 1224 if (do_setcontext(&rt_sf->uc, regs, 1))
1225 goto bad;
1200 1226
1201 /* 1227 /*
1202 * It's not clear whether or why it is desirable to save the 1228 * It's not clear whether or why it is desirable to save the