2005-04-17 02:20:36 +04:00
/*
* Linux / PA - RISC Project ( http : //www.parisc-linux.org/)
*
* Floating - point emulation code
* Copyright ( C ) 2001 Hewlett - Packard ( Paul Bame ) < bame @ debian . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
/*
* linux / arch / math - emu / driver . c . c
*
* decodes and dispatches unimplemented FPU instructions
*
* Copyright ( C ) 1999 , 2000 Philipp Rumpf < prumpf @ tux . org >
* Copyright ( C ) 2001 Hewlett - Packard < bame @ debian . org >
*/
2017-02-08 20:51:30 +03:00
# include <linux/sched/signal.h>
2005-04-17 02:20:36 +04:00
# include "float.h"
# include "math-emu.h"
# define fptpos 31
# define fpr1pos 10
# define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))
# define FPUDEBUG 0
/* Format of the floating-point exception registers. */
struct exc_reg {
unsigned int exception : 6 ;
unsigned int ei : 26 ;
} ;
/* Macros for grabbing bits of the instruction format from the 'ei'
field above . */
/* Major opcode 0c and 0e */
# define FP0CE_UID(i) (((i) >> 6) & 3)
# define FP0CE_CLASS(i) (((i) >> 9) & 3)
# define FP0CE_SUBOP(i) (((i) >> 13) & 7)
# define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
# define FP0C_FORMAT(i) (((i) >> 11) & 3)
# define FP0E_FORMAT(i) (((i) >> 11) & 1)
/* Major opcode 0c, uid 2 (performance monitoring) */
# define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
/* Major opcode 2e (fused operations). */
# define FP2E_SUBOP(i) (((i) >> 5) & 1)
# define FP2E_FORMAT(i) (((i) >> 11) & 1)
/* Major opcode 26 (FMPYSUB) */
/* Major opcode 06 (FMPYADD) */
# define FPx6_FORMAT(i) ((i) & 0x1f)
/* Flags and enable bits of the status word. */
# define FPSW_FLAGS(w) ((w) >> 27)
# define FPSW_ENABLE(w) ((w) & 0x1f)
# define FPSW_V (1<<4)
# define FPSW_Z (1<<3)
# define FPSW_O (1<<2)
# define FPSW_U (1<<1)
# define FPSW_I (1<<0)
/* Handle a floating point exception. Return zero if the faulting
instruction can be completed successfully . */
int
handle_fpe ( struct pt_regs * regs )
{
extern void printbinary ( unsigned long x , int nbits ) ;
struct siginfo si ;
unsigned int orig_sw , sw ;
int signalcode ;
/* need an intermediate copy of float regs because FPU emulation
* code expects an artificial last entry which contains zero
*
* also , the passed in fr registers contain one word that defines
* the fpu type . the fpu type information is constructed
* inside the emulation code
*/
__u64 frcopy [ 36 ] ;
memcpy ( frcopy , regs - > fr , sizeof regs - > fr ) ;
frcopy [ 32 ] = 0 ;
memcpy ( & orig_sw , frcopy , sizeof ( orig_sw ) ) ;
if ( FPUDEBUG ) {
printk ( KERN_DEBUG " FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI -> \n " ) ;
printbinary ( orig_sw , 32 ) ;
printk ( KERN_DEBUG " \n " ) ;
}
signalcode = decode_fpu ( frcopy , 0x666 ) ;
/* Status word = FR0L. */
memcpy ( & sw , frcopy , sizeof ( sw ) ) ;
if ( FPUDEBUG ) {
printk ( KERN_DEBUG " VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x \n " ,
signalcode > > 24 , signalcode & 0xffffff ) ;
printbinary ( sw , 32 ) ;
printk ( KERN_DEBUG " \n " ) ;
}
memcpy ( regs - > fr , frcopy , sizeof regs - > fr ) ;
if ( signalcode ! = 0 ) {
si . si_signo = signalcode > > 24 ;
si . si_errno = 0 ;
si . si_code = signalcode & 0xffffff ;
si . si_addr = ( void __user * ) regs - > iaoq [ 0 ] ;
force_sig_info ( si . si_signo , & si , current ) ;
return - 1 ;
}
return signalcode ? - 1 : 0 ;
}