mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	x86: prioritize the FPU traps for the error code
In the case of multiple FPU errors, prioritize the error codes, instead of returning __SI_FAULT, which ends up pushing a 0 as the error code to userspace, a POSIX violation. For i386, we will simply return if there are no errors at all; for x86-64 this is probably a "can't happen" (and the code should be unified), but for this patch, return __SI_FAULT|SI_KERNEL if this ever happens. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
		
							parent
							
								
									55dac3a555
								
							
						
					
					
						commit
						adf77bac05
					
				
					 1 changed files with 15 additions and 19 deletions
				
			
		| 
						 | 
				
			
			@ -664,7 +664,7 @@ void math_error(void __user *ip)
 | 
			
		|||
{
 | 
			
		||||
	struct task_struct *task;
 | 
			
		||||
	siginfo_t info;
 | 
			
		||||
	unsigned short cwd, swd;
 | 
			
		||||
	unsigned short cwd, swd, err;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Save the info for the exception handler and clear the error.
 | 
			
		||||
| 
						 | 
				
			
			@ -675,7 +675,6 @@ void math_error(void __user *ip)
 | 
			
		|||
	task->thread.error_code = 0;
 | 
			
		||||
	info.si_signo = SIGFPE;
 | 
			
		||||
	info.si_errno = 0;
 | 
			
		||||
	info.si_code = __SI_FAULT;
 | 
			
		||||
	info.si_addr = ip;
 | 
			
		||||
	/*
 | 
			
		||||
	 * (~cwd & swd) will mask out exceptions that are not set to unmasked
 | 
			
		||||
| 
						 | 
				
			
			@ -689,34 +688,31 @@ void math_error(void __user *ip)
 | 
			
		|||
	 */
 | 
			
		||||
	cwd = get_fpu_cwd(task);
 | 
			
		||||
	swd = get_fpu_swd(task);
 | 
			
		||||
	switch (swd & ~cwd & 0x3f) {
 | 
			
		||||
	case 0x000: /* No unmasked exception */
 | 
			
		||||
#ifdef CONFIG_X86_32
 | 
			
		||||
 | 
			
		||||
	err = swd & ~cwd & 0x3f;
 | 
			
		||||
 | 
			
		||||
#if CONFIG_X86_32
 | 
			
		||||
	if (!err)
 | 
			
		||||
		return;
 | 
			
		||||
#endif
 | 
			
		||||
	default: /* Multiple exceptions */
 | 
			
		||||
		break;
 | 
			
		||||
	case 0x001: /* Invalid Op */
 | 
			
		||||
 | 
			
		||||
	if (err & 0x001) {	/* Invalid op */
 | 
			
		||||
		/*
 | 
			
		||||
		 * swd & 0x240 == 0x040: Stack Underflow
 | 
			
		||||
		 * swd & 0x240 == 0x240: Stack Overflow
 | 
			
		||||
		 * User must clear the SF bit (0x40) if set
 | 
			
		||||
		 */
 | 
			
		||||
		info.si_code = FPE_FLTINV;
 | 
			
		||||
		break;
 | 
			
		||||
	case 0x002: /* Denormalize */
 | 
			
		||||
	case 0x010: /* Underflow */
 | 
			
		||||
		info.si_code = FPE_FLTUND;
 | 
			
		||||
		break;
 | 
			
		||||
	case 0x004: /* Zero Divide */
 | 
			
		||||
	} else if (err & 0x004) { /* Divide by Zero */
 | 
			
		||||
		info.si_code = FPE_FLTDIV;
 | 
			
		||||
		break;
 | 
			
		||||
	case 0x008: /* Overflow */
 | 
			
		||||
	} else if (err & 0x008) { /* Overflow */
 | 
			
		||||
		info.si_code = FPE_FLTOVF;
 | 
			
		||||
		break;
 | 
			
		||||
	case 0x020: /* Precision */
 | 
			
		||||
	} else if (err & 0x012) { /* Denormal, Underflow */
 | 
			
		||||
		info.si_code = FPE_FLTUND;
 | 
			
		||||
	} else if (err & 0x020) { /* Precision */
 | 
			
		||||
		info.si_code = FPE_FLTRES;
 | 
			
		||||
		break;
 | 
			
		||||
	} else {
 | 
			
		||||
		info.si_code = __SI_FAULT|SI_KERNEL; /* WTF? */
 | 
			
		||||
	}
 | 
			
		||||
	force_sig_info(SIGFPE, &info, task);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue