aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/mips/kernel
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/Makefile65
-rw-r--r--arch/mips/kernel/binfmt_elfn32.c119
-rw-r--r--arch/mips/kernel/binfmt_elfo32.c139
-rw-r--r--arch/mips/kernel/branch.c199
-rw-r--r--arch/mips/kernel/cpu-bugs64.c321
-rw-r--r--arch/mips/kernel/cpu-probe.c598
-rw-r--r--arch/mips/kernel/entry.S155
-rw-r--r--arch/mips/kernel/gdb-low.S370
-rw-r--r--arch/mips/kernel/gdb-stub.c1091
-rw-r--r--arch/mips/kernel/genex.S302
-rw-r--r--arch/mips/kernel/genrtc.c64
-rw-r--r--arch/mips/kernel/head.S221
-rw-r--r--arch/mips/kernel/i8259.c331
-rw-r--r--arch/mips/kernel/init_task.c42
-rw-r--r--arch/mips/kernel/ioctl32.c58
-rw-r--r--arch/mips/kernel/irix5sys.S1041
-rw-r--r--arch/mips/kernel/irixelf.c1326
-rw-r--r--arch/mips/kernel/irixinv.c77
-rw-r--r--arch/mips/kernel/irixioctl.c261
-rw-r--r--arch/mips/kernel/irixsig.c853
-rw-r--r--arch/mips/kernel/irq-msc01.c189
-rw-r--r--arch/mips/kernel/irq-mv6434x.c161
-rw-r--r--arch/mips/kernel/irq-rm7000.c98
-rw-r--r--arch/mips/kernel/irq-rm9000.c149
-rw-r--r--arch/mips/kernel/irq.c140
-rw-r--r--arch/mips/kernel/irq_cpu.c118
-rw-r--r--arch/mips/kernel/linux32.c1469
-rw-r--r--arch/mips/kernel/mips_ksyms.c67
-rw-r--r--arch/mips/kernel/module-elf32.c250
-rw-r--r--arch/mips/kernel/module-elf64.c274
-rw-r--r--arch/mips/kernel/module.c53
-rw-r--r--arch/mips/kernel/offset.c314
-rw-r--r--arch/mips/kernel/proc.c149
-rw-r--r--arch/mips/kernel/process.c364
-rw-r--r--arch/mips/kernel/ptrace.c338
-rw-r--r--arch/mips/kernel/ptrace32.c285
-rw-r--r--arch/mips/kernel/r2300_fpu.S126
-rw-r--r--arch/mips/kernel/r2300_switch.S174
-rw-r--r--arch/mips/kernel/r4k_fpu.S191
-rw-r--r--arch/mips/kernel/r4k_switch.S221
-rw-r--r--arch/mips/kernel/r6000_fpu.S87
-rw-r--r--arch/mips/kernel/reset.c43
-rw-r--r--arch/mips/kernel/scall32-o32.S641
-rw-r--r--arch/mips/kernel/scall64-64.S451
-rw-r--r--arch/mips/kernel/scall64-n32.S365
-rw-r--r--arch/mips/kernel/scall64-o32.S488
-rw-r--r--arch/mips/kernel/semaphore.c164
-rw-r--r--arch/mips/kernel/setup.c571
-rw-r--r--arch/mips/kernel/signal-common.h137
-rw-r--r--arch/mips/kernel/signal.c517
-rw-r--r--arch/mips/kernel/signal32.c905
-rw-r--r--arch/mips/kernel/signal_n32.c197
-rw-r--r--arch/mips/kernel/smp.c425
-rw-r--r--arch/mips/kernel/syscall.c407
-rw-r--r--arch/mips/kernel/sysirix.c2179
-rw-r--r--arch/mips/kernel/time.c755
-rw-r--r--arch/mips/kernel/traps.c1062
-rw-r--r--arch/mips/kernel/unaligned.c550
-rw-r--r--arch/mips/kernel/vmlinux.lds.S183
59 files changed, 22890 insertions, 0 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
new file mode 100644
index 00000000000..a0230ee0f7f
--- /dev/null
+++ b/arch/mips/kernel/Makefile
@@ -0,0 +1,65 @@
+#
+# Makefile for the Linux/MIPS kernel.
+#
+
+extra-y := head.o init_task.o vmlinux.lds
+
+obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
+ ptrace.o reset.o semaphore.o setup.o signal.o syscall.o \
+ time.o traps.o unaligned.o
+
+binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
+ irix5sys.o sysirix.o
+
+ifdef CONFIG_MODULES
+obj-y += mips_ksyms.o module.o
+obj-$(CONFIG_MIPS32) += module-elf32.o
+obj-$(CONFIG_MIPS64) += module-elf64.o
+endif
+
+obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o
+obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o
+obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_R4000) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_R4300) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_R4X00) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_R5000) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_R5432) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_R8000) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_RM7000) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_RM9000) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_NEVADA) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_R10000) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_SB1) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o
+
+obj-$(CONFIG_SMP) += smp.o
+
+obj-$(CONFIG_NO_ISA) += dma-no-isa.o
+obj-$(CONFIG_I8259) += i8259.o
+obj-$(CONFIG_IRQ_CPU) += irq_cpu.o
+obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o
+obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o
+obj-$(CONFIG_IRQ_MV64340) += irq-mv6434x.o
+
+obj-$(CONFIG_MIPS32) += scall32-o32.o
+obj-$(CONFIG_MIPS64) += scall64-64.o
+obj-$(CONFIG_BINFMT_IRIX) += binfmt_irix.o
+obj-$(CONFIG_MIPS32_COMPAT) += ioctl32.o linux32.o signal32.o
+obj-$(CONFIG_MIPS32_N32) += binfmt_elfn32.o scall64-n32.o signal_n32.o
+obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o ptrace32.o
+
+obj-$(CONFIG_KGDB) += gdb-low.o gdb-stub.o
+obj-$(CONFIG_PROC_FS) += proc.o
+
+obj-$(CONFIG_MIPS64) += cpu-bugs64.o
+
+obj-$(CONFIG_GEN_RTC) += genrtc.o
+
+CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
+CFLAGS_ioctl32.o += -Ifs/
+
+EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c
new file mode 100644
index 00000000000..ed47041f303
--- /dev/null
+++ b/arch/mips/kernel/binfmt_elfn32.c
@@ -0,0 +1,119 @@
+/*
+ * Support for n32 Linux/MIPS ELF binaries.
+ *
+ * Copyright (C) 1999, 2001 Ralf Baechle
+ * Copyright (C) 1999, 2001 Silicon Graphics, Inc.
+ *
+ * Heavily inspired by the 32-bit Sparc compat code which is
+ * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#define ELF_ARCH EM_MIPS
+#define ELF_CLASS ELFCLASS32
+#ifdef __MIPSEB__
+#define ELF_DATA ELFDATA2MSB;
+#else /* __MIPSEL__ */
+#define ELF_DATA ELFDATA2LSB;
+#endif
+
+/* ELF register definitions */
+#define ELF_NGREG 45
+#define ELF_NFPREG 33
+
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(hdr) \
+({ \
+ int __res = 1; \
+ struct elfhdr *__h = (hdr); \
+ \
+ if (__h->e_machine != EM_MIPS) \
+ __res = 0; \
+ if (__h->e_ident[EI_CLASS] != ELFCLASS32) \
+ __res = 0; \
+ if (((__h->e_flags & EF_MIPS_ABI2) == 0) || \
+ ((__h->e_flags & EF_MIPS_ABI) != 0)) \
+ __res = 0; \
+ \
+ __res; \
+})
+
+#define TASK32_SIZE 0x7fff8000UL
+#undef ELF_ET_DYN_BASE
+#define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2)
+
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/elfcore.h>
+#include <linux/compat.h>
+
+#define elf_prstatus elf_prstatus32
+struct elf_prstatus32
+{
+ struct elf_siginfo pr_info; /* Info associated with signal */
+ short pr_cursig; /* Current signal */
+ unsigned int pr_sigpend; /* Set of pending signals */
+ unsigned int pr_sighold; /* Set of held signals */
+ pid_t pr_pid;
+ pid_t pr_ppid;
+ pid_t pr_pgrp;
+ pid_t pr_sid;
+ struct compat_timeval pr_utime; /* User time */
+ struct compat_timeval pr_stime; /* System time */
+ struct compat_timeval pr_cutime;/* Cumulative user time */
+ struct compat_timeval pr_cstime;/* Cumulative system time */
+ elf_gregset_t pr_reg; /* GP registers */
+ int pr_fpvalid; /* True if math co-processor being used. */
+};
+
+#define elf_prpsinfo elf_prpsinfo32
+struct elf_prpsinfo32
+{
+ char pr_state; /* numeric process state */
+ char pr_sname; /* char for pr_state */
+ char pr_zomb; /* zombie */
+ char pr_nice; /* nice val */
+ unsigned int pr_flag; /* flags */
+ __kernel_uid_t pr_uid;
+ __kernel_gid_t pr_gid;
+ pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
+ /* Lots missing */
+ char pr_fname[16]; /* filename of executable */
+ char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+#define elf_addr_t u32
+#define elf_caddr_t u32
+#define init_elf_binfmt init_elfn32_binfmt
+
+#define jiffies_to_timeval jiffies_to_compat_timeval
+static __inline__ void
+jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
+{
+ /*
+ * Convert jiffies to nanoseconds and seperate with
+ * one divide.
+ */
+ u64 nsec = (u64)jiffies * TICK_NSEC;
+ value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_usec);
+ value->tv_usec /= NSEC_PER_USEC;
+}
+
+#define ELF_CORE_EFLAGS EF_MIPS_ABI2
+
+MODULE_DESCRIPTION("Binary format loader for compatibility with n32 Linux/MIPS binaries");
+MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)");
+
+#undef MODULE_DESCRIPTION
+#undef MODULE_AUTHOR
+
+#include "../../../fs/binfmt_elf.c"
diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
new file mode 100644
index 00000000000..ee21b18c37a
--- /dev/null
+++ b/arch/mips/kernel/binfmt_elfo32.c
@@ -0,0 +1,139 @@
+/*
+ * Support for o32 Linux/MIPS ELF binaries.
+ *
+ * Copyright (C) 1999, 2001 Ralf Baechle
+ * Copyright (C) 1999, 2001 Silicon Graphics, Inc.
+ *
+ * Heavily inspired by the 32-bit Sparc compat code which is
+ * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#define ELF_ARCH EM_MIPS
+#define ELF_CLASS ELFCLASS32
+#ifdef __MIPSEB__
+#define ELF_DATA ELFDATA2MSB;
+#else /* __MIPSEL__ */
+#define ELF_DATA ELFDATA2LSB;
+#endif
+
+/* ELF register definitions */
+#define ELF_NGREG 45
+#define ELF_NFPREG 33
+
+typedef unsigned int elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(hdr) \
+({ \
+ int __res = 1; \
+ struct elfhdr *__h = (hdr); \
+ \
+ if (__h->e_machine != EM_MIPS) \
+ __res = 0; \
+ if (__h->e_ident[EI_CLASS] != ELFCLASS32) \
+ __res = 0; \
+ if ((__h->e_flags & EF_MIPS_ABI2) != 0) \
+ __res = 0; \
+ if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
+ ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
+ __res = 0; \
+ \
+ __res; \
+})
+
+#define TASK32_SIZE 0x7fff8000UL
+#undef ELF_ET_DYN_BASE
+#define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2)
+
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/elfcore.h>
+#include <linux/compat.h>
+
+#define elf_prstatus elf_prstatus32
+struct elf_prstatus32
+{
+ struct elf_siginfo pr_info; /* Info associated with signal */
+ short pr_cursig; /* Current signal */
+ unsigned int pr_sigpend; /* Set of pending signals */
+ unsigned int pr_sighold; /* Set of held signals */
+ pid_t pr_pid;
+ pid_t pr_ppid;
+ pid_t pr_pgrp;
+ pid_t pr_sid;
+ struct compat_timeval pr_utime; /* User time */
+ struct compat_timeval pr_stime; /* System time */
+ struct compat_timeval pr_cutime;/* Cumulative user time */
+ struct compat_timeval pr_cstime;/* Cumulative system time */
+ elf_gregset_t pr_reg; /* GP registers */
+ int pr_fpvalid; /* True if math co-processor being used. */
+};
+
+#define elf_prpsinfo elf_prpsinfo32
+struct elf_prpsinfo32
+{
+ char pr_state; /* numeric process state */
+ char pr_sname; /* char for pr_state */
+ char pr_zomb; /* zombie */
+ char pr_nice; /* nice val */
+ unsigned int pr_flag; /* flags */
+ __kernel_uid_t pr_uid;
+ __kernel_gid_t pr_gid;
+ pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
+ /* Lots missing */
+ char pr_fname[16]; /* filename of executable */
+ char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+#define elf_addr_t u32
+#define elf_caddr_t u32
+#define init_elf_binfmt init_elf32_binfmt
+
+#define jiffies_to_timeval jiffies_to_compat_timeval
+static __inline__ void
+jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
+{
+ /*
+ * Convert jiffies to nanoseconds and seperate with
+ * one divide.
+ */
+ u64 nsec = (u64)jiffies * TICK_NSEC;
+ value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_usec);
+ value->tv_usec /= NSEC_PER_USEC;
+}
+
+#undef ELF_CORE_COPY_REGS
+#define ELF_CORE_COPY_REGS(_dest,_regs) elf32_core_copy_regs(_dest,_regs);
+
+void elf32_core_copy_regs(elf_gregset_t _dest, struct pt_regs *_regs)
+{
+ int i;
+
+ memset(_dest, 0, sizeof(elf_gregset_t));
+
+ /* XXXKW the 6 is from EF_REG0 in gdb/gdb/mips-linux-tdep.c, include/asm-mips/reg.h */
+ for (i=6; i<38; i++)
+ _dest[i] = (elf_greg_t) _regs->regs[i-6];
+ _dest[i++] = (elf_greg_t) _regs->lo;
+ _dest[i++] = (elf_greg_t) _regs->hi;
+ _dest[i++] = (elf_greg_t) _regs->cp0_epc;
+ _dest[i++] = (elf_greg_t) _regs->cp0_badvaddr;
+ _dest[i++] = (elf_greg_t) _regs->cp0_status;
+ _dest[i++] = (elf_greg_t) _regs->cp0_cause;
+}
+
+MODULE_DESCRIPTION("Binary format loader for compatibility with o32 Linux/MIPS binaries");
+MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)");
+
+#undef MODULE_DESCRIPTION
+#undef MODULE_AUTHOR
+
+#include "../../../fs/binfmt_elf.c"
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
new file mode 100644
index 00000000000..01117e977a7
--- /dev/null
+++ b/arch/mips/kernel/branch.c
@@ -0,0 +1,199 @@
+/*
+ * 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) 1996, 97, 2000, 2001 by Ralf Baechle
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/branch.h>
+#include <asm/cpu.h>
+#include <asm/cpu-features.h>
+#include <asm/inst.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+/*
+ * Compute the return address and do emulate branch simulation, if required.
+ */
+int __compute_return_epc(struct pt_regs *regs)
+{
+ unsigned int *addr, bit, fcr31;
+ long epc;
+ union mips_instruction insn;
+
+ epc = regs->cp0_epc;
+ if (epc & 3)
+ goto unaligned;
+
+ /*
+ * Read the instruction
+ */
+ addr = (unsigned int *) epc;
+ if (__get_user(insn.word, addr)) {
+ force_sig(SIGSEGV, current);
+ return -EFAULT;
+ }
+
+ regs->regs[0] = 0;
+ switch (insn.i_format.opcode) {
+ /*
+ * jr and jalr are in r_format format.
+ */
+ case spec_op:
+ switch (insn.r_format.func) {
+ case jalr_op:
+ regs->regs[insn.r_format.rd] = epc + 8;
+ /* Fall through */
+ case jr_op:
+ regs->cp0_epc = regs->regs[insn.r_format.rs];
+ break;
+ }
+ break;
+
+ /*
+ * This group contains:
+ * bltz_op, bgez_op, bltzl_op, bgezl_op,
+ * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
+ */
+ case bcond_op:
+ switch (insn.i_format.rt) {
+ case bltz_op:
+ case bltzl_op:
+ if ((long)regs->regs[insn.i_format.rs] < 0)
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+
+ case bgez_op:
+ case bgezl_op:
+ if ((long)regs->regs[insn.i_format.rs] >= 0)
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+
+ case bltzal_op:
+ case bltzall_op:
+ regs->regs[31] = epc + 8;
+ if ((long)regs->regs[insn.i_format.rs] < 0)
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+
+ case bgezal_op:
+ case bgezall_op:
+ regs->regs[31] = epc + 8;
+ if ((long)regs->regs[insn.i_format.rs] >= 0)
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+ }
+ break;
+
+ /*
+ * These are unconditional and in j_format.
+ */
+ case jal_op:
+ regs->regs[31] = regs->cp0_epc + 8;
+ case j_op:
+ epc += 4;
+ epc >>= 28;
+ epc <<= 28;
+ epc |= (insn.j_format.target << 2);
+ regs->cp0_epc = epc;
+ break;
+
+ /*
+ * These are conditional and in i_format.
+ */
+ case beq_op:
+ case beql_op:
+ if (regs->regs[insn.i_format.rs] ==
+ regs->regs[insn.i_format.rt])
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+
+ case bne_op:
+ case bnel_op:
+ if (regs->regs[insn.i_format.rs] !=
+ regs->regs[insn.i_format.rt])
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+
+ case blez_op: /* not really i_format */
+ case blezl_op:
+ /* rt field assumed to be zero */
+ if ((long)regs->regs[insn.i_format.rs] <= 0)
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+
+ case bgtz_op:
+ case bgtzl_op:
+ /* rt field assumed to be zero */
+ if ((long)regs->regs[insn.i_format.rs] > 0)
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+
+ /*
+ * And now the FPA/cp1 branch instructions.
+ */
+ case cop1_op:
+ if (!cpu_has_fpu)
+ fcr31 = current->thread.fpu.soft.fcr31;
+ else
+ asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
+ bit = (insn.i_format.rt >> 2);
+ bit += (bit != 0);
+ bit += 23;
+ switch (insn.i_format.rt) {
+ case 0: /* bc1f */
+ case 2: /* bc1fl */
+ if (~fcr31 & (1 << bit))
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+
+ case 1: /* bc1t */
+ case 3: /* bc1tl */
+ if (fcr31 & (1 << bit))
+ epc = epc + 4 + (insn.i_format.simmediate << 2);
+ else
+ epc += 8;
+ regs->cp0_epc = epc;
+ break;
+ }
+ break;
+ }
+
+ return 0;
+
+unaligned:
+ printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
+ force_sig(SIGBUS, current);
+ return -EFAULT;
+}
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c
new file mode 100644
index 00000000000..11ebe5d4c44
--- /dev/null
+++ b/arch/mips/kernel/cpu-bugs64.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2003, 2004 Maciej W. Rozycki
+ *
+ * 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.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/stddef.h>
+
+#include <asm/bugs.h>
+#include <asm/compiler.h>
+#include <asm/cpu.h>
+#include <asm/fpu.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+static inline void align_mod(const int align, const int mod)
+{
+ asm volatile(
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".balign %0\n\t"
+ ".rept %1\n\t"
+ "nop\n\t"
+ ".endr\n\t"
+ ".set pop"
+ :
+ : "n" (align), "n" (mod));
+}
+
+static inline void mult_sh_align_mod(long *v1, long *v2, long *w,
+ const int align, const int mod)
+{
+ unsigned long flags;
+ int m1, m2;
+ long p, s, lv1, lv2, lw;
+
+ /*
+ * We want the multiply and the shift to be isolated from the
+ * rest of the code to disable gcc optimizations. Hence the
+ * asm statements that execute nothing, but make gcc not know
+ * what the values of m1, m2 and s are and what lv2 and p are
+ * used for.
+ */
+
+ local_irq_save(flags);
+ /*
+ * The following code leads to a wrong result of the first
+ * dsll32 when executed on R4000 rev. 2.2 or 3.0 (PRId
+ * 00000422 or 00000430, respectively).
+ *
+ * See "MIPS R4000PC/SC Errata, Processor Revision 2.2 and
+ * 3.0" by MIPS Technologies, Inc., errata #16 and #28 for
+ * details. I got no permission to duplicate them here,
+ * sigh... --macro
+ */
+ asm volatile(
+ ""
+ : "=r" (m1), "=r" (m2), "=r" (s)
+ : "0" (5), "1" (8), "2" (5));
+ align_mod(align, mod);
+ /*
+ * The trailing nop is needed to fullfill the two-instruction
+ * requirement between reading hi/lo and staring a mult/div.
+ * Leaving it out may cause gas insert a nop itself breaking
+ * the desired alignment of the next chunk.
+ */
+ asm volatile(
+ ".set push\n\t"
+ ".set noat\n\t"
+ ".set noreorder\n\t"
+ ".set nomacro\n\t"
+ "mult %2, %3\n\t"
+ "dsll32 %0, %4, %5\n\t"
+ "mflo $0\n\t"
+ "dsll32 %1, %4, %5\n\t"
+ "nop\n\t"
+ ".set pop"
+ : "=&r" (lv1), "=r" (lw)
+ : "r" (m1), "r" (m2), "r" (s), "I" (0)
+ : "hi", "lo", GCC_REG_ACCUM);
+ /* We have to use single integers for m1 and m2 and a double
+ * one for p to be sure the mulsidi3 gcc's RTL multiplication
+ * instruction has the workaround applied. Older versions of
+ * gcc have correct umulsi3 and mulsi3, but other
+ * multiplication variants lack the workaround.
+ */
+ asm volatile(
+ ""
+ : "=r" (m1), "=r" (m2), "=r" (s)
+ : "0" (m1), "1" (m2), "2" (s));
+ align_mod(align, mod);
+ p = m1 * m2;
+ lv2 = s << 32;
+ asm volatile(
+ ""
+ : "=r" (lv2)
+ : "0" (lv2), "r" (p));
+ local_irq_restore(flags);
+
+ *v1 = lv1;
+ *v2 = lv2;
+ *w = lw;
+}
+
+static inline void check_mult_sh(void)
+{
+ long v1[8], v2[8], w[8];
+ int bug, fix, i;
+
+ printk("Checking for the multiply/shift bug... ");
+
+ /*
+ * Testing discovered f