2005-04-16 15:20:36 -07:00
/*
NetWinder Floating Point Emulator
( c ) Rebel . com , 1998 - 1999
( c ) Philip Blundell , 1998 - 1999
Direct questions , comments to Scott Bambrough < scottb @ netwinder . 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 of the License , 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "fpa11.h"
# include <linux/module.h>
# include <linux/version.h>
/* XXX */
# include <linux/errno.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/signal.h>
# include <linux/sched.h>
# include <linux/init.h>
/* XXX */
# include "softfloat.h"
# include "fpopcode.h"
# include "fpmodule.h"
# include "fpa11.inl"
/* kernel symbols required for signal handling */
typedef struct task_struct * PTASK ;
# ifdef MODULE
void fp_send_sig ( unsigned long sig , PTASK p , int priv ) ;
2006-01-03 13:42:12 +01:00
2005-04-16 15:20:36 -07:00
MODULE_AUTHOR ( " Scott Bambrough <scottb@rebel.com> " ) ;
MODULE_DESCRIPTION ( " NWFPE floating point emulator " ) ;
# else
# define fp_send_sig send_sig
# define kern_fp_enter fp_enter
extern char fpe_type [ ] ;
# endif
/* kernel function prototypes required */
void fp_setup ( void ) ;
/* external declarations for saved kernel symbols */
extern void ( * kern_fp_enter ) ( void ) ;
/* Original value of fp_enter from kernel before patched by fpe_init. */
static void ( * orig_fp_enter ) ( void ) ;
/* forward declarations */
extern void nwfpe_enter ( void ) ;
# ifdef MODULE
/*
* Return 0 if we can be unloaded . This can only happen if
* kern_fp_enter is still pointing at nwfpe_enter
*/
static int fpe_unload ( void )
{
return ( kern_fp_enter = = nwfpe_enter ) ? 0 : 1 ;
}
# endif
static int __init fpe_init ( void )
{
if ( sizeof ( FPA11 ) > sizeof ( union fp_state ) ) {
printk ( KERN_ERR " nwfpe: bad structure size \n " ) ;
return - EINVAL ;
}
if ( sizeof ( FPREG ) ! = 12 ) {
printk ( KERN_ERR " nwfpe: bad register size \n " ) ;
return - EINVAL ;
}
# ifdef MODULE
if ( ! mod_member_present ( & __this_module , can_unload ) )
return - EINVAL ;
__this_module . can_unload = fpe_unload ;
# else
if ( fpe_type [ 0 ] & & strcmp ( fpe_type , " nwfpe " ) )
return 0 ;
# endif
/* Display title, version and copyright information. */
printk ( KERN_WARNING " NetWinder Floating Point Emulator V0.95 "
" (c) 1998-1999 Rebel.com \n " ) ;
/* Save pointer to the old FP handler and then patch ourselves in */
orig_fp_enter = kern_fp_enter ;
kern_fp_enter = nwfpe_enter ;
return 0 ;
}
static void __exit fpe_exit ( void )
{
/* Restore the values we saved earlier. */
kern_fp_enter = orig_fp_enter ;
}
/*
ScottB : November 4 , 1998
Moved this function out of softfloat - specialize into fpmodule . c .
This effectively isolates all the changes required for integrating with the
Linux kernel into fpmodule . c . Porting to NetBSD should only require modifying
fpmodule . c to integrate with the NetBSD kernel ( I hope ! ) .
[ 1 / 1 / 99 : Not quite true any more unfortunately . There is Linux - specific
code to access data in user space in some other source files at the
moment ( grep for get_user / put_user calls ) . - - philb ]
float_exception_flags is a global variable in SoftFloat .
This function is called by the SoftFloat routines to raise a floating
point exception . We check the trap enable byte in the FPSR , and raise
a SIGFPE exception if necessary . If not the relevant bits in the
cumulative exceptions flag byte are set and we return .
*/
void float_raise ( signed char flags )
{
register unsigned int fpsr , cumulativeTraps ;
# ifdef CONFIG_DEBUG_USER
printk ( KERN_DEBUG " NWFPE: %s[%d] takes exception %08x at %p from %08x \n " ,
current - > comm , current - > pid , flags ,
__builtin_return_address ( 0 ) , GET_USERREG ( ) [ 15 ] ) ;
# endif
/* Keep SoftFloat exception flags up to date. */
float_exception_flags | = flags ;
/* Read fpsr and initialize the cumulativeTraps. */
fpsr = readFPSR ( ) ;
cumulativeTraps = 0 ;
/* For each type of exception, the cumulative trap exception bit is only
set if the corresponding trap enable bit is not set . */
if ( ( ! ( fpsr & BIT_IXE ) ) & & ( flags & BIT_IXC ) )
cumulativeTraps | = BIT_IXC ;
if ( ( ! ( fpsr & BIT_UFE ) ) & & ( flags & BIT_UFC ) )
cumulativeTraps | = BIT_UFC ;
if ( ( ! ( fpsr & BIT_OFE ) ) & & ( flags & BIT_OFC ) )
cumulativeTraps | = BIT_OFC ;
if ( ( ! ( fpsr & BIT_DZE ) ) & & ( flags & BIT_DZC ) )
cumulativeTraps | = BIT_DZC ;
if ( ( ! ( fpsr & BIT_IOE ) ) & & ( flags & BIT_IOC ) )
cumulativeTraps | = BIT_IOC ;
/* Set the cumulative exceptions flags. */
if ( cumulativeTraps )
writeFPSR ( fpsr | cumulativeTraps ) ;
/* Raise an exception if necessary. */
if ( fpsr & ( flags < < 16 ) )
fp_send_sig ( SIGFPE , current , 1 ) ;
}
module_init ( fpe_init ) ;
module_exit ( fpe_exit ) ;