Linux-2.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!
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
new file mode 100644
index 0000000..a0230ee
--- /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 0000000..ed47041
--- /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 0000000..ee21b18
--- /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 0000000..01117e9
--- /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 0000000..11ebe5d
--- /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 false negatives for certain code offsets
+	 * into cache lines.  Hence we test all possible offsets for
+	 * the worst assumption of an R4000 I-cache line width of 32
+	 * bytes.
+	 *
+	 * We can't use a loop as alignment directives need to be
+	 * immediates.
+	 */
+	mult_sh_align_mod(&v1[0], &v2[0], &w[0], 32, 0);
+	mult_sh_align_mod(&v1[1], &v2[1], &w[1], 32, 1);
+	mult_sh_align_mod(&v1[2], &v2[2], &w[2], 32, 2);
+	mult_sh_align_mod(&v1[3], &v2[3], &w[3], 32, 3);
+	mult_sh_align_mod(&v1[4], &v2[4], &w[4], 32, 4);
+	mult_sh_align_mod(&v1[5], &v2[5], &w[5], 32, 5);
+	mult_sh_align_mod(&v1[6], &v2[6], &w[6], 32, 6);
+	mult_sh_align_mod(&v1[7], &v2[7], &w[7], 32, 7);
+
+	bug = 0;
+	for (i = 0; i < 8; i++)
+		if (v1[i] != w[i])
+			bug = 1;
+		
+	if (bug == 0) {
+		printk("no.\n");
+		return;
+	}
+
+	printk("yes, workaround... ");
+
+	fix = 1;
+	for (i = 0; i < 8; i++)
+		if (v2[i] != w[i])
+			fix = 0;
+		
+	if (fix == 1) {
+		printk("yes.\n");
+		return;
+	}
+
+	printk("no.\n");
+	panic("Reliable operation impossible!\n"
+#ifndef CONFIG_CPU_R4000
+	      "Configure for R4000 to enable the workaround."
+#else
+	      "Please report to <linux-mips@linux-mips.org>."
+#endif
+	      );
+}
+
+static volatile int daddi_ov __initdata = 0;
+
+asmlinkage void __init do_daddi_ov(struct pt_regs *regs)
+{
+	daddi_ov = 1;
+	regs->cp0_epc += 4;
+}
+
+static inline void check_daddi(void)
+{
+	extern asmlinkage void handle_daddi_ov(void);
+	unsigned long flags;
+	void *handler;
+	long v, tmp;
+
+	printk("Checking for the daddi bug... ");
+
+	local_irq_save(flags);
+	handler = set_except_vector(12, handle_daddi_ov);
+	/*
+	 * The following code fails to trigger an overflow exception
+	 * 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., erratum #23 for details.
+	 * I got no permission to duplicate it here, sigh... --macro
+	 */
+	asm volatile(
+		".set	push\n\t"
+		".set	noat\n\t"
+		".set	noreorder\n\t"
+		".set	nomacro\n\t"
+		"addiu	%1, $0, %2\n\t"
+		"dsrl	%1, %1, 1\n\t"
+#ifdef HAVE_AS_SET_DADDI
+		".set	daddi\n\t"
+#endif
+		"daddi	%0, %1, %3\n\t"
+		".set	pop"
+		: "=r" (v), "=&r" (tmp)
+		: "I" (0xffffffffffffdb9a), "I" (0x1234));
+	set_except_vector(12, handler);
+	local_irq_restore(flags);
+
+	if (daddi_ov) {
+		printk("no.\n");
+		return;
+	}
+
+	printk("yes, workaround... ");
+
+	local_irq_save(flags);
+	handler = set_except_vector(12, handle_daddi_ov);
+	asm volatile(
+		"addiu	%1, $0, %2\n\t"
+		"dsrl	%1, %1, 1\n\t"
+		"daddi	%0, %1, %3"
+		: "=r" (v), "=&r" (tmp)
+		: "I" (0xffffffffffffdb9a), "I" (0x1234));
+	set_except_vector(12, handler);
+	local_irq_restore(flags);
+
+	if (daddi_ov) {
+		printk("yes.\n");
+		return;
+	}
+
+	printk("no.\n");
+	panic("Reliable operation impossible!\n"
+#if !defined(CONFIG_CPU_R4000) && !defined(CONFIG_CPU_R4400)
+	      "Configure for R4000 or R4400 to enable the workaround."
+#else
+	      "Please report to <linux-mips@linux-mips.org>."
+#endif
+	      );
+}
+
+static inline void check_daddiu(void)
+{
+	long v, w, tmp;
+
+	printk("Checking for the daddiu bug... ");
+
+	/*
+	 * The following code leads to a wrong result of daddiu when
+	 * executed on R4400 rev. 1.0 (PRId 00000440).
+	 *
+	 * See "MIPS R4400PC/SC Errata, Processor Revision 1.0" by
+	 * MIPS Technologies, Inc., erratum #7 for details.
+	 *
+	 * According to "MIPS R4000PC/SC Errata, Processor Revision
+	 * 2.2 and 3.0" by MIPS Technologies, Inc., erratum #41 this
+	 * problem affects R4000 rev. 2.2 and 3.0 (PRId 00000422 and
+	 * 00000430, respectively), too.  Testing failed to trigger it
+	 * so far.
+	 *
+	 * I got no permission to duplicate the errata here, sigh...
+	 * --macro
+	 */
+	asm volatile(
+		".set	push\n\t"
+		".set	noat\n\t"
+		".set	noreorder\n\t"
+		".set	nomacro\n\t"
+		"addiu	%2, $0, %3\n\t"
+		"dsrl	%2, %2, 1\n\t"
+#ifdef HAVE_AS_SET_DADDI
+		".set	daddi\n\t"
+#endif
+		"daddiu	%0, %2, %4\n\t"
+		"addiu	%1, $0, %4\n\t"
+		"daddu	%1, %2\n\t"
+		".set	pop"
+		: "=&r" (v), "=&r" (w), "=&r" (tmp)
+		: "I" (0xffffffffffffdb9a), "I" (0x1234));
+
+	if (v == w) {
+		printk("no.\n");
+		return;
+	}
+
+	printk("yes, workaround... ");
+
+	asm volatile(
+		"addiu	%2, $0, %3\n\t"
+		"dsrl	%2, %2, 1\n\t"
+		"daddiu	%0, %2, %4\n\t"
+		"addiu	%1, $0, %4\n\t"
+		"daddu	%1, %2"
+		: "=&r" (v), "=&r" (w), "=&r" (tmp)
+		: "I" (0xffffffffffffdb9a), "I" (0x1234));
+
+	if (v == w) {
+		printk("yes.\n");
+		return;
+	}
+
+	printk("no.\n");
+	panic("Reliable operation impossible!\n"
+#if !defined(CONFIG_CPU_R4000) && !defined(CONFIG_CPU_R4400)
+	      "Configure for R4000 or R4400 to enable the workaround."
+#else
+	      "Please report to <linux-mips@linux-mips.org>."
+#endif
+	      );
+}
+
+void __init check_bugs64(void)
+{
+	check_mult_sh();
+	check_daddi();
+	check_daddiu();
+}
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
new file mode 100644
index 0000000..4bb8495
--- /dev/null
+++ b/arch/mips/kernel/cpu-probe.c
@@ -0,0 +1,598 @@
+/*
+ * Processor capabilities determination functions.
+ *
+ * Copyright (C) xxxx  the Anonymous
+ * Copyright (C) 2003  Maciej W. Rozycki
+ * Copyright (C) 1994 - 2003 Ralf Baechle
+ * Copyright (C) 2001 MIPS Inc.
+ *
+ * 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/cpu.h>
+#include <asm/fpu.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+/*
+ * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
+ * the implementation of the "wait" feature differs between CPU families. This
+ * points to the function that implements CPU specific wait.
+ * The wait instruction stops the pipeline and reduces the power consumption of
+ * the CPU very much.
+ */
+void (*cpu_wait)(void) = NULL;
+
+static void r3081_wait(void)
+{
+	unsigned long cfg = read_c0_conf();
+	write_c0_conf(cfg | R30XX_CONF_HALT);
+}
+
+static void r39xx_wait(void)
+{
+	unsigned long cfg = read_c0_conf();
+	write_c0_conf(cfg | TX39_CONF_HALT);
+}
+
+static void r4k_wait(void)
+{
+	__asm__(".set\tmips3\n\t"
+		"wait\n\t"
+		".set\tmips0");
+}
+
+/*
+ * The Au1xxx wait is available only if we run CONFIG_PM and
+ * the timer setup found we had a 32KHz counter available.
+ * There are still problems with functions that may call au1k_wait
+ * directly, but that will be discovered pretty quickly.
+ */
+extern void (*au1k_wait_ptr)(void);
+
+void au1k_wait(void)
+{
+#ifdef CONFIG_PM
+	/* using the wait instruction makes CP0 counter unusable */
+	__asm__(".set\tmips3\n\t"
+		"wait\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		".set\tmips0");
+#else
+	__asm__("nop\n\t"
+		"nop");
+#endif
+}
+
+static inline void check_wait(void)
+{
+	struct cpuinfo_mips *c = &current_cpu_data;
+
+	printk("Checking for 'wait' instruction... ");
+	switch (c->cputype) {
+	case CPU_R3081:
+	case CPU_R3081E:
+		cpu_wait = r3081_wait;
+		printk(" available.\n");
+		break;
+	case CPU_TX3927:
+		cpu_wait = r39xx_wait;
+		printk(" available.\n");
+		break;
+	case CPU_R4200:
+/*	case CPU_R4300: */
+	case CPU_R4600:
+	case CPU_R4640:
+	case CPU_R4650:
+	case CPU_R4700:
+	case CPU_R5000:
+	case CPU_NEVADA:
+	case CPU_RM7000:
+	case CPU_RM9000:
+	case CPU_TX49XX:
+	case CPU_4KC:
+	case CPU_4KEC:
+	case CPU_4KSC:
+	case CPU_5KC:
+/*	case CPU_20KC:*/
+	case CPU_24K:
+	case CPU_25KF:
+		cpu_wait = r4k_wait;
+		printk(" available.\n");
+		break;
+#ifdef CONFIG_PM
+	case CPU_AU1000:
+	case CPU_AU1100:
+	case CPU_AU1500:
+		if (au1k_wait_ptr != NULL) {
+			cpu_wait = au1k_wait_ptr;
+			printk(" available.\n");
+		}
+		else {
+			printk(" unavailable.\n");
+		}
+		break;
+#endif
+	default:
+		printk(" unavailable.\n");
+		break;
+	}
+}
+
+void __init check_bugs32(void)
+{
+	check_wait();
+}
+
+/*
+ * Probe whether cpu has config register by trying to play with
+ * alternate cache bit and see whether it matters.
+ * It's used by cpu_probe to distinguish between R3000A and R3081.
+ */
+static inline int cpu_has_confreg(void)
+{
+#ifdef CONFIG_CPU_R3000
+	extern unsigned long r3k_cache_size(unsigned long);
+	unsigned long size1, size2;
+	unsigned long cfg = read_c0_conf();
+
+	size1 = r3k_cache_size(ST0_ISC);
+	write_c0_conf(cfg ^ R30XX_CONF_AC);
+	size2 = r3k_cache_size(ST0_ISC);
+	write_c0_conf(cfg);
+	return size1 != size2;
+#else
+	return 0;
+#endif
+}
+
+/*
+ * Get the FPU Implementation/Revision.
+ */
+static inline unsigned long cpu_get_fpu_id(void)
+{
+	unsigned long tmp, fpu_id;
+
+	tmp = read_c0_status();
+	__enable_fpu();
+	fpu_id = read_32bit_cp1_register(CP1_REVISION);
+	write_c0_status(tmp);
+	return fpu_id;
+}
+
+/*
+ * Check the CPU has an FPU the official way.
+ */
+static inline int __cpu_has_fpu(void)
+{
+	return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE);
+}
+
+#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \
+		| MIPS_CPU_COUNTER)
+
+static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
+{
+	switch (c->processor_id & 0xff00) {
+	case PRID_IMP_R2000:
+		c->cputype = CPU_R2000;
+		c->isa_level = MIPS_CPU_ISA_I;
+		c->options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
+		if (__cpu_has_fpu())
+			c->options |= MIPS_CPU_FPU;
+		c->tlbsize = 64;
+		break;
+	case PRID_IMP_R3000:
+		if ((c->processor_id & 0xff) == PRID_REV_R3000A)
+			if (cpu_has_confreg())
+				c->cputype = CPU_R3081E;
+			else
+				c->cputype = CPU_R3000A;
+		else
+			c->cputype = CPU_R3000;
+		c->isa_level = MIPS_CPU_ISA_I;
+		c->options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
+		if (__cpu_has_fpu())
+			c->options |= MIPS_CPU_FPU;
+		c->tlbsize = 64;
+		break;
+	case PRID_IMP_R4000:
+		if (read_c0_config() & CONF_SC) {
+			if ((c->processor_id & 0xff) >= PRID_REV_R4400)
+				c->cputype = CPU_R4400PC;
+			else
+				c->cputype = CPU_R4000PC;
+		} else {
+			if ((c->processor_id & 0xff) >= PRID_REV_R4400)
+				c->cputype = CPU_R4400SC;
+			else
+				c->cputype = CPU_R4000SC;
+		}
+
+		c->isa_level = MIPS_CPU_ISA_III;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_WATCH | MIPS_CPU_VCE |
+		             MIPS_CPU_LLSC;
+		c->tlbsize = 48;
+		break;
+	case PRID_IMP_VR41XX:
+		switch (c->processor_id & 0xf0) {
+#ifndef CONFIG_VR4181
+		case PRID_REV_VR4111:
+			c->cputype = CPU_VR4111;
+			break;
+#else
+		case PRID_REV_VR4181:
+			c->cputype = CPU_VR4181;
+			break;
+#endif
+		case PRID_REV_VR4121:
+			c->cputype = CPU_VR4121;
+			break;
+		case PRID_REV_VR4122:
+			if ((c->processor_id & 0xf) < 0x3)
+				c->cputype = CPU_VR4122;
+			else
+				c->cputype = CPU_VR4181A;
+			break;
+		case PRID_REV_VR4130:
+			if ((c->processor_id & 0xf) < 0x4)
+				c->cputype = CPU_VR4131;
+			else
+				c->cputype = CPU_VR4133;
+			break;
+		default:
+			printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
+			c->cputype = CPU_VR41XX;
+			break;
+		}
+		c->isa_level = MIPS_CPU_ISA_III;
+		c->options = R4K_OPTS;
+		c->tlbsize = 32;
+		break;
+	case PRID_IMP_R4300:
+		c->cputype = CPU_R4300;
+		c->isa_level = MIPS_CPU_ISA_III;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_LLSC;
+		c->tlbsize = 32;
+		break;
+	case PRID_IMP_R4600:
+		c->cputype = CPU_R4600;
+		c->isa_level = MIPS_CPU_ISA_III;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
+		c->tlbsize = 48;
+		break;
+	#if 0
+ 	case PRID_IMP_R4650:
+		/*
+		 * This processor doesn't have an MMU, so it's not
+		 * "real easy" to run Linux on it. It is left purely
+		 * for documentation.  Commented out because it shares
+		 * it's c0_prid id number with the TX3900.
+		 */
+ 		c->cputype = CPU_R4650;
+	 	c->isa_level = MIPS_CPU_ISA_III;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
+	        c->tlbsize = 48;
+		break;
+	#endif
+	case PRID_IMP_TX39:
+		c->isa_level = MIPS_CPU_ISA_I;
+		c->options = MIPS_CPU_TLB;
+
+		if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
+			c->cputype = CPU_TX3927;
+			c->tlbsize = 64;
+		} else {
+			switch (c->processor_id & 0xff) {
+			case PRID_REV_TX3912:
+				c->cputype = CPU_TX3912;
+				c->tlbsize = 32;
+				break;
+			case PRID_REV_TX3922:
+				c->cputype = CPU_TX3922;
+				c->tlbsize = 64;
+				break;
+			default:
+				c->cputype = CPU_UNKNOWN;
+				break;
+			}
+		}
+		break;
+	case PRID_IMP_R4700:
+		c->cputype = CPU_R4700;
+		c->isa_level = MIPS_CPU_ISA_III;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_LLSC;
+		c->tlbsize = 48;
+		break;
+	case PRID_IMP_TX49:
+		c->cputype = CPU_TX49XX;
+		c->isa_level = MIPS_CPU_ISA_III;
+		c->options = R4K_OPTS | MIPS_CPU_LLSC;
+		if (!(c->processor_id & 0x08))
+			c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR;
+		c->tlbsize = 48;
+		break;
+	case PRID_IMP_R5000:
+		c->cputype = CPU_R5000;
+		c->isa_level = MIPS_CPU_ISA_IV;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_LLSC;
+		c->tlbsize = 48;
+		break;
+	case PRID_IMP_R5432:
+		c->cputype = CPU_R5432;
+		c->isa_level = MIPS_CPU_ISA_IV;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_WATCH | MIPS_CPU_LLSC;
+		c->tlbsize = 48;
+		break;
+	case PRID_IMP_R5500:
+		c->cputype = CPU_R5500;
+		c->isa_level = MIPS_CPU_ISA_IV;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_WATCH | MIPS_CPU_LLSC;
+		c->tlbsize = 48;
+		break;
+	case PRID_IMP_NEVADA:
+		c->cputype = CPU_NEVADA;
+		c->isa_level = MIPS_CPU_ISA_IV;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_DIVEC | MIPS_CPU_LLSC;
+		c->tlbsize = 48;
+		break;
+	case PRID_IMP_R6000:
+		c->cputype = CPU_R6000;
+		c->isa_level = MIPS_CPU_ISA_II;
+		c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
+		             MIPS_CPU_LLSC;
+		c->tlbsize = 32;
+		break;
+	case PRID_IMP_R6000A:
+		c->cputype = CPU_R6000A;
+		c->isa_level = MIPS_CPU_ISA_II;
+		c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
+		             MIPS_CPU_LLSC;
+		c->tlbsize = 32;
+		break;
+	case PRID_IMP_RM7000:
+		c->cputype = CPU_RM7000;
+		c->isa_level = MIPS_CPU_ISA_IV;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_LLSC;
+		/*
+		 * Undocumented RM7000:  Bit 29 in the info register of
+		 * the RM7000 v2.0 indicates if the TLB has 48 or 64
+		 * entries.
+		 *
+		 * 29      1 =>    64 entry JTLB
+		 *         0 =>    48 entry JTLB
+		 */
+		c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48;
+		break;
+	case PRID_IMP_RM9000:
+		c->cputype = CPU_RM9000;
+		c->isa_level = MIPS_CPU_ISA_IV;
+		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_LLSC;
+		/*
+		 * Bit 29 in the info register of the RM9000
+		 * indicates if the TLB has 48 or 64 entries.
+		 *
+		 * 29      1 =>    64 entry JTLB
+		 *         0 =>    48 entry JTLB
+		 */
+		c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48;
+		break;
+	case PRID_IMP_R8000:
+		c->cputype = CPU_R8000;
+		c->isa_level = MIPS_CPU_ISA_IV;
+		c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+		             MIPS_CPU_FPU | MIPS_CPU_32FPR |
+		             MIPS_CPU_LLSC;
+		c->tlbsize = 384;      /* has weird TLB: 3-way x 128 */
+		break;
+	case PRID_IMP_R10000:
+		c->cputype = CPU_R10000;
+		c->isa_level = MIPS_CPU_ISA_IV;
+		c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+		             MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			     MIPS_CPU_COUNTER | MIPS_CPU_WATCH |
+		             MIPS_CPU_LLSC;
+		c->tlbsize = 64;
+		break;
+	case PRID_IMP_R12000:
+		c->cputype = CPU_R12000;
+		c->isa_level = MIPS_CPU_ISA_IV;
+		c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+		             MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			     MIPS_CPU_COUNTER | MIPS_CPU_WATCH |
+		             MIPS_CPU_LLSC;
+		c->tlbsize = 64;
+		break;
+	}
+}
+
+static inline void decode_config1(struct cpuinfo_mips *c)
+{
+	unsigned long config0 = read_c0_config();
+	unsigned long config1;
+
+	if ((config0 & (1 << 31)) == 0)
+		return;			/* actually wort a panic() */
+
+	/* MIPS32 or MIPS64 compliant CPU. Read Config 1 register. */
+	c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+		MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
+		MIPS_CPU_LLSC | MIPS_CPU_MCHECK;
+	config1 = read_c0_config1();
+	if (config1 & (1 << 3))
+		c->options |= MIPS_CPU_WATCH;
+	if (config1 & (1 << 2))
+		c->options |= MIPS_CPU_MIPS16;
+	if (config1 & (1 << 1))
+		c->options |= MIPS_CPU_EJTAG;
+	if (config1 & 1) {
+		c->options |= MIPS_CPU_FPU;
+		c->options |= MIPS_CPU_32FPR;
+	}
+	c->scache.flags = MIPS_CACHE_NOT_PRESENT;
+
+	c->tlbsize = ((config1 >> 25) & 0x3f) + 1;
+}
+
+static inline void cpu_probe_mips(struct cpuinfo_mips *c)
+{
+	decode_config1(c);
+	switch (c->processor_id & 0xff00) {
+	case PRID_IMP_4KC:
+		c->cputype = CPU_4KC;
+		c->isa_level = MIPS_CPU_ISA_M32;
+		break;
+	case PRID_IMP_4KEC:
+		c->cputype = CPU_4KEC;
+		c->isa_level = MIPS_CPU_ISA_M32;
+		break;
+	case PRID_IMP_4KSC:
+		c->cputype = CPU_4KSC;
+		c->isa_level = MIPS_CPU_ISA_M32;
+		break;
+	case PRID_IMP_5KC:
+		c->cputype = CPU_5KC;
+		c->isa_level = MIPS_CPU_ISA_M64;
+		break;
+	case PRID_IMP_20KC:
+		c->cputype = CPU_20KC;
+		c->isa_level = MIPS_CPU_ISA_M64;
+		break;
+	case PRID_IMP_24K:
+		c->cputype = CPU_24K;
+		c->isa_level = MIPS_CPU_ISA_M32;
+		break;
+	case PRID_IMP_25KF:
+		c->cputype = CPU_25KF;
+		c->isa_level = MIPS_CPU_ISA_M64;
+		/* Probe for L2 cache */
+		c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+		break;
+	}
+}
+
+static inline void cpu_probe_alchemy(struct cpuinfo_mips *c)
+{
+	decode_config1(c);
+	switch (c->processor_id & 0xff00) {
+	case PRID_IMP_AU1_REV1:
+	case PRID_IMP_AU1_REV2:
+		switch ((c->processor_id >> 24) & 0xff) {
+		case 0:
+ 			c->cputype = CPU_AU1000;
+			break;
+		case 1:
+			c->cputype = CPU_AU1500;
+			break;
+		case 2:
+			c->cputype = CPU_AU1100;
+			break;
+		case 3:
+			c->cputype = CPU_AU1550;
+			break;
+		default:
+			panic("Unknown Au Core!");
+			break;
+		}
+		c->isa_level = MIPS_CPU_ISA_M32;
+		break;
+	}
+}
+
+static inline void cpu_probe_sibyte(struct cpuinfo_mips *c)
+{
+	decode_config1(c);
+	switch (c->processor_id & 0xff00) {
+	case PRID_IMP_SB1:
+		c->cputype = CPU_SB1;
+		c->isa_level = MIPS_CPU_ISA_M64;
+		c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+		             MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
+		             MIPS_CPU_MCHECK | MIPS_CPU_EJTAG |
+		             MIPS_CPU_WATCH | MIPS_CPU_LLSC;
+#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS
+		/* FPU in pass1 is known to have issues. */
+		c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR;
+#endif
+		break;
+	}
+}
+
+static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c)
+{
+	decode_config1(c);
+	switch (c->processor_id & 0xff00) {
+	case PRID_IMP_SR71000:
+		c->cputype = CPU_SR71000;
+		c->isa_level = MIPS_CPU_ISA_M64;
+		c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+		             MIPS_CPU_4KTLB | MIPS_CPU_FPU |
+		             MIPS_CPU_COUNTER | MIPS_CPU_MCHECK;
+		c->scache.ways = 8;
+		c->tlbsize = 64;
+		break;
+	}
+}
+
+__init void cpu_probe(void)
+{
+	struct cpuinfo_mips *c = &current_cpu_data;
+
+	c->processor_id	= PRID_IMP_UNKNOWN;
+	c->fpu_id	= FPIR_IMP_NONE;
+	c->cputype	= CPU_UNKNOWN;
+
+	c->processor_id = read_c0_prid();
+	switch (c->processor_id & 0xff0000) {
+	case PRID_COMP_LEGACY:
+		cpu_probe_legacy(c);
+		break;
+	case PRID_COMP_MIPS:
+		cpu_probe_mips(c);
+		break;
+	case PRID_COMP_ALCHEMY:
+		cpu_probe_alchemy(c);
+		break;
+	case PRID_COMP_SIBYTE:
+		cpu_probe_sibyte(c);
+		break;
+
+	case PRID_COMP_SANDCRAFT:
+		cpu_probe_sandcraft(c);
+		break;
+	default:
+		c->cputype = CPU_UNKNOWN;
+	}
+	if (c->options & MIPS_CPU_FPU)
+		c->fpu_id = cpu_get_fpu_id();
+}
+
+__init void cpu_report(void)
+{
+	struct cpuinfo_mips *c = &current_cpu_data;
+
+	printk("CPU revision is: %08x\n", c->processor_id);
+	if (c->options & MIPS_CPU_FPU)
+		printk("FPU revision is: %08x\n", c->fpu_id);
+}
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
new file mode 100644
index 0000000..5eb4291
--- /dev/null
+++ b/arch/mips/kernel/entry.S
@@ -0,0 +1,155 @@
+/*
+ * 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) 1994 - 2000, 2001, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ */
+#include <linux/config.h>
+
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/isadep.h>
+#include <asm/thread_info.h>
+#include <asm/war.h>
+
+#ifdef CONFIG_PREEMPT
+	.macro	preempt_stop reg=t0
+	.endm
+#else
+	.macro	preempt_stop reg=t0
+	local_irq_disable \reg
+	.endm
+#define resume_kernel	restore_all
+#endif
+
+	.text
+	.align	5
+FEXPORT(ret_from_exception)
+	preempt_stop
+FEXPORT(ret_from_irq)
+	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
+	andi	t0, t0, KU_USER
+	beqz	t0, resume_kernel
+
+FEXPORT(resume_userspace)
+	local_irq_disable	t0	# make sure we dont miss an
+					# interrupt setting need_resched
+					# between sampling and return
+	LONG_L	a2, TI_FLAGS($28)	# current->work
+	andi	a2, _TIF_WORK_MASK	# (ignoring syscall_trace)
+	bnez	a2, work_pending
+	j	restore_all
+
+#ifdef CONFIG_PREEMPT
+ENTRY(resume_kernel)
+	lw	t0, TI_PRE_COUNT($28)
+	bnez	t0, restore_all
+need_resched:
+	LONG_L	t0, TI_FLAGS($28)
+	andi	t1, t0, _TIF_NEED_RESCHED
+	beqz	t1, restore_all
+	LONG_L	t0, PT_STATUS(sp)		# Interrupts off?
+	andi	t0, 1
+	beqz	t0, restore_all
+	li	t0, PREEMPT_ACTIVE
+	sw	t0, TI_PRE_COUNT($28)
+	local_irq_enable t0
+	jal	schedule
+	sw	zero, TI_PRE_COUNT($28)
+	local_irq_disable t0
+	b	need_resched
+#endif
+
+FEXPORT(ret_from_fork)
+	jal	schedule_tail		# a0 = task_t *prev
+
+FEXPORT(syscall_exit)
+	local_irq_disable		# make sure need_resched and
+					# signals dont change between
+					# sampling and return
+	LONG_L	a2, TI_FLAGS($28)	# current->work
+	li	t0, _TIF_ALLWORK_MASK
+	and	t0, a2, t0
+	bnez	t0, syscall_exit_work
+
+FEXPORT(restore_all)			# restore full frame
+	.set	noat
+	RESTORE_TEMP
+	RESTORE_AT
+	RESTORE_STATIC
+FEXPORT(restore_partial)		# restore partial frame
+	RESTORE_SOME
+	RESTORE_SP_AND_RET
+	.set	at
+
+FEXPORT(work_pending)
+	andi	t0, a2, _TIF_NEED_RESCHED
+	beqz	t0, work_notifysig
+work_resched:
+	jal	schedule
+
+	local_irq_disable t0		# make sure need_resched and
+					# signals dont change between
+					# sampling and return
+	LONG_L	a2, TI_FLAGS($28)
+	andi	t0, a2, _TIF_WORK_MASK	# is there any work to be done
+					# other than syscall tracing?
+	beqz	t0, restore_all
+	andi	t0, a2, _TIF_NEED_RESCHED
+	bnez	t0, work_resched
+
+work_notifysig:				# deal with pending signals and
+					# notify-resume requests
+	move	a0, sp
+	li	a1, 0
+	jal	do_notify_resume	# a2 already loaded
+	j	restore_all
+
+FEXPORT(syscall_exit_work_partial)
+	SAVE_STATIC
+FEXPORT(syscall_exit_work)
+	LONG_L	t0, TI_FLAGS($28)
+	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	and	t0, t1
+	beqz	t0, work_pending	# trace bit is set
+	local_irq_enable		# could let do_syscall_trace()
+					# call schedule() instead
+	move	a0, sp
+	li	a1, 1
+	jal	do_syscall_trace
+	b	resume_userspace
+
+/*
+ * Common spurious interrupt handler.
+ */
+	.text
+	.align  5
+LEAF(spurious_interrupt)
+	/*
+	 * Someone tried to fool us by sending an interrupt but we
+	 * couldn't find a cause for it.
+	 */
+#ifdef CONFIG_SMP
+	lui     t1, %hi(irq_err_count)
+1:	ll      t0, %lo(irq_err_count)(t1)
+	addiu   t0, 1
+	sc      t0, %lo(irq_err_count)(t1)
+#if R10000_LLSC_WAR
+	beqzl	t0, 1b
+#else
+	beqz	t0, 1b
+#endif
+#else
+	lui     t1, %hi(irq_err_count)
+	lw      t0, %lo(irq_err_count)(t1)
+	addiu   t0, 1
+	sw      t0, %lo(irq_err_count)(t1)
+#endif
+	j	ret_from_irq
+	END(spurious_interrupt)
diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S
new file mode 100644
index 0000000..ece6dda
--- /dev/null
+++ b/arch/mips/kernel/gdb-low.S
@@ -0,0 +1,370 @@
+/*
+ * gdb-low.S contains the low-level trap handler for the GDB stub.
+ *
+ * Copyright (C) 1995 Andreas Busse
+ */
+#include <linux/config.h>
+#include <linux/sys.h>
+
+#include <asm/asm.h>
+#include <asm/errno.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/gdb-stub.h>
+
+#ifdef CONFIG_MIPS32
+#define DMFC0	mfc0
+#define DMTC0	mtc0
+#define LDC1	lwc1
+#define SDC1	lwc1
+#endif
+#ifdef CONFIG_MIPS64
+#define DMFC0	dmfc0
+#define DMTC0	dmtc0
+#define LDC1	ldc1
+#define SDC1	ldc1
+#endif
+
+/*
+ * [jsun] We reserves about 2x GDB_FR_SIZE in stack.  The lower (addressed)
+ * part is used to store registers and passed to exception handler.
+ * The upper part is reserved for "call func" feature where gdb client
+ * saves some of the regs, setups call frame and passes args.
+ *
+ * A trace shows about 200 bytes are used to store about half of all regs.
+ * The rest should be big enough for frame setup and passing args.
+ */
+
+/*
+ * The low level trap handler
+ */
+		.align 	5
+		NESTED(trap_low, GDB_FR_SIZE, sp)
+ 		.set	noat
+		.set 	noreorder
+
+		mfc0	k0, CP0_STATUS
+		sll	k0, 3     		/* extract cu0 bit */
+		bltz	k0, 1f
+		move	k1, sp
+
+		/*
+		 * Called from user mode, go somewhere else.
+		 */
+		lui	k1, %hi(saved_vectors)
+		mfc0	k0, CP0_CAUSE
+		andi	k0, k0, 0x7c
+		add	k1, k1, k0
+		lw	k0, %lo(saved_vectors)(k1)
+		jr	k0
+		nop
+1:
+		move	k0, sp
+		subu	sp, k1, GDB_FR_SIZE*2	# see comment above
+		LONG_S	k0, GDB_FR_REG29(sp)
+		LONG_S	$2, GDB_FR_REG2(sp)
+
+/*
+ * First save the CP0 and special registers
+ */
+
+		mfc0	v0, CP0_STATUS
+		LONG_S	v0, GDB_FR_STATUS(sp)
+		mfc0	v0, CP0_CAUSE
+		LONG_S	v0, GDB_FR_CAUSE(sp)
+		DMFC0	v0, CP0_EPC
+		LONG_S	v0, GDB_FR_EPC(sp)
+		DMFC0	v0, CP0_BADVADDR
+		LONG_S	v0, GDB_FR_BADVADDR(sp)
+		mfhi	v0
+		LONG_S	v0, GDB_FR_HI(sp)
+		mflo	v0
+		LONG_S	v0, GDB_FR_LO(sp)
+
+/*
+ * Now the integer registers
+ */
+
+		LONG_S	zero, GDB_FR_REG0(sp)		/* I know... */
+		LONG_S	$1, GDB_FR_REG1(sp)
+		/* v0 already saved */
+		LONG_S	$3, GDB_FR_REG3(sp)
+		LONG_S	$4, GDB_FR_REG4(sp)
+		LONG_S	$5, GDB_FR_REG5(sp)
+		LONG_S	$6, GDB_FR_REG6(sp)
+		LONG_S	$7, GDB_FR_REG7(sp)
+		LONG_S	$8, GDB_FR_REG8(sp)
+		LONG_S	$9, GDB_FR_REG9(sp)
+		LONG_S	$10, GDB_FR_REG10(sp)
+		LONG_S	$11, GDB_FR_REG11(sp)
+		LONG_S	$12, GDB_FR_REG12(sp)
+		LONG_S	$13, GDB_FR_REG13(sp)
+		LONG_S	$14, GDB_FR_REG14(sp)
+		LONG_S	$15, GDB_FR_REG15(sp)
+		LONG_S	$16, GDB_FR_REG16(sp)
+		LONG_S	$17, GDB_FR_REG17(sp)
+		LONG_S	$18, GDB_FR_REG18(sp)
+		LONG_S	$19, GDB_FR_REG19(sp)
+		LONG_S	$20, GDB_FR_REG20(sp)
+		LONG_S	$21, GDB_FR_REG21(sp)
+		LONG_S	$22, GDB_FR_REG22(sp)
+		LONG_S	$23, GDB_FR_REG23(sp)
+		LONG_S	$24, GDB_FR_REG24(sp)
+		LONG_S	$25, GDB_FR_REG25(sp)
+		LONG_S	$26, GDB_FR_REG26(sp)
+		LONG_S	$27, GDB_FR_REG27(sp)
+		LONG_S	$28, GDB_FR_REG28(sp)
+		/* sp already saved */
+		LONG_S	$30, GDB_FR_REG30(sp)
+		LONG_S	$31, GDB_FR_REG31(sp)
+
+		CLI				/* disable interrupts */
+
+/*
+ * Followed by the floating point registers
+ */
+		mfc0	v0, CP0_STATUS		/* FPU enabled? */
+		srl	v0, v0, 16
+		andi	v0, v0, (ST0_CU1 >> 16)
+
+		beqz	v0,2f			/* disabled, skip */
+		 nop
+
+		SDC1	$0, GDB_FR_FPR0(sp)
+		SDC1	$1, GDB_FR_FPR1(sp)
+		SDC1	$2, GDB_FR_FPR2(sp)
+		SDC1	$3, GDB_FR_FPR3(sp)
+		SDC1	$4, GDB_FR_FPR4(sp)
+		SDC1	$5, GDB_FR_FPR5(sp)
+		SDC1	$6, GDB_FR_FPR6(sp)
+		SDC1	$7, GDB_FR_FPR7(sp)
+		SDC1	$8, GDB_FR_FPR8(sp)
+		SDC1	$9, GDB_FR_FPR9(sp)
+		SDC1	$10, GDB_FR_FPR10(sp)
+		SDC1	$11, GDB_FR_FPR11(sp)
+		SDC1	$12, GDB_FR_FPR12(sp)
+		SDC1	$13, GDB_FR_FPR13(sp)
+		SDC1	$14, GDB_FR_FPR14(sp)
+		SDC1	$15, GDB_FR_FPR15(sp)
+		SDC1	$16, GDB_FR_FPR16(sp)
+		SDC1	$17, GDB_FR_FPR17(sp)
+		SDC1	$18, GDB_FR_FPR18(sp)
+		SDC1	$19, GDB_FR_FPR19(sp)
+		SDC1	$20, GDB_FR_FPR20(sp)
+		SDC1	$21, GDB_FR_FPR21(sp)
+		SDC1	$22, GDB_FR_FPR22(sp)
+		SDC1	$23, GDB_FR_FPR23(sp)
+		SDC1	$24, GDB_FR_FPR24(sp)
+		SDC1	$25, GDB_FR_FPR25(sp)
+		SDC1	$26, GDB_FR_FPR26(sp)
+		SDC1	$27, GDB_FR_FPR27(sp)
+		SDC1	$28, GDB_FR_FPR28(sp)
+		SDC1	$29, GDB_FR_FPR29(sp)
+		SDC1	$30, GDB_FR_FPR30(sp)
+		SDC1	$31, GDB_FR_FPR31(sp)
+
+/*
+ * FPU control registers
+ */
+
+		cfc1	v0, CP1_STATUS
+		LONG_S	v0, GDB_FR_FSR(sp)
+		cfc1	v0, CP1_REVISION
+		LONG_S	v0, GDB_FR_FIR(sp)
+
+/*
+ * Current stack frame ptr
+ */
+
+2:
+		LONG_S	sp, GDB_FR_FRP(sp)
+
+/*
+ * CP0 registers (R4000/R4400 unused registers skipped)
+ */
+
+		mfc0	v0, CP0_INDEX
+		LONG_S	v0, GDB_FR_CP0_INDEX(sp)
+		mfc0	v0, CP0_RANDOM
+		LONG_S	v0, GDB_FR_CP0_RANDOM(sp)
+		DMFC0	v0, CP0_ENTRYLO0
+		LONG_S	v0, GDB_FR_CP0_ENTRYLO0(sp)
+		DMFC0	v0, CP0_ENTRYLO1
+		LONG_S	v0, GDB_FR_CP0_ENTRYLO1(sp)
+		DMFC0	v0, CP0_CONTEXT
+		LONG_S	v0, GDB_FR_CP0_CONTEXT(sp)
+		mfc0	v0, CP0_PAGEMASK
+		LONG_S	v0, GDB_FR_CP0_PAGEMASK(sp)
+		mfc0	v0, CP0_WIRED
+		LONG_S	v0, GDB_FR_CP0_WIRED(sp)
+		DMFC0	v0, CP0_ENTRYHI
+		LONG_S	v0, GDB_FR_CP0_ENTRYHI(sp)
+		mfc0	v0, CP0_PRID
+		LONG_S	v0, GDB_FR_CP0_PRID(sp)
+
+		.set	at
+
+/*
+ * Continue with the higher level handler
+ */
+
+		move	a0,sp
+
+		jal	handle_exception
+		 nop
+
+/*
+ * Restore all writable registers, in reverse order
+ */
+
+		.set	noat
+
+		LONG_L	v0, GDB_FR_CP0_ENTRYHI(sp)
+		LONG_L	v1, GDB_FR_CP0_WIRED(sp)
+		DMTC0	v0, CP0_ENTRYHI
+		mtc0	v1, CP0_WIRED
+		LONG_L	v0, GDB_FR_CP0_PAGEMASK(sp)
+		LONG_L	v1, GDB_FR_CP0_ENTRYLO1(sp)
+		mtc0	v0, CP0_PAGEMASK
+		DMTC0	v1, CP0_ENTRYLO1
+		LONG_L	v0, GDB_FR_CP0_ENTRYLO0(sp)
+		LONG_L	v1, GDB_FR_CP0_INDEX(sp)
+		DMTC0	v0, CP0_ENTRYLO0
+		LONG_L	v0, GDB_FR_CP0_CONTEXT(sp)
+		mtc0	v1, CP0_INDEX
+		DMTC0	v0, CP0_CONTEXT
+
+
+/*
+ * Next, the floating point registers
+ */
+		mfc0	v0, CP0_STATUS		/* check if the FPU is enabled */
+		srl	v0, v0, 16
+		andi	v0, v0, (ST0_CU1 >> 16)
+
+		beqz	v0, 3f			/* disabled, skip */
+		 nop
+
+		LDC1	$31, GDB_FR_FPR31(sp)
+		LDC1	$30, GDB_FR_FPR30(sp)
+		LDC1	$29, GDB_FR_FPR29(sp)
+		LDC1	$28, GDB_FR_FPR28(sp)
+		LDC1	$27, GDB_FR_FPR27(sp)
+		LDC1	$26, GDB_FR_FPR26(sp)
+		LDC1	$25, GDB_FR_FPR25(sp)
+		LDC1	$24, GDB_FR_FPR24(sp)
+		LDC1	$23, GDB_FR_FPR23(sp)
+		LDC1	$22, GDB_FR_FPR22(sp)
+		LDC1	$21, GDB_FR_FPR21(sp)
+		LDC1	$20, GDB_FR_FPR20(sp)
+		LDC1	$19, GDB_FR_FPR19(sp)
+		LDC1	$18, GDB_FR_FPR18(sp)
+		LDC1	$17, GDB_FR_FPR17(sp)
+		LDC1	$16, GDB_FR_FPR16(sp)
+		LDC1	$15, GDB_FR_FPR15(sp)
+		LDC1	$14, GDB_FR_FPR14(sp)
+		LDC1	$13, GDB_FR_FPR13(sp)
+		LDC1	$12, GDB_FR_FPR12(sp)
+		LDC1	$11, GDB_FR_FPR11(sp)
+		LDC1	$10, GDB_FR_FPR10(sp)
+		LDC1	$9, GDB_FR_FPR9(sp)
+		LDC1	$8, GDB_FR_FPR8(sp)
+		LDC1	$7, GDB_FR_FPR7(sp)
+		LDC1	$6, GDB_FR_FPR6(sp)
+		LDC1	$5, GDB_FR_FPR5(sp)
+		LDC1	$4, GDB_FR_FPR4(sp)
+		LDC1	$3, GDB_FR_FPR3(sp)
+		LDC1	$2, GDB_FR_FPR2(sp)
+		LDC1	$1, GDB_FR_FPR1(sp)
+		LDC1	$0, GDB_FR_FPR0(sp)
+
+/*
+ * Now the CP0 and integer registers
+ */
+
+3:
+		mfc0	t0, CP0_STATUS
+		ori	t0, 0x1f
+		xori	t0, 0x1f
+		mtc0	t0, CP0_STATUS
+
+		LONG_L	v0, GDB_FR_STATUS(sp)
+		LONG_L	v1, GDB_FR_EPC(sp)
+		mtc0	v0, CP0_STATUS
+		DMTC0	v1, CP0_EPC
+		LONG_L	v0, GDB_FR_HI(sp)
+		LONG_L	v1, GDB_FR_LO(sp)
+		mthi	v0
+		mtlo	v1
+		LONG_L	$31, GDB_FR_REG31(sp)
+		LONG_L	$30, GDB_FR_REG30(sp)
+		LONG_L	$28, GDB_FR_REG28(sp)
+		LONG_L	$27, GDB_FR_REG27(sp)
+		LONG_L	$26, GDB_FR_REG26(sp)
+		LONG_L	$25, GDB_FR_REG25(sp)
+		LONG_L	$24, GDB_FR_REG24(sp)
+		LONG_L	$23, GDB_FR_REG23(sp)
+		LONG_L	$22, GDB_FR_REG22(sp)
+		LONG_L	$21, GDB_FR_REG21(sp)
+		LONG_L	$20, GDB_FR_REG20(sp)
+		LONG_L	$19, GDB_FR_REG19(sp)
+		LONG_L	$18, GDB_FR_REG18(sp)
+		LONG_L	$17, GDB_FR_REG17(sp)
+		LONG_L	$16, GDB_FR_REG16(sp)
+		LONG_L	$15, GDB_FR_REG15(sp)
+		LONG_L	$14, GDB_FR_REG14(sp)
+		LONG_L	$13, GDB_FR_REG13(sp)
+		LONG_L	$12, GDB_FR_REG12(sp)
+		LONG_L	$11, GDB_FR_REG11(sp)
+		LONG_L	$10, GDB_FR_REG10(sp)
+		LONG_L	$9, GDB_FR_REG9(sp)
+		LONG_L	$8, GDB_FR_REG8(sp)
+		LONG_L	$7, GDB_FR_REG7(sp)
+		LONG_L	$6, GDB_FR_REG6(sp)
+		LONG_L	$5, GDB_FR_REG5(sp)
+		LONG_L	$4, GDB_FR_REG4(sp)
+		LONG_L	$3, GDB_FR_REG3(sp)
+		LONG_L	$2, GDB_FR_REG2(sp)
+		LONG_L	$1, GDB_FR_REG1(sp)
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+		LONG_L	k0, GDB_FR_EPC(sp)
+		LONG_L	$29, GDB_FR_REG29(sp)		/* Deallocate stack */
+		jr	k0
+		rfe
+#else
+		LONG_L	sp, GDB_FR_REG29(sp)		/* Deallocate stack */
+
+		.set	mips3
+		eret
+		.set	mips0
+#endif
+		.set	at
+		.set	reorder
+		END(trap_low)
+
+LEAF(kgdb_read_byte)
+4:		lb	t0, (a0)
+		sb	t0, (a1)
+		li	v0, 0
+		jr	ra
+		.section __ex_table,"a"
+		PTR	4b, kgdbfault
+		.previous
+		END(kgdb_read_byte)
+
+LEAF(kgdb_write_byte)
+5:		sb	a0, (a1)
+		li	v0, 0
+		jr	ra
+		.section __ex_table,"a"
+		PTR	5b, kgdbfault
+		.previous
+		END(kgdb_write_byte)
+
+		.type	kgdbfault@function
+		.ent	kgdbfault
+
+kgdbfault:	li	v0, -EFAULT
+		jr	ra
+		.end	kgdbfault
diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c
new file mode 100644
index 0000000..2698893
--- /dev/null
+++ b/arch/mips/kernel/gdb-stub.c
@@ -0,0 +1,1091 @@
+/*
+ *  arch/mips/kernel/gdb-stub.c
+ *
+ *  Originally written by Glenn Engel, Lake Stevens Instrument Division
+ *
+ *  Contributed by HP Systems
+ *
+ *  Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ *  Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
+ *  Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
+ *
+ *  Copyright (C) 1995 Andreas Busse
+ *
+ *  Copyright (C) 2003 MontaVista Software Inc.
+ *  Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ */
+
+/*
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing a BREAK instruction.
+ *
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets
+ *							   baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ *
+ *  ==============
+ *  MORE EXAMPLES:
+ *  ==============
+ *
+ *  For reference -- the following are the steps that one
+ *  company took (RidgeRun Inc) to get remote gdb debugging
+ *  going. In this scenario the host machine was a PC and the
+ *  target platform was a Galileo EVB64120A MIPS evaluation
+ *  board.
+ *
+ *  Step 1:
+ *  First download gdb-5.0.tar.gz from the internet.
+ *  and then build/install the package.
+ *
+ *  Example:
+ *    $ tar zxf gdb-5.0.tar.gz
+ *    $ cd gdb-5.0
+ *    $ ./configure --target=mips-linux-elf
+ *    $ make
+ *    $ install
+ *    $ which mips-linux-elf-gdb
+ *    /usr/local/bin/mips-linux-elf-gdb
+ *
+ *  Step 2:
+ *  Configure linux for remote debugging and build it.
+ *
+ *  Example:
+ *    $ cd ~/linux
+ *    $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging>
+ *    $ make
+ *
+ *  Step 3:
+ *  Download the kernel to the remote target and start
+ *  the kernel running. It will promptly halt and wait
+ *  for the host gdb session to connect. It does this
+ *  since the "Kernel Hacking" option has defined
+ *  CONFIG_KGDB which in turn enables your calls
+ *  to:
+ *     set_debug_traps();
+ *     breakpoint();
+ *
+ *  Step 4:
+ *  Start the gdb session on the host.
+ *
+ *  Example:
+ *    $ mips-linux-elf-gdb vmlinux
+ *    (gdb) set remotebaud 115200
+ *    (gdb) target remote /dev/ttyS1
+ *    ...at this point you are connected to
+ *       the remote target and can use gdb
+ *       in the normal fasion. Setting
+ *       breakpoints, single stepping,
+ *       printing variables, etc.
+ */
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/reboot.h>
+
+#include <asm/asm.h>
+#include <asm/cacheflush.h>
+#include <asm/mipsregs.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/gdb-stub.h>
+#include <asm/inst.h>
+
+/*
+ * external low-level support routines
+ */
+
+extern int putDebugChar(char c);    /* write a single character      */
+extern char getDebugChar(void);     /* read and return a single char */
+extern void trap_low(void);
+
+/*
+ * breakpoint and test functions
+ */
+extern void breakpoint(void);
+extern void breakinst(void);
+extern void async_breakpoint(void);
+extern void async_breakinst(void);
+extern void adel(void);
+
+/*
+ * local prototypes
+ */
+
+static void getpacket(char *buffer);
+static void putpacket(char *buffer);
+static int computeSignal(int tt);
+static int hex(unsigned char ch);
+static int hexToInt(char **ptr, int *intValue);
+static int hexToLong(char **ptr, long *longValue);
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
+void handle_exception(struct gdb_regs *regs);
+
+int kgdb_enabled;
+
+/*
+ * spin locks for smp case
+ */
+static spinlock_t kgdb_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t kgdb_cpulock[NR_CPUS] = { [0 ... NR_CPUS-1] = SPIN_LOCK_UNLOCKED};
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+
+static char input_buffer[BUFMAX];
+static char output_buffer[BUFMAX];
+static int initialized;	/* !0 means we've been initialized */
+static int kgdb_started;
+static const char hexchars[]="0123456789abcdef";
+
+/* Used to prevent crashes in memory access.  Note that they'll crash anyway if
+   we haven't set up fault handlers yet... */
+int kgdb_read_byte(unsigned char *address, unsigned char *dest);
+int kgdb_write_byte(unsigned char val, unsigned char *dest);
+
+/*
+ * Convert ch from a hex digit to an int
+ */
+static int hex(unsigned char ch)
+{
+	if (ch >= 'a' && ch <= 'f')
+		return ch-'a'+10;
+	if (ch >= '0' && ch <= '9')
+		return ch-'0';
+	if (ch >= 'A' && ch <= 'F')
+		return ch-'A'+10;
+	return -1;
+}
+
+/*
+ * scan for the sequence $<data>#<checksum>
+ */
+static void getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	unsigned char ch;
+
+	do {
+		/*
+		 * wait around for the start character,
+		 * ignore all other characters
+		 */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+
+		checksum = 0;
+		xmitcsum = -1;
+		count = 0;
+
+		/*
+		 * now, read until a # or end of buffer is found
+		 */
+		while (count < BUFMAX) {
+			ch = getDebugChar();
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+
+		if (count >= BUFMAX)
+			continue;
+
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum |= hex(getDebugChar() & 0x7f);
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+'); /* successful transfer */
+
+				/*
+				 * if a sequence char is present,
+				 * reply the sequence ID
+				 */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+
+					/*
+					 * remove sequence chars from buffer
+					 */
+					count = strlen(buffer);
+					for (i=3; i <= count; i++)
+						buffer[i-3] = buffer[i];
+				}
+			}
+		}
+	}
+	while (checksum != xmitcsum);
+}
+
+/*
+ * send the packet in buffer.
+ */
+static void putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	unsigned char ch;
+
+	/*
+	 * $<packet info>#<checksum>.
+	 */
+
+	do {
+		putDebugChar('$');
+		checksum = 0;
+		count = 0;
+
+		while ((ch = buffer[count]) != 0) {
+			if (!(putDebugChar(ch)))
+				return;
+			checksum += ch;
+			count += 1;
+		}
+
+		putDebugChar('#');
+		putDebugChar(hexchars[checksum >> 4]);
+		putDebugChar(hexchars[checksum & 0xf]);
+
+	}
+	while ((getDebugChar() & 0x7f) != '+');
+}
+
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ * may_fault is non-zero if we are reading from arbitrary memory, but is currently
+ * not used.
+ */
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	unsigned char ch;
+
+	while (count-- > 0) {
+		if (kgdb_read_byte(mem++, &ch) != 0)
+			return 0;
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch & 0xf];
+	}
+
+	*buf = 0;
+
+	return buf;
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ * may_fault is non-zero if we are reading from arbitrary memory, but is currently
+ * not used.
+ */
+static char *hex2mem(char *buf, char *mem, int count, int binary, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	for (i=0; i<count; i++)
+	{
+		if (binary) {
+			ch = *buf++;
+			if (ch == 0x7d)
+				ch = 0x20 ^ *buf++;
+		}
+		else {
+			ch = hex(*buf++) << 4;
+			ch |= hex(*buf++);
+		}
+		if (kgdb_write_byte(ch, mem++) != 0)
+			return 0;
+	}
+
+	return mem;
+}
+
+/*
+ * This table contains the mapping between SPARC hardware trap types, and
+ * signals, which are primarily what GDB understands.  It also indicates
+ * which hardware traps we need to commandeer when initializing the stub.
+ */
+static struct hard_trap_info {
+	unsigned char tt;		/* Trap type code for MIPS R3xxx and R4xxx */
+	unsigned char signo;		/* Signal that we map this trap into */
+} hard_trap_info[] = {
+	{ 6, SIGBUS },			/* instruction bus error */
+	{ 7, SIGBUS },			/* data bus error */
+	{ 9, SIGTRAP },			/* break */
+	{ 10, SIGILL },			/* reserved instruction */
+/*	{ 11, SIGILL },		*/	/* CPU unusable */
+	{ 12, SIGFPE },			/* overflow */
+	{ 13, SIGTRAP },		/* trap */
+	{ 14, SIGSEGV },		/* virtual instruction cache coherency */
+	{ 15, SIGFPE },			/* floating point exception */
+	{ 23, SIGSEGV },		/* watch */
+	{ 31, SIGSEGV },		/* virtual data cache coherency */
+	{ 0, 0}				/* Must be last */
+};
+
+/* Save the normal trap handlers for user-mode traps. */
+void *saved_vectors[32];
+
+/*
+ * Set up exception handlers for tracing and breakpoints
+ */
+void set_debug_traps(void)
+{
+	struct hard_trap_info *ht;
+	unsigned long flags;
+	unsigned char c;
+
+	local_irq_save(flags);
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		saved_vectors[ht->tt] = set_except_vector(ht->tt, trap_low);
+
+	putDebugChar('+'); /* 'hello world' */
+	/*
+	 * In case GDB is started before us, ack any packets
+	 * (presumably "$?#xx") sitting there.
+	 */
+	while((c = getDebugChar()) != '$');
+	while((c = getDebugChar()) != '#');
+	c = getDebugChar(); /* eat first csum byte */
+	c = getDebugChar(); /* eat second csum byte */
+	putDebugChar('+'); /* ack it */
+
+	initialized = 1;
+	local_irq_restore(flags);
+}
+
+void restore_debug_traps(void)
+{
+	struct hard_trap_info *ht;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		set_except_vector(ht->tt, saved_vectors[ht->tt]);
+	local_irq_restore(flags);
+}
+
+/*
+ * Convert the MIPS hardware trap type code to a Unix signal number.
+ */
+static int computeSignal(int tt)
+{
+	struct hard_trap_info *ht;
+
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		if (ht->tt == tt)
+			return ht->signo;
+
+	return SIGHUP;		/* default for things we don't know about */
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue < 0)
+			break;
+
+		*intValue = (*intValue << 4) | hexValue;
+		numChars ++;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+static int hexToLong(char **ptr, long *longValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*longValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue < 0)
+			break;
+
+		*longValue = (*longValue << 4) | hexValue;
+		numChars ++;
+
+		(*ptr)++;
+	}
+
+	return numChars;
+}
+
+
+#if 0
+/*
+ * Print registers (on target console)
+ * Used only to debug the stub...
+ */
+void show_gdbregs(struct gdb_regs * regs)
+{
+	/*
+	 * Saved main processor registers
+	 */
+	printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+	       regs->reg0, regs->reg1, regs->reg2, regs->reg3,
+               regs->reg4, regs->reg5, regs->reg6, regs->reg7);
+	printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+	       regs->reg8, regs->reg9, regs->reg10, regs->reg11,
+               regs->reg12, regs->reg13, regs->reg14, regs->reg15);
+	printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+	       regs->reg16, regs->reg17, regs->reg18, regs->reg19,
+               regs->reg20, regs->reg21, regs->reg22, regs->reg23);
+	printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+	       regs->reg24, regs->reg25, regs->reg26, regs->reg27,
+	       regs->reg28, regs->reg29, regs->reg30, regs->reg31);
+
+	/*
+	 * Saved cp0 registers
+	 */
+	printk("epc  : %08lx\nStatus: %08lx\nCause : %08lx\n",
+	       regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
+}
+#endif /* dead code */
+
+/*
+ * We single-step by setting breakpoints. When an exception
+ * is handled, we need to restore the instructions hoisted
+ * when the breakpoints were set.
+ *
+ * This is where we save the original instructions.
+ */
+static struct gdb_bp_save {
+	unsigned long addr;
+	unsigned int val;
+} step_bp[2];
+
+#define BP 0x0000000d  /* break opcode */
+
+/*
+ * Set breakpoint instructions for single stepping.
+ */
+static void single_step(struct gdb_regs *regs)
+{
+	union mips_instruction insn;
+	unsigned long targ;
+	int is_branch, is_cond, i;
+
+	targ = regs->cp0_epc;
+	insn.word = *(unsigned int *)targ;
+	is_branch = is_cond = 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:
+		case jr_op:
+			targ = *(&regs->reg0 + insn.r_format.rs);
+			is_branch = 1;
+			break;
+		}
+		break;
+
+	/*
+	 * This group contains:
+	 * bltz_op, bgez_op, bltzl_op, bgezl_op,
+	 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
+	 */
+	case bcond_op:
+		is_branch = is_cond = 1;
+		targ += 4 + (insn.i_format.simmediate << 2);
+		break;
+
+	/*
+	 * These are unconditional and in j_format.
+	 */
+	case jal_op:
+	case j_op:
+		is_branch = 1;
+		targ += 4;
+		targ >>= 28;
+		targ <<= 28;
+		targ |= (insn.j_format.target << 2);
+		break;
+
+	/*
+	 * These are conditional.
+	 */
+	case beq_op:
+	case beql_op:
+	case bne_op:
+	case bnel_op:
+	case blez_op:
+	case blezl_op:
+	case bgtz_op:
+	case bgtzl_op:
+	case cop0_op:
+	case cop1_op:
+	case cop2_op:
+	case cop1x_op:
+		is_branch = is_cond = 1;
+		targ += 4 + (insn.i_format.simmediate << 2);
+		break;
+	}
+
+	if (is_branch) {
+		i = 0;
+		if (is_cond && targ != (regs->cp0_epc + 8)) {
+			step_bp[i].addr = regs->cp0_epc + 8;
+			step_bp[i++].val = *(unsigned *)(regs->cp0_epc + 8);
+			*(unsigned *)(regs->cp0_epc + 8) = BP;
+		}
+		step_bp[i].addr = targ;
+		step_bp[i].val  = *(unsigned *)targ;
+		*(unsigned *)targ = BP;
+	} else {
+		step_bp[0].addr = regs->cp0_epc + 4;
+		step_bp[0].val  = *(unsigned *)(regs->cp0_epc + 4);
+		*(unsigned *)(regs->cp0_epc + 4) = BP;
+	}
+}
+
+/*
+ *  If asynchronously interrupted by gdb, then we need to set a breakpoint
+ *  at the interrupted instruction so that we wind up stopped with a
+ *  reasonable stack frame.
+ */
+static struct gdb_bp_save async_bp;
+
+/*
+ * Swap the interrupted EPC with our asynchronous breakpoint routine.
+ * This is safer than stuffing the breakpoint in-place, since no cache
+ * flushes (or resulting smp_call_functions) are required.  The
+ * assumption is that only one CPU will be handling asynchronous bp's,
+ * and only one can be active at a time.
+ */
+extern spinlock_t smp_call_lock;
+void set_async_breakpoint(unsigned long *epc)
+{
+	/* skip breaking into userland */
+	if ((*epc & 0x80000000) == 0)
+		return;
+
+	/* avoid deadlock if someone is make IPC */
+	if (spin_is_locked(&smp_call_lock))
+		return;
+
+	async_bp.addr = *epc;
+	*epc = (unsigned long)async_breakpoint;
+}
+
+void kgdb_wait(void *arg)
+{
+	unsigned flags;
+	int cpu = smp_processor_id();
+
+	local_irq_save(flags);
+
+	spin_lock(&kgdb_cpulock[cpu]);
+	spin_unlock(&kgdb_cpulock[cpu]);
+
+	local_irq_restore(flags);
+}
+
+
+/*
+ * This function does all command processing for interfacing to gdb.  It
+ * returns 1 if you should skip the instruction at the trap address, 0
+ * otherwise.
+ */
+void handle_exception (struct gdb_regs *regs)
+{
+	int trap;			/* Trap type */
+	int sigval;
+	long addr;
+	int length;
+	char *ptr;
+	unsigned long *stack;
+	int i;
+	int bflag = 0;
+
+	kgdb_started = 1;
+
+	/*
+	 * acquire the big kgdb spinlock
+	 */
+	if (!spin_trylock(&kgdb_lock)) {
+		/* 
+		 * some other CPU has the lock, we should go back to 
+		 * receive the gdb_wait IPC
+		 */
+		return;
+	}
+
+	/*
+	 * If we're in async_breakpoint(), restore the real EPC from
+	 * the breakpoint.
+	 */
+	if (regs->cp0_epc == (unsigned long)async_breakinst) {
+		regs->cp0_epc = async_bp.addr;
+		async_bp.addr = 0;
+	}
+
+	/* 
+	 * acquire the CPU spinlocks
+	 */
+	for (i = num_online_cpus()-1; i >= 0; i--)
+		if (spin_trylock(&kgdb_cpulock[i]) == 0)
+			panic("kgdb: couldn't get cpulock %d\n", i);
+
+	/*
+	 * force other cpus to enter kgdb
+	 */
+	smp_call_function(kgdb_wait, NULL, 0, 0);
+
+	/*
+	 * If we're in breakpoint() increment the PC
+	 */
+	trap = (regs->cp0_cause & 0x7c) >> 2;
+	if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst)
+		regs->cp0_epc += 4;
+
+	/*
+	 * If we were single_stepping, restore the opcodes hoisted
+	 * for the breakpoint[s].
+	 */
+	if (step_bp[0].addr) {
+		*(unsigned *)step_bp[0].addr = step_bp[0].val;
+		step_bp[0].addr = 0;
+
+		if (step_bp[1].addr) {
+			*(unsigned *)step_bp[1].addr = step_bp[1].val;
+			step_bp[1].addr = 0;
+		}
+	}
+
+	stack = (long *)regs->reg29;			/* stack ptr */
+	sigval = computeSignal(trap);
+
+	/*
+	 * reply to host that an exception has occurred
+	 */
+	ptr = output_buffer;
+
+	/*
+	 * Send trap type (converted to signal)
+	 */
+	*ptr++ = 'T';
+	*ptr++ = hexchars[sigval >> 4];
+	*ptr++ = hexchars[sigval & 0xf];
+
+	/*
+	 * Send Error PC
+	 */
+	*ptr++ = hexchars[REG_EPC >> 4];
+	*ptr++ = hexchars[REG_EPC & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex((char *)&regs->cp0_epc, ptr, sizeof(long), 0);
+	*ptr++ = ';';
+
+	/*
+	 * Send frame pointer
+	 */
+	*ptr++ = hexchars[REG_FP >> 4];
+	*ptr++ = hexchars[REG_FP & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex((char *)&regs->reg30, ptr, sizeof(long), 0);
+	*ptr++ = ';';
+
+	/*
+	 * Send stack pointer
+	 */
+	*ptr++ = hexchars[REG_SP >> 4];
+	*ptr++ = hexchars[REG_SP & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex((char *)&regs->reg29, ptr, sizeof(long), 0);
+	*ptr++ = ';';
+
+	*ptr++ = 0;
+	putpacket(output_buffer);	/* send it off... */
+
+	/*
+	 * Wait for input from remote GDB
+	 */
+	while (1) {
+		output_buffer[0] = 0;
+		getpacket(input_buffer);
+
+		switch (input_buffer[0])
+		{
+		case '?':
+			output_buffer[0] = 'S';
+			output_buffer[1] = hexchars[sigval >> 4];
+			output_buffer[2] = hexchars[sigval & 0xf];
+			output_buffer[3] = 0;
+			break;
+
+		/*
+		 * Detach debugger; let CPU run
+		 */
+		case 'D':
+			putpacket(output_buffer);
+			goto finish_kgdb;
+			break;
+
+		case 'd':
+			/* toggle debug flag */
+			break;
+
+		/*
+		 * Return the value of the CPU registers
+		 */
+		case 'g':
+			ptr = output_buffer;
+			ptr = mem2hex((char *)&regs->reg0, ptr, 32*sizeof(long), 0); /* r0...r31 */
+			ptr = mem2hex((char *)&regs->cp0_status, ptr, 6*sizeof(long), 0); /* cp0 */
+			ptr = mem2hex((char *)&regs->fpr0, ptr, 32*sizeof(long), 0); /* f0...31 */
+			ptr = mem2hex((char *)&regs->cp1_fsr, ptr, 2*sizeof(long), 0); /* cp1 */
+			ptr = mem2hex((char *)&regs->frame_ptr, ptr, 2*sizeof(long), 0); /* frp */
+			ptr = mem2hex((char *)&regs->cp0_index, ptr, 16*sizeof(long), 0); /* cp0 */
+			break;
+
+		/*
+		 * set the value of the CPU registers - return OK
+		 */
+		case 'G':
+		{
+			ptr = &input_buffer[1];
+			hex2mem(ptr, (char *)&regs->reg0, 32*sizeof(long), 0, 0);
+			ptr += 32*(2*sizeof(long));
+			hex2mem(ptr, (char *)&regs->cp0_status, 6*sizeof(long), 0, 0);
+			ptr += 6*(2*sizeof(long));
+			hex2mem(ptr, (char *)&regs->fpr0, 32*sizeof(long), 0, 0);
+			ptr += 32*(2*sizeof(long));
+			hex2mem(ptr, (char *)&regs->cp1_fsr, 2*sizeof(long), 0, 0);
+			ptr += 2*(2*sizeof(long));
+			hex2mem(ptr, (char *)&regs->frame_ptr, 2*sizeof(long), 0, 0);
+			ptr += 2*(2*sizeof(long));
+			hex2mem(ptr, (char *)&regs->cp0_index, 16*sizeof(long), 0, 0);
+			strcpy(output_buffer,"OK");
+		 }
+		break;
+
+		/*
+		 * mAA..AA,LLLL  Read LLLL bytes at address AA..AA
+		 */
+		case 'm':
+			ptr = &input_buffer[1];
+
+			if (hexToLong(&ptr, &addr)
+				&& *ptr++ == ','
+				&& hexToInt(&ptr, &length)) {
+				if (mem2hex((char *)addr, output_buffer, length, 1))
+					break;
+				strcpy (output_buffer, "E03");
+			} else
+				strcpy(output_buffer,"E01");
+			break;
+
+		/*
+		 * XAA..AA,LLLL: Write LLLL escaped binary bytes at address AA.AA
+		 */
+		case 'X':
+			bflag = 1;
+			/* fall through */
+
+		/*
+		 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
+		 */
+		case 'M':
+			ptr = &input_buffer[1];
+
+			if (hexToLong(&ptr, &addr)
+				&& *ptr++ == ','
+				&& hexToInt(&ptr, &length)
+				&& *ptr++ == ':') {
+				if (hex2mem(ptr, (char *)addr, length, bflag, 1))
+					strcpy(output_buffer, "OK");
+				else
+					strcpy(output_buffer, "E03");
+			}
+			else
+				strcpy(output_buffer, "E02");
+			break;
+
+		/*
+		 * cAA..AA    Continue at address AA..AA(optional)
+		 */
+		case 'c':
+			/* try to read optional parameter, pc unchanged if no parm */
+
+			ptr = &input_buffer[1];
+			if (hexToLong(&ptr, &addr))
+				regs->cp0_epc = addr;
+	  
+			goto exit_kgdb_exception;
+			break;
+
+		/*
+		 * kill the program; let us try to restart the machine
+		 * Reset the whole machine.
+		 */
+		case 'k':
+		case 'r':
+			machine_restart("kgdb restarts machine");
+			break;
+
+		/*
+		 * Step to next instruction
+		 */
+		case 's':
+			/*
+			 * There is no single step insn in the MIPS ISA, so we
+			 * use breakpoints and continue, instead.
+			 */
+			single_step(regs);
+			goto exit_kgdb_exception;
+			/* NOTREACHED */
+			break;
+
+		/*
+		 * Set baud rate (bBB)
+		 * FIXME: Needs to be written
+		 */
+		case 'b':
+		{
+#if 0
+			int baudrate;
+			extern void set_timer_3();
+
+			ptr = &input_buffer[1];
+			if (!hexToInt(&ptr, &baudrate))
+			{
+				strcpy(output_buffer,"B01");
+				break;
+			}
+
+			/* Convert baud rate to uart clock divider */
+
+			switch (baudrate)
+			{
+				case 38400:
+					baudrate = 16;
+					break;
+				case 19200:
+					baudrate = 33;
+					break;
+				case 9600:
+					baudrate = 65;
+					break;
+				default:
+					baudrate = 0;
+					strcpy(output_buffer,"B02");
+					goto x1;
+			}
+
+			if (baudrate) {
+				putpacket("OK");	/* Ack before changing speed */
+				set_timer_3(baudrate); /* Set it */
+			}
+#endif
+		}
+		break;
+
+		}			/* switch */
+
+		/*
+		 * reply to the request
+		 */
+
+		putpacket(output_buffer);
+
+	} /* while */
+
+	return;
+
+finish_kgdb:
+	restore_debug_traps();
+
+exit_kgdb_exception:
+	/* release locks so other CPUs can go */
+	for (i = num_online_cpus()-1; i >= 0; i--)
+		spin_unlock(&kgdb_cpulock[i]);
+	spin_unlock(&kgdb_lock);
+
+	__flush_cache_all();
+	return;
+}
+
+/*
+ * This function will generate a breakpoint exception.  It is used at the
+ * beginning of a program to sync up with a debugger and can be used
+ * otherwise as a quick means to stop program execution and "break" into
+ * the debugger.
+ */
+void breakpoint(void)
+{
+	if (!initialized)
+		return;
+
+	__asm__ __volatile__(
+			".globl	breakinst\n\t" 
+			".set\tnoreorder\n\t"
+			"nop\n"
+			"breakinst:\tbreak\n\t"
+			"nop\n\t"
+			".set\treorder"
+			);
+}
+
+/* Nothing but the break; don't pollute any registers */
+void async_breakpoint(void)
+{
+	__asm__ __volatile__(
+			".globl	async_breakinst\n\t" 
+			".set\tnoreorder\n\t"
+			"nop\n"
+			"async_breakinst:\tbreak\n\t"
+			"nop\n\t"
+			".set\treorder"
+			);
+}
+
+void adel(void)
+{
+	__asm__ __volatile__(
+			".globl\tadel\n\t"
+			"lui\t$8,0x8000\n\t"
+			"lw\t$9,1($8)\n\t"
+			);
+}
+
+/*
+ * malloc is needed by gdb client in "call func()", even a private one
+ * will make gdb happy
+ */
+static void *malloc(size_t size)
+{
+	return kmalloc(size, GFP_ATOMIC);
+}
+
+static void free(void *where)
+{
+	kfree(where);
+}
+
+#ifdef CONFIG_GDB_CONSOLE
+
+void gdb_putsn(const char *str, int l)
+{
+	char outbuf[18];
+
+	if (!kgdb_started)
+		return;
+
+	outbuf[0]='O';
+
+	while(l) {
+		int i = (l>8)?8:l;
+		mem2hex((char *)str, &outbuf[1], i, 0);
+		outbuf[(i*2)+1]=0;
+		putpacket(outbuf);
+		str += i;
+		l -= i;
+	}
+}
+
+static void gdb_console_write(struct console *con, const char *s, unsigned n)
+{
+	gdb_putsn(s, n);
+}
+
+static struct console gdb_console = {
+	.name	= "gdb",
+	.write	= gdb_console_write,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1
+};
+
+static int __init register_gdb_console(void)
+{
+	register_console(&gdb_console);
+
+	return 0;
+}
+
+console_initcall(register_gdb_console);
+
+#endif
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
new file mode 100644
index 0000000..a5b0a38
--- /dev/null
+++ b/arch/mips/kernel/genex.S
@@ -0,0 +1,302 @@
+/*
+ * 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) 1994 - 2000, 2001, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ * Copyright (C) 2002 Maciej W. Rozycki
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/asm.h>
+#include <asm/cacheops.h>
+#include <asm/regdef.h>
+#include <asm/fpregdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/war.h>
+
+#define PANIC_PIC(msg)					\
+		.set push;				\
+		.set	reorder;			\
+		PTR_LA	a0,8f;				\
+		.set	noat;				\
+		PTR_LA	AT, panic;			\
+		jr	AT;				\
+9:		b	9b;				\
+		.set	pop;				\
+		TEXT(msg)
+
+	__INIT
+
+NESTED(except_vec0_generic, 0, sp)
+	PANIC_PIC("Exception vector 0 called")
+	END(except_vec0_generic)
+
+NESTED(except_vec1_generic, 0, sp)
+	PANIC_PIC("Exception vector 1 called")
+	END(except_vec1_generic)
+
+/*
+ * General exception vector for all other CPUs.
+ *
+ * Be careful when changing this, it has to be at most 128 bytes
+ * to fit into space reserved for the exception handler.
+ */
+NESTED(except_vec3_generic, 0, sp)
+	.set	push
+	.set	noat
+#if R5432_CP0_INTERRUPT_WAR
+	mfc0	k0, CP0_INDEX
+#endif
+	mfc0	k1, CP0_CAUSE
+	andi	k1, k1, 0x7c
+#ifdef CONFIG_MIPS64
+	dsll	k1, k1, 1
+#endif
+	PTR_L	k0, exception_handlers(k1)
+	jr	k0
+	.set	pop
+	END(except_vec3_generic)
+
+/*
+ * General exception handler for CPUs with virtual coherency exception.
+ *
+ * Be careful when changing this, it has to be at most 256 (as a special
+ * exception) bytes to fit into space reserved for the exception handler.
+ */
+NESTED(except_vec3_r4000, 0, sp)
+	.set	push
+	.set	mips3
+	.set	noat
+	mfc0	k1, CP0_CAUSE
+	li	k0, 31<<2
+	andi	k1, k1, 0x7c
+	.set	push
+	.set	noreorder
+	.set	nomacro
+	beq	k1, k0, handle_vced
+	 li	k0, 14<<2
+	beq	k1, k0, handle_vcei
+#ifdef CONFIG_MIPS64
+	dsll	k1, k1, 1
+#endif
+	.set	pop
+	PTR_L	k0, exception_handlers(k1)
+	jr	k0
+
+	/*
+	 * Big shit, we now may have two dirty primary cache lines for the same
+	 * physical address.  We can savely invalidate the line pointed to by
+	 * c0_badvaddr because after return from this exception handler the
+	 * load / store will be re-executed.
+	 */
+handle_vced:
+	DMFC0	k0, CP0_BADVADDR
+	li	k1, -4					# Is this ...
+	and	k0, k1					# ... really needed?
+	mtc0	zero, CP0_TAGLO
+	cache	Index_Store_Tag_D,(k0)
+	cache	Hit_Writeback_Inv_SD,(k0)
+#ifdef CONFIG_PROC_FS
+	PTR_LA	k0, vced_count
+	lw	k1, (k0)
+	addiu	k1, 1
+	sw	k1, (k0)
+#endif
+	eret
+
+handle_vcei:
+	MFC0	k0, CP0_BADVADDR
+	cache	Hit_Writeback_Inv_SD, (k0)		# also cleans pi
+#ifdef CONFIG_PROC_FS
+	PTR_LA	k0, vcei_count
+	lw	k1, (k0)
+	addiu	k1, 1
+	sw	k1, (k0)
+#endif
+	eret
+	.set	pop
+	END(except_vec3_r4000)
+
+/*
+ * Special interrupt vector for MIPS64 ISA & embedded MIPS processors.
+ * This is a dedicated interrupt exception vector which reduces the
+ * interrupt processing overhead.  The jump instruction will be replaced
+ * at the initialization time.
+ *
+ * Be careful when changing this, it has to be at most 128 bytes
+ * to fit into space reserved for the exception handler.
+ */
+NESTED(except_vec4, 0, sp)
+1:	j	1b			/* Dummy, will be replaced */
+	END(except_vec4)
+
+/*
+ * EJTAG debug exception handler.
+ * The EJTAG debug exception entry point is 0xbfc00480, which
+ * normally is in the boot PROM, so the boot PROM must do a
+ * unconditional jump to this vector.
+ */
+NESTED(except_vec_ejtag_debug, 0, sp)
+	j	ejtag_debug_handler
+	END(except_vec_ejtag_debug)
+
+	__FINIT
+
+/*
+ * EJTAG debug exception handler.
+ */
+NESTED(ejtag_debug_handler, PT_SIZE, sp)
+	.set	push
+	.set	noat
+	MTC0	k0, CP0_DESAVE
+	mfc0	k0, CP0_DEBUG
+
+	sll	k0, k0, 30	# Check for SDBBP.
+	bgez	k0, ejtag_return
+
+	PTR_LA	k0, ejtag_debug_buffer
+	LONG_S	k1, 0(k0)
+	SAVE_ALL
+	move	a0, sp
+	jal	ejtag_exception_handler
+	RESTORE_ALL
+	PTR_LA	k0, ejtag_debug_buffer
+	LONG_L	k1, 0(k0)
+
+ejtag_return:
+	MFC0	k0, CP0_DESAVE
+	.set	mips32
+	deret
+	.set pop
+	END(ejtag_debug_handler)
+
+/*
+ * This buffer is reserved for the use of the EJTAG debug
+ * handler.
+ */
+	.data
+EXPORT(ejtag_debug_buffer)
+	.fill	LONGSIZE
+	.previous
+
+	__INIT
+
+/*
+ * NMI debug exception handler for MIPS reference boards.
+ * The NMI debug exception entry point is 0xbfc00000, which
+ * normally is in the boot PROM, so the boot PROM must do a
+ * unconditional jump to this vector.
+ */
+NESTED(except_vec_nmi, 0, sp)
+	j	nmi_handler
+	END(except_vec_nmi)
+
+	__FINIT
+
+NESTED(nmi_handler, PT_SIZE, sp)
+	.set	push
+	.set	noat
+	.set	mips3
+	SAVE_ALL
+ 	move	a0, sp
+	jal	nmi_exception_handler
+	RESTORE_ALL
+	eret
+	.set	pop
+	END(nmi_handler)
+
+	.macro	__build_clear_none
+	.endm
+
+	.macro	__build_clear_sti
+	STI
+	.endm
+
+	.macro	__build_clear_cli
+	CLI
+	.endm
+
+	.macro	__build_clear_fpe
+	cfc1	a1, fcr31
+	li	a2, ~(0x3f << 12)
+	and	a2, a1
+	ctc1	a2, fcr31
+	STI
+	.endm
+
+	.macro	__build_clear_ade
+	MFC0	t0, CP0_BADVADDR
+	PTR_S	t0, PT_BVADDR(sp)
+	KMODE
+	.endm
+
+	.macro	__BUILD_silent exception
+	.endm
+
+	/* Gas tries to parse the PRINT argument as a string containing
+	   string escapes and emits bogus warnings if it believes to
+	   recognize an unknown escape code.  So make the arguments
+	   start with an n and gas will believe \n is ok ...  */
+	.macro	__BUILD_verbose	nexception
+	LONG_L	a1, PT_EPC(sp)
+#if CONFIG_MIPS32
+	PRINT("Got \nexception at %08lx\012")
+#endif	
+#if CONFIG_MIPS64
+	PRINT("Got \nexception at %016lx\012")
+#endif	
+	.endm
+
+	.macro	__BUILD_count exception
+	LONG_L	t0,exception_count_\exception
+	LONG_ADDIU t0, 1
+	LONG_S	t0,exception_count_\exception
+	.comm	exception_count\exception, 8, 8
+	.endm
+
+	.macro	__BUILD_HANDLER exception handler clear verbose ext
+	.align	5
+	NESTED(handle_\exception, PT_SIZE, sp)
+	.set	noat
+	SAVE_ALL
+	FEXPORT(handle_\exception\ext)
+	__BUILD_clear_\clear
+	.set	at
+	__BUILD_\verbose \exception
+	move	a0, sp
+	jal	do_\handler
+	j	ret_from_exception
+	END(handle_\exception)
+	.endm
+
+	.macro	BUILD_HANDLER exception handler clear verbose
+	__BUILD_HANDLER	\exception \handler \clear \verbose _int
+	.endm
+
+	BUILD_HANDLER adel ade ade silent		/* #4  */
+	BUILD_HANDLER ades ade ade silent		/* #5  */
+	BUILD_HANDLER ibe be cli silent			/* #6  */
+	BUILD_HANDLER dbe be cli silent			/* #7  */
+	BUILD_HANDLER bp bp sti silent			/* #9  */
+	BUILD_HANDLER ri ri sti silent			/* #10 */
+	BUILD_HANDLER cpu cpu sti silent		/* #11 */
+	BUILD_HANDLER ov ov sti silent			/* #12 */
+	BUILD_HANDLER tr tr sti silent			/* #13 */
+	BUILD_HANDLER fpe fpe fpe silent		/* #15 */
+	BUILD_HANDLER mdmx mdmx sti silent		/* #22 */
+	BUILD_HANDLER watch watch sti verbose		/* #23 */
+	BUILD_HANDLER mcheck mcheck cli verbose		/* #24 */
+	BUILD_HANDLER reserved reserved sti verbose	/* others */
+
+#ifdef CONFIG_MIPS64
+/* A temporary overflow handler used by check_daddi(). */
+
+	__INIT
+
+	BUILD_HANDLER  daddi_ov daddi_ov none silent	/* #12 */
+#endif
diff --git a/arch/mips/kernel/genrtc.c b/arch/mips/kernel/genrtc.c
new file mode 100644
index 0000000..288bf51
--- /dev/null
+++ b/arch/mips/kernel/genrtc.c
@@ -0,0 +1,64 @@
+/*
+ * A glue layer that provides RTC read/write to drivers/char/genrtc.c driver
+ * based on MIPS internal RTC routines.  It does take care locking
+ * issues so that we are SMP/Preemption safe.
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * Please read the COPYING file for all license details.
+ */
+
+#include <linux/spinlock.h>
+
+#include <asm/rtc.h>
+#include <asm/time.h>
+
+static spinlock_t mips_rtc_lock = SPIN_LOCK_UNLOCKED;
+
+unsigned int get_rtc_time(struct rtc_time *time)
+{
+	unsigned long nowtime;
+
+	spin_lock(&mips_rtc_lock);
+	nowtime = rtc_get_time();
+	to_tm(nowtime, time);
+	time->tm_year -= 1900;
+	spin_unlock(&mips_rtc_lock);
+
+	return RTC_24H;
+}
+
+int set_rtc_time(struct rtc_time *time)
+{
+	unsigned long nowtime;
+	int ret;
+
+	spin_lock(&mips_rtc_lock);
+	nowtime = mktime(time->tm_year+1900, time->tm_mon+1,
+			time->tm_mday, time->tm_hour, time->tm_min,
+			time->tm_sec);
+	ret = rtc_set_time(nowtime);
+	spin_unlock(&mips_rtc_lock);
+
+	return ret;
+}
+
+unsigned int get_rtc_ss(void)
+{
+	struct rtc_time h;
+
+	get_rtc_time(&h);
+	return h.tm_sec;
+}
+
+int get_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+
+int set_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
new file mode 100644
index 0000000..a64e87d2
--- /dev/null
+++ b/arch/mips/kernel/head.S
@@ -0,0 +1,221 @@
+/*
+ * 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) 1994, 1995 Waldorf Electronics
+ * Written by Ralf Baechle and Andreas Busse
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003 Ralf Baechle
+ * Copyright (C) 1996 Paul M. Antoine
+ * Modified for DECStation and hence R3000 support by Paul M. Antoine
+ * Further modifications by David S. Miller and Harald Koerfgen
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/threads.h>
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/page.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#ifdef CONFIG_SGI_IP27
+#include <asm/sn/addrs.h>
+#include <asm/sn/sn0/hubni.h>
+#include <asm/sn/klkernvars.h>
+#endif
+
+	.macro	ARC64_TWIDDLE_PC
+#if defined(CONFIG_ARC64) || defined(CONFIG_MAPPED_KERNEL)
+	/* We get launched at a XKPHYS address but the kernel is linked to
+	   run at a KSEG0 address, so jump there.  */
+	PTR_LA	t0, \@f
+	jr	t0
+\@:
+#endif
+	.endm
+
+#ifdef CONFIG_SGI_IP27
+	/*
+	 * outputs the local nasid into res.  IP27 stuff.
+	 */
+	.macro GET_NASID_ASM res
+	dli	\res, LOCAL_HUB_ADDR(NI_STATUS_REV_ID)
+	ld	\res, (\res)
+	and	\res, NSRI_NODEID_MASK
+	dsrl	\res, NSRI_NODEID_SHFT
+	.endm
+#endif /* CONFIG_SGI_IP27 */
+
+	/*
+	 * inputs are the text nasid in t1, data nasid in t2.
+	 */
+	.macro MAPPED_KERNEL_SETUP_TLB
+#ifdef CONFIG_MAPPED_KERNEL
+	/*
+	 * This needs to read the nasid - assume 0 for now.
+	 * Drop in 0xffffffffc0000000 in tlbhi, 0+VG in tlblo_0,
+	 * 0+DVG in tlblo_1.
+	 */
+	dli	t0, 0xffffffffc0000000
+	dmtc0	t0, CP0_ENTRYHI
+	li	t0, 0x1c000		# Offset of text into node memory
+	dsll	t1, NASID_SHFT		# Shift text nasid into place
+	dsll	t2, NASID_SHFT		# Same for data nasid
+	or	t1, t1, t0		# Physical load address of kernel text
+	or	t2, t2, t0		# Physical load address of kernel data
+	dsrl	t1, 12			# 4K pfn
+	dsrl	t2, 12			# 4K pfn
+	dsll	t1, 6			# Get pfn into place
+	dsll	t2, 6			# Get pfn into place
+	li	t0, ((_PAGE_GLOBAL|_PAGE_VALID| _CACHE_CACHABLE_COW) >> 6)
+	or	t0, t0, t1
+	mtc0	t0, CP0_ENTRYLO0	# physaddr, VG, cach exlwr
+	li	t0, ((_PAGE_GLOBAL|_PAGE_VALID| _PAGE_DIRTY|_CACHE_CACHABLE_COW) >> 6)
+	or	t0, t0, t2
+	mtc0	t0, CP0_ENTRYLO1	# physaddr, DVG, cach exlwr
+	li	t0, 0x1ffe000		# MAPPED_KERN_TLBMASK, TLBPGMASK_16M
+	mtc0	t0, CP0_PAGEMASK
+	li	t0, 0			# KMAP_INX
+	mtc0	t0, CP0_INDEX
+	li	t0, 1
+	mtc0	t0, CP0_WIRED
+	tlbwi
+#else
+	mtc0	zero, CP0_WIRED
+#endif
+	.endm
+
+	/*
+	 * For the moment disable interrupts, mark the kernel mode and
+	 * set ST0_KX so that the CPU does not spit fire when using
+	 * 64-bit addresses.  A full initialization of the CPU's status
+	 * register is done later in per_cpu_trap_init().
+	 */
+	.macro	setup_c0_status set clr
+	.set	push
+	mfc0	t0, CP0_STATUS
+	or	t0, ST0_CU0|\set|0x1f|\clr
+	xor	t0, 0x1f|\clr
+	mtc0	t0, CP0_STATUS
+	.set	noreorder
+	sll	zero,3				# ehb
+	.set	pop
+	.endm
+
+	.macro	setup_c0_status_pri
+#ifdef CONFIG_MIPS64
+	setup_c0_status ST0_KX 0
+#else
+	setup_c0_status 0 0
+#endif
+	.endm
+
+	.macro	setup_c0_status_sec
+#ifdef CONFIG_MIPS64
+	setup_c0_status ST0_KX ST0_BEV
+#else
+	setup_c0_status 0 ST0_BEV
+#endif
+	.endm
+
+	/*
+	 * Reserved space for exception handlers.
+	 * Necessary for machines which link their kernels at KSEG0.
+	 */
+	.fill	0x400
+
+EXPORT(stext)					# used for profiling
+EXPORT(_stext)
+
+	__INIT
+
+NESTED(kernel_entry, 16, sp)			# kernel entry point
+	setup_c0_status_pri
+
+#ifdef CONFIG_SGI_IP27
+	GET_NASID_ASM	t1
+	move	t2, t1				# text and data are here
+	MAPPED_KERNEL_SETUP_TLB
+#endif /* IP27 */
+
+	ARC64_TWIDDLE_PC
+
+	PTR_LA		t0, __bss_start		# clear .bss
+	LONG_S		zero, (t0)
+	PTR_LA		t1, __bss_stop - LONGSIZE
+1:
+	PTR_ADDIU	t0, LONGSIZE
+	LONG_S		zero, (t0)
+	bne		t0, t1, 1b
+
+	LONG_S		a0, fw_arg0		# firmware arguments
+	LONG_S		a1, fw_arg1
+	LONG_S		a2, fw_arg2
+	LONG_S		a3, fw_arg3
+
+	PTR_LA		$28, init_thread_union
+	PTR_ADDIU	sp, $28, _THREAD_SIZE - 32
+	set_saved_sp	sp, t0, t1
+	PTR_SUBU	sp, 4 * SZREG		# init stack pointer
+
+	j		start_kernel
+	END(kernel_entry)
+
+#ifdef CONFIG_SMP
+/*
+ * SMP slave cpus entry point.  Board specific code for bootstrap calls this
+ * function after setting up the stack and gp registers.
+ */
+NESTED(smp_bootstrap, 16, sp)
+	setup_c0_status_sec
+
+#ifdef CONFIG_SGI_IP27
+	GET_NASID_ASM	t1
+	dli	t0, KLDIR_OFFSET + (KLI_KERN_VARS * KLDIR_ENT_SIZE) + \
+		    KLDIR_OFF_POINTER + CAC_BASE
+	dsll	t1, NASID_SHFT
+	or	t0, t0, t1
+	ld	t0, 0(t0)			# t0 points to kern_vars struct
+	lh	t1, KV_RO_NASID_OFFSET(t0)
+	lh	t2, KV_RW_NASID_OFFSET(t0)
+	MAPPED_KERNEL_SETUP_TLB
+	ARC64_TWIDDLE_PC
+#endif /* CONFIG_SGI_IP27 */
+
+	j	start_secondary
+	END(smp_bootstrap)
+#endif /* CONFIG_SMP */
+
+	__FINIT
+
+	.comm	kernelsp,    NR_CPUS * 8, 8
+	.comm	pgd_current, NR_CPUS * 8, 8
+
+	.comm	fw_arg0, SZREG, SZREG		# firmware arguments
+	.comm	fw_arg1, SZREG, SZREG
+	.comm	fw_arg2, SZREG, SZREG
+	.comm	fw_arg3, SZREG, SZREG
+
+	.macro	page name, order=0
+	.globl	\name
+\name:	.size	\name, (_PAGE_SIZE << \order)
+	.org	. + (_PAGE_SIZE << \order)
+	.type	\name, @object
+	.endm
+
+	.data
+	.align	PAGE_SHIFT
+
+	/*
+	 * ... but on 64-bit we've got three-level pagetables with a
+	 * slightly different layout ...
+	 */
+	page	swapper_pg_dir, _PGD_ORDER
+#ifdef CONFIG_MIPS64
+	page	invalid_pmd_table, _PMD_ORDER
+#endif
+	page	invalid_pte_table, _PTE_ORDER
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
new file mode 100644
index 0000000..7eec756
--- /dev/null
+++ b/arch/mips/kernel/i8259.c
@@ -0,0 +1,331 @@
+/*
+ * 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.
+ *
+ * Code to handle x86 style IRQs plus some generic interrupt stuff.
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1994 - 2000 Ralf Baechle
+ */
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/sysdev.h>
+
+#include <asm/i8259.h>
+#include <asm/io.h>
+
+void enable_8259A_irq(unsigned int irq);
+void disable_8259A_irq(unsigned int irq);
+
+/*
+ * This is the 'legacy' 8259A Programmable Interrupt Controller,
+ * present in the majority of PC/AT boxes.
+ * plus some generic x86 specific things if generic specifics makes
+ * any sense at all.
+ * this file should become arch/i386/kernel/irq.c when the old irq.c
+ * moves to arch independent land
+ */
+
+spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED;
+
+static void end_8259A_irq (unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
+	    irq_desc[irq].action)
+		enable_8259A_irq(irq);
+}
+
+#define shutdown_8259A_irq	disable_8259A_irq
+
+void mask_and_ack_8259A(unsigned int);
+
+static unsigned int startup_8259A_irq(unsigned int irq)
+{
+	enable_8259A_irq(irq);
+
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type i8259A_irq_type = {
+	"XT-PIC",
+	startup_8259A_irq,
+	shutdown_8259A_irq,
+	enable_8259A_irq,
+	disable_8259A_irq,
+	mask_and_ack_8259A,
+	end_8259A_irq,
+	NULL
+};
+
+/*
+ * 8259A PIC functions to handle ISA devices:
+ */
+
+/*
+ * This contains the irq mask for both 8259A irq controllers,
+ */
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_21	(cached_irq_mask)
+#define cached_A1	(cached_irq_mask >> 8)
+
+void disable_8259A_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+	cached_irq_mask |= mask;
+	if (irq & 8)
+		outb(cached_A1,0xA1);
+	else
+		outb(cached_21,0x21);
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
+void enable_8259A_irq(unsigned int irq)
+{
+	unsigned int mask = ~(1 << irq);
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+	cached_irq_mask &= mask;
+	if (irq & 8)
+		outb(cached_A1,0xA1);
+	else
+		outb(cached_21,0x21);
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
+int i8259A_irq_pending(unsigned int irq)
+{
+	unsigned int mask = 1 << irq;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+	if (irq < 8)
+		ret = inb(0x20) & mask;
+	else
+		ret = inb(0xA0) & (mask >> 8);
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+
+	return ret;
+}
+
+void make_8259A_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+	irq_desc[irq].handler = &i8259A_irq_type;
+	enable_irq(irq);
+}
+
+/*
+ * This function assumes to be called rarely. Switching between
+ * 8259A registers is slow.
+ * This has to be protected by the irq controller spinlock
+ * before being called.
+ */
+static inline int i8259A_irq_real(unsigned int irq)
+{
+	int value;
+	int irqmask = 1 << irq;
+
+	if (irq < 8) {
+		outb(0x0B,0x20);		/* ISR register */
+		value = inb(0x20) & irqmask;
+		outb(0x0A,0x20);		/* back to the IRR register */
+		return value;
+	}
+	outb(0x0B,0xA0);		/* ISR register */
+	value = inb(0xA0) & (irqmask >> 8);
+	outb(0x0A,0xA0);		/* back to the IRR register */
+	return value;
+}
+
+/*
+ * Careful! The 8259A is a fragile beast, it pretty
+ * much _has_ to be done exactly like this (mask it
+ * first, _then_ send the EOI, and the order of EOI
+ * to the two 8259s is important!
+ */
+void mask_and_ack_8259A(unsigned int irq)
+{
+	unsigned int irqmask = 1 << irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+	/*
+	 * Lightweight spurious IRQ detection. We do not want to overdo
+	 * spurious IRQ handling - it's usually a sign of hardware problems, so
+	 * we only do the checks we can do without slowing down good hardware
+	 * nnecesserily.
+	 *
+	 * Note that IRQ7 and IRQ15 (the two spurious IRQs usually resulting
+	 * rom the 8259A-1|2 PICs) occur even if the IRQ is masked in the 8259A.
+	 * Thus we can check spurious 8259A IRQs without doing the quite slow
+	 * i8259A_irq_real() call for every IRQ.  This does not cover 100% of
+	 * spurious interrupts, but should be enough to warn the user that
+	 * there is something bad going on ...
+	 */
+	if (cached_irq_mask & irqmask)
+		goto spurious_8259A_irq;
+	cached_irq_mask |= irqmask;
+
+handle_real_irq:
+	if (irq & 8) {
+		inb(0xA1);		/* DUMMY - (do we need this?) */
+		outb(cached_A1,0xA1);
+		outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */
+		outb(0x62,0x20);	/* 'Specific EOI' to master-IRQ2 */
+	} else {
+		inb(0x21);		/* DUMMY - (do we need this?) */
+		outb(cached_21,0x21);
+		outb(0x60+irq,0x20);	/* 'Specific EOI' to master */
+	}
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+	return;
+
+spurious_8259A_irq:
+	/*
+	 * this is the slow path - should happen rarely.
+	 */
+	if (i8259A_irq_real(irq))
+		/*
+		 * oops, the IRQ _is_ in service according to the
+		 * 8259A - not spurious, go handle it.
+		 */
+		goto handle_real_irq;
+
+	{
+		static int spurious_irq_mask = 0;
+		/*
+		 * At this point we can be sure the IRQ is spurious,
+		 * lets ACK and report it. [once per IRQ]
+		 */
+		if (!(spurious_irq_mask & irqmask)) {
+			printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
+			spurious_irq_mask |= irqmask;
+		}
+		atomic_inc(&irq_err_count);
+		/*
+		 * Theoretically we do not have to handle this IRQ,
+		 * but in Linux this does not cause problems and is
+		 * simpler for us.
+		 */
+		goto handle_real_irq;
+	}
+}
+
+static int i8259A_resume(struct sys_device *dev)
+{
+	init_8259A(0);
+	return 0;
+}
+
+static struct sysdev_class i8259_sysdev_class = {
+	set_kset_name("i8259"),
+	.resume = i8259A_resume,
+};
+
+static struct sys_device device_i8259A = {
+	.id	= 0,
+	.cls	= &i8259_sysdev_class,
+};
+
+static int __init i8259A_init_sysfs(void)
+{
+	int error = sysdev_class_register(&i8259_sysdev_class);
+	if (!error)
+		error = sysdev_register(&device_i8259A);
+	return error;
+}
+
+device_initcall(i8259A_init_sysfs);
+
+void __init init_8259A(int auto_eoi)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259A_lock, flags);
+
+	outb(0xff, 0x21);	/* mask all of 8259A-1 */
+	outb(0xff, 0xA1);	/* mask all of 8259A-2 */
+
+	/*
+	 * outb_p - this has to work on a wide range of PC hardware.
+	 */
+	outb_p(0x11, 0x20);	/* ICW1: select 8259A-1 init */
+	outb_p(0x00, 0x21);	/* ICW2: 8259A-1 IR0-7 mapped to 0x00-0x07 */
+	outb_p(0x04, 0x21);	/* 8259A-1 (the master) has a slave on IR2 */
+	if (auto_eoi)
+		outb_p(0x03, 0x21);	/* master does Auto EOI */
+	else
+		outb_p(0x01, 0x21);	/* master expects normal EOI */
+
+	outb_p(0x11, 0xA0);	/* ICW1: select 8259A-2 init */
+	outb_p(0x08, 0xA1);	/* ICW2: 8259A-2 IR0-7 mapped to 0x08-0x0f */
+	outb_p(0x02, 0xA1);	/* 8259A-2 is a slave on master's IR2 */
+	outb_p(0x01, 0xA1);	/* (slave's support for AEOI in flat mode
+				    is to be investigated) */
+
+	if (auto_eoi)
+		/*
+		 * in AEOI mode we just have to mask the interrupt
+		 * when acking.
+		 */
+		i8259A_irq_type.ack = disable_8259A_irq;
+	else
+		i8259A_irq_type.ack = mask_and_ack_8259A;
+
+	udelay(100);		/* wait for 8259A to initialize */
+
+	outb(cached_21, 0x21);	/* restore master IRQ mask */
+	outb(cached_A1, 0xA1);	/* restore slave IRQ mask */
+
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+}
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+static struct irqaction irq2 = {
+	no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL
+};
+
+static struct resource pic1_io_resource = {
+	"pic1", 0x20, 0x3f, IORESOURCE_BUSY
+};
+
+static struct resource pic2_io_resource = {
+	"pic2", 0xa0, 0xbf, IORESOURCE_BUSY
+};
+
+/*
+ * On systems with i8259-style interrupt controllers we assume for
+ * driver compatibility reasons interrupts 0 - 15 to be the i8295
+ * interrupts even if the hardware uses a different interrupt numbering.
+ */
+void __init init_i8259_irqs (void)
+{
+	int i;
+
+	request_resource(&ioport_resource, &pic1_io_resource);
+	request_resource(&ioport_resource, &pic2_io_resource);
+
+	init_8259A(0);
+
+	for (i = 0; i < 16; i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = 0;
+		irq_desc[i].depth = 1;
+		irq_desc[i].handler = &i8259A_irq_type;
+	}
+
+	setup_irq(2, &irq2);
+}
diff --git a/arch/mips/kernel/init_task.c b/arch/mips/kernel/init_task.c
new file mode 100644
index 0000000..aeda7f5
--- /dev/null
+++ b/arch/mips/kernel/init_task.c
@@ -0,0 +1,42 @@
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init_task.h>
+#include <linux/fs.h>
+#include <linux/mqueue.h>
+
+#include <asm/thread_info.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+EXPORT_SYMBOL(init_mm);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by making sure
+ * the linker maps this in the .text segment right after head.S,
+ * and making head.S ensure the proper alignment.
+ *
+ * The things we do for performance..
+ */
+union thread_union init_thread_union
+	__attribute__((__section__(".data.init_task"),
+	               __aligned__(THREAD_SIZE))) =
+		{ INIT_THREAD_INFO(init_task) };
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
diff --git a/arch/mips/kernel/ioctl32.c b/arch/mips/kernel/ioctl32.c
new file mode 100644
index 0000000..519cd5d
--- /dev/null
+++ b/arch/mips/kernel/ioctl32.c
@@ -0,0 +1,58 @@
+/*
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ *
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Written by Ulf Carlsson (ulfc@engr.sgi.com)
+ * Copyright (C) 2000, 2004 Ralf Baechle
+ * Copyright (C) 2002, 2003  Maciej W. Rozycki
+ */
+#define INCLUDES
+#include "compat_ioctl.c"
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+#include <linux/syscalls.h>
+
+#ifdef CONFIG_SIBYTE_TBPROF
+#include <asm/sibyte/trace_prof.h>
+#endif
+
+#define A(__x) ((unsigned long)(__x))
+
+long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+#define CODE
+#include "compat_ioctl.c"
+
+typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
+                                                                                
+#define COMPATIBLE_IOCTL(cmd)		HANDLE_IOCTL((cmd),sys_ioctl)
+#define HANDLE_IOCTL(cmd,handler)	{ (cmd), (ioctl32_handler_t)(handler), NULL },
+#define IOCTL_TABLE_START \
+	struct ioctl_trans ioctl_start[] = {
+#define IOCTL_TABLE_END \
+	};
+
+IOCTL_TABLE_START
+
+#include <linux/compat_ioctl.h>
+#define DECLARES
+#include "compat_ioctl.c"
+
+#ifdef CONFIG_SIBYTE_TBPROF
+COMPATIBLE_IOCTL(SBPROF_ZBSTART)
+COMPATIBLE_IOCTL(SBPROF_ZBSTOP)
+COMPATIBLE_IOCTL(SBPROF_ZBWAITFULL)
+#endif /* CONFIG_SIBYTE_TBPROF */
+
+/*HANDLE_IOCTL(RTC_IRQP_READ, w_long)
+COMPATIBLE_IOCTL(RTC_IRQP_SET)
+HANDLE_IOCTL(RTC_EPOCH_READ, w_long)
+COMPATIBLE_IOCTL(RTC_EPOCH_SET)
+*/
+
+IOCTL_TABLE_END
+
+int ioctl_table_size = ARRAY_SIZE(ioctl_start);
diff --git a/arch/mips/kernel/irix5sys.S b/arch/mips/kernel/irix5sys.S
new file mode 100644
index 0000000..eeef891
--- /dev/null
+++ b/arch/mips/kernel/irix5sys.S
@@ -0,0 +1,1041 @@
+/*
+ * 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.
+ *
+ * 32-bit IRIX5 ABI system call table derived from original file 'irix5sys.h'
+ * created by David S. Miller.
+ *
+ * Copyright (C) 1996 - 2004 David S. Miller <dm@engr.sgi.com>
+ * Copyright (C) 2004 Steven J. Hill <sjhill@realitydiluted.com>
+ */
+#include <asm/asm.h>
+
+	/*
+	 * Key:
+	 *         V == Valid and should work as expected for most cases.
+	 *        HV == Half Valid, some things will work, some likely will not
+	 *        IV == InValid, certainly will not work at all yet
+	 *        ?V == ?'ably Valid, I have not done enough looking into it
+	 *        DC == Don't Care, a rats ass we couldn't give
+	 */
+
+	.macro	irix5syscalltable
+
+	sys	sys_syscall	0	/* 1000  sysindir()	       V*/
+	sys	sys_exit	1	/* 1001  exit()		       V*/
+	sys	sys_fork	0	/* 1002  fork()		       V*/
+	sys	sys_read	3	/* 1003  read()		       V*/
+	sys	sys_write	3	/* 1004  write()	       V*/
+	sys	sys_open	3	/* 1005  open()		       V*/
+	sys	sys_close	1	/* 1006  close()	       V*/
+	sys	irix_unimp	0	/* 1007  (XXX IRIX 4 wait)     V*/
+	sys	sys_creat	2	/* 1008  creat()	       V*/
+	sys	sys_link	2	/* 1009  link()		       V*/
+	sys	sys_unlink	1	/* 1010  unlink()	       V*/
+	sys	irix_exec	0	/* 1011  exec()		       V*/
+	sys	sys_chdir	1	/* 1012  chdir()	       V*/
+	sys	irix_gtime	0	/* 1013  time()		       V*/
+	sys	irix_unimp	0	/* 1014  (XXX IRIX 4 mknod)    V*/
+	sys	sys_chmod	2	/* 1015  chmod()	       V*/
+	sys	sys_chown	3	/* 1016  chown()	       V*/
+	sys	irix_brk	1	/* 1017  break()	       V*/
+	sys	irix_unimp	0	/* 1018  (XXX IRIX 4 stat)     V*/
+	sys	sys_lseek	3	/* 1019  lseek()     XXX64bit HV*/
+	sys	irix_getpid	0	/* 1020  getpid()	       V*/
+	sys	irix_mount	6	/* 1021  mount()	      IV*/
+	sys	sys_umount	1	/* 1022  umount()	       V*/
+	sys	sys_setuid	1	/* 1023  setuid()	       V*/
+	sys	irix_getuid	0	/* 1024  getuid()	       V*/
+	sys	irix_stime	1	/* 1025  stime()	       V*/
+	sys	irix_unimp	4	/* 1026  XXX ptrace()	      IV*/
+	sys	irix_alarm	1	/* 1027  alarm()	       V*/
+	sys	irix_unimp	0	/* 1028  (XXX IRIX 4 fstat)    V*/
+	sys	irix_pause	0	/* 1029  pause()	       V*/
+	sys	sys_utime	2	/* 1030  utime()	       V*/
+	sys	irix_unimp	0	/* 1031  nuthin'	       V*/
+	sys	irix_unimp	0	/* 1032  nobody home man...    V*/
+	sys	sys_access	2	/* 1033  access()	       V*/
+	sys	sys_nice	1	/* 1034  nice()		       V*/
+	sys	irix_statfs	2	/* 1035  statfs()	       V*/
+	sys	sys_sync	0	/* 1036  sync()		       V*/
+	sys	sys_kill	2	/* 1037  kill()		       V*/
+	sys	irix_fstatfs	2	/* 1038  fstatfs()	       V*/
+	sys	irix_setpgrp	1	/* 1039  setpgrp()	       V*/
+	sys	irix_syssgi	0	/* 1040  syssgi()	      HV*/
+	sys	sys_dup		1	/* 1041  dup()		       V*/
+	sys	sys_pipe	0	/* 1042  pipe()		       V*/
+	sys	irix_times	1	/* 1043  times()	       V*/
+	sys	irix_unimp	0	/* 1044  XXX profil()	      IV*/
+	sys	irix_unimp	0	/* 1045  XXX lock()	      IV*/
+	sys	sys_setgid	1	/* 1046  setgid()	       V*/
+	sys	irix_getgid	0	/* 1047  getgid()	       V*/
+	sys	irix_unimp	0	/* 1048  (XXX IRIX 4 ssig)     V*/
+	sys	irix_msgsys	6	/* 1049  sys_msgsys	       V*/
+	sys	sys_sysmips	4	/* 1050  sysmips()	      HV*/
+	sys	irix_unimp	0	/* 1051	 XXX sysacct()	      IV*/
+	sys	irix_shmsys	5	/* 1052  sys_shmsys	       V*/
+	sys	irix_semsys	0	/* 1053  sys_semsys	       V*/
+	sys	irix_ioctl	3	/* 1054  ioctl()	      HV*/
+	sys	irix_uadmin	0	/* 1055  XXX sys_uadmin()     HC*/
+	sys	irix_sysmp	0	/* 1056  sysmp()	      HV*/
+	sys	irix_utssys	4	/* 1057  sys_utssys()	      HV*/
+	sys	irix_unimp	0	/* 1058  nada enchilada	       V*/
+	sys	irix_exece	0	/* 1059  exece()	       V*/
+	sys	sys_umask	1	/* 1060  umask()	       V*/
+	sys	sys_chroot	1	/* 1061  chroot()	       V*/
+	sys	irix_fcntl	3	/* 1062  fcntl()	      ?V*/
+	sys	irix_ulimit	2	/* 1063  ulimit()	      HV*/
+	sys	irix_unimp	0	/* 1064  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1065  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1066  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1067  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1068  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1069  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1070  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1071  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1072  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1073  XXX AFS shit	      DC*/
+	sys	irix_unimp	0	/* 1074  nuttin'	       V*/
+	sys	irix_unimp	0	/* 1075  XXX sys_getrlimit64()IV*/
+	sys	irix_unimp	0	/* 1076  XXX sys_setrlimit64()IV*/
+	sys	sys_nanosleep	2	/* 1077  nanosleep()	       V*/
+	sys	irix_lseek64	5	/* 1078  lseek64()	      ?V*/
+	sys	sys_rmdir	1	/* 1079  rmdir()	       V*/
+	sys	sys_mkdir	2	/* 1080  mkdir()	       V*/
+	sys	sys_getdents	3	/* 1081  getdents()	       V*/
+	sys	irix_sginap	1	/* 1082  sys_sginap()	       V*/
+	sys	irix_sgikopt	3	/* 1083  sys_sgikopt()	      DC*/
+	sys	sys_sysfs	3	/* 1084  sysfs()	      ?V*/
+	sys	irix_unimp	0	/* 1085  XXX sys_getmsg()     DC*/
+	sys	irix_unimp	0	/* 1086  XXX sys_putmsg()     DC*/
+	sys	sys_poll	3	/* 1087  poll()	               V*/
+	sys	irix_sigreturn	0	/* 1088  sigreturn()	      ?V*/
+	sys	sys_accept	3	/* 1089  accept()	       V*/
+	sys	sys_bind	3	/* 1090  bind()		       V*/
+	sys	sys_connect	3	/* 1091  connect()	       V*/
+	sys	irix_gethostid	0	/* 1092  sys_gethostid()      ?V*/
+	sys	sys_getpeername	3	/* 1093  getpeername()	       V*/
+	sys	sys_getsockname	3	/* 1094  getsockname()	       V*/
+	sys	sys_getsockopt	5	/* 1095  getsockopt()	       V*/
+	sys	sys_listen	2	/* 1096  listen()	       V*/
+	sys	sys_recv	4	/* 1097  recv()		       V*/
+	sys	sys_recvfrom	6	/* 1098  recvfrom()	       V*/
+	sys	sys_recvmsg	3	/* 1099  recvmsg()	       V*/
+	sys	sys_select	5	/* 1100  select()	       V*/
+	sys	sys_send	4	/* 1101  send()		       V*/
+	sys	sys_sendmsg	3	/* 1102  sendmsg()	       V*/
+	sys	sys_sendto	6	/* 1103  sendto()	       V*/
+	sys	irix_sethostid	1	/* 1104  sys_sethostid()      ?V*/
+	sys	sys_setsockopt	5	/* 1105  setsockopt()	       V*/
+	sys	sys_shutdown	2	/* 1106  shutdown()	      ?V*/
+	sys	irix_socket	3	/* 1107  socket()	       V*/
+	sys	sys_gethostname	2	/* 1108  sys_gethostname()    ?V*/
+	sys	sys_sethostname	2	/* 1109  sethostname()	      ?V*/
+	sys	irix_getdomainname 2	/* 1110  sys_getdomainname()  ?V*/
+	sys	sys_setdomainname 2	/* 1111  setdomainname()      ?V*/
+	sys	sys_truncate	2	/* 1112  truncate()	       V*/
+	sys	sys_ftruncate	2	/* 1113  ftruncate()	       V*/
+	sys	sys_rename	2	/* 1114  rename()	       V*/
+	sys	sys_symlink	2	/* 1115  symlink()	       V*/
+	sys	sys_readlink	3	/* 1116  readlink()	       V*/
+	sys	irix_unimp	0	/* 1117  XXX IRIX 4 lstat()   DC*/
+	sys	irix_unimp	0	/* 1118  nothin'	       V*/
+	sys	irix_unimp	0	/* 1119  XXX nfs_svc()	      DC*/
+	sys	irix_unimp	0	/* 1120  XXX nfs_getfh()      DC*/
+	sys	irix_unimp	0	/* 1121  XXX async_daemon()   DC*/
+	sys	irix_unimp	0	/* 1122  XXX exportfs()	      DC*/
+	sys	sys_setregid	2	/* 1123  setregid()	       V*/
+	sys	sys_setreuid	2	/* 1124  setreuid()	       V*/
+	sys	sys_getitimer	2	/* 1125  getitimer()	       V*/
+	sys	sys_setitimer	3	/* 1126  setitimer()	       V*/
+	sys	irix_unimp	1	/* 1127  XXX adjtime() 	      IV*/
+	sys	irix_gettimeofday 1	/* 1128  gettimeofday()	       V*/
+	sys	irix_unimp	0	/* 1129  XXX sproc()	      IV*/
+	sys	irix_prctl	0	/* 1130  prctl()	      HV*/
+	sys	irix_unimp	0	/* 1131  XXX procblk()	      IV*/
+	sys	irix_unimp	0	/* 1132  XXX sprocsp()	      IV*/
+	sys	irix_unimp	0	/* 1133  XXX sgigsc()	      IV*/
+	sys	irix_mmap32	6	/* 1134  mmap()	   XXXflags?  ?V*/
+	sys	sys_munmap	2	/* 1135  munmap()	       V*/
+	sys	sys_mprotect	3	/* 1136  mprotect()	       V*/
+	sys	sys_msync	4	/* 1137  msync()	       V*/
+	sys	irix_madvise	3	/* 1138  madvise()	      DC*/
+	sys	irix_pagelock	3	/* 1139  pagelock()	      IV*/
+	sys	irix_getpagesize 0	/* 1140  getpagesize()         V*/
+	sys	irix_quotactl	0	/* 1141  quotactl()	       V*/
+	sys	irix_unimp	0	/* 1142  nobody home man       V*/
+	sys	sys_getpgid	1	/* 1143  BSD getpgrp()	       V*/
+	sys	irix_BSDsetpgrp 2	/* 1143  BSD setpgrp()	       V*/
+	sys	sys_vhangup	0	/* 1144  vhangup()	       V*/
+	sys	sys_fsync	1	/* 1145  fsync()	       V*/
+	sys	sys_fchdir	1	/* 1146  fchdir()	       V*/
+	sys	sys_getrlimit	2	/* 1147  getrlimit()	      ?V*/
+	sys	sys_setrlimit	2	/* 1148  setrlimit()	      ?V*/
+	sys	sys_cacheflush	3	/* 1150  cacheflush()	      HV*/
+	sys	sys_cachectl	3	/* 1151  cachectl()	      HV*/
+	sys	sys_fchown	3	/* 1152  fchown()	      ?V*/
+	sys	sys_fchmod	2	/* 1153  fchmod()	      ?V*/
+	sys	irix_unimp	0	/* 1154  XXX IRIX 4 wait3()    V*/
+	sys	sys_socketpair	4	/* 1155  socketpair()	       V*/
+	sys	irix_systeminfo	3	/* 1156  systeminfo()	      IV*/
+	sys	irix_uname	1	/* 1157  uname()	      IV*/
+	sys	irix_xstat	3	/* 1158  xstat()	       V*/
+	sys	irix_lxstat	3	/* 1159  lxstat()	       V*/
+	sys	irix_fxstat	3	/* 1160  fxstat()	       V*/
+	sys	irix_xmknod	0	/* 1161  xmknod()	      ?V*/
+	sys	irix_sigaction	4	/* 1162  sigaction()	      ?V*/
+	sys	irix_sigpending	1	/* 1163  sigpending()	      ?V*/
+	sys	irix_sigprocmask 3	/* 1164  sigprocmask()	      ?V*/
+	sys	irix_sigsuspend	0	/* 1165  sigsuspend()	      ?V*/
+	sys	irix_sigpoll_sys 3	/* 1166  sigpoll_sys()	      IV*/
+	sys	irix_swapctl	2	/* 1167  swapctl()	      IV*/
+	sys	irix_getcontext	0	/* 1168  getcontext()	      HV*/
+	sys	irix_setcontext	0	/* 1169  setcontext()	      HV*/
+	sys	irix_waitsys	5	/* 1170  waitsys()	      IV*/
+	sys	irix_sigstack	2	/* 1171  sigstack()	      HV*/
+	sys	irix_sigaltstack 2	/* 1172  sigaltstack()	      HV*/
+	sys	irix_sigsendset	2	/* 1173  sigsendset()	      IV*/
+	sys	irix_statvfs	2	/* 1174  statvfs()	       V*/
+	sys	irix_fstatvfs	2	/* 1175  fstatvfs()	       V*/
+	sys	irix_unimp	0	/* 1176  XXX getpmsg()	      DC*/
+	sys	irix_unimp	0	/* 1177  XXX putpmsg()	      DC*/
+	sys	sys_lchown	3	/* 1178  lchown()	       V*/
+	sys	irix_priocntl	0	/* 1179  priocntl()	      DC*/
+	sys	irix_sigqueue	4	/* 1180  sigqueue()	      IV*/
+	sys	sys_readv	3	/* 1181  readv()	       V*/
+	sys	sys_writev	3	/* 1182  writev()	       V*/
+	sys	irix_truncate64 4	/* 1183  truncate64() XX32bit HV*/
+	sys	irix_ftruncate64 4	/* 1184  ftruncate64()XX32bit HV*/
+	sys	irix_mmap64	0	/* 1185  mmap64()     XX32bit HV*/
+	sys	irix_dmi	0	/* 1186  dmi()		      DC*/
+	sys	irix_pread	6	/* 1187  pread()	      IV*/
+	sys	irix_pwrite	6	/* 1188  pwrite()	      IV*/
+	sys	sys_fsync	1	/* 1189  fdatasync()  XXPOSIX HV*/
+	sys	irix_sgifastpath 7	/* 1190  sgifastpath() WHEEE  IV*/
+	sys	irix_unimp	0	/* 1191  XXX attr_get()	      DC*/
+	sys	irix_unimp	0	/* 1192  XXX attr_getf()      DC*/
+	sys	irix_unimp	0	/* 1193  XXX attr_set()	      DC*/
+	sys	irix_unimp	0	/* 1194  XXX attr_setf()      DC*/
+	sys	irix_unimp	0	/* 1195  XXX attr_remove()    DC*/
+	sys	irix_unimp	0	/* 1196  XXX attr_removef()   DC*/
+	sys	irix_unimp	0	/* 1197  XXX attr_list()      DC*/
+	sys	irix_unimp	0	/* 1198  XXX attr_listf()     DC*/
+	sys	irix_unimp	0	/* 1199  XXX attr_multi()     DC*/
+	sys	irix_unimp	0	/* 1200  XXX attr_multif()    DC*/
+	sys	irix_statvfs64	2	/* 1201  statvfs64()	       V*/
+	sys	irix_fstatvfs64	2	/* 1202  fstatvfs64()	       V*/
+	sys	irix_getmountid	2	/* 1203  getmountid()XXXfsids HV*/
+	sys	irix_nsproc	5	/* 1204  nsproc()	      IV*/
+	sys	irix_getdents64 3	/* 1205  getdents64()	      HV*/
+	sys	irix_unimp	0	/* 1206  XXX DFS garbage      DC*/
+	sys	irix_ngetdents	4	/* 1207  ngetdents() XXXeop   HV*/
+	sys	irix_ngetdents64 4	/* 1208  ngetdents64() XXXeop HV*/
+	sys	irix_unimp	0	/* 1209  nothin'	       V*/
+	sys	irix_unimp	0	/* 1210  XXX pidsprocsp()	*/
+	sys	irix_unimp	0	/* 1211  XXX rexec()		*/
+	sys	irix_unimp	0	/* 1212  XXX timer_create()	*/
+	sys	irix_unimp	0	/* 1213  XXX timer_delete()	*/
+	sys	irix_unimp	0	/* 1214  XXX timer_settime()	*/
+	sys	irix_unimp	0	/* 1215  XXX timer_gettime()	*/
+	sys	irix_unimp	0	/* 1216  XXX timer_setoverrun()	*/
+	sys	sys_sched_rr_get_interval 2		/* 1217  sched_rr_get_interval()V*/
+	sys	sys_sched_yield	0	/* 1218  sched_yield()	       V*/
+	sys	sys_sched_getscheduler 1 /* 1219  sched_getscheduler()  V*/
+	sys	sys_sched_setscheduler 3 /* 1220  sched_setscheduler()  V*/
+	sys	sys_sched_getparam 2	/* 1221  sched_getparam()      V*/
+	sys	sys_sched_setparam 2	/* 1222  sched_setparam()      V*/
+	sys	irix_unimp	0	/* 1223  XXX usync_cntl()	*/
+	sys	irix_unimp	0	/* 1224  XXX psema_cntl()	*/
+	sys	irix_unimp	0	/* 1225  XXX restartreturn()	*/
+
+	/* Just to pad things out nicely. */
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+	sys	irix_unimp	0
+
+	.endm
+
+	/*
+	 * Pre-compute the number of _instruction_ bytes needed to load
+	 * or store the arguments 6-8. Negative values are ignored.
+	 */
+	.macro  sys function, nargs
+	PTR	\function
+	LONG	(\nargs << 2) - (5 << 2)
+	.endm
+
+	.align	4
+EXPORT(sys_call_table_irix5)
+	irix5syscalltable
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
new file mode 100644
index 0000000..4af20cd
--- /dev/null
+++ b/arch/mips/kernel/irixelf.c
@@ -0,0 +1,1326 @@
+/*
+ * 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.
+ *
+ * irixelf.c: Code to load IRIX ELF executables conforming to the MIPS ABI.
+ *            Based off of work by Eric Youngdale.
+ *
+ * Copyright (C) 1993 - 1994 Eric Youngdale <ericy@cais.com>
+ * Copyright (C) 1996 - 2004 David S. Miller <dm@engr.sgi.com>
+ * Copyright (C) 2004 Steven J. Hill <sjhill@realitydiluted.com>
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/binfmts.h>
+#include <linux/string.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/shm.h>
+#include <linux/personality.h>
+#include <linux/elfcore.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/mipsregs.h>
+#include <asm/prctl.h>
+
+#define DLINFO_ITEMS 12
+
+#include <linux/elf.h>
+
+#undef DEBUG_ELF
+
+static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs);
+static int load_irix_library(struct file *);
+static int irix_core_dump(long signr, struct pt_regs * regs,
+                          struct file *file);
+
+static struct linux_binfmt irix_format = {
+	NULL, THIS_MODULE, load_irix_binary, load_irix_library,
+	irix_core_dump, PAGE_SIZE
+};
+
+#ifndef elf_addr_t
+#define elf_addr_t unsigned long
+#endif
+
+#ifdef DEBUG_ELF
+/* Debugging routines. */
+static char *get_elf_p_type(Elf32_Word p_type)
+{
+	int i = (int) p_type;
+
+	switch(i) {
+	case PT_NULL: return("PT_NULL"); break;
+	case PT_LOAD: return("PT_LOAD"); break;
+	case PT_DYNAMIC: return("PT_DYNAMIC"); break;
+	case PT_INTERP: return("PT_INTERP"); break;
+	case PT_NOTE: return("PT_NOTE"); break;
+	case PT_SHLIB: return("PT_SHLIB"); break;
+	case PT_PHDR: return("PT_PHDR"); break;
+	case PT_LOPROC: return("PT_LOPROC/REGINFO"); break;
+	case PT_HIPROC: return("PT_HIPROC"); break;
+	default: return("PT_BOGUS"); break;
+	}
+}
+
+static void print_elfhdr(struct elfhdr *ehp)
+{
+	int i;
+
+	printk("ELFHDR: e_ident<");
+	for(i = 0; i < (EI_NIDENT - 1); i++) printk("%x ", ehp->e_ident[i]);
+	printk("%x>\n", ehp->e_ident[i]);
+	printk("        e_type[%04x] e_machine[%04x] e_version[%08lx]\n",
+	       (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine,
+	       (unsigned long) ehp->e_version);
+	printk("        e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] "
+	       "e_flags[%08lx]\n",
+	       (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff,
+	       (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags);
+	printk("        e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n",
+	       (unsigned short) ehp->e_ehsize, (unsigned short) ehp->e_phentsize,
+	       (unsigned short) ehp->e_phnum);
+	printk("        e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n",
+	       (unsigned short) ehp->e_shentsize, (unsigned short) ehp->e_shnum,
+	       (unsigned short) ehp->e_shstrndx);
+}
+
+static void print_phdr(int i, struct elf_phdr *ep)
+{
+	printk("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] "
+	       "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type),
+	       (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr,
+	       (unsigned long) ep->p_paddr);
+	printk("         p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] "
+	       "p_align[%08lx]\n", (unsigned long) ep->p_filesz,
+	       (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags,
+	       (unsigned long) ep->p_align);
+}
+
+static void dump_phdrs(struct elf_phdr *ep, int pnum)
+{
+	int i;
+
+	for(i = 0; i < pnum; i++, ep++) {
+		if((ep->p_type == PT_LOAD) ||
+		   (ep->p_type == PT_INTERP) ||
+		   (ep->p_type == PT_PHDR))
+			print_phdr(i, ep);
+	}
+}
+#endif /* (DEBUG_ELF) */
+
+static void set_brk(unsigned long start, unsigned long end)
+{
+	start = PAGE_ALIGN(start);
+	end = PAGE_ALIGN(end);
+	if (end <= start)
+		return;
+	down_write(&current->mm->mmap_sem);
+	do_brk(start, end - start);
+	up_write(&current->mm->mmap_sem);
+}
+
+
+/* We need to explicitly zero any fractional pages
+ * after the data section (i.e. bss).  This would
+ * contain the junk from the file that should not
+ * be in memory.
+ */
+static void padzero(unsigned long elf_bss)
+{
+	unsigned long nbyte;
+
+	nbyte = elf_bss & (PAGE_SIZE-1);
+	if (nbyte) {
+		nbyte = PAGE_SIZE - nbyte;
+		clear_user((void *) elf_bss, nbyte);
+	}
+}
+
+unsigned long * create_irix_tables(char * p, int argc, int envc,
+				   struct elfhdr * exec, unsigned int load_addr,
+				   unsigned int interp_load_addr,
+				   struct pt_regs *regs, struct elf_phdr *ephdr)
+{
+	elf_addr_t *argv;
+	elf_addr_t *envp;
+	elf_addr_t *sp, *csp;
+
+#ifdef DEBUG_ELF
+	printk("create_irix_tables: p[%p] argc[%d] envc[%d] "
+	       "load_addr[%08x] interp_load_addr[%08x]\n",
+	       p, argc, envc, load_addr, interp_load_addr);
+#endif
+	sp = (elf_addr_t *) (~15UL & (unsigned long) p);
+	csp = sp;
+	csp -= exec ? DLINFO_ITEMS*2 : 2;
+	csp -= envc+1;
+	csp -= argc+1;
+	csp -= 1;		/* argc itself */
+	if ((unsigned long)csp & 15UL) {
+		sp -= (16UL - ((unsigned long)csp & 15UL)) / sizeof(*sp);
+	}
+
+	/*
+	 * Put the ELF interpreter info on the stack
+	 */
+#define NEW_AUX_ENT(nr, id, val) \
+	  __put_user ((id), sp+(nr*2)); \
+	  __put_user ((val), sp+(nr*2+1)); \
+
+	sp -= 2;
+	NEW_AUX_ENT(0, AT_NULL, 0);
+
+	if(exec) {
+		sp -= 11*2;
+
+		NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
+		NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
+		NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
+		NEW_AUX_ENT (3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
+		NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
+		NEW_AUX_ENT (5, AT_FLAGS, 0);
+		NEW_AUX_ENT (6, AT_ENTRY, (elf_addr_t) exec->e_entry);
+		NEW_AUX_ENT (7, AT_UID, (elf_addr_t) current->uid);
+		NEW_AUX_ENT (8, AT_EUID, (elf_addr_t) current->euid);
+		NEW_AUX_ENT (9, AT_GID, (elf_addr_t) current->gid);
+		NEW_AUX_ENT (10, AT_EGID, (elf_addr_t) current->egid);
+	}
+#undef NEW_AUX_ENT
+
+	sp -= envc+1;
+	envp = sp;
+	sp -= argc+1;
+	argv = sp;
+
+	__put_user((elf_addr_t)argc,--sp);
+	current->mm->arg_start = (unsigned long) p;
+	while (argc-->0) {
+		__put_user((unsigned long)p,argv++);
+		p += strlen_user(p);
+	}
+	__put_user((unsigned long) NULL, argv);
+	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
+	while (envc-->0) {
+		__put_user((unsigned long)p,envp++);
+		p += strlen_user(p);
+	}
+	__put_user((unsigned long) NULL, envp);
+	current->mm->env_end = (unsigned long) p;
+	return sp;
+}
+
+
+/* This is much more generalized than the library routine read function,
+ * so we keep this separate.  Technically the library read function
+ * is only provided so that we can read a.out libraries that have
+ * an ELF header.
+ */
+static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
+				     struct file * interpreter,
+				     unsigned int *interp_load_addr)
+{
+	struct elf_phdr *elf_phdata  =  NULL;
+	struct elf_phdr *eppnt;
+	unsigned int len;
+	unsigned int load_addr;
+	int elf_bss;
+	int retval;
+	unsigned int last_bss;
+	int error;
+	int i;
+	unsigned int k;
+
+	elf_bss = 0;
+	last_bss = 0;
+	error = load_addr = 0;
+
+#ifdef DEBUG_ELF
+	print_elfhdr(interp_elf_ex);
+#endif
+
+	/* First of all, some simple consistency checks */
+	if ((interp_elf_ex->e_type != ET_EXEC &&
+	     interp_elf_ex->e_type != ET_DYN) ||
+	     !irix_elf_check_arch(interp_elf_ex) ||
+	     !interpreter->f_op->mmap) {
+		printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type);
+		return 0xffffffff;
+	}
+
+	/* Now read in all of the header information */
+	if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) {
+	    printk("IRIX interp header bigger than a page (%d)\n",
+		   (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum));
+	    return 0xffffffff;
+	}
+
+	elf_phdata = kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
+			     GFP_KERNEL);
+
+	if(!elf_phdata) {
+          printk("Cannot kmalloc phdata for IRIX interp.\n");
+	  return 0xffffffff;
+	}
+
+	/* If the size of this structure has changed, then punt, since
+	 * we will be doing the wrong thing.
+	 */
+	if(interp_elf_ex->e_phentsize != 32) {
+		printk("IRIX interp e_phentsize == %d != 32 ",
+		       interp_elf_ex->e_phentsize);
+		kfree(elf_phdata);
+		return 0xffffffff;
+	}
+
+	retval = kernel_read(interpreter, interp_elf_ex->e_phoff,
+			   (char *) elf_phdata,
+			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+
+#ifdef DEBUG_ELF
+	dump_phdrs(elf_phdata, interp_elf_ex->e_phnum);
+#endif
+
+	eppnt = elf_phdata;
+	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
+	  if(eppnt->p_type == PT_LOAD) {
+	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+	    int elf_prot = 0;
+	    unsigned long vaddr = 0;
+	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
+	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+	    elf_type |= MAP_FIXED;
+	    vaddr = eppnt->p_vaddr;
+
+#ifdef DEBUG_ELF
+	    printk("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ",
+		   interpreter, vaddr,
+		   (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)),
+		   (unsigned long) elf_prot, (unsigned long) elf_type,
+		   (unsigned long) (eppnt->p_offset & 0xfffff000));
+#endif
+	    down_write(&current->mm->mmap_sem);
+	    error = do_mmap(interpreter, vaddr,
+			    eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
+			    elf_prot, elf_type,
+			    eppnt->p_offset & 0xfffff000);
+	    up_write(&current->mm->mmap_sem);
+
+	    if(error < 0 && error > -1024) {
+		    printk("Aieee IRIX interp mmap error=%d\n", error);
+		    break;  /* Real error */
+	    }
+#ifdef DEBUG_ELF
+	    printk("error=%08lx ", (unsigned long) error);
+#endif
+	    if(!load_addr && interp_elf_ex->e_type == ET_DYN) {
+	      load_addr = error;
+#ifdef DEBUG_ELF
+              printk("load_addr = error ");
+#endif
+	    }
+
+	    /* Find the end of the file  mapping for this phdr, and keep
+	     * track of the largest address we see for this.
+	     */
+	    k = eppnt->p_vaddr + eppnt->p_filesz;
+	    if(k > elf_bss) elf_bss = k;
+
+	    /* Do the same thing for the memory mapping - between
+	     * elf_bss and last_bss is the bss section.
+	     */
+	    k = eppnt->p_memsz + eppnt->p_vaddr;
+	    if(k > last_bss) last_bss = k;
+#ifdef DEBUG_ELF
+	    printk("\n");
+#endif
+	  }
+	}
+
+	/* Now use mmap to map the library into memory. */
+	if(error < 0 && error > -1024) {
+#ifdef DEBUG_ELF
+		printk("got error %d\n", error);
+#endif
+		kfree(elf_phdata);
+		return 0xffffffff;
+	}
+
+	/* Now fill out the bss section.  First pad the last page up
+	 * to the page boundary, and then perform a mmap to make sure
+	 * that there are zero-mapped pages up to and including the
+	 * last bss page.
+	 */
+#ifdef DEBUG_ELF
+	printk("padzero(%08lx) ", (unsigned long) (elf_bss));
+#endif
+	padzero(elf_bss);
+	len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */
+
+#ifdef DEBUG_ELF
+	printk("last_bss[%08lx] len[%08lx]\n", (unsigned long) last_bss,
+	       (unsigned long) len);
+#endif
+
+	/* Map the last of the bss segment */
+	if (last_bss > len) {
+		down_write(&current->mm->mmap_sem);
+		do_brk(len, (last_bss - len));
+		up_write(&current->mm->mmap_sem);
+	}
+	kfree(elf_phdata);
+
+	*interp_load_addr = load_addr;
+	return ((unsigned int) interp_elf_ex->e_entry);
+}
+
+/* Check sanity of IRIX elf executable header. */
+static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
+{
+	if (memcmp(ehp->e_ident, ELFMAG, SELFMAG) != 0)
+		return -ENOEXEC;
+
+	/* First of all, some simple consistency checks */
+	if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
+	    !irix_elf_check_arch(ehp) || !bprm->file->f_op->mmap) {
+		return -ENOEXEC;
+	}
+
+	/* Only support MIPS ARCH2 or greater IRIX binaries for now. */
+	if(!(ehp->e_flags & EF_MIPS_ARCH) && !(ehp->e_flags & 0x04)) {
+		return -ENOEXEC;
+	}
+
+	/* XXX Don't support N32 or 64bit binaries yet because they can
+	 * XXX and do execute 64 bit instructions and expect all registers
+	 * XXX to be 64 bit as well.  We need to make the kernel save
+	 * XXX all registers as 64bits on cpu's capable of this at
+	 * XXX exception time plus frob the XTLB exception vector.
+	 */
+	if((ehp->e_flags & 0x20)) {
+		return -ENOEXEC;
+	}
+
+	return 0; /* It's ok. */
+}
+
+#define IRIX_INTERP_PREFIX "/usr/gnemul/irix"
+
+/* Look for an IRIX ELF interpreter. */
+static inline int look_for_irix_interpreter(char **name,
+					    struct file **interpreter,
+					    struct elfhdr *interp_elf_ex,
+					    struct elf_phdr *epp,
+					    struct linux_binprm *bprm, int pnum)
+{
+	int i;
+	int retval = -EINVAL;
+	struct file *file = NULL;
+
+	*name = NULL;
+	for(i = 0; i < pnum; i++, epp++) {
+		if (epp->p_type != PT_INTERP)
+			continue;
+
+		/* It is illegal to have two interpreters for one executable. */
+		if (*name != NULL)
+			goto out;
+
+		*name = kmalloc((epp->p_filesz + strlen(IRIX_INTERP_PREFIX)),
+				GFP_KERNEL);
+		if (!*name)
+			return -ENOMEM;
+
+		strcpy(*name, IRIX_INTERP_PREFIX);
+		retval = kernel_read(bprm->file, epp->p_offset, (*name + 16),
+		                     epp->p_filesz);
+		if (retval < 0)
+			goto out;
+
+		file = open_exec(*name);
+		if (IS_ERR(file)) {
+			retval = PTR_ERR(file);
+			goto out;
+		}
+		retval = kernel_read(file, 0, bprm->buf, 128);
+		if (retval < 0)
+			goto dput_and_out;
+
+		*interp_elf_ex = *(struct elfhdr *) bprm->buf;
+	}
+	*interpreter = file;
+	return 0;
+
+dput_and_out:
+	fput(file);
+out:
+	kfree(*name);
+	return retval;
+}
+
+static inline int verify_irix_interpreter(struct elfhdr *ihp)
+{
+	if (memcmp(ihp->e_ident, ELFMAG, SELFMAG) != 0)
+		return -ELIBBAD;
+	return 0;
+}
+
+#define EXEC_MAP_FLAGS (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE)
+
+static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnum,
+				  unsigned int *estack, unsigned int *laddr,
+				  unsigned int *scode, unsigned int *ebss,
+				  unsigned int *ecode, unsigned int *edata,
+				  unsigned int *ebrk)
+{
+	unsigned int tmp;
+	int i, prot;
+
+	for(i = 0; i < pnum; i++, epp++) {
+		if(epp->p_type != PT_LOAD)
+			continue;
+
+		/* Map it. */
+		prot  = (epp->p_flags & PF_R) ? PROT_READ : 0;
+		prot |= (epp->p_flags & PF_W) ? PROT_WRITE : 0;
+		prot |= (epp->p_flags & PF_X) ? PROT_EXEC : 0;
+	        down_write(&current->mm->mmap_sem);
+		(void) do_mmap(fp, (epp->p_vaddr & 0xfffff000),
+			       (epp->p_filesz + (epp->p_vaddr & 0xfff)),
+			       prot, EXEC_MAP_FLAGS,
+			       (epp->p_offset & 0xfffff000));
+	        up_write(&current->mm->mmap_sem);
+
+		/* Fixup location tracking vars. */
+		if((epp->p_vaddr & 0xfffff000) < *estack)
+			*estack = (epp->p_vaddr & 0xfffff000);
+		if(!*laddr)
+			*laddr = epp->p_vaddr - epp->p_offset;
+		if(epp->p_vaddr < *scode)
+			*scode = epp->p_vaddr;
+
+		tmp = epp->p_vaddr + epp->p_filesz;
+		if(tmp > *ebss)
+			*ebss = tmp;
+		if((epp->p_flags & PF_X) && *ecode < tmp)
+			*ecode = tmp;
+		if(*edata < tmp)
+			*edata = tmp;
+
+		tmp = epp->p_vaddr + epp->p_memsz;
+		if(tmp > *ebrk)
+			*ebrk = tmp;
+	}
+
+}
+
+static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp,
+				  struct file *interp, unsigned int *iladdr,
+				  int pnum, mm_segment_t old_fs,
+				  unsigned int *eentry)
+{
+	int i;
+
+	*eentry = 0xffffffff;
+	for(i = 0; i < pnum; i++, epp++) {
+		if(epp->p_type != PT_INTERP)
+			continue;
+
+		/* We should have fielded this error elsewhere... */
+		if(*eentry != 0xffffffff)
+			return -1;
+
+		set_fs(old_fs);
+		*eentry = load_irix_interp(ihp, interp, iladdr);
+		old_fs = get_fs();
+		set_fs(get_ds());
+
+		fput(interp);
+
+		if (*eentry == 0xffffffff)
+			return -1;
+	}
+	return 0;
+}
+
+/*
+ * IRIX maps a page at 0x200000 that holds information about the
+ * process and the system, here we map the page and fill the
+ * structure
+ */
+void irix_map_prda_page (void)
+{
+	unsigned long v;
+	struct prda *pp;
+
+	down_write(&current->mm->mmap_sem);
+	v =  do_brk (PRDA_ADDRESS, PAGE_SIZE);
+	up_write(&current->mm->mmap_sem);
+
+	if (v < 0)
+		return;
+
+	pp = (struct prda *) v;
+	pp->prda_sys.t_pid  = current->pid;
+	pp->prda_sys.t_prid = read_c0_prid();
+	pp->prda_sys.t_rpid = current->pid;
+
+	/* We leave the rest set to zero */
+}
+
+
+
+/* These are the functions used to load ELF style executables and shared
+ * libraries.  There is no binary dependent code anywhere else.
+ */
+static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+	struct elfhdr elf_ex, interp_elf_ex;
+	struct file *interpreter;
+	struct elf_phdr *elf_phdata, *elf_ihdr, *elf_ephdr;
+	unsigned int load_addr, elf_bss, elf_brk;
+	unsigned int elf_entry, interp_load_addr = 0;
+	unsigned int start_code, end_code, end_data, elf_stack;
+	int retval, has_interp, has_ephdr, size, i;
+	char *elf_interpreter;
+	mm_segment_t old_fs;
+
+	load_addr = 0;
+	has_interp = has_ephdr = 0;
+	elf_ihdr = elf_ephdr = 0;
+	elf_ex = *((struct elfhdr *) bprm->buf);
+	retval = -ENOEXEC;
+
+	if (verify_binary(&elf_ex, bprm))
+		goto out;
+
+#ifdef DEBUG_ELF
+	print_elfhdr(&elf_ex);
+#endif
+
+	/* Now read in all of the header information */
+	size = elf_ex.e_phentsize * elf_ex.e_phnum;
+	if (size > 65536)
+		goto out;
+	elf_phdata = kmalloc(size, GFP_KERNEL);
+	if (elf_phdata == NULL) {
+		retval = -ENOMEM;
+		goto out;
+	}
+
+	retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *)elf_phdata, size);
+
+	if (retval < 0)
+		goto out_free_ph;
+
+#ifdef DEBUG_ELF
+	dump_phdrs(elf_phdata, elf_ex.e_phnum);
+#endif
+
+	/* Set some things for later. */
+	for(i = 0; i < elf_ex.e_phnum; i++) {
+		switch(elf_phdata[i].p_type) {
+		case PT_INTERP:
+			has_interp = 1;
+			elf_ihdr = &elf_phdata[i];
+			break;
+		case PT_PHDR:
+			has_ephdr = 1;
+			elf_ephdr = &elf_phdata[i];
+			break;
+		};
+	}
+#ifdef DEBUG_ELF
+	printk("\n");
+#endif
+
+	elf_bss = 0;
+	elf_brk = 0;
+
+	elf_stack = 0xffffffff;
+	elf_interpreter = NULL;
+	start_code = 0xffffffff;
+	end_code = 0;
+	end_data = 0;
+
+	retval = look_for_irix_interpreter(&elf_interpreter,
+	                                   &interpreter,
+					   &interp_elf_ex, elf_phdata, bprm,
+					   elf_ex.e_phnum);
+	if (retval)
+		goto out_free_file;
+
+	if (elf_interpreter) {
+		retval = verify_irix_interpreter(&interp_elf_ex);
+		if(retval)
+			goto out_free_interp;
+	}
+
+	/* OK, we are done with that, now set up the arg stuff,
+	 * and then start this sucker up.
+	 */
+	retval = -E2BIG;
+	if (!bprm->sh_bang && !bprm->p)
+		goto out_free_interp;
+
+	/* Flush all traces of the currently running executable */
+	retval = flush_old_exec(bprm);
+	if (retval)
+		goto out_free_dentry;
+
+	/* OK, This is the point of no return */
+	current->mm->end_data = 0;
+	current->mm->end_code = 0;
+	current->mm->mmap = NULL;
+	current->flags &= ~PF_FORKNOEXEC;
+	elf_entry = (unsigned int) elf_ex.e_entry;
+
+	/* Do this so that we can load the interpreter, if need be.  We will
+	 * change some of these later.
+	 */
+	set_mm_counter(current->mm, rss, 0);
+	setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
+	current->mm->start_stack = bprm->p;
+
+	/* At this point, we assume that the image should be loaded at
+	 * fixed address, not at a variable address.
+	 */
+	old_fs = get_fs();
+	set_fs(get_ds());
+
+	map_executable(bprm->file, elf_phdata, elf_ex.e_phnum, &elf_stack,
+	               &load_addr, &start_code, &elf_bss, &end_code,
+	               &end_data, &elf_brk);
+
+	if(elf_interpreter) {
+		retval = map_interpreter(elf_phdata, &interp_elf_ex,
+					 interpreter, &interp_load_addr,
+					 elf_ex.e_phnum, old_fs, &elf_entry);
+		kfree(elf_interpreter);
+		if(retval) {
+			set_fs(old_fs);
+			printk("Unable to load IRIX ELF interpreter\n");
+			send_sig(SIGSEGV, current, 0);
+			retval = 0;
+			goto out_free_file;
+		}
+	}
+
+	set_fs(old_fs);
+
+	kfree(elf_phdata);
+	set_personality(PER_IRIX32);
+	set_binfmt(&irix_format);
+	compute_creds(bprm);
+	current->flags &= ~PF_FORKNOEXEC;
+	bprm->p = (unsigned long)
+	  create_irix_tables((char *)bprm->p, bprm->argc, bprm->envc,
+			(elf_interpreter ? &elf_ex : NULL),
+			load_addr, interp_load_addr, regs, elf_ephdr);
+	current->mm->start_brk = current->mm->brk = elf_brk;
+	current->mm->end_code = end_code;
+	current->mm->start_code = start_code;
+	current->mm->end_data = end_data;
+	current->mm->start_stack = bprm->p;
+
+	/* Calling set_brk effectively mmaps the pages that we need for the
+	 * bss and break sections.
+	 */
+	set_brk(elf_bss, elf_brk);
+
+	/*
+	 * IRIX maps a page at 0x200000 which holds some system
+	 * information.  Programs depend on this.
+	 */
+	irix_map_prda_page ();
+
+	padzero(elf_bss);
+
+#ifdef DEBUG_ELF
+	printk("(start_brk) %lx\n" , (long) current->mm->start_brk);
+	printk("(end_code) %lx\n" , (long) current->mm->end_code);
+	printk("(start_code) %lx\n" , (long) current->mm->start_code);
+	printk("(end_data) %lx\n" , (long) current->mm->end_data);
+	printk("(start_stack) %lx\n" , (long) current->mm->start_stack);
+	printk("(brk) %lx\n" , (long) current->mm->brk);
+#endif
+
+#if 0 /* XXX No fucking way dude... */
+	/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
+	 * and some applications "depend" upon this behavior.
+	 * Since we do not have the power to recompile these, we
+	 * emulate the SVr4 behavior.  Sigh.
+	 */
+	down_write(&current->mm->mmap_sem);
+	(void) do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
+		       MAP_FIXED | MAP_PRIVATE, 0);
+	up_write(&current->mm->mmap_sem);
+#endif
+
+	start_thread(regs, elf_entry, bprm->p);
+	if (current->ptrace & PT_PTRACED)
+		send_sig(SIGTRAP, current, 0);
+	return 0;
+out:
+	return retval;
+
+out_free_dentry:
+	allow_write_access(interpreter);
+	fput(interpreter);
+out_free_interp:
+	if (elf_interpreter)
+		kfree(elf_interpreter);
+out_free_file:
+out_free_ph:
+	kfree (elf_phdata);
+	goto out;
+}
+
+/* This is really simpleminded and specialized - we are loading an
+ * a.out library that is given an ELF header.
+ */
+static int load_irix_library(struct file *file)
+{
+	struct elfhdr elf_ex;
+	struct elf_phdr *elf_phdata  =  NULL;
+	unsigned int len = 0;
+	int elf_bss = 0;
+	int retval;
+	unsigned int bss;
+	int error;
+	int i,j, k;
+
+	error = kernel_read(file, 0, (char *) &elf_ex, sizeof(elf_ex));
+	if (error != sizeof(elf_ex))
+		return -ENOEXEC;
+
+	if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
+		return -ENOEXEC;
+
+	/* First of all, some simple consistency checks. */
+	if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
+	   !irix_elf_check_arch(&elf_ex) || !file->f_op->mmap)
+		return -ENOEXEC;
+
+	/* Now read in all of the header information. */
+	if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+		return -ENOEXEC;
+
+	elf_phdata = kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
+	if (elf_phdata == NULL)
+		return -ENOMEM;
+
+	retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata,
+			   sizeof(struct elf_phdr) * elf_ex.e_phnum);
+
+	j = 0;
+	for(i=0; i<elf_ex.e_phnum; i++)
+		if((elf_phdata + i)->p_type == PT_LOAD) j++;
+
+	if(j != 1)  {
+		kfree(elf_phdata);
+		return -ENOEXEC;
+	}
+
+	while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
+
+	/* Now use mmap to map the library into memory. */
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap(file,
+			elf_phdata->p_vaddr & 0xfffff000,
+			elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
+			PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+			elf_phdata->p_offset & 0xfffff000);
+	up_write(&current->mm->mmap_sem);
+
+	k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
+	if (k > elf_bss) elf_bss = k;
+
+	if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
+		kfree(elf_phdata);
+		return error;
+	}
+
+	padzero(elf_bss);
+
+	len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
+	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+	if (bss > len) {
+	  down_write(&current->mm->mmap_sem);
+	  do_brk(len, bss-len);
+	  up_write(&current->mm->mmap_sem);
+	}
+	kfree(elf_phdata);
+	return 0;
+}
+
+/* Called through irix_syssgi() to map an elf image given an FD,
+ * a phdr ptr USER_PHDRP in userspace, and a count CNT telling how many
+ * phdrs there are in the USER_PHDRP array.  We return the vaddr the
+ * first phdr was successfully mapped to.
+ */
+unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt)
+{
+	struct elf_phdr *hp;
+	struct file *filp;
+	int i, retval;
+
+#ifdef DEBUG_ELF
+	printk("irix_mapelf: fd[%d] user_phdrp[%p] cnt[%d]\n",
+	       fd, user_phdrp, cnt);
+#endif
+
+	/* First get the verification out of the way. */
+	hp = user_phdrp;
+	if (!access_ok(VERIFY_READ, hp, (sizeof(struct elf_phdr) * cnt))) {
+#ifdef DEBUG_ELF
+		printk("irix_mapelf: access_ok fails!\n");
+#endif
+		return -EFAULT;
+	}
+
+#ifdef DEBUG_ELF
+	dump_phdrs(user_phdrp, cnt);
+#endif
+
+	for(i = 0; i < cnt; i++, hp++)
+		if(hp->p_type != PT_LOAD) {
+			printk("irix_mapelf: One section is not PT_LOAD!\n");
+			return -ENOEXEC;
+		}
+
+	filp = fget(fd);
+	if (!filp)
+		return -EACCES;
+	if(!filp->f_op) {
+		printk("irix_mapelf: Bogon filp!\n");
+		fput(filp);
+		return -EACCES;
+	}
+
+	hp = user_phdrp;
+	for(i = 0; i < cnt; i++, hp++) {
+		int prot;
+
+		prot  = (hp->p_flags & PF_R) ? PROT_READ : 0;
+		prot |= (hp->p_flags & PF_W) ? PROT_WRITE : 0;
+		prot |= (hp->p_flags & PF_X) ? PROT_EXEC : 0;
+		down_write(&current->mm->mmap_sem);
+		retval = do_mmap(filp, (hp->p_vaddr & 0xfffff000),
+				 (hp->p_filesz + (hp->p_vaddr & 0xfff)),
+				 prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
+				 (hp->p_offset & 0xfffff000));
+		up_write(&current->mm->mmap_sem);
+
+		if(retval != (hp->p_vaddr & 0xfffff000)) {
+			printk("irix_mapelf: do_mmap fails with %d!\n", retval);
+			fput(filp);
+			return retval;
+		}
+	}
+
+#ifdef DEBUG_ELF
+	printk("irix_mapelf: Success, returning %08lx\n",
+		(unsigned long) user_phdrp->p_vaddr);
+#endif
+	fput(filp);
+	return user_phdrp->p_vaddr;
+}
+
+/*
+ * ELF core dumper
+ *
+ * Modelled on fs/exec.c:aout_core_dump()
+ * Jeremy Fitzhardinge <jeremy@sw.oz.au>
+ */
+
+/* These are the only things you should do on a core-file: use only these
+ * functions to write out all the necessary info.
+ */
+static int dump_write(struct file *file, const void *addr, int nr)
+{
+	return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+}
+
+static int dump_seek(struct file *file, off_t off)
+{
+	if (file->f_op->llseek) {
+		if (file->f_op->llseek(file, off, 0) != off)
+			return 0;
+	} else
+		file->f_pos = off;
+	return 1;
+}
+
+/* Decide whether a segment is worth dumping; default is yes to be
+ * sure (missing info is worse than too much; etc).
+ * Personally I'd include everything, and use the coredump limit...
+ *
+ * I think we should skip something. But I am not sure how. H.J.
+ */
+static inline int maydump(struct vm_area_struct *vma)
+{
+	if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
+		return 0;
+#if 1
+	if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
+		return 1;
+	if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
+		return 0;
+#endif
+	return 1;
+}
+
+#define roundup(x, y)  ((((x)+((y)-1))/(y))*(y))
+
+/* An ELF note in memory. */
+struct memelfnote
+{
+	const char *name;
+	int type;
+	unsigned int datasz;
+	void *data;
+};
+
+static int notesize(struct memelfnote *en)
+{
+	int sz;
+
+	sz = sizeof(struct elf_note);
+	sz += roundup(strlen(en->name), 4);
+	sz += roundup(en->datasz, 4);
+
+	return sz;
+}
+
+/* #define DEBUG */
+
+#define DUMP_WRITE(addr, nr)	\
+	if (!dump_write(file, (addr), (nr))) \
+		goto end_coredump;
+#define DUMP_SEEK(off)	\
+	if (!dump_seek(file, (off))) \
+		goto end_coredump;
+
+static int writenote(struct memelfnote *men, struct file *file)
+{
+	struct elf_note en;
+
+	en.n_namesz = strlen(men->name);
+	en.n_descsz = men->datasz;
+	en.n_type = men->type;
+
+	DUMP_WRITE(&en, sizeof(en));
+	DUMP_WRITE(men->name, en.n_namesz);
+	/* XXX - cast from long long to long to avoid need for libgcc.a */
+	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
+	DUMP_WRITE(men->data, men->datasz);
+	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
+
+	return 1;
+
+end_coredump:
+	return 0;
+}
+#undef DUMP_WRITE
+#undef DUMP_SEEK
+
+#define DUMP_WRITE(addr, nr)	\
+	if (!dump_write(file, (addr), (nr))) \
+		goto end_coredump;
+#define DUMP_SEEK(off)	\
+	if (!dump_seek(file, (off))) \
+		goto end_coredump;
+
+/* Actual dumper.
+ *
+ * This is a two-pass process; first we find the offsets of the bits,
+ * and then they are actually written out.  If we run out of core limit
+ * we just truncate.
+ */
+static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
+{
+	int has_dumped = 0;
+	mm_segment_t fs;
+	int segs;
+	int i;
+	size_t size;
+	struct vm_area_struct *vma;
+	struct elfhdr elf;
+	off_t offset = 0, dataoff;
+	int limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
+	int numnote = 4;
+	struct memelfnote notes[4];
+	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
+	elf_fpregset_t fpu;		/* NT_PRFPREG */
+	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
+
+	/* Count what's needed to dump, up to the limit of coredump size. */
+	segs = 0;
+	size = 0;
+	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+		if (maydump(vma))
+		{
+			int sz = vma->vm_end-vma->vm_start;
+
+			if (size+sz >= limit)
+				break;
+			else
+				size += sz;
+		}
+
+		segs++;
+	}
+#ifdef DEBUG
+	printk("irix_core_dump: %d segs taking %d bytes\n", segs, size);
+#endif
+
+	/* Set up header. */
+	memcpy(elf.e_ident, ELFMAG, SELFMAG);
+	elf.e_ident[EI_CLASS] = ELFCLASS32;
+	elf.e_ident[EI_DATA] = ELFDATA2LSB;
+	elf.e_ident[EI_VERSION] = EV_CURRENT;
+	elf.e_ident[EI_OSABI] = ELF_OSABI;
+	memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+
+	elf.e_type = ET_CORE;
+	elf.e_machine = ELF_ARCH;
+	elf.e_version = EV_CURRENT;
+	elf.e_entry = 0;
+	elf.e_phoff = sizeof(elf);
+	elf.e_shoff = 0;
+	elf.e_flags = 0;
+	elf.e_ehsize = sizeof(elf);
+	elf.e_phentsize = sizeof(struct elf_phdr);
+	elf.e_phnum = segs+1;		/* Include notes. */
+	elf.e_shentsize = 0;
+	elf.e_shnum = 0;
+	elf.e_shstrndx = 0;
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	has_dumped = 1;
+	current->flags |= PF_DUMPCORE;
+
+	DUMP_WRITE(&elf, sizeof(elf));
+	offset += sizeof(elf);				/* Elf header. */
+	offset += (segs+1) * sizeof(struct elf_phdr);	/* Program headers. */
+
+	/* Set up the notes in similar form to SVR4 core dumps made
+	 * with info from their /proc.
+	 */
+	memset(&psinfo, 0, sizeof(psinfo));
+	memset(&prstatus, 0, sizeof(prstatus));
+
+	notes[0].name = "CORE";
+	notes[0].type = NT_PRSTATUS;
+	notes[0].datasz = sizeof(prstatus);
+	notes[0].data = &prstatus;
+	prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
+	prstatus.pr_sigpend = current->pending.signal.sig[0];
+	prstatus.pr_sighold = current->blocked.sig[0];
+	psinfo.pr_pid = prstatus.pr_pid = current->pid;
+	psinfo.pr_ppid = prstatus.pr_ppid = current->parent->pid;
+	psinfo.pr_pgrp = prstatus.pr_pgrp = process_group(current);
+	psinfo.pr_sid = prstatus.pr_sid = current->signal->session;
+	if (current->pid == current->tgid) {
+		/*
+		 * This is the record for the group leader.  Add in the
+		 * cumulative times of previous dead threads.  This total
+		 * won't include the time of each live thread whose state
+		 * is included in the core dump.  The final total reported
+		 * to our parent process when it calls wait4 will include
+		 * those sums as well as the little bit more time it takes
+		 * this and each other thread to finish dying after the
+		 * core dump synchronization phase.
+		 */
+		jiffies_to_timeval(current->utime + current->signal->utime,
+		                   &prstatus.pr_utime);
+		jiffies_to_timeval(current->stime + current->signal->stime,
+		                   &prstatus.pr_stime);
+	} else {
+		jiffies_to_timeval(current->utime, &prstatus.pr_utime);
+		jiffies_to_timeval(current->stime, &prstatus.pr_stime);
+	}
+	jiffies_to_timeval(current->signal->cutime, &prstatus.pr_cutime);
+	jiffies_to_timeval(current->signal->cstime, &prstatus.pr_cstime);
+
+	if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) {
+		printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) "
+		       "(%d)\n", sizeof(elf_gregset_t), sizeof(struct pt_regs));
+	} else {
+		*(struct pt_regs *)&prstatus.pr_reg = *regs;
+	}
+
+	notes[1].name = "CORE";
+	notes[1].type = NT_PRPSINFO;
+	notes[1].datasz = sizeof(psinfo);
+	notes[1].data = &psinfo;
+	i = current->state ? ffz(~current->state) + 1 : 0;
+	psinfo.pr_state = i;
+	psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i];
+	psinfo.pr_zomb = psinfo.pr_sname == 'Z';
+	psinfo.pr_nice = task_nice(current);
+	psinfo.pr_flag = current->flags;
+	psinfo.pr_uid = current->uid;
+	psinfo.pr_gid = current->gid;
+	{
+		int i, len;
+
+		set_fs(fs);
+
+		len = current->mm->arg_end - current->mm->arg_start;
+		len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
+		copy_from_user(&psinfo.pr_psargs,
+			       (const char *)current->mm->arg_start, len);
+		for(i = 0; i < len; i++)
+			if (psinfo.pr_psargs[i] == 0)
+				psinfo.pr_psargs[i] = ' ';
+		psinfo.pr_psargs[len] = 0;
+
+		set_fs(KERNEL_DS);
+	}
+	strlcpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
+
+	notes[2].name = "CORE";
+	notes[2].type = NT_TASKSTRUCT;
+	notes[2].datasz = sizeof(*current);
+	notes[2].data = current;
+
+	/* Try to dump the FPU. */
+	prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
+	if (!prstatus.pr_fpvalid) {
+		numnote--;
+	} else {
+		notes[3].name = "CORE";
+		notes[3].type = NT_PRFPREG;
+		notes[3].datasz = sizeof(fpu);
+		notes[3].data = &fpu;
+	}
+
+	/* Write notes phdr entry. */
+	{
+		struct elf_phdr phdr;
+		int sz = 0;
+
+		for(i = 0; i < numnote; i++)
+			sz += notesize(&notes[i]);
+
+		phdr.p_type = PT_NOTE;
+		phdr.p_offset = offset;
+		phdr.p_vaddr = 0;
+		phdr.p_paddr = 0;
+		phdr.p_filesz = sz;
+		phdr.p_memsz = 0;
+		phdr.p_flags = 0;
+		phdr.p_align = 0;
+
+		offset += phdr.p_filesz;
+		DUMP_WRITE(&phdr, sizeof(phdr));
+	}
+
+	/* Page-align dumped data. */
+	dataoff = offset = roundup(offset, PAGE_SIZE);
+
+	/* Write program headers for segments dump. */
+	for(vma = current->mm->mmap, i = 0;
+		i < segs && vma != NULL; vma = vma->vm_next) {
+		struct elf_phdr phdr;
+		size_t sz;
+
+		i++;
+
+		sz = vma->vm_end - vma->vm_start;
+
+		phdr.p_type = PT_LOAD;
+		phdr.p_offset = offset;
+		phdr.p_vaddr = vma->vm_start;
+		phdr.p_paddr = 0;
+		phdr.p_filesz = maydump(vma) ? sz : 0;
+		phdr.p_memsz = sz;
+		offset += phdr.p_filesz;
+		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
+		if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
+		if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
+		phdr.p_align = PAGE_SIZE;
+
+		DUMP_WRITE(&phdr, sizeof(phdr));
+	}
+
+	for(i = 0; i < numnote; i++)
+		if (!writenote(&notes[i], file))
+			goto end_coredump;
+
+	set_fs(fs);
+
+	DUMP_SEEK(dataoff);
+
+	for(i = 0, vma = current->mm->mmap;
+	    i < segs && vma != NULL;
+	    vma = vma->vm_next) {
+		unsigned long addr = vma->vm_start;
+		unsigned long len = vma->vm_end - vma->vm_start;
+
+		if (!maydump(vma))
+			continue;
+		i++;
+#ifdef DEBUG
+		printk("elf_core_dump: writing %08lx %lx\n", addr, len);
+#endif
+		DUMP_WRITE((void *)addr, len);
+	}
+
+	if ((off_t) file->f_pos != offset) {
+		/* Sanity check. */
+		printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
+		       (off_t) file->f_pos, offset);
+	}
+
+end_coredump:
+	set_fs(fs);
+	return has_dumped;
+}
+
+static int __init init_irix_binfmt(void)
+{
+	int init_inventory(void);
+	extern asmlinkage unsigned long sys_call_table;
+	extern asmlinkage unsigned long sys_call_table_irix5;
+
+	init_inventory();
+
+	/*
+	 * Copy the IRIX5 syscall table (8000 bytes) into the main syscall
+	 * table. The IRIX5 calls are located by an offset of 8000 bytes
+	 * from the beginning of the main table.
+	 */
+	memcpy((void *) ((unsigned long) &sys_call_table + 8000),
+		&sys_call_table_irix5, 8000);
+
+	return register_binfmt(&irix_format);
+}
+
+static void __exit exit_irix_binfmt(void)
+{
+	/* Remove the IRIX ELF loaders. */
+	unregister_binfmt(&irix_format);
+}
+
+module_init(init_irix_binfmt)
+module_exit(exit_irix_binfmt)
diff --git a/arch/mips/kernel/irixinv.c b/arch/mips/kernel/irixinv.c
new file mode 100644
index 0000000..60aa98c
--- /dev/null
+++ b/arch/mips/kernel/irixinv.c
@@ -0,0 +1,77 @@
+/*
+ * Support the inventory interface for IRIX binaries
+ * This is invoked before the mm layer is working, so we do not
+ * use the linked lists for the inventory yet.
+ *
+ * Miguel de Icaza, 1997.
+ */
+#include <linux/mm.h>
+#include <asm/inventory.h>
+#include <asm/uaccess.h>
+
+#define MAX_INVENTORY 50
+int inventory_items = 0;
+
+static inventory_t inventory [MAX_INVENTORY];
+
+void add_to_inventory (int class, int type, int controller, int unit, int state)
+{
+	inventory_t *ni = &inventory [inventory_items];
+
+	if (inventory_items == MAX_INVENTORY)
+		return;
+
+	ni->inv_class      = class;
+	ni->inv_type       = type;
+	ni->inv_controller = controller;
+	ni->inv_unit       = unit;
+	ni->inv_state      = state;
+	ni->inv_next       = ni;
+	inventory_items++;
+}
+
+int dump_inventory_to_user (void *userbuf, int size)
+{
+	inventory_t *inv  = &inventory [0];
+	inventory_t *user = userbuf;
+	int v;
+
+	if (!access_ok(VERIFY_WRITE, userbuf, size))
+		return -EFAULT;
+
+	for (v = 0; v < inventory_items; v++){
+		inv = &inventory [v];
+		copy_to_user (user, inv, sizeof (inventory_t));
+		user++;
+	}
+	return inventory_items * sizeof (inventory_t);
+}
+
+int __init init_inventory(void)
+{
+	/*
+	 * gross hack while we put the right bits all over the kernel
+	 * most likely this will not let just anyone run the X server
+	 * until we put the right values all over the place
+	 */
+	add_to_inventory (10, 3, 0, 0, 16400);
+	add_to_inventory (1, 1, 150, -1, 12);
+	add_to_inventory (1, 3, 0, 0, 8976);
+	add_to_inventory (1, 2, 0, 0, 8976);
+	add_to_inventory (4, 8, 0, 0, 2);
+	add_to_inventory (5, 5, 0, 0, 1);
+	add_to_inventory (3, 3, 0, 0, 32768);
+	add_to_inventory (3, 4, 0, 0, 32768);
+	add_to_inventory (3, 8, 0, 0, 524288);
+	add_to_inventory (3, 9, 0, 0, 64);
+	add_to_inventory (3, 1, 0, 0, 67108864);
+	add_to_inventory (12, 3, 0, 0, 16);
+	add_to_inventory (8, 7, 17, 0, 16777472);
+	add_to_inventory (8, 0, 0, 0, 1);
+	add_to_inventory (2, 1, 0, 13, 2);
+	add_to_inventory (2, 2, 0, 2, 0);
+	add_to_inventory (2, 2, 0, 1, 0);
+	add_to_inventory (7, 14, 0, 0, 6);
+
+	return 0;
+}
diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c
new file mode 100644
index 0000000..4cd3d38
--- /dev/null
+++ b/arch/mips/kernel/irixioctl.c
@@ -0,0 +1,261 @@
+/*
+ * irixioctl.c: A fucking mess...
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sockios.h>
+#include <linux/syscalls.h>
+#include <linux/tty.h>
+#include <linux/file.h>
+
+#include <asm/uaccess.h>
+#include <asm/ioctl.h>
+#include <asm/ioctls.h>
+
+#undef DEBUG_IOCTLS
+#undef DEBUG_MISSING_IOCTL
+
+struct irix_termios {
+	tcflag_t c_iflag, c_oflag, c_cflag, c_lflag;
+	cc_t c_cc[NCCS];
+};
+
+extern void start_tty(struct tty_struct *tty);
+static struct tty_struct *get_tty(int fd)
+{
+	struct file *filp;
+	struct tty_struct *ttyp = NULL;
+
+	spin_lock(&current->files->file_lock);
+	filp = fcheck(fd);
+	if(filp && filp->private_data) {
+		ttyp = (struct tty_struct *) filp->private_data;
+
+		if(ttyp->magic != TTY_MAGIC)
+			ttyp =NULL;
+	}
+	spin_unlock(&current->files->file_lock);
+	return ttyp;
+}
+
+static struct tty_struct *get_real_tty(struct tty_struct *tp)
+{
+	if (tp->driver->type == TTY_DRIVER_TYPE_PTY &&
+	   tp->driver->subtype == PTY_TYPE_MASTER)
+		return tp->link;
+	else
+		return tp;
+}
+
+asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg)
+{
+	struct tty_struct *tp, *rtp;
+	mm_segment_t old_fs;
+	int error = 0;
+
+#ifdef DEBUG_IOCTLS
+	printk("[%s:%d] irix_ioctl(%d, ", current->comm, current->pid, fd);
+#endif
+	switch(cmd) {
+	case 0x00005401:
+#ifdef DEBUG_IOCTLS
+		printk("TCGETA, %08lx) ", arg);
+#endif
+		error = sys_ioctl(fd, TCGETA, arg);
+		break;
+
+	case 0x0000540d: {
+		struct termios kt;
+		struct irix_termios *it = (struct irix_termios *) arg;
+
+#ifdef DEBUG_IOCTLS
+		printk("TCGETS, %08lx) ", arg);
+#endif
+		if(!access_ok(VERIFY_WRITE, it, sizeof(*it))) {
+			error = -EFAULT;
+			break;
+		}
+		old_fs = get_fs(); set_fs(get_ds());
+		error = sys_ioctl(fd, TCGETS, (unsigned long) &kt);
+		set_fs(old_fs);
+		if (error)
+			break;
+		__put_user(kt.c_iflag, &it->c_iflag);
+		__put_user(kt.c_oflag, &it->c_oflag);
+		__put_user(kt.c_cflag, &it->c_cflag);
+		__put_user(kt.c_lflag, &it->c_lflag);
+		for(error = 0; error < NCCS; error++)
+			__put_user(kt.c_cc[error], &it->c_cc[error]);
+		error = 0;
+		break;
+	}
+
+	case 0x0000540e: {
+		struct termios kt;
+		struct irix_termios *it = (struct irix_termios *) arg;
+
+#ifdef DEBUG_IOCTLS
+		printk("TCSETS, %08lx) ", arg);
+#endif
+		if (!access_ok(VERIFY_READ, it, sizeof(*it))) {
+			error = -EFAULT;
+			break;
+		}
+		old_fs = get_fs(); set_fs(get_ds());
+		error = sys_ioctl(fd, TCGETS, (unsigned long) &kt);
+		set_fs(old_fs);
+		if(error)
+			break;
+		__get_user(kt.c_iflag, &it->c_iflag);
+		__get_user(kt.c_oflag, &it->c_oflag);
+		__get_user(kt.c_cflag, &it->c_cflag);
+		__get_user(kt.c_lflag, &it->c_lflag);
+		for(error = 0; error < NCCS; error++)
+			__get_user(kt.c_cc[error], &it->c_cc[error]);
+		old_fs = get_fs(); set_fs(get_ds());
+		error = sys_ioctl(fd, TCSETS, (unsigned long) &kt);
+		set_fs(old_fs);
+		break;
+	}
+
+	case 0x0000540f:
+#ifdef DEBUG_IOCTLS
+		printk("TCSETSW, %08lx) ", arg);
+#endif
+		error = sys_ioctl(fd, TCSETSW, arg);
+		break;
+
+	case 0x00005471:
+#ifdef DEBUG_IOCTLS
+		printk("TIOCNOTTY, %08lx) ", arg);
+#endif
+		error = sys_ioctl(fd, TIOCNOTTY, arg);
+		break;
+
+	case 0x00007416:
+#ifdef DEBUG_IOCTLS
+		printk("TIOCGSID, %08lx) ", arg);
+#endif
+		tp = get_tty(fd);
+		if(!tp) {
+			error = -EINVAL;
+			break;
+		}
+		rtp = get_real_tty(tp);
+#ifdef DEBUG_IOCTLS
+		printk("rtp->session=%d ", rtp->session);
+#endif
+		error = put_user(rtp->session, (unsigned long *) arg);
+		break;
+
+	case 0x746e:
+		/* TIOCSTART, same effect as hitting ^Q */
+#ifdef DEBUG_IOCTLS
+		printk("TIOCSTART, %08lx) ", arg);
+#endif
+		tp = get_tty(fd);
+		if(!tp) {
+			error = -EINVAL;
+			break;
+		}
+		rtp = get_real_tty(tp);
+		start_tty(rtp);
+		break;
+
+	case 0x20006968:
+#ifdef DEBUG_IOCTLS
+		printk("SIOCGETLABEL, %08lx) ", arg);
+#endif
+		error = -ENOPKG;
+		break;
+
+	case 0x40047477:
+#ifdef DEBUG_IOCTLS
+		printk("TIOCGPGRP, %08lx) ", arg);
+#endif
+		error = sys_ioctl(fd, TIOCGPGRP, arg);
+#ifdef DEBUG_IOCTLS
+		printk("arg=%d ", *(int *)arg);
+#endif
+		break;
+
+	case 0x40087468:
+#ifdef DEBUG_IOCTLS
+		printk("TIOCGWINSZ, %08lx) ", arg);
+#endif
+		error = sys_ioctl(fd, TIOCGWINSZ, arg);
+		break;
+
+	case 0x8004667e:
+#ifdef DEBUG_IOCTLS
+		printk("FIONBIO, %08lx) arg=%d ", arg, *(int *)arg);
+#endif
+		error = sys_ioctl(fd, FIONBIO, arg);
+		break;
+
+	case 0x80047476:
+#ifdef DEBUG_IOCTLS
+		printk("TIOCSPGRP, %08lx) arg=%d ", arg, *(int *)arg);
+#endif
+		error = sys_ioctl(fd, TIOCSPGRP, arg);
+		break;
+
+	case 0x8020690c:
+#ifdef DEBUG_IOCTLS
+		printk("SIOCSIFADDR, %08lx) arg=%d ", arg, *(int *)arg);
+#endif
+		error = sys_ioctl(fd, SIOCSIFADDR, arg);
+		break;
+
+	case 0x80206910:
+#ifdef DEBUG_IOCTLS
+		printk("SIOCSIFFLAGS, %08lx) arg=%d ", arg, *(int *)arg);
+#endif
+		error = sys_ioctl(fd, SIOCSIFFLAGS, arg);
+		break;
+
+	case 0xc0206911:
+#ifdef DEBUG_IOCTLS
+		printk("SIOCGIFFLAGS, %08lx) arg=%d ", arg, *(int *)arg);
+#endif
+		error = sys_ioctl(fd, SIOCGIFFLAGS, arg);
+		break;
+
+	case 0xc020691b:
+#ifdef DEBUG_IOCTLS
+		printk("SIOCGIFMETRIC, %08lx) arg=%d ", arg, *(int *)arg);
+#endif
+		error = sys_ioctl(fd, SIOCGIFMETRIC, arg);
+		break;
+
+	default: {
+#ifdef DEBUG_MISSING_IOCTL
+		char *msg = "Unimplemented IOCTL cmd tell linux@engr.sgi.com\n";
+
+#ifdef DEBUG_IOCTLS
+		printk("UNIMP_IOCTL, %08lx)\n", arg);
+#endif
+		old_fs = get_fs(); set_fs(get_ds());
+		sys_write(2, msg, strlen(msg));
+		set_fs(old_fs);
+		printk("[%s:%d] Does unimplemented IRIX ioctl cmd %08lx\n",
+		       current->comm, current->pid, cmd);
+		do_exit(255);
+#else
+		error = sys_ioctl (fd, cmd, arg);
+#endif
+	}
+
+	};
+#ifdef DEBUG_IOCTLS
+	printk("error=%d\n", error);
+#endif
+	return error;
+}
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
new file mode 100644
index 0000000..3f956f8
--- /dev/null
+++ b/arch/mips/kernel/irixsig.c
@@ -0,0 +1,853 @@
+/*
+ * irixsig.c: WHEEE, IRIX signals!  YOW, am I compatible or what?!?!
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1997 - 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/time.h>
+#include <linux/ptrace.h>
+
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+#undef DEBUG_SIG
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+typedef struct {
+	unsigned long sig[4];
+} irix_sigset_t;
+
+struct sigctx_irix5 {
+	u32 rmask, cp0_status;
+	u64 pc;
+	u64 regs[32];
+	u64 fpregs[32];
+	u32 usedfp, fpcsr, fpeir, sstk_flags;
+	u64 hi, lo;
+	u64 cp0_cause, cp0_badvaddr, _unused0;
+	irix_sigset_t sigset;
+	u64 weird_fpu_thing;
+	u64 _unused1[31];
+};
+
+#ifdef DEBUG_SIG
+/* Debugging */
+static inline void dump_irix5_sigctx(struct sigctx_irix5 *c)
+{
+	int i;
+
+	printk("misc: rmask[%08lx] status[%08lx] pc[%08lx]\n",
+	       (unsigned long) c->rmask,
+	       (unsigned long) c->cp0_status,
+	       (unsigned long) c->pc);
+	printk("regs: ");
+	for(i = 0; i < 16; i++)
+		printk("[%d]<%08lx> ", i, (unsigned long) c->regs[i]);
+	printk("\nregs: ");
+	for(i = 16; i < 32; i++)
+		printk("[%d]<%08lx> ", i, (unsigned long) c->regs[i]);
+	printk("\nfpregs: ");
+	for(i = 0; i < 16; i++)
+		printk("[%d]<%08lx> ", i, (unsigned long) c->fpregs[i]);
+	printk("\nfpregs: ");
+	for(i = 16; i < 32; i++)
+		printk("[%d]<%08lx> ", i, (unsigned long) c->fpregs[i]);
+	printk("misc: usedfp[%d] fpcsr[%08lx] fpeir[%08lx] stk_flgs[%08lx]\n",
+	       (int) c->usedfp, (unsigned long) c->fpcsr,
+	       (unsigned long) c->fpeir, (unsigned long) c->sstk_flags);
+	printk("misc: hi[%08lx] lo[%08lx] cause[%08lx] badvaddr[%08lx]\n",
+	       (unsigned long) c->hi, (unsigned long) c->lo,
+	       (unsigned long) c->cp0_cause, (unsigned long) c->cp0_badvaddr);
+	printk("misc: sigset<0>[%08lx] sigset<1>[%08lx] sigset<2>[%08lx] "
+	       "sigset<3>[%08lx]\n", (unsigned long) c->sigset.sig[0],
+	       (unsigned long) c->sigset.sig[1],
+	       (unsigned long) c->sigset.sig[2],
+	       (unsigned long) c->sigset.sig[3]);
+}
+#endif
+
+static void setup_irix_frame(struct k_sigaction *ka, struct pt_regs *regs,
+			     int signr, sigset_t *oldmask)
+{
+	unsigned long sp;
+	struct sigctx_irix5 *ctx;
+	int i;
+
+	sp = regs->regs[29];
+	sp -= sizeof(struct sigctx_irix5);
+	sp &= ~(0xf);
+	ctx = (struct sigctx_irix5 *) sp;
+	if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx)))
+		goto segv_and_exit;
+
+	__put_user(0, &ctx->weird_fpu_thing);
+	__put_user(~(0x00000001), &ctx->rmask);
+	__put_user(0, &ctx->regs[0]);
+	for(i = 1; i < 32; i++)
+		__put_user((u64) regs->regs[i], &ctx->regs[i]);
+
+	__put_user((u64) regs->hi, &ctx->hi);
+	__put_user((u64) regs->lo, &ctx->lo);
+	__put_user((u64) regs->cp0_epc, &ctx->pc);
+	__put_user(!!used_math(), &ctx->usedfp);
+	__put_user((u64) regs->cp0_cause, &ctx->cp0_cause);
+	__put_user((u64) regs->cp0_badvaddr, &ctx->cp0_badvaddr);
+
+	__put_user(0, &ctx->sstk_flags); /* XXX sigstack unimp... todo... */
+
+	__copy_to_user(&ctx->sigset, oldmask, sizeof(irix_sigset_t));
+
+#ifdef DEBUG_SIG
+	dump_irix5_sigctx(ctx);
+#endif
+
+	regs->regs[4] = (unsigned long) signr;
+	regs->regs[5] = 0; /* XXX sigcode XXX */
+	regs->regs[6] = regs->regs[29] = sp;
+	regs->regs[7] = (unsigned long) ka->sa.sa_handler;
+	regs->regs[25] = regs->cp0_epc = (unsigned long) ka->sa_restorer;
+
+	return;
+
+segv_and_exit:
+	force_sigsegv(signr, current);
+}
+
+static void inline
+setup_irix_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
+               int signr, sigset_t *oldmask, siginfo_t *info)
+{
+	printk("Aiee: setup_tr_frame wants to be written");
+	do_exit(SIGSEGV);
+}
+
+static inline void handle_signal(unsigned long sig, siginfo_t *info,
+	struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs)
+{
+	switch(regs->regs[0]) {
+	case ERESTARTNOHAND:
+		regs->regs[2] = EINTR;
+		break;
+	case ERESTARTSYS:
+		if(!(ka->sa.sa_flags & SA_RESTART)) {
+			regs->regs[2] = EINTR;
+			break;
+		}
+	/* fallthrough */
+	case ERESTARTNOINTR:		/* Userland will reload $v0.  */
+		regs->cp0_epc -= 8;
+	}
+
+	regs->regs[0] = 0;		/* Don't deal with this again.  */
+
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_irix_rt_frame(ka, regs, sig, oldset, info);
+	else
+		setup_irix_frame(ka, regs, sig, oldset);
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+}
+
+asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+	struct k_sigaction ka;
+	siginfo_t info;
+	int signr;
+
+	/*
+	 * We want the common case to go fast, which is why we may in certain
+	 * cases get here from kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if (!user_mode(regs))
+		return 1;
+
+	if (try_to_freeze(0))
+		goto no_signal;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	if (signr > 0) {
+		handle_signal(signr, &info, &ka, oldset, regs);
+		return 1;
+	}
+
+no_signal:
+	/*
+	 * Who's code doesn't conform to the restartable syscall convention
+	 * dies here!!!  The li instruction, a single machine instruction,
+	 * must directly be followed by the syscall instruction.
+	 */
+	if (regs->regs[0]) {
+		if (regs->regs[2] == ERESTARTNOHAND ||
+		    regs->regs[2] == ERESTARTSYS ||
+		    regs->regs[2] == ERESTARTNOINTR) {
+			regs->cp0_epc -= 8;
+		}
+	}
+	return 0;
+}
+
+asmlinkage void
+irix_sigreturn(struct pt_regs *regs)
+{
+	struct sigctx_irix5 *context, *magic;
+	unsigned long umask, mask;
+	u64 *fregs;
+	int sig, i, base = 0;
+	sigset_t blocked;
+
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+	if (regs->regs[2] == 1000)
+		base = 1;
+
+	context = (struct sigctx_irix5 *) regs->regs[base + 4];
+	magic = (struct sigctx_irix5 *) regs->regs[base + 5];
+	sig = (int) regs->regs[base + 6];
+#ifdef DEBUG_SIG
+	printk("[%s:%d] IRIX sigreturn(scp[%p],ucp[%p],sig[%d])\n",
+	       current->comm, current->pid, context, magic, sig);
+#endif
+	if (!context)
+		context = magic;
+	if (!access_ok(VERIFY_READ, context, sizeof(struct sigctx_irix5)))
+		goto badframe;
+
+#ifdef DEBUG_SIG
+	dump_irix5_sigctx(context);
+#endif
+
+	__get_user(regs->cp0_epc, &context->pc);
+	umask = context->rmask; mask = 2;
+	for (i = 1; i < 32; i++, mask <<= 1) {
+		if(umask & mask)
+			__get_user(regs->regs[i], &context->regs[i]);
+	}
+	__get_user(regs->hi, &context->hi);
+	__get_user(regs->lo, &context->lo);
+
+	if ((umask & 1) && context->usedfp) {
+		fregs = (u64 *) &current->thread.fpu;
+		for(i = 0; i < 32; i++)
+			fregs[i] = (u64) context->fpregs[i];
+		__get_user(current->thread.fpu.hard.fcr31, &context->fpcsr);
+	}
+
+	/* XXX do sigstack crapola here... XXX */
+
+	if (__copy_from_user(&blocked, &context->sigset, sizeof(blocked)))
+		goto badframe;
+
+	sigdelsetmask(&blocked, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = blocked;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	/*
+	 * Don't let your children do this ...
+	 */
+	if (current_thread_info()->flags & TIF_SYSCALL_TRACE)
+		do_syscall_trace(regs, 1);
+	__asm__ __volatile__(
+		"move\t$29,%0\n\t"
+		"j\tsyscall_exit"
+		:/* no outputs */
+		:"r" (&regs));
+		/* Unreached */
+
+badframe:
+	force_sig(SIGSEGV, current);
+}
+
+struct sigact_irix5 {
+	int flags;
+	void (*handler)(int);
+	u32 sigset[4];
+	int _unused0[2];
+};
+
+#ifdef DEBUG_SIG
+static inline void dump_sigact_irix5(struct sigact_irix5 *p)
+{
+	printk("<f[%d] hndlr[%08lx] msk[%08lx]>", p->flags,
+	       (unsigned long) p->handler,
+	       (unsigned long) p->sigset[0]);
+}
+#endif
+
+asmlinkage int
+irix_sigaction(int sig, const struct sigaction *act,
+	      struct sigaction *oact, void *trampoline)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+#ifdef DEBUG_SIG
+	printk(" (%d,%s,%s,%08lx) ", sig, (!new ? "0" : "NEW"),
+	       (!old ? "0" : "OLD"), trampoline);
+	if(new) {
+		dump_sigact_irix5(new); printk(" ");
+	}
+#endif
+	if (act) {
+		sigset_t mask;
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_flags, &act->sa_flags))
+			return -EFAULT;
+
+		__copy_from_user(&mask, &act->sa_mask, sizeof(sigset_t));
+
+		/*
+		 * Hmmm... methinks IRIX libc always passes a valid trampoline
+		 * value for all invocations of sigaction.  Will have to
+		 * investigate.  POSIX POSIX, die die die...
+		 */
+		new_ka.sa_restorer = trampoline;
+	}
+
+/* XXX Implement SIG_SETMASK32 for IRIX compatibility */
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
+			return -EFAULT;
+		__copy_to_user(&old_ka.sa.sa_mask, &oact->sa_mask,
+		               sizeof(sigset_t));
+	}
+
+	return ret;
+}
+
+asmlinkage int irix_sigpending(irix_sigset_t *set)
+{
+	return do_sigpending(set, sizeof(*set));
+}
+
+asmlinkage int irix_sigprocmask(int how, irix_sigset_t *new, irix_sigset_t *old)
+{
+	sigset_t oldbits, newbits;
+
+	if (new) {
+		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
+			return -EFAULT;
+		__copy_from_user(&newbits, new, sizeof(unsigned long)*4);
+		sigdelsetmask(&newbits, ~_BLOCKABLE);
+
+		spin_lock_irq(&current->sighand->siglock);
+		oldbits = current->blocked;
+
+		switch(how) {
+		case 1:
+			sigorsets(&newbits, &oldbits, &newbits);
+			break;
+
+		case 2:
+			sigandsets(&newbits, &oldbits, &newbits);
+			break;
+
+		case 3:
+			break;
+
+		case 256:
+			siginitset(&newbits, newbits.sig[0]);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+	if(old) {
+		if (!access_ok(VERIFY_WRITE, old, sizeof(*old)))
+			return -EFAULT;
+		__copy_to_user(old, &current->blocked, sizeof(unsigned long)*4);
+	}
+
+	return 0;
+}
+
+asmlinkage int irix_sigsuspend(struct pt_regs *regs)
+{
+	sigset_t *uset, saveset, newset;
+
+	uset = (sigset_t *) regs->regs[4];
+	if (copy_from_user(&newset, uset, sizeof(sigset_t)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs->regs[2] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_irix_signal(&saveset, regs))
+			return -EINTR;
+	}
+}
+
+/* hate hate hate... */
+struct irix5_siginfo {
+	int sig, code, error;
+	union {
+		char unused[128 - (3 * 4)]; /* Safety net. */
+		struct {
+			int pid;
+			union {
+				int uid;
+				struct {
+					int utime, status, stime;
+				} child;
+			} procdata;
+		} procinfo;
+
+		unsigned long fault_addr;
+
+		struct {
+			int fd;
+			long band;
+		} fileinfo;
+
+		unsigned long sigval;
+	} stuff;
+};
+
+static inline unsigned long timespectojiffies(struct timespec *value)
+{
+	unsigned long sec = (unsigned) value->tv_sec;
+	long nsec = value->tv_nsec;
+
+	if (sec > (LONG_MAX / HZ))
+		return LONG_MAX;
+	nsec += 1000000000L / HZ - 1;
+	nsec /= 1000000000L / HZ;
+	return HZ * sec + nsec;
+}
+
+asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info,
+				struct timespec *tp)
+{
+	long expire = MAX_SCHEDULE_TIMEOUT;
+	sigset_t kset;
+	int i, sig, error, timeo = 0;
+
+#ifdef DEBUG_SIG
+	printk("[%s:%d] irix_sigpoll_sys(%p,%p,%p)\n",
+	       current->comm, current->pid, set, info, tp);
+#endif
+
+	/* Must always specify the signal set. */
+	if (!set)
+		return -EINVAL;
+
+	if (!access_ok(VERIFY_READ, set, sizeof(kset))) {
+		error = -EFAULT;
+		goto out;
+	}
+
+	__copy_from_user(&kset, set, sizeof(set));
+	if (error)
+		goto out;
+
+	if (info && clear_user(info, sizeof(*info))) {
+		error = -EFAULT;
+		goto out;
+	}
+
+	if (tp) {
+		if (!access_ok(VERIFY_READ, tp, sizeof(*tp)))
+			return -EFAULT;
+		if (!tp->tv_sec && !tp->tv_nsec) {
+			error = -EINVAL;
+			goto out;
+		}
+		expire = timespectojiffies(tp)+(tp->tv_sec||tp->tv_nsec);
+	}
+
+	while(1) {
+		long tmp = 0;
+
+		current->state = TASK_INTERRUPTIBLE;
+		expire = schedule_timeout(expire);
+
+		for (i=0; i<=4; i++)
+			tmp |= (current->pending.signal.sig[i] & kset.sig[i]);
+
+		if (tmp)
+			break;
+		if (!expire) {
+			timeo = 1;
+			break;
+		}
+		if (signal_pending(current))
+			return -EINTR;
+	}
+	if (timeo)
+		return -EAGAIN;
+
+	for(sig = 1; i <= 65 /* IRIX_NSIG */; sig++) {
+		if (sigismember (&kset, sig))
+			continue;
+		if (sigismember (&current->pending.signal, sig)) {
+			/* XXX need more than this... */
+			if (info)
+				info->sig = sig;
+			error = 0;
+			goto out;
+		}
+	}
+
+	/* Should not get here, but do something sane if we do. */
+	error = -EINTR;
+
+out:
+	return error;
+}
+
+/* This is here because of irix5_siginfo definition. */
+#define IRIX_P_PID    0
+#define IRIX_P_PGID   2
+#define IRIX_P_ALL    7
+
+extern int getrusage(struct task_struct *, int, struct rusage __user *);
+
+#define W_EXITED     1
+#define W_TRAPPED    2
+#define W_STOPPED    4
+#define W_CONT       8
+#define W_NOHANG    64
+
+#define W_MASK      (W_EXITED | W_TRAPPED | W_STOPPED | W_CONT | W_NOHANG)
+
+asmlinkage int irix_waitsys(int type, int pid, struct irix5_siginfo *info,
+			    int options, struct rusage *ru)
+{
+	int flag, retval;
+	DECLARE_WAITQUEUE(wait, current);
+	struct task_struct *tsk;
+	struct task_struct *p;
+	struct list_head *_p;
+
+	if (!info) {
+		retval = -EINVAL;
+		goto out;
+	}
+	if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) {
+		retval = -EFAULT;
+		goto out;
+	}
+	if (ru) {
+		if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru))) {
+			retval = -EFAULT;
+			goto out;
+		}
+	}
+	if (options & ~(W_MASK)) {
+		retval = -EINVAL;
+		goto out;
+	}
+	if (type != IRIX_P_PID && type != IRIX_P_PGID && type != IRIX_P_ALL) {
+		retval = -EINVAL;
+		goto out;
+	}
+	add_wait_queue(&current->signal->wait_chldexit, &wait);
+repeat:
+	flag = 0;
+	current->state = TASK_INTERRUPTIBLE;
+	read_lock(&tasklist_lock);
+	tsk = current;
+	list_for_each(_p,&tsk->children) {
+		p = list_entry(_p,struct task_struct,sibling);
+		if ((type == IRIX_P_PID) && p->pid != pid)
+			continue;
+		if ((type == IRIX_P_PGID) && process_group(p) != pid)
+			continue;
+		if ((p->exit_signal != SIGCHLD))
+			continue;
+		flag = 1;
+		switch (p->state) {
+		case TASK_STOPPED:
+			if (!p->exit_code)
+				continue;
+			if (!(options & (W_TRAPPED|W_STOPPED)) &&
+			    !(p->ptrace & PT_PTRACED))
+				continue;
+			read_unlock(&tasklist_lock);
+
+			/* move to end of parent's list to avoid starvation */
+			write_lock_irq(&tasklist_lock);
+			remove_parent(p);
+			add_parent(p, p->parent);
+			write_unlock_irq(&tasklist_lock);
+			retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
+			if (!retval && ru) {
+				retval |= __put_user(SIGCHLD, &info->sig);
+				retval |= __put_user(0, &info->code);
+				retval |= __put_user(p->pid, &info->stuff.procinfo.pid);
+				retval |= __put_user((p->exit_code >> 8) & 0xff,
+				           &info->stuff.procinfo.procdata.child.status);
+				retval |= __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime);
+				retval |= __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime);
+			}
+			if (!retval) {
+				p->exit_code = 0;
+			}
+			goto end_waitsys;
+
+		case EXIT_ZOMBIE:
+			current->signal->cutime += p->utime + p->signal->cutime;
+			current->signal->cstime += p->stime + p->signal->cstime;
+			if (ru != NULL)
+				getrusage(p, RUSAGE_BOTH, ru);
+			__put_user(SIGCHLD, &info->sig);
+			__put_user(1, &info->code);      /* CLD_EXITED */
+			__put_user(p->pid, &info->stuff.procinfo.pid);
+			__put_user((p->exit_code >> 8) & 0xff,
+			           &info->stuff.procinfo.procdata.child.status);
+			__put_user(p->utime,
+			           &info->stuff.procinfo.procdata.child.utime);
+			__put_user(p->stime,
+			           &info->stuff.procinfo.procdata.child.stime);
+			retval = 0;
+			if (p->real_parent != p->parent) {
+				write_lock_irq(&tasklist_lock);
+				remove_parent(p);
+				p->parent = p->real_parent;
+				add_parent(p, p->parent);
+				do_notify_parent(p, SIGCHLD);
+				write_unlock_irq(&tasklist_lock);
+			} else
+				release_task(p);
+			goto end_waitsys;
+		default:
+			continue;
+		}
+		tsk = next_thread(tsk);
+	}
+	read_unlock(&tasklist_lock);
+	if (flag) {
+		retval = 0;
+		if (options & W_NOHANG)
+			goto end_waitsys;
+		retval = -ERESTARTSYS;
+		if (signal_pending(current))
+			goto end_waitsys;
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		goto repeat;
+	}
+	retval = -ECHILD;
+end_waitsys:
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&current->signal->wait_chldexit, &wait);
+
+out:
+	return retval;
+}
+
+struct irix5_context {
+	u32 flags;
+	u32 link;
+	u32 sigmask[4];
+	struct { u32 sp, size, flags; } stack;
+	int regs[36];
+	u32 fpregs[32];
+	u32 fpcsr;
+	u32 _unused0;
+	u32 _unused1[47];
+	u32 weird_graphics_thing;
+};
+
+asmlinkage int irix_getcontext(struct pt_regs *regs)
+{
+	int i, base = 0;
+	struct irix5_context *ctx;
+	unsigned long flags;
+
+	if (regs->regs[2] == 1000)
+		base = 1;
+	ctx = (struct irix5_context *) regs->regs[base + 4];
+
+#ifdef DEBUG_SIG
+	printk("[%s:%d] irix_getcontext(%p)\n",
+	       current->comm, current->pid, ctx);
+#endif
+
+	if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx)))
+		return -EFAULT;
+
+	__put_user(current->thread.irix_oldctx, &ctx->link);
+
+	__copy_to_user(&ctx->sigmask, &current->blocked, sizeof(irix_sigset_t));
+
+	/* XXX Do sigstack stuff someday... */
+	__put_user(0, &ctx->stack.sp);
+	__put_user(0, &ctx->stack.size);
+	__put_user(0, &ctx->stack.flags);
+
+	__put_user(0, &ctx->weird_graphics_thing);
+	__put_user(0, &ctx->regs[0]);
+	for (i = 1; i < 32; i++)
+		__put_user(regs->regs[i], &ctx->regs[i]);
+	__put_user(regs->lo, &ctx->regs[32]);
+	__put_user(regs->hi, &ctx->regs[33]);
+	__put_user(regs->cp0_cause, &ctx->regs[34]);
+	__put_user(regs->cp0_epc, &ctx->regs[35]);
+
+	flags = 0x0f;
+	if (!used_math()) {
+		flags &= ~(0x08);
+	} else {
+		/* XXX wheee... */
+		printk("Wheee, no code for saving IRIX FPU context yet.\n");
+	}
+	__put_user(flags, &ctx->flags);
+
+	return 0;
+}
+
+asmlinkage unsigned long irix_setcontext(struct pt_regs *regs)
+{
+	int error, base = 0;
+	struct irix5_context *ctx;
+
+	if(regs->regs[2] == 1000)
+		base = 1;
+	ctx = (struct irix5_context *) regs->regs[base + 4];
+
+#ifdef DEBUG_SIG
+	printk("[%s:%d] irix_setcontext(%p)\n",
+	       current->comm, current->pid, ctx);
+#endif
+
+	if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx))) {
+		error = -EFAULT;
+		goto out;
+	}
+
+	if (ctx->flags & 0x02) {
+		/* XXX sigstack garbage, todo... */
+		printk("Wheee, cannot do sigstack stuff in setcontext\n");
+	}
+
+	if (ctx->flags & 0x04) {
+		int i;
+
+		/* XXX extra control block stuff... todo... */
+		for(i = 1; i < 32; i++)
+			regs->regs[i] = ctx->regs[i];
+		regs->lo = ctx->regs[32];
+		regs->hi = ctx->regs[33];
+		regs->cp0_epc = ctx->regs[35];
+	}
+
+	if (ctx->flags & 0x08) {
+		/* XXX fpu context, blah... */
+		printk("Wheee, cannot restore FPU context yet...\n");
+	}
+	current->thread.irix_oldctx = ctx->link;
+	error = regs->regs[2];
+
+out:
+	return error;
+}
+
+struct irix_sigstack { unsigned long sp; int status; };
+
+asmlinkage int irix_sigstack(struct irix_sigstack *new, struct irix_sigstack *old)
+{
+	int error = -EFAULT;
+
+#ifdef DEBUG_SIG
+	printk("[%s:%d] irix_sigstack(%p,%p)\n",
+	       current->comm, current->pid, new, old);
+#endif
+	if(new) {
+		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
+			goto out;
+	}
+
+	if(old) {
+		if (!access_ok(VERIFY_WRITE, old, sizeof(*old)))
+			goto out;
+	}
+	error = 0;
+
+out:
+	return error;
+}
+
+struct irix_sigaltstack { unsigned long sp; int size; int status; };
+
+asmlinkage int irix_sigaltstack(struct irix_sigaltstack *new,
+				struct irix_sigaltstack *old)
+{
+	int error = -EFAULT;
+
+#ifdef DEBUG_SIG
+	printk("[%s:%d] irix_sigaltstack(%p,%p)\n",
+	       current->comm, current->pid, new, old);
+#endif
+	if (new) {
+		if (!access_ok(VERIFY_READ, new, sizeof(*new)))
+			goto out;
+	}
+
+	if (old) {
+		if (!access_ok(VERIFY_WRITE, old, sizeof(*old)))
+			goto out;
+	}
+	error = 0;
+
+out:
+	error = 0;
+
+	return error;
+}
+
+struct irix_procset {
+	int cmd, ltype, lid, rtype, rid;
+};
+
+asmlinkage int irix_sigsendset(struct irix_procset *pset, int sig)
+{
+	if (!access_ok(VERIFY_READ, pset, sizeof(*pset)))
+		return -EFAULT;
+
+#ifdef DEBUG_SIG
+	printk("[%s:%d] irix_sigsendset([%d,%d,%d,%d,%d],%d)\n",
+	       current->comm, current->pid,
+	       pset->cmd, pset->ltype, pset->lid, pset->rtype, pset->rid,
+	       sig);
+#endif
+	return -EINVAL;
+}
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
new file mode 100644
index 0000000..43c00ac
--- /dev/null
+++ b/arch/mips/kernel/irq-msc01.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2004 MIPS Inc
+ * Author: chris@mips.com
+ *
+ * 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <asm/ptrace.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/msc01_ic.h>
+
+static unsigned long _icctrl_msc;
+#define MSC01_IC_REG_BASE	_icctrl_msc
+
+#define MSCIC_WRITE(reg, data)	do { *(volatile u32 *)(reg) = data; } while (0)
+#define MSCIC_READ(reg, data)	do { data = *(volatile u32 *)(reg); } while (0)
+
+static unsigned int irq_base;
+
+/* mask off an interrupt */
+static inline void mask_msc_irq(unsigned int irq)
+{
+	if (irq < (irq_base + 32))
+		MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base));
+	else
+		MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32));
+}
+
+/* unmask an interrupt */
+static inline void unmask_msc_irq(unsigned int irq)
+{
+	if (irq < (irq_base + 32))
+		MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base));
+	else
+		MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32));
+}
+
+/*
+ * Enables the IRQ on SOC-it
+ */
+static void enable_msc_irq(unsigned int irq)
+{
+	unmask_msc_irq(irq);
+}
+
+/*
+ * Initialize the IRQ on SOC-it
+ */
+static unsigned int startup_msc_irq(unsigned int irq)
+{
+	unmask_msc_irq(irq);
+	return 0;
+}
+
+/*
+ * Disables the IRQ on SOC-it
+ */
+static void disable_msc_irq(unsigned int irq)
+{
+	mask_msc_irq(irq);
+}
+
+/*
+ * Masks and ACKs an IRQ
+ */
+static void level_mask_and_ack_msc_irq(unsigned int irq)
+{
+	mask_msc_irq(irq);
+	if (!cpu_has_ei)
+		MSCIC_WRITE(MSC01_IC_EOI, 0);
+}
+
+/*
+ * Masks and ACKs an IRQ
+ */
+static void edge_mask_and_ack_msc_irq(unsigned int irq)
+{
+	mask_msc_irq(irq);
+	if (!cpu_has_ei)
+		MSCIC_WRITE(MSC01_IC_EOI, 0);
+	else {
+		u32 r;
+		MSCIC_READ(MSC01_IC_SUP+irq*8, r);
+		MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT);
+		MSCIC_WRITE(MSC01_IC_SUP+irq*8, r);
+	}
+}
+
+/*
+ * End IRQ processing
+ */
+static void end_msc_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		unmask_msc_irq(irq);
+}
+
+/*
+ * Interrupt handler for interrupts coming from SOC-it.
+ */
+void ll_msc_irq(struct pt_regs *regs)
+{
+ 	unsigned int irq;
+
+	/* read the interrupt vector register */
+	MSCIC_READ(MSC01_IC_VEC, irq);
+	if (irq < 64)
+		do_IRQ(irq + irq_base, regs);
+	else {
+		/* Ignore spurious interrupt */
+	}
+}
+
+void
+msc_bind_eic_interrupt (unsigned int irq, unsigned int set)
+{
+	MSCIC_WRITE(MSC01_IC_RAMW,
+		    (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF));
+}
+
+#define shutdown_msc_irq	disable_msc_irq
+
+struct hw_interrupt_type msc_levelirq_type = {
+	"SOC-it-Level",
+	startup_msc_irq,
+	shutdown_msc_irq,
+	enable_msc_irq,
+	disable_msc_irq,
+	level_mask_and_ack_msc_irq,
+	end_msc_irq,
+	NULL
+};
+
+struct hw_interrupt_type msc_edgeirq_type = {
+	"SOC-it-Edge",
+	startup_msc_irq,
+	shutdown_msc_irq,
+	enable_msc_irq,
+	disable_msc_irq,
+	edge_mask_and_ack_msc_irq,
+	end_msc_irq,
+	NULL
+};
+
+
+void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq)
+{
+	extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset);
+
+	_icctrl_msc = (unsigned long) ioremap (MIPS_MSC01_IC_REG_BASE, 0x40000);
+
+	/* Reset interrupt controller - initialises all registers to 0 */
+	MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT);
+
+	board_bind_eic_interrupt = &msc_bind_eic_interrupt;
+
+	for (; nirq >= 0; nirq--, imp++) {
+		int n = imp->im_irq;
+
+		switch (imp->im_type) {
+		case MSC01_IRQ_EDGE:
+			irq_desc[base+n].handler = &msc_edgeirq_type;
+			if (cpu_has_ei)
+				MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT);
+			else
+				MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl);
+			break;
+		case MSC01_IRQ_LEVEL:
+			irq_desc[base+n].handler = &msc_levelirq_type;
+			if (cpu_has_ei)
+				MSCIC_WRITE(MSC01_IC_SUP+n*8, 0);
+			else
+				MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl);
+		}
+	}
+
+	irq_base = base;
+
+	MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT);	/* Enable interrupt generation */
+
+}
diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c
new file mode 100644
index 0000000..088bbbc
--- /dev/null
+++ b/arch/mips/kernel/irq-mv6434x.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2002 Momentum Computer
+ * Author: mdharm@momenco.com
+ * Copyright (C) 2004 Ralf Baechle <ralf@linux-mips.org>
+ *
+ * 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <asm/ptrace.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/mv643xx.h>
+
+static unsigned int irq_base;
+
+static inline int ls1bit32(unsigned int x)
+{
+        int b = 31, s;
+
+        s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
+        s =  8; if (x <<  8 == 0) s = 0; b -= s; x <<= s;
+        s =  4; if (x <<  4 == 0) s = 0; b -= s; x <<= s;
+        s =  2; if (x <<  2 == 0) s = 0; b -= s; x <<= s;
+        s =  1; if (x <<  1 == 0) s = 0; b -= s;
+
+        return b;
+}
+
+/* mask off an interrupt -- 1 is enable, 0 is disable */
+static inline void mask_mv64340_irq(unsigned int irq)
+{
+	uint32_t value;
+
+	if (irq < (irq_base + 32)) {
+		value = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW);
+		value &= ~(1 << (irq - irq_base));
+		MV_WRITE(MV64340_INTERRUPT0_MASK_0_LOW, value);
+	} else {
+		value = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH);
+		value &= ~(1 << (irq - irq_base - 32));
+		MV_WRITE(MV64340_INTERRUPT0_MASK_0_HIGH, value);
+	}
+}
+
+/* unmask an interrupt -- 1 is enable, 0 is disable */
+static inline void unmask_mv64340_irq(unsigned int irq)
+{
+	uint32_t value;
+
+	if (irq < (irq_base + 32)) {
+		value = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW);
+		value |= 1 << (irq - irq_base);
+		MV_WRITE(MV64340_INTERRUPT0_MASK_0_LOW, value);
+	} else {
+		value = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH);
+		value |= 1 << (irq - irq_base - 32);
+		MV_WRITE(MV64340_INTERRUPT0_MASK_0_HIGH, value);
+	}
+}
+
+/*
+ * Enables the IRQ on Marvell Chip
+ */
+static void enable_mv64340_irq(unsigned int irq)
+{
+	unmask_mv64340_irq(irq);
+}
+
+/*
+ * Initialize the IRQ on Marvell Chip
+ */
+static unsigned int startup_mv64340_irq(unsigned int irq)
+{
+	unmask_mv64340_irq(irq);
+	return 0;
+}
+
+/*
+ * Disables the IRQ on Marvell Chip
+ */
+static void disable_mv64340_irq(unsigned int irq)
+{
+	mask_mv64340_irq(irq);
+}
+
+/*
+ * Masks and ACKs an IRQ
+ */
+static void mask_and_ack_mv64340_irq(unsigned int irq)
+{
+	mask_mv64340_irq(irq);
+}
+
+/*
+ * End IRQ processing
+ */
+static void end_mv64340_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		unmask_mv64340_irq(irq);
+}
+
+/*
+ * Interrupt handler for interrupts coming from the Marvell chip.
+ * It could be built in ethernet ports etc...
+ */
+void ll_mv64340_irq(struct pt_regs *regs)
+{
+	unsigned int irq_src_low, irq_src_high;
+ 	unsigned int irq_mask_low, irq_mask_high;
+
+	/* read the interrupt status registers */
+	irq_mask_low = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW);
+	irq_mask_high = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH);
+	irq_src_low = MV_READ(MV64340_MAIN_INTERRUPT_CAUSE_LOW);
+	irq_src_high = MV_READ(MV64340_MAIN_INTERRUPT_CAUSE_HIGH);
+
+	/* mask for just the interrupts we want */
+	irq_src_low &= irq_mask_low;
+	irq_src_high &= irq_mask_high;
+
+	if (irq_src_low)
+		do_IRQ(ls1bit32(irq_src_low) + irq_base, regs);
+	else
+		do_IRQ(ls1bit32(irq_src_high) + irq_base + 32, regs);
+}
+
+#define shutdown_mv64340_irq	disable_mv64340_irq
+
+struct hw_interrupt_type mv64340_irq_type = {
+	"MV-64340",
+	startup_mv64340_irq,
+	shutdown_mv64340_irq,
+	enable_mv64340_irq,
+	disable_mv64340_irq,
+	mask_and_ack_mv64340_irq,
+	end_mv64340_irq,
+	NULL
+};
+
+void __init mv64340_irq_init(unsigned int base)
+{
+	int i;
+
+	/* Reset irq handlers pointers to NULL */
+	for (i = base; i < base + 64; i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = 0;
+		irq_desc[i].depth = 2;
+		irq_desc[i].handler = &mv64340_irq_type;
+	}
+
+	irq_base = base;
+}
diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c
new file mode 100644
index 0000000..f5d779f
--- /dev/null
+++ b/arch/mips/kernel/irq-rm7000.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2003 Ralf Baechle
+ *
+ * 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.
+ *
+ * Handler for RM7000 extended interrupts.  These are a non-standard
+ * feature so we handle them separately from standard interrupts.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+static int irq_base;
+
+static inline void unmask_rm7k_irq(unsigned int irq)
+{
+	set_c0_intcontrol(0x100 << (irq - irq_base));
+}
+
+static inline void mask_rm7k_irq(unsigned int irq)
+{
+	clear_c0_intcontrol(0x100 << (irq - irq_base));
+}
+
+static inline void rm7k_cpu_irq_enable(unsigned int irq)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	unmask_rm7k_irq(irq);
+	local_irq_restore(flags);
+}
+
+static void rm7k_cpu_irq_disable(unsigned int irq)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	mask_rm7k_irq(irq);
+	local_irq_restore(flags);
+}
+
+static unsigned int rm7k_cpu_irq_startup(unsigned int irq)
+{
+	rm7k_cpu_irq_enable(irq);
+
+	return 0;
+}
+
+#define	rm7k_cpu_irq_shutdown	rm7k_cpu_irq_disable
+
+/*
+ * While we ack the interrupt interrupts are disabled and thus we don't need
+ * to deal with concurrency issues.  Same for rm7k_cpu_irq_end.
+ */
+static void rm7k_cpu_irq_ack(unsigned int irq)
+{
+	mask_rm7k_irq(irq);
+}
+
+static void rm7k_cpu_irq_end(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		unmask_rm7k_irq(irq);
+}
+
+static hw_irq_controller rm7k_irq_controller = {
+	"RM7000",
+	rm7k_cpu_irq_startup,
+	rm7k_cpu_irq_shutdown,
+	rm7k_cpu_irq_enable,
+	rm7k_cpu_irq_disable,
+	rm7k_cpu_irq_ack,
+	rm7k_cpu_irq_end,
+};
+
+void __init rm7k_cpu_irq_init(int base)
+{
+	int i;
+
+	clear_c0_intcontrol(0x00000f00);		/* Mask all */
+
+	for (i = base; i < base + 4; i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = NULL;
+		irq_desc[i].depth = 1;
+		irq_desc[i].handler = &rm7k_irq_controller;
+	}
+
+	irq_base = base;
+}
diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c
new file mode 100644
index 0000000..bdd1302
--- /dev/null
+++ b/arch/mips/kernel/irq-rm9000.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2003 Ralf Baechle
+ *
+ * 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.
+ *
+ * Handler for RM9000 extended interrupts.  These are a non-standard
+ * feature so we handle them separately from standard interrupts.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+static int irq_base;
+
+static inline void unmask_rm9k_irq(unsigned int irq)
+{
+	set_c0_intcontrol(0x1000 << (irq - irq_base));
+}
+
+static inline void mask_rm9k_irq(unsigned int irq)
+{
+	clear_c0_intcontrol(0x1000 << (irq - irq_base));
+}
+
+static inline void rm9k_cpu_irq_enable(unsigned int irq)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	unmask_rm9k_irq(irq);
+	local_irq_restore(flags);
+}
+
+static void rm9k_cpu_irq_disable(unsigned int irq)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	mask_rm9k_irq(irq);
+	local_irq_restore(flags);
+}
+
+static unsigned int rm9k_cpu_irq_startup(unsigned int irq)
+{
+	rm9k_cpu_irq_enable(irq);
+
+	return 0;
+}
+
+#define	rm9k_cpu_irq_shutdown	rm9k_cpu_irq_disable
+
+/*
+ * Performance counter interrupts are global on all processors.
+ */
+static void local_rm9k_perfcounter_irq_startup(void *args)
+{
+	unsigned int irq = (unsigned int) args;
+
+	rm9k_cpu_irq_enable(irq);
+}
+
+static unsigned int rm9k_perfcounter_irq_startup(unsigned int irq)
+{
+	on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 0, 1);
+
+	return 0;
+}
+
+static void local_rm9k_perfcounter_irq_shutdown(void *args)
+{
+	unsigned int irq = (unsigned int) args;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	mask_rm9k_irq(irq);
+	local_irq_restore(flags);
+}
+
+static void rm9k_perfcounter_irq_shutdown(unsigned int irq)
+{
+	on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 0, 1);
+}
+
+
+/*
+ * While we ack the interrupt interrupts are disabled and thus we don't need
+ * to deal with concurrency issues.  Same for rm9k_cpu_irq_end.
+ */
+static void rm9k_cpu_irq_ack(unsigned int irq)
+{
+	mask_rm9k_irq(irq);
+}
+
+static void rm9k_cpu_irq_end(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		unmask_rm9k_irq(irq);
+}
+
+static hw_irq_controller rm9k_irq_controller = {
+	"RM9000",
+	rm9k_cpu_irq_startup,
+	rm9k_cpu_irq_shutdown,
+	rm9k_cpu_irq_enable,
+	rm9k_cpu_irq_disable,
+	rm9k_cpu_irq_ack,
+	rm9k_cpu_irq_end,
+};
+
+static hw_irq_controller rm9k_perfcounter_irq = {
+	"RM9000",
+	rm9k_perfcounter_irq_startup,
+	rm9k_perfcounter_irq_shutdown,
+	rm9k_cpu_irq_enable,
+	rm9k_cpu_irq_disable,
+	rm9k_cpu_irq_ack,
+	rm9k_cpu_irq_end,
+};
+
+unsigned int rm9000_perfcount_irq;
+
+EXPORT_SYMBOL(rm9000_perfcount_irq);
+
+void __init rm9k_cpu_irq_init(int base)
+{
+	int i;
+
+	clear_c0_intcontrol(0x0000f000);		/* Mask all */
+
+	for (i = base; i < base + 4; i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = NULL;
+		irq_desc[i].depth = 1;
+		irq_desc[i].handler = &rm9k_irq_controller;
+	}
+
+	rm9000_perfcount_irq = base + 1;
+	irq_desc[rm9000_perfcount_irq].handler = &rm9k_perfcounter_irq;
+
+	irq_base = base;
+}
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
new file mode 100644
index 0000000..441157a
--- /dev/null
+++ b/arch/mips/kernel/irq.c
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ *
+ * Code to handle x86 style IRQs plus some generic interrupt stuff.
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1994 - 2000 Ralf Baechle
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/kallsyms.h>
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves.
+ */
+void ack_bad_irq(unsigned int irq)
+{
+	printk("unexpected IRQ # %d\n", irq);
+}
+
+atomic_t irq_err_count;
+
+#undef do_IRQ
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs)
+{
+	irq_enter();
+
+	__do_IRQ(irq, regs);
+
+	irq_exit();
+
+	return 1;
+}
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i = *(loff_t *) v, j;
+	struct irqaction * action;
+	unsigned long flags;
+
+	if (i == 0) {
+		seq_printf(p, "           ");
+		for (j=0; j<NR_CPUS; j++)
+			if (cpu_online(j))
+				seq_printf(p, "CPU%d       ",j);
+		seq_putc(p, '\n');
+	}
+
+	if (i < NR_IRQS) {
+		spin_lock_irqsave(&irq_desc[i].lock, flags);
+		action = irq_desc[i].action;
+		if (!action) 
+			goto skip;
+		seq_printf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+		seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+		for (j = 0; j < NR_CPUS; j++)
+			if (cpu_online(j))
+				seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+		seq_printf(p, " %14s", irq_desc[i].handler->typename);
+		seq_printf(p, "  %s", action->name);
+
+		for (action=action->next; action; action = action->next)
+			seq_printf(p, ", %s", action->name);
+
+		seq_putc(p, '\n');
+skip:
+		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+	} else if (i == NR_IRQS) {
+		seq_putc(p, '\n');
+		seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+	}
+	return 0;
+}
+
+#ifdef CONFIG_KGDB
+extern void breakpoint(void);
+extern void set_debug_traps(void);
+
+static int kgdb_flag = 1;
+static int __init nokgdb(char *str)
+{
+	kgdb_flag = 0;
+	return 1;
+}
+__setup("nokgdb", nokgdb);
+#endif
+
+void __init init_IRQ(void)
+{
+	int i;
+
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].status  = IRQ_DISABLED;
+		irq_desc[i].action  = NULL;
+		irq_desc[i].depth   = 1;
+		irq_desc[i].handler = &no_irq_type;
+		spin_lock_init(&irq_desc[i].lock);
+	}
+
+	arch_init_irq();
+
+#ifdef CONFIG_KGDB
+	if (kgdb_flag) {
+		printk("Wait for gdb client connection ...\n");
+		set_debug_traps();
+		breakpoint();
+	}
+#endif
+}
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
new file mode 100644
index 0000000..2b936cf
--- /dev/null
+++ b/arch/mips/kernel/irq_cpu.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * Copyright (C) 2001 Ralf Baechle
+ *
+ * This file define the irq handler for MIPS CPU interrupts.
+ *
+ * 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.
+ */
+
+/*
+ * Almost all MIPS CPUs define 8 interrupt sources.  They are typically
+ * level triggered (i.e., cannot be cleared from CPU; must be cleared from
+ * device).  The first two are software interrupts which we don't really
+ * use or support.  The last one is usually the CPU timer interrupt if
+ * counter register is present or, for CPUs with an external FPU, by
+ * convention it's the FPU exception interrupt.
+ *
+ * Don't even think about using this on SMP.  You have been warned.
+ *
+ * This file exports one global function:
+ *	void mips_cpu_irq_init(int irq_base);
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+static int mips_cpu_irq_base;
+
+static inline void unmask_mips_irq(unsigned int irq)
+{
+	clear_c0_cause(0x100 << (irq - mips_cpu_irq_base));
+	set_c0_status(0x100 << (irq - mips_cpu_irq_base));
+}
+
+static inline void mask_mips_irq(unsigned int irq)
+{
+	clear_c0_status(0x100 << (irq - mips_cpu_irq_base));
+}
+
+static inline void mips_cpu_irq_enable(unsigned int irq)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	unmask_mips_irq(irq);
+	local_irq_restore(flags);
+}
+
+static void mips_cpu_irq_disable(unsigned int irq)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	mask_mips_irq(irq);
+	local_irq_restore(flags);
+}
+
+static unsigned int mips_cpu_irq_startup(unsigned int irq)
+{
+	mips_cpu_irq_enable(irq);
+
+	return 0;
+}
+
+#define	mips_cpu_irq_shutdown	mips_cpu_irq_disable
+
+/*
+ * While we ack the interrupt interrupts are disabled and thus we don't need
+ * to deal with concurrency issues.  Same for mips_cpu_irq_end.
+ */
+static void mips_cpu_irq_ack(unsigned int irq)
+{
+	/* Only necessary for soft interrupts */
+	clear_c0_cause(0x100 << (irq - mips_cpu_irq_base));
+
+	mask_mips_irq(irq);
+}
+
+static void mips_cpu_irq_end(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		unmask_mips_irq(irq);
+}
+
+static hw_irq_controller mips_cpu_irq_controller = {
+	"MIPS",
+	mips_cpu_irq_startup,
+	mips_cpu_irq_shutdown,
+	mips_cpu_irq_enable,
+	mips_cpu_irq_disable,
+	mips_cpu_irq_ack,
+	mips_cpu_irq_end,
+	NULL			/* no affinity stuff for UP */
+};
+
+
+void __init mips_cpu_irq_init(int irq_base)
+{
+	int i;
+
+	for (i = irq_base; i < irq_base + 8; i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = NULL;
+		irq_desc[i].depth = 1;
+		irq_desc[i].handler = &mips_cpu_irq_controller;
+	}
+
+	mips_cpu_irq_base = irq_base;
+}
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
new file mode 100644
index 0000000..993abc8
--- /dev/null
+++ b/arch/mips/kernel/linux32.c
@@ -0,0 +1,1469 @@
+/*
+ * Conversion between 32-bit and 64-bit native system calls.
+ *
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Written by Ulf Carlsson (ulfc@engr.sgi.com)
+ * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com)
+ */
+#include <linux/config.h>
+#include <linux/compiler.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/smp_lock.h>
+#include <linux/highuid.h>
+#include <linux/dirent.h>
+#include <linux/resource.h>
+#include <linux/highmem.h>
+#include <linux/time.h>
+#include <linux/times.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/filter.h>
+#include <linux/shm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/icmpv6.h>
+#include <linux/syscalls.h>
+#include <linux/sysctl.h>
+#include <linux/utime.h>
+#include <linux/utsname.h>
+#include <linux/personality.h>
+#include <linux/timex.h>
+#include <linux/dnotify.h>
+#include <linux/module.h>
+#include <linux/binfmts.h>
+#include <linux/security.h>
+#include <linux/compat.h>
+#include <linux/vfs.h>
+
+#include <net/sock.h>
+#include <net/scm.h>
+
+#include <asm/ipc.h>
+#include <asm/sim.h>
+#include <asm/uaccess.h>
+#include <asm/mmu_context.h>
+#include <asm/mman.h>
+
+/* Use this to get at 32-bit user passed pointers. */
+/* A() macro should be used for places where you e.g.
+   have some internal variable u32 and just want to get
+   rid of a compiler warning. AA() has to be used in
+   places where you want to convert a function argument
+   to 32bit pointer or when you e.g. access pt_regs
+   structure and want to consider 32bit registers only.
+ */
+#define A(__x) ((unsigned long)(__x))
+#define AA(__x) ((unsigned long)((int)__x))
+
+#ifdef __MIPSEB__
+#define merge_64(r1,r2)	((((r1) & 0xffffffffUL) << 32) + ((r2) & 0xffffffffUL))
+#endif
+#ifdef __MIPSEL__
+#define merge_64(r1,r2)	((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL))
+#endif
+
+/*
+ * Revalidate the inode. This is required for proper NFS attribute caching.
+ */
+
+int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
+{
+	struct compat_stat tmp;
+
+	if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev))
+		return -EOVERFLOW;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.st_dev = new_encode_dev(stat->dev);
+	tmp.st_ino = stat->ino;
+	tmp.st_mode = stat->mode;
+	tmp.st_nlink = stat->nlink;
+	SET_UID(tmp.st_uid, stat->uid);
+	SET_GID(tmp.st_gid, stat->gid);
+	tmp.st_rdev = new_encode_dev(stat->rdev);
+	tmp.st_size = stat->size;
+	tmp.st_atime = stat->atime.tv_sec;
+	tmp.st_mtime = stat->mtime.tv_sec;
+	tmp.st_ctime = stat->ctime.tv_sec;
+#ifdef STAT_HAVE_NSEC
+	tmp.st_atime_nsec = stat->atime.tv_nsec;
+	tmp.st_mtime_nsec = stat->mtime.tv_nsec;
+	tmp.st_ctime_nsec = stat->ctime.tv_nsec;
+#endif
+	tmp.st_blocks = stat->blocks;
+	tmp.st_blksize = stat->blksize;
+	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
+
+asmlinkage unsigned long
+sys32_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+         unsigned long flags, unsigned long fd, unsigned long pgoff)
+{
+	struct file * file = NULL;
+	unsigned long error;
+
+	error = -EINVAL;
+	if (!(flags & MAP_ANONYMOUS)) {
+		error = -EBADF;
+		file = fget(fd);
+		if (!file)
+			goto out;
+	}
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+	if (file)
+		fput(file);
+
+out:
+	return error;
+}
+
+
+asmlinkage int sys_truncate64(const char *path, unsigned int high,
+			      unsigned int low)
+{
+	if ((int)high < 0)
+		return -EINVAL;
+	return sys_truncate(path, ((long) high << 32) | low);
+}
+
+asmlinkage int sys_ftruncate64(unsigned int fd, unsigned int high,
+			       unsigned int low)
+{
+	if ((int)high < 0)
+		return -EINVAL;
+	return sys_ftruncate(fd, ((long) high << 32) | low);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
+{
+	int error;
+	char * filename;
+
+	filename = getname(compat_ptr(regs.regs[4]));
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = compat_do_execve(filename, compat_ptr(regs.regs[5]),
+				 compat_ptr(regs.regs[6]), &regs);
+	putname(filename);
+
+out:
+	return error;
+}
+
+struct dirent32 {
+	unsigned int	d_ino;
+	unsigned int	d_off;
+	unsigned short	d_reclen;
+	char		d_name[NAME_MAX + 1];
+};
+
+static void
+xlate_dirent(void *dirent64, void *dirent32, long n)
+{
+	long off;
+	struct dirent *dirp;
+	struct dirent32 *dirp32;
+
+	off = 0;
+	while (off < n) {
+		dirp = (struct dirent *)(dirent64 + off);
+		dirp32 = (struct dirent32 *)(dirent32 + off);
+		off += dirp->d_reclen;
+		dirp32->d_ino = dirp->d_ino;
+		dirp32->d_off = (unsigned int)dirp->d_off;
+		dirp32->d_reclen = dirp->d_reclen;
+		strncpy(dirp32->d_name, dirp->d_name, dirp->d_reclen - ((3 * 4) + 2));
+	}
+	return;
+}
+
+asmlinkage long
+sys32_getdents(unsigned int fd, void * dirent32, unsigned int count)
+{
+	long n;
+	void *dirent64;
+
+	dirent64 = (void *)((unsigned long)(dirent32 + (sizeof(long) - 1)) & ~(sizeof(long) - 1));
+	if ((n = sys_getdents(fd, dirent64, count - (dirent64 - dirent32))) < 0)
+		return(n);
+	xlate_dirent(dirent64, dirent32, n);
+	return(n);
+}
+
+asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count);
+
+asmlinkage int
+sys32_readdir(unsigned int fd, void * dirent32, unsigned int count)
+{
+	int n;
+	struct dirent dirent64;
+
+	if ((n = old_readdir(fd, &dirent64, count)) < 0)
+		return(n);
+	xlate_dirent(&dirent64, dirent32, dirent64.d_reclen);
+	return(n);
+}
+
+struct rusage32 {
+        struct compat_timeval ru_utime;
+        struct compat_timeval ru_stime;
+        int    ru_maxrss;
+        int    ru_ixrss;
+        int    ru_idrss;
+        int    ru_isrss;
+        int    ru_minflt;
+        int    ru_majflt;
+        int    ru_nswap;
+        int    ru_inblock;
+        int    ru_oublock;
+        int    ru_msgsnd;
+        int    ru_msgrcv;
+        int    ru_nsignals;
+        int    ru_nvcsw;
+        int    ru_nivcsw;
+};
+
+static int
+put_rusage (struct rusage32 *ru, struct rusage *r)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, ru, sizeof *ru))
+		return -EFAULT;
+
+	err = __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
+	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
+	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
+	err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
+	err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
+	err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
+	err |= __put_user (r->ru_idrss, &ru->ru_idrss);
+	err |= __put_user (r->ru_isrss, &ru->ru_isrss);
+	err |= __put_user (r->ru_minflt, &ru->ru_minflt);
+	err |= __put_user (r->ru_majflt, &ru->ru_majflt);
+	err |= __put_user (r->ru_nswap, &ru->ru_nswap);
+	err |= __put_user (r->ru_inblock, &ru->ru_inblock);
+	err |= __put_user (r->ru_oublock, &ru->ru_oublock);
+	err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
+	err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
+	err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
+	err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
+	err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
+
+	return err;
+}
+
+asmlinkage int
+sys32_wait4(compat_pid_t pid, unsigned int * stat_addr, int options,
+	    struct rusage32 * ru)
+{
+	if (!ru)
+		return sys_wait4(pid, stat_addr, options, NULL);
+	else {
+		struct rusage r;
+		int ret;
+		unsigned int status;
+		mm_segment_t old_fs = get_fs();
+
+		set_fs(KERNEL_DS);
+		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
+		set_fs(old_fs);
+		if (put_rusage (ru, &r)) return -EFAULT;
+		if (stat_addr && put_user (status, stat_addr))
+			return -EFAULT;
+		return ret;
+	}
+}
+
+asmlinkage int
+sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options)
+{
+	return sys32_wait4(pid, stat_addr, options, NULL);
+}
+
+struct sysinfo32 {
+        s32 uptime;
+        u32 loads[3];
+        u32 totalram;
+        u32 freeram;
+        u32 sharedram;
+        u32 bufferram;
+        u32 totalswap;
+        u32 freeswap;
+        u16 procs;
+	u32 totalhigh;
+	u32 freehigh;
+	u32 mem_unit;
+	char _f[8];
+};
+
+asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
+{
+	struct sysinfo s;
+	int ret, err;
+	mm_segment_t old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_sysinfo(&s);
+	set_fs (old_fs);
+	err = put_user (s.uptime, &info->uptime);
+	err |= __put_user (s.loads[0], &info->loads[0]);
+	err |= __put_user (s.loads[1], &info->loads[1]);
+	err |= __put_user (s.loads[2], &info->loads[2]);
+	err |= __put_user (s.totalram, &info->totalram);
+	err |= __put_user (s.freeram, &info->freeram);
+	err |= __put_user (s.sharedram, &info->sharedram);
+	err |= __put_user (s.bufferram, &info->bufferram);
+	err |= __put_user (s.totalswap, &info->totalswap);
+	err |= __put_user (s.freeswap, &info->freeswap);
+	err |= __put_user (s.procs, &info->procs);
+	err |= __put_user (s.totalhigh, &info->totalhigh);
+	err |= __put_user (s.freehigh, &info->freehigh);
+	err |= __put_user (s.mem_unit, &info->mem_unit);
+	if (err)
+		return -EFAULT;
+	return ret;
+}
+
+#define RLIM_INFINITY32	0x7fffffff
+#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
+
+struct rlimit32 {
+	int	rlim_cur;
+	int	rlim_max;
+};
+
+#ifdef __MIPSEB__
+asmlinkage long sys32_truncate64(const char * path, unsigned long __dummy,
+	int length_hi, int length_lo)
+#endif
+#ifdef __MIPSEL__
+asmlinkage long sys32_truncate64(const char * path, unsigned long __dummy,
+	int length_lo, int length_hi)
+#endif
+{
+	loff_t length;
+
+	length = ((unsigned long) length_hi << 32) | (unsigned int) length_lo;
+
+	return sys_truncate(path, length);
+}
+
+#ifdef __MIPSEB__
+asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long __dummy,
+	int length_hi, int length_lo)
+#endif
+#ifdef __MIPSEL__
+asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long __dummy,
+	int length_lo, int length_hi)
+#endif
+{
+	loff_t length;
+
+	length = ((unsigned long) length_hi << 32) | (unsigned int) length_lo;
+
+	return sys_ftruncate(fd, length);
+}
+
+static inline long
+get_tv32(struct timeval *o, struct compat_timeval *i)
+{
+	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
+		(__get_user(o->tv_sec, &i->tv_sec) |
+		 __get_user(o->tv_usec, &i->tv_usec)));
+}
+
+static inline long
+put_tv32(struct compat_timeval *o, struct timeval *i)
+{
+	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+		(__put_user(i->tv_sec, &o->tv_sec) |
+		 __put_user(i->tv_usec, &o->tv_usec)));
+}
+
+extern struct timezone sys_tz;
+
+asmlinkage int
+sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
+{
+	if (tv) {
+		struct timeval ktv;
+		do_gettimeofday(&ktv);
+		if (put_tv32(tv, &ktv))
+			return -EFAULT;
+	}
+	if (tz) {
+		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
+{
+	long usec;
+
+	if (!access_ok(VERIFY_READ, i, sizeof(*i)))
+		return -EFAULT;
+	if (__get_user(o->tv_sec, &i->tv_sec))
+		return -EFAULT;
+	if (__get_user(usec, &i->tv_usec))
+		return -EFAULT;
+	o->tv_nsec = usec * 1000;
+		return 0;
+}
+
+asmlinkage int
+sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
+{
+	struct timespec kts;
+	struct timezone ktz;
+
+ 	if (tv) {
+		if (get_ts32(&kts, tv))
+			return -EFAULT;
+	}
+	if (tz) {
+		if (copy_from_user(&ktz, tz, sizeof(ktz)))
+			return -EFAULT;
+	}
+
+	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
+}
+
+asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
+			    unsigned int offset_low, loff_t * result,
+			    unsigned int origin)
+{
+	return sys_llseek(fd, offset_high, offset_low, result, origin);
+}
+
+/* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
+   lseek back to original location.  They fail just like lseek does on
+   non-seekable files.  */
+
+asmlinkage ssize_t sys32_pread(unsigned int fd, char * buf,
+			       size_t count, u32 unused, u64 a4, u64 a5)
+{
+	ssize_t ret;
+	struct file * file;
+	ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+	loff_t pos;
+
+	ret = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto bad_file;
+	if (!(file->f_mode & FMODE_READ))
+		goto out;
+	pos = merge_64(a4, a5);
+	ret = rw_verify_area(READ, file, &pos, count);
+	if (ret)
+		goto out;
+	ret = -EINVAL;
+	if (!file->f_op || !(read = file->f_op->read))
+		goto out;
+	if (pos < 0)
+		goto out;
+	ret = -ESPIPE;
+	if (!(file->f_mode & FMODE_PREAD))
+		goto out;
+	ret = read(file, buf, count, &pos);
+	if (ret > 0)
+		dnotify_parent(file->f_dentry, DN_ACCESS);
+out:
+	fput(file);
+bad_file:
+	return ret;
+}
+
+asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char * buf,
+			        size_t count, u32 unused, u64 a4, u64 a5)
+{
+	ssize_t ret;
+	struct file * file;
+	ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+	loff_t pos;
+
+	ret = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto bad_file;
+	if (!(file->f_mode & FMODE_WRITE))
+		goto out;
+	pos = merge_64(a4, a5);
+	ret = rw_verify_area(WRITE, file, &pos, count);
+	if (ret)
+		goto out;
+	ret = -EINVAL;
+	if (!file->f_op || !(write = file->f_op->write))
+		goto out;
+	if (pos < 0)
+		goto out;
+
+	ret = -ESPIPE;
+	if (!(file->f_mode & FMODE_PWRITE))
+		goto out;
+
+	ret = write(file, buf, count, &pos);
+	if (ret > 0)
+		dnotify_parent(file->f_dentry, DN_MODIFY);
+out:
+	fput(file);
+bad_file:
+	return ret;
+}
+
+asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
+	struct compat_timespec *interval)
+{
+	struct timespec t;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+
+	set_fs (KERNEL_DS);
+	ret = sys_sched_rr_get_interval(pid, &t);
+	set_fs (old_fs);
+	if (put_user (t.tv_sec, &interval->tv_sec) ||
+	    __put_user (t.tv_nsec, &interval->tv_nsec))
+		return -EFAULT;
+	return ret;
+}
+
+struct msgbuf32 { s32 mtype; char mtext[1]; };
+
+struct ipc_perm32
+{
+	key_t    	  key;
+        compat_uid_t  uid;
+        compat_gid_t  gid;
+        compat_uid_t  cuid;
+        compat_gid_t  cgid;
+        compat_mode_t	mode;
+        unsigned short  seq;
+};
+
+struct ipc64_perm32 {
+	key_t key;
+	compat_uid_t uid;
+	compat_gid_t gid;
+	compat_uid_t cuid;
+	compat_gid_t cgid;
+	compat_mode_t	mode; 
+	unsigned short	seq;
+	unsigned short __pad1;
+	unsigned int __unused1;
+	unsigned int __unused2;
+};
+
+struct semid_ds32 {
+        struct ipc_perm32 sem_perm;               /* permissions .. see ipc.h */
+        compat_time_t   sem_otime;              /* last semop time */
+        compat_time_t   sem_ctime;              /* last change time */
+        u32 sem_base;              /* ptr to first semaphore in array */
+        u32 sem_pending;          /* pending operations to be processed */
+        u32 sem_pending_last;    /* last pending operation */
+        u32 undo;                  /* undo requests on this array */
+        unsigned short  sem_nsems;              /* no. of semaphores in array */
+};
+
+struct semid64_ds32 {
+	struct ipc64_perm32	sem_perm;
+	compat_time_t	sem_otime;
+	compat_time_t	sem_ctime;
+	unsigned int		sem_nsems;
+	unsigned int		__unused1;
+	unsigned int		__unused2;
+};
+
+struct msqid_ds32
+{
+        struct ipc_perm32 msg_perm;
+        u32 msg_first;
+        u32 msg_last;
+        compat_time_t   msg_stime;
+        compat_time_t   msg_rtime;
+        compat_time_t   msg_ctime;
+        u32 wwait;
+        u32 rwait;
+        unsigned short msg_cbytes;
+        unsigned short msg_qnum;
+        unsigned short msg_qbytes;
+        compat_ipc_pid_t msg_lspid;
+        compat_ipc_pid_t msg_lrpid;
+};
+
+struct msqid64_ds32 {
+	struct ipc64_perm32 msg_perm;
+	compat_time_t msg_stime;
+	unsigned int __unused1;
+	compat_time_t msg_rtime;
+	unsigned int __unused2;
+	compat_time_t msg_ctime;
+	unsigned int __unused3;
+	unsigned int msg_cbytes;
+	unsigned int msg_qnum;
+	unsigned int msg_qbytes;
+	compat_pid_t msg_lspid;
+	compat_pid_t msg_lrpid;
+	unsigned int __unused4;
+	unsigned int __unused5;
+};
+
+struct shmid_ds32 {
+        struct ipc_perm32       shm_perm;
+        int                     shm_segsz;
+        compat_time_t		shm_atime;
+        compat_time_t		shm_dtime;
+        compat_time_t		shm_ctime;
+        compat_ipc_pid_t    shm_cpid;
+        compat_ipc_pid_t    shm_lpid;
+        unsigned short          shm_nattch;
+};
+
+struct shmid64_ds32 {
+	struct ipc64_perm32	shm_perm;
+	compat_size_t		shm_segsz;
+	compat_time_t		shm_atime;
+	compat_time_t		shm_dtime;
+	compat_time_t shm_ctime;
+	compat_pid_t shm_cpid;
+	compat_pid_t shm_lpid;
+	unsigned int shm_nattch;
+	unsigned int __unused1;
+	unsigned int __unused2;
+};
+
+struct ipc_kludge32 {
+	u32 msgp;
+	s32 msgtyp;
+};
+
+static int
+do_sys32_semctl(int first, int second, int third, void *uptr)
+{
+	union semun fourth;
+	u32 pad;
+	int err, err2;
+	struct semid64_ds s;
+	mm_segment_t old_fs;
+
+	if (!uptr)
+		return -EINVAL;
+	err = -EFAULT;
+	if (get_user (pad, (u32 *)uptr))
+		return err;
+	if ((third & ~IPC_64) == SETVAL)
+		fourth.val = (int)pad;
+	else
+		fourth.__pad = (void *)A(pad);
+	switch (third & ~IPC_64) {
+	case IPC_INFO:
+	case IPC_RMID:
+	case IPC_SET:
+	case SEM_INFO:
+	case GETVAL:
+	case GETPID:
+	case GETNCNT:
+	case GETZCNT:
+	case GETALL:
+	case SETVAL:
+	case SETALL:
+		err = sys_semctl (first, second, third, fourth);
+		break;
+
+	case IPC_STAT:
+	case SEM_STAT:
+		fourth.__pad = &s;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_semctl(first, second, third | IPC_64, fourth);
+		set_fs(old_fs);
+
+		if (third & IPC_64) {
+			struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad);
+
+			if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key);
+			err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid);
+			err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid);
+			err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid);
+			err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid);
+			err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode);
+			err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq);
+			err2 |= __put_user(s.sem_otime, &usp64->sem_otime);
+			err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime);
+			err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems);
+		} else {
+			struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad);
+
+			if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key);
+			err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid);
+			err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid);
+			err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid);
+			err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid);
+			err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode);
+			err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq);
+			err2 |= __put_user(s.sem_otime, &usp32->sem_otime);
+			err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime);
+			err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems);
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	default:
+		err = - EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int
+do_sys32_msgsnd (int first, int second, int third, void *uptr)
+{
+	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+	struct msgbuf *p;
+	mm_segment_t old_fs;
+	int err;
+
+	if (second < 0)
+		return -EINVAL;
+	p = kmalloc (second + sizeof (struct msgbuf)
+				    + 4, GFP_USER);
+	if (!p)
+		return -ENOMEM;
+	err = get_user (p->mtype, &up->mtype);
+	if (err)
+		goto out;
+	err |= __copy_from_user (p->mtext, &up->mtext, second);
+	if (err)
+		goto out;
+	old_fs = get_fs ();
+	set_fs (KERNEL_DS);
+	err = sys_msgsnd (first, p, second, third);
+	set_fs (old_fs);
+out:
+	kfree (p);
+
+	return err;
+}
+
+static int
+do_sys32_msgrcv (int first, int second, int msgtyp, int third,
+		 int version, void *uptr)
+{
+	struct msgbuf32 *up;
+	struct msgbuf *p;
+	mm_segment_t old_fs;
+	int err;
+
+	if (!version) {
+		struct ipc_kludge32 *uipck = (struct ipc_kludge32 *)uptr;
+		struct ipc_kludge32 ipck;
+
+		err = -EINVAL;
+		if (!uptr)
+			goto out;
+		err = -EFAULT;
+		if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge32)))
+			goto out;
+		uptr = (void *)AA(ipck.msgp);
+		msgtyp = ipck.msgtyp;
+	}
+
+	if (second < 0)
+		return -EINVAL;
+	err = -ENOMEM;
+	p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+	if (!p)
+		goto out;
+	old_fs = get_fs ();
+	set_fs (KERNEL_DS);
+	err = sys_msgrcv (first, p, second + 4, msgtyp, third);
+	set_fs (old_fs);
+	if (err < 0)
+		goto free_then_out;
+	up = (struct msgbuf32 *)uptr;
+	if (put_user (p->mtype, &up->mtype) ||
+	    __copy_to_user (&up->mtext, p->mtext, err))
+		err = -EFAULT;
+free_then_out:
+	kfree (p);
+out:
+	return err;
+}
+
+static int
+do_sys32_msgctl (int first, int second, void *uptr)
+{
+	int err = -EINVAL, err2;
+	struct msqid64_ds m;
+	struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr;
+	struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr;
+	mm_segment_t old_fs;
+
+	switch (second & ~IPC_64) {
+	case IPC_INFO:
+	case IPC_RMID:
+	case MSG_INFO:
+		err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
+		break;
+
+	case IPC_SET:
+		if (second & IPC_64) {
+			if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) {
+				err = -EFAULT;
+				break;
+			}
+			err = __get_user(m.msg_perm.uid, &up64->msg_perm.uid);
+			err |= __get_user(m.msg_perm.gid, &up64->msg_perm.gid);
+			err |= __get_user(m.msg_perm.mode, &up64->msg_perm.mode);
+			err |= __get_user(m.msg_qbytes, &up64->msg_qbytes);
+		} else {
+			if (!access_ok(VERIFY_READ, up32, sizeof(*up32))) {
+				err = -EFAULT;
+				break;
+			}
+			err = __get_user(m.msg_perm.uid, &up32->msg_perm.uid);
+			err |= __get_user(m.msg_perm.gid, &up32->msg_perm.gid);
+			err |= __get_user(m.msg_perm.mode, &up32->msg_perm.mode);
+			err |= __get_user(m.msg_qbytes, &up32->msg_qbytes);
+		}
+		if (err)
+			break;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_msgctl(first, second | IPC_64, (struct msqid_ds *)&m);
+		set_fs(old_fs);
+		break;
+
+	case IPC_STAT:
+	case MSG_STAT:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_msgctl(first, second | IPC_64, (struct msqid_ds *)&m);
+		set_fs(old_fs);
+		if (second & IPC_64) {
+			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(m.msg_perm.key, &up64->msg_perm.key);
+			err2 |= __put_user(m.msg_perm.uid, &up64->msg_perm.uid);
+			err2 |= __put_user(m.msg_perm.gid, &up64->msg_perm.gid);
+			err2 |= __put_user(m.msg_perm.cuid, &up64->msg_perm.cuid);
+			err2 |= __put_user(m.msg_perm.cgid, &up64->msg_perm.cgid);
+			err2 |= __put_user(m.msg_perm.mode, &up64->msg_perm.mode);
+			err2 |= __put_user(m.msg_perm.seq, &up64->msg_perm.seq);
+			err2 |= __put_user(m.msg_stime, &up64->msg_stime);
+			err2 |= __put_user(m.msg_rtime, &up64->msg_rtime);
+			err2 |= __put_user(m.msg_ctime, &up64->msg_ctime);
+			err2 |= __put_user(m.msg_cbytes, &up64->msg_cbytes);
+			err2 |= __put_user(m.msg_qnum, &up64->msg_qnum);
+			err2 |= __put_user(m.msg_qbytes, &up64->msg_qbytes);
+			err2 |= __put_user(m.msg_lspid, &up64->msg_lspid);
+			err2 |= __put_user(m.msg_lrpid, &up64->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		} else {
+			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(m.msg_perm.key, &up32->msg_perm.key);
+			err2 |= __put_user(m.msg_perm.uid, &up32->msg_perm.uid);
+			err2 |= __put_user(m.msg_perm.gid, &up32->msg_perm.gid);
+			err2 |= __put_user(m.msg_perm.cuid, &up32->msg_perm.cuid);
+			err2 |= __put_user(m.msg_perm.cgid, &up32->msg_perm.cgid);
+			err2 |= __put_user(m.msg_perm.mode, &up32->msg_perm.mode);
+			err2 |= __put_user(m.msg_perm.seq, &up32->msg_perm.seq);
+			err2 |= __put_user(m.msg_stime, &up32->msg_stime);
+			err2 |= __put_user(m.msg_rtime, &up32->msg_rtime);
+			err2 |= __put_user(m.msg_ctime, &up32->msg_ctime);
+			err2 |= __put_user(m.msg_cbytes, &up32->msg_cbytes);
+			err2 |= __put_user(m.msg_qnum, &up32->msg_qnum);
+			err2 |= __put_user(m.msg_qbytes, &up32->msg_qbytes);
+			err2 |= __put_user(m.msg_lspid, &up32->msg_lspid);
+			err2 |= __put_user(m.msg_lrpid, &up32->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		}
+		break;
+	}
+
+	return err;
+}
+
+static int
+do_sys32_shmat (int first, int second, int third, int version, void *uptr)
+{
+	unsigned long raddr;
+	u32 *uaddr = (u32 *)A((u32)third);
+	int err = -EINVAL;
+
+	if (version == 1)
+		return err;
+	err = do_shmat (first, uptr, second, &raddr);
+	if (err)
+		return err;
+	err = put_user (raddr, uaddr);
+	return err;
+}
+
+struct shm_info32 {
+	int used_ids;
+	u32 shm_tot, shm_rss, shm_swp;
+	u32 swap_attempts, swap_successes;
+};
+
+static int
+do_sys32_shmctl (int first, int second, void *uptr)
+{
+	struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr;
+	struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr;
+	struct shm_info32 *uip = (struct shm_info32 *)uptr;
+	int err = -EFAULT, err2;
+	struct shmid64_ds s64;
+	mm_segment_t old_fs;
+	struct shm_info si;
+	struct shmid_ds s;
+
+	switch (second & ~IPC_64) {
+	case IPC_INFO:
+		second = IPC_INFO; /* So that we don't have to translate it */
+	case IPC_RMID:
+	case SHM_LOCK:
+	case SHM_UNLOCK:
+		err = sys_shmctl(first, second, (struct shmid_ds *)uptr);
+		break;
+	case IPC_SET:
+		if (second & IPC_64) {
+			err = get_user(s.shm_perm.uid, &up64->shm_perm.uid);
+			err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid);
+			err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode);
+		} else {
+			err = get_user(s.shm_perm.uid, &up32->shm_perm.uid);
+			err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid);
+			err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode);
+		}
+		if (err)
+			break;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second & ~IPC_64, &s);
+		set_fs(old_fs);
+		break;
+
+	case IPC_STAT:
+	case SHM_STAT:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second | IPC_64, (void *) &s64);
+		set_fs(old_fs);
+		if (err < 0)
+			break;
+		if (second & IPC_64) {
+			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key);
+			err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid);
+			err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid);
+			err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid);
+			err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid);
+			err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode);
+			err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq);
+			err2 |= __put_user(s64.shm_atime, &up64->shm_atime);
+			err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime);
+			err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime);
+			err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz);
+			err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch);
+			err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid);
+			err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid);
+		} else {
+			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {
+				err = -EFAULT;
+				break;
+			}
+			err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key);
+			err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid);
+			err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid);
+			err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid);
+			err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid);
+			err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode);
+			err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq);
+			err2 |= __put_user(s64.shm_atime, &up32->shm_atime);
+			err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime);
+			err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime);
+			err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz);
+			err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch);
+			err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid);
+			err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid);
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	case SHM_INFO:
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second, (void *)&si);
+		set_fs(old_fs);
+		if (err < 0)
+			break;
+		err2 = put_user(si.used_ids, &uip->used_ids);
+		err2 |= __put_user(si.shm_tot, &uip->shm_tot);
+		err2 |= __put_user(si.shm_rss, &uip->shm_rss);
+		err2 |= __put_user(si.shm_swp, &uip->shm_swp);
+		err2 |= __put_user(si.swap_attempts, &uip->swap_attempts);
+		err2 |= __put_user (si.swap_successes, &uip->swap_successes);
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int sys32_semtimedop(int semid, struct sembuf *tsems, int nsems,
+                            const struct compat_timespec *timeout32)
+{
+	struct compat_timespec t32;
+	struct timespec *t64 = compat_alloc_user_space(sizeof(*t64));
+
+	if (copy_from_user(&t32, timeout32, sizeof(t32)))
+		return -EFAULT;
+
+	if (put_user(t32.tv_sec, &t64->tv_sec) ||
+	    put_user(t32.tv_nsec, &t64->tv_nsec))
+		return -EFAULT;
+
+	return sys_semtimedop(semid, tsems, nsems, t64);
+}
+
+asmlinkage long
+sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+{
+	int version, err;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	switch (call) {
+	case SEMOP:
+		/* struct sembuf is the same on 32 and 64bit :)) */
+		err = sys_semtimedop (first, (struct sembuf *)AA(ptr), second,
+		                      NULL);
+		break;
+	case SEMTIMEDOP:
+		err = sys32_semtimedop (first, (struct sembuf *)AA(ptr), second,
+		                      (const struct compat_timespec __user *)AA(fifth));
+		break;
+	case SEMGET:
+		err = sys_semget (first, second, third);
+		break;
+	case SEMCTL:
+		err = do_sys32_semctl (first, second, third,
+				       (void *)AA(ptr));
+		break;
+
+	case MSGSND:
+		err = do_sys32_msgsnd (first, second, third,
+				       (void *)AA(ptr));
+		break;
+	case MSGRCV:
+		err = do_sys32_msgrcv (first, second, fifth, third,
+				       version, (void *)AA(ptr));
+		break;
+	case MSGGET:
+		err = sys_msgget ((key_t) first, second);
+		break;
+	case MSGCTL:
+		err = do_sys32_msgctl (first, second, (void *)AA(ptr));
+		break;
+
+	case SHMAT:
+		err = do_sys32_shmat (first, second, third,
+				      version, (void *)AA(ptr));
+		break;
+	case SHMDT:
+		err = sys_shmdt ((char *)A(ptr));
+		break;
+	case SHMGET:
+		err = sys_shmget (first, (unsigned)second, third);
+		break;
+	case SHMCTL:
+		err = do_sys32_shmctl (first, second, (void *)AA(ptr));
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+asmlinkage long sys32_shmat(int shmid, char __user *shmaddr,
+			  int shmflg, int32_t *addr)
+{
+	unsigned long raddr;
+	int err;
+
+	err = do_shmat(shmid, shmaddr, shmflg, &raddr);
+	if (err)
+		return err;
+
+	return put_user(raddr, addr);
+}
+
+struct sysctl_args32
+{
+	compat_caddr_t name;
+	int nlen;
+	compat_caddr_t oldval;
+	compat_caddr_t oldlenp;
+	compat_caddr_t newval;
+	compat_size_t newlen;
+	unsigned int __unused[4];
+};
+
+#ifdef CONFIG_SYSCTL
+
+asmlinkage long sys32_sysctl(struct sysctl_args32 *args)
+{
+	struct sysctl_args32 tmp;
+	int error;
+	size_t oldlen, *oldlenp = NULL;
+	unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+
+	if (copy_from_user(&tmp, args, sizeof(tmp)))
+		return -EFAULT;
+
+	if (tmp.oldval && tmp.oldlenp) {
+		/* Duh, this is ugly and might not work if sysctl_args
+		   is in read-only memory, but do_sysctl does indirectly
+		   a lot of uaccess in both directions and we'd have to
+		   basically copy the whole sysctl.c here, and
+		   glibc's __sysctl uses rw memory for the structure
+		   anyway.  */
+		if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||
+		    put_user(oldlen, (size_t *)addr))
+			return -EFAULT;
+		oldlenp = (size_t *)addr;
+	}
+
+	lock_kernel();
+	error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),
+			  oldlenp, (void *)A(tmp.newval), tmp.newlen);
+	unlock_kernel();
+	if (oldlenp) {
+		if (!error) {
+			if (get_user(oldlen, (size_t *)addr) ||
+			    put_user(oldlen, (u32 *)A(tmp.oldlenp)))
+				error = -EFAULT;
+		}
+		copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
+	}
+	return error;
+}
+
+#endif /* CONFIG_SYSCTL */
+
+asmlinkage long sys32_newuname(struct new_utsname * name)
+{
+	int ret = 0;
+
+	down_read(&uts_sem);
+	if (copy_to_user(name,&system_utsname,sizeof *name))
+		ret = -EFAULT;
+	up_read(&uts_sem);
+
+	if (current->personality == PER_LINUX32 && !ret)
+		if (copy_to_user(name->machine, "mips\0\0\0", 8))
+			ret = -EFAULT;
+
+	return ret;
+}
+
+asmlinkage int sys32_personality(unsigned long personality)
+{
+	int ret;
+	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+		personality = PER_LINUX32;
+	ret = sys_personality(personality);
+	if (ret == PER_LINUX32)
+		ret = PER_LINUX;
+	return ret;
+}
+
+/* ustat compatibility */
+struct ustat32 {
+	compat_daddr_t	f_tfree;
+	compat_ino_t	f_tinode;
+	char		f_fname[6];
+	char		f_fpack[6];
+};
+
+extern asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf);
+
+asmlinkage int sys32_ustat(dev_t dev, struct ustat32 * ubuf32)
+{
+	int err;
+        struct ustat tmp;
+	struct ustat32 tmp32;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	err = sys_ustat(dev, &tmp);
+	set_fs (old_fs);
+
+	if (err)
+		goto out;
+
+        memset(&tmp32,0,sizeof(struct ustat32));
+        tmp32.f_tfree = tmp.f_tfree;
+        tmp32.f_tinode = tmp.f_tinode;
+
+        err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0;
+
+out:
+	return err;
+}
+
+/* Handle adjtimex compatibility. */
+
+struct timex32 {
+	u32 modes;
+	s32 offset, freq, maxerror, esterror;
+	s32 status, constant, precision, tolerance;
+	struct compat_timeval time;
+	s32 tick;
+	s32 ppsfreq, jitter, shift, stabil;
+	s32 jitcnt, calcnt, errcnt, stbcnt;
+	s32  :32; s32  :32; s32  :32; s32  :32;
+	s32  :32; s32  :32; s32  :32; s32  :32;
+	s32  :32; s32  :32; s32  :32; s32  :32;
+};
+
+extern int do_adjtimex(struct timex *);
+
+asmlinkage int sys32_adjtimex(struct timex32 *utp)
+{
+	struct timex txc;
+	int ret;
+
+	memset(&txc, 0, sizeof(struct timex));
+
+	if (get_user(txc.modes, &utp->modes) ||
+	   __get_user(txc.offset, &utp->offset) ||
+	   __get_user(txc.freq, &utp->freq) ||
+	   __get_user(txc.maxerror, &utp->maxerror) ||
+	   __get_user(txc.esterror, &utp->esterror) ||
+	   __get_user(txc.status, &utp->status) ||
+	   __get_user(txc.constant, &utp->constant) ||
+	   __get_user(txc.precision, &utp->precision) ||
+	   __get_user(txc.tolerance, &utp->tolerance) ||
+	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+	   __get_user(txc.tick, &utp->tick) ||
+	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||
+	   __get_user(txc.jitter, &utp->jitter) ||
+	   __get_user(txc.shift, &utp->shift) ||
+	   __get_user(txc.stabil, &utp->stabil) ||
+	   __get_user(txc.jitcnt, &utp->jitcnt) ||
+	   __get_user(txc.calcnt, &utp->calcnt) ||
+	   __get_user(txc.errcnt, &utp->errcnt) ||
+	   __get_user(txc.stbcnt, &utp->stbcnt))
+		return -EFAULT;
+
+	ret = do_adjtimex(&txc);
+
+	if (put_user(txc.modes, &utp->modes) ||
+	   __put_user(txc.offset, &utp->offset) ||
+	   __put_user(txc.freq, &utp->freq) ||
+	   __put_user(txc.maxerror, &utp->maxerror) ||
+	   __put_user(txc.esterror, &utp->esterror) ||
+	   __put_user(txc.status, &utp->status) ||
+	   __put_user(txc.constant, &utp->constant) ||
+	   __put_user(txc.precision, &utp->precision) ||
+	   __put_user(txc.tolerance, &utp->tolerance) ||
+	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+	   __put_user(txc.tick, &utp->tick) ||
+	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||
+	   __put_user(txc.jitter, &utp->jitter) ||
+	   __put_user(txc.shift, &utp->shift) ||
+	   __put_user(txc.stabil, &utp->stabil) ||
+	   __put_user(txc.jitcnt, &utp->jitcnt) ||
+	   __put_user(txc.calcnt, &utp->calcnt) ||
+	   __put_user(txc.errcnt, &utp->errcnt) ||
+	   __put_user(txc.stbcnt, &utp->stbcnt))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset,
+	s32 count)
+{
+	mm_segment_t old_fs = get_fs();
+	int ret;
+	off_t of;
+	
+	if (offset && get_user(of, offset))
+		return -EFAULT;
+		
+	set_fs(KERNEL_DS);
+	ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+	set_fs(old_fs);
+	
+	if (offset && put_user(of, offset))
+		return -EFAULT;
+		
+	return ret;
+}
+
+asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
+                                   size_t count)
+{
+	return sys_readahead(fd, merge_64(a2, a3), count);
+}
+
+/* Argument list sizes for sys_socketcall */
+#define AL(x) ((x) * sizeof(unsigned int))
+static unsigned char socketcall_nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+				AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
+				AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
+#undef AL
+
+/*
+ *	System call vectors. 
+ *
+ *	Argument checking cleaned up. Saved 20% in size.
+ *  This function doesn't need to set the kernel lock because
+ *  it is set by the callees. 
+ */
+
+asmlinkage long sys32_socketcall(int call, unsigned int *args32)
+{
+	unsigned int a[6];
+	unsigned int a0,a1;
+	int err;
+
+	extern asmlinkage long sys_socket(int family, int type, int protocol);
+	extern asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen);
+	extern asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen);
+	extern asmlinkage long sys_listen(int fd, int backlog);
+	extern asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen);
+	extern asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len);
+	extern asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len);
+	extern asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *usockvec);
+	extern asmlinkage long sys_send(int fd, void __user * buff, size_t len, unsigned flags);
+	extern asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags,
+					  struct sockaddr __user *addr, int addr_len);
+	extern asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags);
+	extern asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned flags,
+					    struct sockaddr __user *addr, int __user *addr_len);
+	extern asmlinkage long sys_shutdown(int fd, int how);
+	extern asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen);
+	extern asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int *optlen);
+	extern asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
+	extern asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flags);
+
+
+	if(call<1||call>SYS_RECVMSG)
+		return -EINVAL;
+
+	/* copy_from_user should be SMP safe. */
+	if (copy_from_user(a, args32, socketcall_nargs[call]))
+		return -EFAULT;
+		
+	a0=a[0];
+	a1=a[1];
+	
+	switch(call) 
+	{
+		case SYS_SOCKET:
+			err = sys_socket(a0,a1,a[2]);
+			break;
+		case SYS_BIND:
+			err = sys_bind(a0,(struct sockaddr __user *)A(a1), a[2]);
+			break;
+		case SYS_CONNECT:
+			err = sys_connect(a0, (struct sockaddr __user *)A(a1), a[2]);
+			break;
+		case SYS_LISTEN:
+			err = sys_listen(a0,a1);
+			break;
+		case SYS_ACCEPT:
+			err = sys_accept(a0,(struct sockaddr __user *)A(a1), (int __user *)A(a[2]));
+			break;
+		case SYS_GETSOCKNAME:
+			err = sys_getsockname(a0,(struct sockaddr __user *)A(a1), (int __user *)A(a[2]));
+			break;
+		case SYS_GETPEERNAME:
+			err = sys_getpeername(a0, (struct sockaddr __user *)A(a1), (int __user *)A(a[2]));
+			break;
+		case SYS_SOCKETPAIR:
+			err = sys_socketpair(a0,a1, a[2], (int __user *)A(a[3]));
+			break;
+		case SYS_SEND:
+			err = sys_send(a0, (void __user *)A(a1), a[2], a[3]);
+			break;
+		case SYS_SENDTO:
+			err = sys_sendto(a0,(void __user *)A(a1), a[2], a[3],
+					 (struct sockaddr __user *)A(a[4]), a[5]);
+			break;
+		case SYS_RECV:
+			err = sys_recv(a0, (void __user *)A(a1), a[2], a[3]);
+			break;
+		case SYS_RECVFROM:
+			err = sys_recvfrom(a0, (void __user *)A(a1), a[2], a[3],
+					   (struct sockaddr __user *)A(a[4]), (int __user *)A(a[5]));
+			break;
+		case SYS_SHUTDOWN:
+			err = sys_shutdown(a0,a1);
+			break;
+		case SYS_SETSOCKOPT:
+			err = sys_setsockopt(a0, a1, a[2], (char __user *)A(a[3]), a[4]);
+			break;
+		case SYS_GETSOCKOPT:
+			err = sys_getsockopt(a0, a1, a[2], (char __user *)A(a[3]), (int __user *)A(a[4]));
+			break;
+		case SYS_SENDMSG:
+			err = sys_sendmsg(a0, (struct msghdr __user *) A(a1), a[2]);
+			break;
+		case SYS_RECVMSG:
+			err = sys_recvmsg(a0, (struct msghdr __user *) A(a1), a[2]);
+			break;
+		default:
+			err = -EINVAL;
+			break;
+	}
+	return err;
+}
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
new file mode 100644
index 0000000..eed29fc
--- /dev/null
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -0,0 +1,67 @@
+/*
+ * Export MIPS-specific functions needed for loadable modules.
+ *
+ * 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, 98, 99, 2000, 01, 03, 04, 05 by Ralf Baechle
+ * Copyright (C) 1999, 2000, 01 Silicon Graphics, Inc.
+ */
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/checksum.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+extern void *__bzero(void *__s, size_t __count);
+extern long __strncpy_from_user_nocheck_asm(char *__to,
+                                            const char *__from, long __len);
+extern long __strncpy_from_user_asm(char *__to, const char *__from,
+                                    long __len);
+extern long __strlen_user_nocheck_asm(const char *s);
+extern long __strlen_user_asm(const char *s);
+extern long __strnlen_user_nocheck_asm(const char *s);
+extern long __strnlen_user_asm(const char *s);
+
+/*
+ * String functions
+ */
+EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strchr);
+#ifdef CONFIG_MIPS64
+EXPORT_SYMBOL(strncmp);
+#endif
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strstr);
+
+EXPORT_SYMBOL(kernel_thread);
+
+/*
+ * Userspace access stuff.
+ */
+EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(__bzero);
+EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm);
+EXPORT_SYMBOL(__strncpy_from_user_asm);
+EXPORT_SYMBOL(__strlen_user_nocheck_asm);
+EXPORT_SYMBOL(__strlen_user_asm);
+EXPORT_SYMBOL(__strnlen_user_nocheck_asm);
+EXPORT_SYMBOL(__strnlen_user_asm);
+
+EXPORT_SYMBOL(csum_partial);
+
+EXPORT_SYMBOL(invalid_pte_table);
+#ifdef CONFIG_GENERIC_IRQ_PROBE
+EXPORT_SYMBOL(probe_irq_mask);
+#endif
diff --git a/arch/mips/kernel/module-elf32.c b/arch/mips/kernel/module-elf32.c
new file mode 100644
index 0000000..ffd216d
--- /dev/null
+++ b/arch/mips/kernel/module-elf32.c
@@ -0,0 +1,250 @@
+/*
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  Copyright (C) 2001 Rusty Russell.
+ *  Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
+ */
+
+#undef DEBUG
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+struct mips_hi16 {
+	struct mips_hi16 *next;
+	Elf32_Addr *addr;
+	Elf32_Addr value;
+};
+
+static struct mips_hi16 *mips_hi16_list;
+
+void *module_alloc(unsigned long size)
+{
+	if (size == 0)
+		return NULL;
+	return vmalloc(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+	vfree(module_region);
+	/* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
+}
+
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+			      Elf_Shdr *sechdrs,
+			      char *secstrings,
+			      struct module *mod)
+{
+	return 0;
+}
+
+static int apply_r_mips_none(struct module *me, uint32_t *location,
+	Elf32_Addr v)
+{
+	return 0;
+}
+
+static int apply_r_mips_32(struct module *me, uint32_t *location,
+	Elf32_Addr v)
+{
+	*location += v;
+
+	return 0;
+}
+
+static int apply_r_mips_26(struct module *me, uint32_t *location,
+	Elf32_Addr v)
+{
+	if (v % 4) {
+		printk(KERN_ERR "module %s: dangerous relocation\n", me->name);
+		return -ENOEXEC;
+	}
+
+	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
+		printk(KERN_ERR
+		       "module %s: relocation overflow\n",
+		       me->name);
+		return -ENOEXEC;
+	}
+
+	*location = (*location & ~0x03ffffff) |
+	            ((*location + (v >> 2)) & 0x03ffffff);
+
+	return 0;
+}
+
+static int apply_r_mips_hi16(struct module *me, uint32_t *location,
+	Elf32_Addr v)
+{
+	struct mips_hi16 *n;
+
+	/*
+	 * We cannot relocate this one now because we don't know the value of
+	 * the carry we need to add.  Save the information, and let LO16 do the
+	 * actual relocation.
+	 */
+	n = kmalloc(sizeof *n, GFP_KERNEL);
+	if (!n)
+		return -ENOMEM;
+
+	n->addr = location;
+	n->value = v;
+	n->next = mips_hi16_list;
+	mips_hi16_list = n;
+
+	return 0;
+}
+
+static int apply_r_mips_lo16(struct module *me, uint32_t *location,
+	Elf32_Addr v)
+{
+	unsigned long insnlo = *location;
+	Elf32_Addr val, vallo;
+
+	/* Sign extend the addend we extract from the lo insn.  */
+	vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
+
+	if (mips_hi16_list != NULL) {
+		struct mips_hi16 *l;
+
+		l = mips_hi16_list;
+		while (l != NULL) {
+			struct mips_hi16 *next;
+			unsigned long insn;
+
+			/*
+			 * The value for the HI16 had best be the same.
+			 */
+			if (v != l->value)
+				goto out_danger;
+
+			/*
+			 * Do the HI16 relocation.  Note that we actually don't
+			 * need to know anything about the LO16 itself, except
+			 * where to find the low 16 bits of the addend needed
+			 * by the LO16.
+			 */
+			insn = *l->addr;
+			val = ((insn & 0xffff) << 16) + vallo;
+			val += v;
+
+			/*
+			 * Account for the sign extension that will happen in
+			 * the low bits.
+			 */
+			val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
+
+			insn = (insn & ~0xffff) | val;
+			*l->addr = insn;
+
+			next = l->next;
+			kfree(l);
+			l = next;
+		}
+
+		mips_hi16_list = NULL;
+	}
+
+	/*
+	 * Ok, we're done with the HI16 relocs.  Now deal with the LO16.
+	 */
+	val = v + vallo;
+	insnlo = (insnlo & ~0xffff) | (val & 0xffff);
+	*location = insnlo;
+
+	return 0;
+
+out_danger:
+	printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name);
+
+	return -ENOEXEC;
+}
+
+static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
+	Elf32_Addr v) = {
+	[R_MIPS_NONE]	= apply_r_mips_none,
+	[R_MIPS_32]	= apply_r_mips_32,
+	[R_MIPS_26]	= apply_r_mips_26,
+	[R_MIPS_HI16]	= apply_r_mips_hi16,
+	[R_MIPS_LO16]	= apply_r_mips_lo16
+};
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+		   const char *strtab,
+		   unsigned int symindex,
+		   unsigned int relsec,
+		   struct module *me)
+{
+	Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr;
+	Elf32_Sym *sym;
+	uint32_t *location;
+	unsigned int i;
+	Elf32_Addr v;
+	int res;
+
+	pr_debug("Applying relocate section %u to %u\n", relsec,
+	       sechdrs[relsec].sh_info);
+
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+		Elf32_Word r_info = rel[i].r_info;
+
+		/* This is where to make the change */
+		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+			+ rel[i].r_offset;
+		/* This is the symbol it is referring to */
+		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+			+ ELF32_R_SYM(r_info);
+		if (!sym->st_value) {
+			printk(KERN_WARNING "%s: Unknown symbol %s\n",
+			       me->name, strtab + sym->st_name);
+			return -ENOENT;
+		}
+
+		v = sym->st_value;
+
+		res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+		       const char *strtab,
+		       unsigned int symindex,
+		       unsigned int relsec,
+		       struct module *me)
+{
+	/*
+	 * Current binutils always generate .rela relocations.  Keep smiling
+	 * if it's empty, abort otherwise.
+	 */
+	if (!sechdrs[relsec].sh_size)
+		return 0;
+
+	printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
+	       me->name);
+	return -ENOEXEC;
+}
diff --git a/arch/mips/kernel/module-elf64.c b/arch/mips/kernel/module-elf64.c
new file mode 100644
index 0000000..e804792
--- /dev/null
+++ b/arch/mips/kernel/module-elf64.c
@@ -0,0 +1,274 @@
+/*
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  Copyright (C) 2001 Rusty Russell.
+ *  Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
+ */
+
+#undef DEBUG
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+struct mips_hi16 {
+	struct mips_hi16 *next;
+	Elf32_Addr *addr;
+	Elf64_Addr value;
+};
+
+static struct mips_hi16 *mips_hi16_list;
+
+void *module_alloc(unsigned long size)
+{
+	if (size == 0)
+		return NULL;
+	return vmalloc(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+	vfree(module_region);
+	/* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
+}
+
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+			      Elf_Shdr *sechdrs,
+			      char *secstrings,
+			      struct module *mod)
+{
+	return 0;
+}
+
+int apply_relocate(Elf64_Shdr *sechdrs,
+		   const char *strtab,
+		   unsigned int symindex,
+		   unsigned int relsec,
+		   struct module *me)
+{
+	/*
+	 * We don't want to deal with REL relocations - RELA is so much saner.
+	 */
+	if (!sechdrs[relsec].sh_size)
+		return 0;
+
+	printk(KERN_ERR "module %s: REL relocation unsupported\n",
+	       me->name);
+	return -ENOEXEC;
+}
+
+static int apply_r_mips_none(struct module *me, uint32_t *location,
+	Elf64_Addr v)
+{
+	return 0;
+}
+
+static int apply_r_mips_32(struct module *me, uint32_t *location,
+	Elf64_Addr v)
+{
+	*location = v;
+
+	return 0;
+}
+
+static int apply_r_mips_26(struct module *me, uint32_t *location,
+	Elf64_Addr v)
+{
+	if (v % 4) {
+		printk(KERN_ERR "module %s: dangerous relocation\n", me->name);
+		return -ENOEXEC;
+	}
+
+	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
+		printk(KERN_ERR
+		       "module %s: relocation overflow\n",
+		       me->name);
+		return -ENOEXEC;
+	}
+
+	*location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
+
+	return 0;
+}
+
+static int apply_r_mips_hi16(struct module *me, uint32_t *location,
+	Elf64_Addr v)
+{
+	struct mips_hi16 *n;
+
+	/*
+	 * We cannot relocate this one now because we don't know the value of
+	 * the carry we need to add.  Save the information, and let LO16 do the
+	 * actual relocation.
+	 */
+	n = kmalloc(sizeof *n, GFP_KERNEL);
+	if (!n)
+		return -ENOMEM;
+
+	n->addr = location;
+	n->value = v;
+	n->next = mips_hi16_list;
+	mips_hi16_list = n;
+
+	return 0;
+}
+
+static int apply_r_mips_lo16(struct module *me, uint32_t *location,
+	Elf64_Addr v)
+{
+	unsigned long insnlo = *location;
+	Elf32_Addr val, vallo;
+
+	/* Sign extend the addend we extract from the lo insn.  */
+	vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
+
+	if (mips_hi16_list != NULL) {
+		struct mips_hi16 *l;
+
+		l = mips_hi16_list;
+		while (l != NULL) {
+			struct mips_hi16 *next;
+			unsigned long insn;
+
+			/*
+			 * The value for the HI16 had best be the same.
+			 */
+			if (v != l->value)
+				goto out_danger;
+
+			/*
+			 * Do the HI16 relocation.  Note that we actually don't
+			 * need to know anything about the LO16 itself, except
+			 * where to find the low 16 bits of the addend needed
+			 * by the LO16.
+			 */
+			insn = *l->addr;
+			val = ((insn & 0xffff) << 16) + vallo;
+			val += v;
+
+			/*
+			 * Account for the sign extension that will happen in
+			 * the low bits.
+			 */
+			val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
+
+			insn = (insn & ~0xffff) | val;
+			*l->addr = insn;
+
+			next = l->next;
+			kfree(l);
+			l = next;
+		}
+
+		mips_hi16_list = NULL;
+	}
+
+	/*
+	 * Ok, we're done with the HI16 relocs.  Now deal with the LO16.
+	 */
+	insnlo = (insnlo & ~0xffff) | (v & 0xffff);
+	*location = insnlo;
+
+	return 0;
+
+out_danger:
+	printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name);
+
+	return -ENOEXEC;
+}
+
+static int apply_r_mips_64(struct module *me, uint32_t *location,
+	Elf64_Addr v)
+{
+	*(uint64_t *) location = v;
+
+	return 0;
+}
+
+
+static int apply_r_mips_higher(struct module *me, uint32_t *location,
+	Elf64_Addr v)
+{
+	*location = (*location & 0xffff0000) |
+	            ((((long long) v + 0x80008000LL) >> 32) & 0xffff);
+
+	return 0;
+}
+
+static int apply_r_mips_highest(struct module *me, uint32_t *location,
+	Elf64_Addr v)
+{
+	*location = (*location & 0xffff0000) |
+	            ((((long long) v + 0x800080008000LL) >> 48) & 0xffff);
+
+	return 0;
+}
+
+static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
+	Elf64_Addr v) = {
+	[R_MIPS_NONE]		= apply_r_mips_none,
+	[R_MIPS_32]		= apply_r_mips_32,
+	[R_MIPS_26]		= apply_r_mips_26,
+	[R_MIPS_HI16]		= apply_r_mips_hi16,
+	[R_MIPS_LO16]		= apply_r_mips_lo16,
+	[R_MIPS_64]		= apply_r_mips_64,
+	[R_MIPS_HIGHER]		= apply_r_mips_higher,
+	[R_MIPS_HIGHEST]	= apply_r_mips_highest
+};
+
+int apply_relocate_add(Elf64_Shdr *sechdrs,
+		       const char *strtab,
+		       unsigned int symindex,
+		       unsigned int relsec,
+		       struct module *me)
+{
+	Elf64_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
+	Elf64_Sym *sym;
+	uint32_t *location;
+	unsigned int i;
+	Elf64_Addr v;
+	int res;
+
+	pr_debug("Applying relocate section %u to %u\n", relsec,
+	       sechdrs[relsec].sh_info);
+
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+		/* This is where to make the change */
+		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+			+ rel[i].r_offset;
+		/* This is the symbol it is referring to */
+		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr + rel[i].r_sym;
+		if (!sym->st_value) {
+			printk(KERN_WARNING "%s: Unknown symbol %s\n",
+			       me->name, strtab + sym->st_name);
+			return -ENOENT;
+		}
+
+		v = sym->st_value;
+
+		res = reloc_handlers[rel[i].r_type](me, location, v);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c
new file mode 100644
index 0000000..458af3c
--- /dev/null
+++ b/arch/mips/kernel/module.c
@@ -0,0 +1,53 @@
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+static LIST_HEAD(dbe_list);
+static DEFINE_SPINLOCK(dbe_lock);
+
+/* Given an address, look for it in the module exception tables. */
+const struct exception_table_entry *search_module_dbetables(unsigned long addr)
+{
+	unsigned long flags;
+	const struct exception_table_entry *e = NULL;
+	struct mod_arch_specific *dbe;
+
+	spin_lock_irqsave(&dbe_lock, flags);
+	list_for_each_entry(dbe, &dbe_list, dbe_list) {
+		e = search_extable(dbe->dbe_start, dbe->dbe_end - 1, addr);
+		if (e)
+			break;
+	}
+	spin_unlock_irqrestore(&dbe_lock, flags);
+
+	/* Now, if we found one, we are running inside it now, hence
+           we cannot unload the module, hence no refcnt needed. */
+	return e;
+}
+
+/* Put in dbe list if neccessary. */
+int module_finalize(const Elf_Ehdr *hdr,
+		    const Elf_Shdr *sechdrs,
+		    struct module *me)
+{
+	const Elf_Shdr *s;
+	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+	INIT_LIST_HEAD(&me->arch.dbe_list);
+	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+		if (strcmp("__dbe_table", secstrings + s->sh_name) != 0)
+			continue;
+		me->arch.dbe_start = (void *)s->sh_addr;
+		me->arch.dbe_end = (void *)s->sh_addr + s->sh_size;
+		spin_lock_irq(&dbe_lock);
+		list_add(&me->arch.dbe_list, &dbe_list);
+		spin_unlock_irq(&dbe_lock);
+	}
+	return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+	spin_lock_irq(&dbe_lock);
+	list_del(&mod->arch.dbe_list);
+	spin_unlock_irq(&dbe_lock);
+}
diff --git a/arch/mips/kernel/offset.c b/arch/mips/kernel/offset.c
new file mode 100644
index 0000000..2c11abb
--- /dev/null
+++ b/arch/mips/kernel/offset.c
@@ -0,0 +1,314 @@
+/*
+ * offset.c: Calculate pt_regs and task_struct offsets.
+ *
+ * Copyright (C) 1996 David S. Miller
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ *
+ * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ */
+#include <linux/config.h>
+#include <linux/compat.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+
+#define text(t) __asm__("\n@@@" t)
+#define _offset(type, member) (&(((type *)NULL)->member))
+#define offset(string, ptr, member) \
+	__asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member)))
+#define constant(string, member) \
+	__asm__("\n@@@" string "%x0" : : "ri" (member))
+#define size(string, size) \
+	__asm__("\n@@@" string "%0" : : "i" (sizeof(size)))
+#define linefeed text("")
+
+void output_ptreg_defines(void)
+{
+	text("/* MIPS pt_regs offsets. */");
+	offset("#define PT_R0     ", struct pt_regs, regs[0]);
+	offset("#define PT_R1     ", struct pt_regs, regs[1]);
+	offset("#define PT_R2     ", struct pt_regs, regs[2]);
+	offset("#define PT_R3     ", struct pt_regs, regs[3]);
+	offset("#define PT_R4     ", struct pt_regs, regs[4]);
+	offset("#define PT_R5     ", struct pt_regs, regs[5]);
+	offset("#define PT_R6     ", struct pt_regs, regs[6]);
+	offset("#define PT_R7     ", struct pt_regs, regs[7]);
+	offset("#define PT_R8     ", struct pt_regs, regs[8]);
+	offset("#define PT_R9     ", struct pt_regs, regs[9]);
+	offset("#define PT_R10    ", struct pt_regs, regs[10]);
+	offset("#define PT_R11    ", struct pt_regs, regs[11]);
+	offset("#define PT_R12    ", struct pt_regs, regs[12]);
+	offset("#define PT_R13    ", struct pt_regs, regs[13]);
+	offset("#define PT_R14    ", struct pt_regs, regs[14]);
+	offset("#define PT_R15    ", struct pt_regs, regs[15]);
+	offset("#define PT_R16    ", struct pt_regs, regs[16]);
+	offset("#define PT_R17    ", struct pt_regs, regs[17]);
+	offset("#define PT_R18    ", struct pt_regs, regs[18]);
+	offset("#define PT_R19    ", struct pt_regs, regs[19]);
+	offset("#define PT_R20    ", struct pt_regs, regs[20]);
+	offset("#define PT_R21    ", struct pt_regs, regs[21]);
+	offset("#define PT_R22    ", struct pt_regs, regs[22]);
+	offset("#define PT_R23    ", struct pt_regs, regs[23]);
+	offset("#define PT_R24    ", struct pt_regs, regs[24]);
+	offset("#define PT_R25    ", struct pt_regs, regs[25]);
+	offset("#define PT_R26    ", struct pt_regs, regs[26]);
+	offset("#define PT_R27    ", struct pt_regs, regs[27]);
+	offset("#define PT_R28    ", struct pt_regs, regs[28]);
+	offset("#define PT_R29    ", struct pt_regs, regs[29]);
+	offset("#define PT_R30    ", struct pt_regs, regs[30]);
+	offset("#define PT_R31    ", struct pt_regs, regs[31]);
+	offset("#define PT_LO     ", struct pt_regs, lo);
+	offset("#define PT_HI     ", struct pt_regs, hi);
+	offset("#define PT_EPC    ", struct pt_regs, cp0_epc);
+	offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr);
+	offset("#define PT_STATUS ", struct pt_regs, cp0_status);
+	offset("#define PT_CAUSE  ", struct pt_regs, cp0_cause);
+	size("#define PT_SIZE   ", struct pt_regs);
+	linefeed;
+}
+
+void output_task_defines(void)
+{
+	text("/* MIPS task_struct offsets. */");
+	offset("#define TASK_STATE         ", struct task_struct, state);
+	offset("#define TASK_THREAD_INFO   ", struct task_struct, thread_info);
+	offset("#define TASK_FLAGS         ", struct task_struct, flags);
+	offset("#define TASK_MM            ", struct task_struct, mm);
+	offset("#define TASK_PID           ", struct task_struct, pid);
+	size(  "#define TASK_STRUCT_SIZE   ", struct task_struct);
+	linefeed;
+}
+
+void output_thread_info_defines(void)
+{
+	text("/* MIPS thread_info offsets. */");
+	offset("#define TI_TASK            ", struct thread_info, task);
+	offset("#define TI_EXEC_DOMAIN     ", struct thread_info, exec_domain);
+	offset("#define TI_FLAGS           ", struct thread_info, flags);
+	offset("#define TI_CPU             ", struct thread_info, cpu);
+	offset("#define TI_PRE_COUNT       ", struct thread_info, preempt_count);
+	offset("#define TI_ADDR_LIMIT      ", struct thread_info, addr_limit);
+	offset("#define TI_RESTART_BLOCK   ", struct thread_info, restart_block);
+	constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER);
+	constant("#define _THREAD_SIZE       ", THREAD_SIZE);
+	constant("#define _THREAD_MASK       ", THREAD_MASK);
+	linefeed;
+}
+
+void output_thread_defines(void)
+{
+	text("/* MIPS specific thread_struct offsets. */");
+	offset("#define THREAD_REG16   ", struct task_struct, thread.reg16);
+	offset("#define THREAD_REG17   ", struct task_struct, thread.reg17);
+	offset("#define THREAD_REG18   ", struct task_struct, thread.reg18);
+	offset("#define THREAD_REG19   ", struct task_struct, thread.reg19);
+	offset("#define THREAD_REG20   ", struct task_struct, thread.reg20);
+	offset("#define THREAD_REG21   ", struct task_struct, thread.reg21);
+	offset("#define THREAD_REG22   ", struct task_struct, thread.reg22);
+	offset("#define THREAD_REG23   ", struct task_struct, thread.reg23);
+	offset("#define THREAD_REG29   ", struct task_struct, thread.reg29);
+	offset("#define THREAD_REG30   ", struct task_struct, thread.reg30);
+	offset("#define THREAD_REG31   ", struct task_struct, thread.reg31);
+	offset("#define THREAD_STATUS  ", struct task_struct,
+	       thread.cp0_status);
+	offset("#define THREAD_FPU     ", struct task_struct, thread.fpu);
+
+	offset("#define THREAD_BVADDR  ", struct task_struct, \
+	       thread.cp0_badvaddr);
+	offset("#define THREAD_BUADDR  ", struct task_struct, \
+	       thread.cp0_baduaddr);
+	offset("#define THREAD_ECODE   ", struct task_struct, \
+	       thread.error_code);
+	offset("#define THREAD_TRAPNO  ", struct task_struct, thread.trap_no);
+	offset("#define THREAD_MFLAGS  ", struct task_struct, thread.mflags);
+	offset("#define THREAD_TRAMP   ", struct task_struct, \
+	       thread.irix_trampoline);
+	offset("#define THREAD_OLDCTX  ", struct task_struct, \
+	       thread.irix_oldctx);
+	linefeed;
+}
+
+void output_thread_fpu_defines(void)
+{
+	offset("#define THREAD_FPR0    ",
+	       struct task_struct, thread.fpu.hard.fpr[0]);
+	offset("#define THREAD_FPR1    ",
+	       struct task_struct, thread.fpu.hard.fpr[1]);
+	offset("#define THREAD_FPR2    ",
+	       struct task_struct, thread.fpu.hard.fpr[2]);
+	offset("#define THREAD_FPR3    ",
+	       struct task_struct, thread.fpu.hard.fpr[3]);
+	offset("#define THREAD_FPR4    ",
+	       struct task_struct, thread.fpu.hard.fpr[4]);
+	offset("#define THREAD_FPR5    ",
+	       struct task_struct, thread.fpu.hard.fpr[5]);
+	offset("#define THREAD_FPR6    ",
+	       struct task_struct, thread.fpu.hard.fpr[6]);
+	offset("#define THREAD_FPR7    ",
+	       struct task_struct, thread.fpu.hard.fpr[7]);
+	offset("#define THREAD_FPR8    ",
+	       struct task_struct, thread.fpu.hard.fpr[8]);
+	offset("#define THREAD_FPR9    ",
+	       struct task_struct, thread.fpu.hard.fpr[9]);
+	offset("#define THREAD_FPR10   ",
+	       struct task_struct, thread.fpu.hard.fpr[10]);
+	offset("#define THREAD_FPR11   ",
+	       struct task_struct, thread.fpu.hard.fpr[11]);
+	offset("#define THREAD_FPR12   ",
+	       struct task_struct, thread.fpu.hard.fpr[12]);
+	offset("#define THREAD_FPR13   ",
+	       struct task_struct, thread.fpu.hard.fpr[13]);
+	offset("#define THREAD_FPR14   ",
+	       struct task_struct, thread.fpu.hard.fpr[14]);
+	offset("#define THREAD_FPR15   ",
+	       struct task_struct, thread.fpu.hard.fpr[15]);
+	offset("#define THREAD_FPR16   ",
+	       struct task_struct, thread.fpu.hard.fpr[16]);
+	offset("#define THREAD_FPR17   ",
+	       struct task_struct, thread.fpu.hard.fpr[17]);
+	offset("#define THREAD_FPR18   ",
+	       struct task_struct, thread.fpu.hard.fpr[18]);
+	offset("#define THREAD_FPR19   ",
+	       struct task_struct, thread.fpu.hard.fpr[19]);
+	offset("#define THREAD_FPR20   ",
+	       struct task_struct, thread.fpu.hard.fpr[20]);
+	offset("#define THREAD_FPR21   ",
+	       struct task_struct, thread.fpu.hard.fpr[21]);
+	offset("#define THREAD_FPR22   ",
+	       struct task_struct, thread.fpu.hard.fpr[22]);
+	offset("#define THREAD_FPR23   ",
+	       struct task_struct, thread.fpu.hard.fpr[23]);
+	offset("#define THREAD_FPR24   ",
+	       struct task_struct, thread.fpu.hard.fpr[24]);
+	offset("#define THREAD_FPR25   ",
+	       struct task_struct, thread.fpu.hard.fpr[25]);
+	offset("#define THREAD_FPR26   ",
+	       struct task_struct, thread.fpu.hard.fpr[26]);
+	offset("#define THREAD_FPR27   ",
+	       struct task_struct, thread.fpu.hard.fpr[27]);
+	offset("#define THREAD_FPR28   ",
+	       struct task_struct, thread.fpu.hard.fpr[28]);
+	offset("#define THREAD_FPR29   ",
+	       struct task_struct, thread.fpu.hard.fpr[29]);
+	offset("#define THREAD_FPR30   ",
+	       struct task_struct, thread.fpu.hard.fpr[30]);
+	offset("#define THREAD_FPR31   ",
+	       struct task_struct, thread.fpu.hard.fpr[31]);
+
+	offset("#define THREAD_FCR31   ",
+	       struct task_struct, thread.fpu.hard.fcr31);
+	linefeed;
+}
+
+void output_mm_defines(void)
+{
+	text("/* Size of struct page  */");
+	size("#define STRUCT_PAGE_SIZE   ", struct page);
+	linefeed;
+	text("/* Linux mm_struct offsets. */");
+	offset("#define MM_USERS      ", struct mm_struct, mm_users);
+	offset("#define MM_PGD        ", struct mm_struct, pgd);
+	offset("#define MM_CONTEXT    ", struct mm_struct, context);
+	linefeed;
+	constant("#define _PAGE_SIZE     ", PAGE_SIZE);
+	constant("#define _PAGE_SHIFT    ", PAGE_SHIFT);
+	linefeed;
+	constant("#define _PGD_T_SIZE    ", sizeof(pgd_t));
+	constant("#define _PMD_T_SIZE    ", sizeof(pmd_t));
+	constant("#define _PTE_T_SIZE    ", sizeof(pte_t));
+	linefeed;
+	constant("#define _PGD_T_LOG2    ", PGD_T_LOG2);
+	constant("#define _PMD_T_LOG2    ", PMD_T_LOG2);
+	constant("#define _PTE_T_LOG2    ", PTE_T_LOG2);
+	linefeed;
+	constant("#define _PMD_SHIFT     ", PMD_SHIFT);
+	constant("#define _PGDIR_SHIFT   ", PGDIR_SHIFT);
+	linefeed;
+	constant("#define _PGD_ORDER     ", PGD_ORDER);
+	constant("#define _PMD_ORDER     ", PMD_ORDER);
+	constant("#define _PTE_ORDER     ", PTE_ORDER);
+	linefeed;
+	constant("#define _PTRS_PER_PGD  ", PTRS_PER_PGD);
+	constant("#define _PTRS_PER_PMD  ", PTRS_PER_PMD);
+	constant("#define _PTRS_PER_PTE  ", PTRS_PER_PTE);
+	linefeed;
+}
+
+void output_sc_defines(void)
+{
+	text("/* Linux sigcontext offsets. */");
+	offset("#define SC_REGS       ", struct sigcontext, sc_regs);
+	offset("#define SC_FPREGS     ", struct sigcontext, sc_fpregs);
+	offset("#define SC_MDHI       ", struct sigcontext, sc_mdhi);
+	offset("#define SC_MDLO       ", struct sigcontext, sc_mdlo);
+	offset("#define SC_PC         ", struct sigcontext, sc_pc);
+	offset("#define SC_STATUS     ", struct sigcontext, sc_status);
+	offset("#define SC_FPC_CSR    ", struct sigcontext, sc_fpc_csr);
+	offset("#define SC_FPC_EIR    ", struct sigcontext, sc_fpc_eir);
+	offset("#define SC_CAUSE      ", struct sigcontext, sc_cause);
+	offset("#define SC_BADVADDR   ", struct sigcontext, sc_badvaddr);
+	linefeed;
+}
+
+#ifdef CONFIG_MIPS32_COMPAT
+void output_sc32_defines(void)
+{
+	text("/* Linux 32-bit sigcontext offsets. */");
+	offset("#define SC32_FPREGS     ", struct sigcontext32, sc_fpregs);
+	offset("#define SC32_FPC_CSR    ", struct sigcontext32, sc_fpc_csr);
+	offset("#define SC32_FPC_EIR    ", struct sigcontext32, sc_fpc_eir);
+	linefeed;
+}
+#endif
+
+void output_signal_defined(void)
+{
+	text("/* Linux signal numbers. */");
+	constant("#define _SIGHUP     ", SIGHUP);
+	constant("#define _SIGINT     ", SIGINT);
+	constant("#define _SIGQUIT    ", SIGQUIT);
+	constant("#define _SIGILL     ", SIGILL);
+	constant("#define _SIGTRAP    ", SIGTRAP);
+	constant("#define _SIGIOT     ", SIGIOT);
+	constant("#define _SIGABRT    ", SIGABRT);
+	constant("#define _SIGEMT     ", SIGEMT);
+	constant("#define _SIGFPE     ", SIGFPE);
+	constant("#define _SIGKILL    ", SIGKILL);
+	constant("#define _SIGBUS     ", SIGBUS);
+	constant("#define _SIGSEGV    ", SIGSEGV);
+	constant("#define _SIGSYS     ", SIGSYS);
+	constant("#define _SIGPIPE    ", SIGPIPE);
+	constant("#define _SIGALRM    ", SIGALRM);
+	constant("#define _SIGTERM    ", SIGTERM);
+	constant("#define _SIGUSR1    ", SIGUSR1);
+	constant("#define _SIGUSR2    ", SIGUSR2);
+	constant("#define _SIGCHLD    ", SIGCHLD);
+	constant("#define _SIGPWR     ", SIGPWR);
+	constant("#define _SIGWINCH   ", SIGWINCH);
+	constant("#define _SIGURG     ", SIGURG);
+	constant("#define _SIGIO      ", SIGIO);
+	constant("#define _SIGSTOP    ", SIGSTOP);
+	constant("#define _SIGTSTP    ", SIGTSTP);
+	constant("#define _SIGCONT    ", SIGCONT);
+	constant("#define _SIGTTIN    ", SIGTTIN);
+	constant("#define _SIGTTOU    ", SIGTTOU);
+	constant("#define _SIGVTALRM  ", SIGVTALRM);
+	constant("#define _SIGPROF    ", SIGPROF);
+	constant("#define _SIGXCPU    ", SIGXCPU);
+	constant("#define _SIGXFSZ    ", SIGXFSZ);
+	linefeed;
+}
+
+void output_irq_cpustat_t_defines(void)
+{
+	text("/* Linux irq_cpustat_t offsets. */");
+	offset("#define IC_SOFTIRQ_PENDING ", irq_cpustat_t, __softirq_pending);
+	size("#define IC_IRQ_CPUSTAT_T   ", irq_cpustat_t);
+	linefeed;
+}
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
new file mode 100644
index 0000000..0f159f3
--- /dev/null
+++ b/arch/mips/kernel/proc.c
@@ -0,0 +1,149 @@
+/*
+ *  linux/arch/mips/kernel/proc.c
+ *
+ *  Copyright (C) 1995, 1996, 2001  Ralf Baechle
+ *  Copyright (C) 2001  MIPS Technologies, Inc.
+ */
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/cpu-features.h>
+#include <asm/mipsregs.h>
+#include <asm/processor.h>
+#include <asm/watch.h>
+
+unsigned int vced_count, vcei_count;
+
+static const char *cpu_name[] = {
+	[CPU_UNKNOWN]	"unknown",
+	[CPU_R2000]	"R2000",
+	[CPU_R3000]	"R3000",
+	[CPU_R3000A]	"R3000A",
+	[CPU_R3041]	"R3041",
+	[CPU_R3051]	"R3051",
+	[CPU_R3052]	"R3052",
+	[CPU_R3081]	"R3081",
+	[CPU_R3081E]	"R3081E",
+	[CPU_R4000PC]	"R4000PC",
+	[CPU_R4000SC]	"R4000SC",
+	[CPU_R4000MC]	"R4000MC",
+        [CPU_R4200]	"R4200",
+	[CPU_R4400PC]	"R4400PC",
+	[CPU_R4400SC]	"R4400SC",
+	[CPU_R4400MC]	"R4400MC",
+	[CPU_R4600]	"R4600",
+	[CPU_R6000]	"R6000",
+        [CPU_R6000A]	"R6000A",
+	[CPU_R8000]	"R8000",
+	[CPU_R10000]	"R10000",
+	[CPU_R12000]	"R12000",
+	[CPU_R4300]	"R4300",
+	[CPU_R4650]	"R4650",
+	[CPU_R4700]	"R4700",
+	[CPU_R5000]	"R5000",
+        [CPU_R5000A]	"R5000A",
+	[CPU_R4640]	"R4640",
+	[CPU_NEVADA]	"Nevada",
+	[CPU_RM7000]	"RM7000",
+	[CPU_RM9000]	"RM9000",
+	[CPU_R5432]	"R5432",
+	[CPU_4KC]	"MIPS 4Kc",
+        [CPU_5KC]	"MIPS 5Kc",
+	[CPU_R4310]	"R4310",
+	[CPU_SB1]	"SiByte SB1",
+	[CPU_TX3912]	"TX3912",
+	[CPU_TX3922]	"TX3922",
+	[CPU_TX3927]	"TX3927",
+	[CPU_AU1000]	"Au1000",
+	[CPU_AU1500]	"Au1500",
+	[CPU_4KEC]	"MIPS 4KEc",
+	[CPU_4KSC]	"MIPS 4KSc",
+	[CPU_VR41XX]	"NEC Vr41xx",
+	[CPU_R5500]	"R5500",
+	[CPU_TX49XX]	"TX49xx",
+	[CPU_20KC]	"MIPS 20Kc",
+	[CPU_24K]	"MIPS 24K",
+	[CPU_25KF]	"MIPS 25Kf",
+	[CPU_VR4111]	"NEC VR4111",
+	[CPU_VR4121]	"NEC VR4121",
+	[CPU_VR4122]	"NEC VR4122",
+	[CPU_VR4131]	"NEC VR4131",
+	[CPU_VR4133]	"NEC VR4133",
+	[CPU_VR4181]	"NEC VR4181",
+	[CPU_VR4181A]	"NEC VR4181A",
+	[CPU_SR71000]	"Sandcraft SR71000"
+};
+
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	unsigned int version = current_cpu_data.processor_id;
+	unsigned int fp_vers = current_cpu_data.fpu_id;
+	unsigned long n = (unsigned long) v - 1;
+	char fmt [64];
+
+#ifdef CONFIG_SMP
+	if (!cpu_isset(n, cpu_online_map))
+		return 0;
+#endif
+
+	/*
+	 * For the first processor also print the system type
+	 */
+	if (n == 0)
+		seq_printf(m, "system type\t\t: %s\n", get_system_type());
+
+	seq_printf(m, "processor\t\t: %ld\n", n);
+	sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
+	        cpu_has_fpu ? "  FPU V%d.%d" : "");
+	seq_printf(m, fmt, cpu_name[current_cpu_data.cputype <= CPU_LAST ?
+	                            current_cpu_data.cputype : CPU_UNKNOWN],
+	                           (version >> 4) & 0x0f, version & 0x0f,
+	                           (fp_vers >> 4) & 0x0f, fp_vers & 0x0f);
+	seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n",
+	              loops_per_jiffy / (500000/HZ),
+	              (loops_per_jiffy / (5000/HZ)) % 100);
+	seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no");
+	seq_printf(m, "microsecond timers\t: %s\n",
+	              cpu_has_counter ? "yes" : "no");
+	seq_printf(m, "tlb_entries\t\t: %d\n", current_cpu_data.tlbsize);
+	seq_printf(m, "extra interrupt vector\t: %s\n",
+	              cpu_has_divec ? "yes" : "no");
+	seq_printf(m, "hardware watchpoint\t: %s\n",
+	              cpu_has_watch ? "yes" : "no");
+
+	sprintf(fmt, "VCE%%c exceptions\t\t: %s\n",
+	        cpu_has_vce ? "%u" : "not available");
+	seq_printf(m, fmt, 'D', vced_count);
+	seq_printf(m, fmt, 'I', vcei_count);
+
+	return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	unsigned long i = *pos;
+
+	return i < NR_CPUS ? (void *) (i + 1) : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+	.start	= c_start,
+	.next	= c_next,
+	.stop	= c_stop,
+	.show	= show_cpuinfo,
+};
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
new file mode 100644
index 0000000..6e70c42
--- /dev/null
+++ b/arch/mips/kernel/process.c
@@ -0,0 +1,364 @@
+/*
+ * 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) 1994 - 1999, 2000 by Ralf Baechle and others.
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2004 Thiemo Seufer
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/mman.h>
+#include <linux/personality.h>
+#include <linux/sys.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/fpu.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/mipsregs.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/elf.h>
+#include <asm/isadep.h>
+#include <asm/inst.h>
+
+/*
+ * We use this if we don't have any better idle routine..
+ * (This to kill: kernel/platform.c.
+ */
+void default_idle (void)
+{
+}
+
+/*
+ * The idle thread. There's no useful work to be done, so just try to conserve
+ * power and have a low exit latency (ie sit in a loop waiting for somebody to
+ * say that they'd like to reschedule)
+ */
+ATTRIB_NORET void cpu_idle(void)
+{
+	/* endless idle loop with no priority at all */
+	while (1) {
+		while (!need_resched())
+			if (cpu_wait)
+				(*cpu_wait)();
+		schedule();
+	}
+}
+
+asmlinkage void ret_from_fork(void);
+
+void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
+{
+	unsigned long status;
+
+	/* New thread loses kernel privileges. */
+	status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|KU_MASK);
+#ifdef CONFIG_MIPS64
+	status &= ~ST0_FR;
+	status |= (current->thread.mflags & MF_32BIT_REGS) ? 0 : ST0_FR;
+#endif
+	status |= KU_USER;
+	regs->cp0_status = status;
+	clear_used_math();
+	lose_fpu();
+	regs->cp0_epc = pc;
+	regs->regs[29] = sp;
+	current_thread_info()->addr_limit = USER_DS;
+}
+
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+	unsigned long unused, struct task_struct *p, struct pt_regs *regs)
+{
+	struct thread_info *ti = p->thread_info;
+	struct pt_regs *childregs;
+	long childksp;
+
+	childksp = (unsigned long)ti + THREAD_SIZE - 32;
+
+	preempt_disable();
+
+	if (is_fpu_owner()) {
+		save_fp(p);
+	}
+
+	preempt_enable();
+
+	/* set up new TSS. */
+	childregs = (struct pt_regs *) childksp - 1;
+	*childregs = *regs;
+	childregs->regs[7] = 0;	/* Clear error flag */
+
+#if defined(CONFIG_BINFMT_IRIX)
+	if (current->personality != PER_LINUX) {
+		/* Under IRIX things are a little different. */
+		childregs->regs[3] = 1;
+		regs->regs[3] = 0;
+	}
+#endif
+	childregs->regs[2] = 0;	/* Child gets zero as return value */
+	regs->regs[2] = p->pid;
+
+	if (childregs->cp0_status & ST0_CU0) {
+		childregs->regs[28] = (unsigned long) ti;
+		childregs->regs[29] = childksp;
+		ti->addr_limit = KERNEL_DS;
+	} else {
+		childregs->regs[29] = usp;
+		ti->addr_limit = USER_DS;
+	}
+	p->thread.reg29 = (unsigned long) childregs;
+	p->thread.reg31 = (unsigned long) ret_from_fork;
+
+	/*
+	 * New tasks lose permission to use the fpu. This accelerates context
+	 * switching for most programs since they don't use the fpu.
+	 */
+	p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1);
+	childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
+	clear_tsk_thread_flag(p, TIF_USEDFPU);
+
+	return 0;
+}
+
+/* Fill in the fpu structure for a core dump.. */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
+{
+	memcpy(r, &current->thread.fpu, sizeof(current->thread.fpu));
+
+	return 1;
+}
+
+void dump_regs(elf_greg_t *gp, struct pt_regs *regs)
+{
+	int i;
+
+	for (i = 0; i < EF_R0; i++)
+		gp[i] = 0;
+	gp[EF_R0] = 0;
+	for (i = 1; i <= 31; i++)
+		gp[EF_R0 + i] = regs->regs[i];
+	gp[EF_R26] = 0;
+	gp[EF_R27] = 0;
+	gp[EF_LO] = regs->lo;
+	gp[EF_HI] = regs->hi;
+	gp[EF_CP0_EPC] = regs->cp0_epc;
+	gp[EF_CP0_BADVADDR] = regs->cp0_badvaddr;
+	gp[EF_CP0_STATUS] = regs->cp0_status;
+	gp[EF_CP0_CAUSE] = regs->cp0_cause;
+#ifdef EF_UNUSED0
+	gp[EF_UNUSED0] = 0;
+#endif
+}
+
+int dump_task_fpu (struct task_struct *t, elf_fpregset_t *fpr)
+{
+	memcpy(fpr, &t->thread.fpu, sizeof(current->thread.fpu));
+
+	return 1;
+}
+
+/*
+ * Create a kernel thread
+ */
+ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+{
+	do_exit(fn(arg));
+}
+
+long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+	struct pt_regs regs;
+
+	memset(&regs, 0, sizeof(regs));
+
+	regs.regs[4] = (unsigned long) arg;
+	regs.regs[5] = (unsigned long) fn;
+	regs.cp0_epc = (unsigned long) kernel_thread_helper;
+	regs.cp0_status = read_c0_status();
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+	regs.cp0_status &= ~(ST0_KUP | ST0_IEC);
+	regs.cp0_status |= ST0_IEP;
+#else
+	regs.cp0_status |= ST0_EXL;
+#endif
+
+	/* Ok, create the new process.. */
+	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+}
+
+struct mips_frame_info {
+	int frame_offset;
+	int pc_offset;
+};
+static struct mips_frame_info schedule_frame;
+static struct mips_frame_info schedule_timeout_frame;
+static struct mips_frame_info sleep_on_frame;
+static struct mips_frame_info sleep_on_timeout_frame;
+static struct mips_frame_info wait_for_completion_frame;
+static int mips_frame_info_initialized;
+static int __init get_frame_info(struct mips_frame_info *info, void *func)
+{
+	int i;
+	union mips_instruction *ip = (union mips_instruction *)func;
+	info->pc_offset = -1;
+	info->frame_offset = -1;
+	for (i = 0; i < 128; i++, ip++) {
+		/* if jal, jalr, jr, stop. */
+		if (ip->j_format.opcode == jal_op ||
+		    (ip->r_format.opcode == spec_op &&
+		     (ip->r_format.func == jalr_op ||
+		      ip->r_format.func == jr_op)))
+			break;
+
+		if (
+#ifdef CONFIG_MIPS32
+		    ip->i_format.opcode == sw_op &&
+#endif
+#ifdef CONFIG_MIPS64
+		    ip->i_format.opcode == sd_op &&
+#endif
+		    ip->i_format.rs == 29)
+		{
+			/* sw / sd $ra, offset($sp) */
+			if (ip->i_format.rt == 31) {
+				if (info->pc_offset != -1)
+					break;
+				info->pc_offset =
+					ip->i_format.simmediate / sizeof(long);
+			}
+			/* sw / sd $s8, offset($sp) */
+			if (ip->i_format.rt == 30) {
+				if (info->frame_offset != -1)
+					break;
+				info->frame_offset =
+					ip->i_format.simmediate / sizeof(long);
+			}
+		}
+	}
+	if (info->pc_offset == -1 || info->frame_offset == -1) {
+		printk("Can't analyze prologue code at %p\n", func);
+		info->pc_offset = -1;
+		info->frame_offset = -1;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int __init frame_info_init(void)
+{
+	mips_frame_info_initialized =
+		!get_frame_info(&schedule_frame, schedule) &&
+		!get_frame_info(&schedule_timeout_frame, schedule_timeout) &&
+		!get_frame_info(&sleep_on_frame, sleep_on) &&
+		!get_frame_info(&sleep_on_timeout_frame, sleep_on_timeout) &&
+		!get_frame_info(&wait_for_completion_frame, wait_for_completion);
+
+	return 0;
+}
+
+arch_initcall(frame_info_init);
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+	struct thread_struct *t = &tsk->thread;
+
+	/* New born processes are a special case */
+	if (t->reg31 == (unsigned long) ret_from_fork)
+		return t->reg31;
+
+	if (schedule_frame.pc_offset < 0)
+		return 0;
+	return ((unsigned long *)t->reg29)[schedule_frame.pc_offset];
+}
+
+/* get_wchan - a maintenance nightmare^W^Wpain in the ass ...  */
+unsigned long get_wchan(struct task_struct *p)
+{
+	unsigned long frame, pc;
+
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+
+	if (!mips_frame_info_initialized)
+		return 0;
+	pc = thread_saved_pc(p);
+	if (!in_sched_functions(pc))
+		goto out;
+
+	if (pc >= (unsigned long) sleep_on_timeout)
+		goto schedule_timeout_caller;
+	if (pc >= (unsigned long) sleep_on)
+		goto schedule_caller;
+	if (pc >= (unsigned long) interruptible_sleep_on_timeout)
+		goto schedule_timeout_caller;
+	if (pc >= (unsigned long)interruptible_sleep_on)
+		goto schedule_caller;
+	if (pc >= (unsigned long)wait_for_completion)
+		goto schedule_caller;
+	goto schedule_timeout_caller;
+
+schedule_caller:
+	frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset];
+	if (pc >= (unsigned long) sleep_on)
+		pc = ((unsigned long *)frame)[sleep_on_frame.pc_offset];
+	else
+		pc = ((unsigned long *)frame)[wait_for_completion_frame.pc_offset];
+	goto out;
+
+schedule_timeout_caller:
+	/*
+	 * The schedule_timeout frame
+	 */
+	frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset];
+
+	/*
+	 * frame now points to sleep_on_timeout's frame
+	 */
+	pc    = ((unsigned long *)frame)[schedule_timeout_frame.pc_offset];
+
+	if (in_sched_functions(pc)) {
+		/* schedule_timeout called by [interruptible_]sleep_on_timeout */
+		frame = ((unsigned long *)frame)[schedule_timeout_frame.frame_offset];
+		pc    = ((unsigned long *)frame)[sleep_on_timeout_frame.pc_offset];
+	}
+
+out:
+
+#ifdef CONFIG_MIPS64
+	if (current->thread.mflags & MF_32BIT_REGS) /* Kludge for 32-bit ps  */
+		pc &= 0xffffffffUL;
+#endif
+
+	return pc;
+}
+
+EXPORT_SYMBOL(get_wchan);
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
new file mode 100644
index 0000000..a166954
--- /dev/null
+++ b/arch/mips/kernel/ptrace.c
@@ -0,0 +1,338 @@
+/*
+ * 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, 95, 96, 97, 98, 2000 Ralf Baechle
+ * Copyright (C) 1996 David S. Miller
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999 MIPS Technologies, Inc.
+ * Copyright (C) 2000 Ulf Carlsson
+ *
+ * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
+ * binaries.
+ */
+#include <linux/config.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/audit.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/user.h>
+#include <linux/security.h>
+#include <linux/audit.h>
+
+#include <asm/cpu.h>
+#include <asm/fpu.h>
+#include <asm/mipsregs.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/bootinfo.h>
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+	/* Nothing to do.. */
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret;
+
+#if 0
+	printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
+	       (int) request, (int) pid, (unsigned long) addr,
+	       (unsigned long) data);
+#endif
+	lock_kernel();
+	ret = -EPERM;
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+		if ((ret = security_ptrace(current->parent, current)))
+			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out_tsk;
+
+	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;
+		int copied;
+
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		ret = -EIO;
+		if (copied != sizeof(tmp))
+			break;
+		ret = put_user(tmp,(unsigned long *) data);
+		break;
+	}
+
+	/* Read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR: {
+		struct pt_regs *regs;
+		unsigned long tmp = 0;
+
+		regs = (struct pt_regs *) ((unsigned long) child->thread_info +
+		       THREAD_SIZE - 32 - sizeof(struct pt_regs));
+		ret = 0;  /* Default return value. */
+
+		switch (addr) {
+		case 0 ... 31:
+			tmp = regs->regs[addr];
+			break;
+		case FPR_BASE ... FPR_BASE + 31:
+			if (tsk_used_math(child)) {
+				fpureg_t *fregs = get_fpu_regs(child);
+
+#ifdef CONFIG_MIPS32
+				/*
+				 * The odd registers are actually the high
+				 * order bits of the values stored in the even
+				 * registers - unless we're using r2k_switch.S.
+				 */
+				if (addr & 1)
+					tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
+				else
+					tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
+#endif
+#ifdef CONFIG_MIPS64
+				tmp = fregs[addr - FPR_BASE];
+#endif
+			} else {
+				tmp = -1;	/* FP not yet used  */
+			}
+			break;
+		case PC:
+			tmp = regs->cp0_epc;
+			break;
+		case CAUSE:
+			tmp = regs->cp0_cause;
+			break;
+		case BADVADDR:
+			tmp = regs->cp0_badvaddr;
+			break;
+		case MMHI:
+			tmp = regs->hi;
+			break;
+		case MMLO:
+			tmp = regs->lo;
+			break;
+		case FPC_CSR:
+			if (cpu_has_fpu)
+				tmp = child->thread.fpu.hard.fcr31;
+			else
+				tmp = child->thread.fpu.soft.fcr31;
+			break;
+		case FPC_EIR: {	/* implementation / version register */
+			unsigned int flags;
+
+			if (!cpu_has_fpu)
+				break;
+
+			flags = read_c0_status();
+			__enable_fpu();
+			__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
+			write_c0_status(flags);
+			break;
+		}
+		default:
+			tmp = 0;
+			ret = -EIO;
+			goto out_tsk;
+		}
+		ret = put_user(tmp, (unsigned long *) data);
+		break;
+	}
+
+	/* 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:
+		ret = 0;
+		if (access_process_vm(child, addr, &data, sizeof(data), 1)
+		    == sizeof(data))
+			break;
+		ret = -EIO;
+		break;
+
+	case PTRACE_POKEUSR: {
+		struct pt_regs *regs;
+		ret = 0;
+		regs = (struct pt_regs *) ((unsigned long) child->thread_info +
+		       THREAD_SIZE - 32 - sizeof(struct pt_regs));
+
+		switch (addr) {
+		case 0 ... 31:
+			regs->regs[addr] = data;
+			break;
+		case FPR_BASE ... FPR_BASE + 31: {
+			fpureg_t *fregs = get_fpu_regs(child);
+
+			if (!tsk_used_math(child)) {
+				/* FP not yet used  */
+				memset(&child->thread.fpu.hard, ~0,
+				       sizeof(child->thread.fpu.hard));
+				child->thread.fpu.hard.fcr31 = 0;
+			}
+#ifdef CONFIG_MIPS32
+			/*
+			 * The odd registers are actually the high order bits
+			 * of the values stored in the even registers - unless
+			 * we're using r2k_switch.S.
+			 */
+			if (addr & 1) {
+				fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
+				fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
+			} else {
+				fregs[addr - FPR_BASE] &= ~0xffffffffLL;
+				fregs[addr - FPR_BASE] |= data;
+			}
+#endif
+#ifdef CONFIG_MIPS64
+			fregs[addr - FPR_BASE] = data;
+#endif
+			break;
+		}
+		case PC:
+			regs->cp0_epc = data;
+			break;
+		case MMHI:
+			regs->hi = data;
+			break;
+		case MMLO:
+			regs->lo = data;
+			break;
+		case FPC_CSR:
+			if (cpu_has_fpu)
+				child->thread.fpu.hard.fcr31 = data;
+			else
+				child->thread.fpu.soft.fcr31 = data;
+			break;
+		default:
+			/* The rest are not allowed. */
+			ret = -EIO;
+			break;
+		}
+		break;
+		}
+
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL) {
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		}
+		else {
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		}
+		child->exit_code = data;
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	/*
+	 * 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:
+		ret = 0;
+		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		wake_up_process(child);
+		break;
+
+	case PTRACE_DETACH: /* detach a process that was attached. */
+		ret = ptrace_detach(child, data);
+		break;
+
+	default:
+		ret = ptrace_request(child, request, addr, data);
+		break;
+	}
+
+out_tsk:
+	put_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
+
+/*
+ * Notification of system call entry/exit
+ * - triggered by current->work.syscall_trace
+ */
+asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
+{
+	if (unlikely(current->audit_context)) {
+		if (!entryexit)
+			audit_syscall_entry(current, regs->regs[2],
+			                    regs->regs[4], regs->regs[5],
+			                    regs->regs[6], regs->regs[7]);
+		else
+			audit_syscall_exit(current, regs->regs[2]);
+	}
+
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+
+	/* The 0x80 provides a way for the tracing parent to distinguish
+	   between a syscall stop and SIGTRAP delivery */
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
+	                         0x80 : 0));
+
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
new file mode 100644
index 0000000..611dee9
--- /dev/null
+++ b/arch/mips/kernel/ptrace32.c
@@ -0,0 +1,285 @@
+/*
+ * 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, 95, 96, 97, 98, 2000 Ralf Baechle
+ * Copyright (C) 1996 David S. Miller
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999 MIPS Technologies, Inc.
+ * Copyright (C) 2000 Ulf Carlsson
+ *
+ * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
+ * binaries.
+ */
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/user.h>
+#include <linux/security.h>
+
+#include <asm/cpu.h>
+#include <asm/fpu.h>
+#include <asm/mipsregs.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/bootinfo.h>
+
+/*
+ * Tracing a 32-bit process with a 64-bit strace and vice versa will not
+ * work.  I don't know how to fix this.
+ */
+asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
+{
+	struct task_struct *child;
+	int ret;
+
+#if 0
+	printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
+	       (int) request, (int) pid, (unsigned long) addr,
+	       (unsigned long) data);
+#endif
+	lock_kernel();
+	ret = -EPERM;
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+		if ((ret = security_ptrace(current->parent, current)))
+			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out_tsk;
+
+	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 int tmp;
+		int copied;
+
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		ret = -EIO;
+		if (copied != sizeof(tmp))
+			break;
+		ret = put_user(tmp, (unsigned int *) (unsigned long) data);
+		break;
+	}
+
+	/* Read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR: {
+		struct pt_regs *regs;
+		unsigned int tmp;
+
+		regs = (struct pt_regs *) ((unsigned long) child->thread_info +
+		       THREAD_SIZE - 32 - sizeof(struct pt_regs));
+		ret = 0;  /* Default return value. */
+
+		switch (addr) {
+		case 0 ... 31:
+			tmp = regs->regs[addr];
+			break;
+		case FPR_BASE ... FPR_BASE + 31:
+			if (tsk_used_math(child)) {
+				fpureg_t *fregs = get_fpu_regs(child);
+
+				/*
+				 * The odd registers are actually the high
+				 * order bits of the values stored in the even
+				 * registers - unless we're using r2k_switch.S.
+				 */
+				if (addr & 1)
+					tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
+				else
+					tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
+			} else {
+				tmp = -1;	/* FP not yet used  */
+			}
+			break;
+		case PC:
+			tmp = regs->cp0_epc;
+			break;
+		case CAUSE:
+			tmp = regs->cp0_cause;
+			break;
+		case BADVADDR:
+			tmp = regs->cp0_badvaddr;
+			break;
+		case MMHI:
+			tmp = regs->hi;
+			break;
+		case MMLO:
+			tmp = regs->lo;
+			break;
+		case FPC_CSR:
+			if (cpu_has_fpu)
+				tmp = child->thread.fpu.hard.fcr31;
+			else
+				tmp = child->thread.fpu.soft.fcr31;
+			break;
+		case FPC_EIR: {	/* implementation / version register */
+			unsigned int flags;
+
+			if (!cpu_has_fpu)
+				break;
+
+			flags = read_c0_status();
+			__enable_fpu();
+			__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
+			write_c0_status(flags);
+			break;
+		}
+		default:
+			tmp = 0;
+			ret = -EIO;
+			goto out_tsk;
+		}
+		ret = put_user(tmp, (unsigned *) (unsigned long) data);
+		break;
+	}
+
+	/* 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:
+		ret = 0;
+		if (access_process_vm(child, addr, &data, sizeof(data), 1)
+		    == sizeof(data))
+			break;
+		ret = -EIO;
+		break;
+
+	case PTRACE_POKEUSR: {
+		struct pt_regs *regs;
+		ret = 0;
+		regs = (struct pt_regs *) ((unsigned long) child->thread_info +
+		       THREAD_SIZE - 32 - sizeof(struct pt_regs));
+
+		switch (addr) {
+		case 0 ... 31:
+			regs->regs[addr] = data;
+			break;
+		case FPR_BASE ... FPR_BASE + 31: {
+			fpureg_t *fregs = get_fpu_regs(child);
+
+			if (!tsk_used_math(child)) {
+				/* FP not yet used  */
+				memset(&child->thread.fpu.hard, ~0,
+				       sizeof(child->thread.fpu.hard));
+				child->thread.fpu.hard.fcr31 = 0;
+			}
+			/*
+			 * The odd registers are actually the high order bits
+			 * of the values stored in the even registers - unless
+			 * we're using r2k_switch.S.
+			 */
+			if (addr & 1) {
+				fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
+				fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
+			} else {
+				fregs[addr - FPR_BASE] &= ~0xffffffffLL;
+				/* Must cast, lest sign extension fill upper
+				   bits!  */
+				fregs[addr - FPR_BASE] |= (unsigned int)data;
+			}
+			break;
+		}
+		case PC:
+			regs->cp0_epc = data;
+			break;
+		case MMHI:
+			regs->hi = data;
+			break;
+		case MMLO:
+			regs->lo = data;
+			break;
+		case FPC_CSR:
+			if (cpu_has_fpu)
+				child->thread.fpu.hard.fcr31 = data;
+			else
+				child->thread.fpu.soft.fcr31 = data;
+			break;
+		default:
+			/* The rest are not allowed. */
+			ret = -EIO;
+			break;
+		}
+		break;
+		}
+
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		ret = -EIO;
+		if ((unsigned int) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL) {
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		}
+		else {
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		}
+		child->exit_code = data;
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	/*
+	 * 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:
+		ret = 0;
+		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		wake_up_process(child);
+		break;
+
+	case PTRACE_DETACH: /* detach a process that was attached. */
+		ret = ptrace_detach(child, data);
+		break;
+
+	default:
+		ret = ptrace_request(child, request, addr, data);
+		break;
+	}
+
+out_tsk:
+	put_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S
new file mode 100644
index 0000000..f83c31f
--- /dev/null
+++ b/arch/mips/kernel/r2300_fpu.S
@@ -0,0 +1,126 @@
+/*
+ * 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, 1998 by Ralf Baechle
+ *
+ * Multi-arch abstraction and asm macros for easier reading:
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * Further modifications to make this work:
+ * Copyright (c) 1998 Harald Koerfgen
+ */
+#include <asm/asm.h>
+#include <asm/errno.h>
+#include <asm/fpregdef.h>
+#include <asm/mipsregs.h>
+#include <asm/offset.h>
+#include <asm/regdef.h>
+
+#define EX(a,b)							\
+9:	a,##b;							\
+	.section __ex_table,"a";				\
+	PTR	9b,bad_stack;					\
+	.previous
+
+	.set	noreorder
+	.set	mips1
+	/* Save floating point context */
+LEAF(_save_fp_context)
+	li	v0, 0					# assume success
+	cfc1	t1,fcr31
+	EX(swc1	$f0,(SC_FPREGS+0)(a0))
+	EX(swc1	$f1,(SC_FPREGS+8)(a0))
+	EX(swc1	$f2,(SC_FPREGS+16)(a0))
+	EX(swc1	$f3,(SC_FPREGS+24)(a0))
+	EX(swc1	$f4,(SC_FPREGS+32)(a0))
+	EX(swc1	$f5,(SC_FPREGS+40)(a0))
+	EX(swc1	$f6,(SC_FPREGS+48)(a0))
+	EX(swc1	$f7,(SC_FPREGS+56)(a0))
+	EX(swc1	$f8,(SC_FPREGS+64)(a0))
+	EX(swc1	$f9,(SC_FPREGS+72)(a0))
+	EX(swc1	$f10,(SC_FPREGS+80)(a0))
+	EX(swc1	$f11,(SC_FPREGS+88)(a0))
+	EX(swc1	$f12,(SC_FPREGS+96)(a0))
+	EX(swc1	$f13,(SC_FPREGS+104)(a0))
+	EX(swc1	$f14,(SC_FPREGS+112)(a0))
+	EX(swc1	$f15,(SC_FPREGS+120)(a0))
+	EX(swc1	$f16,(SC_FPREGS+128)(a0))
+	EX(swc1	$f17,(SC_FPREGS+136)(a0))
+	EX(swc1	$f18,(SC_FPREGS+144)(a0))
+	EX(swc1	$f19,(SC_FPREGS+152)(a0))
+	EX(swc1	$f20,(SC_FPREGS+160)(a0))
+	EX(swc1	$f21,(SC_FPREGS+168)(a0))
+	EX(swc1	$f22,(SC_FPREGS+176)(a0))
+	EX(swc1	$f23,(SC_FPREGS+184)(a0))
+	EX(swc1	$f24,(SC_FPREGS+192)(a0))
+	EX(swc1	$f25,(SC_FPREGS+200)(a0))
+	EX(swc1	$f26,(SC_FPREGS+208)(a0))
+	EX(swc1	$f27,(SC_FPREGS+216)(a0))
+	EX(swc1	$f28,(SC_FPREGS+224)(a0))
+	EX(swc1	$f29,(SC_FPREGS+232)(a0))
+	EX(swc1	$f30,(SC_FPREGS+240)(a0))
+	EX(swc1	$f31,(SC_FPREGS+248)(a0))
+	EX(sw	t1,(SC_FPC_CSR)(a0))
+	cfc1	t0,$0				# implementation/version
+	jr	ra
+	.set	nomacro
+	 EX(sw	t0,(SC_FPC_EIR)(a0))
+	.set	macro
+	END(_save_fp_context)
+
+/*
+ * Restore FPU state:
+ *  - fp gp registers
+ *  - cp1 status/control register
+ *
+ * We base the decision which registers to restore from the signal stack
+ * frame on the current content of c0_status, not on the content of the
+ * stack frame which might have been changed by the user.
+ */
+LEAF(_restore_fp_context)
+	li	v0, 0					# assume success
+	EX(lw t0,(SC_FPC_CSR)(a0))
+	EX(lwc1	$f0,(SC_FPREGS+0)(a0))
+	EX(lwc1	$f1,(SC_FPREGS+8)(a0))
+	EX(lwc1	$f2,(SC_FPREGS+16)(a0))
+	EX(lwc1	$f3,(SC_FPREGS+24)(a0))
+	EX(lwc1	$f4,(SC_FPREGS+32)(a0))
+	EX(lwc1	$f5,(SC_FPREGS+40)(a0))
+	EX(lwc1	$f6,(SC_FPREGS+48)(a0))
+	EX(lwc1	$f7,(SC_FPREGS+56)(a0))
+	EX(lwc1	$f8,(SC_FPREGS+64)(a0))
+	EX(lwc1	$f9,(SC_FPREGS+72)(a0))
+	EX(lwc1	$f10,(SC_FPREGS+80)(a0))
+	EX(lwc1	$f11,(SC_FPREGS+88)(a0))
+	EX(lwc1	$f12,(SC_FPREGS+96)(a0))
+	EX(lwc1	$f13,(SC_FPREGS+104)(a0))
+	EX(lwc1	$f14,(SC_FPREGS+112)(a0))
+	EX(lwc1	$f15,(SC_FPREGS+120)(a0))
+	EX(lwc1	$f16,(SC_FPREGS+128)(a0))
+	EX(lwc1	$f17,(SC_FPREGS+136)(a0))
+	EX(lwc1	$f18,(SC_FPREGS+144)(a0))
+	EX(lwc1	$f19,(SC_FPREGS+152)(a0))
+	EX(lwc1	$f20,(SC_FPREGS+160)(a0))
+	EX(lwc1	$f21,(SC_FPREGS+168)(a0))
+	EX(lwc1	$f22,(SC_FPREGS+176)(a0))
+	EX(lwc1	$f23,(SC_FPREGS+184)(a0))
+	EX(lwc1	$f24,(SC_FPREGS+192)(a0))
+	EX(lwc1	$f25,(SC_FPREGS+200)(a0))
+	EX(lwc1	$f26,(SC_FPREGS+208)(a0))
+	EX(lwc1	$f27,(SC_FPREGS+216)(a0))
+	EX(lwc1	$f28,(SC_FPREGS+224)(a0))
+	EX(lwc1	$f29,(SC_FPREGS+232)(a0))
+	EX(lwc1	$f30,(SC_FPREGS+240)(a0))
+	EX(lwc1	$f31,(SC_FPREGS+248)(a0))
+	jr	ra
+	 ctc1	t0,fcr31
+	END(_restore_fp_context)
+	.set	reorder
+
+	.type	fault@function
+	.ent	fault
+fault:	li	v0, -EFAULT
+	jr	ra
+	.end	fault
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
new file mode 100644
index 0000000..243e7b6
--- /dev/null
+++ b/arch/mips/kernel/r2300_switch.S
@@ -0,0 +1,174 @@
+/*
+ * r2300_switch.S: R2300 specific task switching code.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1999 by Ralf Baechle
+ * Copyright (C) 1994, 1995, 1996 by Andreas Busse
+ *
+ * Multi-cpu abstraction and macros for easier reading:
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * Further modifications to make this work:
+ * Copyright (c) 1998-2000 Harald Koerfgen
+ */
+#include <linux/config.h>
+#include <asm/asm.h>
+#include <asm/cachectl.h>
+#include <asm/fpregdef.h>
+#include <asm/mipsregs.h>
+#include <asm/offset.h>
+#include <asm/page.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/thread_info.h>
+
+#include <asm/asmmacro.h>
+
+	.set	mips1
+	.align	5
+
+/*
+ * Offset to the current process status flags, the first 32 bytes of the
+ * stack are not used.
+ */
+#define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
+
+/*
+ * FPU context is saved iff the process has used it's FPU in the current
+ * time slice as indicated by TIF_USEDFPU.  In any case, the CU1 bit for user
+ * space STATUS register should be 0, so that a process *always* starts its 
+ * userland with FPU disabled after each context switch.
+ *
+ * FPU will be enabled as soon as the process accesses FPU again, through
+ * do_cpu() trap.
+ */
+
+/*
+ * task_struct *resume(task_struct *prev, task_struct *next,
+ *                     struct thread_info *next_ti) )
+ */
+LEAF(resume)
+#ifndef CONFIG_CPU_HAS_LLSC
+	sw      zero, ll_bit
+#endif
+	mfc0	t1, CP0_STATUS
+	sw	t1, THREAD_STATUS(a0)
+	cpu_save_nonscratch a0
+	sw	ra, THREAD_REG31(a0)
+
+	/* 
+	 * check if we need to save FPU registers
+	 */
+	lw	t3, TASK_THREAD_INFO(a0)
+	lw	t0, TI_FLAGS(t3)
+	li	t1, _TIF_USEDFPU
+	and	t2, t0, t1
+	beqz	t2, 1f
+	nor	t1, zero, t1
+
+	and	t0, t0, t1
+	sw	t0, TI_FLAGS(t3)
+
+	/*
+	 * clear saved user stack CU1 bit
+	 */
+	lw	t0, ST_OFF(t3)
+	li	t1, ~ST0_CU1
+	and	t0, t0, t1
+	sw	t0, ST_OFF(t3)
+
+	fpu_save_single a0, t0			# clobbers t0
+
+1:
+	/*
+	 * The order of restoring the registers takes care of the race
+	 * updating $28, $29 and kernelsp without disabling ints.
+	 */
+	move	$28, a2
+	cpu_restore_nonscratch a1
+
+	addiu	t1, $28, _THREAD_SIZE - 32
+	sw	t1, kernelsp
+
+	mfc0	t1, CP0_STATUS		/* Do we really need this? */
+	li	a3, 0xff01
+	and	t1, a3
+	lw	a2, THREAD_STATUS(a1)
+	nor	a3, $0, a3
+	and	a2, a3
+	or	a2, t1
+	mtc0	a2, CP0_STATUS
+	move	v0, a0
+	jr	ra
+	END(resume)
+
+/*
+ * Save a thread's fp context.
+ */
+LEAF(_save_fp)
+	fpu_save_single a0, t1			# clobbers t1
+	jr	ra
+	END(_save_fp)
+
+/*
+ * Restore a thread's fp context.
+ */
+LEAF(_restore_fp)
+	fpu_restore_single a0, t1		# clobbers t1
+	jr	ra
+	END(_restore_fp)
+
+/*
+ * Load the FPU with signalling NANS.  This bit pattern we're using has
+ * the property that no matter whether considered as single or as double
+ * precision represents signaling NANS.
+ *
+ * We initialize fcr31 to rounding to nearest, no exceptions.
+ */
+
+#define FPU_DEFAULT  0x00000000
+
+LEAF(_init_fpu)
+	mfc0	t0, CP0_STATUS
+	li	t1, ST0_CU1
+	or	t0, t1
+	mtc0	t0, CP0_STATUS
+
+	li	t1, FPU_DEFAULT
+	ctc1	t1, fcr31
+
+	li	t0, -1
+
+	mtc1	t0, $f0
+	mtc1	t0, $f1
+	mtc1	t0, $f2
+	mtc1	t0, $f3
+	mtc1	t0, $f4
+	mtc1	t0, $f5
+	mtc1	t0, $f6
+	mtc1	t0, $f7
+	mtc1	t0, $f8
+	mtc1	t0, $f9
+	mtc1	t0, $f10
+	mtc1	t0, $f11
+	mtc1	t0, $f12
+	mtc1	t0, $f13
+	mtc1	t0, $f14
+	mtc1	t0, $f15
+	mtc1	t0, $f16
+	mtc1	t0, $f17
+	mtc1	t0, $f18
+	mtc1	t0, $f19
+	mtc1	t0, $f20
+	mtc1	t0, $f21
+	mtc1	t0, $f22
+	mtc1	t0, $f23
+	mtc1	t0, $f24
+	mtc1	t0, $f25
+	mtc1	t0, $f26
+	mtc1	t0, $f27
+	mtc1	t0, $f28
+	mtc1	t0, $f29
+	mtc1	t0, $f30
+	mtc1	t0, $f31
+	jr	ra
+	END(_init_fpu)
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
new file mode 100644
index 0000000..ebb643d
--- /dev/null
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -0,0 +1,191 @@
+/*
+ * 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, 98, 99, 2000, 01 Ralf Baechle
+ *
+ * Multi-arch abstraction and asm macros for easier reading:
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ * Copyright (C) 1999, 2001 Silicon Graphics, Inc.
+ */
+#include <linux/config.h>
+#include <asm/asm.h>
+#include <asm/errno.h>
+#include <asm/fpregdef.h>
+#include <asm/mipsregs.h>
+#include <asm/offset.h>
+#include <asm/regdef.h>
+
+	.macro	EX insn, reg, src
+	.set	push
+	.set	nomacro
+.ex\@:	\insn	\reg, \src
+	.set	pop
+	.section __ex_table,"a"
+	PTR	.ex\@, fault
+	.previous
+	.endm
+
+	.set	noreorder
+	.set	mips3
+	/* Save floating point context */
+LEAF(_save_fp_context)
+	cfc1	t1, fcr31
+
+#ifdef CONFIG_MIPS64
+	/* Store the 16 odd double precision registers */
+	EX	sdc1 $f1, SC_FPREGS+8(a0)
+	EX	sdc1 $f3, SC_FPREGS+24(a0)
+	EX	sdc1 $f5, SC_FPREGS+40(a0)
+	EX	sdc1 $f7, SC_FPREGS+56(a0)
+	EX	sdc1 $f9, SC_FPREGS+72(a0)
+	EX	sdc1 $f11, SC_FPREGS+88(a0)
+	EX	sdc1 $f13, SC_FPREGS+104(a0)
+	EX	sdc1 $f15, SC_FPREGS+120(a0)
+	EX	sdc1 $f17, SC_FPREGS+136(a0)
+	EX	sdc1 $f19, SC_FPREGS+152(a0)
+	EX	sdc1 $f21, SC_FPREGS+168(a0)
+	EX	sdc1 $f23, SC_FPREGS+184(a0)
+	EX	sdc1 $f25, SC_FPREGS+200(a0)
+	EX	sdc1 $f27, SC_FPREGS+216(a0)
+	EX	sdc1 $f29, SC_FPREGS+232(a0)
+	EX	sdc1 $f31, SC_FPREGS+248(a0)
+#endif
+
+	/* Store the 16 even double precision registers */
+	EX	sdc1 $f0, SC_FPREGS+0(a0)
+	EX	sdc1 $f2, SC_FPREGS+16(a0)
+	EX	sdc1 $f4, SC_FPREGS+32(a0)
+	EX	sdc1 $f6, SC_FPREGS+48(a0)
+	EX	sdc1 $f8, SC_FPREGS+64(a0)
+	EX	sdc1 $f10, SC_FPREGS+80(a0)
+	EX	sdc1 $f12, SC_FPREGS+96(a0)
+	EX	sdc1 $f14, SC_FPREGS+112(a0)
+	EX	sdc1 $f16, SC_FPREGS+128(a0)
+	EX	sdc1 $f18, SC_FPREGS+144(a0)
+	EX	sdc1 $f20, SC_FPREGS+160(a0)
+	EX	sdc1 $f22, SC_FPREGS+176(a0)
+	EX	sdc1 $f24, SC_FPREGS+192(a0)
+	EX	sdc1 $f26, SC_FPREGS+208(a0)
+	EX	sdc1 $f28, SC_FPREGS+224(a0)
+	EX	sdc1 $f30, SC_FPREGS+240(a0)
+	EX	sw t1, SC_FPC_CSR(a0)
+	cfc1	t0, $0				# implementation/version
+	EX	sw t0, SC_FPC_EIR(a0)
+
+	jr	ra
+	 li	v0, 0					# success
+	END(_save_fp_context)
+
+#ifdef CONFIG_MIPS32_COMPAT
+	/* Save 32-bit process floating point context */
+LEAF(_save_fp_context32)
+	cfc1	t1, fcr31
+
+	EX	sdc1 $f0, SC32_FPREGS+0(a0)
+	EX	sdc1 $f2, SC32_FPREGS+16(a0)
+	EX	sdc1 $f4, SC32_FPREGS+32(a0)
+	EX	sdc1 $f6, SC32_FPREGS+48(a0)
+	EX	sdc1 $f8, SC32_FPREGS+64(a0)
+	EX	sdc1 $f10, SC32_FPREGS+80(a0)
+	EX	sdc1 $f12, SC32_FPREGS+96(a0)
+	EX	sdc1 $f14, SC32_FPREGS+112(a0)
+	EX	sdc1 $f16, SC32_FPREGS+128(a0)
+	EX	sdc1 $f18, SC32_FPREGS+144(a0)
+	EX	sdc1 $f20, SC32_FPREGS+160(a0)
+	EX	sdc1 $f22, SC32_FPREGS+176(a0)
+	EX	sdc1 $f24, SC32_FPREGS+192(a0)
+	EX	sdc1 $f26, SC32_FPREGS+208(a0)
+	EX	sdc1 $f28, SC32_FPREGS+224(a0)
+	EX	sdc1 $f30, SC32_FPREGS+240(a0)
+	EX	sw t1, SC32_FPC_CSR(a0)
+	cfc1	t0, $0				# implementation/version
+	EX	sw t0, SC32_FPC_EIR(a0)
+
+	jr	ra
+	 li	v0, 0					# success
+	END(_save_fp_context32)
+#endif
+
+/*
+ * Restore FPU state:
+ *  - fp gp registers
+ *  - cp1 status/control register
+ */
+LEAF(_restore_fp_context)
+	EX	lw t0, SC_FPC_CSR(a0)
+#ifdef CONFIG_MIPS64
+	EX	ldc1 $f1, SC_FPREGS+8(a0)
+	EX	ldc1 $f3, SC_FPREGS+24(a0)
+	EX	ldc1 $f5, SC_FPREGS+40(a0)
+	EX	ldc1 $f7, SC_FPREGS+56(a0)
+	EX	ldc1 $f9, SC_FPREGS+72(a0)
+	EX	ldc1 $f11, SC_FPREGS+88(a0)
+	EX	ldc1 $f13, SC_FPREGS+104(a0)
+	EX	ldc1 $f15, SC_FPREGS+120(a0)
+	EX	ldc1 $f17, SC_FPREGS+136(a0)
+	EX	ldc1 $f19, SC_FPREGS+152(a0)
+	EX	ldc1 $f21, SC_FPREGS+168(a0)
+	EX	ldc1 $f23, SC_FPREGS+184(a0)
+	EX	ldc1 $f25, SC_FPREGS+200(a0)
+	EX	ldc1 $f27, SC_FPREGS+216(a0)
+	EX	ldc1 $f29, SC_FPREGS+232(a0)
+	EX	ldc1 $f31, SC_FPREGS+248(a0)
+#endif
+	EX	ldc1 $f0, SC_FPREGS+0(a0)
+	EX	ldc1 $f2, SC_FPREGS+16(a0)
+	EX	ldc1 $f4, SC_FPREGS+32(a0)
+	EX	ldc1 $f6, SC_FPREGS+48(a0)
+	EX	ldc1 $f8, SC_FPREGS+64(a0)
+	EX	ldc1 $f10, SC_FPREGS+80(a0)
+	EX	ldc1 $f12, SC_FPREGS+96(a0)
+	EX	ldc1 $f14, SC_FPREGS+112(a0)
+	EX	ldc1 $f16, SC_FPREGS+128(a0)
+	EX	ldc1 $f18, SC_FPREGS+144(a0)
+	EX	ldc1 $f20, SC_FPREGS+160(a0)
+	EX	ldc1 $f22, SC_FPREGS+176(a0)
+	EX	ldc1 $f24, SC_FPREGS+192(a0)
+	EX	ldc1 $f26, SC_FPREGS+208(a0)
+	EX	ldc1 $f28, SC_FPREGS+224(a0)
+	EX	ldc1 $f30, SC_FPREGS+240(a0)
+	ctc1	t0, fcr31
+	jr	ra
+	 li	v0, 0					# success
+	END(_restore_fp_context)
+
+#ifdef CONFIG_MIPS32_COMPAT
+LEAF(_restore_fp_context32)
+	/* Restore an o32 sigcontext.  */
+	EX	lw t0, SC32_FPC_CSR(a0)
+	EX	ldc1 $f0, SC32_FPREGS+0(a0)
+	EX	ldc1 $f2, SC32_FPREGS+16(a0)
+	EX	ldc1 $f4, SC32_FPREGS+32(a0)
+	EX	ldc1 $f6, SC32_FPREGS+48(a0)
+	EX	ldc1 $f8, SC32_FPREGS+64(a0)
+	EX	ldc1 $f10, SC32_FPREGS+80(a0)
+	EX	ldc1 $f12, SC32_FPREGS+96(a0)
+	EX	ldc1 $f14, SC32_FPREGS+112(a0)
+	EX	ldc1 $f16, SC32_FPREGS+128(a0)
+	EX	ldc1 $f18, SC32_FPREGS+144(a0)
+	EX	ldc1 $f20, SC32_FPREGS+160(a0)
+	EX	ldc1 $f22, SC32_FPREGS+176(a0)
+	EX	ldc1 $f24, SC32_FPREGS+192(a0)
+	EX	ldc1 $f26, SC32_FPREGS+208(a0)
+	EX	ldc1 $f28, SC32_FPREGS+224(a0)
+	EX	ldc1 $f30, SC32_FPREGS+240(a0)
+	ctc1	t0, fcr31
+	jr	ra
+	 li	v0, 0					# success
+	END(_restore_fp_context32)
+	.set	reorder
+#endif
+
+	.type	fault@function
+	.ent	fault
+fault:	li	v0, -EFAULT				# failure
+	jr	ra
+	.end	fault
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
new file mode 100644
index 0000000..1fc3b2e
--- /dev/null
+++ b/arch/mips/kernel/r4k_switch.S
@@ -0,0 +1,221 @@
+/*
+ * 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) 1994, 1995, 1996, 1998, 1999, 2002, 2003 Ralf Baechle
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1994, 1995, 1996, by Andreas Busse
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ *    written by Carsten Langgaard, carstenl@mips.com
+ */
+#include <linux/config.h>
+#include <asm/asm.h>
+#include <asm/cachectl.h>
+#include <asm/fpregdef.h>
+#include <asm/mipsregs.h>
+#include <asm/offset.h>
+#include <asm/page.h>
+#include <asm/pgtable-bits.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/thread_info.h>
+
+#include <asm/asmmacro.h>
+
+/*
+ * Offset to the current process status flags, the first 32 bytes of the
+ * stack are not used.
+ */
+#define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
+
+/*
+ * FPU context is saved iff the process has used it's FPU in the current
+ * time slice as indicated by _TIF_USEDFPU.  In any case, the CU1 bit for user
+ * space STATUS register should be 0, so that a process *always* starts its 
+ * userland with FPU disabled after each context switch.
+ *
+ * FPU will be enabled as soon as the process accesses FPU again, through
+ * do_cpu() trap.
+ */
+
+/*
+ * task_struct *resume(task_struct *prev, task_struct *next,
+ *                     struct thread_info *next_ti)
+ */
+	.align	5
+	LEAF(resume)
+#ifndef CONFIG_CPU_HAS_LLSC
+	sw	zero, ll_bit
+#endif
+	mfc0	t1, CP0_STATUS
+	LONG_S	t1, THREAD_STATUS(a0)
+	cpu_save_nonscratch a0
+	LONG_S	ra, THREAD_REG31(a0)
+
+	/*
+	 * check if we need to save FPU registers
+	 */
+	PTR_L	t3, TASK_THREAD_INFO(a0)
+	LONG_L	t0, TI_FLAGS(t3)
+	li	t1, _TIF_USEDFPU
+	and	t2, t0, t1
+	beqz	t2, 1f
+	nor	t1, zero, t1
+
+	and	t0, t0, t1
+	LONG_S	t0, TI_FLAGS(t3)
+
+	/*
+	 * clear saved user stack CU1 bit
+	 */
+	LONG_L	t0, ST_OFF(t3)
+	li	t1, ~ST0_CU1
+	and	t0, t0, t1
+	LONG_S	t0, ST_OFF(t3)
+
+	fpu_save_double a0 t1 t0 t2		# c0_status passed in t1
+						# clobbers t0 and t2
+1:
+
+	/*
+	 * The order of restoring the registers takes care of the race
+	 * updating $28, $29 and kernelsp without disabling ints.
+	 */
+	move	$28, a2
+	cpu_restore_nonscratch a1
+
+	PTR_ADDIU	t0, $28, _THREAD_SIZE - 32
+	set_saved_sp	t0, t1, t2
+
+	mfc0	t1, CP0_STATUS		/* Do we really need this? */
+	li	a3, 0xff01
+	and	t1, a3
+	LONG_L	a2, THREAD_STATUS(a1)
+	nor	a3, $0, a3
+	and	a2, a3
+	or	a2, t1
+	mtc0	a2, CP0_STATUS
+	move	v0, a0
+	jr	ra
+	END(resume)
+
+/*
+ * Save a thread's fp context.
+ */
+LEAF(_save_fp)
+#ifdef CONFIG_MIPS64
+	mfc0	t1, CP0_STATUS
+#endif
+	fpu_save_double a0 t1 t0 t2		# clobbers t1
+	jr	ra
+	END(_save_fp)
+
+/*
+ * Restore a thread's fp context.
+ */
+LEAF(_restore_fp)
+	fpu_restore_double a0, t1		# clobbers t1
+	jr	ra
+	END(_restore_fp)
+
+/*
+ * Load the FPU with signalling NANS.  This bit pattern we're using has
+ * the property that no matter whether considered as single or as double
+ * precision represents signaling NANS.
+ *
+ * We initialize fcr31 to rounding to nearest, no exceptions.
+ */
+
+#define FPU_DEFAULT  0x00000000
+
+LEAF(_init_fpu)
+	mfc0	t0, CP0_STATUS
+	li	t1, ST0_CU1
+	or	t0, t1
+	mtc0	t0, CP0_STATUS
+	fpu_enable_hazard
+
+	li	t1, FPU_DEFAULT
+	ctc1	t1, fcr31
+
+	li	t1, -1				# SNaN
+
+#ifdef CONFIG_MIPS64
+	sll	t0, t0, 5
+	bgez	t0, 1f				# 16 / 32 register mode?
+
+	dmtc1	t1, $f1
+	dmtc1	t1, $f3
+	dmtc1	t1, $f5
+	dmtc1	t1, $f7
+	dmtc1	t1, $f9
+	dmtc1	t1, $f11
+	dmtc1	t1, $f13
+	dmtc1	t1, $f15
+	dmtc1	t1, $f17
+	dmtc1	t1, $f19
+	dmtc1	t1, $f21
+	dmtc1	t1, $f23
+	dmtc1	t1, $f25
+	dmtc1	t1, $f27
+	dmtc1	t1, $f29
+	dmtc1	t1, $f31
+1:
+#endif
+	
+#ifdef CONFIG_CPU_MIPS32
+	mtc1	t1, $f0
+	mtc1	t1, $f1
+	mtc1	t1, $f2
+	mtc1	t1, $f3
+	mtc1	t1, $f4
+	mtc1	t1, $f5
+	mtc1	t1, $f6
+	mtc1	t1, $f7
+	mtc1	t1, $f8
+	mtc1	t1, $f9
+	mtc1	t1, $f10
+	mtc1	t1, $f11
+	mtc1	t1, $f12
+	mtc1	t1, $f13
+	mtc1	t1, $f14
+	mtc1	t1, $f15
+	mtc1	t1, $f16
+	mtc1	t1, $f17
+	mtc1	t1, $f18
+	mtc1	t1, $f19
+	mtc1	t1, $f20
+	mtc1	t1, $f21
+	mtc1	t1, $f22
+	mtc1	t1, $f23
+	mtc1	t1, $f24
+	mtc1	t1, $f25
+	mtc1	t1, $f26
+	mtc1	t1, $f27
+	mtc1	t1, $f28
+	mtc1	t1, $f29
+	mtc1	t1, $f30
+	mtc1	t1, $f31
+#else
+	.set	mips3
+	dmtc1	t1, $f0
+	dmtc1	t1, $f2
+	dmtc1	t1, $f4
+	dmtc1	t1, $f6
+	dmtc1	t1, $f8
+	dmtc1	t1, $f10
+	dmtc1	t1, $f12
+	dmtc1	t1, $f14
+	dmtc1	t1, $f16
+	dmtc1	t1, $f18
+	dmtc1	t1, $f20
+	dmtc1	t1, $f22
+	dmtc1	t1, $f24
+	dmtc1	t1, $f26
+	dmtc1	t1, $f28
+	dmtc1	t1, $f30
+#endif
+	jr	ra
+	END(_init_fpu)
diff --git a/arch/mips/kernel/r6000_fpu.S b/arch/mips/kernel/r6000_fpu.S
new file mode 100644
index 0000000..d8d3b13
--- /dev/null
+++ b/arch/mips/kernel/r6000_fpu.S
@@ -0,0 +1,87 @@
+/*
+ * r6000_fpu.S: Save/restore floating point context for signal handlers.
+ *
+ * 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 by Ralf Baechle
+ *
+ * Multi-arch abstraction and asm macros for easier reading:
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+#include <asm/asm.h>
+#include <asm/fpregdef.h>
+#include <asm/mipsregs.h>
+#include <asm/offset.h>
+#include <asm/regdef.h>
+
+	.set	noreorder
+	.set	mips2
+	/* Save floating point context */
+	LEAF(_save_fp_context)
+	mfc0	t0,CP0_STATUS
+	sll	t0,t0,2
+	bgez	t0,1f
+	 nop
+
+	cfc1	t1,fcr31
+	/* Store the 16 double precision registers */
+	sdc1	$f0,(SC_FPREGS+0)(a0)
+	sdc1	$f2,(SC_FPREGS+16)(a0)
+	sdc1	$f4,(SC_FPREGS+32)(a0)
+	sdc1	$f6,(SC_FPREGS+48)(a0)
+	sdc1	$f8,(SC_FPREGS+64)(a0)
+	sdc1	$f10,(SC_FPREGS+80)(a0)
+	sdc1	$f12,(SC_FPREGS+96)(a0)
+	sdc1	$f14,(SC_FPREGS+112)(a0)
+	sdc1	$f16,(SC_FPREGS+128)(a0)
+	sdc1	$f18,(SC_FPREGS+144)(a0)
+	sdc1	$f20,(SC_FPREGS+160)(a0)
+	sdc1	$f22,(SC_FPREGS+176)(a0)
+	sdc1	$f24,(SC_FPREGS+192)(a0)
+	sdc1	$f26,(SC_FPREGS+208)(a0)
+	sdc1	$f28,(SC_FPREGS+224)(a0)
+	sdc1	$f30,(SC_FPREGS+240)(a0)
+	jr	ra
+	 sw	t0,SC_FPC_CSR(a0)
+1:	jr	ra
+	 nop
+	END(_save_fp_context)
+
+/* Restore FPU state:
+ *  - fp gp registers
+ *  - cp1 status/control register
+ *
+ * We base the decision which registers to restore from the signal stack
+ * frame on the current content of c0_status, not on the content of the
+ * stack frame which might have been changed by the user.
+ */
+	LEAF(_restore_fp_context)
+	mfc0	t0,CP0_STATUS
+	sll	t0,t0,2
+
+	bgez	t0,1f
+	 lw	t0,SC_FPC_CSR(a0)
+	/* Restore the 16 double precision registers */
+	ldc1	$f0,(SC_FPREGS+0)(a0)
+	ldc1	$f2,(SC_FPREGS+16)(a0)
+	ldc1	$f4,(SC_FPREGS+32)(a0)
+	ldc1	$f6,(SC_FPREGS+48)(a0)
+	ldc1	$f8,(SC_FPREGS+64)(a0)
+	ldc1	$f10,(SC_FPREGS+80)(a0)
+	ldc1	$f12,(SC_FPREGS+96)(a0)
+	ldc1	$f14,(SC_FPREGS+112)(a0)
+	ldc1	$f16,(SC_FPREGS+128)(a0)
+	ldc1	$f18,(SC_FPREGS+144)(a0)
+	ldc1	$f20,(SC_FPREGS+160)(a0)
+	ldc1	$f22,(SC_FPREGS+176)(a0)
+	ldc1	$f24,(SC_FPREGS+192)(a0)
+	ldc1	$f26,(SC_FPREGS+208)(a0)
+	ldc1	$f28,(SC_FPREGS+224)(a0)
+	ldc1	$f30,(SC_FPREGS+240)(a0)
+	jr	ra
+	 ctc1	t0,fcr31
+1:	jr	ra
+	 nop
+	END(_restore_fp_context)
diff --git a/arch/mips/kernel/reset.c b/arch/mips/kernel/reset.c
new file mode 100644
index 0000000..7e0a982
--- /dev/null
+++ b/arch/mips/kernel/reset.c
@@ -0,0 +1,43 @@
+/*
+ * 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) 2001 by Ralf Baechle
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/reboot.h>
+#include <asm/reboot.h>
+
+/*
+ * Urgs ...  Too many MIPS machines to handle this in a generic way.
+ * So handle all using function pointers to machine specific
+ * functions.
+ */
+void (*_machine_restart)(char *command);
+void (*_machine_halt)(void);
+void (*_machine_power_off)(void);
+
+void machine_restart(char *command)
+{
+	_machine_restart(command);
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void machine_halt(void)
+{
+	_machine_halt();
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_power_off(void)
+{
+	_machine_power_off();
+}
+
+EXPORT_SYMBOL(machine_power_off);
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
new file mode 100644
index 0000000..344f2e2
--- /dev/null
+++ b/arch/mips/kernel/scall32-o32.S
@@ -0,0 +1,641 @@
+/*
+ * 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) 1995, 96, 97, 98, 99, 2000, 01, 02 by Ralf Baechle
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ * Copyright (C) 2004 Thiemo Seufer
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/isadep.h>
+#include <asm/sysmips.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+#include <asm/war.h>
+#include <asm/offset.h>
+
+/* Highest syscall used of any syscall flavour */
+#define MAX_SYSCALL_NO	__NR_O32_Linux + __NR_O32_Linux_syscalls
+
+	.align  5
+NESTED(handle_sys, PT_SIZE, sp)
+	.set	noat
+	SAVE_SOME
+	STI
+	.set	at
+
+	lw	t1, PT_EPC(sp)		# skip syscall on return
+
+#if defined(CONFIG_BINFMT_IRIX)
+	sltiu	t0, v0, MAX_SYSCALL_NO + 1 # check syscall number
+#else
+	subu	v0, v0, __NR_O32_Linux	# check syscall number
+	sltiu	t0, v0, __NR_O32_Linux_syscalls + 1
+#endif
+	addiu	t1, 4			# skip to next instruction
+	sw	t1, PT_EPC(sp)
+	beqz	t0, illegal_syscall
+
+	sll	t0, v0, 3
+	la	t1, sys_call_table
+	addu	t1, t0
+	lw	t2, (t1)		# syscall routine
+	lw	t3, 4(t1)		# >= 0 if we need stack arguments
+	beqz	t2, illegal_syscall
+
+	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
+	bgez	t3, stackargs
+
+stack_done:
+	lw	t0, TI_FLAGS($28)	# syscall tracing enabled?
+	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	and	t0, t1
+	bnez	t0, syscall_trace_entry	# -> yes
+
+	jalr	t2			# Do The Real Thing (TM)
+
+	li	t0, -EMAXERRNO - 1	# error?
+	sltu	t0, t0, v0
+	sw	t0, PT_R7(sp)		# set error flag
+	beqz	t0, 1f
+
+	negu	v0			# error
+	sw	v0, PT_R0(sp)		# set flag for syscall
+					# restarting
+1:	sw	v0, PT_R2(sp)		# result
+
+o32_syscall_exit:
+	local_irq_disable		# make sure need_resched and
+					# signals dont change between
+					# sampling and return
+	lw	a2, TI_FLAGS($28)	# current->work
+	li	t0, _TIF_ALLWORK_MASK
+	and	t0, a2
+	bnez	t0, o32_syscall_exit_work
+
+	j	restore_partial
+
+o32_syscall_exit_work:
+	j	syscall_exit_work_partial
+
+/* ------------------------------------------------------------------------ */
+
+syscall_trace_entry:
+	SAVE_STATIC
+	move	s0, t2
+	move	a0, sp
+	li	a1, 0
+	jal	do_syscall_trace
+
+	lw	a0, PT_R4(sp)		# Restore argument registers
+	lw	a1, PT_R5(sp)
+	lw	a2, PT_R6(sp)
+	lw	a3, PT_R7(sp)
+	jalr	s0
+
+	li	t0, -EMAXERRNO - 1	# error?
+	sltu	t0, t0, v0
+	sw	t0, PT_R7(sp)		# set error flag
+	beqz	t0, 1f
+
+	negu	v0			# error
+	sw	v0, PT_R0(sp)		# set flag for syscall
+					# restarting
+1:	sw	v0, PT_R2(sp)		# result
+
+	j	syscall_exit
+
+/* ------------------------------------------------------------------------ */
+
+	/*
+	 * More than four arguments.  Try to deal with it by copying the
+	 * stack arguments from the user stack to the kernel stack.
+	 * This Sucks (TM).
+	 */
+stackargs:
+	lw	t0, PT_R29(sp)		# get old user stack pointer
+
+	/*
+	 * We intentionally keep the kernel stack a little below the top of
+	 * userspace so we don't have to do a slower byte accurate check here.
+	 */
+	lw	t5, TI_ADDR_LIMIT($28)
+	addu	t4, t0, 32
+	and	t5, t4
+	bltz	t5, bad_stack		# -> sp is bad
+
+	/* Ok, copy the args from the luser stack to the kernel stack.
+	 * t3 is the precomputed number of instruction bytes needed to
+	 * load or store arguments 6-8.
+	 */
+
+	la	t1, 5f			# load up to 3 arguments
+	subu	t1, t3
+1:	lw	t5, 16(t0)		# argument #5 from usp
+	.set    push
+	.set    noreorder
+	.set	nomacro
+	jr	t1
+	 addiu	t1, 6f - 5f
+
+2:	lw	t8, 28(t0)		# argument #8 from usp
+3:	lw	t7, 24(t0)		# argument #7 from usp
+4:	lw	t6, 20(t0)		# argument #6 from usp
+5:	jr	t1
+	 sw	t5, 16(sp)		# argument #5 to ksp
+
+	sw	t8, 28(sp)		# argument #8 to ksp
+	sw	t7, 24(sp)		# argument #7 to ksp
+	sw	t6, 20(sp)		# argument #6 to ksp
+6:	j	stack_done		# go back
+	 nop
+	.set	pop
+
+	.section __ex_table,"a"
+	PTR	1b,bad_stack
+	PTR	2b,bad_stack
+	PTR	3b,bad_stack
+	PTR	4b,bad_stack
+	.previous
+
+	/*
+	 * The stackpointer for a call with more than 4 arguments is bad.
+	 * We probably should handle this case a bit more drastic.
+	 */
+bad_stack:
+	negu	v0				# error
+	sw	v0, PT_R0(sp)
+	sw	v0, PT_R2(sp)
+	li	t0, 1				# set error flag
+	sw	t0, PT_R7(sp)
+	j	o32_syscall_exit
+
+	/*
+	 * The system call does not exist in this kernel
+	 */
+illegal_syscall:
+	li	v0, -ENOSYS			# error
+	sw	v0, PT_R2(sp)
+	li	t0, 1				# set error flag
+	sw	t0, PT_R7(sp)
+	j	o32_syscall_exit
+	END(handle_sys)
+
+	LEAF(mips_atomic_set)
+	andi	v0, a1, 3			# must be word aligned
+	bnez	v0, bad_alignment
+
+	lw	v1, TI_ADDR_LIMIT($28)		# in legal address range?
+	addiu	a0, a1, 4
+	or	a0, a0, a1
+	and	a0, a0, v1
+	bltz	a0, bad_address
+
+#ifdef CONFIG_CPU_HAS_LLSC
+	/* Ok, this is the ll/sc case.  World is sane :-)  */
+1:	ll	v0, (a1)
+	move	a0, a2
+2:	sc	a0, (a1)
+#if R10000_LLSC_WAR
+	beqzl	a0, 1b
+#else
+	beqz	a0, 1b
+#endif
+
+	.section __ex_table,"a"
+	PTR	1b, bad_stack
+	PTR	2b, bad_stack
+	.previous
+#else
+	sw	a1, 16(sp)
+	sw	a2, 20(sp)
+
+	move	a0, sp
+	move	a2, a1
+	li	a1, 1
+	jal	do_page_fault
+
+	lw	a1, 16(sp)
+	lw	a2, 20(sp)
+
+	/*
+	 * At this point the page should be readable and writable unless
+	 * there was no more memory available.
+	 */
+1:	lw	v0, (a1)
+2:	sw	a2, (a1)
+
+	.section __ex_table,"a"
+	PTR	1b, no_mem
+	PTR	2b, no_mem
+	.previous
+#endif
+
+	sw	zero, PT_R7(sp)		# success
+	sw	v0, PT_R2(sp)		# result
+
+	/* Success, so skip usual error handling garbage.  */
+	lw	a2, TI_FLAGS($28)	# syscall tracing enabled?
+	li	t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	and	t0, a2, t0
+	bnez	t0, 1f
+
+	j	o32_syscall_exit
+
+1:	SAVE_STATIC
+	move	a0, sp
+	li	a1, 1
+	jal	do_syscall_trace
+	j	syscall_exit
+
+no_mem:	li	v0, -ENOMEM
+	jr	ra
+
+bad_address:
+	li	v0, -EFAULT
+	jr	ra
+
+bad_alignment:
+	li	v0, -EINVAL
+	jr	ra
+	END(mips_atomic_set)
+
+	LEAF(sys_sysmips)
+	beq	a0, MIPS_ATOMIC_SET, mips_atomic_set
+	j	_sys_sysmips
+	END(sys_sysmips)
+
+	LEAF(sys_syscall)
+#if defined(CONFIG_BINFMT_IRIX)
+	sltiu	v0, a0, MAX_SYSCALL_NO + 1 # check syscall number
+#else
+	subu	t0, a0, __NR_O32_Linux	# check syscall number
+	sltiu	v0, t0, __NR_O32_Linux_syscalls + 1
+#endif
+	sll	t1, t0, 3
+	beqz	v0, einval
+
+	lw	t2, sys_call_table(t1)		# syscall routine
+
+#if defined(CONFIG_BINFMT_IRIX)
+	li	v1, 4000			# nr of sys_syscall
+#else
+	li	v1, 4000 - __NR_O32_Linux	# index of sys_syscall
+#endif
+	beq	t0, v1, einval			# do not recurse
+
+	/* Some syscalls like execve get their arguments from struct pt_regs
+	   and claim zero arguments in the syscall table. Thus we have to
+	   assume the worst case and shuffle around all potential arguments.
+	   If you want performance, don't use indirect syscalls. */
+
+	move	a0, a1				# shift argument registers
+	move	a1, a2
+	move	a2, a3
+	lw	a3, 16(sp)
+	lw	t4, 20(sp)
+	lw	t5, 24(sp)
+	lw	t6, 28(sp)
+	sw	t4, 16(sp)
+	sw	t5, 20(sp)
+	sw	t6, 24(sp)
+	sw	a0, PT_R4(sp)			# .. and push back a0 - a3, some
+	sw	a1, PT_R5(sp)			# syscalls expect them there
+	sw	a2, PT_R6(sp)
+	sw	a3, PT_R7(sp)
+	sw	a3, PT_R26(sp)			# update a3 for syscall restarting
+	jr	t2
+	/* Unreached */
+
+einval:	li	v0, -EINVAL
+	jr	ra
+	END(sys_syscall)
+
+	.macro	fifty ptr, nargs, from=1, to=50
+	sys	\ptr		\nargs
+	.if	\to-\from
+	fifty	\ptr,\nargs,"(\from+1)",\to
+	.endif
+	.endm
+
+	.macro	mille ptr, nargs, from=1, to=20
+	fifty	\ptr,\nargs
+	.if	\to-\from
+	mille	\ptr,\nargs,"(\from+1)",\to
+	.endif
+	.endm
+
+	.macro	syscalltable
+#if defined(CONFIG_BINFMT_IRIX)
+	mille	sys_ni_syscall		0	/*    0 -  999 SVR4 flavour */
+	mille	sys_ni_syscall		0	/* 1000 - 1999 32-bit IRIX */
+	mille	sys_ni_syscall		0	/* 2000 - 2999 BSD43 flavour */
+	mille	sys_ni_syscall		0	/* 3000 - 3999 POSIX flavour */
+#endif
+
+	sys	sys_syscall		8	/* 4000 */
+	sys	sys_exit		1
+	sys	sys_fork		0
+	sys	sys_read		3
+	sys	sys_write		3
+	sys	sys_open		3	/* 4005 */
+	sys	sys_close		1
+	sys	sys_waitpid		3
+	sys	sys_creat		2
+	sys	sys_link		2
+	sys	sys_unlink		1	/* 4010 */
+	sys	sys_execve		0
+	sys	sys_chdir		1
+	sys	sys_time		1
+	sys	sys_mknod		3
+	sys	sys_chmod		2	/* 4015 */
+	sys	sys_lchown		3
+	sys	sys_ni_syscall		0
+	sys	sys_ni_syscall		0	/* was sys_stat */
+	sys	sys_lseek		3
+	sys	sys_getpid		0	/* 4020 */
+	sys	sys_mount		5
+	sys	sys_oldumount		1
+	sys	sys_setuid		1
+	sys	sys_getuid		0
+	sys	sys_stime		1	/* 4025 */
+	sys	sys_ptrace		4
+	sys	sys_alarm		1
+	sys	sys_ni_syscall		0	/* was sys_fstat */
+	sys	sys_pause		0
+	sys	sys_utime		2	/* 4030 */
+	sys	sys_ni_syscall		0
+	sys	sys_ni_syscall		0
+	sys	sys_access		2
+	sys	sys_nice		1
+	sys	sys_ni_syscall		0	/* 4035 */
+	sys	sys_sync		0
+	sys	sys_kill		2
+	sys	sys_rename		2
+	sys	sys_mkdir		2
+	sys	sys_rmdir		1	/* 4040 */
+	sys	sys_dup			1
+	sys	sys_pipe		0
+	sys	sys_times		1
+	sys	sys_ni_syscall		0
+	sys	sys_brk			1	/* 4045 */
+	sys	sys_setgid		1
+	sys	sys_getgid		0
+	sys	sys_ni_syscall		0	/* was signal(2) */
+	sys	sys_geteuid		0
+	sys	sys_getegid		0	/* 4050 */
+	sys	sys_acct		1
+	sys	sys_umount		2
+	sys	sys_ni_syscall		0
+	sys	sys_ioctl		3
+	sys	sys_fcntl		3	/* 4055 */
+	sys	sys_ni_syscall		2
+	sys	sys_setpgid		2
+	sys	sys_ni_syscall		0
+	sys	sys_olduname		1
+	sys	sys_umask		1	/* 4060 */
+	sys	sys_chroot		1
+	sys	sys_ustat		2
+	sys	sys_dup2		2
+	sys	sys_getppid		0
+	sys	sys_getpgrp		0	/* 4065 */
+	sys	sys_setsid		0
+	sys	sys_sigaction		3
+	sys	sys_sgetmask		0
+	sys	sys_ssetmask		1
+	sys	sys_setreuid		2	/* 4070 */
+	sys	sys_setregid		2
+	sys	sys_sigsuspend		0
+	sys	sys_sigpending		1
+	sys	sys_sethostname		2
+	sys	sys_setrlimit		2	/* 4075 */
+	sys	sys_getrlimit		2
+	sys	sys_getrusage		2
+	sys	sys_gettimeofday	2
+	sys	sys_settimeofday	2
+	sys	sys_getgroups		2	/* 4080 */
+	sys	sys_setgroups		2
+	sys	sys_ni_syscall		0	/* old_select */
+	sys	sys_symlink		2
+	sys	sys_ni_syscall		0	/* was sys_lstat */
+	sys	sys_readlink		3	/* 4085 */
+	sys	sys_uselib		1
+	sys	sys_swapon		2
+	sys	sys_reboot		3
+	sys	old_readdir		3
+	sys	old_mmap		6	/* 4090 */
+	sys	sys_munmap		2
+	sys	sys_truncate		2
+	sys	sys_ftruncate		2
+	sys	sys_fchmod		2
+	sys	sys_fchown		3	/* 4095 */
+	sys	sys_getpriority		2
+	sys	sys_setpriority		3
+	sys	sys_ni_syscall		0
+	sys	sys_statfs		2
+	sys	sys_fstatfs		2	/* 4100 */
+	sys	sys_ni_syscall		0	/* was ioperm(2) */
+	sys	sys_socketcall		2
+	sys	sys_syslog		3
+	sys	sys_setitimer		3
+	sys	sys_getitimer		2	/* 4105 */
+	sys	sys_newstat		2
+	sys	sys_newlstat		2
+	sys	sys_newfstat		2
+	sys	sys_uname		1
+	sys	sys_ni_syscall		0	/* 4110 was iopl(2) */
+	sys	sys_vhangup		0
+	sys	sys_ni_syscall		0	/* was sys_idle() */
+	sys	sys_ni_syscall		0	/* was sys_vm86 */
+	sys	sys_wait4		4
+	sys	sys_swapoff		1	/* 4115 */
+	sys	sys_sysinfo		1
+	sys	sys_ipc			6
+	sys	sys_fsync		1
+	sys	sys_sigreturn		0
+	sys	sys_clone		0	/* 4120 */
+	sys	sys_setdomainname	2
+	sys	sys_newuname		1
+	sys	sys_ni_syscall		0	/* sys_modify_ldt */
+	sys	sys_adjtimex		1
+	sys	sys_mprotect		3	/* 4125 */
+	sys	sys_sigprocmask		3
+	sys	sys_ni_syscall		0	/* was create_module */
+	sys	sys_init_module		5
+	sys	sys_delete_module	1
+	sys	sys_ni_syscall		0	/* 4130	was get_kernel_syms */
+	sys	sys_quotactl		4
+	sys	sys_getpgid		1
+	sys	sys_fchdir		1
+	sys	sys_bdflush		2
+	sys	sys_sysfs		3	/* 4135 */
+	sys	sys_personality		1
+	sys	sys_ni_syscall		0	/* for afs_syscall */
+	sys	sys_setfsuid		1
+	sys	sys_setfsgid		1
+	sys	sys_llseek		5	/* 4140 */
+	sys	sys_getdents		3
+	sys	sys_select		5
+	sys	sys_flock		2
+	sys	sys_msync		3
+	sys	sys_readv		3	/* 4145 */
+	sys	sys_writev		3
+	sys	sys_cacheflush		3
+	sys	sys_cachectl		3
+	sys	sys_sysmips		4
+	sys	sys_ni_syscall		0	/* 4150 */
+	sys	sys_getsid		1
+	sys	sys_fdatasync		1
+	sys	sys_sysctl		1
+	sys	sys_mlock		2
+	sys	sys_munlock		2	/* 4155 */
+	sys	sys_mlockall		1
+	sys	sys_munlockall		0
+	sys	sys_sched_setparam	2
+	sys	sys_sched_getparam	2
+	sys	sys_sched_setscheduler	3	/* 4160 */
+	sys	sys_sched_getscheduler	1
+	sys	sys_sched_yield		0
+	sys	sys_sched_get_priority_max 1
+	sys	sys_sched_get_priority_min 1
+	sys	sys_sched_rr_get_interval 2	/* 4165 */
+	sys	sys_nanosleep,		2
+	sys	sys_mremap,		4
+	sys	sys_accept		3
+	sys	sys_bind		3
+	sys	sys_connect		3	/* 4170 */
+	sys	sys_getpeername		3
+	sys	sys_getsockname		3
+	sys	sys_getsockopt		5
+	sys	sys_listen		2
+	sys	sys_recv		4	/* 4175 */
+	sys	sys_recvfrom		6
+	sys	sys_recvmsg		3
+	sys	sys_send		4
+	sys	sys_sendmsg		3
+	sys	sys_sendto		6	/* 4180 */
+	sys	sys_setsockopt		5
+	sys	sys_shutdown		2
+	sys	sys_socket		3
+	sys	sys_socketpair		4
+	sys	sys_setresuid		3	/* 4185 */
+	sys	sys_getresuid		3
+	sys	sys_ni_syscall		0	/* was sys_query_module */
+	sys	sys_poll		3
+	sys	sys_nfsservctl		3
+	sys	sys_setresgid		3	/* 4190 */
+	sys	sys_getresgid		3
+	sys	sys_prctl		5
+	sys	sys_rt_sigreturn	0
+	sys	sys_rt_sigaction	4
+	sys	sys_rt_sigprocmask	4	/* 4195 */
+	sys	sys_rt_sigpending	2
+	sys	sys_rt_sigtimedwait	4
+	sys	sys_rt_sigqueueinfo	3
+	sys	sys_rt_sigsuspend	0
+	sys	sys_pread64		6	/* 4200 */
+	sys	sys_pwrite64		6
+	sys	sys_chown		3
+	sys	sys_getcwd		2
+	sys	sys_capget		2
+	sys	sys_capset		2	/* 4205 */
+	sys	sys_sigaltstack		0
+	sys	sys_sendfile		4
+	sys	sys_ni_syscall		0
+	sys	sys_ni_syscall		0
+	sys	sys_mmap2		6	/* 4210 */
+	sys	sys_truncate64		4
+	sys	sys_ftruncate64		4
+	sys	sys_stat64		2
+	sys	sys_lstat64		2
+	sys	sys_fstat64		2	/* 4215 */
+	sys	sys_pivot_root		2
+	sys	sys_mincore		3
+	sys	sys_madvise		3
+	sys	sys_getdents64		3
+	sys	sys_fcntl64		3	/* 4220 */
+	sys	sys_ni_syscall		0
+	sys	sys_gettid		0
+	sys	sys_readahead		5
+	sys	sys_setxattr		5
+	sys	sys_lsetxattr		5	/* 4225 */
+	sys	sys_fsetxattr		5
+	sys	sys_getxattr		4
+	sys	sys_lgetxattr		4
+	sys	sys_fgetxattr		4
+	sys	sys_listxattr		3	/* 4230 */
+	sys	sys_llistxattr		3
+	sys	sys_flistxattr		3
+	sys	sys_removexattr		2
+	sys	sys_lremovexattr	2
+	sys	sys_fremovexattr	2	/* 4235 */
+	sys	sys_tkill		2
+	sys	sys_sendfile64		5
+	sys	sys_futex		2
+	sys	sys_sched_setaffinity	3
+	sys	sys_sched_getaffinity	3	/* 4240 */
+	sys	sys_io_setup		2
+	sys	sys_io_destroy		1
+	sys	sys_io_getevents	5
+	sys	sys_io_submit		3
+	sys	sys_io_cancel		3	/* 4245 */
+	sys	sys_exit_group		1
+	sys	sys_lookup_dcookie	3
+	sys	sys_epoll_create	1
+	sys	sys_epoll_ctl		4
+	sys	sys_epoll_wait		3	/* 4250 */
+	sys	sys_remap_file_pages	5
+	sys	sys_set_tid_address	1
+	sys	sys_restart_syscall	0
+	sys	sys_fadvise64_64	7
+	sys	sys_statfs64		3	/* 4255 */
+	sys	sys_fstatfs64		2
+	sys	sys_timer_create	3
+	sys	sys_timer_settime	4
+	sys	sys_timer_gettime	2
+	sys	sys_timer_getoverrun	1	/* 4260 */
+	sys	sys_timer_delete	1
+	sys	sys_clock_settime	2
+	sys	sys_clock_gettime	2
+	sys	sys_clock_getres	2
+	sys	sys_clock_nanosleep	4	/* 4265 */
+	sys	sys_tgkill		3
+	sys	sys_utimes		2
+	sys	sys_mbind		4
+	sys	sys_ni_syscall		0	/* sys_get_mempolicy */
+	sys	sys_ni_syscall		0	/* 4270 sys_set_mempolicy */
+	sys	sys_mq_open		4
+	sys	sys_mq_unlink		1
+	sys	sys_mq_timedsend	5
+	sys	sys_mq_timedreceive	5
+	sys	sys_mq_notify		2	/* 4275 */
+	sys	sys_mq_getsetattr	3
+	sys	sys_ni_syscall		0	/* sys_vserver */
+	sys	sys_waitid		4
+	sys	sys_ni_syscall		0	/* available, was setaltroot */
+	sys	sys_add_key		5
+	sys	sys_request_key		4
+	sys	sys_keyctl		5
+
+	.endm
+
+	/* We pre-compute the number of _instruction_ bytes needed to
+	   load or store the arguments 6-8. Negative values are ignored. */
+
+	.macro  sys function, nargs
+	PTR	\function
+	LONG	(\nargs << 2) - (5 << 2)
+	.endm
+
+	.align	3
+	.type	sys_call_table,@object
+EXPORT(sys_call_table)
+	syscalltable
+	.size	sys_call_table, . - sys_call_table
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
new file mode 100644
index 0000000..32efb88
--- /dev/null
+++ b/arch/mips/kernel/scall64-64.S
@@ -0,0 +1,451 @@
+/*
+ * 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) 1995, 96, 97, 98, 99, 2000, 01, 02 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/offset.h>
+#include <asm/sysmips.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+#include <asm/war.h>
+
+#ifndef CONFIG_BINFMT_ELF32
+/* Neither O32 nor N32, so define handle_sys here */
+#define handle_sys64 handle_sys
+#endif
+
+	.align  5
+NESTED(handle_sys64, PT_SIZE, sp)
+#if !defined(CONFIG_MIPS32_O32) && !defined(CONFIG_MIPS32_N32)
+	/*
+	 * When 32-bit compatibility is configured scall_o32.S
+	 * already did this.
+	 */
+	.set	noat
+	SAVE_SOME
+	STI
+	.set	at
+#endif
+
+	dsubu	t0, v0, __NR_64_Linux	# check syscall number
+	sltiu	t0, t0,	__NR_64_Linux_syscalls + 1
+#if !defined(CONFIG_MIPS32_O32) && !defined(CONFIG_MIPS32_N32)
+	ld	t1, PT_EPC(sp)		# skip syscall on return
+	daddiu	t1, 4			# skip to next instruction
+	sd	t1, PT_EPC(sp)
+#endif
+	beqz	t0, illegal_syscall
+
+	dsll	t0, v0, 3		# offset into table
+	ld	t2, (sys_call_table - (__NR_64_Linux * 8))(t0)
+					# syscall routine
+
+	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
+
+	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	LONG_L	t0, TI_FLAGS($28)	# syscall tracing enabled?
+	and	t0, t1, t0
+	bnez	t0, syscall_trace_entry
+
+	jalr	t2			# Do The Real Thing (TM)
+
+	li	t0, -EMAXERRNO - 1	# error?
+	sltu	t0, t0, v0
+	sd	t0, PT_R7(sp)		# set error flag
+	beqz	t0, 1f
+
+	dnegu	v0			# error
+	sd	v0, PT_R0(sp)		# set flag for syscall
+					# restarting
+1:	sd	v0, PT_R2(sp)		# result
+
+n64_syscall_exit:
+	local_irq_disable		# make sure need_resched and
+					# signals dont change between
+					# sampling and return
+	LONG_L	a2, TI_FLAGS($28)	# current->work
+	li	t0, _TIF_ALLWORK_MASK
+	and	t0, a2, t0
+	bnez	t0, n64_syscall_exit_work
+
+	j	restore_partial
+
+n64_syscall_exit_work:
+	j	syscall_exit_work_partial
+
+/* ------------------------------------------------------------------------ */
+
+syscall_trace_entry:
+	SAVE_STATIC
+	move	s0, t2
+	move	a0, sp
+	li	a1, 0
+	jal	do_syscall_trace
+
+	ld	a0, PT_R4(sp)		# Restore argument registers
+	ld	a1, PT_R5(sp)
+	ld	a2, PT_R6(sp)
+	ld	a3, PT_R7(sp)
+	ld	a4, PT_R8(sp)
+	ld	a5, PT_R9(sp)
+	jalr	s0
+
+	li	t0, -EMAXERRNO - 1	# error?
+	sltu	t0, t0, v0
+	sd	t0, PT_R7(sp)		# set error flag
+	beqz	t0, 1f
+
+	dnegu	v0			# error
+	sd	v0, PT_R0(sp)		# set flag for syscall restarting
+1:	sd	v0, PT_R2(sp)		# result
+
+	j	syscall_exit
+
+illegal_syscall:
+	/* This also isn't a 64-bit syscall, throw an error.  */
+	li	v0, -ENOSYS			# error
+	sd	v0, PT_R2(sp)
+	li	t0, 1				# set error flag
+	sd	t0, PT_R7(sp)
+	j	n64_syscall_exit
+	END(handle_sys64)
+
+	LEAF(mips_atomic_set)
+	andi	v0, a1, 3			# must be word aligned
+	bnez	v0, bad_alignment
+
+	LONG_L	v1, TI_ADDR_LIMIT($28)		# in legal address range?
+	LONG_ADDIU	a0, a1, 4
+	or	a0, a0, a1
+	and	a0, a0, v1
+	bltz	a0, bad_address
+
+#ifdef CONFIG_CPU_HAS_LLSC
+	/* Ok, this is the ll/sc case.  World is sane :-)  */
+1:	ll	v0, (a1)
+	move	a0, a2
+2:	sc	a0, (a1)
+#if R10000_LLSC_WAR
+	beqzl	a0, 1b
+#else
+	beqz	a0, 1b
+#endif
+
+	.section __ex_table,"a"
+	PTR	1b, bad_stack
+	PTR	2b, bad_stack
+	.previous
+#else
+	sw	a1, 16(sp)
+	sw	a2, 20(sp)
+
+	move	a0, sp
+	move	a2, a1
+	li	a1, 1
+	jal	do_page_fault
+
+	lw	a1, 16(sp)
+	lw	a2, 20(sp)
+
+	/*
+	 * At this point the page should be readable and writable unless
+	 * there was no more memory available.
+	 */
+1:	lw	v0, (a1)
+2:	sw	a2, (a1)
+
+	.section __ex_table,"a"
+	PTR	1b, no_mem
+	PTR	2b, no_mem
+	.previous
+#endif
+
+	sd	zero, PT_R7(sp)		# success
+	sd	v0, PT_R2(sp)		# result
+
+	/* Success, so skip usual error handling garbage.  */
+	li	t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	LONG_L	a2, TI_FLAGS($28)	# syscall tracing enabled?
+	and	t0, a2, t0
+	bnez	t0, 1f
+
+	j	n64_syscall_exit
+
+1:	SAVE_STATIC
+	move	a0, sp
+	li	a1, 1
+	jal	do_syscall_trace
+	j	syscall_exit
+
+no_mem:	li	v0, -ENOMEM
+	jr	ra
+
+bad_address:
+	li	v0, -EFAULT
+	jr	ra
+
+bad_alignment:
+	li	v0, -EINVAL
+	jr	ra
+	END(mips_atomic_set)
+
+	LEAF(sys_sysmips)
+	beq	a0, MIPS_ATOMIC_SET, mips_atomic_set
+	j	_sys_sysmips
+	END(sys_sysmips)
+
+	.align	3
+sys_call_table:
+	PTR	sys_read			/* 5000 */
+	PTR	sys_write
+	PTR	sys_open
+	PTR	sys_close
+	PTR	sys_newstat
+	PTR	sys_newfstat			/* 5005 */
+	PTR	sys_newlstat
+	PTR	sys_poll
+	PTR	sys_lseek
+	PTR	old_mmap
+	PTR	sys_mprotect			/* 5010 */
+	PTR	sys_munmap
+	PTR	sys_brk
+	PTR	sys_rt_sigaction
+	PTR	sys_rt_sigprocmask
+	PTR	sys_ioctl			/* 5015 */
+	PTR	sys_pread64
+	PTR	sys_pwrite64
+	PTR	sys_readv
+	PTR	sys_writev
+	PTR	sys_access			/* 5020 */
+	PTR	sys_pipe
+	PTR	sys_select
+	PTR	sys_sched_yield
+	PTR	sys_mremap
+	PTR	sys_msync			/* 5025 */
+	PTR	sys_mincore
+	PTR	sys_madvise
+	PTR	sys_shmget
+	PTR	sys_shmat
+	PTR	sys_shmctl			/* 5030 */
+	PTR	sys_dup
+	PTR	sys_dup2
+	PTR	sys_pause
+	PTR	sys_nanosleep
+	PTR	sys_getitimer			/* 5035 */
+	PTR	sys_setitimer
+	PTR	sys_alarm
+	PTR	sys_getpid
+	PTR	sys_sendfile64
+	PTR	sys_socket			/* 5040 */
+	PTR	sys_connect
+	PTR	sys_accept
+	PTR	sys_sendto
+	PTR	sys_recvfrom
+	PTR	sys_sendmsg			/* 5045 */
+	PTR	sys_recvmsg
+	PTR	sys_shutdown
+	PTR	sys_bind
+	PTR	sys_listen
+	PTR	sys_getsockname			/* 5050 */
+	PTR	sys_getpeername
+	PTR	sys_socketpair
+	PTR	sys_setsockopt
+	PTR	sys_getsockopt
+	PTR	sys_clone			/* 5055 */
+	PTR	sys_fork
+	PTR	sys_execve
+	PTR	sys_exit
+	PTR	sys_wait4
+	PTR	sys_kill			/* 5060 */
+	PTR	sys_newuname
+	PTR	sys_semget
+	PTR	sys_semop
+	PTR	sys_semctl
+	PTR	sys_shmdt			/* 5065 */
+	PTR	sys_msgget
+	PTR	sys_msgsnd
+	PTR	sys_msgrcv
+	PTR	sys_msgctl
+	PTR	sys_fcntl			/* 5070 */
+	PTR	sys_flock
+	PTR	sys_fsync
+	PTR	sys_fdatasync
+	PTR	sys_truncate
+	PTR	sys_ftruncate			/* 5075 */
+	PTR	sys_getdents
+	PTR	sys_getcwd
+	PTR	sys_chdir
+	PTR	sys_fchdir
+	PTR	sys_rename			/* 5080 */
+	PTR	sys_mkdir
+	PTR	sys_rmdir
+	PTR	sys_creat
+	PTR	sys_link
+	PTR	sys_unlink			/* 5085 */
+	PTR	sys_symlink
+	PTR	sys_readlink
+	PTR	sys_chmod
+	PTR	sys_fchmod
+	PTR	sys_chown			/* 5090 */
+	PTR	sys_fchown
+	PTR	sys_lchown
+	PTR	sys_umask
+	PTR	sys_gettimeofday
+	PTR	sys_getrlimit			/* 5095 */
+	PTR	sys_getrusage
+	PTR	sys_sysinfo
+	PTR	sys_times
+	PTR	sys_ptrace
+	PTR	sys_getuid			/* 5100 */
+	PTR	sys_syslog
+	PTR	sys_getgid
+	PTR	sys_setuid
+	PTR	sys_setgid
+	PTR	sys_geteuid			/* 5105 */
+	PTR	sys_getegid
+	PTR	sys_setpgid
+	PTR	sys_getppid
+	PTR	sys_getpgrp
+	PTR	sys_setsid			/* 5110 */
+	PTR	sys_setreuid
+	PTR	sys_setregid
+	PTR	sys_getgroups
+	PTR	sys_setgroups
+	PTR	sys_setresuid			/* 5115 */
+	PTR	sys_getresuid
+	PTR	sys_setresgid
+	PTR	sys_getresgid
+	PTR	sys_getpgid
+	PTR	sys_setfsuid			/* 5120 */
+	PTR	sys_setfsgid
+	PTR	sys_getsid
+	PTR	sys_capget
+	PTR	sys_capset
+	PTR	sys_rt_sigpending		/* 5125 */
+	PTR	sys_rt_sigtimedwait
+	PTR	sys_rt_sigqueueinfo
+	PTR	sys_rt_sigsuspend
+	PTR	sys_sigaltstack
+	PTR	sys_utime			/* 5130 */
+	PTR	sys_mknod
+	PTR	sys_personality
+	PTR	sys_ustat
+	PTR	sys_statfs
+	PTR	sys_fstatfs			/* 5135 */
+	PTR	sys_sysfs
+	PTR	sys_getpriority
+	PTR	sys_setpriority
+	PTR	sys_sched_setparam
+	PTR	sys_sched_getparam		/* 5140 */
+	PTR	sys_sched_setscheduler
+	PTR	sys_sched_getscheduler
+	PTR	sys_sched_get_priority_max
+	PTR	sys_sched_get_priority_min
+	PTR	sys_sched_rr_get_interval	/* 5145 */
+	PTR	sys_mlock
+	PTR	sys_munlock
+	PTR	sys_mlockall
+	PTR	sys_munlockall
+	PTR	sys_vhangup			/* 5150 */
+	PTR	sys_pivot_root
+	PTR	sys_sysctl
+	PTR	sys_prctl
+	PTR	sys_adjtimex
+	PTR	sys_setrlimit			/* 5155 */
+	PTR	sys_chroot
+	PTR	sys_sync
+	PTR	sys_acct
+	PTR	sys_settimeofday
+	PTR	sys_mount			/* 5160 */
+	PTR	sys_umount
+	PTR	sys_swapon
+	PTR	sys_swapoff
+	PTR	sys_reboot
+	PTR	sys_sethostname			/* 5165 */
+	PTR	sys_setdomainname
+	PTR	sys_ni_syscall			/* was create_module */
+	PTR	sys_init_module
+	PTR	sys_delete_module
+	PTR	sys_ni_syscall			/* 5170, was get_kernel_syms */
+	PTR	sys_ni_syscall			/* was query_module */
+	PTR	sys_quotactl
+	PTR	sys_nfsservctl
+	PTR	sys_ni_syscall			/* res. for getpmsg */
+	PTR	sys_ni_syscall			/* 5175  for putpmsg */
+	PTR	sys_ni_syscall			/* res. for afs_syscall */
+	PTR	sys_ni_syscall			/* res. for security */
+	PTR	sys_gettid
+	PTR	sys_readahead
+	PTR	sys_setxattr			/* 5180 */
+	PTR	sys_lsetxattr
+	PTR	sys_fsetxattr
+	PTR	sys_getxattr
+	PTR	sys_lgetxattr
+	PTR	sys_fgetxattr			/* 5185 */
+	PTR	sys_listxattr
+	PTR	sys_llistxattr
+	PTR	sys_flistxattr
+	PTR	sys_removexattr
+	PTR	sys_lremovexattr		/* 5190 */
+	PTR	sys_fremovexattr
+	PTR	sys_tkill
+	PTR	sys_ni_syscall
+	PTR	sys_futex
+	PTR	sys_sched_setaffinity		/* 5195 */
+	PTR	sys_sched_getaffinity
+	PTR	sys_cacheflush
+	PTR	sys_cachectl
+	PTR	sys_sysmips
+	PTR	sys_io_setup			/* 5200 */
+	PTR	sys_io_destroy
+	PTR	sys_io_getevents
+	PTR	sys_io_submit
+	PTR	sys_io_cancel
+	PTR	sys_exit_group			/* 5205 */
+	PTR	sys_lookup_dcookie
+	PTR	sys_epoll_create
+	PTR	sys_epoll_ctl
+	PTR	sys_epoll_wait
+	PTR	sys_remap_file_pages		/* 5210 */
+	PTR	sys_rt_sigreturn
+	PTR	sys_set_tid_address
+	PTR	sys_restart_syscall
+	PTR	sys_semtimedop
+	PTR	sys_fadvise64_64		/* 5215 */
+	PTR	sys_timer_create
+	PTR	sys_timer_settime
+	PTR	sys_timer_gettime
+	PTR	sys_timer_getoverrun
+	PTR	sys_timer_delete		/* 5220 */
+	PTR	sys_clock_settime
+	PTR	sys_clock_gettime
+	PTR	sys_clock_getres
+	PTR	sys_clock_nanosleep
+	PTR	sys_tgkill			/* 5225 */
+	PTR	sys_utimes
+	PTR	sys_mbind
+	PTR	sys_ni_syscall			/* sys_get_mempolicy */
+	PTR	sys_ni_syscall			/* sys_set_mempolicy */
+	PTR	sys_mq_open			/* 5230 */
+	PTR	sys_mq_unlink
+	PTR	sys_mq_timedsend
+	PTR	sys_mq_timedreceive
+	PTR	sys_mq_notify
+	PTR	sys_mq_getsetattr		/* 5235 */
+	PTR	sys_ni_syscall			/* sys_vserver */
+	PTR	sys_waitid
+	PTR	sys_ni_syscall			/* available, was setaltroot */
+	PTR	sys_add_key
+	PTR	sys_request_key			/* 5240 */
+	PTR	sys_keyctl
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
new file mode 100644
index 0000000..e52049c
--- /dev/null
+++ b/arch/mips/kernel/scall64-n32.S
@@ -0,0 +1,365 @@
+/*
+ * 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) 1995, 96, 97, 98, 99, 2000, 01 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+
+/* This duplicates the definition from <linux/sched.h> */
+#define PT_TRACESYS	0x00000002	/* tracing system calls */
+
+/* This duplicates the definition from <asm/signal.h> */
+#define SIGILL		4		/* Illegal instruction (ANSI).  */
+
+#ifndef CONFIG_MIPS32_O32
+/* No O32, so define handle_sys here */
+#define handle_sysn32 handle_sys
+#endif
+
+	.align  5
+NESTED(handle_sysn32, PT_SIZE, sp)
+#ifndef CONFIG_MIPS32_O32
+	.set	noat
+	SAVE_SOME
+	STI
+	.set	at
+#endif
+
+	dsubu	t0, v0, __NR_N32_Linux	# check syscall number
+	sltiu	t0, t0,	__NR_N32_Linux_syscalls + 1
+
+#ifndef CONFIG_MIPS32_O32
+	ld	t1, PT_EPC(sp)		# skip syscall on return
+	daddiu	t1, 4			# skip to next instruction
+	sd	t1, PT_EPC(sp)
+#endif
+	beqz	t0, not_n32_scall
+
+	dsll	t0, v0, 3		# offset into table
+	ld	t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0)
+
+	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
+
+	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	LONG_L	t0, TI_FLAGS($28)	# syscall tracing enabled?
+	and	t0, t1, t0
+	bnez	t0, n32_syscall_trace_entry
+
+	jalr	t2			# Do The Real Thing (TM)
+
+	li	t0, -EMAXERRNO - 1	# error?
+	sltu	t0, t0, v0
+	sd	t0, PT_R7(sp)		# set error flag
+	beqz	t0, 1f
+
+	dnegu	v0			# error
+	sd	v0, PT_R0(sp)		# set flag for syscall restarting
+1:	sd	v0, PT_R2(sp)		# result
+
+	local_irq_disable		# make sure need_resched and
+					# signals dont change between
+					# sampling and return
+	LONG_L  a2, TI_FLAGS($28)	# current->work
+	li	t0, _TIF_ALLWORK_MASK
+	and	t0, a2, t0
+	bnez	t0, n32_syscall_exit_work
+
+	j	restore_partial
+
+n32_syscall_exit_work:
+	j	syscall_exit_work_partial
+
+/* ------------------------------------------------------------------------ */
+
+n32_syscall_trace_entry:
+	SAVE_STATIC
+	move	s0, t2
+	move	a0, sp
+	li	a1, 0
+	jal	do_syscall_trace
+
+	ld	a0, PT_R4(sp)		# Restore argument registers
+	ld	a1, PT_R5(sp)
+	ld	a2, PT_R6(sp)
+	ld	a3, PT_R7(sp)
+	ld	a4, PT_R8(sp)
+	ld	a5, PT_R9(sp)
+	jalr	s0
+
+	li	t0, -EMAXERRNO - 1	# error?
+	sltu	t0, t0, v0
+	sd	t0, PT_R7(sp)		# set error flag
+	beqz	t0, 1f
+
+	dnegu	v0			# error
+	sd	v0, PT_R0(sp)		# set flag for syscall restarting
+1:	sd	v0, PT_R2(sp)		# result
+
+	j	syscall_exit
+
+not_n32_scall:
+	/* This is not an n32 compatibility syscall, pass it on to
+	   the n64 syscall handlers.  */
+	j	handle_sys64
+
+	END(handle_sysn32)
+
+EXPORT(sysn32_call_table)
+	PTR	sys_read			/* 6000 */
+	PTR	sys_write
+	PTR	sys_open
+	PTR	sys_close
+	PTR	sys_newstat
+	PTR	sys_newfstat			/* 6005 */
+	PTR	sys_newlstat
+	PTR	sys_poll
+	PTR	sys_lseek
+	PTR	old_mmap
+	PTR	sys_mprotect			/* 6010 */
+	PTR	sys_munmap
+	PTR	sys_brk
+	PTR	sys32_rt_sigaction
+	PTR	sys32_rt_sigprocmask
+	PTR	compat_sys_ioctl		/* 6015 */
+	PTR	sys_pread64
+	PTR	sys_pwrite64
+	PTR	compat_sys_readv
+	PTR	compat_sys_writev
+	PTR	sys_access			/* 6020 */
+	PTR	sys_pipe
+	PTR	compat_sys_select
+	PTR	sys_sched_yield
+	PTR	sys_mremap
+	PTR	sys_msync			/* 6025 */
+	PTR	sys_mincore
+	PTR	sys_madvise
+	PTR	sys_shmget
+	PTR	sys32_shmat
+	PTR	sys_shmctl			/* 6030 */
+	PTR	sys_dup
+	PTR	sys_dup2
+	PTR	sys_pause
+	PTR	compat_sys_nanosleep
+	PTR	compat_sys_getitimer		/* 6035 */
+	PTR	compat_sys_setitimer
+	PTR	sys_alarm
+	PTR	sys_getpid
+	PTR	sys32_sendfile
+	PTR	sys_socket			/* 6040 */
+	PTR	sys_connect
+	PTR	sys_accept
+	PTR	sys_sendto
+	PTR	sys_recvfrom
+	PTR	compat_sys_sendmsg		/* 6045 */
+	PTR	compat_sys_recvmsg
+	PTR	sys_shutdown
+	PTR	sys_bind
+	PTR	sys_listen
+	PTR	sys_getsockname			/* 6050 */
+	PTR	sys_getpeername
+	PTR	sys_socketpair
+	PTR	compat_sys_setsockopt
+	PTR	sys_getsockopt
+	PTR	sys_clone			/* 6055 */
+	PTR	sys_fork
+	PTR	sys32_execve
+	PTR	sys_exit
+	PTR	sys32_wait4
+	PTR	sys_kill			/* 6060 */
+	PTR	sys32_newuname
+	PTR	sys_semget
+	PTR	sys_semop
+	PTR	sys_semctl
+	PTR	sys_shmdt			/* 6065 */
+	PTR	sys_msgget
+	PTR	sys_msgsnd
+	PTR	sys_msgrcv
+	PTR	sys_msgctl
+	PTR	compat_sys_fcntl		/* 6070 */
+	PTR	sys_flock
+	PTR	sys_fsync
+	PTR	sys_fdatasync
+	PTR	sys_truncate
+	PTR	sys_ftruncate			/* 6075 */
+	PTR	sys32_getdents
+	PTR	sys_getcwd
+	PTR	sys_chdir
+	PTR	sys_fchdir
+	PTR	sys_rename			/* 6080 */
+	PTR	sys_mkdir
+	PTR	sys_rmdir
+	PTR	sys_creat
+	PTR	sys_link
+	PTR	sys_unlink			/* 6085 */
+	PTR	sys_symlink
+	PTR	sys_readlink
+	PTR	sys_chmod
+	PTR	sys_fchmod
+	PTR	sys_chown			/* 6090 */
+	PTR	sys_fchown
+	PTR	sys_lchown
+	PTR	sys_umask
+	PTR	sys32_gettimeofday
+	PTR	compat_sys_getrlimit		/* 6095 */
+	PTR	compat_sys_getrusage
+	PTR	sys32_sysinfo
+	PTR	compat_sys_times
+	PTR	sys_ptrace
+	PTR	sys_getuid			/* 6100 */
+	PTR	sys_syslog
+	PTR	sys_getgid
+	PTR	sys_setuid
+	PTR	sys_setgid
+	PTR	sys_geteuid			/* 6105 */
+	PTR	sys_getegid
+	PTR	sys_setpgid
+	PTR	sys_getppid
+	PTR	sys_getpgrp
+	PTR	sys_setsid			/* 6110 */
+	PTR	sys_setreuid
+	PTR	sys_setregid
+	PTR	sys_getgroups
+	PTR	sys_setgroups
+	PTR	sys_setresuid			/* 6115 */
+	PTR	sys_getresuid
+	PTR	sys_setresgid
+	PTR	sys_getresgid
+	PTR	sys_getpgid
+	PTR	sys_setfsuid			/* 6120 */
+	PTR	sys_setfsgid
+	PTR	sys_getsid
+	PTR	sys_capget
+	PTR	sys_capset
+	PTR	sys32_rt_sigpending		/* 6125 */
+	PTR	compat_sys_rt_sigtimedwait
+	PTR	sys32_rt_sigqueueinfo
+	PTR	sys32_rt_sigsuspend
+	PTR	sys32_sigaltstack
+	PTR	compat_sys_utime		/* 6130 */
+	PTR	sys_mknod
+	PTR	sys32_personality
+	PTR	sys_ustat
+	PTR	compat_sys_statfs
+	PTR	compat_sys_fstatfs		/* 6135 */
+	PTR	sys_sysfs
+	PTR	sys_getpriority
+	PTR	sys_setpriority
+	PTR	sys_sched_setparam
+	PTR	sys_sched_getparam		/* 6140 */
+	PTR	sys_sched_setscheduler
+	PTR	sys_sched_getscheduler
+	PTR	sys_sched_get_priority_max
+	PTR	sys_sched_get_priority_min
+	PTR	sys32_sched_rr_get_interval	/* 6145 */
+	PTR	sys_mlock
+	PTR	sys_munlock
+	PTR	sys_mlockall
+	PTR	sys_munlockall
+	PTR	sys_vhangup			/* 6150 */
+	PTR	sys_pivot_root
+	PTR	sys32_sysctl
+	PTR	sys_prctl
+	PTR	sys32_adjtimex
+	PTR	compat_sys_setrlimit		/* 6155 */
+	PTR	sys_chroot
+	PTR	sys_sync
+	PTR	sys_acct
+	PTR	sys32_settimeofday
+	PTR	sys_mount			/* 6160 */
+	PTR	sys_umount
+	PTR	sys_swapon
+	PTR	sys_swapoff
+	PTR	sys_reboot
+	PTR	sys_sethostname			/* 6165 */
+	PTR	sys_setdomainname
+	PTR	sys_ni_syscall			/* was create_module */
+	PTR	sys_init_module
+	PTR	sys_delete_module
+	PTR	sys_ni_syscall			/* 6170, was get_kernel_syms */
+	PTR	sys_ni_syscall			/* was query_module */
+	PTR	sys_quotactl
+	PTR	sys_nfsservctl
+	PTR	sys_ni_syscall			/* res. for getpmsg */
+	PTR	sys_ni_syscall			/* 6175  for putpmsg */
+	PTR	sys_ni_syscall			/* res. for afs_syscall */
+	PTR	sys_ni_syscall			/* res. for security */
+	PTR	sys_gettid
+	PTR	sys32_readahead
+	PTR	sys_setxattr			/* 6180 */
+	PTR	sys_lsetxattr
+	PTR	sys_fsetxattr
+	PTR	sys_getxattr
+	PTR	sys_lgetxattr
+	PTR	sys_fgetxattr			/* 6185 */
+	PTR	sys_listxattr
+	PTR	sys_llistxattr
+	PTR	sys_flistxattr
+	PTR	sys_removexattr
+	PTR	sys_lremovexattr		/* 6190 */
+	PTR	sys_fremovexattr
+	PTR	sys_tkill
+	PTR	sys_ni_syscall
+	PTR	compat_sys_futex
+	PTR	compat_sys_sched_setaffinity	/* 6195 */
+	PTR	compat_sys_sched_getaffinity
+	PTR	sys_cacheflush
+	PTR	sys_cachectl
+	PTR	sys_sysmips
+	PTR	sys_io_setup			/* 6200 */
+	PTR	sys_io_destroy
+	PTR	sys_io_getevents
+	PTR	sys_io_submit
+	PTR	sys_io_cancel
+	PTR	sys_exit_group			/* 6205 */
+	PTR	sys_lookup_dcookie
+	PTR	sys_epoll_create
+	PTR	sys_epoll_ctl
+	PTR	sys_epoll_wait
+	PTR	sys_remap_file_pages		/* 6210 */
+	PTR	sysn32_rt_sigreturn
+	PTR	sys_fcntl
+	PTR	sys_set_tid_address
+	PTR	sys_restart_syscall
+	PTR	sys_semtimedop			/* 6215 */
+	PTR	sys_fadvise64_64
+	PTR	compat_sys_statfs64
+	PTR	compat_sys_fstatfs64
+	PTR	sys_sendfile64
+	PTR	sys_timer_create		/* 6220 */
+	PTR	sys_timer_settime
+	PTR	sys_timer_gettime
+	PTR	sys_timer_getoverrun
+	PTR	sys_timer_delete
+	PTR	sys_clock_settime		/* 6225 */
+	PTR	sys_clock_gettime
+	PTR	sys_clock_getres
+	PTR	sys_clock_nanosleep
+	PTR	sys_tgkill
+	PTR	compat_sys_utimes		/* 6230 */
+	PTR	sys_ni_syscall			/* sys_mbind */
+	PTR	sys_ni_syscall			/* sys_get_mempolicy */
+	PTR	sys_ni_syscall			/* sys_set_mempolicy */
+	PTR	compat_sys_mq_open
+	PTR	sys_mq_unlink			/* 6235 */
+	PTR	compat_sys_mq_timedsend
+	PTR	compat_sys_mq_timedreceive
+	PTR	compat_sys_mq_notify
+	PTR	compat_sys_mq_getsetattr
+	PTR	sys_ni_syscall			/* 6240, sys_vserver */
+	PTR	sys_waitid
+	PTR	sys_ni_syscall			/* available, was setaltroot */
+	PTR	sys_add_key
+	PTR	sys_request_key
+	PTR	sys_keyctl			/* 6245 */
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
new file mode 100644
index 0000000..739f399
--- /dev/null
+++ b/arch/mips/kernel/scall64-o32.S
@@ -0,0 +1,488 @@
+/*
+ * 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) 1995 - 2000, 2001 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ * Copyright (C) 2004 Thiemo Seufer
+ *
+ * Hairy, the userspace application uses a different argument passing
+ * convention than the kernel, so we have to translate things from o32
+ * to ABI64 calling convention.  64-bit syscalls are also processed
+ * here for now.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+#include <asm/sysmips.h>
+
+	.align  5
+NESTED(handle_sys, PT_SIZE, sp)
+	.set	noat
+	SAVE_SOME
+	STI
+	.set	at
+	ld	t1, PT_EPC(sp)		# skip syscall on return
+
+	dsubu	t0, v0, __NR_O32_Linux	# check syscall number
+	sltiu	t0, t0, __NR_O32_Linux_syscalls + 1
+	daddiu	t1, 4			# skip to next instruction
+	sd	t1, PT_EPC(sp)
+	beqz	t0, not_o32_scall
+#if 0
+ SAVE_ALL
+ move a1, v0
+ PRINT("Scall %ld\n")
+ RESTORE_ALL
+#endif
+
+	/* We don't want to stumble over broken sign extensions from
+	   userland. O32 does never use the upper half. */
+	sll	a0, a0, 0
+	sll	a1, a1, 0
+	sll	a2, a2, 0
+	sll	a3, a3, 0
+
+	dsll	t0, v0, 3		# offset into table
+	ld	t2, (sys_call_table - (__NR_O32_Linux * 8))(t0)
+
+	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
+
+	/*
+	 * More than four arguments.  Try to deal with it by copying the
+	 * stack arguments from the user stack to the kernel stack.
+	 * This Sucks (TM).
+	 *
+	 * We intentionally keep the kernel stack a little below the top of
+	 * userspace so we don't have to do a slower byte accurate check here.
+	 */
+	ld	t0, PT_R29(sp)		# get old user stack pointer
+	daddu	t1, t0, 32
+	bltz	t1, bad_stack
+
+1:	lw	a4, 16(t0)		# argument #5 from usp
+2:	lw	a5, 20(t0)		# argument #6 from usp
+3:	lw	a6, 24(t0)		# argument #7 from usp
+4:	lw	a7, 28(t0)		# argument #8 from usp (for indirect syscalls)
+
+	.section __ex_table,"a"
+	PTR	1b, bad_stack
+	PTR	2b, bad_stack
+	PTR	3b, bad_stack
+	PTR	4b, bad_stack
+	.previous
+
+	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	LONG_L	t0, TI_FLAGS($28)	# syscall tracing enabled?
+	and	t0, t1, t0
+	bnez	t0, trace_a_syscall
+
+	jalr	t2			# Do The Real Thing (TM)
+
+	li	t0, -EMAXERRNO - 1	# error?
+	sltu	t0, t0, v0
+	sd	t0, PT_R7(sp)		# set error flag
+	beqz	t0, 1f
+
+	dnegu	v0			# error
+	sd	v0, PT_R0(sp)		# flag for syscall restarting
+1:	sd	v0, PT_R2(sp)		# result
+
+o32_syscall_exit:
+	local_irq_disable		# make need_resched and
+					# signals dont change between
+					# sampling and return
+	LONG_L	a2, TI_FLAGS($28)
+	li	t0, _TIF_ALLWORK_MASK
+	and	t0, a2, t0
+	bnez	t0, o32_syscall_exit_work
+
+	j	restore_partial
+
+o32_syscall_exit_work:
+	j	syscall_exit_work_partial
+
+/* ------------------------------------------------------------------------ */
+
+trace_a_syscall:
+	SAVE_STATIC
+	sd	a4, PT_R8(sp)		# Save argument registers
+	sd	a5, PT_R9(sp)
+	sd	a6, PT_R10(sp)
+	sd	a7, PT_R11(sp)		# For indirect syscalls
+
+	move	s0, t2			# Save syscall pointer
+	move	a0, sp
+	li	a1, 0
+	jal	do_syscall_trace
+
+	ld	a0, PT_R4(sp)		# Restore argument registers
+	ld	a1, PT_R5(sp)
+	ld	a2, PT_R6(sp)
+	ld	a3, PT_R7(sp)
+	ld	a4, PT_R8(sp)
+	ld	a5, PT_R9(sp)
+	ld	a6, PT_R10(sp)
+	ld	a7, PT_R11(sp)		# For indirect syscalls
+	jalr	s0
+
+	li	t0, -EMAXERRNO - 1	# error?
+	sltu	t0, t0, v0
+	sd	t0, PT_R7(sp)		# set error flag
+	beqz	t0, 1f
+
+	dnegu	v0			# error
+	sd	v0, PT_R0(sp)		# set flag for syscall restarting
+1:	sd	v0, PT_R2(sp)		# result
+
+	j	syscall_exit
+
+/* ------------------------------------------------------------------------ */
+
+	/*
+	 * The stackpointer for a call with more than 4 arguments is bad.
+	 */
+bad_stack:
+	dnegu	v0			# error
+	sd	v0, PT_R0(sp)
+	sd	v0, PT_R2(sp)
+	li	t0, 1			# set error flag
+	sd	t0, PT_R7(sp)
+	j	o32_syscall_exit
+
+not_o32_scall:
+	/*
+	 * This is not an o32 compatibility syscall, pass it on
+	 * to the 64-bit syscall handlers.
+	 */
+#ifdef CONFIG_MIPS32_N32
+	j	handle_sysn32
+#else
+	j	handle_sys64
+#endif
+	END(handle_sys)
+
+LEAF(sys32_syscall)
+	sltu	v0, a0, __NR_O32_Linux + __NR_O32_Linux_syscalls + 1
+	beqz	v0, einval
+
+	dsll	v0, a0, 3
+	ld	t2, (sys_call_table - (__NR_O32_Linux * 8))(v0)
+
+	li	v1, 4000		# indirect syscall number
+	beq	a0, v1, einval		# do not recurse
+
+	move	a0, a1			# shift argument registers
+	move	a1, a2
+	move	a2, a3
+	move	a3, a4
+	move	a4, a5
+	move	a5, a6
+	move	a6, a7
+	sd	a0, PT_R4(sp)		# ... and push back a0 - a3, some
+	sd	a1, PT_R5(sp)		# syscalls expect them there
+	sd	a2, PT_R6(sp)
+	sd	a3, PT_R7(sp)
+	sd	a3, PT_R26(sp)		# update a3 for syscall restarting
+	jr	t2
+	/* Unreached */
+
+einval:	li	v0, -EINVAL
+	jr	ra
+	END(sys32_syscall)
+
+	.align	3
+	.type	sys_call_table,@object
+sys_call_table:
+	PTR	sys32_syscall			/* 4000 */
+	PTR	sys_exit
+	PTR	sys_fork
+	PTR	sys_read
+	PTR	sys_write
+	PTR	sys_open			/* 4005 */
+	PTR	sys_close
+	PTR	sys_waitpid
+	PTR	sys_creat
+	PTR	sys_link
+	PTR	sys_unlink			/* 4010 */
+	PTR	sys32_execve
+	PTR	sys_chdir
+	PTR	compat_sys_time
+	PTR	sys_mknod
+	PTR	sys_chmod			/* 4015 */
+	PTR	sys_lchown
+	PTR	sys_ni_syscall
+	PTR	sys_ni_syscall			/* was sys_stat */
+	PTR	sys_lseek
+	PTR	sys_getpid			/* 4020 */
+	PTR	sys_mount
+	PTR	sys_oldumount
+	PTR	sys_setuid
+	PTR	sys_getuid
+	PTR	compat_sys_stime		/* 4025 */
+	PTR	sys32_ptrace
+	PTR	sys_alarm
+	PTR	sys_ni_syscall			/* was sys_fstat */
+	PTR	sys_pause
+	PTR	compat_sys_utime		/* 4030 */
+	PTR	sys_ni_syscall
+	PTR	sys_ni_syscall
+	PTR	sys_access
+	PTR	sys_nice
+	PTR	sys_ni_syscall			/* 4035 */
+	PTR	sys_sync
+	PTR	sys_kill
+	PTR	sys_rename
+	PTR	sys_mkdir
+	PTR	sys_rmdir			/* 4040 */
+	PTR	sys_dup
+	PTR	sys_pipe
+	PTR	compat_sys_times
+	PTR	sys_ni_syscall
+	PTR	sys_brk				/* 4045 */
+	PTR	sys_setgid
+	PTR	sys_getgid
+	PTR	sys_ni_syscall			/* was signal	2 */
+	PTR	sys_geteuid
+	PTR	sys_getegid			/* 4050 */
+	PTR	sys_acct
+	PTR	sys_umount
+	PTR	sys_ni_syscall
+	PTR	compat_sys_ioctl
+	PTR	compat_sys_fcntl		/* 4055 */
+	PTR	sys_ni_syscall
+	PTR	sys_setpgid
+	PTR	sys_ni_syscall
+	PTR	sys_olduname
+	PTR	sys_umask			/* 4060 */
+	PTR	sys_chroot
+	PTR	sys32_ustat
+	PTR	sys_dup2
+	PTR	sys_getppid
+	PTR	sys_getpgrp			/* 4065 */
+	PTR	sys_setsid
+	PTR	sys32_sigaction
+	PTR	sys_sgetmask
+	PTR	sys_ssetmask
+	PTR	sys_setreuid			/* 4070 */
+	PTR	sys_setregid
+	PTR	sys32_sigsuspend
+	PTR	compat_sys_sigpending
+	PTR	sys_sethostname
+	PTR	compat_sys_setrlimit		/* 4075 */
+	PTR	compat_sys_getrlimit
+	PTR	compat_sys_getrusage
+	PTR	sys32_gettimeofday
+	PTR	sys32_settimeofday
+	PTR	sys_getgroups			/* 4080 */
+	PTR	sys_setgroups
+	PTR	sys_ni_syscall			/* old_select */
+	PTR	sys_symlink
+	PTR	sys_ni_syscall			/* was sys_lstat */
+	PTR	sys_readlink			/* 4085 */
+	PTR	sys_uselib
+	PTR	sys_swapon
+	PTR	sys_reboot
+	PTR	sys32_readdir
+	PTR	old_mmap			/* 4090 */
+	PTR	sys_munmap
+	PTR	sys_truncate
+	PTR	sys_ftruncate
+	PTR	sys_fchmod
+	PTR	sys_fchown			/* 4095 */
+	PTR	sys_getpriority
+	PTR	sys_setpriority
+	PTR	sys_ni_syscall
+	PTR	compat_sys_statfs
+	PTR	compat_sys_fstatfs		/* 4100 */
+	PTR	sys_ni_syscall			/* sys_ioperm */
+	PTR	sys32_socketcall
+	PTR	sys_syslog
+	PTR	compat_sys_setitimer
+	PTR	compat_sys_getitimer		/* 4105 */
+	PTR	compat_sys_newstat
+	PTR	compat_sys_newlstat
+	PTR	compat_sys_newfstat
+	PTR	sys_uname
+	PTR	sys_ni_syscall			/* sys_ioperm  *//* 4110 */
+	PTR	sys_vhangup
+	PTR	sys_ni_syscall			/* was sys_idle	 */
+	PTR	sys_ni_syscall			/* sys_vm86 */
+	PTR	sys32_wait4
+	PTR	sys_swapoff			/* 4115 */
+	PTR	sys32_sysinfo
+	PTR	sys32_ipc
+	PTR	sys_fsync
+	PTR	sys32_sigreturn
+	PTR	sys_clone			/* 4120 */
+	PTR	sys_setdomainname
+	PTR	sys32_newuname
+	PTR	sys_ni_syscall			/* sys_modify_ldt */
+	PTR	sys32_adjtimex
+	PTR	sys_mprotect			/* 4125 */
+	PTR	compat_sys_sigprocmask
+	PTR	sys_ni_syscall			/* was creat_module */
+	PTR	sys_init_module
+	PTR	sys_delete_module
+	PTR	sys_ni_syscall			/* 4130, get_kernel_syms */
+	PTR	sys_quotactl
+	PTR	sys_getpgid
+	PTR	sys_fchdir
+	PTR	sys_bdflush
+	PTR	sys_sysfs			/* 4135 */
+	PTR	sys32_personality
+	PTR	sys_ni_syscall	 		/* for afs_syscall */
+	PTR	sys_setfsuid
+	PTR	sys_setfsgid
+	PTR	sys32_llseek			/* 4140 */
+	PTR	sys32_getdents
+	PTR	compat_sys_select
+	PTR	sys_flock
+	PTR	sys_msync
+	PTR	compat_sys_readv		/* 4145 */
+	PTR	compat_sys_writev
+	PTR	sys_cacheflush
+	PTR	sys_cachectl
+	PTR	sys_sysmips
+	PTR	sys_ni_syscall			/* 4150 */
+	PTR	sys_getsid
+	PTR	sys_fdatasync
+	PTR	sys32_sysctl
+	PTR	sys_mlock
+	PTR	sys_munlock			/* 4155 */
+	PTR	sys_mlockall
+	PTR	sys_munlockall
+	PTR	sys_sched_setparam
+	PTR	sys_sched_getparam
+	PTR	sys_sched_setscheduler 		/* 4160 */
+	PTR	sys_sched_getscheduler
+	PTR	sys_sched_yield
+	PTR	sys_sched_get_priority_max
+	PTR	sys_sched_get_priority_min
+	PTR	sys32_sched_rr_get_interval 	/* 4165 */
+	PTR	compat_sys_nanosleep
+	PTR	sys_mremap
+	PTR	sys_accept
+	PTR	sys_bind
+	PTR	sys_connect			/* 4170 */
+	PTR	sys_getpeername
+	PTR	sys_getsockname
+	PTR	sys_getsockopt
+	PTR	sys_listen
+	PTR	sys_recv			/* 4175 */
+	PTR	sys_recvfrom
+	PTR	compat_sys_recvmsg
+	PTR	sys_send
+	PTR	compat_sys_sendmsg
+	PTR	sys_sendto			/* 4180 */
+	PTR	compat_sys_setsockopt
+	PTR	sys_shutdown
+	PTR	sys_socket
+	PTR	sys_socketpair
+	PTR	sys_setresuid			/* 4185 */
+	PTR	sys_getresuid
+	PTR	sys_ni_syscall			/* was query_module */
+	PTR	sys_poll
+	PTR	sys_nfsservctl
+	PTR	sys_setresgid			/* 4190 */
+	PTR	sys_getresgid
+	PTR	sys_prctl
+	PTR	sys32_rt_sigreturn
+	PTR	sys32_rt_sigaction
+	PTR	sys32_rt_sigprocmask 		/* 4195 */
+	PTR	sys32_rt_sigpending
+	PTR	compat_sys_rt_sigtimedwait
+	PTR	sys32_rt_sigqueueinfo
+	PTR	sys32_rt_sigsuspend
+	PTR	sys32_pread			/* 4200 */
+	PTR	sys32_pwrite
+	PTR	sys_chown
+	PTR	sys_getcwd
+	PTR	sys_capget
+	PTR	sys_capset			/* 4205 */
+	PTR	sys32_sigaltstack
+	PTR	sys32_sendfile
+	PTR	sys_ni_syscall
+	PTR	sys_ni_syscall
+	PTR	sys32_mmap2			/* 4210 */
+	PTR	sys32_truncate64
+	PTR	sys32_ftruncate64
+	PTR	sys_newstat
+	PTR	sys_newlstat
+	PTR	sys_newfstat			/* 4215 */
+	PTR	sys_pivot_root
+	PTR	sys_mincore
+	PTR	sys_madvise
+	PTR	sys_getdents64
+	PTR	compat_sys_fcntl64		/* 4220 */
+	PTR	sys_ni_syscall
+	PTR	sys_gettid
+	PTR	sys32_readahead
+	PTR	sys_setxattr
+	PTR	sys_lsetxattr			/* 4225 */
+	PTR	sys_fsetxattr
+	PTR	sys_getxattr
+	PTR	sys_lgetxattr
+	PTR	sys_fgetxattr
+	PTR	sys_listxattr			/* 4230 */
+	PTR	sys_llistxattr
+	PTR	sys_flistxattr
+	PTR	sys_removexattr
+	PTR	sys_lremovexattr
+	PTR	sys_fremovexattr		/* 4235 */
+	PTR	sys_tkill
+	PTR	sys_sendfile64
+	PTR	compat_sys_futex
+	PTR	compat_sys_sched_setaffinity
+	PTR	compat_sys_sched_getaffinity	/* 4240 */
+	PTR	sys_io_setup
+	PTR	sys_io_destroy
+	PTR	sys_io_getevents
+	PTR	sys_io_submit
+	PTR	sys_io_cancel			/* 4245 */
+	PTR	sys_exit_group
+	PTR	sys_lookup_dcookie
+	PTR	sys_epoll_create
+	PTR	sys_epoll_ctl
+	PTR	sys_epoll_wait			/* 4250 */
+	PTR	sys_remap_file_pages
+	PTR	sys_set_tid_address
+	PTR	sys_restart_syscall
+	PTR	sys_fadvise64_64
+	PTR	compat_sys_statfs64		/* 4255 */
+	PTR	compat_sys_fstatfs64
+	PTR	sys_timer_create
+	PTR	compat_sys_timer_settime
+	PTR	compat_sys_timer_gettime
+	PTR	sys_timer_getoverrun		/* 4260 */
+	PTR	sys_timer_delete
+	PTR	compat_sys_clock_settime
+	PTR	compat_sys_clock_gettime
+	PTR	compat_sys_clock_getres
+	PTR	compat_sys_clock_nanosleep	/* 4265 */
+	PTR	sys_tgkill
+	PTR	compat_sys_utimes
+	PTR	sys_ni_syscall			/* sys_mbind */
+	PTR	sys_ni_syscall			/* sys_get_mempolicy */
+	PTR	sys_ni_syscall			/* 4270 sys_set_mempolicy */
+	PTR	compat_sys_mq_open
+	PTR	sys_mq_unlink
+	PTR	compat_sys_mq_timedsend
+	PTR	compat_sys_mq_timedreceive
+	PTR	compat_sys_mq_notify		/* 4275 */
+	PTR	compat_sys_mq_getsetattr
+	PTR	sys_ni_syscall			/* sys_vserver */
+	PTR	sys_waitid
+	PTR	sys_ni_syscall			/* available, was setaltroot */
+	PTR	sys_add_key			/* 4280 */
+	PTR	sys_request_key
+	PTR	sys_keyctl
+	.size	sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/semaphore.c b/arch/mips/kernel/semaphore.c
new file mode 100644
index 0000000..9c40fe5
--- /dev/null
+++ b/arch/mips/kernel/semaphore.c
@@ -0,0 +1,164 @@
+/*
+ * MIPS-specific semaphore code.
+ *
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ * Copyright (C) 2004 Ralf Baechle <ralf@linux-mips.org>
+ *
+ * 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.
+ *
+ * April 2001 - Reworked by Paul Mackerras <paulus@samba.org>
+ * to eliminate the SMP races in the old version between the updates
+ * of `count' and `waking'.  Now we use negative `count' values to
+ * indicate that some process(es) are waiting for the semaphore.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+#include <asm/cpu-features.h>
+#include <asm/errno.h>
+#include <asm/semaphore.h>
+#include <asm/war.h>
+/*
+ * Atomically update sem->count.
+ * This does the equivalent of the following:
+ *
+ *	old_count = sem->count;
+ *	tmp = MAX(old_count, 0) + incr;
+ *	sem->count = tmp;
+ *	return old_count;
+ *
+ * On machines without lld/scd we need a spinlock to make the manipulation of
+ * sem->count and sem->waking atomic.  Scalability isn't an issue because
+ * this lock is used on UP only so it's just an empty variable.
+ */
+static inline int __sem_update_count(struct semaphore *sem, int incr)
+{
+	int old_count, tmp;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"1:	ll	%0, %2					\n"
+		"	sra	%1, %0, 31				\n"
+		"	not	%1					\n"
+		"	and	%1, %0, %1				\n"
+		"	add	%1, %1, %3				\n"
+		"	sc	%1, %2					\n"
+		"	beqzl	%1, 1b					\n"
+		: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
+		: "r" (incr), "m" (sem->count));
+	} else if (cpu_has_llsc) {
+		__asm__ __volatile__(
+		"1:	ll	%0, %2					\n"
+		"	sra	%1, %0, 31				\n"
+		"	not	%1					\n"
+		"	and	%1, %0, %1				\n"
+		"	add	%1, %1, %3				\n"
+		"	sc	%1, %2					\n"
+		"	beqz	%1, 1b					\n"
+		: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
+		: "r" (incr), "m" (sem->count));
+	} else {
+		static DEFINE_SPINLOCK(semaphore_lock);
+		unsigned long flags;
+
+		spin_lock_irqsave(&semaphore_lock, flags);
+		old_count = atomic_read(&sem->count);
+		tmp = max_t(int, old_count, 0) + incr;
+		atomic_set(&sem->count, tmp);
+		spin_unlock_irqrestore(&semaphore_lock, flags);
+	}
+
+	return old_count;
+}
+
+void __up(struct semaphore *sem)
+{
+	/*
+	 * Note that we incremented count in up() before we came here,
+	 * but that was ineffective since the result was <= 0, and
+	 * any negative value of count is equivalent to 0.
+	 * This ends up setting count to 1, unless count is now > 0
+	 * (i.e. because some other cpu has called up() in the meantime),
+	 * in which case we just increment count.
+	 */
+	__sem_update_count(sem, 1);
+	wake_up(&sem->wait);
+}
+
+EXPORT_SYMBOL(__up);
+
+/*
+ * Note that when we come in to __down or __down_interruptible,
+ * we have already decremented count, but that decrement was
+ * ineffective since the result was < 0, and any negative value
+ * of count is equivalent to 0.
+ * Thus it is only when we decrement count from some value > 0
+ * that we have actually got the semaphore.
+ */
+void __sched __down(struct semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	__set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	/*
+	 * Try to get the semaphore.  If the count is > 0, then we've
+	 * got the semaphore; we decrement count and exit the loop.
+	 * If the count is 0 or negative, we set it to -1, indicating
+	 * that we are asleep, and then sleep.
+	 */
+	while (__sem_update_count(sem, -1) <= 0) {
+		schedule();
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+	}
+	remove_wait_queue(&sem->wait, &wait);
+	__set_task_state(tsk, TASK_RUNNING);
+
+	/*
+	 * If there are any more sleepers, wake one of them up so
+	 * that it can either get the semaphore, or set count to -1
+	 * indicating that there are still processes sleeping.
+	 */
+	wake_up(&sem->wait);
+}
+
+EXPORT_SYMBOL(__down);
+
+int __sched __down_interruptible(struct semaphore * sem)
+{
+	int retval = 0;
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	__set_task_state(tsk, TASK_INTERRUPTIBLE);
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	while (__sem_update_count(sem, -1) <= 0) {
+		if (signal_pending(current)) {
+			/*
+			 * A signal is pending - give up trying.
+			 * Set sem->count to 0 if it is negative,
+			 * since we are no longer sleeping.
+			 */
+			__sem_update_count(sem, 0);
+			retval = -EINTR;
+			break;
+		}
+		schedule();
+		set_task_state(tsk, TASK_INTERRUPTIBLE);
+	}
+	remove_wait_queue(&sem->wait, &wait);
+	__set_task_state(tsk, TASK_RUNNING);
+
+	wake_up(&sem->wait);
+	return retval;
+}
+
+EXPORT_SYMBOL(__down_interruptible);
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
new file mode 100644
index 0000000..6018ca2
--- /dev/null
+++ b/arch/mips/kernel/setup.c
@@ -0,0 +1,571 @@
+/*
+ * 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) 1995 Linus Torvalds
+ * Copyright (C) 1995 Waldorf Electronics
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03  Ralf Baechle
+ * Copyright (C) 1996 Stoned Elipot
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 2000 2001, 2002  Maciej W. Rozycki
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/utsname.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/bootmem.h>
+#include <linux/initrd.h>
+#include <linux/major.h>
+#include <linux/kdev_t.h>
+#include <linux/root_dev.h>
+#include <linux/highmem.h>
+#include <linux/console.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+
+struct cpuinfo_mips cpu_data[NR_CPUS];
+
+EXPORT_SYMBOL(cpu_data);
+
+#ifdef CONFIG_VT
+struct screen_info screen_info;
+#endif
+
+/*
+ * Despite it's name this variable is even if we don't have PCI
+ */
+unsigned int PCI_DMA_BUS_IS_PHYS;
+
+EXPORT_SYMBOL(PCI_DMA_BUS_IS_PHYS);
+
+/*
+ * Setup information
+ *
+ * These are initialized so they are in the .data section
+ */
+unsigned long mips_machtype = MACH_UNKNOWN;
+unsigned long mips_machgroup = MACH_GROUP_UNKNOWN;
+
+EXPORT_SYMBOL(mips_machtype);
+EXPORT_SYMBOL(mips_machgroup);
+
+struct boot_mem_map boot_mem_map;
+
+static char command_line[CL_SIZE];
+       char arcs_cmdline[CL_SIZE]=CONFIG_CMDLINE;
+
+/*
+ * mips_io_port_base is the begin of the address space to which x86 style
+ * I/O ports are mapped.
+ */
+const unsigned long mips_io_port_base = -1;
+EXPORT_SYMBOL(mips_io_port_base);
+
+/*
+ * isa_slot_offset is the address where E(ISA) busaddress 0 is mapped
+ * for the processor.
+ */
+unsigned long isa_slot_offset;
+EXPORT_SYMBOL(isa_slot_offset);
+
+static struct resource code_resource = { .name = "Kernel code", };
+static struct resource data_resource = { .name = "Kernel data", };
+
+void __init add_memory_region(phys_t start, phys_t size, long type)
+{
+	int x = boot_mem_map.nr_map;
+	struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1;
+
+	/*
+	 * Try to merge with previous entry if any.  This is far less than
+	 * perfect but is sufficient for most real world cases.
+	 */
+	if (x && prev->addr + prev->size == start && prev->type == type) {
+		prev->size += size;
+		return;
+	}
+
+	if (x == BOOT_MEM_MAP_MAX) {
+		printk("Ooops! Too many entries in the memory map!\n");
+		return;
+	}
+
+	boot_mem_map.map[x].addr = start;
+	boot_mem_map.map[x].size = size;
+	boot_mem_map.map[x].type = type;
+	boot_mem_map.nr_map++;
+}
+
+static void __init print_memory_map(void)
+{
+	int i;
+	const int field = 2 * sizeof(unsigned long);
+
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		printk(" memory: %0*Lx @ %0*Lx ",
+		       field, (unsigned long long) boot_mem_map.map[i].size,
+		       field, (unsigned long long) boot_mem_map.map[i].addr);
+
+		switch (boot_mem_map.map[i].type) {
+		case BOOT_MEM_RAM:
+			printk("(usable)\n");
+			break;
+		case BOOT_MEM_ROM_DATA:
+			printk("(ROM data)\n");
+			break;
+		case BOOT_MEM_RESERVED:
+			printk("(reserved)\n");
+			break;
+		default:
+			printk("type %lu\n", boot_mem_map.map[i].type);
+			break;
+		}
+	}
+}
+
+static inline void parse_cmdline_early(void)
+{
+	char c = ' ', *to = command_line, *from = saved_command_line;
+	unsigned long start_at, mem_size;
+	int len = 0;
+	int usermem = 0;
+
+	printk("Determined physical RAM map:\n");
+	print_memory_map();
+
+	for (;;) {
+		/*
+		 * "mem=XXX[kKmM]" defines a memory region from
+		 * 0 to <XXX>, overriding the determined size.
+		 * "mem=XXX[KkmM]@YYY[KkmM]" defines a memory region from
+		 * <YYY> to <YYY>+<XXX>, overriding the determined size.
+		 */
+		if (c == ' ' && !memcmp(from, "mem=", 4)) {
+			if (to != command_line)
+				to--;
+			/*
+			 * If a user specifies memory size, we
+			 * blow away any automatically generated
+			 * size.
+			 */
+			if (usermem == 0) {
+				boot_mem_map.nr_map = 0;
+				usermem = 1;
+			}
+			mem_size = memparse(from + 4, &from);
+			if (*from == '@')
+				start_at = memparse(from + 1, &from);
+			else
+				start_at = 0;
+			add_memory_region(start_at, mem_size, BOOT_MEM_RAM);
+		}
+		c = *(from++);
+		if (!c)
+			break;
+		if (CL_SIZE <= ++len)
+			break;
+		*(to++) = c;
+	}
+	*to = '\0';
+
+	if (usermem) {
+		printk("User-defined physical RAM map:\n");
+		print_memory_map();
+	}
+}
+
+static inline int parse_rd_cmdline(unsigned long* rd_start, unsigned long* rd_end)
+{
+	/*
+	 * "rd_start=0xNNNNNNNN" defines the memory address of an initrd
+	 * "rd_size=0xNN" it's size
+	 */
+	unsigned long start = 0;
+	unsigned long size = 0;
+	unsigned long end;
+	char cmd_line[CL_SIZE];
+	char *start_str;
+	char *size_str;
+	char *tmp;
+
+	strcpy(cmd_line, command_line);
+	*command_line = 0;
+	tmp = cmd_line;
+	/* Ignore "rd_start=" strings in other parameters. */
+	start_str = strstr(cmd_line, "rd_start=");
+	if (start_str && start_str != cmd_line && *(start_str - 1) != ' ')
+		start_str = strstr(start_str, " rd_start=");
+	while (start_str) {
+		if (start_str != cmd_line)
+			strncat(command_line, tmp, start_str - tmp);
+		start = memparse(start_str + 9, &start_str);
+		tmp = start_str + 1;
+		start_str = strstr(start_str, " rd_start=");
+	}
+	if (*tmp)
+		strcat(command_line, tmp);
+
+	strcpy(cmd_line, command_line);
+	*command_line = 0;
+	tmp = cmd_line;
+	/* Ignore "rd_size" strings in other parameters. */
+	size_str = strstr(cmd_line, "rd_size=");
+	if (size_str && size_str != cmd_line && *(size_str - 1) != ' ')
+		size_str = strstr(size_str, " rd_size=");
+	while (size_str) {
+		if (size_str != cmd_line)
+			strncat(command_line, tmp, size_str - tmp);
+		size = memparse(size_str + 8, &size_str);
+		tmp = size_str + 1;
+		size_str = strstr(size_str, " rd_size=");
+	}
+	if (*tmp)
+		strcat(command_line, tmp);
+
+#ifdef CONFIG_MIPS64
+	/* HACK: Guess if the sign extension was forgotten */
+	if (start > 0x0000000080000000 && start < 0x00000000ffffffff)
+		start |= 0xffffffff00000000;
+#endif
+
+	end = start + size;
+	if (start && end) {
+		*rd_start = start;
+		*rd_end = end;
+		return 1;
+	}
+	return 0;
+}
+
+#define PFN_UP(x)	(((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+
+#define MAXMEM		HIGHMEM_START
+#define MAXMEM_PFN	PFN_DOWN(MAXMEM)
+
+static inline void bootmem_init(void)
+{
+	unsigned long start_pfn;
+	unsigned long reserved_end = (unsigned long)&_end;
+#ifndef CONFIG_SGI_IP27
+	unsigned long first_usable_pfn;
+	unsigned long bootmap_size;
+	int i;
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+	int initrd_reserve_bootmem = 0;
+
+	/* Board specific code should have set up initrd_start and initrd_end */
+ 	ROOT_DEV = Root_RAM0;
+	if (parse_rd_cmdline(&initrd_start, &initrd_end)) {
+		reserved_end = max(reserved_end, initrd_end);
+		initrd_reserve_bootmem = 1;
+	} else {
+		unsigned long tmp;
+		u32 *initrd_header;
+
+		tmp = ((reserved_end + PAGE_SIZE-1) & PAGE_MASK) - sizeof(u32) * 2;
+		if (tmp < reserved_end)
+			tmp += PAGE_SIZE;
+		initrd_header = (u32 *)tmp;
+		if (initrd_header[0] == 0x494E5244) {
+			initrd_start = (unsigned long)&initrd_header[2];
+			initrd_end = initrd_start + initrd_header[1];
+			reserved_end = max(reserved_end, initrd_end);
+			initrd_reserve_bootmem = 1;
+		}
+	}
+#endif	/* CONFIG_BLK_DEV_INITRD */
+
+	/*
+	 * Partially used pages are not usable - thus
+	 * we are rounding upwards.
+	 */
+	start_pfn = PFN_UP(CPHYSADDR(reserved_end));
+
+#ifndef CONFIG_SGI_IP27
+	/* Find the highest page frame number we have available.  */
+	max_pfn = 0;
+	first_usable_pfn = -1UL;
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		unsigned long start, end;
+
+		if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+			continue;
+
+		start = PFN_UP(boot_mem_map.map[i].addr);
+		end = PFN_DOWN(boot_mem_map.map[i].addr
+		      + boot_mem_map.map[i].size);
+
+		if (start >= end)
+			continue;
+		if (end > max_pfn)
+			max_pfn = end;
+		if (start < first_usable_pfn) {
+			if (start > start_pfn) {
+				first_usable_pfn = start;
+			} else if (end > start_pfn) {
+				first_usable_pfn = start_pfn;
+			}
+		}
+	}
+
+	/*
+	 * Determine low and high memory ranges
+	 */
+	max_low_pfn = max_pfn;
+	if (max_low_pfn > MAXMEM_PFN) {
+		max_low_pfn = MAXMEM_PFN;
+#ifndef CONFIG_HIGHMEM
+		/* Maximum memory usable is what is directly addressable */
+		printk(KERN_WARNING "Warning only %ldMB will be used.\n",
+		       MAXMEM >> 20);
+		printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+#endif
+	}
+
+#ifdef CONFIG_HIGHMEM
+	/*
+	 * Crude, we really should make a better attempt at detecting
+	 * highstart_pfn
+	 */
+	highstart_pfn = highend_pfn = max_pfn;
+	if (max_pfn > MAXMEM_PFN) {
+		highstart_pfn = MAXMEM_PFN;
+		printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+		       (highend_pfn - highstart_pfn) >> (20 - PAGE_SHIFT));
+	}
+#endif
+
+	/* Initialize the boot-time allocator with low memory only.  */
+	bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn);
+
+	/*
+	 * Register fully available low RAM pages with the bootmem allocator.
+	 */
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		unsigned long curr_pfn, last_pfn, size;
+
+		/*
+		 * Reserve usable memory.
+		 */
+		if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+			continue;
+
+		/*
+		 * We are rounding up the start address of usable memory:
+		 */
+		curr_pfn = PFN_UP(boot_mem_map.map[i].addr);
+		if (curr_pfn >= max_low_pfn)
+			continue;
+		if (curr_pfn < start_pfn)
+			curr_pfn = start_pfn;
+
+		/*
+		 * ... and at the end of the usable range downwards:
+		 */
+		last_pfn = PFN_DOWN(boot_mem_map.map[i].addr
+				    + boot_mem_map.map[i].size);
+
+		if (last_pfn > max_low_pfn)
+			last_pfn = max_low_pfn;
+
+		/*
+		 * Only register lowmem part of lowmem segment with bootmem.
+		 */
+		size = last_pfn - curr_pfn;
+		if (curr_pfn > PFN_DOWN(HIGHMEM_START))
+			continue;
+		if (curr_pfn + size - 1 > PFN_DOWN(HIGHMEM_START))
+			size = PFN_DOWN(HIGHMEM_START) - curr_pfn;
+		if (!size)
+			continue;
+
+		/*
+		 * ... finally, did all the rounding and playing
+		 * around just make the area go away?
+		 */
+		if (last_pfn <= curr_pfn)
+			continue;
+
+		/* Register lowmem ranges */
+		free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
+	}
+
+	/* Reserve the bootmap memory.  */
+	reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size);
+#endif /* CONFIG_SGI_IP27 */
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	initrd_below_start_ok = 1;
+	if (initrd_start) {
+		unsigned long initrd_size = ((unsigned char *)initrd_end) - ((unsigned char *)initrd_start);
+		printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
+		       (void *)initrd_start, initrd_size);
+
+		if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) {
+			printk("initrd extends beyond end of memory "
+			       "(0x%0*Lx > 0x%0*Lx)\ndisabling initrd\n",
+			       sizeof(long) * 2,
+			       (unsigned long long)CPHYSADDR(initrd_end),
+			       sizeof(long) * 2,
+			       (unsigned long long)PFN_PHYS(max_low_pfn));
+			initrd_start = initrd_end = 0;
+			initrd_reserve_bootmem = 0;
+		}
+
+		if (initrd_reserve_bootmem)
+			reserve_bootmem(CPHYSADDR(initrd_start), initrd_size);
+	}
+#endif /* CONFIG_BLK_DEV_INITRD  */
+}
+
+static inline void resource_init(void)
+{
+	int i;
+
+#if defined(CONFIG_MIPS64) && !defined(CONFIG_BUILD_ELF64)
+	/*
+	 * The 64bit code in 32bit object format trick can't represent
+	 * 64bit wide relocations for linker script symbols.
+	 */
+	code_resource.start = CPHYSADDR(&_text);
+	code_resource.end = CPHYSADDR(&_etext) - 1;
+	data_resource.start = CPHYSADDR(&_etext);
+	data_resource.end = CPHYSADDR(&_edata) - 1;
+#else
+	code_resource.start = virt_to_phys(&_text);
+	code_resource.end = virt_to_phys(&_etext) - 1;
+	data_resource.start = virt_to_phys(&_etext);
+	data_resource.end = virt_to_phys(&_edata) - 1;
+#endif
+
+	/*
+	 * Request address space for all standard RAM.
+	 */
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		struct resource *res;
+		unsigned long start, end;
+
+		start = boot_mem_map.map[i].addr;
+		end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1;
+		if (start >= MAXMEM)
+			continue;
+		if (end >= MAXMEM)
+			end = MAXMEM - 1;
+
+		res = alloc_bootmem(sizeof(struct resource));
+		switch (boot_mem_map.map[i].type) {
+		case BOOT_MEM_RAM:
+		case BOOT_MEM_ROM_DATA:
+			res->name = "System RAM";
+			break;
+		case BOOT_MEM_RESERVED:
+		default:
+			res->name = "reserved";
+		}
+
+		res->start = start;
+		res->end = end;
+
+		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+		request_resource(&iomem_resource, res);
+
+		/*
+		 *  We don't know which RAM region contains kernel data,
+		 *  so we try it repeatedly and let the resource manager
+		 *  test it.
+		 */
+		request_resource(res, &code_resource);
+		request_resource(res, &data_resource);
+	}
+}
+
+#undef PFN_UP
+#undef PFN_DOWN
+#undef PFN_PHYS
+
+#undef MAXMEM
+#undef MAXMEM_PFN
+
+static int __initdata earlyinit_debug;
+
+static int __init earlyinit_debug_setup(char *str)
+{
+	earlyinit_debug = 1;
+	return 1;
+}
+__setup("earlyinit_debug", earlyinit_debug_setup);
+
+extern initcall_t __earlyinitcall_start, __earlyinitcall_end;
+
+static void __init do_earlyinitcalls(void)
+{
+	initcall_t *call, *start, *end;
+
+	start = &__earlyinitcall_start;
+	end = &__earlyinitcall_end;
+
+	for (call = start; call < end; call++) {
+		if (earlyinit_debug)
+			printk("calling earlyinitcall 0x%p\n", *call);
+
+		(*call)();
+	}
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+	cpu_probe();
+	prom_init();
+	cpu_report();
+
+#if defined(CONFIG_VT)
+#if defined(CONFIG_VGA_CONSOLE)
+        conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+        conswitchp = &dummy_con;
+#endif
+#endif
+
+	/* call board setup routine */
+	do_earlyinitcalls();
+
+	strlcpy(command_line, arcs_cmdline, sizeof(command_line));
+	strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
+
+	*cmdline_p = command_line;
+
+	parse_cmdline_early();
+	bootmem_init();
+	paging_init();
+	resource_init();
+}
+
+int __init fpu_disable(char *s)
+{
+	cpu_data[0].options &= ~MIPS_CPU_FPU;
+
+	return 1;
+}
+
+__setup("nofpu", fpu_disable);
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h
new file mode 100644
index 0000000..f9234df
--- /dev/null
+++ b/arch/mips/kernel/signal-common.h
@@ -0,0 +1,137 @@
+/*
+ * 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) 1991, 1992  Linus Torvalds
+ * Copyright (C) 1994 - 2000  Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+
+static inline int
+setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+{
+	int err = 0;
+
+	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
+	err |= __put_user(regs->cp0_status, &sc->sc_status);
+
+#define save_gp_reg(i) do {						\
+	err |= __put_user(regs->regs[i], &sc->sc_regs[i]);		\
+} while(0)
+	__put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
+	save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
+	save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
+	save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
+	save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
+	save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
+	save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
+	save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
+	save_gp_reg(31);
+#undef save_gp_reg
+
+	err |= __put_user(regs->hi, &sc->sc_mdhi);
+	err |= __put_user(regs->lo, &sc->sc_mdlo);
+	err |= __put_user(regs->cp0_cause, &sc->sc_cause);
+	err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
+
+	err |= __put_user(!!used_math(), &sc->sc_used_math);
+
+	if (!used_math())
+		goto out;
+
+	/*
+	 * Save FPU state to signal context.  Signal handler will "inherit"
+	 * current FPU state.
+	 */
+	preempt_disable();
+
+	if (!is_fpu_owner()) {
+		own_fpu();
+		restore_fp(current);
+	}
+	err |= save_fp_context(sc);
+
+	preempt_enable();
+
+out:
+	return err;
+}
+
+static inline int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+{
+	int err = 0;
+	unsigned int used_math;
+
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
+	err |= __get_user(regs->hi, &sc->sc_mdhi);
+	err |= __get_user(regs->lo, &sc->sc_mdlo);
+
+#define restore_gp_reg(i) do {						\
+	err |= __get_user(regs->regs[i], &sc->sc_regs[i]);		\
+} while(0)
+	restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
+	restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
+	restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
+	restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
+	restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
+	restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
+	restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
+	restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
+	restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
+	restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
+	restore_gp_reg(31);
+#undef restore_gp_reg
+
+	err |= __get_user(used_math, &sc->sc_used_math);
+	conditional_used_math(used_math);
+
+	preempt_disable();
+
+	if (used_math()) {
+		/* restore fpu context if we have used it before */
+		own_fpu();
+		err |= restore_fp_context(sc);
+	} else {
+		/* signal handler may have used FPU.  Give it up. */
+		lose_fpu();
+	}
+
+	preempt_enable();
+
+	return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+	unsigned long sp, almask;
+
+	/* Default to using normal stack */
+	sp = regs->regs[29];
+
+	/*
+ 	 * FPU emulator may have it's own trampoline active just
+ 	 * above the user stack, 16-bytes before the next lowest
+ 	 * 16 byte boundary.  Try to avoid trashing it.
+ 	 */
+ 	sp -= 32;
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
+		sp = current->sas_ss_sp + current->sas_ss_size;
+
+	if (PLAT_TRAMPOLINE_STUFF_LINE)
+		almask = ~(PLAT_TRAMPOLINE_STUFF_LINE - 1);
+	else
+		almask = ALMASK;
+
+	return (void *)((sp - frame_size) & almask);
+}
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
new file mode 100644
index 0000000..508026a
--- /dev/null
+++ b/arch/mips/kernel/signal.c
@@ -0,0 +1,517 @@
+/*
+ * 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) 1991, 1992  Linus Torvalds
+ * Copyright (C) 1994 - 2000  Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/personality.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/compiler.h>
+
+#include <asm/asm.h>
+#include <linux/bitops.h>
+#include <asm/cacheflush.h>
+#include <asm/fpu.h>
+#include <asm/sim.h>
+#include <asm/uaccess.h>
+#include <asm/ucontext.h>
+#include <asm/cpu-features.h>
+
+#include "signal-common.h"
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+static int do_signal(sigset_t *oldset, struct pt_regs *regs);
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+
+#ifdef CONFIG_TRAD_SIGNALS
+save_static_function(sys_sigsuspend);
+__attribute_used__ noinline static int
+_sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
+{
+	sigset_t *uset, saveset, newset;
+
+	uset = (sigset_t *) regs.regs[4];
+	if (copy_from_user(&newset, uset, sizeof(sigset_t)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs.regs[2] = EINTR;
+	regs.regs[7] = 1;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&saveset, &regs))
+			return -EINTR;
+	}
+}
+#endif
+
+save_static_function(sys_rt_sigsuspend);
+__attribute_used__ noinline static int
+_sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
+{
+	sigset_t *unewset, saveset, newset;
+	size_t sigsetsize;
+
+	/* XXX Don't preclude handling different sized sigset_t's.  */
+	sigsetsize = regs.regs[5];
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	unewset = (sigset_t *) regs.regs[4];
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+        recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs.regs[2] = EINTR;
+	regs.regs[7] = 1;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&saveset, &regs))
+			return -EINTR;
+	}
+}
+
+#ifdef CONFIG_TRAD_SIGNALS
+asmlinkage int sys_sigaction(int sig, const struct sigaction *act,
+	struct sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+	int err = 0;
+
+	if (act) {
+		old_sigset_t mask;
+
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
+			return -EFAULT;
+		err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler);
+		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		err |= __get_user(mask, &act->sa_mask.sig[0]);
+		if (err)
+			return -EFAULT;
+
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
+                        return -EFAULT;
+		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler);
+		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
+		err |= __put_user(0, &oact->sa_mask.sig[1]);
+		err |= __put_user(0, &oact->sa_mask.sig[2]);
+		err |= __put_user(0, &oact->sa_mask.sig[3]);
+		if (err)
+			return -EFAULT;
+	}
+
+	return ret;
+}
+#endif
+
+asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs)
+{
+	const stack_t *uss = (const stack_t *) regs.regs[4];
+	stack_t *uoss = (stack_t *) regs.regs[5];
+	unsigned long usp = regs.regs[29];
+
+	return do_sigaltstack(uss, uoss, usp);
+}
+
+#if PLAT_TRAMPOLINE_STUFF_LINE
+#define __tramp __attribute__((aligned(PLAT_TRAMPOLINE_STUFF_LINE)))
+#else
+#define __tramp
+#endif
+
+#ifdef CONFIG_TRAD_SIGNALS
+struct sigframe {
+	u32 sf_ass[4];			/* argument save space for o32 */
+	u32 sf_code[2] __tramp;		/* signal trampoline */
+	struct sigcontext sf_sc __tramp;
+	sigset_t sf_mask;
+};
+#endif
+
+struct rt_sigframe {
+	u32 rs_ass[4];			/* argument save space for o32 */
+	u32 rs_code[2] __tramp;		/* signal trampoline */
+	struct siginfo rs_info __tramp;
+	struct ucontext rs_uc;
+};
+
+#ifdef CONFIG_TRAD_SIGNALS
+save_static_function(sys_sigreturn);
+__attribute_used__ noinline static void
+_sys_sigreturn(nabi_no_regargs struct pt_regs regs)
+{
+	struct sigframe *frame;
+	sigset_t blocked;
+
+	frame = (struct sigframe *) regs.regs[29];
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
+		goto badframe;
+
+	sigdelsetmask(&blocked, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = blocked;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (restore_sigcontext(&regs, &frame->sf_sc))
+		goto badframe;
+
+	/*
+	 * Don't let your children do this ...
+	 */
+	if (current_thread_info()->flags & TIF_SYSCALL_TRACE)
+		do_syscall_trace(&regs, 1);
+	__asm__ __volatile__(
+		"move\t$29, %0\n\t"
+		"j\tsyscall_exit"
+		:/* no outputs */
+		:"r" (&regs));
+	/* Unreached */
+
+badframe:
+	force_sig(SIGSEGV, current);
+}
+#endif
+
+save_static_function(sys_rt_sigreturn);
+__attribute_used__ noinline static void
+_sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
+{
+	struct rt_sigframe *frame;
+	sigset_t set;
+	stack_t st;
+
+	frame = (struct rt_sigframe *) regs.regs[29];
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext))
+		goto badframe;
+
+	if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st)))
+		goto badframe;
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, regs.regs[29]);
+
+	/*
+	 * Don't let your children do this ...
+	 */
+	__asm__ __volatile__(
+		"move\t$29, %0\n\t"
+		"j\tsyscall_exit"
+		:/* no outputs */
+		:"r" (&regs));
+	/* Unreached */
+
+badframe:
+	force_sig(SIGSEGV, current);
+}
+
+#ifdef CONFIG_TRAD_SIGNALS
+static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
+	int signr, sigset_t *set)
+{
+	struct sigframe *frame;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+		goto give_sigsegv;
+
+	/*
+	 * Set up the return code ...
+	 *
+	 *         li      v0, __NR_sigreturn
+	 *         syscall
+	 */
+	if (PLAT_TRAMPOLINE_STUFF_LINE)
+		__clear_user(frame->sf_code, PLAT_TRAMPOLINE_STUFF_LINE);
+	err |= __put_user(0x24020000 + __NR_sigreturn, frame->sf_code + 0);
+	err |= __put_user(0x0000000c                 , frame->sf_code + 1);
+	flush_cache_sigtramp((unsigned long) frame->sf_code);
+
+	err |= setup_sigcontext(regs, &frame->sf_sc);
+	err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
+
+	/*
+	 * Arguments to signal handler:
+	 *
+	 *   a0 = signal number
+	 *   a1 = 0 (should be cause)
+	 *   a2 = pointer to struct sigcontext
+	 *
+	 * $25 and c0_epc point to the signal handler, $29 points to the
+	 * struct sigframe.
+	 */
+	regs->regs[ 4] = signr;
+	regs->regs[ 5] = 0;
+	regs->regs[ 6] = (unsigned long) &frame->sf_sc;
+	regs->regs[29] = (unsigned long) frame;
+	regs->regs[31] = (unsigned long) frame->sf_code;
+	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+	       current->comm, current->pid,
+	       frame, regs->cp0_epc, frame->regs[31]);
+#endif
+        return;
+
+give_sigsegv:
+	force_sigsegv(signr, current);
+}
+#endif
+
+static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
+	int signr, sigset_t *set, siginfo_t *info)
+{
+	struct rt_sigframe *frame;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+		goto give_sigsegv;
+
+	/*
+	 * Set up the return code ...
+	 *
+	 *         li      v0, __NR_rt_sigreturn
+	 *         syscall
+	 */
+	if (PLAT_TRAMPOLINE_STUFF_LINE)
+		__clear_user(frame->rs_code, PLAT_TRAMPOLINE_STUFF_LINE);
+	err |= __put_user(0x24020000 + __NR_rt_sigreturn, frame->rs_code + 0);
+	err |= __put_user(0x0000000c                    , frame->rs_code + 1);
+	flush_cache_sigtramp((unsigned long) frame->rs_code);
+
+	/* Create siginfo.  */
+	err |= copy_siginfo_to_user(&frame->rs_info, info);
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->rs_uc.uc_flags);
+	err |= __put_user(0, &frame->rs_uc.uc_link);
+	err |= __put_user((void *)current->sas_ss_sp,
+	                  &frame->rs_uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->regs[29]),
+	                  &frame->rs_uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size,
+	                  &frame->rs_uc.uc_stack.ss_size);
+	err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
+	err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
+
+	if (err)
+		goto give_sigsegv;
+
+	/*
+	 * Arguments to signal handler:
+	 *
+	 *   a0 = signal number
+	 *   a1 = 0 (should be cause)
+	 *   a2 = pointer to ucontext
+	 *
+	 * $25 and c0_epc point to the signal handler, $29 points to
+	 * the struct rt_sigframe.
+	 */
+	regs->regs[ 4] = signr;
+	regs->regs[ 5] = (unsigned long) &frame->rs_info;
+	regs->regs[ 6] = (unsigned long) &frame->rs_uc;
+	regs->regs[29] = (unsigned long) frame;
+	regs->regs[31] = (unsigned long) frame->rs_code;
+	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+	       current->comm, current->pid,
+	       frame, regs->cp0_epc, regs->regs[31]);
+#endif
+	return;
+
+give_sigsegv:
+	force_sigsegv(signr, current);
+}
+
+extern void setup_rt_frame_n32(struct k_sigaction * ka,
+	struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info);
+
+static inline void handle_signal(unsigned long sig, siginfo_t *info,
+	struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
+{
+	switch(regs->regs[0]) {
+	case ERESTART_RESTARTBLOCK:
+	case ERESTARTNOHAND:
+		regs->regs[2] = EINTR;
+		break;
+	case ERESTARTSYS:
+		if(!(ka->sa.sa_flags & SA_RESTART)) {
+			regs->regs[2] = EINTR;
+			break;
+		}
+	/* fallthrough */
+	case ERESTARTNOINTR:		/* Userland will reload $v0.  */
+		regs->regs[7] = regs->regs[26];
+		regs->cp0_epc -= 8;
+	}
+
+	regs->regs[0] = 0;		/* Don't deal with this again.  */
+
+#ifdef CONFIG_TRAD_SIGNALS
+	if (ka->sa.sa_flags & SA_SIGINFO) {
+#else
+	if (1) {
+#endif
+#ifdef CONFIG_MIPS32_N32
+		if ((current->thread.mflags & MF_ABI_MASK) == MF_N32)
+			setup_rt_frame_n32 (ka, regs, sig, oldset, info);
+		else
+#endif
+			setup_rt_frame(ka, regs, sig, oldset, info);
+	}
+#ifdef CONFIG_TRAD_SIGNALS
+	else
+		setup_frame(ka, regs, sig, oldset);
+#endif
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+}
+
+extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
+extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs);
+
+static int do_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+	struct k_sigaction ka;
+	siginfo_t info;
+	int signr;
+
+#ifdef CONFIG_BINFMT_ELF32
+	if ((current->thread.mflags & MF_ABI_MASK) == MF_O32) {
+		return do_signal32(oldset, regs);
+	}
+#endif
+
+	/*
+	 * We want the common case to go fast, which is why we may in certain
+	 * cases get here from kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if (!user_mode(regs))
+		return 1;
+
+	if (try_to_freeze(0))
+		goto no_signal;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	if (signr > 0) {
+		handle_signal(signr, &info, &ka, oldset, regs);
+		return 1;
+	}
+
+no_signal:
+	/*
+	 * Who's code doesn't conform to the restartable syscall convention
+	 * dies here!!!  The li instruction, a single machine instruction,
+	 * must directly be followed by the syscall instruction.
+	 */
+	if (regs->regs[0]) {
+		if (regs->regs[2] == ERESTARTNOHAND ||
+		    regs->regs[2] == ERESTARTSYS ||
+		    regs->regs[2] == ERESTARTNOINTR) {
+			regs->regs[7] = regs->regs[26];
+			regs->cp0_epc -= 8;
+		}
+		if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
+			regs->regs[2] = __NR_restart_syscall;
+			regs->regs[7] = regs->regs[26];
+			regs->cp0_epc -= 4;
+		}
+	}
+	return 0;
+}
+
+/*
+ * notification of userspace execution resumption
+ * - triggered by current->work.notify_resume
+ */
+asmlinkage void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
+	__u32 thread_info_flags)
+{
+	/* deal with pending signal delivery */
+	if (thread_info_flags & _TIF_SIGPENDING) {
+#ifdef CONFIG_BINFMT_ELF32
+		if (likely((current->thread.mflags & MF_ABI_MASK) == MF_O32)) {
+			do_signal32(oldset, regs);
+			return;
+		}
+#endif
+#ifdef CONFIG_BINFMT_IRIX
+		if (unlikely(current->personality != PER_LINUX)) {
+			do_irix_signal(oldset, regs);
+			return;
+		}
+#endif
+		do_signal(oldset, regs);
+	}
+}
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
new file mode 100644
index 0000000..1f3b191
--- /dev/null
+++ b/arch/mips/kernel/signal32.c
@@ -0,0 +1,905 @@
+/*
+ * 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) 1991, 1992  Linus Torvalds
+ * Copyright (C) 1994 - 2000  Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/compat.h>
+#include <linux/suspend.h>
+#include <linux/compiler.h>
+
+#include <asm/asm.h>
+#include <linux/bitops.h>
+#include <asm/cacheflush.h>
+#include <asm/sim.h>
+#include <asm/uaccess.h>
+#include <asm/ucontext.h>
+#include <asm/system.h>
+#include <asm/fpu.h>
+
+#define SI_PAD_SIZE32   ((SI_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct compat_siginfo {
+	int si_signo;
+	int si_code;
+	int si_errno;
+
+	union {
+		int _pad[SI_PAD_SIZE32];
+
+		/* kill() */
+		struct {
+			compat_pid_t _pid;	/* sender's pid */
+			compat_uid_t _uid;	/* sender's uid */
+		} _kill;
+
+		/* SIGCHLD */
+		struct {
+			compat_pid_t _pid;	/* which child */
+			compat_uid_t _uid;	/* sender's uid */
+			int _status;		/* exit code */
+			compat_clock_t _utime;
+			compat_clock_t _stime;
+		} _sigchld;
+
+		/* IRIX SIGCHLD */
+		struct {
+			compat_pid_t _pid;	/* which child */
+			compat_clock_t _utime;
+			int _status;		/* exit code */
+			compat_clock_t _stime;
+		} _irix_sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			s32 _addr; /* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL, SIGXFSZ (To do ...)  */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			compat_pid_t _pid;	/* sender's pid */
+			compat_uid_t _uid;	/* sender's uid */
+			compat_sigval_t _sigval;
+		} _rt;
+
+	} _sifields;
+} compat_siginfo_t;
+
+/*
+ * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
+ */
+#define __NR_O32_sigreturn		4119
+#define __NR_O32_rt_sigreturn		4193
+#define __NR_O32_restart_syscall	4253
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
+
+/* 32-bit compatibility types */
+
+#define _NSIG_BPW32	32
+#define _NSIG_WORDS32	(_NSIG / _NSIG_BPW32)
+
+typedef struct {
+	unsigned int sig[_NSIG_WORDS32];
+} sigset_t32;
+
+typedef unsigned int __sighandler32_t;
+typedef void (*vfptr_t)(void);
+
+struct sigaction32 {
+	unsigned int		sa_flags;
+	__sighandler32_t	sa_handler;
+	compat_sigset_t		sa_mask;
+};
+
+/* IRIX compatible stack_t  */
+typedef struct sigaltstack32 {
+	s32 ss_sp;
+	compat_size_t ss_size;
+	int ss_flags;
+} stack32_t;
+
+struct ucontext32 {
+	u32                 uc_flags;
+	s32                 uc_link;
+	stack32_t           uc_stack;
+	struct sigcontext32 uc_mcontext;
+	sigset_t32          uc_sigmask;   /* mask last for extensibility */
+};
+
+extern void __put_sigset_unknown_nsig(void);
+extern void __get_sigset_unknown_nsig(void);
+
+static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t *ubuf)
+{
+	int err = 0;
+
+	if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)))
+		return -EFAULT;
+
+	switch (_NSIG_WORDS) {
+	default:
+		__put_sigset_unknown_nsig();
+	case 2:
+		err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]);
+		err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]);
+	case 1:
+		err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]);
+		err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]);
+	}
+
+	return err;
+}
+
+static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t *ubuf)
+{
+	int err = 0;
+	unsigned long sig[4];
+
+	if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf)))
+		return -EFAULT;
+
+	switch (_NSIG_WORDS) {
+	default:
+		__get_sigset_unknown_nsig();
+	case 2:
+		err |= __get_user (sig[3], &ubuf->sig[3]);
+		err |= __get_user (sig[2], &ubuf->sig[2]);
+		kbuf->sig[1] = sig[2] | (sig[3] << 32);
+	case 1:
+		err |= __get_user (sig[1], &ubuf->sig[1]);
+		err |= __get_user (sig[0], &ubuf->sig[0]);
+		kbuf->sig[0] = sig[0] | (sig[1] << 32);
+	}
+
+	return err;
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+
+save_static_function(sys32_sigsuspend);
+__attribute_used__ noinline static int
+_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
+{
+	compat_sigset_t *uset;
+	sigset_t newset, saveset;
+
+	uset = (compat_sigset_t *) regs.regs[4];
+	if (get_sigset(&newset, uset))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs.regs[2] = EINTR;
+	regs.regs[7] = 1;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal32(&saveset, &regs))
+			return -EINTR;
+	}
+}
+
+save_static_function(sys32_rt_sigsuspend);
+__attribute_used__ noinline static int
+_sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
+{
+	compat_sigset_t *uset;
+	sigset_t newset, saveset;
+        size_t sigsetsize;
+
+	/* XXX Don't preclude handling different sized sigset_t's.  */
+	sigsetsize = regs.regs[5];
+	if (sigsetsize != sizeof(compat_sigset_t))
+		return -EINVAL;
+
+	uset = (compat_sigset_t *) regs.regs[4];
+	if (get_sigset(&newset, uset))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+        recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs.regs[2] = EINTR;
+	regs.regs[7] = 1;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal32(&saveset, &regs))
+			return -EINTR;
+	}
+}
+
+asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act,
+                               struct sigaction32 *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+	int err = 0;
+
+	if (act) {
+		old_sigset_t mask;
+
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
+			return -EFAULT;
+		err |= __get_user((u32)(u64)new_ka.sa.sa_handler,
+		                  &act->sa_handler);
+		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		err |= __get_user(mask, &act->sa_mask.sig[0]);
+		if (err)
+			return -EFAULT;
+
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
+                        return -EFAULT;
+		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
+		                  &oact->sa_handler);
+		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
+                err |= __put_user(0, &oact->sa_mask.sig[1]);
+                err |= __put_user(0, &oact->sa_mask.sig[2]);
+                err |= __put_user(0, &oact->sa_mask.sig[3]);
+                if (err)
+			return -EFAULT;
+	}
+
+	return ret;
+}
+
+asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
+{
+	const stack32_t *uss = (const stack32_t *) regs.regs[4];
+	stack32_t *uoss = (stack32_t *) regs.regs[5];
+	unsigned long usp = regs.regs[29];
+	stack_t kss, koss;
+	int ret, err = 0;
+	mm_segment_t old_fs = get_fs();
+	s32 sp;
+
+	if (uss) {
+		if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
+			return -EFAULT;
+		err |= __get_user(sp, &uss->ss_sp);
+		kss.ss_sp = (void *) (long) sp;
+		err |= __get_user(kss.ss_size, &uss->ss_size);
+		err |= __get_user(kss.ss_flags, &uss->ss_flags);
+		if (err)
+			return -EFAULT;
+	}
+
+	set_fs (KERNEL_DS);
+	ret = do_sigaltstack(uss ? &kss : NULL , uoss ? &koss : NULL, usp);
+	set_fs (old_fs);
+
+	if (!ret && uoss) {
+		if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
+			return -EFAULT;
+		sp = (int) (long) koss.ss_sp;
+		err |= __put_user(sp, &uoss->ss_sp);
+		err |= __put_user(koss.ss_size, &uoss->ss_size);
+		err |= __put_user(koss.ss_flags, &uoss->ss_flags);
+		if (err)
+			return -EFAULT;
+	}
+	return ret;
+}
+
+static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc)
+{
+	int err = 0;
+	__u32 used_math;
+
+	/* Always make any pending restarted system calls return -EINTR */
+	current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
+	err |= __get_user(regs->hi, &sc->sc_mdhi);
+	err |= __get_user(regs->lo, &sc->sc_mdlo);
+
+#define restore_gp_reg(i) do {						\
+	err |= __get_user(regs->regs[i], &sc->sc_regs[i]);		\
+} while(0)
+	restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
+	restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
+	restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
+	restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
+	restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
+	restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
+	restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
+	restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
+	restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
+	restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
+	restore_gp_reg(31);
+#undef restore_gp_reg
+
+	err |= __get_user(used_math, &sc->sc_used_math);
+	conditional_used_math(used_math);
+
+	preempt_disable();
+
+	if (used_math()) {
+		/* restore fpu context if we have used it before */
+		own_fpu();
+		err |= restore_fp_context32(sc);
+	} else {
+		/* signal handler may have used FPU.  Give it up. */
+		lose_fpu();
+	}
+
+	preempt_enable();
+
+	return err;
+}
+
+struct sigframe {
+	u32 sf_ass[4];			/* argument save space for o32 */
+	u32 sf_code[2];			/* signal trampoline */
+	struct sigcontext32 sf_sc;
+	sigset_t sf_mask;
+};
+
+struct rt_sigframe32 {
+	u32 rs_ass[4];			/* argument save space for o32 */
+	u32 rs_code[2];			/* signal trampoline */
+	compat_siginfo_t rs_info;
+	struct ucontext32 rs_uc;
+};
+
+int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from)
+{
+	int err;
+
+	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
+		return -EFAULT;
+
+	/* If you change siginfo_t structure, please be sure
+	   this code is fixed accordingly.
+	   It should never copy any pad contained in the structure
+	   to avoid security leaks, but must copy the generic
+	   3 ints plus the relevant union member.
+	   This routine must convert siginfo from 64bit to 32bit as well
+	   at the same time.  */
+	err = __put_user(from->si_signo, &to->si_signo);
+	err |= __put_user(from->si_errno, &to->si_errno);
+	err |= __put_user((short)from->si_code, &to->si_code);
+	if (from->si_code < 0)
+		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+	else {
+		switch (from->si_code >> 16) {
+		case __SI_CHLD >> 16:
+			err |= __put_user(from->si_utime, &to->si_utime);
+			err |= __put_user(from->si_stime, &to->si_stime);
+			err |= __put_user(from->si_status, &to->si_status);
+		default:
+			err |= __put_user(from->si_pid, &to->si_pid);
+			err |= __put_user(from->si_uid, &to->si_uid);
+			break;
+		case __SI_FAULT >> 16:
+			err |= __put_user((long)from->si_addr, &to->si_addr);
+			break;
+		case __SI_POLL >> 16:
+			err |= __put_user(from->si_band, &to->si_band);
+			err |= __put_user(from->si_fd, &to->si_fd);
+			break;
+		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
+		case __SI_MESGQ >> 16:
+			err |= __put_user(from->si_pid, &to->si_pid);
+			err |= __put_user(from->si_uid, &to->si_uid);
+			err |= __put_user(from->si_int, &to->si_int);
+			break;
+		}
+	}
+	return err;
+}
+
+save_static_function(sys32_sigreturn);
+__attribute_used__ noinline static void
+_sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
+{
+	struct sigframe *frame;
+	sigset_t blocked;
+
+	frame = (struct sigframe *) regs.regs[29];
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
+		goto badframe;
+
+	sigdelsetmask(&blocked, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = blocked;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (restore_sigcontext32(&regs, &frame->sf_sc))
+		goto badframe;
+
+	/*
+	 * Don't let your children do this ...
+	 */
+	if (current_thread_info()->flags & TIF_SYSCALL_TRACE)
+		do_syscall_trace(&regs, 1);
+	__asm__ __volatile__(
+		"move\t$29, %0\n\t"
+		"j\tsyscall_exit"
+		:/* no outputs */
+		:"r" (&regs));
+	/* Unreached */
+
+badframe:
+	force_sig(SIGSEGV, current);
+}
+
+save_static_function(sys32_rt_sigreturn);
+__attribute_used__ noinline static void
+_sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
+{
+	struct rt_sigframe32 *frame;
+	sigset_t set;
+	stack_t st;
+	s32 sp;
+
+	frame = (struct rt_sigframe32 *) regs.regs[29];
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext))
+		goto badframe;
+
+	/* The ucontext contains a stack32_t, so we must convert!  */
+	if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
+		goto badframe;
+	st.ss_size = (long) sp;
+	if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
+		goto badframe;
+	if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
+		goto badframe;
+
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, regs.regs[29]);
+
+	/*
+	 * Don't let your children do this ...
+	 */
+	__asm__ __volatile__(
+		"move\t$29, %0\n\t"
+		"j\tsyscall_exit"
+		:/* no outputs */
+		:"r" (&regs));
+	/* Unreached */
+
+badframe:
+	force_sig(SIGSEGV, current);
+}
+
+static inline int setup_sigcontext32(struct pt_regs *regs,
+				     struct sigcontext32 *sc)
+{
+	int err = 0;
+
+	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
+	err |= __put_user(regs->cp0_status, &sc->sc_status);
+
+#define save_gp_reg(i) {						\
+	err |= __put_user(regs->regs[i], &sc->sc_regs[i]);		\
+} while(0)
+	__put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
+	save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
+	save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
+	save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
+	save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
+	save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
+	save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
+	save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
+	save_gp_reg(31);
+#undef save_gp_reg
+
+	err |= __put_user(regs->hi, &sc->sc_mdhi);
+	err |= __put_user(regs->lo, &sc->sc_mdlo);
+	err |= __put_user(regs->cp0_cause, &sc->sc_cause);
+	err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
+
+	err |= __put_user(!!used_math(), &sc->sc_used_math);
+
+	if (!used_math())
+		goto out;
+
+	/* 
+	 * Save FPU state to signal context.  Signal handler will "inherit"
+	 * current FPU state.
+	 */
+	preempt_disable();
+
+	if (!is_fpu_owner()) {
+		own_fpu();
+		restore_fp(current);
+	}
+	err |= save_fp_context32(sc);
+
+	preempt_enable();
+
+out:
+	return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+				 size_t frame_size)
+{
+	unsigned long sp;
+
+	/* Default to using normal stack */
+	sp = regs->regs[29];
+
+	/*
+ 	 * FPU emulator may have it's own trampoline active just
+ 	 * above the user stack, 16-bytes before the next lowest
+ 	 * 16 byte boundary.  Try to avoid trashing it.
+ 	 */
+ 	sp -= 32;
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
+		sp = current->sas_ss_sp + current->sas_ss_size;
+
+	return (void *)((sp - frame_size) & ALMASK);
+}
+
+static inline void setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
+			       int signr, sigset_t *set)
+{
+	struct sigframe *frame;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+		goto give_sigsegv;
+
+	/*
+	 * Set up the return code ...
+	 *
+	 *         li      v0, __NR_O32_sigreturn
+	 *         syscall
+	 */
+	err |= __put_user(0x24020000 + __NR_O32_sigreturn, frame->sf_code + 0);
+	err |= __put_user(0x0000000c                     , frame->sf_code + 1);
+	flush_cache_sigtramp((unsigned long) frame->sf_code);
+
+	err |= setup_sigcontext32(regs, &frame->sf_sc);
+	err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
+
+	/*
+	 * Arguments to signal handler:
+	 *
+	 *   a0 = signal number
+	 *   a1 = 0 (should be cause)
+	 *   a2 = pointer to struct sigcontext
+	 *
+	 * $25 and c0_epc point to the signal handler, $29 points to the
+	 * struct sigframe.
+	 */
+	regs->regs[ 4] = signr;
+	regs->regs[ 5] = 0;
+	regs->regs[ 6] = (unsigned long) &frame->sf_sc;
+	regs->regs[29] = (unsigned long) frame;
+	regs->regs[31] = (unsigned long) frame->sf_code;
+	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+	       current->comm, current->pid,
+	       frame, regs->cp0_epc, frame->sf_code);
+#endif
+        return;
+
+give_sigsegv:
+	force_sigsegv(signr, current);
+}
+
+static inline void setup_rt_frame(struct k_sigaction * ka,
+				  struct pt_regs *regs, int signr,
+				  sigset_t *set, siginfo_t *info)
+{
+	struct rt_sigframe32 *frame;
+	int err = 0;
+	s32 sp;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+		goto give_sigsegv;
+
+	/* Set up to return from userspace.  If provided, use a stub already
+	   in userspace.  */
+	/*
+	 * Set up the return code ...
+	 *
+	 *         li      v0, __NR_O32_rt_sigreturn
+	 *         syscall
+	 */
+	err |= __put_user(0x24020000 + __NR_O32_rt_sigreturn, frame->rs_code + 0);
+	err |= __put_user(0x0000000c                      , frame->rs_code + 1);
+	flush_cache_sigtramp((unsigned long) frame->rs_code);
+
+	/* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
+	err |= copy_siginfo_to_user32(&frame->rs_info, info);
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->rs_uc.uc_flags);
+	err |= __put_user(0, &frame->rs_uc.uc_link);
+	sp = (int) (long) current->sas_ss_sp;
+	err |= __put_user(sp,
+	                  &frame->rs_uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->regs[29]),
+	                  &frame->rs_uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size,
+	                  &frame->rs_uc.uc_stack.ss_size);
+	err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
+	err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
+
+	if (err)
+		goto give_sigsegv;
+
+	/*
+	 * Arguments to signal handler:
+	 *
+	 *   a0 = signal number
+	 *   a1 = 0 (should be cause)
+	 *   a2 = pointer to ucontext
+	 *
+	 * $25 and c0_epc point to the signal handler, $29 points to
+	 * the struct rt_sigframe32.
+	 */
+	regs->regs[ 4] = signr;
+	regs->regs[ 5] = (unsigned long) &frame->rs_info;
+	regs->regs[ 6] = (unsigned long) &frame->rs_uc;
+	regs->regs[29] = (unsigned long) frame;
+	regs->regs[31] = (unsigned long) frame->rs_code;
+	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+	       current->comm, current->pid,
+	       frame, regs->cp0_epc, frame->rs_code);
+#endif
+	return;
+
+give_sigsegv:
+	force_sigsegv(signr, current);
+}
+
+static inline void handle_signal(unsigned long sig, siginfo_t *info,
+	struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs)
+{
+	switch (regs->regs[0]) {
+	case ERESTART_RESTARTBLOCK:
+	case ERESTARTNOHAND:
+		regs->regs[2] = EINTR;
+		break;
+	case ERESTARTSYS:
+		if(!(ka->sa.sa_flags & SA_RESTART)) {
+			regs->regs[2] = EINTR;
+			break;
+		}
+	/* fallthrough */
+	case ERESTARTNOINTR:		/* Userland will reload $v0.  */
+		regs->regs[7] = regs->regs[26];
+		regs->cp0_epc -= 8;
+	}
+
+	regs->regs[0] = 0;		/* Don't deal with this again.  */
+
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(ka, regs, sig, oldset, info);
+	else
+		setup_frame(ka, regs, sig, oldset);
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+}
+
+int do_signal32(sigset_t *oldset, struct pt_regs *regs)
+{
+	struct k_sigaction ka;
+	siginfo_t info;
+	int signr;
+
+	/*
+	 * We want the common case to go fast, which is why we may in certain
+	 * cases get here from kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if (!user_mode(regs))
+		return 1;
+
+	if (try_to_freeze(0))
+		goto no_signal;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	if (signr > 0) {
+		handle_signal(signr, &info, &ka, oldset, regs);
+		return 1;
+	}
+
+no_signal:
+	/*
+	 * Who's code doesn't conform to the restartable syscall convention
+	 * dies here!!!  The li instruction, a single machine instruction,
+	 * must directly be followed by the syscall instruction.
+	 */
+	if (regs->regs[0]) {
+		if (regs->regs[2] == ERESTARTNOHAND ||
+		    regs->regs[2] == ERESTARTSYS ||
+		    regs->regs[2] == ERESTARTNOINTR) {
+			regs->regs[7] = regs->regs[26];
+			regs->cp0_epc -= 8;
+		}
+		if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
+			regs->regs[2] = __NR_O32_restart_syscall;
+			regs->regs[7] = regs->regs[26];
+			regs->cp0_epc -= 4;
+		}
+	}
+	return 0;
+}
+
+asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act,
+				  struct sigaction32 *oact,
+				  unsigned int sigsetsize)
+{
+	struct k_sigaction new_sa, old_sa;
+	int ret = -EINVAL;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		goto out;
+
+	if (act) {
+		int err = 0;
+
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
+			return -EFAULT;
+		err |= __get_user((u32)(u64)new_sa.sa.sa_handler,
+		                  &act->sa_handler);
+		err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
+		err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
+		if (err)
+			return -EFAULT;
+	}
+
+	ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
+
+	if (!ret && oact) {
+		int err = 0;
+
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
+			return -EFAULT;
+
+		err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
+		                   &oact->sa_handler);
+		err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
+		err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
+		if (err)
+			return -EFAULT;
+	}
+out:
+	return ret;
+}
+
+asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set,
+	compat_sigset_t *oset, unsigned int sigsetsize)
+{
+	sigset_t old_set, new_set;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	if (set && get_sigset(&new_set, set))
+		return -EFAULT;
+
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigprocmask(how, set ? &new_set : NULL,
+				 oset ? &old_set : NULL, sigsetsize);
+	set_fs (old_fs);
+
+	if (!ret && oset && put_sigset(&old_set, oset))
+		return -EFAULT;
+
+	return ret;
+}
+
+asmlinkage int sys32_rt_sigpending(compat_sigset_t *uset,
+	unsigned int sigsetsize)
+{
+	int ret;
+	sigset_t set;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigpending(&set, sigsetsize);
+	set_fs (old_fs);
+
+	if (!ret && put_sigset(&set, uset))
+		return -EFAULT;
+
+	return ret;
+}
+
+asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t *uinfo)
+{
+	siginfo_t info;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
+	    copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigqueueinfo(pid, sig, &info);
+	set_fs (old_fs);
+	return ret;
+}
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
new file mode 100644
index 0000000..3544208
--- /dev/null
+++ b/arch/mips/kernel/signal_n32.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2003 Broadcom Corporation
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/compat.h>
+#include <linux/bitops.h>
+
+#include <asm/asm.h>
+#include <asm/cacheflush.h>
+#include <asm/sim.h>
+#include <asm/uaccess.h>
+#include <asm/ucontext.h>
+#include <asm/system.h>
+#include <asm/fpu.h>
+#include <asm/cpu-features.h>
+
+#include "signal-common.h"
+
+/*
+ * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
+ */
+#define __NR_N32_rt_sigreturn		6211
+#define __NR_N32_restart_syscall	6214
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/* IRIX compatible stack_t  */
+typedef struct sigaltstack32 {
+	s32 ss_sp;
+	compat_size_t ss_size;
+	int ss_flags;
+} stack32_t;
+
+struct ucontextn32 {
+	u32                 uc_flags;
+	s32                 uc_link;
+	stack32_t           uc_stack;
+	struct sigcontext   uc_mcontext;
+	sigset_t            uc_sigmask;   /* mask last for extensibility */
+};
+
+#if PLAT_TRAMPOLINE_STUFF_LINE
+#define __tramp __attribute__((aligned(PLAT_TRAMPOLINE_STUFF_LINE)))
+#else
+#define __tramp
+#endif
+
+struct rt_sigframe_n32 {
+	u32 rs_ass[4];			/* argument save space for o32 */
+	u32 rs_code[2] __tramp;		/* signal trampoline */
+	struct siginfo rs_info __tramp;
+	struct ucontextn32 rs_uc;
+};
+
+save_static_function(sysn32_rt_sigreturn);
+__attribute_used__ noinline static void
+_sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
+{
+	struct rt_sigframe_n32 *frame;
+	sigset_t set;
+	stack_t st;
+	s32 sp;
+
+	frame = (struct rt_sigframe_n32 *) regs.regs[29];
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext))
+		goto badframe;
+
+	/* The ucontext contains a stack32_t, so we must convert!  */
+	if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
+		goto badframe;
+	st.ss_size = (long) sp;
+	if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
+		goto badframe;
+	if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
+		goto badframe;
+
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, regs.regs[29]);
+
+	/*
+	 * Don't let your children do this ...
+	 */
+	__asm__ __volatile__(
+		"move\t$29, %0\n\t"
+		"j\tsyscall_exit"
+		:/* no outputs */
+		:"r" (&regs));
+	/* Unreached */
+
+badframe:
+	force_sig(SIGSEGV, current);
+}
+
+void setup_rt_frame_n32(struct k_sigaction * ka,
+	struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info)
+{
+	struct rt_sigframe_n32 *frame;
+	int err = 0;
+	s32 sp;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+		goto give_sigsegv;
+
+	/*
+	 * Set up the return code ...
+	 *
+	 *         li      v0, __NR_rt_sigreturn
+	 *         syscall
+	 */
+	if (PLAT_TRAMPOLINE_STUFF_LINE)
+		__clear_user(frame->rs_code, PLAT_TRAMPOLINE_STUFF_LINE);
+	err |= __put_user(0x24020000 + __NR_N32_rt_sigreturn, frame->rs_code + 0);
+	err |= __put_user(0x0000000c                        , frame->rs_code + 1);
+	flush_cache_sigtramp((unsigned long) frame->rs_code);
+
+	/* Create siginfo.  */
+	err |= copy_siginfo_to_user(&frame->rs_info, info);
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->rs_uc.uc_flags);
+	err |= __put_user(0, &frame->rs_uc.uc_link);
+        sp = (int) (long) current->sas_ss_sp;
+	err |= __put_user(sp,
+	                  &frame->rs_uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->regs[29]),
+	                  &frame->rs_uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size,
+	                  &frame->rs_uc.uc_stack.ss_size);
+	err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
+	err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
+
+	if (err)
+		goto give_sigsegv;
+
+	/*
+	 * Arguments to signal handler:
+	 *
+	 *   a0 = signal number
+	 *   a1 = 0 (should be cause)
+	 *   a2 = pointer to ucontext
+	 *
+	 * $25 and c0_epc point to the signal handler, $29 points to
+	 * the struct rt_sigframe.
+	 */
+	regs->regs[ 4] = signr;
+	regs->regs[ 5] = (unsigned long) &frame->rs_info;
+	regs->regs[ 6] = (unsigned long) &frame->rs_uc;
+	regs->regs[29] = (unsigned long) frame;
+	regs->regs[31] = (unsigned long) frame->rs_code;
+	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+	       current->comm, current->pid,
+	       frame, regs->cp0_epc, regs->regs[31]);
+#endif
+	return;
+
+give_sigsegv:
+	force_sigsegv(signr, current);
+}
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
new file mode 100644
index 0000000..af5cd3b
--- /dev/null
+++ b/arch/mips/kernel/smp.c
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Copyright (C) 2000, 2001 Kanoj Sarcar
+ * Copyright (C) 2000, 2001 Ralf Baechle
+ * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
+ * Copyright (C) 2000, 2001, 2003 Broadcom Corporation
+ */
+#include <linux/cache.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+
+#include <asm/atomic.h>
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+
+cpumask_t phys_cpu_present_map;		/* Bitmask of available CPUs */
+volatile cpumask_t cpu_callin_map;	/* Bitmask of started secondaries */
+cpumask_t cpu_online_map;		/* Bitmask of currently online CPUs */
+int __cpu_number_map[NR_CPUS];		/* Map physical to logical */
+int __cpu_logical_map[NR_CPUS];		/* Map logical to physical */
+
+EXPORT_SYMBOL(phys_cpu_present_map);
+EXPORT_SYMBOL(cpu_online_map);
+
+static void smp_tune_scheduling (void)
+{
+	struct cache_desc *cd = &current_cpu_data.scache;
+	unsigned long cachesize;       /* kB   */
+	unsigned long bandwidth = 350; /* MB/s */
+	unsigned long cpu_khz;
+
+	/*
+	 * Crude estimate until we actually meassure ...
+	 */
+	cpu_khz = loops_per_jiffy * 2 * HZ / 1000;
+
+	/*
+	 * Rough estimation for SMP scheduling, this is the number of
+	 * cycles it takes for a fully memory-limited process to flush
+	 * the SMP-local cache.
+	 *
+	 * (For a P5 this pretty much means we will choose another idle
+	 *  CPU almost always at wakeup time (this is due to the small
+	 *  L1 cache), on PIIs it's around 50-100 usecs, depending on
+	 *  the cache size)
+	 */
+	if (!cpu_khz)
+		return;
+
+	cachesize = cd->linesz * cd->sets * cd->ways;
+}
+
+extern void __init calibrate_delay(void);
+extern ATTRIB_NORET void cpu_idle(void);
+
+/*
+ * First C code run on the secondary CPUs after being started up by
+ * the master.
+ */
+asmlinkage void start_secondary(void)
+{
+	unsigned int cpu = smp_processor_id();
+
+	cpu_probe();
+	cpu_report();
+	per_cpu_trap_init();
+	prom_init_secondary();
+
+	/*
+	 * XXX parity protection should be folded in here when it's converted
+	 * to an option instead of something based on .cputype
+	 */
+
+	calibrate_delay();
+	cpu_data[cpu].udelay_val = loops_per_jiffy;
+
+	prom_smp_finish();
+
+	cpu_set(cpu, cpu_callin_map);
+
+	cpu_idle();
+}
+
+DEFINE_SPINLOCK(smp_call_lock);
+
+struct call_data_struct *call_data;
+
+/*
+ * Run a function on all other CPUs.
+ *  <func>      The function to run. This must be fast and non-blocking.
+ *  <info>      An arbitrary pointer to pass to the function.
+ *  <retry>     If true, keep retrying until ready.
+ *  <wait>      If true, wait until function has completed on other CPUs.
+ *  [RETURNS]   0 on success, else a negative status code.
+ *
+ * Does not return until remote CPUs are nearly ready to execute <func>
+ * or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.
+ */
+int smp_call_function (void (*func) (void *info), void *info, int retry,
+								int wait)
+{
+	struct call_data_struct data;
+	int i, cpus = num_online_cpus() - 1;
+	int cpu = smp_processor_id();
+
+	if (!cpus)
+		return 0;
+
+	/* Can deadlock when called with interrupts disabled */
+	WARN_ON(irqs_disabled());
+
+	data.func = func;
+	data.info = info;
+	atomic_set(&data.started, 0);
+	data.wait = wait;
+	if (wait)
+		atomic_set(&data.finished, 0);
+
+	spin_lock(&smp_call_lock);
+	call_data = &data;
+	mb();
+
+	/* Send a message to all other CPUs and wait for them to respond */
+	for (i = 0; i < NR_CPUS; i++)
+		if (cpu_online(i) && i != cpu)
+			core_send_ipi(i, SMP_CALL_FUNCTION);
+
+	/* Wait for response */
+	/* FIXME: lock-up detection, backtrace on lock-up */
+	while (atomic_read(&data.started) != cpus)
+		barrier();
+
+	if (wait)
+		while (atomic_read(&data.finished) != cpus)
+			barrier();
+	spin_unlock(&smp_call_lock);
+
+	return 0;
+}
+
+void smp_call_function_interrupt(void)
+{
+	void (*func) (void *info) = call_data->func;
+	void *info = call_data->info;
+	int wait = call_data->wait;
+
+	/*
+	 * Notify initiating CPU that I've grabbed the data and am
+	 * about to execute the function.
+	 */
+	mb();
+	atomic_inc(&call_data->started);
+
+	/*
+	 * At this point the info structure may be out of scope unless wait==1.
+	 */
+	irq_enter();
+	(*func)(info);
+	irq_exit();
+
+	if (wait) {
+		mb();
+		atomic_inc(&call_data->finished);
+	}
+}
+
+static void stop_this_cpu(void *dummy)
+{
+	/*
+	 * Remove this CPU:
+	 */
+	cpu_clear(smp_processor_id(), cpu_online_map);
+	local_irq_enable();	/* May need to service _machine_restart IPI */
+	for (;;);		/* Wait if available. */
+}
+
+void smp_send_stop(void)
+{
+	smp_call_function(stop_this_cpu, NULL, 1, 0);
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+	prom_cpus_done();
+}
+
+/* called from main before smp_init() */
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+	cpu_data[0].udelay_val = loops_per_jiffy;
+	init_new_context(current, &init_mm);
+	current_thread_info()->cpu = 0;
+	smp_tune_scheduling();
+	prom_prepare_cpus(max_cpus);
+}
+
+/* preload SMP state for boot cpu */
+void __devinit smp_prepare_boot_cpu(void)
+{
+	/*
+	 * This assumes that bootup is always handled by the processor
+	 * with the logic and physical number 0.
+	 */
+	__cpu_number_map[0] = 0;
+	__cpu_logical_map[0] = 0;
+	cpu_set(0, phys_cpu_present_map);
+	cpu_set(0, cpu_online_map);
+	cpu_set(0, cpu_callin_map);
+}
+
+/*
+ * Startup the CPU with this logical number
+ */
+static int __init do_boot_cpu(int cpu)
+{
+	struct task_struct *idle;
+
+	/*
+	 * The following code is purely to make sure
+	 * Linux can schedule processes on this slave.
+	 */
+	idle = fork_idle(cpu);
+	if (IS_ERR(idle))
+		panic("failed fork for CPU %d\n", cpu);
+
+	prom_boot_secondary(cpu, idle);
+
+	/* XXXKW timeout */
+	while (!cpu_isset(cpu, cpu_callin_map))
+		udelay(100);
+
+	cpu_set(cpu, cpu_online_map);
+
+	return 0;
+}
+
+/*
+ * Called once for each "cpu_possible(cpu)".  Needs to spin up the cpu
+ * and keep control until "cpu_online(cpu)" is set.  Note: cpu is
+ * physical, not logical.
+ */
+int __devinit __cpu_up(unsigned int cpu)
+{
+	int ret;
+
+	/* Processor goes to start_secondary(), sets online flag */
+	ret = do_boot_cpu(cpu);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/* Not really SMP stuff ... */
+int setup_profiling_timer(unsigned int multiplier)
+{
+	return 0;
+}
+
+static void flush_tlb_all_ipi(void *info)
+{
+	local_flush_tlb_all();
+}
+
+void flush_tlb_all(void)
+{
+	on_each_cpu(flush_tlb_all_ipi, 0, 1, 1);
+}
+
+static void flush_tlb_mm_ipi(void *mm)
+{
+	local_flush_tlb_mm((struct mm_struct *)mm);
+}
+
+/*
+ * The following tlb flush calls are invoked when old translations are
+ * being torn down, or pte attributes are changing. For single threaded
+ * address spaces, a new context is obtained on the current cpu, and tlb
+ * context on other cpus are invalidated to force a new context allocation
+ * at switch_mm time, should the mm ever be used on other cpus. For
+ * multithreaded address spaces, intercpu interrupts have to be sent.
+ * Another case where intercpu interrupts are required is when the target
+ * mm might be active on another cpu (eg debuggers doing the flushes on
+ * behalf of debugees, kswapd stealing pages from another process etc).
+ * Kanoj 07/00.
+ */
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+	preempt_disable();
+
+	if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
+		smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1);
+	} else {
+		int i;
+		for (i = 0; i < num_online_cpus(); i++)
+			if (smp_processor_id() != i)
+				cpu_context(i, mm) = 0;
+	}
+	local_flush_tlb_mm(mm);
+
+	preempt_enable();
+}
+
+struct flush_tlb_data {
+	struct vm_area_struct *vma;
+	unsigned long addr1;
+	unsigned long addr2;
+};
+
+static void flush_tlb_range_ipi(void *info)
+{
+	struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+
+	local_flush_tlb_range(fd->vma, fd->addr1, fd->addr2);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+	struct mm_struct *mm = vma->vm_mm;
+
+	preempt_disable();
+	if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
+		struct flush_tlb_data fd;
+
+		fd.vma = vma;
+		fd.addr1 = start;
+		fd.addr2 = end;
+		smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
+	} else {
+		int i;
+		for (i = 0; i < num_online_cpus(); i++)
+			if (smp_processor_id() != i)
+				cpu_context(i, mm) = 0;
+	}
+	local_flush_tlb_range(vma, start, end);
+	preempt_enable();
+}
+
+static void flush_tlb_kernel_range_ipi(void *info)
+{
+	struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+
+	local_flush_tlb_kernel_range(fd->addr1, fd->addr2);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+	struct flush_tlb_data fd;
+
+	fd.addr1 = start;
+	fd.addr2 = end;
+	on_each_cpu(flush_tlb_kernel_range_ipi, (void *)&fd, 1, 1);
+}
+
+static void flush_tlb_page_ipi(void *info)
+{
+	struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
+
+	local_flush_tlb_page(fd->vma, fd->addr1);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+	preempt_disable();
+	if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) {
+		struct flush_tlb_data fd;
+
+		fd.vma = vma;
+		fd.addr1 = page;
+		smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1);
+	} else {
+		int i;
+		for (i = 0; i < num_online_cpus(); i++)
+			if (smp_processor_id() != i)
+				cpu_context(i, vma->vm_mm) = 0;
+	}
+	local_flush_tlb_page(vma, page);
+	preempt_enable();
+}
+
+static void flush_tlb_one_ipi(void *info)
+{
+	unsigned long vaddr = (unsigned long) info;
+
+	local_flush_tlb_one(vaddr);
+}
+
+void flush_tlb_one(unsigned long vaddr)
+{
+	smp_call_function(flush_tlb_one_ipi, (void *) vaddr, 1, 1);
+	local_flush_tlb_one(vaddr);
+}
+
+EXPORT_SYMBOL(flush_tlb_page);
+EXPORT_SYMBOL(flush_tlb_one);
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL(synchronize_irq);
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
new file mode 100644
index 0000000..598bfe7
--- /dev/null
+++ b/arch/mips/kernel/syscall.c
@@ -0,0 +1,407 @@
+/*
+ * 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) 1995, 1996, 1997, 2000, 2001, 05 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ */
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/mman.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/utsname.h>
+#include <linux/unistd.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/compiler.h>
+
+#include <asm/branch.h>
+#include <asm/cachectl.h>
+#include <asm/cacheflush.h>
+#include <asm/ipc.h>
+#include <asm/offset.h>
+#include <asm/signal.h>
+#include <asm/sim.h>
+#include <asm/shmparam.h>
+#include <asm/sysmips.h>
+#include <asm/uaccess.h>
+
+asmlinkage int sys_pipe(nabi_no_regargs volatile struct pt_regs regs)
+{
+	int fd[2];
+	int error, res;
+
+	error = do_pipe(fd);
+	if (error) {
+		res = error;
+		goto out;
+	}
+	regs.regs[3] = fd[1];
+	res = fd[0];
+out:
+	return res;
+}
+
+unsigned long shm_align_mask = PAGE_SIZE - 1;	/* Sane caches */
+
+#define COLOUR_ALIGN(addr,pgoff)				\
+	((((addr) + shm_align_mask) & ~shm_align_mask) +	\
+	 (((pgoff) << PAGE_SHIFT) & shm_align_mask))
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+	unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	struct vm_area_struct * vmm;
+	int do_color_align;
+	unsigned long task_size;
+
+	task_size = STACK_TOP;
+
+	if (flags & MAP_FIXED) {
+		/*
+		 * We do not accept a shared mapping if it would violate
+		 * cache aliasing constraints.
+		 */
+		if ((flags & MAP_SHARED) && (addr & shm_align_mask))
+			return -EINVAL;
+		return addr;
+	}
+
+	if (len > task_size)
+		return -ENOMEM;
+	do_color_align = 0;
+	if (filp || (flags & MAP_SHARED))
+		do_color_align = 1;
+	if (addr) {
+		if (do_color_align)
+			addr = COLOUR_ALIGN(addr, pgoff);
+		else
+			addr = PAGE_ALIGN(addr);
+		vmm = find_vma(current->mm, addr);
+		if (task_size - len >= addr &&
+		    (!vmm || addr + len <= vmm->vm_start))
+			return addr;
+	}
+	addr = TASK_UNMAPPED_BASE;
+	if (do_color_align)
+		addr = COLOUR_ALIGN(addr, pgoff);
+	else
+		addr = PAGE_ALIGN(addr);
+
+	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
+		/* At this point:  (!vmm || addr < vmm->vm_end). */
+		if (task_size - len < addr)
+			return -ENOMEM;
+		if (!vmm || addr + len <= vmm->vm_start)
+			return addr;
+		addr = vmm->vm_end;
+		if (do_color_align)
+			addr = COLOUR_ALIGN(addr, pgoff);
+	}
+}
+
+/* common code for old and new mmaps */
+static inline unsigned long
+do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+        unsigned long flags, unsigned long fd, unsigned long pgoff)
+{
+	unsigned long error = -EBADF;
+	struct file * file = NULL;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			goto out;
+	}
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
+	if (file)
+		fput(file);
+out:
+	return error;
+}
+
+asmlinkage unsigned long
+old_mmap(unsigned long addr, unsigned long len, int prot,
+	int flags, int fd, off_t offset)
+{
+	unsigned long result;
+
+	result = -EINVAL;
+	if (offset & ~PAGE_MASK)
+		goto out;
+
+	result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+
+out:
+	return result;
+}
+
+asmlinkage unsigned long
+sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+          unsigned long flags, unsigned long fd, unsigned long pgoff)
+{
+	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+save_static_function(sys_fork);
+__attribute_used__ noinline static int
+_sys_fork(nabi_no_regargs struct pt_regs regs)
+{
+	return do_fork(SIGCHLD, regs.regs[29], &regs, 0, NULL, NULL);
+}
+
+save_static_function(sys_clone);
+__attribute_used__ noinline static int
+_sys_clone(nabi_no_regargs struct pt_regs regs)
+{
+	unsigned long clone_flags;
+	unsigned long newsp;
+	int *parent_tidptr, *child_tidptr;
+
+	clone_flags = regs.regs[4];
+	newsp = regs.regs[5];
+	if (!newsp)
+		newsp = regs.regs[29];
+	parent_tidptr = (int *) regs.regs[6];
+	child_tidptr = (int *) regs.regs[7];
+	return do_fork(clone_flags, newsp, &regs, 0,
+	               parent_tidptr, child_tidptr);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
+{
+	int error;
+	char * filename;
+
+	filename = getname((char *) (long)regs.regs[4]);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = do_execve(filename, (char **) (long)regs.regs[5],
+	                  (char **) (long)regs.regs[6], &regs);
+	putname(filename);
+
+out:
+	return error;
+}
+
+/*
+ * Compacrapability ...
+ */
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+		return 0;
+	return -EFAULT;
+}
+
+/*
+ * Compacrapability ...
+ */
+asmlinkage int sys_olduname(struct oldold_utsname * name)
+{
+	int error;
+
+	if (!name)
+		return -EFAULT;
+	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+		return -EFAULT;
+
+	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+	error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+	error -= __put_user(0,name->release+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+	error -= __put_user(0,name->version+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+	error = __put_user(0,name->machine+__OLD_UTS_LEN);
+	error = error ? -EFAULT : 0;
+
+	return error;
+}
+
+asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
+{
+	int	tmp, len;
+	char	*name;
+
+	switch(cmd) {
+	case SETNAME: {
+		char nodename[__NEW_UTS_LEN + 1];
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		name = (char *) arg1;
+
+		len = strncpy_from_user(nodename, name, __NEW_UTS_LEN);
+		if (len < 0)
+			return -EFAULT;
+
+		down_write(&uts_sem);
+		strncpy(system_utsname.nodename, nodename, len);
+		nodename[__NEW_UTS_LEN] = '\0';
+		strlcpy(system_utsname.nodename, nodename,
+		        sizeof(system_utsname.nodename));
+		up_write(&uts_sem);
+		return 0;
+	}
+
+	case MIPS_ATOMIC_SET:
+		printk(KERN_CRIT "How did I get here?\n");
+		return -EINVAL;
+
+	case MIPS_FIXADE:
+		tmp = current->thread.mflags & ~3;
+		current->thread.mflags = tmp | (arg1 & 3);
+		return 0;
+
+	case FLUSH_CACHE:
+		__flush_cache_all();
+		return 0;
+
+	case MIPS_RDNVRAM:
+		return -EIO;
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage int sys_ipc (uint call, int first, int second,
+			unsigned long third, void *ptr, long fifth)
+{
+	int version, ret;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	switch (call) {
+	case SEMOP:
+		return sys_semtimedop (first, (struct sembuf *)ptr, second,
+		                       NULL);
+	case SEMTIMEDOP:
+		return sys_semtimedop (first, (struct sembuf *)ptr, second,
+		                       (const struct timespec __user *)fifth);
+	case SEMGET:
+		return sys_semget (first, second, third);
+	case SEMCTL: {
+		union semun fourth;
+		if (!ptr)
+			return -EINVAL;
+		if (get_user(fourth.__pad, (void **) ptr))
+			return -EFAULT;
+		return sys_semctl (first, second, third, fourth);
+	}
+
+	case MSGSND:
+		return sys_msgsnd (first, (struct msgbuf *) ptr,
+				   second, third);
+	case MSGRCV:
+		switch (version) {
+		case 0: {
+			struct ipc_kludge tmp;
+			if (!ptr)
+				return -EINVAL;
+
+			if (copy_from_user(&tmp,
+					   (struct ipc_kludge *) ptr,
+					   sizeof (tmp)))
+				return -EFAULT;
+			return sys_msgrcv (first, tmp.msgp, second,
+					   tmp.msgtyp, third);
+		}
+		default:
+			return sys_msgrcv (first,
+					   (struct msgbuf *) ptr,
+					   second, fifth, third);
+		}
+	case MSGGET:
+		return sys_msgget ((key_t) first, second);
+	case MSGCTL:
+		return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+
+	case SHMAT:
+		switch (version) {
+		default: {
+			ulong raddr;
+			ret = do_shmat (first, (char *) ptr, second, &raddr);
+			if (ret)
+				return ret;
+			return put_user (raddr, (ulong *) third);
+		}
+		case 1:	/* iBCS2 emulator entry point */
+			if (!segment_eq(get_fs(), get_ds()))
+				return -EINVAL;
+			return do_shmat (first, (char *) ptr, second, (ulong *) third);
+		}
+	case SHMDT:
+		return sys_shmdt ((char *)ptr);
+	case SHMGET:
+		return sys_shmget (first, second, third);
+	case SHMCTL:
+		return sys_shmctl (first, second,
+				   (struct shmid_ds *) ptr);
+	default:
+		return -ENOSYS;
+	}
+}
+
+/*
+ * Native ABI that is O32 or N64 version
+ */
+asmlinkage long sys_shmat(int shmid, char __user *shmaddr,
+                          int shmflg, unsigned long *addr)
+{
+	unsigned long raddr;
+	int err;
+
+	err = do_shmat(shmid, shmaddr, shmflg, &raddr);
+	if (err)
+		return err;
+
+	return put_user(raddr, addr);
+}
+
+/*
+ * No implemented yet ...
+ */
+asmlinkage int sys_cachectl(char *addr, int nbytes, int op)
+{
+	return -ENOSYS;
+}
+
+/*
+ * If we ever come here the user sp is bad.  Zap the process right away.
+ * Due to the bad stack signaling wouldn't work.
+ */
+asmlinkage void bad_stack(void)
+{
+	do_exit(SIGSEGV);
+}
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
new file mode 100644
index 0000000..f3bf0e4
--- /dev/null
+++ b/arch/mips/kernel/sysirix.c
@@ -0,0 +1,2179 @@
+/*
+ * sysirix.c: IRIX system call emulation.
+ *
+ * Copyright (C) 1996 David S. Miller
+ * Copyright (C) 1997 Miguel de Icaza
+ * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/binfmts.h>
+#include <linux/highuid.h>
+#include <linux/pagemap.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/slab.h>
+#include <linux/swap.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/times.h>
+#include <linux/elf.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/utsname.h>
+#include <linux/file.h>
+#include <linux/vfs.h>
+#include <linux/namei.h>
+#include <linux/socket.h>
+#include <linux/security.h>
+#include <linux/syscalls.h>
+
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <asm/inventory.h>
+
+/* 2,191 lines of complete and utter shit coming up... */
+
+extern int max_threads;
+
+/* The sysmp commands supported thus far. */
+#define MP_NPROCS       	1 /* # processor in complex */
+#define MP_NAPROCS      	2 /* # active processors in complex */
+#define MP_PGSIZE           	14 /* Return system page size in v1. */
+
+asmlinkage int irix_sysmp(struct pt_regs *regs)
+{
+	unsigned long cmd;
+	int base = 0;
+	int error = 0;
+
+	if(regs->regs[2] == 1000)
+		base = 1;
+	cmd = regs->regs[base + 4];
+	switch(cmd) {
+	case MP_PGSIZE:
+		error = PAGE_SIZE;
+		break;
+	case MP_NPROCS:
+	case MP_NAPROCS:
+		error = num_online_cpus();
+		break;
+	default:
+		printk("SYSMP[%s:%d]: Unsupported opcode %d\n",
+		       current->comm, current->pid, (int)cmd);
+		error = -EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+/* The prctl commands. */
+#define PR_MAXPROCS          1 /* Tasks/user. */
+#define PR_ISBLOCKED         2 /* If blocked, return 1. */
+#define PR_SETSTACKSIZE      3 /* Set largest task stack size. */
+#define PR_GETSTACKSIZE      4 /* Get largest task stack size. */
+#define PR_MAXPPROCS         5 /* Num parallel tasks. */
+#define PR_UNBLKONEXEC       6 /* When task exec/exit's, unblock. */
+#define PR_SETEXITSIG        8 /* When task exit's, set signal. */
+#define PR_RESIDENT          9 /* Make task unswappable. */
+#define PR_ATTACHADDR       10 /* (Re-)Connect a vma to a task. */
+#define PR_DETACHADDR       11 /* Disconnect a vma from a task. */
+#define PR_TERMCHILD        12 /* When parent sleeps with fishes, kill child. */
+#define PR_GETSHMASK        13 /* Get the sproc() share mask. */
+#define PR_GETNSHARE        14 /* Number of share group members. */
+#define PR_COREPID          15 /* Add task pid to name when it core. */
+#define	PR_ATTACHADDRPERM   16 /* (Re-)Connect vma, with specified prot. */
+#define PR_PTHREADEXIT      17 /* Kill a pthread without prejudice. */
+
+asmlinkage int irix_prctl(struct pt_regs *regs)
+{
+	unsigned long cmd;
+	int error = 0, base = 0;
+
+	if (regs->regs[2] == 1000)
+		base = 1;
+	cmd = regs->regs[base + 4];
+	switch (cmd) {
+	case PR_MAXPROCS:
+		printk("irix_prctl[%s:%d]: Wants PR_MAXPROCS\n",
+		       current->comm, current->pid);
+		error = max_threads;
+		break;
+
+	case PR_ISBLOCKED: {
+		struct task_struct *task;
+
+		printk("irix_prctl[%s:%d]: Wants PR_ISBLOCKED\n",
+		       current->comm, current->pid);
+		read_lock(&tasklist_lock);
+		task = find_task_by_pid(regs->regs[base + 5]);
+		error = -ESRCH;
+		if (error)
+			error = (task->run_list.next != NULL);
+		read_unlock(&tasklist_lock);
+		/* Can _your_ OS find this out that fast? */
+		break;
+	}
+
+	case PR_SETSTACKSIZE: {
+		long value = regs->regs[base + 5];
+
+		printk("irix_prctl[%s:%d]: Wants PR_SETSTACKSIZE<%08lx>\n",
+		       current->comm, current->pid, (unsigned long) value);
+		if (value > RLIM_INFINITY)
+			value = RLIM_INFINITY;
+		if (capable(CAP_SYS_ADMIN)) {
+			task_lock(current->group_leader);
+			current->signal->rlim[RLIMIT_STACK].rlim_max =
+				current->signal->rlim[RLIMIT_STACK].rlim_cur = value;
+			task_unlock(current->group_leader);
+			error = value;
+			break;
+		}
+		task_lock(current->group_leader);
+		if (value > current->signal->rlim[RLIMIT_STACK].rlim_max) {
+			error = -EINVAL;
+			task_unlock(current->group_leader);
+			break;
+		}
+		current->signal->rlim[RLIMIT_STACK].rlim_cur = value;
+		task_unlock(current->group_leader);
+		error = value;
+		break;
+	}
+
+	case PR_GETSTACKSIZE:
+		printk("irix_prctl[%s:%d]: Wants PR_GETSTACKSIZE\n",
+		       current->comm, current->pid);
+		error = current->signal->rlim[RLIMIT_STACK].rlim_cur;
+		break;
+
+	case PR_MAXPPROCS:
+		printk("irix_prctl[%s:%d]: Wants PR_MAXPROCS\n",
+		       current->comm, current->pid);
+		error = 1;
+		break;
+
+	case PR_UNBLKONEXEC:
+		printk("irix_prctl[%s:%d]: Wants PR_UNBLKONEXEC\n",
+		       current->comm, current->pid);
+		error = -EINVAL;
+		break;
+
+	case PR_SETEXITSIG:
+		printk("irix_prctl[%s:%d]: Wants PR_SETEXITSIG\n",
+		       current->comm, current->pid);
+
+		/* We can probably play some game where we set the task
+		 * exit_code to some non-zero value when this is requested,
+		 * and check whether exit_code is already set in do_exit().
+		 */
+		error = -EINVAL;
+		break;
+
+	case PR_RESIDENT:
+		printk("irix_prctl[%s:%d]: Wants PR_RESIDENT\n",
+		       current->comm, current->pid);
+		error = 0; /* Compatibility indeed. */
+		break;
+
+	case PR_ATTACHADDR:
+		printk("irix_prctl[%s:%d]: Wants PR_ATTACHADDR\n",
+		       current->comm, current->pid);
+		error = -EINVAL;
+		break;
+
+	case PR_DETACHADDR:
+		printk("irix_prctl[%s:%d]: Wants PR_DETACHADDR\n",
+		       current->comm, current->pid);
+		error = -EINVAL;
+		break;
+
+	case PR_TERMCHILD:
+		printk("irix_prctl[%s:%d]: Wants PR_TERMCHILD\n",
+		       current->comm, current->pid);
+		error = -EINVAL;
+		break;
+
+	case PR_GETSHMASK:
+		printk("irix_prctl[%s:%d]: Wants PR_GETSHMASK\n",
+		       current->comm, current->pid);
+		error = -EINVAL; /* Until I have the sproc() stuff in. */
+		break;
+
+	case PR_GETNSHARE:
+		error = 0;       /* Until I have the sproc() stuff in. */
+		break;
+
+	case PR_COREPID:
+		printk("irix_prctl[%s:%d]: Wants PR_COREPID\n",
+		       current->comm, current->pid);
+		error = -EINVAL;
+		break;
+
+	case PR_ATTACHADDRPERM:
+		printk("irix_prctl[%s:%d]: Wants PR_ATTACHADDRPERM\n",
+		       current->comm, current->pid);
+		error = -EINVAL;
+		break;
+
+	case PR_PTHREADEXIT:
+		printk("irix_prctl[%s:%d]: Wants PR_PTHREADEXIT\n",
+		       current->comm, current->pid);
+		do_exit(regs->regs[base + 5]);
+
+	default:
+		printk("irix_prctl[%s:%d]: Non-existant opcode %d\n",
+		       current->comm, current->pid, (int)cmd);
+		error = -EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+#undef DEBUG_PROCGRPS
+
+extern unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt);
+extern int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
+extern char *prom_getenv(char *name);
+extern long prom_setenv(char *name, char *value);
+
+/* The syssgi commands supported thus far. */
+#define SGI_SYSID         1       /* Return unique per-machine identifier. */
+#define SGI_INVENT        5       /* Fetch inventory  */
+#   define SGI_INV_SIZEOF 1
+#   define SGI_INV_READ   2
+#define SGI_RDNAME        6       /* Return string name of a process. */
+#define SGI_SETNVRAM	  8	  /* Set PROM variable. */
+#define SGI_GETNVRAM	  9	  /* Get PROM variable. */
+#define SGI_SETPGID      21       /* Set process group id. */
+#define SGI_SYSCONF      22       /* POSIX sysconf garbage. */
+#define SGI_PATHCONF     24       /* POSIX sysconf garbage. */
+#define SGI_SETGROUPS    40       /* POSIX sysconf garbage. */
+#define SGI_GETGROUPS    41       /* POSIX sysconf garbage. */
+#define SGI_RUSAGE       56       /* BSD style rusage(). */
+#define SGI_SSYNC        62       /* Synchronous fs sync. */
+#define SGI_GETSID       65       /* SysVr4 get session id. */
+#define SGI_ELFMAP       68       /* Map an elf image. */
+#define SGI_TOSSTSAVE   108       /* Toss saved vma's. */
+#define SGI_FP_BCOPY    129       /* Should FPU bcopy be used on this machine? */
+#define SGI_PHYSP      1011       /* Translate virtual into physical page. */
+
+asmlinkage int irix_syssgi(struct pt_regs *regs)
+{
+	unsigned long cmd;
+	int retval, base = 0;
+
+	if (regs->regs[2] == 1000)
+		base = 1;
+
+	cmd = regs->regs[base + 4];
+	switch(cmd) {
+	case SGI_SYSID: {
+		char *buf = (char *) regs->regs[base + 5];
+
+		/* XXX Use ethernet addr.... */
+		retval = clear_user(buf, 64);
+		break;
+	}
+#if 0
+	case SGI_RDNAME: {
+		int pid = (int) regs->regs[base + 5];
+		char *buf = (char *) regs->regs[base + 6];
+		struct task_struct *p;
+		char tcomm[sizeof(current->comm)];
+
+		if (!access_ok(VERIFY_WRITE, buf, sizeof(tcomm))) {
+			retval = -EFAULT;
+			break;
+		}
+		read_lock(&tasklist_lock);
+		p = find_task_by_pid(pid);
+		if (!p) {
+			read_unlock(&tasklist_lock);
+			retval = -ESRCH;
+			break;
+		}
+		get_task_comm(tcomm, p);
+		read_unlock(&tasklist_lock);
+
+		/* XXX Need to check sizes. */
+		copy_to_user(buf, tcomm, sizeof(tcomm));
+		retval = 0;
+		break;
+	}
+
+	case SGI_GETNVRAM: {
+		char *name = (char *) regs->regs[base+5];
+		char *buf = (char *) regs->regs[base+6];
+		char *value;
+		return -EINVAL;	/* til I fix it */
+		if (!access_ok(VERIFY_WRITE, buf, 128)) {
+			retval = -EFAULT;
+			break;
+		}
+		value = prom_getenv(name);	/* PROM lock?  */
+		if (!value) {
+			retval = -EINVAL;
+			break;
+		}
+		/* Do I strlen() for the length? */
+		copy_to_user(buf, value, 128);
+		retval = 0;
+		break;
+	}
+
+	case SGI_SETNVRAM: {
+		char *name = (char *) regs->regs[base+5];
+		char *value = (char *) regs->regs[base+6];
+		return -EINVAL;	/* til I fix it */
+		retval = prom_setenv(name, value);
+		/* XXX make sure retval conforms to syssgi(2) */
+		printk("[%s:%d] setnvram(\"%s\", \"%s\"): retval %d",
+		       current->comm, current->pid, name, value, retval);
+/*		if (retval == PROM_ENOENT)
+		  	retval = -ENOENT; */
+		break;
+	}
+#endif
+
+	case SGI_SETPGID: {
+#ifdef DEBUG_PROCGRPS
+		printk("[%s:%d] setpgid(%d, %d) ",
+		       current->comm, current->pid,
+		       (int) regs->regs[base + 5], (int)regs->regs[base + 6]);
+#endif
+		retval = sys_setpgid(regs->regs[base + 5], regs->regs[base + 6]);
+
+#ifdef DEBUG_PROCGRPS
+		printk("retval=%d\n", retval);
+#endif
+	}
+
+	case SGI_SYSCONF: {
+		switch(regs->regs[base + 5]) {
+		case 1:
+			retval = (MAX_ARG_PAGES >> 4); /* XXX estimate... */
+			goto out;
+		case 2:
+			retval = max_threads;
+			goto out;
+		case 3:
+			retval = HZ;
+			goto out;
+		case 4:
+			retval = NGROUPS_MAX;
+			goto out;
+		case 5:
+			retval = NR_OPEN;
+			goto out;
+		case 6:
+			retval = 1;
+			goto out;
+		case 7:
+			retval = 1;
+			goto out;
+		case 8:
+			retval = 199009;
+			goto out;
+		case 11:
+			retval = PAGE_SIZE;
+			goto out;
+		case 12:
+			retval = 4;
+			goto out;
+		case 25:
+		case 26:
+		case 27:
+		case 28:
+		case 29:
+		case 30:
+			retval = 0;
+			goto out;
+		case 31:
+			retval = 32;
+			goto out;
+		default:
+			retval = -EINVAL;
+			goto out;
+		};
+	}
+
+	case SGI_SETGROUPS:
+		retval = sys_setgroups((int) regs->regs[base + 5],
+		                       (gid_t *) regs->regs[base + 6]);
+		break;
+
+	case SGI_GETGROUPS:
+		retval = sys_getgroups((int) regs->regs[base + 5],
+		                       (gid_t *) regs->regs[base + 6]);
+		break;
+
+	case SGI_RUSAGE: {
+		struct rusage *ru = (struct rusage *) regs->regs[base + 6];
+
+		switch((int) regs->regs[base + 5]) {
+		case 0:
+			/* rusage self */
+			retval = getrusage(current, RUSAGE_SELF, ru);
+			goto out;
+
+		case -1:
+			/* rusage children */
+			retval = getrusage(current, RUSAGE_CHILDREN, ru);
+			goto out;
+
+		default:
+			retval = -EINVAL;
+			goto out;
+		};
+	}
+
+	case SGI_SSYNC:
+		sys_sync();
+		retval = 0;
+		break;
+
+	case SGI_GETSID:
+#ifdef DEBUG_PROCGRPS
+		printk("[%s:%d] getsid(%d) ", current->comm, current->pid,
+		       (int) regs->regs[base + 5]);
+#endif
+		retval = sys_getsid(regs->regs[base + 5]);
+#ifdef DEBUG_PROCGRPS
+		printk("retval=%d\n", retval);
+#endif
+		break;
+
+	case SGI_ELFMAP:
+		retval = irix_mapelf((int) regs->regs[base + 5],
+				     (struct elf_phdr *) regs->regs[base + 6],
+				     (int) regs->regs[base + 7]);
+		break;
+
+	case SGI_TOSSTSAVE:
+		/* XXX We don't need to do anything? */
+		retval = 0;
+		break;
+
+	case SGI_FP_BCOPY:
+		retval = 0;
+		break;
+
+	case SGI_PHYSP: {
+		unsigned long addr = regs->regs[base + 5];
+		int *pageno = (int *) (regs->regs[base + 6]);
+		struct mm_struct *mm = current->mm;
+		pgd_t *pgdp;
+		pmd_t *pmdp;
+		pte_t *ptep;
+
+		if (!access_ok(VERIFY_WRITE, pageno, sizeof(int)))
+			return -EFAULT;
+
+		down_read(&mm->mmap_sem);
+		pgdp = pgd_offset(mm, addr);
+		pmdp = pmd_offset(pgdp, addr);
+		ptep = pte_offset(pmdp, addr);
+		retval = -EINVAL;
+		if (ptep) {
+			pte_t pte = *ptep;
+
+			if (pte_val(pte) & (_PAGE_VALID | _PAGE_PRESENT)) {
+				retval =  put_user((pte_val(pte) & PAGE_MASK) >>
+				                   PAGE_SHIFT, pageno);
+			}
+		}
+		up_read(&mm->mmap_sem);
+		break;
+	}
+
+	case SGI_INVENT: {
+		int  arg1    = (int)    regs->regs [base + 5];
+		void *buffer = (void *) regs->regs [base + 6];
+		int  count   = (int)    regs->regs [base + 7];
+
+		switch (arg1) {
+		case SGI_INV_SIZEOF:
+			retval = sizeof (inventory_t);
+			break;
+		case SGI_INV_READ:
+			retval = dump_inventory_to_user (buffer, count);
+			break;
+		default:
+			retval = -EINVAL;
+		}
+		break;
+	}
+
+	default:
+		printk("irix_syssgi: Unsupported command %d\n", (int)cmd);
+		retval = -EINVAL;
+		break;
+	};
+
+out:
+	return retval;
+}
+
+asmlinkage int irix_gtime(struct pt_regs *regs)
+{
+	return get_seconds();
+}
+
+/*
+ * IRIX is completely broken... it returns 0 on success, otherwise
+ * ENOMEM.
+ */
+asmlinkage int irix_brk(unsigned long brk)
+{
+	unsigned long rlim;
+	unsigned long newbrk, oldbrk;
+	struct mm_struct *mm = current->mm;
+	int ret;
+
+	down_write(&mm->mmap_sem);
+	if (brk < mm->end_code) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	newbrk = PAGE_ALIGN(brk);
+	oldbrk = PAGE_ALIGN(mm->brk);
+	if (oldbrk == newbrk) {
+		mm->brk = brk;
+		ret = 0;
+		goto out;
+	}
+
+	/*
+	 * Always allow shrinking brk
+	 */
+	if (brk <= mm->brk) {
+		mm->brk = brk;
+		do_munmap(mm, newbrk, oldbrk-newbrk);
+		ret = 0;
+		goto out;
+	}
+	/*
+	 * Check against rlimit and stack..
+	 */
+	rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
+	if (rlim >= RLIM_INFINITY)
+		rlim = ~0;
+	if (brk - mm->end_code > rlim) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * Check against existing mmap mappings.
+	 */
+	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * Check if we have enough memory..
+	 */
+	if (security_vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * Ok, looks good - let it rip.
+	 */
+	mm->brk = brk;
+	do_brk(oldbrk, newbrk-oldbrk);
+	ret = 0;
+
+out:
+	up_write(&mm->mmap_sem);
+	return ret;
+}
+
+asmlinkage int irix_getpid(struct pt_regs *regs)
+{
+	regs->regs[3] = current->real_parent->pid;
+	return current->pid;
+}
+
+asmlinkage int irix_getuid(struct pt_regs *regs)
+{
+	regs->regs[3] = current->euid;
+	return current->uid;
+}
+
+asmlinkage int irix_getgid(struct pt_regs *regs)
+{
+	regs->regs[3] = current->egid;
+	return current->gid;
+}
+
+asmlinkage int irix_stime(int value)
+{
+	int err;
+	struct timespec tv;
+
+	tv.tv_sec = value;
+	tv.tv_nsec = 0;
+	err = security_settime(&tv, NULL);
+	if (err)
+		return err;
+
+	write_seqlock_irq(&xtime_lock);
+	xtime.tv_sec = value;
+	xtime.tv_nsec = 0;
+	time_adjust = 0;			/* stop active adjtime() */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+	write_sequnlock_irq(&xtime_lock);
+
+	return 0;
+}
+
+static inline void jiffiestotv(unsigned long jiffies, struct timeval *value)
+{
+	value->tv_usec = (jiffies % HZ) * (1000000 / HZ);
+	value->tv_sec = jiffies / HZ;
+}
+
+static inline void getitimer_real(struct itimerval *value)
+{
+	register unsigned long val, interval;
+
+	interval = current->it_real_incr;
+	val = 0;
+	if (del_timer(&current->real_timer)) {
+		unsigned long now = jiffies;
+		val = current->real_timer.expires;
+		add_timer(&current->real_timer);
+		/* look out for negative/zero itimer.. */
+		if (val <= now)
+			val = now+1;
+		val -= now;
+	}
+	jiffiestotv(val, &value->it_value);
+	jiffiestotv(interval, &value->it_interval);
+}
+
+asmlinkage unsigned int irix_alarm(unsigned int seconds)
+{
+	struct itimerval it_new, it_old;
+	unsigned int oldalarm;
+
+	if (!seconds) {
+		getitimer_real(&it_old);
+		del_timer(&current->real_timer);
+	} else {
+		it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
+		it_new.it_value.tv_sec = seconds;
+		it_new.it_value.tv_usec = 0;
+		do_setitimer(ITIMER_REAL, &it_new, &it_old);
+	}
+	oldalarm = it_old.it_value.tv_sec;
+	/*
+	 * ehhh.. We can't return 0 if we have an alarm pending ...
+	 * And we'd better return too much than too little anyway
+	 */
+	if (it_old.it_value.tv_usec)
+		oldalarm++;
+
+	return oldalarm;
+}
+
+asmlinkage int irix_pause(void)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+
+	return -EINTR;
+}
+
+/* XXX need more than this... */
+asmlinkage int irix_mount(char *dev_name, char *dir_name, unsigned long flags,
+			  char *type, void *data, int datalen)
+{
+	printk("[%s:%d] irix_mount(%p,%p,%08lx,%p,%p,%d)\n",
+	       current->comm, current->pid,
+	       dev_name, dir_name, flags, type, data, datalen);
+
+	return sys_mount(dev_name, dir_name, type, flags, data);
+}
+
+struct irix_statfs {
+	short f_type;
+        long  f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree;
+	char  f_fname[6], f_fpack[6];
+};
+
+asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
+			   int len, int fs_type)
+{
+	struct nameidata nd;
+	struct kstatfs kbuf;
+	int error, i;
+
+	/* We don't support this feature yet. */
+	if (fs_type) {
+		error = -EINVAL;
+		goto out;
+	}
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statfs))) {
+		error = -EFAULT;
+		goto out;
+	}
+	error = user_path_walk(path, &nd);
+	if (error)
+		goto out;
+
+	error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf);
+	if (error)
+		goto dput_and_out;
+
+	__put_user(kbuf.f_type, &buf->f_type);
+	__put_user(kbuf.f_bsize, &buf->f_bsize);
+	__put_user(kbuf.f_frsize, &buf->f_frsize);
+	__put_user(kbuf.f_blocks, &buf->f_blocks);
+	__put_user(kbuf.f_bfree, &buf->f_bfree);
+	__put_user(kbuf.f_files, &buf->f_files);
+	__put_user(kbuf.f_ffree, &buf->f_ffree);
+	for (i = 0; i < 6; i++) {
+		__put_user(0, &buf->f_fname[i]);
+		__put_user(0, &buf->f_fpack[i]);
+	}
+	error = 0;
+
+dput_and_out:
+	path_release(&nd);
+out:
+	return error;
+}
+
+asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
+{
+	struct kstatfs kbuf;
+	struct file *file;
+	int error, i;
+
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statfs))) {
+		error = -EFAULT;
+		goto out;
+	}
+	if (!(file = fget(fd))) {
+		error = -EBADF;
+		goto out;
+	}
+
+	error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
+	if (error)
+		goto out_f;
+
+	__put_user(kbuf.f_type, &buf->f_type);
+	__put_user(kbuf.f_bsize, &buf->f_bsize);
+	__put_user(kbuf.f_frsize, &buf->f_frsize);
+	__put_user(kbuf.f_blocks, &buf->f_blocks);
+	__put_user(kbuf.f_bfree, &buf->f_bfree);
+	__put_user(kbuf.f_files, &buf->f_files);
+	__put_user(kbuf.f_ffree, &buf->f_ffree);
+	for(i = 0; i < 6; i++) {
+		__put_user(0, &buf->f_fname[i]);
+		__put_user(0, &buf->f_fpack[i]);
+	}
+
+out_f:
+	fput(file);
+out:
+	return error;
+}
+
+asmlinkage int irix_setpgrp(int flags)
+{
+	int error;
+
+#ifdef DEBUG_PROCGRPS
+	printk("[%s:%d] setpgrp(%d) ", current->comm, current->pid, flags);
+#endif
+	if(!flags)
+		error = process_group(current);
+	else
+		error = sys_setsid();
+#ifdef DEBUG_PROCGRPS
+	printk("returning %d\n", process_group(current));
+#endif
+
+	return error;
+}
+
+asmlinkage int irix_times(struct tms * tbuf)
+{
+	int err = 0;
+
+	if (tbuf) {
+		if (!access_ok(VERIFY_WRITE,tbuf,sizeof *tbuf))
+			return -EFAULT;
+		err |= __put_user(current->utime, &tbuf->tms_utime);
+		err |= __put_user(current->stime, &tbuf->tms_stime);
+		err |= __put_user(current->signal->cutime, &tbuf->tms_cutime);
+		err |= __put_user(current->signal->cstime, &tbuf->tms_cstime);
+	}
+
+	return err;
+}
+
+asmlinkage int irix_exec(struct pt_regs *regs)
+{
+	int error, base = 0;
+	char *filename;
+
+	if(regs->regs[2] == 1000)
+		base = 1;
+	filename = getname((char *) (long)regs->regs[base + 4]);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		return error;
+
+	error = do_execve(filename, (char **) (long)regs->regs[base + 5],
+	                  (char **) 0, regs);
+	putname(filename);
+
+	return error;
+}
+
+asmlinkage int irix_exece(struct pt_regs *regs)
+{
+	int error, base = 0;
+	char *filename;
+
+	if (regs->regs[2] == 1000)
+		base = 1;
+	filename = getname((char *) (long)regs->regs[base + 4]);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		return error;
+	error = do_execve(filename, (char **) (long)regs->regs[base + 5],
+	                  (char **) (long)regs->regs[base + 6], regs);
+	putname(filename);
+
+	return error;
+}
+
+asmlinkage unsigned long irix_gethostid(void)
+{
+	printk("[%s:%d]: irix_gethostid() called...\n",
+	       current->comm, current->pid);
+
+	return -EINVAL;
+}
+
+asmlinkage unsigned long irix_sethostid(unsigned long val)
+{
+	printk("[%s:%d]: irix_sethostid(%08lx) called...\n",
+	       current->comm, current->pid, val);
+
+	return -EINVAL;
+}
+
+asmlinkage int irix_socket(int family, int type, int protocol)
+{
+	switch(type) {
+	case 1:
+		type = SOCK_DGRAM;
+		break;
+
+	case 2:
+		type = SOCK_STREAM;
+		break;
+
+	case 3:
+		type = 9; /* Invalid... */
+		break;
+
+	case 4:
+		type = SOCK_RAW;
+		break;
+
+	case 5:
+		type = SOCK_RDM;
+		break;
+
+	case 6:
+		type = SOCK_SEQPACKET;
+		break;
+
+	default:
+		break;
+	}
+
+	return sys_socket(family, type, protocol);
+}
+
+asmlinkage int irix_getdomainname(char *name, int len)
+{
+	int error;
+
+	if (!access_ok(VERIFY_WRITE, name, len))
+		return -EFAULT;
+
+	down_read(&uts_sem);
+	if (len > __NEW_UTS_LEN)
+		len = __NEW_UTS_LEN;
+	error = 0;
+	if (copy_to_user(name, system_utsname.domainname, len))
+		error = -EFAULT;
+	up_read(&uts_sem);
+
+	return error;
+}
+
+asmlinkage unsigned long irix_getpagesize(void)
+{
+	return PAGE_SIZE;
+}
+
+asmlinkage int irix_msgsys(int opcode, unsigned long arg0, unsigned long arg1,
+			   unsigned long arg2, unsigned long arg3,
+			   unsigned long arg4)
+{
+	switch (opcode) {
+	case 0:
+		return sys_msgget((key_t) arg0, (int) arg1);
+	case 1:
+		return sys_msgctl((int) arg0, (int) arg1, (struct msqid_ds *)arg2);
+	case 2:
+		return sys_msgrcv((int) arg0, (struct msgbuf *) arg1,
+				  (size_t) arg2, (long) arg3, (int) arg4);
+	case 3:
+		return sys_msgsnd((int) arg0, (struct msgbuf *) arg1,
+				  (size_t) arg2, (int) arg3);
+	default:
+		return -EINVAL;
+	}
+}
+
+asmlinkage int irix_shmsys(int opcode, unsigned long arg0, unsigned long arg1,
+			   unsigned long arg2, unsigned long arg3)
+{
+	switch (opcode) {
+	case 0:
+		return do_shmat((int) arg0, (char *)arg1, (int) arg2,
+				 (unsigned long *) arg3);
+	case 1:
+		return sys_shmctl((int)arg0, (int)arg1, (struct shmid_ds *)arg2);
+	case 2:
+		return sys_shmdt((char *)arg0);
+	case 3:
+		return sys_shmget((key_t) arg0, (int) arg1, (int) arg2);
+	default:
+		return -EINVAL;
+	}
+}
+
+asmlinkage int irix_semsys(int opcode, unsigned long arg0, unsigned long arg1,
+			   unsigned long arg2, int arg3)
+{
+	switch (opcode) {
+	case 0:
+		return sys_semctl((int) arg0, (int) arg1, (int) arg2,
+				  (union semun) arg3);
+	case 1:
+		return sys_semget((key_t) arg0, (int) arg1, (int) arg2);
+	case 2:
+		return sys_semop((int) arg0, (struct sembuf *)arg1,
+				 (unsigned int) arg2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static inline loff_t llseek(struct file *file, loff_t offset, int origin)
+{
+	loff_t (*fn)(struct file *, loff_t, int);
+	loff_t retval;
+
+	fn = default_llseek;
+	if (file->f_op && file->f_op->llseek)
+        fn = file->f_op->llseek;
+	lock_kernel();
+	retval = fn(file, offset, origin);
+	unlock_kernel();
+	return retval;
+}
+
+asmlinkage int irix_lseek64(int fd, int _unused, int offhi, int offlow,
+                            int origin)
+{
+	int retval;
+	struct file * file;
+	loff_t offset;
+
+	retval = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto bad;
+	retval = -EINVAL;
+	if (origin > 2)
+		goto out_putf;
+
+	offset = llseek(file, ((loff_t) offhi << 32) | offlow, origin);
+	retval = (int) offset;
+
+out_putf:
+	fput(file);
+bad:
+	return retval;
+}
+
+asmlinkage int irix_sginap(int ticks)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(ticks);
+	return 0;
+}
+
+asmlinkage int irix_sgikopt(char *istring, char *ostring, int len)
+{
+	return -EINVAL;
+}
+
+asmlinkage int irix_gettimeofday(struct timeval *tv)
+{
+	time_t sec;
+	long nsec, seq;
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, tv, sizeof(struct timeval)))
+		return -EFAULT;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		sec = xtime.tv_sec;
+		nsec = xtime.tv_nsec;
+	} while (read_seqretry(&xtime_lock, seq));
+
+	err = __put_user(sec, &tv->tv_sec);
+	err |= __put_user((nsec / 1000), &tv->tv_usec);
+
+	return err;
+}
+
+#define IRIX_MAP_AUTOGROW 0x40
+
+asmlinkage unsigned long irix_mmap32(unsigned long addr, size_t len, int prot,
+				     int flags, int fd, off_t offset)
+{
+	struct file *file = NULL;
+	unsigned long retval;
+
+	if (!(flags & MAP_ANONYMOUS)) {
+		if (!(file = fget(fd)))
+			return -EBADF;
+
+		/* Ok, bad taste hack follows, try to think in something else
+		 * when reading this.  */
+		if (flags & IRIX_MAP_AUTOGROW) {
+			unsigned long old_pos;
+			long max_size = offset + len;
+
+			if (max_size > file->f_dentry->d_inode->i_size) {
+				old_pos = sys_lseek (fd, max_size - 1, 0);
+				sys_write (fd, "", 1);
+				sys_lseek (fd, old_pos, 0);
+			}
+		}
+	}
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+	down_write(&current->mm->mmap_sem);
+	retval = do_mmap(file, addr, len, prot, flags, offset);
+	up_write(&current->mm->mmap_sem);
+	if (file)
+		fput(file);
+
+	return retval;
+}
+
+asmlinkage int irix_madvise(unsigned long addr, int len, int behavior)
+{
+	printk("[%s:%d] Wheee.. irix_madvise(%08lx,%d,%d)\n",
+	       current->comm, current->pid, addr, len, behavior);
+
+	return -EINVAL;
+}
+
+asmlinkage int irix_pagelock(char *addr, int len, int op)
+{
+	printk("[%s:%d] Wheee.. irix_pagelock(%p,%d,%d)\n",
+	       current->comm, current->pid, addr, len, op);
+
+	return -EINVAL;
+}
+
+asmlinkage int irix_quotactl(struct pt_regs *regs)
+{
+	printk("[%s:%d] Wheee.. irix_quotactl()\n",
+	       current->comm, current->pid);
+
+	return -EINVAL;
+}
+
+asmlinkage int irix_BSDsetpgrp(int pid, int pgrp)
+{
+	int error;
+
+#ifdef DEBUG_PROCGRPS
+	printk("[%s:%d] BSDsetpgrp(%d, %d) ", current->comm, current->pid,
+	       pid, pgrp);
+#endif
+	if(!pid)
+		pid = current->pid;
+
+	/* Wheee, weird sysv thing... */
+	if ((pgrp == 0) && (pid == current->pid))
+		error = sys_setsid();
+	else
+		error = sys_setpgid(pid, pgrp);
+
+#ifdef DEBUG_PROCGRPS
+	printk("error = %d\n", error);
+#endif
+
+	return error;
+}
+
+asmlinkage int irix_systeminfo(int cmd, char *buf, int cnt)
+{
+	printk("[%s:%d] Wheee.. irix_systeminfo(%d,%p,%d)\n",
+	       current->comm, current->pid, cmd, buf, cnt);
+
+	return -EINVAL;
+}
+
+struct iuname {
+	char sysname[257], nodename[257], release[257];
+	char version[257], machine[257];
+	char m_type[257], base_rel[257];
+	char _unused0[257], _unused1[257], _unused2[257];
+	char _unused3[257], _unused4[257], _unused5[257];
+};
+
+asmlinkage int irix_uname(struct iuname *buf)
+{
+	down_read(&uts_sem);
+	if (copy_to_user(system_utsname.sysname, buf->sysname, 65)
+	    || copy_to_user(system_utsname.nodename, buf->nodename, 65)
+	    || copy_to_user(system_utsname.release, buf->release, 65)
+	    || copy_to_user(system_utsname.version, buf->version, 65)
+	    || copy_to_user(system_utsname.machine, buf->machine, 65)) {
+		return -EFAULT;
+	}
+	up_read(&uts_sem);
+
+	return 1;
+}
+
+#undef DEBUG_XSTAT
+
+static int irix_xstat32_xlate(struct kstat *stat, void *ubuf)
+{
+	struct xstat32 {
+		u32 st_dev, st_pad1[3], st_ino, st_mode, st_nlink, st_uid, st_gid;
+		u32 st_rdev, st_pad2[2], st_size, st_pad3;
+		u32 st_atime0, st_atime1;
+		u32 st_mtime0, st_mtime1;
+		u32 st_ctime0, st_ctime1;
+		u32 st_blksize, st_blocks;
+		char st_fstype[16];
+		u32 st_pad4[8];
+	} ub;
+
+	if (!sysv_valid_dev(stat->dev) || !sysv_valid_dev(stat->rdev))
+		return -EOVERFLOW;
+	ub.st_dev     = sysv_encode_dev(stat->dev);
+	ub.st_ino     = stat->ino;
+	ub.st_mode    = stat->mode;
+	ub.st_nlink   = stat->nlink;
+	SET_UID(ub.st_uid, stat->uid);
+	SET_GID(ub.st_gid, stat->gid);
+	ub.st_rdev    = sysv_encode_dev(stat->rdev);
+#if BITS_PER_LONG == 32
+	if (stat->size > MAX_NON_LFS)
+		return -EOVERFLOW;
+#endif
+	ub.st_size    = stat->size;
+	ub.st_atime0  = stat->atime.tv_sec;
+	ub.st_atime1  = stat->atime.tv_nsec;
+	ub.st_mtime0  = stat->mtime.tv_sec;
+	ub.st_mtime1  = stat->atime.tv_nsec;
+	ub.st_ctime0  = stat->ctime.tv_sec;
+	ub.st_ctime1  = stat->atime.tv_nsec;
+	ub.st_blksize = stat->blksize;
+	ub.st_blocks  = stat->blocks;
+	strcpy (ub.st_fstype, "efs");
+
+	return copy_to_user(ubuf, &ub, sizeof(ub)) ? -EFAULT : 0;
+}
+
+static int irix_xstat64_xlate(struct kstat *stat, void *ubuf)
+{
+	struct xstat64 {
+		u32 st_dev; s32 st_pad1[3];
+		unsigned long long st_ino;
+		u32 st_mode;
+		u32 st_nlink; s32 st_uid; s32 st_gid; u32 st_rdev;
+		s32 st_pad2[2];
+		long long st_size;
+		s32 st_pad3;
+		struct { s32 tv_sec, tv_nsec; } st_atime, st_mtime, st_ctime;
+		s32 st_blksize;
+		long long  st_blocks;
+		char st_fstype[16];
+		s32 st_pad4[8];
+	} ks;
+
+	if (!sysv_valid_dev(stat->dev) || !sysv_valid_dev(stat->rdev))
+		return -EOVERFLOW;
+
+	ks.st_dev = sysv_encode_dev(stat->dev);
+	ks.st_pad1[0] = ks.st_pad1[1] = ks.st_pad1[2] = 0;
+	ks.st_ino = (unsigned long long) stat->ino;
+	ks.st_mode = (u32) stat->mode;
+	ks.st_nlink = (u32) stat->nlink;
+	ks.st_uid = (s32) stat->uid;
+	ks.st_gid = (s32) stat->gid;
+	ks.st_rdev = sysv_encode_dev (stat->rdev);
+	ks.st_pad2[0] = ks.st_pad2[1] = 0;
+	ks.st_size = (long long) stat->size;
+	ks.st_pad3 = 0;
+
+	/* XXX hackety hack... */
+	ks.st_atime.tv_sec = (s32) stat->atime.tv_sec;
+	ks.st_atime.tv_nsec = stat->atime.tv_nsec;
+	ks.st_mtime.tv_sec = (s32) stat->mtime.tv_sec;
+	ks.st_mtime.tv_nsec = stat->mtime.tv_nsec;
+	ks.st_ctime.tv_sec = (s32) stat->ctime.tv_sec;
+	ks.st_ctime.tv_nsec = stat->ctime.tv_nsec;
+
+	ks.st_blksize = (s32) stat->blksize;
+	ks.st_blocks = (long long) stat->blocks;
+	memset(ks.st_fstype, 0, 16);
+	ks.st_pad4[0] = ks.st_pad4[1] = ks.st_pad4[2] = ks.st_pad4[3] = 0;
+	ks.st_pad4[4] = ks.st_pad4[5] = ks.st_pad4[6] = ks.st_pad4[7] = 0;
+
+	/* Now write it all back. */
+	return copy_to_user(ubuf, &ks, sizeof(ks)) ? -EFAULT : 0;
+}
+
+asmlinkage int irix_xstat(int version, char *filename, struct stat *statbuf)
+{
+	int retval;
+	struct kstat stat;
+
+#ifdef DEBUG_XSTAT
+	printk("[%s:%d] Wheee.. irix_xstat(%d,%s,%p) ",
+	       current->comm, current->pid, version, filename, statbuf);
+#endif
+
+	retval = vfs_stat(filename, &stat);
+	if (!retval) {
+		switch(version) {
+			case 2:
+				retval = irix_xstat32_xlate(&stat, statbuf);
+				break;
+			case 3:
+				retval = irix_xstat64_xlate(&stat, statbuf);
+				break;
+			default:
+				retval = -EINVAL;
+		}
+	}
+	return retval;
+}
+
+asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf)
+{
+	int error;
+	struct kstat stat;
+
+#ifdef DEBUG_XSTAT
+	printk("[%s:%d] Wheee.. irix_lxstat(%d,%s,%p) ",
+	       current->comm, current->pid, version, filename, statbuf);
+#endif
+
+	error = vfs_lstat(filename, &stat);
+
+	if (!error) {
+		switch (version) {
+			case 2:
+				error = irix_xstat32_xlate(&stat, statbuf);
+				break;
+			case 3:
+				error = irix_xstat64_xlate(&stat, statbuf);
+				break;
+			default:
+				error = -EINVAL;
+		}
+	}
+	return error;
+}
+
+asmlinkage int irix_fxstat(int version, int fd, struct stat *statbuf)
+{
+	int error;
+	struct kstat stat;
+
+#ifdef DEBUG_XSTAT
+	printk("[%s:%d] Wheee.. irix_fxstat(%d,%d,%p) ",
+	       current->comm, current->pid, version, fd, statbuf);
+#endif
+
+	error = vfs_fstat(fd, &stat);
+	if (!error) {
+		switch (version) {
+			case 2:
+				error = irix_xstat32_xlate(&stat, statbuf);
+				break;
+			case 3:
+				error = irix_xstat64_xlate(&stat, statbuf);
+				break;
+			default:
+				error = -EINVAL;
+		}
+	}
+	return error;
+}
+
+asmlinkage int irix_xmknod(int ver, char *filename, int mode, unsigned dev)
+{
+	int retval;
+	printk("[%s:%d] Wheee.. irix_xmknod(%d,%s,%x,%x)\n",
+	       current->comm, current->pid, ver, filename, mode, dev);
+
+	switch(ver) {
+	case 2:
+		/* shouldn't we convert here as well as on stat()? */
+		retval = sys_mknod(filename, mode, dev);
+		break;
+
+	default:
+		retval = -EINVAL;
+		break;
+	};
+
+	return retval;
+}
+
+asmlinkage int irix_swapctl(int cmd, char *arg)
+{
+	printk("[%s:%d] Wheee.. irix_swapctl(%d,%p)\n",
+	       current->comm, current->pid, cmd, arg);
+
+	return -EINVAL;
+}
+
+struct irix_statvfs {
+	u32 f_bsize; u32 f_frsize; u32 f_blocks;
+	u32 f_bfree; u32 f_bavail; u32 f_files; u32 f_ffree; u32 f_favail;
+	u32 f_fsid; char f_basetype[16];
+	u32 f_flag; u32 f_namemax;
+	char	f_fstr[32]; u32 f_filler[16];
+};
+
+asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
+{
+	struct nameidata nd;
+	struct kstatfs kbuf;
+	int error, i;
+
+	printk("[%s:%d] Wheee.. irix_statvfs(%s,%p)\n",
+	       current->comm, current->pid, fname, buf);
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) {
+		error = -EFAULT;
+		goto out;
+	}
+	error = user_path_walk(fname, &nd);
+	if (error)
+		goto out;
+	error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf);
+	if (error)
+		goto dput_and_out;
+
+	__put_user(kbuf.f_bsize, &buf->f_bsize);
+	__put_user(kbuf.f_frsize, &buf->f_frsize);
+	__put_user(kbuf.f_blocks, &buf->f_blocks);
+	__put_user(kbuf.f_bfree, &buf->f_bfree);
+	__put_user(kbuf.f_bfree, &buf->f_bavail);  /* XXX hackety hack... */
+	__put_user(kbuf.f_files, &buf->f_files);
+	__put_user(kbuf.f_ffree, &buf->f_ffree);
+	__put_user(kbuf.f_ffree, &buf->f_favail);  /* XXX hackety hack... */
+#ifdef __MIPSEB__
+	__put_user(kbuf.f_fsid.val[1], &buf->f_fsid);
+#else
+	__put_user(kbuf.f_fsid.val[0], &buf->f_fsid);
+#endif
+	for (i = 0; i < 16; i++)
+		__put_user(0, &buf->f_basetype[i]);
+	__put_user(0, &buf->f_flag);
+	__put_user(kbuf.f_namelen, &buf->f_namemax);
+	for (i = 0; i < 32; i++)
+		__put_user(0, &buf->f_fstr[i]);
+
+	error = 0;
+
+dput_and_out:
+	path_release(&nd);
+out:
+	return error;
+}
+
+asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
+{
+	struct kstatfs kbuf;
+	struct file *file;
+	int error, i;
+
+	printk("[%s:%d] Wheee.. irix_fstatvfs(%d,%p)\n",
+	       current->comm, current->pid, fd, buf);
+
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) {
+		error = -EFAULT;
+		goto out;
+	}
+	if (!(file = fget(fd))) {
+		error = -EBADF;
+		goto out;
+	}
+	error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
+	if (error)
+		goto out_f;
+
+	__put_user(kbuf.f_bsize, &buf->f_bsize);
+	__put_user(kbuf.f_frsize, &buf->f_frsize);
+	__put_user(kbuf.f_blocks, &buf->f_blocks);
+	__put_user(kbuf.f_bfree, &buf->f_bfree);
+	__put_user(kbuf.f_bfree, &buf->f_bavail); /* XXX hackety hack... */
+	__put_user(kbuf.f_files, &buf->f_files);
+	__put_user(kbuf.f_ffree, &buf->f_ffree);
+	__put_user(kbuf.f_ffree, &buf->f_favail); /* XXX hackety hack... */
+#ifdef __MIPSEB__
+	__put_user(kbuf.f_fsid.val[1], &buf->f_fsid);
+#else
+	__put_user(kbuf.f_fsid.val[0], &buf->f_fsid);
+#endif
+	for(i = 0; i < 16; i++)
+		__put_user(0, &buf->f_basetype[i]);
+	__put_user(0, &buf->f_flag);
+	__put_user(kbuf.f_namelen, &buf->f_namemax);
+	__clear_user(&buf->f_fstr, sizeof(buf->f_fstr));
+
+out_f:
+	fput(file);
+out:
+	return error;
+}
+
+asmlinkage int irix_priocntl(struct pt_regs *regs)
+{
+	printk("[%s:%d] Wheee.. irix_priocntl()\n",
+	       current->comm, current->pid);
+
+	return -EINVAL;
+}
+
+asmlinkage int irix_sigqueue(int pid, int sig, int code, int val)
+{
+	printk("[%s:%d] Wheee.. irix_sigqueue(%d,%d,%d,%d)\n",
+	       current->comm, current->pid, pid, sig, code, val);
+
+	return -EINVAL;
+}
+
+asmlinkage int irix_truncate64(char *name, int pad, int size1, int size2)
+{
+	int retval;
+
+	if (size1) {
+		retval = -EINVAL;
+		goto out;
+	}
+	retval = sys_truncate(name, size2);
+
+out:
+	return retval;
+}
+
+asmlinkage int irix_ftruncate64(int fd, int pad, int size1, int size2)
+{
+	int retval;
+
+	if (size1) {
+		retval = -EINVAL;
+		goto out;
+	}
+	retval = sys_ftruncate(fd, size2);
+
+out:
+	return retval;
+}
+
+asmlinkage int irix_mmap64(struct pt_regs *regs)
+{
+	int len, prot, flags, fd, off1, off2, error, base = 0;
+	unsigned long addr, pgoff, *sp;
+	struct file *file = NULL;
+
+	if (regs->regs[2] == 1000)
+		base = 1;
+	sp = (unsigned long *) (regs->regs[29] + 16);
+	addr = regs->regs[base + 4];
+	len = regs->regs[base + 5];
+	prot = regs->regs[base + 6];
+	if (!base) {
+		flags = regs->regs[base + 7];
+		if (!access_ok(VERIFY_READ, sp, (4 * sizeof(unsigned long)))) {
+			error = -EFAULT;
+			goto out;
+		}
+		fd = sp[0];
+		__get_user(off1, &sp[1]);
+		__get_user(off2, &sp[2]);
+	} else {
+		if (!access_ok(VERIFY_READ, sp, (5 * sizeof(unsigned long)))) {
+			error = -EFAULT;
+			goto out;
+		}
+		__get_user(flags, &sp[0]);
+		__get_user(fd, &sp[1]);
+		__get_user(off1, &sp[2]);
+		__get_user(off2, &sp[3]);
+	}
+
+	if (off1 & PAGE_MASK) {
+		error = -EOVERFLOW;
+		goto out;
+	}
+
+	pgoff = (off1 << (32 - PAGE_SHIFT)) | (off2 >> PAGE_SHIFT);
+
+	if (!(flags & MAP_ANONYMOUS)) {
+		if (!(file = fget(fd))) {
+			error = -EBADF;
+			goto out;
+		}
+
+		/* Ok, bad taste hack follows, try to think in something else
+		   when reading this */
+		if (flags & IRIX_MAP_AUTOGROW) {
+			unsigned long old_pos;
+			long max_size = off2 + len;
+
+			if (max_size > file->f_dentry->d_inode->i_size) {
+				old_pos = sys_lseek (fd, max_size - 1, 0);
+				sys_write (fd, "", 1);
+				sys_lseek (fd, old_pos, 0);
+			}
+		}
+	}
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
+	if (file)
+		fput(file);
+
+out:
+	return error;
+}
+
+asmlinkage int irix_dmi(struct pt_regs *regs)
+{
+	printk("[%s:%d] Wheee.. irix_dmi()\n",
+	       current->comm, current->pid);
+
+	return -EINVAL;
+}
+
+asmlinkage int irix_pread(int fd, char *buf, int cnt, int off64,
+			  int off1, int off2)
+{
+	printk("[%s:%d] Wheee.. irix_pread(%d,%p,%d,%d,%d,%d)\n",
+	       current->comm, current->pid, fd, buf, cnt, off64, off1, off2);
+
+	return -EINVAL;
+}
+
+asmlinkage int irix_pwrite(int fd, char *buf, int cnt, int off64,
+			   int off1, int off2)
+{
+	printk("[%s:%d] Wheee.. irix_pwrite(%d,%p,%d,%d,%d,%d)\n",
+	       current->comm, current->pid, fd, buf, cnt, off64, off1, off2);
+
+	return -EINVAL;
+}
+
+asmlinkage int irix_sgifastpath(int cmd, unsigned long arg0, unsigned long arg1,
+				unsigned long arg2, unsigned long arg3,
+				unsigned long arg4, unsigned long arg5)
+{
+	printk("[%s:%d] Wheee.. irix_fastpath(%d,%08lx,%08lx,%08lx,%08lx,"
+	       "%08lx,%08lx)\n",
+	       current->comm, current->pid, cmd, arg0, arg1, arg2,
+	       arg3, arg4, arg5);
+
+	return -EINVAL;
+}
+
+struct irix_statvfs64 {
+	u32  f_bsize; u32 f_frsize;
+	u64  f_blocks; u64 f_bfree; u64 f_bavail;
+	u64  f_files; u64 f_ffree; u64 f_favail;
+	u32  f_fsid;
+	char f_basetype[16];
+	u32  f_flag; u32 f_namemax;
+	char f_fstr[32];
+	u32  f_filler[16];
+};
+
+asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
+{
+	struct nameidata nd;
+	struct kstatfs kbuf;
+	int error, i;
+
+	printk("[%s:%d] Wheee.. irix_statvfs64(%s,%p)\n",
+	       current->comm, current->pid, fname, buf);
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs64))) {
+		error = -EFAULT;
+		goto out;
+	}
+	error = user_path_walk(fname, &nd);
+	if (error)
+		goto out;
+	error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf);
+	if (error)
+		goto dput_and_out;
+
+	__put_user(kbuf.f_bsize, &buf->f_bsize);
+	__put_user(kbuf.f_frsize, &buf->f_frsize);
+	__put_user(kbuf.f_blocks, &buf->f_blocks);
+	__put_user(kbuf.f_bfree, &buf->f_bfree);
+	__put_user(kbuf.f_bfree, &buf->f_bavail);  /* XXX hackety hack... */
+	__put_user(kbuf.f_files, &buf->f_files);
+	__put_user(kbuf.f_ffree, &buf->f_ffree);
+	__put_user(kbuf.f_ffree, &buf->f_favail);  /* XXX hackety hack... */
+#ifdef __MIPSEB__
+	__put_user(kbuf.f_fsid.val[1], &buf->f_fsid);
+#else
+	__put_user(kbuf.f_fsid.val[0], &buf->f_fsid);
+#endif
+	for(i = 0; i < 16; i++)
+		__put_user(0, &buf->f_basetype[i]);
+	__put_user(0, &buf->f_flag);
+	__put_user(kbuf.f_namelen, &buf->f_namemax);
+	for(i = 0; i < 32; i++)
+		__put_user(0, &buf->f_fstr[i]);
+
+	error = 0;
+
+dput_and_out:
+	path_release(&nd);
+out:
+	return error;
+}
+
+asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
+{
+	struct kstatfs kbuf;
+	struct file *file;
+	int error, i;
+
+	printk("[%s:%d] Wheee.. irix_fstatvfs64(%d,%p)\n",
+	       current->comm, current->pid, fd, buf);
+
+	if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) {
+		error = -EFAULT;
+		goto out;
+	}
+	if (!(file = fget(fd))) {
+		error = -EBADF;
+		goto out;
+	}
+	error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
+	if (error)
+		goto out_f;
+
+	__put_user(kbuf.f_bsize, &buf->f_bsize);
+	__put_user(kbuf.f_frsize, &buf->f_frsize);
+	__put_user(kbuf.f_blocks, &buf->f_blocks);
+	__put_user(kbuf.f_bfree, &buf->f_bfree);
+	__put_user(kbuf.f_bfree, &buf->f_bavail);  /* XXX hackety hack... */
+	__put_user(kbuf.f_files, &buf->f_files);
+	__put_user(kbuf.f_ffree, &buf->f_ffree);
+	__put_user(kbuf.f_ffree, &buf->f_favail);  /* XXX hackety hack... */
+#ifdef __MIPSEB__
+	__put_user(kbuf.f_fsid.val[1], &buf->f_fsid);
+#else
+	__put_user(kbuf.f_fsid.val[0], &buf->f_fsid);
+#endif
+	for(i = 0; i < 16; i++)
+		__put_user(0, &buf->f_basetype[i]);
+	__put_user(0, &buf->f_flag);
+	__put_user(kbuf.f_namelen, &buf->f_namemax);
+	__clear_user(buf->f_fstr, sizeof(buf->f_fstr[i]));
+
+out_f:
+	fput(file);
+out:
+	return error;
+}
+
+asmlinkage int irix_getmountid(char *fname, unsigned long *midbuf)
+{
+	int err = 0;
+
+	printk("[%s:%d] irix_getmountid(%s, %p)\n",
+	       current->comm, current->pid, fname, midbuf);
+	if (!access_ok(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4)))
+		return -EFAULT;
+
+	/*
+	 * The idea with this system call is that when trying to determine
+	 * 'pwd' and it's a toss-up for some reason, userland can use the
+	 * fsid of the filesystem to try and make the right decision, but
+	 * we don't have this so for now. XXX
+	 */
+	err |= __put_user(0, &midbuf[0]);
+	err |= __put_user(0, &midbuf[1]);
+	err |= __put_user(0, &midbuf[2]);
+	err |= __put_user(0, &midbuf[3]);
+
+	return err;
+}
+
+asmlinkage int irix_nsproc(unsigned long entry, unsigned long mask,
+			   unsigned long arg, unsigned long sp, int slen)
+{
+	printk("[%s:%d] Wheee.. irix_nsproc(%08lx,%08lx,%08lx,%08lx,%d)\n",
+	       current->comm, current->pid, entry, mask, arg, sp, slen);
+
+	return -EINVAL;
+}
+
+#undef DEBUG_GETDENTS
+
+struct irix_dirent32 {
+	u32  d_ino;
+	u32  d_off;
+	unsigned short  d_reclen;
+	char d_name[1];
+};
+
+struct irix_dirent32_callback {
+	struct irix_dirent32 *current_dir;
+	struct irix_dirent32 *previous;
+	int count;
+	int error;
+};
+
+#define NAME_OFFSET32(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
+
+static int irix_filldir32(void *__buf, const char *name, int namlen,
+                          loff_t offset, ino_t ino, unsigned int d_type)
+{
+	struct irix_dirent32 *dirent;
+	struct irix_dirent32_callback *buf =
+		 (struct irix_dirent32_callback *)__buf;
+	unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1);
+
+#ifdef DEBUG_GETDENTS
+	printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]",
+	       reclen, namlen, buf->count);
+#endif
+	buf->error = -EINVAL;	/* only used if we fail.. */
+	if (reclen > buf->count)
+		return -EINVAL;
+	dirent = buf->previous;
+	if (dirent)
+		__put_user(offset, &dirent->d_off);
+	dirent = buf->current_dir;
+	buf->previous = dirent;
+	__put_user(ino, &dirent->d_ino);
+	__put_user(reclen, &dirent->d_reclen);
+	copy_to_user(dirent->d_name, name, namlen);
+	__put_user(0, &dirent->d_name[namlen]);
+	((char *) dirent) += reclen;
+	buf->current_dir = dirent;
+	buf->count -= reclen;
+
+	return 0;
+}
+
+asmlinkage int irix_ngetdents(unsigned int fd, void * dirent,
+	unsigned int count, int *eob)
+{
+	struct file *file;
+	struct irix_dirent32 *lastdirent;
+	struct irix_dirent32_callback buf;
+	int error;
+
+#ifdef DEBUG_GETDENTS
+	printk("[%s:%d] ngetdents(%d, %p, %d, %p) ", current->comm,
+	       current->pid, fd, dirent, count, eob);
+#endif
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.current_dir = (struct irix_dirent32 *) dirent;
+	buf.previous = NULL;
+	buf.count = count;
+	buf.error = 0;
+
+	error = vfs_readdir(file, irix_filldir32, &buf);
+	if (error < 0)
+		goto out_putf;
+
+	error = buf.error;
+	lastdirent = buf.previous;
+	if (lastdirent) {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = count - buf.count;
+	}
+
+	if (put_user(0, eob) < 0) {
+		error = -EFAULT;
+		goto out_putf;
+	}
+
+#ifdef DEBUG_GETDENTS
+	printk("eob=%d returning %d\n", *eob, count - buf.count);
+#endif
+	error = count - buf.count;
+
+out_putf:
+	fput(file);
+out:
+	return error;
+}
+
+struct irix_dirent64 {
+	u64            d_ino;
+	u64            d_off;
+	unsigned short d_reclen;
+	char           d_name[1];
+};
+
+struct irix_dirent64_callback {
+	struct irix_dirent64 *curr;
+	struct irix_dirent64 *previous;
+	int count;
+	int error;
+};
+
+#define NAME_OFFSET64(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
+
+static int irix_filldir64(void * __buf, const char * name, int namlen,
+			  loff_t offset, ino_t ino, unsigned int d_type)
+{
+	struct irix_dirent64 *dirent;
+	struct irix_dirent64_callback * buf =
+		(struct irix_dirent64_callback *) __buf;
+	unsigned short reclen = ROUND_UP64(NAME_OFFSET64(dirent) + namlen + 1);
+
+	buf->error = -EINVAL;	/* only used if we fail.. */
+	if (reclen > buf->count)
+		return -EINVAL;
+	dirent = buf->previous;
+	if (dirent)
+		__put_user(offset, &dirent->d_off);
+	dirent = buf->curr;
+	buf->previous = dirent;
+	__put_user(ino, &dirent->d_ino);
+	__put_user(reclen, &dirent->d_reclen);
+	__copy_to_user(dirent->d_name, name, namlen);
+	__put_user(0, &dirent->d_name[namlen]);
+	((char *) dirent) += reclen;
+	buf->curr = dirent;
+	buf->count -= reclen;
+
+	return 0;
+}
+
+asmlinkage int irix_getdents64(int fd, void *dirent, int cnt)
+{
+	struct file *file;
+	struct irix_dirent64 *lastdirent;
+	struct irix_dirent64_callback buf;
+	int error;
+
+#ifdef DEBUG_GETDENTS
+	printk("[%s:%d] getdents64(%d, %p, %d) ", current->comm,
+	       current->pid, fd, dirent, cnt);
+#endif
+	error = -EBADF;
+	if (!(file = fget(fd)))
+		goto out;
+
+	error = -EFAULT;
+	if (!access_ok(VERIFY_WRITE, dirent, cnt))
+		goto out_f;
+
+	error = -EINVAL;
+	if (cnt < (sizeof(struct irix_dirent64) + 255))
+		goto out_f;
+
+	buf.curr = (struct irix_dirent64 *) dirent;
+	buf.previous = NULL;
+	buf.count = cnt;
+	buf.error = 0;
+	error = vfs_readdir(file, irix_filldir64, &buf);
+	if (error < 0)
+		goto out_f;
+	lastdirent = buf.previous;
+	if (!lastdirent) {
+		error = buf.error;
+		goto out_f;
+	}
+	lastdirent->d_off = (u64) file->f_pos;
+#ifdef DEBUG_GETDENTS
+	printk("returning %d\n", cnt - buf.count);
+#endif
+	error = cnt - buf.count;
+
+out_f:
+	fput(file);
+out:
+	return error;
+}
+
+asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob)
+{
+	struct file *file;
+	struct irix_dirent64 *lastdirent;
+	struct irix_dirent64_callback buf;
+	int error;
+
+#ifdef DEBUG_GETDENTS
+	printk("[%s:%d] ngetdents64(%d, %p, %d) ", current->comm,
+	       current->pid, fd, dirent, cnt);
+#endif
+	error = -EBADF;
+	if (!(file = fget(fd)))
+		goto out;
+
+	error = -EFAULT;
+	if (!access_ok(VERIFY_WRITE, dirent, cnt) ||
+	    !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
+		goto out_f;
+
+	error = -EINVAL;
+	if (cnt < (sizeof(struct irix_dirent64) + 255))
+		goto out_f;
+
+	*eob = 0;
+	buf.curr = (struct irix_dirent64 *) dirent;
+	buf.previous = NULL;
+	buf.count = cnt;
+	buf.error = 0;
+	error = vfs_readdir(file, irix_filldir64, &buf);
+	if (error < 0)
+		goto out_f;
+	lastdirent = buf.previous;
+	if (!lastdirent) {
+		error = buf.error;
+		goto out_f;
+	}
+	lastdirent->d_off = (u64) file->f_pos;
+#ifdef DEBUG_GETDENTS
+	printk("eob=%d returning %d\n", *eob, cnt - buf.count);
+#endif
+	error = cnt - buf.count;
+
+out_f:
+	fput(file);
+out:
+	return error;
+}
+
+asmlinkage int irix_uadmin(unsigned long op, unsigned long func, unsigned long arg)
+{
+	int retval;
+
+	switch (op) {
+	case 1:
+		/* Reboot */
+		printk("[%s:%d] irix_uadmin: Wants to reboot...\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	case 2:
+		/* Shutdown */
+		printk("[%s:%d] irix_uadmin: Wants to shutdown...\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	case 4:
+		/* Remount-root */
+		printk("[%s:%d] irix_uadmin: Wants to remount root...\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	case 8:
+		/* Kill all tasks. */
+		printk("[%s:%d] irix_uadmin: Wants to kill all tasks...\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	case 256:
+		/* Set magic mushrooms... */
+		printk("[%s:%d] irix_uadmin: Wants to set magic mushroom[%d]...\n",
+		       current->comm, current->pid, (int) func);
+		retval = -EINVAL;
+		goto out;
+
+	default:
+		printk("[%s:%d] irix_uadmin: Unknown operation [%d]...\n",
+		       current->comm, current->pid, (int) op);
+		retval = -EINVAL;
+		goto out;
+	};
+
+out:
+	return retval;
+}
+
+asmlinkage int irix_utssys(char *inbuf, int arg, int type, char *outbuf)
+{
+	int retval;
+
+	switch(type) {
+	case 0:
+		/* uname() */
+		retval = irix_uname((struct iuname *)inbuf);
+		goto out;
+
+	case 2:
+		/* ustat() */
+		printk("[%s:%d] irix_utssys: Wants to do ustat()\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	case 3:
+		/* fusers() */
+		printk("[%s:%d] irix_utssys: Wants to do fusers()\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	default:
+		printk("[%s:%d] irix_utssys: Wants to do unknown type[%d]\n",
+		       current->comm, current->pid, (int) type);
+		retval = -EINVAL;
+		goto out;
+	}
+
+out:
+	return retval;
+}
+
+#undef DEBUG_FCNTL
+
+#define IRIX_F_ALLOCSP 10
+
+asmlinkage int irix_fcntl(int fd, int cmd, int arg)
+{
+	int retval;
+
+#ifdef DEBUG_FCNTL
+	printk("[%s:%d] irix_fcntl(%d, %d, %d) ", current->comm,
+	       current->pid, fd, cmd, arg);
+#endif
+	if (cmd == IRIX_F_ALLOCSP){
+		return 0;
+	}
+	retval = sys_fcntl(fd, cmd, arg);
+#ifdef DEBUG_FCNTL
+	printk("%d\n", retval);
+#endif
+	return retval;
+}
+
+asmlinkage int irix_ulimit(int cmd, int arg)
+{
+	int retval;
+
+	switch(cmd) {
+	case 1:
+		printk("[%s:%d] irix_ulimit: Wants to get file size limit.\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	case 2:
+		printk("[%s:%d] irix_ulimit: Wants to set file size limit.\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	case 3:
+		printk("[%s:%d] irix_ulimit: Wants to get brk limit.\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	case 4:
+#if 0
+		printk("[%s:%d] irix_ulimit: Wants to get fd limit.\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+#endif
+		retval = current->signal->rlim[RLIMIT_NOFILE].rlim_cur;
+		goto out;
+
+	case 5:
+		printk("[%s:%d] irix_ulimit: Wants to get txt offset.\n",
+		       current->comm, current->pid);
+		retval = -EINVAL;
+		goto out;
+
+	default:
+		printk("[%s:%d] irix_ulimit: Unknown command [%d].\n",
+		       current->comm, current->pid, cmd);
+		retval = -EINVAL;
+		goto out;
+	}
+out:
+	return retval;
+}
+
+asmlinkage int irix_unimp(struct pt_regs *regs)
+{
+	printk("irix_unimp [%s:%d] v0=%d v1=%d a0=%08lx a1=%08lx a2=%08lx "
+	       "a3=%08lx\n", current->comm, current->pid,
+	       (int) regs->regs[2], (int) regs->regs[3],
+	       regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
+
+	return -ENOSYS;
+}
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
new file mode 100644
index 0000000..648c822
--- /dev/null
+++ b/arch/mips/kernel/time.c
@@ -0,0 +1,755 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ * Copyright (c) 2003, 2004  Maciej W. Rozycki
+ *
+ * Common time service routines for MIPS machines. See
+ * Documentation/mips/time.README.
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/bootinfo.h>
+#include <asm/compiler.h>
+#include <asm/cpu.h>
+#include <asm/cpu-features.h>
+#include <asm/div64.h>
+#include <asm/sections.h>
+#include <asm/time.h>
+
+/*
+ * The integer part of the number of usecs per jiffy is taken from tick,
+ * but the fractional part is not recorded, so we calculate it using the
+ * initial value of HZ.  This aids systems where tick isn't really an
+ * integer (e.g. for HZ = 128).
+ */
+#define USECS_PER_JIFFY		TICK_SIZE
+#define USECS_PER_JIFFY_FRAC	((unsigned long)(u32)((1000000ULL << 32) / HZ))
+
+#define TICK_SIZE	(tick_nsec / 1000)
+
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+EXPORT_SYMBOL(jiffies_64);
+
+/*
+ * forward reference
+ */
+extern volatile unsigned long wall_jiffies;
+
+DEFINE_SPINLOCK(rtc_lock);
+
+/*
+ * By default we provide the null RTC ops
+ */
+static unsigned long null_rtc_get_time(void)
+{
+	return mktime(2000, 1, 1, 0, 0, 0);
+}
+
+static int null_rtc_set_time(unsigned long sec)
+{
+	return 0;
+}
+
+unsigned long (*rtc_get_time)(void) = null_rtc_get_time;
+int (*rtc_set_time)(unsigned long) = null_rtc_set_time;
+int (*rtc_set_mmss)(unsigned long);
+
+
+/* usecs per counter cycle, shifted to left by 32 bits */
+static unsigned int sll32_usecs_per_cycle;
+
+/* how many counter cycles in a jiffy */
+static unsigned long cycles_per_jiffy;
+
+/* Cycle counter value at the previous timer interrupt.. */
+static unsigned int timerhi, timerlo;
+
+/* expirelo is the count value for next CPU timer interrupt */
+static unsigned int expirelo;
+
+
+/*
+ * Null timer ack for systems not needing one (e.g. i8254).
+ */
+static void null_timer_ack(void) { /* nothing */ }
+
+/*
+ * Null high precision timer functions for systems lacking one.
+ */
+static unsigned int null_hpt_read(void)
+{
+	return 0;
+}
+
+static void null_hpt_init(unsigned int count) { /* nothing */ }
+
+
+/*
+ * Timer ack for an R4k-compatible timer of a known frequency.
+ */
+static void c0_timer_ack(void)
+{
+	unsigned int count;
+
+	/* Ack this timer interrupt and set the next one.  */
+	expirelo += cycles_per_jiffy;
+	write_c0_compare(expirelo);
+
+	/* Check to see if we have missed any timer interrupts.  */
+	count = read_c0_count();
+	if ((count - expirelo) < 0x7fffffff) {
+		/* missed_timer_count++; */
+		expirelo = count + cycles_per_jiffy;
+		write_c0_compare(expirelo);
+	}
+}
+
+/*
+ * High precision timer functions for a R4k-compatible timer.
+ */
+static unsigned int c0_hpt_read(void)
+{
+	return read_c0_count();
+}
+
+/* For use solely as a high precision timer.  */
+static void c0_hpt_init(unsigned int count)
+{
+	write_c0_count(read_c0_count() - count);
+}
+
+/* For use both as a high precision timer and an interrupt source.  */
+static void c0_hpt_timer_init(unsigned int count)
+{
+	count = read_c0_count() - count;
+	expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy;
+	write_c0_count(expirelo - cycles_per_jiffy);
+	write_c0_compare(expirelo);
+	write_c0_count(count);
+}
+
+int (*mips_timer_state)(void);
+void (*mips_timer_ack)(void);
+unsigned int (*mips_hpt_read)(void);
+void (*mips_hpt_init)(unsigned int);
+
+
+/*
+ * This version of gettimeofday has microsecond resolution and better than
+ * microsecond precision on fast machines with cycle counter.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long seq;
+	unsigned long lost;
+	unsigned long usec, sec;
+	unsigned long max_ntp_tick = tick_usec - tickadj;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+
+		usec = do_gettimeoffset();
+
+		lost = jiffies - wall_jiffies;
+
+		/*
+		 * If time_adjust is negative then NTP is slowing the clock
+		 * so make sure not to go into next possible interval.
+		 * Better to lose some accuracy than have time go backwards..
+		 */
+		if (unlikely(time_adjust < 0)) {
+			usec = min(usec, max_ntp_tick);
+
+			if (lost)
+				usec += lost * max_ntp_tick;
+		} else if (unlikely(lost))
+			usec += lost * tick_usec;
+
+		sec = xtime.tv_sec;
+		usec += (xtime.tv_nsec / 1000);
+
+	} while (read_seqretry(&xtime_lock, seq));
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
+int do_settimeofday(struct timespec *tv)
+{
+	time_t wtm_sec, sec = tv->tv_sec;
+	long wtm_nsec, nsec = tv->tv_nsec;
+
+	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+		return -EINVAL;
+
+	write_seqlock_irq(&xtime_lock);
+
+	/*
+	 * This is revolting.  We need to set "xtime" correctly.  However,
+	 * the value in this location is the value at the most recent update
+	 * of wall time.  Discover what correction gettimeofday() would have
+	 * made, and then undo it!
+	 */
+	nsec -= do_gettimeoffset() * NSEC_PER_USEC;
+	nsec -= (jiffies - wall_jiffies) * tick_nsec;
+
+	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+	set_normalized_timespec(&xtime, sec, nsec);
+	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+	time_adjust = 0;			/* stop active adjtime() */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+
+	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
+	return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+/*
+ * Gettimeoffset routines.  These routines returns the time duration
+ * since last timer interrupt in usecs.
+ *
+ * If the exact CPU counter frequency is known, use fixed_rate_gettimeoffset.
+ * Otherwise use calibrate_gettimeoffset()
+ *
+ * If the CPU does not have the counter register, you can either supply
+ * your own gettimeoffset() routine, or use null_gettimeoffset(), which
+ * gives the same resolution as HZ.
+ */
+
+static unsigned long null_gettimeoffset(void)
+{
+	return 0;
+}
+
+
+/* The function pointer to one of the gettimeoffset funcs.  */
+unsigned long (*do_gettimeoffset)(void) = null_gettimeoffset;
+
+
+static unsigned long fixed_rate_gettimeoffset(void)
+{
+	u32 count;
+	unsigned long res;
+
+	/* Get last timer tick in absolute kernel time */
+	count = mips_hpt_read();
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	count -= timerlo;
+
+	__asm__("multu	%1,%2"
+		: "=h" (res)
+		: "r" (count), "r" (sll32_usecs_per_cycle)
+		: "lo", GCC_REG_ACCUM);
+
+	/*
+	 * Due to possible jiffies inconsistencies, we need to check
+	 * the result so that we'll get a timer that is monotonic.
+	 */
+	if (res >= USECS_PER_JIFFY)
+		res = USECS_PER_JIFFY - 1;
+
+	return res;
+}
+
+
+/*
+ * Cached "1/(clocks per usec) * 2^32" value.
+ * It has to be recalculated once each jiffy.
+ */
+static unsigned long cached_quotient;
+
+/* Last jiffy when calibrate_divXX_gettimeoffset() was called. */
+static unsigned long last_jiffies;
+
+/*
+ * This is moved from dec/time.c:do_ioasic_gettimeoffset() by Maciej.
+ */
+static unsigned long calibrate_div32_gettimeoffset(void)
+{
+	u32 count;
+	unsigned long res, tmp;
+	unsigned long quotient;
+
+	tmp = jiffies;
+
+	quotient = cached_quotient;
+
+	if (last_jiffies != tmp) {
+		last_jiffies = tmp;
+		if (last_jiffies != 0) {
+			unsigned long r0;
+			do_div64_32(r0, timerhi, timerlo, tmp);
+			do_div64_32(quotient, USECS_PER_JIFFY,
+				    USECS_PER_JIFFY_FRAC, r0);
+			cached_quotient = quotient;
+		}
+	}
+
+	/* Get last timer tick in absolute kernel time */
+	count = mips_hpt_read();
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	count -= timerlo;
+
+	__asm__("multu  %1,%2"
+		: "=h" (res)
+		: "r" (count), "r" (quotient)
+		: "lo", GCC_REG_ACCUM);
+
+	/*
+	 * Due to possible jiffies inconsistencies, we need to check
+	 * the result so that we'll get a timer that is monotonic.
+	 */
+	if (res >= USECS_PER_JIFFY)
+		res = USECS_PER_JIFFY - 1;
+
+	return res;
+}
+
+static unsigned long calibrate_div64_gettimeoffset(void)
+{
+	u32 count;
+	unsigned long res, tmp;
+	unsigned long quotient;
+
+	tmp = jiffies;
+
+	quotient = cached_quotient;
+
+	if (last_jiffies != tmp) {
+		last_jiffies = tmp;
+		if (last_jiffies) {
+			unsigned long r0;
+			__asm__(".set	push\n\t"
+				".set	mips3\n\t"
+				"lwu	%0,%3\n\t"
+				"dsll32	%1,%2,0\n\t"
+				"or	%1,%1,%0\n\t"
+				"ddivu	$0,%1,%4\n\t"
+				"mflo	%1\n\t"
+				"dsll32	%0,%5,0\n\t"
+				"or	%0,%0,%6\n\t"
+				"ddivu	$0,%0,%1\n\t"
+				"mflo	%0\n\t"
+				".set	pop"
+				: "=&r" (quotient), "=&r" (r0)
+				: "r" (timerhi), "m" (timerlo),
+				  "r" (tmp), "r" (USECS_PER_JIFFY),
+				  "r" (USECS_PER_JIFFY_FRAC)
+				: "hi", "lo", GCC_REG_ACCUM);
+			cached_quotient = quotient;
+		}
+	}
+
+	/* Get last timer tick in absolute kernel time */
+	count = mips_hpt_read();
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	count -= timerlo;
+
+	__asm__("multu	%1,%2"
+		: "=h" (res)
+		: "r" (count), "r" (quotient)
+		: "lo", GCC_REG_ACCUM);
+
+	/*
+	 * Due to possible jiffies inconsistencies, we need to check
+	 * the result so that we'll get a timer that is monotonic.
+	 */
+	if (res >= USECS_PER_JIFFY)
+		res = USECS_PER_JIFFY - 1;
+
+	return res;
+}
+
+
+/* last time when xtime and rtc are sync'ed up */
+static long last_rtc_update;
+
+/*
+ * local_timer_interrupt() does profiling and process accounting
+ * on a per-CPU basis.
+ *
+ * In UP mode, it is invoked from the (global) timer_interrupt.
+ *
+ * In SMP mode, it might invoked by per-CPU timer interrupt, or
+ * a broadcasted inter-processor interrupt which itself is triggered
+ * by the global timer interrupt.
+ */
+void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (current->pid)
+		profile_tick(CPU_PROFILING, regs);
+	update_process_times(user_mode(regs));
+}
+
+/*
+ * High-level timer interrupt service routines.  This function
+ * is set as irqaction->handler and is invoked through do_IRQ.
+ */
+irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long j;
+	unsigned int count;
+
+	count = mips_hpt_read();
+	mips_timer_ack();
+
+	/* Update timerhi/timerlo for intra-jiffy calibration. */
+	timerhi += count < timerlo;			/* Wrap around */
+	timerlo = count;
+
+	/*
+	 * call the generic timer interrupt handling
+	 */
+	do_timer(regs);
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes. rtc_set_time() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	write_seqlock(&xtime_lock);
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
+		if (rtc_set_mmss(xtime.tv_sec) == 0) {
+			last_rtc_update = xtime.tv_sec;
+		} else {
+			/* do it again in 60 s */
+			last_rtc_update = xtime.tv_sec - 600;
+		}
+	}
+	write_sequnlock(&xtime_lock);
+
+	/*
+	 * If jiffies has overflown in this timer_interrupt, we must
+	 * update the timer[hi]/[lo] to make fast gettimeoffset funcs
+	 * quotient calc still valid. -arca
+	 *
+	 * The first timer interrupt comes late as interrupts are
+	 * enabled long after timers are initialized.  Therefore the
+	 * high precision timer is fast, leading to wrong gettimeoffset()
+	 * calculations.  We deal with it by setting it based on the
+	 * number of its ticks between the second and the third interrupt.
+	 * That is still somewhat imprecise, but it's a good estimate.
+	 * --macro
+	 */
+	j = jiffies;
+	if (j < 4) {
+		static unsigned int prev_count;
+		static int hpt_initialized;
+
+		switch (j) {
+		case 0:
+			timerhi = timerlo = 0;
+			mips_hpt_init(count);
+			break;
+		case 2:
+			prev_count = count;
+			break;
+		case 3:
+			if (!hpt_initialized) {
+				unsigned int c3 = 3 * (count - prev_count);
+
+				timerhi = 0;
+				timerlo = c3;
+				mips_hpt_init(count - c3);
+				hpt_initialized = 1;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * In UP mode, we call local_timer_interrupt() to do profiling
+	 * and process accouting.
+	 *
+	 * In SMP mode, local_timer_interrupt() is invoked by appropriate
+	 * low-level local timer interrupt handler.
+	 */
+	local_timer_interrupt(irq, dev_id, regs);
+
+	return IRQ_HANDLED;
+}
+
+asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs)
+{
+	irq_enter();
+	kstat_this_cpu.irqs[irq]++;
+
+	/* we keep interrupt disabled all the time */
+	timer_interrupt(irq, NULL, regs);
+
+	irq_exit();
+}
+
+asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs)
+{
+	irq_enter();
+	if (smp_processor_id() != 0)
+		kstat_this_cpu.irqs[irq]++;
+
+	/* we keep interrupt disabled all the time */
+	local_timer_interrupt(irq, NULL, regs);
+
+	irq_exit();
+}
+
+/*
+ * time_init() - it does the following things.
+ *
+ * 1) board_time_init() -
+ * 	a) (optional) set up RTC routines,
+ *      b) (optional) calibrate and set the mips_hpt_frequency
+ *	    (only needed if you intended to use fixed_rate_gettimeoffset
+ *	     or use cpu counter as timer interrupt source)
+ * 2) setup xtime based on rtc_get_time().
+ * 3) choose a appropriate gettimeoffset routine.
+ * 4) calculate a couple of cached variables for later usage
+ * 5) board_timer_setup() -
+ *	a) (optional) over-write any choices made above by time_init().
+ *	b) machine specific code should setup the timer irqaction.
+ *	c) enable the timer interrupt
+ */
+
+void (*board_time_init)(void);
+void (*board_timer_setup)(struct irqaction *irq);
+
+unsigned int mips_hpt_frequency;
+
+static struct irqaction timer_irqaction = {
+	.handler = timer_interrupt,
+	.flags = SA_INTERRUPT,
+	.name = "timer",
+};
+
+static unsigned int __init calibrate_hpt(void)
+{
+	u64 frequency;
+	u32 hpt_start, hpt_end, hpt_count, hz;
+
+	const int loops = HZ / 10;
+	int log_2_loops = 0;
+	int i;
+
+	/*
+	 * We want to calibrate for 0.1s, but to avoid a 64-bit
+	 * division we round the number of loops up to the nearest
+	 * power of 2.
+	 */
+	while (loops > 1 << log_2_loops)
+		log_2_loops++;
+	i = 1 << log_2_loops;
+
+	/*
+	 * Wait for a rising edge of the timer interrupt.
+	 */
+	while (mips_timer_state());
+	while (!mips_timer_state());
+
+	/*
+	 * Now see how many high precision timer ticks happen
+	 * during the calculated number of periods between timer
+	 * interrupts.
+	 */
+	hpt_start = mips_hpt_read();
+	do {
+		while (mips_timer_state());
+		while (!mips_timer_state());
+	} while (--i);
+	hpt_end = mips_hpt_read();
+
+	hpt_count = hpt_end - hpt_start;
+	hz = HZ;
+	frequency = (u64)hpt_count * (u64)hz;
+
+	return frequency >> log_2_loops;
+}
+
+void __init time_init(void)
+{
+	if (board_time_init)
+		board_time_init();
+
+	if (!rtc_set_mmss)
+		rtc_set_mmss = rtc_set_time;
+
+	xtime.tv_sec = rtc_get_time();
+	xtime.tv_nsec = 0;
+
+	set_normalized_timespec(&wall_to_monotonic,
+	                        -xtime.tv_sec, -xtime.tv_nsec);
+
+	/* Choose appropriate high precision timer routines.  */
+	if (!cpu_has_counter && !mips_hpt_read) {
+		/* No high precision timer -- sorry.  */
+		mips_hpt_read = null_hpt_read;
+		mips_hpt_init = null_hpt_init;
+	} else if (!mips_hpt_frequency && !mips_timer_state) {
+		/* A high precision timer of unknown frequency.  */
+		if (!mips_hpt_read) {
+			/* No external high precision timer -- use R4k.  */
+			mips_hpt_read = c0_hpt_read;
+			mips_hpt_init = c0_hpt_init;
+		}
+
+		if ((current_cpu_data.isa_level == MIPS_CPU_ISA_M32) ||
+			 (current_cpu_data.isa_level == MIPS_CPU_ISA_I) ||
+			 (current_cpu_data.isa_level == MIPS_CPU_ISA_II))
+			/*
+			 * We need to calibrate the counter but we don't have
+			 * 64-bit division.
+			 */
+			do_gettimeoffset = calibrate_div32_gettimeoffset;
+		else
+			/*
+			 * We need to calibrate the counter but we *do* have
+			 * 64-bit division.
+			 */
+			do_gettimeoffset = calibrate_div64_gettimeoffset;
+	} else {
+		/* We know counter frequency.  Or we can get it.  */
+		if (!mips_hpt_read) {
+			/* No external high precision timer -- use R4k.  */
+			mips_hpt_read = c0_hpt_read;
+
+			if (mips_timer_state)
+				mips_hpt_init = c0_hpt_init;
+			else {
+				/* No external timer interrupt -- use R4k.  */
+				mips_hpt_init = c0_hpt_timer_init;
+				mips_timer_ack = c0_timer_ack;
+			}
+		}
+		if (!mips_hpt_frequency)
+			mips_hpt_frequency = calibrate_hpt();
+
+		do_gettimeoffset = fixed_rate_gettimeoffset;
+
+		/* Calculate cache parameters.  */
+		cycles_per_jiffy = (mips_hpt_frequency + HZ / 2) / HZ;
+
+		/* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq  */
+		do_div64_32(sll32_usecs_per_cycle,
+			    1000000, mips_hpt_frequency / 2,
+			    mips_hpt_frequency);
+
+		/* Report the high precision timer rate for a reference.  */
+		printk("Using %u.%03u MHz high precision timer.\n",
+		       ((mips_hpt_frequency + 500) / 1000) / 1000,
+		       ((mips_hpt_frequency + 500) / 1000) % 1000);
+	}
+
+	if (!mips_timer_ack)
+		/* No timer interrupt ack (e.g. i8254).  */
+		mips_timer_ack = null_timer_ack;
+
+	/* This sets up the high precision timer for the first interrupt.  */
+	mips_hpt_init(mips_hpt_read());
+
+	/*
+	 * Call board specific timer interrupt setup.
+	 *
+	 * this pointer must be setup in machine setup routine.
+	 *
+	 * Even if a machine chooses to use a low-level timer interrupt,
+	 * it still needs to setup the timer_irqaction.
+	 * In that case, it might be better to set timer_irqaction.handler
+	 * to be NULL function so that we are sure the high-level code
+	 * is not invoked accidentally.
+	 */
+	board_timer_setup(&timer_irqaction);
+}
+
+#define FEBRUARY		2
+#define STARTOFTIME		1970
+#define SECDAY			86400L
+#define SECYR			(SECDAY * 365)
+#define leapyear(y)		((!((y) % 4) && ((y) % 100)) || !((y) % 400))
+#define days_in_year(y)		(leapyear(y) ? 366 : 365)
+#define days_in_month(m)	(month_days[(m) - 1])
+
+static int month_days[12] = {
+	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+void to_tm(unsigned long tim, struct rtc_time *tm)
+{
+	long hms, day, gday;
+	int i;
+
+	gday = day = tim / SECDAY;
+	hms = tim % SECDAY;
+
+	/* Hours, minutes, seconds are easy */
+	tm->tm_hour = hms / 3600;
+	tm->tm_min = (hms % 3600) / 60;
+	tm->tm_sec = (hms % 3600) % 60;
+
+	/* Number of years in days */
+	for (i = STARTOFTIME; day >= days_in_year(i); i++)
+		day -= days_in_year(i);
+	tm->tm_year = i;
+
+	/* Number of months in days left */
+	if (leapyear(tm->tm_year))
+		days_in_month(FEBRUARY) = 29;
+	for (i = 1; day >= days_in_month(i); i++)
+		day -= days_in_month(i);
+	days_in_month(FEBRUARY) = 28;
+	tm->tm_mon = i - 1;		/* tm_mon starts from 0 to 11 */
+
+	/* Days are what is left over (+1) from all that. */
+	tm->tm_mday = day + 1;
+
+	/*
+	 * Determine the day of week
+	 */
+	tm->tm_wday = (gday + 4) % 7;	/* 1970/1/1 was Thursday */
+}
+
+EXPORT_SYMBOL(rtc_lock);
+EXPORT_SYMBOL(to_tm);
+EXPORT_SYMBOL(rtc_set_time);
+EXPORT_SYMBOL(rtc_get_time);
+
+unsigned long long sched_clock(void)
+{
+	return (unsigned long long)jiffies*(1000000000/HZ);
+}
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
new file mode 100644
index 0000000..56c36e4
--- /dev/null
+++ b/arch/mips/kernel/traps.c
@@ -0,0 +1,1062 @@
+/*
+ * 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) 1994 - 1999, 2000, 01 Ralf Baechle
+ * Copyright (C) 1995, 1996 Paul M. Antoine
+ * Copyright (C) 1998 Ulf Carlsson
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000, 01 MIPS Technologies, Inc.
+ * Copyright (C) 2002, 2003, 2004  Maciej W. Rozycki
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/kallsyms.h>
+
+#include <asm/bootinfo.h>
+#include <asm/branch.h>
+#include <asm/break.h>
+#include <asm/cpu.h>
+#include <asm/fpu.h>
+#include <asm/module.h>
+#include <asm/pgtable.h>
+#include <asm/ptrace.h>
+#include <asm/sections.h>
+#include <asm/system.h>
+#include <asm/tlbdebug.h>
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+#include <asm/mmu_context.h>
+#include <asm/watch.h>
+#include <asm/types.h>
+
+extern asmlinkage void handle_tlbm(void);
+extern asmlinkage void handle_tlbl(void);
+extern asmlinkage void handle_tlbs(void);
+extern asmlinkage void handle_adel(void);
+extern asmlinkage void handle_ades(void);
+extern asmlinkage void handle_ibe(void);
+extern asmlinkage void handle_dbe(void);
+extern asmlinkage void handle_sys(void);
+extern asmlinkage void handle_bp(void);
+extern asmlinkage void handle_ri(void);
+extern asmlinkage void handle_cpu(void);
+extern asmlinkage void handle_ov(void);
+extern asmlinkage void handle_tr(void);
+extern asmlinkage void handle_fpe(void);
+extern asmlinkage void handle_mdmx(void);
+extern asmlinkage void handle_watch(void);
+extern asmlinkage void handle_mcheck(void);
+extern asmlinkage void handle_reserved(void);
+
+extern int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp,
+	struct mips_fpu_soft_struct *ctx);
+
+void (*board_be_init)(void);
+int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
+
+/*
+ * These constant is for searching for possible module text segments.
+ * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
+ */
+#define MODULE_RANGE (8*1024*1024)
+
+/*
+ * This routine abuses get_user()/put_user() to reference pointers
+ * with at least a bit of error checking ...
+ */
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+	const int field = 2 * sizeof(unsigned long);
+	long stackdata;
+	int i;
+
+	if (!sp) {
+		if (task && task != current)
+			sp = (unsigned long *) task->thread.reg29;
+		else
+			sp = (unsigned long *) &sp;
+	}
+
+	printk("Stack :");
+	i = 0;
+	while ((unsigned long) sp & (PAGE_SIZE - 1)) {
+		if (i && ((i % (64 / field)) == 0))
+			printk("\n       ");
+		if (i > 39) {
+			printk(" ...");
+			break;
+		}
+
+		if (__get_user(stackdata, sp++)) {
+			printk(" (Bad stack address)");
+			break;
+		}
+
+		printk(" %0*lx", field, stackdata);
+		i++;
+	}
+	printk("\n");
+}
+
+void show_trace(struct task_struct *task, unsigned long *stack)
+{
+	const int field = 2 * sizeof(unsigned long);
+	unsigned long addr;
+
+	if (!stack) {
+		if (task && task != current)
+			stack = (unsigned long *) task->thread.reg29;
+		else
+			stack = (unsigned long *) &stack;
+	}
+
+	printk("Call Trace:");
+#ifdef CONFIG_KALLSYMS
+	printk("\n");
+#endif
+	while (!kstack_end(stack)) {
+		addr = *stack++;
+		if (__kernel_text_address(addr)) {
+			printk(" [<%0*lx>] ", field, addr);
+			print_symbol("%s\n", addr);
+		}
+	}
+	printk("\n");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+	unsigned long stack;
+
+	show_trace(current, &stack);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void show_code(unsigned int *pc)
+{
+	long i;
+
+	printk("\nCode:");
+
+	for(i = -3 ; i < 6 ; i++) {
+		unsigned int insn;
+		if (__get_user(insn, pc + i)) {
+			printk(" (Bad address in epc)\n");
+			break;
+		}
+		printk("%c%08x%c", (i?' ':'<'), insn, (i?' ':'>'));
+	}
+}
+
+void show_regs(struct pt_regs *regs)
+{
+	const int field = 2 * sizeof(unsigned long);
+	unsigned int cause = regs->cp0_cause;
+	int i;
+
+	printk("Cpu %d\n", smp_processor_id());
+
+	/*
+	 * Saved main processor registers
+	 */
+	for (i = 0; i < 32; ) {
+		if ((i % 4) == 0)
+			printk("$%2d   :", i);
+		if (i == 0)
+			printk(" %0*lx", field, 0UL);
+		else if (i == 26 || i == 27)
+			printk(" %*s", field, "");
+		else
+			printk(" %0*lx", field, regs->regs[i]);
+
+		i++;
+		if ((i % 4) == 0)
+			printk("\n");
+	}
+
+	printk("Hi    : %0*lx\n", field, regs->hi);
+	printk("Lo    : %0*lx\n", field, regs->lo);
+
+	/*
+	 * Saved cp0 registers
+	 */
+	printk("epc   : %0*lx ", field, regs->cp0_epc);
+	print_symbol("%s ", regs->cp0_epc);
+	printk("    %s\n", print_tainted());
+	printk("ra    : %0*lx ", field, regs->regs[31]);
+	print_symbol("%s\n", regs->regs[31]);
+
+	printk("Status: %08x    ", (uint32_t) regs->cp0_status);
+
+	if (regs->cp0_status & ST0_KX)
+		printk("KX ");
+	if (regs->cp0_status & ST0_SX)
+		printk("SX ");
+	if (regs->cp0_status & ST0_UX)
+		printk("UX ");
+	switch (regs->cp0_status & ST0_KSU) {
+	case KSU_USER:
+		printk("USER ");
+		break;
+	case KSU_SUPERVISOR:
+		printk("SUPERVISOR ");
+		break;
+	case KSU_KERNEL:
+		printk("KERNEL ");
+		break;
+	default:
+		printk("BAD_MODE ");
+		break;
+	}
+	if (regs->cp0_status & ST0_ERL)
+		printk("ERL ");
+	if (regs->cp0_status & ST0_EXL)
+		printk("EXL ");
+	if (regs->cp0_status & ST0_IE)
+		printk("IE ");
+	printk("\n");
+
+	printk("Cause : %08x\n", cause);
+
+	cause = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
+	if (1 <= cause && cause <= 5)
+		printk("BadVA : %0*lx\n", field, regs->cp0_badvaddr);
+
+	printk("PrId  : %08x\n", read_c0_prid());
+}
+
+void show_registers(struct pt_regs *regs)
+{
+	show_regs(regs);
+	print_modules();
+	printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
+	        current->comm, current->pid, current_thread_info(), current);
+	show_stack(current, (long *) regs->regs[29]);
+	show_trace(current, (long *) regs->regs[29]);
+	show_code((unsigned int *) regs->cp0_epc);
+	printk("\n");
+}
+
+static DEFINE_SPINLOCK(die_lock);
+
+NORET_TYPE void __die(const char * str, struct pt_regs * regs,
+	const char * file, const char * func, unsigned long line)
+{
+	static int die_counter;
+
+	console_verbose();
+	spin_lock_irq(&die_lock);
+	printk("%s", str);
+	if (file && func)
+		printk(" in %s:%s, line %ld", file, func, line);
+	printk("[#%d]:\n", ++die_counter);
+	show_registers(regs);
+	spin_unlock_irq(&die_lock);
+	do_exit(SIGSEGV);
+}
+
+void __die_if_kernel(const char * str, struct pt_regs * regs,
+		     const char * file, const char * func, unsigned long line)
+{
+	if (!user_mode(regs))
+		__die(str, regs, file, func, line);
+}
+
+extern const struct exception_table_entry __start___dbe_table[];
+extern const struct exception_table_entry __stop___dbe_table[];
+
+void __declare_dbe_table(void)
+{
+	__asm__ __volatile__(
+	".section\t__dbe_table,\"a\"\n\t"
+	".previous"
+	);
+}
+
+/* Given an address, look for it in the exception tables. */
+static const struct exception_table_entry *search_dbe_tables(unsigned long addr)
+{
+	const struct exception_table_entry *e;
+
+	e = search_extable(__start___dbe_table, __stop___dbe_table - 1, addr);
+	if (!e)
+		e = search_module_dbetables(addr);
+	return e;
+}
+
+asmlinkage void do_be(struct pt_regs *regs)
+{
+	const int field = 2 * sizeof(unsigned long);
+	const struct exception_table_entry *fixup = NULL;
+	int data = regs->cp0_cause & 4;
+	int action = MIPS_BE_FATAL;
+
+	/* XXX For now.  Fixme, this searches the wrong table ...  */
+	if (data && !user_mode(regs))
+		fixup = search_dbe_tables(exception_epc(regs));
+
+	if (fixup)
+		action = MIPS_BE_FIXUP;
+
+	if (board_be_handler)
+		action = board_be_handler(regs, fixup != 0);
+
+	switch (action) {
+	case MIPS_BE_DISCARD:
+		return;
+	case MIPS_BE_FIXUP:
+		if (fixup) {
+			regs->cp0_epc = fixup->nextinsn;
+			return;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * Assume it would be too dangerous to continue ...
+	 */
+	printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n",
+	       data ? "Data" : "Instruction",
+	       field, regs->cp0_epc, field, regs->regs[31]);
+	die_if_kernel("Oops", regs);
+	force_sig(SIGBUS, current);
+}
+
+static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode)
+{
+	unsigned int *epc;
+
+	epc = (unsigned int *) regs->cp0_epc +
+	      ((regs->cp0_cause & CAUSEF_BD) != 0);
+	if (!get_user(*opcode, epc))
+		return 0;
+
+	force_sig(SIGSEGV, current);
+	return 1;
+}
+
+/*
+ * ll/sc emulation
+ */
+
+#define OPCODE 0xfc000000
+#define BASE   0x03e00000
+#define RT     0x001f0000
+#define OFFSET 0x0000ffff
+#define LL     0xc0000000
+#define SC     0xe0000000
+
+/*
+ * The ll_bit is cleared by r*_switch.S
+ */
+
+unsigned long ll_bit;
+
+static struct task_struct *ll_task = NULL;
+
+static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode)
+{
+	unsigned long value, *vaddr;
+	long offset;
+	int signal = 0;
+
+	/*
+	 * analyse the ll instruction that just caused a ri exception
+	 * and put the referenced address to addr.
+	 */
+
+	/* sign extend offset */
+	offset = opcode & OFFSET;
+	offset <<= 16;
+	offset >>= 16;
+
+	vaddr = (unsigned long *)((long)(regs->regs[(opcode & BASE) >> 21]) + offset);
+
+	if ((unsigned long)vaddr & 3) {
+		signal = SIGBUS;
+		goto sig;
+	}
+	if (get_user(value, vaddr)) {
+		signal = SIGSEGV;
+		goto sig;
+	}
+
+	preempt_disable();
+
+	if (ll_task == NULL || ll_task == current) {
+		ll_bit = 1;
+	} else {
+		ll_bit = 0;
+	}
+	ll_task = current;
+
+	preempt_enable();
+
+	regs->regs[(opcode & RT) >> 16] = value;
+
+	compute_return_epc(regs);
+	return;
+
+sig:
+	force_sig(signal, current);
+}
+
+static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode)
+{
+	unsigned long *vaddr, reg;
+	long offset;
+	int signal = 0;
+
+	/*
+	 * analyse the sc instruction that just caused a ri exception
+	 * and put the referenced address to addr.
+	 */
+
+	/* sign extend offset */
+	offset = opcode & OFFSET;
+	offset <<= 16;
+	offset >>= 16;
+
+	vaddr = (unsigned long *)((long)(regs->regs[(opcode & BASE) >> 21]) + offset);
+	reg = (opcode & RT) >> 16;
+
+	if ((unsigned long)vaddr & 3) {
+		signal = SIGBUS;
+		goto sig;
+	}
+
+	preempt_disable();
+
+	if (ll_bit == 0 || ll_task != current) {
+		regs->regs[reg] = 0;
+		preempt_enable();
+		compute_return_epc(regs);
+		return;
+	}
+
+	preempt_enable();
+
+	if (put_user(regs->regs[reg], vaddr)) {
+		signal = SIGSEGV;
+		goto sig;
+	}
+
+	regs->regs[reg] = 1;
+
+	compute_return_epc(regs);
+	return;
+
+sig:
+	force_sig(signal, current);
+}
+
+/*
+ * ll uses the opcode of lwc0 and sc uses the opcode of swc0.  That is both
+ * opcodes are supposed to result in coprocessor unusable exceptions if
+ * executed on ll/sc-less processors.  That's the theory.  In practice a
+ * few processors such as NEC's VR4100 throw reserved instruction exceptions
+ * instead, so we're doing the emulation thing in both exception handlers.
+ */
+static inline int simulate_llsc(struct pt_regs *regs)
+{
+	unsigned int opcode;
+
+	if (unlikely(get_insn_opcode(regs, &opcode)))
+		return -EFAULT;
+
+	if ((opcode & OPCODE) == LL) {
+		simulate_ll(regs, opcode);
+		return 0;
+	}
+	if ((opcode & OPCODE) == SC) {
+		simulate_sc(regs, opcode);
+		return 0;
+	}
+
+	return -EFAULT;			/* Strange things going on ... */
+}
+
+asmlinkage void do_ov(struct pt_regs *regs)
+{
+	siginfo_t info;
+
+	info.si_code = FPE_INTOVF;
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_addr = (void *)regs->cp0_epc;
+	force_sig_info(SIGFPE, &info, current);
+}
+
+/*
+ * XXX Delayed fp exceptions when doing a lazy ctx switch XXX
+ */
+asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
+{
+	if (fcr31 & FPU_CSR_UNI_X) {
+		int sig;
+
+		preempt_disable();
+
+		/*
+	 	 * Unimplemented operation exception.  If we've got the full
+		 * software emulator on-board, let's use it...
+		 *
+		 * Force FPU to dump state into task/thread context.  We're
+		 * moving a lot of data here for what is probably a single
+		 * instruction, but the alternative is to pre-decode the FP
+		 * register operands before invoking the emulator, which seems
+		 * a bit extreme for what should be an infrequent event.
+		 */
+		save_fp(current);
+
+		/* Run the emulator */
+		sig = fpu_emulator_cop1Handler (0, regs,
+			&current->thread.fpu.soft);
+
+		/*
+		 * We can't allow the emulated instruction to leave any of
+		 * the cause bit set in $fcr31.
+		 */
+		current->thread.fpu.soft.fcr31 &= ~FPU_CSR_ALL_X;
+
+		/* Restore the hardware register state */
+		restore_fp(current);
+
+		preempt_enable();
+
+		/* If something went wrong, signal */
+		if (sig)
+			force_sig(sig, current);
+
+		return;
+	}
+
+	force_sig(SIGFPE, current);
+}
+
+asmlinkage void do_bp(struct pt_regs *regs)
+{
+	unsigned int opcode, bcode;
+	siginfo_t info;
+
+	die_if_kernel("Break instruction in kernel code", regs);
+
+	if (get_insn_opcode(regs, &opcode))
+		return;
+
+	/*
+	 * There is the ancient bug in the MIPS assemblers that the break
+	 * code starts left to bit 16 instead to bit 6 in the opcode.
+	 * Gas is bug-compatible, but not always, grrr...
+	 * We handle both cases with a simple heuristics.  --macro
+	 */
+	bcode = ((opcode >> 6) & ((1 << 20) - 1));
+	if (bcode < (1 << 10))
+		bcode <<= 10;
+
+	/*
+	 * (A short test says that IRIX 5.3 sends SIGTRAP for all break
+	 * insns, even for break codes that indicate arithmetic failures.
+	 * Weird ...)
+	 * But should we continue the brokenness???  --macro
+	 */
+	switch (bcode) {
+	case BRK_OVERFLOW << 10:
+	case BRK_DIVZERO << 10:
+		if (bcode == (BRK_DIVZERO << 10))
+			info.si_code = FPE_INTDIV;
+		else
+			info.si_code = FPE_INTOVF;
+		info.si_signo = SIGFPE;
+		info.si_errno = 0;
+		info.si_addr = (void *)regs->cp0_epc;
+		force_sig_info(SIGFPE, &info, current);
+		break;
+	default:
+		force_sig(SIGTRAP, current);
+	}
+}
+
+asmlinkage void do_tr(struct pt_regs *regs)
+{
+	unsigned int opcode, tcode = 0;
+	siginfo_t info;
+
+	die_if_kernel("Trap instruction in kernel code", regs);
+
+	if (get_insn_opcode(regs, &opcode))
+		return;
+
+	/* Immediate versions don't provide a code.  */
+	if (!(opcode & OPCODE))
+		tcode = ((opcode >> 6) & ((1 << 10) - 1));
+
+	/*
+	 * (A short test says that IRIX 5.3 sends SIGTRAP for all trap
+	 * insns, even for trap codes that indicate arithmetic failures.
+	 * Weird ...)
+	 * But should we continue the brokenness???  --macro
+	 */
+	switch (tcode) {
+	case BRK_OVERFLOW:
+	case BRK_DIVZERO:
+		if (tcode == BRK_DIVZERO)
+			info.si_code = FPE_INTDIV;
+		else
+			info.si_code = FPE_INTOVF;
+		info.si_signo = SIGFPE;
+		info.si_errno = 0;
+		info.si_addr = (void *)regs->cp0_epc;
+		force_sig_info(SIGFPE, &info, current);
+		break;
+	default:
+		force_sig(SIGTRAP, current);
+	}
+}
+
+asmlinkage void do_ri(struct pt_regs *regs)
+{
+	die_if_kernel("Reserved instruction in kernel code", regs);
+
+	if (!cpu_has_llsc)
+		if (!simulate_llsc(regs))
+			return;
+
+	force_sig(SIGILL, current);
+}
+
+asmlinkage void do_cpu(struct pt_regs *regs)
+{
+	unsigned int cpid;
+
+	die_if_kernel("do_cpu invoked from kernel context!", regs);
+
+	cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
+
+	switch (cpid) {
+	case 0:
+		if (cpu_has_llsc)
+			break;
+
+		if (!simulate_llsc(regs))
+			return;
+		break;
+
+	case 1:
+		preempt_disable();
+
+		own_fpu();
+		if (used_math()) {	/* Using the FPU again.  */
+			restore_fp(current);
+		} else {			/* First time FPU user.  */
+			init_fpu();
+			set_used_math();
+		}
+
+		if (!cpu_has_fpu) {
+			int sig = fpu_emulator_cop1Handler(0, regs,
+						&current->thread.fpu.soft);
+			if (sig)
+				force_sig(sig, current);
+		}
+
+		preempt_enable();
+
+		return;
+
+	case 2:
+	case 3:
+		break;
+	}
+
+	force_sig(SIGILL, current);
+}
+
+asmlinkage void do_mdmx(struct pt_regs *regs)
+{
+	force_sig(SIGILL, current);
+}
+
+asmlinkage void do_watch(struct pt_regs *regs)
+{
+	/*
+	 * We use the watch exception where available to detect stack
+	 * overflows.
+	 */
+	dump_tlb_all();
+	show_regs(regs);
+	panic("Caught WATCH exception - probably caused by stack overflow.");
+}
+
+asmlinkage void do_mcheck(struct pt_regs *regs)
+{
+	show_regs(regs);
+	dump_tlb_all();
+	/*
+	 * Some chips may have other causes of machine check (e.g. SB1
+	 * graduation timer)
+	 */
+	panic("Caught Machine Check exception - %scaused by multiple "
+	      "matching entries in the TLB.",
+	      (regs->cp0_status & ST0_TS) ? "" : "not ");
+}
+
+asmlinkage void do_reserved(struct pt_regs *regs)
+{
+	/*
+	 * Game over - no way to handle this if it ever occurs.  Most probably
+	 * caused by a new unknown cpu type or after another deadly
+	 * hard/software error.
+	 */
+	show_regs(regs);
+	panic("Caught reserved exception %ld - should not happen.",
+	      (regs->cp0_cause & 0x7f) >> 2);
+}
+
+/*
+ * Some MIPS CPUs can enable/disable for cache parity detection, but do
+ * it different ways.
+ */
+static inline void parity_protection_init(void)
+{
+	switch (current_cpu_data.cputype) {
+	case CPU_24K:
+		/* 24K cache parity not currently implemented in FPGA */
+		printk(KERN_INFO "Disable cache parity protection for "
+		       "MIPS 24K CPU.\n");
+		write_c0_ecc(read_c0_ecc() & ~0x80000000);
+		break;
+	case CPU_5KC:
+		/* Set the PE bit (bit 31) in the c0_ecc register. */
+		printk(KERN_INFO "Enable cache parity protection for "
+		       "MIPS 5KC/24K CPUs.\n");
+		write_c0_ecc(read_c0_ecc() | 0x80000000);
+		break;
+	case CPU_20KC:
+	case CPU_25KF:
+		/* Clear the DE bit (bit 16) in the c0_status register. */
+		printk(KERN_INFO "Enable cache parity protection for "
+		       "MIPS 20KC/25KF CPUs.\n");
+		clear_c0_status(ST0_DE);
+		break;
+	default:
+		break;
+	}
+}
+
+asmlinkage void cache_parity_error(void)
+{
+	const int field = 2 * sizeof(unsigned long);
+	unsigned int reg_val;
+
+	/* For the moment, report the problem and hang. */
+	printk("Cache error exception:\n");
+	printk("cp0_errorepc == %0*lx\n", field, read_c0_errorepc());
+	reg_val = read_c0_cacheerr();
+	printk("c0_cacheerr == %08x\n", reg_val);
+
+	printk("Decoded c0_cacheerr: %s cache fault in %s reference.\n",
+	       reg_val & (1<<30) ? "secondary" : "primary",
+	       reg_val & (1<<31) ? "data" : "insn");
+	printk("Error bits: %s%s%s%s%s%s%s\n",
+	       reg_val & (1<<29) ? "ED " : "",
+	       reg_val & (1<<28) ? "ET " : "",
+	       reg_val & (1<<26) ? "EE " : "",
+	       reg_val & (1<<25) ? "EB " : "",
+	       reg_val & (1<<24) ? "EI " : "",
+	       reg_val & (1<<23) ? "E1 " : "",
+	       reg_val & (1<<22) ? "E0 " : "");
+	printk("IDX: 0x%08x\n", reg_val & ((1<<22)-1));
+
+#if defined(CONFIG_CPU_MIPS32) || defined (CONFIG_CPU_MIPS64)
+	if (reg_val & (1<<22))
+		printk("DErrAddr0: 0x%0*lx\n", field, read_c0_derraddr0());
+
+	if (reg_val & (1<<23))
+		printk("DErrAddr1: 0x%0*lx\n", field, read_c0_derraddr1());
+#endif
+
+	panic("Can't handle the cache error!");
+}
+
+/*
+ * SDBBP EJTAG debug exception handler.
+ * We skip the instruction and return to the next instruction.
+ */
+void ejtag_exception_handler(struct pt_regs *regs)
+{
+	const int field = 2 * sizeof(unsigned long);
+	unsigned long depc, old_epc;
+	unsigned int debug;
+
+	printk("SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
+	depc = read_c0_depc();
+	debug = read_c0_debug();
+	printk("c0_depc = %0*lx, DEBUG = %08x\n", field, depc, debug);
+	if (debug & 0x80000000) {
+		/*
+		 * In branch delay slot.
+		 * We cheat a little bit here and use EPC to calculate the
+		 * debug return address (DEPC). EPC is restored after the
+		 * calculation.
+		 */
+		old_epc = regs->cp0_epc;
+		regs->cp0_epc = depc;
+		__compute_return_epc(regs);
+		depc = regs->cp0_epc;
+		regs->cp0_epc = old_epc;
+	} else
+		depc += 4;
+	write_c0_depc(depc);
+
+#if 0
+	printk("\n\n----- Enable EJTAG single stepping ----\n\n");
+	write_c0_debug(debug | 0x100);
+#endif
+}
+
+/*
+ * NMI exception handler.
+ */
+void nmi_exception_handler(struct pt_regs *regs)
+{
+	printk("NMI taken!!!!\n");
+	die("NMI", regs);
+	while(1) ;
+}
+
+unsigned long exception_handlers[32];
+
+/*
+ * As a side effect of the way this is implemented we're limited
+ * to interrupt handlers in the address range from
+ * KSEG0 <= x < KSEG0 + 256mb on the Nevada.  Oh well ...
+ */
+void *set_except_vector(int n, void *addr)
+{
+	unsigned long handler = (unsigned long) addr;
+	unsigned long old_handler = exception_handlers[n];
+
+	exception_handlers[n] = handler;
+	if (n == 0 && cpu_has_divec) {
+		*(volatile u32 *)(CAC_BASE + 0x200) = 0x08000000 |
+		                                 (0x03ffffff & (handler >> 2));
+		flush_icache_range(CAC_BASE + 0x200, CAC_BASE + 0x204);
+	}
+	return (void *)old_handler;
+}
+
+/*
+ * This is used by native signal handling
+ */
+asmlinkage int (*save_fp_context)(struct sigcontext *sc);
+asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
+
+extern asmlinkage int _save_fp_context(struct sigcontext *sc);
+extern asmlinkage int _restore_fp_context(struct sigcontext *sc);
+
+extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc);
+extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc);
+
+static inline void signal_init(void)
+{
+	if (cpu_has_fpu) {
+		save_fp_context = _save_fp_context;
+		restore_fp_context = _restore_fp_context;
+	} else {
+		save_fp_context = fpu_emulator_save_context;
+		restore_fp_context = fpu_emulator_restore_context;
+	}
+}
+
+#ifdef CONFIG_MIPS32_COMPAT
+
+/*
+ * This is used by 32-bit signal stuff on the 64-bit kernel
+ */
+asmlinkage int (*save_fp_context32)(struct sigcontext32 *sc);
+asmlinkage int (*restore_fp_context32)(struct sigcontext32 *sc);
+
+extern asmlinkage int _save_fp_context32(struct sigcontext32 *sc);
+extern asmlinkage int _restore_fp_context32(struct sigcontext32 *sc);
+
+extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 *sc);
+extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 *sc);
+
+static inline void signal32_init(void)
+{
+	if (cpu_has_fpu) {
+		save_fp_context32 = _save_fp_context32;
+		restore_fp_context32 = _restore_fp_context32;
+	} else {
+		save_fp_context32 = fpu_emulator_save_context32;
+		restore_fp_context32 = fpu_emulator_restore_context32;
+	}
+}
+#endif
+
+extern void cpu_cache_init(void);
+extern void tlb_init(void);
+
+void __init per_cpu_trap_init(void)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned int status_set = ST0_CU0;
+
+	/*
+	 * Disable coprocessors and select 32-bit or 64-bit addressing
+	 * and the 16/32 or 32/32 FPR register model.  Reset the BEV
+	 * flag that some firmware may have left set and the TS bit (for
+	 * IP27).  Set XX for ISA IV code to work.
+	 */
+#ifdef CONFIG_MIPS64
+	status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX;
+#endif
+	if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV)
+		status_set |= ST0_XX;
+	change_c0_status(ST0_CU|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
+			 status_set);
+
+	/*
+	 * Some MIPS CPUs have a dedicated interrupt vector which reduces the
+	 * interrupt processing overhead.  Use it where available.
+	 */
+	if (cpu_has_divec)
+		set_c0_cause(CAUSEF_IV);
+
+	cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
+	TLBMISS_HANDLER_SETUP();
+
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+	BUG_ON(current->mm);
+	enter_lazy_tlb(&init_mm, current);
+
+	cpu_cache_init();
+	tlb_init();
+}
+
+void __init trap_init(void)
+{
+	extern char except_vec3_generic, except_vec3_r4000;
+	extern char except_vec_ejtag_debug;
+	extern char except_vec4;
+	unsigned long i;
+
+	per_cpu_trap_init();
+
+	/*
+	 * Copy the generic exception handlers to their final destination.
+	 * This will be overriden later as suitable for a particular
+	 * configuration.
+	 */
+	memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80);
+
+	/*
+	 * Setup default vectors
+	 */
+	for (i = 0; i <= 31; i++)
+		set_except_vector(i, handle_reserved);
+
+	/*
+	 * Copy the EJTAG debug exception vector handler code to it's final
+	 * destination.
+	 */
+	if (cpu_has_ejtag)
+		memcpy((void *)(CAC_BASE + 0x300), &except_vec_ejtag_debug, 0x80);
+
+	/*
+	 * Only some CPUs have the watch exceptions.
+	 */
+	if (cpu_has_watch)
+		set_except_vector(23, handle_watch);
+
+	/*
+	 * Some MIPS CPUs have a dedicated interrupt vector which reduces the
+	 * interrupt processing overhead.  Use it where available.
+	 */
+	if (cpu_has_divec)
+		memcpy((void *)(CAC_BASE + 0x200), &except_vec4, 0x8);
+
+	/*
+	 * Some CPUs can enable/disable for cache parity detection, but does
+	 * it different ways.
+	 */
+	parity_protection_init();
+
+	/*
+	 * The Data Bus Errors / Instruction Bus Errors are signaled
+	 * by external hardware.  Therefore these two exceptions
+	 * may have board specific handlers.
+	 */
+	if (board_be_init)
+		board_be_init();
+
+	set_except_vector(1, handle_tlbm);
+	set_except_vector(2, handle_tlbl);
+	set_except_vector(3, handle_tlbs);
+
+	set_except_vector(4, handle_adel);
+	set_except_vector(5, handle_ades);
+
+	set_except_vector(6, handle_ibe);
+	set_except_vector(7, handle_dbe);
+
+	set_except_vector(8, handle_sys);
+	set_except_vector(9, handle_bp);
+	set_except_vector(10, handle_ri);
+	set_except_vector(11, handle_cpu);
+	set_except_vector(12, handle_ov);
+	set_except_vector(13, handle_tr);
+	set_except_vector(22, handle_mdmx);
+
+	if (cpu_has_fpu && !cpu_has_nofpuex)
+		set_except_vector(15, handle_fpe);
+
+	if (cpu_has_mcheck)
+		set_except_vector(24, handle_mcheck);
+
+	if (cpu_has_vce)
+		/* Special exception: R4[04]00 uses also the divec space. */
+		memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100);
+	else if (cpu_has_4kex)
+		memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80);
+	else
+		memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80);
+
+	if (current_cpu_data.cputype == CPU_R6000 ||
+	    current_cpu_data.cputype == CPU_R6000A) {
+		/*
+		 * The R6000 is the only R-series CPU that features a machine
+		 * check exception (similar to the R4000 cache error) and
+		 * unaligned ldc1/sdc1 exception.  The handlers have not been
+		 * written yet.  Well, anyway there is no R6000 machine on the
+		 * current list of targets for Linux/MIPS.
+		 * (Duh, crap, there is someone with a triple R6k machine)
+		 */
+		//set_except_vector(14, handle_mc);
+		//set_except_vector(15, handle_ndc);
+	}
+
+	signal_init();
+#ifdef CONFIG_MIPS32_COMPAT
+	signal32_init();
+#endif
+
+	flush_icache_range(CAC_BASE, CAC_BASE + 0x400);
+}
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
new file mode 100644
index 0000000..3f24a1d
--- /dev/null
+++ b/arch/mips/kernel/unaligned.c
@@ -0,0 +1,550 @@
+/*
+ * Handle unaligned accesses by emulation.
+ *
+ * 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, 1998, 1999, 2002 by Ralf Baechle
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ *
+ * This file contains exception handler for address error exception with the
+ * special capability to execute faulting instructions in software.  The
+ * handler does not try to handle the case when the program counter points
+ * to an address not aligned to a word boundary.
+ *
+ * Putting data to unaligned addresses is a bad practice even on Intel where
+ * only the performance is affected.  Much worse is that such code is non-
+ * portable.  Due to several programs that die on MIPS due to alignment
+ * problems I decided to implement this handler anyway though I originally
+ * didn't intend to do this at all for user code.
+ *
+ * For now I enable fixing of address errors by default to make life easier.
+ * I however intend to disable this somewhen in the future when the alignment
+ * problems with user programs have been fixed.  For programmers this is the
+ * right way to go.
+ *
+ * Fixing address errors is a per process option.  The option is inherited
+ * across fork(2) and execve(2) calls.  If you really want to use the
+ * option in your user programs - I discourage the use of the software
+ * emulation strongly - use the following code in your userland stuff:
+ *
+ * #include <sys/sysmips.h>
+ *
+ * ...
+ * sysmips(MIPS_FIXADE, x);
+ * ...
+ *
+ * The argument x is 0 for disabling software emulation, enabled otherwise.
+ *
+ * Below a little program to play around with this feature.
+ *
+ * #include <stdio.h>
+ * #include <sys/sysmips.h>
+ *
+ * struct foo {
+ *         unsigned char bar[8];
+ * };
+ *
+ * main(int argc, char *argv[])
+ * {
+ *         struct foo x = {0, 1, 2, 3, 4, 5, 6, 7};
+ *         unsigned int *p = (unsigned int *) (x.bar + 3);
+ *         int i;
+ *
+ *         if (argc > 1)
+ *                 sysmips(MIPS_FIXADE, atoi(argv[1]));
+ *
+ *         printf("*p = %08lx\n", *p);
+ *
+ *         *p = 0xdeadface;
+ *
+ *         for(i = 0; i <= 7; i++)
+ *         printf("%02x ", x.bar[i]);
+ *         printf("\n");
+ * }
+ *
+ * Coprocessor loads are not supported; I think this case is unimportant
+ * in the practice.
+ *
+ * TODO: Handle ndc (attempted store to doubleword in uncached memory)
+ *       exception for the R6000.
+ *       A store crossing a page boundary might be executed only partially.
+ *       Undo the partial store in this case.
+ */
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/asm.h>
+#include <asm/branch.h>
+#include <asm/byteorder.h>
+#include <asm/inst.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#define STR(x)  __STR(x)
+#define __STR(x)  #x
+
+#ifdef CONFIG_PROC_FS
+unsigned long unaligned_instructions;
+#endif
+
+static inline int emulate_load_store_insn(struct pt_regs *regs,
+	void *addr, unsigned long pc,
+	unsigned long **regptr, unsigned long *newvalue)
+{
+	union mips_instruction insn;
+	unsigned long value;
+	unsigned int res;
+
+	regs->regs[0] = 0;
+	*regptr=NULL;
+
+	/*
+	 * This load never faults.
+	 */
+	__get_user(insn.word, (unsigned int *)pc);
+
+	switch (insn.i_format.opcode) {
+	/*
+	 * These are instructions that a compiler doesn't generate.  We
+	 * can assume therefore that the code is MIPS-aware and
+	 * really buggy.  Emulating these instructions would break the
+	 * semantics anyway.
+	 */
+	case ll_op:
+	case lld_op:
+	case sc_op:
+	case scd_op:
+
+	/*
+	 * For these instructions the only way to create an address
+	 * error is an attempted access to kernel/supervisor address
+	 * space.
+	 */
+	case ldl_op:
+	case ldr_op:
+	case lwl_op:
+	case lwr_op:
+	case sdl_op:
+	case sdr_op:
+	case swl_op:
+	case swr_op:
+	case lb_op:
+	case lbu_op:
+	case sb_op:
+		goto sigbus;
+
+	/*
+	 * The remaining opcodes are the ones that are really of interest.
+	 */
+	case lh_op:
+		if (!access_ok(VERIFY_READ, addr, 2))
+			goto sigbus;
+
+		__asm__ __volatile__ (".set\tnoat\n"
+#ifdef __BIG_ENDIAN
+			"1:\tlb\t%0, 0(%2)\n"
+			"2:\tlbu\t$1, 1(%2)\n\t"
+#endif
+#ifdef __LITTLE_ENDIAN
+			"1:\tlb\t%0, 1(%2)\n"
+			"2:\tlbu\t$1, 0(%2)\n\t"
+#endif
+			"sll\t%0, 0x8\n\t"
+			"or\t%0, $1\n\t"
+			"li\t%1, 0\n"
+			"3:\t.set\tat\n\t"
+			".section\t.fixup,\"ax\"\n\t"
+			"4:\tli\t%1, %3\n\t"
+			"j\t3b\n\t"
+			".previous\n\t"
+			".section\t__ex_table,\"a\"\n\t"
+			STR(PTR)"\t1b, 4b\n\t"
+			STR(PTR)"\t2b, 4b\n\t"
+			".previous"
+			: "=&r" (value), "=r" (res)
+			: "r" (addr), "i" (-EFAULT));
+		if (res)
+			goto fault;
+		*newvalue = value;
+		*regptr = &regs->regs[insn.i_format.rt];
+		break;
+
+	case lw_op:
+		if (!access_ok(VERIFY_READ, addr, 4))
+			goto sigbus;
+
+		__asm__ __volatile__ (
+#ifdef __BIG_ENDIAN
+			"1:\tlwl\t%0, (%2)\n"
+			"2:\tlwr\t%0, 3(%2)\n\t"
+#endif
+#ifdef __LITTLE_ENDIAN
+			"1:\tlwl\t%0, 3(%2)\n"
+			"2:\tlwr\t%0, (%2)\n\t"
+#endif
+			"li\t%1, 0\n"
+			"3:\t.section\t.fixup,\"ax\"\n\t"
+			"4:\tli\t%1, %3\n\t"
+			"j\t3b\n\t"
+			".previous\n\t"
+			".section\t__ex_table,\"a\"\n\t"
+			STR(PTR)"\t1b, 4b\n\t"
+			STR(PTR)"\t2b, 4b\n\t"
+			".previous"
+			: "=&r" (value), "=r" (res)
+			: "r" (addr), "i" (-EFAULT));
+		if (res)
+			goto fault;
+		*newvalue = value;
+		*regptr = &regs->regs[insn.i_format.rt];
+		break;
+
+	case lhu_op:
+		if (!access_ok(VERIFY_READ, addr, 2))
+			goto sigbus;
+
+		__asm__ __volatile__ (
+			".set\tnoat\n"
+#ifdef __BIG_ENDIAN
+			"1:\tlbu\t%0, 0(%2)\n"
+			"2:\tlbu\t$1, 1(%2)\n\t"
+#endif
+#ifdef __LITTLE_ENDIAN
+			"1:\tlbu\t%0, 1(%2)\n"
+			"2:\tlbu\t$1, 0(%2)\n\t"
+#endif
+			"sll\t%0, 0x8\n\t"
+			"or\t%0, $1\n\t"
+			"li\t%1, 0\n"
+			"3:\t.set\tat\n\t"
+			".section\t.fixup,\"ax\"\n\t"
+			"4:\tli\t%1, %3\n\t"
+			"j\t3b\n\t"
+			".previous\n\t"
+			".section\t__ex_table,\"a\"\n\t"
+			STR(PTR)"\t1b, 4b\n\t"
+			STR(PTR)"\t2b, 4b\n\t"
+			".previous"
+			: "=&r" (value), "=r" (res)
+			: "r" (addr), "i" (-EFAULT));
+		if (res)
+			goto fault;
+		*newvalue = value;
+		*regptr = &regs->regs[insn.i_format.rt];
+		break;
+
+	case lwu_op:
+#ifdef CONFIG_MIPS64
+		/*
+		 * A 32-bit kernel might be running on a 64-bit processor.  But
+		 * if we're on a 32-bit processor and an i-cache incoherency
+		 * or race makes us see a 64-bit instruction here the sdl/sdr
+		 * would blow up, so for now we don't handle unaligned 64-bit
+		 * instructions on 32-bit kernels.
+		 */
+		if (!access_ok(VERIFY_READ, addr, 4))
+			goto sigbus;
+
+		__asm__ __volatile__ (
+#ifdef __BIG_ENDIAN
+			"1:\tlwl\t%0, (%2)\n"
+			"2:\tlwr\t%0, 3(%2)\n\t"
+#endif
+#ifdef __LITTLE_ENDIAN
+			"1:\tlwl\t%0, 3(%2)\n"
+			"2:\tlwr\t%0, (%2)\n\t"
+#endif
+			"dsll\t%0, %0, 32\n\t"
+			"dsrl\t%0, %0, 32\n\t"
+			"li\t%1, 0\n"
+			"3:\t.section\t.fixup,\"ax\"\n\t"
+			"4:\tli\t%1, %3\n\t"
+			"j\t3b\n\t"
+			".previous\n\t"
+			".section\t__ex_table,\"a\"\n\t"
+			STR(PTR)"\t1b, 4b\n\t"
+			STR(PTR)"\t2b, 4b\n\t"
+			".previous"
+			: "=&r" (value), "=r" (res)
+			: "r" (addr), "i" (-EFAULT));
+		if (res)
+			goto fault;
+		*newvalue = value;
+		*regptr = &regs->regs[insn.i_format.rt];
+		break;
+#endif /* CONFIG_MIPS64 */
+
+		/* Cannot handle 64-bit instructions in 32-bit kernel */
+		goto sigill;
+
+	case ld_op:
+#ifdef CONFIG_MIPS64
+		/*
+		 * A 32-bit kernel might be running on a 64-bit processor.  But
+		 * if we're on a 32-bit processor and an i-cache incoherency
+		 * or race makes us see a 64-bit instruction here the sdl/sdr
+		 * would blow up, so for now we don't handle unaligned 64-bit
+		 * instructions on 32-bit kernels.
+		 */
+		if (!access_ok(VERIFY_READ, addr, 8))
+			goto sigbus;
+
+		__asm__ __volatile__ (
+#ifdef __BIG_ENDIAN
+			"1:\tldl\t%0, (%2)\n"
+			"2:\tldr\t%0, 7(%2)\n\t"
+#endif
+#ifdef __LITTLE_ENDIAN
+			"1:\tldl\t%0, 7(%2)\n"
+			"2:\tldr\t%0, (%2)\n\t"
+#endif
+			"li\t%1, 0\n"
+			"3:\t.section\t.fixup,\"ax\"\n\t"
+			"4:\tli\t%1, %3\n\t"
+			"j\t3b\n\t"
+			".previous\n\t"
+			".section\t__ex_table,\"a\"\n\t"
+			STR(PTR)"\t1b, 4b\n\t"
+			STR(PTR)"\t2b, 4b\n\t"
+			".previous"
+			: "=&r" (value), "=r" (res)
+			: "r" (addr), "i" (-EFAULT));
+		if (res)
+			goto fault;
+		*newvalue = value;
+		*regptr = &regs->regs[insn.i_format.rt];
+		break;
+#endif /* CONFIG_MIPS64 */
+
+		/* Cannot handle 64-bit instructions in 32-bit kernel */
+		goto sigill;
+
+	case sh_op:
+		if (!access_ok(VERIFY_WRITE, addr, 2))
+			goto sigbus;
+
+		value = regs->regs[insn.i_format.rt];
+		__asm__ __volatile__ (
+#ifdef __BIG_ENDIAN
+			".set\tnoat\n"
+			"1:\tsb\t%1, 1(%2)\n\t"
+			"srl\t$1, %1, 0x8\n"
+			"2:\tsb\t$1, 0(%2)\n\t"
+			".set\tat\n\t"
+#endif
+#ifdef __LITTLE_ENDIAN
+			".set\tnoat\n"
+			"1:\tsb\t%1, 0(%2)\n\t"
+			"srl\t$1,%1, 0x8\n"
+			"2:\tsb\t$1, 1(%2)\n\t"
+			".set\tat\n\t"
+#endif
+			"li\t%0, 0\n"
+			"3:\n\t"
+			".section\t.fixup,\"ax\"\n\t"
+			"4:\tli\t%0, %3\n\t"
+			"j\t3b\n\t"
+			".previous\n\t"
+			".section\t__ex_table,\"a\"\n\t"
+			STR(PTR)"\t1b, 4b\n\t"
+			STR(PTR)"\t2b, 4b\n\t"
+			".previous"
+			: "=r" (res)
+			: "r" (value), "r" (addr), "i" (-EFAULT));
+		if (res)
+			goto fault;
+		break;
+
+	case sw_op:
+		if (!access_ok(VERIFY_WRITE, addr, 4))
+			goto sigbus;
+
+		value = regs->regs[insn.i_format.rt];
+		__asm__ __volatile__ (
+#ifdef __BIG_ENDIAN
+			"1:\tswl\t%1,(%2)\n"
+			"2:\tswr\t%1, 3(%2)\n\t"
+#endif
+#ifdef __LITTLE_ENDIAN
+			"1:\tswl\t%1, 3(%2)\n"
+			"2:\tswr\t%1, (%2)\n\t"
+#endif
+			"li\t%0, 0\n"
+			"3:\n\t"
+			".section\t.fixup,\"ax\"\n\t"
+			"4:\tli\t%0, %3\n\t"
+			"j\t3b\n\t"
+			".previous\n\t"
+			".section\t__ex_table,\"a\"\n\t"
+			STR(PTR)"\t1b, 4b\n\t"
+			STR(PTR)"\t2b, 4b\n\t"
+			".previous"
+		: "=r" (res)
+		: "r" (value), "r" (addr), "i" (-EFAULT));
+		if (res)
+			goto fault;
+		break;
+
+	case sd_op:
+#ifdef CONFIG_MIPS64
+		/*
+		 * A 32-bit kernel might be running on a 64-bit processor.  But
+		 * if we're on a 32-bit processor and an i-cache incoherency
+		 * or race makes us see a 64-bit instruction here the sdl/sdr
+		 * would blow up, so for now we don't handle unaligned 64-bit
+		 * instructions on 32-bit kernels.
+		 */
+		if (!access_ok(VERIFY_WRITE, addr, 8))
+			goto sigbus;
+
+		value = regs->regs[insn.i_format.rt];
+		__asm__ __volatile__ (
+#ifdef __BIG_ENDIAN
+			"1:\tsdl\t%1,(%2)\n"
+			"2:\tsdr\t%1, 7(%2)\n\t"
+#endif
+#ifdef __LITTLE_ENDIAN
+			"1:\tsdl\t%1, 7(%2)\n"
+			"2:\tsdr\t%1, (%2)\n\t"
+#endif
+			"li\t%0, 0\n"
+			"3:\n\t"
+			".section\t.fixup,\"ax\"\n\t"
+			"4:\tli\t%0, %3\n\t"
+			"j\t3b\n\t"
+			".previous\n\t"
+			".section\t__ex_table,\"a\"\n\t"
+			STR(PTR)"\t1b, 4b\n\t"
+			STR(PTR)"\t2b, 4b\n\t"
+			".previous"
+		: "=r" (res)
+		: "r" (value), "r" (addr), "i" (-EFAULT));
+		if (res)
+			goto fault;
+		break;
+#endif /* CONFIG_MIPS64 */
+
+		/* Cannot handle 64-bit instructions in 32-bit kernel */
+		goto sigill;
+
+	case lwc1_op:
+	case ldc1_op:
+	case swc1_op:
+	case sdc1_op:
+		/*
+		 * I herewith declare: this does not happen.  So send SIGBUS.
+		 */
+		goto sigbus;
+
+	case lwc2_op:
+	case ldc2_op:
+	case swc2_op:
+	case sdc2_op:
+		/*
+		 * These are the coprocessor 2 load/stores.  The current
+		 * implementations don't use cp2 and cp2 should always be
+		 * disabled in c0_status.  So send SIGILL.
+                 * (No longer true: The Sony Praystation uses cp2 for
+                 * 3D matrix operations.  Dunno if that thingy has a MMU ...)
+		 */
+	default:
+		/*
+		 * Pheeee...  We encountered an yet unknown instruction or
+		 * cache coherence problem.  Die sucker, die ...
+		 */
+		goto sigill;
+	}
+
+#ifdef CONFIG_PROC_FS
+	unaligned_instructions++;
+#endif
+
+	return 0;
+
+fault:
+	/* Did we have an exception handler installed? */
+	if (fixup_exception(regs))
+		return 1;
+
+	die_if_kernel ("Unhandled kernel unaligned access", regs);
+	send_sig(SIGSEGV, current, 1);
+
+	return 0;
+
+sigbus:
+	die_if_kernel("Unhandled kernel unaligned access", regs);
+	send_sig(SIGBUS, current, 1);
+
+	return 0;
+
+sigill:
+	die_if_kernel("Unhandled kernel unaligned access or invalid instruction", regs);
+	send_sig(SIGILL, current, 1);
+
+	return 0;
+}
+
+asmlinkage void do_ade(struct pt_regs *regs)
+{
+	unsigned long *regptr, newval;
+	extern int do_dsemulret(struct pt_regs *);
+	mm_segment_t seg;
+	unsigned long pc;
+
+	/*
+	 * Address errors may be deliberately induced by the FPU emulator to
+	 * retake control of the CPU after executing the instruction in the
+	 * delay slot of an emulated branch.
+	 */
+	/* Terminate if exception was recognized as a delay slot return */
+	if (do_dsemulret(regs))
+		return;
+
+	/* Otherwise handle as normal */
+
+	/*
+	 * Did we catch a fault trying to load an instruction?
+	 * Or are we running in MIPS16 mode?
+	 */
+	if ((regs->cp0_badvaddr == regs->cp0_epc) || (regs->cp0_epc & 0x1))
+		goto sigbus;
+
+	pc = exception_epc(regs);
+	if ((current->thread.mflags & MF_FIXADE) == 0)
+		goto sigbus;
+
+	/*
+	 * Do branch emulation only if we didn't forward the exception.
+	 * This is all so but ugly ...
+	 */
+	seg = get_fs();
+	if (!user_mode(regs))
+		set_fs(KERNEL_DS);
+	if (!emulate_load_store_insn(regs, (void *)regs->cp0_badvaddr, pc,
+	                             &regptr, &newval)) {
+		compute_return_epc(regs);
+		/*
+		 * Now that branch is evaluated, update the dest
+		 * register if necessary
+		 */
+		if (regptr)
+			*regptr = newval;
+	}
+	set_fs(seg);
+
+	return;
+
+sigbus:
+	die_if_kernel("Kernel unaligned instruction access", regs);
+	force_sig(SIGBUS, current);
+
+	/*
+	 * XXX On return from the signal handler we should advance the epc
+	 */
+}
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
new file mode 100644
index 0000000..e830d78
--- /dev/null
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -0,0 +1,183 @@
+#include <linux/config.h>
+#include <asm-generic/vmlinux.lds.h>
+
+#undef mips		/* CPP really sucks for this job  */
+#define mips mips
+OUTPUT_ARCH(mips)
+ENTRY(kernel_entry)
+jiffies = JIFFIES;
+SECTIONS
+{
+#ifdef CONFIG_BOOT_ELF64
+  /* Read-only sections, merged into text segment: */
+  /* . = 0xc000000000000000; */
+
+  /* This is the value for an Origin kernel, taken from an IRIX kernel.  */
+  /* . = 0xc00000000001c000; */
+
+  /* Set the vaddr for the text segment to a value 
+        >= 0xa800 0000 0001 9000 if no symmon is going to configured
+        >= 0xa800 0000 0030 0000 otherwise  */
+
+  /* . = 0xa800000000300000; */
+  /* . = 0xa800000000300000; */
+  . = 0xffffffff80300000;
+#endif
+  . = LOADADDR;
+  /* read-only */
+  _text = .;			/* Text and read-only data */
+  .text : {
+    *(.text)
+    SCHED_TEXT
+    LOCK_TEXT
+    *(.fixup)
+    *(.gnu.warning)
+  } =0
+
+  _etext = .;			/* End of text section */
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___dbe_table = .;	/* Exception table for data bus errors */
+  __dbe_table : { *(__dbe_table) }
+  __stop___dbe_table = .;
+
+  RODATA
+
+  /* writeable */
+  .data : {			/* Data */
+    . = . + DATAOFFSET;		/* for CONFIG_MAPPED_KERNEL */
+    *(.data.init_task)
+
+    *(.data)
+
+   /* Align the initial ramdisk image (INITRD) on page boundaries. */
+   . = ALIGN(4096);
+   __rd_start = .;
+   *(.initrd)
+   . = ALIGN(4096);
+   __rd_end = .;
+
+    CONSTRUCTORS
+  }
+  _gp = . + 0x8000;
+  .lit8 : { *(.lit8) }
+  .lit4 : { *(.lit4) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+
+  . = ALIGN(4096);
+  __nosave_begin = .;
+  .data_nosave : { *(.data.nosave) }
+  . = ALIGN(4096);
+  __nosave_end = .;
+
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  _edata =  .;			/* End of data section */
+
+  /* will be freed after init */
+  . = ALIGN(4096);		/* Init code and data */
+  __init_begin = .;
+  .init.text : {
+	_sinittext = .;
+	*(.init.text)
+	_einittext = .;
+  }
+  .init.data : { *(.init.data) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .init.setup : { *(.init.setup) }
+  __setup_end = .;
+
+  .early_initcall.init : {
+  __earlyinitcall_start = .;
+	*(.initcall.early1.init)
+  }
+  __earlyinitcall_end = .;
+
+  __initcall_start = .;
+  .initcall.init : {
+	*(.initcall1.init)
+	*(.initcall2.init)
+	*(.initcall3.init)
+	*(.initcall4.init)
+	*(.initcall5.init)
+	*(.initcall6.init)
+	*(.initcall7.init)
+  }
+  __initcall_end = .;
+
+  __con_initcall_start = .;
+  .con_initcall.init : { *(.con_initcall.init) }
+  __con_initcall_end = .;
+  SECURITY_INIT
+  . = ALIGN(4096);
+  __initramfs_start = .;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
+  . = ALIGN(32);
+  __per_cpu_start = .;
+  .data.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
+  . = ALIGN(4096);
+  __init_end = .;
+  /* freed after init ends here */
+
+  __bss_start = .;		/* BSS */
+  .sbss      : {
+    *(.sbss)
+    *(.scommon)
+  }
+  .bss : {
+    *(.bss)
+    *(COMMON)
+  }
+  __bss_stop = .;
+
+  _end = . ;
+
+  /* Sections to be discarded */
+  /DISCARD/ : {
+        *(.exit.text)
+        *(.exit.data)
+        *(.exitcall.exit)
+
+	/* ABI crap starts here */
+	*(.comment)
+	*(.MIPS.options)
+	*(.note)
+	*(.options)
+	*(.pdr)
+	*(.reginfo)
+	*(.mdebug*)
+  }
+
+  /* This is the MIPS specific mdebug section.  */
+  .mdebug : { *(.mdebug) }
+  /* These are needed for ELF backends which have not yet been
+     converted to the new style linker.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  /* DWARF debug sections.
+     Symbols in the .debug DWARF section are relative to the beginning of the
+     section so we begin .debug at 0.  It's not clear yet what needs to happen
+     for the others.   */
+  .debug          0 : { *(.debug) }
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  .line           0 : { *(.line) }
+  /* These must appear regardless of  .  */
+  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+  .comment : { *(.comment) }
+  .note : { *(.note) }
+}