linux/arch/arm/nwfpe/fpmodule.c
<<
>>
Prefs
   1
   2/*
   3    NetWinder Floating Point Emulator
   4    (c) Rebel.com, 1998-1999
   5    (c) Philip Blundell, 1998-1999
   6
   7    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
   8
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 2 of the License, or
  12    (at your option) any later version.
  13
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18
  19    You should have received a copy of the GNU General Public License
  20    along with this program; if not, write to the Free Software
  21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22*/
  23
  24#include "fpa11.h"
  25
  26#include <linux/module.h>
  27
  28/* XXX */
  29#include <linux/errno.h>
  30#include <linux/types.h>
  31#include <linux/kernel.h>
  32#include <linux/signal.h>
  33#include <linux/sched.h>
  34#include <linux/init.h>
  35
  36#include <asm/thread_notify.h>
  37
  38#include "softfloat.h"
  39#include "fpopcode.h"
  40#include "fpmodule.h"
  41#include "fpa11.inl"
  42
  43/* kernel symbols required for signal handling */
  44#ifdef CONFIG_FPE_NWFPE_XP
  45#define NWFPE_BITS "extended"
  46#else
  47#define NWFPE_BITS "double"
  48#endif
  49
  50#ifdef MODULE
  51void fp_send_sig(unsigned long sig, struct task_struct *p, int priv);
  52#else
  53#define fp_send_sig     send_sig
  54#define kern_fp_enter   fp_enter
  55
  56extern char fpe_type[];
  57#endif
  58
  59static int nwfpe_notify(struct notifier_block *self, unsigned long cmd, void *v)
  60{
  61        struct thread_info *thread = v;
  62
  63        if (cmd == THREAD_NOTIFY_FLUSH)
  64                nwfpe_init_fpa(&thread->fpstate);
  65
  66        return NOTIFY_DONE;
  67}
  68
  69static struct notifier_block nwfpe_notifier_block = {
  70        .notifier_call = nwfpe_notify,
  71};
  72
  73/* kernel function prototypes required */
  74void fp_setup(void);
  75
  76/* external declarations for saved kernel symbols */
  77extern void (*kern_fp_enter)(void);
  78
  79/* Original value of fp_enter from kernel before patched by fpe_init. */
  80static void (*orig_fp_enter)(void);
  81
  82/* forward declarations */
  83extern void nwfpe_enter(void);
  84
  85static int __init fpe_init(void)
  86{
  87        if (sizeof(FPA11) > sizeof(union fp_state)) {
  88                printk(KERN_ERR "nwfpe: bad structure size\n");
  89                return -EINVAL;
  90        }
  91
  92        if (sizeof(FPREG) != 12) {
  93                printk(KERN_ERR "nwfpe: bad register size\n");
  94                return -EINVAL;
  95        }
  96        if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
  97                return 0;
  98
  99        /* Display title, version and copyright information. */
 100        printk(KERN_WARNING "NetWinder Floating Point Emulator V0.97 ("
 101               NWFPE_BITS " precision)\n");
 102
 103        thread_register_notifier(&nwfpe_notifier_block);
 104
 105        /* Save pointer to the old FP handler and then patch ourselves in */
 106        orig_fp_enter = kern_fp_enter;
 107        kern_fp_enter = nwfpe_enter;
 108
 109        return 0;
 110}
 111
 112static void __exit fpe_exit(void)
 113{
 114        thread_unregister_notifier(&nwfpe_notifier_block);
 115        /* Restore the values we saved earlier. */
 116        kern_fp_enter = orig_fp_enter;
 117}
 118
 119/*
 120ScottB:  November 4, 1998
 121
 122Moved this function out of softfloat-specialize into fpmodule.c.
 123This effectively isolates all the changes required for integrating with the
 124Linux kernel into fpmodule.c.  Porting to NetBSD should only require modifying
 125fpmodule.c to integrate with the NetBSD kernel (I hope!).
 126
 127[1/1/99: Not quite true any more unfortunately.  There is Linux-specific
 128code to access data in user space in some other source files at the 
 129moment (grep for get_user / put_user calls).  --philb]
 130
 131This function is called by the SoftFloat routines to raise a floating
 132point exception.  We check the trap enable byte in the FPSR, and raise
 133a SIGFPE exception if necessary.  If not the relevant bits in the 
 134cumulative exceptions flag byte are set and we return.
 135*/
 136
 137void float_raise(signed char flags)
 138{
 139        register unsigned int fpsr, cumulativeTraps;
 140
 141#ifdef CONFIG_DEBUG_USER
 142        /* Ignore inexact errors as there are far too many of them to log */
 143        if (flags & ~BIT_IXC)
 144                printk(KERN_DEBUG
 145                       "NWFPE: %s[%d] takes exception %08x at %p from %08lx\n",
 146                       current->comm, current->pid, flags,
 147                       __builtin_return_address(0), GET_USERREG()->ARM_pc);
 148#endif
 149
 150        /* Read fpsr and initialize the cumulativeTraps.  */
 151        fpsr = readFPSR();
 152        cumulativeTraps = 0;
 153
 154        /* For each type of exception, the cumulative trap exception bit is only
 155           set if the corresponding trap enable bit is not set.  */
 156        if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC))
 157                cumulativeTraps |= BIT_IXC;
 158        if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC))
 159                cumulativeTraps |= BIT_UFC;
 160        if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC))
 161                cumulativeTraps |= BIT_OFC;
 162        if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC))
 163                cumulativeTraps |= BIT_DZC;
 164        if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC))
 165                cumulativeTraps |= BIT_IOC;
 166
 167        /* Set the cumulative exceptions flags.  */
 168        if (cumulativeTraps)
 169                writeFPSR(fpsr | cumulativeTraps);
 170
 171        /* Raise an exception if necessary.  */
 172        if (fpsr & (flags << 16))
 173                fp_send_sig(SIGFPE, current, 1);
 174}
 175
 176module_init(fpe_init);
 177module_exit(fpe_exit);
 178
 179MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
 180MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)");
 181MODULE_LICENSE("GPL");
 182