diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-26 14:19:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-26 14:19:59 -0500 |
commit | 02a5fec18297bb6991f5bc5ebc7e73fa6810809d (patch) | |
tree | 6976eb940b5f0e37083366f0140525deef9c2925 | |
parent | 78c4a49a69e910a162b05e4e8727b9bdbf948f13 (diff) | |
parent | 7f821fc9c77a9b01fe7b1d6e72717b33d8d64142 (diff) |
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
-rw-r--r-- | arch/powerpc/include/asm/reg.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 18 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 14 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 4 |
4 files changed, 32 insertions, 5 deletions
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index a908ada8e0a5..2220f7a60def 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h | |||
@@ -108,6 +108,7 @@ | |||
108 | #define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */ | 108 | #define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */ |
109 | #define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */ | 109 | #define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */ |
110 | #define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */ | 110 | #define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */ |
111 | #define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */ | ||
111 | #define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T) | 112 | #define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T) |
112 | #define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S) | 113 | #define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S) |
113 | 114 | ||
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 75b6676c1a0b..646bf4d222c1 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -551,6 +551,24 @@ static void tm_reclaim_thread(struct thread_struct *thr, | |||
551 | msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1; | 551 | msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1; |
552 | } | 552 | } |
553 | 553 | ||
554 | /* | ||
555 | * Use the current MSR TM suspended bit to track if we have | ||
556 | * checkpointed state outstanding. | ||
557 | * On signal delivery, we'd normally reclaim the checkpointed | ||
558 | * state to obtain stack pointer (see:get_tm_stackpointer()). | ||
559 | * This will then directly return to userspace without going | ||
560 | * through __switch_to(). However, if the stack frame is bad, | ||
561 | * we need to exit this thread which calls __switch_to() which | ||
562 | * will again attempt to reclaim the already saved tm state. | ||
563 | * Hence we need to check that we've not already reclaimed | ||
564 | * this state. | ||
565 | * We do this using the current MSR, rather tracking it in | ||
566 | * some specific thread_struct bit, as it has the additional | ||
567 | * benifit of checking for a potential TM bad thing exception. | ||
568 | */ | ||
569 | if (!MSR_TM_SUSPENDED(mfmsr())) | ||
570 | return; | ||
571 | |||
554 | tm_reclaim(thr, thr->regs->msr, cause); | 572 | tm_reclaim(thr, thr->regs->msr, cause); |
555 | 573 | ||
556 | /* Having done the reclaim, we now have the checkpointed | 574 | /* Having done the reclaim, we now have the checkpointed |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 0dbee465af7a..ef7c24e84a62 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -875,6 +875,15 @@ static long restore_tm_user_regs(struct pt_regs *regs, | |||
875 | return 1; | 875 | return 1; |
876 | #endif /* CONFIG_SPE */ | 876 | #endif /* CONFIG_SPE */ |
877 | 877 | ||
878 | /* Get the top half of the MSR from the user context */ | ||
879 | if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR])) | ||
880 | return 1; | ||
881 | msr_hi <<= 32; | ||
882 | /* If TM bits are set to the reserved value, it's an invalid context */ | ||
883 | if (MSR_TM_RESV(msr_hi)) | ||
884 | return 1; | ||
885 | /* Pull in the MSR TM bits from the user context */ | ||
886 | regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK); | ||
878 | /* Now, recheckpoint. This loads up all of the checkpointed (older) | 887 | /* Now, recheckpoint. This loads up all of the checkpointed (older) |
879 | * registers, including FP and V[S]Rs. After recheckpointing, the | 888 | * registers, including FP and V[S]Rs. After recheckpointing, the |
880 | * transactional versions should be loaded. | 889 | * transactional versions should be loaded. |
@@ -884,11 +893,6 @@ static long restore_tm_user_regs(struct pt_regs *regs, | |||
884 | current->thread.tm_texasr |= TEXASR_FS; | 893 | current->thread.tm_texasr |= TEXASR_FS; |
885 | /* This loads the checkpointed FP/VEC state, if used */ | 894 | /* This loads the checkpointed FP/VEC state, if used */ |
886 | tm_recheckpoint(¤t->thread, msr); | 895 | tm_recheckpoint(¤t->thread, msr); |
887 | /* Get the top half of the MSR */ | ||
888 | if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR])) | ||
889 | return 1; | ||
890 | /* Pull in MSR TM from user context */ | ||
891 | regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK); | ||
892 | 896 | ||
893 | /* This loads the speculative FP/VEC state, if used */ | 897 | /* This loads the speculative FP/VEC state, if used */ |
894 | if (msr & MSR_FP) { | 898 | if (msr & MSR_FP) { |
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 20756dfb9f34..c676ecec0869 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -438,6 +438,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, | |||
438 | 438 | ||
439 | /* get MSR separately, transfer the LE bit if doing signal return */ | 439 | /* get MSR separately, transfer the LE bit if doing signal return */ |
440 | err |= __get_user(msr, &sc->gp_regs[PT_MSR]); | 440 | err |= __get_user(msr, &sc->gp_regs[PT_MSR]); |
441 | /* Don't allow reserved mode. */ | ||
442 | if (MSR_TM_RESV(msr)) | ||
443 | return -EINVAL; | ||
444 | |||
441 | /* pull in MSR TM from user context */ | 445 | /* pull in MSR TM from user context */ |
442 | regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK); | 446 | regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK); |
443 | 447 | ||