Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 
0003 /*
0004     NetWinder Floating Point Emulator
0005     (c) Rebel.com, 1998-1999
0006     (c) Philip Blundell, 1998-1999
0007 
0008     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
0009 
0010 */
0011 
0012 #include "fpa11.h"
0013 
0014 #include <linux/module.h>
0015 #include <linux/moduleparam.h>
0016 
0017 /* XXX */
0018 #include <linux/errno.h>
0019 #include <linux/types.h>
0020 #include <linux/kernel.h>
0021 #include <linux/signal.h>
0022 #include <linux/sched/signal.h>
0023 #include <linux/init.h>
0024 
0025 #include <asm/thread_notify.h>
0026 
0027 #include "softfloat.h"
0028 #include "fpopcode.h"
0029 #include "fpmodule.h"
0030 #include "fpa11.inl"
0031 
0032 /* kernel symbols required for signal handling */
0033 #ifdef CONFIG_FPE_NWFPE_XP
0034 #define NWFPE_BITS "extended"
0035 #else
0036 #define NWFPE_BITS "double"
0037 #endif
0038 
0039 #ifdef MODULE
0040 void fp_send_sig(unsigned long sig, struct task_struct *p, int priv);
0041 #else
0042 #define fp_send_sig send_sig
0043 #define kern_fp_enter   fp_enter
0044 
0045 extern char fpe_type[];
0046 #endif
0047 
0048 static int nwfpe_notify(struct notifier_block *self, unsigned long cmd, void *v)
0049 {
0050     struct thread_info *thread = v;
0051 
0052     if (cmd == THREAD_NOTIFY_FLUSH)
0053         nwfpe_init_fpa(&thread->fpstate);
0054 
0055     return NOTIFY_DONE;
0056 }
0057 
0058 static struct notifier_block nwfpe_notifier_block = {
0059     .notifier_call = nwfpe_notify,
0060 };
0061 
0062 /* kernel function prototypes required */
0063 void fp_setup(void);
0064 
0065 /* external declarations for saved kernel symbols */
0066 extern void (*kern_fp_enter)(void);
0067 
0068 /* Original value of fp_enter from kernel before patched by fpe_init. */
0069 static void (*orig_fp_enter)(void);
0070 
0071 /* forward declarations */
0072 extern void nwfpe_enter(void);
0073 
0074 static int __init fpe_init(void)
0075 {
0076     if (sizeof(FPA11) > sizeof(union fp_state)) {
0077         pr_err("nwfpe: bad structure size\n");
0078         return -EINVAL;
0079     }
0080 
0081     if (sizeof(FPREG) != 12) {
0082         pr_err("nwfpe: bad register size\n");
0083         return -EINVAL;
0084     }
0085     if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
0086         return 0;
0087 
0088     /* Display title, version and copyright information. */
0089     pr_info("NetWinder Floating Point Emulator V0.97 ("
0090             NWFPE_BITS " precision)\n");
0091 
0092     thread_register_notifier(&nwfpe_notifier_block);
0093 
0094     /* Save pointer to the old FP handler and then patch ourselves in */
0095     orig_fp_enter = kern_fp_enter;
0096     kern_fp_enter = nwfpe_enter;
0097 
0098     return 0;
0099 }
0100 
0101 static void __exit fpe_exit(void)
0102 {
0103     thread_unregister_notifier(&nwfpe_notifier_block);
0104     /* Restore the values we saved earlier. */
0105     kern_fp_enter = orig_fp_enter;
0106 }
0107 
0108 /*
0109 ScottB:  November 4, 1998
0110 
0111 Moved this function out of softfloat-specialize into fpmodule.c.
0112 This effectively isolates all the changes required for integrating with the
0113 Linux kernel into fpmodule.c.  Porting to NetBSD should only require modifying
0114 fpmodule.c to integrate with the NetBSD kernel (I hope!).
0115 
0116 [1/1/99: Not quite true any more unfortunately.  There is Linux-specific
0117 code to access data in user space in some other source files at the 
0118 moment (grep for get_user / put_user calls).  --philb]
0119 
0120 This function is called by the SoftFloat routines to raise a floating
0121 point exception.  We check the trap enable byte in the FPSR, and raise
0122 a SIGFPE exception if necessary.  If not the relevant bits in the 
0123 cumulative exceptions flag byte are set and we return.
0124 */
0125 
0126 #ifdef CONFIG_DEBUG_USER
0127 /* By default, ignore inexact errors as there are far too many of them to log */
0128 static int debug = ~BIT_IXC;
0129 #endif
0130 
0131 void float_raise(signed char flags)
0132 {
0133     register unsigned int fpsr, cumulativeTraps;
0134 
0135 #ifdef CONFIG_DEBUG_USER
0136     if (flags & debug)
0137         printk(KERN_DEBUG
0138                "NWFPE: %s[%d] takes exception %08x at %ps from %08lx\n",
0139                current->comm, current->pid, flags,
0140                __builtin_return_address(0), GET_USERREG()->ARM_pc);
0141 #endif
0142 
0143     /* Read fpsr and initialize the cumulativeTraps.  */
0144     fpsr = readFPSR();
0145     cumulativeTraps = 0;
0146 
0147     /* For each type of exception, the cumulative trap exception bit is only
0148        set if the corresponding trap enable bit is not set.  */
0149     if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC))
0150         cumulativeTraps |= BIT_IXC;
0151     if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC))
0152         cumulativeTraps |= BIT_UFC;
0153     if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC))
0154         cumulativeTraps |= BIT_OFC;
0155     if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC))
0156         cumulativeTraps |= BIT_DZC;
0157     if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC))
0158         cumulativeTraps |= BIT_IOC;
0159 
0160     /* Set the cumulative exceptions flags.  */
0161     if (cumulativeTraps)
0162         writeFPSR(fpsr | cumulativeTraps);
0163 
0164     /* Raise an exception if necessary.  */
0165     if (fpsr & (flags << 16))
0166         fp_send_sig(SIGFPE, current, 1);
0167 }
0168 
0169 module_init(fpe_init);
0170 module_exit(fpe_exit);
0171 
0172 MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
0173 MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)");
0174 MODULE_LICENSE("GPL");
0175 
0176 #ifdef CONFIG_DEBUG_USER
0177 module_param(debug, int, 0644);
0178 #endif