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