amd64/169927: siginfo, si_code for fpe errors when error occurs using the SSE math processor

Mark Linimon linimon at lonesome.com
Tue Jul 17 22:00:30 UTC 2012


The following reply was made to PR amd64/169927; it has been noted by GNATS.

From: Mark Linimon <linimon at lonesome.com>
To: bug-followup at FreeBSD.org
Cc:  
Subject: Re: amd64/169927: siginfo, si_code for fpe errors when error
 occurs using the SSE math processor
Date: Tue, 17 Jul 2012 16:50:18 -0500

 ----- Forwarded message from Konstantin Belousov <kostikbel at gmail.com> -----
 
 Date: Tue, 17 Jul 2012 21:26:19 +0300
 From: Konstantin Belousov <kostikbel at gmail.com>
 To: Bruce Evans <brde at optusnet.com.au>
 Cc: freebsd-amd64 at freebsd.org
 Subject: Re: amd64/169927: siginfo,
 	si_code for fpe errors when error occurs using the SSE math
 	processor
 
 On Tue, Jul 17, 2012 at 08:09:15PM +0300, Konstantin Belousov wrote:
 > The trap number is available for SA_SIGINFO type of handlers with
 > si_trapno member of siginfo_t. I think this is final argument to have
 > separate fputrap_{x87,sse} functions.
 > 
 > For amd64, SSE hardware is FPU, so I do not see much wrong with the name.
 > 
 > I changed fputrap_sse() according to your suggestion.
 
 Below is the actually tested patch. After it, I put the test program.
 
 diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
 index a7812b7..ae241ce 100644
 --- a/sys/amd64/amd64/fpu.c
 +++ b/sys/amd64/amd64/fpu.c
 @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
  #define	fxrstor(addr)		__asm __volatile("fxrstor %0" : : "m" (*(addr)))
  #define	fxsave(addr)		__asm __volatile("fxsave %0" : "=m" (*(addr)))
  #define	ldmxcsr(csr)		__asm __volatile("ldmxcsr %0" : : "m" (csr))
 +#define	stmxcsr(addr)		__asm __volatile("stmxcsr %0" : : "m" (*(addr)))
  
  static __inline void
  xrstor(char *addr, uint64_t mask)
 @@ -105,6 +106,7 @@ void	fnstsw(caddr_t addr);
  void	fxsave(caddr_t addr);
  void	fxrstor(caddr_t addr);
  void	ldmxcsr(u_int csr);
 +void	stmxcsr(u_int csr);
  void	xrstor(char *addr, uint64_t mask);
  void	xsave(char *addr, uint64_t mask);
  
 @@ -113,9 +115,6 @@ void	xsave(char *addr, uint64_t mask);
  #define	start_emulating()	load_cr0(rcr0() | CR0_TS)
  #define	stop_emulating()	clts()
  
 -#define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_cw)
 -#define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_sw)
 -
  CTASSERT(sizeof(struct savefpu) == 512);
  CTASSERT(sizeof(struct xstate_hdr) == 64);
  CTASSERT(sizeof(struct savefpu_ymm) == 832);
 @@ -514,11 +513,15 @@ static char fpetable[128] = {
  };
  
  /*
 - * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE.
 + * Preserve the FP status word, clear FP exceptions for x87, then
 + * generate a SIGFPE.
 + *
 + * Clearing exceptions was necessary mainly to avoid IRQ13 bugs and is
 + * engraved in our i386 ABI.  We now depend on longjmp() restoring a
 + * usable state.  Restoring the state or examining it might fail if we
 + * didn't clear exceptions.
   *
 - * Clearing exceptions is necessary mainly to avoid IRQ13 bugs.  We now
 - * depend on longjmp() restoring a usable state.  Restoring the state
 - * or examining it might fail if we didn't clear exceptions.
 + * For SSE exceptions, the exceptions are not cleared.
   *
   * The error code chosen will be one of the FPE_... macros. It will be
   * sent as the second argument to old BSD-style signal handlers and as
 @@ -531,8 +534,9 @@ static char fpetable[128] = {
   * solution for signals other than SIGFPE.
   */
  int
 -fputrap()
 +fputrap_x87(void)
  {
 +	struct savefpu *pcb_save;
  	u_short control, status;
  
  	critical_enter();
 @@ -543,19 +547,40 @@ fputrap()
  	 * wherever they are.
  	 */
  	if (PCPU_GET(fpcurthread) != curthread) {
 -		control = GET_FPU_CW(curthread);
 -		status = GET_FPU_SW(curthread);
 +		pcb_save = curthread->td_pcb->pcb_save;
 +		control = pcb_save->sv_env.en_cw;
 +		status = pcb_save->sv_env.en_sw;
  	} else {
  		fnstcw(&control);
  		fnstsw(&status);
 +		fnclex();
  	}
  
 -	if (PCPU_GET(fpcurthread) == curthread)
 -		fnclex();
  	critical_exit();
  	return (fpetable[status & ((~control & 0x3f) | 0x40)]);
  }
  
 +int
 +fputrap_sse(void)
 +{
 +	u_int mxcsr;
 +
 +	critical_enter();
 +
 +	/*
 +	 * Coomparing with the x87 #MF handler, we do not clear
 +	 * exceptions from the mxcsr.
 +	 */
 +	if (PCPU_GET(fpcurthread) != curthread)
 +		mxcsr = curthread->td_pcb->pcb_save->sv_env.en_mxcsr;
 +	else
 +		stmxcsr(&mxcsr);
 +
 +	critical_exit();
 +
 +	return (fpetable[(mxcsr & (~mxcsr >> 7)) & 0x3f]);
 +}
 +
  /*
   * Implement device not available (DNA) exception
   *
 diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
 index 75e15e0..57d1cc2 100644
 --- a/sys/amd64/amd64/trap.c
 +++ b/sys/amd64/amd64/trap.c
 @@ -328,7 +328,7 @@ trap(struct trapframe *frame)
  			break;
  
  		case T_ARITHTRAP:	/* arithmetic trap */
 -			ucode = fputrap();
 +			ucode = fputrap_x87();
  			if (ucode == -1)
  				goto userout;
  			i = SIGFPE;
 @@ -442,7 +442,9 @@ trap(struct trapframe *frame)
  			break;
  
  		case T_XMMFLT:		/* SIMD floating-point exception */
 -			ucode = 0; /* XXX */
 +			ucode = fputrap_sse();
 +			if (ucode == -1)
 +				goto userout;
  			i = SIGFPE;
  			break;
  		}
 diff --git a/sys/amd64/include/fpu.h b/sys/amd64/include/fpu.h
 index 98a016b..7d0f0ea 100644
 --- a/sys/amd64/include/fpu.h
 +++ b/sys/amd64/include/fpu.h
 @@ -62,7 +62,8 @@ int	fpusetregs(struct thread *td, struct savefpu *addr,
  	    char *xfpustate, size_t xfpustate_size);
  int	fpusetxstate(struct thread *td, char *xfpustate,
  	    size_t xfpustate_size);
 -int	fputrap(void);
 +int	fputrap_sse(void);
 +int	fputrap_x87(void);
  void	fpuuserinited(struct thread *td);
  struct fpu_kern_ctx *fpu_kern_alloc_ctx(u_int flags);
  void	fpu_kern_free_ctx(struct fpu_kern_ctx *ctx);
 
 fpuex.c:
 
 /* $Id: fpuex.c,v 1.2 2012/07/17 18:22:54 kostik Exp kostik $ */
 #include <sys/types.h>
 #include <err.h>
 #include <errno.h>
 #include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ucontext.h>
 #if defined(__amd64__)
 #include <machine/fpu.h>
 #elif defined(__i386__)
 #include <machine/npx.h>
 #endif
 
 static void
 handler(int signo __unused, siginfo_t *info, void *v)
 {
 	ucontext_t *uap;
 	mcontext_t *mc;
 #if defined(__amd64__)
 	struct savefpu *sf;
 #elif defined(__i386__)
 	struct savexmm *sf;
 #endif
 
 	uap = v;
 	mc = &uap->uc_mcontext;
 	sf = &mc->mc_fpstate;
 	printf("intr handler: trapno %d code %d cw 0x%04x sw 0x%04x mxcsr 0x%08x ip 0x%lx\n",
 	    info->si_trapno, info->si_code,
 #if defined(__amd64__)
 	    sf->sv_env.en_cw, sf->sv_env.en_sw, sf->sv_env.en_mxcsr,
 	    sf->sv_env.en_rip
 #elif defined(__i386__)
 	    sf->sv_env.en_cw, sf->sv_env.en_sw,
 	    sf->sv_env.en_mxcsr, (unsigned long)sf->sv_env.en_fip
 #endif
 	    );
 	exit(0);
 }
 
 double a[3];
 
 double x(void) __attribute__((noinline));
 double
 x(void)
 {
 
 	a[3] = a[0] / a[1];
 	return (a[3]);
 }
 
 int
 main(void)
 {
 	struct sigaction sa;
 	uint32_t mxcsr;
 	uint16_t cw;
 
 	bzero(&sa, sizeof(sa));
 	sa.sa_sigaction = handler;
 	sa.sa_flags = SA_SIGINFO;
 	if (sigaction(SIGFPE, &sa, NULL) == -1)
 		err(1, "sigaction SIGFPE");
 
 	mxcsr = 0;
 	__asm __volatile("ldmxcsr %0" : : "m" (mxcsr));
 #ifdef __i386__
 	cw = 0;
 	__asm __volatile("fldcw %0" : : "m" (cw));
 #endif
 	a[0] = 1.0;
 	a[1] = 0.0;
 	x();
 	return (0);
 }
 
 
 
 ----- End forwarded message -----


More information about the freebsd-amd64 mailing list