diff options
Diffstat (limited to 'arch/mips/kernel/unaligned.c')
-rw-r--r-- | arch/mips/kernel/unaligned.c | 51 |
1 files changed, 30 insertions, 21 deletions
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 490cea569d57..5c62065cbf22 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c | |||
@@ -885,7 +885,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
885 | { | 885 | { |
886 | union mips_instruction insn; | 886 | union mips_instruction insn; |
887 | unsigned long value; | 887 | unsigned long value; |
888 | unsigned int res; | 888 | unsigned int res, preempted; |
889 | unsigned long origpc; | 889 | unsigned long origpc; |
890 | unsigned long orig31; | 890 | unsigned long orig31; |
891 | void __user *fault_addr = NULL; | 891 | void __user *fault_addr = NULL; |
@@ -1226,27 +1226,36 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
1226 | if (!access_ok(VERIFY_READ, addr, sizeof(*fpr))) | 1226 | if (!access_ok(VERIFY_READ, addr, sizeof(*fpr))) |
1227 | goto sigbus; | 1227 | goto sigbus; |
1228 | 1228 | ||
1229 | /* | 1229 | do { |
1230 | * Disable preemption to avoid a race between copying | 1230 | /* |
1231 | * state from userland, migrating to another CPU and | 1231 | * If we have live MSA context keep track of |
1232 | * updating the hardware vector register below. | 1232 | * whether we get preempted in order to avoid |
1233 | */ | 1233 | * the register context we load being clobbered |
1234 | preempt_disable(); | 1234 | * by the live context as it's saved during |
1235 | 1235 | * preemption. If we don't have live context | |
1236 | res = __copy_from_user_inatomic(fpr, addr, | 1236 | * then it can't be saved to clobber the value |
1237 | sizeof(*fpr)); | 1237 | * we load. |
1238 | if (res) | 1238 | */ |
1239 | goto fault; | 1239 | preempted = test_thread_flag(TIF_USEDMSA); |
1240 | 1240 | ||
1241 | /* | 1241 | res = __copy_from_user_inatomic(fpr, addr, |
1242 | * Update the hardware register if it is in use by the | 1242 | sizeof(*fpr)); |
1243 | * task in this quantum, in order to avoid having to | 1243 | if (res) |
1244 | * save & restore the whole vector context. | 1244 | goto fault; |
1245 | */ | ||
1246 | if (test_thread_flag(TIF_USEDMSA)) | ||
1247 | write_msa_wr(wd, fpr, df); | ||
1248 | 1245 | ||
1249 | preempt_enable(); | 1246 | /* |
1247 | * Update the hardware register if it is in use | ||
1248 | * by the task in this quantum, in order to | ||
1249 | * avoid having to save & restore the whole | ||
1250 | * vector context. | ||
1251 | */ | ||
1252 | preempt_disable(); | ||
1253 | if (test_thread_flag(TIF_USEDMSA)) { | ||
1254 | write_msa_wr(wd, fpr, df); | ||
1255 | preempted = 0; | ||
1256 | } | ||
1257 | preempt_enable(); | ||
1258 | } while (preempted); | ||
1250 | break; | 1259 | break; |
1251 | 1260 | ||
1252 | case msa_st_op: | 1261 | case msa_st_op: |