mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	MIPS: Always clear FCSR cause bits after emulation
Clear any FCSR cause bits recorded in the saved FPU context after emulation in all cases rather than in `do_fpe' only, so that any unmasked IEEE 754 exception left from emulation does not cause a fatal kernel-mode FPE hardware exception with the CTC1 instruction used by the kernel to subsequently restore FCSR hardware from the saved FPU context. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9704/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
		
							parent
							
								
									ed2d72c1eb
								
							
						
					
					
						commit
						443c44032a
					
				
					 2 changed files with 20 additions and 1 deletions
				
			
		| 
						 | 
					@ -1169,6 +1169,12 @@ int mipsr2_decoder(struct pt_regs *regs, u32 inst)
 | 
				
			||||||
		err = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 0,
 | 
							err = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 0,
 | 
				
			||||||
					       &fault_addr);
 | 
										       &fault_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * We can't allow the emulated instruction to leave any of
 | 
				
			||||||
 | 
							 * the cause bits set in $fcr31.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * this is a tricky issue - lose_fpu() uses LL/SC atomics
 | 
							 * this is a tricky issue - lose_fpu() uses LL/SC atomics
 | 
				
			||||||
		 * if FPU is owned and effectively cancels user level LL/SC.
 | 
							 * if FPU is owned and effectively cancels user level LL/SC.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -761,6 +761,12 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
 | 
				
			||||||
	sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
 | 
						sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
 | 
				
			||||||
				       &fault_addr);
 | 
									       &fault_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We can't allow the emulated instruction to leave any of
 | 
				
			||||||
 | 
						 * the cause bits set in $fcr31.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If something went wrong, signal */
 | 
						/* If something went wrong, signal */
 | 
				
			||||||
	process_fpemu_return(sig, fault_addr);
 | 
						process_fpemu_return(sig, fault_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -807,7 +813,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * We can't allow the emulated instruction to leave any of
 | 
							 * We can't allow the emulated instruction to leave any of
 | 
				
			||||||
		 * the cause bit set in $fcr31.
 | 
							 * the cause bits set in $fcr31.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
 | 
							current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1384,6 +1390,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 | 
				
			||||||
			sig = fpu_emulator_cop1Handler(regs,
 | 
								sig = fpu_emulator_cop1Handler(regs,
 | 
				
			||||||
						       ¤t->thread.fpu,
 | 
											       ¤t->thread.fpu,
 | 
				
			||||||
						       0, &fault_addr);
 | 
											       0, &fault_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * We can't allow the emulated instruction to leave
 | 
				
			||||||
 | 
								 * any of the cause bits set in $fcr31.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!process_fpemu_return(sig, fault_addr) && !err)
 | 
								if (!process_fpemu_return(sig, fault_addr) && !err)
 | 
				
			||||||
				mt_ase_fp_affinity();
 | 
									mt_ase_fp_affinity();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue