powerpc/64s: Fix crash in load_fp_state() due to fpexc_mode
The recent commit01eb01877f
("powerpc/64s: Fix restore_math unnecessarily changing MSR") changed some of the handling of floating point/vector restore. In particular it caused current->thread.fpexc_mode to be copied into the current MSR (via msr_check_and_set()), rather than just into regs->msr (which is moved into MSR on return to userspace). This can lead to a crash in the kernel if we take a floating point exception when restoring FPSCR: Oops: Exception in kernel mode, sig: 8 [#1] LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA PowerNV Modules linked in: CPU: 3 PID: 101213 Comm: ld64.so.2 Not tainted 5.9.0-rc1-00098-g18445bf405cb-dirty #9 NIP: c00000000000fbb4 LR: c00000000001a7ac CTR: c000000000183570 REGS: c0000016b7cfb3b0 TRAP: 0700 Not tainted (5.9.0-rc1-00098-g18445bf405cb-dirty) MSR: 900000000290b933 <SF,HV,VEC,VSX,EE,FP,ME,IR,DR,RI,LE> CR: 44002444 XER: 00000000 CFAR: c00000000001a7a8 IRQMASK: 1 GPR00: c00000000001ae40 c0000016b7cfb640 c0000000011b7f00 c000001542a0f740 GPR04: c000001542a0f720 c000001542a0eb00 0000000000000900 c000001542a0eb00 GPR08: 000000000000000a 0000000000002000 9000000000009033 0000000000000000 GPR12: 0000000000004000 c0000017ffffd900 0000000000000001 c000000000df5a58 GPR16: c000000000e19c18 c0000000010e1123 0000000000000001 c000000000e1a638 GPR20: 0000000000000000 c0000000044b1d00 0000000000000000 c000001542a0f2a0 GPR24: 00000016c7fe0000 c000001542a0f720 c000000001c93da0 c000000000fe5f28 GPR28: c000001542a0f720 0000000000800000 c0000016b7cfbe90 0000000002802900 NIP load_fp_state+0x4/0x214 LR restore_math+0x17c/0x1f0 Call Trace: 0xc0000016b7cfb680 (unreliable) __switch_to+0x330/0x460 __schedule+0x318/0x920 schedule+0x74/0x140 schedule_timeout+0x318/0x3f0 wait_for_completion+0xc8/0x210 call_usermodehelper_exec+0x234/0x280 do_coredump+0xedc/0x13c0 get_signal+0x1d4/0xbe0 do_notify_resume+0x1a0/0x490 interrupt_exit_user_prepare+0x1c4/0x230 interrupt_return+0x14/0x1c0 Instruction dump: ebe10168 e88101a0 7c8ff120 382101e0 e8010010 7c0803a6 4e800020 790605c4 782905c4 7c0008a8 7c0008a8 c8030200 <fffe058e> 48000088 c8030000 c8230010 Fix it by only loading the fpexc_mode value into regs->msr. Also add a comment to explain that although VSX is subject to the value of fpexc_mode, we don't have to handle that separately because we only allow VSX to be enabled if FP is also enabled. Fixes:01eb01877f
("powerpc/64s: Fix restore_math unnecessarily changing MSR") Reported-by: Milton Miller <miltonm@us.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Reviewed-by: Nicholas Piggin <npiggin@gmail.com> Link: https://lore.kernel.org/r/20200825093424.3967813-1-mpe@ellerman.id.au
This commit is contained in:
Родитель
e5fe56092e
Коммит
b91eb51824
|
@ -548,7 +548,7 @@ void notrace restore_math(struct pt_regs *regs)
|
|||
* are live for the user thread).
|
||||
*/
|
||||
if ((!(msr & MSR_FP)) && should_restore_fp())
|
||||
new_msr |= MSR_FP | current->thread.fpexc_mode;
|
||||
new_msr |= MSR_FP;
|
||||
|
||||
if ((!(msr & MSR_VEC)) && should_restore_altivec())
|
||||
new_msr |= MSR_VEC;
|
||||
|
@ -559,11 +559,17 @@ void notrace restore_math(struct pt_regs *regs)
|
|||
}
|
||||
|
||||
if (new_msr) {
|
||||
unsigned long fpexc_mode = 0;
|
||||
|
||||
msr_check_and_set(new_msr);
|
||||
|
||||
if (new_msr & MSR_FP)
|
||||
if (new_msr & MSR_FP) {
|
||||
do_restore_fp();
|
||||
|
||||
// This also covers VSX, because VSX implies FP
|
||||
fpexc_mode = current->thread.fpexc_mode;
|
||||
}
|
||||
|
||||
if (new_msr & MSR_VEC)
|
||||
do_restore_altivec();
|
||||
|
||||
|
@ -572,7 +578,7 @@ void notrace restore_math(struct pt_regs *regs)
|
|||
|
||||
msr_check_and_clear(new_msr);
|
||||
|
||||
regs->msr |= new_msr;
|
||||
regs->msr |= new_msr | fpexc_mode;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче