summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-07-16 19:10:01 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-07-16 19:10:01 +0000
commit1ace72167d23543960d517e3d444762cb92bd211 (patch)
treec5d5aaf9501edcc48dc8dfdca9ed694d0d26763f /arch
parentcb9368e29107fdf541cb68499a04f67949c131c5 (diff)
- Reformat ptrace.c for readability.
- Handle lazy fpu context switches correctly for ptrace(2). - Don't read $fcr31 on context switch, it's pure bloat. - New processes get $fcr31 initialized to no exceptions. - First beginnings of floating point support kernel code. For now we only can handle cvt.w.s and cvt.w.d instructions where the source register is a NaN, infinity or denorm. This is good enough to get Mozilla up. - Don't send SIGFPE on every floating point instruction we don't know how to handle, rather just complain. - Cleanup headerfile inclusions in the HPC3 code. - Fix the definition of PAGE_NONE.
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/ptrace.c291
-rw-r--r--arch/mips/kernel/r4k_switch.S22
-rw-r--r--arch/mips/kernel/softfp.S667
-rw-r--r--arch/mips/kernel/traps.c20
-rw-r--r--arch/mips/sgi/kernel/indy_hpc.c4
6 files changed, 853 insertions, 153 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 224d57a4e..8bea8ab5b 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -15,7 +15,7 @@ O_TARGET := kernel.o
O_OBJS := branch.o process.o signal.o entry.o traps.o ptrace.o vm86.o \
ioport.o pci.o reset.o setup.o syscall.o sysmips.o ipc.o \
r4k_switch.o r4k_misc.o r4k_fpu.o r2300_switch.o r2300_misc.o \
- r2300_fpu.o r6000_fpu.o scall_o32.o unaligned.o
+ r2300_fpu.o r6000_fpu.o scall_o32.o softfp.o unaligned.o
OX_OBJS := mips_ksyms.o
ifdef CONFIG_MIPS_FPE_MODULE
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index f9172b726..05fafefe3 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -1,8 +1,14 @@
-/* ptrace.c */
-/* By Ross Biro 1/23/92 */
-/* edited by Linus Torvalds */
-/* further hacked for MIPS by David S. Miller (dm@engr.sgi.com) */
-
+/* $Id: ptrace.c,v 1.9 1998/07/16 17:01:52 ralf Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 Ross Biro
+ * Copyright (C) Linus Torvalds
+ * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
+ * Copyright (C) 1996 David S. Miller
+ */
#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -13,10 +19,12 @@
#include <linux/smp_lock.h>
#include <linux/user.h>
-#include <asm/uaccess.h>
+#include <asm/fp.h>
+#include <asm/mipsregs.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/system.h>
+#include <asm/uaccess.h>
/*
* This routine gets a long from any process space by following the page
@@ -326,163 +334,182 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
switch (request) {
- /* when I and D space are separate, these will need to be fixed. */
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA: {
+ unsigned long tmp;
- res = read_long(child, addr, &tmp);
- if (res < 0)
- goto out;
- res = put_user(tmp,(unsigned long *) data);
+ res = read_long(child, addr, &tmp);
+ if (res < 0)
goto out;
+ res = put_user(tmp,(unsigned long *) data);
+ goto out;
}
/* read the word at location addr in the USER area. */
/* #define DEBUG_PEEKUSR */
- case PTRACE_PEEKUSR: {
- struct pt_regs *regs;
- unsigned long tmp;
+ case PTRACE_PEEKUSR: {
+ struct pt_regs *regs;
+ unsigned long tmp;
- regs = (struct pt_regs *) ((unsigned long) child +
- KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
- tmp = 0; /* Default return value. */
- if(addr < 32 && addr >= 0) {
- tmp = regs->regs[addr];
- } else if(addr >= 32 && addr < 64) {
- unsigned long long *fregs;
+ regs = (struct pt_regs *) ((unsigned long) child +
+ KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
+ tmp = 0; /* Default return value. */
+ if (addr < 32 && addr >= 0)
+ tmp = regs->regs[addr];
+ else if (addr >= 32 && addr < 64) {
+ unsigned long long *fregs;
- /* We don't want to do a FPU operation here. */
+ if (child->used_math) {
+ if (last_task_used_math == child) {
+ enable_cp1();
+ r4xx0_save_fp(child);
+ disable_cp1();
+ last_task_used_math = NULL;
+ }
fregs = (unsigned long long *)
&child->tss.fpu.hard.fp_regs[0];
tmp = (unsigned long) fregs[(addr - 32)];
} else {
- addr -= 64;
- switch(addr) {
- case 0:
- tmp = regs->cp0_epc;
- break;
- case 1:
- tmp = regs->cp0_cause;
- break;
- case 2:
- tmp = regs->cp0_badvaddr;
- break;
- case 3:
- tmp = regs->lo;
- break;
- case 4:
- tmp = regs->hi;
- break;
- case 5:
- tmp = child->tss.fpu.hard.control;
- break;
- case 6: /* implementation / version register */
- tmp = 0;
- break;
- default:
- tmp = 0;
- res = -EIO;
- goto out;
- };
+ tmp = -1; /* FP not yet used */
}
- res = put_user(tmp, (unsigned long *) data);
- goto out;
+ } else {
+ addr -= 64;
+ switch(addr) {
+ case 0:
+ tmp = regs->cp0_epc;
+ break;
+ case 1:
+ tmp = regs->cp0_cause;
+ break;
+ case 2:
+ tmp = regs->cp0_badvaddr;
+ break;
+ case 3:
+ tmp = regs->lo;
+ break;
+ case 4:
+ tmp = regs->hi;
+ break;
+ case 5:
+ tmp = child->tss.fpu.hard.control;
+ break;
+ case 6: /* implementation / version register */
+ tmp = 0; /* XXX */
+ break;
+ default:
+ tmp = 0;
+ res = -EIO;
+ goto out;
+ }
+ }
+ res = put_user(tmp, (unsigned long *) data);
+ goto out;
}
- /* when I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- res = write_long(child,addr,data);
- goto out;
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ res = write_long(child,addr,data);
+ goto out;
- case PTRACE_POKEUSR: {
- struct pt_regs *regs;
- int res = 0;
+ case PTRACE_POKEUSR: {
+ struct pt_regs *regs;
+ int res = 0;
- regs = (struct pt_regs *) ((unsigned long) child +
- KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
- if(addr < 32 && addr >= 0) {
- regs->regs[addr] = data;
- } else if(addr >= 32 && addr < 64) {
- unsigned long long *fregs;
+ regs = (struct pt_regs *) ((unsigned long) child +
+ KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
+ if (addr < 32 && addr >= 0)
+ regs->regs[addr] = data;
+ else if (addr >= 32 && addr < 64) {
+ unsigned long long *fregs;
- /* We don't want to do a FPU operation here. */
- fregs = (unsigned long long *)
- &child->tss.fpu.hard.fp_regs[0];
- fregs[(addr - 32)] = (unsigned long long) data;
+ if (child->used_math) {
+ if (last_task_used_math == child) {
+ enable_cp1();
+ r4xx0_save_fp(child);
+ disable_cp1();
+ last_task_used_math = NULL;
+ }
} else {
- addr -= 64;
- switch(addr) {
- case 0:
- regs->cp0_epc = data;
- break;
- case 3:
- regs->lo = data;
- break;
- case 4:
- regs->hi = data;
- break;
- case 5:
- child->tss.fpu.hard.control = data;
- break;
- default:
- /* The rest are not allowed. */
- res = -EIO;
- break;
- };
+ /* FP not yet used */
+ memset(&child->tss.fpu.hard, ~0,
+ sizeof(child->tss.fpu.hard));
+ child->tss.fpu.hard.control = 0;
}
- goto out;
- }
-
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- if ((unsigned long) data > _NSIG) {
+ fregs = (unsigned long long *)
+ &child->tss.fpu.hard.fp_regs[0];
+ fregs[(addr - 32)] = (unsigned long long) data;
+ } else {
+ addr -= 64;
+ switch (addr) {
+ case 0:
+ regs->cp0_epc = data;
+ break;
+ case 3:
+ regs->lo = data;
+ break;
+ case 4:
+ regs->hi = data;
+ break;
+ case 5:
+ child->tss.fpu.hard.control = data;
+ break;
+ default:
+ /* The rest are not allowed. */
res = -EIO;
- goto out;
- }
- if (request == PTRACE_SYSCALL)
- child->flags |= PF_TRACESYS;
- else
- child->flags &= ~PF_TRACESYS;
- child->exit_code = data;
- wake_up_process(child);
- res = data;
- goto out;
+ break;
+ };
+ }
+ goto out;
}
-/*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL: {
- if (child->state != TASK_ZOMBIE) {
- wake_up_process(child);
- child->exit_code = SIGKILL;
- }
- res = 0;
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: { /* restart after signal. */
+ if ((unsigned long) data > _NSIG) {
+ res = -EIO;
goto out;
}
+ if (request == PTRACE_SYSCALL)
+ child->flags |= PF_TRACESYS;
+ else
+ child->flags &= ~PF_TRACESYS;
+ child->exit_code = data;
+ wake_up_process(child);
+ res = data;
+ goto out;
+ }
- case PTRACE_DETACH: { /* detach a process that was attached. */
- if ((unsigned long) data > _NSIG) {
- res = -EIO;
- goto out;
- }
- child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ /*
+ * make the child exit. Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
+ * exit.
+ */
+ case PTRACE_KILL: {
+ if (child->state != TASK_ZOMBIE) {
wake_up_process(child);
- child->exit_code = data;
- REMOVE_LINKS(child);
- child->p_pptr = child->p_opptr;
- SET_LINKS(child);
- res = 0;
- goto out;
+ child->exit_code = SIGKILL;
+ }
+ res = 0;
+ goto out;
}
- default:
+ case PTRACE_DETACH: { /* detach a process that was attached. */
+ if ((unsigned long) data > _NSIG) {
res = -EIO;
goto out;
+ }
+ child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ wake_up_process(child);
+ child->exit_code = data;
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ res = 0;
+ goto out;
+ }
+
+ default:
+ res = -EIO;
+ goto out;
}
out:
unlock_kernel();
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 765de0d85..e8bc524a4 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -1,12 +1,12 @@
-/*
- * r4k_switch.S: R4xx0 specific task switching code.
+/* $Id: r4k_switch.S,v 1.3 1998/04/05 11:23:52 ralf Exp $
*
- * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*
- * Multi-cpu abstraction and macros for easier reading:
+ * Copyright (C) 1994, 1995, 1996, 1998 by Ralf Baechle
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: r4k_switch.S,v 1.3 1998/04/04 13:59:38 ralf Exp $
+ * Copyright (C) 1994, 1995, 1996, by Andreas Busse
*/
#include <asm/asm.h>
#include <asm/bootinfo.h>
@@ -28,12 +28,8 @@
.set mips3
.align 5
LEAF(r4xx0_resume)
- mfc0 t1, CP0_STATUS # fp exception boundary
- sll t0, t1, 2
- bgez t0, 1f
- nop
- cfc1 zero, fcr31
-1: sw t1, THREAD_STATUS($28)
+ mfc0 t1, CP0_STATUS
+ sw t1, THREAD_STATUS($28)
CPU_SAVE_NONSCRATCH($28)
sw ra, THREAD_REG31($28)
@@ -114,7 +110,7 @@ LEAF(r4xx0_save_fp)
* We initialize fcr31 to rounding to nearest, no exceptions.
*/
-#define FPU_DEFAULT 0x00000600
+#define FPU_DEFAULT 0x00000000
LEAF(r4xx0_init_fpu)
mfc0 t0, CP0_STATUS
diff --git a/arch/mips/kernel/softfp.S b/arch/mips/kernel/softfp.S
new file mode 100644
index 000000000..85ab779a9
--- /dev/null
+++ b/arch/mips/kernel/softfp.S
@@ -0,0 +1,667 @@
+/* $Id: softfp.S,v 1.1 1998/07/14 09:33:48 ralf Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1998 by Ralf Baechle
+ *
+ * For now it's just a crude hack good enough to run certain fp programs like
+ * Mozilla.
+ * XXX: Handle MIPS II/III/IV/V enhancements, exceptions, ...
+ */
+#include <asm/regdef.h>
+#include <asm/asm.h>
+
+#ifndef __KERNEL__
+#define printk printf
+#endif
+
+#define LOCK_KERNEL
+#define UNLOCK_KERNEL
+
+/*
+ * This duplicates definitions from <linux/kernel.h>.
+ */
+#define KERN_EMERG "<0>" /* system is unusable */
+#define KERN_ALERT "<1>" /* action must be taken immediately */
+#define KERN_CRIT "<2>" /* critical conditions */
+#define KERN_ERR "<3>" /* error conditions */
+#define KERN_WARNING "<4>" /* warning conditions */
+#define KERN_NOTICE "<5>" /* normal but significant condition */
+#define KERN_INFO "<6>" /* informational */
+#define KERN_DEBUG "<7>" /* debug-level messages */
+
+/*
+ * This duplicates definitions from <asm/signal.h>
+ */
+#define SIGILL 4 /* Illegal instruction (ANSI). */
+
+/*
+ * Definitions about the instruction format
+ */
+#define fd_shift 6
+#define fr_shift 21
+#define fs_shift 11
+#define ft_shift 16
+
+/*
+ * NaNs as use by the MIPS architecture
+ */
+#define S_QNaN 0x7fbfffff
+#define D_QNaN 0x7ff7ffffffffffff
+#define W_QNaN 0x7fffffff
+#define L_QNaN 0x7fffffffffffffff
+
+/*
+ * Checking for NaNs
+ */
+#define S_is_QNaN(reg,res) \
+ sll res, reg, S_F_size - S_F_bits
+#define D_is_QNaN(reg1,reg2,res) \
+ sll res, reg1, (D_F_size - 32) - (D_F_bits - 32); \
+ or res, reg2
+
+/*
+ * Checking for Denorms
+ */
+#define S_is_Denorm(reg,res) \
+ li res, 1 << (S_F_bits - 1); \
+ and reg, res
+
+/*
+ * Some constants that define the properties of single precission numbers.
+ */
+#define S_M_prec 24
+#define S_E_max 127
+#define S_E_min -126
+#define S_E_bias 127
+#define S_E_bits 8
+#define S_F_bits 23
+#define S_F_size 32
+
+/* Set temp0, if exponent of reg is S_E_max + 1. */
+#define S_is_E_max(reg,temp0,temp1) \
+ li temp0, (S_E_max + 1 + S_E_bias) << S_F_bits; \
+ and temp1, temp0, reg; \
+ seq temp0, temp1 /* temp0 != 0 if NaN */
+
+/* Clear temp0, if exponent of reg is S_E_min - 1. */
+#define S_is_E_min(reg,temp0) \
+ li temp0, (S_E_min - 1 + S_E_bias) << S_F_bits; \
+ and temp0, reg /* temp0 == 0 if denorm or zero */
+
+/* Set temp0 if reg is a NaN assuming S_is_E_max is true */
+#define S_get_F(reg,temp0) \
+ li temp0, (1 << S_F_bits) - 1; \
+ and temp0, reg /* temp0 != 0 if NaN */
+
+/* Set res if fraction of reg is != 0. */
+#define S_is_Inf(reg,res) \
+ li res, (1 << S_F_bits) - 1; \
+ and res, reg /* temp0 == 0 if Inf */
+
+
+/*
+ * Some constants that define the properties of double precission numbers.
+ */
+#define D_M_prec 53
+#define D_E_max 1023
+#define D_E_min -1022
+#define D_E_bias 1023
+#define D_E_bits 8
+#define D_F_bits 52
+#define D_F_size 64
+
+/* Set temp0, if exponent of reg1/reg2 is D_E_max. */
+#define D_is_E_max(reg1,reg2,temp0,temp1) \
+ li temp0, (D_E_max + 1 + D_E_bias) << (D_F_bits - 32); \
+ and temp1, temp0, reg1; \
+ seq temp0, temp1 /* temp0 != 0 if NaN */
+
+/* Clear temp0, if exponent of reg is D_E_min. */
+#define D_is_E_min(reg1,reg2,res) \
+ li res, (D_E_min + 1 + D_E_bias) << (D_F_bits - 32); \
+ and res, reg1 /* temp0 == 0 if NaN or zero */
+
+/* Set res if reg is a NaN assuming S_is_E_max is true */
+#define D_get_F(reg1,reg2,res) \
+ li res, (1 << (D_F_bits - 32)) - 1; \
+ and res, reg1 /* temp0 != 0 if NaN */
+
+/* Set temp0 if reg1/reg2 is a NaN */
+#define D_is_NAN(reg1,reg2,temp0,temp1) \
+ li temp0, (1 << (D_F_bits - 32) - 1; \
+ and temp0, reg1; \
+ or temp0, reg2; \
+ sne temp0, zero, temp0 /* temp0 != 0 if NaN */
+
+/* Set res if fraction of reg1/reg2 is != 0. */
+#define D_is_Inf(reg1,reg2,res) \
+ li res, (1 << (D_F_bits - 32)) - 1; \
+ and res, reg1; \
+ or res, reg2 /* temp0 == 0 if Inf */
+
+/* Complain about yet unhandled instruction. */
+#define BITCH(insn) \
+insn: LOCK_KERNEL; \
+ la a1, 8f; \
+ TEXT(#insn); \
+ la a1, nosim; \
+ UNLOCK_KERNEL; \
+ j done
+
+ .data
+nosim: .asciz KERN_DEBUG "Don't know how to simulate %s instruction\n"
+ .previous
+
+/*
+ * When we come here, we've saved some of the integer registers and
+ * reenabled interrupts.
+ */
+LEAF(simfp)
+ .set noreorder
+ .cpload $25
+ .set reorder
+
+ subu sp, 16
+ .cprestore 20
+ sw ra, 16(sp)
+
+ /* For now we assume that we get the opcode to simulate passed in as
+ an argument. */
+ move t0, a0
+
+ /*
+ * First table lookup using insn[5:0]
+ */
+ la t1, lowtab
+ andi t2, t0, 0x3f
+ sll t2, t2, 2
+ addu t1, t2
+ lw t1, (t1)
+ jr t1
+ END(simfp)
+
+/*
+ * We only decode the lower 3 of the 5 bit in the fmt field. That way we
+ * can keep the jump table significantly shorter.
+ */
+#define FMT_switch(insn,opc,temp0,temp1) \
+insn: srl temp0, opc, 19; \
+ andi temp0, 0x1c; \
+ la temp1, insn ## .tab; \
+ addu temp0, temp1; \
+ lw temp0, (temp0); \
+ jr temp0; \
+ \
+ .data; \
+insn ## .tab: \
+ .word insn ## .s, insn ## .d, unimp, unimp; \
+ .word insn ## .w, insn ## .l, unimp, unimp; \
+ .previous
+
+ BITCH(add)
+ BITCH(sub)
+ BITCH(mul)
+ BITCH(div)
+ BITCH(sqrt)
+ BITCH(abs)
+ BITCH(mov)
+ BITCH(neg)
+ BITCH(round.l)
+ BITCH(trunc.l)
+ BITCH(ceil.l)
+ BITCH(floor.l)
+ BITCH(round.w)
+ BITCH(trunc.w)
+ BITCH(ceil.w)
+ BITCH(floor.w)
+ BITCH(cvt.s)
+ BITCH(cvt.d)
+
+/* ------------------------------------------------------------------------ */
+
+FMT_switch(cvt.w,t0,t1,t2)
+
+/* Convert a single fp to a fixed point integer. */
+cvt.w.s:
+ srl t1, t0, fs_shift # Get source register
+ andi t1, 31
+ jal s_get_fpreg
+
+ S_is_E_max(t1,t2,t3)
+ beqz t2, 3f
+ /* Might be a NaN or Inf. */
+ S_get_F(t1,t2)
+ beqz t2, 2f
+
+ /* It's a NaN. IEEE says undefined. */
+ /* Is it a QNaN? Then the result is a QNaN as well. */
+ S_is_QNaN(t1,t2)
+ bltz t2, 1f
+
+ /* XXX Ok, it's a SNaN. Signal invalid exception, if enabled.
+ For now we don't signal and supply a QNaN for result. */
+
+1: li t2, W_QNaN
+ srl t1, t0, fd_shift # Put result register
+ andi t1, 31
+ jal s_put_fpreg
+ j done
+2:
+
+ S_is_Inf(t1,t2)
+ bnez t2, 2f
+
+ /* It's +/- Inf. Set register to +/- max. integer. */
+ /* XXX Send invalid operation exception instead, if enabled. */
+ srl t1, t1, 31 # Extract sign bit
+ li t2, 0x7fffffff
+ addu t2, t1
+
+ srl t1, t0, fd_shift # Put result register
+ andi t1, 31
+ jal s_put_fpreg
+ j done
+2:
+3:
+
+ /* But then it might be a denorm or zero? */
+ S_is_E_min(t1,t2)
+ bnez t2, 2f
+
+ /* Ok, it's a denorm or zero. */
+ S_get_F(t1,t2)
+ beqz t2, 1f
+
+ /* It's a denorm. */
+ /* XXX Should be signaling inexact exception, if enabled. */
+ /* Fall through. */
+1:
+ /* Yes, it is a denorm or zero. Supply a zero as result. */
+ move t2, zero
+ srl t1, t0, fd_shift # Put result register
+ andi t1, 31
+ jal s_put_fpreg
+ j done
+2:
+
+ /* XXX Ok, it's a normal number. We don't handle that case yet.
+ If we have fp hardware this case is unreached. Add this for
+ full fp simulation. */
+
+ /* Done, return. */
+ lw ra, 16(sp)
+ addu sp, 16
+ jr ra
+
+/* Convert a double fp to a fixed point integer. */
+cvt.w.d:
+ srl t1, t0, fs_shift # Get source register
+ andi t1, 31
+ jal d_get_fpreg
+
+ D_is_E_max(t1,t2,t3,t4)
+ beqz t3, 3f
+
+ /* Might be a NaN or Inf. */
+ D_get_F(t1,t2,t3)
+ or t3, t2
+ beqz t3, 2f
+
+ /* It's a NaN. IEEE says undefined. */
+ /* Is it a QNaN? Then the result is a QNaN as well. */
+ D_is_QNaN(t1,t2,t3)
+ bltz t3, 1f
+
+ /* XXX Ok, it's a SNaN. Signal invalid exception, if enabled.
+ For now we don't signal and supply a QNaN for result. */
+
+1: li t2, W_QNaN
+ srl t1, t0, fd_shift # Put result register
+ andi t1, 31
+ jal s_put_fpreg
+ j done
+2:
+
+ D_is_Inf(t1,t2,t3)
+ bnez t3, 2f
+
+ /* It's +/- Inf. Set register to +/- max. integer. */
+ /* XXX Send invalid operation exception instead, if enabled. */
+ srl t1, t1, 31 # Extract sign bit
+ li t2, 0x7fffffff
+ addu t2, t1
+
+ srl t1, t0, fd_shift # Put result register
+ andi t1, 31
+ jal s_put_fpreg
+ j done
+2:
+3:
+
+ /* But then it might be a denorm or zero? */
+ D_is_E_min(t1,t2,t3)
+ bnez t3, 2f
+
+ /* Ok, it's a denorm or zero. */
+ D_get_F(t1,t2,t3)
+ or t3, t2
+ beqz t3, 1f
+
+ /* It's a denorm. */
+ /* XXX Should be signaling inexact exception, if enabled. */
+ /* Fall through. */
+1:
+ /* Yes, it is a denorm or zero. Supply a zero as result. */
+ move t2, zero
+ srl t1, t0, fd_shift # Put result register
+ andi t1, 31
+ jal s_put_fpreg
+ j done
+2:
+
+ /* XXX Ok, it's a normal number. We don't handle that case yet.
+ If we have fp hardware this case is only reached if the value
+ of the source register exceeds the range which is representable
+ in a single precission register. For now we kludge by returning
+ +/- maxint and don't signal overflow. */
+
+ srl t1, t1, 31 # Extract sign bit
+ li t2, 0x7fffffff
+ addu t2, t1
+
+ srl t1, t0, fd_shift # Put result register
+ andi t1, 31
+ jal s_put_fpreg
+
+ /* Done, return. */
+ lw ra, 16(sp)
+ addu sp, 16
+ jr ra
+
+cvt.w.w = unimp # undefined result
+cvt.w.l = unimp # undefined result
+
+/* MIPS III extension, no need to handle for 32bit OS. */
+cvt.l = unimp
+
+/* ------------------------------------------------------------------------ */
+
+ BITCH(c.f)
+ BITCH(c.un)
+ BITCH(c.eq)
+ BITCH(c.ueq)
+ BITCH(c.olt)
+ BITCH(c.ult)
+ BITCH(c.ole)
+ BITCH(c.ule)
+ BITCH(c.sf)
+ BITCH(c.ngle)
+ BITCH(c.seq)
+ BITCH(c.ngl)
+ BITCH(c.lt)
+ BITCH(c.nge)
+ BITCH(c.le)
+ BITCH(c.ngt)
+
+/* Get the single precission register which's number is in t1. */
+s_get_fpreg:
+ .set noat
+ sll AT, t1, 2
+ sll t1, 3
+ addu t1, AT
+ la AT, 1f
+ addu AT, t1
+ jr AT
+ .set at
+
+1: mfc1 t1, $0
+ jr ra
+ mfc1 t1, $1
+ jr ra
+ mfc1 t1, $2
+ jr ra
+ mfc1 t1, $3
+ jr ra
+ mfc1 t1, $4
+ jr ra
+ mfc1 t1, $5
+ jr ra
+ mfc1 t1, $6
+ jr ra
+ mfc1 t1, $7
+ jr ra
+ mfc1 t1, $8
+ jr ra
+ mfc1 t1, $9
+ jr ra
+ mfc1 t1, $10
+ jr ra
+ mfc1 t1, $11
+ jr ra
+ mfc1 t1, $12
+ jr ra
+ mfc1 t1, $13
+ jr ra
+ mfc1 t1, $14
+ jr ra
+ mfc1 t1, $15
+ jr ra
+ mfc1 t1, $16
+ jr ra
+ mfc1 t1, $17
+ jr ra
+ mfc1 t1, $18
+ jr ra
+ mfc1 t1, $19
+ jr ra
+ mfc1 t1, $20
+ jr ra
+ mfc1 t1, $21
+ jr ra
+ mfc1 t1, $22
+ jr ra
+ mfc1 t1, $23
+ jr ra
+ mfc1 t1, $24
+ jr ra
+ mfc1 t1, $25
+ jr ra
+ mfc1 t1, $26
+ jr ra
+ mfc1 t1, $27
+ jr ra
+ mfc1 t1, $28
+ jr ra
+ mfc1 t1, $29
+ jr ra
+ mfc1 t1, $30
+ jr ra
+ mfc1 t1, $31
+ jr ra
+
+/*
+ * Put the value in t2 into the single precission register which's number
+ * is in t1.
+ */
+s_put_fpreg:
+ .set noat
+ sll AT, t1, 2
+ sll t1, 3
+ addu t1, AT
+ la AT, 1f
+ addu AT, t1
+ jr AT
+ .set at
+
+1: mtc1 t2, $0
+ jr ra
+ mtc1 t2, $1
+ jr ra
+ mtc1 t2, $2
+ jr ra
+ mtc1 t2, $3
+ jr ra
+ mtc1 t2, $4
+ jr ra
+ mtc1 t2, $5
+ jr ra
+ mtc1 t2, $6
+ jr ra
+ mtc1 t2, $7
+ jr ra
+ mtc1 t2, $8
+ jr ra
+ mtc1 t2, $9
+ jr ra
+ mtc1 t2, $10
+ jr ra
+ mtc1 t2, $11
+ jr ra
+ mtc1 t2, $12
+ jr ra
+ mtc1 t2, $13
+ jr ra
+ mtc1 t2, $14
+ jr ra
+ mtc1 t2, $15
+ jr ra
+ mtc1 t2, $16
+ jr ra
+ mtc1 t2, $17
+ jr ra
+ mtc1 t2, $18
+ jr ra
+ mtc1 t2, $19
+ jr ra
+ mtc1 t2, $20
+ jr ra
+ mtc1 t2, $21
+ jr ra
+ mtc1 t2, $22
+ jr ra
+ mtc1 t2, $23
+ jr ra
+ mtc1 t2, $24
+ jr ra
+ mtc1 t2, $25
+ jr ra
+ mtc1 t2, $26
+ jr ra
+ mtc1 t2, $27
+ jr ra
+ mtc1 t2, $28
+ jr ra
+ mtc1 t2, $29
+ jr ra
+ mtc1 t2, $30
+ jr ra
+ mtc1 t2, $31
+ jr ra
+
+/* Get the double precission register which's number is in t1 into t1/t2. */
+d_get_fpreg:
+ .set noat
+ sll t1, 3
+ la AT, 1f
+ addu AT, t1
+ jr AT
+ .set at
+
+1: mfc1 t1, $0
+ mfc1 t2, $1
+ jr ra
+ mfc1 t1, $2
+ mfc1 t2, $3
+ jr ra
+ mfc1 t1, $4
+ mfc1 t2, $5
+ jr ra
+ mfc1 t1, $6
+ mfc1 t2, $7
+ jr ra
+ mfc1 t1, $8
+ mfc1 t2, $9
+ jr ra
+ mfc1 t1, $10
+ mfc1 t2, $11
+ jr ra
+ mfc1 t1, $12
+ mfc1 t2, $13
+ jr ra
+ mfc1 t1, $14
+ mfc1 t2, $15
+ jr ra
+ mfc1 t1, $16
+ mfc1 t2, $17
+ jr ra
+ mfc1 t1, $18
+ mfc1 t2, $19
+ jr ra
+ mfc1 t1, $20
+ mfc1 t2, $21
+ jr ra
+ mfc1 t1, $22
+ mfc1 t2, $23
+ jr ra
+ mfc1 t1, $24
+ mfc1 t2, $25
+ jr ra
+ mfc1 t1, $26
+ mfc1 t2, $27
+ jr ra
+ mfc1 t1, $28
+ mfc1 t2, $29
+ jr ra
+ mfc1 t1, $30
+ mfc1 t2, $31
+ jr ra
+
+/*
+ * Send an invalid operation exception.
+ */
+invalid:
+ lw ra, 16(sp)
+ addu sp, 16
+ jr ra
+
+/*
+ * Done, just skip over the current instruction
+ */
+done:
+ lw ra, 16(sp)
+ addu sp, 16
+ jr ra
+
+unimp:
+ /* We've run into an yet unknown instruction. This happens either
+ on new, yet unsupported CPU types or when the faulting instruction
+ is being executed for cache but has been overwritten in memory. */
+ LOCK_KERNEL
+ move a0, t0
+ PRINT(KERN_DEBUG "FP support: unknown fp op %08lx, ")
+ PRINT("please mail to ralf@gnu.org.\n")
+
+ li a0, SIGILL # Die, sucker ...
+ move a1, $28
+ jal force_sig
+ UNLOCK_KERNEL
+
+ lw ra, 16(sp)
+ addu sp, 16
+ jr ra
+
+/*
+ * Jump table for the lowest 6 bits of a cp1 instruction.
+ */
+ .data
+lowtab: .word add, sub, mul, div, sqrt, abs, mov, neg
+ .word round.l,trunc.l,ceil.l,floor.l,round.w,trunc.w,ceil.w,floor.w
+ .word unimp, unimp, unimp, unimp, unimp, unimp, unimp, unimp
+ .word unimp, unimp, unimp, unimp, unimp, unimp, unimp, unimp
+ .word cvt.s, cvt.d, unimp, unimp, cvt.w, cvt.l, unimp, unimp
+ .word unimp, unimp, unimp, unimp, unimp, unimp, unimp, unimp
+ .word c.f, c.un, c.eq, c.ueq, c.olt, c.ult, c.ole, c.ule
+ .word c.sf, c.ngle,c.seq, c.ngl, c.lt, c.nge, c.le, c.ngt
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 7d5a703f6..8c941c4ee 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.12 1998/06/30 00:21:53 ralf Exp $
+/* $Id: traps.c,v 1.13 1998/07/10 01:14:48 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -226,6 +226,9 @@ int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31))
*/
void do_fpe(struct pt_regs *regs, unsigned long fcr31)
{
+ unsigned long pc;
+ unsigned int insn;
+
#ifdef CONFIG_MIPS_FPE_MODULE
if (fpe_handler != NULL) {
fpe_handler(regs, fcr31);
@@ -246,13 +249,22 @@ void do_fpe(struct pt_regs *regs, unsigned long fcr31)
: "r" (fcr31));
goto out;
}
- printk("Unimplemented exception at 0x%08lx in %s.\n",
- regs->cp0_epc, current->comm);
+ pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0);
+ if (get_user(insn, (unsigned int *)pc)) {
+ /* XXX Can this happen? */
+ force_sig(SIGSEGV, current);
+ }
+
+ printk(KERN_DEBUG "Unimplemented exception for insn %08x at 0x%08lx in %s.\n",
+ insn, regs->cp0_epc, current->comm);
+ simfp(insn);
}
if (compute_return_epc(regs))
goto out;
- force_sig(SIGFPE, current);
+ //force_sig(SIGFPE, current);
+ printk(KERN_DEBUG "Should send SIGFPE to %s\n", current->comm);
+
out:
unlock_kernel();
}
diff --git a/arch/mips/sgi/kernel/indy_hpc.c b/arch/mips/sgi/kernel/indy_hpc.c
index eb62c3150..2762bb097 100644
--- a/arch/mips/sgi/kernel/indy_hpc.c
+++ b/arch/mips/sgi/kernel/indy_hpc.c
@@ -3,13 +3,11 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: indy_hpc.c,v 1.2 1998/04/05 11:23:57 ralf Exp $
+ * $Id: indy_hpc.c,v 1.3 1998/07/10 01:14:50 ralf Exp $
*/
#include <linux/init.h>
#include <asm/addrspace.h>
-#include <asm/ptrace.h>
-#include <asm/processor.h>
#include <asm/sgihpc.h>
#include <asm/sgint23.h>
#include <asm/sgialib.h>