Commit 02a5fec1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'powerpc-4.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc fixes from Michael Ellerman:

 - tm: Block signal return from setting invalid MSR state from Michael
   Neuling

 - tm: Check for already reclaimed tasks from Michael Neuling

* tag 'powerpc-4.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/tm: Check for already reclaimed tasks
  powerpc/tm: Block signal return setting invalid MSR state
parents 78c4a49a 7f821fc9
...@@ -108,6 +108,7 @@ ...@@ -108,6 +108,7 @@
#define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */ #define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */
#define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */ #define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */
#define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */ #define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */
#define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */
#define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T) #define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T)
#define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S) #define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S)
......
...@@ -551,6 +551,24 @@ static void tm_reclaim_thread(struct thread_struct *thr, ...@@ -551,6 +551,24 @@ static void tm_reclaim_thread(struct thread_struct *thr,
msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1; msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1;
} }
/*
* Use the current MSR TM suspended bit to track if we have
* checkpointed state outstanding.
* On signal delivery, we'd normally reclaim the checkpointed
* state to obtain stack pointer (see:get_tm_stackpointer()).
* This will then directly return to userspace without going
* through __switch_to(). However, if the stack frame is bad,
* we need to exit this thread which calls __switch_to() which
* will again attempt to reclaim the already saved tm state.
* Hence we need to check that we've not already reclaimed
* this state.
* We do this using the current MSR, rather tracking it in
* some specific thread_struct bit, as it has the additional
* benifit of checking for a potential TM bad thing exception.
*/
if (!MSR_TM_SUSPENDED(mfmsr()))
return;
tm_reclaim(thr, thr->regs->msr, cause); tm_reclaim(thr, thr->regs->msr, cause);
/* Having done the reclaim, we now have the checkpointed /* Having done the reclaim, we now have the checkpointed
......
...@@ -875,6 +875,15 @@ static long restore_tm_user_regs(struct pt_regs *regs, ...@@ -875,6 +875,15 @@ static long restore_tm_user_regs(struct pt_regs *regs,
return 1; return 1;
#endif /* CONFIG_SPE */ #endif /* CONFIG_SPE */
/* Get the top half of the MSR from the user context */
if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
return 1;
msr_hi <<= 32;
/* If TM bits are set to the reserved value, it's an invalid context */
if (MSR_TM_RESV(msr_hi))
return 1;
/* Pull in the MSR TM bits from the user context */
regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK);
/* Now, recheckpoint. This loads up all of the checkpointed (older) /* Now, recheckpoint. This loads up all of the checkpointed (older)
* registers, including FP and V[S]Rs. After recheckpointing, the * registers, including FP and V[S]Rs. After recheckpointing, the
* transactional versions should be loaded. * transactional versions should be loaded.
...@@ -884,11 +893,6 @@ static long restore_tm_user_regs(struct pt_regs *regs, ...@@ -884,11 +893,6 @@ static long restore_tm_user_regs(struct pt_regs *regs,
current->thread.tm_texasr |= TEXASR_FS; current->thread.tm_texasr |= TEXASR_FS;
/* This loads the checkpointed FP/VEC state, if used */ /* This loads the checkpointed FP/VEC state, if used */
tm_recheckpoint(&current->thread, msr); tm_recheckpoint(&current->thread, msr);
/* Get the top half of the MSR */
if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
return 1;
/* Pull in MSR TM from user context */
regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK);
/* This loads the speculative FP/VEC state, if used */ /* This loads the speculative FP/VEC state, if used */
if (msr & MSR_FP) { if (msr & MSR_FP) {
......
...@@ -438,6 +438,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, ...@@ -438,6 +438,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
/* get MSR separately, transfer the LE bit if doing signal return */ /* get MSR separately, transfer the LE bit if doing signal return */
err |= __get_user(msr, &sc->gp_regs[PT_MSR]); err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
/* Don't allow reserved mode. */
if (MSR_TM_RESV(msr))
return -EINVAL;
/* pull in MSR TM from user context */ /* pull in MSR TM from user context */
regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK); regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment